From 6dc7faf4b5d9218755a7bbb16e9f429b1da62624 Mon Sep 17 00:00:00 2001 From: heltai <heltai@0785d39b-7218-0410-832d-ea1e28bc413d> Date: Sun, 25 Aug 2013 14:20:31 +0000 Subject: [PATCH] Merged from trunk git-svn-id: https://svn.dealii.org/branches/branch_manifold_id@30480 0785d39b-7218-0410-832d-ea1e28bc413d --- deal.II/cmake/config/CMakeLists.txt | 6 +- .../cmake/configure/configure_1_lapack.cmake | 2 +- deal.II/cmake/configure/configure_1_mpi.cmake | 2 +- .../cmake/configure/configure_1_threads.cmake | 8 +- .../cmake/configure/configure_2_metis.cmake | 1 + .../cmake/configure/configure_2_petsc.cmake | 3 +- .../configure/configure_2_trilinos.cmake | 11 +- deal.II/cmake/configure/configure_boost.cmake | 21 +- deal.II/cmake/configure/configure_hdf5.cmake | 6 + deal.II/cmake/configure/configure_mumps.cmake | 2 +- deal.II/cmake/configure/configure_p4est.cmake | 9 +- deal.II/cmake/configure/configure_slepc.cmake | 3 +- .../macros/macro_configure_feature.cmake | 2 +- ...e => macro_deal_ii_append_libraries.cmake} | 36 +- deal.II/cmake/modules/FindMETIS.cmake | 1 + deal.II/cmake/modules/FindP4EST.cmake | 90 +- deal.II/cmake/modules/FindTRILINOS.cmake | 2 + deal.II/doc/development/Config.sample | 11 + deal.II/doc/documentation.html | 36 +- deal.II/doc/news/changes.h | 83 + deal.II/examples/step-10/doc/results.dox | 153 +- deal.II/examples/step-14/step-14.cc | 2 +- deal.II/examples/step-42/step-42.cc | 58 +- deal.II/examples/step-51/doc/intro.dox | 40 +- deal.II/examples/step-51/doc/results.dox | 128 +- deal.II/examples/step-51/step-51.cc | 85 +- deal.II/include/deal.II/base/data_out_base.h | 1663 +++---- .../include/deal.II/base/parameter_handler.h | 73 +- .../deal.II/dofs/dof_accessor.templates.h | 9 + deal.II/include/deal.II/fe/component_mask.h | 5 + deal.II/include/deal.II/fe/fe_tools.h | 7 +- deal.II/include/deal.II/fe/mapping_c1.h | 67 +- deal.II/include/deal.II/fe/mapping_q.h | 400 +- .../include/deal.II/fe/mapping_q_eulerian.h | 88 +- deal.II/include/deal.II/grid/tria.h | 2 +- deal.II/include/deal.II/grid/tria_boundary.h | 509 +-- deal.II/include/deal.II/hp/fe_values.h | 49 + deal.II/include/deal.II/integrators/laplace.h | 71 + .../include/deal.II/lac/constraint_matrix.h | 17 + deal.II/include/deal.II/lac/slepc_solver.h | 32 +- .../deal.II/meshworker/integration_info.h | 418 +- deal.II/include/deal.II/meshworker/simple.h | 169 +- .../multigrid/sparse_matrix_collection.h | 124 + deal.II/include/deal.II/numerics/data_out.h | 882 +--- .../deal.II/numerics/data_out_dof_data.h | 920 ++++ .../deal.II/numerics/data_out_rotation.h | 2 +- .../deal.II/numerics/error_estimator.h | 338 +- .../include/deal.II/numerics/vector_tools.h | 438 +- .../deal.II/numerics/vector_tools.templates.h | 969 ++-- deal.II/source/CMakeLists.txt | 2 +- deal.II/source/base/data_out_base.cc | 28 +- deal.II/source/base/parameter_handler.cc | 199 +- deal.II/source/base/partitioner.cc | 64 +- deal.II/source/dofs/CMakeLists.txt | 8 + deal.II/source/dofs/dof_accessor.cc | 178 - deal.II/source/dofs/dof_accessor.inst.in | 79 - deal.II/source/dofs/dof_accessor_get.cc | 125 + deal.II/source/dofs/dof_accessor_get.inst.in | 72 + deal.II/source/dofs/dof_accessor_set.cc | 93 + deal.II/source/dofs/dof_accessor_set.inst.in | 72 + deal.II/source/dofs/dof_tools.cc | 3963 +---------------- deal.II/source/dofs/dof_tools.inst.in | 448 +- deal.II/source/dofs/dof_tools_constraints.cc | 2891 ++++++++++++ .../source/dofs/dof_tools_constraints.inst.in | 147 + deal.II/source/dofs/dof_tools_sparsity.cc | 1179 +++++ .../source/dofs/dof_tools_sparsity.inst.in | 323 ++ deal.II/source/fe/CMakeLists.txt | 2 + deal.II/source/fe/fe.cc | 16 +- deal.II/source/fe/fe_q_base.cc | 127 +- deal.II/source/fe/fe_tools.cc | 711 +-- deal.II/source/fe/fe_tools.inst.in | 99 +- deal.II/source/fe/fe_tools_interpolate.cc | 761 ++++ .../source/fe/fe_tools_interpolate.inst.in | 107 + deal.II/source/fe/mapping_c1.cc | 114 +- deal.II/source/fe/mapping_q.cc | 681 +-- deal.II/source/fe/mapping_q_eulerian.cc | 78 +- deal.II/source/grid/grid_out.cc | 2 +- deal.II/source/grid/tria_boundary.cc | 92 +- deal.II/source/grid/tria_boundary_lib.cc | 226 +- deal.II/source/lac/slepc_solver.cc | 40 +- deal.II/source/numerics/CMakeLists.txt | 26 +- deal.II/source/numerics/data_out.cc | 1091 ----- deal.II/source/numerics/data_out.inst.in | 357 +- deal.II/source/numerics/data_out_dof_data.cc | 1146 +++++ .../source/numerics/data_out_dof_data.inst.in | 428 ++ deal.II/source/numerics/error_estimator.cc | 1095 +---- .../source/numerics/error_estimator.inst.in | 2 +- deal.II/source/numerics/error_estimator_1d.cc | 439 ++ .../numerics/error_estimator_1d.inst.in | 143 + deal.II/source/numerics/solution_transfer.cc | 83 +- .../source/numerics/solution_transfer.inst.in | 3 + .../numerics/solution_transfer_inst2.cc | 5 +- .../numerics/solution_transfer_inst3.cc | 23 + .../numerics/solution_transfer_inst4.cc | 23 + deal.II/source/numerics/vector_tools.inst.in | 703 --- .../source/numerics/vector_tools_boundary.cc | 25 + .../numerics/vector_tools_boundary.inst.in | 186 + .../numerics/vector_tools_constraints.cc | 25 + .../numerics/vector_tools_constraints.inst.in | 58 + .../vector_tools_integrate_difference.cc | 25 + .../vector_tools_integrate_difference.inst.in | 117 + .../numerics/vector_tools_interpolate.cc | 25 + .../numerics/vector_tools_interpolate.inst.in | 199 + .../numerics/vector_tools_mean_value.cc | 25 + .../numerics/vector_tools_mean_value.inst.in | 50 + .../numerics/vector_tools_point_value.cc | 25 + .../numerics/vector_tools_point_value.inst.in | 165 + ...ector_tools.cc => vector_tools_project.cc} | 2 +- .../numerics/vector_tools_project.inst.in | 70 + deal.II/source/numerics/vector_tools_rhs.cc | 86 + .../source/numerics/vector_tools_rhs.inst.in | 108 + 111 files changed, 13891 insertions(+), 13847 deletions(-) rename deal.II/cmake/macros/{macro_split_debug_release.cmake => macro_deal_ii_append_libraries.cmake} (51%) create mode 100644 deal.II/include/deal.II/multigrid/sparse_matrix_collection.h create mode 100644 deal.II/include/deal.II/numerics/data_out_dof_data.h create mode 100644 deal.II/source/dofs/dof_accessor_get.cc create mode 100644 deal.II/source/dofs/dof_accessor_get.inst.in create mode 100644 deal.II/source/dofs/dof_accessor_set.cc create mode 100644 deal.II/source/dofs/dof_accessor_set.inst.in create mode 100644 deal.II/source/dofs/dof_tools_constraints.cc create mode 100644 deal.II/source/dofs/dof_tools_constraints.inst.in create mode 100644 deal.II/source/dofs/dof_tools_sparsity.cc create mode 100644 deal.II/source/dofs/dof_tools_sparsity.inst.in create mode 100644 deal.II/source/fe/fe_tools_interpolate.cc create mode 100644 deal.II/source/fe/fe_tools_interpolate.inst.in create mode 100644 deal.II/source/numerics/data_out_dof_data.cc create mode 100644 deal.II/source/numerics/data_out_dof_data.inst.in create mode 100644 deal.II/source/numerics/error_estimator_1d.cc create mode 100644 deal.II/source/numerics/error_estimator_1d.inst.in create mode 100644 deal.II/source/numerics/solution_transfer_inst3.cc create mode 100644 deal.II/source/numerics/solution_transfer_inst4.cc delete mode 100644 deal.II/source/numerics/vector_tools.inst.in create mode 100644 deal.II/source/numerics/vector_tools_boundary.cc create mode 100644 deal.II/source/numerics/vector_tools_boundary.inst.in create mode 100644 deal.II/source/numerics/vector_tools_constraints.cc create mode 100644 deal.II/source/numerics/vector_tools_constraints.inst.in create mode 100644 deal.II/source/numerics/vector_tools_integrate_difference.cc create mode 100644 deal.II/source/numerics/vector_tools_integrate_difference.inst.in create mode 100644 deal.II/source/numerics/vector_tools_interpolate.cc create mode 100644 deal.II/source/numerics/vector_tools_interpolate.inst.in create mode 100644 deal.II/source/numerics/vector_tools_mean_value.cc create mode 100644 deal.II/source/numerics/vector_tools_mean_value.inst.in create mode 100644 deal.II/source/numerics/vector_tools_point_value.cc create mode 100644 deal.II/source/numerics/vector_tools_point_value.inst.in rename deal.II/source/numerics/{vector_tools.cc => vector_tools_project.cc} (95%) create mode 100644 deal.II/source/numerics/vector_tools_project.inst.in create mode 100644 deal.II/source/numerics/vector_tools_rhs.cc create mode 100644 deal.II/source/numerics/vector_tools_rhs.inst.in diff --git a/deal.II/cmake/config/CMakeLists.txt b/deal.II/cmake/config/CMakeLists.txt index 071ba6110b..8cea9494f3 100644 --- a/deal.II/cmake/config/CMakeLists.txt +++ b/deal.II/cmake/config/CMakeLists.txt @@ -76,8 +76,8 @@ FOREACH(_build ${DEAL_II_BUILD_TYPES}) SET(CONFIG_LIBRARIES_${_build} \${DEAL_II_PATH}/\${DEAL_II_LIBRARY_RELDIR}/${CONFIG_LIBRARY_${_build}} - ${DEAL_II_EXTERNAL_LIBRARIES} ${DEAL_II_EXTERNAL_LIBRARIES_${_build}} + ${DEAL_II_EXTERNAL_LIBRARIES} ) LIST(APPEND CONFIG_LIBRARIES ${_keyword} @@ -172,8 +172,8 @@ IF(DEAL_II_COMPONENT_COMPAT_FILES) # SET(_libs) FOREACH(_lib - ${DEAL_II_EXTERNAL_LIBRARIES} ${DEAL_II_EXTERNAL_LIBRARIES_${build}} + ${DEAL_II_EXTERNAL_LIBRARIES} ) IF(_lib MATCHES "^\\s*/") LIST(APPEND _libs "${_lib}") @@ -190,8 +190,8 @@ IF(DEAL_II_COMPONENT_COMPAT_FILES) SET(_paths) FOREACH(_lib $(D)/${DEAL_II_LIBRARY_RELDIR}/${CONFIG_LIBRARY_${build}} - ${DEAL_II_EXTERNAL_LIBRARIES} ${DEAL_II_EXTERNAL_LIBRARIES_${build}} + ${DEAL_II_EXTERNAL_LIBRARIES} ) # diff --git a/deal.II/cmake/configure/configure_1_lapack.cmake b/deal.II/cmake/configure/configure_1_lapack.cmake index 455a4944b4..7c64e0dbe9 100644 --- a/deal.II/cmake/configure/configure_1_lapack.cmake +++ b/deal.II/cmake/configure/configure_1_lapack.cmake @@ -83,7 +83,7 @@ ENDMACRO() MACRO(FEATURE_LAPACK_CONFIGURE_EXTERNAL) ADD_FLAGS(DEAL_II_LINKER_FLAGS "${LAPACK_LINKER_FLAGS}") - LIST(APPEND DEAL_II_EXTERNAL_LIBRARIES ${LAPACK_LIBRARIES}) + DEAL_II_APPEND_LIBRARIES(${LAPACK_LIBRARIES}) CHECK_FOR_LAPACK_FUNCTIONS() ENDMACRO() diff --git a/deal.II/cmake/configure/configure_1_mpi.cmake b/deal.II/cmake/configure/configure_1_mpi.cmake index 2eb6bd3847..5140848840 100644 --- a/deal.II/cmake/configure/configure_1_mpi.cmake +++ b/deal.II/cmake/configure/configure_1_mpi.cmake @@ -95,7 +95,7 @@ MACRO(FEATURE_MPI_CONFIGURE_EXTERNAL) ADD_FLAGS(CMAKE_CXX_FLAGS "${MPI_CXX_COMPILE_FLAGS}") ADD_FLAGS(DEAL_II_LINKER_FLAGS "${MPI_CXX_LINK_FLAGS}") - LIST(APPEND DEAL_II_EXTERNAL_LIBRARIES ${MPI_CXX_LIBRARIES}) + DEAL_II_APPEND_LIBRARIES(${MPI_CXX_LIBRARIES}) INCLUDE_DIRECTORIES(${MPI_CXX_INCLUDE_PATH}) # The user has to know the location of the mpi headers as well: diff --git a/deal.II/cmake/configure/configure_1_threads.cmake b/deal.II/cmake/configure/configure_1_threads.cmake index d43fd3ea49..e6ddef4076 100644 --- a/deal.II/cmake/configure/configure_1_threads.cmake +++ b/deal.II/cmake/configure/configure_1_threads.cmake @@ -153,7 +153,7 @@ ENDMACRO() MACRO(FEATURE_THREADS_CONFIGURE_EXTERNAL) INCLUDE_DIRECTORIES(${TBB_INCLUDE_DIR}) - SPLIT_DEBUG_RELEASE(_tbb_debug _tbb_release ${TBB_LIBRARIES}) + DEAL_II_APPEND_LIBRARIES(${TBB_LIBRARIES}) IF(CMAKE_BUILD_TYPE MATCHES "Debug") IF(TBB_WITH_DEBUG_LIB) @@ -162,12 +162,8 @@ MACRO(FEATURE_THREADS_CONFIGURE_EXTERNAL) ) ENDIF() - LIST(APPEND DEAL_II_EXTERNAL_LIBRARIES_DEBUG ${_tbb_debug}) ENDIF() - IF(CMAKE_BUILD_TYPE MATCHES "Release") - LIST(APPEND DEAL_II_EXTERNAL_LIBRARIES_RELEASE ${_tbb_release}) - ENDIF() SETUP_THREADING() ENDMACRO() @@ -200,7 +196,7 @@ MACRO(FEATURE_THREADS_CONFIGURE_BUNDLED) FIND_LIBRARY(dl_LIBRARY NAMES dl) MARK_AS_ADVANCED(dl_LIBRARY) IF(NOT dl_LIBRARY MATCHES "-NOTFOUND") - LIST(APPEND DEAL_II_EXTERNAL_LIBRARIES ${dl_LIBRARY}) + DEAL_II_APPEND_LIBRARIES(${dl_LIBRARY}) ENDIF() INCLUDE_DIRECTORIES(${TBB_FOLDER}/include) diff --git a/deal.II/cmake/configure/configure_2_metis.cmake b/deal.II/cmake/configure/configure_2_metis.cmake index 8d83b9661d..1a49a2c7c2 100644 --- a/deal.II/cmake/configure/configure_2_metis.cmake +++ b/deal.II/cmake/configure/configure_2_metis.cmake @@ -38,6 +38,7 @@ MACRO(FEATURE_METIS_FIND_EXTERNAL var) SET(METIS_DIR "" CACHE PATH "An optional hint to a metis directory" ) + MARK_AS_ADVANCED(CLEAR METIS_DIR) ENDIF() ENDIF() ENDMACRO() diff --git a/deal.II/cmake/configure/configure_2_petsc.cmake b/deal.II/cmake/configure/configure_2_petsc.cmake index a78757796a..23465a2eb0 100644 --- a/deal.II/cmake/configure/configure_2_petsc.cmake +++ b/deal.II/cmake/configure/configure_2_petsc.cmake @@ -104,6 +104,7 @@ MACRO(FEATURE_PETSC_FIND_EXTERNAL var) SET(PETSC_ARCH "" CACHE STRING "An optional hint to a PETSc arch" ) + MARK_AS_ADVANCED(CLEAR PETSC_DIR PETSC_ARCH) ENDIF() ENDIF() ENDMACRO() @@ -115,7 +116,7 @@ MACRO(FEATURE_PETSC_CONFIGURE_EXTERNAL) # The user has to know the location of the petsc headers as well: LIST(APPEND DEAL_II_USER_INCLUDE_DIRS ${PETSC_INCLUDE_DIRS}) - LIST(APPEND DEAL_II_EXTERNAL_LIBRARIES ${PETSC_LIBRARIES}) + DEAL_II_APPEND_LIBRARIES(${PETSC_LIBRARIES}) # # Disable a bunch of warnings when compiling with petsc: diff --git a/deal.II/cmake/configure/configure_2_trilinos.cmake b/deal.II/cmake/configure/configure_2_trilinos.cmake index 3669492796..ac15b34051 100644 --- a/deal.II/cmake/configure/configure_2_trilinos.cmake +++ b/deal.II/cmake/configure/configure_2_trilinos.cmake @@ -181,6 +181,15 @@ MACRO(FEATURE_TRILINOS_FIND_EXTERNAL var) ENDIF() ENDIF(TRILINOS_FOUND) + + IF(NOT ${var}) + UNSET(TRILINOS_CONFIG CACHE) + SET(TRILINOS_DIR "" CACHE STRING + "An optional hint to a Trilinos installation" + ) + MARK_AS_ADVANCED(CLEAR TRILINOS_DIR) + ENDIF() + ENDMACRO() @@ -191,7 +200,7 @@ MACRO(FEATURE_TRILINOS_CONFIGURE_EXTERNAL) # The user has to know the location of the trilinos headers as well: LIST(APPEND DEAL_II_USER_INCLUDE_DIRS ${TRILINOS_INCLUDE_DIRS}) - LIST(APPEND DEAL_II_EXTERNAL_LIBRARIES ${TRILINOS_LIBRARIES}) + DEAL_II_APPEND_LIBRARIES(${TRILINOS_LIBRARIES}) SET(DEAL_II_EXPAND_TRILINOS_VECTOR "TrilinosWrappers::Vector") SET(DEAL_II_EXPAND_TRILINOS_BLOCKVECTOR "TrilinosWrappers::BlockVector") diff --git a/deal.II/cmake/configure/configure_boost.cmake b/deal.II/cmake/configure/configure_boost.cmake index f2071971ea..b6ed7c3b2c 100644 --- a/deal.II/cmake/configure/configure_boost.cmake +++ b/deal.II/cmake/configure/configure_boost.cmake @@ -26,7 +26,7 @@ IF(NOT FEATURE_THREADS_PROCESSED) MESSAGE(FATAL_ERROR "\n" "Internal build system error:\n" - "configure_boost.cmake included before configure_tbb.cmake\n\n" + "configure_boost.cmake included before configure_1_threads.cmake\n\n" ) ENDIF() @@ -38,7 +38,11 @@ SET(DEAL_II_WITH_BOOST ON # Always true. We need it :-] MACRO(FEATURE_BOOST_FIND_EXTERNAL var) - SET_IF_EMPTY(BOOST_DIR "$ENV{BOOST_DIR}") + IF(NOT DEFINED BOOST_DIR) + SET(BOOST_DIR "$ENV{BOOST_DIR}") + ELSE() + SET_IF_EMPTY(BOOST_DIR "$ENV{BOOST_DIR}") + ENDIF() IF(NOT "${BOOST_DIR}" STREQUAL "") SET(BOOST_ROOT "${BOOST_DIR}") ENDIF() @@ -104,19 +108,8 @@ MACRO(FEATURE_BOOST_CONFIGURE_EXTERNAL) # LIST(REMOVE_ITEM Boost_LIBRARIES "pthread") - # - # Transform Boost_LIBRARIES into a list of debug and release libraries - # without keywords: - # - SPLIT_DEBUG_RELEASE(_boost_debug _boost_release ${Boost_LIBRARIES}) + DEAL_II_APPEND_LIBRARIES(${Boost_LIBRARIES}) - IF (CMAKE_BUILD_TYPE MATCHES "Debug") - LIST(APPEND DEAL_II_EXTERNAL_LIBRARIES_DEBUG ${_boost_debug}) - ENDIF() - - IF (CMAKE_BUILD_TYPE MATCHES "Release") - LIST(APPEND DEAL_II_EXTERNAL_LIBRARIES_RELEASE ${_boost_release}) - ENDIF() ENDMACRO() diff --git a/deal.II/cmake/configure/configure_hdf5.cmake b/deal.II/cmake/configure/configure_hdf5.cmake index d46c23409b..9816054301 100644 --- a/deal.II/cmake/configure/configure_hdf5.cmake +++ b/deal.II/cmake/configure/configure_hdf5.cmake @@ -37,6 +37,12 @@ MACRO(FEATURE_HDF5_FIND_EXTERNAL var) " HDF5_WITH_MPI = ${HDF5_WITH_MPI}\n" ) ENDIF() + + INCLUDE_DIRECTORIES(${HDF5_INCLUDE_DIRS}) + LIST(APPEND DEAL_II_USER_INCLUDE_DIRS ${HDF5_INCLUDE_DIRS}) + DEAL_II_APPEND_LIBRARIES(${HDF5_LIBRARIES}) + + ENDIF() ENDMACRO() diff --git a/deal.II/cmake/configure/configure_mumps.cmake b/deal.II/cmake/configure/configure_mumps.cmake index f4a9a27446..0739098602 100644 --- a/deal.II/cmake/configure/configure_mumps.cmake +++ b/deal.II/cmake/configure/configure_mumps.cmake @@ -26,7 +26,7 @@ MACRO(FEATURE_MUMPS_CONFIGURE_EXTERNAL) # The user has to know the location of the MUMPS headers as well: LIST(APPEND DEAL_II_USER_INCLUDE_DIRS ${MUMPS_INCLUDE_DIRS}) - LIST(APPEND DEAL_II_EXTERNAL_LIBRARIES ${MUMPS_LIBRARIES}) + DEAL_II_APPEND_LIBRARIES(${MUMPS_LIBRARIES}) ENDMACRO() CONFIGURE_FEATURE(MUMPS) diff --git a/deal.II/cmake/configure/configure_p4est.cmake b/deal.II/cmake/configure/configure_p4est.cmake index 3773a88b12..9780127bc6 100644 --- a/deal.II/cmake/configure/configure_p4est.cmake +++ b/deal.II/cmake/configure/configure_p4est.cmake @@ -36,13 +36,16 @@ MACRO(FEATURE_P4EST_FIND_EXTERNAL var) "p4est has to be configured with MPI enabled.\n" ) - UNSET(P4EST_LIBRARY CACHE) + UNSET(P4EST_LIBRARY_OPTIMIZED CACHE) + UNSET(P4EST_LIBRARY_DEBUG CACHE) UNSET(P4EST_INCLUDE_DIR CACHE) - UNSET(SC_LIBRARY CACHE) + UNSET(SC_LIBRARY_OPTIMIZED CACHE) + UNSET(SC_LIBRARY_DEBUG CACHE) UNSET(SC_INCLUDE_DIR CACHE) SET(P4EST_DIR "" CACHE PATH "An optional hint to a p4est installation/directory" ) + MARK_AS_ADVANCED(CLEAR P4EST_DIR) ELSE() SET(${var} TRUE) ENDIF() @@ -55,7 +58,7 @@ MACRO(FEATURE_P4EST_CONFIGURE_EXTERNAL) # The user has to know the location of the P4EST headers as well: LIST(APPEND DEAL_II_USER_INCLUDE_DIRS ${P4EST_INCLUDE_DIRS}) - LIST(APPEND DEAL_II_EXTERNAL_LIBRARIES ${P4EST_LIBRARIES}) + DEAL_II_APPEND_LIBRARIES(${P4EST_LIBRARIES}) ENDMACRO() CONFIGURE_FEATURE(P4EST) diff --git a/deal.II/cmake/configure/configure_slepc.cmake b/deal.II/cmake/configure/configure_slepc.cmake index c0d1b212b0..bf5415a0ff 100644 --- a/deal.II/cmake/configure/configure_slepc.cmake +++ b/deal.II/cmake/configure/configure_slepc.cmake @@ -50,6 +50,7 @@ MACRO(FEATURE_SLEPC_FIND_EXTERNAL var) SET(SLEPC_DIR "" CACHE PATH "An optional hint to a SLEPc directory" ) + MARK_AS_ADVANCED(CLEAR SLEPC_DIR) SET(${var} FALSE) ENDIF() @@ -62,7 +63,7 @@ MACRO(FEATURE_SLEPC_CONFIGURE_EXTERNAL) # The user has to know the location of the SLEPC headers as well: LIST(APPEND DEAL_II_USER_INCLUDE_DIRS ${SLEPC_INCLUDE_DIRS}) - LIST(APPEND DEAL_II_EXTERNAL_LIBRARIES ${SLEPC_LIBRARIES}) + DEAL_II_APPEND_LIBRARIES(${SLEPC_LIBRARIES}) ENDMACRO() diff --git a/deal.II/cmake/macros/macro_configure_feature.cmake b/deal.II/cmake/macros/macro_configure_feature.cmake index 0ae79de3c0..0ffbf4fb10 100644 --- a/deal.II/cmake/macros/macro_configure_feature.cmake +++ b/deal.II/cmake/macros/macro_configure_feature.cmake @@ -142,7 +142,7 @@ MACRO(FEATURE_CONFIGURE_EXTERNAL _feature) INCLUDE_DIRECTORIES(${${_feature}_INCLUDE_DIRS}) ENDIF() IF(DEFINED ${_feature}_LIBRARIES) - LIST(APPEND DEAL_II_EXTERNAL_LIBRARIES ${${_feature}_LIBRARIES}) + DEAL_II_APPEND_LIBRARIES(${${_feature}_LIBRARIES}) ENDIF() IF(DEFINED ${_feature}_LINKER_FLAGS) ADD_FLAGS(DEAL_II_LINKER_FLAGS "${${_feature}_LINKER_FLAGS}") diff --git a/deal.II/cmake/macros/macro_split_debug_release.cmake b/deal.II/cmake/macros/macro_deal_ii_append_libraries.cmake similarity index 51% rename from deal.II/cmake/macros/macro_split_debug_release.cmake rename to deal.II/cmake/macros/macro_deal_ii_append_libraries.cmake index dd05b98c9c..de291d39b6 100644 --- a/deal.II/cmake/macros/macro_split_debug_release.cmake +++ b/deal.II/cmake/macros/macro_deal_ii_append_libraries.cmake @@ -14,42 +14,34 @@ ## ## --------------------------------------------------------------------- - # -# A small macro to split a list of libraries with debug, optimized and -# general keywords into two lists consisting of all libraries necessary for -# the debug and release target only. If no keyword is given "optimized" is -# assumed. +# A small macro to add libraries to +# DEAL_II_EXTERNAL_LIBRARIES +# DEAL_II_EXTERNAL_LIBRARIES_DEBUG +# DEAL_II_EXTERNAL_LIBRARIES_RELEASE +# depending on the "optmized", "debug" or "general" keyword # # Usage: -# SPLIT_DEBUG_RELEASE(list_debug list_release <...list of libraries...>) -# +# DEAL_II_APPEND_LIBRARIES(<list of libraries>) # -MACRO(SPLIT_DEBUG_RELEASE _list_debug _list_release) +MACRO(DEAL_II_APPEND_LIBRARIES) - SET(_toggle "optimized") + SET(_toggle "general") FOREACH(_tmp ${ARGN}) - IF("${_tmp}" STREQUAL "debug" OR - "${_tmp}" STREQUAL "optimized" OR - "${_tmp}" STREQUAL "general") + IF( "${_tmp}" STREQUAL "debug" OR + "${_tmp}" STREQUAL "optimized" OR + "${_tmp}" STREQUAL "general" ) SET(_toggle "${_tmp}") ELSE() IF("${_toggle}" STREQUAL "general") - LIST(APPEND ${_list_debug} "${_tmp}") - LIST(APPEND ${_list_release} "${_tmp}") + LIST(APPEND DEAL_II_EXTERNAL_LIBRARIES ${_tmp}) ELSEIF("${_toggle}" STREQUAL "debug") - LIST(APPEND ${_list_debug} "${_tmp}") + LIST(APPEND DEAL_II_EXTERNAL_LIBRARIES_DEBUG ${_tmp}) ELSEIF("${_toggle}" STREQUAL "optimized") - LIST(APPEND ${_list_release} "${_tmp}") + LIST(APPEND DEAL_II_EXTERNAL_LIBRARIES_RELEASE ${_tmp}) ENDIF() ENDIF() ENDFOREACH() - IF("${${_list_debug}}" STREQUAL "") - SET(${_list_debug} ${${_list_release}}) - ELSEIF("${${_list_release}}" STREQUAL "") - SET(${_list_release} ${${_list_debug}}) - ENDIF() - ENDMACRO() diff --git a/deal.II/cmake/modules/FindMETIS.cmake b/deal.II/cmake/modules/FindMETIS.cmake index 80cbd97d47..29c9be531f 100644 --- a/deal.II/cmake/modules/FindMETIS.cmake +++ b/deal.II/cmake/modules/FindMETIS.cmake @@ -24,6 +24,7 @@ # METIS_VERSION # METIS_VERSION_MAJOR # METIS_VERSION_MINOR +# METIS_VERSION_SUBMINOR # INCLUDE(FindPackageHandleStandardArgs) diff --git a/deal.II/cmake/modules/FindP4EST.cmake b/deal.II/cmake/modules/FindP4EST.cmake index 173da3893a..32a6f08497 100644 --- a/deal.II/cmake/modules/FindP4EST.cmake +++ b/deal.II/cmake/modules/FindP4EST.cmake @@ -33,23 +33,6 @@ INCLUDE(FindPackageHandleStandardArgs) SET_IF_EMPTY(P4EST_DIR "$ENV{P4EST_DIR}") SET_IF_EMPTY(SC_DIR "$ENV{SC_DIR}") -# -# We used to recommend installing p4est with a custom script that -# compiled p4est twice, once in debug and once in optimized mode. -# the installation would then have happened into directories -# $P4EST_DIR/DEBUG and $P4EST_DIR/FAST. If we can find these -# two directories, then use the FAST directory rather than trying -# to figure out how we can build deal.II against the two libraries -# depending on whether we are in debug or optimized mode. -# -IF(P4EST_DIR - AND EXISTS ${P4EST_DIR}/DEBUG - AND EXISTS ${P4EST_DIR}/FAST) - MESSAGE(STATUS "Found old-style p4est directory layout") - SET (P4EST_DIR ${P4EST_DIR}/FAST) -ENDIF() - - # # Search for the sc library, usually bundled with p4est. If no SC_DIR was # given, take what we chose for p4est. @@ -57,6 +40,8 @@ ENDIF() FIND_PATH(P4EST_INCLUDE_DIR p4est_config.h HINTS + ${P4EST_DIR}/FAST + ${P4EST_DIR}/DEBUG ${P4EST_DIR} PATH_SUFFIXES p4est include/p4est include src @@ -64,49 +49,99 @@ FIND_PATH(P4EST_INCLUDE_DIR p4est_config.h FIND_PATH(SC_INCLUDE_DIR sc.h HINTS + ${SC_DIR}/FAST + ${SC_DIR}/DEBUG ${SC_DIR} + ${P4EST_DIR}/FAST + ${P4EST_DIR}/DEBUG ${P4EST_DIR} PATH_SUFFIXES sc include/p4est include src sc/src ) -FIND_LIBRARY(P4EST_LIBRARY +FIND_LIBRARY(P4EST_LIBRARY_OPTIMIZED NAMES p4est HINTS + ${P4EST_DIR}/FAST + ${P4EST_DIR}/DEBUG ${P4EST_DIR} PATH_SUFFIXES lib${LIB_SUFFIX} lib64 lib src ) -FIND_LIBRARY(SC_LIBRARY +FIND_LIBRARY(P4EST_LIBRARY_DEBUG + NAMES p4est + HINTS + ${P4EST_DIR}/DEBUG + PATH_SUFFIXES + lib${LIB_SUFFIX} lib64 lib src + ) + +FIND_LIBRARY(SC_LIBRARY_OPTIMIZED NAMES sc HINTS + ${SC_DIR}/FAST + ${SC_DIR}/DEBUG ${SC_DIR} + ${P4EST_DIR}/FAST + ${P4EST_DIR}/DEBUG ${P4EST_DIR} PATH_SUFFIXES lib${LIB_SUFFIX} lib64 lib src sc/src ) -SET(_output ${P4EST_LIBRARY} ${SC_LIBRARY}) +FIND_LIBRARY(SC_LIBRARY_DEBUG + NAMES sc + HINTS + ${SC_DIR}/DEBUG + ${P4EST_DIR}/DEBUG + PATH_SUFFIXES + lib${LIB_SUFFIX} lib64 lib src sc/src + ) + +SET(_output ${P4EST_LIBRARY_OPTMIZED} ${SC_LIBRARY_OPTIMIZED}) FIND_PACKAGE_HANDLE_STANDARD_ARGS(P4EST DEFAULT_MSG _output # Cosmetic: Gives nice output - P4EST_LIBRARY - SC_LIBRARY + P4EST_LIBRARY_OPTIMIZED + SC_LIBRARY_OPTIMIZED P4EST_INCLUDE_DIR SC_INCLUDE_DIR ) MARK_AS_ADVANCED( - P4EST_LIBRARY + P4EST_LIBRARY_OPTIMIZED + P4EST_LIBRARY_DEBUG P4EST_INCLUDE_DIR - SC_LIBRARY + SC_LIBRARY_OPTIMIZED + SC_LIBRARY_DEBUG SC_INCLUDE_DIR ) + IF(P4EST_FOUND) - SET(P4EST_LIBRARIES - ${P4EST_LIBRARY} - ${SC_LIBRARY} + + IF( ( "${P4EST_LIBRARY_OPTIMIZED}" STREQUAL "${P4EST_LIBRARY_DEBUG}" + AND + "${SC_LIBRARY_OPTIMIZED}" STREQUAL "${SC_LIBRARY_DEBUG}" ) + OR P4EST_LIBRARY_DEBUG MATCHES "-NOTFOUND" + OR SC_LIBRARY_DEBUG MATCHES "-NOTFOUND" ) + SET(P4EST_LIBRARIES + ${P4EST_LIBRARY_OPTIMIZED} + ${SC_LIBRARY_OPTIMIZED} + ) + ELSE() + SET(P4EST_LIBRARIES + optimized + ${P4EST_LIBRARY_OPTIMIZED} + ${SC_LIBRARY_OPTIMIZED} + debug + ${P4EST_LIBRARY_DEBUG} + ${SC_LIBRARY_DEBUG} + general + ) + ENDIF() + + LIST(APPEND P4EST_LIBRARIES ${LAPACK_LIBRARIES} # for good measure ${MPI_C_LIBRARIES} # for good measure ) @@ -123,6 +158,7 @@ IF(P4EST_FOUND) IF("${P4EST_MPI_STRING}" STREQUAL "") SET(P4EST_WITH_MPI FALSE) ELSE() + SET(P4EST_WITH_MPI TRUE) ENDIF() diff --git a/deal.II/cmake/modules/FindTRILINOS.cmake b/deal.II/cmake/modules/FindTRILINOS.cmake index b347b32ccf..2ff349ebac 100644 --- a/deal.II/cmake/modules/FindTRILINOS.cmake +++ b/deal.II/cmake/modules/FindTRILINOS.cmake @@ -141,6 +141,8 @@ FOREACH(_library ${Trilinos_LIBRARIES}) NO_CMAKE_FIND_ROOT_PATH ) + MARK_AS_ADVANCED(TRILINOS_LIBRARY_${_library}) + IF(TRILINOS_LIBRARY_${_library} MATCHES "-NOTFOUND") SET(TRILINOS_CONFIG_FOUND FALSE) ELSE() diff --git a/deal.II/doc/development/Config.sample b/deal.II/doc/development/Config.sample index aeb340ced3..df14dc07d3 100644 --- a/deal.II/doc/development/Config.sample +++ b/deal.II/doc/development/Config.sample @@ -283,6 +283,10 @@ # SET(METIS_FOUND TRUE CACHE BOOL "") # SET(METIS_LIBRARIES "library;and;semicolon;separated;list;of;link;interface" CACHE STRING "") # SET(METIS_INCLUDE_DIRS "semicolon;separated;list;of;include;dirs" CACHE STRING "") +# SET(METIS_VERSION "x.y.z" CACHE STRING "") +# SET(METIS_VERSION_MAJOR "x" CACHE STRING "") +# SET(METIS_VERSION_MINOR "y" CACHE STRING "") +# SET(METIS_VERSION_SUBMINOR "z" CACHE STRING "") # @@ -400,6 +404,11 @@ # SET(P4EST_LIBRARIES "library;and;semicolon;separated;list;of;link;interface" CACHE STRING "") # SET(P4EST_INCLUDE_DIRS "semicolon;separated;list;of;include;dirs" CACHE STRING "") # SET(P4EST_WITH_MPI TRUE CACHE BOOL "") +# SET(P4EST_VERSION "x.y.z.p" CACHE STRING "") +# SET(P4EST_VERSION_MAJOR "x" CACHE STRING "") +# SET(P4EST_VERSION_MINOR "y" CACHE STRING "") +# SET(P4EST_VERSION_SUBMINOR "z" CACHE STRING "") +# SET(P4EST_VERSION_PATCH "p" CACHE STRING "") # @@ -425,6 +434,7 @@ # SET(PETSC_VERSION_MAJOR "x" CACHE STRING "") # SET(PETSC_VERSION_MINOR "y" CACHE STRING "") # SET(PETSC_VERSION_SUBMINOR "z" CACHE STRING "") +# SET(PETSC_VERSION_PATCH "" CACHE STRING "") # SET(PETSC_WITH_MPI_UNI FALSE CACHE BOOL "") # @@ -450,6 +460,7 @@ # SET(SLEPC_VERSION_MAJOR "x" CACHE STRING "") # SET(SLEPC_VERSION_MINOR "y" CACHE STRING "") # SET(SLEPC_VERSION_SUBMINOR "z" CACHE STRING "") +# SET(SLEPC_VERSION_PATCH "" CACHE STRING "") # SET(SLEPC_WITH_MPI_UNI FALSE CACHE BOOL "") # diff --git a/deal.II/doc/documentation.html b/deal.II/doc/documentation.html index cc3d35bffb..941beef63e 100644 --- a/deal.II/doc/documentation.html +++ b/deal.II/doc/documentation.html @@ -5,15 +5,35 @@ <link href="screen.css" rel="StyleSheet" type="text/css"> <title>The deal.II Online Documentation</title> <meta name="author" content="the deal.II authors <authors@dealii.org>"> - <meta name="copyright" content="Copyright (C) 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010, 2011, 2012 by the deal.II authors"> + <meta name="copyright" content="Copyright (C) 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010, 2011, 2012, 2013 by the deal.II authors"> <meta name="date" content="2006/02/07 22:49:01"> <meta name="keywords" content="deal.II"> <meta name="svn_id" content="$Id$"> </head> <body> + + + <h2>Online documentation</h2> + <table class="tutorial" width="40%"> + <tr><th colspan="2"><b><small>Table of contents</small></b></th></tr> + <tr><td valign="top"> + <ul> + <li> <a href="#readme.html">ReadMe</a></li> + <li> <a href="#tutorials">Tutorials</a></li> + <li> <a href="#API">Programming interface</a></li> + <li> <a href="#dev">Development information</a></li> + <li> <a href="#reports">Reports</a></li> + <li> <a href="#publications">Publications</a></li> + <li> <a href="#license">Copyright and licence</a></li> + </ul> + </td> + </tr> + </table> + + <p> <acronym>deal.II</acronym> comes with quite extensive online documentation, which falls into several categories. They are @@ -21,7 +41,7 @@ </p> - <h3><a href="readme.html">README</a></h3> + <h3><a href="readme.html">ReadMe</a></h3> <p> First, there is the <a href="readme.html" target="body">README file</a> of @@ -29,7 +49,7 @@ installation, and copyright. </p> - <h3>Tutorials</h3> + <h3><a href="tutorials">Tutorials</a></h3> <p> The <a href="doxygen/tutorial/index.html" @@ -49,7 +69,7 @@ </p> - <h3>Programming interface</h3> + <h3><a href="API">Programming interface</a></h3> <p> The <a href="doxygen/deal.II/index.html" target="_top">programming @@ -81,7 +101,7 @@ </p> - <h3>Development information</h3> + <h3><a name="dev">Development information</a></h3> <p> If you plan to <a href="development/index.html" @@ -92,7 +112,7 @@ </p> - <h3>Reports</h3> + <h3><a name="reports">Reports</a></h3> <p> There are a number of papers that describe the overall design or @@ -183,7 +203,7 @@ </ul> - <h3>Publications</h3> + <h3><a name="publications">Publications</a></h3> <p> A <a href="publications/index.html" target="body">list of @@ -193,7 +213,7 @@ </p> - <h3>Copyright and License</h3> + <h3><a name="license">Copyright and License</a></h3> <p> <acronym>deal.II</acronym> is copyright of the <a href="authors.html" target="body">deal.II authors</a>. diff --git a/deal.II/doc/news/changes.h b/deal.II/doc/news/changes.h index 93d16b5ed8..e4ff71cee2 100644 --- a/deal.II/doc/news/changes.h +++ b/deal.II/doc/news/changes.h @@ -31,6 +31,18 @@ inconvenience this causes. <br> (Wolfgang Bangerth, 2013/08/09) </li> + + <li> + Changed: The typedefs DataOut::cell_iterator and + DataOut::active_cell_iterator were previously defined as + DoFHandler::(active)_cell_iterator, while they are now + Triangulation::(active)_cell_iterator. This is necessary to support DataOut + on multiple DoFHandler objects. This affects possible overloading of + DataOut::next_cell(cell_iterator). Use the typedef + DataOut::(active)_cell_iterator as argument type instead. + <br> + (Martin Kronbichler, 2013/07/24) + </li> </ol> @@ -56,6 +68,77 @@ inconvenience this causes. <h3>Specific improvements</h3> <ol> + <li> + Fixed: The ParameterHandler class can now deal with including one parameter + file from another. + <br> + (Wolfgang Bangerth, 2013/08/25) + </li> + + <li> + New: The method VectorTools::compute_normal_flux_constraints can be used to + force a vector finite element function to be normal to the boundary. + <br> + (Martin Kronbichler, 2013/08/23) + </li> + + <li> + Improved: MappingQ now uses the points of the Gauss-Lobatto quadrature + formula as support points instead of equispaced ones. This allows its use + for high polynomial orders and also gives better interpolation of circular + boundaries. Beware that mappings of order three and higher will behave + slightly differently now (usually better). + <br> + (Martin Kronbichler, 2013/08/23) + </li> + + <li> + Improved: Several .cc files in the deal.II directory have been split in + order to better utilize multiple processors when compiling in parallel and + reduce memory requirements of the compilation stage. + <br> + (Martin Kronbichler, 2013/08/22) + </li> + + <li> + Fixed: The ParameterHandler::declare_entry() did not check that the + default value of a parameter indeed satisfies the pattern given for this + parameter (despite a statement in the documentation that this checking + would happen). This is now fixed. + <br> + (Wolfgang Bangerth, 2013/08/21) + </li> + + <li> + New: Patterns::List and Patterns::Map now accept a string + different than the default comma that denotes the separator + between entries of the list or map. + <br> + (Wolfgang Bangerth, 2013/08/21) + </li> + + <li> + Fixed: Some operations in the MappingQ class are now done in higher + precision arithmetic to mitigate the ill-conditioning that appears + when using mappings of high order (say, order 6 or 8 or 10). + <br> + (Juan Carlos Araujo Cabarcas, 2013/08/20) + </li> + + <li> + Fixed: The SLEPcWrappers classes could not be compiled for 64-bit + indices. This is now fixed. + <br> + (Denis Davydov, Wolfgang Bangerth, 2013/08/20) + </li> + + <li> + Fixed: SolutionTransfer used to crash whenever one transfered in the hp + context between cells that use FE_Nothing and FE_Q. This is now fixed. + <br> + (Krzyszof Bzowski, Wolfgang Bangerth, 2013/08/18) + </li> + <li> Fixed: Under some circumstances (see http://code.google.com/p/dealii/issues/detail?id=82) the DoFTools::make_periodicity_constraints() function could create cycles in diff --git a/deal.II/examples/step-10/doc/results.dox b/deal.II/examples/step-10/doc/results.dox index 2e25ba40fa..dcc5dac011 100644 --- a/deal.II/examples/step-10/doc/results.dox +++ b/deal.II/examples/step-10/doc/results.dox @@ -9,7 +9,7 @@ the commands @code set style data lines set size 0.721, 1 -set nokey +unset key plot [-1:1][-1:1] "ball0_mapping_q1.dat" @endcode or using one of the other filenames. The second line makes sure that @@ -90,104 +90,101 @@ good accuracy. This is the output of this part of the program: Computation of Pi by the area: ============================== Degree = 1 -cells eval.pi error -5 1.9999999999999998 1.1416e+00 - -20 2.8284271247461898 3.1317e-01 1.87 -80 3.0614674589207178 8.0125e-02 1.97 -320 3.1214451522580520 2.0148e-02 1.99 -1280 3.1365484905459389 5.0442e-03 2.00 -5120 3.1403311569547521 1.2615e-03 2.00 +cells eval.pi error + 5 1.9999999999999993 1.1416e+00 - + 20 2.8284271247461894 3.1317e-01 1.87 + 80 3.0614674589207178 8.0125e-02 1.97 + 320 3.1214451522580520 2.0148e-02 1.99 + 1280 3.1365484905459393 5.0442e-03 2.00 + 5120 3.1403311569547534 1.2615e-03 2.00 Degree = 2 -cells eval.pi error -5 3.1045694996615869 3.7023e-02 - -20 3.1391475703122276 2.4451e-03 3.92 -80 3.1414377167038303 1.5494e-04 3.98 -320 3.1415829366419019 9.7169e-06 4.00 -1280 3.1415920457576907 6.0783e-07 4.00 -5120 3.1415926155921126 3.7998e-08 4.00 +cells eval.pi error + 5 3.1045694996615865 3.7023e-02 - + 20 3.1391475703122271 2.4451e-03 3.92 + 80 3.1414377167038303 1.5494e-04 3.98 + 320 3.1415829366419015 9.7169e-06 4.00 + 1280 3.1415920457576911 6.0783e-07 4.00 + 5120 3.1415926155921139 3.7998e-08 4.00 Degree = 3 -cells eval.pi error -5 3.1465390309173475 4.9464e-03 - -20 3.1419461263297386 3.5347e-04 3.81 -80 3.1416154689089382 2.2815e-05 3.95 -320 3.1415940909713274 1.4374e-06 3.99 -1280 3.1415927436051230 9.0015e-08 4.00 -5120 3.1415926592185492 5.6288e-09 4.00 +cells eval.pi error + 5 3.1410033851499310 5.8927e-04 - + 20 3.1415830393583861 9.6142e-06 5.94 + 80 3.1415925017363837 1.5185e-07 5.98 + 320 3.1415926512106722 2.3791e-09 6.00 + 1280 3.1415926535525962 3.7197e-11 6.00 + 5120 3.1415926535892140 5.7923e-13 6.00 Degree = 4 -cells eval.pi error -5 3.1418185737113964 2.2592e-04 - -20 3.1415963919525050 3.7384e-06 5.92 -80 3.1415927128397780 5.9250e-08 5.98 -320 3.1415926545188264 9.2903e-10 5.99 -1280 3.1415926536042722 1.4479e-11 6.00 -5120 3.1415926535899668 1.7343e-13 6.38 - +cells eval.pi error + 5 3.1415871927401127 5.4608e-06 - + 20 3.1415926314742437 2.2116e-08 7.95 + 80 3.1415926535026228 8.7170e-11 7.99 + 320 3.1415926535894529 3.4036e-13 8.00 + 1280 3.1415926535897927 2.9187e-16 10.19 + 5120 3.1415926535897944 1.3509e-15 -2.21 Computation of Pi by the perimeter: =================================== Degree = 1 -cells eval.pi error -5 2.8284271247461903 3.1317e-01 - -20 3.0614674589207183 8.0125e-02 1.97 -80 3.1214451522580524 2.0148e-02 1.99 -320 3.1365484905459393 5.0442e-03 2.00 -1280 3.1403311569547525 1.2615e-03 2.00 -5120 3.1412772509327729 3.1540e-04 2.00 +cells eval.pi error + 5 2.8284271247461898 3.1317e-01 - + 20 3.0614674589207178 8.0125e-02 1.97 + 80 3.1214451522580520 2.0148e-02 1.99 + 320 3.1365484905459393 5.0442e-03 2.00 + 1280 3.1403311569547525 1.2615e-03 2.00 + 5120 3.1412772509327729 3.1540e-04 2.00 Degree = 2 -cells eval.pi error -5 3.1248930668550599 1.6700e-02 - -20 3.1404050605605454 1.1876e-03 3.81 -80 3.1415157631807014 7.6890e-05 3.95 -320 3.1415878042798613 4.8493e-06 3.99 -1280 3.1415923498174538 3.0377e-07 4.00 -5120 3.1415926345932004 1.8997e-08 4.00 +cells eval.pi error + 5 3.1248930668550594 1.6700e-02 - + 20 3.1404050605605449 1.1876e-03 3.81 + 80 3.1415157631807014 7.6890e-05 3.95 + 320 3.1415878042798617 4.8493e-06 3.99 + 1280 3.1415923498174534 3.0377e-07 4.00 + 5120 3.1415926345932004 1.8997e-08 4.00 Degree = 3 -cells eval.pi error -5 3.1442603311164286 2.6677e-03 - -20 3.1417729561193588 1.8030e-04 3.89 -80 3.1416041192612365 1.1466e-05 3.98 -320 3.1415933731961760 7.1961e-07 3.99 -1280 3.1415926986118001 4.5022e-08 4.00 -5120 3.1415926564043946 2.8146e-09 4.00 +cells eval.pi error + 5 3.1414940401456057 9.8613e-05 - + 20 3.1415913432549156 1.3103e-06 6.23 + 80 3.1415926341726914 1.9417e-08 6.08 + 320 3.1415926532906893 2.9910e-10 6.02 + 1280 3.1415926535851360 4.6571e-12 6.01 + 5120 3.1415926535897203 7.2845e-14 6.00 Degree = 4 -cells eval.pi error -5 3.1417078926581086 1.1524e-04 - -20 3.1415945317216001 1.8781e-06 5.94 -80 3.1415926832497720 2.9660e-08 5.98 -320 3.1415926540544636 4.6467e-10 6.00 -1280 3.1415926535970535 7.2602e-12 6.00 -5120 3.1415926535899010 1.0805e-13 6.07 +cells eval.pi error + 5 3.1415921029432576 5.5065e-07 - + 20 3.1415926513737600 2.2160e-09 7.96 + 80 3.1415926535810712 8.7218e-12 7.99 + 320 3.1415926535897594 3.3668e-14 8.02 + 1280 3.1415926535897922 1.0617e-15 4.99 + 5120 3.1415926535897931 1.0061e-16 3.40 @endcode -One of the immediate observations from the output is that in all cases -the values converge quickly to the true value of -$\pi=3.141592653589793238462643$. Note that for the $Q_4$ mapping, the last -number is correct to 13 digits in both computations, which is already -quite a lot. However, also note that for the $Q_1$ mapping, even on the -finest grid the accuracy is significantly worse than on the coarse -grid for a $Q_4$ mapping! +One of the immediate observations from the output is that in all cases the +values converge quickly to the true value of +$\pi=3.141592653589793238462643$. Note that for the $Q_4$ mapping, we are +already in the regime of roundoff errors and the convergence rate levels off, +which is already quite a lot. However, also note that for the $Q_1$ mapping, +even on the finest grid the accuracy is significantly worse than on the coarse +grid for a $Q_3$ mapping! -The last column of the output shows the convergence order, in powers -of the mesh width $h$. In the introduction, we had stated that -the convergence order for a $Q_p$ mapping should be -$h^{p+1}$. However, in the example shown, the $Q_2$ and $Q_4$ -mappings show a convergence order of $h^{p+2}$! This at -first surprising fact is readily explained by the particular boundary -we have chosen in this example. In fact, the circle is described by the function -$\sqrt{1-x^2}$, which has the series expansion -$1-x^2/2-x^4/8-x^6/16+\ldots$ -around $x=0$. Thus, for the quadratic mapping where the -truncation error of the quadratic approximation should be cubic, there -is no such term but only a quartic one, which raises the convergence -order to 4, instead of 3. The same happens for the $Q_4$ mapping. +The last column of the output shows the convergence order, in powers of the +mesh width $h$. In the introduction, we had stated that the convergence order +for a $Q_p$ mapping should be $h^{p+1}$. However, in the example shown, the +order is rather $h^{2p}$! This at first surprising fact is explained by the +properties of the $Q_p$ mapping. At order <i>p</i>, it uses support points +that are based on the <i>p</i>+1 point Gauss-Lobatto quadrature rule that +selects the support points in such a way that the quadrature rule converges at +order 2<i>p</i>. Even though these points are here only used for interpolation +of a <i>p</i>th order polynomial, we get a superconvergence effect when +numerically evaluating the integral that actually gives this high order of +convergence. diff --git a/deal.II/examples/step-14/step-14.cc b/deal.II/examples/step-14/step-14.cc index f91bbfc666..d2d982b129 100644 --- a/deal.II/examples/step-14/step-14.cc +++ b/deal.II/examples/step-14/step-14.cc @@ -1692,7 +1692,7 @@ namespace Step14 // Finally, we have by now only integrated the gradients of the shape // functions, not taking their mean value. We fix this by dividing by // the measure of the volume over which we have integrated: - rhs.scale (1./total_volume); + rhs /= total_volume; } diff --git a/deal.II/examples/step-42/step-42.cc b/deal.II/examples/step-42/step-42.cc index 81a5202a62..37c7826788 100644 --- a/deal.II/examples/step-42/step-42.cc +++ b/deal.II/examples/step-42/step-42.cc @@ -217,7 +217,7 @@ double Input<dim>::obstacle_function(double x, double y) { } // As mentioned above this function reads in the -// obstacle datas and stores them in the std::vector +// obstacle data and stores them in the std::vector // obstacle_data. It will be used only in run (). template<int dim> void Input<dim>::read_obstacle(const char* name) { @@ -244,11 +244,11 @@ void Input<dim>::read_obstacle(const char* name) { // This class provides an interface // for a constitutive law. In this -// example we are using an elasto -// plastic material behavior with linear, +// example we are using an elastoplastic +// material behavior with linear, // isotropic hardening. -// For gamma = 0 we obtain perfect elasto -// plasticity behavior. +// For gamma = 0 we obtain perfect elastoplastic +// behavior. template<int dim> class ConstitutiveLaw { public: @@ -312,7 +312,8 @@ ConstitutiveLaw<dim>::ConstitutiveLaw(double _E, double _nu, double _sigma_0, // @sect3{ConstitutiveLaw::ConstitutiveLaw} -// Calculates the strain for the shape functions. +// Calculates the strain $\varepsilon(\varphi)=\dfrac{1}{2}\left(\nabla\varphi + \nabla\varphi^T$ +// for the shape functions $\varphi$. template<int dim> inline SymmetricTensor<2, dim> ConstitutiveLaw<dim>::get_strain( const FEValues<dim> &fe_values, const unsigned int shape_func, @@ -331,7 +332,9 @@ inline SymmetricTensor<2, dim> ConstitutiveLaw<dim>::get_strain( // deviator part of the stresses in a quadrature point back to // the yield stress plus the linear isotropic hardening. // Also we sum up the elastic and the plastic quadrature -// points. +// points. We need this function to calculate the nonlinear +// residual in +// PlasticityContactProblem::residual_nl_system(TrilinosWrappers::MPI::Vector &u). template<int dim> void ConstitutiveLaw<dim>::plast_linear_hardening( SymmetricTensor<4, dim> &stress_strain_tensor, @@ -364,8 +367,16 @@ void ConstitutiveLaw<dim>::plast_linear_hardening( // @sect3{ConstitutiveLaw::linearized_plast_linear_hardening} -// This function returns the linearized stress strain tensor. -// It contains the derivative of the nonlinear constitutive law. +// This function returns the linearized stress strain tensor +// in the solution $u^{i-1}$ of the previous Newton $i-1$ step. +// The parameter strain_tensor $\varepsilon(u^{i-1})$ is calculated +// by $u^{i-1}$. It contains the derivative of the nonlinear +// constitutive law. As the result this function returns +// the stress_strain_tensor of the nonlinear problem as well as +// the stress_strain_tensor_linearized of the linearized problem. +// See +// PlasticityContactProblem::assemble_nl_system(TrilinosWrappers::MPI::Vector &u) +// where this function is used. template<int dim> void ConstitutiveLaw<dim>::linearized_plast_linear_hardening( SymmetricTensor<4, dim> &stress_strain_tensor_linearized, @@ -426,7 +437,7 @@ double RightHandSide<dim>::value(const Point<dim> &p, if (component == 1) return_value = 0.0; if (component == 2) - return_value = 0.0;//-26923.07692; + return_value = 0.0; return return_value; } @@ -592,7 +603,7 @@ private: void output_results(const std::string &title); void - output_for_benchmark(const unsigned int cycle); + output_contact_force(const unsigned int cycle); double to_refine_factor; double to_coarsen_factor; @@ -606,6 +617,9 @@ private: FESystem<dim> fe; DoFHandler<dim> dof_handler; + // We are using the SolutionTransfer class to interpolate the + // solution on the new refined mesh. It appears in th refine_grid() + // and the run() function. std_cxx1x::shared_ptr< parallel::distributed::SolutionTransfer<dim, TrilinosWrappers::MPI::Vector> > soltrans; @@ -1755,10 +1769,24 @@ void PlasticityContactProblem<dim>::output_results( move_mesh(tmp); } -// @sect4{PlasticityContactProblem::output_for_benchmark} - +// @sect4{PlasticityContactProblem::output_contact_force} + +// This function provides the contact force by calculating +// an integral over the contact pressure in z-directions +// over the contact area. For this purpose we set the contact +// pressure lambda to 0 for all inactive dofs. For all +// active dofs we lambda contains the quotient of the nonlinear +// residual (resid_vector) and corresponding diagonal entry +// of the mass matrix (diag_mass_matrix_vector). Because it is +// not unlikely that hanging nodes shows up in the contact area +// it is important to apply contraints_hanging_nodes.distribute +// to the distributed_lambda vector. +// To calculate the contact pressure in a certain point in the +// contact area, we have make use of the Functions::FEFieldFunction +// In parallel this is little tricky because we have to find the +// process with the right cell which contains this point. template<int dim> -void PlasticityContactProblem<dim>::output_for_benchmark( +void PlasticityContactProblem<dim>::output_contact_force( const unsigned int cycle) { Functions::FEFieldFunction<dim, DoFHandler<dim>, TrilinosWrappers::MPI::Vector> solution_function(dof_handler, @@ -1819,7 +1847,7 @@ void PlasticityContactProblem<dim>::output_for_benchmark( typename DoFHandler<dim>::active_cell_iterator cell = dof_handler.begin_active(), endc = dof_handler.end(); for (; cell != endc; ++cell) - if (cell->is_locally_owned()) + if (cell->is_locally_owned()) for (unsigned int face = 0; face < GeometryInfo < dim > ::faces_per_cell; ++face) if (cell->face(face)->at_boundary() diff --git a/deal.II/examples/step-51/doc/intro.dox b/deal.II/examples/step-51/doc/intro.dox index d5ecfd4b70..22dc984e08 100644 --- a/deal.II/examples/step-51/doc/intro.dox +++ b/deal.II/examples/step-51/doc/intro.dox @@ -16,6 +16,7 @@ to all of the degrees of freedom in the adjacent elements. The resulting discrete equations yield very large linear systems very quickly, especially for systems of equations in dim=2 or dim=3. +<h4> Reducing the size of the linear system </h4> To alleviate the computational cost of solving such large linear systems, the hybridizable discontinuous Galerkin (HDG) methodology has recently been developed by Cockburn and co-workers @@ -40,12 +41,45 @@ element solutions no longer couple to neighboring elements. This is known as th solution process. <li> Use the local element solutions to construct the global problem for the trace values. These are the only globally coupled unknowns. - <li> Modify the local solutions from the computed trace values. + <li> Reconstruct the local solutions from the computed trace values. </ol> +The above procedure also has a linear algebra interpretation and referred to +as static condensation. Let us write the complete linear system associated to +the HDG problem as a block system with the discrete DG variables <i>U</i> as +first block and the skeleton variables $\Lambda$ as the second block: +@f{eqnarray*} +\begin{pmatrix} A & B \\ C & D \end{pmatrix} +\begin{pmatrix} U \\ \Lambda \end{pmatrix} += +\begin{pmatrix} F \\ G \end{pmatrix} +@f} +Our aim is now to eliminate the <i>U</i> block with a Schur complement +approach similar to step-20, which results in the following two steps: +@f{eqnarray*} +(D - C A^{-1} B) \Lambda &=& G - C A^{-1} F \\ +A U &=& F - B \Lambda +@f} +The steps in the Dirichlet-to-Neumann map concept hence correspond to +<ol> + <li> constructing the Schur complement matrix $D-C A^{-1} B$ and right hand side $G - C A^{-1} F$, + <li> solving the Schur complement system for $\Lambda$, and + <li> solving the equation for <i>U</i> using the second equation which uses $\Lambda$. +</ol> + +The important ingredient from the linear algebra point of view is that the +matrix <i>A</i> is block-diagonal with block size equal to the number of +degrees of freedom of the interior DG variables which are always only related +to a single cell. The coupling to other cells is introduced by the matrices +<i>B</i> and <i>C</i> over the skeleton variable. The block-diagonality of +<i>A</i> and the structure in <i>B</i> and <i>C</i> allow us to invert the +matrix <i>A</i> element by element (the local solution of the Dirichelt +problem) and subtract $CA^{-1}B$ from $D$. + +<h4> Solution quality and rates of convergence</h4> Another criticism of traditional DG methods is that the approximate fluxes -converge suboptimally. The local HDG solutions can be shown to converge -as $\mathcal{O}(h^{p+1})$. Additionally, a super-convergence property can +converge suboptimally. The local HDG solutions can be shown to converge +as $\mathcal{O}(h^{p+1})$, i.e., at optimal order. Additionally, a super-convergence property can be used to post-process a new approximate solution that converges at the rate $\mathcal{O}(h^{p+2})$. diff --git a/deal.II/examples/step-51/doc/results.dox b/deal.II/examples/step-51/doc/results.dox index ae6e002753..96eabb1724 100644 --- a/deal.II/examples/step-51/doc/results.dox +++ b/deal.II/examples/step-51/doc/results.dox @@ -7,43 +7,43 @@ the convergence tables look the following: @code Q1 elements, adaptive refinement: -cells dofs val L2 grad L2 val L2-post - 4 24 6.101e+00 1.065e+01 5.098e+00 - 10 58 3.168e+00 9.223e+00 2.431e+00 - 28 148 2.888e+00 9.368e+00 2.644e+00 - 55 272 6.756e-01 4.088e+00 2.400e-01 - 109 578 2.175e-01 1.529e+00 7.350e-02 - 214 1072 9.783e-02 9.006e-01 2.219e-02 - 409 2056 4.812e-02 5.193e-01 1.081e-02 - 811 3880 2.714e-02 2.971e-01 4.669e-03 - 1555 7204 1.365e-02 1.789e-01 2.627e-03 - 2956 13198 7.919e-03 1.009e-01 1.006e-03 +cells dofs val L2 grad L2 val L2-post + 16 80 1.804e+01 2.207e+01 1.798e+01 + 31 170 9.874e+00 1.322e+01 9.798e+00 + 61 314 7.452e-01 3.793e+00 4.891e-01 + 121 634 3.240e-01 1.511e+00 2.616e-01 + 238 1198 8.585e-02 8.212e-01 1.808e-02 + 454 2290 4.802e-02 5.178e-01 2.195e-02 + 898 4378 2.561e-02 2.947e-01 4.318e-03 + 1720 7864 1.306e-02 1.664e-01 2.978e-03 + 3271 14638 7.025e-03 9.815e-02 1.075e-03 + 6217 27214 4.119e-03 6.407e-02 9.975e-04 Q1 elements, global refinement: -cells dofs val L2 grad L2 val L2-post - 16 80 4.570e+00 - 1.221e+01 - 4.333e+00 - - 36 168 1.869e+00 2.20 7.299e+00 1.27 1.734e+00 2.26 - 64 288 7.177e-01 3.33 4.218e+00 1.91 2.538e-01 6.68 - 144 624 2.729e-01 2.38 1.867e+00 2.01 6.110e-02 3.51 - 256 1088 1.493e-01 2.10 1.046e+00 2.01 2.878e-02 2.62 - 576 2400 6.964e-02 1.88 4.847e-01 1.90 9.202e-03 2.81 - 1024 4224 4.018e-02 1.91 2.785e-01 1.93 4.027e-03 2.87 +cells dofs val L2 grad L2 val L2-post + 16 80 1.804e+01 - 2.207e+01 - 1.798e+01 - + 36 168 6.125e+00 2.66 9.472e+00 2.09 6.084e+00 2.67 + 64 288 9.785e-01 6.38 4.260e+00 2.78 7.102e-01 7.47 + 144 624 2.730e-01 3.15 1.866e+00 2.04 6.115e-02 6.05 + 256 1088 1.493e-01 2.10 1.046e+00 2.01 2.880e-02 2.62 + 576 2400 6.965e-02 1.88 4.846e-01 1.90 9.204e-03 2.81 + 1024 4224 4.018e-02 1.91 2.784e-01 1.93 4.027e-03 2.87 2304 9408 1.831e-02 1.94 1.264e-01 1.95 1.236e-03 2.91 4096 16640 1.043e-02 1.96 7.185e-02 1.96 5.306e-04 2.94 - 9216 37248 4.690e-03 1.97 3.228e-02 1.97 1.600e-04 2.96 + 9216 37248 4.690e-03 1.97 3.228e-02 1.97 1.599e-04 2.96 Q3 elements, global refinement: -cells dofs val L2 grad L2 val L2-post - 16 160 2.398e-01 - 1.873e+00 - 1.354e-01 - - 36 336 5.843e-02 3.48 5.075e-01 3.22 1.882e-02 4.87 - 64 576 3.466e-02 1.82 2.534e-01 2.41 4.326e-03 5.11 - 144 1248 8.297e-03 3.53 5.925e-02 3.58 6.330e-04 4.74 - 256 2176 2.254e-03 4.53 1.636e-02 4.47 1.403e-04 5.24 - 576 4800 4.558e-04 3.94 3.278e-03 3.96 1.844e-05 5.01 - 1024 8448 1.471e-04 3.93 1.052e-03 3.95 4.378e-06 5.00 - 2304 18816 2.956e-05 3.96 2.104e-04 3.97 5.751e-07 5.01 - 4096 33280 9.428e-06 3.97 6.697e-05 3.98 1.362e-07 5.01 - 9216 74496 1.876e-06 3.98 1.330e-05 3.99 1.817e-08 4.97 +cells dofs val L2 grad L2 val L2-post + 16 160 3.613e-01 - 1.891e+00 - 3.020e-01 - + 36 336 6.411e-02 4.26 5.081e-01 3.24 3.238e-02 5.51 + 64 576 3.480e-02 2.12 2.533e-01 2.42 5.277e-03 6.31 + 144 1248 8.297e-03 3.54 5.924e-02 3.58 6.330e-04 5.23 + 256 2176 2.254e-03 4.53 1.636e-02 4.47 1.403e-04 5.24 + 576 4800 4.558e-04 3.94 3.277e-03 3.96 1.844e-05 5.01 + 1024 8448 1.471e-04 3.93 1.052e-03 3.95 4.378e-06 5.00 + 2304 18816 2.956e-05 3.96 2.104e-04 3.97 5.750e-07 5.01 + 4096 33280 9.428e-06 3.97 6.697e-05 3.98 1.362e-07 5.01 + 9216 74496 1.876e-06 3.98 1.330e-05 3.99 1.788e-08 5.01 @endcode @@ -58,43 +58,43 @@ postprocessed scalar variable at fifth order. The same convergence rates are observed in 3d. @code Q1 elements, adaptive refinement: -cells dofs val L2 grad L2 val L2-post - 8 144 3.846e+00 1.519e+01 2.388e+00 - 29 500 2.800e+00 9.885e+00 1.185e+00 - 113 1792 1.772e+00 9.911e+00 1.423e+00 - 379 5736 6.057e-01 5.011e+00 2.180e-01 - 1317 19412 1.542e-01 1.465e+00 4.176e-02 - 4579 64768 5.059e-02 5.615e-01 9.563e-03 - 14596 199552 2.128e-02 3.124e-01 4.599e-03 - 46180 611380 1.032e-02 1.623e-01 1.643e-03 -144859 1864212 4.996e-03 8.376e-02 6.898e-04 -451053 5684324 2.516e-03 4.559e-02 2.832e-04 +cells dofs val L2 grad L2 val L2-post + 8 144 7.122e+00 1.941e+01 6.102e+00 + 29 500 3.309e+00 1.023e+01 2.145e+00 + 113 1792 2.204e+00 1.023e+01 1.912e+00 + 379 5732 6.085e-01 5.008e+00 2.233e-01 + 1317 19412 1.543e-01 1.464e+00 4.196e-02 + 4579 64768 5.058e-02 5.611e-01 9.521e-03 + 14596 199552 2.129e-02 3.122e-01 4.569e-03 + 46180 611400 1.033e-02 1.622e-01 1.684e-03 +144859 1864212 5.007e-03 8.371e-02 7.364e-04 +451060 5684508 2.518e-03 4.562e-02 3.070e-04 Q1 elements, global refinement: -cells dofs val L2 grad L2 val L2-post - 8 144 3.846e+00 - 1.519e+01 - 2.388e+00 - - 27 432 4.677e+00 -0.48 2.158e+01 -0.87 3.441e+00 -0.90 - 64 960 2.366e+00 2.37 1.228e+01 1.96 1.831e+00 2.19 - 216 3024 1.225e+00 1.62 8.396e+00 0.94 1.017e+00 1.45 - 512 6912 6.870e-01 2.01 5.314e+00 1.59 2.421e-01 4.99 - 1728 22464 2.912e-01 2.12 2.494e+00 1.87 8.593e-02 2.56 - 4096 52224 1.683e-01 1.91 1.455e+00 1.87 4.056e-02 2.61 - 13824 172800 7.970e-02 1.84 6.866e-01 1.85 1.335e-02 2.74 - 32768 405504 4.637e-02 1.88 3.986e-01 1.89 5.932e-03 2.82 -110592 1354752 2.133e-02 1.92 1.831e-01 1.92 1.851e-03 2.87 +cells dofs val L2 grad L2 val L2-post + 8 144 7.122e+00 - 1.941e+01 - 6.102e+00 - + 27 432 5.491e+00 0.64 2.184e+01 -0.29 4.448e+00 0.78 + 64 960 3.646e+00 1.42 1.299e+01 1.81 3.306e+00 1.03 + 216 3024 1.595e+00 2.04 8.550e+00 1.03 1.441e+00 2.05 + 512 6912 6.922e-01 2.90 5.306e+00 1.66 2.511e-01 6.07 + 1728 22464 2.915e-01 2.13 2.490e+00 1.87 8.588e-02 2.65 + 4096 52224 1.684e-01 1.91 1.453e+00 1.87 4.055e-02 2.61 + 13824 172800 7.972e-02 1.84 6.861e-01 1.85 1.335e-02 2.74 + 32768 405504 4.637e-02 1.88 3.984e-01 1.89 5.932e-03 2.82 +110592 1354752 2.133e-02 1.92 1.830e-01 1.92 1.851e-03 2.87 Q3 elements, global refinement: -cells dofs val L2 grad L2 val L2-post - 8 576 3.845e+00 - 1.742e+01 - 3.550e+00 - - 27 1728 8.915e-01 3.60 6.939e+00 2.27 5.865e-01 4.44 - 64 3840 2.807e-01 4.02 2.713e+00 3.26 1.326e-01 5.17 - 216 12096 7.866e-02 3.14 7.727e-01 3.10 2.112e-02 4.53 - 512 27648 3.640e-02 2.68 3.307e-01 2.95 5.224e-03 4.86 - 1728 89856 8.545e-03 3.57 7.586e-02 3.63 7.642e-04 4.74 - 4096 208896 2.598e-03 4.14 2.314e-02 4.13 1.783e-04 5.06 - 13824 691200 5.314e-04 3.91 4.699e-03 3.93 2.355e-05 4.99 - 32768 1622016 1.723e-04 3.91 1.518e-03 3.93 5.603e-06 4.99 -110592 5419008 3.482e-05 3.94 3.057e-04 3.95 7.375e-07 5.00 +cells dofs val L2 grad L2 val L2-post + 8 576 5.670e+00 - 1.868e+01 - 5.462e+00 - + 27 1728 1.048e+00 4.16 6.988e+00 2.42 8.011e-01 4.73 + 64 3840 2.831e-01 4.55 2.710e+00 3.29 1.363e-01 6.16 + 216 12096 7.883e-02 3.15 7.721e-01 3.10 2.158e-02 4.55 + 512 27648 3.642e-02 2.68 3.305e-01 2.95 5.231e-03 4.93 + 1728 89856 8.546e-03 3.58 7.581e-02 3.63 7.640e-04 4.74 + 4096 208896 2.598e-03 4.14 2.313e-02 4.13 1.783e-04 5.06 + 13824 691200 5.314e-04 3.91 4.697e-03 3.93 2.355e-05 4.99 + 32768 1622016 1.723e-04 3.91 1.517e-03 3.93 5.602e-06 4.99 +110592 5419008 3.482e-05 3.94 3.055e-04 3.95 7.374e-07 5.00 @endcode diff --git a/deal.II/examples/step-51/step-51.cc b/deal.II/examples/step-51/step-51.cc index ab772a39a1..9049e88e1a 100644 --- a/deal.II/examples/step-51/step-51.cc +++ b/deal.II/examples/step-51/step-51.cc @@ -33,7 +33,7 @@ #include <deal.II/lac/vector.h> #include <deal.II/lac/full_matrix.h> #include <deal.II/lac/compressed_simple_sparsity_pattern.h> -#include <deal.II/lac/solver_gmres.h> +#include <deal.II/lac/solver_bicgstab.h> #include <deal.II/lac/precondition.h> #include <deal.II/grid/tria.h> #include <deal.II/grid/tria_accessor.h> @@ -738,9 +738,11 @@ Step51<dim>::assemble_system_one_cell (const typename DoFHandler<dim>::active_ce for (unsigned int q=0; q<n_face_q_points; ++q) { const double JxW = scratch.fe_face_values.JxW(q); + const Point<dim> quadrature_point = + scratch.fe_face_values.quadrature_point(q); const Point<dim> normal = scratch.fe_face_values.normal_vector(q); const Tensor<1,dim> convection - = scratch.convection_velocity.value(scratch.fe_face_values.quadrature_point(q)); + = scratch.convection_velocity.value(quadrature_point); const double tau_stab = (tau_stab_diffusion + std::abs(convection * normal)); @@ -792,11 +794,12 @@ Step51<dim>::assemble_system_one_cell (const typename DoFHandler<dim>::active_ce (cell->face(face)->boundary_indicator() == 1)) { const double neumann_value = - scratch.exact_solution.value(scratch.fe_face_values.quadrature_point(q)); + - scratch.exact_solution.gradient (quadrature_point) * normal + + convection * normal * scratch.exact_solution.value(quadrature_point); for (unsigned int i=0; i<scratch.fe_support_on_face[face].size(); ++i) { const unsigned int ii=scratch.fe_support_on_face[face][i]; - task_data.cell_vector(ii) -= scratch.tr_phi[i] * neumann_value * JxW; + task_data.cell_vector(ii) += scratch.tr_phi[i] * neumann_value * JxW; } } } @@ -815,9 +818,9 @@ Step51<dim>::assemble_system_one_cell (const typename DoFHandler<dim>::active_ce { const unsigned int ii=scratch.fe_local_support_on_face[face][i]; scratch.l_rhs(ii) -= (scratch.q_phi[i] * normal - + - scratch.u_phi[i] * (convection * normal - tau_stab) - ) * scratch.trace_values[q] * JxW; + + + scratch.u_phi[i] * (convection * normal - tau_stab) + ) * scratch.trace_values[q] * JxW; } } } @@ -843,12 +846,12 @@ template <int dim> void Step51<dim>::solve () { SolverControl solver_control (system_matrix.m()*10, - 1e-10*system_rhs.l2_norm()); - SolverGMRES<> solver (solver_control, 50); + 1e-11*system_rhs.l2_norm()); + SolverBicgstab<> solver (solver_control, false); solver.solve (system_matrix, solution, system_rhs, PreconditionIdentity()); - std::cout << " Number of GMRES iterations: " << solver_control.last_step() + std::cout << " Number of BiCGStab iterations: " << solver_control.last_step() << std::endl; system_matrix.clear(); @@ -1067,46 +1070,62 @@ void Step51<dim>::refine_grid (const unsigned int cycle) if (cycle == 0) { GridGenerator::subdivided_hyper_cube (triangulation, 2, -1, 1); + triangulation.refine_global(3-dim); } else switch (refinement_mode) { case global_refinement: { - triangulation.clear(); - GridGenerator::subdivided_hyper_cube (triangulation, 2+(cycle%2), -1, 1); - triangulation.refine_global(3-dim+cycle/2); + triangulation.clear(); + GridGenerator::subdivided_hyper_cube (triangulation, 2+(cycle%2), -1, 1); + triangulation.refine_global(3-dim+cycle/2); break; } case adaptive_refinement: - { - Vector<float> estimated_error_per_cell (triangulation.n_active_cells()); + { + Vector<float> estimated_error_per_cell (triangulation.n_active_cells()); - FEValuesExtractors::Scalar scalar(dim); - typename FunctionMap<dim>::type neumann_boundary; - KellyErrorEstimator<dim>::estimate (dof_handler_local, - QGauss<dim-1>(3), - neumann_boundary, - solution_local, - estimated_error_per_cell, - fe_local.component_mask(scalar)); + FEValuesExtractors::Scalar scalar(dim); + typename FunctionMap<dim>::type neumann_boundary; + KellyErrorEstimator<dim>::estimate (dof_handler_local, + QGauss<dim-1>(3), + neumann_boundary, + solution_local, + estimated_error_per_cell, + fe_local.component_mask(scalar)); - GridRefinement::refine_and_coarsen_fixed_number (triangulation, - estimated_error_per_cell, - 0.3, 0.); + GridRefinement::refine_and_coarsen_fixed_number (triangulation, + estimated_error_per_cell, + 0.3, 0.); - triangulation.execute_coarsening_and_refinement (); + triangulation.execute_coarsening_and_refinement (); - break; - } + break; + } default: - { - Assert (false, ExcNotImplemented()); - } + { + Assert (false, ExcNotImplemented()); + } } - } + + // Just as in step-7, we set the boundary indicator of one of the faces to 1 + // where we want to specify Neumann boundary conditions instead of Dirichlet + // conditions. Since we re-create the triangulation every time for global + // refinement, the flags are set in every refinement step, not just at the + // beginning. + typename Triangulation<dim>::cell_iterator + cell = triangulation.begin (), + endc = triangulation.end(); + for (; cell!=endc; ++cell) + for (unsigned int face=0; face<GeometryInfo<dim>::faces_per_cell; ++face) + if ((std::fabs(cell->face(face)->center()(0) - (-1)) < 1e-12) + || + (std::fabs(cell->face(face)->center()(1) - (-1)) < 1e-12)) + cell->face(face)->set_boundary_indicator (1); +} diff --git a/deal.II/include/deal.II/base/data_out_base.h b/deal.II/include/deal.II/base/data_out_base.h index 43e7e9a294..082e98bb39 100644 --- a/deal.II/include/deal.II/base/data_out_base.h +++ b/deal.II/include/deal.II/base/data_out_base.h @@ -219,33 +219,24 @@ class DataOutBase { public: /** - * Data structure describing a patch of - * data in <tt>dim</tt> space + * Data structure describing a patch of data in <tt>dim</tt> space * dimensions. * * A patch consists of the following data: * <ul> * <li>the corner #vertices, - * <li> the number - * #n_subdivisions of the number - * of cells the Patch has in each - * space direction, - * <li> the #data attached to - * each vertex, in the usual + * <li> the number #n_subdivisions of the number of cells the Patch + * has in each space direction, + * <li> the #data attached to each vertex, in the usual * lexicographic ordering, * <li> Information on #neighbors. * </ul> * - * See the general - * documentation of the - * <tt>DataOutBase</tt> class for more - * information on its contents and - * purposes. In the case of two - * dimensions, the next picture ist an - * example of <tt>n_subdivision</tt> = 4 - * because the number of (sub)cells - * within each patch is equal to - * <tt>2^dim</tt>. + * See the general documentation of the DataOutBase class for more + * information on its contents and purposes. In the case of two + * dimensions, the next picture ist an example of + * <tt>n_subdivision</tt> = 4 because the number of (sub)cells + * within each patch is equal to <tt>2<sup>dim</sup></tt>. * * @ingroup output * @@ -255,34 +246,23 @@ public: struct Patch { /** - * Make the <tt>spacedim</tt> template - * parameter available. + * Make the <tt>spacedim</tt> template parameter available. */ static const unsigned int space_dim=spacedim; /** - * Corner points of a patch. - * Inner points are computed by - * a multilinear transform of - * the unit cell to the cell - * specified by these corner - * points. The order of points - * is the same as for cells - * in the triangulation. + * Corner points of a patch. Inner points are computed by a + * multilinear transform of the unit cell to the cell specified by + * these corner points. The order of points is the same as for + * cells in the triangulation. */ Point<spacedim> vertices[GeometryInfo<dim>::vertices_per_cell]; /** - * Numbers of neighbors of a patch. - * OpenDX format requires - * neighbor information for - * advanced output. Here the - * neighborship relationship - * of patches is - * stored. During output, - * this must be transformed - * into neighborship of - * sub-grid cells. + * Numbers of neighbors of a patch. OpenDX format requires + * neighbor information for advanced output. Here the neighborship + * relationship of patches is stored. During output, this must be + * transformed into neighborship of sub-grid cells. */ unsigned int neighbors[dim > 0 ? @@ -291,124 +271,77 @@ public: 1]; /** - * Number of this - * patch. Since we are not - * sure patches are handled - * in the same order, always, - * we better store this. + * Number of this patch. Since we are not sure patches are handled + * in the same order, always, we better store this. */ unsigned int patch_index; /** - * Number of subdivisions with - * which this patch is to be - * written. <tt>1</tt> means no - * subdivision, <tt>2</tt> means - * bisection, <tt>3</tt> trisection, - * etc. + * Number of subdivisions with which this patch is to be + * written. <tt>1</tt> means no subdivision, <tt>2</tt> means + * bisection, <tt>3</tt> trisection, etc. */ unsigned int n_subdivisions; /** - * Data vectors. The format is - * as follows: - * <tt>data(i,.)</tt> denotes the data - * belonging to the <tt>i</tt>th data - * vector. <tt>data.n()</tt> - * therefore equals the number - * of output points; this - * number is <tt>(subdivisions+1)^{dim</tt>}. - * <tt>data.m()</tt> equals the number of - * data vectors. + * Data vectors. The format is as follows: <tt>data(i,.)</tt> + * denotes the data belonging to the <tt>i</tt>th data + * vector. <tt>data.n()</tt> therefore equals the number of output + * points; this number is <tt>(subdivisions+1)^{dim</tt>}. + * <tt>data.m()</tt> equals the number of data vectors. * - * Within each column, - * <tt>data(.,j)</tt> are the - * data values at the output - * point <tt>j</tt>, where - * <tt>j</tt> denotes the - * usual lexicographic - * ordering in deal.II. This - * is also the order of - * points as provided by the - * <tt>QIterated</tt> class - * when used with the - * <tt>QTrapez</tt> class as - * subquadrature. + * Within each column, <tt>data(.,j)</tt> are the data values at + * the output point <tt>j</tt>, where <tt>j</tt> denotes the usual + * lexicographic ordering in deal.II. This is also the order of + * points as provided by the <tt>QIterated</tt> class when used + * with the <tt>QTrapez</tt> class as subquadrature. * - * Since the number of data vectors - * is usually the same for all - * patches to be printed, - * <tt>data.size()</tt> should yield - * the same value for all patches - * provided. The exception are - * patches for which - * points_are_available are set, - * where the actual coordinates of - * the point are appended to the - * 'data' field, see the - * documentation of the - * points_are_available flag. + * Since the number of data vectors is usually the same for all + * patches to be printed, <tt>data.size()</tt> should yield the + * same value for all patches provided. The exception are patches + * for which points_are_available are set, where the actual + * coordinates of the point are appended to the 'data' field, see + * the documentation of the points_are_available flag. */ Table<2,float> data; /** - * Bool flag indicating, whether the - * coordinates of the inner patch - * points are appended to the @p data - * table (@ true) or not (@ false), - * where the second is the standard and - * can be found for all cells in the - * interior of a domain. + * Bool flag indicating, whether the coordinates of the inner + * patch points are appended to the @p data table (@p true) or not + * (@p false), where the second is the standard and can be found + * for all cells in the interior of a domain. * - * On the boundary of a domain, patch - * points are evaluated using a - * Mapping and therefore have to be - * stored inside the patch, as the - * Mapping and the corresponding - * boundary information are no longer - * available later on when we - * actually write the patch out to an - * output stream. + * On the boundary of a domain, patch points are evaluated using a + * Mapping and therefore have to be stored inside the patch, as + * the Mapping and the corresponding boundary information are no + * longer available later on when we actually write the patch out + * to an output stream. */ bool points_are_available; /** - * Default constructor. Sets - * <tt>n_subdivisions</tt> to one. + * Default constructor. Sets #n_subdivisions to one. */ Patch (); /** - * Compare the present patch - * for equality with another - * one. This is used in a few - * of the automated tests in - * our testsuite. + * Compare the present patch for equality with another one. This + * is used in a few of the automated tests in our testsuite. */ bool operator == (const Patch &patch) const; /** - * Determine an estimate for - * the memory consumption (in - * bytes) of this - * object. Since sometimes - * the size of objects can - * not be determined exactly - * (for example: what is the - * memory consumption of an - * STL <tt>std::map</tt> type with a - * certain number of - * elements?), this is only - * an estimate. however often - * quite close to the true - * value. + * Determine an estimate for the memory consumption (in bytes) of + * this object. Since sometimes the size of objects can not be + * determined exactly (for example: what is the memory consumption + * of an STL <tt>std::map</tt> type with a certain number of + * elements?), this is only an estimate. however often quite close + * to the true value. */ std::size_t memory_consumption () const; /** - * Value to be used if this - * patch has no neighbor on - * one side. + * Value to be used if this patch has no neighbor on one side. */ static const unsigned int no_neighbor = numbers::invalid_unsigned_int; /** @addtogroup Exceptions @@ -426,47 +359,36 @@ public: }; /** - * Flags controlling the details of - * output in OpenDX format. + * Flags controlling the details of output in OpenDX format. * * @ingroup output */ struct DXFlags { /** - * Write neighbor - * information. This - * information is necessary - * for instance, if OpenDX is - * supposed to compute - * integral curves - * (streamlines). If it is - * not present, streamlines - * end at cell boundaries. + * Write neighbor information. This information is necessary for + * instance, if OpenDX is supposed to compute integral curves + * (streamlines). If it is not present, streamlines end at cell + * boundaries. */ bool write_neighbors; /** - * Write integer values of - * the Triangulation in - * binary format. + * Write integer values of the Triangulation in binary format. */ bool int_binary; /** - * Write coordinate vectors in - * binary format. + * Write coordinate vectors in binary format. */ bool coordinates_binary; /** - * Write data vectors in - * binary format. + * Write data vectors in binary format. */ bool data_binary; /** - * Write binary coordinate - * vectors as double (64 bit) - * numbers instead of float (32 bit). + * Write binary coordinate vectors as double (64 bit) numbers + * instead of float (32 bit). */ bool data_double; @@ -479,56 +401,40 @@ public: const bool data_binary = false); /** - * Declare all flags with name - * and type as offered by this - * class, for use in input files. + * Declare all flags with name and type as offered by this class, + * for use in input files. */ static void declare_parameters (ParameterHandler &prm); /** - * Read the parameters declared in - * <tt>declare_parameters</tt> and set the - * flags for this output format - * accordingly. + * Read the parameters declared in declare_parameters() and set + * the flags for this output format accordingly. * - * The flags thus obtained overwrite - * all previous contents of this object. + * The flags thus obtained overwrite all previous contents of this + * object. */ void parse_parameters (const ParameterHandler &prm); /** - * Determine an estimate for - * the memory consumption (in - * bytes) of this - * object. + * Determine an estimate for the memory consumption (in bytes) of + * this object. */ std::size_t memory_consumption () const; }; /** - * Flags controlling the details - * of output in UCD format for - * AVS. + * Flags controlling the details of output in UCD format for AVS. * * @ingroup output */ struct UcdFlags { /** - * Write a comment at the - * beginning of the file - * stating the date of - * creation and some other - * data. While this is - * supported by the UCD - * format and - * AVS, some other - * programs get confused by - * this, so the default is to - * not write a - * preamble. However, a - * preamble can be written - * using this flag. + * Write a comment at the beginning of the file stating the date + * of creation and some other data. While this is supported by + * the UCD format and AVS, some other programs get confused by + * this, so the default is to not write a preamble. However, a + * preamble can be written using this flag. * * Default: <code>false</code>. */ @@ -540,45 +446,33 @@ public: UcdFlags (const bool write_preamble = false); /** - * Declare all flags with name - * and type as offered by this - * class, for use in input files. + * Declare all flags with name and type as offered by this class, + * for use in input files. */ static void declare_parameters (ParameterHandler &prm); /** - * Read the parameters declared in - * <tt>declare_parameters</tt> and set the - * flags for this output format - * accordingly. + * Read the parameters declared in declare_parameters() and + * set the flags for this output format accordingly. * - * The flags thus obtained overwrite - * all previous contents of this object. + * The flags thus obtained overwrite all previous contents of this + * object. */ void parse_parameters (const ParameterHandler &prm); /** - * Determine an estimate for - * the memory consumption (in - * bytes) of this - * object. Since sometimes - * the size of objects can - * not be determined exactly - * (for example: what is the - * memory consumption of an - * STL <tt>std::map</tt> type with a - * certain number of - * elements?), this is only - * an estimate. however often - * quite close to the true - * value. + * Determine an estimate for the memory consumption (in bytes) of + * this object. Since sometimes the size of objects can not be + * determined exactly (for example: what is the memory consumption + * of an STL <tt>std::map</tt> type with a certain number of + * elements?), this is only an estimate. however often quite close + * to the true value. */ std::size_t memory_consumption () const; }; /** - * Flags controlling the details of - * output in Gnuplot format. At + * Flags controlling the details of output in Gnuplot format. At * present no flags are implemented. * * @ingroup output @@ -587,12 +481,9 @@ public: { private: /** - * Dummy entry to suppress compiler - * warnings when copying an empty - * structure. Remove this member - * when adding the first flag to - * this structure (and remove the - * <tt>private</tt> as well). + * Dummy entry to suppress compiler warnings when copying an empty + * structure. Remove this member when adding the first flag to + * this structure (and remove the <tt>private</tt> as well). */ int dummy; @@ -603,74 +494,56 @@ public: GnuplotFlags (); /** - * Declare all flags with name - * and type as offered by this - * class, for use in input files. + * Declare all flags with name and type as offered by this class, + * for use in input files. */ static void declare_parameters (ParameterHandler &prm); /** - * Read the parameters declared in - * <tt>declare_parameters</tt> and set the - * flags for this output format - * accordingly. + * Read the parameters declared in declare_parameters() and set + * the flags for this output format accordingly. * - * The flags thus obtained overwrite - * all previous contents of this object. + * The flags thus obtained overwrite all previous contents of this + * object. */ void parse_parameters (const ParameterHandler &prm) const; /** - * Determine an estimate for - * the memory consumption (in - * bytes) of this - * object. Since sometimes - * the size of objects can - * not be determined exactly - * (for example: what is the - * memory consumption of an - * STL <tt>std::map</tt> type with a - * certain number of - * elements?), this is only - * an estimate. however often - * quite close to the true - * value. + * Determine an estimate for the memory consumption (in bytes) of + * this object. Since sometimes the size of objects can not be + * determined exactly (for example: what is the memory consumption + * of an STL <tt>std::map</tt> type with a certain number of + * elements?), this is only an estimate. however often quite close + * to the true value. */ std::size_t memory_consumption () const; }; /** - * Flags controlling the details - * of output in Povray - * format. Several flags are - * implemented, see their - * respective documentation. + * Flags controlling the details of output in Povray format. Several + * flags are implemented, see their respective documentation. * * @ingroup output */ struct PovrayFlags { /** - * Normal vector interpolation, - * if set to true + * Normal vector interpolation, if set to true * * default = false */ bool smooth; /** - * Use bicubic patches (b-splines) - * instead of triangles. + * Use bicubic patches (b-splines) instead of triangles. * * default = false */ bool bicubic_patch; /** - * include external "data.inc" - * with camera, light and - * texture definition for the - * scene. + * include external "data.inc" with camera, light and texture + * definition for the scene. * * default = false */ @@ -684,79 +557,59 @@ public: const bool external_data = false); /** - * Declare all flags with name - * and type as offered by this - * class, for use in input files. + * Declare all flags with name and type as offered by this class, + * for use in input files. */ static void declare_parameters (ParameterHandler &prm); /** - * Read the parameters declared in - * <tt>declare_parameters</tt> and set the - * flags for this output format - * accordingly. + * Read the parameters declared in declare_parameters() and + * set the flags for this output format accordingly. * - * The flags thus obtained overwrite - * all previous contents of this object. + * The flags thus obtained overwrite all previous contents of this + * object. */ void parse_parameters (const ParameterHandler &prm); /** - * Determine an estimate for - * the memory consumption (in - * bytes) of this - * object. Since sometimes - * the size of objects can - * not be determined exactly - * (for example: what is the - * memory consumption of an - * STL <tt>std::map</tt> type with a - * certain number of - * elements?), this is only - * an estimate. however often - * quite close to the true - * value. + * Determine an estimate for the memory consumption (in bytes) of + * this object. Since sometimes the size of objects can not be + * determined exactly (for example: what is the memory consumption + * of an STL <tt>std::map</tt> type with a certain number of + * elements?), this is only an estimate. however often quite close + * to the true value. */ std::size_t memory_consumption () const; }; /** - * Flags controlling the details of - * output in encapsulated postscript - * format. + * Flags controlling the details of output in encapsulated + * postscript format. * * @ingroup output */ struct EpsFlags { /** - * This denotes the number of the - * data vector which shall be used - * for generating the height - * information. By default, the - * first data vector is taken, - * i.e. <tt>height_vector==0</tt>, if - * there is any data vector. If there - * is no data vector, no height + * This denotes the number of the data vector which shall be used + * for generating the height information. By default, the first + * data vector is taken, i.e. <tt>height_vector==0</tt>, if there + * is any data vector. If there is no data vector, no height * information is generated. */ unsigned int height_vector; /** - * Number of the vector which is - * to be taken to colorize cells. - * The same applies as for - * <tt>height_vector</tt>. + * Number of the vector which is to be taken to colorize cells. + * The same applies as for #height_vector. */ unsigned int color_vector; /** - * Enum denoting the possibilities - * whether the scaling should be done - * such that the given <tt>size</tt> equals - * the width or the height of - * the resulting picture. + * Enum denoting the possibilities whether the scaling should be + * done such that the given <tt>size</tt> equals the width or the + * height of the resulting picture. */ enum SizeType { @@ -772,49 +625,34 @@ public: SizeType size_type; /** - * Width or height of the output - * as given in postscript units - * This usually is given by the - * strange unit 1/72 inch. Whether - * this is height or width is - * specified by the flag - * <tt>size_type</tt>. + * Width or height of the output as given in postscript units This + * usually is given by the strange unit 1/72 inch. Whether this is + * height or width is specified by the flag <tt>size_type</tt>. * - * Default is 300, which represents - * a size of roughly 10 cm. + * Default is 300, which represents a size of roughly 10 cm. */ unsigned int size; /** - * Width of a line in postscript - * units. Default is 0.5. + * Width of a line in postscript units. Default is 0.5. */ double line_width; /** - * Angle of the line origin-viewer - * against the z-axis in degrees. + * Angle of the line origin-viewer against the z-axis in degrees. * - * Default is the Gnuplot-default - * of 60. + * Default is the Gnuplot-default of 60. */ double azimut_angle; /** - * Angle by which the viewers - * position projected onto the - * x-y-plane is rotated around - * the z-axis, in positive sense - * when viewed from above. The - * unit are degrees, and zero - * equals a position above or below - * the negative y-axis. + * Angle by which the viewers position projected onto the + * x-y-plane is rotated around the z-axis, in positive sense when + * viewed from above. The unit are degrees, and zero equals a + * position above or below the negative y-axis. * - * Default is the - * Gnuplot-default of 30. - * An example of a - * Gnuplot-default of 0 is - * the following: + * Default is the Gnuplot-default of 30. An example of a + * Gnuplot-default of 0 is the following: * * @verbatim * @@ -833,75 +671,58 @@ public: double turn_angle; /** - * Factor by which the z-axis is to - * be stretched as compared to the - * x- and y-axes. This is to compensate - * for the different sizes that - * coordinate and solution values may - * have and to prevent that the plot - * looks to much out-of-place (no - * elevation at all if solution values - * are much smaller than coordinate - * values, or the common "extremely - * mountainous area" in the opposite - * case. + * Factor by which the z-axis is to be stretched as compared to + * the x- and y-axes. This is to compensate for the different + * sizes that coordinate and solution values may have and to + * prevent that the plot looks to much out-of-place (no elevation + * at all if solution values are much smaller than coordinate + * values, or the common "extremely mountainous area" in the + * opposite case. * * Default is <tt>1.0</tt>. */ double z_scaling; /** - * Flag the determines whether the - * lines bounding the cells (or the - * parts of each patch) are to be - * plotted. + * Flag the determines whether the lines bounding the cells (or + * the parts of each patch) are to be plotted. * * Default: <tt>true</tt>. */ bool draw_mesh; /** - * Flag whether to fill the regions - * between the lines bounding the cells - * or not. If not, no hidden line removal - * is performed, which in this crude - * implementation is done through - * writing the cells in a back-to-front - * order, thereby hiding the cells in - * the background by cells in the - * foreground. + * Flag whether to fill the regions between the lines bounding the + * cells or not. If not, no hidden line removal is performed, + * which in this crude implementation is done through writing the + * cells in a back-to-front order, thereby hiding the cells in the + * background by cells in the foreground. * - * If this flag is <tt>false</tt> and <tt>draw_mesh</tt> - * is <tt>false</tt> as well, nothing will be - * printed. + * If this flag is <tt>false</tt> and #draw_mesh is <tt>false</tt> + * as well, nothing will be printed. * - * If this flag is <tt>true</tt>, then the cells - * will be drawn either colored by one - * of the data sets (if <tt>shade_cells</tt> is - * <tt>true</tt>), or pure white (if - * <tt>shade_cells</tt> is false or if there are - * no data sets). + * If this flag is <tt>true</tt>, then the cells will be drawn + * either colored by one of the data sets (if #shade_cells is + * <tt>true</tt>), or pure white (if #shade_cells is false or if + * there are no data sets). * * Default is <tt>true</tt>. */ bool draw_cells; /** - * Flag to determine whether the cells - * shall be colorized by the data - * set denoted by <tt>color_vector</tt>, or - * simply be painted in white. This - * flag only makes sense if - * <tt>draw_cells==true</tt>. Colorization is - * done through the <tt>color_function</tt>. + * Flag to determine whether the cells shall be colorized by the + * data set denoted by #color_vector, or simply be painted in + * white. This flag only makes sense if + * <tt>#draw_cells==true</tt>. Colorization is done through + * #color_function. * * Default is <tt>true</tt>. */ bool shade_cells; /** - * Structure keeping the three color - * values in the RGB system. + * Structure keeping the three color values in the RGB system. */ struct RgbValues { @@ -910,52 +731,39 @@ public: float blue; /** - * Return <tt>true</tt> if the - * color represented by - * the three color values - * is a grey scale, - * i.e. all components - * are equal. + * Return <tt>true</tt> if the color represented by the three + * color values is a grey scale, i.e. all components are equal. */ bool is_grey () const; }; /** - * Definition of a function pointer - * type taking a value and returning - * a triple of color values in RGB - * values. + * Definition of a function pointer type taking a value and + * returning a triple of color values in RGB values. * - * Besides the actual value by which - * the color is to be computed, min - * and max values of the data to - * be colorized are given as well. + * Besides the actual value by which the color is to be computed, + * min and max values of the data to be colorized are given as + * well. */ typedef RgbValues (*ColorFunction) (const double value, const double min_value, const double max_value); /** - * This is a pointer to the function - * which is used to colorize the cells. - * By default, it points to the - * static function <tt>default_color_function</tt> - * which is a member of this class. + * This is a pointer to the function which is used to colorize the + * cells. By default, it points to the static function + * default_color_function() which is a member of this class. */ ColorFunction color_function; /** - * Default colorization function. This - * one does what one usually wants: - * It shifts colors from black (lowest - * value) through blue, green and red - * to white (highest value). For the - * exact defition of the color scale - * refer to the implementation. + * Default colorization function. This one does what one usually + * wants: It shifts colors from black (lowest value) through blue, + * green and red to white (highest value). For the exact defition + * of the color scale refer to the implementation. * - * This function was originally written - * by Stefan Nauber. + * This function was originally written by Stefan Nauber. */ static RgbValues default_color_function (const double value, @@ -963,12 +771,9 @@ public: const double max_value); /** - * This is an alternative color - * function producing a grey scale - * between black (lowest values) - * and white (highest values). You - * may use it by setting the - * <tt>color_function</tt> variable to the + * This is an alternative color function producing a grey scale + * between black (lowest values) and white (highest values). You + * may use it by setting the #color_function variable to the * address of this function. */ static RgbValues @@ -977,18 +782,11 @@ public: const double max_value); /** - * This is one more - * alternative color function - * producing a grey scale - * between white (lowest - * values) and black (highest - * values), i.e. the scale is - * reversed to the previous - * one. You may use it by - * setting the - * <tt>color_function</tt> - * variable to the address of - * this function. + * This is one more alternative color function producing a grey + * scale between white (lowest values) and black (highest values), + * i.e. the scale is reversed to the previous one. You may use it + * by setting the #color_function variable to the address of this + * function. */ static RgbValues reverse_grey_scale_color_function (const double value, @@ -1012,51 +810,37 @@ public: const ColorFunction color_function= &default_color_function); /** - * Declare all flags with name - * and type as offered by this - * class, for use in input files. + * Declare all flags with name and type as offered by this class, + * for use in input files. * - * For coloring, only the color - * functions declared in this - * class are offered. + * For coloring, only the color functions declared in this class + * are offered. */ static void declare_parameters (ParameterHandler &prm); /** - * Read the parameters declared in - * <tt>declare_parameters</tt> and set the - * flags for this output format - * accordingly. + * Read the parameters declared in declare_parameters() and set + * the flags for this output format accordingly. * - * The flags thus obtained overwrite - * all previous contents of this object. + * The flags thus obtained overwrite all previous contents of this + * object. */ void parse_parameters (const ParameterHandler &prm); /** - * Determine an estimate for - * the memory consumption (in - * bytes) of this - * object. Since sometimes - * the size of objects can - * not be determined exactly - * (for example: what is the - * memory consumption of an - * STL <tt>std::map</tt> type with a - * certain number of - * elements?), this is only - * an estimate. however often - * quite close to the true - * value. + * Determine an estimate for the memory consumption (in bytes) of + * this object. Since sometimes the size of objects can not be + * determined exactly (for example: what is the memory consumption + * of an STL <tt>std::map</tt> type with a certain number of + * elements?), this is only an estimate. however often quite close + * to the true value. */ std::size_t memory_consumption () const; }; /** - * Flags controlling the details - * of output in GMV - * format. At present no flags - * are implemented. + * Flags controlling the details of output in GMV format. At present + * no flags are implemented. * * @ingroup output */ @@ -1064,12 +848,9 @@ public: { private: /** - * Dummy entry to suppress compiler - * warnings when copying an empty - * structure. Remove this member - * when adding the first flag to - * this structure (and remove the - * <tt>private</tt> as well). + * Dummy entry to suppress compiler warnings when copying an empty + * structure. Remove this member when adding the first flag to + * this structure (and remove the <tt>private</tt> as well). */ int dummy; @@ -1080,46 +861,33 @@ public: GmvFlags (); /** - * Declare all flags with name - * and type as offered by this - * class, for use in input files. + * Declare all flags with name and type as offered by this class, + * for use in input files. */ static void declare_parameters (ParameterHandler &prm); /** - * Read the parameters declared in - * <tt>declare_parameters</tt> and set the - * flags for this output format - * accordingly. + * Read the parameters declared in declare_parameters() and set + * the flags for this output format accordingly. * - * The flags thus obtained overwrite - * all previous contents of this object. + * The flags thus obtained overwrite all previous contents of this + * object. */ void parse_parameters (const ParameterHandler &prm) const; /** - * Determine an estimate for - * the memory consumption (in - * bytes) of this - * object. Since sometimes - * the size of objects can - * not be determined exactly - * (for example: what is the - * memory consumption of an - * STL <tt>std::map</tt> type with a - * certain number of - * elements?), this is only - * an estimate. however often - * quite close to the true - * value. + * Determine an estimate for the memory consumption (in bytes) of + * this object. Since sometimes the size of objects can not be + * determined exactly (for example: what is the memory consumption + * of an STL <tt>std::map</tt> type with a certain number of + * elements?), this is only an estimate. however often quite close + * to the true value. */ std::size_t memory_consumption () const; }; /** - * Flags controlling the details - * of output in - * Tecplot format. + * Flags controlling the details of output in Tecplot format. * * @ingroup output */ @@ -1129,20 +897,16 @@ public: public: /** - * This variable is needed to hold the - * output file name when using the - * Tecplot API to write binary files. - * If the user doesn't set the file - * name with this variable only - * ASCII Tecplot output will be - * produced. + * This variable is needed to hold the output file name when using + * the Tecplot API to write binary files. If the user doesn't set + * the file name with this variable only ASCII Tecplot output will + * be produced. */ const char *tecplot_binary_file_name; /** - * Tecplot allows to assign - * names to zones. This - * variable stores this name. + * Tecplot allows to assign names to zones. This variable stores + * this name. */ const char *zone_name; @@ -1153,46 +917,33 @@ public: const char *zone_name = NULL); /** - * Declare all flags with name - * and type as offered by this - * class, for use in input files. + * Declare all flags with name and type as offered by this class, + * for use in input files. */ static void declare_parameters (ParameterHandler &prm); /** - * Read the parameters declared in - * <tt>declare_parameters</tt> and set the - * flags for this output format - * accordingly. + * Read the parameters declared in declare_parameters() and set + * the flags for this output format accordingly. * - * The flags thus obtained overwrite - * all previous contents of this object. + * The flags thus obtained overwrite all previous contents of this + * object. */ void parse_parameters (const ParameterHandler &prm) const; /** - * Determine an estimate for - * the memory consumption (in - * bytes) of this - * object. Since sometimes - * the size of objects can - * not be determined exactly - * (for example: what is the - * memory consumption of an - * STL <tt>std::map</tt> type with a - * certain number of - * elements?), this is only - * an estimate. however often - * quite close to the true - * value. + * Determine an estimate for the memory consumption (in bytes) of + * this object. Since sometimes the size of objects can not be + * determined exactly (for example: what is the memory consumption + * of an STL <tt>std::map</tt> type with a certain number of + * elements?), this is only an estimate. however often quite close + * to the true value. */ std::size_t memory_consumption () const; }; /** - * Flags controlling the details - * of output in VTK - * format. + * Flags controlling the details of output in VTK format. * * @ingroup output */ @@ -1200,32 +951,33 @@ public: { public: /** - * The time of the time step if this file is part of a - * time dependent simulation. + * The time of the time step if this file is part of a time + * dependent simulation. * - * The value of this variable is written into the output file according - * to the instructions provided in + * The value of this variable is written into the output file + * according to the instructions provided in * http://www.visitusers.org/index.php?title=Time_and_Cycle_in_VTK_files - * unless it is at its default value of std::numeric_limits<double>::min(). + * unless it is at its default value of + * std::numeric_limits<double>::min(). */ double time; /** - * The number of the time step if this file is part of a - * time dependent simulation, or the cycle within a nonlinear or other + * The number of the time step if this file is part of a time + * dependent simulation, or the cycle within a nonlinear or other * iteration. * - * The value of this variable is written into the output file according - * to the instructions provided in + * The value of this variable is written into the output file + * according to the instructions provided in * http://www.visitusers.org/index.php?title=Time_and_Cycle_in_VTK_files - * unless it is at its default value of std::numeric_limits<unsigned int>::min(). + * unless it is at its default value of + * std::numeric_limits<unsigned int>::min(). */ unsigned int cycle; /** - * Flag to determine whether the current - * date and time shall be printed as a comment - * in the file's second line. + * Flag to determine whether the current date and time shall be + * printed as a comment in the file's second line. * * Default is <tt>true</tt>. */ @@ -1239,9 +991,8 @@ public: const bool print_date_and_time = true); /** - * Declare the flags with name - * and type as offered by this - * class, for use in input files. + * Declare the flags with name and type as offered by this class, + * for use in input files. * * Unlike the flags in many of the other classes similar to this one, we do * not actually declare parameters for the #cycle and #time member variables @@ -1254,31 +1005,21 @@ public: static void declare_parameters (ParameterHandler &prm); /** - * Read the parameters declared in - * <tt>declare_parameters</tt> and set the - * flags for this output format - * accordingly. + * Read the parameters declared in declare_parameters() and + * set the flags for this output format accordingly. * - * The flags thus obtained overwrite - * all previous contents of this object. + * The flags thus obtained overwrite all previous contents of this + * object. */ void parse_parameters (const ParameterHandler &prm) const; /** - * Determine an estimate for - * the memory consumption (in - * bytes) of this - * object. Since sometimes - * the size of objects can - * not be determined exactly - * (for example: what is the - * memory consumption of an - * STL <tt>std::map</tt> type with a - * certain number of - * elements?), this is only - * an estimate. however often - * quite close to the true - * value. + * Determine an estimate for the memory consumption (in bytes) of + * this object. Since sometimes the size of objects can not be + * determined exactly (for example: what is the memory consumption + * of an STL <tt>std::map</tt> type with a certain number of + * elements?), this is only an estimate. however often quite close + * to the true value. */ std::size_t memory_consumption () const; }; @@ -1290,37 +1031,45 @@ public: struct SvgFlags { public: - /** - * This denotes the number of the - * data vector which shall be used - * for generating the height - * information. By default, the - * first data vector is taken, - * i.e. <tt>height_vector==0</tt>, if - * there is any data vector. If there - * is no data vector, no height + /** + * Height of the image in SVG + * units. Default value is 4000. + */ + unsigned int height; + + /** + * Width of the image in SVG + units. If left zero, the width is computed from the height. + */ + unsigned int width; + + /** + * This denotes the number of the data vector which shall be used + * for generating the height information. By default, the first + * data vector is taken, i.e. <tt>#height_vector==0</tt>, if there + * is any data vector. If there is no data vector, no height * information is generated. */ - unsigned int height_vector; - - /* + unsigned int height_vector; + + /** * Angles for the perspective view */ int azimuth_angle, polar_angle; unsigned int line_thickness; - /* + /** * Draw a margin of 5% around the plotted area */ bool margin; - /* + /** * Draw a colorbar encoding the cell coloring */ bool draw_colorbar; - /* + /** * Constructor. */ SvgFlags(const unsigned int height_vector = 0, @@ -1331,20 +1080,12 @@ public: const bool draw_colorbar = true); /** - * Determine an estimate for - * the memory consumption (in - * bytes) of this - * object. Since sometimes - * the size of objects can - * not be determined exactly - * (for example: what is the - * memory consumption of an - * STL <tt>std::map</tt> type with a - * certain number of - * elements?), this is only - * an estimate. however often - * quite close to the true - * value. + * Determine an estimate for the memory consumption (in bytes) of + * this object. Since sometimes the size of objects can not be + * determined exactly (for example: what is the memory consumption + * of an STL <tt>std::map</tt> type with a certain number of + * elements?), this is only an estimate. however often quite close + * to the true value. */ std::size_t memory_consumption () const; @@ -1354,38 +1095,26 @@ public: /** - * Flags controlling the details - * of output in deal.II - * intermediate format. At - * present no flags are - * implemented. + * Flags controlling the details of output in deal.II intermediate + * format. At present no flags are implemented. * * @ingroup output */ struct Deal_II_IntermediateFlags { /** - * An indicator of the - * currect file format - * version used to write - * intermediate format. We do - * not attempt to be backward - * compatible, so this number - * is used only to verify - * that the format we are - * writing is what the - * current readers and - * writers understand. + * An indicator of the currect file format version used to write + * intermediate format. We do not attempt to be backward + * compatible, so this number is used only to verify that the + * format we are writing is what the current readers and writers + * understand. */ static const unsigned int format_version = 3; private: /** - * Dummy entry to suppress compiler - * warnings when copying an empty - * structure. Remove this member - * when adding the first flag to - * this structure (and remove the - * <tt>private</tt> as well). + * Dummy entry to suppress compiler warnings when copying an empty + * structure. Remove this member when adding the first flag to + * this structure (and remove the <tt>private</tt> as well). */ int dummy; @@ -1396,17 +1125,14 @@ public: Deal_II_IntermediateFlags (); /** - * Declare all flags with name - * and type as offered by this - * class, for use in input files. + * Declare all flags with name and type as offered by this class, + * for use in input files. */ static void declare_parameters (ParameterHandler &prm); /** - * Read the parameters declared in - * <tt>declare_parameters</tt> and set the - * flags for this output format - * accordingly. + * Read the parameters declared in declare_parameters() and + * set the flags for this output format accordingly. * * The flags thus obtained overwrite * all previous contents of this object. @@ -1414,34 +1140,24 @@ public: void parse_parameters (const ParameterHandler &prm) const; /** - * Determine an estimate for - * the memory consumption (in - * bytes) of this - * object. Since sometimes - * the size of objects can - * not be determined exactly - * (for example: what is the - * memory consumption of an - * STL <tt>std::map</tt> type with a - * certain number of - * elements?), this is only - * an estimate. however often - * quite close to the true - * value. + * Determine an estimate for the memory consumption (in bytes) of + * this object. Since sometimes the size of objects can not be + * determined exactly (for example: what is the memory consumption + * of an STL <tt>std::map</tt> type with a certain number of + * elements?), this is only an estimate. however often quite close + * to the true value. */ std::size_t memory_consumption () const; }; /** - * Provide a data type specifying - * the presently supported output + * Provide a data type specifying the presently supported output * formats. */ enum OutputFormat { /** - * Use the format already - * stored in the object. + * Use the format already stored in the object. */ default_format, /** @@ -1453,24 +1169,19 @@ public: */ dx, /** - * Output in the UCD format - * for AVS. + * Output in the UCD format for AVS. */ ucd, /** - * Output for the - * Gnuplot tool. + * Output for the Gnuplot tool. */ gnuplot, /** - * Output for the - * Povray - * raytracer. + * Output for the Povray raytracer. */ povray, /** - * Output in encapsulated - * PostScript. + * Output in encapsulated PostScript. */ eps, /** @@ -1478,56 +1189,46 @@ public: */ gmv, /** - * Output for - * Tecplot in text - * format. + * Output for Tecplot in text format. */ tecplot, /** - * Output for - * Tecplot in - * binary format. Faster - * and smaller than text - * format. + * Output for Tecplot in binary format. Faster and smaller than + * text format. */ tecplot_binary, /** - * Output in - * VTK format. + * Output in VTK format. */ vtk, /** - * Output in - * VTK format. + * Output in VTK format. */ vtu, /** - * Output in - * SVG format. + * Output in SVG format. */ svg, /** - * Output in deal.II - * intermediate format. + * Output in deal.II intermediate format. */ deal_II_intermediate, /** - * Output in - * HDF5 format. + * Output in HDF5 format. */ hdf5 }; /** - * Write the given list of patches to the output stream in - * OpenDX format. + * Write the given list of patches to the output stream in OpenDX + * format. * * Since OpenDX uses some kind of visual data flow oriented * programming language, some of these programs are provided in @@ -1544,15 +1245,15 @@ public: * Write the given list of patches to the output stream in eps format. * * Output in this format circumvents the use of auxiliary graphic - * programs converting some output format into a graphics format. This - * has the advantage that output is easy and fast, and the - * disadvantage that you have to give a whole bunch of parameters - * which determine the direction of sight, the mode of colorization, - * the scaling of the height axis, etc. (Of course, all these - * parameters have reasonable default values, which you may want to - * change from time to time.) At present, this format only supports - * output for two-dimensional data, with values in the third direction - * taken from a data vector. + * programs converting some output format into a graphics + * format. This has the advantage that output is easy and fast, and + * the disadvantage that you have to give a whole bunch of + * parameters which determine the direction of sight, the mode of + * colorization, the scaling of the height axis, etc. (Of course, + * all these parameters have reasonable default values, which you + * may want to change from time to time.) At present, this format + * only supports output for two-dimensional data, with values in the + * third direction taken from a data vector. * * Basically, output consists of the mesh and the cells in between * them. You can draw either of these, or both, or none if you are @@ -1982,71 +1683,49 @@ public: MPI_Comm comm); /** - * Given an input stream that contains - * data written by - * write_deal_II_intermediate, determine - * the <tt>dim</tt> and <tt>spacedim</tt> - * template parameters with which that - * function was called, and return them - * as a pair of values. + * Given an input stream that contains data written by + * write_deal_II_intermediate(), determine the <tt>dim</tt> and + * <tt>spacedim</tt> template parameters with which that function + * was called, and return them as a pair of values. * - * Note that this function eats a number - * of elements at the present position of - * the stream, and therefore alters - * it. In order to read from it using, - * for example, the DataOutReader class, - * you may wish to either reset the - * stream to its previous position, or - * close and reopen it. + * Note that this function eats a number of elements at the present + * position of the stream, and therefore alters it. In order to read + * from it using, for example, the DataOutReader class, you may wish + * to either reset the stream to its previous position, or close and + * reopen it. */ static std::pair<unsigned int, unsigned int> determine_intermediate_format_dimensions (std::istream &input); /** - * Return the <tt>OutputFormat</tt> - * value corresponding to the - * given string. If the string - * does not match any known - * format, an exception is - * thrown. - * - * Since this function does not - * need data from this object, it - * is static and can thus be - * called without creating an - * object of this class. Its main - * purpose is to allow a program - * to use any implemented output - * format without the need to - * extend the program's parser - * each time a new format is - * implemented. - * - * To get a list of presently - * available format names, - * e.g. to give it to the - * ParameterHandler class, - * use the function + * Return the OutputFormat value corresponding to the given + * string. If the string does not match any known format, an + * exception is thrown. + * + * Since this function does not need data from this object, it is + * static and can thus be called without creating an object of this + * class. Its main purpose is to allow a program to use any + * implemented output format without the need to extend the + * program's parser each time a new format is implemented. + * + * To get a list of presently available format names, e.g. to give + * it to the ParameterHandler class, use the function * get_output_format_names(). */ static OutputFormat parse_output_format (const std::string &format_name); /** - * Return a list of implemented - * output formats. The different - * names are separated by - * vertical bar signs (<tt>`|'</tt>) - * as used by the + * Return a list of implemented output formats. The different names + * are separated by vertical bar signs (<tt>`|'</tt>) as used by the * ParameterHandler classes. */ static std::string get_output_format_names (); /** - * Provide a function which tells us which - * suffix a file with a given output format - * usually has. At present the following - * formats are defined: + * Provide a function which tells us which suffix a file with a + * given output format usually has. At present the following formats + * are defined: * <ul> * <li> <tt>dx</tt>: <tt>.dx</tt> * <li> <tt>ucd</tt>: <tt>.inp</tt> @@ -2065,20 +1744,12 @@ public: static std::string default_suffix (const OutputFormat output_format); /** - * Determine an estimate for - * the memory consumption (in - * bytes) of this - * object. Since sometimes - * the size of objects can - * not be determined exactly - * (for example: what is the - * memory consumption of an - * STL <tt>std::map</tt> type with a - * certain number of - * elements?), this is only - * an estimate. however often - * quite close to the true - * value. + * Determine an estimate for the memory consumption (in bytes) of + * this object. Since sometimes the size of objects can not be + * determined exactly (for example: what is the memory consumption + * of an STL <tt>std::map</tt> type with a certain number of + * elements?), this is only an estimate. however often quite close + * to the true value. */ static std::size_t memory_consumption (); @@ -2093,9 +1764,7 @@ public: << "The number of points in this data set is " << arg1 << ", but we expected " << arg2 << " in each space direction."); /** - * An output function did not - * receive any patches for - * writing. + * An output function did not receive any patches for writing. */ DeclException0 (ExcNoPatches); /** @@ -2113,24 +1782,21 @@ public: //@} private: /** - * Write the coordinates of nodes - * in the desired format. + * Write the coordinates of nodes in the desired format. */ template <int dim, int spacedim, typename STREAM> static void write_nodes (const std::vector<Patch<dim,spacedim> > &patches, STREAM &out); /** - * Write the node numbers of a - * cell in the desired format. + * Write the node numbers of a cell in the desired format. */ template <int dim, int spacedim, typename STREAM> static void write_cells (const std::vector<Patch<dim,spacedim> > &patches, STREAM &out); /** - * Write data in the desired - * format. + * Write data in the desired format. */ template <int dim, int spacedim, class STREAM> static void write_data (const std::vector<Patch<dim,spacedim> > &patches, @@ -2155,8 +1821,8 @@ private: Point<3> camera_horizontal, float camera_focus); /** - * Function to compute the gradient parameters for - * a triangle with given values for the vertices. + * Function to compute the gradient parameters for a triangle with + * given values for the vertices. * * Used for svg output. */ @@ -2165,8 +1831,8 @@ private: /** * Class holding the data of one cell of a patch in two space * dimensions for output. It is the projection of a cell in - * three-dimensional space (two coordinates, one height value) - * to the direction of sight. + * three-dimensional space (two coordinates, one height value) to + * the direction of sight. */ class SvgCell { @@ -2181,10 +1847,8 @@ private: Point<3> vertices[4]; /** - * Depth into the picture, which - * is defined as the distance from - * an observer at an the origin in - * direction of the line of sight. + * Depth into the picture, which is defined as the distance from + * an observer at an the origin in direction of the line of sight. */ float depth; @@ -2197,21 +1861,17 @@ private: Point<2> projected_center; /** - * Comparison operator for - * sorting. + * Comparison operator for sorting. */ bool operator < (const SvgCell &) const; }; /** - * Class holding the data of one - * cell of a patch in two space - * dimensions for output. It is - * the projection of a cell in - * three-dimensional space (two - * coordinates, one height value) - * to the direction of sight. + * Class holding the data of one cell of a patch in two space + * dimensions for output. It is the projection of a cell in + * three-dimensional space (two coordinates, one height value) to + * the direction of sight. */ class EpsCell2d { @@ -2223,48 +1883,33 @@ private: Point<2> vertices[4]; /** - * Data value from which the actual - * colors will be computed by - * the colorization function stated - * in the <tt>EpsFlags</tt> class. + * Data value from which the actual colors will be computed by the + * colorization function stated in the <tt>EpsFlags</tt> class. */ float color_value; /** - * Depth into the picture, which - * is defined as the distance from - * an observer at an the origin in - * direction of the line of sight. + * Depth into the picture, which is defined as the distance from + * an observer at an the origin in direction of the line of sight. */ float depth; /** - * Comparison operator for - * sorting. + * Comparison operator for sorting. */ bool operator < (const EpsCell2d &) const; }; /** - * This is a helper function for - * the <tt>write_gmv</tt> - * function. There, the data in - * the patches needs to be copied - * around as output is one - * variable globally at a time, - * rather than all data on each - * vertex at a time. This copying - * around can be done detached - * from the main thread, and is - * thus moved into this separate - * function. + * This is a helper function for the write_gmv() function. There, + * the data in the patches needs to be copied around as output is + * one variable globally at a time, rather than all data on each + * vertex at a time. This copying around can be done detached from + * the main thread, and is thus moved into this separate function. * - * Note that because of the - * similarity of the formats, - * this function is also used by - * the Vtk and Tecplot output - * functions. + * Note that because of the similarity of the formats, this function + * is also used by the Vtk and Tecplot output functions. */ template <int dim, int spacedim> static void @@ -2286,9 +1931,9 @@ private: * * This class is thought as a base class to classes actually * generating data for output. It has two abstract virtual functions, - * <tt>get_patches</tt> and <tt>get_dataset_names</tt> which are to produce the data - * which is actually needed. These are the only functions that need to - * be overloaded by a derived class. In additional to that, it has a + * get_patches() and get_dataset_names() produce the data which is + * actually needed. These are the only functions that need to be + * overloaded by a derived class. In additional to that, it has a * function for each output format supported by the underlying base * class which gets the output data using these two virtual functions * and passes them to the raw output functions. @@ -2653,8 +2298,8 @@ public: * @endcode * * @note See DataOutBase::write_vtu or - * DataOutInterface::write_pvtu_record for - * writing solutions at each timestep. + * DataOutInterface::write_pvtu_record for writing solutions at each + * timestep. * * @note The second element of each pair, i.e., the file in which * the graphical data for each time is stored, may itself be again @@ -2668,18 +2313,12 @@ public: const std::vector<std::pair<double,std::string> > ×_and_names) const; /** - * This function is the exact - * equivalent of the - * write_pvtu_record() function - * but for the VisIt - * visualization program. See - * there for the purpose of this - * function. + * This function is the exact equivalent of the write_pvtu_record() + * function but for the VisIt visualization program. See there for + * the purpose of this function. * - * This function is documented - * in the "Creating a master file - * for parallel" section (section 5.7) - * of the "Getting data into VisIt" + * This function is documented in the "Creating a master file for + * parallel" section (section 5.7) of the "Getting data into VisIt" * report that can be found here: * https://wci.llnl.gov/codes/visit/2.0.0/GettingDataIntoVisIt2.0.0.pdf */ @@ -2687,32 +2326,21 @@ public: const std::vector<std::string> &piece_names) const; /** - * Obtain data through get_patches() - * and write it to <tt>out</tt> - * in SVG format. See - * DataOutBase::write_svg. + * Obtain data through get_patches() and write it to <tt>out</tt> in + * SVG format. See DataOutBase::write_svg. */ void write_svg(std::ostream &out) const; /** - * Obtain data through get_patches() - * and write it to <tt>out</tt> - * in deal.II intermediate - * format. See + * Obtain data through get_patches() and write it to <tt>out</tt> in + * deal.II intermediate format. See * DataOutBase::write_deal_II_intermediate. * - * Note that the intermediate - * format is what its name - * suggests: a direct - * representation of internal - * data. It isn't standardized - * and will change whenever we - * change our internal - * representation. You can only - * expect to process files - * written in this format using - * the same version of deal.II - * that was used for writing. + * Note that the intermediate format is what its name suggests: a + * direct representation of internal data. It isn't standardized and + * will change whenever we change our internal representation. You + * can only expect to process files written in this format using the + * same version of deal.II that was used for writing. */ void write_deal_II_intermediate (std::ostream &out) const; @@ -2743,211 +2371,147 @@ public: const OutputFormat output_format = default_format) const; /** - * Set the default format. The - * value set here is used - * anytime, output for format - * <tt>default_format</tt> is - * requested. + * Set the default format. The value set here is used anytime, + * output for format <tt>default_format</tt> is requested. */ void set_default_format (const OutputFormat default_format); /** - * Set the flags to be used for - * output in OpenDX format. + * Set the flags to be used for output in OpenDX format. */ void set_flags (const DXFlags &dx_flags); /** - * Set the flags to be used for - * output in UCD format. + * Set the flags to be used for output in UCD format. */ void set_flags (const UcdFlags &ucd_flags); /** - * Set the flags to be used for - * output in GNUPLOT format. + * Set the flags to be used for output in GNUPLOT format. */ void set_flags (const GnuplotFlags &gnuplot_flags); /** - * Set the flags to be used for - * output in POVRAY format. + * Set the flags to be used for output in POVRAY format. */ void set_flags (const PovrayFlags &povray_flags); /** - * Set the flags to be used for - * output in EPS output. + * Set the flags to be used for output in EPS output. */ void set_flags (const EpsFlags &eps_flags); /** - * Set the flags to be used for - * output in GMV format. + * Set the flags to be used for output in GMV format. */ void set_flags (const GmvFlags &gmv_flags); /** - * Set the flags to be used for - * output in Tecplot format. + * Set the flags to be used for output in Tecplot format. */ void set_flags (const TecplotFlags &tecplot_flags); /** - * Set the flags to be used for - * output in VTK format. + * Set the flags to be used for output in VTK format. */ void set_flags (const VtkFlags &vtk_flags); /** - * Set the flags to be used for - * output in SVG format. + * Set the flags to be used for output in SVG format. */ void set_flags (const SvgFlags &svg_flags); /** - * Set the flags to be used for output in - * deal.II intermediate format. + * Set the flags to be used for output in deal.II intermediate + * format. */ void set_flags (const Deal_II_IntermediateFlags &deal_II_intermediate_flags); /** - * A function that returns the same - * string as the respective function in - * the base class does; the only - * exception being that if the parameter - * is omitted, then the value for the - * present default format is returned, - * i.e. the correct suffix for the format - * that was set through - * set_default_format() or - * parse_parameters() before calling this - * function. + * A function that returns the same string as the respective + * function in the base class does; the only exception being that if + * the parameter is omitted, then the value for the present default + * format is returned, i.e. the correct suffix for the format that + * was set through set_default_format() or parse_parameters() before + * calling this function. */ std::string default_suffix (const OutputFormat output_format = default_format) const; /** - * Declare parameters for all - * output formats by declaring - * subsections within the - * parameter file for each output - * format and call the respective - * <tt>declare_parameters</tt> - * functions of the flag classes - * for each output format. - * - * Some of the declared - * subsections may not contain - * entries, if the respective - * format does not export any - * flags. - * - * Note that the top-level - * parameters denoting the number - * of subdivisions per patch and - * the output format are not - * declared, since they are only - * passed to virtual functions - * and are not stored inside - * objects of this type. You have - * to declare them yourself. + * Declare parameters for all output formats by declaring + * subsections within the parameter file for each output format and + * call the respective <tt>declare_parameters</tt> functions of the + * flag classes for each output format. + * + * Some of the declared subsections may not contain entries, if the + * respective format does not export any flags. + * + * Note that the top-level parameters denoting the number of + * subdivisions per patch and the output format are not declared, + * since they are only passed to virtual functions and are not + * stored inside objects of this type. You have to declare them + * yourself. */ static void declare_parameters (ParameterHandler &prm); /** - * Read the parameters declared - * in <tt>declare_parameters</tt> and - * set the flags for the output - * formats accordingly. + * Read the parameters declared in declare_parameters() and + * set the flags for the output formats accordingly. * - * The flags thus obtained - * overwrite all previous - * contents of the flag objects - * as default-constructed or set - * by the set_flags() function. + * The flags thus obtained overwrite all previous contents of the + * flag objects as default-constructed or set by the set_flags() + * function. */ void parse_parameters (ParameterHandler &prm); /** - * Determine an estimate for - * the memory consumption (in - * bytes) of this - * object. Since sometimes - * the size of objects can - * not be determined exactly - * (for example: what is the - * memory consumption of an - * STL <tt>std::map</tt> type with a - * certain number of - * elements?), this is only - * an estimate. however often - * quite close to the true - * value. + * Determine an estimate for the memory consumption (in bytes) of + * this object. Since sometimes the size of objects can not be + * determined exactly (for example: what is the memory consumption + * of an STL <tt>std::map</tt> type with a certain number of + * elements?), this is only an estimate. however often quite close + * to the true value. */ std::size_t memory_consumption () const; protected: /** - * This is the abstract function - * through which derived classes - * propagate preprocessed data in - * the form of Patch - * structures (declared in the - * base class DataOutBase) to - * the actual output - * function. You need to overload - * this function to allow the - * output functions to know what - * they shall print. + * This is the abstract function through which derived classes + * propagate preprocessed data in the form of Patch structures + * (declared in the base class DataOutBase) to the actual output + * function. You need to overload this function to allow the output + * functions to know what they shall print. */ virtual const std::vector<typename DataOutBase::Patch<dim,spacedim> > & get_patches () const = 0; /** - * Abstract virtual function - * through which the names of - * data sets are obtained by the - * output functions of the base - * class. + * Abstract virtual function through which the names of data sets + * are obtained by the output functions of the base class. */ virtual std::vector<std::string> get_dataset_names () const = 0; /** - * This functions returns - * information about how the - * individual components of - * output files that consist of - * more than one data set are to - * be interpreted. - * - * It returns a list of index - * pairs and corresponding name - * indicating which components of - * the output are to be - * considered vector-valued - * rather than just a collection - * of scalar data. The index - * pairs are inclusive; for - * example, if we have a Stokes - * problem in 2d with components - * (u,v,p), then the - * corresponding vector data - * range should be (0,1), and the - * returned list would consist of - * only a single element with a - * tuple such as (0,1,"velocity"). - * - * Since some of the derived - * classes do not know about - * vector data, this function has - * a default implementation that - * simply returns an empty - * string, meaning that all data - * is to be considered a + * This functions returns information about how the individual + * components of output files that consist of more than one data set + * are to be interpreted. + * + * It returns a list of index pairs and corresponding name + * indicating which components of the output are to be considered + * vector-valued rather than just a collection of scalar data. The + * index pairs are inclusive; for example, if we have a Stokes + * problem in 2d with components (u,v,p), then the corresponding + * vector data range should be (0,1), and the returned list would + * consist of only a single element with a tuple such as + * (0,1,"velocity"). + * + * Since some of the derived classes do not know about vector data, + * this function has a default implementation that simply returns an + * empty string, meaning that all data is to be considered a * collection of scalar fields. */ virtual @@ -2955,108 +2519,83 @@ protected: get_vector_data_ranges () const; /** - * The default number of - * subdivisions for patches. This - * is filled by parse_parameters() - * and should be obeyed by - * build_patches() in derived - * classes. + * The default number of subdivisions for patches. This is filled by + * parse_parameters() and should be obeyed by build_patches() in + * derived classes. */ unsigned int default_subdivisions; private: /** - * Standard output format. Use - * this format, if output format - * default_format is - * requested. It can be changed - * by the <tt>set_format</tt> function - * or in a parameter file. + * Standard output format. Use this format, if output format + * default_format is requested. It can be changed by the + * <tt>set_format</tt> function or in a parameter file. */ OutputFormat default_fmt; /** - * Flags to be used upon output - * of OpenDX data. Can be changed by - * using the <tt>set_flags</tt> - * function. + * Flags to be used upon output of OpenDX data. Can be changed by + * using the <tt>set_flags</tt> function. */ DXFlags dx_flags; /** - * Flags to be used upon output - * of UCD data. Can be changed by - * using the <tt>set_flags</tt> - * function. + * Flags to be used upon output of UCD data. Can be changed by using + * the <tt>set_flags</tt> function. */ UcdFlags ucd_flags; /** - * Flags to be used upon output - * of GNUPLOT data. Can be - * changed by using the - * <tt>set_flags</tt> function. + * Flags to be used upon output of GNUPLOT data. Can be changed by + * using the <tt>set_flags</tt> function. */ GnuplotFlags gnuplot_flags; /** - * Flags to be used upon output - * of POVRAY data. Can be changed - * by using the <tt>set_flags</tt> - * function. + * Flags to be used upon output of POVRAY data. Can be changed by + * using the <tt>set_flags</tt> function. */ PovrayFlags povray_flags; /** - * Flags to be used upon output - * of EPS data in one space - * dimension. Can be changed by - * using the <tt>set_flags</tt> + * Flags to be used upon output of EPS data in one space + * dimension. Can be changed by using the <tt>set_flags</tt> * function. */ EpsFlags eps_flags; /** - * Flags to be used upon output - * of gmv data in one space - * dimension. Can be changed by - * using the <tt>set_flags</tt> + * Flags to be used upon output of gmv data in one space + * dimension. Can be changed by using the <tt>set_flags</tt> * function. */ GmvFlags gmv_flags; /** - * Flags to be used upon output - * of Tecplot data in one space - * dimension. Can be changed by - * using the <tt>set_flags</tt> + * Flags to be used upon output of Tecplot data in one space + * dimension. Can be changed by using the <tt>set_flags</tt> * function. */ TecplotFlags tecplot_flags; /** - * Flags to be used upon output - * of vtk data in one space - * dimension. Can be changed by - * using the <tt>set_flags</tt> + * Flags to be used upon output of vtk data in one space + * dimension. Can be changed by using the <tt>set_flags</tt> * function. */ VtkFlags vtk_flags; /** - * Flags to be used upon output - * of svg data in one space - * dimension. Can be changed by - * using the <tt>set_flags</tt> + * Flags to be used upon output of svg data in one space + * dimension. Can be changed by using the <tt>set_flags</tt> * function. */ SvgFlags svg_flags; /** - * Flags to be used upon output of - * deal.II intermediate data in one space - * dimension. Can be changed by using the - * <tt>set_flags</tt> function. + * Flags to be used upon output of deal.II intermediate data in one + * space dimension. Can be changed by using the <tt>set_flags</tt> + * function. */ Deal_II_IntermediateFlags deal_II_intermediate_flags; }; @@ -3118,60 +2657,36 @@ class DataOutReader : public DataOutInterface<dim,spacedim> { public: /** - * Read a sequence of patches as - * written previously by - * <tt>DataOutBase::write_deal_II_intermediate</tt> - * and store them in the present - * object. This overwrites any - * previous content. + * Read a sequence of patches as written previously by + * <tt>DataOutBase::write_deal_II_intermediate</tt> and store them + * in the present object. This overwrites any previous content. */ void read (std::istream &in); /** - * This function can be used to - * merge the patches read by the - * other object into the patches - * that this present object - * stores. This is sometimes - * handy if one has, for example, - * a domain decomposition - * algorithm where each block is - * represented by a DoFHandler of - * its own, but one wants to - * output the solution on all the - * blocks at the same - * time. Alternatively, it may - * also be used for parallel - * programs, where each process - * only generates output for its - * share of the cells, even if - * all processes can see all - * cells. - * - * For this to work, the input - * files for the present object - * and the given argument need to - * have the same number of output - * vectors, and they need to use - * the same number of - * subdivisions per patch. The - * output will probably look - * rather funny if patches in + * This function can be used to merge the patches read by the other + * object into the patches that this present object stores. This is + * sometimes handy if one has, for example, a domain decomposition + * algorithm where each block is represented by a DoFHandler of its + * own, but one wants to output the solution on all the blocks at + * the same time. Alternatively, it may also be used for parallel + * programs, where each process only generates output for its share + * of the cells, even if all processes can see all cells. + * + * For this to work, the input files for the present object and the + * given argument need to have the same number of output vectors, + * and they need to use the same number of subdivisions per + * patch. The output will probably look rather funny if patches in * both objects overlap in space. * - * If you call read() for this - * object after merging in - * patches, the previous state is - * overwritten, and the merged-in - * patches are lost. + * If you call read() for this object after merging in patches, the + * previous state is overwritten, and the merged-in patches are + * lost. * - * This function will fail if - * either this or the other - * object did not yet set up any - * patches. + * This function will fail if either this or the other object did + * not yet set up any patches. * - * The use of this function is - * demonstrated in step-19. + * The use of this function is demonstrated in step-19. */ void merge (const DataOutReader<dim,spacedim> &other); @@ -3199,67 +2714,42 @@ public: protected: /** - * This is the function - * through which this class - * propagates preprocessed data in - * the form of Patch - * structures (declared in the - * base class DataOutBase) to - * the actual output - * function. + * This is the function through which this class propagates + * preprocessed data in the form of Patch structures (declared in + * the base class DataOutBase) to the actual output function. * - * It returns the patches as read - * the last time a stream was - * given to the read() function. + * It returns the patches as read the last time a stream was given + * to the read() function. */ virtual const std::vector<typename dealii::DataOutBase::Patch<dim,spacedim> > & get_patches () const; /** - * Abstract virtual function - * through which the names of - * data sets are obtained by the - * output functions of the base - * class. + * Abstract virtual function through which the names of data sets + * are obtained by the output functions of the base class. * - * Return the names of the - * variables as read the last - * time we read a file. + * Return the names of the variables as read the last time we read a + * file. */ virtual std::vector<std::string> get_dataset_names () const; /** - * This functions returns - * information about how the - * individual components of - * output files that consist of - * more than one data set are to - * be interpreted. - * - * It returns a list of index - * pairs and corresponding name - * indicating which components of - * the output are to be - * considered vector-valued - * rather than just a collection - * of scalar data. The index - * pairs are inclusive; for - * example, if we have a Stokes - * problem in 2d with components - * (u,v,p), then the - * corresponding vector data - * range should be (0,1), and the - * returned list would consist of - * only a single element with a - * tuple such as (0,1,"velocity"). - * - * Since some of the derived - * classes do not know about - * vector data, this function has - * a default implementation that - * simply returns an empty - * string, meaning that all data - * is to be considered a + * This functions returns information about how the individual + * components of output files that consist of more than one data set + * are to be interpreted. + * + * It returns a list of index pairs and corresponding name + * indicating which components of the output are to be considered + * vector-valued rather than just a collection of scalar data. The + * index pairs are inclusive; for example, if we have a Stokes + * problem in 2d with components (u,v,p), then the corresponding + * vector data range should be (0,1), and the returned list would + * consist of only a single element with a tuple such as + * (0,1,"velocity"). + * + * Since some of the derived classes do not know about vector data, + * this function has a default implementation that simply returns an + * empty string, meaning that all data is to be considered a * collection of scalar fields. */ virtual @@ -3268,20 +2758,15 @@ protected: private: /** - * Arrays holding the set of - * patches as well as the names - * of output variables, all of - * which we read from an input - * stream. + * Arrays holding the set of patches as well as the names of output + * variables, all of which we read from an input stream. */ std::vector<typename dealii::DataOutBase::Patch<dim,spacedim> > patches; std::vector<std::string> dataset_names; /** - * Information about whether - * certain components of the - * output field are to be - * considered vectors. + * Information about whether certain components of the output field + * are to be considered vectors. */ std::vector<std_cxx1x::tuple<unsigned int, unsigned int, std::string> > vector_data_ranges; diff --git a/deal.II/include/deal.II/base/parameter_handler.h b/deal.II/include/deal.II/base/parameter_handler.h index f6bfc184de..70712ea751 100644 --- a/deal.II/include/deal.II/base/parameter_handler.h +++ b/deal.II/include/deal.II/base/parameter_handler.h @@ -369,7 +369,8 @@ namespace Patterns /** - * This pattern matches a list of comma-separated values each of which + * This pattern matches a list of values separated by commas (or another + * string), each of which * have to match a pattern given to the constructor. With two additional * parameters, the number of elements this list has to have can be * specified. If none is specified, the list may have zero or more @@ -389,12 +390,14 @@ namespace Patterns * Constructor. Take the given parameter as the specification of valid * elements of the list. * - * The two other arguments can be used to denote minimal and maximal - * allowable lengths of the list. + * The three other arguments can be used to denote minimal and maximal + * allowable lengths of the list, and the string that is used as a + * separator between elements of the list. */ List (const PatternBase &base_pattern, const unsigned int min_elements = 0, - const unsigned int max_elements = max_int_value); + const unsigned int max_elements = max_int_value, + const std::string &separator = ","); /** * Destructor. @@ -461,6 +464,11 @@ namespace Patterns */ const unsigned int max_elements; + /** + * Separator between elements of the list. + */ + const std::string separator; + /** * Initial part of description */ @@ -474,7 +482,8 @@ namespace Patterns * pattern given to the constructor. For each entry of the map, * parameters have to be entered in the form <code>key: value</code>. In * other words, a map is described in the form - * <code>key1: value1, key2: value2, key3: value3, ...</code>. + * <code>key1: value1, key2: value2, key3: value3, ...</code>. A constructor + * argument allows to choose a delimiter between pairs other than the comma. * * With two additional parameters, the number of elements this list has * to have can be specified. If none is specified, the map may have zero @@ -494,13 +503,15 @@ namespace Patterns * Constructor. Take the given parameter as the specification of valid * elements of the list. * - * The two other arguments can be used to denote minimal and maximal - * allowable lengths of the list. + * The three other arguments can be used to denote minimal and maximal + * allowable lengths of the list as well as the separator used to delimit + * pairs of the map. */ Map (const PatternBase &key_pattern, const PatternBase &value_pattern, const unsigned int min_elements = 0, - const unsigned int max_elements = max_int_value); + const unsigned int max_elements = max_int_value, + const std::string &separator = ","); /** * Destructor. @@ -568,6 +579,11 @@ namespace Patterns */ const unsigned int max_elements; + /** + * Separator between elements of the list. + */ + const std::string separator; + /** * Initial part of description */ @@ -873,7 +889,7 @@ namespace Patterns * set Geometry = [0,1]x[0,3] * @endcode * Input may be sorted into subsection trees in order to give the input a - * logical structure. + * logical structure, and input files may include other files. * * The ParameterHandler class is discussed in detail in the @ref step_19 * "step-19" example program, and is used in more realistic situations in @@ -1018,9 +1034,23 @@ namespace Patterns * <tt>=</tt> sign. * * + * <h3>Including other input files</h3> + * + * An input file can include other include files using the syntax + * @code + * ... + * include some_other_file.prm + * ... + * @endcode + * The file so referenced is searched for relative to the current + * directory (not relative to the directory in which the including + * parameter file is located, since this is not known to all three + * versions of the read_input() function). + * + * * <h3>Reading data from input sources</h3> * - * In order to read input you can use three possibilities: reading from + * In order to read input there are three possibilities: reading from * an <tt>std::istream</tt> object, reading from a file of which the name * is given and reading from a string in memory in which the lines are * separated by <tt>@\n</tt> characters. These possibilities are used as @@ -1559,12 +1589,15 @@ public: virtual ~ParameterHandler (); /** - * Read input from a stream until stream returns <tt>eof</tt> condition - * or error. + * Read input from a stream until the stream returns the <tt>eof</tt> condition + * or error. The second argument can be used to denote the name of the file + * (if that's what the input stream represents) we are reading from; this + * is only used when creating output for error messages. * * Return whether the read was successful. */ - virtual bool read_input (std::istream &input); + virtual bool read_input (std::istream &input, + const std::string &filename = "input file"); /** * Read input from a file the name of which is given. The PathSearch @@ -1615,8 +1648,14 @@ public: * this class is asked to write out all declarations to a stream using * the print_parameters() function. * - * The function generates an exception if the default value doesn't match - * the given pattern. An entry can be declared more than once without + * The function generates an exception of type ExcValueDoesNotMatchPattern + * if the default value doesn't match the given pattern, using the C++ + * throw mechanism. However, this exception is only generated <i>after</i> + * the entry has been created; if you have code where no sensible default + * value for a parameter is possible, you can then catch and ignore this + * exception. + * + * @note An entry can be declared more than once without * generating an error, for example to override an earlier default value. */ void declare_entry (const std::string &entry, @@ -1923,7 +1962,8 @@ private: std::string get_current_full_path (const std::string &name) const; /** - * Scan one line of input. <tt>lineno</tt> is the number of the line + * Scan one line of input. <tt>input_filename</tt> and <tt>lineno</tt> + * are the name of the input file and the current number of the line * presently scanned (for the logs if there are messages). Return * <tt>false</tt> if line contained stuff that could not be understood, * the uppermost subsection was to be left by an <tt>END</tt> or @@ -1935,6 +1975,7 @@ private: * caller's variable is not changed. */ bool scan_line (std::string line, + const std::string &input_filename, const unsigned int lineno); friend class MultipleParameterLoop; diff --git a/deal.II/include/deal.II/dofs/dof_accessor.templates.h b/deal.II/include/deal.II/dofs/dof_accessor.templates.h index 8006dba0d0..989591f843 100644 --- a/deal.II/include/deal.II/dofs/dof_accessor.templates.h +++ b/deal.II/include/deal.II/dofs/dof_accessor.templates.h @@ -3492,6 +3492,7 @@ namespace internal template <class DH, bool lda> +inline TriaIterator<DoFAccessor<DH::dimension-1,DH,lda> > DoFCellAccessor<DH,lda>::face (const unsigned int i) const { @@ -3519,6 +3520,7 @@ DoFCellAccessor<DH,lda>::get_dof_indices (std::vector<types::global_dof_index> & } + template<class DH, bool lda> inline void DoFCellAccessor<DH,lda>::get_mg_dof_indices (std::vector<types::global_dof_index> &dof_indices) const @@ -3526,6 +3528,8 @@ void DoFCellAccessor<DH,lda>::get_mg_dof_indices (std::vector<types::global_dof_ DoFAccessor<dim, DH,lda>::get_mg_dof_indices (this->level (), dof_indices); } + + template<class DH, bool lda> inline void DoFCellAccessor<DH,lda>::set_mg_dof_indices (const std::vector<types::global_dof_index> &dof_indices) @@ -3534,6 +3538,7 @@ void DoFCellAccessor<DH,lda>::set_mg_dof_indices (const std::vector<types::globa } + template<class DH, bool lda> inline void DoFCellAccessor<DH,lda>::get_active_or_mg_dof_indices (std::vector<types::global_dof_index> &dof_indices) const @@ -3548,6 +3553,7 @@ void DoFCellAccessor<DH,lda>::get_active_or_mg_dof_indices (std::vector<types::g template <class DH, bool lda> template <class InputVector, typename number> +inline void DoFCellAccessor<DH,lda>::get_dof_values (const InputVector &values, Vector<number> &local_values) const @@ -3564,6 +3570,7 @@ DoFCellAccessor<DH,lda>::get_dof_values (const InputVector &values, template <class DH, bool lda> template <class InputVector, typename ForwardIterator> +inline void DoFCellAccessor<DH,lda>::get_dof_values (const InputVector &values, ForwardIterator local_values_begin, @@ -3579,6 +3586,7 @@ DoFCellAccessor<DH,lda>::get_dof_values (const InputVector &values, template <class DH, bool lda> template <class InputVector, typename ForwardIterator> +inline void DoFCellAccessor<DH,lda>::get_dof_values (const ConstraintMatrix &constraints, const InputVector &values, @@ -3596,6 +3604,7 @@ DoFCellAccessor<DH,lda>::get_dof_values (const ConstraintMatrix &constraints, template <class DH, bool lda> template <class OutputVector, typename number> +inline void DoFCellAccessor<DH,lda>::set_dof_values (const Vector<number> &local_values, OutputVector &values) const diff --git a/deal.II/include/deal.II/fe/component_mask.h b/deal.II/include/deal.II/fe/component_mask.h index 0661aa2c63..bb60046fc4 100644 --- a/deal.II/include/deal.II/fe/component_mask.h +++ b/deal.II/include/deal.II/fe/component_mask.h @@ -209,6 +209,11 @@ public: std::size_t memory_consumption () const; + /** + * Exception + */ + DeclException0 (ExcNoComponentSelected); + private: /** * The actual component mask. diff --git a/deal.II/include/deal.II/fe/fe_tools.h b/deal.II/include/deal.II/fe/fe_tools.h index 0722155e82..1cc390f751 100644 --- a/deal.II/include/deal.II/fe/fe_tools.h +++ b/deal.II/include/deal.II/fe/fe_tools.h @@ -160,7 +160,12 @@ namespace FETools * indices of each local block. If it is false, then the block sizes are * returned. * - * @todo Which way does this vector map the numbers? + * The vector <tt>renumbering</tt> will be indexed by the standard + * numbering of local degrees of freedom, namely first first vertex, + * then second vertex, after vertices lines, quads, and hexes. For + * each index, the entry indicates the index which this degree of + * freedom receives in a numbering scheme, where the first block is + * numbered completely before the second. */ template<int dim, int spacedim> void compute_block_renumbering ( diff --git a/deal.II/include/deal.II/fe/mapping_c1.h b/deal.II/include/deal.II/fe/mapping_c1.h index 85f900bf28..62bbafecda 100644 --- a/deal.II/include/deal.II/fe/mapping_c1.h +++ b/deal.II/include/deal.II/fe/mapping_c1.h @@ -37,7 +37,7 @@ DEAL_II_NAMESPACE_OPEN * * To use this class, make sure that the * Boundary::@p get_normals_at_vertices function is implemented - * for the users boundary object. + * for the user's boundary object. * * For more information about the <tt>spacedim</tt> template parameter * check the documentation of FiniteElement or the one of @@ -50,71 +50,46 @@ class MappingC1 : public MappingQ<dim,spacedim> { public: /** - * Constructor. Pass the fixed - * degree @p 3 down to the base - * class, as a cubic mapping - * suffices to generate a - * continuous mapping of the - * boundary. + * Constructor. Pass the fixed degree @p 3 down to the base class, as a + * cubic mapping suffices to generate a continuous mapping of the boundary. */ MappingC1 (); /** - * Return a pointer to a copy of the - * present object. The caller of this - * copy then assumes ownership of it. + * Return a pointer to a copy of the present object. The caller of this copy + * then assumes ownership of it. */ virtual Mapping<dim,spacedim> *clone () const; protected: /** - * For <tt>dim=2,3</tt>. Append the - * support points of all shape - * functions located on bounding - * lines to the vector - * @p a. Points located on the - * line but on vertices are not - * included. + * For <tt>dim=2,3</tt>. Append the support points of all shape functions + * located on bounding lines to the vector @p a. Points located on the line + * but on vertices are not included. * - * Needed by the - * <tt>compute_support_points_simple(laplace)</tt> - * functions. For <tt>dim=1</tt> this - * function is empty. + * Needed by the <tt>compute_support_points_simple(laplace)</tt> + * functions. For <tt>dim=1</tt> this function is empty. * - * This function chooses the - * respective points not such - * that they are interpolating - * the boundary (as does the base - * class), but rather such that - * the resulting cubic mapping is - * a continuous one. + * This function chooses the respective points not such that they are + * interpolating the boundary (as does the base class), but rather such that + * the resulting cubic mapping is a continuous one. */ virtual void add_line_support_points (const typename Triangulation<dim>::cell_iterator &cell, std::vector<Point<dim> > &a) const; /** - * For <tt>dim=3</tt>. Append the - * support points of all shape - * functions located on bounding - * faces (quads in 3d) to the - * vector @p a. Points located - * on the line but on vertices - * are not included. + * For <tt>dim=3</tt>. Append the support points of all shape functions + * located on bounding faces (quads in 3d) to the vector @p a. Points + * located on the line but on vertices are not included. * - * Needed by the - * @p compute_support_points_laplace - * function. For <tt>dim=1</tt> and 2 - * this function is empty. + * Needed by the @p compute_support_points_laplace function. For + * <tt>dim=1</tt> and 2 this function is empty. * - * This function chooses the - * respective points not such - * that they are interpolating - * the boundary (as does the base - * class), but rather such that - * the resulting cubic mapping is - * a continuous one. + * This function chooses the respective points not such that they are + * interpolating the boundary (as does the base class), but rather such that + * the resulting cubic mapping is a continuous one. */ virtual void add_quad_support_points(const typename Triangulation<dim>::cell_iterator &cell, diff --git a/deal.II/include/deal.II/fe/mapping_q.h b/deal.II/include/deal.II/fe/mapping_q.h index 484963727b..28e4aefcbf 100644 --- a/deal.II/include/deal.II/fe/mapping_q.h +++ b/deal.II/include/deal.II/fe/mapping_q.h @@ -32,9 +32,11 @@ template <int dim, typename POLY> class TensorProductPolynomials; /*@{*/ /** - * Mapping class that uses Qp-mappings on boundary cells. The mapping - * shape functions make use of tensor product polynomials with - * equidistant (on the unit cell) support points. + * Mapping class that uses Qp-mappings on boundary cells. The mapping shape + * functions make use of tensor product polynomials with unit cell support + * points equal to the points of the Gauss-Lobatto quadrature formula. These + * points give a well-conditioned interpolation also for very high orders and + * are therefore preferred over equidistant support points. * * For more details about Qp-mappings, see the `mapping' report at * <tt>deal.II/doc/reports/mapping_q/index.html</tt> in the `Reports' @@ -44,6 +46,10 @@ template <int dim, typename POLY> class TensorProductPolynomials; * check the documentation of FiniteElement or the one of * Triangulation. * + * @note Since the boundary description is closely tied to the unit cell + * support points, new boundary descriptions need to explicitly use the + * Gauss-Lobatto points. + * * @author Ralf Hartmann, 2000, 2001, 2005; Guido Kanschat 2000, 2001 */ template <int dim, int spacedim=dim> @@ -51,41 +57,25 @@ class MappingQ : public MappingQ1<dim,spacedim> { public: /** - * Constructor. @p p gives the - * degree of mapping polynomials - * on boundary cells. + * Constructor. @p p gives the degree of mapping polynomials on boundary + * cells. * - * The second argument determines - * whether the higher order - * mapping should also be used on - * interior cells. If its value - * is <code>false</code> (the - * default), the a lower-order - * mapping is used in the - * interior. This is sufficient - * for most cases where higher - * order mappings are only used - * to better approximate the - * boundary. In that case, cells - * bounded by straight lines are - * acceptable in the - * interior. However, there are - * cases where one would also - * like to use a higher order - * mapping in the interior. The - * MappingQEulerian class is one - * such case. + * The second argument determines whether the higher order mapping should + * also be used on interior cells. If its value is <code>false</code> (the + * default), the a lower-order mapping is used in the interior. This is + * sufficient for most cases where higher order mappings are only used to + * better approximate the boundary. In that case, cells bounded by straight + * lines are acceptable in the interior. However, there are cases where one + * would also like to use a higher order mapping in the interior. The + * MappingQEulerian class is one such case. */ MappingQ (const unsigned int p, const bool use_mapping_q_on_all_cells = false); /** - * Copy constructor. Performs a - * deep copy, i.e. duplicates - * what #tensor_pols points to - * instead of simply copying the - * #tensor_pols pointer as done - * by a default copy constructor. + * Copy constructor. Performs a deep copy, i.e. duplicates what #tensor_pols + * points to instead of simply copying the #tensor_pols pointer as done by a + * default copy constructor. */ MappingQ (const MappingQ<dim,spacedim> &mapping); @@ -95,10 +85,8 @@ public: virtual ~MappingQ (); /** - * Transforms the point @p p on - * the unit cell to the point - * @p p_real on the real cell - * @p cell and returns @p p_real. + * Transforms the point @p p on the unit cell to the point @p p_real on the + * real cell @p cell and returns @p p_real. */ virtual Point<spacedim> transform_unit_to_real_cell ( @@ -106,46 +94,25 @@ public: const Point<dim> &p) const; /** - * Transforms the point @p p on - * the real cell to the point - * @p p_unit on the unit cell - * @p cell and returns @p p_unit. + * Transforms the point @p p on the real cell to the point @p p_unit on the + * unit cell @p cell and returns @p p_unit. * - * Uses Newton iteration and the - * @p transform_unit_to_real_cell - * function. + * Uses Newton iteration and the @p transform_unit_to_real_cell function. * - * In the codimension one case, - * this function returns the - * normal projection of the real - * point @p p on the curve or - * surface identified by the @p - * cell. + * In the codimension one case, this function returns the normal projection + * of the real point @p p on the curve or surface identified by the @p cell. * - * @note Polynomial mappings from - * the reference (unit) cell coordinates - * to the coordinate system of a real - * cell are not always invertible if - * the point for which the inverse - * mapping is to be computed lies - * outside the cell's boundaries. - * In such cases, the current function - * may fail to compute a point on - * the reference cell whose image - * under the mapping equals the given - * point @p p. If this is the case - * then this function throws an - * exception of type - * Mapping::ExcTransformationFailed . - * Whether the given point @p p lies - * outside the cell can therefore be - * determined by checking whether the - * return reference coordinates lie - * inside of outside the reference - * cell (e.g., using - * GeometryInfo::is_inside_unit_cell) - * or whether the exception mentioned - * above has been thrown. + * @note Polynomial mappings from the reference (unit) cell coordinates to + * the coordinate system of a real cell are not always invertible if the + * point for which the inverse mapping is to be computed lies outside the + * cell's boundaries. In such cases, the current function may fail to + * compute a point on the reference cell whose image under the mapping + * equals the given point @p p. If this is the case then this function + * throws an exception of type Mapping::ExcTransformationFailed . Whether + * the given point @p p lies outside the cell can therefore be determined by + * checking whether the return reference coordinates lie inside of outside + * the reference cell (e.g., using GeometryInfo::is_inside_unit_cell) or + * whether the exception mentioned above has been thrown. */ virtual Point<dim> transform_real_to_unit_cell ( @@ -172,23 +139,20 @@ public: const MappingType type) const; /** - * Return the degree of the - * mapping, i.e. the value which - * was passed to the constructor. + * Return the degree of the mapping, i.e. the value which was passed to the + * constructor. */ unsigned int get_degree () const; /** - * Return a pointer to a copy of the - * present object. The caller of this - * copy then assumes ownership of it. + * Return a pointer to a copy of the present object. The caller of this copy + * then assumes ownership of it. */ virtual Mapping<dim,spacedim> *clone () const; /** - * Storage for internal data of - * Q_degree transformation. + * Storage for internal data of Q_degree transformation. */ class InternalData : public MappingQ1<dim,spacedim>::InternalData { @@ -200,50 +164,35 @@ public: /** - * Return an estimate (in - * bytes) or the memory - * consumption of this - * object. + * Return an estimate (in bytes) or the memory consumption of this object. */ virtual std::size_t memory_consumption () const; /** - * Unit normal vectors. Used - * for the alternative - * computation of the normal - * vectors. See doc of the - * @p alternative_normals_computation - * flag. + * Unit normal vectors. Used for the alternative computation of the normal + * vectors. See doc of the @p alternative_normals_computation flag. * - * Filled (hardcoded) once in - * @p get_face_data. + * Filled (hardcoded) once in @p get_face_data. */ std::vector<std::vector<Point<dim> > > unit_normals; /** - * Flag that is set by the - * <tt>fill_fe_[[sub]face]_values</tt> - * function. + * Flag that is set by the <tt>fill_fe_[[sub]face]_values</tt> function. * - * If this flag is @p true - * we are on an interior cell - * and the - * @p mapping_q1_data is - * used. + * If this flag is @p true we are on an interior cell and the @p + * mapping_q1_data is used. */ bool use_mapping_q1_on_current_cell; /** - * On interior cells - * @p MappingQ1 is used. + * On interior cells @p MappingQ1 is used. */ typename MappingQ1<dim,spacedim>::InternalData mapping_q1_data; }; protected: /** - * Implementation of the interface in - * Mapping. + * Implementation of the interface in Mapping. */ virtual void fill_fe_values (const typename Triangulation<dim,spacedim>::cell_iterator &cell, @@ -258,8 +207,7 @@ protected: CellSimilarity::Similarity &cell_similarity) const ; /** - * Implementation of the interface in - * Mapping. + * Implementation of the interface in Mapping. */ virtual void fill_fe_face_values (const typename Triangulation<dim,spacedim>::cell_iterator &cell, @@ -272,8 +220,7 @@ protected: typename std::vector<Point<spacedim> > &normal_vectors) const ; /** - * Implementation of the interface in - * Mapping. + * Implementation of the interface in Mapping. */ virtual void fill_fe_subface_values (const typename Triangulation<dim,spacedim>::cell_iterator &cell, @@ -287,55 +234,32 @@ protected: typename std::vector<Point<spacedim> > &normal_vectors) const ; /** - * For <tt>dim=2,3</tt>. Append the - * support points of all shape - * functions located on bounding - * lines to the vector - * @p a. Points located on the - * line but not on vertices are not - * included. + * For <tt>dim=2,3</tt>. Append the support points of all shape functions + * located on bounding lines to the vector @p a. Points located on the line + * but not on vertices are not included. * - * Needed by the - * @p compute_support_points_laplace - * function . For <tt>dim=1</tt> this - * function is empty. + * Needed by the @p compute_support_points_laplace function . For + * <tt>dim=1</tt> this function is empty. * - * This function is made virtual - * in order to allow derived - * classes to choose shape - * function support points - * differently than the present - * class, which chooses the - * points as interpolation points - * on the boundary. + * This function is made virtual in order to allow derived classes to choose + * shape function support points differently than the present class, which + * chooses the points as interpolation points on the boundary. */ virtual void add_line_support_points (const typename Triangulation<dim,spacedim>::cell_iterator &cell, std::vector<Point<spacedim> > &a) const; /** - * For <tt>dim=3</tt>. Append the - * support points of all shape - * functions located on bounding - * faces (quads in 3d) to the - * vector @p a. Points located - * on the quad but not on vertices - * are not included. + * For <tt>dim=3</tt>. Append the support points of all shape functions + * located on bounding faces (quads in 3d) to the vector @p a. Points + * located on the quad but not on vertices are not included. * - * Needed by the - * @p compute_support_points_laplace - * function. For <tt>dim=1</tt> and - * <tt>dim=2</tt> this function is - * empty. + * Needed by the @p compute_support_points_laplace function. For + * <tt>dim=1</tt> and <tt>dim=2</tt> this function is empty. * - * This function is made virtual - * in order to allow derived - * classes to choose shape - * function support points - * differently than the present - * class, which chooses the - * points as interpolation points - * on the boundary. + * This function is made virtual in order to allow derived classes to choose + * shape function support points differently than the present class, which + * chooses the points as interpolation points on the boundary. */ virtual void add_quad_support_points(const typename Triangulation<dim,spacedim>::cell_iterator &cell, @@ -359,145 +283,99 @@ private: const Quadrature<dim-1>& quadrature) const; /** - * Compute shape values and/or - * derivatives. + * Compute shape values and/or derivatives. */ virtual void compute_shapes_virtual (const std::vector<Point<dim> > &unit_points, typename MappingQ1<dim,spacedim>::InternalData &data) const; /** - * This function is needed by the - * constructor of <tt>MappingQ<dim,spacedim></tt> - * for <tt>dim=</tt> 2 and 3. + * This function is needed by the constructor of + * <tt>MappingQ<dim,spacedim></tt> for <tt>dim=</tt> 2 and 3. * - * For <tt>degree<4</tt> this function - * sets the - * @p laplace_on_quad_vector to - * the hardcoded data. For - * <tt>degree>=4</tt> and MappingQ<2> - * this vector is computed. + * For <tt>degree<4</tt> this function sets the @p laplace_on_quad_vector to + * the hardcoded data. For <tt>degree>=4</tt> and MappingQ<2> this vector is + * computed. * - * For the definition of the - * @p laplace_on_quad_vector - * please refer to equation (8) - * of the `mapping' report. + * For the definition of the @p laplace_on_quad_vector please refer to + * equation (8) of the `mapping' report. */ void set_laplace_on_quad_vector(Table<2,double> &loqvs) const; /** - * This function is needed by the - * constructor of <tt>MappingQ<3></tt>. + * This function is needed by the constructor of <tt>MappingQ<3></tt>. * - * For <tt>degree==2</tt> this function - * sets the - * @p laplace_on_hex_vector to - * the hardcoded data. For - * <tt>degree>2</tt> this vector is - * computed. + * For <tt>degree==2</tt> this function sets the @p laplace_on_hex_vector to + * the hardcoded data. For <tt>degree>2</tt> this vector is computed. * - * For the definition of the - * @p laplace_on_hex_vector - * please refer to equation (8) - * of the `mapping' report. + * For the definition of the @p laplace_on_hex_vector please refer to + * equation (8) of the `mapping' report. */ void set_laplace_on_hex_vector(Table<2,double> &lohvs) const; /** - * Computes the - * <tt>laplace_on_quad(hex)_vector</tt>. + * Computes the <tt>laplace_on_quad(hex)_vector</tt>. * - * Called by the - * <tt>set_laplace_on_quad(hex)_vector</tt> - * functions if the data is not - * yet hardcoded. + * Called by the <tt>set_laplace_on_quad(hex)_vector</tt> functions if the + * data is not yet hardcoded. * - * For the definition of the - * <tt>laplace_on_quad(hex)_vector</tt> - * please refer to equation (8) - * of the `mapping' report. + * For the definition of the <tt>laplace_on_quad(hex)_vector</tt> please + * refer to equation (8) of the `mapping' report. */ void compute_laplace_vector(Table<2,double> &lvs) const; /** - * Takes a - * <tt>laplace_on_hex(quad)_vector</tt> - * and applies it to the vector - * @p a to compute the inner - * support points as a linear - * combination of the exterior - * points. + * Takes a <tt>laplace_on_hex(quad)_vector</tt> and applies it to the vector + * @p a to compute the inner support points as a linear combination of the + * exterior points. * - * The vector @p a initially - * contains the locations of the - * @p n_outer points, the - * @p n_inner computed inner - * points are appended. + * The vector @p a initially contains the locations of the @p n_outer + * points, the @p n_inner computed inner points are appended. * - * See equation (7) of the - * `mapping' report. + * See equation (7) of the `mapping' report. */ void apply_laplace_vector(const Table<2,double> &lvs, std::vector<Point<spacedim> > &a) const; /** - * Computes the support points of - * the mapping. + * Computes the support points of the mapping. */ virtual void compute_mapping_support_points( const typename Triangulation<dim,spacedim>::cell_iterator &cell, std::vector<Point<spacedim> > &a) const; /** - * Computes all support points of - * the mapping shape - * functions. The inner support - * points (ie. support points in - * quads for 2d, in hexes for 3d) - * are computed using the - * solution of a Laplace equation - * with the position of the outer - * support points as boundary - * values, in order to make the - * transformation as smooth as - * possible. + * Computes all support points of the mapping shape functions. The inner + * support points (ie. support points in quads for 2d, in hexes for 3d) are + * computed using the solution of a Laplace equation with the position of + * the outer support points as boundary values, in order to make the + * transformation as smooth as possible. */ void compute_support_points_laplace( const typename Triangulation<dim,spacedim>::cell_iterator &cell, std::vector<Point<spacedim> > &a) const; /** - * Needed by the - * @p laplace_on_quad function - * (for <tt>dim==2</tt>). Filled by the - * constructor. + * Needed by the @p laplace_on_quad function (for <tt>dim==2</tt>). Filled + * by the constructor. * * Sizes: - * laplace_on_quad_vector.size()= - * number of inner - * unit_support_points - * laplace_on_quad_vector[i].size()= - * number of outer - * unit_support_points, i.e. - * unit_support_points on the - * boundary of the quad + * laplace_on_quad_vector.size()= number of inner unit_support_points + * laplace_on_quad_vector[i].size()= number of outer unit_support_points, + * i.e. unit_support_points on the boundary of the quad * - * For the definition of this - * vector see equation (8) of the - * `mapping' report. + * For the definition of this vector see equation (8) of the `mapping' + * report. */ Table<2,double> laplace_on_quad_vector; /** - * Needed by the - * @p laplace_on_hex function - * (for <tt>dim==3</tt>). Filled by the - * constructor. + * Needed by the @p laplace_on_hex function (for <tt>dim==3</tt>). Filled by + * the constructor. * - * For the definition of this - * vector see equation (8) of the - * `mapping' report. + * For the definition of this vector see equation (8) of the `mapping' + * report. */ Table<2,double> laplace_on_hex_vector; @@ -509,69 +387,57 @@ private: << "laplace_vector not set for degree=" << arg1 << "."); /** - * Degree @p p of the - * polynomials used as shape - * functions for the Qp mapping + * Degree @p p of the polynomials used as shape functions for the Qp mapping * of cells at the boundary. */ const unsigned int degree; /** - * Number of inner mapping shape - * functions. + * Number of inner mapping shape functions. */ const unsigned int n_inner; /** - * Number of mapping shape - * functions on the boundary. + * Number of mapping shape functions on the boundary. */ const unsigned int n_outer; /** - * Pointer to the - * @p dim-dimensional tensor - * product polynomials used as - * shape functions for the Qp - * mapping of cells at the - * boundary. + * Pointer to the @p dim-dimensional tensor product polynomials used as + * shape functions for the Qp mapping of cells at the boundary. */ const TensorProductPolynomials<dim> *tensor_pols; /** - * Number of the Qp tensor - * product shape functions. + * Number of the Qp tensor product shape functions. */ const unsigned int n_shape_functions; /** - * Mapping from lexicographic to - * to the Qp shape function - * numbering. Its size is - * @p dofs_per_cell. + * Mapping from lexicographic to to the Qp shape function numbering. Its + * size is @p dofs_per_cell. */ const std::vector<unsigned int> renumber; /** - * If this flag is set @p true - * then @p MappingQ is used on - * all cells, not only on - * boundary cells. + * If this flag is set @p true then @p MappingQ is used on all cells, not + * only on boundary cells. */ const bool use_mapping_q_on_all_cells; /** - * An FE_Q object which is only needed in - * 3D, since it knows how to reorder shape - * functions/DoFs on non-standard - * faces. This is used to reorder support - * points in the same way. We could make - * this a pointer to prevent construction - * in 1D and 2D, but since memory and time - * requirements are not particularly high - * this seems unnecessary at the moment. + * An FE_Q object which is only needed in 3D, since it knows how to reorder + * shape functions/DoFs on non-standard faces. This is used to reorder + * support points in the same way. We could make this a pointer to prevent + * construction in 1D and 2D, but since memory and time requirements are not + * particularly high this seems unnecessary at the moment. */ const FE_Q<dim> feq; + + /** + * Declare other MappingQ classes friends. + */ + template <int,int> friend class MappingQ; }; /*@}*/ diff --git a/deal.II/include/deal.II/fe/mapping_q_eulerian.h b/deal.II/include/deal.II/fe/mapping_q_eulerian.h index 4d4ba9cc9c..f0a79f1066 100644 --- a/deal.II/include/deal.II/fe/mapping_q_eulerian.h +++ b/deal.II/include/deal.II/fe/mapping_q_eulerian.h @@ -95,25 +95,14 @@ class MappingQEulerian : public MappingQ<dim, spacedim> { public: /** - * Constructor. The first argument is - * the polynomical degree of the desired - * Qp mapping. It then takes a - * <tt>Vector<double> &</tt> to specify the - * transformation of the domain - * from the reference to - * the current configuration. - * The organization of the - * elements in the @p Vector - * must follow the concept how - * deal.II stores solutions that - * are associated to a - * triangulation. This is - * automatically the case if the - * @p Vector represents the - * solution of the previous step - * of a nonlinear problem. - * Alternatively, the @p Vector - * can be initialized by + * Constructor. The first argument is the polynomical degree of the desired + * Qp mapping. It then takes a <tt>Vector<double> &</tt> to specify the + * transformation of the domain from the reference to the current + * configuration. The organization of the elements in the @p Vector must + * follow the concept how deal.II stores solutions that are associated to a + * triangulation. This is automatically the case if the @p Vector + * represents the solution of the previous step of a nonlinear problem. + * Alternatively, the @p Vector can be initialized by * <tt>DoFAccessor::set_dof_values()</tt>. */ @@ -122,20 +111,16 @@ public: const DoFHandler<dim,spacedim> &euler_dof_handler); /** - * Return a pointer to a copy of the - * present object. The caller of this - * copy then assumes ownership of it. + * Return a pointer to a copy of the present object. The caller of this copy + * then assumes ownership of it. */ virtual Mapping<dim,spacedim> *clone () const; /** - * Always returns @p false because - * MappingQ1Eulerian does not in general - * preserve vertex locations (unless the - * translation vector happens to provide - * for zero displacements at vertex - * locations). + * Always returns @p false because MappingQ1Eulerian does not in general + * preserve vertex locations (unless the translation vector happens to + * provide for zero displacements at vertex locations). */ bool preserves_vertex_locations () const; @@ -146,10 +131,8 @@ public: protected: /** - * Implementation of the interface in - * MappingQ. Overrides the function in - * the base class, since we cannot use - * any cell similarity for this class. + * Implementation of the interface in MappingQ. Overrides the function in + * the base class, since we cannot use any cell similarity for this class. */ virtual void fill_fe_values (const typename Triangulation<dim,spacedim>::cell_iterator &cell, @@ -164,36 +147,29 @@ protected: CellSimilarity::Similarity &cell_similarity) const; /** - * Reference to the vector of - * shifts. + * Reference to the vector of shifts. */ SmartPointer<const VECTOR, MappingQEulerian<dim,VECTOR,spacedim> > euler_vector; /** - * Pointer to the DoFHandler to - * which the mapping vector is - * associated. + * Pointer to the DoFHandler to which the mapping vector is associated. */ - SmartPointer<const DoFHandler<dim,spacedim>,MappingQEulerian<dim,VECTOR,spacedim> > euler_dof_handler; private: /** - * Special quadrature rule used - * to define the support points - * in the reference configuration. + * Special quadrature rule used to define the support points in the + * reference configuration. */ class SupportQuadrature : public Quadrature<dim> { public: /** - * Constructor, with an argument - * defining the desired polynomial - * degree. + * Constructor, with an argument defining the desired polynomial degree. */ SupportQuadrature (const unsigned int map_degree); @@ -201,36 +177,26 @@ private: }; /** - * A member variable holding the - * quadrature points in the right - * order. + * A member variable holding the quadrature points in the right order. */ const SupportQuadrature support_quadrature; /** - * FEValues object used to query the - * the given finite element field - * at the support points in the - * reference configuration. + * FEValues object used to query the the given finite element field at the + * support points in the reference configuration. * - * The variable is marked as - * mutable since we have to call - * FEValues::reinit from - * compute_mapping_support_points, - * a function that is 'const'. + * The variable is marked as mutable since we have to call FEValues::reinit + * from compute_mapping_support_points, a function that is 'const'. */ mutable FEValues<dim,spacedim> fe_values; /** - * A variable to guard access to - * the fe_values variable. + * A variable to guard access to the fe_values variable. */ mutable Threads::Mutex fe_values_mutex; /** - * Compute the positions of the - * support points in the current - * configuration + * Compute the positions of the support points in the current configuration */ virtual void compute_mapping_support_points( const typename Triangulation<dim,spacedim>::cell_iterator &cell, diff --git a/deal.II/include/deal.II/grid/tria.h b/deal.II/include/deal.II/grid/tria.h index e74d18321d..994f59ef17 100644 --- a/deal.II/include/deal.II/grid/tria.h +++ b/deal.II/include/deal.II/grid/tria.h @@ -1593,7 +1593,7 @@ public: virtual void create_notification (const Triangulation<dim, spacedim> &tria); - }; // DEAL_II_DEPRECATED; + }; /** * A structure that is used as an diff --git a/deal.II/include/deal.II/grid/tria_boundary.h b/deal.II/include/deal.II/grid/tria_boundary.h index ba83065200..ca948550fc 100644 --- a/deal.II/include/deal.II/grid/tria_boundary.h +++ b/deal.II/include/deal.II/grid/tria_boundary.h @@ -22,6 +22,8 @@ #include <deal.II/base/config.h> #include <deal.II/base/subscriptor.h> +#include <deal.II/base/quadrature_lib.h> +#include <deal.II/base/thread_management.h> #include <deal.II/base/point.h> #include <deal.II/grid/tria.h> @@ -85,120 +87,75 @@ class Boundary : public Subscriptor public: /** - * Type keeping information about - * the normals at the vertices of - * a face of a cell. Thus, there - * are - * <tt>GeometryInfo<dim>::vertices_per_face</tt> - * normal vectors, that define - * the tangent spaces of the - * boundary at the vertices. Note - * that the vectors stored in - * this object are not required - * to be normalized, nor to - * actually point outward, as one - * often will only want to check - * for orthogonality to define - * the tangent plane; if a - * function requires the normals - * to be normalized, then it must - * do so itself. + * Type keeping information about the normals at the vertices of a face of a + * cell. Thus, there are <tt>GeometryInfo<dim>::vertices_per_face</tt> + * normal vectors, that define the tangent spaces of the boundary at the + * vertices. Note that the vectors stored in this object are not required to + * be normalized, nor to actually point outward, as one often will only want + * to check for orthogonality to define the tangent plane; if a function + * requires the normals to be normalized, then it must do so itself. * - * For obvious reasons, this - * type is not useful in 1d. + * For obvious reasons, this type is not useful in 1d. */ typedef Tensor<1,spacedim> FaceVertexNormals[GeometryInfo<dim>::vertices_per_face]; /** - * Destructor. Does nothing here, but - * needs to be declared to make it + * Destructor. Does nothing here, but needs to be declared to make it * virtual. */ virtual ~Boundary (); /** - * Return the point which shall - * become the new middle vertex - * of the two children of a - * regular line. In 2D, this line - * is a line at the boundary, - * while in 3d, it is bounding a - * face at the boundary (the - * lines therefore is also on the - * boundary). + * Return the point which shall become the new middle vertex of the two + * children of a regular line. In 2D, this line is a line at the boundary, + * while in 3d, it is bounding a face at the boundary (the lines therefore + * is also on the boundary). */ virtual Point<spacedim> get_new_point_on_line (const typename Triangulation<dim,spacedim>::line_iterator &line) const = 0; /** - * Return the point which shall - * become the common point of the - * four children of a quad at the - * boundary in three or more - * spatial dimensions. This - * function therefore is only - * useful in at least three - * dimensions and should not be - * called for lower dimensions. + * Return the point which shall become the common point of the four children + * of a quad at the boundary in three or more spatial dimensions. This + * function therefore is only useful in at least three dimensions and should + * not be called for lower dimensions. * - * This function is called after - * the four lines bounding the - * given @p quad are refined, so - * you may want to use the - * information provided by - * <tt>quad->line(i)->child(j)</tt>, - * <tt>i=0...3</tt>, <tt>j=0,1</tt>. + * This function is called after the four lines bounding the given @p quad + * are refined, so you may want to use the information provided by + * <tt>quad->line(i)->child(j)</tt>, <tt>i=0...3</tt>, <tt>j=0,1</tt>. * - * Because in 2D, this function - * is not needed, it is not made - * pure virtual, to avoid the - * need to overload it. The - * default implementation throws - * an error in any case, however. + * Because in 2D, this function is not needed, it is not made pure virtual, + * to avoid the need to overload it. The default implementation throws an + * error in any case, however. */ virtual Point<spacedim> get_new_point_on_quad (const typename Triangulation<dim,spacedim>::quad_iterator &quad) const; /** - * Depending on <tt>dim=2</tt> or - * <tt>dim=3</tt> this function - * calls the - * get_new_point_on_line or the - * get_new_point_on_quad - * function. It throws an - * exception for - * <tt>dim=1</tt>. This wrapper - * allows dimension independent + * Depending on <tt>dim=2</tt> or <tt>dim=3</tt> this function calls the + * get_new_point_on_line or the get_new_point_on_quad function. It throws an + * exception for <tt>dim=1</tt>. This wrapper allows dimension independent * programming. */ Point<spacedim> get_new_point_on_face (const typename Triangulation<dim,spacedim>::face_iterator &face) const; /** - * Return equally spaced - * intermediate points on a line. + * Return intermediate points on a line spaced according to the interior + * support points of the 1D Gauss-Lobatto quadrature formula. * - * The number of points requested - * is given by the size of the - * vector @p points. It is the - * task of the derived classes to - * arrange the points in + * The number of points requested is given by the size of the vector @p + * points. It is the task of the derived classes to arrange the points in * approximately equal distances. * - * This function is called by the - * @p MappingQ class. This - * happens on each face line of a - * cells that has got at least - * one boundary line. + * This function is called by the @p MappingQ class. This happens on each + * face line of a cells that has got at least one boundary line. * - * As this function is not needed - * for @p MappingQ1, it is not - * made pure virtual, to avoid - * the need to overload it. The - * default implementation throws - * an error in any case, however. + * As this function is not needed for @p MappingQ1, it is not made pure + * virtual, to avoid the need to overload it. The default implementation + * throws an error in any case, however. */ virtual void @@ -206,34 +163,23 @@ public: std::vector<Point<spacedim> > &points) const; /** - * Return equally spaced - * intermediate points on a - * boundary quad. + * Return intermediate points on a line spaced according to the tensor + * product of the interior support points of the 1D Gauss-Lobatto quadrature + * formula. * - * The number of points requested - * is given by the size of the - * vector @p points. It is - * required that this number is a - * square of another integer, - * i.e. <tt>n=points.size()=m*m</tt>. It - * is the task of the derived - * classes to arrange the points - * such they split the quad into - * <tt>(m+1)(m+1)</tt> approximately - * equal-sized subquads. + * The number of points requested is given by the size of the vector @p + * points. It is required that this number is a square of another integer, + * i.e. <tt>n=points.size()=m*m</tt>. It is the task of the derived classes + * to arrange the points such they split the quad into <tt>(m+1)(m+1)</tt> + * approximately equal-sized subquads. * - * This function is called by the - * <tt>MappingQ<3></tt> class. This - * happens each face quad of - * cells in 3d that has got at - * least one boundary face quad. + * This function is called by the <tt>MappingQ<3></tt> class. This happens + * each face quad of cells in 3d that has got at least one boundary face + * quad. * - * As this function is not needed - * for @p MappingQ1, it is not - * made pure virtual, to avoid - * the need to overload it. The - * default implementation throws - * an error in any case, however. + * As this function is not needed for @p MappingQ1, it is not made pure + * virtual, to avoid the need to overload it. The default implementation + * throws an error in any case, however. */ virtual void @@ -241,56 +187,36 @@ public: std::vector<Point<spacedim> > &points) const; /** - * Depending on <tt>dim=2</tt> or - * <tt>dim=3</tt> this function - * calls the - * get_intermediate_points_on_line - * or the - * get_intermediate_points_on_quad - * function. It throws an - * exception for - * <tt>dim=1</tt>. This wrapper - * allows dimension independent - * programming. + * Depending on <tt>dim=2</tt> or <tt>dim=3</tt> this function calls the + * get_intermediate_points_on_line or the get_intermediate_points_on_quad + * function. It throws an exception for <tt>dim=1</tt>. This wrapper allows + * dimension independent programming. */ void get_intermediate_points_on_face (const typename Triangulation<dim,spacedim>::face_iterator &face, std::vector<Point<spacedim> > &points) const; /** - * Return the normal vector to the surface - * at the point p. If p is not in fact - * on the surface, but only closeby, - * try to return something reasonable, - * for example the normal vector - * at the surface point closest to p. - * (The point p will in fact not normally - * lie on the actual surface, but rather - * be a quadrature point mapped by some - * polynomial mapping; the mapped surface, - * however, will not usually coincide with - * the actual surface.) + * Return the normal vector to the surface at the point p. If p is not in + * fact on the surface, but only close-by, try to return something + * reasonable, for example the normal vector at the surface point closest to + * p. (The point p will in fact not normally lie on the actual surface, but + * rather be a quadrature point mapped by some polynomial mapping; the + * mapped surface, however, will not usually coincide with the actual + * surface.) * - * The face iterator gives an indication - * which face this function is supposed - * to compute the normal vector for. - * This is useful if the boundary of - * the domain is composed of different - * nondifferential pieces (for example - * when using the StraightBoundary class - * to approximate a geometry that is - * completely described by the coarse mesh, - * with piecewise (bi-)linear components - * between the vertices, but where the - * boundary may have a kink at the vertices - * itself). + * The face iterator gives an indication which face this function is + * supposed to compute the normal vector for. This is useful if the + * boundary of the domain is composed of different nondifferential pieces + * (for example when using the StraightBoundary class to approximate a + * geometry that is completely described by the coarse mesh, with piecewise + * (bi-)linear components between the vertices, but where the boundary may + * have a kink at the vertices itself). * - * @note Implementations of this function - * should be able to assume that the point p - * lies within or close to the face described by the - * first argument. In turn, callers of this - * function should ensure that this is - * in fact the case. + * @note Implementations of this function should be able to assume that the + * point p lies within or close to the face described by the first + * argument. In turn, callers of this function should ensure that this is in + * fact the case. */ virtual Tensor<1,spacedim> @@ -298,32 +224,17 @@ public: const Point<spacedim> &p) const; /** - * Compute the normal vectors to - * the boundary at each vertex of - * the given face. It is not - * required that the normal - * vectors be normed - * somehow. Neither is it - * required that the normals - * actually point outward. + * Compute the normal vectors to the boundary at each vertex of the given + * face. It is not required that the normal vectors be normed + * somehow. Neither is it required that the normals actually point outward. * - * This function is - * needed to compute data for C1 - * mappings. The default - * implementation is to throw an - * error, so you need not - * overload this function in case - * you do not intend to use C1 - * mappings. + * This function is needed to compute data for C1 mappings. The default + * implementation is to throw an error, so you need not overload this + * function in case you do not intend to use C1 mappings. * - * Note that when computing - * normal vectors at a vertex - * where the boundary is not - * differentiable, you have to - * make sure that you compute the - * one-sided limits, i.e. limit - * with respect to points inside - * the given face. + * Note that when computing normal vectors at a vertex where the boundary is + * not differentiable, you have to make sure that you compute the one-sided + * limits, i.e. limit with respect to points inside the given face. */ virtual void @@ -331,35 +242,20 @@ public: FaceVertexNormals &face_vertex_normals) const; /** - * Given a candidate point and a - * line segment characterized by - * the iterator, return a point - * that lies on the surface - * described by this object. This - * function is used in some mesh - * smoothing algorithms that try - * to move around points in order - * to improve the mesh quality - * but need to ensure that points - * that were on the boundary - * remain on the boundary. + * Given a candidate point and a line segment characterized by the iterator, + * return a point that lies on the surface described by this object. This + * function is used in some mesh smoothing algorithms that try to move + * around points in order to improve the mesh quality but need to ensure + * that points that were on the boundary remain on the boundary. * - * If spacedim==1, then the line - * represented by the line - * iterator is the entire space - * (i.e. it is a cell, not a part - * of the boundary), and the - * returned point equals the - * given input point. + * If spacedim==1, then the line represented by the line iterator is the + * entire space (i.e. it is a cell, not a part of the boundary), and the + * returned point equals the given input point. * - * Derived classes do not need to - * implement this function unless - * mesh smoothing algorithms are - * used with a particular - * boundary object. The default - * implementation of this - * function throws an exception - * of type ExcPureFunctionCalled. + * Derived classes do not need to implement this function unless mesh + * smoothing algorithms are used with a particular boundary object. The + * default implementation of this function throws an exception of type + * ExcPureFunctionCalled. */ virtual Point<spacedim> @@ -367,19 +263,12 @@ public: const Point<spacedim> &candidate) const; /** - * Same function as above but for - * a point that is to be - * projected onto the area - * characterized by the given - * quad. + * Same function as above but for a point that is to be projected onto the + * area characterized by the given quad. * - * If spacedim<=2, then the surface - * represented by the quad - * iterator is the entire space - * (i.e. it is a cell, not a part - * of the boundary), and the - * returned point equals the - * given input point. + * If spacedim<=2, then the surface represented by the quad iterator is the + * entire space (i.e. it is a cell, not a part of the boundary), and the + * returned point equals the given input point. */ virtual Point<spacedim> @@ -387,24 +276,40 @@ public: const Point<spacedim> &candidate) const; /** - * Same function as above but for - * a point that is to be - * projected onto the area - * characterized by the given - * quad. + * Same function as above but for a point that is to be projected onto the + * area characterized by the given quad. * - * If spacedim<=3, then the manifold - * represented by the hex - * iterator is the entire space - * (i.e. it is a cell, not a part - * of the boundary), and the - * returned point equals the - * given input point. + * If spacedim<=3, then the manifold represented by the hex iterator is the + * entire space (i.e. it is a cell, not a part of the boundary), and the + * returned point equals the given input point. */ virtual Point<spacedim> project_to_surface (const typename Triangulation<dim,spacedim>::hex_iterator &hex, const Point<spacedim> &candidate) const; + +protected: + /** + * Returns the support points of the Gauss-Lobatto quadrature formula used + * for intermediate points. + * + * @note Since the boundary description is closely tied to the unit cell + * support points of MappingQ, new boundary descriptions need to explicitly + * use these Gauss-Lobatto points and not equidistant points. + */ + const std::vector<Point<1> > & + get_line_support_points (const unsigned int n_intermediate_points) const; + +private: + /** + * Point generator for the intermediate points on a boundary. + */ + mutable std::vector<std_cxx1x::shared_ptr<QGaussLobatto<1> > > points; + + /** + * Mutex for protecting the points array. + */ + mutable Threads::Mutex mutex; }; @@ -429,56 +334,37 @@ class StraightBoundary : public Boundary<dim,spacedim> { public: /** - * Default constructor. Some - * compilers require this for - * some reasons. + * Default constructor. Some compilers require this for some reasons. */ StraightBoundary (); /** - * Let the new point be the - * arithmetic mean of the two - * vertices of the line. + * Let the new point be the arithmetic mean of the two vertices of the line. * - * Refer to the general - * documentation of this class - * and the documentation of the - * base class for more - * information. + * Refer to the general documentation of this class and the documentation of + * the base class for more information. */ virtual Point<spacedim> get_new_point_on_line (const typename Triangulation<dim,spacedim>::line_iterator &line) const; /** - * Let the new point be the - * arithmetic mean of the four - * vertices of this quad and the - * four midpoints of the lines, - * which are already created at - * the time of calling this - * function. + * Let the new point be the arithmetic mean of the four vertices of this + * quad and the four midpoints of the lines, which are already created at + * the time of calling this function. * - * Refer to the general - * documentation of this class - * and the documentation of the - * base class for more - * information. + * Refer to the general documentation of this class and the documentation of + * the base class for more information. */ virtual Point<spacedim> get_new_point_on_quad (const typename Triangulation<dim,spacedim>::quad_iterator &quad) const; /** - * Gives <tt>n=points.size()</tt> - * points that splits the - * StraightBoundary line into - * $n+1$ partitions of equal - * lengths. + * Gives <tt>n=points.size()</tt> points that splits the StraightBoundary + * line into $n+1$ partitions of equal lengths. * - * Refer to the general - * documentation of this class - * and the documentation of the - * base class. + * Refer to the general documentation of this class and the documentation of + * the base class. */ virtual void @@ -486,16 +372,11 @@ public: std::vector<Point<spacedim> > &points) const; /** - * Gives <tt>n=points.size()=m*m</tt> - * points that splits the - * StraightBoundary quad into - * $(m+1)(m+1)$ subquads of equal - * size. + * Gives <tt>n=points.size()=m*m</tt> points that splits the + * StraightBoundary quad into $(m+1)(m+1)$ subquads of equal size. * - * Refer to the general - * documentation of this class - * and the documentation of the - * base class. + * Refer to the general documentation of this class and the documentation of + * the base class. */ virtual void @@ -503,13 +384,10 @@ public: std::vector<Point<spacedim> > &points) const; /** - * Implementation of the function - * declared in the base class. + * Implementation of the function declared in the base class. * - * Refer to the general - * documentation of this class - * and the documentation of the - * base class. + * Refer to the general documentation of this class and the documentation of + * the base class. */ virtual Tensor<1,spacedim> @@ -517,14 +395,10 @@ public: const Point<spacedim> &p) const; /** - * Compute the normals to the - * boundary at the vertices of - * the given face. + * Compute the normals to the boundary at the vertices of the given face. * - * Refer to the general - * documentation of this class - * and the documentation of the - * base class. + * Refer to the general documentation of this class and the documentation of + * the base class. */ virtual void @@ -532,32 +406,18 @@ public: typename Boundary<dim,spacedim>::FaceVertexNormals &face_vertex_normals) const; /** - * Given a candidate point and a - * line segment characterized by - * the iterator, return a point - * that lies on the surface - * described by this object. This - * function is used in some mesh - * smoothing algorithms that try - * to move around points in order - * to improve the mesh quality - * but need to ensure that points - * that were on the boundary - * remain on the boundary. + * Given a candidate point and a line segment characterized by the iterator, + * return a point that lies on the surface described by this object. This + * function is used in some mesh smoothing algorithms that try to move + * around points in order to improve the mesh quality but need to ensure + * that points that were on the boundary remain on the boundary. * - * The point returned is the - * projection of the candidate - * point onto the line through - * the two vertices of the given - * line iterator. + * The point returned is the projection of the candidate point onto the line + * through the two vertices of the given line iterator. * - * If spacedim==1, then the line - * represented by the line - * iterator is the entire space - * (i.e. it is a cell, not a part - * of the boundary), and the - * returned point equals the - * given input point. + * If spacedim==1, then the line represented by the line iterator is the + * entire space (i.e. it is a cell, not a part of the boundary), and the + * returned point equals the given input point. */ virtual Point<spacedim> @@ -565,26 +425,15 @@ public: const Point<spacedim> &candidate) const; /** - * Same function as above but for - * a point that is to be - * projected onto the area - * characterized by the given - * quad. + * Same function as above but for a point that is to be projected onto the + * area characterized by the given quad. * - * The point returned is the - * projection of the candidate - * point onto the bilinear - * surface spanned by the four - * vertices of the given quad - * iterator. + * The point returned is the projection of the candidate point onto the + * bilinear surface spanned by the four vertices of the given quad iterator. * - * If spacedim<=2, then the surface - * represented by the quad - * iterator is the entire space - * (i.e. it is a cell, not a part - * of the boundary), and the - * returned point equals the - * given input point. + * If spacedim<=2, then the surface represented by the quad iterator is the + * entire space (i.e. it is a cell, not a part of the boundary), and the + * returned point equals the given input point. */ virtual Point<spacedim> @@ -592,26 +441,16 @@ public: const Point<spacedim> &candidate) const; /** - * Same function as above but for - * a point that is to be - * projected onto the area - * characterized by the given - * quad. + * Same function as above but for a point that is to be projected onto the + * area characterized by the given quad. * - * The point returned is the - * projection of the candidate - * point onto the trilinear - * manifold spanned by the eight - * vertices of the given hex + * The point returned is the projection of the candidate point onto the + * trilinear manifold spanned by the eight vertices of the given hex * iterator. * - * If spacedim<=3, then the manifold - * represented by the hex - * iterator is the entire space - * (i.e. it is a cell, not a part - * of the boundary), and the - * returned point equals the - * given input point. + * If spacedim<=3, then the manifold represented by the hex iterator is the + * entire space (i.e. it is a cell, not a part of the boundary), and the + * returned point equals the given input point. */ virtual Point<spacedim> diff --git a/deal.II/include/deal.II/hp/fe_values.h b/deal.II/include/deal.II/hp/fe_values.h index d077e4d838..cad63fdf4f 100644 --- a/deal.II/include/deal.II/hp/fe_values.h +++ b/deal.II/include/deal.II/hp/fe_values.h @@ -87,6 +87,25 @@ namespace internal const dealii::hp::FECollection<dim,FEValues::space_dimension> & get_fe_collection () const; + /** + * Get a reference to the collection of mapping objects used + * here. + */ + const dealii::hp::MappingCollection<dim,FEValues::space_dimension> & + get_mapping_collection () const; + + /** + * Get a reference to the collection of quadrature objects used + * here. + */ + const dealii::hp::QCollection<q_dim> & + get_quadrature_collection () const; + + /** + * Get the underlying update flags. + */ + UpdateFlags get_update_flags() const; + /** * Return a reference to the @p FEValues object selected by the last * call to select_fe_values(). select_fe_values() in turn is called when @@ -592,6 +611,36 @@ namespace internal { return *fe_collection; } + + + + template <int dim, int q_dim, class FEValues> + inline + const dealii::hp::MappingCollection<dim,FEValues::space_dimension> & + FEValuesBase<dim,q_dim,FEValues>::get_mapping_collection () const + { + return *mapping_collection; + } + + + + template <int dim, int q_dim, class FEValues> + inline + const dealii::hp::QCollection<q_dim> & + FEValuesBase<dim,q_dim,FEValues>::get_quadrature_collection () const + { + return q_collection; + } + + + + template <int dim, int q_dim, class FEValues> + inline + dealii::UpdateFlags + FEValuesBase<dim,q_dim,FEValues>::get_update_flags () const + { + return update_flags; + } } } diff --git a/deal.II/include/deal.II/integrators/laplace.h b/deal.II/include/deal.II/integrators/laplace.h index c20eb4beba..fd9564c374 100644 --- a/deal.II/include/deal.II/integrators/laplace.h +++ b/deal.II/include/deal.II/integrators/laplace.h @@ -349,6 +349,77 @@ namespace LocalIntegrators } } + template <int dim> + void ip_tangential_matrix ( + FullMatrix<double> &M11, + FullMatrix<double> &M12, + FullMatrix<double> &M21, + FullMatrix<double> &M22, + const FEValuesBase<dim> &fe1, + const FEValuesBase<dim> &fe2, + double penalty, + double factor1 = 1., + double factor2 = -1.) + { + const unsigned int n_dofs = fe1.dofs_per_cell; + AssertDimension(fe1.get_fe().n_components(), dim); + AssertDimension(fe2.get_fe().n_components(), dim); + AssertDimension(M11.n(), n_dofs); + AssertDimension(M11.m(), n_dofs); + AssertDimension(M12.n(), n_dofs); + AssertDimension(M12.m(), n_dofs); + AssertDimension(M21.n(), n_dofs); + AssertDimension(M21.m(), n_dofs); + AssertDimension(M22.n(), n_dofs); + AssertDimension(M22.m(), n_dofs); + + const double nui = factor1; + const double nue = (factor2 < 0) ? factor1 : factor2; + const double nu = .5*(nui+nue); + + for (unsigned int k=0; k<fe1.n_quadrature_points; ++k) + { + const double dx = fe1.JxW(k); + const Point<dim> &n = fe1.normal_vector(k); + for (unsigned int i=0; i<n_dofs; ++i) + { + for (unsigned int j=0; j<n_dofs; ++j) + { + double u1dotn = 0.; + double v1dotn = 0.; + double u2dotn = 0.; + double v2dotn = 0.; + + for (unsigned int d=0; d<dim; ++d) + { + u1dotn += n(d)*fe1.shape_value_component(j,k,d); + v1dotn += n(d)*fe1.shape_value_component(i,k,d); + u2dotn += n(d)*fe2.shape_value_component(j,k,d); + v2dotn += n(d)*fe2.shape_value_component(i,k,d); + } + + for (unsigned int d=0; d<fe1.get_fe().n_components(); ++d) + { + + // multiply by + const double vi = fe1.shape_value_component(i,k,d)*(1-v1dotn); + const double dnvi = n * fe1.shape_grad_component(i,k,d)*(1-v1dotn); + const double ve = fe2.shape_value_component(i,k,d)*(1-v2dotn); + const double dnve = n * fe2.shape_grad_component(i,k,d)*(1-v2dotn); + const double ui = fe1.shape_value_component(j,k,d)*(1-u1dotn); + const double dnui = n * fe1.shape_grad_component(j,k,d)*(1-u1dotn); + const double ue = fe2.shape_value_component(j,k,d)*(1-u2dotn); + const double dnue = n * fe2.shape_grad_component(j,k,d)*(1-u2dotn); + M11(i,j) += dx*(-.5*nui*dnvi*ui-.5*nui*dnui*vi+nu*penalty*ui*vi); + M12(i,j) += dx*( .5*nui*dnvi*ue-.5*nue*dnue*vi-nu*penalty*vi*ue); + M21(i,j) += dx*(-.5*nue*dnve*ui+.5*nui*dnui*ve-nu*penalty*ui*ve); + M22(i,j) += dx*( .5*nue*dnve*ue+.5*nue*dnue*ve+nu*penalty*ue*ve); + } + } + } + } + } + /** * Residual term for the symmetric interior penalty method. * diff --git a/deal.II/include/deal.II/lac/constraint_matrix.h b/deal.II/include/deal.II/lac/constraint_matrix.h index 6c623eef0e..7d5ae2e78b 100644 --- a/deal.II/include/deal.II/lac/constraint_matrix.h +++ b/deal.II/include/deal.II/lac/constraint_matrix.h @@ -233,6 +233,14 @@ public: */ bool can_store_line (const size_type line_index) const; + /** + * Returns the index set describing locally relevant lines if any are + * present. Note that if no local lines were given, this represents an empty + * IndexSet, whereas otherwise it contains the global problem size and the + * local range. + */ + const IndexSet & get_local_lines() const; + /** * This function copies the content of @p * constraints_in with DoFs that are @@ -2050,6 +2058,15 @@ ConstraintMatrix::can_store_line (size_type line_index) const +inline +const IndexSet & +ConstraintMatrix::get_local_lines () const +{ + return local_lines; +} + + + template <class VectorType> inline void ConstraintMatrix::distribute_local_to_global ( diff --git a/deal.II/include/deal.II/lac/slepc_solver.h b/deal.II/include/deal.II/lac/slepc_solver.h index 509297a574..184164369d 100644 --- a/deal.II/include/deal.II/lac/slepc_solver.h +++ b/deal.II/include/deal.II/lac/slepc_solver.h @@ -119,11 +119,6 @@ namespace SLEPcWrappers class SolverBase { public: - /** - * Declare type for container size. - */ - typedef types::global_dof_index size_type; - /** * Constructor. Takes the MPI communicator over which parallel * computations are to happen. @@ -161,7 +156,7 @@ namespace SLEPcWrappers solve (const PETScWrappers::MatrixBase &A, std::vector<double> &eigenvalues, std::vector<OutputVector> &eigenvectors, - const size_type n_eigenpairs = 1); + const unsigned int n_eigenpairs = 1); /** * Same as above, but here a composite method for solving the @@ -174,7 +169,7 @@ namespace SLEPcWrappers const PETScWrappers::MatrixBase &B, std::vector<double> &eigenvalues, std::vector<OutputVector> &eigenvectors, - const size_type n_eigenpairs = 1); + const unsigned int n_eigenpairs = 1); /** * Same as above, but here a composite method for solving the @@ -299,12 +294,13 @@ namespace SLEPcWrappers /** * Solve the linear system for <code>n_eigenpairs</code> * eigenstates. Parameter <code>n_converged</code> contains the - * actual number of eigenstates that have . converged; this can + * actual number of eigenstates that have converged; this can * be both fewer or more than n_eigenpairs, depending on the * SLEPc eigensolver used. */ void - solve (const unsigned int n_eigenpairs, unsigned int *n_converged); + solve (const unsigned int n_eigenpairs, + unsigned int *n_converged); /** * Access the real parts of solutions for a solved eigenvector @@ -754,7 +750,7 @@ namespace SLEPcWrappers SolverBase::solve (const PETScWrappers::MatrixBase &A, std::vector<double> &eigenvalues, std::vector<OutputVector> &eigenvectors, - const size_type n_eigenpairs) + const unsigned int n_eigenpairs) { // Panic if the number of eigenpairs wanted is out of bounds. AssertThrow ((n_eigenpairs > 0) && (n_eigenpairs <= A.m ()), @@ -764,7 +760,7 @@ namespace SLEPcWrappers set_matrices (A); // and solve - size_type n_converged = 0; + unsigned int n_converged = 0; solve (n_eigenpairs, &n_converged); if (n_converged > n_eigenpairs) @@ -776,7 +772,7 @@ namespace SLEPcWrappers eigenvectors.resize (n_converged, eigenvectors.front()); eigenvalues.resize (n_converged); - for (size_type index=0; index<n_converged; ++index) + for (unsigned int index=0; index<n_converged; ++index) get_eigenpair (index, eigenvalues[index], eigenvectors[index]); } @@ -786,7 +782,7 @@ namespace SLEPcWrappers const PETScWrappers::MatrixBase &B, std::vector<double> &eigenvalues, std::vector<OutputVector> &eigenvectors, - const size_type n_eigenpairs) + const unsigned int n_eigenpairs) { // Guard against incompatible matrix sizes: AssertThrow (A.m() == B.m (), ExcDimensionMismatch(A.m(), B.m())); @@ -800,7 +796,7 @@ namespace SLEPcWrappers set_matrices (A, B); // and solve - size_type n_converged = 0; + unsigned int n_converged = 0; solve (n_eigenpairs, &n_converged); if (n_converged>=n_eigenpairs) @@ -813,7 +809,7 @@ namespace SLEPcWrappers eigenvectors.resize (n_converged, eigenvectors.front()); eigenvalues.resize (n_converged); - for (size_type index=0; index<n_converged; ++index) + for (unsigned int index=0; index<n_converged; ++index) get_eigenpair (index, eigenvalues[index], eigenvectors[index]); } @@ -825,7 +821,7 @@ namespace SLEPcWrappers std::vector<double> &imag_eigenvalues, std::vector<OutputVector> &real_eigenvectors, std::vector<OutputVector> &imag_eigenvectors, - const size_type n_eigenpairs) + const unsigned int n_eigenpairs) { // Guard against incompatible matrix sizes: AssertThrow (A.m() == B.m (), ExcDimensionMismatch(A.m(), B.m())); @@ -845,7 +841,7 @@ namespace SLEPcWrappers set_matrices (A, B); // and solve - size_type n_converged = 0; + unsigned int n_converged = 0; solve (n_eigenpairs, &n_converged); if (n_converged>=n_eigenpairs) @@ -861,7 +857,7 @@ namespace SLEPcWrappers real_eigenvalues.resize (n_converged); imag_eigenvalues.resize (n_converged); - for (size_type index=0; index<n_converged; ++index) + for (unsigned int index=0; index<n_converged; ++index) get_eigenpair (index, real_eigenvalues[index], imag_eigenvalues[index], real_eigenvectors[index], imag_eigenvectors[index]); diff --git a/deal.II/include/deal.II/meshworker/integration_info.h b/deal.II/include/deal.II/meshworker/integration_info.h index 4323bbf83a..1bd8c63b5c 100644 --- a/deal.II/include/deal.II/meshworker/integration_info.h +++ b/deal.II/include/deal.II/meshworker/integration_info.h @@ -90,44 +90,30 @@ namespace MeshWorker IntegrationInfo(); /** - * Copy constructor, creating a - * clone to be used by + * Copy constructor, creating a clone to be used by * WorksTream::run(). */ IntegrationInfo(const IntegrationInfo<dim, spacedim> &other); /** - * Build all internal - * structures, in particular - * the FEValuesBase objects - * and allocate space for - * data vectors. + * Build all internal structures, in particular the FEValuesBase + * objects and allocate space for data vectors. * - * @param el is the finite - * element of the DoFHandler. + * @param el is the finite element of the DoFHandler. * - * @param mapping is the Mapping - * object used to map the - * mesh cells. + * @param mapping is the Mapping object used to map the mesh + * cells. * - * @param quadrature is a - * Quadrature formula used in - * the constructor of the - * FEVALUES objects. + * @param quadrature is a Quadrature formula used in the + * constructor of the FEVALUES objects. * - * @param flags are the - * UpdateFlags used in - * the constructor of the + * @param flags are the UpdateFlags used in the constructor of the * FEVALUES objects. * - * @param local_block_info is - * an optional parameter for - * systems of PDE. If it is - * provided with reasonable - * data, then the degrees of - * freedom on the cells will be - * re-ordered to reflect the - * block structure of the system. + * @param local_block_info is an optional parameter for systems of + * PDE. If it is provided with reasonable data, then the degrees + * of freedom on the cells will be re-ordered to reflect the block + * structure of the system. */ template <class FEVALUES> void initialize(const FiniteElement<dim,spacedim> &el, @@ -137,9 +123,7 @@ namespace MeshWorker const BlockInfo *local_block_info = 0); /** - * Initialize the data - * vector and cache the - * selector. + * Initialize the data vector and cache the selector. */ void initialize_data(const std_cxx1x::shared_ptr<VectorDataBase<dim,spacedim> > &data); @@ -152,97 +136,67 @@ namespace MeshWorker bool multigrid; /// Access to finite element /** - * This is the access - * function being used, if - * the constructor for a - * single element was - * used. It throws an - * exception, if applied to a - * vector of elements. + * This is the access function being used, if the constructor for + * a single element was used. It throws an exception, if applied + * to a vector of elements. */ const FEValuesBase<dim, spacedim> &fe_values () const; /// Access to finite elements /** - * This access function must - * be used if the constructor - * for a group of elements - * was used. + * This access function must be used if the constructor for a + * group of elements was used. * * @see DGBlockSplitApplication */ const FEValuesBase<dim, spacedim> &fe_values (const unsigned int i) const; /** - * The vector containing the - * values of finite element - * functions in the quadrature - * points. + * The vector containing the values of finite element functions in + * the quadrature points. * - * There is one vector per - * selected finite element - * function, containing one - * vector for each component, - * containing vectors with - * values for each quadrature - * point. + * There is one vector per selected finite element function, + * containing one vector for each component, containing vectors + * with values for each quadrature point. */ std::vector<std::vector<std::vector<double> > > values; /** - * The vector containing the - * derivatives of finite - * element functions in the - * quadrature points. + * The vector containing the derivatives of finite element + * functions in the quadrature points. * - * There is one vector per - * selected finite element - * function, containing one - * vector for each component, - * containing vectors with - * values for each quadrature - * point. + * There is one vector per selected finite element function, + * containing one vector for each component, containing vectors + * with values for each quadrature point. */ std::vector<std::vector<std::vector<Tensor<1,dim> > > > gradients; /** - * The vector containing the - * second derivatives of finite - * element functions in the - * quadrature points. + * The vector containing the second derivatives of finite element + * functions in the quadrature points. * - * There is one vector per - * selected finite element - * function, containing one - * vector for each component, - * containing vectors with - * values for each quadrature - * point. + * There is one vector per selected finite element function, + * containing one vector for each component, containing vectors + * with values for each quadrature point. */ std::vector<std::vector<std::vector<Tensor<2,dim> > > > hessians; /** - * Reinitialize internal data - * structures for use on a cell. + * Reinitialize internal data structures for use on a cell. */ template <typename number> void reinit(const DoFInfo<dim, spacedim, number> &i); /** - * Use the finite element - * functions in #global_data - * and fill the vectors - * #values, #gradients and - * #hessians. + * Use the finite element functions in #global_data and fill the + * vectors #values, #gradients and #hessians. */ template<typename number> void fill_local_data(const DoFInfo<dim, spacedim, number> &info, bool split_fevalues); /** - * The global data vector - * used to compute function - * values in quadrature - * points. + * The global data vector used to compute function values in + * quadrature points. */ std_cxx1x::shared_ptr<VectorDataBase<dim, spacedim> > global_data; @@ -253,13 +207,9 @@ namespace MeshWorker private: /** - * Use the finite element - * functions in #global_data - * and fill the vectors - * #values, #gradients and - * #hessians with values - * according to the - * selector. + * Use the finite element functions in #global_data and fill the + * vectors #values, #gradients and #hessians with values according + * to the selector. */ template <typename TYPE> void fill_local_data( @@ -267,8 +217,7 @@ namespace MeshWorker VectorSelector &selector, bool split_fevalues) const; /** - * Cache the number of - * components of the system element. + * Cache the number of components of the system element. */ unsigned int n_components; }; @@ -346,34 +295,22 @@ namespace MeshWorker IntegrationInfoBox (); /** - * Initialize the - * IntegrationInfo objects - * contained. + * Initialize the IntegrationInfo objects contained. * - * Before doing so, add update - * flags necessary to produce - * the data needed and also - * set uninitialized quadrature - * rules to Gauss formulas, - * which integrate polynomial - * bilinear forms exactly. + * Before doing so, add update flags necessary to produce the data + * needed and also set uninitialized quadrature rules to Gauss + * formulas, which integrate polynomial bilinear forms exactly. */ void initialize(const FiniteElement<dim, spacedim> &el, const Mapping<dim, spacedim> &mapping, const BlockInfo *block_info = 0); /** - * Initialize the - * IntegrationInfo objects - * contained. + * Initialize the IntegrationInfo objects contained. * - * Before doing so, add update - * flags necessary to produce - * the data needed and also - * set uninitialized quadrature - * rules to Gauss formulas, - * which integrate polynomial - * bilinear forms exactly. + * Before doing so, add update flags necessary to produce the data + * needed and also set uninitialized quadrature rules to Gauss + * formulas, which integrate polynomial bilinear forms exactly. */ template <typename VECTOR> void initialize(const FiniteElement<dim, spacedim> &el, @@ -382,17 +319,11 @@ namespace MeshWorker const BlockInfo *block_info = 0); /** - * Initialize the - * IntegrationInfo objects - * contained. + * Initialize the IntegrationInfo objects contained. * - * Before doing so, add update - * flags necessary to produce - * the data needed and also - * set uninitialized quadrature - * rules to Gauss formulas, - * which integrate polynomial - * bilinear forms exactly. + * Before doing so, add update flags necessary to produce the data + * needed and also set uninitialized quadrature rules to Gauss + * formulas, which integrate polynomial bilinear forms exactly. */ template <typename VECTOR> void initialize(const FiniteElement<dim, spacedim> &el, @@ -405,64 +336,43 @@ namespace MeshWorker /* @{ */ /** - * Call this function before - * initialize() in order to - * guess the update flags - * needed, based on the data - * selected. + * Call this function before initialize() in order to guess the + * update flags needed, based on the data selected. * - * When computing face fluxes, - * we normally can use the - * geometry (integration - * weights and normal vectors) - * from the original cell and - * thus can avoid updating - * these values on the - * neighboring cell. Set - * <tt>neighbor_geometry</tt> - * to true in order to - * initialize these values as - * well. + * When computing face fluxes, we normally can use the geometry + * (integration weights and normal vectors) from the original cell + * and thus can avoid updating these values on the neighboring + * cell. Set <tt>neighbor_geometry</tt> to true in order to + * initialize these values as well. */ void initialize_update_flags(bool neighbor_geometry = false); /** - * Add FEValues UpdateFlags for - * integration on all objects - * (cells, boundary faces and - * all interior faces). + * Add FEValues UpdateFlags for integration on all objects (cells, + * boundary faces and all interior faces). */ void add_update_flags_all (const UpdateFlags flags); /** - * Add FEValues UpdateFlags for - * integration on cells. + * Add FEValues UpdateFlags for integration on cells. */ void add_update_flags_cell(const UpdateFlags flags); /** - * Add FEValues UpdateFlags for - * integration on boundary faces. + * Add FEValues UpdateFlags for integration on boundary faces. */ void add_update_flags_boundary(const UpdateFlags flags); /** - * Add FEValues UpdateFlags for - * integration on interior faces. + * Add FEValues UpdateFlags for integration on interior faces. */ void add_update_flags_face(const UpdateFlags flags); /** - * Add additional update flags - * to the ones already set in - * this program. The four - * boolean flags indicate - * whether the additional flags - * should be set for cell, - * boundary, interelement face - * for the cell itself - * or neighbor cell, or - * any combination thereof. + * Add additional update flags to the ones already set in this + * program. The four boolean flags indicate whether the additional + * flags should be set for cell, boundary, interelement face for + * the cell itself or neighbor cell, or any combination thereof. */ void add_update_flags(const UpdateFlags flags, const bool cell = true, @@ -471,19 +381,12 @@ namespace MeshWorker const bool neighbor = true); /** - * Assign n-point Gauss - * quadratures to each of the - * quadrature rules. Here, a - * size of zero points means - * that no loop over these grid - * entities should be - * performed. + * Assign n-point Gauss quadratures to each of the quadrature + * rules. Here, a size of zero points means that no loop over + * these grid entities should be performed. * - * If the parameter - * <tt>force</tt> is true, then - * all quadrature sets are - * filled with new quadrature - * ruels. If it is false, then + * If the parameter <tt>force</tt> is true, then all quadrature + * sets are filled with new quadrature ruels. If it is false, then * only empty rules are changed. */ void initialize_gauss_quadrature(unsigned int n_cell_points, @@ -497,59 +400,45 @@ namespace MeshWorker std::size_t memory_consumption () const; /** - * The set of update flags - * for boundary cell integration. + * The set of update flags for boundary cell integration. * - * Defaults to - * #update_JxW_values. + * Defaults to #update_JxW_values. */ UpdateFlags cell_flags; /** - * The set of update flags - * for boundary face integration. + * The set of update flags for boundary face integration. * - * Defaults to - * #update_JxW_values and - * #update_normal_vectors. + * Defaults to #update_JxW_values and #update_normal_vectors. */ UpdateFlags boundary_flags; /** - * The set of update flags - * for interior face integration. + * The set of update flags for interior face integration. * - * Defaults to - * #update_JxW_values and - * #update_normal_vectors. + * Defaults to #update_JxW_values and #update_normal_vectors. */ UpdateFlags face_flags; /** - * The set of update flags - * for interior face integration. + * The set of update flags for interior face integration. * - * Defaults to - * #update_default, since - * quadrature weights are - * taken from the other cell. + * Defaults to #update_default, since quadrature weights are taken + * from the other cell. */ UpdateFlags neighbor_flags; /** - * The quadrature rule used - * on cells. + * The quadrature rule used on cells. */ Quadrature<dim> cell_quadrature; /** - * The quadrature rule used - * on boundary faces. + * The quadrature rule used on boundary faces. */ Quadrature<dim-1> boundary_quadrature; /** - * The quadrature rule used - * on interior faces. + * The quadrature rule used on interior faces. */ Quadrature<dim-1> face_quadrature; /* @} */ @@ -560,46 +449,30 @@ namespace MeshWorker /* @{ */ /** - * Initialize the - * VectorSelector objects - * #cell_selector, - * #boundary_selector and - * #face_selector in order to - * save computational - * effort. If no selectors - * are used, then values for - * all named vectors in - * DoFInfo::global_data will be - * computed in all quadrature - * points. + * Initialize the VectorSelector objects #cell_selector, + * #boundary_selector and #face_selector in order to save + * computational effort. If no selectors are used, then values for + * all named vectors in DoFInfo::global_data will be computed in + * all quadrature points. * - * This function will also - * add UpdateFlags to the - * flags stored in this class. + * This function will also add UpdateFlags to the flags stored in + * this class. */ /** - * Select the vectors from - * DoFInfo::global_data - * that should be computed in - * the quadrature points on cells. + * Select the vectors from DoFInfo::global_data that should be + * computed in the quadrature points on cells. */ MeshWorker::VectorSelector cell_selector; /** - * Select the vectors from - * DoFInfo::global_data - * that should be computed in - * the quadrature points on - * boundary faces. + * Select the vectors from DoFInfo::global_data that should be + * computed in the quadrature points on boundary faces. */ MeshWorker::VectorSelector boundary_selector; /** - * Select the vectors from - * DoFInfo::global_data - * that should be computed in - * the quadrature points on - * interior faces. + * Select the vectors from DoFInfo::global_data that should be + * computed in the quadrature points on interior faces. */ MeshWorker::VectorSelector face_selector; @@ -613,68 +486,41 @@ namespace MeshWorker */ /* @{ */ /** - * A callback function which is - * called in the loop over all - * cells, after the action on a - * cell has been performed and - * before the faces are dealt - * with. + * A callback function which is called in the loop over all cells, + * after the action on a cell has been performed and before the + * faces are dealt with. * - * In order for this function - * to have this effect, - * at least either of the - * arguments - * <tt>boundary_worker</tt> or - * <tt>face_worker</tt> - * arguments of loop() should - * be nonzero. Additionally, - * <tt>cells_first</tt> should - * be true. If - * <tt>cells_first</tt> is - * false, this function is - * called before any action on - * a cell is taken. + * In order for this function to have this effect, at least either + * of the arguments <tt>boundary_worker</tt> or + * <tt>face_worker</tt> arguments of loop() should be + * nonzero. Additionally, <tt>cells_first</tt> should be true. If + * <tt>cells_first</tt> is false, this function is called before + * any action on a cell is taken. * - * And empty function in this - * class, but can be replaced - * in other classes given to - * loop() instead. + * And empty function in this class, but can be replaced in other + * classes given to loop() instead. * - * See loop() and cell_action() - * for more details of how this + * See loop() and cell_action() for more details of how this * function can be used. */ template <class DOFINFO> void post_cell(const DoFInfoBox<dim, DOFINFO> &); /** - * A callback function which is - * called in the loop over all - * cells, after the action on - * the faces of a cell has been - * performed and before the - * cell itself is dealt with - * (assumes + * A callback function which is called in the loop over all cells, + * after the action on the faces of a cell has been performed and + * before the cell itself is dealt with (assumes * <tt>cells_first</tt> is false). * - * In order for this function - * to have a reasonable effect, - * at least either of the - * arguments - * <tt>boundary_worker</tt> or - * <tt>face_worker</tt> - * arguments of loop() should - * be nonzero. Additionally, - * <tt>cells_first</tt> should - * be false. + * In order for this function to have a reasonable effect, at + * least either of the arguments <tt>boundary_worker</tt> or + * <tt>face_worker</tt> arguments of loop() should be + * nonzero. Additionally, <tt>cells_first</tt> should be false. * - * And empty function in this - * class, but can be replaced - * in other classes given to - * loop() instead. + * And empty function in this class, but can be replaced in other + * classes given to loop() instead. * - * See loop() and cell_action() - * for more details of how this + * See loop() and cell_action() for more details of how this * function can be used. */ template <class DOFINFO> @@ -685,27 +531,21 @@ namespace MeshWorker */ CellInfo cell; /** - * The info object for a - * boundary face. + * The info object for a boundary face. */ CellInfo boundary; /** - * The info object for a - * regular interior face, seen - * from the first cell. + * The info object for a regular interior face, seen from the + * first cell. */ CellInfo face; /** - * The info object for the - * refined side of an interior - * face seen from the first - * cell. + * The info object for the refined side of an interior face seen + * from the first cell. */ CellInfo subface; /** - * The info object for an - * interior face, seen from the - * other cell. + * The info object for an interior face, seen from the other cell. */ CellInfo neighbor; diff --git a/deal.II/include/deal.II/meshworker/simple.h b/deal.II/include/deal.II/meshworker/simple.h index 88e201777a..e43257df15 100644 --- a/deal.II/include/deal.II/meshworker/simple.h +++ b/deal.II/include/deal.II/meshworker/simple.h @@ -256,29 +256,24 @@ namespace MeshWorker { public: /** - * Constructor, initializing - * the #threshold, which - * limits how small numbers - * may be to be entered into - * the matrix. + * Constructor, initializing the #threshold, which limits how + * small numbers may be to be entered into the matrix. */ MGMatrixSimple(double threshold = 1.e-12); /** - * Store the result matrix - * for later assembling. + * Store the result matrix for later assembling. */ void initialize(MGLevelObject<MATRIX> &m); /** - * Initialize the multilevel - * constraints. + * Initialize the multilevel constraints. */ void initialize(const MGConstrainedDoFs &mg_constrained_dofs); /** - * @deprecated This function is of no effect. Only the block info - * structure in DoFInfo is being used. + * @deprecated This function is of no effect. Only the block + * info structure in DoFInfo is being used. * * Store information on the local block structure. If the * assembler is inititialized with this function, @@ -458,6 +453,15 @@ namespace MeshWorker */ void initialize(MATRIX &m, VECTOR &rhs); + /** + * Initialize the constraints. After this function has been + * called with a valid ConstraintMatrix, the function + * ConstraintMatrix::distribute_local_to_global() will be used + * by assemble() to distribute the cell and face matrices into a + * global sparse matrix. + */ + void initialize(const ConstraintMatrix &constraints); + /** * Initialize the local data * in the @@ -911,8 +915,7 @@ namespace MeshWorker for (unsigned int j=0; j<i1.size(); ++j) for (unsigned int k=0; k<i2.size(); ++k) if (std::fabs(M(k,j)) >= threshold) - if (mg_constrained_dofs->at_refinement_edge(level, i1[j]) && - !mg_constrained_dofs->at_refinement_edge(level, i2[k])) + if (!mg_constrained_dofs->at_refinement_edge(level, i2[k])) G.add(i1[j], i2[k], M(k,j)); } } @@ -941,8 +944,7 @@ namespace MeshWorker for (unsigned int j=0; j<i1.size(); ++j) for (unsigned int k=0; k<i2.size(); ++k) if (std::fabs(M(j,k)) >= threshold) - if (mg_constrained_dofs->at_refinement_edge(level, i1[j]) && - !mg_constrained_dofs->at_refinement_edge(level, i2[k])) + if (!mg_constrained_dofs->at_refinement_edge(level, i2[k])) G.add(i1[j], i2[k], M(j,k)); } } @@ -958,49 +960,41 @@ namespace MeshWorker { AssertDimension(M.m(), i1.size()); AssertDimension(M.n(), i2.size()); - - if (mg_constrained_dofs == 0) - { - for (unsigned int j=0; j<i1.size(); ++j) - for (unsigned int k=0; k<i2.size(); ++k) - if (std::fabs(M(j,k)) >= threshold) - G.add(i1[j], i2[k], M(j,k)); - } - else - { - for (unsigned int j=0; j<i1.size(); ++j) - for (unsigned int k=0; k<i2.size(); ++k) - if (std::fabs(M(j,k)) >= threshold) - // Enter values into matrix only if j corresponds to a - // degree of freedom on the refinemenent edge, k does - // not, and both are not on the boundary. This is part - // the difference between the complete matrix with no - // boundary condition at the refinement edge and and - // the matrix assembled above by assemble(). - - // Thus the logic is: enter the row if it is - // constrained by hanging node constraints (actually, - // the whole refinement edge), but not if it is - // constrained by a boundary constraint. - if (mg_constrained_dofs->at_refinement_edge(level, i1[j]) && - !mg_constrained_dofs->at_refinement_edge(level, i2[k])) - { - if (mg_constrained_dofs->set_boundary_values()) - { - if ((!mg_constrained_dofs->at_refinement_edge_boundary(level, i1[j]) && - !mg_constrained_dofs->at_refinement_edge_boundary(level, i2[k])) - || - (mg_constrained_dofs->at_refinement_edge_boundary(level, i1[j]) && - mg_constrained_dofs->at_refinement_edge_boundary(level, i2[k]) && - i1[j] == i2[k])) - G.add(i1[j], i2[k], M(j,k)); - } - else - G.add(i1[j], i2[k], M(j,k)); - } - } + Assert(mg_constrained_dofs != 0, ExcInternalError()); + + for (unsigned int j=0; j<i1.size(); ++j) + for (unsigned int k=0; k<i2.size(); ++k) + if (std::fabs(M(j,k)) >= threshold) + // Enter values into matrix only if j corresponds to a + // degree of freedom on the refinemenent edge, k does + // not, and both are not on the boundary. This is part + // the difference between the complete matrix with no + // boundary condition at the refinement edge and and + // the matrix assembled above by assemble(). + + // Thus the logic is: enter the row if it is + // constrained by hanging node constraints (actually, + // the whole refinement edge), but not if it is + // constrained by a boundary constraint. + if (mg_constrained_dofs->at_refinement_edge(level, i1[j]) && + !mg_constrained_dofs->at_refinement_edge(level, i2[k])) + { + if (mg_constrained_dofs->set_boundary_values()) + { + if ((!mg_constrained_dofs->at_refinement_edge_boundary(level, i1[j]) && + !mg_constrained_dofs->at_refinement_edge_boundary(level, i2[k])) + || + (mg_constrained_dofs->at_refinement_edge_boundary(level, i1[j]) && + mg_constrained_dofs->at_refinement_edge_boundary(level, i2[k]) && + i1[j] == i2[k])) + G.add(i1[j], i2[k], M(j,k)); + } + else + G.add(i1[j], i2[k], M(j,k)); + } } - + + template <class MATRIX> inline void MGMatrixSimple<MATRIX>::assemble_out( @@ -1012,38 +1006,29 @@ namespace MeshWorker { AssertDimension(M.n(), i1.size()); AssertDimension(M.m(), i2.size()); - - if (mg_constrained_dofs == 0) - { - for (unsigned int j=0; j<i1.size(); ++j) - for (unsigned int k=0; k<i2.size(); ++k) - if (std::fabs(M(k,j)) >= threshold) - G.add(i1[j], i2[k], M(k,j)); - } - else - { - for (unsigned int j=0; j<i1.size(); ++j) - for (unsigned int k=0; k<i2.size(); ++k) - if (std::fabs(M(k,j)) >= threshold) - if (mg_constrained_dofs->at_refinement_edge(level, i1[j]) && - !mg_constrained_dofs->at_refinement_edge(level, i2[k])) - { - if (mg_constrained_dofs->set_boundary_values()) - { - if ((!mg_constrained_dofs->at_refinement_edge_boundary(level, i1[j]) && - !mg_constrained_dofs->at_refinement_edge_boundary(level, i2[k])) - || - (mg_constrained_dofs->at_refinement_edge_boundary(level, i1[j]) && - mg_constrained_dofs->at_refinement_edge_boundary(level, i2[k]) && - i1[j] == i2[k])) - G.add(i1[j], i2[k], M(k,j)); - } - else - G.add(i1[j], i2[k], M(k,j)); - } - } + Assert(mg_constrained_dofs != 0, ExcInternalError()); + + for (unsigned int j=0; j<i1.size(); ++j) + for (unsigned int k=0; k<i2.size(); ++k) + if (std::fabs(M(k,j)) >= threshold) + if (mg_constrained_dofs->at_refinement_edge(level, i1[j]) && + !mg_constrained_dofs->at_refinement_edge(level, i2[k])) + { + if (mg_constrained_dofs->set_boundary_values()) + { + if ((!mg_constrained_dofs->at_refinement_edge_boundary(level, i1[j]) && + !mg_constrained_dofs->at_refinement_edge_boundary(level, i2[k])) + || + (mg_constrained_dofs->at_refinement_edge_boundary(level, i1[j]) && + mg_constrained_dofs->at_refinement_edge_boundary(level, i2[k]) && + i1[j] == i2[k])) + G.add(i1[j], i2[k], M(k,j)); + } + else + G.add(i1[j], i2[k], M(k,j)); + } } - + template <class MATRIX> template <class DOFINFO> @@ -1189,7 +1174,15 @@ namespace MeshWorker ResidualSimple<VECTOR>::initialize(data); } + template <class MATRIX, class VECTOR> + inline void + SystemSimple<MATRIX,VECTOR>::initialize(const ConstraintMatrix &c) + { + MatrixSimple<MATRIX>::initialize(c); + ResidualSimple<VECTOR>::initialize(c); + } + template <class MATRIX, class VECTOR> template <class DOFINFO> inline void diff --git a/deal.II/include/deal.II/multigrid/sparse_matrix_collection.h b/deal.II/include/deal.II/multigrid/sparse_matrix_collection.h new file mode 100644 index 0000000000..a7dd03816e --- /dev/null +++ b/deal.II/include/deal.II/multigrid/sparse_matrix_collection.h @@ -0,0 +1,124 @@ +// --------------------------------------------------------------------- +// $Id: mg_matrix.h 30036 2013-07-18 16:55:32Z maier $ +// +// Copyright (C) 2003 - 2013 by the deal.II authors +// +// This file is part of the deal.II library. +// +// The deal.II library is free software; you can use it, redistribute +// it, and/or modify it under the terms of the GNU Lesser General +// Public License as published by the Free Software Foundation; either +// version 2.1 of the License, or (at your option) any later version. +// The full text of the license can be found in the file LICENSE at +// the top level of the deal.II distribution. +// +// --------------------------------------------------------------------- + +#ifndef __deal2__mg_sparse_matrix_collection_h +#define __deal2__mg_sparse_matrix_collection_h + +#include <deal.II/lac/vector.h> +#include <deal.II/lac/pointer_matrix.h> +#include <deal.II/lac/sparse_matrix.h> +#include <deal.II/lac/compressed_sparsity_pattern.h> +#include <deal.II/multigrid/mg_base.h> +#include <deal.II/multigrid/mg_tools.h> +#include <deal.II/base/mg_level_object.h> +#include <deal.II/base/std_cxx1x/shared_ptr.h> + +DEAL_II_NAMESPACE_OPEN + +namespace mg +{ +/** + * Handler and storage for all five SparseMatrix object involved in + * using multigrid with local refinement. + * + * @author Baerbel Janssen, Guido Kanschat + * @date 2013 + */ + template <typename number> + class SparseMatrixCollection : public Subscriptor + { + public: + void resize(const unsigned int minlevel, const unsigned int maxlevel); + + template <class DH> + void reinit(const DH& dof_handler); + + void set_zero(); + + MGLevelObject<SparsityPattern> sparsity; + MGLevelObject<SparsityPattern> sparsity_edge; + + MGLevelObject<SparseMatrix<number> > matrix; + MGLevelObject<SparseMatrix<number> > matrix_down; + MGLevelObject<SparseMatrix<number> > matrix_up; + MGLevelObject<SparseMatrix<number> > matrix_in; + MGLevelObject<SparseMatrix<number> > matrix_out; + }; + + + template <typename number> + void + SparseMatrixCollection<number>::resize(const unsigned int minlevel, const unsigned int maxlevel) + { + matrix.resize(minlevel, maxlevel); + matrix.clear(); + matrix_up.resize(minlevel+1, maxlevel); + matrix_up.clear(); + matrix_down.resize(minlevel+1, maxlevel); + matrix_down.clear(); + matrix_in.resize(minlevel, maxlevel); + matrix_in.clear(); + matrix_out.resize(minlevel, maxlevel); + matrix_out.clear(); + sparsity.resize(minlevel, maxlevel); + sparsity_edge.resize(minlevel, maxlevel); + } + + + template <typename number> + template <class DH> + void + SparseMatrixCollection<number>::reinit(const DH& dof_handler) + { + AssertIndexRange(sparsity.max_level(), dof_handler.get_tria().n_levels()); + + for (unsigned int level=sparsity.min_level(); + level<=sparsity.max_level();++level) + { + CompressedSparsityPattern c_sparsity(dof_handler.n_dofs(level)); + MGTools::make_flux_sparsity_pattern(dof_handler, c_sparsity, level); + sparsity[level].copy_from(c_sparsity); + matrix[level].reinit(sparsity[level]); + matrix_in[level].reinit(sparsity[level]); + matrix_out[level].reinit(sparsity[level]); + if (level>0) + { + CompressedSparsityPattern ci_sparsity; + ci_sparsity.reinit(dof_handler.n_dofs(level-1), dof_handler.n_dofs(level)); + MGTools::make_flux_sparsity_pattern_edge(dof_handler, ci_sparsity, level); + sparsity_edge[level].copy_from(ci_sparsity); + matrix_up[level].reinit(sparsity_edge[level]); + matrix_down[level].reinit(sparsity_edge[level]); + } + } + } + + template <typename number> + void + SparseMatrixCollection<number>::set_zero() + { + matrix = 0.; + matrix_in = 0.; + matrix_out = 0.; + matrix_up = 0.; + matrix_down = 0.; + } + +} + +DEAL_II_NAMESPACE_CLOSE + +#endif diff --git a/deal.II/include/deal.II/numerics/data_out.h b/deal.II/include/deal.II/numerics/data_out.h index 26cf9b1a53..7dfe9c9bd4 100644 --- a/deal.II/include/deal.II/numerics/data_out.h +++ b/deal.II/include/deal.II/numerics/data_out.h @@ -20,17 +20,7 @@ #include <deal.II/base/config.h> -#include <deal.II/base/smartpointer.h> -#include <deal.II/base/data_out_base.h> -#include <deal.II/dofs/dof_handler.h> -#include <deal.II/grid/tria.h> -#include <deal.II/fe/mapping.h> -#include <deal.II/hp/q_collection.h> -#include <deal.II/hp/fe_collection.h> -#include <deal.II/hp/mapping_collection.h> -#include <deal.II/hp/fe_values.h> -#include <deal.II/numerics/data_postprocessor.h> -#include <deal.II/numerics/data_component_interpretation.h> +#include <deal.II/numerics/data_out_dof_data.h> #include <deal.II/base/std_cxx1x/shared_ptr.h> @@ -42,214 +32,6 @@ namespace internal { namespace DataOut { - /** - * For each vector that has been added through the add_data_vector() - * functions, we need to keep track of a pointer to it, and allow data - * extraction from it when we generate patches. Unfortunately, we need to - * do this for a number of different vector types. Fortunately, they all - * have the same interface. So the way we go is to have a base class that - * provides the functions to access the vector's information, and to have - * a derived template class that can be instantiated for each vector - * type. Since the vectors all have the same interface, this is no big - * problem, as they can all use the same general templatized code. - * - * @author Wolfgang Bangerth, 2004 - */ - template <class DH> - class DataEntryBase - { - public: - /** - * Constructor. Give a list of names for the individual components of - * the vector and their interpretation as scalar or vector data. This - * constructor assumes that no postprocessor is going to be used. - */ - DataEntryBase (const DH *dofs, - const std::vector<std::string> &names, - const std::vector<DataComponentInterpretation::DataComponentInterpretation> &data_component_interpretation); - - /** - * Constructor when a data postprocessor is going to be used. In that - * case, the names and vector declarations are going to be acquired from - * the postprocessor. - */ - DataEntryBase (const DH *dofs, - const DataPostprocessor<DH::space_dimension> *data_postprocessor); - - /** - * Destructor made virtual. - */ - virtual ~DataEntryBase (); - - /** - * Assuming that the stored vector is a cell vector, extract the given - * element from it. - */ - virtual - double - get_cell_data_value (const unsigned int cell_number) const = 0; - - /** - * Given a FEValuesBase object, extract the values on the present cell - * from the vector we actually store. - */ - virtual - void - get_function_values (const FEValuesBase<DH::dimension,DH::space_dimension> &fe_patch_values, - std::vector<double> &patch_values) const = 0; - - /** - * Given a FEValuesBase object, extract the values on the present cell - * from the vector we actually store. This function does the same as the - * one above but for vector-valued finite elements. - */ - virtual - void - get_function_values (const FEValuesBase<DH::dimension,DH::space_dimension> &fe_patch_values, - std::vector<dealii::Vector<double> > &patch_values_system) const = 0; - - /** - * Given a FEValuesBase object, extract the gradients on the present - * cell from the vector we actually store. - */ - virtual - void - get_function_gradients (const FEValuesBase<DH::dimension,DH::space_dimension> &fe_patch_values, - std::vector<Tensor<1,DH::space_dimension> > &patch_gradients) const = 0; - - /** - * Given a FEValuesBase object, extract the gradients on the present - * cell from the vector we actually store. This function does the same - * as the one above but for vector-valued finite elements. - */ - virtual - void - get_function_gradients (const FEValuesBase<DH::dimension,DH::space_dimension> &fe_patch_values, - std::vector<std::vector<Tensor<1,DH::space_dimension> > > &patch_gradients_system) const = 0; - - /** - * Given a FEValuesBase object, extract the second derivatives on the - * present cell from the vector we actually store. - */ - virtual - void - get_function_hessians (const FEValuesBase<DH::dimension,DH::space_dimension> &fe_patch_values, - std::vector<Tensor<2,DH::space_dimension> > &patch_hessians) const = 0; - - /** - * Given a FEValuesBase object, extract the second derivatives on the - * present cell from the vector we actually store. This function does - * the same as the one above but for vector-valued finite elements. - */ - virtual - void - get_function_hessians (const FEValuesBase<DH::dimension,DH::space_dimension> &fe_patch_values, - std::vector<std::vector< Tensor<2,DH::space_dimension> > > &patch_hessians_system) const = 0; - - /** - * Clear all references to the vectors. - */ - virtual void clear () = 0; - - /** - * Determine an estimate for the memory consumption (in bytes) of this - * object. - */ - virtual std::size_t memory_consumption () const = 0; - - /** - * Pointer to the DoFHandler object that the vector is based on. - */ - SmartPointer<const DH> dof_handler; - - /** - * Names of the components of this data vector. - */ - const std::vector<std::string> names; - - /** - * A vector that for each of the n_output_variables variables of the - * current data set indicates whether they are scalar fields, parts of a - * vector-field, or any of the other supported kinds of data. - */ - const std::vector<DataComponentInterpretation::DataComponentInterpretation> - data_component_interpretation; - - /** - * Pointer to a DataPostprocessing object which shall be applied to this - * data vector. - */ - SmartPointer<const dealii::DataPostprocessor<DH::space_dimension> > postprocessor; - - /** - * Number of output variables this dataset provides (either number of - * components in vector valued function / data vector or number of - * computed quantities, if DataPostprocessor is applied). This variable - * is determined via and thus equivalent to <tt>names.size()</tt>. - */ - unsigned int n_output_variables; - }; - - - /** - * A data structure that holds all data needed in one thread when building - * patches in parallel. These data structures are created globally rather - * than on each cell to avoid allocation of memory in the threads. This is - * a base class for the AdditionalData kind of data structure discussed in - * the documentation of the WorkStream class. - * - * The <code>cell_to_patch_index_map</code> is an array that stores for - * index <tt>[i][j]</tt> the number of the patch that associated with the - * cell with index @p j on level @p i. This information is set up prior to - * generation of the patches, and is needed to generate neighborship - * information. - * - * This structure is used by several of the DataOut* classes, which - * derived their own ParallelData classes from it for additional fields. - */ - template <int dim, int spacedim> - struct ParallelDataBase - { - ParallelDataBase (const unsigned int n_datasets, - const unsigned int n_subdivisions, - const std::vector<unsigned int> &n_postprocessor_outputs, - const Mapping<dim,spacedim> &mapping, - const std::vector<std_cxx1x::shared_ptr<dealii::hp::FECollection<dim,spacedim> > > &finite_elements, - const UpdateFlags update_flags, - const bool use_face_values); - - ParallelDataBase (const ParallelDataBase &data); - - template <typename DH> - void reinit_all_fe_values(std::vector<std_cxx1x::shared_ptr<DataEntryBase<DH> > > &dof_data, - const typename dealii::Triangulation<dim,spacedim>::cell_iterator &cell, - const unsigned int face = numbers::invalid_unsigned_int); - - const FEValuesBase<dim,spacedim> & - get_present_fe_values(const unsigned int dataset) const; - - void resize_system_vectors(const unsigned int n_components); - - const unsigned int n_datasets; - const unsigned int n_subdivisions; - - std::vector<double> patch_values; - std::vector<dealii::Vector<double> > patch_values_system; - std::vector<Tensor<1,spacedim> > patch_gradients; - std::vector<std::vector<Tensor<1,spacedim> > > patch_gradients_system; - std::vector<Tensor<2,spacedim> > patch_hessians; - std::vector<std::vector<Tensor<2,spacedim> > > patch_hessians_system; - std::vector<std::vector<dealii::Vector<double> > > postprocessed_values; - - const dealii::hp::MappingCollection<dim,spacedim> mapping_collection; - const std::vector<std_cxx1x::shared_ptr<dealii::hp::FECollection<dim,spacedim> > > finite_elements; - const UpdateFlags update_flags; - - std::vector<std_cxx1x::shared_ptr<dealii::hp::FEValues<dim,spacedim> > > x_fe_values; - std::vector<std_cxx1x::shared_ptr<dealii::hp::FEFaceValues<dim,spacedim> > > x_fe_face_values; - }; - - /** * A derived class for use in the DataOut class. This is a class for the * AdditionalData kind of data structure discussed in the documentation of @@ -274,591 +56,6 @@ namespace internal } -//TODO: Most of the documentation of DataOut_DoFData applies to DataOut. - -/** - * This is an abstract class which provides the functionality to generate - * patches for output by base classes from data vectors on a grid. It allows - * to store one or more pointers to a DoFHandler and attached node and cell - * data denoting functions on the grid which shall later be written in any of - * the implemented data formats. - * - * - * <h3>User visible interface</h3> - * - * The user visible interface of this class allows the user to specify data in - * two different ways. One is to make a DoFHandler object known to this class - * and to add data vectors that all correspond to this DoFHandler or the grid - * cells which will later be written to a file in some format. The second - * approach is to pass a DoFHandler object along with the vector. This allows - * setting data from different DoFHandlers in a neat way (of course, they both - * need to be based on the same triangulation). Instead of pondering about the - * different functions, an example for the first kind is probably the best - * explanation: - * @code - * ... - * ... // compute solution, which contains nodal values - * ... - * ... // compute error_estimator, which contains one value per cell - * - * std::vector<std::string> solution_names; - * solution_names.push_back ("x-displacement"); - * solution_names.push_back ("y-displacement"); - * - * DataOut<dim> data_out; - * data_out.attach_dof_handler (dof_handler); - * data_out.add_data_vector (solution, solution_names); - * data_out.add_data_vector (error_estimator, "estimated_error"); - * - * data_out.build_patches (); - * - * ofstream output_file ("output"); - * data_out.write_xxx (output_file); - * - * data_out.clear(); - * @endcode - * - * attach_dof_handler() tells this class that all future operations - * are to take place with the DoFHandler object and the triangulation - * it lives on. We then add the solution vector and the error - * estimator; note that they have different dimensions, because the - * solution is a nodal vector, here consisting of two components - * ("x-displacement" and "y-displacement") while the error estimator - * probably is a vector holding cell data. When attaching a data - * vector, you have to give a name to each component of the vector, - * which is done through an object of type <tt>vector<string></tt> as - * second argument; if only one component is in the vector, for - * example if we are adding cell data as in the second case, or if the - * finite element used by the DoFHandler has only one component, then - * you can use the second add_data_vector() function which takes a @p - * string instead of the <tt>vector<string></tt>. - * - * The add_data_vector() functions have additional arguments (with default - * values) that can be used to specify certain transformations. In particular, - * it allows to attach DataPostprocessor arguments to compute derived - * information from a data vector at each point at which the field will - * be evaluated so that it can be written to a file (for example, the - * Mach number in hypersonic flow can be computed from density and velocities; - * step-29 also shows an example); another piece of information - * specified through arguments with default values is how certain output - * components should be interpreted, i.e. whether each component of the data - * is logically an independent scalar field, or whether some of them together - * form logically a vector-field (see the - * DataComponentInterpretation::DataComponentInterpretation enum, and the @ref - * step_22 "step-22" tutorial program). - * - * It should be noted that this class does not copy the vector given to it through - * the add_data_vector() functions, for memory consumption reasons. It only - * stores a reference to it, so it is in your responsibility to make sure that - * the data vectors exist long enough. - * - * After adding all data vectors, you need to call a function which generates - * the patches for output from the stored data. Derived classes name this - * function build_patches(). Finally, you write() the data in one format or other, - * to a file. - * - * Please note that in the example above, an object of type DataOut was - * used, i.e. an object of a derived class. This is necessary since this - * class does not provide means to actually generate the patches, only aids to - * store and access data. - * - * Note that the base class of this class, DataOutInterface offers - * several functions to ease programming with run-time determinable - * output formats (i.e. you need not use a fixed format by calling - * DataOutInterface::write_xxx in the above example, but you can - * select it by a run-time parameter without having to write the - * <tt>if () ... else ...</tt> clauses yourself), and also functions - * and classes offering ways to control the appearance of the output - * by setting flags for each output format. - * - * - * <h3>Information for derived classes</h3> - * - * What is actually missing this class is a way to produce the patches - * for output itself, from the stored data and degree of freedom - * information. Since this task is often application dependent it is - * left to derived classes. For example, in many applications, it - * might be wanted to limit the depth of output to a certain number of - * refinement levels and write data from finer cells only in a way - * interpolated to coarser cells, to reduce the amount of - * output. Also, it might be wanted to use different numbers of - * subdivisions on different cells when forming a patch, for example - * to accomplish for different polynomial degrees of the trial space - * on different cells. Also, the output need not necessarily consist - * of a patch for each cell, but might be made up of patches for - * faces, of other things. Take a look at derived classes to what is - * possible in this respect. - * - * For this reason, it is left to a derived class to provide a - * function, named usually build_patches() or the like, which fills - * the #patches array of this class. - * - * Regarding the templates of this class, it needs three values: first - * the space dimension in which the triangulation and the DoF handler - * operate, second the dimension of the objects which the patches - * represent. Although in most cases they are equal, there are also - * classes for which this does not hold, for example if one outputs - * the result of a computation exploiting rotational symmetry in the - * original domain (in which the space dimension of the output would - * be one higher than that of the DoF handler, see the - * DataOut_Rotation() class), or one might conceive that one could - * write a class that only outputs the solution on a cut through the - * domain, in which case the space dimension of the output is less - * than that of the DoF handler. The last template argument denotes - * the dimension of the space into which the patches are embedded; - * usually, this dimension is the same as the dimensio of the patches - * themselves (which is also the default value of the template - * parameter), but there might be cases where this is not so. For - * example, in the DataOut_Faces() class, patches are generated - * from faces of the triangulation. Thus, the dimension of the patch - * is one less than the dimension of the embedding space, which is, in - * this case, equal to the dimension of the triangulation and DoF - * handler. However, for the cut through the domain mentioned above, - * if the cut is a straight one, then the cut can be embedded into a - * space of one dimension lower than the dimension of the - * triangulation, so that the last template parameter has the same - * value as the second one. - * - * @ingroup output - * @author Wolfgang Bangerth, 1999 - */ -template <class DH, int patch_dim, int patch_space_dim=patch_dim> -class DataOut_DoFData : public DataOutInterface<patch_dim,patch_space_dim> -{ -public: - - /** - * Typedef to the iterator type of the dof handler class under - * consideration. - */ - typedef typename Triangulation<DH::dimension,DH::space_dimension>::cell_iterator cell_iterator; - typedef typename Triangulation<DH::dimension,DH::space_dimension>::active_cell_iterator active_cell_iterator; - -public: - - /** - * Type describing what the vector given to add_data_vector() is: a vector - * that has one entry per degree of freedom in a DoFHandler object (such as - * solution vectors), or one entry per cell in the triangulation underlying - * the DoFHandler object (such as error per cell data). The value - * #type_automatic tells add_data_vector() to find out itself (see the - * documentation of add_data_vector() for the method used). - */ - enum DataVectorType - { - /** - * Data vector entries are associated to degrees of freedom - */ - type_dof_data, - - /** - * Data vector entries are one per grid cell - */ - type_cell_data, - - /** - * Find out automatically - */ - type_automatic - }; - - /** - * Constructor - */ - DataOut_DoFData (); - - /** - * Destructor. - */ - virtual ~DataOut_DoFData (); - - /** - * Designate a dof handler to be used to extract geometry data and the - * mapping between nodes and node values. This call is not necessary if all - * added data vectors are supplemented with a DoFHandler argument. - * - * This call is optional: If you add data vectors with specified DoFHandler - * object, then that contains all information needed to generate the output. - */ - void attach_dof_handler (const DH &); - - /** - * Designate a triangulation to be used to extract geometry data and the - * mapping between nodes and node values. - * - * This call is optional: If you add data vectors with specified DoFHandler - * object, then that contains all information needed to generate the - * output. This call is useful when you only output cell vectors and no - * DoFHandler at all, in which case it provides the geometry. - */ - void attach_triangulation (const Triangulation<DH::dimension, - DH::space_dimension> &); - - /** - * Add a data vector together with its name. - * - * A pointer to the vector is stored, so you have to make sure the vector - * exists at that address at least as long as you call the <tt>write_*</tt> - * functions. - * - * It is assumed that the vector has the same number of components as there - * are degrees of freedom in the dof handler, in which case it is assumed to - * be a vector storing nodal data; or the size may be the number of active - * cells on the present grid, in which case it is assumed to be a cell data - * vector. As the number of degrees of freedom and of cells is usually not - * equal, the function can determine itself which type of vector it is - * given. However, there are corner cases where this automatic determination - * does not work. One example is if you compute with piecewise constant - * elements and have a scalar solution, then there are as many cells as - * there are degrees of freedom (though they may be numbered - * differently). Another possibility is if you have a 1d mesh embedded in 2d - * space and the mesh consists of a closed curve of cells; in this case, - * there are as many nodes as there are cells, and when using a Q1 element - * you will have as many degrees of freedom as there are cells. In these - * cases, you can change the last argument of the function from its default - * value #type_automatic to either #type_dof_data or #type_cell_data, - * depending on what the vector represents. Apart from such corner cases, - * you can leave the argument at its default value and let the function - * determine the type of the vector itself. - * - * If it is a vector holding DoF data, the names given shall be one for each - * component of the underlying finite element. If it is a finite element - * composed of only one subelement, then there is another function following - * which takes a single name instead of a vector of names. - * - * The data_component_interpretation argument contains information about how - * the individual components of output files that consist of more than one - * data set are to be interpreted. - * - * For example, if one has a finite element for the Stokes equations in 2d, - * representing components (u,v,p), one would like to indicate that the - * first two, u and v, represent a logical vector so that later on when we - * generate graphical output we can hand them off to a visualization program - * that will automatically know to render them as a vector field, rather - * than as two separate and independent scalar fields. - * - * The default value of this argument (i.e. an empty vector) corresponds is - * equivalent to a vector of values - * DataComponentInterpretation::component_is_scalar, indicating that all - * output components are independent scalar fields. However, if the given - * data vector represents logical vectors, you may pass a vector that - * contains values - * DataComponentInterpretation::component_is_part_of_vector. In the example - * above, one would pass in a vector with components - * (DataComponentInterpretation::component_is_part_of_vector, - * DataComponentInterpretation::component_is_part_of_vector, - * DataComponentInterpretation::component_is_scalar) for (u,v,p). - * - * The names of a data vector shall only contain characters which are - * letters, underscore and a few other ones. Refer to the - * ExcInvalidCharacter exception declared in this class to see which - * characters are valid and which are not. - * - * @note The actual type for the vector argument may be any vector type from - * which FEValues can extract values on a cell using the - * FEValuesBase::get_function_values() function. In particular, this - * includes all of the usual vector types, but also IndexSet (see step-41 - * for a use of this). - */ - template <class VECTOR> - void add_data_vector (const VECTOR &data, - const std::vector<std::string> &names, - const DataVectorType type = type_automatic, - const std::vector<DataComponentInterpretation::DataComponentInterpretation> &data_component_interpretation - = std::vector<DataComponentInterpretation::DataComponentInterpretation>()); - - /** - * This function is an abbreviation to the above one (see there for a - * discussion of the various arguments), intended for use with finite - * elements that are not composed of subelements. In this case, only one - * name per data vector needs to be given, which is what this function - * takes. It simply relays its arguments after a conversion of the @p name - * to a vector of strings, to the other add_data_vector() function above. - * - * If @p data is a vector with multiple components this function will - * generate distinct names for all components by appending an underscore and - * the number of each component to @p name - * - * The actual type for the template argument may be any vector type from - * which FEValues can extract values on a cell using the - * FEValuesBase::get_function_values() function. - */ - template <class VECTOR> - void add_data_vector (const VECTOR &data, - const std::string &name, - const DataVectorType type = type_automatic, - const std::vector<DataComponentInterpretation::DataComponentInterpretation> &data_component_interpretation - = std::vector<DataComponentInterpretation::DataComponentInterpretation>()); - - /** - * This function is an extension of the above one (see there for a - * discussion of the arguments except the first one) and allows to set a - * vector with its own DoFHandler object. This DoFHandler needs to be - * compatible with the other DoFHandler objects assigned with calls to @p - * add_data_vector or @p attach_dof_handler, in the sense that the - * DoFHandler objects need to be based on the same triangulation. This - * function allows you to export data from multiple DoFHandlers that - * describe different solution components. - * - * Since this function takes a DoFHandler object and hence naturally - * represents dof data, the data vector type argument present in the other - * methods above is skipped. - */ - template <class VECTOR> - void add_data_vector (const DH &dof_handler, - const VECTOR &data, - const std::vector<std::string> &names, - const std::vector<DataComponentInterpretation::DataComponentInterpretation> &data_component_interpretation - = std::vector<DataComponentInterpretation::DataComponentInterpretation>()); - - - /** - * This function is an abbreviation of the function above with only a scalar - * @p dof_handler given and a single data name. - */ - template <class VECTOR> - void add_data_vector (const DH &dof_handler, - const VECTOR &data, - const std::string &name, - const std::vector<DataComponentInterpretation::DataComponentInterpretation> &data_component_interpretation - = std::vector<DataComponentInterpretation::DataComponentInterpretation>()); - - /** - * This function is an alternative to the above ones, allowing the output of - * derived quantities instead of the given data. This converison has to be - * done in a class derived from DataPostprocessor. - * - * The names for these derived quantities are provided by the @p - * data_postprocessor argument. Likewise, the data_component_interpretation - * argument of the other add_data_vector() functions is provided by the - * data_postprocessor argument. As only data of type @p type_dof_data can be - * transformed, this type is also known implicitly and does not have to be - * given. - * - * @note The actual type for the vector argument may be any vector type from - * which FEValues can extract values on a cell using the - * FEValuesBase::get_function_values() function. In particular, this - * includes all of the usual vector types, but also IndexSet (see step-41 - * for a use of this). - */ - template <class VECTOR> - void add_data_vector (const VECTOR &data, - const DataPostprocessor<DH::space_dimension> &data_postprocessor); - - /** - * Same function as above, but with a DoFHandler object that does not need - * to coincide with the DoFHandler initially set. Note that the - * postprocessor can only read data from the given DoFHandler and solution - * vector, not other solution vectors or DoFHandlers. - */ - template <class VECTOR> - void add_data_vector (const DH &dof_handler, - const VECTOR &data, - const DataPostprocessor<DH::space_dimension> &data_postprocessor); - - /** - * Release the pointers to the data vectors. This allows output of a new set - * of vectors without supplying the DoF handler again. Therefore, the - * DataOut object can be used in an algebraic context. Note that besides the - * data vectors also the patches already computed are deleted. - */ - void clear_data_vectors (); - - /** - * Release pointers to all input data elements, i.e. pointers to data - * vectors and to the DoF handler object. This function may be useful when - * you have called the @p build_patches function of derived class, since - * then the patches are built and the input data is no more needed, nor is - * there a need to reference it. You can then output the patches detached - * from the main thread and need not make sure anymore that the DoF handler - * object and vectors must not be deleted before the output thread is - * finished. - */ - void clear_input_data_references (); - - /** - * This function can be used to merge the patches that were created using - * the @p build_patches function of the object given as argument into the - * list of patches created by this object. This is sometimes handy if one - * has, for example, a domain decomposition algorithm where each block is - * represented by a DoFHandler of its own, but one wants to output the - * solution on all the blocks at the same time. - * - * For this to work, the given argument and this object need to have the - * same number of output vectors, and they need to use the same number of - * subdivisions per patch. The output will probably look rather funny if - * patches in both objects overlap in space. - * - * If you call build_patches() for this object after merging in patches, the - * previous state is overwritten, and the merged-in patches are lost. - * - * The second parameter allows to shift each node of the patches in the - * object passed in in the first parameter by a certain amount. This is - * sometimes useful to generate "exploded" views of a collection of blocks. - * - * This function will fail if either this or the other object did not yet - * set up any patches. - */ - template <class DH2> - void merge_patches (const DataOut_DoFData<DH2,patch_dim,patch_space_dim> &source, - const Point<patch_space_dim> &shift = Point<patch_space_dim>()); - - /** - * Release the pointers to the data vectors and the DoF handler. You have to - * set all data entries again using the add_data_vector() function. The - * pointer to the dof handler is cleared as well, along with all other - * data. In effect, this function resets everything to a virgin state. - */ - virtual void clear (); - - /** - * Determine an estimate for the memory consumption (in bytes) of this - * object. - */ - std::size_t memory_consumption () const; - - /** - * Exception - */ - DeclException0 (ExcNoTriangulationSelected); - - /** - * Exception - */ - DeclException0 (ExcNoDoFHandlerSelected); - - /** - * Exception - */ - DeclException0 (ExcDataPostprocessingIsNotPossibleForCellData); - - /** - * Exception - */ - DeclException3 (ExcInvalidVectorSize, - int, int, int, - << "The vector has size " << arg1 - << " but the DoFHandler objects says there are " << arg2 - << " degrees of freedom and there are " << arg3 - << " active cells."); - /** - * Exception - */ - DeclException2 (ExcInvalidCharacter, - std::string, size_t, - << "Please use only the characters [a-zA-Z0-9_<>()] for" << std::endl - << "description strings since some graphics formats will only accept these." - << std::endl - << "The string you gave was <" << arg1 - << ">, the invalid character is <" << arg1[arg2] - << ">." << std::endl); - /** - * Exception - */ - DeclException0 (ExcOldDataStillPresent); - /** - * Exception - */ - DeclException2 (ExcInvalidNumberOfNames, - int, int, - << "You have to give one name per component in your " - << "data vector. The number you gave was " << arg1 - << ", but the number of components is " << arg2); - /** - * Exception - */ - DeclException0 (ExcNoPatches); - /** - * Exception - */ - DeclException0 (ExcIncompatibleDatasetNames); - /** - * Exception - */ - DeclException0 (ExcIncompatiblePatchLists); - - DeclException2 (ExcInvalidVectorDeclaration, - int, std::string, - << "When declaring that a number of components in a data\n" - << "set to be output logically form a vector instead of\n" - << "simply a set of scalar fields, you need to specify\n" - << "this for all relevant components. Furthermore,\n" - << "vectors must always consist of exactly <dim>\n" - << "components. However, the vector component at\n" - << "position " << arg1 << " with name <" << arg2 - << "> does not satisfy these conditions."); - -protected: - /** - * Abbreviate the somewhat lengthy name for the Patch class. - */ - typedef dealii::DataOutBase::Patch<patch_dim,patch_space_dim> Patch; - - /** - * Pointer to the triangulation object. - */ - SmartPointer<const Triangulation<DH::dimension,DH::space_dimension> > triangulation; - - /** - * Pointer to the optional handler object. - */ - SmartPointer<const DH> dofs; - - /** - * List of data elements with vectors of values for each degree of freedom. - */ - std::vector<std_cxx1x::shared_ptr<internal::DataOut::DataEntryBase<DH> > > dof_data; - - /** - * List of data elements with vectors of values for each cell. - */ - std::vector<std_cxx1x::shared_ptr<internal::DataOut::DataEntryBase<DH> > > cell_data; - - /** - * This is a list of patches that is created each time build_patches() is - * called. These patches are used in the output routines of the base - * classes. - */ - std::vector<Patch> patches; - - /** - * Function by which the base class's functions get to know what patches - * they shall write to a file. - */ - virtual - const std::vector<Patch> &get_patches () const; - - /** - * Virtual function through which the names of data sets are obtained by the - * output functions of the base class. - */ - virtual - std::vector<std::string> get_dataset_names () const; - - /** - * Extracts the finite elements stored in the dof_data object, including a - * dummy object of FE_DGQ<dim>(0) in case only the triangulation is used. - */ - std::vector<std_cxx1x::shared_ptr<dealii::hp::FECollection<DH::dimension,DH::space_dimension> > > - get_finite_elements() const; - - /** - * Overload of the respective DataOutInterface::get_vector_data_ranges() - * function. See there for a more extensive documentation. - */ - virtual - std::vector<std_cxx1x::tuple<unsigned int, unsigned int, std::string> > - get_vector_data_ranges () const; - - /** - * Make all template siblings friends. Needed for the merge_patches() - * function. - */ - template <class, int, int> - friend class DataOut_DoFData; -}; - - /** * This class is the main class to provide output of data described by finite @@ -1061,83 +258,6 @@ private: -// -------------------- template and inline functions ------------------------ - - -template <class DH, int patch_dim, int patch_space_dim> -template <class DH2> -void -DataOut_DoFData<DH,patch_dim,patch_space_dim>:: -merge_patches (const DataOut_DoFData<DH2,patch_dim,patch_space_dim> &source, - const Point<patch_space_dim> &shift) -{ - const std::vector<Patch> source_patches = source.get_patches (); - Assert (patches.size () != 0, ExcNoPatches ()); - Assert (source_patches.size () != 0, ExcNoPatches ()); - // check equality of component - // names - Assert (get_dataset_names() == source.get_dataset_names(), - ExcIncompatibleDatasetNames()); - // make sure patches are compatible. we'll - // assume that if the first respective - // patches are ok that all the other ones - // are ok as well - Assert (patches[0].n_subdivisions == source_patches[0].n_subdivisions, - ExcIncompatiblePatchLists()); - Assert (patches[0].data.n_rows() == source_patches[0].data.n_rows(), - ExcIncompatiblePatchLists()); - Assert (patches[0].data.n_cols() == source_patches[0].data.n_cols(), - ExcIncompatiblePatchLists()); - - // check equality of the vector data - // specifications - Assert (get_vector_data_ranges().size() == - source.get_vector_data_ranges().size(), - ExcMessage ("Both sources need to declare the same components " - "as vectors.")); - for (unsigned int i=0; i<get_vector_data_ranges().size(); ++i) - { - Assert (std_cxx1x::get<0>(get_vector_data_ranges()[i]) == - std_cxx1x::get<0>(source.get_vector_data_ranges()[i]), - ExcMessage ("Both sources need to declare the same components " - "as vectors.")); - Assert (std_cxx1x::get<1>(get_vector_data_ranges()[i]) == - std_cxx1x::get<1>(source.get_vector_data_ranges()[i]), - ExcMessage ("Both sources need to declare the same components " - "as vectors.")); - Assert (std_cxx1x::get<2>(get_vector_data_ranges()[i]) == - std_cxx1x::get<2>(source.get_vector_data_ranges()[i]), - ExcMessage ("Both sources need to declare the same components " - "as vectors.")); - } - - // merge patches. store old number - // of elements, since we need to - // adjust patch numbers, etc - // afterwards - const unsigned int old_n_patches = patches.size(); - patches.insert (patches.end(), - source_patches.begin(), - source_patches.end()); - - // perform shift, if so desired - if (shift != Point<patch_space_dim>()) - for (unsigned int i=old_n_patches; i<patches.size(); ++i) - for (unsigned int v=0; v<GeometryInfo<patch_dim>::vertices_per_cell; ++v) - patches[i].vertices[v] += shift; - - // adjust patch numbers - for (unsigned int i=old_n_patches; i<patches.size(); ++i) - patches[i].patch_index += old_n_patches; - - // adjust patch neighbors - for (unsigned int i=old_n_patches; i<patches.size(); ++i) - for (unsigned int n=0; n<GeometryInfo<patch_dim>::faces_per_cell; ++n) - if (patches[i].neighbors[n] != Patch::no_neighbor) - patches[i].neighbors[n] += old_n_patches; -} - - DEAL_II_NAMESPACE_CLOSE #endif diff --git a/deal.II/include/deal.II/numerics/data_out_dof_data.h b/deal.II/include/deal.II/numerics/data_out_dof_data.h new file mode 100644 index 0000000000..fdc24dbd2f --- /dev/null +++ b/deal.II/include/deal.II/numerics/data_out_dof_data.h @@ -0,0 +1,920 @@ +// --------------------------------------------------------------------- +// $Id$ +// +// Copyright (C) 1999 - 2013 by the deal.II authors +// +// This file is part of the deal.II library. +// +// The deal.II library is free software; you can use it, redistribute +// it, and/or modify it under the terms of the GNU Lesser General +// Public License as published by the Free Software Foundation; either +// version 2.1 of the License, or (at your option) any later version. +// The full text of the license can be found in the file LICENSE at +// the top level of the deal.II distribution. +// +// --------------------------------------------------------------------- + +#ifndef __deal2__data_out_dof_data_h +#define __deal2__data_out_dof_data_h + + + +#include <deal.II/base/config.h> +#include <deal.II/base/smartpointer.h> +#include <deal.II/base/data_out_base.h> +#include <deal.II/dofs/dof_handler.h> +#include <deal.II/grid/tria.h> +#include <deal.II/fe/mapping.h> +#include <deal.II/hp/q_collection.h> +#include <deal.II/hp/fe_collection.h> +#include <deal.II/hp/mapping_collection.h> +#include <deal.II/hp/fe_values.h> +#include <deal.II/numerics/data_postprocessor.h> +#include <deal.II/numerics/data_component_interpretation.h> + +#include <deal.II/base/std_cxx1x/shared_ptr.h> + +DEAL_II_NAMESPACE_OPEN + +template <int, int> class FEValuesBase; + +namespace internal +{ + namespace DataOut + { + /** + * For each vector that has been added through the add_data_vector() + * functions, we need to keep track of a pointer to it, and allow data + * extraction from it when we generate patches. Unfortunately, we need to + * do this for a number of different vector types. Fortunately, they all + * have the same interface. So the way we go is to have a base class that + * provides the functions to access the vector's information, and to have + * a derived template class that can be instantiated for each vector + * type. Since the vectors all have the same interface, this is no big + * problem, as they can all use the same general templatized code. + * + * @author Wolfgang Bangerth, 2004 + */ + template <class DH> + class DataEntryBase + { + public: + /** + * Constructor. Give a list of names for the individual components of + * the vector and their interpretation as scalar or vector data. This + * constructor assumes that no postprocessor is going to be used. + */ + DataEntryBase (const DH *dofs, + const std::vector<std::string> &names, + const std::vector<DataComponentInterpretation::DataComponentInterpretation> &data_component_interpretation); + + /** + * Constructor when a data postprocessor is going to be used. In that + * case, the names and vector declarations are going to be acquired from + * the postprocessor. + */ + DataEntryBase (const DH *dofs, + const DataPostprocessor<DH::space_dimension> *data_postprocessor); + + /** + * Destructor made virtual. + */ + virtual ~DataEntryBase (); + + /** + * Assuming that the stored vector is a cell vector, extract the given + * element from it. + */ + virtual + double + get_cell_data_value (const unsigned int cell_number) const = 0; + + /** + * Given a FEValuesBase object, extract the values on the present cell + * from the vector we actually store. + */ + virtual + void + get_function_values (const FEValuesBase<DH::dimension,DH::space_dimension> &fe_patch_values, + std::vector<double> &patch_values) const = 0; + + /** + * Given a FEValuesBase object, extract the values on the present cell + * from the vector we actually store. This function does the same as the + * one above but for vector-valued finite elements. + */ + virtual + void + get_function_values (const FEValuesBase<DH::dimension,DH::space_dimension> &fe_patch_values, + std::vector<dealii::Vector<double> > &patch_values_system) const = 0; + + /** + * Given a FEValuesBase object, extract the gradients on the present + * cell from the vector we actually store. + */ + virtual + void + get_function_gradients (const FEValuesBase<DH::dimension,DH::space_dimension> &fe_patch_values, + std::vector<Tensor<1,DH::space_dimension> > &patch_gradients) const = 0; + + /** + * Given a FEValuesBase object, extract the gradients on the present + * cell from the vector we actually store. This function does the same + * as the one above but for vector-valued finite elements. + */ + virtual + void + get_function_gradients (const FEValuesBase<DH::dimension,DH::space_dimension> &fe_patch_values, + std::vector<std::vector<Tensor<1,DH::space_dimension> > > &patch_gradients_system) const = 0; + + /** + * Given a FEValuesBase object, extract the second derivatives on the + * present cell from the vector we actually store. + */ + virtual + void + get_function_hessians (const FEValuesBase<DH::dimension,DH::space_dimension> &fe_patch_values, + std::vector<Tensor<2,DH::space_dimension> > &patch_hessians) const = 0; + + /** + * Given a FEValuesBase object, extract the second derivatives on the + * present cell from the vector we actually store. This function does + * the same as the one above but for vector-valued finite elements. + */ + virtual + void + get_function_hessians (const FEValuesBase<DH::dimension,DH::space_dimension> &fe_patch_values, + std::vector<std::vector< Tensor<2,DH::space_dimension> > > &patch_hessians_system) const = 0; + + /** + * Clear all references to the vectors. + */ + virtual void clear () = 0; + + /** + * Determine an estimate for the memory consumption (in bytes) of this + * object. + */ + virtual std::size_t memory_consumption () const = 0; + + /** + * Pointer to the DoFHandler object that the vector is based on. + */ + SmartPointer<const DH> dof_handler; + + /** + * Names of the components of this data vector. + */ + const std::vector<std::string> names; + + /** + * A vector that for each of the n_output_variables variables of the + * current data set indicates whether they are scalar fields, parts of a + * vector-field, or any of the other supported kinds of data. + */ + const std::vector<DataComponentInterpretation::DataComponentInterpretation> + data_component_interpretation; + + /** + * Pointer to a DataPostprocessing object which shall be applied to this + * data vector. + */ + SmartPointer<const dealii::DataPostprocessor<DH::space_dimension> > postprocessor; + + /** + * Number of output variables this dataset provides (either number of + * components in vector valued function / data vector or number of + * computed quantities, if DataPostprocessor is applied). This variable + * is determined via and thus equivalent to <tt>names.size()</tt>. + */ + unsigned int n_output_variables; + }; + + + /** + * A data structure that holds all data needed in one thread when building + * patches in parallel. These data structures are created globally rather + * than on each cell to avoid allocation of memory in the threads. This is + * a base class for the AdditionalData kind of data structure discussed in + * the documentation of the WorkStream class. + * + * The <code>cell_to_patch_index_map</code> is an array that stores for + * index <tt>[i][j]</tt> the number of the patch that associated with the + * cell with index @p j on level @p i. This information is set up prior to + * generation of the patches, and is needed to generate neighborship + * information. + * + * This structure is used by several of the DataOut* classes, which + * derived their own ParallelData classes from it for additional fields. + */ + template <int dim, int spacedim> + struct ParallelDataBase + { + ParallelDataBase (const unsigned int n_datasets, + const unsigned int n_subdivisions, + const std::vector<unsigned int> &n_postprocessor_outputs, + const Mapping<dim,spacedim> &mapping, + const std::vector<std_cxx1x::shared_ptr<dealii::hp::FECollection<dim,spacedim> > > &finite_elements, + const UpdateFlags update_flags, + const bool use_face_values); + + ParallelDataBase (const ParallelDataBase &data); + + template <typename DH> + void reinit_all_fe_values(std::vector<std_cxx1x::shared_ptr<DataEntryBase<DH> > > &dof_data, + const typename dealii::Triangulation<dim,spacedim>::cell_iterator &cell, + const unsigned int face = numbers::invalid_unsigned_int); + + const FEValuesBase<dim,spacedim> & + get_present_fe_values(const unsigned int dataset) const; + + void resize_system_vectors(const unsigned int n_components); + + const unsigned int n_datasets; + const unsigned int n_subdivisions; + + std::vector<double> patch_values; + std::vector<dealii::Vector<double> > patch_values_system; + std::vector<Tensor<1,spacedim> > patch_gradients; + std::vector<std::vector<Tensor<1,spacedim> > > patch_gradients_system; + std::vector<Tensor<2,spacedim> > patch_hessians; + std::vector<std::vector<Tensor<2,spacedim> > > patch_hessians_system; + std::vector<std::vector<dealii::Vector<double> > > postprocessed_values; + + const dealii::hp::MappingCollection<dim,spacedim> mapping_collection; + const std::vector<std_cxx1x::shared_ptr<dealii::hp::FECollection<dim,spacedim> > > finite_elements; + const UpdateFlags update_flags; + + std::vector<std_cxx1x::shared_ptr<dealii::hp::FEValues<dim,spacedim> > > x_fe_values; + std::vector<std_cxx1x::shared_ptr<dealii::hp::FEFaceValues<dim,spacedim> > > x_fe_face_values; + }; + } +} + + +//TODO: Most of the documentation of DataOut_DoFData applies to DataOut. + +/** + * This is an abstract class which provides the functionality to generate + * patches for output by base classes from data vectors on a grid. It allows + * to store one or more pointers to a DoFHandler and attached node and cell + * data denoting functions on the grid which shall later be written in any of + * the implemented data formats. + * + * + * <h3>User visible interface</h3> + * + * The user visible interface of this class allows the user to specify data in + * two different ways. One is to make a DoFHandler object known to this class + * and to add data vectors that all correspond to this DoFHandler or the grid + * cells which will later be written to a file in some format. The second + * approach is to pass a DoFHandler object along with the vector. This allows + * setting data from different DoFHandlers in a neat way (of course, they both + * need to be based on the same triangulation). Instead of pondering about the + * different functions, an example for the first kind is probably the best + * explanation: + * @code + * ... + * ... // compute solution, which contains nodal values + * ... + * ... // compute error_estimator, which contains one value per cell + * + * std::vector<std::string> solution_names; + * solution_names.push_back ("x-displacement"); + * solution_names.push_back ("y-displacement"); + * + * DataOut<dim> data_out; + * data_out.attach_dof_handler (dof_handler); + * data_out.add_data_vector (solution, solution_names); + * data_out.add_data_vector (error_estimator, "estimated_error"); + * + * data_out.build_patches (); + * + * ofstream output_file ("output"); + * data_out.write_xxx (output_file); + * + * data_out.clear(); + * @endcode + * + * attach_dof_handler() tells this class that all future operations + * are to take place with the DoFHandler object and the triangulation + * it lives on. We then add the solution vector and the error + * estimator; note that they have different dimensions, because the + * solution is a nodal vector, here consisting of two components + * ("x-displacement" and "y-displacement") while the error estimator + * probably is a vector holding cell data. When attaching a data + * vector, you have to give a name to each component of the vector, + * which is done through an object of type <tt>vector<string></tt> as + * second argument; if only one component is in the vector, for + * example if we are adding cell data as in the second case, or if the + * finite element used by the DoFHandler has only one component, then + * you can use the second add_data_vector() function which takes a @p + * string instead of the <tt>vector<string></tt>. + * + * The add_data_vector() functions have additional arguments (with default + * values) that can be used to specify certain transformations. In particular, + * it allows to attach DataPostprocessor arguments to compute derived + * information from a data vector at each point at which the field will + * be evaluated so that it can be written to a file (for example, the + * Mach number in hypersonic flow can be computed from density and velocities; + * step-29 also shows an example); another piece of information + * specified through arguments with default values is how certain output + * components should be interpreted, i.e. whether each component of the data + * is logically an independent scalar field, or whether some of them together + * form logically a vector-field (see the + * DataComponentInterpretation::DataComponentInterpretation enum, and the @ref + * step_22 "step-22" tutorial program). + * + * It should be noted that this class does not copy the vector given to it through + * the add_data_vector() functions, for memory consumption reasons. It only + * stores a reference to it, so it is in your responsibility to make sure that + * the data vectors exist long enough. + * + * After adding all data vectors, you need to call a function which generates + * the patches for output from the stored data. Derived classes name this + * function build_patches(). Finally, you write() the data in one format or other, + * to a file. + * + * Please note that in the example above, an object of type DataOut was + * used, i.e. an object of a derived class. This is necessary since this + * class does not provide means to actually generate the patches, only aids to + * store and access data. + * + * Note that the base class of this class, DataOutInterface offers + * several functions to ease programming with run-time determinable + * output formats (i.e. you need not use a fixed format by calling + * DataOutInterface::write_xxx in the above example, but you can + * select it by a run-time parameter without having to write the + * <tt>if () ... else ...</tt> clauses yourself), and also functions + * and classes offering ways to control the appearance of the output + * by setting flags for each output format. + * + * + * <h3>Information for derived classes</h3> + * + * What is actually missing this class is a way to produce the patches + * for output itself, from the stored data and degree of freedom + * information. Since this task is often application dependent it is + * left to derived classes. For example, in many applications, it + * might be wanted to limit the depth of output to a certain number of + * refinement levels and write data from finer cells only in a way + * interpolated to coarser cells, to reduce the amount of + * output. Also, it might be wanted to use different numbers of + * subdivisions on different cells when forming a patch, for example + * to accomplish for different polynomial degrees of the trial space + * on different cells. Also, the output need not necessarily consist + * of a patch for each cell, but might be made up of patches for + * faces, of other things. Take a look at derived classes to what is + * possible in this respect. + * + * For this reason, it is left to a derived class to provide a + * function, named usually build_patches() or the like, which fills + * the #patches array of this class. + * + * Regarding the templates of this class, it needs three values: first + * the space dimension in which the triangulation and the DoF handler + * operate, second the dimension of the objects which the patches + * represent. Although in most cases they are equal, there are also + * classes for which this does not hold, for example if one outputs + * the result of a computation exploiting rotational symmetry in the + * original domain (in which the space dimension of the output would + * be one higher than that of the DoF handler, see the + * DataOut_Rotation() class), or one might conceive that one could + * write a class that only outputs the solution on a cut through the + * domain, in which case the space dimension of the output is less + * than that of the DoF handler. The last template argument denotes + * the dimension of the space into which the patches are embedded; + * usually, this dimension is the same as the dimensio of the patches + * themselves (which is also the default value of the template + * parameter), but there might be cases where this is not so. For + * example, in the DataOut_Faces() class, patches are generated + * from faces of the triangulation. Thus, the dimension of the patch + * is one less than the dimension of the embedding space, which is, in + * this case, equal to the dimension of the triangulation and DoF + * handler. However, for the cut through the domain mentioned above, + * if the cut is a straight one, then the cut can be embedded into a + * space of one dimension lower than the dimension of the + * triangulation, so that the last template parameter has the same + * value as the second one. + * + * @ingroup output + * @author Wolfgang Bangerth, 1999 + */ +template <class DH, int patch_dim, int patch_space_dim=patch_dim> +class DataOut_DoFData : public DataOutInterface<patch_dim,patch_space_dim> +{ +public: + + /** + * Typedef to the iterator type of the dof handler class under + * consideration. + */ + typedef typename Triangulation<DH::dimension,DH::space_dimension>::cell_iterator cell_iterator; + typedef typename Triangulation<DH::dimension,DH::space_dimension>::active_cell_iterator active_cell_iterator; + +public: + + /** + * Type describing what the vector given to add_data_vector() is: a vector + * that has one entry per degree of freedom in a DoFHandler object (such as + * solution vectors), or one entry per cell in the triangulation underlying + * the DoFHandler object (such as error per cell data). The value + * #type_automatic tells add_data_vector() to find out itself (see the + * documentation of add_data_vector() for the method used). + */ + enum DataVectorType + { + /** + * Data vector entries are associated to degrees of freedom + */ + type_dof_data, + + /** + * Data vector entries are one per grid cell + */ + type_cell_data, + + /** + * Find out automatically + */ + type_automatic + }; + + /** + * Constructor + */ + DataOut_DoFData (); + + /** + * Destructor. + */ + virtual ~DataOut_DoFData (); + + /** + * Designate a dof handler to be used to extract geometry data and the + * mapping between nodes and node values. This call is not necessary if all + * added data vectors are supplemented with a DoFHandler argument. + * + * This call is optional: If you add data vectors with specified DoFHandler + * object, then that contains all information needed to generate the output. + */ + void attach_dof_handler (const DH &); + + /** + * Designate a triangulation to be used to extract geometry data and the + * mapping between nodes and node values. + * + * This call is optional: If you add data vectors with specified DoFHandler + * object, then that contains all information needed to generate the + * output. This call is useful when you only output cell vectors and no + * DoFHandler at all, in which case it provides the geometry. + */ + void attach_triangulation (const Triangulation<DH::dimension, + DH::space_dimension> &); + + /** + * Add a data vector together with its name. + * + * A pointer to the vector is stored, so you have to make sure the vector + * exists at that address at least as long as you call the <tt>write_*</tt> + * functions. + * + * It is assumed that the vector has the same number of components as there + * are degrees of freedom in the dof handler, in which case it is assumed to + * be a vector storing nodal data; or the size may be the number of active + * cells on the present grid, in which case it is assumed to be a cell data + * vector. As the number of degrees of freedom and of cells is usually not + * equal, the function can determine itself which type of vector it is + * given. However, there are corner cases where this automatic determination + * does not work. One example is if you compute with piecewise constant + * elements and have a scalar solution, then there are as many cells as + * there are degrees of freedom (though they may be numbered + * differently). Another possibility is if you have a 1d mesh embedded in 2d + * space and the mesh consists of a closed curve of cells; in this case, + * there are as many nodes as there are cells, and when using a Q1 element + * you will have as many degrees of freedom as there are cells. In these + * cases, you can change the last argument of the function from its default + * value #type_automatic to either #type_dof_data or #type_cell_data, + * depending on what the vector represents. Apart from such corner cases, + * you can leave the argument at its default value and let the function + * determine the type of the vector itself. + * + * If it is a vector holding DoF data, the names given shall be one for each + * component of the underlying finite element. If it is a finite element + * composed of only one subelement, then there is another function following + * which takes a single name instead of a vector of names. + * + * The data_component_interpretation argument contains information about how + * the individual components of output files that consist of more than one + * data set are to be interpreted. + * + * For example, if one has a finite element for the Stokes equations in 2d, + * representing components (u,v,p), one would like to indicate that the + * first two, u and v, represent a logical vector so that later on when we + * generate graphical output we can hand them off to a visualization program + * that will automatically know to render them as a vector field, rather + * than as two separate and independent scalar fields. + * + * The default value of this argument (i.e. an empty vector) corresponds is + * equivalent to a vector of values + * DataComponentInterpretation::component_is_scalar, indicating that all + * output components are independent scalar fields. However, if the given + * data vector represents logical vectors, you may pass a vector that + * contains values + * DataComponentInterpretation::component_is_part_of_vector. In the example + * above, one would pass in a vector with components + * (DataComponentInterpretation::component_is_part_of_vector, + * DataComponentInterpretation::component_is_part_of_vector, + * DataComponentInterpretation::component_is_scalar) for (u,v,p). + * + * The names of a data vector shall only contain characters which are + * letters, underscore and a few other ones. Refer to the + * ExcInvalidCharacter exception declared in this class to see which + * characters are valid and which are not. + * + * @note The actual type for the vector argument may be any vector type from + * which FEValues can extract values on a cell using the + * FEValuesBase::get_function_values() function. In particular, this + * includes all of the usual vector types, but also IndexSet (see step-41 + * for a use of this). + */ + template <class VECTOR> + void add_data_vector (const VECTOR &data, + const std::vector<std::string> &names, + const DataVectorType type = type_automatic, + const std::vector<DataComponentInterpretation::DataComponentInterpretation> &data_component_interpretation + = std::vector<DataComponentInterpretation::DataComponentInterpretation>()); + + /** + * This function is an abbreviation to the above one (see there for a + * discussion of the various arguments), intended for use with finite + * elements that are not composed of subelements. In this case, only one + * name per data vector needs to be given, which is what this function + * takes. It simply relays its arguments after a conversion of the @p name + * to a vector of strings, to the other add_data_vector() function above. + * + * If @p data is a vector with multiple components this function will + * generate distinct names for all components by appending an underscore and + * the number of each component to @p name + * + * The actual type for the template argument may be any vector type from + * which FEValues can extract values on a cell using the + * FEValuesBase::get_function_values() function. + */ + template <class VECTOR> + void add_data_vector (const VECTOR &data, + const std::string &name, + const DataVectorType type = type_automatic, + const std::vector<DataComponentInterpretation::DataComponentInterpretation> &data_component_interpretation + = std::vector<DataComponentInterpretation::DataComponentInterpretation>()); + + /** + * This function is an extension of the above one (see there for a + * discussion of the arguments except the first one) and allows to set a + * vector with its own DoFHandler object. This DoFHandler needs to be + * compatible with the other DoFHandler objects assigned with calls to @p + * add_data_vector or @p attach_dof_handler, in the sense that the + * DoFHandler objects need to be based on the same triangulation. This + * function allows you to export data from multiple DoFHandlers that + * describe different solution components. + * + * Since this function takes a DoFHandler object and hence naturally + * represents dof data, the data vector type argument present in the other + * methods above is skipped. + */ + template <class VECTOR> + void add_data_vector (const DH &dof_handler, + const VECTOR &data, + const std::vector<std::string> &names, + const std::vector<DataComponentInterpretation::DataComponentInterpretation> &data_component_interpretation + = std::vector<DataComponentInterpretation::DataComponentInterpretation>()); + + + /** + * This function is an abbreviation of the function above with only a scalar + * @p dof_handler given and a single data name. + */ + template <class VECTOR> + void add_data_vector (const DH &dof_handler, + const VECTOR &data, + const std::string &name, + const std::vector<DataComponentInterpretation::DataComponentInterpretation> &data_component_interpretation + = std::vector<DataComponentInterpretation::DataComponentInterpretation>()); + + /** + * This function is an alternative to the above ones, allowing the output of + * derived quantities instead of the given data. This converison has to be + * done in a class derived from DataPostprocessor. + * + * The names for these derived quantities are provided by the @p + * data_postprocessor argument. Likewise, the data_component_interpretation + * argument of the other add_data_vector() functions is provided by the + * data_postprocessor argument. As only data of type @p type_dof_data can be + * transformed, this type is also known implicitly and does not have to be + * given. + * + * @note The actual type for the vector argument may be any vector type from + * which FEValues can extract values on a cell using the + * FEValuesBase::get_function_values() function. In particular, this + * includes all of the usual vector types, but also IndexSet (see step-41 + * for a use of this). + */ + template <class VECTOR> + void add_data_vector (const VECTOR &data, + const DataPostprocessor<DH::space_dimension> &data_postprocessor); + + /** + * Same function as above, but with a DoFHandler object that does not need + * to coincide with the DoFHandler initially set. Note that the + * postprocessor can only read data from the given DoFHandler and solution + * vector, not other solution vectors or DoFHandlers. + */ + template <class VECTOR> + void add_data_vector (const DH &dof_handler, + const VECTOR &data, + const DataPostprocessor<DH::space_dimension> &data_postprocessor); + + /** + * Release the pointers to the data vectors. This allows output of a new set + * of vectors without supplying the DoF handler again. Therefore, the + * DataOut object can be used in an algebraic context. Note that besides the + * data vectors also the patches already computed are deleted. + */ + void clear_data_vectors (); + + /** + * Release pointers to all input data elements, i.e. pointers to data + * vectors and to the DoF handler object. This function may be useful when + * you have called the @p build_patches function of derived class, since + * then the patches are built and the input data is no more needed, nor is + * there a need to reference it. You can then output the patches detached + * from the main thread and need not make sure anymore that the DoF handler + * object and vectors must not be deleted before the output thread is + * finished. + */ + void clear_input_data_references (); + + /** + * This function can be used to merge the patches that were created using + * the @p build_patches function of the object given as argument into the + * list of patches created by this object. This is sometimes handy if one + * has, for example, a domain decomposition algorithm where each block is + * represented by a DoFHandler of its own, but one wants to output the + * solution on all the blocks at the same time. + * + * For this to work, the given argument and this object need to have the + * same number of output vectors, and they need to use the same number of + * subdivisions per patch. The output will probably look rather funny if + * patches in both objects overlap in space. + * + * If you call build_patches() for this object after merging in patches, the + * previous state is overwritten, and the merged-in patches are lost. + * + * The second parameter allows to shift each node of the patches in the + * object passed in in the first parameter by a certain amount. This is + * sometimes useful to generate "exploded" views of a collection of blocks. + * + * This function will fail if either this or the other object did not yet + * set up any patches. + */ + template <class DH2> + void merge_patches (const DataOut_DoFData<DH2,patch_dim,patch_space_dim> &source, + const Point<patch_space_dim> &shift = Point<patch_space_dim>()); + + /** + * Release the pointers to the data vectors and the DoF handler. You have to + * set all data entries again using the add_data_vector() function. The + * pointer to the dof handler is cleared as well, along with all other + * data. In effect, this function resets everything to a virgin state. + */ + virtual void clear (); + + /** + * Determine an estimate for the memory consumption (in bytes) of this + * object. + */ + std::size_t memory_consumption () const; + + /** + * Exception + */ + DeclException0 (ExcNoTriangulationSelected); + + /** + * Exception + */ + DeclException0 (ExcNoDoFHandlerSelected); + + /** + * Exception + */ + DeclException0 (ExcDataPostprocessingIsNotPossibleForCellData); + + /** + * Exception + */ + DeclException3 (ExcInvalidVectorSize, + int, int, int, + << "The vector has size " << arg1 + << " but the DoFHandler objects says there are " << arg2 + << " degrees of freedom and there are " << arg3 + << " active cells."); + /** + * Exception + */ + DeclException2 (ExcInvalidCharacter, + std::string, size_t, + << "Please use only the characters [a-zA-Z0-9_<>()] for" << std::endl + << "description strings since some graphics formats will only accept these." + << std::endl + << "The string you gave was <" << arg1 + << ">, the invalid character is <" << arg1[arg2] + << ">." << std::endl); + /** + * Exception + */ + DeclException0 (ExcOldDataStillPresent); + /** + * Exception + */ + DeclException2 (ExcInvalidNumberOfNames, + int, int, + << "You have to give one name per component in your " + << "data vector. The number you gave was " << arg1 + << ", but the number of components is " << arg2); + /** + * Exception + */ + DeclException0 (ExcNoPatches); + /** + * Exception + */ + DeclException0 (ExcIncompatibleDatasetNames); + /** + * Exception + */ + DeclException0 (ExcIncompatiblePatchLists); + + DeclException2 (ExcInvalidVectorDeclaration, + int, std::string, + << "When declaring that a number of components in a data\n" + << "set to be output logically form a vector instead of\n" + << "simply a set of scalar fields, you need to specify\n" + << "this for all relevant components. Furthermore,\n" + << "vectors must always consist of exactly <dim>\n" + << "components. However, the vector component at\n" + << "position " << arg1 << " with name <" << arg2 + << "> does not satisfy these conditions."); + +protected: + /** + * Abbreviate the somewhat lengthy name for the Patch class. + */ + typedef dealii::DataOutBase::Patch<patch_dim,patch_space_dim> Patch; + + /** + * Pointer to the triangulation object. + */ + SmartPointer<const Triangulation<DH::dimension,DH::space_dimension> > triangulation; + + /** + * Pointer to the optional handler object. + */ + SmartPointer<const DH> dofs; + + /** + * List of data elements with vectors of values for each degree of freedom. + */ + std::vector<std_cxx1x::shared_ptr<internal::DataOut::DataEntryBase<DH> > > dof_data; + + /** + * List of data elements with vectors of values for each cell. + */ + std::vector<std_cxx1x::shared_ptr<internal::DataOut::DataEntryBase<DH> > > cell_data; + + /** + * This is a list of patches that is created each time build_patches() is + * called. These patches are used in the output routines of the base + * classes. + */ + std::vector<Patch> patches; + + /** + * Function by which the base class's functions get to know what patches + * they shall write to a file. + */ + virtual + const std::vector<Patch> &get_patches () const; + + /** + * Virtual function through which the names of data sets are obtained by the + * output functions of the base class. + */ + virtual + std::vector<std::string> get_dataset_names () const; + + /** + * Extracts the finite elements stored in the dof_data object, including a + * dummy object of FE_DGQ<dim>(0) in case only the triangulation is used. + */ + std::vector<std_cxx1x::shared_ptr<dealii::hp::FECollection<DH::dimension,DH::space_dimension> > > + get_finite_elements() const; + + /** + * Overload of the respective DataOutInterface::get_vector_data_ranges() + * function. See there for a more extensive documentation. + */ + virtual + std::vector<std_cxx1x::tuple<unsigned int, unsigned int, std::string> > + get_vector_data_ranges () const; + + /** + * Make all template siblings friends. Needed for the merge_patches() + * function. + */ + template <class, int, int> + friend class DataOut_DoFData; +}; + + + +// -------------------- template and inline functions ------------------------ + + +template <class DH, int patch_dim, int patch_space_dim> +template <class DH2> +void +DataOut_DoFData<DH,patch_dim,patch_space_dim>:: +merge_patches (const DataOut_DoFData<DH2,patch_dim,patch_space_dim> &source, + const Point<patch_space_dim> &shift) +{ + const std::vector<Patch> source_patches = source.get_patches (); + Assert (patches.size () != 0, ExcNoPatches ()); + Assert (source_patches.size () != 0, ExcNoPatches ()); + // check equality of component + // names + Assert (get_dataset_names() == source.get_dataset_names(), + ExcIncompatibleDatasetNames()); + // make sure patches are compatible. we'll + // assume that if the first respective + // patches are ok that all the other ones + // are ok as well + Assert (patches[0].n_subdivisions == source_patches[0].n_subdivisions, + ExcIncompatiblePatchLists()); + Assert (patches[0].data.n_rows() == source_patches[0].data.n_rows(), + ExcIncompatiblePatchLists()); + Assert (patches[0].data.n_cols() == source_patches[0].data.n_cols(), + ExcIncompatiblePatchLists()); + + // check equality of the vector data + // specifications + Assert (get_vector_data_ranges().size() == + source.get_vector_data_ranges().size(), + ExcMessage ("Both sources need to declare the same components " + "as vectors.")); + for (unsigned int i=0; i<get_vector_data_ranges().size(); ++i) + { + Assert (std_cxx1x::get<0>(get_vector_data_ranges()[i]) == + std_cxx1x::get<0>(source.get_vector_data_ranges()[i]), + ExcMessage ("Both sources need to declare the same components " + "as vectors.")); + Assert (std_cxx1x::get<1>(get_vector_data_ranges()[i]) == + std_cxx1x::get<1>(source.get_vector_data_ranges()[i]), + ExcMessage ("Both sources need to declare the same components " + "as vectors.")); + Assert (std_cxx1x::get<2>(get_vector_data_ranges()[i]) == + std_cxx1x::get<2>(source.get_vector_data_ranges()[i]), + ExcMessage ("Both sources need to declare the same components " + "as vectors.")); + } + + // merge patches. store old number + // of elements, since we need to + // adjust patch numbers, etc + // afterwards + const unsigned int old_n_patches = patches.size(); + patches.insert (patches.end(), + source_patches.begin(), + source_patches.end()); + + // perform shift, if so desired + if (shift != Point<patch_space_dim>()) + for (unsigned int i=old_n_patches; i<patches.size(); ++i) + for (unsigned int v=0; v<GeometryInfo<patch_dim>::vertices_per_cell; ++v) + patches[i].vertices[v] += shift; + + // adjust patch numbers + for (unsigned int i=old_n_patches; i<patches.size(); ++i) + patches[i].patch_index += old_n_patches; + + // adjust patch neighbors + for (unsigned int i=old_n_patches; i<patches.size(); ++i) + for (unsigned int n=0; n<GeometryInfo<patch_dim>::faces_per_cell; ++n) + if (patches[i].neighbors[n] != Patch::no_neighbor) + patches[i].neighbors[n] += old_n_patches; +} + + +DEAL_II_NAMESPACE_CLOSE + +#endif diff --git a/deal.II/include/deal.II/numerics/data_out_rotation.h b/deal.II/include/deal.II/numerics/data_out_rotation.h index 1a45fd3fbb..bdf5a84778 100644 --- a/deal.II/include/deal.II/numerics/data_out_rotation.h +++ b/deal.II/include/deal.II/numerics/data_out_rotation.h @@ -19,7 +19,7 @@ #include <deal.II/base/config.h> -#include <deal.II/numerics/data_out.h> +#include <deal.II/numerics/data_out_dof_data.h> #include <string> #include <vector> diff --git a/deal.II/include/deal.II/numerics/error_estimator.h b/deal.II/include/deal.II/numerics/error_estimator.h index f47c98b30b..6f15d97c2e 100644 --- a/deal.II/include/deal.II/numerics/error_estimator.h +++ b/deal.II/include/deal.II/numerics/error_estimator.h @@ -234,114 +234,59 @@ class KellyErrorEstimator { public: /** - * Implementation of the error - * estimator described above. You - * may give a coefficient, but - * there is a default value which - * denotes the constant - * coefficient with value - * one. The coefficient function - * may either be a scalar one, in - * which case it is used for all - * components of the finite - * element, or a vector-valued - * one with as many components as - * there are in the finite - * element; in the latter case, - * each component is weighted by - * the respective component in - * the coefficient. + * Implementation of the error estimator described above. You may give a + * coefficient, but there is a default value which denotes the constant + * coefficient with value one. The coefficient function may either be a + * scalar one, in which case it is used for all components of the finite + * element, or a vector-valued one with as many components as there are in + * the finite element; in the latter case, each component is weighted by the + * respective component in the coefficient. * - * You might give a list of - * components you want to - * evaluate, in case the finite - * element used by the - * DoFHandler object is - * vector-valued. You then have - * to set those entries to true - * in the bit-vector - * @p component_mask - * (see @ref GlossComponentMask) - * for which the - * respective component is to be - * used in the error - * estimator. The default is to - * use all components, which is - * done by either providing a - * bit-vector with all-set - * entries, or an empty - * bit-vector. + * You might give a list of components you want to evaluate, in case the + * finite element used by the DoFHandler object is vector-valued. You then + * have to set those entries to true in the bit-vector @p component_mask + * (see @ref GlossComponentMask) for which the respective component is to be + * used in the error estimator. The default is to use all components, which + * is done by either providing a bit-vector with all-set entries, or an + * empty bit-vector. * - * The @p subdomain_id parameter - * indicates whether we shall compute - * indicators for all cells (in case its - * value is the default, - * <tt>numbers::invalid_unsigned_int</tt>), - * or only for the cells belonging to a - * certain subdomain with the given - * indicator. The latter case is used for - * parallel computations where all - * processor nodes have the global grid - * stored, and could well compute all the - * indicators for all cells themselves, - * but where it is more efficient to have - * each process compute only indicators - * for the cells it owns, and have them - * exchange the resulting information - * afterwards. This is in particular true - * for the case where meshes are very - * large and computing indicators for @em - * every cell is too expensive, while - * computing indicators for only local - * cells is acceptable. Note that if you - * only ask for the indicators of a - * certain subdomain to be computed, you - * must nevertheless make sure that this - * function has access to the correct - * node values of @em all degrees of - * freedom. This is since the function - * needs to access DoF values on - * neighboring cells as well, even if - * they belong to a different subdomain. + * The @p subdomain_id parameter indicates whether we shall compute + * indicators for all cells (in case its value is the default, + * <tt>numbers::invalid_unsigned_int</tt>), or only for the cells belonging + * to a certain subdomain with the given indicator. The latter case is used + * for parallel computations where all processor nodes have the global grid + * stored, and could well compute all the indicators for all cells + * themselves, but where it is more efficient to have each process compute + * only indicators for the cells it owns, and have them exchange the + * resulting information afterwards. This is in particular true for the case + * where meshes are very large and computing indicators for @em every cell + * is too expensive, while computing indicators for only local cells is + * acceptable. Note that if you only ask for the indicators of a certain + * subdomain to be computed, you must nevertheless make sure that this + * function has access to the correct node values of @em all degrees of + * freedom. This is since the function needs to access DoF values on + * neighboring cells as well, even if they belong to a different subdomain. * - * The @p material_id parameter has a similar - * meaning: if not set to its default value - * (which is numbers::invalid_material_id), - * it means that indicators will only be - * computed for cells with this particular - * material id. + * The @p material_id parameter has a similar meaning: if not set to its + * default value (which is numbers::invalid_material_id), it means that + * indicators will only be computed for cells with this particular material + * id. * - * The @p n_threads parameter used to - * indicate the number of threads to be - * used to compute the error - * estimator. This parameter is now - * ignored, with the number of threads - * determined automatically. The - * parameter is retained for - * compatibility with old versions of the - * library. + * The @p n_threads parameter used to indicate the number of threads to be + * used to compute the error estimator. This parameter is now ignored, with + * the number of threads determined automatically. The parameter is retained + * for compatibility with old versions of the library. * - * @note If the DoFHandler object - * given as an argument to this - * function builds on a - * parallel::distributed::Triangulation, - * this function skips - * computations on all cells that - * are not locally owned. In that - * case, the only valid value for - * the subdomain_id argument - * (besides the invalid value) is - * the subdomain id that is - * associated with the currently + * @note If the DoFHandler object given as an argument to this function + * builds on a parallel::distributed::Triangulation, this function skips + * computations on all cells that are not locally owned. In that case, the + * only valid value for the subdomain_id argument (besides the invalid + * value) is the subdomain id that is associated with the currently * processor, as reported by * parallel::distributed::Triangulation::locally_owned_subdomain(). Even - * though nothing is computed on - * cells that we don't locally - * own, the error indicator - * vector must still have a - * length equal to the number of - * active cell in the mesh as - * reported by + * though nothing is computed on cells that we don't locally own, the error + * indicator vector must still have a length equal to the number of active + * cell in the mesh as reported by * parallel::distributed::Triangulation::n_locally_owned_active_cells(). */ template <typename InputVector, class DH> @@ -358,8 +303,7 @@ public: const types::material_id material_id = numbers::invalid_material_id); /** - * Calls the @p estimate - * function, see above, with + * Calls the @p estimate function, see above, with * <tt>mapping=MappingQ1@<dim@>()</tt>. */ template <typename InputVector, class DH> @@ -375,31 +319,17 @@ public: const types::material_id material_id = numbers::invalid_material_id); /** - * Same function as above, but - * accepts more than one solution - * vector and returns one error - * vector for each solution - * vector. For the reason of - * existence of this function, - * see the general documentation - * of this class. + * Same function as above, but accepts more than one solution vector and + * returns one error vector for each solution vector. For the reason of + * existence of this function, see the general documentation of this class. * - * Since we do not want to force - * the user of this function to - * copy around their solution - * vectors, the vector of - * solution vectors takes - * pointers to the solutions, - * rather than being a vector of - * vectors. This makes it simpler - * to have the solution vectors - * somewhere in memory, rather - * than to have them collected - * somewhere special. (Note that - * it is not possible to - * construct of vector of - * references, so we had to use a - * vector of pointers.) + * Since we do not want to force the user of this function to copy around + * their solution vectors, the vector of solution vectors takes pointers to + * the solutions, rather than being a vector of vectors. This makes it + * simpler to have the solution vectors somewhere in memory, rather than to + * have them collected somewhere special. (Note that it is not possible to + * construct of vector of references, so we had to use a vector of + * pointers.) */ template <typename InputVector, class DH> static void estimate (const Mapping<dim, spacedim> &mapping, @@ -415,8 +345,7 @@ public: const types::material_id material_id = numbers::invalid_material_id); /** - * Calls the @p estimate - * function, see above, with + * Calls the @p estimate function, see above, with * <tt>mapping=MappingQ1@<dim@>()</tt>. */ template <typename InputVector, class DH> @@ -433,10 +362,8 @@ public: /** - * Equivalent to the set of functions - * above, except that this one takes a - * quadrature collection for hp finite - * element dof handlers. + * Equivalent to the set of functions above, except that this one takes a + * quadrature collection for hp finite element dof handlers. */ template <typename InputVector, class DH> static void estimate (const Mapping<dim, spacedim> &mapping, @@ -453,10 +380,8 @@ public: /** - * Equivalent to the set of functions - * above, except that this one takes a - * quadrature collection for hp finite - * element dof handlers. + * Equivalent to the set of functions above, except that this one takes a + * quadrature collection for hp finite element dof handlers. */ template <typename InputVector, class DH> static void estimate (const DH &dof, @@ -472,10 +397,8 @@ public: /** - * Equivalent to the set of functions - * above, except that this one takes a - * quadrature collection for hp finite - * element dof handlers. + * Equivalent to the set of functions above, except that this one takes a + * quadrature collection for hp finite element dof handlers. */ template <typename InputVector, class DH> static void estimate (const Mapping<dim, spacedim> &mapping, @@ -492,10 +415,8 @@ public: /** - * Equivalent to the set of functions - * above, except that this one takes a - * quadrature collection for hp finite - * element dof handlers. + * Equivalent to the set of functions above, except that this one takes a + * quadrature collection for hp finite element dof handlers. */ template <typename InputVector, class DH> static void estimate (const DH &dof, @@ -561,51 +482,28 @@ class KellyErrorEstimator<1,spacedim> { public: /** - * Implementation of the error - * estimator described above. You - * may give a coefficient, but - * there is a default value which - * denotes the constant - * coefficient with value - * one. The coefficient function - * may either be a scalar one, in - * which case it is used for all - * components of the finite - * element, or a vector-valued - * one with as many components as - * there are in the finite - * element; in the latter case, - * each component is weighted by - * the respective component in - * the coefficient. + * Implementation of the error estimator described above. You may give a + * coefficient, but there is a default value which denotes the constant + * coefficient with value one. The coefficient function may either be a + * scalar one, in which case it is used for all components of the finite + * element, or a vector-valued one with as many components as there are in + * the finite element; in the latter case, each component is weighted by the + * respective component in the coefficient. * - * You might give a list of components - * you want to evaluate, in case the - * finite element used by the DoFHandler - * object is vector-valued. You then have - * to set those entries to true in the - * bit-vector @p component_mask for which - * the respective component is to be used - * in the error estimator. The default is - * to use all components, which is done - * by either providing a bit-vector with - * all-set entries, or an empty - * bit-vector. All the other parameters - * are as in the general case used for 2d - * and higher. + * You might give a list of components you want to evaluate, in case the + * finite element used by the DoFHandler object is vector-valued. You then + * have to set those entries to true in the bit-vector @p component_mask for + * which the respective component is to be used in the error estimator. The + * default is to use all components, which is done by either providing a + * bit-vector with all-set entries, or an empty bit-vector. All the other + * parameters are as in the general case used for 2d and higher. * - * The estimator supports multithreading - * and splits the cells to - * <tt>multithread_info.n_default_threads</tt> - * (default) threads. The number of - * threads to be used in multithreaded - * mode can be set with the last - * parameter of the error estimator. - * Multithreading is not presently - * implemented for 1d, but we retain the - * respective parameter for compatibility - * with the function signature in the - * general case. + * The estimator supports multithreading and splits the cells to + * <tt>multithread_info.n_default_threads</tt> (default) threads. The number + * of threads to be used in multithreaded mode can be set with the last + * parameter of the error estimator. Multithreading is not presently + * implemented for 1d, but we retain the respective parameter for + * compatibility with the function signature in the general case. */ template <typename InputVector, class DH> static void estimate (const Mapping<1,spacedim> &mapping, @@ -621,8 +519,7 @@ public: const types::material_id material_id = numbers::invalid_material_id); /** - * Calls the @p estimate - * function, see above, with + * Calls the @p estimate function, see above, with * <tt>mapping=MappingQ1<1>()</tt>. */ template <typename InputVector, class DH> @@ -638,31 +535,17 @@ public: const types::material_id material_id = numbers::invalid_material_id); /** - * Same function as above, but - * accepts more than one solution - * vectors and returns one error - * vector for each solution - * vector. For the reason of - * existence of this function, - * see the general documentation - * of this class. + * Same function as above, but accepts more than one solution vectors and + * returns one error vector for each solution vector. For the reason of + * existence of this function, see the general documentation of this class. * - * Since we do not want to force - * the user of this function to - * copy around their solution - * vectors, the vector of - * solution vectors takes - * pointers to the solutions, - * rather than being a vector of - * vectors. This makes it simpler - * to have the solution vectors - * somewhere in memory, rather - * than to have them collected - * somewhere special. (Note that - * it is not possible to - * construct of vector of - * references, so we had to use a - * vector of pointers.) + * Since we do not want to force the user of this function to copy around + * their solution vectors, the vector of solution vectors takes pointers to + * the solutions, rather than being a vector of vectors. This makes it + * simpler to have the solution vectors somewhere in memory, rather than to + * have them collected somewhere special. (Note that it is not possible to + * construct of vector of references, so we had to use a vector of + * pointers.) */ template <typename InputVector, class DH> static void estimate (const Mapping<1,spacedim> &mapping, @@ -678,8 +561,7 @@ public: const types::material_id material_id = numbers::invalid_material_id); /** - * Calls the @p estimate - * function, see above, with + * Calls the @p estimate function, see above, with * <tt>mapping=MappingQ1<1>()</tt>. */ template <typename InputVector, class DH> @@ -696,10 +578,8 @@ public: /** - * Equivalent to the set of functions - * above, except that this one takes a - * quadrature collection for hp finite - * element dof handlers. + * Equivalent to the set of functions above, except that this one takes a + * quadrature collection for hp finite element dof handlers. */ template <typename InputVector, class DH> static void estimate (const Mapping<1,spacedim> &mapping, @@ -716,10 +596,8 @@ public: /** - * Equivalent to the set of functions - * above, except that this one takes a - * quadrature collection for hp finite - * element dof handlers. + * Equivalent to the set of functions above, except that this one takes a + * quadrature collection for hp finite element dof handlers. */ template <typename InputVector, class DH> static void estimate (const DH &dof, @@ -735,10 +613,8 @@ public: /** - * Equivalent to the set of functions - * above, except that this one takes a - * quadrature collection for hp finite - * element dof handlers. + * Equivalent to the set of functions above, except that this one takes a + * quadrature collection for hp finite element dof handlers. */ template <typename InputVector, class DH> static void estimate (const Mapping<1,spacedim> &mapping, @@ -755,10 +631,8 @@ public: /** - * Equivalent to the set of functions - * above, except that this one takes a - * quadrature collection for hp finite - * element dof handlers. + * Equivalent to the set of functions above, except that this one takes a + * quadrature collection for hp finite element dof handlers. */ template <typename InputVector, class DH> static void estimate (const DH &dof, diff --git a/deal.II/include/deal.II/numerics/vector_tools.h b/deal.II/include/deal.II/numerics/vector_tools.h index d7cf41a6ed..5cb317c497 100644 --- a/deal.II/include/deal.II/numerics/vector_tools.h +++ b/deal.II/include/deal.II/numerics/vector_tools.h @@ -1404,300 +1404,173 @@ namespace VectorTools /** - * Compute the constraints that - * correspond to boundary conditions of - * the form $\vec n \cdot \vec u=0$, - * i.e. no normal flux if $\vec u$ is a - * vector-valued quantity. These - * conditions have exactly the form - * handled by the ConstraintMatrix class, - * so instead of creating a map between - * boundary degrees of freedom and - * corresponding value, we here create a - * list of constraints that are written - * into a ConstraintMatrix. This object - * may already have some content, for - * example from hanging node constraints, - * that remains untouched. These - * constraints have to be applied to the - * linear system like any other such - * constraints, i.e. you have to condense - * the linear system with the constraints - * before solving, and you have to - * distribute the solution vector - * afterwards. - * - * The use of this function is - * explained in more detail in - * step-31. It - * doesn't make much sense in 1d, - * so the function throws an - * exception in that case. - * - * The second argument of this - * function denotes the first - * vector component in the finite - * element that corresponds to - * the vector function that you - * want to constrain. For - * example, if we were solving a - * Stokes equation in 2d and the - * finite element had components - * $(u,v,p)$, then @p - * first_vector_component would - * be zero. On the other hand, if - * we solved the Maxwell - * equations in 3d and the finite - * element has components - * $(E_x,E_y,E_z,B_x,B_y,B_z)$ - * and we want the boundary - * condition $\vec n\cdot \vec - * B=0$, then @p - * first_vector_component would - * be 3. Vectors are implicitly - * assumed to have exactly - * <code>dim</code> components - * that are ordered in the same - * way as we usually order the - * coordinate directions, - * i.e. $x$-, $y$-, and finally - * $z$-component. The function - * assumes, but can't check, that - * the vector components in the - * range - * <code>[first_vector_component,first_vector_component+dim)</code> - * come from the same base finite - * element. For example, in the - * Stokes example above, it would - * not make sense to use a - * <code>FESystem@<dim@>(FE_Q@<dim@>(2), - * 1, FE_Q@<dim@>(1), dim)</code> - * (note that the first velocity - * vector component is a $Q_2$ - * element, whereas all the other - * ones are $Q_1$ elements) as - * there would be points on the - * boundary where the - * $x$-velocity is defined but no - * corresponding $y$- or - * $z$-velocities. - * - * The third argument denotes the set of - * boundary indicators on which the - * boundary condition is to be - * enforced. Note that, as explained - * below, this is one of the few - * functions where it makes a difference - * where we call the function multiple - * times with only one boundary - * indicator, or whether we call the - * function onces with the whole set of - * boundary indicators at once. - * - * The mapping argument is used to - * compute the boundary points where the function - * needs to request the normal vector $\vec n$ - * from the boundary description. - * - * @note When combining adaptively - * refined meshes with hanging node - * constraints and boundary conditions - * like from the current function within - * one ConstraintMatrix object, the - * hanging node constraints should always - * be set first, and then the boundary - * conditions since boundary conditions - * are not set in the second operation on - * degrees of freedom that are already - * constrained. This makes sure that the - * discretization remains conforming as - * is needed. See the discussion on - * conflicting constraints in the module - * on @ref constraints . + * Compute the constraints that correspond to boundary conditions of the + * form $\vec n \cdot \vec u=0$, i.e. no normal flux if $\vec u$ is a + * vector-valued quantity. These conditions have exactly the form handled by + * the ConstraintMatrix class, so instead of creating a map between boundary + * degrees of freedom and corresponding value, we here create a list of + * constraints that are written into a ConstraintMatrix. This object may + * already have some content, for example from hanging node constraints, + * that remains untouched. These constraints have to be applied to the + * linear system like any other such constraints, i.e. you have to condense + * the linear system with the constraints before solving, and you have to + * distribute the solution vector afterwards. + * + * The use of this function is explained in more detail in step-31. It + * doesn't make much sense in 1d, so the function throws an exception in + * that case. + * + * The second argument of this function denotes the first vector component + * in the finite element that corresponds to the vector function that you + * want to constrain. For example, if we were solving a Stokes equation in + * 2d and the finite element had components $(u,v,p)$, then @p + * first_vector_component would be zero. On the other hand, if we solved the + * Maxwell equations in 3d and the finite element has components + * $(E_x,E_y,E_z,B_x,B_y,B_z)$ and we want the boundary condition $\vec + * n\cdot \vec B=0$, then @p first_vector_component would be 3. Vectors are + * implicitly assumed to have exactly <code>dim</code> components that are + * ordered in the same way as we usually order the coordinate directions, + * i.e. $x$-, $y$-, and finally $z$-component. The function assumes, but + * can't check, that the vector components in the range + * <code>[first_vector_component,first_vector_component+dim)</code> come + * from the same base finite element. For example, in the Stokes example + * above, it would not make sense to use a + * <code>FESystem@<dim@>(FE_Q@<dim@>(2), 1, FE_Q@<dim@>(1), dim)</code> + * (note that the first velocity vector component is a $Q_2$ element, + * whereas all the other ones are $Q_1$ elements) as there would be points + * on the boundary where the $x$-velocity is defined but no corresponding + * $y$- or $z$-velocities. + * + * The third argument denotes the set of boundary indicators on which the + * boundary condition is to be enforced. Note that, as explained below, this + * is one of the few functions where it makes a difference where we call the + * function multiple times with only one boundary indicator, or whether we + * call the function onces with the whole set of boundary indicators at + * once. + * + * The mapping argument is used to compute the boundary points where the + * function needs to request the normal vector $\vec n$ from the boundary + * description. + * + * @note When combining adaptively refined meshes with hanging node + * constraints and boundary conditions like from the current function within + * one ConstraintMatrix object, the hanging node constraints should always + * be set first, and then the boundary conditions since boundary conditions + * are not set in the second operation on degrees of freedom that are + * already constrained. This makes sure that the discretization remains + * conforming as is needed. See the discussion on conflicting constraints in + * the module on @ref constraints . * * * <h4>Computing constraints in 2d</h4> * - * Computing these constraints requires - * some smarts. The main question - * revolves around the question what the - * normal vector is. Consider the - * following situation: - * <p ALIGN="center"> - * @image html no_normal_flux_1.png + * Computing these constraints requires some smarts. The main question + * revolves around the question what the normal vector is. Consider the + * following situation: <p ALIGN="center"> @image html no_normal_flux_1.png * </p> * - * Here, we have two cells that use a - * bilinear mapping - * (i.e. MappingQ1). Consequently, for - * each of the cells, the normal vector - * is perpendicular to the straight - * edge. If the two edges at the top and - * right are meant to approximate a - * curved boundary (as indicated by the - * dashed line), then neither of the two - * computed normal vectors are equal to - * the exact normal vector (though they - * approximate it as the mesh is refined - * further). What is worse, if we - * constrain $\vec n \cdot \vec u=0$ at - * the common vertex with the normal - * vector from both cells, then we - * constrain the vector $\vec u$ with - * respect to two linearly independent - * vectors; consequently, the constraint - * would be $\vec u=0$ at this point - * (i.e. <i>all</i> components of the - * vector), which is not what we wanted. - * - * To deal with this situation, the - * algorithm works in the following way: - * at each point where we want to - * constrain $\vec u$, we first collect - * all normal vectors that adjacent cells - * might compute at this point. We then - * do not constrain $\vec n \cdot \vec - * u=0$ for <i>each</i> of these normal - * vectors but only for the - * <i>average</i> of the normal - * vectors. In the example above, we - * therefore record only a single - * constraint $\vec n \cdot \vec {\bar - * u}=0$, where $\vec {\bar u}$ is the - * average of the two indicated normal - * vectors. - * - * Unfortunately, this is not quite - * enough. Consider the situation here: + * Here, we have two cells that use a bilinear mapping + * (i.e. MappingQ1). Consequently, for each of the cells, the normal vector + * is perpendicular to the straight edge. If the two edges at the top and + * right are meant to approximate a curved boundary (as indicated by the + * dashed line), then neither of the two computed normal vectors are equal + * to the exact normal vector (though they approximate it as the mesh is + * refined further). What is worse, if we constrain $\vec n \cdot \vec u=0$ + * at the common vertex with the normal vector from both cells, then we + * constrain the vector $\vec u$ with respect to two linearly independent + * vectors; consequently, the constraint would be $\vec u=0$ at this point + * (i.e. <i>all</i> components of the vector), which is not what we wanted. + * + * To deal with this situation, the algorithm works in the following way: at + * each point where we want to constrain $\vec u$, we first collect all + * normal vectors that adjacent cells might compute at this point. We then + * do not constrain $\vec n \cdot \vec u=0$ for <i>each</i> of these normal + * vectors but only for the <i>average</i> of the normal vectors. In the + * example above, we therefore record only a single constraint $\vec n \cdot + * \vec {\bar u}=0$, where $\vec {\bar u}$ is the average of the two + * indicated normal vectors. + * + * Unfortunately, this is not quite enough. Consider the situation here: * * <p ALIGN="center"> * @image html no_normal_flux_2.png * </p> * - * If again the top and right edges - * approximate a curved boundary, and the - * left boundary a separate boundary (for - * example straight) so that the exact - * boundary has indeed a corner at the - * top left vertex, then the above - * construction would not work: here, we - * indeed want the constraint that $\vec - * u$ at this point (because the normal - * velocities with respect to both the - * left normal as well as the top normal - * vector should be zero), not that the - * velocity in the direction of the - * average normal vector is zero. - * - * Consequently, we use the following - * heuristic to determine whether all - * normal vectors computed at one point - * are to be averaged: if two normal - * vectors for the same point are - * computed on <i>different</i> cells, - * then they are to be averaged. This - * covers the first example above. If - * they are computed from the same cell, - * then the fact that they are different - * is considered indication that they - * come from different parts of the - * boundary that might be joined by a - * real corner, and must not be averaged. - * - * There is one problem with this - * scheme. If, for example, the same - * domain we have considered above, is - * discretized with the following mesh, - * then we get into trouble: + * If again the top and right edges approximate a curved boundary, and the + * left boundary a separate boundary (for example straight) so that the + * exact boundary has indeed a corner at the top left vertex, then the above + * construction would not work: here, we indeed want the constraint that + * $\vec u$ at this point (because the normal velocities with respect to + * both the left normal as well as the top normal vector should be zero), + * not that the velocity in the direction of the average normal vector is + * zero. + * + * Consequently, we use the following heuristic to determine whether all + * normal vectors computed at one point are to be averaged: if two normal + * vectors for the same point are computed on <i>different</i> cells, then + * they are to be averaged. This covers the first example above. If they are + * computed from the same cell, then the fact that they are different is + * considered indication that they come from different parts of the boundary + * that might be joined by a real corner, and must not be averaged. + * + * There is one problem with this scheme. If, for example, the same domain + * we have considered above, is discretized with the following mesh, then we + * get into trouble: * * <p ALIGN="center"> * @image html no_normal_flux_3.png * </p> * - * Here, the algorithm assumes that the - * boundary does not have a corner at the - * point where faces $F1$ and $F2$ join - * because at that point there are two - * different normal vectors computed from - * different cells. If you intend for - * there to be a corner of the exact - * boundary at this point, the only way - * to deal with this is to assign the two - * parts of the boundary different - * boundary indicators and call this - * function twice, once for each boundary - * indicators; doing so will yield only - * one normal vector at this point per - * invocation (because we consider only - * one boundary part at a time), with the - * result that the normal vectors will - * not be averaged. + * Here, the algorithm assumes that the boundary does not have a corner at + * the point where faces $F1$ and $F2$ join because at that point there are + * two different normal vectors computed from different cells. If you intend + * for there to be a corner of the exact boundary at this point, the only + * way to deal with this is to assign the two parts of the boundary + * different boundary indicators and call this function twice, once for each + * boundary indicators; doing so will yield only one normal vector at this + * point per invocation (because we consider only one boundary part at a + * time), with the result that the normal vectors will not be averaged. This + * situation also needs to be taken into account when using this function + * around reentrant corners on Cartesian meshes. If no-normal-flux boundary + * conditions are to be enforced on non-Cartesian meshes around reentrant + * corners, one may even get cycles in the constraints as one will in + * general constrain different components from the two sides. In that case, + * set a no-slip constraint on the reentrant vertex first. * * * <h4>Computing constraints in 3d</h4> * - * The situation is more - * complicated in 3d. Consider - * the following case where we - * want to compute the - * constraints at the marked - * vertex: + * The situation is more complicated in 3d. Consider the following case + * where we want to compute the constraints at the marked vertex: * * <p ALIGN="center"> * @image html no_normal_flux_4.png * </p> * - * Here, we get four different - * normal vectors, one from each - * of the four faces that meet at - * the vertex. Even though they - * may form a complete set of - * vectors, it is not our intent - * to constrain all components of - * the vector field at this - * point. Rather, we would like - * to still allow tangential - * flow, where the term - * "tangential" has to be - * suitably defined. - * - * In a case like this, the - * algorithm proceeds as follows: - * for each cell that has - * computed two tangential - * vectors at this point, we - * compute the unconstrained - * direction as the outer product - * of the two tangential vectors - * (if necessary multiplied by - * minus one). We then average - * these tangential - * vectors. Finally, we compute - * constraints for the two - * directions perpendicular to - * this averaged tangential - * direction. - * - * There are cases where one cell - * contributes two tangential - * directions and another one - * only one; for example, this - * would happen if both top and - * front faces of the left cell - * belong to the boundary - * selected whereas only the top - * face of the right cell belongs - * to it. This case is not - * currently implemented. + * Here, we get four different normal vectors, one from each of the four + * faces that meet at the vertex. Even though they may form a complete set + * of vectors, it is not our intent to constrain all components of the + * vector field at this point. Rather, we would like to still allow + * tangential flow, where the term "tangential" has to be suitably defined. + * + * In a case like this, the algorithm proceeds as follows: for each cell + * that has computed two tangential vectors at this point, we compute the + * unconstrained direction as the outer product of the two tangential + * vectors (if necessary multiplied by minus one). We then average these + * tangential vectors. Finally, we compute constraints for the two + * directions perpendicular to this averaged tangential direction. + * + * There are cases where one cell contributes two tangential directions and + * another one only one; for example, this would happen if both top and + * front faces of the left cell belong to the boundary selected whereas only + * the top face of the right cell belongs to it. This case is not currently + * implemented. * * * <h4>Results</h4> * - * Because it makes for good - * pictures, here are two images - * of vector fields on a circle - * and on a sphere to which the - * constraints computed by this + * Because it makes for good pictures, here are two images of vector fields + * on a circle and on a sphere to which the constraints computed by this * function have been applied: * * <p ALIGN="center"> @@ -1705,16 +1578,10 @@ namespace VectorTools * @image html no_normal_flux_6.png * </p> * - * The vectors fields are not - * physically reasonable but the - * tangentiality constraint is - * clearly enforced. The fact - * that the vector fields are - * zero at some points on the - * boundary is an artifact of the - * way it is created, it is not - * constrained to be zero at - * these points. + * The vectors fields are not physically reasonable but the tangentiality + * constraint is clearly enforced. The fact that the vector fields are zero + * at some points on the boundary is an artifact of the way it is created, + * it is not constrained to be zero at these points. * * @ingroup constraints * @@ -1728,6 +1595,22 @@ namespace VectorTools ConstraintMatrix &constraints, const Mapping<dim, spacedim> &mapping = StaticMappingQ1<dim>::mapping); + /** + * Compute the constraints that correspond to boundary conditions of the + * form $\vec n \times \vec u=0$, i.e. flow normal to the boundary if $\vec + * u$ is a vector-valued quantity. This function constrains exactly those + * vector-valued components that are left unconstrained by + * compute_no_normal_flux_constraints, and leaves the one component + * unconstrained that is constrained by compute_no_normal_flux_constraints. + */ + template <int dim, template <int, int> class DH, int spacedim> + void + compute_normal_flux_constraints (const DH<dim,spacedim> &dof_handler, + const unsigned int first_vector_component, + const std::set<types::boundary_id> &boundary_ids, + ConstraintMatrix &constraints, + const Mapping<dim, spacedim> &mapping = StaticMappingQ1<dim>::mapping); + //@} /** @@ -2418,11 +2301,6 @@ namespace VectorTools * Exception */ DeclException0 (ExcNonInterpolatingFE); - - /** - * Exception - */ - DeclException0 (ExcNoComponentSelected); } diff --git a/deal.II/include/deal.II/numerics/vector_tools.templates.h b/deal.II/include/deal.II/numerics/vector_tools.templates.h index a501795529..39b16c8cf1 100644 --- a/deal.II/include/deal.II/numerics/vector_tools.templates.h +++ b/deal.II/include/deal.II/numerics/vector_tools.templates.h @@ -60,6 +60,7 @@ #include <deal.II/numerics/vector_tools.h> #include <deal.II/numerics/matrix_tools.h> +#include <deal.II/base/std_cxx1x/array.h> #include <numeric> #include <algorithm> #include <vector> @@ -1180,36 +1181,6 @@ namespace VectorTools -// separate implementation for 1D because otherwise we get linker errors since -// FEFaceValues<1> is not compiled - template <> - void - create_boundary_right_hand_side (const Mapping<1,1> &, - const DoFHandler<1,1> &, - const Quadrature<0> &, - const Function<1> &, - Vector<double> &, - const std::set<types::boundary_id> &) - { - Assert (false, ExcImpossibleInDim(1)); - } - - - - template <> - void - create_boundary_right_hand_side (const Mapping<1,2> &, - const DoFHandler<1,2> &, - const Quadrature<0> &, - const Function<2> &, - Vector<double> &, - const std::set<types::boundary_id> &) - { - Assert (false, ExcImpossibleInDim(1)); - } - - - template <int dim, int spacedim> void create_boundary_right_hand_side (const Mapping<dim, spacedim> &mapping, @@ -1349,36 +1320,6 @@ namespace VectorTools -// separate implementation for 1D because otherwise we get linker errors since -// hp::FEFaceValues<1> is not compiled - template <> - void - create_boundary_right_hand_side (const hp::MappingCollection<1,1> &, - const hp::DoFHandler<1,1> &, - const hp::QCollection<0> &, - const Function<1> &, - Vector<double> &, - const std::set<types::boundary_id> &) - { - Assert (false, ExcImpossibleInDim(1)); - } - - - - template <> - void - create_boundary_right_hand_side (const hp::MappingCollection<1,2> &, - const hp::DoFHandler<1,2> &, - const hp::QCollection<0> &, - const Function<2> &, - Vector<double> &, - const std::set<types::boundary_id> &) - { - Assert (false, ExcImpossibleInDim(1)); - } - - - template <int dim, int spacedim> void create_boundary_right_hand_side (const hp::MappingCollection<dim,spacedim> &mapping, @@ -1584,7 +1525,7 @@ namespace VectorTools boundary_function.n_components)); Assert (component_mask.n_selected_components(fe.n_components()) > 0, - ExcNoComponentSelected()); + ComponentMask::ExcNoComponentSelected()); // now set the value of // the vertex degree of @@ -3243,19 +3184,10 @@ namespace VectorTools } } - // Create the system - // matrix by - // multiplying the - // assembling matrix - // with its transposed - // and the right - // hand side vector - // by mutliplying - // the assembling - // matrix with the - // assembling vector. - // Invert the system - // matrix. + // Create the system matrix by multiplying the assembling matrix + // with its transposed and the right hand side vector by mutliplying + // the assembling matrix with the assembling vector. Invert the + // system matrix. assembling_matrix.mTmult (cell_matrix, assembling_matrix); cell_matrix_inv.invert (cell_matrix); assembling_matrix.vmult (cell_rhs, assembling_vector); @@ -3285,12 +3217,8 @@ namespace VectorTools } } - // Now we do the - // same as above - // with the vertical - // shape functions - // instead of the - // horizontal ones. + // Now we do the same as above with the vertical shape functions + // instead of the horizontal ones. for (unsigned int q_point = 0; q_point < fe_values.n_quadrature_points; ++q_point) { @@ -3395,32 +3323,18 @@ namespace VectorTools ConstraintMatrix &constraints, const Mapping<dim> &mapping) { - // Projection-based interpolation - // is performed in two (in 2D) - // respectively three (in 3D) - // steps. First the tangential - // component of the function is - // interpolated on each edge. This - // gives the values for the degrees - // of freedom corresponding to the - // edge shape functions. Now we are - // done for 2D, but in 3D we possibly - // have also degrees of freedom, which - // are located in the interior of - // the faces. Therefore we compute - // the residual of the function - // describing the boundary values - // and the interpolated part, which - // we have computed in the last - // step. On the faces there are - // two kinds of shape functions, - // the horizontal and the vertical - // ones. Thus we have to solve two - // linear systems of equations of - // size <tt>degree * (degree + - // 1)<tt> to obtain the values for - // the corresponding degrees of - // freedom. + // Projection-based interpolation is performed in two (in 2D) respectively + // three (in 3D) steps. First the tangential component of the function is + // interpolated on each edge. This gives the values for the degrees of + // freedom corresponding to the edge shape functions. Now we are done for + // 2D, but in 3D we possibly have also degrees of freedom, which are + // located in the interior of the faces. Therefore we compute the residual + // of the function describing the boundary values and the interpolated + // part, which we have computed in the last step. On the faces there are + // two kinds of shape functions, the horizontal and the vertical + // ones. Thus we have to solve two linear systems of equations of size + // <tt>degree * (degree + 1)<tt> to obtain the values for the + // corresponding degrees of freedom. const unsigned int superdegree = dof_handler.get_fe ().degree; const QGauss<dim - 1> reference_face_quadrature (2 * superdegree); const unsigned int dofs_per_face = dof_handler.get_fe ().dofs_per_face; @@ -3663,19 +3577,12 @@ namespace VectorTools for (unsigned int face = 0; face < GeometryInfo<dim>::faces_per_cell; ++face) if (cell->face (face)->boundary_indicator () == boundary_component) { - // if the FE is a - // FE_Nothing object - // there is no work to - // do + // if the FE is a FE_Nothing object there is no work to do if (dynamic_cast<const FE_Nothing<dim>*> (&cell->get_fe ()) != 0) return; - // This is only - // implemented, if the - // FE is a Nedelec - // element. If the FE is - // a FESystem we cannot - // check this. + // This is only implemented, if the FE is a Nedelec + // element. If the FE is a FESystem we cannot check this. if (dynamic_cast<const FESystem<dim>*> (&cell->get_fe ()) == 0) { typedef FiniteElement<dim> FEL; @@ -3749,19 +3656,12 @@ namespace VectorTools for (unsigned int face = 0; face < GeometryInfo<dim>::faces_per_cell; ++face) if (cell->face (face)->boundary_indicator () == boundary_component) { - // if the FE is a - // FE_Nothing object - // there is no work to - // do + // if the FE is a FE_Nothing object there is no work to do if (dynamic_cast<const FE_Nothing<dim>*> (&cell->get_fe ()) != 0) return; - // This is only - // implemented, if the - // FE is a Nedelec - // element. If the FE is - // a FESystem we cannot - // check this. + // This is only implemented, if the FE is a Nedelec + // element. If the FE is a FESystem we cannot check this. if (dynamic_cast<const FESystem<dim>*> (&cell->get_fe ()) == 0) { typedef FiniteElement<dim> FEL; @@ -3791,11 +3691,8 @@ namespace VectorTools first_vector_component, dof_values, dofs_processed); - // If there are higher - // order shape - // functions, there is - // still some work - // left. + // If there are higher order shape functions, there is still + // some work left. if (degree > 0) internals ::compute_face_projection_curl_conforming (cell, face, fe_face_values, @@ -3832,10 +3729,8 @@ namespace VectorTools namespace internals { - // This function computes the - // projection of the boundary - // function on the boundary - // in 2d. + // This function computes the projection of the boundary function on the + // boundary in 2d. template <typename cell_iterator> void compute_face_projection_div_conforming (const cell_iterator &cell, @@ -3846,13 +3741,9 @@ namespace VectorTools const std::vector<DerivativeForm<1,2,2> > &jacobians, ConstraintMatrix &constraints) { - // Compute the intergral over - // the product of the normal - // components of the boundary - // function times the normal - // components of the shape - // functions supported on the - // boundary. + // Compute the intergral over the product of the normal components of + // the boundary function times the normal components of the shape + // functions supported on the boundary. const FEValuesExtractors::Vector vec (first_vector_component); const FiniteElement<2> &fe = cell->get_fe (); const std::vector<Point<2> > &normals = fe_values.get_normal_vectors (); @@ -3862,9 +3753,7 @@ namespace VectorTools values (fe_values.n_quadrature_points, Vector<double> (2)); Vector<double> dof_values (fe.dofs_per_face); - // Get the values of the - // boundary function at the - // quadrature points. + // Get the values of the boundary function at the quadrature points. { const std::vector<Point<2> > & quadrature_points = fe_values.get_quadrature_points (); @@ -3894,10 +3783,8 @@ namespace VectorTools cell->face (face)->get_dof_indices (face_dof_indices, cell->active_fe_index ()); - // Copy the computed values - // in the ConstraintMatrix only, - // if the degree of freedom is - // not already constrained. + // Copy the computed values in the ConstraintMatrix only, if the degree + // of freedom is not already constrained. for (unsigned int i = 0; i < fe.dofs_per_face; ++i) if (!(constraints.is_constrained (face_dof_indices[i]))) { @@ -3908,9 +3795,7 @@ namespace VectorTools } } - // dummy implementation of above - // function for all other - // dimensions + // dummy implementation of above function for all other dimensions template<int dim, typename cell_iterator> void compute_face_projection_div_conforming (const cell_iterator &, @@ -3924,10 +3809,8 @@ namespace VectorTools Assert (false, ExcNotImplemented ()); } - // This function computes the - // projection of the boundary - // function on the boundary - // in 3d. + // This function computes the projection of the boundary function on the + // boundary in 3d. template<typename cell_iterator> void compute_face_projection_div_conforming (const cell_iterator &cell, @@ -3939,13 +3822,9 @@ namespace VectorTools std::vector<double> &dof_values, std::vector<types::global_dof_index> &projected_dofs) { - // Compute the intergral over - // the product of the normal - // components of the boundary - // function times the normal - // components of the shape - // functions supported on the - // boundary. + // Compute the intergral over the product of the normal components of + // the boundary function times the normal components of the shape + // functions supported on the boundary. const FEValuesExtractors::Vector vec (first_vector_component); const FiniteElement<3> &fe = cell->get_fe (); const std::vector<Point<3> > &normals = fe_values.get_normal_vectors (); @@ -4771,12 +4650,452 @@ namespace VectorTools + namespace + { + template <int dim> + struct PointComparator + { + bool operator ()(const std_cxx1x::array<types::global_dof_index,dim> &p1, + const std_cxx1x::array<types::global_dof_index,dim> &p2) + { + for (unsigned int d=0; d<dim; ++d) + if (p1[d] < p2[d]) + return true; + return false; + } + }; + } + + + + template <int dim, template <int, int> class DH, int spacedim> + void + compute_normal_flux_constraints (const DH<dim,spacedim>&dof_handler, + const unsigned int first_vector_component, + const std::set<types::boundary_id> &boundary_ids, + ConstraintMatrix &constraints, + const Mapping<dim, spacedim> &mapping) + { + ConstraintMatrix no_normal_flux_constraints(constraints.get_local_lines()); + compute_no_normal_flux_constraints (dof_handler, + first_vector_component, + boundary_ids, + no_normal_flux_constraints, + mapping); + + // Extract a list that collects all vector components that belong to the + // same node (scalar basis function). When creating that list, we use an + // array of dim components that stores the global degree of freedom. + std::set<std_cxx1x::array<types::global_dof_index,dim>, PointComparator<dim> > vector_dofs; + std::vector<types::global_dof_index> face_dofs; + + std::vector<std_cxx1x::array<types::global_dof_index,dim> > cell_vector_dofs; + for (typename DH<dim,spacedim>::active_cell_iterator cell = + dof_handler.begin_active(); cell != dof_handler.end(); ++cell) + if (!cell->is_artificial()) + for (unsigned int face_no=0; face_no < GeometryInfo<dim>::faces_per_cell; + ++face_no) + if (boundary_ids.find(cell->face(face_no)->boundary_indicator()) + != boundary_ids.end()) + { + const FiniteElement<dim> &fe = cell->get_fe(); + typename DH<dim,spacedim>::face_iterator face=cell->face(face_no); + + // get the indices of the dofs on this cell... + face_dofs.resize (fe.dofs_per_face); + face->get_dof_indices (face_dofs, cell->active_fe_index()); + + unsigned int n_scalar_indices = 0; + cell_vector_dofs.resize(fe.dofs_per_face); + for (unsigned int i=0; i<fe.dofs_per_face; ++i) + if (fe.face_system_to_component_index(i).first >= first_vector_component && + fe.face_system_to_component_index(i).first < first_vector_component + dim) + { + n_scalar_indices = + std::max(n_scalar_indices, + fe.face_system_to_component_index(i).second+1); + cell_vector_dofs[fe.face_system_to_component_index(i).second] + [fe.face_system_to_component_index(i).first-first_vector_component] + = face_dofs[i]; + } + + // now we identified the vector indices on the cell, so next + // insert them into the set (it would be expensive to directly + // insert incomplete points into the set) + for (unsigned int i=0; i<n_scalar_indices; ++i) + vector_dofs.insert(cell_vector_dofs[i]); + } + + // iterate over the list of all vector components we found and see if we + // can find constrained ones + unsigned int n_total_constraints_found = 0; + for (typename std::set<std_cxx1x::array<unsigned int,dim>,PointComparator<dim> >:: + const_iterator it=vector_dofs.begin(); it!=vector_dofs.end(); ++it) + { + unsigned int n_constraints = 0; + bool is_constrained[dim]; + for (unsigned int d=0; d<dim; ++d) + if (no_normal_flux_constraints.is_constrained((*it)[d])) + { + is_constrained[d] = true; + ++n_constraints; + ++n_total_constraints_found; + } + else + is_constrained[d] = false; + if (n_constraints > 0) + { + // if more than one no-flux constraint is present, we need to + // constrain all vector degrees of freedom (we are in a corner + // where several faces meet and to get a continuous FE solution we + // need to set all conditions to zero). + if (n_constraints > 1) + { + for (unsigned int d=0; d<dim; ++d) + constraints.add_line((*it)[d]); + continue; + } + + // ok, this is a no-flux constraint, so get the index of the dof + // that is currently constrained and make it unconstrained. The + // constraint indices will get the normal that contain the other + // indices. + Tensor<1,dim> normal; + unsigned constrained_index = -1; + for (unsigned int d=0; d<dim; ++d) + if (is_constrained[d]) + { + constrained_index = d; + normal[d] = 1.; + } + AssertIndexRange(constrained_index, dim); + const std::vector<std::pair<unsigned int, double> >* constrained + = no_normal_flux_constraints.get_constraint_entries((*it)[constrained_index]); + // find components to which this index is constrained to + Assert(constrained != 0, ExcInternalError()); + Assert(constrained->size() < dim, ExcInternalError()); + for (unsigned int c=0; c<constrained->size(); ++c) + { + int index = -1; + for (unsigned int d=0; d<dim; ++d) + if ((*constrained)[c].first == (*it)[d]) + index = d; + Assert (index != -1, ExcInternalError()); + normal[index] = (*constrained)[c].second; + } + for (unsigned int d=0; d<dim; ++d) + { + if (is_constrained[d]) + continue; + const unsigned int new_index = (*it)[d]; + if (!constraints.is_constrained(new_index)) + { + constraints.add_line(new_index); + if (std::abs(normal[d]) > 1e-13) + constraints.add_entry(new_index, (*it)[constrained_index], + -normal[d]); + } + } + } + } + AssertDimension(n_total_constraints_found, + no_normal_flux_constraints.n_constraints()); + } + + + namespace internal { + template <int dim, int spacedim> + struct IDScratchData + { + IDScratchData (const dealii::hp::MappingCollection<dim,spacedim> &mapping, + const dealii::hp::FECollection<dim,spacedim> &fe, + const dealii::hp::QCollection<dim> &q, + const UpdateFlags update_flags); + + IDScratchData (const IDScratchData &data); + + void resize_vectors (const unsigned int n_q_points, + const unsigned int n_components); + + std::vector<dealii::Vector<double> > function_values; + std::vector<std::vector<Tensor<1,spacedim> > > function_grads; + std::vector<double> weight_values; + std::vector<dealii::Vector<double> > weight_vectors; + + std::vector<dealii::Vector<double> > psi_values; + std::vector<std::vector<Tensor<1,spacedim> > > psi_grads; + std::vector<double> psi_scalar; + + std::vector<double> tmp_values; + std::vector<Tensor<1,spacedim> > tmp_gradients; + + dealii::hp::FEValues<dim,spacedim> x_fe_values; + }; + + + template <int dim, int spacedim> + IDScratchData<dim,spacedim> + ::IDScratchData(const dealii::hp::MappingCollection<dim,spacedim> &mapping, + const dealii::hp::FECollection<dim,spacedim> &fe, + const dealii::hp::QCollection<dim> &q, + const UpdateFlags update_flags) + : + x_fe_values(mapping, fe, q, update_flags) + {} + + template <int dim, int spacedim> + IDScratchData<dim,spacedim>::IDScratchData (const IDScratchData &data) + : + x_fe_values(data.x_fe_values.get_mapping_collection(), + data.x_fe_values.get_fe_collection(), + data.x_fe_values.get_quadrature_collection(), + data.x_fe_values.get_update_flags()) + {} + + template <int dim, int spacedim> + void + IDScratchData<dim,spacedim>::resize_vectors (const unsigned int n_q_points, + const unsigned int n_components) + { + function_values.resize (n_q_points, + dealii::Vector<double>(n_components)); + function_grads.resize (n_q_points, + std::vector<Tensor<1,spacedim> >(n_components)); + + weight_values.resize (n_q_points); + weight_vectors.resize (n_q_points, + dealii::Vector<double>(n_components)); + + psi_values.resize (n_q_points, + dealii::Vector<double>(n_components)); + psi_grads.resize (n_q_points, + std::vector<Tensor<1,spacedim> >(n_components)); + psi_scalar.resize (n_q_points); + + tmp_values.resize (n_q_points); + tmp_gradients.resize (n_q_points); + } + + + // avoid compiling inner function for many vector types when we always + // really do the same thing by putting the main work into this helper + // function + template <int dim, int spacedim> + double + integrate_difference_inner (const Function<spacedim> &exact_solution, + const NormType &norm, + const Function<spacedim> *weight, + const UpdateFlags update_flags, + const double exponent, + const unsigned int n_components, + IDScratchData<dim,spacedim> &data) + { + const bool fe_is_system = (n_components != 1); + const dealii::FEValues<dim, spacedim> &fe_values = data.x_fe_values.get_present_fe_values (); + const unsigned int n_q_points = fe_values.n_quadrature_points; + + if (weight!=0) + { + if (weight->n_components>1) + weight->vector_value_list (fe_values.get_quadrature_points(), + data.weight_vectors); + else + { + weight->value_list (fe_values.get_quadrature_points(), + data.weight_values); + for (unsigned int k=0; k<n_q_points; ++k) + data.weight_vectors[k] = data.weight_values[k]; + } + } + else + { + for (unsigned int k=0; k<n_q_points; ++k) + data.weight_vectors[k] = 1.; + } + + + if (update_flags & update_values) + { + // first compute the exact solution (vectors) at the quadrature + // points try to do this as efficient as possible by avoiding a + // second virtual function call in case the function really has only + // one component + if (fe_is_system) + exact_solution.vector_value_list (fe_values.get_quadrature_points(), + data.psi_values); + else + { + exact_solution.value_list (fe_values.get_quadrature_points(), + data.tmp_values); + for (unsigned int i=0; i<n_q_points; ++i) + data.psi_values[i](0) = data.tmp_values[i]; + } + + // then subtract finite element fe_function + for (unsigned int q=0; q<n_q_points; ++q) + data.psi_values[q] -= data.function_values[q]; + } + + // Do the same for gradients, if required + if (update_flags & update_gradients) + { + // try to be a little clever to avoid recursive virtual function + // calls when calling gradient_list for functions that are really + // scalar functions + if (fe_is_system) + exact_solution.vector_gradient_list (fe_values.get_quadrature_points(), + data.psi_grads); + else + { + exact_solution.gradient_list (fe_values.get_quadrature_points(), + data.tmp_gradients); + for (unsigned int i=0; i<n_q_points; ++i) + data.psi_grads[i][0] = data.tmp_gradients[i]; + } + + // then subtract finite element function_grads. We need to be + // careful in the codimension one case, since there we only have + // tangential gradients in the finite element function, not the full + // gradient. This is taken care of, by subtracting the normal + // component of the gradient from the exact function. + if (update_flags & update_normal_vectors) + for (unsigned int k=0; k<n_components; ++k) + for (unsigned int q=0; q<n_q_points; ++q) + data.psi_grads[q][k] -= (data.function_grads[q][k] + + (data.psi_grads[q][k]* // (f.n) n + fe_values.normal_vector(q))* + fe_values.normal_vector(q)); + else + for (unsigned int k=0; k<n_components; ++k) + for (unsigned int q=0; q<n_q_points; ++q) + data.psi_grads[q][k] -= data.function_grads[q][k]; + } + + double diff = 0; + switch (norm) + { + case mean: + // Compute values in quadrature points and integrate + for (unsigned int q=0; q<n_q_points; ++q) + { + double sum = 0; + for (unsigned int k=0; k<n_components; ++k) + sum += data.psi_values[q](k) * data.weight_vectors[q](k); + diff += sum * fe_values.JxW(q); + } + break; + + case Lp_norm: + case L1_norm: + case W1p_norm: + // Compute values in quadrature points and integrate + for (unsigned int q=0; q<n_q_points; ++q) + { + double sum = 0; + for (unsigned int k=0; k<n_components; ++k) + sum += std::pow(data.psi_values[q](k)*data.psi_values[q](k), + exponent/2.) * data.weight_vectors[q](k); + diff += sum * fe_values.JxW(q); + } + + // Compute the root only, if no derivative values are added later + if (!(update_flags & update_gradients)) + diff = std::pow(diff, 1./exponent); + break; + + case L2_norm: + case H1_norm: + // Compute values in quadrature points and integrate + for (unsigned int q=0; q<n_q_points; ++q) + { + double sum = 0; + for (unsigned int k=0; k<n_components; ++k) + sum += data.psi_values[q](k) * data.psi_values[q](k) * + data.weight_vectors[q](k); + diff += sum * fe_values.JxW(q); + } + // Compute the root only, if no derivative values are added later + if (norm == L2_norm) + diff=std::sqrt(diff); + break; + + case Linfty_norm: + case W1infty_norm: + for (unsigned int q=0; q<n_q_points; ++q) + for (unsigned int k=0; k<n_components; ++k) + diff = std::max (diff, std::abs(data.psi_values[q](k)* + data.weight_vectors[q](k))); + break; + + case H1_seminorm: + case W1p_seminorm: + case W1infty_seminorm: + break; + + default: + Assert (false, ExcNotImplemented()); + break; + } + + switch (norm) + { + case W1p_seminorm: + case W1p_norm: + for (unsigned int q=0; q<n_q_points; ++q) + { + double sum = 0; + for (unsigned int k=0; k<n_components; ++k) + sum += std::pow(data.psi_grads[q][k]*data.psi_grads[q][k], + exponent/2.) * data.weight_vectors[q](k); + diff += sum * fe_values.JxW(q); + } + diff = std::pow(diff, 1./exponent); + break; + + case H1_seminorm: + case H1_norm: + for (unsigned int q=0; q<n_q_points; ++q) + { + double sum = 0; + for (unsigned int k=0; k<n_components; ++k) + sum += (data.psi_grads[q][k] * data.psi_grads[q][k]) * + data.weight_vectors[q](k); + diff += sum * fe_values.JxW(q); + } + diff = std::sqrt(diff); + break; + + case W1infty_seminorm: + case W1infty_norm: + { + double t = 0; + for (unsigned int q=0; q<n_q_points; ++q) + for (unsigned int k=0; k<n_components; ++k) + for (unsigned int d=0; d<dim; ++d) + t = std::max(t, std::abs(data.psi_grads[q][k][d]) * + data.weight_vectors[q](k)); + + // then add seminorm to norm if that had previously been computed + diff += t; + } + break; + default: + break; + } + + // append result of this cell to the end of the vector + Assert (numbers::is_finite(diff), ExcNumberNotFinite()); + return diff; + } + + + template <int dim, class InVector, class OutVector, class DH, int spacedim> static void - do_integrate_difference (const dealii::hp::MappingCollection<dim,spacedim> &mapping, + do_integrate_difference (const dealii::hp::MappingCollection<dim,spacedim> &mapping, const DH &dof, const InVector &fe_function, const Function<spacedim> &exact_solution, @@ -4786,13 +5105,9 @@ namespace VectorTools const Function<spacedim> *weight, const double exponent_1) { - // we mark the "exponent" parameter - // to this function "const" since - // it is strictly incoming, but we - // need to set it to something - // different later on, if - // necessary, so have a read-write - // version of it: + // we mark the "exponent" parameter to this function "const" since it is + // strictly incoming, but we need to set it to something different later + // on, if necessary, so have a read-write version of it: double exponent = exponent_1; const unsigned int n_components = dof.get_fe().n_components(); @@ -4843,32 +5158,7 @@ namespace VectorTools } dealii::hp::FECollection<dim,spacedim> fe_collection (dof.get_fe()); - dealii::hp::FEValues<dim,spacedim> x_fe_values(mapping, fe_collection, q, update_flags); - - const unsigned int max_n_q_points = q.max_n_quadrature_points (); - - std::vector< dealii::Vector<double> > - function_values (max_n_q_points, dealii::Vector<double>(n_components)); - std::vector<std::vector<Tensor<1,spacedim> > > - function_grads (max_n_q_points, std::vector<Tensor<1,spacedim> >(n_components)); - - std::vector<double> - weight_values (max_n_q_points); - std::vector<dealii::Vector<double> > - weight_vectors (max_n_q_points, dealii::Vector<double>(n_components)); - - std::vector<dealii::Vector<double> > - psi_values (max_n_q_points, dealii::Vector<double>(n_components)); - std::vector<std::vector<Tensor<1,spacedim> > > - psi_grads (max_n_q_points, std::vector<Tensor<1,spacedim> >(n_components)); - std::vector<double> - psi_scalar (max_n_q_points); - - // tmp vector when we use the - // Function<spacedim> functions for - // scalar functions - std::vector<double> tmp_values (max_n_q_points); - std::vector<Tensor<1,spacedim> > tmp_gradients (max_n_q_points); + IDScratchData<dim,spacedim> data(mapping, fe_collection, q, update_flags); // loop over all cells typename DH::active_cell_iterator cell = dof.begin_active(), @@ -4876,285 +5166,26 @@ namespace VectorTools for (unsigned int index=0; cell != endc; ++cell, ++index) if (cell->is_locally_owned()) { - double diff=0; // initialize for this cell - x_fe_values.reinit (cell); + data.x_fe_values.reinit (cell); - const dealii::FEValues<dim, spacedim> &fe_values = x_fe_values.get_present_fe_values (); + const dealii::FEValues<dim, spacedim> &fe_values = data.x_fe_values.get_present_fe_values (); const unsigned int n_q_points = fe_values.n_quadrature_points; - - // resize all out scratch - // arrays to the number of - // quadrature points we use - // for the present cell - function_values.resize (n_q_points, - dealii::Vector<double>(n_components)); - function_grads.resize (n_q_points, - std::vector<Tensor<1,spacedim> >(n_components)); - - weight_values.resize (n_q_points); - weight_vectors.resize (n_q_points, - dealii::Vector<double>(n_components)); - - psi_values.resize (n_q_points, - dealii::Vector<double>(n_components)); - psi_grads.resize (n_q_points, - std::vector<Tensor<1,spacedim> >(n_components)); - psi_scalar.resize (n_q_points); - - tmp_values.resize (n_q_points); - tmp_gradients.resize (n_q_points); - - if (weight!=0) - { - if (weight->n_components>1) - weight->vector_value_list (fe_values.get_quadrature_points(), - weight_vectors); - else - { - weight->value_list (fe_values.get_quadrature_points(), - weight_values); - for (unsigned int k=0; k<n_q_points; ++k) - weight_vectors[k] = weight_values[k]; - } - } - else - { - for (unsigned int k=0; k<n_q_points; ++k) - weight_vectors[k] = 1.; - } - + data.resize_vectors (n_q_points, n_components); if (update_flags & update_values) - { - // first compute the exact solution - // (vectors) at the quadrature points - // try to do this as efficient as - // possible by avoiding a second - // virtual function call in case - // the function really has only - // one component - if (fe_is_system) - exact_solution.vector_value_list (fe_values.get_quadrature_points(), - psi_values); - else - { - exact_solution.value_list (fe_values.get_quadrature_points(), - tmp_values); - for (unsigned int i=0; i<n_q_points; ++i) - psi_values[i](0) = tmp_values[i]; - } - - // then subtract finite element - // fe_function - fe_values.get_function_values (fe_function, function_values); - for (unsigned int q=0; q<n_q_points; ++q) - psi_values[q] -= function_values[q]; - } - - // Do the same for gradients, if required + fe_values.get_function_values (fe_function, data.function_values); if (update_flags & update_gradients) - { - // try to be a little clever - // to avoid recursive virtual - // function calls when calling - // gradient_list for functions - // that are really scalar - // functions - if (fe_is_system) - exact_solution.vector_gradient_list (fe_values.get_quadrature_points(), - psi_grads); - else - { - exact_solution.gradient_list (fe_values.get_quadrature_points(), - tmp_gradients); - for (unsigned int i=0; i<n_q_points; ++i) - psi_grads[i][0] = tmp_gradients[i]; - } - - // then subtract finite element - // function_grads. We - // need to be careful - // in the codimension - // one case, since - // there we only have - // tangential gradients - // in the finite - // element function, - // not the full - // gradient. This is - // taken care of, by - // subtracting the - // normal component of - // the gradient from - // the exact function. - fe_values.get_function_grads (fe_function, function_grads); - if (update_flags & update_normal_vectors) - for (unsigned int k=0; k<n_components; ++k) - for (unsigned int q=0; q<n_q_points; ++q) - psi_grads[q][k] -= (function_grads[q][k] + - (psi_grads[q][k]* // (f.n) n - fe_values.normal_vector(q))* - fe_values.normal_vector(q)); - else - for (unsigned int k=0; k<n_components; ++k) - for (unsigned int q=0; q<n_q_points; ++q) - psi_grads[q][k] -= function_grads[q][k]; - } - - switch (norm) - { - case mean: - std::fill_n (psi_scalar.begin(), n_q_points, 0.0); - // Compute values in - // quadrature points - for (unsigned int k=0; k<n_components; ++k) - for (unsigned int q=0; q<n_q_points; ++q) - psi_scalar[q] += psi_values[q](k) - * weight_vectors[q](k); - - // Integrate - diff = std::inner_product (psi_scalar.begin(), psi_scalar.end(), - fe_values.get_JxW_values().begin(), - 0.0); - break; - case Lp_norm: - case L1_norm: - case W1p_norm: - std::fill_n (psi_scalar.begin(), n_q_points, 0.0); - // Compute values in - // quadrature points - for (unsigned int k=0; k<n_components; ++k) - for (unsigned int q=0; q<n_q_points; ++q) - psi_scalar[q] += std::pow(psi_values[q](k)*psi_values[q](k), - exponent/2.) - * weight_vectors[q](k); - - // Integrate - diff = std::inner_product (psi_scalar.begin(), psi_scalar.end(), - fe_values.get_JxW_values().begin(), - 0.0); - // Compute the root only, - // if no derivative - // values are added later - if (!(update_flags & update_gradients)) - diff = std::pow(diff, 1./exponent); - break; - case L2_norm: - case H1_norm: - std::fill_n (psi_scalar.begin(), n_q_points, 0.0); - // Compute values in - // quadrature points - for (unsigned int k=0; k<n_components; ++k) - for (unsigned int q=0; q<n_q_points; ++q) - psi_scalar[q] += psi_values[q](k)*psi_values[q](k) - * weight_vectors[q](k); - - // Integrate - diff = std::inner_product (psi_scalar.begin(), psi_scalar.end(), - fe_values.get_JxW_values().begin(), - 0.0); - // Compute the root only, - // if no derivative - // values are added later - if (norm == L2_norm) - diff=std::sqrt(diff); - break; - case Linfty_norm: - case W1infty_norm: - std::fill_n (psi_scalar.begin(), n_q_points, 0.0); - for (unsigned int k=0; k<n_components; ++k) - for (unsigned int q=0; q<n_q_points; ++q) - { - double newval = std::fabs(psi_values[q](k)) - * weight_vectors[q](k); - if (psi_scalar[q]<newval) - psi_scalar[q] = newval; - } - // Maximum on one cell - diff = *std::max_element (psi_scalar.begin(), psi_scalar.end()); - break; - case H1_seminorm: - case W1p_seminorm: - case W1infty_seminorm: - break; - default: - Assert (false, ExcNotImplemented()); - break; - } + fe_values.get_function_grads (fe_function, data.function_grads); - switch (norm) - { - case W1p_seminorm: - case W1p_norm: - std::fill_n (psi_scalar.begin(), n_q_points, 0.0); - for (unsigned int k=0; k<n_components; ++k) - for (unsigned int q=0; q<n_q_points; ++q) - psi_scalar[q] += std::pow(psi_grads[q][k] * psi_grads[q][k], - exponent/2.) - * weight_vectors[q](k); - - diff += std::inner_product (psi_scalar.begin(), psi_scalar.end(), - fe_values.get_JxW_values().begin(), - 0.0); - diff = std::pow(diff, 1./exponent); - break; - case H1_seminorm: - case H1_norm: - // take square of integrand - std::fill_n (psi_scalar.begin(), n_q_points, 0.0); - for (unsigned int k=0; k<n_components; ++k) - for (unsigned int q=0; q<n_q_points; ++q) - psi_scalar[q] += (psi_grads[q][k] * psi_grads[q][k]) - * weight_vectors[q](k); - - // add seminorm to L_2 norm or - // to zero - diff += std::inner_product (psi_scalar.begin(), psi_scalar.end(), - fe_values.get_JxW_values().begin(), - 0.0); - diff = std::sqrt(diff); - break; - - case W1infty_seminorm: - case W1infty_norm: - std::fill_n (psi_scalar.begin(), n_q_points, 0.0); - for (unsigned int k=0; k<n_components; ++k) - for (unsigned int q=0; q<n_q_points; ++q) - { - double t = 0.; - for (unsigned int d=0; d<dim; ++d) - t = std::max(t,std::fabs(psi_grads[q][k][d]) - * weight_vectors[q](k)); - - psi_scalar[q] = std::max(psi_scalar[q],t); - } - - // compute seminorm - { - double t = 0; - for (unsigned int i=0; i<psi_scalar.size(); ++i) - t = std::max (t, psi_scalar[i]); - - // then add seminorm to norm if that had previously been - // computed - diff += t; - } - break; - default: - break; - } - // append result of this cell - // to the end of the vector - Assert (numbers::is_finite(diff), ExcNumberNotFinite()); - difference(index) = diff; + difference(index) = + integrate_difference_inner (exact_solution, norm, weight, + update_flags, exponent, + n_components, data); } else - // the cell is a ghost cell - // or is artificial. write - // a zero into the - // corresponding value of - // the returned vector + // the cell is a ghost cell or is artificial. write a zero into the + // corresponding value of the returned vector difference(index) = 0; } @@ -5235,7 +5266,7 @@ namespace VectorTools const double exponent) { internal - ::do_integrate_difference(hp::StaticMappingQ1<dim>::mapping_collection, + ::do_integrate_difference(hp::StaticMappingQ1<dim,spacedim>::mapping_collection, dof, fe_function, exact_solution, difference, q, norm, weight, exponent); @@ -5544,7 +5575,7 @@ namespace VectorTools } // Error out if we have not constrained anything. Note that in this // case the vector v is always nonempty. - Assert (n == 0 || counter > 0, ExcNoComponentSelected()); + Assert (n == 0 || counter > 0, ComponentMask::ExcNoComponentSelected()); s /= counter; diff --git a/deal.II/source/CMakeLists.txt b/deal.II/source/CMakeLists.txt index 96c55ff3db..bab0c9796e 100644 --- a/deal.II/source/CMakeLists.txt +++ b/deal.II/source/CMakeLists.txt @@ -85,8 +85,8 @@ FOREACH(build ${DEAL_II_BUILD_TYPES}) ) TARGET_LINK_LIBRARIES(${DEAL_II_BASE_NAME}${DEAL_II_${build}_SUFFIX} - ${DEAL_II_EXTERNAL_LIBRARIES} ${DEAL_II_EXTERNAL_LIBRARIES_${build}} + ${DEAL_II_EXTERNAL_LIBRARIES} ) INSTALL(TARGETS ${DEAL_II_BASE_NAME}${DEAL_II_${build}_SUFFIX} diff --git a/deal.II/source/base/data_out_base.cc b/deal.II/source/base/data_out_base.cc index 7277a8520d..b285026281 100644 --- a/deal.II/source/base/data_out_base.cc +++ b/deal.II/source/base/data_out_base.cc @@ -2228,13 +2228,16 @@ DataOutBase::SvgFlags::SvgFlags (const unsigned int height_vector, const int polar_angle, const unsigned int line_thickness, const bool margin, - const bool draw_colorbar) : - height_vector(height_vector), - azimuth_angle(azimuth_angle), - polar_angle(polar_angle), - line_thickness(line_thickness), - margin(margin), - draw_colorbar(draw_colorbar) + const bool draw_colorbar) + : + height(4000), + width(0), + height_vector(height_vector), + azimuth_angle(azimuth_angle), + polar_angle(polar_angle), + line_thickness(line_thickness), + margin(margin), + draw_colorbar(draw_colorbar) {} @@ -5611,8 +5614,8 @@ void DataOutBase::write_svg (const std::vector<Patch<dim,spacedim> > &patches, // do not allow volume rendering AssertThrow (dim==2, ExcNotImplemented()); - const unsigned int height = 4000; - unsigned int width; + const unsigned int height = flags.height; + unsigned int width = flags.width; // margin around the plotted area unsigned int margin_in_percent = 0; @@ -5932,10 +5935,11 @@ void DataOutBase::write_svg (const std::vector<Patch<dim,spacedim> > &patches, } } } - + // write the svg file - width = static_cast<unsigned int>(.5 + height * (x_dimension_perspective / y_dimension_perspective)); + if (width==0) + width = static_cast<unsigned int>(.5 + height * (x_dimension_perspective / y_dimension_perspective)); unsigned int additional_width = 0; if (flags.draw_colorbar) additional_width = static_cast<unsigned int>(.5 + height * .3); // additional width for colorbar @@ -6494,7 +6498,7 @@ void DataOutInterface<dim,spacedim>::write_vtu_in_parallel (const char *filename MPI_Info info; MPI_Info_create(&info); MPI_File fh; - MPI_File_open(MPI_COMM_WORLD, const_cast<char *>(filename), + MPI_File_open(comm, const_cast<char *>(filename), MPI_MODE_CREATE | MPI_MODE_WRONLY, info, &fh); MPI_File_set_size(fh, 0); // delete the file contents // this barrier is necessary, because otherwise others might already diff --git a/deal.II/source/base/parameter_handler.cc b/deal.II/source/base/parameter_handler.cc index 6a8c426d4e..eb0bde28f4 100644 --- a/deal.II/source/base/parameter_handler.cc +++ b/deal.II/source/base/parameter_handler.cc @@ -433,14 +433,18 @@ namespace Patterns List::List (const PatternBase &p, const unsigned int min_elements, - const unsigned int max_elements) + const unsigned int max_elements, + const std::string &separator) : pattern (p.clone()), min_elements (min_elements), - max_elements (max_elements) + max_elements (max_elements), + separator (separator) { Assert (min_elements <= max_elements, ExcInvalidRange (min_elements, max_elements)); + Assert (separator.size() > 0, + ExcMessage ("The separator must have a non-zero length.")); } @@ -457,7 +461,6 @@ namespace Patterns { std::string tmp = test_string_list; std::vector<std::string> split_list; - split_list.reserve (std::count (tmp.begin(), tmp.end(), ',')+1); // first split the input list while (tmp.length() != 0) @@ -465,10 +468,10 @@ namespace Patterns std::string name; name = tmp; - if (name.find(",") != std::string::npos) + if (name.find(separator) != std::string::npos) { - name.erase (name.find(","), std::string::npos); - tmp.erase (0, tmp.find(",")+1); + name.erase (name.find(separator), std::string::npos); + tmp.erase (0, tmp.find(separator)+separator.size()); } else tmp = ""; @@ -481,7 +484,7 @@ namespace Patterns name.erase (name.length()-1, 1); split_list.push_back (name); - }; + } if ((split_list.size() < min_elements) || (split_list.size() > max_elements)) @@ -506,8 +509,10 @@ namespace Patterns description << description_init << " list of <" << pattern->description() << ">" << " of length " << min_elements << "..." << max_elements - << " (inclusive)" - << "]"; + << " (inclusive)"; + if (separator != ",") + description << " separated by <" << separator << ">"; + description << "]"; return description.str(); } @@ -517,7 +522,7 @@ namespace Patterns PatternBase * List::clone () const { - return new List(*pattern, min_elements, max_elements); + return new List(*pattern, min_elements, max_elements, separator); } @@ -525,7 +530,8 @@ namespace Patterns List::memory_consumption () const { return (sizeof(*this) + - MemoryConsumption::memory_consumption(*pattern)); + MemoryConsumption::memory_consumption(*pattern) + + MemoryConsumption::memory_consumption(separator)); } @@ -552,7 +558,14 @@ namespace Patterns if (!(is >> max_elements)) return new List(*base_pattern, min_elements); - return new List(*base_pattern, min_elements, max_elements); + is.ignore(strlen(" separated by <")); + std::string separator; + if (!is) + std::getline(is, separator, '>'); + else + separator = ","; + + return new List(*base_pattern, min_elements, max_elements, separator); } else return 0; @@ -569,15 +582,22 @@ namespace Patterns Map::Map (const PatternBase &p_key, const PatternBase &p_value, const unsigned int min_elements, - const unsigned int max_elements) + const unsigned int max_elements, + const std::string &separator) : key_pattern (p_key.clone()), value_pattern (p_value.clone()), min_elements (min_elements), - max_elements (max_elements) + max_elements (max_elements), + separator (separator) { Assert (min_elements <= max_elements, ExcInvalidRange (min_elements, max_elements)); + Assert (separator.size() > 0, + ExcMessage ("The separator must have a non-zero length.")); + Assert (separator != ":", + ExcMessage ("The separator can not be a colon ':' sicne that " + "is the separator between the two elements of <key:value> pairs")); } @@ -597,7 +617,6 @@ namespace Patterns { std::string tmp = test_string_list; std::vector<std::string> split_list; - split_list.reserve (std::count (tmp.begin(), tmp.end(), ',')+1); // first split the input list at comma sites while (tmp.length() != 0) @@ -605,10 +624,10 @@ namespace Patterns std::string map_entry; map_entry = tmp; - if (map_entry.find(",") != std::string::npos) + if (map_entry.find(separator) != std::string::npos) { - map_entry.erase (map_entry.find(","), std::string::npos); - tmp.erase (0, tmp.find(",")+1); + map_entry.erase (map_entry.find(separator), std::string::npos); + tmp.erase (0, tmp.find(separator)+separator.size()); } else tmp = ""; @@ -621,7 +640,7 @@ namespace Patterns map_entry.erase (map_entry.length()-1, 1); split_list.push_back (map_entry); - }; + } if ((split_list.size() < min_elements) || (split_list.size() > max_elements)) @@ -669,8 +688,10 @@ namespace Patterns << key_pattern->description() << ":" << value_pattern->description() << ">" << " of length " << min_elements << "..." << max_elements - << " (inclusive)" - << "]"; + << " (inclusive)"; + if (separator != ",") + description << " separated by <" << separator << ">"; + description << "]"; return description.str(); } @@ -680,7 +701,9 @@ namespace Patterns PatternBase * Map::clone () const { - return new Map(*key_pattern, *value_pattern, min_elements, max_elements); + return new Map(*key_pattern, *value_pattern, + min_elements, max_elements, + separator); } @@ -689,7 +712,8 @@ namespace Patterns { return (sizeof(*this) + MemoryConsumption::memory_consumption (*key_pattern) + - MemoryConsumption::memory_consumption (*value_pattern)); + MemoryConsumption::memory_consumption (*value_pattern) + + MemoryConsumption::memory_consumption (separator)); } @@ -724,7 +748,16 @@ namespace Patterns if (!(is >> max_elements)) return new Map(*key_pattern, *value_pattern, min_elements); - return new Map(*key_pattern, *value_pattern, min_elements, max_elements); + is.ignore(strlen(" separated by <")); + std::string separator; + if (!is) + std::getline(is, separator, '>'); + else + separator = ","; + + return new Map(*key_pattern, *value_pattern, + min_elements, max_elements, + separator); } else return 0; @@ -1280,7 +1313,8 @@ ParameterHandler::get_current_full_path (const std::string &name) const -bool ParameterHandler::read_input (std::istream &input) +bool ParameterHandler::read_input (std::istream &input, + const std::string &filename) { AssertThrow (input, ExcIO()); @@ -1292,8 +1326,7 @@ bool ParameterHandler::read_input (std::istream &input) { ++lineno; getline (input, line); - if (!scan_line (line, lineno)) - status = false; + status &= scan_line (line, filename, lineno); } return status; @@ -1313,7 +1346,7 @@ bool ParameterHandler::read_input (const std::string &filename, std::ifstream input (openname.c_str()); AssertThrow(input, ExcIO()); - return read_input (input); + return read_input (input, filename); } catch (const PathSearch::ExcFileNotFound &) { @@ -1335,34 +1368,10 @@ bool ParameterHandler::read_input (const std::string &filename, bool ParameterHandler::read_input_from_string (const char *s) { - // if empty std::string then exit - // with success - if ((s == 0) || ((*s) == 0)) return true; - - std::string line; - std::string input (s); - int lineno=0; - - // if necessary append a newline char - // to make all lines equal - if (input[input.length()-1] != '\n') - input += '\n'; - - bool status = true; - while (input.size() != 0) - { - // get one line from Input (=s) - line.assign (input, 0, input.find('\n')); - // delete this part including - // the backspace - input.erase (0, input.find('\n')+1); - ++lineno; - - if (!scan_line (line, lineno)) - status = false; - } - - return status; + // create an istringstream representation and pass it off + // to the other functions doing this work + std::istringstream in (s); + return read_input (in, "input string"); } @@ -1571,6 +1580,10 @@ ParameterHandler::declare_entry (const std::string &entry, entries->put (get_current_full_path(entry) + path_separator + "pattern_description", patterns.back()->description()); + + // as documented, do the default value checking at the very end + AssertThrow (pattern.match (default_value), + ExcValueDoesNotMatchPattern (default_value, pattern.description())); } @@ -2242,8 +2255,9 @@ ParameterHandler::log_parameters_section (LogStream &out) bool -ParameterHandler::scan_line (std::string line, - const unsigned int lineno) +ParameterHandler::scan_line (std::string line, + const std::string &input_filename, + const unsigned int lineno) { // if there is a comment, delete it if (line.find('#') != std::string::npos) @@ -2256,11 +2270,14 @@ ParameterHandler::scan_line (std::string line, line.erase (line.find(" "), 1); // now every existing whitespace // should be exactly one ' '; - // if at end or beginning: delete - if ((line.length() != 0) && (std::isspace (line[0]))) line.erase (0, 1); + // if at beginning: delete + if ((line.length() != 0) && (std::isspace (line[0]))) + line.erase (0, 1); // if line is now empty: leave - if (line.length() == 0) return true; + if (line.length() == 0) + return true; + // also delete spaces at the end if (std::isspace (line[line.length()-1])) line.erase (line.size()-1, 1); @@ -2276,8 +2293,9 @@ ParameterHandler::scan_line (std::string line, // check whether subsection exists if (!entries->get_child_optional (get_current_full_path(subsection))) { - std::cerr << "Line " << lineno - << ": There is no such subsection to be entered: " + std::cerr << "Line <" << lineno + << "> of file <" << input_filename + << ">: There is no such subsection to be entered: " << demangle(get_current_full_path(subsection)) << std::endl; for (unsigned int i=0; i<subsection_path.size(); ++i) std::cerr << std::setw(i*2+4) << " " @@ -2298,8 +2316,9 @@ ParameterHandler::scan_line (std::string line, { if (subsection_path.size() == 0) { - std::cerr << "Line " << lineno - << ": There is no subsection to leave here!" << std::endl; + std::cerr << "Line <" << lineno + << "> of file <" << input_filename + << ">: There is no subsection to leave here!" << std::endl; return false; } else @@ -2340,7 +2359,9 @@ ParameterHandler::scan_line (std::string line, = entries->get<unsigned int> (get_current_full_path(entry_name) + path_separator + "pattern"); if (!patterns[pattern_index]->match(entry_value)) { - std::cerr << "Line " << lineno << ":" << std::endl + std::cerr << "Line <" << lineno + << "> of file <" << input_filename + << ">:" << std::endl << " The entry value" << std::endl << " " << entry_value << std::endl << " for the entry named" << std::endl @@ -2358,8 +2379,9 @@ ParameterHandler::scan_line (std::string line, } else { - std::cerr << "Line " << lineno - << ": No such entry was declared:" << std::endl + std::cerr << "Line <" << lineno + << "> of file <" << input_filename + << ">: No such entry was declared:" << std::endl << " " << entry_name << std::endl << " <Present subsection:" << std::endl; for (unsigned int i=0; i<subsection_path.size(); ++i) @@ -2371,9 +2393,46 @@ ParameterHandler::scan_line (std::string line, } } + // an include statement? + if ((line.find ("INCLUDE ") == 0) || + (line.find ("include ") == 0)) + { + // erase "set" statement and eliminate + // spaces around the '=' + line.erase (0, 7); + while ((line.size() > 0) && (line[0] == ' ')) + line.erase (0, 1); + + // the remainder must then be a filename + if (line.size() == 0) + { + std::cerr << "Line <" << lineno + << "> of file <" << input_filename + << "> is an include statement but does not name a file!" + << std::endl; + + return false; + } + + std::ifstream input (line.c_str()); + if (!input) + { + std::cerr << "Line <" << lineno + << "> of file <" << input_filename + << "> is an include statement but the file <" + << line << "> could not be opened!" + << std::endl; + + return false; + } + else + return read_input (input); + } + // this line matched nothing known - std::cerr << "Line " << lineno - << ": This line matched nothing known ('set' or 'subsection' missing!?):" << std::endl + std::cerr << "Line <" << lineno + << "> of file <" << input_filename + << ">: This line matched nothing known ('set' or 'subsection' missing!?):" << std::endl << " " << line << std::endl; return false; } diff --git a/deal.II/source/base/partitioner.cc b/deal.II/source/base/partitioner.cc index bd9748bc5b..b800411896 100644 --- a/deal.II/source/base/partitioner.cc +++ b/deal.II/source/base/partitioner.cc @@ -122,10 +122,9 @@ namespace Utilities void Partitioner::set_ghost_indices (const IndexSet &ghost_indices_in) { - // Set ghost indices from input. To be sure - // that no entries from the locally owned - // range are present, subtract the locally - // owned indices in any case. + // Set ghost indices from input. To be sure that no entries from the + // locally owned range are present, subtract the locally owned indices + // in any case. Assert (ghost_indices_in.n_elements() == 0 || ghost_indices_in.size() == locally_owned_range_data.size(), ExcDimensionMismatch (ghost_indices_in.size(), @@ -137,18 +136,14 @@ namespace Utilities ghost_indices_data.compress(); n_ghost_indices_data = ghost_indices_data.n_elements(); - // In the rest of this function, we determine - // the point-to-point communication pattern of - // the partitioner. We make up a list with - // both the processors the ghost indices - // actually belong to, and the indices that - // are locally held but ghost indices of other - // processors. This allows then to import and - // export data very easily. - - // find out the end index for each processor - // and communicate it (this implies the start - // index for the next processor) + // In the rest of this function, we determine the point-to-point + // communication pattern of the partitioner. We make up a list with both + // the processors the ghost indices actually belong to, and the indices + // that are locally held but ghost indices of other processors. This + // allows then to import and export data very easily. + + // find out the end index for each processor and communicate it (this + // implies the start index for the next processor) #ifdef DEAL_II_WITH_MPI if (n_procs < 2) { @@ -165,9 +160,8 @@ namespace Utilities MPI_BYTE, communicator); first_index[n_procs] = global_size; - // fix case when there are some processors - // without any locally owned indices: then - // there might be a zero in some entries + // fix case when there are some processors without any locally owned + // indices: then there might be a zero in some entries if (global_size > 0) { unsigned int first_proc_with_nonzero_dofs = 0; @@ -181,8 +175,7 @@ namespace Utilities if (first_index[i] == 0) first_index[i] = first_index[i-1]; - // correct if our processor has a wrong local - // range + // correct if our processor has a wrong local range if (first_index[my_pid] != local_range_data.first) { Assert(local_range_data.first == local_range_data.second, @@ -191,20 +184,16 @@ namespace Utilities } } - // Allocate memory for data that will be - // exported + // Allocate memory for data that will be exported std::vector<types::global_dof_index> expanded_ghost_indices (n_ghost_indices_data); unsigned int n_ghost_targets = 0; if (n_ghost_indices_data > 0) { - // Create first a vector of ghost_targets from - // the list of ghost indices and then push - // back new values. When we are done, copy the - // data to that field of the partitioner. This - // way, the variable ghost_targets will have - // exactly the size we need, whereas the - // vector filled with push_back might actually - // be too long. + // Create first a vector of ghost_targets from the list of ghost + // indices and then push back new values. When we are done, copy the + // data to that field of the partitioner. This way, the variable + // ghost_targets will have exactly the size we need, whereas the + // vector filled with push_back might actually be too long. unsigned int current_proc = 0; ghost_indices_data.fill_index_vector (expanded_ghost_indices); unsigned int current_index = expanded_ghost_indices[0]; @@ -233,8 +222,7 @@ namespace Utilities n_ghost_indices_data - ghost_targets_temp[n_ghost_targets-1].second; ghost_targets_data = ghost_targets_temp; } - // find the processes that want to import to - // me + // find the processes that want to import to me { std::vector<int> send_buffer (n_procs, 0); std::vector<int> receive_buffer (n_procs, 0); @@ -257,9 +245,8 @@ namespace Utilities import_targets_data = import_targets_temp; } - // send and receive indices for import - // data. non-blocking receives and blocking - // sends + // send and receive indices for import data. non-blocking receives and + // blocking sends std::vector<types::global_dof_index> expanded_import_indices (n_import_indices_data); { unsigned int current_index_start = 0; @@ -290,9 +277,8 @@ namespace Utilities MPI_Waitall (import_requests.size(), &import_requests[0], MPI_STATUSES_IGNORE); - // transform import indices to local index - // space and compress contiguous indices in - // form of ranges + // transform import indices to local index space and compress + // contiguous indices in form of ranges { types::global_dof_index last_index = numbers::invalid_dof_index-1; std::vector<std::pair<types::global_dof_index,types::global_dof_index> > compressed_import_indices; diff --git a/deal.II/source/dofs/CMakeLists.txt b/deal.II/source/dofs/CMakeLists.txt index f791bd398e..e3bf9d5631 100644 --- a/deal.II/source/dofs/CMakeLists.txt +++ b/deal.II/source/dofs/CMakeLists.txt @@ -23,23 +23,31 @@ FILE(GLOB _header SET(_src block_info.cc dof_accessor.cc + dof_accessor_get.cc + dof_accessor_set.cc dof_faces.cc dof_handler.cc dof_handler_policy.cc dof_objects.cc dof_renumbering.cc dof_tools.cc + dof_tools_constraints.cc + dof_tools_sparsity.cc number_cache.cc ) SET(_inst block_info.inst.in dof_accessor.inst.in + dof_accessor_get.inst.in + dof_accessor_set.inst.in dof_handler.inst.in dof_handler_policy.inst.in dof_objects.inst.in dof_renumbering.inst.in dof_tools.inst.in + dof_tools_constraints.inst.in + dof_tools_sparsity.inst.in ) DEAL_II_ADD_LIBRARY(obj_dofs OBJECT ${_src} ${_header} ${_inst}) diff --git a/deal.II/source/dofs/dof_accessor.cc b/deal.II/source/dofs/dof_accessor.cc index 59b8c48334..34dbb34906 100644 --- a/deal.II/source/dofs/dof_accessor.cc +++ b/deal.II/source/dofs/dof_accessor.cc @@ -14,16 +14,6 @@ // // --------------------------------------------------------------------- -#include <deal.II/lac/vector.h> -#include <deal.II/lac/block_vector.h> -#include <deal.II/lac/parallel_vector.h> -#include <deal.II/lac/parallel_block_vector.h> -#include <deal.II/lac/petsc_vector.h> -#include <deal.II/lac/petsc_block_vector.h> -#include <deal.II/lac/trilinos_vector.h> -#include <deal.II/lac/trilinos_block_vector.h> -#include <deal.II/lac/sparse_matrix.h> - #include <deal.II/dofs/dof_accessor.h> #include <deal.II/dofs/dof_handler.h> #include <deal.II/dofs/dof_levels.h> @@ -97,174 +87,6 @@ DoFCellAccessor<DH,lda>::neighbor_child_on_subface (const unsigned int face, -template <class DH, bool lda> -template <class InputVector, typename number> -void -DoFCellAccessor<DH,lda>:: -get_interpolated_dof_values (const InputVector &values, - Vector<number> &interpolated_values) const -{ - const FiniteElement<dim,spacedim> &fe = this->get_fe(); - const unsigned int dofs_per_cell = fe.dofs_per_cell; - - Assert (this->dof_handler != 0, - typename BaseClass::ExcInvalidObject()); - Assert (&fe != 0, - typename BaseClass::ExcInvalidObject()); - Assert (interpolated_values.size() == dofs_per_cell, - typename BaseClass::ExcVectorDoesNotMatch()); - Assert (values.size() == this->dof_handler->n_dofs(), - typename BaseClass::ExcVectorDoesNotMatch()); - - if (!this->has_children()) - // if this cell has no children: simply - // return the exact values on this cell - this->get_dof_values (values, interpolated_values); - else - // otherwise clobber them from the children - { - Vector<number> tmp1(dofs_per_cell); - Vector<number> tmp2(dofs_per_cell); - - interpolated_values = 0; - - // later on we will have to - // push the values interpolated - // from the child to the mother - // cell into the output - // vector. unfortunately, there - // are two types of elements: - // ones where you add up the - // contributions from the - // different child cells, and - // ones where you overwrite. - // - // an example for the first is - // piecewise constant (and - // discontinuous) elements, - // where we build the value on - // the coarse cell by averaging - // the values from the cell - // (i.e. by adding up a - // fraction of the values of - // their values) - // - // an example for the latter - // are the usual continuous - // elements. the value on a - // vertex of a coarse cell must - // there be the same, - // irrespective of the adjacent - // cell we are presently on. so - // we always overwrite. in - // fact, we must, since we - // cannot know in advance how - // many neighbors there will - // be, so there is no way to - // compute the average with - // fixed factors - // - // so we have to find out to - // which type this element - // belongs. the difficulty is: - // the finite element may be a - // composed one, so we can only - // hope to do this for each - // shape function - // individually. in fact, there - // are even weird finite - // elements (for example the - // Raviart-Thomas element) - // which have shape functions - // that are additive (interior - // ones) and others that are - // overwriting (face degrees of - // freedom that need to be - // continuous across the - // face). to avoid checking - // this over and over again, we - // do this once now and cache - // the results - std::vector<bool> restriction_is_additive (dofs_per_cell); - for (unsigned int i=0; i<dofs_per_cell; ++i) - restriction_is_additive[i] = fe.restriction_is_additive(i); - - for (unsigned int child=0; child<this->n_children(); ++child) - { - // get the values from the present - // child, if necessary by - // interpolation itself - this->child(child)->get_interpolated_dof_values (values, - tmp1); - // interpolate these to the mother - // cell - fe.get_restriction_matrix(child, this->refinement_case()).vmult (tmp2, tmp1); - - // and add up or set them - // in the output vector - for (unsigned int i=0; i<dofs_per_cell; ++i) - if (restriction_is_additive[i]) - interpolated_values(i) += tmp2(i); - else if (tmp2(i) != number()) - interpolated_values(i) = tmp2(i); - } - } -} - - - -template <class DH, bool lda> -template <class OutputVector, typename number> -void -DoFCellAccessor<DH,lda>:: -set_dof_values_by_interpolation (const Vector<number> &local_values, - OutputVector &values) const -{ - const unsigned int dofs_per_cell = this->get_fe().dofs_per_cell; - - Assert (this->dof_handler != 0, - typename BaseClass::ExcInvalidObject()); - Assert (&this->get_fe() != 0, - typename BaseClass::ExcInvalidObject()); - Assert (local_values.size() == dofs_per_cell, - typename BaseClass::ExcVectorDoesNotMatch()); - Assert (values.size() == this->dof_handler->n_dofs(), - typename BaseClass::ExcVectorDoesNotMatch()); - - if (!this->has_children()) - // if this cell has no children: simply - // set the values on this cell - this->set_dof_values (local_values, values); - else - // otherwise distribute them to the children - { - Vector<number> tmp(dofs_per_cell); - - for (unsigned int child=0; child<this->n_children(); ++child) - { - Assert (this->child(child)->get_fe().dofs_per_cell == dofs_per_cell, - ExcNotImplemented()); - - // prolong the given data - // to the present - // cell. FullMatrix only - // wants us to call vmult - // if the matrix size is - // actually non-zero, so - // check that case - if (tmp.size() > 0) - { - this->get_fe().get_prolongation_matrix(child, this->refinement_case()) - .vmult (tmp, local_values); - - this->child(child)->set_dof_values_by_interpolation (tmp, values); - } - } - } -} - - - // -------------------------------------------------------------------------- // explicit instantiations #include "dof_accessor.inst" diff --git a/deal.II/source/dofs/dof_accessor.inst.in b/deal.II/source/dofs/dof_accessor.inst.in index 103290a711..297e98c829 100644 --- a/deal.II/source/dofs/dof_accessor.inst.in +++ b/deal.II/source/dofs/dof_accessor.inst.in @@ -165,82 +165,3 @@ for (deal_II_dimension : DIMENSIONS; lda : BOOL) #endif } - -for (VEC : SERIAL_VECTORS; SCALAR : REAL_SCALARS; deal_II_dimension : DIMENSIONS; lda : BOOL) - { - template - void - DoFCellAccessor<DoFHandler<deal_II_dimension>, lda>::get_interpolated_dof_values - (const VEC&, Vector<SCALAR>&) const; - template - void - DoFCellAccessor<DoFHandler<deal_II_dimension>, lda>::set_dof_values_by_interpolation - (const Vector<SCALAR>&, VEC&) const; - -#if deal_II_dimension != 3 - - template - void - DoFCellAccessor<DoFHandler<deal_II_dimension,deal_II_dimension+1>, lda>::get_interpolated_dof_values - (const VEC&, Vector<SCALAR>&) const; - template - void - DoFCellAccessor<DoFHandler<deal_II_dimension,deal_II_dimension+1>, lda>::set_dof_values_by_interpolation - (const Vector<SCALAR>&, VEC&) const; - -#endif - -#if deal_II_dimension == 3 - - template - void - DoFCellAccessor<DoFHandler<1,3>, lda>::get_interpolated_dof_values - (const VEC&, Vector<SCALAR>&) const; - template - void - DoFCellAccessor<DoFHandler<1,3>, lda>::set_dof_values_by_interpolation - (const Vector<SCALAR>&, VEC&) const; - -#endif - - } - - -for (VEC : SERIAL_VECTORS; SCALAR : REAL_SCALARS; deal_II_dimension : DIMENSIONS; lda : BOOL) - { - template - void - DoFCellAccessor<hp::DoFHandler<deal_II_dimension>, lda>::get_interpolated_dof_values - (const VEC&, Vector<SCALAR>&) const; - template - void - DoFCellAccessor<hp::DoFHandler<deal_II_dimension>, lda>::set_dof_values_by_interpolation - (const Vector<SCALAR>&, VEC&) const; - -#if deal_II_dimension != 3 - - template - void - DoFCellAccessor<hp::DoFHandler<deal_II_dimension,deal_II_dimension+1>, lda>::get_interpolated_dof_values - (const VEC&, Vector<SCALAR>&) const; - template - void - DoFCellAccessor<hp::DoFHandler<deal_II_dimension,deal_II_dimension+1>, lda>::set_dof_values_by_interpolation - (const Vector<SCALAR>&, VEC&) const; - -#endif - -#if deal_II_dimension == 3 - - template - void - DoFCellAccessor<hp::DoFHandler<1,3>, lda>::get_interpolated_dof_values - (const VEC&, Vector<SCALAR>&) const; - template - void - DoFCellAccessor<hp::DoFHandler<1,3>, lda>::set_dof_values_by_interpolation - (const Vector<SCALAR>&, VEC&) const; - -#endif - } - diff --git a/deal.II/source/dofs/dof_accessor_get.cc b/deal.II/source/dofs/dof_accessor_get.cc new file mode 100644 index 0000000000..9b9ca8b7b8 --- /dev/null +++ b/deal.II/source/dofs/dof_accessor_get.cc @@ -0,0 +1,125 @@ +// --------------------------------------------------------------------- +// $Id$ +// +// Copyright (C) 1998 - 2013 by the deal.II authors +// +// This file is part of the deal.II library. +// +// The deal.II library is free software; you can use it, redistribute +// it, and/or modify it under the terms of the GNU Lesser General +// Public License as published by the Free Software Foundation; either +// version 2.1 of the License, or (at your option) any later version. +// The full text of the license can be found in the file LICENSE at +// the top level of the deal.II distribution. +// +// --------------------------------------------------------------------- + +#include <deal.II/lac/vector.h> +#include <deal.II/lac/block_vector.h> +#include <deal.II/lac/parallel_vector.h> +#include <deal.II/lac/parallel_block_vector.h> +#include <deal.II/lac/petsc_vector.h> +#include <deal.II/lac/petsc_block_vector.h> +#include <deal.II/lac/trilinos_vector.h> +#include <deal.II/lac/trilinos_block_vector.h> +#include <deal.II/lac/sparse_matrix.h> + +#include <deal.II/dofs/dof_accessor.h> +#include <deal.II/dofs/dof_handler.h> +#include <deal.II/dofs/dof_levels.h> +#include <deal.II/hp/dof_handler.h> +#include <deal.II/grid/tria_boundary.h> +#include <deal.II/grid/tria_iterator.h> +#include <deal.II/grid/tria_iterator.templates.h> +#include <deal.II/fe/fe.h> + +#include <vector> + +DEAL_II_NAMESPACE_OPEN + + +template <class DH, bool lda> +template <class InputVector, typename number> +void +DoFCellAccessor<DH,lda>:: +get_interpolated_dof_values (const InputVector &values, + Vector<number> &interpolated_values) const +{ + const FiniteElement<dim,spacedim> &fe = this->get_fe(); + const unsigned int dofs_per_cell = fe.dofs_per_cell; + + Assert (this->dof_handler != 0, + typename BaseClass::ExcInvalidObject()); + Assert (&fe != 0, + typename BaseClass::ExcInvalidObject()); + Assert (interpolated_values.size() == dofs_per_cell, + typename BaseClass::ExcVectorDoesNotMatch()); + Assert (values.size() == this->dof_handler->n_dofs(), + typename BaseClass::ExcVectorDoesNotMatch()); + + if (!this->has_children()) + // if this cell has no children: simply return the exact values on this + // cell + this->get_dof_values (values, interpolated_values); + else + // otherwise clobber them from the children + { + Vector<number> tmp1(dofs_per_cell); + Vector<number> tmp2(dofs_per_cell); + + interpolated_values = 0; + + // later on we will have to push the values interpolated from the child + // to the mother cell into the output vector. unfortunately, there are + // two types of elements: ones where you add up the contributions from + // the different child cells, and ones where you overwrite. + // + // an example for the first is piecewise constant (and discontinuous) + // elements, where we build the value on the coarse cell by averaging + // the values from the cell (i.e. by adding up a fraction of the values + // of their values) + // + // an example for the latter are the usual continuous elements. the + // value on a vertex of a coarse cell must there be the same, + // irrespective of the adjacent cell we are presently on. so we always + // overwrite. in fact, we must, since we cannot know in advance how many + // neighbors there will be, so there is no way to compute the average + // with fixed factors + // + // so we have to find out to which type this element belongs. the + // difficulty is: the finite element may be a composed one, so we can + // only hope to do this for each shape function individually. in fact, + // there are even weird finite elements (for example the Raviart-Thomas + // element) which have shape functions that are additive (interior ones) + // and others that are overwriting (face degrees of freedom that need to + // be continuous across the face). to avoid checking this over and over + // again, we do this once now and cache the results + std::vector<bool> restriction_is_additive (dofs_per_cell); + for (unsigned int i=0; i<dofs_per_cell; ++i) + restriction_is_additive[i] = fe.restriction_is_additive(i); + + for (unsigned int child=0; child<this->n_children(); ++child) + { + // get the values from the present child, if necessary by + // interpolation itself + this->child(child)->get_interpolated_dof_values (values, + tmp1); + // interpolate these to the mother cell + fe.get_restriction_matrix(child, this->refinement_case()).vmult (tmp2, tmp1); + + // and add up or set them in the output vector + for (unsigned int i=0; i<dofs_per_cell; ++i) + if (restriction_is_additive[i]) + interpolated_values(i) += tmp2(i); + else if (tmp2(i) != number()) + interpolated_values(i) = tmp2(i); + } + } +} + + +// -------------------------------------------------------------------------- +// explicit instantiations +#include "dof_accessor_get.inst" + +DEAL_II_NAMESPACE_CLOSE diff --git a/deal.II/source/dofs/dof_accessor_get.inst.in b/deal.II/source/dofs/dof_accessor_get.inst.in new file mode 100644 index 0000000000..75d1009f06 --- /dev/null +++ b/deal.II/source/dofs/dof_accessor_get.inst.in @@ -0,0 +1,72 @@ +// --------------------------------------------------------------------- +// $Id$ +// +// Copyright (C) 1998 - 2013 by the deal.II authors +// +// This file is part of the deal.II library. +// +// The deal.II library is free software; you can use it, redistribute +// it, and/or modify it under the terms of the GNU Lesser General +// Public License as published by the Free Software Foundation; either +// version 2.1 of the License, or (at your option) any later version. +// The full text of the license can be found in the file LICENSE at +// the top level of the deal.II distribution. +// +// --------------------------------------------------------------------- + + + +for (VEC : SERIAL_VECTORS; SCALAR : REAL_SCALARS; deal_II_dimension : DIMENSIONS; lda : BOOL) + { + template + void + DoFCellAccessor<DoFHandler<deal_II_dimension>, lda>::get_interpolated_dof_values + (const VEC&, Vector<SCALAR>&) const; + +#if deal_II_dimension != 3 + + template + void + DoFCellAccessor<DoFHandler<deal_II_dimension,deal_II_dimension+1>, lda>::get_interpolated_dof_values + (const VEC&, Vector<SCALAR>&) const; + +#endif + +#if deal_II_dimension == 3 + + template + void + DoFCellAccessor<DoFHandler<1,3>, lda>::get_interpolated_dof_values + (const VEC&, Vector<SCALAR>&) const; + +#endif + + } + + +for (VEC : SERIAL_VECTORS; SCALAR : REAL_SCALARS; deal_II_dimension : DIMENSIONS; lda : BOOL) + { + template + void + DoFCellAccessor<hp::DoFHandler<deal_II_dimension>, lda>::get_interpolated_dof_values + (const VEC&, Vector<SCALAR>&) const; + +#if deal_II_dimension != 3 + + template + void + DoFCellAccessor<hp::DoFHandler<deal_II_dimension,deal_II_dimension+1>, lda>::get_interpolated_dof_values + (const VEC&, Vector<SCALAR>&) const; + +#endif + +#if deal_II_dimension == 3 + + template + void + DoFCellAccessor<hp::DoFHandler<1,3>, lda>::get_interpolated_dof_values + (const VEC&, Vector<SCALAR>&) const; + +#endif + } + diff --git a/deal.II/source/dofs/dof_accessor_set.cc b/deal.II/source/dofs/dof_accessor_set.cc new file mode 100644 index 0000000000..f11fc845a0 --- /dev/null +++ b/deal.II/source/dofs/dof_accessor_set.cc @@ -0,0 +1,93 @@ +// --------------------------------------------------------------------- +// $Id$ +// +// Copyright (C) 1998 - 2013 by the deal.II authors +// +// This file is part of the deal.II library. +// +// The deal.II library is free software; you can use it, redistribute +// it, and/or modify it under the terms of the GNU Lesser General +// Public License as published by the Free Software Foundation; either +// version 2.1 of the License, or (at your option) any later version. +// The full text of the license can be found in the file LICENSE at +// the top level of the deal.II distribution. +// +// --------------------------------------------------------------------- + +#include <deal.II/lac/vector.h> +#include <deal.II/lac/block_vector.h> +#include <deal.II/lac/parallel_vector.h> +#include <deal.II/lac/parallel_block_vector.h> +#include <deal.II/lac/petsc_vector.h> +#include <deal.II/lac/petsc_block_vector.h> +#include <deal.II/lac/trilinos_vector.h> +#include <deal.II/lac/trilinos_block_vector.h> +#include <deal.II/lac/sparse_matrix.h> + +#include <deal.II/dofs/dof_accessor.h> +#include <deal.II/dofs/dof_handler.h> +#include <deal.II/dofs/dof_levels.h> +#include <deal.II/hp/dof_handler.h> +#include <deal.II/grid/tria_boundary.h> +#include <deal.II/grid/tria_iterator.h> +#include <deal.II/grid/tria_iterator.templates.h> +#include <deal.II/fe/fe.h> + +#include <vector> + +DEAL_II_NAMESPACE_OPEN + + + +template <class DH, bool lda> +template <class OutputVector, typename number> +void +DoFCellAccessor<DH,lda>:: +set_dof_values_by_interpolation (const Vector<number> &local_values, + OutputVector &values) const +{ + const unsigned int dofs_per_cell = this->get_fe().dofs_per_cell; + + Assert (this->dof_handler != 0, + typename BaseClass::ExcInvalidObject()); + Assert (&this->get_fe() != 0, + typename BaseClass::ExcInvalidObject()); + Assert (local_values.size() == dofs_per_cell, + typename BaseClass::ExcVectorDoesNotMatch()); + Assert (values.size() == this->dof_handler->n_dofs(), + typename BaseClass::ExcVectorDoesNotMatch()); + + if (!this->has_children()) + // if this cell has no children: simply set the values on this cell + this->set_dof_values (local_values, values); + else + // otherwise distribute them to the children + { + Vector<number> tmp(dofs_per_cell); + + for (unsigned int child=0; child<this->n_children(); ++child) + { + Assert (this->child(child)->get_fe().dofs_per_cell == dofs_per_cell, + ExcNotImplemented()); + + // prolong the given data to the present cell. FullMatrix only wants + // us to call vmult if the matrix size is actually non-zero, so + // check that case + if (tmp.size() > 0) + { + this->get_fe().get_prolongation_matrix(child, this->refinement_case()) + .vmult (tmp, local_values); + + this->child(child)->set_dof_values_by_interpolation (tmp, values); + } + } + } +} + + + +// -------------------------------------------------------------------------- +// explicit instantiations +#include "dof_accessor_set.inst" + +DEAL_II_NAMESPACE_CLOSE diff --git a/deal.II/source/dofs/dof_accessor_set.inst.in b/deal.II/source/dofs/dof_accessor_set.inst.in new file mode 100644 index 0000000000..74948318e8 --- /dev/null +++ b/deal.II/source/dofs/dof_accessor_set.inst.in @@ -0,0 +1,72 @@ +// --------------------------------------------------------------------- +// $Id$ +// +// Copyright (C) 1998 - 2013 by the deal.II authors +// +// This file is part of the deal.II library. +// +// The deal.II library is free software; you can use it, redistribute +// it, and/or modify it under the terms of the GNU Lesser General +// Public License as published by the Free Software Foundation; either +// version 2.1 of the License, or (at your option) any later version. +// The full text of the license can be found in the file LICENSE at +// the top level of the deal.II distribution. +// +// --------------------------------------------------------------------- + + + +for (VEC : SERIAL_VECTORS; SCALAR : REAL_SCALARS; deal_II_dimension : DIMENSIONS; lda : BOOL) + { + template + void + DoFCellAccessor<DoFHandler<deal_II_dimension>, lda>::set_dof_values_by_interpolation + (const Vector<SCALAR>&, VEC&) const; + +#if deal_II_dimension != 3 + + template + void + DoFCellAccessor<DoFHandler<deal_II_dimension,deal_II_dimension+1>, lda>::set_dof_values_by_interpolation + (const Vector<SCALAR>&, VEC&) const; + +#endif + +#if deal_II_dimension == 3 + + template + void + DoFCellAccessor<DoFHandler<1,3>, lda>::set_dof_values_by_interpolation + (const Vector<SCALAR>&, VEC&) const; + +#endif + + } + + +for (VEC : SERIAL_VECTORS; SCALAR : REAL_SCALARS; deal_II_dimension : DIMENSIONS; lda : BOOL) + { + template + void + DoFCellAccessor<hp::DoFHandler<deal_II_dimension>, lda>::set_dof_values_by_interpolation + (const Vector<SCALAR>&, VEC&) const; + +#if deal_II_dimension != 3 + + template + void + DoFCellAccessor<hp::DoFHandler<deal_II_dimension,deal_II_dimension+1>, lda>::set_dof_values_by_interpolation + (const Vector<SCALAR>&, VEC&) const; + +#endif + +#if deal_II_dimension == 3 + + template + void + DoFCellAccessor<hp::DoFHandler<1,3>, lda>::set_dof_values_by_interpolation + (const Vector<SCALAR>&, VEC&) const; + +#endif + } + diff --git a/deal.II/source/dofs/dof_tools.cc b/deal.II/source/dofs/dof_tools.cc index ad41b28892..51b5f2ec55 100644 --- a/deal.II/source/dofs/dof_tools.cc +++ b/deal.II/source/dofs/dof_tools.cc @@ -41,7 +41,6 @@ #include <deal.II/hp/q_collection.h> #include <deal.II/hp/fe_values.h> #include <deal.II/dofs/dof_tools.h> -#include <deal.II/numerics/vector_tools.h> #include <deal.II/multigrid/mg_dof_handler.h> @@ -54,3212 +53,6 @@ DEAL_II_NAMESPACE_OPEN namespace DoFTools { - - template <class DH, class SparsityPattern> - void - make_sparsity_pattern (const DH &dof, - SparsityPattern &sparsity, - const ConstraintMatrix &constraints, - const bool keep_constrained_dofs, - const types::subdomain_id subdomain_id) - { - const types::global_dof_index n_dofs = dof.n_dofs(); - - Assert (sparsity.n_rows() == n_dofs, - ExcDimensionMismatch (sparsity.n_rows(), n_dofs)); - Assert (sparsity.n_cols() == n_dofs, - ExcDimensionMismatch (sparsity.n_cols(), n_dofs)); - - // If we have a distributed::Triangulation only allow locally_owned - // subdomain. Not setting a subdomain is also okay, because we skip - // ghost cells in the loop below. - Assert ( - (dof.get_tria().locally_owned_subdomain() == numbers::invalid_subdomain_id) - || - (subdomain_id == numbers::invalid_subdomain_id) - || - (subdomain_id == dof.get_tria().locally_owned_subdomain()), - ExcMessage ("For parallel::distributed::Triangulation objects and " - "associated DoF handler objects, asking for any subdomain other " - "than the locally owned one does not make sense.")); - - std::vector<types::global_dof_index> dofs_on_this_cell; - dofs_on_this_cell.reserve (max_dofs_per_cell(dof)); - typename DH::active_cell_iterator cell = dof.begin_active(), - endc = dof.end(); - - // In case we work with a distributed sparsity pattern of Trilinos - // type, we only have to do the work if the current cell is owned by - // the calling processor. Otherwise, just continue. - for (; cell!=endc; ++cell) - if (((subdomain_id == numbers::invalid_subdomain_id) - || - (subdomain_id == cell->subdomain_id())) - && - cell->is_locally_owned()) - { - const unsigned int dofs_per_cell = cell->get_fe().dofs_per_cell; - dofs_on_this_cell.resize (dofs_per_cell); - cell->get_dof_indices (dofs_on_this_cell); - - // make sparsity pattern for this cell. if no constraints pattern - // was given, then the following call acts as if simply no - // constraints existed - constraints.add_entries_local_to_global (dofs_on_this_cell, - sparsity, - keep_constrained_dofs); - } - } - - - - template <class DH, class SparsityPattern> - void - make_sparsity_pattern (const DH &dof, - const Table<2,Coupling> &couplings, - SparsityPattern &sparsity, - const ConstraintMatrix &constraints, - const bool keep_constrained_dofs, - const types::subdomain_id subdomain_id) - { - const types::global_dof_index n_dofs = dof.n_dofs(); - - Assert (sparsity.n_rows() == n_dofs, - ExcDimensionMismatch (sparsity.n_rows(), n_dofs)); - Assert (sparsity.n_cols() == n_dofs, - ExcDimensionMismatch (sparsity.n_cols(), n_dofs)); - Assert (couplings.n_rows() == dof.get_fe().n_components(), - ExcDimensionMismatch(couplings.n_rows(), dof.get_fe().n_components())); - Assert (couplings.n_cols() == dof.get_fe().n_components(), - ExcDimensionMismatch(couplings.n_cols(), dof.get_fe().n_components())); - - // If we have a distributed::Triangulation only allow locally_owned - // subdomain. Not setting a subdomain is also okay, because we skip - // ghost cells in the loop below. - Assert ( - (dof.get_tria().locally_owned_subdomain() == numbers::invalid_subdomain_id) - || - (subdomain_id == numbers::invalid_subdomain_id) - || - (subdomain_id == dof.get_tria().locally_owned_subdomain()), - ExcMessage ("For parallel::distributed::Triangulation objects and " - "associated DoF handler objects, asking for any subdomain other " - "than the locally owned one does not make sense.")); - - const hp::FECollection<DH::dimension,DH::space_dimension> fe_collection (dof.get_fe()); - - // first, for each finite element, build a mask for each dof, not like - // the one given which represents components. make sure we do the right - // thing also with respect to non-primitive shape functions, which - // takes some additional thought - std::vector<Table<2,bool> > dof_mask(fe_collection.size()); - - // check whether the table of couplings contains only true arguments, - // i.e., we do not exclude any index. that is the easy case, since we - // don't have to set up the tables - bool need_dof_mask = false; - for (unsigned int i=0; i<couplings.n_rows(); ++i) - for (unsigned int j=0; j<couplings.n_cols(); ++j) - if (couplings(i,j) == none) - need_dof_mask = true; - - if (need_dof_mask == true) - for (unsigned int f=0; f<fe_collection.size(); ++f) - { - const unsigned int dofs_per_cell = fe_collection[f].dofs_per_cell; - - dof_mask[f].reinit (dofs_per_cell, dofs_per_cell); - - for (unsigned int i=0; i<dofs_per_cell; ++i) - for (unsigned int j=0; j<dofs_per_cell; ++j) - if (fe_collection[f].is_primitive(i) && - fe_collection[f].is_primitive(j)) - dof_mask[f](i,j) - = (couplings(fe_collection[f].system_to_component_index(i).first, - fe_collection[f].system_to_component_index(j).first) != none); - else - { - const unsigned int first_nonzero_comp_i - = fe_collection[f].get_nonzero_components(i).first_selected_component(); - const unsigned int first_nonzero_comp_j - = fe_collection[f].get_nonzero_components(j).first_selected_component(); - Assert (first_nonzero_comp_i < fe_collection[f].n_components(), - ExcInternalError()); - Assert (first_nonzero_comp_j < fe_collection[f].n_components(), - ExcInternalError()); - - dof_mask[f](i,j) - = (couplings(first_nonzero_comp_i,first_nonzero_comp_j) != none); - } - } - - - std::vector<types::global_dof_index> dofs_on_this_cell(fe_collection.max_dofs_per_cell()); - typename DH::active_cell_iterator cell = dof.begin_active(), - endc = dof.end(); - - // In case we work with a distributed sparsity pattern of Trilinos - // type, we only have to do the work if the current cell is owned by - // the calling processor. Otherwise, just continue. - for (; cell!=endc; ++cell) - if (((subdomain_id == numbers::invalid_subdomain_id) - || - (subdomain_id == cell->subdomain_id())) - && - cell->is_locally_owned()) - { - const unsigned int fe_index = cell->active_fe_index(); - const unsigned int dofs_per_cell =fe_collection[fe_index].dofs_per_cell; - - dofs_on_this_cell.resize (dofs_per_cell); - cell->get_dof_indices (dofs_on_this_cell); - - - // make sparsity pattern for this cell. if no constraints pattern - // was given, then the following call acts as if simply no - // constraints existed - constraints.add_entries_local_to_global (dofs_on_this_cell, - sparsity, - keep_constrained_dofs, - dof_mask[fe_index]); - } - } - - - - template <class DH, class SparsityPattern> - void - make_sparsity_pattern ( - const DH &dof_row, - const DH &dof_col, - SparsityPattern &sparsity) - { - const types::global_dof_index n_dofs_row = dof_row.n_dofs(); - const types::global_dof_index n_dofs_col = dof_col.n_dofs(); - - Assert (sparsity.n_rows() == n_dofs_row, - ExcDimensionMismatch (sparsity.n_rows(), n_dofs_row)); - Assert (sparsity.n_cols() == n_dofs_col, - ExcDimensionMismatch (sparsity.n_cols(), n_dofs_col)); - -//TODO: Looks like wasteful memory management here - - const std::list<std::pair<typename DH::cell_iterator, - typename DH::cell_iterator> > - cell_list - = GridTools::get_finest_common_cells (dof_row, dof_col); - - - typename std::list<std::pair<typename DH::cell_iterator, - typename DH::cell_iterator> >::const_iterator - cell_iter = cell_list.begin(); - - for (; cell_iter!=cell_list.end(); ++cell_iter) - { - const typename DH::cell_iterator cell_row = cell_iter->first; - const typename DH::cell_iterator cell_col = cell_iter->second; - - if (!cell_row->has_children() && !cell_col->has_children()) - { - const unsigned int dofs_per_cell_row = - cell_row->get_fe().dofs_per_cell; - const unsigned int dofs_per_cell_col = - cell_col->get_fe().dofs_per_cell; - std::vector<types::global_dof_index> - local_dof_indices_row(dofs_per_cell_row); - std::vector<types::global_dof_index> - local_dof_indices_col(dofs_per_cell_col); - cell_row->get_dof_indices (local_dof_indices_row); - cell_col->get_dof_indices (local_dof_indices_col); - for (unsigned int i=0; i<dofs_per_cell_row; ++i) - sparsity.add_entries (local_dof_indices_row[i], - local_dof_indices_col.begin(), - local_dof_indices_col.end()); - } - else if (cell_row->has_children()) - { - const std::vector<typename DH::active_cell_iterator > - child_cells = GridTools::get_active_child_cells<DH> (cell_row); - for (unsigned int i=0; i<child_cells.size(); i++) - { - const typename DH::cell_iterator - cell_row_child = child_cells[i]; - const unsigned int dofs_per_cell_row = - cell_row_child->get_fe().dofs_per_cell; - const unsigned int dofs_per_cell_col = - cell_col->get_fe().dofs_per_cell; - std::vector<types::global_dof_index> - local_dof_indices_row(dofs_per_cell_row); - std::vector<types::global_dof_index> - local_dof_indices_col(dofs_per_cell_col); - cell_row_child->get_dof_indices (local_dof_indices_row); - cell_col->get_dof_indices (local_dof_indices_col); - for (unsigned int i=0; i<dofs_per_cell_row; ++i) - sparsity.add_entries (local_dof_indices_row[i], - local_dof_indices_col.begin(), - local_dof_indices_col.end()); - } - } - else - { - std::vector<typename DH::active_cell_iterator> - child_cells = GridTools::get_active_child_cells<DH> (cell_col); - for (unsigned int i=0; i<child_cells.size(); i++) - { - const typename DH::active_cell_iterator - cell_col_child = child_cells[i]; - const unsigned int dofs_per_cell_row = - cell_row->get_fe().dofs_per_cell; - const unsigned int dofs_per_cell_col = - cell_col_child->get_fe().dofs_per_cell; - std::vector<types::global_dof_index> - local_dof_indices_row(dofs_per_cell_row); - std::vector<types::global_dof_index> - local_dof_indices_col(dofs_per_cell_col); - cell_row->get_dof_indices (local_dof_indices_row); - cell_col_child->get_dof_indices (local_dof_indices_col); - for (unsigned int i=0; i<dofs_per_cell_row; ++i) - sparsity.add_entries (local_dof_indices_row[i], - local_dof_indices_col.begin(), - local_dof_indices_col.end()); - } - } - } - } - - - - template <class DH, class SparsityPattern> - void - make_boundary_sparsity_pattern ( - const DH &dof, - const std::vector<types::global_dof_index> &dof_to_boundary_mapping, - SparsityPattern &sparsity) - { - if (DH::dimension == 1) - { - // there are only 2 boundary indicators in 1d, so it is no - // performance problem to call the other function - typename DH::FunctionMap boundary_indicators; - boundary_indicators[0] = 0; - boundary_indicators[1] = 0; - make_boundary_sparsity_pattern<DH, SparsityPattern> (dof, - boundary_indicators, - dof_to_boundary_mapping, - sparsity); - return; - } - - const types::global_dof_index n_dofs = dof.n_dofs(); - - AssertDimension (dof_to_boundary_mapping.size(), n_dofs); - AssertDimension (sparsity.n_rows(), dof.n_boundary_dofs()); - AssertDimension (sparsity.n_cols(), dof.n_boundary_dofs()); -#ifdef DEBUG - if (sparsity.n_rows() != 0) - { - types::global_dof_index max_element = 0; - for (std::vector<types::global_dof_index>::const_iterator i=dof_to_boundary_mapping.begin(); - i!=dof_to_boundary_mapping.end(); ++i) - if ((*i != DH::invalid_dof_index) && - (*i > max_element)) - max_element = *i; - AssertDimension (max_element, sparsity.n_rows()-1); - }; -#endif - - std::vector<types::global_dof_index> dofs_on_this_face; - dofs_on_this_face.reserve (max_dofs_per_face(dof)); - - // loop over all faces to check whether they are at a boundary. note - // that we need not take special care of single lines (using - // @p{cell->has_boundary_lines}), since we do not support boundaries of - // dimension dim-2, and so every boundary line is also part of a - // boundary face. - typename DH::active_cell_iterator cell = dof.begin_active(), - endc = dof.end(); - for (; cell!=endc; ++cell) - for (unsigned int f=0; f<GeometryInfo<DH::dimension>::faces_per_cell; ++f) - if (cell->at_boundary(f)) - { - const unsigned int dofs_per_face = cell->get_fe().dofs_per_face; - dofs_on_this_face.resize (dofs_per_face); - cell->face(f)->get_dof_indices (dofs_on_this_face, - cell->active_fe_index()); - - // make sparsity pattern for this cell - for (unsigned int i=0; i<dofs_per_face; ++i) - for (unsigned int j=0; j<dofs_per_face; ++j) - sparsity.add (dof_to_boundary_mapping[dofs_on_this_face[i]], - dof_to_boundary_mapping[dofs_on_this_face[j]]); - } - } - - - - template <class DH, class SparsityPattern> - void make_boundary_sparsity_pattern ( - const DH &dof, - const typename FunctionMap<DH::space_dimension>::type &boundary_indicators, - const std::vector<types::global_dof_index> &dof_to_boundary_mapping, - SparsityPattern &sparsity) - { - if (DH::dimension == 1) - { - // first check left, then right boundary point - for (unsigned int direction=0; direction<2; ++direction) - { - // if this boundary is not requested, then go on with next one - if (boundary_indicators.find(direction) == - boundary_indicators.end()) - continue; - - // find active cell at that boundary: first go to left/right, - // then to children - typename DH::level_cell_iterator cell = dof.begin(0); - while (!cell->at_boundary(direction)) - cell = cell->neighbor(direction); - while (!cell->active()) - cell = cell->child(direction); - - const unsigned int dofs_per_vertex = cell->get_fe().dofs_per_vertex; - std::vector<types::global_dof_index> boundary_dof_boundary_indices (dofs_per_vertex); - - // next get boundary mapped dof indices of boundary dofs - for (unsigned int i=0; i<dofs_per_vertex; ++i) - boundary_dof_boundary_indices[i] - = dof_to_boundary_mapping[cell->vertex_dof_index(direction,i)]; - - for (unsigned int i=0; i<dofs_per_vertex; ++i) - sparsity.add_entries (boundary_dof_boundary_indices[i], - boundary_dof_boundary_indices.begin(), - boundary_dof_boundary_indices.end()); - }; - return; - } - - const types::global_dof_index n_dofs = dof.n_dofs(); - - AssertDimension (dof_to_boundary_mapping.size(), n_dofs); - Assert (boundary_indicators.find(numbers::internal_face_boundary_id) == boundary_indicators.end(), - typename DH::ExcInvalidBoundaryIndicator()); - Assert (sparsity.n_rows() == dof.n_boundary_dofs (boundary_indicators), - ExcDimensionMismatch (sparsity.n_rows(), dof.n_boundary_dofs (boundary_indicators))); - Assert (sparsity.n_cols() == dof.n_boundary_dofs (boundary_indicators), - ExcDimensionMismatch (sparsity.n_cols(), dof.n_boundary_dofs (boundary_indicators))); -#ifdef DEBUG - if (sparsity.n_rows() != 0) - { - types::global_dof_index max_element = 0; - for (std::vector<types::global_dof_index>::const_iterator i=dof_to_boundary_mapping.begin(); - i!=dof_to_boundary_mapping.end(); ++i) - if ((*i != DH::invalid_dof_index) && - (*i > max_element)) - max_element = *i; - AssertDimension (max_element, sparsity.n_rows()-1); - }; -#endif - - std::vector<types::global_dof_index> dofs_on_this_face; - dofs_on_this_face.reserve (max_dofs_per_face(dof)); - typename DH::active_cell_iterator cell = dof.begin_active(), - endc = dof.end(); - for (; cell!=endc; ++cell) - for (unsigned int f=0; f<GeometryInfo<DH::dimension>::faces_per_cell; ++f) - if (boundary_indicators.find(cell->face(f)->boundary_indicator()) != - boundary_indicators.end()) - { - const unsigned int dofs_per_face = cell->get_fe().dofs_per_face; - dofs_on_this_face.resize (dofs_per_face); - cell->face(f)->get_dof_indices (dofs_on_this_face, - cell->active_fe_index()); - - // make sparsity pattern for this cell - for (unsigned int i=0; i<dofs_per_face; ++i) - for (unsigned int j=0; j<dofs_per_face; ++j) - sparsity.add (dof_to_boundary_mapping[dofs_on_this_face[i]], - dof_to_boundary_mapping[dofs_on_this_face[j]]); - } - } - - - - template <class DH, class SparsityPattern> - void - make_flux_sparsity_pattern (const DH &dof, - SparsityPattern &sparsity, - const ConstraintMatrix &constraints, - const bool keep_constrained_dofs, - const types::subdomain_id subdomain_id) - - // TODO: QA: reduce the indentation level of this method..., Maier 2012 - - { - const types::global_dof_index n_dofs = dof.n_dofs(); - - AssertDimension (sparsity.n_rows(), n_dofs); - AssertDimension (sparsity.n_cols(), n_dofs); - - // If we have a distributed::Triangulation only allow locally_owned - // subdomain. Not setting a subdomain is also okay, because we skip - // ghost cells in the loop below. - Assert ( - (dof.get_tria().locally_owned_subdomain() == numbers::invalid_subdomain_id) - || - (subdomain_id == numbers::invalid_subdomain_id) - || - (subdomain_id == dof.get_tria().locally_owned_subdomain()), - ExcMessage ("For parallel::distributed::Triangulation objects and " - "associated DoF handler objects, asking for any subdomain other " - "than the locally owned one does not make sense.")); - - std::vector<types::global_dof_index> dofs_on_this_cell; - std::vector<types::global_dof_index> dofs_on_other_cell; - dofs_on_this_cell.reserve (max_dofs_per_cell(dof)); - dofs_on_other_cell.reserve (max_dofs_per_cell(dof)); - typename DH::active_cell_iterator cell = dof.begin_active(), - endc = dof.end(); - - // TODO: in an old implementation, we used user flags before to tag - // faces that were already touched. this way, we could reduce the work - // a little bit. now, we instead add only data from one side. this - // should be OK, but we need to actually verify it. - - // In case we work with a distributed sparsity pattern of Trilinos - // type, we only have to do the work if the current cell is owned by - // the calling processor. Otherwise, just continue. - for (; cell!=endc; ++cell) - if (((subdomain_id == numbers::invalid_subdomain_id) - || - (subdomain_id == cell->subdomain_id())) - && - cell->is_locally_owned()) - { - const unsigned int n_dofs_on_this_cell = cell->get_fe().dofs_per_cell; - dofs_on_this_cell.resize (n_dofs_on_this_cell); - cell->get_dof_indices (dofs_on_this_cell); - - // make sparsity pattern for this cell. if no constraints pattern - // was given, then the following call acts as if simply no - // constraints existed - constraints.add_entries_local_to_global (dofs_on_this_cell, - sparsity, - keep_constrained_dofs); - - for (unsigned int face = 0; - face < GeometryInfo<DH::dimension>::faces_per_cell; - ++face) - { - typename DH::face_iterator cell_face = cell->face(face); - if (! cell->at_boundary(face) ) - { - typename DH::level_cell_iterator neighbor = cell->neighbor(face); - - // in 1d, we do not need to worry whether the neighbor - // might have children and then loop over those children. - // rather, we may as well go straight to to cell behind - // this particular cell's most terminal child - if (DH::dimension==1) - while (neighbor->has_children()) - neighbor = neighbor->child(face==0 ? 1 : 0); - - if (neighbor->has_children()) - { - for (unsigned int sub_nr = 0; - sub_nr != cell_face->number_of_children(); - ++sub_nr) - { - const typename DH::level_cell_iterator - sub_neighbor - = cell->neighbor_child_on_subface (face, sub_nr); - - const unsigned int n_dofs_on_neighbor - = sub_neighbor->get_fe().dofs_per_cell; - dofs_on_other_cell.resize (n_dofs_on_neighbor); - sub_neighbor->get_dof_indices (dofs_on_other_cell); - - constraints.add_entries_local_to_global - (dofs_on_this_cell, dofs_on_other_cell, - sparsity, keep_constrained_dofs); - constraints.add_entries_local_to_global - (dofs_on_other_cell, dofs_on_this_cell, - sparsity, keep_constrained_dofs); - } - } - else - { - // Refinement edges are taken care of by coarser - // cells - - // TODO: in the distributed case, we miss out the - // constraints when the neighbor cell is coarser, but - // only the current cell is owned locally! - if (cell->neighbor_is_coarser(face)) - continue; - - const unsigned int n_dofs_on_neighbor - = neighbor->get_fe().dofs_per_cell; - dofs_on_other_cell.resize (n_dofs_on_neighbor); - - neighbor->get_dof_indices (dofs_on_other_cell); - - constraints.add_entries_local_to_global - (dofs_on_this_cell, dofs_on_other_cell, - sparsity, keep_constrained_dofs); - - // only need to add these in case the neighbor cell - // is not locally owned - otherwise, we touch each - // face twice and hence put the indices the other way - // around - if (!cell->neighbor(face)->active() - || - (cell->neighbor(face)->subdomain_id() != - cell->subdomain_id())) - constraints.add_entries_local_to_global - (dofs_on_other_cell, dofs_on_this_cell, - sparsity, keep_constrained_dofs); - } - } - } - } - } - - - - template <class DH, class SparsityPattern> - void - make_flux_sparsity_pattern (const DH &dof, - SparsityPattern &sparsity) - { - ConstraintMatrix constraints; - make_flux_sparsity_pattern (dof, sparsity, constraints); - } - - - - template <int dim, int spacedim> - Table<2,Coupling> - dof_couplings_from_component_couplings (const FiniteElement<dim,spacedim> &fe, - const Table<2,Coupling> &component_couplings) - { - Assert(component_couplings.n_rows() == fe.n_components(), - ExcDimensionMismatch(component_couplings.n_rows(), - fe.n_components())); - Assert(component_couplings.n_cols() == fe.n_components(), - ExcDimensionMismatch(component_couplings.n_cols(), - fe.n_components())); - - const unsigned int n_dofs = fe.dofs_per_cell; - - Table<2,Coupling> dof_couplings (n_dofs, n_dofs); - - for (unsigned int i=0; i<n_dofs; ++i) - { - const unsigned int ii - = (fe.is_primitive(i) ? - fe.system_to_component_index(i).first - : - fe.get_nonzero_components(i).first_selected_component() - ); - Assert (ii < fe.n_components(), ExcInternalError()); - - for (unsigned int j=0; j<n_dofs; ++j) - { - const unsigned int jj - = (fe.is_primitive(j) ? - fe.system_to_component_index(j).first - : - fe.get_nonzero_components(j).first_selected_component() - ); - Assert (jj < fe.n_components(), ExcInternalError()); - - dof_couplings(i,j) = component_couplings(ii,jj); - } - } - return dof_couplings; - } - - - - template <int dim, int spacedim> - std::vector<Table<2,Coupling> > - dof_couplings_from_component_couplings - (const hp::FECollection<dim,spacedim> &fe, - const Table<2,Coupling> &component_couplings) - { - std::vector<Table<2,Coupling> > return_value (fe.size()); - for (unsigned int i=0; i<fe.size(); ++i) - return_value[i] - = dof_couplings_from_component_couplings(fe[i], component_couplings); - - return return_value; - } - - - - namespace internal - { - namespace - { - - // implementation of the same function in namespace DoFTools for - // non-hp DoFHandlers - template <class DH, class SparsityPattern> - void - make_flux_sparsity_pattern (const DH &dof, - SparsityPattern &sparsity, - const Table<2,Coupling> &int_mask, - const Table<2,Coupling> &flux_mask) - { - const FiniteElement<DH::dimension,DH::space_dimension> &fe = dof.get_fe(); - - std::vector<types::global_dof_index> dofs_on_this_cell(fe.dofs_per_cell); - std::vector<types::global_dof_index> dofs_on_other_cell(fe.dofs_per_cell); - - const Table<2,Coupling> - int_dof_mask = dof_couplings_from_component_couplings(fe, int_mask), - flux_dof_mask = dof_couplings_from_component_couplings(fe, flux_mask); - - Table<2,bool> support_on_face(fe.dofs_per_cell, - GeometryInfo<DH::dimension>::faces_per_cell); - for (unsigned int i=0; i<fe.dofs_per_cell; ++i) - for (unsigned int f=0; f<GeometryInfo<DH::dimension>::faces_per_cell; ++f) - support_on_face(i,f) = fe.has_support_on_face(i,f); - - typename DH::active_cell_iterator cell = dof.begin_active(), - endc = dof.end(); - for (; cell!=endc; ++cell) - if (cell->is_locally_owned()) - { - cell->get_dof_indices (dofs_on_this_cell); - // make sparsity pattern for this cell - for (unsigned int i=0; i<fe.dofs_per_cell; ++i) - for (unsigned int j=0; j<fe.dofs_per_cell; ++j) - if (int_dof_mask(i,j) != none) - sparsity.add (dofs_on_this_cell[i], - dofs_on_this_cell[j]); - - // Loop over all interior neighbors - for (unsigned int face = 0; - face < GeometryInfo<DH::dimension>::faces_per_cell; - ++face) - { - const typename DH::face_iterator - cell_face = cell->face(face); - if (cell_face->user_flag_set ()) - continue; - - if (cell->at_boundary (face) ) - { - for (unsigned int i=0; i<fe.dofs_per_cell; ++i) - { - const bool i_non_zero_i = support_on_face (i, face); - for (unsigned int j=0; j<fe.dofs_per_cell; ++j) - { - const bool j_non_zero_i = support_on_face (j, face); - - if ((flux_dof_mask(i,j) == always) - || - (flux_dof_mask(i,j) == nonzero - && - i_non_zero_i - && - j_non_zero_i)) - sparsity.add (dofs_on_this_cell[i], - dofs_on_this_cell[j]); - } - } - } - else - { - typename DH::level_cell_iterator - neighbor = cell->neighbor(face); - // Refinement edges are taken care of by coarser - // cells - if (cell->neighbor_is_coarser(face)) - continue; - - typename DH::face_iterator cell_face = cell->face(face); - const unsigned int - neighbor_face = cell->neighbor_of_neighbor(face); - - if (cell_face->has_children()) - { - for (unsigned int sub_nr = 0; - sub_nr != cell_face->n_children(); - ++sub_nr) - { - const typename DH::level_cell_iterator - sub_neighbor - = cell->neighbor_child_on_subface (face, sub_nr); - - sub_neighbor->get_dof_indices (dofs_on_other_cell); - for (unsigned int i=0; i<fe.dofs_per_cell; ++i) - { - const bool i_non_zero_i = support_on_face (i, face); - const bool i_non_zero_e = support_on_face (i, neighbor_face); - for (unsigned int j=0; j<fe.dofs_per_cell; ++j) - { - const bool j_non_zero_i = support_on_face (j, face); - const bool j_non_zero_e = support_on_face (j, neighbor_face); - - if (flux_dof_mask(i,j) == always) - { - sparsity.add (dofs_on_this_cell[i], - dofs_on_other_cell[j]); - sparsity.add (dofs_on_other_cell[i], - dofs_on_this_cell[j]); - sparsity.add (dofs_on_this_cell[i], - dofs_on_this_cell[j]); - sparsity.add (dofs_on_other_cell[i], - dofs_on_other_cell[j]); - } - else if (flux_dof_mask(i,j) == nonzero) - { - if (i_non_zero_i && j_non_zero_e) - sparsity.add (dofs_on_this_cell[i], - dofs_on_other_cell[j]); - if (i_non_zero_e && j_non_zero_i) - sparsity.add (dofs_on_other_cell[i], - dofs_on_this_cell[j]); - if (i_non_zero_i && j_non_zero_i) - sparsity.add (dofs_on_this_cell[i], - dofs_on_this_cell[j]); - if (i_non_zero_e && j_non_zero_e) - sparsity.add (dofs_on_other_cell[i], - dofs_on_other_cell[j]); - } - - if (flux_dof_mask(j,i) == always) - { - sparsity.add (dofs_on_this_cell[j], - dofs_on_other_cell[i]); - sparsity.add (dofs_on_other_cell[j], - dofs_on_this_cell[i]); - sparsity.add (dofs_on_this_cell[j], - dofs_on_this_cell[i]); - sparsity.add (dofs_on_other_cell[j], - dofs_on_other_cell[i]); - } - else if (flux_dof_mask(j,i) == nonzero) - { - if (j_non_zero_i && i_non_zero_e) - sparsity.add (dofs_on_this_cell[j], - dofs_on_other_cell[i]); - if (j_non_zero_e && i_non_zero_i) - sparsity.add (dofs_on_other_cell[j], - dofs_on_this_cell[i]); - if (j_non_zero_i && i_non_zero_i) - sparsity.add (dofs_on_this_cell[j], - dofs_on_this_cell[i]); - if (j_non_zero_e && i_non_zero_e) - sparsity.add (dofs_on_other_cell[j], - dofs_on_other_cell[i]); - } - } - } - sub_neighbor->face(neighbor_face)->set_user_flag (); - } - } - else - { - neighbor->get_dof_indices (dofs_on_other_cell); - for (unsigned int i=0; i<fe.dofs_per_cell; ++i) - { - const bool i_non_zero_i = support_on_face (i, face); - const bool i_non_zero_e = support_on_face (i, neighbor_face); - for (unsigned int j=0; j<fe.dofs_per_cell; ++j) - { - const bool j_non_zero_i = support_on_face (j, face); - const bool j_non_zero_e = support_on_face (j, neighbor_face); - if (flux_dof_mask(i,j) == always) - { - sparsity.add (dofs_on_this_cell[i], - dofs_on_other_cell[j]); - sparsity.add (dofs_on_other_cell[i], - dofs_on_this_cell[j]); - sparsity.add (dofs_on_this_cell[i], - dofs_on_this_cell[j]); - sparsity.add (dofs_on_other_cell[i], - dofs_on_other_cell[j]); - } - if (flux_dof_mask(i,j) == nonzero) - { - if (i_non_zero_i && j_non_zero_e) - sparsity.add (dofs_on_this_cell[i], - dofs_on_other_cell[j]); - if (i_non_zero_e && j_non_zero_i) - sparsity.add (dofs_on_other_cell[i], - dofs_on_this_cell[j]); - if (i_non_zero_i && j_non_zero_i) - sparsity.add (dofs_on_this_cell[i], - dofs_on_this_cell[j]); - if (i_non_zero_e && j_non_zero_e) - sparsity.add (dofs_on_other_cell[i], - dofs_on_other_cell[j]); - } - - if (flux_dof_mask(j,i) == always) - { - sparsity.add (dofs_on_this_cell[j], - dofs_on_other_cell[i]); - sparsity.add (dofs_on_other_cell[j], - dofs_on_this_cell[i]); - sparsity.add (dofs_on_this_cell[j], - dofs_on_this_cell[i]); - sparsity.add (dofs_on_other_cell[j], - dofs_on_other_cell[i]); - } - if (flux_dof_mask(j,i) == nonzero) - { - if (j_non_zero_i && i_non_zero_e) - sparsity.add (dofs_on_this_cell[j], - dofs_on_other_cell[i]); - if (j_non_zero_e && i_non_zero_i) - sparsity.add (dofs_on_other_cell[j], - dofs_on_this_cell[i]); - if (j_non_zero_i && i_non_zero_i) - sparsity.add (dofs_on_this_cell[j], - dofs_on_this_cell[i]); - if (j_non_zero_e && i_non_zero_e) - sparsity.add (dofs_on_other_cell[j], - dofs_on_other_cell[i]); - } - } - } - neighbor->face(neighbor_face)->set_user_flag (); - } - } - } - } - } - - - // implementation of the same function in namespace DoFTools for - // non-hp DoFHandlers - template <int dim, int spacedim, class SparsityPattern> - void - make_flux_sparsity_pattern (const dealii::hp::DoFHandler<dim,spacedim> &dof, - SparsityPattern &sparsity, - const Table<2,Coupling> &int_mask, - const Table<2,Coupling> &flux_mask) - { - // while the implementation above is quite optimized and caches a - // lot of data (see e.g. the int/flux_dof_mask tables), this is no - // longer practical for the hp version since we would have to have - // it for all combinations of elements in the hp::FECollection. - // consequently, the implementation here is simpler and probably - // less efficient but at least readable... - - const dealii::hp::FECollection<dim,spacedim> &fe = dof.get_fe(); - - std::vector<types::global_dof_index> dofs_on_this_cell(DoFTools::max_dofs_per_cell(dof)); - std::vector<types::global_dof_index> dofs_on_other_cell(DoFTools::max_dofs_per_cell(dof)); - - const std::vector<Table<2,Coupling> > - int_dof_mask - = dof_couplings_from_component_couplings(fe, int_mask); - - typename dealii::hp::DoFHandler<dim,spacedim>::active_cell_iterator - cell = dof.begin_active(), - endc = dof.end(); - for (; cell!=endc; ++cell) - { - dofs_on_this_cell.resize (cell->get_fe().dofs_per_cell); - cell->get_dof_indices (dofs_on_this_cell); - - // make sparsity pattern for this cell - for (unsigned int i=0; i<cell->get_fe().dofs_per_cell; ++i) - for (unsigned int j=0; j<cell->get_fe().dofs_per_cell; ++j) - if (int_dof_mask[cell->active_fe_index()](i,j) != none) - sparsity.add (dofs_on_this_cell[i], - dofs_on_this_cell[j]); - - // Loop over all interior neighbors - for (unsigned int face = 0; - face < GeometryInfo<dim>::faces_per_cell; - ++face) - { - const typename dealii::hp::DoFHandler<dim,spacedim>::face_iterator - cell_face = cell->face(face); - if (cell_face->user_flag_set ()) - continue; - - if (cell->at_boundary (face) ) - { - for (unsigned int i=0; i<cell->get_fe().dofs_per_cell; ++i) - for (unsigned int j=0; j<cell->get_fe().dofs_per_cell; ++j) - if ((flux_mask(cell->get_fe().system_to_component_index(i).first, - cell->get_fe().system_to_component_index(j).first) - == always) - || - (flux_mask(cell->get_fe().system_to_component_index(i).first, - cell->get_fe().system_to_component_index(j).first) - == nonzero)) - sparsity.add (dofs_on_this_cell[i], - dofs_on_this_cell[j]); - } - else - { - typename dealii::hp::DoFHandler<dim,spacedim>::level_cell_iterator - neighbor = cell->neighbor(face); - - // Refinement edges are taken care of by coarser cells - if (cell->neighbor_is_coarser(face)) - continue; - - typename dealii::hp::DoFHandler<dim,spacedim>::face_iterator - cell_face = cell->face(face); - const unsigned int - neighbor_face = cell->neighbor_of_neighbor(face); - - if (cell_face->has_children()) - { - for (unsigned int sub_nr = 0; - sub_nr != cell_face->n_children(); - ++sub_nr) - { - const typename dealii::hp::DoFHandler<dim,spacedim>::level_cell_iterator - sub_neighbor - = cell->neighbor_child_on_subface (face, sub_nr); - - dofs_on_other_cell.resize (sub_neighbor->get_fe().dofs_per_cell); - sub_neighbor->get_dof_indices (dofs_on_other_cell); - for (unsigned int i=0; i<cell->get_fe().dofs_per_cell; ++i) - { - for (unsigned int j=0; j<sub_neighbor->get_fe().dofs_per_cell; - ++j) - { - if ((flux_mask(cell->get_fe().system_to_component_index(i).first, - sub_neighbor->get_fe().system_to_component_index(j).first) - == always) - || - (flux_mask(cell->get_fe().system_to_component_index(i).first, - sub_neighbor->get_fe().system_to_component_index(j).first) - == nonzero)) - { - sparsity.add (dofs_on_this_cell[i], - dofs_on_other_cell[j]); - sparsity.add (dofs_on_other_cell[i], - dofs_on_this_cell[j]); - sparsity.add (dofs_on_this_cell[i], - dofs_on_this_cell[j]); - sparsity.add (dofs_on_other_cell[i], - dofs_on_other_cell[j]); - } - - if ((flux_mask(sub_neighbor->get_fe().system_to_component_index(j).first, - cell->get_fe().system_to_component_index(i).first) - == always) - || - (flux_mask(sub_neighbor->get_fe().system_to_component_index(j).first, - cell->get_fe().system_to_component_index(i).first) - == nonzero)) - { - sparsity.add (dofs_on_this_cell[j], - dofs_on_other_cell[i]); - sparsity.add (dofs_on_other_cell[j], - dofs_on_this_cell[i]); - sparsity.add (dofs_on_this_cell[j], - dofs_on_this_cell[i]); - sparsity.add (dofs_on_other_cell[j], - dofs_on_other_cell[i]); - } - } - } - sub_neighbor->face(neighbor_face)->set_user_flag (); - } - } - else - { - dofs_on_other_cell.resize (neighbor->get_fe().dofs_per_cell); - neighbor->get_dof_indices (dofs_on_other_cell); - for (unsigned int i=0; i<cell->get_fe().dofs_per_cell; ++i) - { - for (unsigned int j=0; j<neighbor->get_fe().dofs_per_cell; ++j) - { - if ((flux_mask(cell->get_fe().system_to_component_index(i).first, - neighbor->get_fe().system_to_component_index(j).first) - == always) - || - (flux_mask(cell->get_fe().system_to_component_index(i).first, - neighbor->get_fe().system_to_component_index(j).first) - == nonzero)) - { - sparsity.add (dofs_on_this_cell[i], - dofs_on_other_cell[j]); - sparsity.add (dofs_on_other_cell[i], - dofs_on_this_cell[j]); - sparsity.add (dofs_on_this_cell[i], - dofs_on_this_cell[j]); - sparsity.add (dofs_on_other_cell[i], - dofs_on_other_cell[j]); - } - - if ((flux_mask(neighbor->get_fe().system_to_component_index(j).first, - cell->get_fe().system_to_component_index(i).first) - == always) - || - (flux_mask(neighbor->get_fe().system_to_component_index(j).first, - cell->get_fe().system_to_component_index(i).first) - == nonzero)) - { - sparsity.add (dofs_on_this_cell[j], - dofs_on_other_cell[i]); - sparsity.add (dofs_on_other_cell[j], - dofs_on_this_cell[i]); - sparsity.add (dofs_on_this_cell[j], - dofs_on_this_cell[i]); - sparsity.add (dofs_on_other_cell[j], - dofs_on_other_cell[i]); - } - } - } - neighbor->face(neighbor_face)->set_user_flag (); - } - } - } - } - } - } - - } - - - - - template <class DH, class SparsityPattern> - void - make_flux_sparsity_pattern (const DH &dof, - SparsityPattern &sparsity, - const Table<2,Coupling> &int_mask, - const Table<2,Coupling> &flux_mask) - { - // do the error checking and frame code here, and then pass on to more - // specialized functions in the internal namespace - const types::global_dof_index n_dofs = dof.n_dofs(); - const unsigned int n_comp = dof.get_fe().n_components(); - - Assert (sparsity.n_rows() == n_dofs, - ExcDimensionMismatch (sparsity.n_rows(), n_dofs)); - Assert (sparsity.n_cols() == n_dofs, - ExcDimensionMismatch (sparsity.n_cols(), n_dofs)); - Assert (int_mask.n_rows() == n_comp, - ExcDimensionMismatch (int_mask.n_rows(), n_comp)); - Assert (int_mask.n_cols() == n_comp, - ExcDimensionMismatch (int_mask.n_cols(), n_comp)); - Assert (flux_mask.n_rows() == n_comp, - ExcDimensionMismatch (flux_mask.n_rows(), n_comp)); - Assert (flux_mask.n_cols() == n_comp, - ExcDimensionMismatch (flux_mask.n_cols(), n_comp)); - - // Clear user flags because we will need them. But first we save them - // and make sure that we restore them later such that at the end of - // this function the Triangulation will be in the same state as it was - // at the beginning of this function. - std::vector<bool> user_flags; - dof.get_tria().save_user_flags(user_flags); - const_cast<Triangulation<DH::dimension,DH::space_dimension> &>(dof.get_tria()).clear_user_flags (); - - internal::make_flux_sparsity_pattern (dof, sparsity, - int_mask, flux_mask); - - // finally restore the user flags - const_cast<Triangulation<DH::dimension,DH::space_dimension> &>(dof.get_tria()).load_user_flags(user_flags); - } - - - - - namespace internal - { - namespace - { - inline bool - check_master_dof_list (const FullMatrix<double> &face_interpolation_matrix, - const std::vector<types::global_dof_index> &master_dof_list) - { - const unsigned int N = master_dof_list.size(); - - FullMatrix<double> tmp (N,N); - for (unsigned int i=0; i<N; ++i) - for (unsigned int j=0; j<N; ++j) - tmp(i,j) = face_interpolation_matrix (master_dof_list[i], j); - - // then use the algorithm from FullMatrix::gauss_jordan on this - // matrix to find out whether it is singular. the algorithm there - // does piviting and at the end swaps rows back into their proper - // order -- we omit this step here, since we don't care about the - // inverse matrix, all we care about is whether the matrix is - // regular or singular - - // first get an estimate of the size of the elements of this - // matrix, for later checks whether the pivot element is large - // enough, or whether we have to fear that the matrix is not - // regular - double diagonal_sum = 0; - for (unsigned int i=0; i<N; ++i) - diagonal_sum += std::fabs(tmp(i,i)); - const double typical_diagonal_element = diagonal_sum/N; - - // initialize the array that holds the permutations that we find - // during pivot search - std::vector<unsigned int> p(N); - for (unsigned int i=0; i<N; ++i) - p[i] = i; - - for (unsigned int j=0; j<N; ++j) - { - // pivot search: search that part of the line on and right of - // the diagonal for the largest element - double max = std::fabs(tmp(j,j)); - unsigned int r = j; - for (unsigned int i=j+1; i<N; ++i) - { - if (std::fabs(tmp(i,j)) > max) - { - max = std::fabs(tmp(i,j)); - r = i; - } - } - // check whether the pivot is too small. if that is the case, - // then the matrix is singular and we shouldn't use this set of - // master dofs - if (max < 1.e-12*typical_diagonal_element) - return false; - - // row interchange - if (r>j) - { - for (unsigned int k=0; k<N; ++k) - std::swap (tmp(j,k), tmp(r,k)); - - std::swap (p[j], p[r]); - } - - // transformation - const double hr = 1./tmp(j,j); - tmp(j,j) = hr; - for (unsigned int k=0; k<N; ++k) - { - if (k==j) continue; - for (unsigned int i=0; i<N; ++i) - { - if (i==j) continue; - tmp(i,k) -= tmp(i,j)*tmp(j,k)*hr; - } - } - for (unsigned int i=0; i<N; ++i) - { - tmp(i,j) *= hr; - tmp(j,i) *= -hr; - } - tmp(j,j) = hr; - } - - // everything went fine, so we can accept this set of master dofs - // (at least as far as they have already been collected) - return true; - } - - - - /** - * When restricting, on a face, the degrees of freedom of fe1 to the - * space described by fe2 (for example for the complex case described - * in the @ref hp_paper "hp paper"), we have to select - * fe2.dofs_per_face out of the fe1.dofs_per_face face DoFs as the - * master DoFs, and the rest become slave dofs. This function selects - * which ones will be masters, and which ones will be slaves. - * - * The function assumes that master_dofs already has size - * fe1.dofs_per_face. After the function, exactly fe2.dofs_per_face - * entries will be true. - * - * The function is a bit complicated since it has to figure out a set - * a DoFs so that the corresponding rows in the face interpolation - * matrix are all linearly independent. we have a good heuristic (see - * the function body) for selecting these rows, but there are cases - * where this fails and we have to pick them differently. what we do - * is to run the heuristic and then go back to determine whether we - * have a set of rows with full row rank. if this isn't the case, go - * back and select dofs differently - */ - template <int dim, int spacedim> - void - select_master_dofs_for_face_restriction (const FiniteElement<dim,spacedim> &fe1, - const FiniteElement<dim,spacedim> &fe2, - const FullMatrix<double> &face_interpolation_matrix, - std::vector<bool> &master_dof_mask) - { - Assert (fe1.dofs_per_face >= fe2.dofs_per_face, - ExcInternalError()); - AssertDimension (master_dof_mask.size(), fe1.dofs_per_face); - - Assert (fe2.dofs_per_vertex <= fe1.dofs_per_vertex, - ExcInternalError()); - Assert (fe2.dofs_per_line <= fe1.dofs_per_line, - ExcInternalError()); - Assert ((dim < 3) - || - (fe2.dofs_per_quad <= fe1.dofs_per_quad), - ExcInternalError()); - - // the idea here is to designate as many DoFs in fe1 per object - // (vertex, line, quad) as master as there are such dofs in fe2 - // (indices are int, because we want to avoid the 'unsigned int < 0 - // is always false warning for the cases at the bottom in 1d and - // 2d) - // - // as mentioned in the paper, it is not always easy to find a set - // of master dofs that produces an invertible matrix. to this end, - // we check in each step whether the matrix is still invertible and - // simply discard this dof if the matrix is not invertible anymore. - // - // the cases where we did have trouble in the past were with adding - // more quad dofs when Q3 and Q4 elements meet at a refined face in - // 3d (see the hp/crash_12 test that tests that we can do exactly - // this, and failed before we had code to compensate for this - // case). the other case are system elements: if we have say a Q1Q2 - // vs a Q2Q3 element, then we can't just take all master dofs on a - // line from a single base element, since the shape functions of - // that base element are independent of that of the other one. this - // latter case shows up when running hp/hp_constraints_q_system_06 - - std::vector<types::global_dof_index> master_dof_list; - unsigned int index = 0; - for (int v=0; - v<static_cast<signed int>(GeometryInfo<dim>::vertices_per_face); - ++v) - { - unsigned int dofs_added = 0; - unsigned int i = 0; - while (dofs_added < fe2.dofs_per_vertex) - { - // make sure that we were able to find a set of master dofs - // and that the code down below didn't just reject all our - // efforts - Assert (i < fe1.dofs_per_vertex, - ExcInternalError()); - - // tentatively push this vertex dof - master_dof_list.push_back (index+i); - - // then see what happens. if it succeeds, fine - if (check_master_dof_list (face_interpolation_matrix, - master_dof_list) - == true) - ++dofs_added; - else - // well, it didn't. simply pop that dof from the list - // again and try with the next dof - master_dof_list.pop_back (); - - // forward counter by one - ++i; - } - index += fe1.dofs_per_vertex; - } - - for (int l=0; - l<static_cast<signed int>(GeometryInfo<dim>::lines_per_face); - ++l) - { - // same algorithm as above - unsigned int dofs_added = 0; - unsigned int i = 0; - while (dofs_added < fe2.dofs_per_line) - { - Assert (i < fe1.dofs_per_line, - ExcInternalError()); - - master_dof_list.push_back (index+i); - if (check_master_dof_list (face_interpolation_matrix, - master_dof_list) - == true) - ++dofs_added; - else - master_dof_list.pop_back (); - - ++i; - } - index += fe1.dofs_per_line; - } - - for (int q=0; - q<static_cast<signed int>(GeometryInfo<dim>::quads_per_face); - ++q) - { - // same algorithm as above - unsigned int dofs_added = 0; - unsigned int i = 0; - while (dofs_added < fe2.dofs_per_quad) - { - Assert (i < fe1.dofs_per_quad, - ExcInternalError()); - - master_dof_list.push_back (index+i); - if (check_master_dof_list (face_interpolation_matrix, - master_dof_list) - == true) - ++dofs_added; - else - master_dof_list.pop_back (); - - ++i; - } - index += fe1.dofs_per_quad; - } - - AssertDimension (index, fe1.dofs_per_face); - AssertDimension (master_dof_list.size(), fe2.dofs_per_face); - - // finally copy the list into the mask - std::fill (master_dof_mask.begin(), master_dof_mask.end(), false); - for (std::vector<types::global_dof_index>::const_iterator i=master_dof_list.begin(); - i!=master_dof_list.end(); ++i) - master_dof_mask[*i] = true; - } - - - - /** - * Make sure that the mask exists that determines which dofs will be - * the masters on refined faces where an fe1 and a fe2 meet. - */ - template <int dim, int spacedim> - void - ensure_existence_of_master_dof_mask (const FiniteElement<dim,spacedim> &fe1, - const FiniteElement<dim,spacedim> &fe2, - const FullMatrix<double> &face_interpolation_matrix, - std_cxx1x::shared_ptr<std::vector<bool> > &master_dof_mask) - { - if (master_dof_mask == std_cxx1x::shared_ptr<std::vector<bool> >()) - { - master_dof_mask = std_cxx1x::shared_ptr<std::vector<bool> > - (new std::vector<bool> (fe1.dofs_per_face)); - select_master_dofs_for_face_restriction (fe1, - fe2, - face_interpolation_matrix, - *master_dof_mask); - } - } - - - - /** - * Make sure that the given @p face_interpolation_matrix pointer - * points to a valid matrix. If the pointer is zero beforehand, - * create an entry with the correct data. If it is nonzero, don't - * touch it. - */ - template <int dim, int spacedim> - void - ensure_existence_of_face_matrix (const FiniteElement<dim,spacedim> &fe1, - const FiniteElement<dim,spacedim> &fe2, - std_cxx1x::shared_ptr<FullMatrix<double> > &matrix) - { - if (matrix == std_cxx1x::shared_ptr<FullMatrix<double> >()) - { - matrix = std_cxx1x::shared_ptr<FullMatrix<double> > - (new FullMatrix<double> (fe2.dofs_per_face, - fe1.dofs_per_face)); - fe1.get_face_interpolation_matrix (fe2, - *matrix); - } - } - - - - /** - * Same, but for subface interpolation matrices. - */ - template <int dim, int spacedim> - void - ensure_existence_of_subface_matrix (const FiniteElement<dim,spacedim> &fe1, - const FiniteElement<dim,spacedim> &fe2, - const unsigned int subface, - std_cxx1x::shared_ptr<FullMatrix<double> > &matrix) - { - if (matrix == std_cxx1x::shared_ptr<FullMatrix<double> >()) - { - matrix = std_cxx1x::shared_ptr<FullMatrix<double> > - (new FullMatrix<double> (fe2.dofs_per_face, - fe1.dofs_per_face)); - fe1.get_subface_interpolation_matrix (fe2, - subface, - *matrix); - } - } - - - - /** - * Given the face interpolation matrix between two elements, split it - * into its master and slave parts and invert the master part as - * explained in the @ref hp_paper "hp paper". - */ - void - ensure_existence_of_split_face_matrix (const FullMatrix<double> &face_interpolation_matrix, - const std::vector<bool> &master_dof_mask, - std_cxx1x::shared_ptr<std::pair<FullMatrix<double>,FullMatrix<double> > > &split_matrix) - { - AssertDimension (master_dof_mask.size(), face_interpolation_matrix.m()); - Assert (std::count (master_dof_mask.begin(), master_dof_mask.end(), true) == - static_cast<signed int>(face_interpolation_matrix.n()), - ExcInternalError()); - - if (split_matrix == - std_cxx1x::shared_ptr<std::pair<FullMatrix<double>,FullMatrix<double> > >()) - { - split_matrix - = std_cxx1x::shared_ptr<std::pair<FullMatrix<double>,FullMatrix<double> > > - (new std::pair<FullMatrix<double>,FullMatrix<double> >()); - - const unsigned int n_master_dofs = face_interpolation_matrix.n(); - const unsigned int n_dofs = face_interpolation_matrix.m(); - - Assert (n_master_dofs <= n_dofs, ExcInternalError()); - - // copy and invert the master - // component, copy the slave - // component - split_matrix->first.reinit (n_master_dofs, n_master_dofs); - split_matrix->second.reinit (n_dofs-n_master_dofs, n_master_dofs); - - unsigned int nth_master_dof = 0, - nth_slave_dof = 0; - - for (unsigned int i=0; i<n_dofs; ++i) - if (master_dof_mask[i] == true) - { - for (unsigned int j=0; j<n_master_dofs; ++j) - split_matrix->first(nth_master_dof,j) - = face_interpolation_matrix(i,j); - ++nth_master_dof; - } - else - { - for (unsigned int j=0; j<n_master_dofs; ++j) - split_matrix->second(nth_slave_dof,j) - = face_interpolation_matrix(i,j); - ++nth_slave_dof; - } - - AssertDimension (nth_master_dof, n_master_dofs); - AssertDimension (nth_slave_dof, n_dofs-n_master_dofs); - - //TODO[WB]: We should make sure very small entries are removed after inversion - split_matrix->first.gauss_jordan (); - } - } - - - // a template that can determine statically whether a given - // DoFHandler class supports different finite element elements - template <typename> - struct DoFHandlerSupportsDifferentFEs - { - static const bool value = true; - }; - - - template <int dim, int spacedim> - struct DoFHandlerSupportsDifferentFEs< dealii::DoFHandler<dim,spacedim> > - { - static const bool value = false; - }; - - - template <int dim, int spacedim> - struct DoFHandlerSupportsDifferentFEs< dealii::MGDoFHandler<dim,spacedim> > - { - static const bool value = false; - }; - - - /** - * A function that returns how many different finite elements a dof - * handler uses. This is one for non-hp DoFHandlers and - * dof_handler.get_fe().size() for the hp-versions. - */ - template <int dim, int spacedim> - unsigned int - n_finite_elements (const dealii::hp::DoFHandler<dim,spacedim> &dof_handler) - { - return dof_handler.get_fe().size(); - } - - - template <class DH> - unsigned int - n_finite_elements (const DH &) - { - return 1; - } - - - /** - * For a given face belonging to an active cell that borders to a - * more refined cell, return the fe_index of the most dominating - * finite element used on any of the face's subfaces. - */ - template <typename face_iterator> - unsigned int - get_most_dominating_subface_fe_index (const face_iterator &face) - { - const unsigned int dim - = face_iterator::AccessorType::dimension; - const unsigned int spacedim - = face_iterator::AccessorType::space_dimension; - - unsigned int dominating_subface_no = 0; - for (; dominating_subface_no<face->n_children(); - ++dominating_subface_no) - { - // each of the subfaces can have only a single fe_index - // associated with them, since there is no cell on the other - // side - Assert (face->child(dominating_subface_no) - ->n_active_fe_indices() - == 1, - ExcInternalError()); - - const FiniteElement<dim,spacedim> & - this_subface_fe = (face->child(dominating_subface_no) - ->get_fe (face->child(dominating_subface_no) - ->nth_active_fe_index(0))); - - FiniteElementDomination::Domination - domination = FiniteElementDomination::either_element_can_dominate; - for (unsigned int sf=0; sf<face->n_children(); ++sf) - if (sf != dominating_subface_no) - { - const FiniteElement<dim,spacedim> & - that_subface_fe = (face->child(sf) - ->get_fe (face->child(sf) - ->nth_active_fe_index(0))); - - domination = domination & - this_subface_fe.compare_for_face_domination(that_subface_fe); - } - - // see if the element on this subface is able to dominate the - // ones on all other subfaces, and if so take it - if ((domination == FiniteElementDomination::this_element_dominates) - || - (domination == FiniteElementDomination::either_element_can_dominate)) - break; - } - - // check that we have found one such subface - Assert (dominating_subface_no < face->n_children(), - ExcNotImplemented()); - - // return the finite element index used on it. note that only a - // single fe can be active on such subfaces - return face->child (dominating_subface_no)->nth_active_fe_index(0); - } - - - - /** - * Copy constraints into a constraint matrix object. - * - * This function removes zero constraints and those, which constrain - * a DoF which was already eliminated in one of the previous steps of - * the hp hanging node procedure. - * - * It also suppresses very small entries in the constraint matrix to - * avoid making the sparsity pattern fuller than necessary. - */ - void - filter_constraints (const std::vector<types::global_dof_index> &master_dofs, - const std::vector<types::global_dof_index> &slave_dofs, - const FullMatrix<double> &face_constraints, - ConstraintMatrix &constraints) - { - Assert (face_constraints.n () == master_dofs.size (), - ExcDimensionMismatch(master_dofs.size (), - face_constraints.n())); - Assert (face_constraints.m () == slave_dofs.size (), - ExcDimensionMismatch(slave_dofs.size (), - face_constraints.m())); - - const unsigned int n_master_dofs = master_dofs.size (); - const unsigned int n_slave_dofs = slave_dofs.size (); - - // check for a couple conditions that happened in parallel - // distributed mode - for (unsigned int row=0; row!=n_slave_dofs; ++row) - Assert (slave_dofs[row] != numbers::invalid_dof_index, - ExcInternalError()); - for (unsigned int col=0; col!=n_master_dofs; ++col) - Assert (master_dofs[col] != numbers::invalid_dof_index, - ExcInternalError()); - - - for (unsigned int row=0; row!=n_slave_dofs; ++row) - if (constraints.is_constrained (slave_dofs[row]) == false) - { - bool constraint_already_satisfied = false; - - // Check if we have an identity constraint, which is already - // satisfied by unification of the corresponding global dof - // indices - for (unsigned int i=0; i<n_master_dofs; ++i) - if (face_constraints (row,i) == 1.0) - if (master_dofs[i] == slave_dofs[row]) - { - constraint_already_satisfied = true; - break; - } - - if (constraint_already_satisfied == false) - { - // add up the absolute values of all constraints in this - // line to get a measure of their absolute size - double abs_sum = 0; - for (unsigned int i=0; i<n_master_dofs; ++i) - abs_sum += std::abs (face_constraints(row,i)); - - // then enter those constraints that are larger than - // 1e-14*abs_sum. everything else probably originated - // from inexact inversion of matrices and similar - // effects. having those constraints in here will only - // lead to problems because it makes sparsity patterns - // fuller than necessary without producing any - // significant effect - constraints.add_line (slave_dofs[row]); - for (unsigned int i=0; i<n_master_dofs; ++i) - if ((face_constraints(row,i) != 0) - && - (std::fabs(face_constraints(row,i)) >= 1e-14*abs_sum)) - constraints.add_entry (slave_dofs[row], - master_dofs[i], - face_constraints (row,i)); - constraints.set_inhomogeneity (slave_dofs[row], 0.); - } - } - } - - } - - - - void - make_hp_hanging_node_constraints (const dealii::DoFHandler<1> &, - ConstraintMatrix &) - { - // nothing to do for regular dof handlers in 1d - } - - - - void - make_oldstyle_hanging_node_constraints (const dealii::DoFHandler<1> &, - ConstraintMatrix &, - dealii::internal::int2type<1>) - { - // nothing to do for regular dof handlers in 1d - } - - - void - make_hp_hanging_node_constraints (const dealii::MGDoFHandler<1> &, - ConstraintMatrix &) - { - // nothing to do for regular dof handlers in 1d - } - - - - void - make_oldstyle_hanging_node_constraints (const dealii::MGDoFHandler<1> &, - ConstraintMatrix &, - dealii::internal::int2type<1>) - { - // nothing to do for regular dof handlers in 1d - } - - - void - make_hp_hanging_node_constraints (const dealii::hp::DoFHandler<1> &/*dof_handler*/, - ConstraintMatrix &/*constraints*/) - { - // we may have to compute constraints for vertices. gotta think about - // that a bit more - - //TODO[WB]: think about what to do here... - } - - - - void - make_oldstyle_hanging_node_constraints (const dealii::hp::DoFHandler<1> &/*dof_handler*/, - ConstraintMatrix &/*constraints*/, - dealii::internal::int2type<1>) - { - // we may have to compute constraints for vertices. gotta think about - // that a bit more - - //TODO[WB]: think about what to do here... - } - - - void - make_hp_hanging_node_constraints (const dealii::DoFHandler<1,2> &, - ConstraintMatrix &) - { - // nothing to do for regular dof handlers in 1d - } - - - - void - make_oldstyle_hanging_node_constraints (const dealii::DoFHandler<1,2> &, - ConstraintMatrix &, - dealii::internal::int2type<1>) - { - // nothing to do for regular dof handlers in 1d - } - - - void - make_hp_hanging_node_constraints (const dealii::DoFHandler<1,3> &, - ConstraintMatrix &) - { - // nothing to do for regular dof handlers in 1d - } - - void - make_oldstyle_hanging_node_constraints (const dealii::DoFHandler<1,3> &, - ConstraintMatrix &, - dealii::internal::int2type<1>) - { - // nothing to do for regular dof handlers in 1d - } - - -// currently not used but may be in the future: - -// void -// make_hp_hanging_node_constraints (const dealii::MDoFHandler<1,2> &, -// ConstraintMatrix &) -// { -// // nothing to do for regular -// // dof handlers in 1d -// } - - - -// void -// make_oldstyle_hanging_node_constraints (const dealii::DoFHandler<1,2> &, -// ConstraintMatrix &, -// dealii::internal::int2type<1>) -// { -// // nothing to do for regular -// // dof handlers in 1d -// } - - -// void -// make_oldstyle_hanging_node_constraints (const dealii::hp::DoFHandler<1,2> &/*dof_handler*/, -// ConstraintMatrix &/*constraints*/, -// dealii::internal::int2type<1>) -// { -// // we may have to compute -// // constraints for -// // vertices. gotta think about -// // that a bit more -// -// //TODO[WB]: think about what to do here... -// } -//#endif - - - - template <class DH> - void - make_oldstyle_hanging_node_constraints (const DH &dof_handler, - ConstraintMatrix &constraints, - dealii::internal::int2type<2>) - { - const unsigned int dim = 2; - - const unsigned int spacedim = DH::space_dimension; - - std::vector<types::global_dof_index> dofs_on_mother; - std::vector<types::global_dof_index> dofs_on_children; - - // loop over all lines; only on lines there can be constraints. We do - // so by looping over all active cells and checking whether any of - // the faces are refined which can only be from the neighboring cell - // because this one is active. In that case, the face is subject to - // constraints - // - // note that even though we may visit a face twice if the neighboring - // cells are equally refined, we can only visit each face with - // hanging nodes once - typename DH::active_cell_iterator cell = dof_handler.begin_active(), - endc = dof_handler.end(); - for (; cell!=endc; ++cell) - // artificial cells can at best neighbor ghost cells, but we're not - // interested in these interfaces - if (!cell->is_artificial ()) - for (unsigned int face=0; face<GeometryInfo<dim>::faces_per_cell; ++face) - if (cell->face(face)->has_children()) - { - // in any case, faces can have at most two active fe - // indices, but here the face can have only one (namely the - // same as that from the cell we're sitting on), and each - // of the children can have only one as well. check this - Assert (cell->face(face)->n_active_fe_indices() == 1, - ExcInternalError()); - Assert (cell->face(face)->fe_index_is_active(cell->active_fe_index()) - == true, - ExcInternalError()); - for (unsigned int c=0; c<cell->face(face)->n_children(); ++c) - if (!cell->neighbor_child_on_subface(face,c)->is_artificial()) - Assert (cell->face(face)->child(c)->n_active_fe_indices() == 1, - ExcInternalError()); - - // right now, all that is implemented is the case that both - // sides use the same fe - for (unsigned int c=0; c<cell->face(face)->n_children(); ++c) - if (!cell->neighbor_child_on_subface(face,c)->is_artificial()) - Assert (cell->face(face)->child(c) - ->fe_index_is_active(cell->active_fe_index()) == true, - ExcNotImplemented()); - - // ok, start up the work - const FiniteElement<dim,spacedim> &fe = cell->get_fe(); - const unsigned int fe_index = cell->active_fe_index(); - - const unsigned int - n_dofs_on_mother = 2*fe.dofs_per_vertex + fe.dofs_per_line, - n_dofs_on_children = fe.dofs_per_vertex + 2*fe.dofs_per_line; - - dofs_on_mother.resize (n_dofs_on_mother); - dofs_on_children.resize (n_dofs_on_children); - - Assert(n_dofs_on_mother == fe.constraints().n(), - ExcDimensionMismatch(n_dofs_on_mother, - fe.constraints().n())); - Assert(n_dofs_on_children == fe.constraints().m(), - ExcDimensionMismatch(n_dofs_on_children, - fe.constraints().m())); - - const typename DH::line_iterator this_face = cell->face(face); - - // fill the dofs indices. Use same enumeration scheme as in - // @p{FiniteElement::constraints()} - unsigned int next_index = 0; - for (unsigned int vertex=0; vertex<2; ++vertex) - for (unsigned int dof=0; dof!=fe.dofs_per_vertex; ++dof) - dofs_on_mother[next_index++] = this_face->vertex_dof_index(vertex,dof, - fe_index); - for (unsigned int dof=0; dof!=fe.dofs_per_line; ++dof) - dofs_on_mother[next_index++] = this_face->dof_index(dof, fe_index); - AssertDimension (next_index, dofs_on_mother.size()); - - next_index = 0; - for (unsigned int dof=0; dof!=fe.dofs_per_vertex; ++dof) - dofs_on_children[next_index++] - = this_face->child(0)->vertex_dof_index(1,dof,fe_index); - for (unsigned int child=0; child<2; ++child) - for (unsigned int dof=0; dof!=fe.dofs_per_line; ++dof) - dofs_on_children[next_index++] - = this_face->child(child)->dof_index(dof, fe_index); - AssertDimension (next_index, dofs_on_children.size()); - - // for each row in the constraint matrix for this line: - for (unsigned int row=0; row!=dofs_on_children.size(); ++row) - { - constraints.add_line (dofs_on_children[row]); - for (unsigned int i=0; i!=dofs_on_mother.size(); ++i) - constraints.add_entry (dofs_on_children[row], - dofs_on_mother[i], - fe.constraints()(row,i)); - - constraints.set_inhomogeneity (dofs_on_children[row], 0.); - } - } - else - { - // this face has no children, but it could still be that it - // is shared by two cells that use a different fe index. - // check a couple of things, but ignore the case that the - // neighbor is an artificial cell - if (!cell->at_boundary(face) && - !cell->neighbor(face)->is_artificial()) - { - Assert (cell->face(face)->n_active_fe_indices() == 1, - ExcNotImplemented()); - Assert (cell->face(face) - ->fe_index_is_active(cell->active_fe_index()) == true, - ExcInternalError()); - } - } - } - - - - template <class DH> - void - make_oldstyle_hanging_node_constraints (const DH &dof_handler, - ConstraintMatrix &constraints, - dealii::internal::int2type<3>) - { - const unsigned int dim = 3; - - std::vector<types::global_dof_index> dofs_on_mother; - std::vector<types::global_dof_index> dofs_on_children; - - // loop over all quads; only on quads there can be constraints. We do - // so by looping over all active cells and checking whether any of - // the faces are refined which can only be from the neighboring cell - // because this one is active. In that case, the face is subject to - // constraints - // - // note that even though we may visit a face twice if the neighboring - // cells are equally refined, we can only visit each face with - // hanging nodes once - typename DH::active_cell_iterator cell = dof_handler.begin_active(), - endc = dof_handler.end(); - for (; cell!=endc; ++cell) - // artificial cells can at best neighbor ghost cells, but we're not - // interested in these interfaces - if (!cell->is_artificial ()) - for (unsigned int face=0; face<GeometryInfo<dim>::faces_per_cell; ++face) - if (cell->face(face)->has_children()) - { - // first of all, make sure that we treat a case which is - // possible, i.e. either no dofs on the face at all or no - // anisotropic refinement - if (cell->get_fe().dofs_per_face == 0) - continue; - - Assert(cell->face(face)->refinement_case()==RefinementCase<dim-1>::isotropic_refinement, - ExcNotImplemented()); - - // in any case, faces can have at most two active fe - // indices, but here the face can have only one (namely the - // same as that from the cell we're sitting on), and each - // of the children can have only one as well. check this - AssertDimension (cell->face(face)->n_active_fe_indices(), 1); - Assert (cell->face(face)->fe_index_is_active(cell->active_fe_index()) - == true, - ExcInternalError()); - for (unsigned int c=0; c<cell->face(face)->n_children(); ++c) - AssertDimension (cell->face(face)->child(c)->n_active_fe_indices(), 1); - - // right now, all that is implemented is the case that both - // sides use the same fe, and not only that but also that - // all lines bounding this face and the children have the - // same fe - for (unsigned int c=0; c<cell->face(face)->n_children(); ++c) - if (!cell->neighbor_child_on_subface(face,c)->is_artificial()) - { - Assert (cell->face(face)->child(c) - ->fe_index_is_active(cell->active_fe_index()) == true, - ExcNotImplemented()); - for (unsigned int e=0; e<4; ++e) - { - Assert (cell->face(face)->child(c)->line(e) - ->n_active_fe_indices() == 1, - ExcNotImplemented()); - Assert (cell->face(face)->child(c)->line(e) - ->fe_index_is_active(cell->active_fe_index()) == true, - ExcNotImplemented()); - } - } - for (unsigned int e=0; e<4; ++e) - { - Assert (cell->face(face)->line(e) - ->n_active_fe_indices() == 1, - ExcNotImplemented()); - Assert (cell->face(face)->line(e) - ->fe_index_is_active(cell->active_fe_index()) == true, - ExcNotImplemented()); - } - - // ok, start up the work - const FiniteElement<dim> &fe = cell->get_fe(); - const unsigned int fe_index = cell->active_fe_index(); - - const unsigned int n_dofs_on_mother = fe.dofs_per_face; - const unsigned int n_dofs_on_children = (5*fe.dofs_per_vertex+ - 12*fe.dofs_per_line+ - 4*fe.dofs_per_quad); - - //TODO[TL]: think about this and the following in case of anisotropic refinement - - dofs_on_mother.resize (n_dofs_on_mother); - dofs_on_children.resize (n_dofs_on_children); - - Assert(n_dofs_on_mother == fe.constraints().n(), - ExcDimensionMismatch(n_dofs_on_mother, - fe.constraints().n())); - Assert(n_dofs_on_children == fe.constraints().m(), - ExcDimensionMismatch(n_dofs_on_children, - fe.constraints().m())); - - const typename DH::face_iterator this_face = cell->face(face); - - // fill the dofs indices. Use same enumeration scheme as in - // @p{FiniteElement::constraints()} - unsigned int next_index = 0; - for (unsigned int vertex=0; vertex<4; ++vertex) - for (unsigned int dof=0; dof!=fe.dofs_per_vertex; ++dof) - dofs_on_mother[next_index++] = this_face->vertex_dof_index(vertex,dof, - fe_index); - for (unsigned int line=0; line<4; ++line) - for (unsigned int dof=0; dof!=fe.dofs_per_line; ++dof) - dofs_on_mother[next_index++] - = this_face->line(line)->dof_index(dof, fe_index); - for (unsigned int dof=0; dof!=fe.dofs_per_quad; ++dof) - dofs_on_mother[next_index++] = this_face->dof_index(dof, fe_index); - AssertDimension (next_index, dofs_on_mother.size()); - - next_index = 0; - - // assert some consistency assumptions - - //TODO[TL]: think about this in case of anisotropic - //refinement - - Assert (dof_handler.get_tria().get_anisotropic_refinement_flag() || - ((this_face->child(0)->vertex_index(3) == - this_face->child(1)->vertex_index(2)) && - (this_face->child(0)->vertex_index(3) == - this_face->child(2)->vertex_index(1)) && - (this_face->child(0)->vertex_index(3) == - this_face->child(3)->vertex_index(0))), - ExcInternalError()); - for (unsigned int dof=0; dof!=fe.dofs_per_vertex; ++dof) - dofs_on_children[next_index++] - = this_face->child(0)->vertex_dof_index(3,dof); - - // dof numbers on the centers of the lines bounding this - // face - for (unsigned int line=0; line<4; ++line) - for (unsigned int dof=0; dof!=fe.dofs_per_vertex; ++dof) - dofs_on_children[next_index++] - = this_face->line(line)->child(0)->vertex_dof_index(1,dof, fe_index); - - // next the dofs on the lines interior to the face; the - // order of these lines is laid down in the FiniteElement - // class documentation - for (unsigned int dof=0; dof<fe.dofs_per_line; ++dof) - dofs_on_children[next_index++] - = this_face->child(0)->line(1)->dof_index(dof, fe_index); - for (unsigned int dof=0; dof<fe.dofs_per_line; ++dof) - dofs_on_children[next_index++] - = this_face->child(2)->line(1)->dof_index(dof, fe_index); - for (unsigned int dof=0; dof<fe.dofs_per_line; ++dof) - dofs_on_children[next_index++] - = this_face->child(0)->line(3)->dof_index(dof, fe_index); - for (unsigned int dof=0; dof<fe.dofs_per_line; ++dof) - dofs_on_children[next_index++] - = this_face->child(1)->line(3)->dof_index(dof, fe_index); - - // dofs on the bordering lines - for (unsigned int line=0; line<4; ++line) - for (unsigned int child=0; child<2; ++child) - for (unsigned int dof=0; dof!=fe.dofs_per_line; ++dof) - dofs_on_children[next_index++] - = this_face->line(line)->child(child)->dof_index(dof, fe_index); - - // finally, for the dofs interior to the four child faces - for (unsigned int child=0; child<4; ++child) - for (unsigned int dof=0; dof!=fe.dofs_per_quad; ++dof) - dofs_on_children[next_index++] - = this_face->child(child)->dof_index(dof, fe_index); - AssertDimension (next_index, dofs_on_children.size()); - - // for each row in the constraint matrix for this line: - for (unsigned int row=0; row!=dofs_on_children.size(); ++row) - { - constraints.add_line (dofs_on_children[row]); - for (unsigned int i=0; i!=dofs_on_mother.size(); ++i) - constraints.add_entry (dofs_on_children[row], - dofs_on_mother[i], - fe.constraints()(row,i)); - - constraints.set_inhomogeneity(dofs_on_children[row], 0.); - } - } - else - { - // this face has no children, but it could still be that it - // is shared by two cells that use a different fe index. - // check a couple of things, but ignore the case that the - // neighbor is an artificial cell - if (!cell->at_boundary(face) && - !cell->neighbor(face)->is_artificial()) - { - Assert (cell->face(face)->n_active_fe_indices() == 1, - ExcNotImplemented()); - Assert (cell->face(face) - ->fe_index_is_active(cell->active_fe_index()) == true, - ExcInternalError()); - } - } - } - - - template <class DH> - void - make_hp_hanging_node_constraints (const DH &dof_handler, - ConstraintMatrix &constraints) - { - // note: this function is going to be hard to understand if you - // haven't read the hp paper. however, we try to follow the notation - // laid out there, so go read the paper before you try to understand - // what is going on here - - const unsigned int dim = DH::dimension; - - const unsigned int spacedim = DH::space_dimension; - - - // a matrix to be used for constraints below. declared here and - // simply resized down below to avoid permanent re-allocation of - // memory - FullMatrix<double> constraint_matrix; - - // similarly have arrays that will hold master and slave dof numbers, - // as well as a scratch array needed for the complicated case below - std::vector<types::global_dof_index> master_dofs; - std::vector<types::global_dof_index> slave_dofs; - std::vector<types::global_dof_index> scratch_dofs; - - // caches for the face and subface interpolation matrices between - // different (or the same) finite elements. we compute them only - // once, namely the first time they are needed, and then just reuse - // them - Table<2,std_cxx1x::shared_ptr<FullMatrix<double> > > - face_interpolation_matrices (n_finite_elements (dof_handler), - n_finite_elements (dof_handler)); - Table<3,std_cxx1x::shared_ptr<FullMatrix<double> > > - subface_interpolation_matrices (n_finite_elements (dof_handler), - n_finite_elements (dof_handler), - GeometryInfo<dim>::max_children_per_face); - - // similarly have a cache for the matrices that are split into their - // master and slave parts, and for which the master part is inverted. - // these two matrices are derived from the face interpolation matrix - // as described in the @ref hp_paper "hp paper" - Table<2,std_cxx1x::shared_ptr<std::pair<FullMatrix<double>,FullMatrix<double> > > > - split_face_interpolation_matrices (n_finite_elements (dof_handler), - n_finite_elements (dof_handler)); - - // finally, for each pair of finite elements, have a mask that states - // which of the degrees of freedom on the coarse side of a refined - // face will act as master dofs. - Table<2,std_cxx1x::shared_ptr<std::vector<bool> > > - master_dof_masks (n_finite_elements (dof_handler), - n_finite_elements (dof_handler)); - - // loop over all faces - // - // note that even though we may visit a face twice if the neighboring - // cells are equally refined, we can only visit each face with - // hanging nodes once - typename DH::active_cell_iterator cell = dof_handler.begin_active(), - endc = dof_handler.end(); - for (; cell!=endc; ++cell) - // artificial cells can at best neighbor ghost cells, but we're not - // interested in these interfaces - if (!cell->is_artificial ()) - for (unsigned int face=0; face<GeometryInfo<dim>::faces_per_cell; ++face) - if (cell->face(face)->has_children()) - { - // first of all, make sure that we treat a case which is - // possible, i.e. either no dofs on the face at all or no - // anisotropic refinement - if (cell->get_fe().dofs_per_face == 0) - continue; - - Assert(cell->face(face)->refinement_case()==RefinementCase<dim-1>::isotropic_refinement, - ExcNotImplemented()); - - // so now we've found a face of an active cell that has - // children. that means that there are hanging nodes here. - - // in any case, faces can have at most two sets of active - // fe indices, but here the face can have only one (namely - // the same as that from the cell we're sitting on), and - // each of the children can have only one as well. check - // this - Assert (cell->face(face)->n_active_fe_indices() == 1, - ExcInternalError()); - Assert (cell->face(face)->fe_index_is_active(cell->active_fe_index()) - == true, - ExcInternalError()); - for (unsigned int c=0; c<cell->face(face)->n_children(); ++c) - Assert (cell->face(face)->child(c)->n_active_fe_indices() == 1, - ExcInternalError()); - - // first find out whether we can constrain each of the - // subfaces to the mother face. in the lingo of the hp - // paper, this would be the simple case. note that we can - // short-circuit this decision if the dof_handler doesn't - // support hp at all - // - // ignore all interfaces with artificial cells - FiniteElementDomination::Domination - mother_face_dominates = FiniteElementDomination::either_element_can_dominate; - - if (DoFHandlerSupportsDifferentFEs<DH>::value == true) - for (unsigned int c=0; c<cell->face(face)->number_of_children(); ++c) - if (!cell->neighbor_child_on_subface (face, c)->is_artificial()) - mother_face_dominates = mother_face_dominates & - (cell->get_fe().compare_for_face_domination - (cell->neighbor_child_on_subface (face, c)->get_fe())); - - switch (mother_face_dominates) - { - case FiniteElementDomination::this_element_dominates: - case FiniteElementDomination::either_element_can_dominate: - { - // Case 1 (the simple case and the only case that can - // happen for non-hp DoFHandlers): The coarse element - // dominates the elements on the subfaces (or they are - // all the same) - // - // so we are going to constrain the DoFs on the face - // children against the DoFs on the face itself - master_dofs.resize (cell->get_fe().dofs_per_face); - - cell->face(face)->get_dof_indices (master_dofs, - cell->active_fe_index ()); - - // Now create constraint matrix for the subfaces and - // assemble it. ignore all interfaces with artificial - // cells because we can only get to such interfaces if - // the current cell is a ghost cell - for (unsigned int c=0; c<cell->face(face)->n_children(); ++c) - { - if (cell->neighbor_child_on_subface (face, c)->is_artificial()) - continue; - - const typename DH::active_face_iterator - subface = cell->face(face)->child(c); - - Assert (subface->n_active_fe_indices() == 1, - ExcInternalError()); - - const unsigned int - subface_fe_index = subface->nth_active_fe_index(0); - - // we sometime run into the situation where for - // example on one big cell we have a FE_Q(1) and on - // the subfaces we have a mixture of FE_Q(1) and - // FE_Nothing. In that case, the face domination is - // either_element_can_dominate for the whole - // collection of subfaces, but on the particular - // subface between FE_Q(1) and FE_Nothing, there - // are no constraints that we need to take care of. - // in that case, just continue - if (cell->get_fe().compare_for_face_domination - (subface->get_fe(subface_fe_index)) - == - FiniteElementDomination::no_requirements) - continue; - - // Same procedure as for the mother cell. Extract - // the face DoFs from the cell DoFs. - slave_dofs.resize (subface->get_fe(subface_fe_index) - .dofs_per_face); - subface->get_dof_indices (slave_dofs, subface_fe_index); - - for (unsigned int i=0; i<slave_dofs.size(); ++i) - Assert (slave_dofs[i] != numbers::invalid_dof_index, - ExcInternalError()); - - // Now create the element constraint for this - // subface. - // - // As a side remark, one may wonder the following: - // neighbor_child is clearly computed correctly, - // i.e. taking into account face_orientation (just - // look at the implementation of that function). - // however, we don't care about this here, when we - // ask for subface_interpolation on subface c. the - // question rather is: do we have to translate 'c' - // here as well? - // - // the answer is in fact 'no'. if one does that, - // results are wrong: constraints are added twice - // for the same pair of nodes but with differing - // weights. in addition, one can look at the - // deal.II/project_*_03 tests that look at exactly - // this case: there, we have a mesh with at least - // one face_orientation==false and hanging nodes, - // and the results of those tests show that the - // result of projection verifies the approximation - // properties of a finite element onto that mesh - ensure_existence_of_subface_matrix - (cell->get_fe(), - subface->get_fe(subface_fe_index), - c, - subface_interpolation_matrices - [cell->active_fe_index()][subface_fe_index][c]); - - // Add constraints to global constraint matrix. - filter_constraints (master_dofs, - slave_dofs, - *(subface_interpolation_matrices - [cell->active_fe_index()][subface_fe_index][c]), - constraints); - } - - break; - } - - case FiniteElementDomination::other_element_dominates: - case FiniteElementDomination::neither_element_dominates: - { - // Case 2 (the "complex" case): at least one (the - // neither_... case) of the finer elements or all of - // them (the other_... case) is dominating. See the hp - // paper for a way how to deal with this situation - // - // since this is something that can only happen for hp - // dof handlers, add a check here... - Assert (DoFHandlerSupportsDifferentFEs<DH>::value == true, - ExcInternalError()); - - // we first have to find the finite element that is - // able to generate a space that all the other ones can - // be constrained to - const unsigned int dominating_fe_index - = get_most_dominating_subface_fe_index (cell->face(face)); - - const FiniteElement<dim,spacedim> &dominating_fe - = dof_handler.get_fe()[dominating_fe_index]; - - // check also that it is able to constrain the mother - // face. it should be, or we wouldn't have gotten into - // the branch for the 'complex' case - Assert ((dominating_fe.compare_for_face_domination - (cell->face(face)->get_fe(cell->face(face)->nth_active_fe_index(0))) - == FiniteElementDomination::this_element_dominates) - || - (dominating_fe.compare_for_face_domination - (cell->face(face)->get_fe(cell->face(face)->nth_active_fe_index(0))) - == FiniteElementDomination::either_element_can_dominate), - ExcInternalError()); - - - // first get the interpolation matrix from the mother - // to the virtual dofs - Assert (dominating_fe.dofs_per_face <= - cell->get_fe().dofs_per_face, - ExcInternalError()); - - ensure_existence_of_face_matrix - (dominating_fe, - cell->get_fe(), - face_interpolation_matrices - [dominating_fe_index][cell->active_fe_index()]); - - // split this matrix into master and slave components. - // invert the master component - ensure_existence_of_master_dof_mask - (cell->get_fe(), - dominating_fe, - (*face_interpolation_matrices - [dominating_fe_index] - [cell->active_fe_index()]), - master_dof_masks - [dominating_fe_index] - [cell->active_fe_index()]); - - ensure_existence_of_split_face_matrix - (*face_interpolation_matrices - [dominating_fe_index][cell->active_fe_index()], - (*master_dof_masks - [dominating_fe_index][cell->active_fe_index()]), - split_face_interpolation_matrices - [dominating_fe_index][cell->active_fe_index()]); - - const FullMatrix<double> &restrict_mother_to_virtual_master_inv - = (split_face_interpolation_matrices - [dominating_fe_index][cell->active_fe_index()]->first); - - const FullMatrix<double> &restrict_mother_to_virtual_slave - = (split_face_interpolation_matrices - [dominating_fe_index][cell->active_fe_index()]->second); - - // now compute the constraint matrix as the product - // between the inverse matrix and the slave part - constraint_matrix.reinit (cell->get_fe().dofs_per_face - - dominating_fe.dofs_per_face, - dominating_fe.dofs_per_face); - restrict_mother_to_virtual_slave - .mmult (constraint_matrix, - restrict_mother_to_virtual_master_inv); - - // then figure out the global numbers of master and - // slave dofs and apply constraints - scratch_dofs.resize (cell->get_fe().dofs_per_face); - cell->face(face)->get_dof_indices (scratch_dofs, - cell->active_fe_index ()); - - // split dofs into master and slave components - master_dofs.clear (); - slave_dofs.clear (); - for (unsigned int i=0; i<cell->get_fe().dofs_per_face; ++i) - if ((*master_dof_masks - [dominating_fe_index][cell->active_fe_index()])[i] == true) - master_dofs.push_back (scratch_dofs[i]); - else - slave_dofs.push_back (scratch_dofs[i]); - - AssertDimension (master_dofs.size(), dominating_fe.dofs_per_face); - AssertDimension (slave_dofs.size(), - cell->get_fe().dofs_per_face - dominating_fe.dofs_per_face); - - filter_constraints (master_dofs, - slave_dofs, - constraint_matrix, - constraints); - - - - // next we have to deal with the subfaces. do as - // discussed in the hp paper - for (unsigned int sf=0; - sf<cell->face(face)->n_children(); ++sf) - { - // ignore interfaces with artificial cells as well - // as interfaces between ghost cells in 2d - if (cell->neighbor_child_on_subface (face, sf)->is_artificial() - || - (dim==2 && cell->is_ghost() - && - cell->neighbor_child_on_subface (face, sf)->is_ghost())) - continue; - - Assert (cell->face(face)->child(sf) - ->n_active_fe_indices() == 1, - ExcInternalError()); - - const unsigned int subface_fe_index - = cell->face(face)->child(sf)->nth_active_fe_index(0); - const FiniteElement<dim,spacedim> &subface_fe - = dof_handler.get_fe()[subface_fe_index]; - - // first get the interpolation matrix from the - // subface to the virtual dofs - Assert (dominating_fe.dofs_per_face <= - subface_fe.dofs_per_face, - ExcInternalError()); - ensure_existence_of_subface_matrix - (dominating_fe, - subface_fe, - sf, - subface_interpolation_matrices - [dominating_fe_index][subface_fe_index][sf]); - - const FullMatrix<double> &restrict_subface_to_virtual - = *(subface_interpolation_matrices - [dominating_fe_index][subface_fe_index][sf]); - - constraint_matrix.reinit (subface_fe.dofs_per_face, - dominating_fe.dofs_per_face); - - restrict_subface_to_virtual - .mmult (constraint_matrix, - restrict_mother_to_virtual_master_inv); - - slave_dofs.resize (subface_fe.dofs_per_face); - cell->face(face)->child(sf)->get_dof_indices (slave_dofs, - subface_fe_index); - - filter_constraints (master_dofs, - slave_dofs, - constraint_matrix, - constraints); - } - - break; - } - - case FiniteElementDomination::no_requirements: - // there are no continuity requirements between the two - // elements. record no constraints - break; - - default: - // we shouldn't get here - Assert (false, ExcInternalError()); - } - } - else - { - // this face has no children, but it could still be that it - // is shared by two cells that use a different fe index - Assert (cell->face(face) - ->fe_index_is_active(cell->active_fe_index()) == true, - ExcInternalError()); - - // see if there is a neighbor that is an artificial cell. - // in that case, we're not interested in this interface. we - // test this case first since artificial cells may not have - // an active_fe_index set, etc - if (!cell->at_boundary(face) - && - cell->neighbor(face)->is_artificial()) - continue; - - // Only if there is a neighbor with a different - // active_fe_index and the same h-level, some action has to - // be taken. - if ((DoFHandlerSupportsDifferentFEs<DH>::value == true) - && - !cell->face(face)->at_boundary () - && - (cell->neighbor(face)->active_fe_index () != - cell->active_fe_index ()) - && - (!cell->face(face)->has_children() && - !cell->neighbor_is_coarser(face) )) - { - const typename DH::level_cell_iterator neighbor = cell->neighbor (face); - - // see which side of the face we have to constrain - switch (cell->get_fe().compare_for_face_domination (neighbor->get_fe ())) - { - case FiniteElementDomination::this_element_dominates: - { - // Get DoFs on dominating and dominated side of the - // face - master_dofs.resize (cell->get_fe().dofs_per_face); - cell->face(face)->get_dof_indices (master_dofs, - cell->active_fe_index ()); - - slave_dofs.resize (neighbor->get_fe().dofs_per_face); - cell->face(face)->get_dof_indices (slave_dofs, - neighbor->active_fe_index ()); - - // break if the n_master_dofs == 0, because we are - // attempting to constrain to an element that has - // no face dofs - if (master_dofs.size() == 0) break; - - // make sure the element constraints for this face - // are available - ensure_existence_of_face_matrix - (cell->get_fe(), - neighbor->get_fe(), - face_interpolation_matrices - [cell->active_fe_index()][neighbor->active_fe_index()]); - - // Add constraints to global constraint matrix. - filter_constraints (master_dofs, - slave_dofs, - *(face_interpolation_matrices - [cell->active_fe_index()] - [neighbor->active_fe_index()]), - constraints); - - break; - } - - case FiniteElementDomination::other_element_dominates: - { - // we don't do anything here since we will come - // back to this face from the other cell, at which - // time we will fall into the first case clause - // above - break; - } - - case FiniteElementDomination::either_element_can_dominate: - { - // it appears as if neither element has any - // constraints on its neighbor. this may be because - // neither element has any DoFs on faces at all. or - // that the two elements are actually the same, - // although they happen to run under different - // fe_indices (this is what happens in - // hp/hp_hanging_nodes_01 for example). - // - // another possibility is what happens in crash_13. - // there, we have FESystem(FE_Q(1),FE_DGQ(0)) vs. - // FESystem(FE_Q(1),FE_DGQ(1)). neither of them - // dominates the other. - // - // a final possibility is that we have something like - // FESystem(FE_Q(1),FE_Q(1)) vs - // FESystem(FE_Q(1),FE_Nothing()), see - // hp/fe_nothing_18/19. - // - // in any case, the point is that it doesn't - // matter. there is nothing to do here. - break; - } - - case FiniteElementDomination::neither_element_dominates: - { - // we don't presently know what exactly to do here. - // it isn't quite clear what exactly we would have - // to do here. sit tight until someone trips over - // the following statement and see what exactly is - // going on - Assert (false, ExcNotImplemented()); - break; - } - - case FiniteElementDomination::no_requirements: - { - // nothing to do here - break; - } - - default: - // we shouldn't get here - Assert (false, ExcInternalError()); - } - } - } - } - } - - - - - template <class DH> - void - make_hanging_node_constraints (const DH &dof_handler, - ConstraintMatrix &constraints) - { - // Decide whether to use the new or old make_hanging_node_constraints - // function. If all the FiniteElement or all elements in a FECollection - // support the new face constraint matrix, the new code will be used. - // Otherwise, the old implementation is used for the moment. - if (dof_handler.get_fe().hp_constraints_are_implemented ()) - internal:: - make_hp_hanging_node_constraints (dof_handler, - constraints); - else - internal:: - make_oldstyle_hanging_node_constraints (dof_handler, - constraints, - dealii::internal::int2type<DH::dimension>()); - } - - - - namespace - { - // enter constraints for periodicity into the given ConstraintMatrix object. - // this function is called when at least one of the two face iterators corresponds - // to an active object without further children - // - // @param transformation A matrix that maps degrees of freedom from one face - // to another. If the DoFs on the two faces are supposed to match exactly, then - // the matrix so provided will be the identity matrix. if face 2 is once refined - // from face 1, then the matrix needs to be the interpolation matrix from a face - // to this particular child - // - // @precondition: face_1 is supposed to be active - // - // @note As bug #82 ((http://code.google.com/p/dealii/issues/detail?id=82) and the - // corresponding testcase bits/periodicity_05 demonstrate, we can occasionally - // get into trouble if we already have the constraint x1=x2 and want to insert - // x2=x1. we avoid this by skipping an identity constraint if the opposite - // constraint already exists - template <typename FaceIterator> - void - set_periodicity_constraints (const FaceIterator &face_1, - const typename identity<FaceIterator>::type &face_2, - const FullMatrix<double> &transformation, - dealii::ConstraintMatrix &constraint_matrix, - const ComponentMask &component_mask, - const bool face_orientation, - const bool face_flip, - const bool face_rotation) - { - static const int dim = FaceIterator::AccessorType::dimension; - static const int spacedim = FaceIterator::AccessorType::space_dimension; - - // we should be in the case where face_1 is active, i.e. has no children: - Assert (!face_1->has_children(), - ExcInternalError()); - - Assert (face_1->n_active_fe_indices() == 1, - ExcInternalError()); - - // if face_2 does have children, then we need to iterate over them - if (face_2->has_children()) - { - Assert (face_2->n_children() == GeometryInfo<dim>::max_children_per_face, - ExcNotImplemented()); - const unsigned int dofs_per_face - = face_1->get_fe(face_1->nth_active_fe_index(0)).dofs_per_face; - FullMatrix<double> child_transformation (dofs_per_face, dofs_per_face); - FullMatrix<double> subface_interpolation (dofs_per_face, dofs_per_face); - for (unsigned int c=0; c<face_2->n_children(); ++c) - { - // get the interpolation matrix recursively from the one that - // interpolated from face_1 to face_2 by multiplying from the - // left with the one that interpolates from face_2 to - // its child - face_1->get_fe(face_1->nth_active_fe_index(0)) - .get_subface_interpolation_matrix (face_1->get_fe(face_1->nth_active_fe_index(0)), - c, - subface_interpolation); - subface_interpolation.mmult (child_transformation, transformation); - set_periodicity_constraints(face_1, face_2->child(c), - child_transformation, - constraint_matrix, component_mask, - face_orientation, face_flip, face_rotation); - } - } - else - // both faces are active. we need to match the corresponding DoFs of both faces - { - const unsigned int face_1_index = face_1->nth_active_fe_index(0); - const unsigned int face_2_index = face_2->nth_active_fe_index(0); - Assert(face_1->get_fe(face_1_index) == face_2->get_fe(face_1_index), - ExcMessage ("Matching periodic cells need to use the same finite element")); - - const FiniteElement<dim, spacedim> &fe = face_1->get_fe(face_1_index); - - Assert(component_mask.represents_n_components(fe.n_components()), - ExcMessage ("The number of components in the mask has to be either " - "zero or equal to the number of components in the finite " "element.")); - - const unsigned int dofs_per_face = fe.dofs_per_face; - - std::vector<types::global_dof_index> dofs_1(dofs_per_face); - std::vector<types::global_dof_index> dofs_2(dofs_per_face); - - face_1->get_dof_indices(dofs_1, face_1_index); - face_2->get_dof_indices(dofs_2, face_2_index); - - // Well, this is a hack: - // - // There is no - // face_to_face_index(face_index, - // face_orientation, - // face_flip, - // face_rotation) - // function in FiniteElementData, so we have to use - // face_to_cell_index(face_index, face - // face_orientation, - // face_flip, - // face_rotation) - // But this will give us an index on a cell - something we cannot work - // with directly. But luckily we can match them back :-] - - std::map<unsigned int, unsigned int> cell_to_rotated_face_index; - - // Build up a cell to face index for face_2: - for (unsigned int i = 0; i < dofs_per_face; ++i) - { - const unsigned int cell_index = fe.face_to_cell_index(i, 0, /* It doesn't really matter, just assume - * we're on the first face... - */ - true, false, false // default orientation - ); - cell_to_rotated_face_index[cell_index] = i; - } - - // loop over all dofs on face 2 and constrain them again the ones on face 1 - for (unsigned int i=0; i<dofs_per_face; ++i) - if (!constraint_matrix.is_constrained(dofs_2[i])) - if ((component_mask.n_selected_components(fe.n_components()) - == fe.n_components()) - || - component_mask[fe.face_system_to_component_index(i).first]) - { - // as mentioned in the comment above this function, we need - // to be careful about treating identity constraints differently. - // consequently, find out whether this dof 'i' will be - // identity constrained - // - // to check whether this is the case, first see whether there are - // any weights other than 0 and 1, then in a first stage make sure - // that if so there is only one weight equal to 1 - bool is_identity_constrained = true; - for (unsigned int jj=0; jj<dofs_per_face; ++jj) - if (((transformation(i,jj) == 0) || (transformation(i,jj) == 1)) == false) - { - is_identity_constrained = false; - break; - } - unsigned int identity_constraint_target = numbers::invalid_unsigned_int; - if (is_identity_constrained == true) - { - bool one_identity_found = false; - for (unsigned int jj=0; jj<dofs_per_face; ++jj) - if (transformation(i,jj) == 1) - { - if (one_identity_found == false) - { - one_identity_found = true; - identity_constraint_target = jj; - } - else - { - is_identity_constrained = false; - identity_constraint_target = numbers::invalid_unsigned_int; - break; - } - } - } - - // now treat constraints, either as an equality constraint or - // as a sequence of constraints - if (is_identity_constrained == true) - { - // Query the correct face_index on face_2 respecting the given - // orientation: - const unsigned int j = - cell_to_rotated_face_index[fe.face_to_cell_index(identity_constraint_target, - 0, /* It doesn't really matter, just assume - * we're on the first face... - */ - face_orientation, face_flip, face_rotation)]; - - // if the two aren't already identity constrained (whichever way - // around, then enter the constraint. otherwise there is nothing - // for us still to do - if (constraint_matrix.are_identity_constrained(dofs_2[i], dofs_1[i]) == false) - { - constraint_matrix.add_line(dofs_2[i]); - constraint_matrix.add_entry(dofs_2[i], dofs_1[j], 1); - } - } - else - { - // this is just a regular constraint. enter it piece by piece - constraint_matrix.add_line(dofs_2[i]); - for (unsigned int jj=0; jj<dofs_per_face; ++jj) - { - // Query the correct face_index on face_2 respecting the given - // orientation: - const unsigned int j = - cell_to_rotated_face_index[fe.face_to_cell_index(jj, 0, /* It doesn't really matter, just assume - * we're on the first face... - */ - face_orientation, face_flip, face_rotation)]; - - // And finally constrain the two DoFs respecting component_mask: - if (transformation(i,jj) != 0) - constraint_matrix.add_entry(dofs_2[i], dofs_1[j], - transformation(i,jj)); - } - } - } - } - } - } - - - template <typename FaceIterator> - void - make_periodicity_constraints (const FaceIterator &face_1, - const typename identity<FaceIterator>::type &face_2, - dealii::ConstraintMatrix &constraint_matrix, - const ComponentMask &component_mask, - const bool face_orientation, - const bool face_flip, - const bool face_rotation) - { - static const int dim = FaceIterator::AccessorType::dimension; - - Assert( (dim != 1) || - (face_orientation == true && - face_flip == false && - face_rotation == false), - ExcMessage ("The supplied orientation " - "(face_orientation, face_flip, face_rotation) " - "is invalid for 1D")); - - Assert( (dim != 2) || - (face_orientation == true && - face_rotation == false), - ExcMessage ("The supplied orientation " - "(face_orientation, face_flip, face_rotation) " - "is invalid for 2D")); - - Assert(face_1 != face_2, - ExcMessage ("face_1 and face_2 are equal! Cannot constrain DoFs " - "on the very same face")); - - Assert(face_1->at_boundary() && face_2->at_boundary(), - ExcMessage ("Faces for periodicity constraints must be on the boundary")); - - - // A lookup table on how to go through the child faces depending on the - // orientation: - - static const int lookup_table_2d[2][2] = - { - // flip: - {0, 1}, // false - {1, 0}, // true - }; - - static const int lookup_table_3d[2][2][2][4] = - { - // orientation flip rotation - { { {0, 2, 1, 3}, // false false false - {2, 3, 0, 1}, // false false true - }, - { {3, 1, 2, 0}, // false true false - {1, 0, 3, 2}, // false true true - }, - }, - { { {0, 1, 2, 3}, // true false false - {1, 3, 0, 2}, // true false true - }, - { {3, 2, 1, 0}, // true true false - {2, 0, 3, 1}, // true true true - }, - }, - }; - - // In the case that both faces have children, we loop over all - // children and apply make_periodicty_constrains recursively: - if (face_1->has_children() && face_2->has_children()) - { - Assert(face_1->n_children() == GeometryInfo<dim>::max_children_per_face && - face_2->n_children() == GeometryInfo<dim>::max_children_per_face, - ExcNotImplemented()); - - for (unsigned int i = 0; i < GeometryInfo<dim>::max_children_per_face; ++i) - { - // Lookup the index for the second face - unsigned int j; - switch (dim) - { - case 2: - j = lookup_table_2d[face_flip][i]; - break; - case 3: - j = lookup_table_3d[face_orientation][face_flip][face_rotation][i]; - break; - default: - AssertThrow(false, ExcNotImplemented()); - } - - make_periodicity_constraints (face_1->child(i), - face_2->child(j), - constraint_matrix, - component_mask, - face_orientation, - face_flip, - face_rotation); - } - } - else - // otherwise at least one of the two faces is active and - // we need to enter the constraints - { - if (face_2->has_children() == false) - set_periodicity_constraints(face_2, face_1, - FullMatrix<double>(IdentityMatrix(face_1->get_fe(face_1->nth_active_fe_index(0)).dofs_per_face)), - constraint_matrix, - component_mask, - face_orientation, face_flip, face_rotation); - else - set_periodicity_constraints(face_1, face_2, - FullMatrix<double>(IdentityMatrix(face_1->get_fe(face_1->nth_active_fe_index(0)).dofs_per_face)), - constraint_matrix, - component_mask, - face_orientation, face_flip, face_rotation); - } - } - - - - template<typename DH> - void - make_periodicity_constraints (const DH &dof_handler, - const types::boundary_id b_id1, - const types::boundary_id b_id2, - const int direction, - dealii::ConstraintMatrix &constraint_matrix, - const ComponentMask &component_mask) - { - Tensor<1,DH::space_dimension> dummy; - make_periodicity_constraints (dof_handler, - b_id1, - b_id2, - direction, - dummy, - constraint_matrix, - component_mask); - } - - - - template<typename DH> - void - make_periodicity_constraints (const DH &dof_handler, - const types::boundary_id b_id1, - const types::boundary_id b_id2, - const int direction, - dealii::Tensor<1,DH::space_dimension> &offset, - dealii::ConstraintMatrix &constraint_matrix, - const ComponentMask &component_mask) - { - static const int space_dim = DH::space_dimension; - Assert (0<=direction && direction<space_dim, - ExcIndexRange (direction, 0, space_dim)); - -#if defined(DEBUG) && defined(DEAL_II_WITH_P4EST) - // Check whether we run on a non parallel mesh or on a - // parallel::distributed::Triangulation in serial - { - typedef parallel::distributed::Triangulation<DH::dimension,DH::space_dimension> PTRIA; - const PTRIA *ptria_p = dynamic_cast<const PTRIA *> (&dof_handler.get_tria()); - Assert ((ptria_p == 0 || Utilities::MPI::n_mpi_processes(ptria_p->get_communicator()) == 1), - ExcMessage ("This function can not be used with distributed triangulations." - "See the documentation for more information.")); - } -#endif - - Assert (b_id1 != b_id2, - ExcMessage ("The boundary indicators b_id1 and b_id2 must be" - "different to denote different boundaries.")); - - typedef typename DH::face_iterator FaceIterator; - typedef std::map<FaceIterator, std::pair<FaceIterator, std::bitset<3> > > FaceMap; - - // Collect matching periodic cells on the coarsest level: - FaceMap matched_cells = - GridTools::collect_periodic_face_pairs(dof_handler, - b_id1, b_id2, - direction, offset); - - // And apply the low level make_periodicity_constraints function to - // every matching pair: - for (typename FaceMap::iterator it = matched_cells.begin(); - it != matched_cells.end(); ++it) - { - typedef typename DH::face_iterator FaceIterator; - const FaceIterator &face_1 = it->first; - const FaceIterator &face_2 = it->second.first; - const std::bitset<3> &orientation = it->second.second; - - Assert(face_1->at_boundary() && face_2->at_boundary(), - ExcInternalError()); - - Assert (face_1->boundary_indicator() == b_id1 && - face_2->boundary_indicator() == b_id2, - ExcInternalError()); - - Assert (face_1 != face_2, - ExcInternalError()); - - make_periodicity_constraints(face_1, - face_2, - constraint_matrix, - component_mask, - orientation[0], - orientation[1], - orientation[2]); - } - } - - - - template<typename DH> - void - make_periodicity_constraints (const DH &dof_handler, - const types::boundary_id b_id, - const int direction, - dealii::ConstraintMatrix &constraint_matrix, - const ComponentMask &component_mask) - { - Tensor<1,DH::space_dimension> dummy; - make_periodicity_constraints (dof_handler, - b_id, - direction, - dummy, - constraint_matrix, - component_mask); - } - - - - template<typename DH> - void - make_periodicity_constraints (const DH &dof_handler, - const types::boundary_id b_id, - const int direction, - dealii::Tensor<1,DH::space_dimension> &offset, - dealii::ConstraintMatrix &constraint_matrix, - const ComponentMask &component_mask) - { - static const int dim = DH::dimension; - static const int space_dim = DH::space_dimension; - - Assert (0<=direction && direction<space_dim, - ExcIndexRange (direction, 0, space_dim)); - - Assert(dim == space_dim, - ExcNotImplemented()); - -#if defined(DEBUG) && defined(DEAL_II_WITH_P4EST) - // Check whether we run on a non parallel mesh or on a - // parallel::distributed::Triangulation in serial - { - typedef typename parallel::distributed::Triangulation<DH::dimension,DH::space_dimension> PTRIA; - const PTRIA *ptria_p = dynamic_cast<const PTRIA *> (&dof_handler.get_tria()); - Assert ((ptria_p == 0 || Utilities::MPI::n_mpi_processes(ptria_p->get_communicator()) == 1), - ExcMessage ("This function can not be used with distributed triangulations." - "See the documentation for more information.")); - } -#endif - - typedef typename DH::face_iterator FaceIterator; - typedef std::map<FaceIterator, FaceIterator> FaceMap; - - // Collect matching periodic cells on the coarsest level: - FaceMap matched_cells = - GridTools::collect_periodic_face_pairs(dof_handler, - b_id, - direction, offset); - - // And apply the low level make_periodicity_constraints function to - // every matching pair: - for (typename FaceMap::iterator it = matched_cells.begin(); - it != matched_cells.end(); ++it) - { - typedef typename DH::face_iterator FaceIterator; - const FaceIterator &face_1 = it->first; - const FaceIterator &face_2 = it->second; - - Assert(face_1->at_boundary() && face_2->at_boundary(), - ExcInternalError()); - - Assert (face_1->boundary_indicator() == b_id && - face_2->boundary_indicator() == b_id, - ExcInternalError()); - - Assert (face_1 != face_2, - ExcInternalError()); - - make_periodicity_constraints(face_1, - face_2, - constraint_matrix, - component_mask - /* standard orientation */); - } - } - - - namespace internal { // return an array that for each dof on the reference cell @@ -4719,677 +1512,6 @@ namespace DoFTools - - namespace internal - { - namespace - { - /** - * This is a function that is called by the _2 function and that - * operates on a range of cells only. It is used to split up the - * whole range of cells into chunks which are then worked on in - * parallel, if multithreading is available. - */ - template <int dim, int spacedim> - void - compute_intergrid_weights_3 ( - const dealii::DoFHandler<dim,spacedim> &coarse_grid, - const unsigned int coarse_component, - const InterGridMap<dealii::DoFHandler<dim,spacedim> > &coarse_to_fine_grid_map, - const std::vector<dealii::Vector<double> > ¶meter_dofs, - const std::vector<types::global_dof_index> &weight_mapping, - std::vector<std::map<types::global_dof_index, float> > &weights, - const typename dealii::DoFHandler<dim,spacedim>::active_cell_iterator &begin, - const typename dealii::DoFHandler<dim,spacedim>::active_cell_iterator &end) - { - // aliases to the finite elements used by the dof handlers: - const FiniteElement<dim,spacedim> &coarse_fe = coarse_grid.get_fe(); - - // for each cell on the parameter grid: find out which degrees of - // freedom on the fine grid correspond in which way to the degrees - // of freedom on the parameter grid - // - // since for continuous FEs some dofs exist on more than one cell, - // we have to track which ones were already visited. the problem is - // that if we visit a dof first on one cell and compute its weight - // with respect to some global dofs to be non-zero, and later visit - // the dof again on another cell and (since we are on another cell) - // recompute the weights with respect to the same dofs as above to - // be zero now, we have to preserve them. we therefore overwrite - // all weights if they are nonzero and do not enforce zero weights - // since that might be only due to the fact that we are on another - // cell. - // - // example: - // coarse grid - // | | | - // *-----*-----* - // | cell|cell | - // | 1 | 2 | - // | | | - // 0-----1-----* - // - // fine grid - // | | | | | - // *--*--*--*--* - // | | | | | - // *--*--*--*--* - // | | | | | - // *--x--y--*--* - // - // when on cell 1, we compute the weights of dof 'x' to be 1/2 from - // parameter dofs 0 and 1, respectively. however, when later we are - // on cell 2, we again compute the prolongation of shape function 1 - // restricted to cell 2 to the globla grid and find that the weight - // of global dof 'x' now is zero. however, we should not overwrite - // the old value. - // - // we therefore always only set nonzero values. why adding up is - // not useful: dof 'y' would get weight 1 from parameter dof 1 on - // both cells 1 and 2, but the correct weight is nevertheless only - // 1. - - // vector to hold the representation of a single degree of freedom - // on the coarse grid (for the selected fe) on the fine grid - const types::global_dof_index n_fine_dofs = weight_mapping.size(); - dealii::Vector<double> global_parameter_representation (n_fine_dofs); - - typename dealii::DoFHandler<dim,spacedim>::active_cell_iterator cell; - std::vector<types::global_dof_index> parameter_dof_indices (coarse_fe.dofs_per_cell); - - for (cell=begin; cell!=end; ++cell) - { - // get the global indices of the parameter dofs on this - // parameter grid cell - cell->get_dof_indices (parameter_dof_indices); - - // loop over all dofs on this cell and check whether they are - // interesting for us - for (unsigned int local_dof=0; - local_dof<coarse_fe.dofs_per_cell; - ++local_dof) - if (coarse_fe.system_to_component_index(local_dof).first - == - coarse_component) - { - // the how-many-th parameter is this on this cell? - const unsigned int local_parameter_dof - = coarse_fe.system_to_component_index(local_dof).second; - - global_parameter_representation = 0; - - // distribute the representation of - // @p{local_parameter_dof} on the parameter grid cell - // @p{cell} to the global data space - coarse_to_fine_grid_map[cell]-> - set_dof_values_by_interpolation (parameter_dofs[local_parameter_dof], - global_parameter_representation); - // now that we've got the global representation of each - // parameter dof, we've only got to clobber the non-zero - // entries in that vector and store the result - // - // what we have learned: if entry @p{i} of the global - // vector holds the value @p{v[i]}, then this is the - // weight with which the present dof contributes to - // @p{i}. there may be several such @p{i}s and their - // weights' sum should be one. Then, @p{v[i]} should be - // equal to @p{\sum_j w_{ij} p[j]} with @p{p[j]} be the - // values of the degrees of freedom on the coarse grid. - // we can thus compute constraints which link the degrees - // of freedom @p{v[i]} on the fine grid to those on the - // coarse grid, @p{p[j]}. Now to use these as real - // constraints, rather than as additional equations, we - // have to identify representants among the @p{i} for - // each @p{j}. this will be done by simply taking the - // first @p{i} for which @p{w_{ij}==1}. - // - // guard modification of the weights array by a Mutex. - // since it should happen rather rarely that there are - // several threads operating on different intergrid - // weights, have only one mutex for all of them - static Threads::Mutex mutex; - Threads::Mutex::ScopedLock lock (mutex); - for (types::global_dof_index i=0; i<global_parameter_representation.size(); ++i) - // set this weight if it belongs to a parameter dof. - if (weight_mapping[i] != numbers::invalid_dof_index) - { - // only overwrite old value if not by zero - if (global_parameter_representation(i) != 0) - { - const types::global_dof_index wi = parameter_dof_indices[local_dof], - wj = weight_mapping[i]; - weights[wi][wj] = global_parameter_representation(i); - }; - } - else - Assert (global_parameter_representation(i) == 0, - ExcInternalError()); - } - } - } - - - /** - * This is a helper function that is used in the computation of - * integrid constraints. See the function for a thorough description - * of how it works. - */ - template <int dim, int spacedim> - void - compute_intergrid_weights_2 ( - const dealii::DoFHandler<dim,spacedim> &coarse_grid, - const unsigned int coarse_component, - const InterGridMap<dealii::DoFHandler<dim,spacedim> > &coarse_to_fine_grid_map, - const std::vector<dealii::Vector<double> > ¶meter_dofs, - const std::vector<types::global_dof_index> &weight_mapping, - std::vector<std::map<types::global_dof_index,float> > &weights) - { - // simply distribute the range of cells to different threads - typedef typename dealii::DoFHandler<dim,spacedim>::active_cell_iterator active_cell_iterator; - std::vector<std::pair<active_cell_iterator,active_cell_iterator> > - cell_intervals = Threads::split_range<active_cell_iterator> (coarse_grid.begin_active(), - coarse_grid.end(), - multithread_info.n_default_threads); - - // TODO: use WorkStream here - - Threads::TaskGroup<> tasks; - void (*fun_ptr) (const dealii::DoFHandler<dim,spacedim> &, - const unsigned int , - const InterGridMap<dealii::DoFHandler<dim,spacedim> > &, - const std::vector<dealii::Vector<double> > &, - const std::vector<types::global_dof_index> &, - std::vector<std::map<types::global_dof_index, float> > &, - const typename dealii::DoFHandler<dim,spacedim>::active_cell_iterator &, - const typename dealii::DoFHandler<dim,spacedim>::active_cell_iterator &) - = &compute_intergrid_weights_3<dim>; - for (unsigned int i=0; i<multithread_info.n_default_threads; ++i) - tasks += Threads::new_task (fun_ptr, - coarse_grid, coarse_component, - coarse_to_fine_grid_map, parameter_dofs, - weight_mapping, weights, - cell_intervals[i].first, - cell_intervals[i].second); - - // wait for the tasks to finish - tasks.join_all (); - } - - - - /** - * This is a helper function that is used in the computation of - * integrid constraints. See the function for a thorough description - * of how it works. - */ - template <int dim, int spacedim> - unsigned int - compute_intergrid_weights_1 ( - const dealii::DoFHandler<dim,spacedim> &coarse_grid, - const unsigned int coarse_component, - const dealii::DoFHandler<dim,spacedim> &fine_grid, - const unsigned int fine_component, - const InterGridMap<dealii::DoFHandler<dim,spacedim> > &coarse_to_fine_grid_map, - std::vector<std::map<types::global_dof_index, float> > &weights, - std::vector<types::global_dof_index> &weight_mapping) - { - // aliases to the finite elements used by the dof handlers: - const FiniteElement<dim,spacedim> &coarse_fe = coarse_grid.get_fe(), - &fine_fe = fine_grid.get_fe(); - - // global numbers of dofs - const types::global_dof_index n_coarse_dofs = coarse_grid.n_dofs(), - n_fine_dofs = fine_grid.n_dofs(); - - // local numbers of dofs - const unsigned int fine_dofs_per_cell = fine_fe.dofs_per_cell; - - // alias the number of dofs per cell belonging to the - // coarse_component which is to be the restriction of the fine - // grid: - const unsigned int coarse_dofs_per_cell_component - = coarse_fe.base_element(coarse_fe.component_to_base_index(coarse_component).first).dofs_per_cell; - - - // Try to find out whether the grids stem from the same coarse - // grid. This is a rather crude test, but better than nothing - Assert (coarse_grid.get_tria().n_cells(0) == fine_grid.get_tria().n_cells(0), - ExcGridsDontMatch()); - - // check whether the map correlates the right objects - Assert (&coarse_to_fine_grid_map.get_source_grid() == &coarse_grid, - ExcGridsDontMatch ()); - Assert (&coarse_to_fine_grid_map.get_destination_grid() == &fine_grid, - ExcGridsDontMatch ()); - - - // check whether component numbers are valid - AssertIndexRange (coarse_component,coarse_fe.n_components()); - AssertIndexRange (fine_component, fine_fe.n_components()); - - // check whether respective finite elements are equal - Assert (coarse_fe.base_element (coarse_fe.component_to_base_index(coarse_component).first) - == - fine_fe.base_element (fine_fe.component_to_base_index(fine_component).first), - ExcFiniteElementsDontMatch()); - -#ifdef DEBUG - // if in debug mode, check whether the coarse grid is indeed - // coarser everywhere than the fine grid - for (typename dealii::DoFHandler<dim,spacedim>::active_cell_iterator - cell=coarse_grid.begin_active(); - cell != coarse_grid.end(); ++cell) - Assert (cell->level() <= coarse_to_fine_grid_map[cell]->level(), - ExcGridNotCoarser()); -#endif - - /* - * From here on: the term `parameter' refers to the selected - * component on the coarse grid and its analogon on the fine grid. - * The naming of variables containing this term is due to the fact - * that `selected_component' is longer, but also due to the fact - * that the code of this function was initially written for a - * program where the component which we wanted to match between - * grids was actually the `parameter' variable. - * - * Likewise, the terms `parameter grid' and `state grid' refer to - * the coarse and fine grids, respectively. - * - * Changing the names of variables would in principle be a good - * idea, but would not make things simpler and would be another - * source of errors. If anyone feels like doing so: patches would - * be welcome! - */ - - - - // set up vectors of cell-local data; each vector represents one - // degree of freedom of the coarse-grid variable in the fine-grid - // element - std::vector<dealii::Vector<double> > - parameter_dofs (coarse_dofs_per_cell_component, - dealii::Vector<double>(fine_dofs_per_cell)); - // for each coarse dof: find its position within the fine element - // and set this value to one in the respective vector (all other - // values are zero by construction) - for (unsigned int local_coarse_dof=0; - local_coarse_dof<coarse_dofs_per_cell_component; - ++local_coarse_dof) - for (unsigned int fine_dof=0; fine_dof<fine_fe.dofs_per_cell; ++fine_dof) - if (fine_fe.system_to_component_index(fine_dof) - == - std::make_pair (fine_component, local_coarse_dof)) - { - parameter_dofs[local_coarse_dof](fine_dof) = 1.; - break; - }; - - - // find out how many DoFs there are on the grids belonging to the - // components we want to match - unsigned int n_parameters_on_fine_grid=0; - if (true) - { - // have a flag for each dof on the fine grid and set it to true - // if this is an interesting dof. finally count how many true's - // there - std::vector<bool> dof_is_interesting (fine_grid.n_dofs(), false); - std::vector<types::global_dof_index> local_dof_indices (fine_fe.dofs_per_cell); - - for (typename dealii::DoFHandler<dim,spacedim>::active_cell_iterator - cell=fine_grid.begin_active(); - cell!=fine_grid.end(); ++cell) - { - cell->get_dof_indices (local_dof_indices); - for (unsigned int i=0; i<fine_fe.dofs_per_cell; ++i) - if (fine_fe.system_to_component_index(i).first == fine_component) - dof_is_interesting[local_dof_indices[i]] = true; - }; - - n_parameters_on_fine_grid = std::count (dof_is_interesting.begin(), - dof_is_interesting.end(), - true); - }; - - - // set up the weights mapping - weights.clear (); - weights.resize (n_coarse_dofs); - - weight_mapping.clear (); - weight_mapping.resize (n_fine_dofs, numbers::invalid_dof_index); - - if (true) - { - std::vector<types::global_dof_index> local_dof_indices(fine_fe.dofs_per_cell); - unsigned int next_free_index=0; - for (typename dealii::DoFHandler<dim,spacedim>::active_cell_iterator - cell=fine_grid.begin_active(); - cell != fine_grid.end(); ++cell) - { - cell->get_dof_indices (local_dof_indices); - for (unsigned int i=0; i<fine_fe.dofs_per_cell; ++i) - // if this DoF is a parameter dof and has not yet been - // numbered, then do so - if ((fine_fe.system_to_component_index(i).first == fine_component) && - (weight_mapping[local_dof_indices[i]] == numbers::invalid_dof_index)) - { - weight_mapping[local_dof_indices[i]] = next_free_index; - ++next_free_index; - }; - }; - - Assert (next_free_index == n_parameters_on_fine_grid, - ExcInternalError()); - }; - - - // for each cell on the parameter grid: find out which degrees of - // freedom on the fine grid correspond in which way to the degrees - // of freedom on the parameter grid - // - // do this in a separate function to allow for multithreading - // there. see this function also if you want to read more - // information on the algorithm used. - compute_intergrid_weights_2 (coarse_grid, coarse_component, - coarse_to_fine_grid_map, parameter_dofs, - weight_mapping, weights); - - - // ok, now we have all weights for each dof on the fine grid. if in - // debug mode lets see if everything went smooth, i.e. each dof has - // sum of weights one - // - // in other words this means that if the sum of all shape functions - // on the parameter grid is one (which is always the case), then - // the representation on the state grid should be as well (division - // of unity) - // - // if the parameter grid has more than one component, then the - // respective dofs of the other components have sum of weights - // zero, of course. we do not explicitly ask which component a dof - // belongs to, but this at least tests some errors -#ifdef DEBUG - for (unsigned int col=0; col<n_parameters_on_fine_grid; ++col) - { - double sum=0; - for (types::global_dof_index row=0; row<n_coarse_dofs; ++row) - if (weights[row].find(col) != weights[row].end()) - sum += weights[row][col]; - Assert ((std::fabs(sum-1) < 1.e-12) || - ((coarse_fe.n_components()>1) && (sum==0)), ExcInternalError()); - }; -#endif - - - return n_parameters_on_fine_grid; - } - - - } - } - - - - template <int dim, int spacedim> - void - compute_intergrid_constraints ( - const DoFHandler<dim,spacedim> &coarse_grid, - const unsigned int coarse_component, - const DoFHandler<dim,spacedim> &fine_grid, - const unsigned int fine_component, - const InterGridMap<DoFHandler<dim,spacedim> > &coarse_to_fine_grid_map, - ConstraintMatrix &constraints) - { - // store the weights with which a dof on the parameter grid contributes - // to a dof on the fine grid. see the long doc below for more info - // - // allocate as many rows as there are parameter dofs on the coarse grid - // and as many columns as there are parameter dofs on the fine grid. - // - // weight_mapping is used to map the global (fine grid) parameter dof - // indices to the columns - // - // in the original implementation, the weights array was actually of - // FullMatrix<double> type. this wasted huge amounts of memory, but was - // fast. nonetheless, since the memory consumption was quadratic in the - // number of degrees of freedom, this was not very practical, so we now - // use a vector of rows of the matrix, and in each row a vector of - // pairs (colnum,value). this seems like the best tradeoff between - // memory and speed, as it is now linear in memory and still fast - // enough. - // - // to save some memory and since the weights are usually (negative) - // powers of 2, we choose the value type of the matrix to be @p{float} - // rather than @p{double}. - std::vector<std::map<types::global_dof_index, float> > weights; - - // this is this mapping. there is one entry for each dof on the fine - // grid; if it is a parameter dof, then its value is the column in - // weights for that parameter dof, if it is any other dof, then its - // value is -1, indicating an error - std::vector<types::global_dof_index> weight_mapping; - - const unsigned int n_parameters_on_fine_grid - = internal::compute_intergrid_weights_1 (coarse_grid, coarse_component, - fine_grid, fine_component, - coarse_to_fine_grid_map, - weights, weight_mapping); - - // global numbers of dofs - const types::global_dof_index n_coarse_dofs = coarse_grid.n_dofs(), - n_fine_dofs = fine_grid.n_dofs(); - - - // get an array in which we store which dof on the coarse grid is a - // parameter and which is not - std::vector<bool> coarse_dof_is_parameter (coarse_grid.n_dofs()); - if (true) - { - std::vector<bool> mask (coarse_grid.get_fe().n_components(), - false); - mask[coarse_component] = true; - extract_dofs (coarse_grid, ComponentMask(mask), coarse_dof_is_parameter); - } - - // now we know that the weights in each row constitute a constraint. - // enter this into the constraints object - // - // first task: for each parameter dof on the parameter grid, find a - // representant on the fine, global grid. this is possible since we use - // conforming finite element. we take this representant to be the first - // element in this row with weight identical to one. the representant - // will become an unconstrained degree of freedom, while all others - // will be constrained to this dof (and possibly others) - std::vector<types::global_dof_index> representants(n_coarse_dofs, numbers::invalid_dof_index); - for (types::global_dof_index parameter_dof=0; parameter_dof<n_coarse_dofs; - ++parameter_dof) - if (coarse_dof_is_parameter[parameter_dof] == true) - { - // if this is the line of a parameter dof on the coarse grid, - // then it should have at least one dependent node on the fine - // grid - Assert (weights[parameter_dof].size() > 0, ExcInternalError()); - - // find the column where the representant is mentioned - std::map<types::global_dof_index,float>::const_iterator i = weights[parameter_dof].begin(); - for (; i!=weights[parameter_dof].end(); ++i) - if (i->second == 1) - break; - Assert (i!=weights[parameter_dof].end(), ExcInternalError()); - const types::global_dof_index column = i->first; - - // now we know in which column of weights the representant is, - // but we don't know its global index. get it using the inverse - // operation of the weight_mapping - types::global_dof_index global_dof=0; - for (; global_dof<weight_mapping.size(); ++global_dof) - if (weight_mapping[global_dof] == static_cast<types::global_dof_index>(column)) - break; - Assert (global_dof < weight_mapping.size(), ExcInternalError()); - - // now enter the representants global index into our list - representants[parameter_dof] = global_dof; - } - else - { - // consistency check: if this is no parameter dof on the coarse - // grid, then the respective row must be empty! - Assert (weights[parameter_dof].size() == 0, ExcInternalError()); - }; - - - - // note for people that want to optimize this function: the largest - // part of the computing time is spent in the following, rather - // innocent block of code. basically, it must be the - // ConstraintMatrix::add_entry call which takes the bulk of the time, - // but it is not known to the author how to make it faster... - std::vector<std::pair<types::global_dof_index,double> > constraint_line; - for (types::global_dof_index global_dof=0; global_dof<n_fine_dofs; ++global_dof) - if (weight_mapping[global_dof] != numbers::invalid_dof_index) - // this global dof is a parameter dof, so it may carry a constraint - // note that for each global dof, the sum of weights shall be one, - // so we can find out whether this dof is constrained in the - // following way: if the only weight in this row is a one, and the - // representant for the parameter dof of the line in which this one - // is is the present dof, then we consider this dof to be - // unconstrained. otherwise, all other dofs are constrained - { - const types::global_dof_index col = weight_mapping[global_dof]; - Assert (col < n_parameters_on_fine_grid, ExcInternalError()); - - types::global_dof_index first_used_row=0; - - { - Assert (weights.size() > 0, ExcInternalError()); - std::map<types::global_dof_index,float>::const_iterator - col_entry = weights[0].end(); - for (; first_used_row<n_coarse_dofs; ++first_used_row) - { - col_entry = weights[first_used_row].find(col); - if (col_entry != weights[first_used_row].end()) - break; - } - - Assert (col_entry != weights[first_used_row].end(), ExcInternalError()); - - if ((col_entry->second == 1) && - (representants[first_used_row] == global_dof)) - // dof unconstrained or constrained to itself (in case this - // cell is mapped to itself, rather than to children of - // itself) - continue; - } - - - // otherwise enter all constraints - constraints.add_line (global_dof); - - constraint_line.clear (); - for (types::global_dof_index row=first_used_row; row<n_coarse_dofs; ++row) - { - const std::map<types::global_dof_index,float>::const_iterator - j = weights[row].find(col); - if ((j != weights[row].end()) && (j->second != 0)) - constraint_line.push_back (std::pair<types::global_dof_index,double>(representants[row], - j->second)); - }; - - constraints.add_entries (global_dof, constraint_line); - }; - } - - - - template <int dim, int spacedim> - void - compute_intergrid_transfer_representation ( - const DoFHandler<dim,spacedim> &coarse_grid, - const unsigned int coarse_component, - const DoFHandler<dim,spacedim> &fine_grid, - const unsigned int fine_component, - const InterGridMap<DoFHandler<dim,spacedim> > &coarse_to_fine_grid_map, - std::vector<std::map<types::global_dof_index, float> > &transfer_representation) - { - // store the weights with which a dof on the parameter grid contributes - // to a dof on the fine grid. see the long doc below for more info - // - // allocate as many rows as there are parameter dofs on the coarse grid - // and as many columns as there are parameter dofs on the fine grid. - // - // weight_mapping is used to map the global (fine grid) parameter dof - // indices to the columns - // - // in the original implementation, the weights array was actually of - // FullMatrix<double> type. this wasted huge amounts of memory, but was - // fast. nonetheless, since the memory consumption was quadratic in the - // number of degrees of freedom, this was not very practical, so we now - // use a vector of rows of the matrix, and in each row a vector of - // pairs (colnum,value). this seems like the best tradeoff between - // memory and speed, as it is now linear in memory and still fast - // enough. - // - // to save some memory and since the weights are usually (negative) - // powers of 2, we choose the value type of the matrix to be @p{float} - // rather than @p{double}. - std::vector<std::map<types::global_dof_index, float> > weights; - - // this is this mapping. there is one entry for each dof on the fine - // grid; if it is a parameter dof, then its value is the column in - // weights for that parameter dof, if it is any other dof, then its - // value is -1, indicating an error - std::vector<types::global_dof_index> weight_mapping; - - internal::compute_intergrid_weights_1 (coarse_grid, coarse_component, - fine_grid, fine_component, - coarse_to_fine_grid_map, - weights, weight_mapping); - - // now compute the requested representation - const types::global_dof_index n_global_parm_dofs - = std::count_if (weight_mapping.begin(), weight_mapping.end(), - std::bind2nd (std::not_equal_to<types::global_dof_index> (), numbers::invalid_dof_index)); - - // first construct the inverse mapping of weight_mapping - std::vector<types::global_dof_index> inverse_weight_mapping (n_global_parm_dofs, - DoFHandler<dim,spacedim>::invalid_dof_index); - for (types::global_dof_index i=0; i<weight_mapping.size(); ++i) - { - const types::global_dof_index parameter_dof = weight_mapping[i]; - // if this global dof is a parameter - if (parameter_dof != numbers::invalid_dof_index) - { - Assert (parameter_dof < n_global_parm_dofs, ExcInternalError()); - Assert ((inverse_weight_mapping[parameter_dof] == DoFHandler<dim,spacedim>::invalid_dof_index), - ExcInternalError()); - - inverse_weight_mapping[parameter_dof] = i; - }; - }; - - // next copy over weights array and replace respective numbers - const types::global_dof_index n_rows = weight_mapping.size(); - - transfer_representation.clear (); - transfer_representation.resize (n_rows); - - const types::global_dof_index n_coarse_dofs = coarse_grid.n_dofs(); - for (types::global_dof_index i=0; i<n_coarse_dofs; ++i) - { - std::map<types::global_dof_index, float>::const_iterator j = weights[i].begin(); - for (; j!=weights[i].end(); ++j) - { - const types::global_dof_index p = inverse_weight_mapping[j->first]; - Assert (p<n_rows, ExcInternalError()); - - transfer_representation[p][i] = j->second; - }; - }; - } - - - template <class DH> void map_dof_to_boundary_indices (const DH &dof_handler, @@ -5689,87 +1811,6 @@ namespace DoFTools - template <int dim, int spacedim, template <int,int> class DH> - void - make_zero_boundary_constraints (const DH<dim, spacedim> &dof, - const types::boundary_id boundary_indicator, - ConstraintMatrix &zero_boundary_constraints, - const ComponentMask &component_mask) - { - Assert (component_mask.represents_n_components(dof.get_fe().n_components()), - ExcMessage ("The number of components in the mask has to be either " - "zero or equal to the number of components in the finite " - "element.")); - - const unsigned int n_components = DoFTools::n_components (dof); - - Assert (component_mask.n_selected_components(n_components) > 0, - VectorTools::ExcNoComponentSelected()); - - // a field to store the indices - std::vector<types::global_dof_index> face_dofs; - face_dofs.reserve (max_dofs_per_face(dof)); - - typename DH<dim,spacedim>::active_cell_iterator - cell = dof.begin_active(), - endc = dof.end(); - for (; cell!=endc; ++cell) - if (!cell->is_artificial()) - for (unsigned int face_no = 0; face_no < GeometryInfo<dim>::faces_per_cell; - ++face_no) - { - const FiniteElement<dim,spacedim> &fe = cell->get_fe(); - - const typename DH<dim,spacedim>::face_iterator face = cell->face(face_no); - - // if face is on the boundary and satisfies the correct - // boundary id property - if (face->at_boundary () - && - ((boundary_indicator == numbers::invalid_boundary_id) - || - (face->boundary_indicator() == boundary_indicator))) - { - // get indices and physical location on this face - face_dofs.resize (fe.dofs_per_face); - face->get_dof_indices (face_dofs, cell->active_fe_index()); - - // enter those dofs into the list that match the component - // signature. - for (unsigned int i=0; i<face_dofs.size(); ++i) - { - // Find out if a dof has a contribution in this - // component, and if so, add it to the list - const ComponentMask &nonzero_component_array - = cell->get_fe().get_nonzero_components (i); - bool nonzero = false; - for (unsigned int c=0; c<n_components; ++c) - if (nonzero_component_array[c] && component_mask[c]) - { - nonzero = true; - break; - } - - if (nonzero) - zero_boundary_constraints.add_line (face_dofs[i]); - } - } - } - } - - - - template <int dim, int spacedim, template <int,int> class DH> - void - make_zero_boundary_constraints (const DH<dim, spacedim> &dof, - ConstraintMatrix &zero_boundary_constraints, - const ComponentMask &component_mask) - { - make_zero_boundary_constraints(dof, numbers::invalid_boundary_id, - zero_boundary_constraints, component_mask); - } - - template <class DH, class Sparsity> void make_cell_patches( Sparsity &block_list, @@ -6029,7 +2070,9 @@ namespace DoFTools } } } -} + + +} // end of namespace DoFTools diff --git a/deal.II/source/dofs/dof_tools.inst.in b/deal.II/source/dofs/dof_tools.inst.in index 17d1beaa6c..f4121a9d63 100644 --- a/deal.II/source/dofs/dof_tools.inst.in +++ b/deal.II/source/dofs/dof_tools.inst.in @@ -15,394 +15,21 @@ // --------------------------------------------------------------------- - for (SP : SPARSITY_PATTERNS; deal_II_dimension : DIMENSIONS) { - template void - DoFTools::make_sparsity_pattern<DoFHandler<deal_II_dimension,deal_II_dimension>, SP> - (const DoFHandler<deal_II_dimension,deal_II_dimension> &dof, - SP &sparsity, - const ConstraintMatrix &, - const bool, - const unsigned int); - - template void - DoFTools::make_sparsity_pattern<hp::DoFHandler<deal_II_dimension,deal_II_dimension>, SP> - (const hp::DoFHandler<deal_II_dimension,deal_II_dimension> &dof, - SP &sparsity, - const ConstraintMatrix &, - const bool, - const unsigned int); - - template void - DoFTools::make_sparsity_pattern<MGDoFHandler<deal_II_dimension,deal_II_dimension>, SP> - (const MGDoFHandler<deal_II_dimension,deal_II_dimension> &dof, - SP &sparsity, - const ConstraintMatrix &, - const bool, - const unsigned int); - - template void - DoFTools::make_sparsity_pattern<DoFHandler<deal_II_dimension,deal_II_dimension>, SP> - (const DoFHandler<deal_II_dimension,deal_II_dimension>&, - const Table<2,Coupling>&, - SP &, - const ConstraintMatrix &, - const bool, - const unsigned int); - - template void - DoFTools::make_sparsity_pattern<hp::DoFHandler<deal_II_dimension,deal_II_dimension>, SP> - (const hp::DoFHandler<deal_II_dimension,deal_II_dimension>&, - const Table<2,Coupling>&, - SP &, - const ConstraintMatrix &, - const bool, - const unsigned int); - - template void - DoFTools::make_sparsity_pattern<MGDoFHandler<deal_II_dimension,deal_II_dimension>, SP> - (const MGDoFHandler<deal_II_dimension,deal_II_dimension>&, - const Table<2,Coupling>&, - SP &, - const ConstraintMatrix &, - const bool, - const unsigned int); - - template void - DoFTools::make_sparsity_pattern<DoFHandler<deal_II_dimension,deal_II_dimension>, SP> - (const DoFHandler<deal_II_dimension,deal_II_dimension> &dof_row, - const DoFHandler<deal_II_dimension,deal_II_dimension> &dof_col, - SP &sparsity); - - template void - DoFTools::make_sparsity_pattern<hp::DoFHandler<deal_II_dimension,deal_II_dimension>, SP> - (const hp::DoFHandler<deal_II_dimension,deal_II_dimension> &dof_row, - const hp::DoFHandler<deal_II_dimension,deal_II_dimension> &dof_col, - SP &sparsity); - - template void - DoFTools::make_boundary_sparsity_pattern<DoFHandler<deal_II_dimension>,SP> - (const DoFHandler<deal_II_dimension>& dof, - const std::vector<types::global_dof_index> &, - SP &); - - template void - DoFTools::make_boundary_sparsity_pattern<hp::DoFHandler<deal_II_dimension>,SP> - (const hp::DoFHandler<deal_II_dimension>& dof, - const std::vector<types::global_dof_index> &, - SP &); - - template void - DoFTools::make_boundary_sparsity_pattern<DoFHandler<deal_II_dimension>,SP> - (const DoFHandler<deal_II_dimension>& dof, - const FunctionMap<deal_II_dimension>::type &boundary_indicators, - const std::vector<types::global_dof_index> &dof_to_boundary_mapping, - SP &sparsity); - - template void - DoFTools::make_boundary_sparsity_pattern<hp::DoFHandler<deal_II_dimension>,SP> - (const hp::DoFHandler<deal_II_dimension>& dof, - const FunctionMap<deal_II_dimension>::type &boundary_indicators, - const std::vector<types::global_dof_index> &dof_to_boundary_mapping, - SP &sparsity); - -#if deal_II_dimension < 3 - template void - DoFTools::make_boundary_sparsity_pattern<hp::DoFHandler<deal_II_dimension,deal_II_dimension+1>,SP> - (const hp::DoFHandler<deal_II_dimension,deal_II_dimension+1>& dof, - const FunctionMap<deal_II_dimension+1>::type &boundary_indicators, - const std::vector<types::global_dof_index> &dof_to_boundary_mapping, - SP &sparsity); - #endif - - template void - DoFTools::make_flux_sparsity_pattern<DoFHandler<deal_II_dimension>,SP> - (const DoFHandler<deal_II_dimension> &dof, - SP &sparsity); - - template void - DoFTools::make_flux_sparsity_pattern<hp::DoFHandler<deal_II_dimension>,SP> - (const hp::DoFHandler<deal_II_dimension> &dof, - SP &sparsity); - - template void - DoFTools::make_cell_patches<DoFHandler<deal_II_dimension>,SP> - (SP&, const DoFHandler<deal_II_dimension>&, const unsigned int, const std::vector<bool>&, types::global_dof_index); - - template void - DoFTools::make_cell_patches<MGDoFHandler<deal_II_dimension>,SP> - (SP&, const MGDoFHandler<deal_II_dimension>&, const unsigned int, const std::vector<bool>&, types::global_dof_index); - -#if deal_II_dimension > 1 - - template void - DoFTools::make_flux_sparsity_pattern<DoFHandler<deal_II_dimension>,SP> - (const DoFHandler<deal_II_dimension> &dof, - SP &, - const Table<2,Coupling>&, - const Table<2,Coupling>&); - - template void - DoFTools::make_flux_sparsity_pattern<DoFHandler<deal_II_dimension>,SP> - (const DoFHandler<deal_II_dimension> &dof, - SP &sparsity, - const ConstraintMatrix &constraints, - const bool, const unsigned int); - - template void - DoFTools::make_flux_sparsity_pattern<hp::DoFHandler<deal_II_dimension>,SP> - (const hp::DoFHandler<deal_II_dimension> &dof, - SP &sparsity, - const ConstraintMatrix &constraints, - const bool, const unsigned int); - - template void - DoFTools::make_flux_sparsity_pattern<hp::DoFHandler<deal_II_dimension>,SP> - (const hp::DoFHandler<deal_II_dimension> &dof, - SP &, - const Table<2,Coupling>&, - const Table<2,Coupling>&); -#endif - -#if deal_II_dimension < 3 - - template void - DoFTools::make_sparsity_pattern<DoFHandler<deal_II_dimension,deal_II_dimension+1>, SP> - (const DoFHandler<deal_II_dimension,deal_II_dimension+1> &dof, - SP &sparsity, - const ConstraintMatrix &, - const bool, - const unsigned int); - - template void - DoFTools::make_sparsity_pattern<hp::DoFHandler<deal_II_dimension,deal_II_dimension+1>, SP> - (const hp::DoFHandler<deal_II_dimension,deal_II_dimension+1> &dof, - SP &sparsity, - const ConstraintMatrix &, - const bool, - const unsigned int); - - template void - DoFTools::make_sparsity_pattern<DoFHandler<deal_II_dimension,deal_II_dimension+1>, SP> - (const DoFHandler<deal_II_dimension,deal_II_dimension+1>&, - const Table<2,Coupling>&, - SP &, - const ConstraintMatrix &, - const bool, - const unsigned int); - - template void - DoFTools::make_sparsity_pattern<hp::DoFHandler<deal_II_dimension,deal_II_dimension+1>, SP> - (const hp::DoFHandler<deal_II_dimension,deal_II_dimension+1>&, - const Table<2,Coupling>&, - SP &, - const ConstraintMatrix &, - const bool, - const unsigned int); - - template void - DoFTools::make_sparsity_pattern<DoFHandler<deal_II_dimension,deal_II_dimension+1>, SP> - (const DoFHandler<deal_II_dimension,deal_II_dimension+1> &dof_row, - const DoFHandler<deal_II_dimension,deal_II_dimension+1> &dof_col, - SP &sparsity); - - template void - DoFTools::make_sparsity_pattern<hp::DoFHandler<deal_II_dimension,deal_II_dimension+1>, SP> - (const hp::DoFHandler<deal_II_dimension,deal_II_dimension+1> &dof_row, - const hp::DoFHandler<deal_II_dimension,deal_II_dimension+1> &dof_col, - SP &sparsity); - - template void - DoFTools::make_boundary_sparsity_pattern<DoFHandler<deal_II_dimension,deal_II_dimension+1>,SP> - (const DoFHandler<deal_II_dimension,deal_II_dimension+1>& dof, - const std::vector<types::global_dof_index> &, - SP &); - - //template void - //DoFTools::make_boundary_sparsity_pattern<hp::DoFHandler<deal_II_dimension,deal_II_dimension+1>,SP> - //(const hp::DoFHandler<deal_II_dimension,deal_II_dimension+1>& dof, - // const std::vector<types::global_dof_index> &, - // SP &); - - template void - DoFTools::make_boundary_sparsity_pattern<DoFHandler<deal_II_dimension,deal_II_dimension+1>,SP> - (const DoFHandler<deal_II_dimension,deal_II_dimension+1>& dof, - const FunctionMap<deal_II_dimension+1>::type &boundary_indicators, - const std::vector<types::global_dof_index> &dof_to_boundary_mapping, - SP &sparsity); - - //template void - //DoFTools::make_boundary_sparsity_pattern<hp::DoFHandler<deal_II_dimension,deal_II_dimension+1>,SP> - //(const hp::DoFHandler<deal_II_dimension,deal_II_dimension+1>& dof, - // const FunctionMap<deal_II_dimension+1>::type &boundary_indicators, - // const std::vector<types::global_dof_index> &dof_to_boundary_mapping, - // SP &sparsity); - -#endif - - -#if deal_II_dimension == 3 - - template void - DoFTools::make_sparsity_pattern<DoFHandler<1,3>, SP> - (const DoFHandler<1,3> &dof, - SP &sparsity, - const ConstraintMatrix &, - const bool, - const unsigned int); - - template void - DoFTools::make_sparsity_pattern<hp::DoFHandler<1,3>, SP> - (const hp::DoFHandler<1,3> &dof, - SP &sparsity, - const ConstraintMatrix &, - const bool, - const unsigned int); - - template void - DoFTools::make_sparsity_pattern<DoFHandler<1,3>, SP> - (const DoFHandler<1,3>&, - const Table<2,Coupling>&, - SP &, - const ConstraintMatrix &, - const bool, - const unsigned int); - - template void - DoFTools::make_sparsity_pattern<hp::DoFHandler<1,3>, SP> - (const hp::DoFHandler<1,3>&, - const Table<2,Coupling>&, - SP &, - const ConstraintMatrix &, - const bool, - const unsigned int); - - template void - DoFTools::make_sparsity_pattern<DoFHandler<1,3>, SP> - (const DoFHandler<1,3> &dof_row, - const DoFHandler<1,3> &dof_col, - SP &sparsity); - - template void - DoFTools::make_sparsity_pattern<hp::DoFHandler<1,3>, SP> - (const hp::DoFHandler<1,3> &dof_row, - const hp::DoFHandler<1,3> &dof_col, - SP &sparsity); - - template void - DoFTools::make_boundary_sparsity_pattern<DoFHandler<1,3>,SP> - (const DoFHandler<1,3>& dof, - const std::vector<types::global_dof_index> &, - SP &); - - template void - DoFTools::make_boundary_sparsity_pattern<hp::DoFHandler<1,3>,SP> - (const hp::DoFHandler<1,3>& dof, - const std::vector<types::global_dof_index> &, - SP &); - - template void - DoFTools::make_boundary_sparsity_pattern<DoFHandler<1,3>,SP> - (const DoFHandler<1,3>& dof, - const FunctionMap<3>::type &boundary_indicators, - const std::vector<types::global_dof_index> &dof_to_boundary_mapping, - SP &sparsity); - - template void - DoFTools::make_boundary_sparsity_pattern<hp::DoFHandler<1,3>,SP> - (const hp::DoFHandler<1,3>& dof, - const FunctionMap<3>::type &boundary_indicators, - const std::vector<types::global_dof_index> &dof_to_boundary_mapping, - SP &sparsity); - -#endif - - } - + template void + DoFTools::make_cell_patches<DoFHandler<deal_II_dimension>,SP> + (SP&, const DoFHandler<deal_II_dimension>&, const unsigned int, const std::vector<bool>&, types::global_dof_index); - - -for (DH : DOFHANDLERS; deal_II_dimension : DIMENSIONS) -{ - template - void - DoFTools::make_hanging_node_constraints (const DH &dof_handler, - ConstraintMatrix &constraints); -} - - - -for (DH : DOFHANDLERS; deal_II_dimension : DIMENSIONS) -{ - -#if deal_II_dimension != 1 - template - void - DoFTools::make_periodicity_constraints (const DH::face_iterator &, - const DH::face_iterator &, - dealii::ConstraintMatrix &, - const ComponentMask &, - bool, bool, bool); - - template - void - DoFTools::make_periodicity_constraints(const DH &, - const types::boundary_id, - const types::boundary_id, - const int, - dealii::ConstraintMatrix &, - const ComponentMask &); - - template - void - DoFTools::make_periodicity_constraints(const DH &, - const types::boundary_id, - const types::boundary_id, - const int, - dealii::Tensor<1,DH::space_dimension> &, - dealii::ConstraintMatrix &, - const ComponentMask &); - - template - void - DoFTools::make_periodicity_constraints(const DH &, - const types::boundary_id, - const int, - dealii::ConstraintMatrix &, - const ComponentMask &); - - template - void - DoFTools::make_periodicity_constraints(const DH &, - const types::boundary_id, - const int, - dealii::Tensor<1,DH::space_dimension> &, - dealii::ConstraintMatrix &, - const ComponentMask &); -#endif + template void + DoFTools::make_cell_patches<MGDoFHandler<deal_II_dimension>,SP> + (SP&, const MGDoFHandler<deal_II_dimension>&, const unsigned int, const std::vector<bool>&, types::global_dof_index); } -for (deal_II_dimension : DIMENSIONS) -{ -#if deal_II_dimension != 1 - template - void - DoFTools::make_hanging_node_constraints (const MGDoFHandler<deal_II_dimension> &dof_handler, - ConstraintMatrix &constraints); - -#endif - } for (deal_II_dimension : DIMENSIONS) { - template - Table<2,DoFTools::Coupling> - DoFTools::dof_couplings_from_component_couplings - (const FiniteElement<deal_II_dimension> &fe, - const Table<2,DoFTools::Coupling> &component_couplings); - template void DoFTools::make_vertex_patches (SparsityPattern&, const DoFHandler<deal_II_dimension>&, unsigned int, bool, bool, bool, bool); @@ -427,22 +54,6 @@ for (deal_II_dimension : DIMENSIONS) void DoFTools::make_child_patches(SparsityPattern&, const MGDoFHandler<deal_II_dimension>&, unsigned int, bool, bool); -#if deal_II_dimension < 3 -template -void -DoFTools:: -make_hanging_node_constraints (const DoFHandler<deal_II_dimension,deal_II_dimension+1> &dof_handler, - ConstraintMatrix &constraints); -#endif - -#if deal_II_dimension == 3 -template -void -DoFTools:: -make_hanging_node_constraints (const DoFHandler<1,3> &dof_handler, - ConstraintMatrix &constraints); -#endif - // TODO: can cleanup a bit more to fit into the scheme used above @@ -912,23 +523,6 @@ DoFTools::count_dofs_per_component<deal_II_dimension> ( const DoFHandler<deal_II_dimension>&, std::vector<types::global_dof_index>&, std::vector<unsigned int>); -template -void -DoFTools::compute_intergrid_constraints<deal_II_dimension> ( - const DoFHandler<deal_II_dimension> &, const unsigned int, - const DoFHandler<deal_II_dimension> &, const unsigned int, - const InterGridMap<DoFHandler<deal_II_dimension> > &, - ConstraintMatrix&); - -template -void -DoFTools::compute_intergrid_transfer_representation<deal_II_dimension> -(const DoFHandler<deal_II_dimension> &, const unsigned int, - const DoFHandler<deal_II_dimension> &, const unsigned int, - const InterGridMap<DoFHandler<deal_II_dimension> > &, - std::vector<std::map<types::global_dof_index, float> > &); - - template void DoFTools::map_dof_to_boundary_indices<DoFHandler<deal_II_dimension> > @@ -1089,36 +683,6 @@ DoFTools::convert_couplings_to_blocks ( const hp::DoFHandler<deal_II_dimension>&, const Table<2, Coupling>&, std::vector<Table<2,Coupling> >&); -template -void -DoFTools::make_zero_boundary_constraints -(const DoFHandler<deal_II_dimension> &, - ConstraintMatrix &, - const ComponentMask &); - -template -void -DoFTools::make_zero_boundary_constraints -(const DoFHandler<deal_II_dimension> &, - const types::boundary_id , - ConstraintMatrix &, - const ComponentMask &); - -template -void -DoFTools::make_zero_boundary_constraints -(const hp::DoFHandler<deal_II_dimension> &, - ConstraintMatrix &, - const ComponentMask &); - -template -void -DoFTools::make_zero_boundary_constraints -(const hp::DoFHandler<deal_II_dimension> &, - const types::boundary_id , - ConstraintMatrix &, - const ComponentMask &); - #if deal_II_dimension < 3 diff --git a/deal.II/source/dofs/dof_tools_constraints.cc b/deal.II/source/dofs/dof_tools_constraints.cc new file mode 100644 index 0000000000..6e21770c30 --- /dev/null +++ b/deal.II/source/dofs/dof_tools_constraints.cc @@ -0,0 +1,2891 @@ +// --------------------------------------------------------------------- +// $Id$ +// +// Copyright (C) 1999 - 2013 by the deal.II authors +// +// This file is part of the deal.II library. +// +// The deal.II library is free software; you can use it, redistribute +// it, and/or modify it under the terms of the GNU Lesser General +// Public License as published by the Free Software Foundation; either +// version 2.1 of the License, or (at your option) any later version. +// The full text of the license can be found in the file LICENSE at +// the top level of the deal.II distribution. +// +// --------------------------------------------------------------------- + +#include <deal.II/base/multithread_info.h> +#include <deal.II/base/thread_management.h> +#include <deal.II/base/table.h> +#include <deal.II/base/template_constraints.h> +#include <deal.II/base/utilities.h> +#include <deal.II/lac/vector.h> +#include <deal.II/lac/constraint_matrix.h> +#include <deal.II/grid/tria.h> +#include <deal.II/grid/tria_iterator.h> +#include <deal.II/grid/intergrid_map.h> +#include <deal.II/grid/grid_tools.h> +#include <deal.II/dofs/dof_handler.h> +#include <deal.II/dofs/dof_accessor.h> +#include <deal.II/fe/fe.h> +#include <deal.II/fe/fe_values.h> +#include <deal.II/fe/fe_tools.h> +#include <deal.II/hp/fe_collection.h> +#include <deal.II/hp/fe_values.h> +#include <deal.II/dofs/dof_tools.h> + +#include <deal.II/multigrid/mg_dof_handler.h> + +#include <algorithm> +#include <numeric> + +DEAL_II_NAMESPACE_OPEN + + + +namespace DoFTools +{ + namespace internal + { + namespace + { + inline bool + check_master_dof_list (const FullMatrix<double> &face_interpolation_matrix, + const std::vector<types::global_dof_index> &master_dof_list) + { + const unsigned int N = master_dof_list.size(); + + FullMatrix<double> tmp (N,N); + for (unsigned int i=0; i<N; ++i) + for (unsigned int j=0; j<N; ++j) + tmp(i,j) = face_interpolation_matrix (master_dof_list[i], j); + + // then use the algorithm from FullMatrix::gauss_jordan on this + // matrix to find out whether it is singular. the algorithm there + // does piviting and at the end swaps rows back into their proper + // order -- we omit this step here, since we don't care about the + // inverse matrix, all we care about is whether the matrix is + // regular or singular + + // first get an estimate of the size of the elements of this + // matrix, for later checks whether the pivot element is large + // enough, or whether we have to fear that the matrix is not + // regular + double diagonal_sum = 0; + for (unsigned int i=0; i<N; ++i) + diagonal_sum += std::fabs(tmp(i,i)); + const double typical_diagonal_element = diagonal_sum/N; + + // initialize the array that holds the permutations that we find + // during pivot search + std::vector<unsigned int> p(N); + for (unsigned int i=0; i<N; ++i) + p[i] = i; + + for (unsigned int j=0; j<N; ++j) + { + // pivot search: search that part of the line on and right of + // the diagonal for the largest element + double max = std::fabs(tmp(j,j)); + unsigned int r = j; + for (unsigned int i=j+1; i<N; ++i) + { + if (std::fabs(tmp(i,j)) > max) + { + max = std::fabs(tmp(i,j)); + r = i; + } + } + // check whether the pivot is too small. if that is the case, + // then the matrix is singular and we shouldn't use this set of + // master dofs + if (max < 1.e-12*typical_diagonal_element) + return false; + + // row interchange + if (r>j) + { + for (unsigned int k=0; k<N; ++k) + std::swap (tmp(j,k), tmp(r,k)); + + std::swap (p[j], p[r]); + } + + // transformation + const double hr = 1./tmp(j,j); + tmp(j,j) = hr; + for (unsigned int k=0; k<N; ++k) + { + if (k==j) continue; + for (unsigned int i=0; i<N; ++i) + { + if (i==j) continue; + tmp(i,k) -= tmp(i,j)*tmp(j,k)*hr; + } + } + for (unsigned int i=0; i<N; ++i) + { + tmp(i,j) *= hr; + tmp(j,i) *= -hr; + } + tmp(j,j) = hr; + } + + // everything went fine, so we can accept this set of master dofs + // (at least as far as they have already been collected) + return true; + } + + + + /** + * When restricting, on a face, the degrees of freedom of fe1 to the + * space described by fe2 (for example for the complex case described + * in the @ref hp_paper "hp paper"), we have to select + * fe2.dofs_per_face out of the fe1.dofs_per_face face DoFs as the + * master DoFs, and the rest become slave dofs. This function selects + * which ones will be masters, and which ones will be slaves. + * + * The function assumes that master_dofs already has size + * fe1.dofs_per_face. After the function, exactly fe2.dofs_per_face + * entries will be true. + * + * The function is a bit complicated since it has to figure out a set + * a DoFs so that the corresponding rows in the face interpolation + * matrix are all linearly independent. we have a good heuristic (see + * the function body) for selecting these rows, but there are cases + * where this fails and we have to pick them differently. what we do + * is to run the heuristic and then go back to determine whether we + * have a set of rows with full row rank. if this isn't the case, go + * back and select dofs differently + */ + template <int dim, int spacedim> + void + select_master_dofs_for_face_restriction (const FiniteElement<dim,spacedim> &fe1, + const FiniteElement<dim,spacedim> &fe2, + const FullMatrix<double> &face_interpolation_matrix, + std::vector<bool> &master_dof_mask) + { + Assert (fe1.dofs_per_face >= fe2.dofs_per_face, + ExcInternalError()); + AssertDimension (master_dof_mask.size(), fe1.dofs_per_face); + + Assert (fe2.dofs_per_vertex <= fe1.dofs_per_vertex, + ExcInternalError()); + Assert (fe2.dofs_per_line <= fe1.dofs_per_line, + ExcInternalError()); + Assert ((dim < 3) + || + (fe2.dofs_per_quad <= fe1.dofs_per_quad), + ExcInternalError()); + + // the idea here is to designate as many DoFs in fe1 per object + // (vertex, line, quad) as master as there are such dofs in fe2 + // (indices are int, because we want to avoid the 'unsigned int < 0 + // is always false warning for the cases at the bottom in 1d and + // 2d) + // + // as mentioned in the paper, it is not always easy to find a set + // of master dofs that produces an invertible matrix. to this end, + // we check in each step whether the matrix is still invertible and + // simply discard this dof if the matrix is not invertible anymore. + // + // the cases where we did have trouble in the past were with adding + // more quad dofs when Q3 and Q4 elements meet at a refined face in + // 3d (see the hp/crash_12 test that tests that we can do exactly + // this, and failed before we had code to compensate for this + // case). the other case are system elements: if we have say a Q1Q2 + // vs a Q2Q3 element, then we can't just take all master dofs on a + // line from a single base element, since the shape functions of + // that base element are independent of that of the other one. this + // latter case shows up when running hp/hp_constraints_q_system_06 + + std::vector<types::global_dof_index> master_dof_list; + unsigned int index = 0; + for (int v=0; + v<static_cast<signed int>(GeometryInfo<dim>::vertices_per_face); + ++v) + { + unsigned int dofs_added = 0; + unsigned int i = 0; + while (dofs_added < fe2.dofs_per_vertex) + { + // make sure that we were able to find a set of master dofs + // and that the code down below didn't just reject all our + // efforts + Assert (i < fe1.dofs_per_vertex, + ExcInternalError()); + + // tentatively push this vertex dof + master_dof_list.push_back (index+i); + + // then see what happens. if it succeeds, fine + if (check_master_dof_list (face_interpolation_matrix, + master_dof_list) + == true) + ++dofs_added; + else + // well, it didn't. simply pop that dof from the list + // again and try with the next dof + master_dof_list.pop_back (); + + // forward counter by one + ++i; + } + index += fe1.dofs_per_vertex; + } + + for (int l=0; + l<static_cast<signed int>(GeometryInfo<dim>::lines_per_face); + ++l) + { + // same algorithm as above + unsigned int dofs_added = 0; + unsigned int i = 0; + while (dofs_added < fe2.dofs_per_line) + { + Assert (i < fe1.dofs_per_line, + ExcInternalError()); + + master_dof_list.push_back (index+i); + if (check_master_dof_list (face_interpolation_matrix, + master_dof_list) + == true) + ++dofs_added; + else + master_dof_list.pop_back (); + + ++i; + } + index += fe1.dofs_per_line; + } + + for (int q=0; + q<static_cast<signed int>(GeometryInfo<dim>::quads_per_face); + ++q) + { + // same algorithm as above + unsigned int dofs_added = 0; + unsigned int i = 0; + while (dofs_added < fe2.dofs_per_quad) + { + Assert (i < fe1.dofs_per_quad, + ExcInternalError()); + + master_dof_list.push_back (index+i); + if (check_master_dof_list (face_interpolation_matrix, + master_dof_list) + == true) + ++dofs_added; + else + master_dof_list.pop_back (); + + ++i; + } + index += fe1.dofs_per_quad; + } + + AssertDimension (index, fe1.dofs_per_face); + AssertDimension (master_dof_list.size(), fe2.dofs_per_face); + + // finally copy the list into the mask + std::fill (master_dof_mask.begin(), master_dof_mask.end(), false); + for (std::vector<types::global_dof_index>::const_iterator i=master_dof_list.begin(); + i!=master_dof_list.end(); ++i) + master_dof_mask[*i] = true; + } + + + + /** + * Make sure that the mask exists that determines which dofs will be + * the masters on refined faces where an fe1 and a fe2 meet. + */ + template <int dim, int spacedim> + void + ensure_existence_of_master_dof_mask (const FiniteElement<dim,spacedim> &fe1, + const FiniteElement<dim,spacedim> &fe2, + const FullMatrix<double> &face_interpolation_matrix, + std_cxx1x::shared_ptr<std::vector<bool> > &master_dof_mask) + { + if (master_dof_mask == std_cxx1x::shared_ptr<std::vector<bool> >()) + { + master_dof_mask = std_cxx1x::shared_ptr<std::vector<bool> > + (new std::vector<bool> (fe1.dofs_per_face)); + select_master_dofs_for_face_restriction (fe1, + fe2, + face_interpolation_matrix, + *master_dof_mask); + } + } + + + + /** + * Make sure that the given @p face_interpolation_matrix pointer + * points to a valid matrix. If the pointer is zero beforehand, + * create an entry with the correct data. If it is nonzero, don't + * touch it. + */ + template <int dim, int spacedim> + void + ensure_existence_of_face_matrix (const FiniteElement<dim,spacedim> &fe1, + const FiniteElement<dim,spacedim> &fe2, + std_cxx1x::shared_ptr<FullMatrix<double> > &matrix) + { + if (matrix == std_cxx1x::shared_ptr<FullMatrix<double> >()) + { + matrix = std_cxx1x::shared_ptr<FullMatrix<double> > + (new FullMatrix<double> (fe2.dofs_per_face, + fe1.dofs_per_face)); + fe1.get_face_interpolation_matrix (fe2, + *matrix); + } + } + + + + /** + * Same, but for subface interpolation matrices. + */ + template <int dim, int spacedim> + void + ensure_existence_of_subface_matrix (const FiniteElement<dim,spacedim> &fe1, + const FiniteElement<dim,spacedim> &fe2, + const unsigned int subface, + std_cxx1x::shared_ptr<FullMatrix<double> > &matrix) + { + if (matrix == std_cxx1x::shared_ptr<FullMatrix<double> >()) + { + matrix = std_cxx1x::shared_ptr<FullMatrix<double> > + (new FullMatrix<double> (fe2.dofs_per_face, + fe1.dofs_per_face)); + fe1.get_subface_interpolation_matrix (fe2, + subface, + *matrix); + } + } + + + + /** + * Given the face interpolation matrix between two elements, split it + * into its master and slave parts and invert the master part as + * explained in the @ref hp_paper "hp paper". + */ + void + ensure_existence_of_split_face_matrix (const FullMatrix<double> &face_interpolation_matrix, + const std::vector<bool> &master_dof_mask, + std_cxx1x::shared_ptr<std::pair<FullMatrix<double>,FullMatrix<double> > > &split_matrix) + { + AssertDimension (master_dof_mask.size(), face_interpolation_matrix.m()); + Assert (std::count (master_dof_mask.begin(), master_dof_mask.end(), true) == + static_cast<signed int>(face_interpolation_matrix.n()), + ExcInternalError()); + + if (split_matrix == + std_cxx1x::shared_ptr<std::pair<FullMatrix<double>,FullMatrix<double> > >()) + { + split_matrix + = std_cxx1x::shared_ptr<std::pair<FullMatrix<double>,FullMatrix<double> > > + (new std::pair<FullMatrix<double>,FullMatrix<double> >()); + + const unsigned int n_master_dofs = face_interpolation_matrix.n(); + const unsigned int n_dofs = face_interpolation_matrix.m(); + + Assert (n_master_dofs <= n_dofs, ExcInternalError()); + + // copy and invert the master + // component, copy the slave + // component + split_matrix->first.reinit (n_master_dofs, n_master_dofs); + split_matrix->second.reinit (n_dofs-n_master_dofs, n_master_dofs); + + unsigned int nth_master_dof = 0, + nth_slave_dof = 0; + + for (unsigned int i=0; i<n_dofs; ++i) + if (master_dof_mask[i] == true) + { + for (unsigned int j=0; j<n_master_dofs; ++j) + split_matrix->first(nth_master_dof,j) + = face_interpolation_matrix(i,j); + ++nth_master_dof; + } + else + { + for (unsigned int j=0; j<n_master_dofs; ++j) + split_matrix->second(nth_slave_dof,j) + = face_interpolation_matrix(i,j); + ++nth_slave_dof; + } + + AssertDimension (nth_master_dof, n_master_dofs); + AssertDimension (nth_slave_dof, n_dofs-n_master_dofs); + + //TODO[WB]: We should make sure very small entries are removed after inversion + split_matrix->first.gauss_jordan (); + } + } + + + // a template that can determine statically whether a given + // DoFHandler class supports different finite element elements + template <typename> + struct DoFHandlerSupportsDifferentFEs + { + static const bool value = true; + }; + + + template <int dim, int spacedim> + struct DoFHandlerSupportsDifferentFEs< dealii::DoFHandler<dim,spacedim> > + { + static const bool value = false; + }; + + + /** + * A function that returns how many different finite elements a dof + * handler uses. This is one for non-hp DoFHandlers and + * dof_handler.get_fe().size() for the hp-versions. + */ + template <int dim, int spacedim> + unsigned int + n_finite_elements (const dealii::hp::DoFHandler<dim,spacedim> &dof_handler) + { + return dof_handler.get_fe().size(); + } + + + template <class DH> + unsigned int + n_finite_elements (const DH &) + { + return 1; + } + + + /** + * For a given face belonging to an active cell that borders to a + * more refined cell, return the fe_index of the most dominating + * finite element used on any of the face's subfaces. + */ + template <typename face_iterator> + unsigned int + get_most_dominating_subface_fe_index (const face_iterator &face) + { + const unsigned int dim + = face_iterator::AccessorType::dimension; + const unsigned int spacedim + = face_iterator::AccessorType::space_dimension; + + unsigned int dominating_subface_no = 0; + for (; dominating_subface_no<face->n_children(); + ++dominating_subface_no) + { + // each of the subfaces can have only a single fe_index + // associated with them, since there is no cell on the other + // side + Assert (face->child(dominating_subface_no) + ->n_active_fe_indices() + == 1, + ExcInternalError()); + + const FiniteElement<dim,spacedim> & + this_subface_fe = (face->child(dominating_subface_no) + ->get_fe (face->child(dominating_subface_no) + ->nth_active_fe_index(0))); + + FiniteElementDomination::Domination + domination = FiniteElementDomination::either_element_can_dominate; + for (unsigned int sf=0; sf<face->n_children(); ++sf) + if (sf != dominating_subface_no) + { + const FiniteElement<dim,spacedim> & + that_subface_fe = (face->child(sf) + ->get_fe (face->child(sf) + ->nth_active_fe_index(0))); + + domination = domination & + this_subface_fe.compare_for_face_domination(that_subface_fe); + } + + // see if the element on this subface is able to dominate the + // ones on all other subfaces, and if so take it + if ((domination == FiniteElementDomination::this_element_dominates) + || + (domination == FiniteElementDomination::either_element_can_dominate)) + break; + } + + // check that we have found one such subface + Assert (dominating_subface_no < face->n_children(), + ExcNotImplemented()); + + // return the finite element index used on it. note that only a + // single fe can be active on such subfaces + return face->child (dominating_subface_no)->nth_active_fe_index(0); + } + + + + /** + * Copy constraints into a constraint matrix object. + * + * This function removes zero constraints and those, which constrain + * a DoF which was already eliminated in one of the previous steps of + * the hp hanging node procedure. + * + * It also suppresses very small entries in the constraint matrix to + * avoid making the sparsity pattern fuller than necessary. + */ + void + filter_constraints (const std::vector<types::global_dof_index> &master_dofs, + const std::vector<types::global_dof_index> &slave_dofs, + const FullMatrix<double> &face_constraints, + ConstraintMatrix &constraints) + { + Assert (face_constraints.n () == master_dofs.size (), + ExcDimensionMismatch(master_dofs.size (), + face_constraints.n())); + Assert (face_constraints.m () == slave_dofs.size (), + ExcDimensionMismatch(slave_dofs.size (), + face_constraints.m())); + + const unsigned int n_master_dofs = master_dofs.size (); + const unsigned int n_slave_dofs = slave_dofs.size (); + + // check for a couple conditions that happened in parallel + // distributed mode + for (unsigned int row=0; row!=n_slave_dofs; ++row) + Assert (slave_dofs[row] != numbers::invalid_dof_index, + ExcInternalError()); + for (unsigned int col=0; col!=n_master_dofs; ++col) + Assert (master_dofs[col] != numbers::invalid_dof_index, + ExcInternalError()); + + + for (unsigned int row=0; row!=n_slave_dofs; ++row) + if (constraints.is_constrained (slave_dofs[row]) == false) + { + bool constraint_already_satisfied = false; + + // Check if we have an identity constraint, which is already + // satisfied by unification of the corresponding global dof + // indices + for (unsigned int i=0; i<n_master_dofs; ++i) + if (face_constraints (row,i) == 1.0) + if (master_dofs[i] == slave_dofs[row]) + { + constraint_already_satisfied = true; + break; + } + + if (constraint_already_satisfied == false) + { + // add up the absolute values of all constraints in this + // line to get a measure of their absolute size + double abs_sum = 0; + for (unsigned int i=0; i<n_master_dofs; ++i) + abs_sum += std::abs (face_constraints(row,i)); + + // then enter those constraints that are larger than + // 1e-14*abs_sum. everything else probably originated + // from inexact inversion of matrices and similar + // effects. having those constraints in here will only + // lead to problems because it makes sparsity patterns + // fuller than necessary without producing any + // significant effect + constraints.add_line (slave_dofs[row]); + for (unsigned int i=0; i<n_master_dofs; ++i) + if ((face_constraints(row,i) != 0) + && + (std::fabs(face_constraints(row,i)) >= 1e-14*abs_sum)) + constraints.add_entry (slave_dofs[row], + master_dofs[i], + face_constraints (row,i)); + constraints.set_inhomogeneity (slave_dofs[row], 0.); + } + } + } + + } + + + + void + make_hp_hanging_node_constraints (const dealii::DoFHandler<1> &, + ConstraintMatrix &) + { + // nothing to do for regular dof handlers in 1d + } + + + + void + make_oldstyle_hanging_node_constraints (const dealii::DoFHandler<1> &, + ConstraintMatrix &, + dealii::internal::int2type<1>) + { + // nothing to do for regular dof handlers in 1d + } + + + void + make_hp_hanging_node_constraints (const dealii::MGDoFHandler<1> &, + ConstraintMatrix &) + { + // nothing to do for regular dof handlers in 1d + } + + + + void + make_oldstyle_hanging_node_constraints (const dealii::MGDoFHandler<1> &, + ConstraintMatrix &, + dealii::internal::int2type<1>) + { + // nothing to do for regular dof handlers in 1d + } + + + void + make_hp_hanging_node_constraints (const dealii::hp::DoFHandler<1> &/*dof_handler*/, + ConstraintMatrix &/*constraints*/) + { + // we may have to compute constraints for vertices. gotta think about + // that a bit more + + //TODO[WB]: think about what to do here... + } + + + + void + make_oldstyle_hanging_node_constraints (const dealii::hp::DoFHandler<1> &/*dof_handler*/, + ConstraintMatrix &/*constraints*/, + dealii::internal::int2type<1>) + { + // we may have to compute constraints for vertices. gotta think about + // that a bit more + + //TODO[WB]: think about what to do here... + } + + + void + make_hp_hanging_node_constraints (const dealii::DoFHandler<1,2> &, + ConstraintMatrix &) + { + // nothing to do for regular dof handlers in 1d + } + + + + void + make_oldstyle_hanging_node_constraints (const dealii::DoFHandler<1,2> &, + ConstraintMatrix &, + dealii::internal::int2type<1>) + { + // nothing to do for regular dof handlers in 1d + } + + + void + make_hp_hanging_node_constraints (const dealii::DoFHandler<1,3> &, + ConstraintMatrix &) + { + // nothing to do for regular dof handlers in 1d + } + + void + make_oldstyle_hanging_node_constraints (const dealii::DoFHandler<1,3> &, + ConstraintMatrix &, + dealii::internal::int2type<1>) + { + // nothing to do for regular dof handlers in 1d + } + + +// currently not used but may be in the future: + +// void +// make_hp_hanging_node_constraints (const dealii::MDoFHandler<1,2> &, +// ConstraintMatrix &) +// { +// // nothing to do for regular +// // dof handlers in 1d +// } + + + +// void +// make_oldstyle_hanging_node_constraints (const dealii::DoFHandler<1,2> &, +// ConstraintMatrix &, +// dealii::internal::int2type<1>) +// { +// // nothing to do for regular +// // dof handlers in 1d +// } + + +// void +// make_oldstyle_hanging_node_constraints (const dealii::hp::DoFHandler<1,2> &/*dof_handler*/, +// ConstraintMatrix &/*constraints*/, +// dealii::internal::int2type<1>) +// { +// // we may have to compute +// // constraints for +// // vertices. gotta think about +// // that a bit more +// +// //TODO[WB]: think about what to do here... +// } +//#endif + + + + template <class DH> + void + make_oldstyle_hanging_node_constraints (const DH &dof_handler, + ConstraintMatrix &constraints, + dealii::internal::int2type<2>) + { + const unsigned int dim = 2; + + const unsigned int spacedim = DH::space_dimension; + + std::vector<types::global_dof_index> dofs_on_mother; + std::vector<types::global_dof_index> dofs_on_children; + + // loop over all lines; only on lines there can be constraints. We do + // so by looping over all active cells and checking whether any of + // the faces are refined which can only be from the neighboring cell + // because this one is active. In that case, the face is subject to + // constraints + // + // note that even though we may visit a face twice if the neighboring + // cells are equally refined, we can only visit each face with + // hanging nodes once + typename DH::active_cell_iterator cell = dof_handler.begin_active(), + endc = dof_handler.end(); + for (; cell!=endc; ++cell) + // artificial cells can at best neighbor ghost cells, but we're not + // interested in these interfaces + if (!cell->is_artificial ()) + for (unsigned int face=0; face<GeometryInfo<dim>::faces_per_cell; ++face) + if (cell->face(face)->has_children()) + { + // in any case, faces can have at most two active fe + // indices, but here the face can have only one (namely the + // same as that from the cell we're sitting on), and each + // of the children can have only one as well. check this + Assert (cell->face(face)->n_active_fe_indices() == 1, + ExcInternalError()); + Assert (cell->face(face)->fe_index_is_active(cell->active_fe_index()) + == true, + ExcInternalError()); + for (unsigned int c=0; c<cell->face(face)->n_children(); ++c) + if (!cell->neighbor_child_on_subface(face,c)->is_artificial()) + Assert (cell->face(face)->child(c)->n_active_fe_indices() == 1, + ExcInternalError()); + + // right now, all that is implemented is the case that both + // sides use the same fe + for (unsigned int c=0; c<cell->face(face)->n_children(); ++c) + if (!cell->neighbor_child_on_subface(face,c)->is_artificial()) + Assert (cell->face(face)->child(c) + ->fe_index_is_active(cell->active_fe_index()) == true, + ExcNotImplemented()); + + // ok, start up the work + const FiniteElement<dim,spacedim> &fe = cell->get_fe(); + const unsigned int fe_index = cell->active_fe_index(); + + const unsigned int + n_dofs_on_mother = 2*fe.dofs_per_vertex + fe.dofs_per_line, + n_dofs_on_children = fe.dofs_per_vertex + 2*fe.dofs_per_line; + + dofs_on_mother.resize (n_dofs_on_mother); + dofs_on_children.resize (n_dofs_on_children); + + Assert(n_dofs_on_mother == fe.constraints().n(), + ExcDimensionMismatch(n_dofs_on_mother, + fe.constraints().n())); + Assert(n_dofs_on_children == fe.constraints().m(), + ExcDimensionMismatch(n_dofs_on_children, + fe.constraints().m())); + + const typename DH::line_iterator this_face = cell->face(face); + + // fill the dofs indices. Use same enumeration scheme as in + // @p{FiniteElement::constraints()} + unsigned int next_index = 0; + for (unsigned int vertex=0; vertex<2; ++vertex) + for (unsigned int dof=0; dof!=fe.dofs_per_vertex; ++dof) + dofs_on_mother[next_index++] = this_face->vertex_dof_index(vertex,dof, + fe_index); + for (unsigned int dof=0; dof!=fe.dofs_per_line; ++dof) + dofs_on_mother[next_index++] = this_face->dof_index(dof, fe_index); + AssertDimension (next_index, dofs_on_mother.size()); + + next_index = 0; + for (unsigned int dof=0; dof!=fe.dofs_per_vertex; ++dof) + dofs_on_children[next_index++] + = this_face->child(0)->vertex_dof_index(1,dof,fe_index); + for (unsigned int child=0; child<2; ++child) + for (unsigned int dof=0; dof!=fe.dofs_per_line; ++dof) + dofs_on_children[next_index++] + = this_face->child(child)->dof_index(dof, fe_index); + AssertDimension (next_index, dofs_on_children.size()); + + // for each row in the constraint matrix for this line: + for (unsigned int row=0; row!=dofs_on_children.size(); ++row) + { + constraints.add_line (dofs_on_children[row]); + for (unsigned int i=0; i!=dofs_on_mother.size(); ++i) + constraints.add_entry (dofs_on_children[row], + dofs_on_mother[i], + fe.constraints()(row,i)); + + constraints.set_inhomogeneity (dofs_on_children[row], 0.); + } + } + else + { + // this face has no children, but it could still be that it + // is shared by two cells that use a different fe index. + // check a couple of things, but ignore the case that the + // neighbor is an artificial cell + if (!cell->at_boundary(face) && + !cell->neighbor(face)->is_artificial()) + { + Assert (cell->face(face)->n_active_fe_indices() == 1, + ExcNotImplemented()); + Assert (cell->face(face) + ->fe_index_is_active(cell->active_fe_index()) == true, + ExcInternalError()); + } + } + } + + + + template <class DH> + void + make_oldstyle_hanging_node_constraints (const DH &dof_handler, + ConstraintMatrix &constraints, + dealii::internal::int2type<3>) + { + const unsigned int dim = 3; + + std::vector<types::global_dof_index> dofs_on_mother; + std::vector<types::global_dof_index> dofs_on_children; + + // loop over all quads; only on quads there can be constraints. We do + // so by looping over all active cells and checking whether any of + // the faces are refined which can only be from the neighboring cell + // because this one is active. In that case, the face is subject to + // constraints + // + // note that even though we may visit a face twice if the neighboring + // cells are equally refined, we can only visit each face with + // hanging nodes once + typename DH::active_cell_iterator cell = dof_handler.begin_active(), + endc = dof_handler.end(); + for (; cell!=endc; ++cell) + // artificial cells can at best neighbor ghost cells, but we're not + // interested in these interfaces + if (!cell->is_artificial ()) + for (unsigned int face=0; face<GeometryInfo<dim>::faces_per_cell; ++face) + if (cell->face(face)->has_children()) + { + // first of all, make sure that we treat a case which is + // possible, i.e. either no dofs on the face at all or no + // anisotropic refinement + if (cell->get_fe().dofs_per_face == 0) + continue; + + Assert(cell->face(face)->refinement_case()==RefinementCase<dim-1>::isotropic_refinement, + ExcNotImplemented()); + + // in any case, faces can have at most two active fe + // indices, but here the face can have only one (namely the + // same as that from the cell we're sitting on), and each + // of the children can have only one as well. check this + AssertDimension (cell->face(face)->n_active_fe_indices(), 1); + Assert (cell->face(face)->fe_index_is_active(cell->active_fe_index()) + == true, + ExcInternalError()); + for (unsigned int c=0; c<cell->face(face)->n_children(); ++c) + AssertDimension (cell->face(face)->child(c)->n_active_fe_indices(), 1); + + // right now, all that is implemented is the case that both + // sides use the same fe, and not only that but also that + // all lines bounding this face and the children have the + // same fe + for (unsigned int c=0; c<cell->face(face)->n_children(); ++c) + if (!cell->neighbor_child_on_subface(face,c)->is_artificial()) + { + Assert (cell->face(face)->child(c) + ->fe_index_is_active(cell->active_fe_index()) == true, + ExcNotImplemented()); + for (unsigned int e=0; e<4; ++e) + { + Assert (cell->face(face)->child(c)->line(e) + ->n_active_fe_indices() == 1, + ExcNotImplemented()); + Assert (cell->face(face)->child(c)->line(e) + ->fe_index_is_active(cell->active_fe_index()) == true, + ExcNotImplemented()); + } + } + for (unsigned int e=0; e<4; ++e) + { + Assert (cell->face(face)->line(e) + ->n_active_fe_indices() == 1, + ExcNotImplemented()); + Assert (cell->face(face)->line(e) + ->fe_index_is_active(cell->active_fe_index()) == true, + ExcNotImplemented()); + } + + // ok, start up the work + const FiniteElement<dim> &fe = cell->get_fe(); + const unsigned int fe_index = cell->active_fe_index(); + + const unsigned int n_dofs_on_mother = fe.dofs_per_face; + const unsigned int n_dofs_on_children = (5*fe.dofs_per_vertex+ + 12*fe.dofs_per_line+ + 4*fe.dofs_per_quad); + + //TODO[TL]: think about this and the following in case of anisotropic refinement + + dofs_on_mother.resize (n_dofs_on_mother); + dofs_on_children.resize (n_dofs_on_children); + + Assert(n_dofs_on_mother == fe.constraints().n(), + ExcDimensionMismatch(n_dofs_on_mother, + fe.constraints().n())); + Assert(n_dofs_on_children == fe.constraints().m(), + ExcDimensionMismatch(n_dofs_on_children, + fe.constraints().m())); + + const typename DH::face_iterator this_face = cell->face(face); + + // fill the dofs indices. Use same enumeration scheme as in + // @p{FiniteElement::constraints()} + unsigned int next_index = 0; + for (unsigned int vertex=0; vertex<4; ++vertex) + for (unsigned int dof=0; dof!=fe.dofs_per_vertex; ++dof) + dofs_on_mother[next_index++] = this_face->vertex_dof_index(vertex,dof, + fe_index); + for (unsigned int line=0; line<4; ++line) + for (unsigned int dof=0; dof!=fe.dofs_per_line; ++dof) + dofs_on_mother[next_index++] + = this_face->line(line)->dof_index(dof, fe_index); + for (unsigned int dof=0; dof!=fe.dofs_per_quad; ++dof) + dofs_on_mother[next_index++] = this_face->dof_index(dof, fe_index); + AssertDimension (next_index, dofs_on_mother.size()); + + next_index = 0; + + // assert some consistency assumptions + + //TODO[TL]: think about this in case of anisotropic + //refinement + + Assert (dof_handler.get_tria().get_anisotropic_refinement_flag() || + ((this_face->child(0)->vertex_index(3) == + this_face->child(1)->vertex_index(2)) && + (this_face->child(0)->vertex_index(3) == + this_face->child(2)->vertex_index(1)) && + (this_face->child(0)->vertex_index(3) == + this_face->child(3)->vertex_index(0))), + ExcInternalError()); + for (unsigned int dof=0; dof!=fe.dofs_per_vertex; ++dof) + dofs_on_children[next_index++] + = this_face->child(0)->vertex_dof_index(3,dof); + + // dof numbers on the centers of the lines bounding this + // face + for (unsigned int line=0; line<4; ++line) + for (unsigned int dof=0; dof!=fe.dofs_per_vertex; ++dof) + dofs_on_children[next_index++] + = this_face->line(line)->child(0)->vertex_dof_index(1,dof, fe_index); + + // next the dofs on the lines interior to the face; the + // order of these lines is laid down in the FiniteElement + // class documentation + for (unsigned int dof=0; dof<fe.dofs_per_line; ++dof) + dofs_on_children[next_index++] + = this_face->child(0)->line(1)->dof_index(dof, fe_index); + for (unsigned int dof=0; dof<fe.dofs_per_line; ++dof) + dofs_on_children[next_index++] + = this_face->child(2)->line(1)->dof_index(dof, fe_index); + for (unsigned int dof=0; dof<fe.dofs_per_line; ++dof) + dofs_on_children[next_index++] + = this_face->child(0)->line(3)->dof_index(dof, fe_index); + for (unsigned int dof=0; dof<fe.dofs_per_line; ++dof) + dofs_on_children[next_index++] + = this_face->child(1)->line(3)->dof_index(dof, fe_index); + + // dofs on the bordering lines + for (unsigned int line=0; line<4; ++line) + for (unsigned int child=0; child<2; ++child) + for (unsigned int dof=0; dof!=fe.dofs_per_line; ++dof) + dofs_on_children[next_index++] + = this_face->line(line)->child(child)->dof_index(dof, fe_index); + + // finally, for the dofs interior to the four child faces + for (unsigned int child=0; child<4; ++child) + for (unsigned int dof=0; dof!=fe.dofs_per_quad; ++dof) + dofs_on_children[next_index++] + = this_face->child(child)->dof_index(dof, fe_index); + AssertDimension (next_index, dofs_on_children.size()); + + // for each row in the constraint matrix for this line: + for (unsigned int row=0; row!=dofs_on_children.size(); ++row) + { + constraints.add_line (dofs_on_children[row]); + for (unsigned int i=0; i!=dofs_on_mother.size(); ++i) + constraints.add_entry (dofs_on_children[row], + dofs_on_mother[i], + fe.constraints()(row,i)); + + constraints.set_inhomogeneity(dofs_on_children[row], 0.); + } + } + else + { + // this face has no children, but it could still be that it + // is shared by two cells that use a different fe index. + // check a couple of things, but ignore the case that the + // neighbor is an artificial cell + if (!cell->at_boundary(face) && + !cell->neighbor(face)->is_artificial()) + { + Assert (cell->face(face)->n_active_fe_indices() == 1, + ExcNotImplemented()); + Assert (cell->face(face) + ->fe_index_is_active(cell->active_fe_index()) == true, + ExcInternalError()); + } + } + } + + + template <class DH> + void + make_hp_hanging_node_constraints (const DH &dof_handler, + ConstraintMatrix &constraints) + { + // note: this function is going to be hard to understand if you + // haven't read the hp paper. however, we try to follow the notation + // laid out there, so go read the paper before you try to understand + // what is going on here + + const unsigned int dim = DH::dimension; + + const unsigned int spacedim = DH::space_dimension; + + + // a matrix to be used for constraints below. declared here and + // simply resized down below to avoid permanent re-allocation of + // memory + FullMatrix<double> constraint_matrix; + + // similarly have arrays that will hold master and slave dof numbers, + // as well as a scratch array needed for the complicated case below + std::vector<types::global_dof_index> master_dofs; + std::vector<types::global_dof_index> slave_dofs; + std::vector<types::global_dof_index> scratch_dofs; + + // caches for the face and subface interpolation matrices between + // different (or the same) finite elements. we compute them only + // once, namely the first time they are needed, and then just reuse + // them + Table<2,std_cxx1x::shared_ptr<FullMatrix<double> > > + face_interpolation_matrices (n_finite_elements (dof_handler), + n_finite_elements (dof_handler)); + Table<3,std_cxx1x::shared_ptr<FullMatrix<double> > > + subface_interpolation_matrices (n_finite_elements (dof_handler), + n_finite_elements (dof_handler), + GeometryInfo<dim>::max_children_per_face); + + // similarly have a cache for the matrices that are split into their + // master and slave parts, and for which the master part is inverted. + // these two matrices are derived from the face interpolation matrix + // as described in the @ref hp_paper "hp paper" + Table<2,std_cxx1x::shared_ptr<std::pair<FullMatrix<double>,FullMatrix<double> > > > + split_face_interpolation_matrices (n_finite_elements (dof_handler), + n_finite_elements (dof_handler)); + + // finally, for each pair of finite elements, have a mask that states + // which of the degrees of freedom on the coarse side of a refined + // face will act as master dofs. + Table<2,std_cxx1x::shared_ptr<std::vector<bool> > > + master_dof_masks (n_finite_elements (dof_handler), + n_finite_elements (dof_handler)); + + // loop over all faces + // + // note that even though we may visit a face twice if the neighboring + // cells are equally refined, we can only visit each face with + // hanging nodes once + typename DH::active_cell_iterator cell = dof_handler.begin_active(), + endc = dof_handler.end(); + for (; cell!=endc; ++cell) + // artificial cells can at best neighbor ghost cells, but we're not + // interested in these interfaces + if (!cell->is_artificial ()) + for (unsigned int face=0; face<GeometryInfo<dim>::faces_per_cell; ++face) + if (cell->face(face)->has_children()) + { + // first of all, make sure that we treat a case which is + // possible, i.e. either no dofs on the face at all or no + // anisotropic refinement + if (cell->get_fe().dofs_per_face == 0) + continue; + + Assert(cell->face(face)->refinement_case()==RefinementCase<dim-1>::isotropic_refinement, + ExcNotImplemented()); + + // so now we've found a face of an active cell that has + // children. that means that there are hanging nodes here. + + // in any case, faces can have at most two sets of active + // fe indices, but here the face can have only one (namely + // the same as that from the cell we're sitting on), and + // each of the children can have only one as well. check + // this + Assert (cell->face(face)->n_active_fe_indices() == 1, + ExcInternalError()); + Assert (cell->face(face)->fe_index_is_active(cell->active_fe_index()) + == true, + ExcInternalError()); + for (unsigned int c=0; c<cell->face(face)->n_children(); ++c) + Assert (cell->face(face)->child(c)->n_active_fe_indices() == 1, + ExcInternalError()); + + // first find out whether we can constrain each of the + // subfaces to the mother face. in the lingo of the hp + // paper, this would be the simple case. note that we can + // short-circuit this decision if the dof_handler doesn't + // support hp at all + // + // ignore all interfaces with artificial cells + FiniteElementDomination::Domination + mother_face_dominates = FiniteElementDomination::either_element_can_dominate; + + if (DoFHandlerSupportsDifferentFEs<DH>::value == true) + for (unsigned int c=0; c<cell->face(face)->number_of_children(); ++c) + if (!cell->neighbor_child_on_subface (face, c)->is_artificial()) + mother_face_dominates = mother_face_dominates & + (cell->get_fe().compare_for_face_domination + (cell->neighbor_child_on_subface (face, c)->get_fe())); + + switch (mother_face_dominates) + { + case FiniteElementDomination::this_element_dominates: + case FiniteElementDomination::either_element_can_dominate: + { + // Case 1 (the simple case and the only case that can + // happen for non-hp DoFHandlers): The coarse element + // dominates the elements on the subfaces (or they are + // all the same) + // + // so we are going to constrain the DoFs on the face + // children against the DoFs on the face itself + master_dofs.resize (cell->get_fe().dofs_per_face); + + cell->face(face)->get_dof_indices (master_dofs, + cell->active_fe_index ()); + + // Now create constraint matrix for the subfaces and + // assemble it. ignore all interfaces with artificial + // cells because we can only get to such interfaces if + // the current cell is a ghost cell + for (unsigned int c=0; c<cell->face(face)->n_children(); ++c) + { + if (cell->neighbor_child_on_subface (face, c)->is_artificial()) + continue; + + const typename DH::active_face_iterator + subface = cell->face(face)->child(c); + + Assert (subface->n_active_fe_indices() == 1, + ExcInternalError()); + + const unsigned int + subface_fe_index = subface->nth_active_fe_index(0); + + // we sometime run into the situation where for + // example on one big cell we have a FE_Q(1) and on + // the subfaces we have a mixture of FE_Q(1) and + // FE_Nothing. In that case, the face domination is + // either_element_can_dominate for the whole + // collection of subfaces, but on the particular + // subface between FE_Q(1) and FE_Nothing, there + // are no constraints that we need to take care of. + // in that case, just continue + if (cell->get_fe().compare_for_face_domination + (subface->get_fe(subface_fe_index)) + == + FiniteElementDomination::no_requirements) + continue; + + // Same procedure as for the mother cell. Extract + // the face DoFs from the cell DoFs. + slave_dofs.resize (subface->get_fe(subface_fe_index) + .dofs_per_face); + subface->get_dof_indices (slave_dofs, subface_fe_index); + + for (unsigned int i=0; i<slave_dofs.size(); ++i) + Assert (slave_dofs[i] != numbers::invalid_dof_index, + ExcInternalError()); + + // Now create the element constraint for this + // subface. + // + // As a side remark, one may wonder the following: + // neighbor_child is clearly computed correctly, + // i.e. taking into account face_orientation (just + // look at the implementation of that function). + // however, we don't care about this here, when we + // ask for subface_interpolation on subface c. the + // question rather is: do we have to translate 'c' + // here as well? + // + // the answer is in fact 'no'. if one does that, + // results are wrong: constraints are added twice + // for the same pair of nodes but with differing + // weights. in addition, one can look at the + // deal.II/project_*_03 tests that look at exactly + // this case: there, we have a mesh with at least + // one face_orientation==false and hanging nodes, + // and the results of those tests show that the + // result of projection verifies the approximation + // properties of a finite element onto that mesh + ensure_existence_of_subface_matrix + (cell->get_fe(), + subface->get_fe(subface_fe_index), + c, + subface_interpolation_matrices + [cell->active_fe_index()][subface_fe_index][c]); + + // Add constraints to global constraint matrix. + filter_constraints (master_dofs, + slave_dofs, + *(subface_interpolation_matrices + [cell->active_fe_index()][subface_fe_index][c]), + constraints); + } + + break; + } + + case FiniteElementDomination::other_element_dominates: + case FiniteElementDomination::neither_element_dominates: + { + // Case 2 (the "complex" case): at least one (the + // neither_... case) of the finer elements or all of + // them (the other_... case) is dominating. See the hp + // paper for a way how to deal with this situation + // + // since this is something that can only happen for hp + // dof handlers, add a check here... + Assert (DoFHandlerSupportsDifferentFEs<DH>::value == true, + ExcInternalError()); + + // we first have to find the finite element that is + // able to generate a space that all the other ones can + // be constrained to + const unsigned int dominating_fe_index + = get_most_dominating_subface_fe_index (cell->face(face)); + + const FiniteElement<dim,spacedim> &dominating_fe + = dof_handler.get_fe()[dominating_fe_index]; + + // check also that it is able to constrain the mother + // face. it should be, or we wouldn't have gotten into + // the branch for the 'complex' case + Assert ((dominating_fe.compare_for_face_domination + (cell->face(face)->get_fe(cell->face(face)->nth_active_fe_index(0))) + == FiniteElementDomination::this_element_dominates) + || + (dominating_fe.compare_for_face_domination + (cell->face(face)->get_fe(cell->face(face)->nth_active_fe_index(0))) + == FiniteElementDomination::either_element_can_dominate), + ExcInternalError()); + + + // first get the interpolation matrix from the mother + // to the virtual dofs + Assert (dominating_fe.dofs_per_face <= + cell->get_fe().dofs_per_face, + ExcInternalError()); + + ensure_existence_of_face_matrix + (dominating_fe, + cell->get_fe(), + face_interpolation_matrices + [dominating_fe_index][cell->active_fe_index()]); + + // split this matrix into master and slave components. + // invert the master component + ensure_existence_of_master_dof_mask + (cell->get_fe(), + dominating_fe, + (*face_interpolation_matrices + [dominating_fe_index] + [cell->active_fe_index()]), + master_dof_masks + [dominating_fe_index] + [cell->active_fe_index()]); + + ensure_existence_of_split_face_matrix + (*face_interpolation_matrices + [dominating_fe_index][cell->active_fe_index()], + (*master_dof_masks + [dominating_fe_index][cell->active_fe_index()]), + split_face_interpolation_matrices + [dominating_fe_index][cell->active_fe_index()]); + + const FullMatrix<double> &restrict_mother_to_virtual_master_inv + = (split_face_interpolation_matrices + [dominating_fe_index][cell->active_fe_index()]->first); + + const FullMatrix<double> &restrict_mother_to_virtual_slave + = (split_face_interpolation_matrices + [dominating_fe_index][cell->active_fe_index()]->second); + + // now compute the constraint matrix as the product + // between the inverse matrix and the slave part + constraint_matrix.reinit (cell->get_fe().dofs_per_face - + dominating_fe.dofs_per_face, + dominating_fe.dofs_per_face); + restrict_mother_to_virtual_slave + .mmult (constraint_matrix, + restrict_mother_to_virtual_master_inv); + + // then figure out the global numbers of master and + // slave dofs and apply constraints + scratch_dofs.resize (cell->get_fe().dofs_per_face); + cell->face(face)->get_dof_indices (scratch_dofs, + cell->active_fe_index ()); + + // split dofs into master and slave components + master_dofs.clear (); + slave_dofs.clear (); + for (unsigned int i=0; i<cell->get_fe().dofs_per_face; ++i) + if ((*master_dof_masks + [dominating_fe_index][cell->active_fe_index()])[i] == true) + master_dofs.push_back (scratch_dofs[i]); + else + slave_dofs.push_back (scratch_dofs[i]); + + AssertDimension (master_dofs.size(), dominating_fe.dofs_per_face); + AssertDimension (slave_dofs.size(), + cell->get_fe().dofs_per_face - dominating_fe.dofs_per_face); + + filter_constraints (master_dofs, + slave_dofs, + constraint_matrix, + constraints); + + + + // next we have to deal with the subfaces. do as + // discussed in the hp paper + for (unsigned int sf=0; + sf<cell->face(face)->n_children(); ++sf) + { + // ignore interfaces with artificial cells as well + // as interfaces between ghost cells in 2d + if (cell->neighbor_child_on_subface (face, sf)->is_artificial() + || + (dim==2 && cell->is_ghost() + && + cell->neighbor_child_on_subface (face, sf)->is_ghost())) + continue; + + Assert (cell->face(face)->child(sf) + ->n_active_fe_indices() == 1, + ExcInternalError()); + + const unsigned int subface_fe_index + = cell->face(face)->child(sf)->nth_active_fe_index(0); + const FiniteElement<dim,spacedim> &subface_fe + = dof_handler.get_fe()[subface_fe_index]; + + // first get the interpolation matrix from the + // subface to the virtual dofs + Assert (dominating_fe.dofs_per_face <= + subface_fe.dofs_per_face, + ExcInternalError()); + ensure_existence_of_subface_matrix + (dominating_fe, + subface_fe, + sf, + subface_interpolation_matrices + [dominating_fe_index][subface_fe_index][sf]); + + const FullMatrix<double> &restrict_subface_to_virtual + = *(subface_interpolation_matrices + [dominating_fe_index][subface_fe_index][sf]); + + constraint_matrix.reinit (subface_fe.dofs_per_face, + dominating_fe.dofs_per_face); + + restrict_subface_to_virtual + .mmult (constraint_matrix, + restrict_mother_to_virtual_master_inv); + + slave_dofs.resize (subface_fe.dofs_per_face); + cell->face(face)->child(sf)->get_dof_indices (slave_dofs, + subface_fe_index); + + filter_constraints (master_dofs, + slave_dofs, + constraint_matrix, + constraints); + } + + break; + } + + case FiniteElementDomination::no_requirements: + // there are no continuity requirements between the two + // elements. record no constraints + break; + + default: + // we shouldn't get here + Assert (false, ExcInternalError()); + } + } + else + { + // this face has no children, but it could still be that it + // is shared by two cells that use a different fe index + Assert (cell->face(face) + ->fe_index_is_active(cell->active_fe_index()) == true, + ExcInternalError()); + + // see if there is a neighbor that is an artificial cell. + // in that case, we're not interested in this interface. we + // test this case first since artificial cells may not have + // an active_fe_index set, etc + if (!cell->at_boundary(face) + && + cell->neighbor(face)->is_artificial()) + continue; + + // Only if there is a neighbor with a different + // active_fe_index and the same h-level, some action has to + // be taken. + if ((DoFHandlerSupportsDifferentFEs<DH>::value == true) + && + !cell->face(face)->at_boundary () + && + (cell->neighbor(face)->active_fe_index () != + cell->active_fe_index ()) + && + (!cell->face(face)->has_children() && + !cell->neighbor_is_coarser(face) )) + { + const typename DH::level_cell_iterator neighbor = cell->neighbor (face); + + // see which side of the face we have to constrain + switch (cell->get_fe().compare_for_face_domination (neighbor->get_fe ())) + { + case FiniteElementDomination::this_element_dominates: + { + // Get DoFs on dominating and dominated side of the + // face + master_dofs.resize (cell->get_fe().dofs_per_face); + cell->face(face)->get_dof_indices (master_dofs, + cell->active_fe_index ()); + + slave_dofs.resize (neighbor->get_fe().dofs_per_face); + cell->face(face)->get_dof_indices (slave_dofs, + neighbor->active_fe_index ()); + + // break if the n_master_dofs == 0, because we are + // attempting to constrain to an element that has + // no face dofs + if (master_dofs.size() == 0) break; + + // make sure the element constraints for this face + // are available + ensure_existence_of_face_matrix + (cell->get_fe(), + neighbor->get_fe(), + face_interpolation_matrices + [cell->active_fe_index()][neighbor->active_fe_index()]); + + // Add constraints to global constraint matrix. + filter_constraints (master_dofs, + slave_dofs, + *(face_interpolation_matrices + [cell->active_fe_index()] + [neighbor->active_fe_index()]), + constraints); + + break; + } + + case FiniteElementDomination::other_element_dominates: + { + // we don't do anything here since we will come + // back to this face from the other cell, at which + // time we will fall into the first case clause + // above + break; + } + + case FiniteElementDomination::either_element_can_dominate: + { + // it appears as if neither element has any + // constraints on its neighbor. this may be because + // neither element has any DoFs on faces at all. or + // that the two elements are actually the same, + // although they happen to run under different + // fe_indices (this is what happens in + // hp/hp_hanging_nodes_01 for example). + // + // another possibility is what happens in crash_13. + // there, we have FESystem(FE_Q(1),FE_DGQ(0)) vs. + // FESystem(FE_Q(1),FE_DGQ(1)). neither of them + // dominates the other. + // + // a final possibility is that we have something like + // FESystem(FE_Q(1),FE_Q(1)) vs + // FESystem(FE_Q(1),FE_Nothing()), see + // hp/fe_nothing_18/19. + // + // in any case, the point is that it doesn't + // matter. there is nothing to do here. + break; + } + + case FiniteElementDomination::neither_element_dominates: + { + // we don't presently know what exactly to do here. + // it isn't quite clear what exactly we would have + // to do here. sit tight until someone trips over + // the following statement and see what exactly is + // going on + Assert (false, ExcNotImplemented()); + break; + } + + case FiniteElementDomination::no_requirements: + { + // nothing to do here + break; + } + + default: + // we shouldn't get here + Assert (false, ExcInternalError()); + } + } + } + } + } + + + + + template <class DH> + void + make_hanging_node_constraints (const DH &dof_handler, + ConstraintMatrix &constraints) + { + // Decide whether to use the new or old make_hanging_node_constraints + // function. If all the FiniteElement or all elements in a FECollection + // support the new face constraint matrix, the new code will be used. + // Otherwise, the old implementation is used for the moment. + if (dof_handler.get_fe().hp_constraints_are_implemented ()) + internal:: + make_hp_hanging_node_constraints (dof_handler, + constraints); + else + internal:: + make_oldstyle_hanging_node_constraints (dof_handler, + constraints, + dealii::internal::int2type<DH::dimension>()); + } + + + + namespace + { + // enter constraints for periodicity into the given ConstraintMatrix object. + // this function is called when at least one of the two face iterators corresponds + // to an active object without further children + // + // @param transformation A matrix that maps degrees of freedom from one face + // to another. If the DoFs on the two faces are supposed to match exactly, then + // the matrix so provided will be the identity matrix. if face 2 is once refined + // from face 1, then the matrix needs to be the interpolation matrix from a face + // to this particular child + // + // @precondition: face_1 is supposed to be active + // + // @note As bug #82 ((http://code.google.com/p/dealii/issues/detail?id=82) and the + // corresponding testcase bits/periodicity_05 demonstrate, we can occasionally + // get into trouble if we already have the constraint x1=x2 and want to insert + // x2=x1. we avoid this by skipping an identity constraint if the opposite + // constraint already exists + template <typename FaceIterator> + void + set_periodicity_constraints (const FaceIterator &face_1, + const typename identity<FaceIterator>::type &face_2, + const FullMatrix<double> &transformation, + dealii::ConstraintMatrix &constraint_matrix, + const ComponentMask &component_mask, + const bool face_orientation, + const bool face_flip, + const bool face_rotation) + { + static const int dim = FaceIterator::AccessorType::dimension; + static const int spacedim = FaceIterator::AccessorType::space_dimension; + + // we should be in the case where face_1 is active, i.e. has no children: + Assert (!face_1->has_children(), + ExcInternalError()); + + Assert (face_1->n_active_fe_indices() == 1, + ExcInternalError()); + + // if face_2 does have children, then we need to iterate over them + if (face_2->has_children()) + { + Assert (face_2->n_children() == GeometryInfo<dim>::max_children_per_face, + ExcNotImplemented()); + const unsigned int dofs_per_face + = face_1->get_fe(face_1->nth_active_fe_index(0)).dofs_per_face; + FullMatrix<double> child_transformation (dofs_per_face, dofs_per_face); + FullMatrix<double> subface_interpolation (dofs_per_face, dofs_per_face); + for (unsigned int c=0; c<face_2->n_children(); ++c) + { + // get the interpolation matrix recursively from the one that + // interpolated from face_1 to face_2 by multiplying from the + // left with the one that interpolates from face_2 to + // its child + face_1->get_fe(face_1->nth_active_fe_index(0)) + .get_subface_interpolation_matrix (face_1->get_fe(face_1->nth_active_fe_index(0)), + c, + subface_interpolation); + subface_interpolation.mmult (child_transformation, transformation); + set_periodicity_constraints(face_1, face_2->child(c), + child_transformation, + constraint_matrix, component_mask, + face_orientation, face_flip, face_rotation); + } + } + else + // both faces are active. we need to match the corresponding DoFs of both faces + { + const unsigned int face_1_index = face_1->nth_active_fe_index(0); + const unsigned int face_2_index = face_2->nth_active_fe_index(0); + Assert(face_1->get_fe(face_1_index) == face_2->get_fe(face_1_index), + ExcMessage ("Matching periodic cells need to use the same finite element")); + + const FiniteElement<dim, spacedim> &fe = face_1->get_fe(face_1_index); + + Assert(component_mask.represents_n_components(fe.n_components()), + ExcMessage ("The number of components in the mask has to be either " + "zero or equal to the number of components in the finite " "element.")); + + const unsigned int dofs_per_face = fe.dofs_per_face; + + std::vector<types::global_dof_index> dofs_1(dofs_per_face); + std::vector<types::global_dof_index> dofs_2(dofs_per_face); + + face_1->get_dof_indices(dofs_1, face_1_index); + face_2->get_dof_indices(dofs_2, face_2_index); + + // Well, this is a hack: + // + // There is no + // face_to_face_index(face_index, + // face_orientation, + // face_flip, + // face_rotation) + // function in FiniteElementData, so we have to use + // face_to_cell_index(face_index, face + // face_orientation, + // face_flip, + // face_rotation) + // But this will give us an index on a cell - something we cannot work + // with directly. But luckily we can match them back :-] + + std::map<unsigned int, unsigned int> cell_to_rotated_face_index; + + // Build up a cell to face index for face_2: + for (unsigned int i = 0; i < dofs_per_face; ++i) + { + const unsigned int cell_index = fe.face_to_cell_index(i, 0, /* It doesn't really matter, just assume + * we're on the first face... + */ + true, false, false // default orientation + ); + cell_to_rotated_face_index[cell_index] = i; + } + + // loop over all dofs on face 2 and constrain them again the ones on face 1 + for (unsigned int i=0; i<dofs_per_face; ++i) + if (!constraint_matrix.is_constrained(dofs_2[i])) + if ((component_mask.n_selected_components(fe.n_components()) + == fe.n_components()) + || + component_mask[fe.face_system_to_component_index(i).first]) + { + // as mentioned in the comment above this function, we need + // to be careful about treating identity constraints differently. + // consequently, find out whether this dof 'i' will be + // identity constrained + // + // to check whether this is the case, first see whether there are + // any weights other than 0 and 1, then in a first stage make sure + // that if so there is only one weight equal to 1 + bool is_identity_constrained = true; + for (unsigned int jj=0; jj<dofs_per_face; ++jj) + if (((transformation(i,jj) == 0) || (transformation(i,jj) == 1)) == false) + { + is_identity_constrained = false; + break; + } + unsigned int identity_constraint_target = numbers::invalid_unsigned_int; + if (is_identity_constrained == true) + { + bool one_identity_found = false; + for (unsigned int jj=0; jj<dofs_per_face; ++jj) + if (transformation(i,jj) == 1) + { + if (one_identity_found == false) + { + one_identity_found = true; + identity_constraint_target = jj; + } + else + { + is_identity_constrained = false; + identity_constraint_target = numbers::invalid_unsigned_int; + break; + } + } + } + + // now treat constraints, either as an equality constraint or + // as a sequence of constraints + if (is_identity_constrained == true) + { + // Query the correct face_index on face_2 respecting the given + // orientation: + const unsigned int j = + cell_to_rotated_face_index[fe.face_to_cell_index(identity_constraint_target, + 0, /* It doesn't really matter, just assume + * we're on the first face... + */ + face_orientation, face_flip, face_rotation)]; + + // if the two aren't already identity constrained (whichever way + // around, then enter the constraint. otherwise there is nothing + // for us still to do + if (constraint_matrix.are_identity_constrained(dofs_2[i], dofs_1[i]) == false) + { + constraint_matrix.add_line(dofs_2[i]); + constraint_matrix.add_entry(dofs_2[i], dofs_1[j], 1); + } + } + else + { + // this is just a regular constraint. enter it piece by piece + constraint_matrix.add_line(dofs_2[i]); + for (unsigned int jj=0; jj<dofs_per_face; ++jj) + { + // Query the correct face_index on face_2 respecting the given + // orientation: + const unsigned int j = + cell_to_rotated_face_index[fe.face_to_cell_index(jj, 0, /* It doesn't really matter, just assume + * we're on the first face... + */ + face_orientation, face_flip, face_rotation)]; + + // And finally constrain the two DoFs respecting component_mask: + if (transformation(i,jj) != 0) + constraint_matrix.add_entry(dofs_2[i], dofs_1[j], + transformation(i,jj)); + } + } + } + } + } + } + + + template <typename FaceIterator> + void + make_periodicity_constraints (const FaceIterator &face_1, + const typename identity<FaceIterator>::type &face_2, + dealii::ConstraintMatrix &constraint_matrix, + const ComponentMask &component_mask, + const bool face_orientation, + const bool face_flip, + const bool face_rotation) + { + static const int dim = FaceIterator::AccessorType::dimension; + + Assert( (dim != 1) || + (face_orientation == true && + face_flip == false && + face_rotation == false), + ExcMessage ("The supplied orientation " + "(face_orientation, face_flip, face_rotation) " + "is invalid for 1D")); + + Assert( (dim != 2) || + (face_orientation == true && + face_rotation == false), + ExcMessage ("The supplied orientation " + "(face_orientation, face_flip, face_rotation) " + "is invalid for 2D")); + + Assert(face_1 != face_2, + ExcMessage ("face_1 and face_2 are equal! Cannot constrain DoFs " + "on the very same face")); + + Assert(face_1->at_boundary() && face_2->at_boundary(), + ExcMessage ("Faces for periodicity constraints must be on the boundary")); + + + // A lookup table on how to go through the child faces depending on the + // orientation: + + static const int lookup_table_2d[2][2] = + { + // flip: + {0, 1}, // false + {1, 0}, // true + }; + + static const int lookup_table_3d[2][2][2][4] = + { + // orientation flip rotation + { { {0, 2, 1, 3}, // false false false + {2, 3, 0, 1}, // false false true + }, + { {3, 1, 2, 0}, // false true false + {1, 0, 3, 2}, // false true true + }, + }, + { { {0, 1, 2, 3}, // true false false + {1, 3, 0, 2}, // true false true + }, + { {3, 2, 1, 0}, // true true false + {2, 0, 3, 1}, // true true true + }, + }, + }; + + // In the case that both faces have children, we loop over all + // children and apply make_periodicty_constrains recursively: + if (face_1->has_children() && face_2->has_children()) + { + Assert(face_1->n_children() == GeometryInfo<dim>::max_children_per_face && + face_2->n_children() == GeometryInfo<dim>::max_children_per_face, + ExcNotImplemented()); + + for (unsigned int i = 0; i < GeometryInfo<dim>::max_children_per_face; ++i) + { + // Lookup the index for the second face + unsigned int j; + switch (dim) + { + case 2: + j = lookup_table_2d[face_flip][i]; + break; + case 3: + j = lookup_table_3d[face_orientation][face_flip][face_rotation][i]; + break; + default: + AssertThrow(false, ExcNotImplemented()); + } + + make_periodicity_constraints (face_1->child(i), + face_2->child(j), + constraint_matrix, + component_mask, + face_orientation, + face_flip, + face_rotation); + } + } + else + // otherwise at least one of the two faces is active and + // we need to enter the constraints + { + if (face_2->has_children() == false) + set_periodicity_constraints(face_2, face_1, + FullMatrix<double>(IdentityMatrix(face_1->get_fe(face_1->nth_active_fe_index(0)).dofs_per_face)), + constraint_matrix, + component_mask, + face_orientation, face_flip, face_rotation); + else + set_periodicity_constraints(face_1, face_2, + FullMatrix<double>(IdentityMatrix(face_1->get_fe(face_1->nth_active_fe_index(0)).dofs_per_face)), + constraint_matrix, + component_mask, + face_orientation, face_flip, face_rotation); + } + } + + + + template<typename DH> + void + make_periodicity_constraints (const DH &dof_handler, + const types::boundary_id b_id1, + const types::boundary_id b_id2, + const int direction, + dealii::ConstraintMatrix &constraint_matrix, + const ComponentMask &component_mask) + { + Tensor<1,DH::space_dimension> dummy; + make_periodicity_constraints (dof_handler, + b_id1, + b_id2, + direction, + dummy, + constraint_matrix, + component_mask); + } + + + + template<typename DH> + void + make_periodicity_constraints (const DH &dof_handler, + const types::boundary_id b_id1, + const types::boundary_id b_id2, + const int direction, + dealii::Tensor<1,DH::space_dimension> &offset, + dealii::ConstraintMatrix &constraint_matrix, + const ComponentMask &component_mask) + { + static const int space_dim = DH::space_dimension; + Assert (0<=direction && direction<space_dim, + ExcIndexRange (direction, 0, space_dim)); + +#if defined(DEBUG) && defined(DEAL_II_WITH_P4EST) + // Check whether we run on a non parallel mesh or on a + // parallel::distributed::Triangulation in serial + { + typedef parallel::distributed::Triangulation<DH::dimension,DH::space_dimension> PTRIA; + const PTRIA *ptria_p = dynamic_cast<const PTRIA *> (&dof_handler.get_tria()); + Assert ((ptria_p == 0 || Utilities::MPI::n_mpi_processes(ptria_p->get_communicator()) == 1), + ExcMessage ("This function can not be used with distributed triangulations." + "See the documentation for more information.")); + } +#endif + + Assert (b_id1 != b_id2, + ExcMessage ("The boundary indicators b_id1 and b_id2 must be" + "different to denote different boundaries.")); + + typedef typename DH::face_iterator FaceIterator; + typedef std::map<FaceIterator, std::pair<FaceIterator, std::bitset<3> > > FaceMap; + + // Collect matching periodic cells on the coarsest level: + FaceMap matched_cells = + GridTools::collect_periodic_face_pairs(dof_handler, + b_id1, b_id2, + direction, offset); + + // And apply the low level make_periodicity_constraints function to + // every matching pair: + for (typename FaceMap::iterator it = matched_cells.begin(); + it != matched_cells.end(); ++it) + { + typedef typename DH::face_iterator FaceIterator; + const FaceIterator &face_1 = it->first; + const FaceIterator &face_2 = it->second.first; + const std::bitset<3> &orientation = it->second.second; + + Assert(face_1->at_boundary() && face_2->at_boundary(), + ExcInternalError()); + + Assert (face_1->boundary_indicator() == b_id1 && + face_2->boundary_indicator() == b_id2, + ExcInternalError()); + + Assert (face_1 != face_2, + ExcInternalError()); + + make_periodicity_constraints(face_1, + face_2, + constraint_matrix, + component_mask, + orientation[0], + orientation[1], + orientation[2]); + } + } + + + + template<typename DH> + void + make_periodicity_constraints (const DH &dof_handler, + const types::boundary_id b_id, + const int direction, + dealii::ConstraintMatrix &constraint_matrix, + const ComponentMask &component_mask) + { + Tensor<1,DH::space_dimension> dummy; + make_periodicity_constraints (dof_handler, + b_id, + direction, + dummy, + constraint_matrix, + component_mask); + } + + + + template<typename DH> + void + make_periodicity_constraints (const DH &dof_handler, + const types::boundary_id b_id, + const int direction, + dealii::Tensor<1,DH::space_dimension> &offset, + dealii::ConstraintMatrix &constraint_matrix, + const ComponentMask &component_mask) + { + static const int dim = DH::dimension; + static const int space_dim = DH::space_dimension; + + Assert (0<=direction && direction<space_dim, + ExcIndexRange (direction, 0, space_dim)); + + Assert(dim == space_dim, + ExcNotImplemented()); + +#if defined(DEBUG) && defined(DEAL_II_WITH_P4EST) + // Check whether we run on a non parallel mesh or on a + // parallel::distributed::Triangulation in serial + { + typedef typename parallel::distributed::Triangulation<DH::dimension,DH::space_dimension> PTRIA; + const PTRIA *ptria_p = dynamic_cast<const PTRIA *> (&dof_handler.get_tria()); + Assert ((ptria_p == 0 || Utilities::MPI::n_mpi_processes(ptria_p->get_communicator()) == 1), + ExcMessage ("This function can not be used with distributed triangulations." + "See the documentation for more information.")); + } +#endif + + typedef typename DH::face_iterator FaceIterator; + typedef std::map<FaceIterator, FaceIterator> FaceMap; + + // Collect matching periodic cells on the coarsest level: + FaceMap matched_cells = + GridTools::collect_periodic_face_pairs(dof_handler, + b_id, + direction, offset); + + // And apply the low level make_periodicity_constraints function to + // every matching pair: + for (typename FaceMap::iterator it = matched_cells.begin(); + it != matched_cells.end(); ++it) + { + typedef typename DH::face_iterator FaceIterator; + const FaceIterator &face_1 = it->first; + const FaceIterator &face_2 = it->second; + + Assert(face_1->at_boundary() && face_2->at_boundary(), + ExcInternalError()); + + Assert (face_1->boundary_indicator() == b_id && + face_2->boundary_indicator() == b_id, + ExcInternalError()); + + Assert (face_1 != face_2, + ExcInternalError()); + + make_periodicity_constraints(face_1, + face_2, + constraint_matrix, + component_mask + /* standard orientation */); + } + } + + + + namespace internal + { + namespace + { + /** + * This is a function that is called by the _2 function and that + * operates on a range of cells only. It is used to split up the + * whole range of cells into chunks which are then worked on in + * parallel, if multithreading is available. + */ + template <int dim, int spacedim> + void + compute_intergrid_weights_3 ( + const dealii::DoFHandler<dim,spacedim> &coarse_grid, + const unsigned int coarse_component, + const InterGridMap<dealii::DoFHandler<dim,spacedim> > &coarse_to_fine_grid_map, + const std::vector<dealii::Vector<double> > ¶meter_dofs, + const std::vector<types::global_dof_index> &weight_mapping, + std::vector<std::map<types::global_dof_index, float> > &weights, + const typename dealii::DoFHandler<dim,spacedim>::active_cell_iterator &begin, + const typename dealii::DoFHandler<dim,spacedim>::active_cell_iterator &end) + { + // aliases to the finite elements used by the dof handlers: + const FiniteElement<dim,spacedim> &coarse_fe = coarse_grid.get_fe(); + + // for each cell on the parameter grid: find out which degrees of + // freedom on the fine grid correspond in which way to the degrees + // of freedom on the parameter grid + // + // since for continuous FEs some dofs exist on more than one cell, + // we have to track which ones were already visited. the problem is + // that if we visit a dof first on one cell and compute its weight + // with respect to some global dofs to be non-zero, and later visit + // the dof again on another cell and (since we are on another cell) + // recompute the weights with respect to the same dofs as above to + // be zero now, we have to preserve them. we therefore overwrite + // all weights if they are nonzero and do not enforce zero weights + // since that might be only due to the fact that we are on another + // cell. + // + // example: + // coarse grid + // | | | + // *-----*-----* + // | cell|cell | + // | 1 | 2 | + // | | | + // 0-----1-----* + // + // fine grid + // | | | | | + // *--*--*--*--* + // | | | | | + // *--*--*--*--* + // | | | | | + // *--x--y--*--* + // + // when on cell 1, we compute the weights of dof 'x' to be 1/2 from + // parameter dofs 0 and 1, respectively. however, when later we are + // on cell 2, we again compute the prolongation of shape function 1 + // restricted to cell 2 to the globla grid and find that the weight + // of global dof 'x' now is zero. however, we should not overwrite + // the old value. + // + // we therefore always only set nonzero values. why adding up is + // not useful: dof 'y' would get weight 1 from parameter dof 1 on + // both cells 1 and 2, but the correct weight is nevertheless only + // 1. + + // vector to hold the representation of a single degree of freedom + // on the coarse grid (for the selected fe) on the fine grid + const types::global_dof_index n_fine_dofs = weight_mapping.size(); + dealii::Vector<double> global_parameter_representation (n_fine_dofs); + + typename dealii::DoFHandler<dim,spacedim>::active_cell_iterator cell; + std::vector<types::global_dof_index> parameter_dof_indices (coarse_fe.dofs_per_cell); + + for (cell=begin; cell!=end; ++cell) + { + // get the global indices of the parameter dofs on this + // parameter grid cell + cell->get_dof_indices (parameter_dof_indices); + + // loop over all dofs on this cell and check whether they are + // interesting for us + for (unsigned int local_dof=0; + local_dof<coarse_fe.dofs_per_cell; + ++local_dof) + if (coarse_fe.system_to_component_index(local_dof).first + == + coarse_component) + { + // the how-many-th parameter is this on this cell? + const unsigned int local_parameter_dof + = coarse_fe.system_to_component_index(local_dof).second; + + global_parameter_representation = 0; + + // distribute the representation of + // @p{local_parameter_dof} on the parameter grid cell + // @p{cell} to the global data space + coarse_to_fine_grid_map[cell]-> + set_dof_values_by_interpolation (parameter_dofs[local_parameter_dof], + global_parameter_representation); + // now that we've got the global representation of each + // parameter dof, we've only got to clobber the non-zero + // entries in that vector and store the result + // + // what we have learned: if entry @p{i} of the global + // vector holds the value @p{v[i]}, then this is the + // weight with which the present dof contributes to + // @p{i}. there may be several such @p{i}s and their + // weights' sum should be one. Then, @p{v[i]} should be + // equal to @p{\sum_j w_{ij} p[j]} with @p{p[j]} be the + // values of the degrees of freedom on the coarse grid. + // we can thus compute constraints which link the degrees + // of freedom @p{v[i]} on the fine grid to those on the + // coarse grid, @p{p[j]}. Now to use these as real + // constraints, rather than as additional equations, we + // have to identify representants among the @p{i} for + // each @p{j}. this will be done by simply taking the + // first @p{i} for which @p{w_{ij}==1}. + // + // guard modification of the weights array by a Mutex. + // since it should happen rather rarely that there are + // several threads operating on different intergrid + // weights, have only one mutex for all of them + static Threads::Mutex mutex; + Threads::Mutex::ScopedLock lock (mutex); + for (types::global_dof_index i=0; i<global_parameter_representation.size(); ++i) + // set this weight if it belongs to a parameter dof. + if (weight_mapping[i] != numbers::invalid_dof_index) + { + // only overwrite old value if not by zero + if (global_parameter_representation(i) != 0) + { + const types::global_dof_index wi = parameter_dof_indices[local_dof], + wj = weight_mapping[i]; + weights[wi][wj] = global_parameter_representation(i); + }; + } + else + Assert (global_parameter_representation(i) == 0, + ExcInternalError()); + } + } + } + + + /** + * This is a helper function that is used in the computation of + * integrid constraints. See the function for a thorough description + * of how it works. + */ + template <int dim, int spacedim> + void + compute_intergrid_weights_2 ( + const dealii::DoFHandler<dim,spacedim> &coarse_grid, + const unsigned int coarse_component, + const InterGridMap<dealii::DoFHandler<dim,spacedim> > &coarse_to_fine_grid_map, + const std::vector<dealii::Vector<double> > ¶meter_dofs, + const std::vector<types::global_dof_index> &weight_mapping, + std::vector<std::map<types::global_dof_index,float> > &weights) + { + // simply distribute the range of cells to different threads + typedef typename dealii::DoFHandler<dim,spacedim>::active_cell_iterator active_cell_iterator; + std::vector<std::pair<active_cell_iterator,active_cell_iterator> > + cell_intervals = Threads::split_range<active_cell_iterator> (coarse_grid.begin_active(), + coarse_grid.end(), + multithread_info.n_default_threads); + + // TODO: use WorkStream here + + Threads::TaskGroup<> tasks; + void (*fun_ptr) (const dealii::DoFHandler<dim,spacedim> &, + const unsigned int , + const InterGridMap<dealii::DoFHandler<dim,spacedim> > &, + const std::vector<dealii::Vector<double> > &, + const std::vector<types::global_dof_index> &, + std::vector<std::map<types::global_dof_index, float> > &, + const typename dealii::DoFHandler<dim,spacedim>::active_cell_iterator &, + const typename dealii::DoFHandler<dim,spacedim>::active_cell_iterator &) + = &compute_intergrid_weights_3<dim>; + for (unsigned int i=0; i<multithread_info.n_default_threads; ++i) + tasks += Threads::new_task (fun_ptr, + coarse_grid, coarse_component, + coarse_to_fine_grid_map, parameter_dofs, + weight_mapping, weights, + cell_intervals[i].first, + cell_intervals[i].second); + + // wait for the tasks to finish + tasks.join_all (); + } + + + + /** + * This is a helper function that is used in the computation of + * integrid constraints. See the function for a thorough description + * of how it works. + */ + template <int dim, int spacedim> + unsigned int + compute_intergrid_weights_1 ( + const dealii::DoFHandler<dim,spacedim> &coarse_grid, + const unsigned int coarse_component, + const dealii::DoFHandler<dim,spacedim> &fine_grid, + const unsigned int fine_component, + const InterGridMap<dealii::DoFHandler<dim,spacedim> > &coarse_to_fine_grid_map, + std::vector<std::map<types::global_dof_index, float> > &weights, + std::vector<types::global_dof_index> &weight_mapping) + { + // aliases to the finite elements used by the dof handlers: + const FiniteElement<dim,spacedim> &coarse_fe = coarse_grid.get_fe(), + &fine_fe = fine_grid.get_fe(); + + // global numbers of dofs + const types::global_dof_index n_coarse_dofs = coarse_grid.n_dofs(), + n_fine_dofs = fine_grid.n_dofs(); + + // local numbers of dofs + const unsigned int fine_dofs_per_cell = fine_fe.dofs_per_cell; + + // alias the number of dofs per cell belonging to the + // coarse_component which is to be the restriction of the fine + // grid: + const unsigned int coarse_dofs_per_cell_component + = coarse_fe.base_element(coarse_fe.component_to_base_index(coarse_component).first).dofs_per_cell; + + + // Try to find out whether the grids stem from the same coarse + // grid. This is a rather crude test, but better than nothing + Assert (coarse_grid.get_tria().n_cells(0) == fine_grid.get_tria().n_cells(0), + ExcGridsDontMatch()); + + // check whether the map correlates the right objects + Assert (&coarse_to_fine_grid_map.get_source_grid() == &coarse_grid, + ExcGridsDontMatch ()); + Assert (&coarse_to_fine_grid_map.get_destination_grid() == &fine_grid, + ExcGridsDontMatch ()); + + + // check whether component numbers are valid + AssertIndexRange (coarse_component,coarse_fe.n_components()); + AssertIndexRange (fine_component, fine_fe.n_components()); + + // check whether respective finite elements are equal + Assert (coarse_fe.base_element (coarse_fe.component_to_base_index(coarse_component).first) + == + fine_fe.base_element (fine_fe.component_to_base_index(fine_component).first), + ExcFiniteElementsDontMatch()); + +#ifdef DEBUG + // if in debug mode, check whether the coarse grid is indeed + // coarser everywhere than the fine grid + for (typename dealii::DoFHandler<dim,spacedim>::active_cell_iterator + cell=coarse_grid.begin_active(); + cell != coarse_grid.end(); ++cell) + Assert (cell->level() <= coarse_to_fine_grid_map[cell]->level(), + ExcGridNotCoarser()); +#endif + + /* + * From here on: the term `parameter' refers to the selected + * component on the coarse grid and its analogon on the fine grid. + * The naming of variables containing this term is due to the fact + * that `selected_component' is longer, but also due to the fact + * that the code of this function was initially written for a + * program where the component which we wanted to match between + * grids was actually the `parameter' variable. + * + * Likewise, the terms `parameter grid' and `state grid' refer to + * the coarse and fine grids, respectively. + * + * Changing the names of variables would in principle be a good + * idea, but would not make things simpler and would be another + * source of errors. If anyone feels like doing so: patches would + * be welcome! + */ + + + + // set up vectors of cell-local data; each vector represents one + // degree of freedom of the coarse-grid variable in the fine-grid + // element + std::vector<dealii::Vector<double> > + parameter_dofs (coarse_dofs_per_cell_component, + dealii::Vector<double>(fine_dofs_per_cell)); + // for each coarse dof: find its position within the fine element + // and set this value to one in the respective vector (all other + // values are zero by construction) + for (unsigned int local_coarse_dof=0; + local_coarse_dof<coarse_dofs_per_cell_component; + ++local_coarse_dof) + for (unsigned int fine_dof=0; fine_dof<fine_fe.dofs_per_cell; ++fine_dof) + if (fine_fe.system_to_component_index(fine_dof) + == + std::make_pair (fine_component, local_coarse_dof)) + { + parameter_dofs[local_coarse_dof](fine_dof) = 1.; + break; + }; + + + // find out how many DoFs there are on the grids belonging to the + // components we want to match + unsigned int n_parameters_on_fine_grid=0; + if (true) + { + // have a flag for each dof on the fine grid and set it to true + // if this is an interesting dof. finally count how many true's + // there + std::vector<bool> dof_is_interesting (fine_grid.n_dofs(), false); + std::vector<types::global_dof_index> local_dof_indices (fine_fe.dofs_per_cell); + + for (typename dealii::DoFHandler<dim,spacedim>::active_cell_iterator + cell=fine_grid.begin_active(); + cell!=fine_grid.end(); ++cell) + { + cell->get_dof_indices (local_dof_indices); + for (unsigned int i=0; i<fine_fe.dofs_per_cell; ++i) + if (fine_fe.system_to_component_index(i).first == fine_component) + dof_is_interesting[local_dof_indices[i]] = true; + }; + + n_parameters_on_fine_grid = std::count (dof_is_interesting.begin(), + dof_is_interesting.end(), + true); + }; + + + // set up the weights mapping + weights.clear (); + weights.resize (n_coarse_dofs); + + weight_mapping.clear (); + weight_mapping.resize (n_fine_dofs, numbers::invalid_dof_index); + + if (true) + { + std::vector<types::global_dof_index> local_dof_indices(fine_fe.dofs_per_cell); + unsigned int next_free_index=0; + for (typename dealii::DoFHandler<dim,spacedim>::active_cell_iterator + cell=fine_grid.begin_active(); + cell != fine_grid.end(); ++cell) + { + cell->get_dof_indices (local_dof_indices); + for (unsigned int i=0; i<fine_fe.dofs_per_cell; ++i) + // if this DoF is a parameter dof and has not yet been + // numbered, then do so + if ((fine_fe.system_to_component_index(i).first == fine_component) && + (weight_mapping[local_dof_indices[i]] == numbers::invalid_dof_index)) + { + weight_mapping[local_dof_indices[i]] = next_free_index; + ++next_free_index; + }; + }; + + Assert (next_free_index == n_parameters_on_fine_grid, + ExcInternalError()); + }; + + + // for each cell on the parameter grid: find out which degrees of + // freedom on the fine grid correspond in which way to the degrees + // of freedom on the parameter grid + // + // do this in a separate function to allow for multithreading + // there. see this function also if you want to read more + // information on the algorithm used. + compute_intergrid_weights_2 (coarse_grid, coarse_component, + coarse_to_fine_grid_map, parameter_dofs, + weight_mapping, weights); + + + // ok, now we have all weights for each dof on the fine grid. if in + // debug mode lets see if everything went smooth, i.e. each dof has + // sum of weights one + // + // in other words this means that if the sum of all shape functions + // on the parameter grid is one (which is always the case), then + // the representation on the state grid should be as well (division + // of unity) + // + // if the parameter grid has more than one component, then the + // respective dofs of the other components have sum of weights + // zero, of course. we do not explicitly ask which component a dof + // belongs to, but this at least tests some errors +#ifdef DEBUG + for (unsigned int col=0; col<n_parameters_on_fine_grid; ++col) + { + double sum=0; + for (types::global_dof_index row=0; row<n_coarse_dofs; ++row) + if (weights[row].find(col) != weights[row].end()) + sum += weights[row][col]; + Assert ((std::fabs(sum-1) < 1.e-12) || + ((coarse_fe.n_components()>1) && (sum==0)), ExcInternalError()); + }; +#endif + + + return n_parameters_on_fine_grid; + } + + + } + } + + + + template <int dim, int spacedim> + void + compute_intergrid_constraints ( + const DoFHandler<dim,spacedim> &coarse_grid, + const unsigned int coarse_component, + const DoFHandler<dim,spacedim> &fine_grid, + const unsigned int fine_component, + const InterGridMap<DoFHandler<dim,spacedim> > &coarse_to_fine_grid_map, + ConstraintMatrix &constraints) + { + // store the weights with which a dof on the parameter grid contributes + // to a dof on the fine grid. see the long doc below for more info + // + // allocate as many rows as there are parameter dofs on the coarse grid + // and as many columns as there are parameter dofs on the fine grid. + // + // weight_mapping is used to map the global (fine grid) parameter dof + // indices to the columns + // + // in the original implementation, the weights array was actually of + // FullMatrix<double> type. this wasted huge amounts of memory, but was + // fast. nonetheless, since the memory consumption was quadratic in the + // number of degrees of freedom, this was not very practical, so we now + // use a vector of rows of the matrix, and in each row a vector of + // pairs (colnum,value). this seems like the best tradeoff between + // memory and speed, as it is now linear in memory and still fast + // enough. + // + // to save some memory and since the weights are usually (negative) + // powers of 2, we choose the value type of the matrix to be @p{float} + // rather than @p{double}. + std::vector<std::map<types::global_dof_index, float> > weights; + + // this is this mapping. there is one entry for each dof on the fine + // grid; if it is a parameter dof, then its value is the column in + // weights for that parameter dof, if it is any other dof, then its + // value is -1, indicating an error + std::vector<types::global_dof_index> weight_mapping; + + const unsigned int n_parameters_on_fine_grid + = internal::compute_intergrid_weights_1 (coarse_grid, coarse_component, + fine_grid, fine_component, + coarse_to_fine_grid_map, + weights, weight_mapping); + + // global numbers of dofs + const types::global_dof_index n_coarse_dofs = coarse_grid.n_dofs(), + n_fine_dofs = fine_grid.n_dofs(); + + + // get an array in which we store which dof on the coarse grid is a + // parameter and which is not + std::vector<bool> coarse_dof_is_parameter (coarse_grid.n_dofs()); + if (true) + { + std::vector<bool> mask (coarse_grid.get_fe().n_components(), + false); + mask[coarse_component] = true; + extract_dofs (coarse_grid, ComponentMask(mask), coarse_dof_is_parameter); + } + + // now we know that the weights in each row constitute a constraint. + // enter this into the constraints object + // + // first task: for each parameter dof on the parameter grid, find a + // representant on the fine, global grid. this is possible since we use + // conforming finite element. we take this representant to be the first + // element in this row with weight identical to one. the representant + // will become an unconstrained degree of freedom, while all others + // will be constrained to this dof (and possibly others) + std::vector<types::global_dof_index> representants(n_coarse_dofs, numbers::invalid_dof_index); + for (types::global_dof_index parameter_dof=0; parameter_dof<n_coarse_dofs; + ++parameter_dof) + if (coarse_dof_is_parameter[parameter_dof] == true) + { + // if this is the line of a parameter dof on the coarse grid, + // then it should have at least one dependent node on the fine + // grid + Assert (weights[parameter_dof].size() > 0, ExcInternalError()); + + // find the column where the representant is mentioned + std::map<types::global_dof_index,float>::const_iterator i = weights[parameter_dof].begin(); + for (; i!=weights[parameter_dof].end(); ++i) + if (i->second == 1) + break; + Assert (i!=weights[parameter_dof].end(), ExcInternalError()); + const types::global_dof_index column = i->first; + + // now we know in which column of weights the representant is, + // but we don't know its global index. get it using the inverse + // operation of the weight_mapping + types::global_dof_index global_dof=0; + for (; global_dof<weight_mapping.size(); ++global_dof) + if (weight_mapping[global_dof] == static_cast<types::global_dof_index>(column)) + break; + Assert (global_dof < weight_mapping.size(), ExcInternalError()); + + // now enter the representants global index into our list + representants[parameter_dof] = global_dof; + } + else + { + // consistency check: if this is no parameter dof on the coarse + // grid, then the respective row must be empty! + Assert (weights[parameter_dof].size() == 0, ExcInternalError()); + }; + + + + // note for people that want to optimize this function: the largest + // part of the computing time is spent in the following, rather + // innocent block of code. basically, it must be the + // ConstraintMatrix::add_entry call which takes the bulk of the time, + // but it is not known to the author how to make it faster... + std::vector<std::pair<types::global_dof_index,double> > constraint_line; + for (types::global_dof_index global_dof=0; global_dof<n_fine_dofs; ++global_dof) + if (weight_mapping[global_dof] != numbers::invalid_dof_index) + // this global dof is a parameter dof, so it may carry a constraint + // note that for each global dof, the sum of weights shall be one, + // so we can find out whether this dof is constrained in the + // following way: if the only weight in this row is a one, and the + // representant for the parameter dof of the line in which this one + // is is the present dof, then we consider this dof to be + // unconstrained. otherwise, all other dofs are constrained + { + const types::global_dof_index col = weight_mapping[global_dof]; + Assert (col < n_parameters_on_fine_grid, ExcInternalError()); + + types::global_dof_index first_used_row=0; + + { + Assert (weights.size() > 0, ExcInternalError()); + std::map<types::global_dof_index,float>::const_iterator + col_entry = weights[0].end(); + for (; first_used_row<n_coarse_dofs; ++first_used_row) + { + col_entry = weights[first_used_row].find(col); + if (col_entry != weights[first_used_row].end()) + break; + } + + Assert (col_entry != weights[first_used_row].end(), ExcInternalError()); + + if ((col_entry->second == 1) && + (representants[first_used_row] == global_dof)) + // dof unconstrained or constrained to itself (in case this + // cell is mapped to itself, rather than to children of + // itself) + continue; + } + + + // otherwise enter all constraints + constraints.add_line (global_dof); + + constraint_line.clear (); + for (types::global_dof_index row=first_used_row; row<n_coarse_dofs; ++row) + { + const std::map<types::global_dof_index,float>::const_iterator + j = weights[row].find(col); + if ((j != weights[row].end()) && (j->second != 0)) + constraint_line.push_back (std::pair<types::global_dof_index,double>(representants[row], + j->second)); + }; + + constraints.add_entries (global_dof, constraint_line); + }; + } + + + + template <int dim, int spacedim> + void + compute_intergrid_transfer_representation ( + const DoFHandler<dim,spacedim> &coarse_grid, + const unsigned int coarse_component, + const DoFHandler<dim,spacedim> &fine_grid, + const unsigned int fine_component, + const InterGridMap<DoFHandler<dim,spacedim> > &coarse_to_fine_grid_map, + std::vector<std::map<types::global_dof_index, float> > &transfer_representation) + { + // store the weights with which a dof on the parameter grid contributes + // to a dof on the fine grid. see the long doc below for more info + // + // allocate as many rows as there are parameter dofs on the coarse grid + // and as many columns as there are parameter dofs on the fine grid. + // + // weight_mapping is used to map the global (fine grid) parameter dof + // indices to the columns + // + // in the original implementation, the weights array was actually of + // FullMatrix<double> type. this wasted huge amounts of memory, but was + // fast. nonetheless, since the memory consumption was quadratic in the + // number of degrees of freedom, this was not very practical, so we now + // use a vector of rows of the matrix, and in each row a vector of + // pairs (colnum,value). this seems like the best tradeoff between + // memory and speed, as it is now linear in memory and still fast + // enough. + // + // to save some memory and since the weights are usually (negative) + // powers of 2, we choose the value type of the matrix to be @p{float} + // rather than @p{double}. + std::vector<std::map<types::global_dof_index, float> > weights; + + // this is this mapping. there is one entry for each dof on the fine + // grid; if it is a parameter dof, then its value is the column in + // weights for that parameter dof, if it is any other dof, then its + // value is -1, indicating an error + std::vector<types::global_dof_index> weight_mapping; + + internal::compute_intergrid_weights_1 (coarse_grid, coarse_component, + fine_grid, fine_component, + coarse_to_fine_grid_map, + weights, weight_mapping); + + // now compute the requested representation + const types::global_dof_index n_global_parm_dofs + = std::count_if (weight_mapping.begin(), weight_mapping.end(), + std::bind2nd (std::not_equal_to<types::global_dof_index> (), numbers::invalid_dof_index)); + + // first construct the inverse mapping of weight_mapping + std::vector<types::global_dof_index> inverse_weight_mapping (n_global_parm_dofs, + DoFHandler<dim,spacedim>::invalid_dof_index); + for (types::global_dof_index i=0; i<weight_mapping.size(); ++i) + { + const types::global_dof_index parameter_dof = weight_mapping[i]; + // if this global dof is a parameter + if (parameter_dof != numbers::invalid_dof_index) + { + Assert (parameter_dof < n_global_parm_dofs, ExcInternalError()); + Assert ((inverse_weight_mapping[parameter_dof] == DoFHandler<dim,spacedim>::invalid_dof_index), + ExcInternalError()); + + inverse_weight_mapping[parameter_dof] = i; + }; + }; + + // next copy over weights array and replace respective numbers + const types::global_dof_index n_rows = weight_mapping.size(); + + transfer_representation.clear (); + transfer_representation.resize (n_rows); + + const types::global_dof_index n_coarse_dofs = coarse_grid.n_dofs(); + for (types::global_dof_index i=0; i<n_coarse_dofs; ++i) + { + std::map<types::global_dof_index, float>::const_iterator j = weights[i].begin(); + for (; j!=weights[i].end(); ++j) + { + const types::global_dof_index p = inverse_weight_mapping[j->first]; + Assert (p<n_rows, ExcInternalError()); + + transfer_representation[p][i] = j->second; + }; + }; + } + + + + template <int dim, int spacedim, template <int,int> class DH> + void + make_zero_boundary_constraints (const DH<dim, spacedim> &dof, + const types::boundary_id boundary_indicator, + ConstraintMatrix &zero_boundary_constraints, + const ComponentMask &component_mask) + { + Assert (component_mask.represents_n_components(dof.get_fe().n_components()), + ExcMessage ("The number of components in the mask has to be either " + "zero or equal to the number of components in the finite " + "element.")); + + const unsigned int n_components = DoFTools::n_components (dof); + + Assert (component_mask.n_selected_components(n_components) > 0, + ComponentMask::ExcNoComponentSelected()); + + // a field to store the indices + std::vector<types::global_dof_index> face_dofs; + face_dofs.reserve (max_dofs_per_face(dof)); + + typename DH<dim,spacedim>::active_cell_iterator + cell = dof.begin_active(), + endc = dof.end(); + for (; cell!=endc; ++cell) + if (!cell->is_artificial()) + for (unsigned int face_no = 0; face_no < GeometryInfo<dim>::faces_per_cell; + ++face_no) + { + const FiniteElement<dim,spacedim> &fe = cell->get_fe(); + + const typename DH<dim,spacedim>::face_iterator face = cell->face(face_no); + + // if face is on the boundary and satisfies the correct + // boundary id property + if (face->at_boundary () + && + ((boundary_indicator == numbers::invalid_boundary_id) + || + (face->boundary_indicator() == boundary_indicator))) + { + // get indices and physical location on this face + face_dofs.resize (fe.dofs_per_face); + face->get_dof_indices (face_dofs, cell->active_fe_index()); + + // enter those dofs into the list that match the component + // signature. + for (unsigned int i=0; i<face_dofs.size(); ++i) + { + // Find out if a dof has a contribution in this + // component, and if so, add it to the list + const ComponentMask &nonzero_component_array + = cell->get_fe().get_nonzero_components (i); + bool nonzero = false; + for (unsigned int c=0; c<n_components; ++c) + if (nonzero_component_array[c] && component_mask[c]) + { + nonzero = true; + break; + } + + if (nonzero) + zero_boundary_constraints.add_line (face_dofs[i]); + } + } + } + } + + + + template <int dim, int spacedim, template <int,int> class DH> + void + make_zero_boundary_constraints (const DH<dim, spacedim> &dof, + ConstraintMatrix &zero_boundary_constraints, + const ComponentMask &component_mask) + { + make_zero_boundary_constraints(dof, numbers::invalid_boundary_id, + zero_boundary_constraints, component_mask); + } + + +} // end of namespace DoFTools + + + +// explicit instantiations + +#include "dof_tools_constraints.inst" + + + +DEAL_II_NAMESPACE_CLOSE diff --git a/deal.II/source/dofs/dof_tools_constraints.inst.in b/deal.II/source/dofs/dof_tools_constraints.inst.in new file mode 100644 index 0000000000..246f53aa02 --- /dev/null +++ b/deal.II/source/dofs/dof_tools_constraints.inst.in @@ -0,0 +1,147 @@ +// --------------------------------------------------------------------- +// $Id$ +// +// Copyright (C) 2009 - 2013 by the deal.II authors +// +// This file is part of the deal.II library. +// +// The deal.II library is free software; you can use it, redistribute +// it, and/or modify it under the terms of the GNU Lesser General +// Public License as published by the Free Software Foundation; either +// version 2.1 of the License, or (at your option) any later version. +// The full text of the license can be found in the file LICENSE at +// the top level of the deal.II distribution. +// +// --------------------------------------------------------------------- + + + + +for (DH : DOFHANDLERS; deal_II_dimension : DIMENSIONS) +{ + template + void + DoFTools::make_hanging_node_constraints (const DH &dof_handler, + ConstraintMatrix &constraints); + +#if deal_II_dimension != 1 + template + void + DoFTools::make_periodicity_constraints (const DH::face_iterator &, + const DH::face_iterator &, + dealii::ConstraintMatrix &, + const ComponentMask &, + bool, bool, bool); + + template + void + DoFTools::make_periodicity_constraints(const DH &, + const types::boundary_id, + const types::boundary_id, + const int, + dealii::ConstraintMatrix &, + const ComponentMask &); + + template + void + DoFTools::make_periodicity_constraints(const DH &, + const types::boundary_id, + const types::boundary_id, + const int, + dealii::Tensor<1,DH::space_dimension> &, + dealii::ConstraintMatrix &, + const ComponentMask &); + + template + void + DoFTools::make_periodicity_constraints(const DH &, + const types::boundary_id, + const int, + dealii::ConstraintMatrix &, + const ComponentMask &); + + template + void + DoFTools::make_periodicity_constraints(const DH &, + const types::boundary_id, + const int, + dealii::Tensor<1,DH::space_dimension> &, + dealii::ConstraintMatrix &, + const ComponentMask &); +#endif +} + +for (deal_II_dimension : DIMENSIONS) +{ +#if deal_II_dimension != 1 + template + void + DoFTools::make_hanging_node_constraints (const MGDoFHandler<deal_II_dimension> &dof_handler, + ConstraintMatrix &constraints); + +#endif + +#if deal_II_dimension < 3 + +template +void +DoFTools:: +make_hanging_node_constraints (const DoFHandler<deal_II_dimension,deal_II_dimension+1> &dof_handler, + ConstraintMatrix &constraints); +#endif + +#if deal_II_dimension == 3 +template +void +DoFTools:: +make_hanging_node_constraints (const DoFHandler<1,3> &dof_handler, + ConstraintMatrix &constraints); +#endif + +template +void +DoFTools::make_zero_boundary_constraints +(const DoFHandler<deal_II_dimension> &, + ConstraintMatrix &, + const ComponentMask &); + +template +void +DoFTools::make_zero_boundary_constraints +(const DoFHandler<deal_II_dimension> &, + const types::boundary_id , + ConstraintMatrix &, + const ComponentMask &); + +template +void +DoFTools::make_zero_boundary_constraints +(const hp::DoFHandler<deal_II_dimension> &, + ConstraintMatrix &, + const ComponentMask &); + +template +void +DoFTools::make_zero_boundary_constraints +(const hp::DoFHandler<deal_II_dimension> &, + const types::boundary_id , + ConstraintMatrix &, + const ComponentMask &); + +template +void +DoFTools::compute_intergrid_constraints<deal_II_dimension> ( + const DoFHandler<deal_II_dimension> &, const unsigned int, + const DoFHandler<deal_II_dimension> &, const unsigned int, + const InterGridMap<DoFHandler<deal_II_dimension> > &, + ConstraintMatrix&); + +template +void +DoFTools::compute_intergrid_transfer_representation<deal_II_dimension> +(const DoFHandler<deal_II_dimension> &, const unsigned int, + const DoFHandler<deal_II_dimension> &, const unsigned int, + const InterGridMap<DoFHandler<deal_II_dimension> > &, + std::vector<std::map<types::global_dof_index, float> > &); + +} diff --git a/deal.II/source/dofs/dof_tools_sparsity.cc b/deal.II/source/dofs/dof_tools_sparsity.cc new file mode 100644 index 0000000000..c48bf2f677 --- /dev/null +++ b/deal.II/source/dofs/dof_tools_sparsity.cc @@ -0,0 +1,1179 @@ +// --------------------------------------------------------------------- +// $Id$ +// +// Copyright (C) 1999 - 2013 by the deal.II authors +// +// This file is part of the deal.II library. +// +// The deal.II library is free software; you can use it, redistribute +// it, and/or modify it under the terms of the GNU Lesser General +// Public License as published by the Free Software Foundation; either +// version 2.1 of the License, or (at your option) any later version. +// The full text of the license can be found in the file LICENSE at +// the top level of the deal.II distribution. +// +// --------------------------------------------------------------------- + +#include <deal.II/base/multithread_info.h> +#include <deal.II/base/thread_management.h> +#include <deal.II/base/quadrature_lib.h> +#include <deal.II/base/table.h> +#include <deal.II/base/template_constraints.h> +#include <deal.II/base/utilities.h> +#include <deal.II/lac/sparsity_pattern.h> +#include <deal.II/lac/compressed_sparsity_pattern.h> +#include <deal.II/lac/compressed_set_sparsity_pattern.h> +#include <deal.II/lac/compressed_simple_sparsity_pattern.h> +#include <deal.II/lac/trilinos_sparsity_pattern.h> +#include <deal.II/lac/block_sparsity_pattern.h> +#include <deal.II/lac/vector.h> +#include <deal.II/lac/constraint_matrix.h> +#include <deal.II/grid/tria.h> +#include <deal.II/grid/tria_iterator.h> +#include <deal.II/grid/intergrid_map.h> +#include <deal.II/grid/grid_tools.h> +#include <deal.II/dofs/dof_handler.h> +#include <deal.II/dofs/dof_accessor.h> +#include <deal.II/fe/fe.h> +#include <deal.II/fe/fe_values.h> +#include <deal.II/fe/fe_tools.h> +#include <deal.II/hp/fe_collection.h> +#include <deal.II/hp/q_collection.h> +#include <deal.II/hp/fe_values.h> +#include <deal.II/dofs/dof_tools.h> +#include <deal.II/numerics/vector_tools.h> + +#include <deal.II/multigrid/mg_dof_handler.h> + +#include <algorithm> +#include <numeric> + +DEAL_II_NAMESPACE_OPEN + + + +namespace DoFTools +{ + + template <class DH, class SparsityPattern> + void + make_sparsity_pattern (const DH &dof, + SparsityPattern &sparsity, + const ConstraintMatrix &constraints, + const bool keep_constrained_dofs, + const types::subdomain_id subdomain_id) + { + const types::global_dof_index n_dofs = dof.n_dofs(); + + Assert (sparsity.n_rows() == n_dofs, + ExcDimensionMismatch (sparsity.n_rows(), n_dofs)); + Assert (sparsity.n_cols() == n_dofs, + ExcDimensionMismatch (sparsity.n_cols(), n_dofs)); + + // If we have a distributed::Triangulation only allow locally_owned + // subdomain. Not setting a subdomain is also okay, because we skip + // ghost cells in the loop below. + Assert ( + (dof.get_tria().locally_owned_subdomain() == numbers::invalid_subdomain_id) + || + (subdomain_id == numbers::invalid_subdomain_id) + || + (subdomain_id == dof.get_tria().locally_owned_subdomain()), + ExcMessage ("For parallel::distributed::Triangulation objects and " + "associated DoF handler objects, asking for any subdomain other " + "than the locally owned one does not make sense.")); + + std::vector<types::global_dof_index> dofs_on_this_cell; + dofs_on_this_cell.reserve (max_dofs_per_cell(dof)); + typename DH::active_cell_iterator cell = dof.begin_active(), + endc = dof.end(); + + // In case we work with a distributed sparsity pattern of Trilinos + // type, we only have to do the work if the current cell is owned by + // the calling processor. Otherwise, just continue. + for (; cell!=endc; ++cell) + if (((subdomain_id == numbers::invalid_subdomain_id) + || + (subdomain_id == cell->subdomain_id())) + && + cell->is_locally_owned()) + { + const unsigned int dofs_per_cell = cell->get_fe().dofs_per_cell; + dofs_on_this_cell.resize (dofs_per_cell); + cell->get_dof_indices (dofs_on_this_cell); + + // make sparsity pattern for this cell. if no constraints pattern + // was given, then the following call acts as if simply no + // constraints existed + constraints.add_entries_local_to_global (dofs_on_this_cell, + sparsity, + keep_constrained_dofs); + } + } + + + + template <class DH, class SparsityPattern> + void + make_sparsity_pattern (const DH &dof, + const Table<2,Coupling> &couplings, + SparsityPattern &sparsity, + const ConstraintMatrix &constraints, + const bool keep_constrained_dofs, + const types::subdomain_id subdomain_id) + { + const types::global_dof_index n_dofs = dof.n_dofs(); + + Assert (sparsity.n_rows() == n_dofs, + ExcDimensionMismatch (sparsity.n_rows(), n_dofs)); + Assert (sparsity.n_cols() == n_dofs, + ExcDimensionMismatch (sparsity.n_cols(), n_dofs)); + Assert (couplings.n_rows() == dof.get_fe().n_components(), + ExcDimensionMismatch(couplings.n_rows(), dof.get_fe().n_components())); + Assert (couplings.n_cols() == dof.get_fe().n_components(), + ExcDimensionMismatch(couplings.n_cols(), dof.get_fe().n_components())); + + // If we have a distributed::Triangulation only allow locally_owned + // subdomain. Not setting a subdomain is also okay, because we skip + // ghost cells in the loop below. + Assert ( + (dof.get_tria().locally_owned_subdomain() == numbers::invalid_subdomain_id) + || + (subdomain_id == numbers::invalid_subdomain_id) + || + (subdomain_id == dof.get_tria().locally_owned_subdomain()), + ExcMessage ("For parallel::distributed::Triangulation objects and " + "associated DoF handler objects, asking for any subdomain other " + "than the locally owned one does not make sense.")); + + const hp::FECollection<DH::dimension,DH::space_dimension> fe_collection (dof.get_fe()); + + // first, for each finite element, build a mask for each dof, not like + // the one given which represents components. make sure we do the right + // thing also with respect to non-primitive shape functions, which + // takes some additional thought + std::vector<Table<2,bool> > dof_mask(fe_collection.size()); + + // check whether the table of couplings contains only true arguments, + // i.e., we do not exclude any index. that is the easy case, since we + // don't have to set up the tables + bool need_dof_mask = false; + for (unsigned int i=0; i<couplings.n_rows(); ++i) + for (unsigned int j=0; j<couplings.n_cols(); ++j) + if (couplings(i,j) == none) + need_dof_mask = true; + + if (need_dof_mask == true) + for (unsigned int f=0; f<fe_collection.size(); ++f) + { + const unsigned int dofs_per_cell = fe_collection[f].dofs_per_cell; + + dof_mask[f].reinit (dofs_per_cell, dofs_per_cell); + + for (unsigned int i=0; i<dofs_per_cell; ++i) + for (unsigned int j=0; j<dofs_per_cell; ++j) + if (fe_collection[f].is_primitive(i) && + fe_collection[f].is_primitive(j)) + dof_mask[f](i,j) + = (couplings(fe_collection[f].system_to_component_index(i).first, + fe_collection[f].system_to_component_index(j).first) != none); + else + { + const unsigned int first_nonzero_comp_i + = fe_collection[f].get_nonzero_components(i).first_selected_component(); + const unsigned int first_nonzero_comp_j + = fe_collection[f].get_nonzero_components(j).first_selected_component(); + Assert (first_nonzero_comp_i < fe_collection[f].n_components(), + ExcInternalError()); + Assert (first_nonzero_comp_j < fe_collection[f].n_components(), + ExcInternalError()); + + dof_mask[f](i,j) + = (couplings(first_nonzero_comp_i,first_nonzero_comp_j) != none); + } + } + + + std::vector<types::global_dof_index> dofs_on_this_cell(fe_collection.max_dofs_per_cell()); + typename DH::active_cell_iterator cell = dof.begin_active(), + endc = dof.end(); + + // In case we work with a distributed sparsity pattern of Trilinos + // type, we only have to do the work if the current cell is owned by + // the calling processor. Otherwise, just continue. + for (; cell!=endc; ++cell) + if (((subdomain_id == numbers::invalid_subdomain_id) + || + (subdomain_id == cell->subdomain_id())) + && + cell->is_locally_owned()) + { + const unsigned int fe_index = cell->active_fe_index(); + const unsigned int dofs_per_cell =fe_collection[fe_index].dofs_per_cell; + + dofs_on_this_cell.resize (dofs_per_cell); + cell->get_dof_indices (dofs_on_this_cell); + + + // make sparsity pattern for this cell. if no constraints pattern + // was given, then the following call acts as if simply no + // constraints existed + constraints.add_entries_local_to_global (dofs_on_this_cell, + sparsity, + keep_constrained_dofs, + dof_mask[fe_index]); + } + } + + + + template <class DH, class SparsityPattern> + void + make_sparsity_pattern ( + const DH &dof_row, + const DH &dof_col, + SparsityPattern &sparsity) + { + const types::global_dof_index n_dofs_row = dof_row.n_dofs(); + const types::global_dof_index n_dofs_col = dof_col.n_dofs(); + + Assert (sparsity.n_rows() == n_dofs_row, + ExcDimensionMismatch (sparsity.n_rows(), n_dofs_row)); + Assert (sparsity.n_cols() == n_dofs_col, + ExcDimensionMismatch (sparsity.n_cols(), n_dofs_col)); + +//TODO: Looks like wasteful memory management here + + const std::list<std::pair<typename DH::cell_iterator, + typename DH::cell_iterator> > + cell_list + = GridTools::get_finest_common_cells (dof_row, dof_col); + + + typename std::list<std::pair<typename DH::cell_iterator, + typename DH::cell_iterator> >::const_iterator + cell_iter = cell_list.begin(); + + for (; cell_iter!=cell_list.end(); ++cell_iter) + { + const typename DH::cell_iterator cell_row = cell_iter->first; + const typename DH::cell_iterator cell_col = cell_iter->second; + + if (!cell_row->has_children() && !cell_col->has_children()) + { + const unsigned int dofs_per_cell_row = + cell_row->get_fe().dofs_per_cell; + const unsigned int dofs_per_cell_col = + cell_col->get_fe().dofs_per_cell; + std::vector<types::global_dof_index> + local_dof_indices_row(dofs_per_cell_row); + std::vector<types::global_dof_index> + local_dof_indices_col(dofs_per_cell_col); + cell_row->get_dof_indices (local_dof_indices_row); + cell_col->get_dof_indices (local_dof_indices_col); + for (unsigned int i=0; i<dofs_per_cell_row; ++i) + sparsity.add_entries (local_dof_indices_row[i], + local_dof_indices_col.begin(), + local_dof_indices_col.end()); + } + else if (cell_row->has_children()) + { + const std::vector<typename DH::active_cell_iterator > + child_cells = GridTools::get_active_child_cells<DH> (cell_row); + for (unsigned int i=0; i<child_cells.size(); i++) + { + const typename DH::cell_iterator + cell_row_child = child_cells[i]; + const unsigned int dofs_per_cell_row = + cell_row_child->get_fe().dofs_per_cell; + const unsigned int dofs_per_cell_col = + cell_col->get_fe().dofs_per_cell; + std::vector<types::global_dof_index> + local_dof_indices_row(dofs_per_cell_row); + std::vector<types::global_dof_index> + local_dof_indices_col(dofs_per_cell_col); + cell_row_child->get_dof_indices (local_dof_indices_row); + cell_col->get_dof_indices (local_dof_indices_col); + for (unsigned int i=0; i<dofs_per_cell_row; ++i) + sparsity.add_entries (local_dof_indices_row[i], + local_dof_indices_col.begin(), + local_dof_indices_col.end()); + } + } + else + { + std::vector<typename DH::active_cell_iterator> + child_cells = GridTools::get_active_child_cells<DH> (cell_col); + for (unsigned int i=0; i<child_cells.size(); i++) + { + const typename DH::active_cell_iterator + cell_col_child = child_cells[i]; + const unsigned int dofs_per_cell_row = + cell_row->get_fe().dofs_per_cell; + const unsigned int dofs_per_cell_col = + cell_col_child->get_fe().dofs_per_cell; + std::vector<types::global_dof_index> + local_dof_indices_row(dofs_per_cell_row); + std::vector<types::global_dof_index> + local_dof_indices_col(dofs_per_cell_col); + cell_row->get_dof_indices (local_dof_indices_row); + cell_col_child->get_dof_indices (local_dof_indices_col); + for (unsigned int i=0; i<dofs_per_cell_row; ++i) + sparsity.add_entries (local_dof_indices_row[i], + local_dof_indices_col.begin(), + local_dof_indices_col.end()); + } + } + } + } + + + + template <class DH, class SparsityPattern> + void + make_boundary_sparsity_pattern ( + const DH &dof, + const std::vector<types::global_dof_index> &dof_to_boundary_mapping, + SparsityPattern &sparsity) + { + if (DH::dimension == 1) + { + // there are only 2 boundary indicators in 1d, so it is no + // performance problem to call the other function + typename DH::FunctionMap boundary_indicators; + boundary_indicators[0] = 0; + boundary_indicators[1] = 0; + make_boundary_sparsity_pattern<DH, SparsityPattern> (dof, + boundary_indicators, + dof_to_boundary_mapping, + sparsity); + return; + } + + const types::global_dof_index n_dofs = dof.n_dofs(); + + AssertDimension (dof_to_boundary_mapping.size(), n_dofs); + AssertDimension (sparsity.n_rows(), dof.n_boundary_dofs()); + AssertDimension (sparsity.n_cols(), dof.n_boundary_dofs()); +#ifdef DEBUG + if (sparsity.n_rows() != 0) + { + types::global_dof_index max_element = 0; + for (std::vector<types::global_dof_index>::const_iterator i=dof_to_boundary_mapping.begin(); + i!=dof_to_boundary_mapping.end(); ++i) + if ((*i != DH::invalid_dof_index) && + (*i > max_element)) + max_element = *i; + AssertDimension (max_element, sparsity.n_rows()-1); + }; +#endif + + std::vector<types::global_dof_index> dofs_on_this_face; + dofs_on_this_face.reserve (max_dofs_per_face(dof)); + + // loop over all faces to check whether they are at a boundary. note + // that we need not take special care of single lines (using + // @p{cell->has_boundary_lines}), since we do not support boundaries of + // dimension dim-2, and so every boundary line is also part of a + // boundary face. + typename DH::active_cell_iterator cell = dof.begin_active(), + endc = dof.end(); + for (; cell!=endc; ++cell) + for (unsigned int f=0; f<GeometryInfo<DH::dimension>::faces_per_cell; ++f) + if (cell->at_boundary(f)) + { + const unsigned int dofs_per_face = cell->get_fe().dofs_per_face; + dofs_on_this_face.resize (dofs_per_face); + cell->face(f)->get_dof_indices (dofs_on_this_face, + cell->active_fe_index()); + + // make sparsity pattern for this cell + for (unsigned int i=0; i<dofs_per_face; ++i) + for (unsigned int j=0; j<dofs_per_face; ++j) + sparsity.add (dof_to_boundary_mapping[dofs_on_this_face[i]], + dof_to_boundary_mapping[dofs_on_this_face[j]]); + } + } + + + + template <class DH, class SparsityPattern> + void make_boundary_sparsity_pattern ( + const DH &dof, + const typename FunctionMap<DH::space_dimension>::type &boundary_indicators, + const std::vector<types::global_dof_index> &dof_to_boundary_mapping, + SparsityPattern &sparsity) + { + if (DH::dimension == 1) + { + // first check left, then right boundary point + for (unsigned int direction=0; direction<2; ++direction) + { + // if this boundary is not requested, then go on with next one + if (boundary_indicators.find(direction) == + boundary_indicators.end()) + continue; + + // find active cell at that boundary: first go to left/right, + // then to children + typename DH::level_cell_iterator cell = dof.begin(0); + while (!cell->at_boundary(direction)) + cell = cell->neighbor(direction); + while (!cell->active()) + cell = cell->child(direction); + + const unsigned int dofs_per_vertex = cell->get_fe().dofs_per_vertex; + std::vector<types::global_dof_index> boundary_dof_boundary_indices (dofs_per_vertex); + + // next get boundary mapped dof indices of boundary dofs + for (unsigned int i=0; i<dofs_per_vertex; ++i) + boundary_dof_boundary_indices[i] + = dof_to_boundary_mapping[cell->vertex_dof_index(direction,i)]; + + for (unsigned int i=0; i<dofs_per_vertex; ++i) + sparsity.add_entries (boundary_dof_boundary_indices[i], + boundary_dof_boundary_indices.begin(), + boundary_dof_boundary_indices.end()); + }; + return; + } + + const types::global_dof_index n_dofs = dof.n_dofs(); + + AssertDimension (dof_to_boundary_mapping.size(), n_dofs); + Assert (boundary_indicators.find(numbers::internal_face_boundary_id) == boundary_indicators.end(), + typename DH::ExcInvalidBoundaryIndicator()); + Assert (sparsity.n_rows() == dof.n_boundary_dofs (boundary_indicators), + ExcDimensionMismatch (sparsity.n_rows(), dof.n_boundary_dofs (boundary_indicators))); + Assert (sparsity.n_cols() == dof.n_boundary_dofs (boundary_indicators), + ExcDimensionMismatch (sparsity.n_cols(), dof.n_boundary_dofs (boundary_indicators))); +#ifdef DEBUG + if (sparsity.n_rows() != 0) + { + types::global_dof_index max_element = 0; + for (std::vector<types::global_dof_index>::const_iterator i=dof_to_boundary_mapping.begin(); + i!=dof_to_boundary_mapping.end(); ++i) + if ((*i != DH::invalid_dof_index) && + (*i > max_element)) + max_element = *i; + AssertDimension (max_element, sparsity.n_rows()-1); + }; +#endif + + std::vector<types::global_dof_index> dofs_on_this_face; + dofs_on_this_face.reserve (max_dofs_per_face(dof)); + typename DH::active_cell_iterator cell = dof.begin_active(), + endc = dof.end(); + for (; cell!=endc; ++cell) + for (unsigned int f=0; f<GeometryInfo<DH::dimension>::faces_per_cell; ++f) + if (boundary_indicators.find(cell->face(f)->boundary_indicator()) != + boundary_indicators.end()) + { + const unsigned int dofs_per_face = cell->get_fe().dofs_per_face; + dofs_on_this_face.resize (dofs_per_face); + cell->face(f)->get_dof_indices (dofs_on_this_face, + cell->active_fe_index()); + + // make sparsity pattern for this cell + for (unsigned int i=0; i<dofs_per_face; ++i) + for (unsigned int j=0; j<dofs_per_face; ++j) + sparsity.add (dof_to_boundary_mapping[dofs_on_this_face[i]], + dof_to_boundary_mapping[dofs_on_this_face[j]]); + } + } + + + + template <class DH, class SparsityPattern> + void + make_flux_sparsity_pattern (const DH &dof, + SparsityPattern &sparsity, + const ConstraintMatrix &constraints, + const bool keep_constrained_dofs, + const types::subdomain_id subdomain_id) + + // TODO: QA: reduce the indentation level of this method..., Maier 2012 + + { + const types::global_dof_index n_dofs = dof.n_dofs(); + + AssertDimension (sparsity.n_rows(), n_dofs); + AssertDimension (sparsity.n_cols(), n_dofs); + + // If we have a distributed::Triangulation only allow locally_owned + // subdomain. Not setting a subdomain is also okay, because we skip + // ghost cells in the loop below. + Assert ( + (dof.get_tria().locally_owned_subdomain() == numbers::invalid_subdomain_id) + || + (subdomain_id == numbers::invalid_subdomain_id) + || + (subdomain_id == dof.get_tria().locally_owned_subdomain()), + ExcMessage ("For parallel::distributed::Triangulation objects and " + "associated DoF handler objects, asking for any subdomain other " + "than the locally owned one does not make sense.")); + + std::vector<types::global_dof_index> dofs_on_this_cell; + std::vector<types::global_dof_index> dofs_on_other_cell; + dofs_on_this_cell.reserve (max_dofs_per_cell(dof)); + dofs_on_other_cell.reserve (max_dofs_per_cell(dof)); + typename DH::active_cell_iterator cell = dof.begin_active(), + endc = dof.end(); + + // TODO: in an old implementation, we used user flags before to tag + // faces that were already touched. this way, we could reduce the work + // a little bit. now, we instead add only data from one side. this + // should be OK, but we need to actually verify it. + + // In case we work with a distributed sparsity pattern of Trilinos + // type, we only have to do the work if the current cell is owned by + // the calling processor. Otherwise, just continue. + for (; cell!=endc; ++cell) + if (((subdomain_id == numbers::invalid_subdomain_id) + || + (subdomain_id == cell->subdomain_id())) + && + cell->is_locally_owned()) + { + const unsigned int n_dofs_on_this_cell = cell->get_fe().dofs_per_cell; + dofs_on_this_cell.resize (n_dofs_on_this_cell); + cell->get_dof_indices (dofs_on_this_cell); + + // make sparsity pattern for this cell. if no constraints pattern + // was given, then the following call acts as if simply no + // constraints existed + constraints.add_entries_local_to_global (dofs_on_this_cell, + sparsity, + keep_constrained_dofs); + + for (unsigned int face = 0; + face < GeometryInfo<DH::dimension>::faces_per_cell; + ++face) + { + typename DH::face_iterator cell_face = cell->face(face); + if (! cell->at_boundary(face) ) + { + typename DH::level_cell_iterator neighbor = cell->neighbor(face); + + // in 1d, we do not need to worry whether the neighbor + // might have children and then loop over those children. + // rather, we may as well go straight to to cell behind + // this particular cell's most terminal child + if (DH::dimension==1) + while (neighbor->has_children()) + neighbor = neighbor->child(face==0 ? 1 : 0); + + if (neighbor->has_children()) + { + for (unsigned int sub_nr = 0; + sub_nr != cell_face->number_of_children(); + ++sub_nr) + { + const typename DH::level_cell_iterator + sub_neighbor + = cell->neighbor_child_on_subface (face, sub_nr); + + const unsigned int n_dofs_on_neighbor + = sub_neighbor->get_fe().dofs_per_cell; + dofs_on_other_cell.resize (n_dofs_on_neighbor); + sub_neighbor->get_dof_indices (dofs_on_other_cell); + + constraints.add_entries_local_to_global + (dofs_on_this_cell, dofs_on_other_cell, + sparsity, keep_constrained_dofs); + constraints.add_entries_local_to_global + (dofs_on_other_cell, dofs_on_this_cell, + sparsity, keep_constrained_dofs); + } + } + else + { + // Refinement edges are taken care of by coarser + // cells + + // TODO: in the distributed case, we miss out the + // constraints when the neighbor cell is coarser, but + // only the current cell is owned locally! + if (cell->neighbor_is_coarser(face)) + continue; + + const unsigned int n_dofs_on_neighbor + = neighbor->get_fe().dofs_per_cell; + dofs_on_other_cell.resize (n_dofs_on_neighbor); + + neighbor->get_dof_indices (dofs_on_other_cell); + + constraints.add_entries_local_to_global + (dofs_on_this_cell, dofs_on_other_cell, + sparsity, keep_constrained_dofs); + + // only need to add these in case the neighbor cell + // is not locally owned - otherwise, we touch each + // face twice and hence put the indices the other way + // around + if (!cell->neighbor(face)->active() + || + (cell->neighbor(face)->subdomain_id() != + cell->subdomain_id())) + constraints.add_entries_local_to_global + (dofs_on_other_cell, dofs_on_this_cell, + sparsity, keep_constrained_dofs); + } + } + } + } + } + + + + template <class DH, class SparsityPattern> + void + make_flux_sparsity_pattern (const DH &dof, + SparsityPattern &sparsity) + { + ConstraintMatrix constraints; + make_flux_sparsity_pattern (dof, sparsity, constraints); + } + + template <int dim, int spacedim> + Table<2,Coupling> + dof_couplings_from_component_couplings (const FiniteElement<dim,spacedim> &fe, + const Table<2,Coupling> &component_couplings) + { + Assert(component_couplings.n_rows() == fe.n_components(), + ExcDimensionMismatch(component_couplings.n_rows(), + fe.n_components())); + Assert(component_couplings.n_cols() == fe.n_components(), + ExcDimensionMismatch(component_couplings.n_cols(), + fe.n_components())); + + const unsigned int n_dofs = fe.dofs_per_cell; + + Table<2,Coupling> dof_couplings (n_dofs, n_dofs); + + for (unsigned int i=0; i<n_dofs; ++i) + { + const unsigned int ii + = (fe.is_primitive(i) ? + fe.system_to_component_index(i).first + : + fe.get_nonzero_components(i).first_selected_component() + ); + Assert (ii < fe.n_components(), ExcInternalError()); + + for (unsigned int j=0; j<n_dofs; ++j) + { + const unsigned int jj + = (fe.is_primitive(j) ? + fe.system_to_component_index(j).first + : + fe.get_nonzero_components(j).first_selected_component() + ); + Assert (jj < fe.n_components(), ExcInternalError()); + + dof_couplings(i,j) = component_couplings(ii,jj); + } + } + return dof_couplings; + } + + + + template <int dim, int spacedim> + std::vector<Table<2,Coupling> > + dof_couplings_from_component_couplings + (const hp::FECollection<dim,spacedim> &fe, + const Table<2,Coupling> &component_couplings) + { + std::vector<Table<2,Coupling> > return_value (fe.size()); + for (unsigned int i=0; i<fe.size(); ++i) + return_value[i] + = dof_couplings_from_component_couplings(fe[i], component_couplings); + + return return_value; + } + + + + namespace internal + { + namespace + { + + // implementation of the same function in namespace DoFTools for + // non-hp DoFHandlers + template <class DH, class SparsityPattern> + void + make_flux_sparsity_pattern (const DH &dof, + SparsityPattern &sparsity, + const Table<2,Coupling> &int_mask, + const Table<2,Coupling> &flux_mask) + { + const FiniteElement<DH::dimension,DH::space_dimension> &fe = dof.get_fe(); + + std::vector<types::global_dof_index> dofs_on_this_cell(fe.dofs_per_cell); + std::vector<types::global_dof_index> dofs_on_other_cell(fe.dofs_per_cell); + + const Table<2,Coupling> + int_dof_mask = dof_couplings_from_component_couplings(fe, int_mask), + flux_dof_mask = dof_couplings_from_component_couplings(fe, flux_mask); + + Table<2,bool> support_on_face(fe.dofs_per_cell, + GeometryInfo<DH::dimension>::faces_per_cell); + for (unsigned int i=0; i<fe.dofs_per_cell; ++i) + for (unsigned int f=0; f<GeometryInfo<DH::dimension>::faces_per_cell; ++f) + support_on_face(i,f) = fe.has_support_on_face(i,f); + + typename DH::active_cell_iterator cell = dof.begin_active(), + endc = dof.end(); + for (; cell!=endc; ++cell) + if (cell->is_locally_owned()) + { + cell->get_dof_indices (dofs_on_this_cell); + // make sparsity pattern for this cell + for (unsigned int i=0; i<fe.dofs_per_cell; ++i) + for (unsigned int j=0; j<fe.dofs_per_cell; ++j) + if (int_dof_mask(i,j) != none) + sparsity.add (dofs_on_this_cell[i], + dofs_on_this_cell[j]); + + // Loop over all interior neighbors + for (unsigned int face = 0; + face < GeometryInfo<DH::dimension>::faces_per_cell; + ++face) + { + const typename DH::face_iterator + cell_face = cell->face(face); + if (cell_face->user_flag_set ()) + continue; + + if (cell->at_boundary (face) ) + { + for (unsigned int i=0; i<fe.dofs_per_cell; ++i) + { + const bool i_non_zero_i = support_on_face (i, face); + for (unsigned int j=0; j<fe.dofs_per_cell; ++j) + { + const bool j_non_zero_i = support_on_face (j, face); + + if ((flux_dof_mask(i,j) == always) + || + (flux_dof_mask(i,j) == nonzero + && + i_non_zero_i + && + j_non_zero_i)) + sparsity.add (dofs_on_this_cell[i], + dofs_on_this_cell[j]); + } + } + } + else + { + typename DH::level_cell_iterator + neighbor = cell->neighbor(face); + // Refinement edges are taken care of by coarser + // cells + if (cell->neighbor_is_coarser(face)) + continue; + + typename DH::face_iterator cell_face = cell->face(face); + const unsigned int + neighbor_face = cell->neighbor_of_neighbor(face); + + if (cell_face->has_children()) + { + for (unsigned int sub_nr = 0; + sub_nr != cell_face->n_children(); + ++sub_nr) + { + const typename DH::level_cell_iterator + sub_neighbor + = cell->neighbor_child_on_subface (face, sub_nr); + + sub_neighbor->get_dof_indices (dofs_on_other_cell); + for (unsigned int i=0; i<fe.dofs_per_cell; ++i) + { + const bool i_non_zero_i = support_on_face (i, face); + const bool i_non_zero_e = support_on_face (i, neighbor_face); + for (unsigned int j=0; j<fe.dofs_per_cell; ++j) + { + const bool j_non_zero_i = support_on_face (j, face); + const bool j_non_zero_e = support_on_face (j, neighbor_face); + + if (flux_dof_mask(i,j) == always) + { + sparsity.add (dofs_on_this_cell[i], + dofs_on_other_cell[j]); + sparsity.add (dofs_on_other_cell[i], + dofs_on_this_cell[j]); + sparsity.add (dofs_on_this_cell[i], + dofs_on_this_cell[j]); + sparsity.add (dofs_on_other_cell[i], + dofs_on_other_cell[j]); + } + else if (flux_dof_mask(i,j) == nonzero) + { + if (i_non_zero_i && j_non_zero_e) + sparsity.add (dofs_on_this_cell[i], + dofs_on_other_cell[j]); + if (i_non_zero_e && j_non_zero_i) + sparsity.add (dofs_on_other_cell[i], + dofs_on_this_cell[j]); + if (i_non_zero_i && j_non_zero_i) + sparsity.add (dofs_on_this_cell[i], + dofs_on_this_cell[j]); + if (i_non_zero_e && j_non_zero_e) + sparsity.add (dofs_on_other_cell[i], + dofs_on_other_cell[j]); + } + + if (flux_dof_mask(j,i) == always) + { + sparsity.add (dofs_on_this_cell[j], + dofs_on_other_cell[i]); + sparsity.add (dofs_on_other_cell[j], + dofs_on_this_cell[i]); + sparsity.add (dofs_on_this_cell[j], + dofs_on_this_cell[i]); + sparsity.add (dofs_on_other_cell[j], + dofs_on_other_cell[i]); + } + else if (flux_dof_mask(j,i) == nonzero) + { + if (j_non_zero_i && i_non_zero_e) + sparsity.add (dofs_on_this_cell[j], + dofs_on_other_cell[i]); + if (j_non_zero_e && i_non_zero_i) + sparsity.add (dofs_on_other_cell[j], + dofs_on_this_cell[i]); + if (j_non_zero_i && i_non_zero_i) + sparsity.add (dofs_on_this_cell[j], + dofs_on_this_cell[i]); + if (j_non_zero_e && i_non_zero_e) + sparsity.add (dofs_on_other_cell[j], + dofs_on_other_cell[i]); + } + } + } + sub_neighbor->face(neighbor_face)->set_user_flag (); + } + } + else + { + neighbor->get_dof_indices (dofs_on_other_cell); + for (unsigned int i=0; i<fe.dofs_per_cell; ++i) + { + const bool i_non_zero_i = support_on_face (i, face); + const bool i_non_zero_e = support_on_face (i, neighbor_face); + for (unsigned int j=0; j<fe.dofs_per_cell; ++j) + { + const bool j_non_zero_i = support_on_face (j, face); + const bool j_non_zero_e = support_on_face (j, neighbor_face); + if (flux_dof_mask(i,j) == always) + { + sparsity.add (dofs_on_this_cell[i], + dofs_on_other_cell[j]); + sparsity.add (dofs_on_other_cell[i], + dofs_on_this_cell[j]); + sparsity.add (dofs_on_this_cell[i], + dofs_on_this_cell[j]); + sparsity.add (dofs_on_other_cell[i], + dofs_on_other_cell[j]); + } + if (flux_dof_mask(i,j) == nonzero) + { + if (i_non_zero_i && j_non_zero_e) + sparsity.add (dofs_on_this_cell[i], + dofs_on_other_cell[j]); + if (i_non_zero_e && j_non_zero_i) + sparsity.add (dofs_on_other_cell[i], + dofs_on_this_cell[j]); + if (i_non_zero_i && j_non_zero_i) + sparsity.add (dofs_on_this_cell[i], + dofs_on_this_cell[j]); + if (i_non_zero_e && j_non_zero_e) + sparsity.add (dofs_on_other_cell[i], + dofs_on_other_cell[j]); + } + + if (flux_dof_mask(j,i) == always) + { + sparsity.add (dofs_on_this_cell[j], + dofs_on_other_cell[i]); + sparsity.add (dofs_on_other_cell[j], + dofs_on_this_cell[i]); + sparsity.add (dofs_on_this_cell[j], + dofs_on_this_cell[i]); + sparsity.add (dofs_on_other_cell[j], + dofs_on_other_cell[i]); + } + if (flux_dof_mask(j,i) == nonzero) + { + if (j_non_zero_i && i_non_zero_e) + sparsity.add (dofs_on_this_cell[j], + dofs_on_other_cell[i]); + if (j_non_zero_e && i_non_zero_i) + sparsity.add (dofs_on_other_cell[j], + dofs_on_this_cell[i]); + if (j_non_zero_i && i_non_zero_i) + sparsity.add (dofs_on_this_cell[j], + dofs_on_this_cell[i]); + if (j_non_zero_e && i_non_zero_e) + sparsity.add (dofs_on_other_cell[j], + dofs_on_other_cell[i]); + } + } + } + neighbor->face(neighbor_face)->set_user_flag (); + } + } + } + } + } + + + // implementation of the same function in namespace DoFTools for + // non-hp DoFHandlers + template <int dim, int spacedim, class SparsityPattern> + void + make_flux_sparsity_pattern (const dealii::hp::DoFHandler<dim,spacedim> &dof, + SparsityPattern &sparsity, + const Table<2,Coupling> &int_mask, + const Table<2,Coupling> &flux_mask) + { + // while the implementation above is quite optimized and caches a + // lot of data (see e.g. the int/flux_dof_mask tables), this is no + // longer practical for the hp version since we would have to have + // it for all combinations of elements in the hp::FECollection. + // consequently, the implementation here is simpler and probably + // less efficient but at least readable... + + const dealii::hp::FECollection<dim,spacedim> &fe = dof.get_fe(); + + std::vector<types::global_dof_index> dofs_on_this_cell(DoFTools::max_dofs_per_cell(dof)); + std::vector<types::global_dof_index> dofs_on_other_cell(DoFTools::max_dofs_per_cell(dof)); + + const std::vector<Table<2,Coupling> > + int_dof_mask + = dof_couplings_from_component_couplings(fe, int_mask); + + typename dealii::hp::DoFHandler<dim,spacedim>::active_cell_iterator + cell = dof.begin_active(), + endc = dof.end(); + for (; cell!=endc; ++cell) + { + dofs_on_this_cell.resize (cell->get_fe().dofs_per_cell); + cell->get_dof_indices (dofs_on_this_cell); + + // make sparsity pattern for this cell + for (unsigned int i=0; i<cell->get_fe().dofs_per_cell; ++i) + for (unsigned int j=0; j<cell->get_fe().dofs_per_cell; ++j) + if (int_dof_mask[cell->active_fe_index()](i,j) != none) + sparsity.add (dofs_on_this_cell[i], + dofs_on_this_cell[j]); + + // Loop over all interior neighbors + for (unsigned int face = 0; + face < GeometryInfo<dim>::faces_per_cell; + ++face) + { + const typename dealii::hp::DoFHandler<dim,spacedim>::face_iterator + cell_face = cell->face(face); + if (cell_face->user_flag_set ()) + continue; + + if (cell->at_boundary (face) ) + { + for (unsigned int i=0; i<cell->get_fe().dofs_per_cell; ++i) + for (unsigned int j=0; j<cell->get_fe().dofs_per_cell; ++j) + if ((flux_mask(cell->get_fe().system_to_component_index(i).first, + cell->get_fe().system_to_component_index(j).first) + == always) + || + (flux_mask(cell->get_fe().system_to_component_index(i).first, + cell->get_fe().system_to_component_index(j).first) + == nonzero)) + sparsity.add (dofs_on_this_cell[i], + dofs_on_this_cell[j]); + } + else + { + typename dealii::hp::DoFHandler<dim,spacedim>::level_cell_iterator + neighbor = cell->neighbor(face); + + // Refinement edges are taken care of by coarser cells + if (cell->neighbor_is_coarser(face)) + continue; + + typename dealii::hp::DoFHandler<dim,spacedim>::face_iterator + cell_face = cell->face(face); + const unsigned int + neighbor_face = cell->neighbor_of_neighbor(face); + + if (cell_face->has_children()) + { + for (unsigned int sub_nr = 0; + sub_nr != cell_face->n_children(); + ++sub_nr) + { + const typename dealii::hp::DoFHandler<dim,spacedim>::level_cell_iterator + sub_neighbor + = cell->neighbor_child_on_subface (face, sub_nr); + + dofs_on_other_cell.resize (sub_neighbor->get_fe().dofs_per_cell); + sub_neighbor->get_dof_indices (dofs_on_other_cell); + for (unsigned int i=0; i<cell->get_fe().dofs_per_cell; ++i) + { + for (unsigned int j=0; j<sub_neighbor->get_fe().dofs_per_cell; + ++j) + { + if ((flux_mask(cell->get_fe().system_to_component_index(i).first, + sub_neighbor->get_fe().system_to_component_index(j).first) + == always) + || + (flux_mask(cell->get_fe().system_to_component_index(i).first, + sub_neighbor->get_fe().system_to_component_index(j).first) + == nonzero)) + { + sparsity.add (dofs_on_this_cell[i], + dofs_on_other_cell[j]); + sparsity.add (dofs_on_other_cell[i], + dofs_on_this_cell[j]); + sparsity.add (dofs_on_this_cell[i], + dofs_on_this_cell[j]); + sparsity.add (dofs_on_other_cell[i], + dofs_on_other_cell[j]); + } + + if ((flux_mask(sub_neighbor->get_fe().system_to_component_index(j).first, + cell->get_fe().system_to_component_index(i).first) + == always) + || + (flux_mask(sub_neighbor->get_fe().system_to_component_index(j).first, + cell->get_fe().system_to_component_index(i).first) + == nonzero)) + { + sparsity.add (dofs_on_this_cell[j], + dofs_on_other_cell[i]); + sparsity.add (dofs_on_other_cell[j], + dofs_on_this_cell[i]); + sparsity.add (dofs_on_this_cell[j], + dofs_on_this_cell[i]); + sparsity.add (dofs_on_other_cell[j], + dofs_on_other_cell[i]); + } + } + } + sub_neighbor->face(neighbor_face)->set_user_flag (); + } + } + else + { + dofs_on_other_cell.resize (neighbor->get_fe().dofs_per_cell); + neighbor->get_dof_indices (dofs_on_other_cell); + for (unsigned int i=0; i<cell->get_fe().dofs_per_cell; ++i) + { + for (unsigned int j=0; j<neighbor->get_fe().dofs_per_cell; ++j) + { + if ((flux_mask(cell->get_fe().system_to_component_index(i).first, + neighbor->get_fe().system_to_component_index(j).first) + == always) + || + (flux_mask(cell->get_fe().system_to_component_index(i).first, + neighbor->get_fe().system_to_component_index(j).first) + == nonzero)) + { + sparsity.add (dofs_on_this_cell[i], + dofs_on_other_cell[j]); + sparsity.add (dofs_on_other_cell[i], + dofs_on_this_cell[j]); + sparsity.add (dofs_on_this_cell[i], + dofs_on_this_cell[j]); + sparsity.add (dofs_on_other_cell[i], + dofs_on_other_cell[j]); + } + + if ((flux_mask(neighbor->get_fe().system_to_component_index(j).first, + cell->get_fe().system_to_component_index(i).first) + == always) + || + (flux_mask(neighbor->get_fe().system_to_component_index(j).first, + cell->get_fe().system_to_component_index(i).first) + == nonzero)) + { + sparsity.add (dofs_on_this_cell[j], + dofs_on_other_cell[i]); + sparsity.add (dofs_on_other_cell[j], + dofs_on_this_cell[i]); + sparsity.add (dofs_on_this_cell[j], + dofs_on_this_cell[i]); + sparsity.add (dofs_on_other_cell[j], + dofs_on_other_cell[i]); + } + } + } + neighbor->face(neighbor_face)->set_user_flag (); + } + } + } + } + } + } + + } + + + + + template <class DH, class SparsityPattern> + void + make_flux_sparsity_pattern (const DH &dof, + SparsityPattern &sparsity, + const Table<2,Coupling> &int_mask, + const Table<2,Coupling> &flux_mask) + { + // do the error checking and frame code here, and then pass on to more + // specialized functions in the internal namespace + const types::global_dof_index n_dofs = dof.n_dofs(); + const unsigned int n_comp = dof.get_fe().n_components(); + + Assert (sparsity.n_rows() == n_dofs, + ExcDimensionMismatch (sparsity.n_rows(), n_dofs)); + Assert (sparsity.n_cols() == n_dofs, + ExcDimensionMismatch (sparsity.n_cols(), n_dofs)); + Assert (int_mask.n_rows() == n_comp, + ExcDimensionMismatch (int_mask.n_rows(), n_comp)); + Assert (int_mask.n_cols() == n_comp, + ExcDimensionMismatch (int_mask.n_cols(), n_comp)); + Assert (flux_mask.n_rows() == n_comp, + ExcDimensionMismatch (flux_mask.n_rows(), n_comp)); + Assert (flux_mask.n_cols() == n_comp, + ExcDimensionMismatch (flux_mask.n_cols(), n_comp)); + + // Clear user flags because we will need them. But first we save them + // and make sure that we restore them later such that at the end of + // this function the Triangulation will be in the same state as it was + // at the beginning of this function. + std::vector<bool> user_flags; + dof.get_tria().save_user_flags(user_flags); + const_cast<Triangulation<DH::dimension,DH::space_dimension> &>(dof.get_tria()).clear_user_flags (); + + internal::make_flux_sparsity_pattern (dof, sparsity, + int_mask, flux_mask); + + // finally restore the user flags + const_cast<Triangulation<DH::dimension,DH::space_dimension> &>(dof.get_tria()).load_user_flags(user_flags); + } + + +} // end of namespace DoFTools + + +// --------------------------------------------------- explicit instantiations + +#include "dof_tools_sparsity.inst" + + + +DEAL_II_NAMESPACE_CLOSE diff --git a/deal.II/source/dofs/dof_tools_sparsity.inst.in b/deal.II/source/dofs/dof_tools_sparsity.inst.in new file mode 100644 index 0000000000..6781dbeab2 --- /dev/null +++ b/deal.II/source/dofs/dof_tools_sparsity.inst.in @@ -0,0 +1,323 @@ +// --------------------------------------------------------------------- +// $Id$ +// +// Copyright (C) 2009 - 2013 by the deal.II authors +// +// This file is part of the deal.II library. +// +// The deal.II library is free software; you can use it, redistribute +// it, and/or modify it under the terms of the GNU Lesser General +// Public License as published by the Free Software Foundation; either +// version 2.1 of the License, or (at your option) any later version. +// The full text of the license can be found in the file LICENSE at +// the top level of the deal.II distribution. +// +// --------------------------------------------------------------------- + + + +for (SP : SPARSITY_PATTERNS; deal_II_dimension : DIMENSIONS) + { + template void + DoFTools::make_sparsity_pattern<DoFHandler<deal_II_dimension,deal_II_dimension>, SP> + (const DoFHandler<deal_II_dimension,deal_II_dimension> &dof, + SP &sparsity, + const ConstraintMatrix &, + const bool, + const unsigned int); + + template void + DoFTools::make_sparsity_pattern<hp::DoFHandler<deal_II_dimension,deal_II_dimension>, SP> + (const hp::DoFHandler<deal_II_dimension,deal_II_dimension> &dof, + SP &sparsity, + const ConstraintMatrix &, + const bool, + const unsigned int); + + template void + DoFTools::make_sparsity_pattern<MGDoFHandler<deal_II_dimension,deal_II_dimension>, SP> + (const MGDoFHandler<deal_II_dimension,deal_II_dimension> &dof, + SP &sparsity, + const ConstraintMatrix &, + const bool, + const unsigned int); + + template void + DoFTools::make_sparsity_pattern<DoFHandler<deal_II_dimension,deal_II_dimension>, SP> + (const DoFHandler<deal_II_dimension,deal_II_dimension>&, + const Table<2,Coupling>&, + SP &, + const ConstraintMatrix &, + const bool, + const unsigned int); + + template void + DoFTools::make_sparsity_pattern<hp::DoFHandler<deal_II_dimension,deal_II_dimension>, SP> + (const hp::DoFHandler<deal_II_dimension,deal_II_dimension>&, + const Table<2,Coupling>&, + SP &, + const ConstraintMatrix &, + const bool, + const unsigned int); + + template void + DoFTools::make_sparsity_pattern<MGDoFHandler<deal_II_dimension,deal_II_dimension>, SP> + (const MGDoFHandler<deal_II_dimension,deal_II_dimension>&, + const Table<2,Coupling>&, + SP &, + const ConstraintMatrix &, + const bool, + const unsigned int); + + template void + DoFTools::make_sparsity_pattern<DoFHandler<deal_II_dimension,deal_II_dimension>, SP> + (const DoFHandler<deal_II_dimension,deal_II_dimension> &dof_row, + const DoFHandler<deal_II_dimension,deal_II_dimension> &dof_col, + SP &sparsity); + + template void + DoFTools::make_sparsity_pattern<hp::DoFHandler<deal_II_dimension,deal_II_dimension>, SP> + (const hp::DoFHandler<deal_II_dimension,deal_II_dimension> &dof_row, + const hp::DoFHandler<deal_II_dimension,deal_II_dimension> &dof_col, + SP &sparsity); + + template void + DoFTools::make_boundary_sparsity_pattern<DoFHandler<deal_II_dimension>,SP> + (const DoFHandler<deal_II_dimension>& dof, + const std::vector<types::global_dof_index> &, + SP &); + + template void + DoFTools::make_boundary_sparsity_pattern<hp::DoFHandler<deal_II_dimension>,SP> + (const hp::DoFHandler<deal_II_dimension>& dof, + const std::vector<types::global_dof_index> &, + SP &); + + template void + DoFTools::make_boundary_sparsity_pattern<DoFHandler<deal_II_dimension>,SP> + (const DoFHandler<deal_II_dimension>& dof, + const FunctionMap<deal_II_dimension>::type &boundary_indicators, + const std::vector<types::global_dof_index> &dof_to_boundary_mapping, + SP &sparsity); + + template void + DoFTools::make_boundary_sparsity_pattern<hp::DoFHandler<deal_II_dimension>,SP> + (const hp::DoFHandler<deal_II_dimension>& dof, + const FunctionMap<deal_II_dimension>::type &boundary_indicators, + const std::vector<types::global_dof_index> &dof_to_boundary_mapping, + SP &sparsity); + +#if deal_II_dimension < 3 + template void + DoFTools::make_boundary_sparsity_pattern<hp::DoFHandler<deal_II_dimension,deal_II_dimension+1>,SP> + (const hp::DoFHandler<deal_II_dimension,deal_II_dimension+1>& dof, + const FunctionMap<deal_II_dimension+1>::type &boundary_indicators, + const std::vector<types::global_dof_index> &dof_to_boundary_mapping, + SP &sparsity); + #endif + + template void + DoFTools::make_flux_sparsity_pattern<DoFHandler<deal_II_dimension>,SP> + (const DoFHandler<deal_II_dimension> &dof, + SP &sparsity); + + template void + DoFTools::make_flux_sparsity_pattern<hp::DoFHandler<deal_II_dimension>,SP> + (const hp::DoFHandler<deal_II_dimension> &dof, + SP &sparsity); + +#if deal_II_dimension > 1 + + template void + DoFTools::make_flux_sparsity_pattern<DoFHandler<deal_II_dimension>,SP> + (const DoFHandler<deal_II_dimension> &dof, + SP &, + const Table<2,Coupling>&, + const Table<2,Coupling>&); + + template void + DoFTools::make_flux_sparsity_pattern<DoFHandler<deal_II_dimension>,SP> + (const DoFHandler<deal_II_dimension> &dof, + SP &sparsity, + const ConstraintMatrix &constraints, + const bool, const unsigned int); + + template void + DoFTools::make_flux_sparsity_pattern<hp::DoFHandler<deal_II_dimension>,SP> + (const hp::DoFHandler<deal_II_dimension> &dof, + SP &sparsity, + const ConstraintMatrix &constraints, + const bool, const unsigned int); + + template void + DoFTools::make_flux_sparsity_pattern<hp::DoFHandler<deal_II_dimension>,SP> + (const hp::DoFHandler<deal_II_dimension> &dof, + SP &, + const Table<2,Coupling>&, + const Table<2,Coupling>&); +#endif + +#if deal_II_dimension < 3 + + template void + DoFTools::make_sparsity_pattern<DoFHandler<deal_II_dimension,deal_II_dimension+1>, SP> + (const DoFHandler<deal_II_dimension,deal_II_dimension+1> &dof, + SP &sparsity, + const ConstraintMatrix &, + const bool, + const unsigned int); + + template void + DoFTools::make_sparsity_pattern<hp::DoFHandler<deal_II_dimension,deal_II_dimension+1>, SP> + (const hp::DoFHandler<deal_II_dimension,deal_II_dimension+1> &dof, + SP &sparsity, + const ConstraintMatrix &, + const bool, + const unsigned int); + + template void + DoFTools::make_sparsity_pattern<DoFHandler<deal_II_dimension,deal_II_dimension+1>, SP> + (const DoFHandler<deal_II_dimension,deal_II_dimension+1>&, + const Table<2,Coupling>&, + SP &, + const ConstraintMatrix &, + const bool, + const unsigned int); + + template void + DoFTools::make_sparsity_pattern<hp::DoFHandler<deal_II_dimension,deal_II_dimension+1>, SP> + (const hp::DoFHandler<deal_II_dimension,deal_II_dimension+1>&, + const Table<2,Coupling>&, + SP &, + const ConstraintMatrix &, + const bool, + const unsigned int); + + template void + DoFTools::make_sparsity_pattern<DoFHandler<deal_II_dimension,deal_II_dimension+1>, SP> + (const DoFHandler<deal_II_dimension,deal_II_dimension+1> &dof_row, + const DoFHandler<deal_II_dimension,deal_II_dimension+1> &dof_col, + SP &sparsity); + + template void + DoFTools::make_sparsity_pattern<hp::DoFHandler<deal_II_dimension,deal_II_dimension+1>, SP> + (const hp::DoFHandler<deal_II_dimension,deal_II_dimension+1> &dof_row, + const hp::DoFHandler<deal_II_dimension,deal_II_dimension+1> &dof_col, + SP &sparsity); + + template void + DoFTools::make_boundary_sparsity_pattern<DoFHandler<deal_II_dimension,deal_II_dimension+1>,SP> + (const DoFHandler<deal_II_dimension,deal_II_dimension+1>& dof, + const std::vector<types::global_dof_index> &, + SP &); + + //template void + //DoFTools::make_boundary_sparsity_pattern<hp::DoFHandler<deal_II_dimension,deal_II_dimension+1>,SP> + //(const hp::DoFHandler<deal_II_dimension,deal_II_dimension+1>& dof, + // const std::vector<types::global_dof_index> &, + // SP &); + + template void + DoFTools::make_boundary_sparsity_pattern<DoFHandler<deal_II_dimension,deal_II_dimension+1>,SP> + (const DoFHandler<deal_II_dimension,deal_II_dimension+1>& dof, + const FunctionMap<deal_II_dimension+1>::type &boundary_indicators, + const std::vector<types::global_dof_index> &dof_to_boundary_mapping, + SP &sparsity); + + //template void + //DoFTools::make_boundary_sparsity_pattern<hp::DoFHandler<deal_II_dimension,deal_II_dimension+1>,SP> + //(const hp::DoFHandler<deal_II_dimension,deal_II_dimension+1>& dof, + // const FunctionMap<deal_II_dimension+1>::type &boundary_indicators, + // const std::vector<types::global_dof_index> &dof_to_boundary_mapping, + // SP &sparsity); + +#endif + + +#if deal_II_dimension == 3 + + template void + DoFTools::make_sparsity_pattern<DoFHandler<1,3>, SP> + (const DoFHandler<1,3> &dof, + SP &sparsity, + const ConstraintMatrix &, + const bool, + const unsigned int); + + template void + DoFTools::make_sparsity_pattern<hp::DoFHandler<1,3>, SP> + (const hp::DoFHandler<1,3> &dof, + SP &sparsity, + const ConstraintMatrix &, + const bool, + const unsigned int); + + template void + DoFTools::make_sparsity_pattern<DoFHandler<1,3>, SP> + (const DoFHandler<1,3>&, + const Table<2,Coupling>&, + SP &, + const ConstraintMatrix &, + const bool, + const unsigned int); + + template void + DoFTools::make_sparsity_pattern<hp::DoFHandler<1,3>, SP> + (const hp::DoFHandler<1,3>&, + const Table<2,Coupling>&, + SP &, + const ConstraintMatrix &, + const bool, + const unsigned int); + + template void + DoFTools::make_sparsity_pattern<DoFHandler<1,3>, SP> + (const DoFHandler<1,3> &dof_row, + const DoFHandler<1,3> &dof_col, + SP &sparsity); + + template void + DoFTools::make_sparsity_pattern<hp::DoFHandler<1,3>, SP> + (const hp::DoFHandler<1,3> &dof_row, + const hp::DoFHandler<1,3> &dof_col, + SP &sparsity); + + template void + DoFTools::make_boundary_sparsity_pattern<DoFHandler<1,3>,SP> + (const DoFHandler<1,3>& dof, + const std::vector<types::global_dof_index> &, + SP &); + + template void + DoFTools::make_boundary_sparsity_pattern<hp::DoFHandler<1,3>,SP> + (const hp::DoFHandler<1,3>& dof, + const std::vector<types::global_dof_index> &, + SP &); + + template void + DoFTools::make_boundary_sparsity_pattern<DoFHandler<1,3>,SP> + (const DoFHandler<1,3>& dof, + const FunctionMap<3>::type &boundary_indicators, + const std::vector<types::global_dof_index> &dof_to_boundary_mapping, + SP &sparsity); + + template void + DoFTools::make_boundary_sparsity_pattern<hp::DoFHandler<1,3>,SP> + (const hp::DoFHandler<1,3>& dof, + const FunctionMap<3>::type &boundary_indicators, + const std::vector<types::global_dof_index> &dof_to_boundary_mapping, + SP &sparsity); + +#endif + + } + + +for (deal_II_dimension : DIMENSIONS) +{ + template + Table<2,DoFTools::Coupling> + DoFTools::dof_couplings_from_component_couplings + (const FiniteElement<deal_II_dimension> &fe, + const Table<2,DoFTools::Coupling> &component_couplings); +} diff --git a/deal.II/source/fe/CMakeLists.txt b/deal.II/source/fe/CMakeLists.txt index 5604f19339..5fa933789b 100644 --- a/deal.II/source/fe/CMakeLists.txt +++ b/deal.II/source/fe/CMakeLists.txt @@ -46,6 +46,7 @@ SET(_src fe_raviart_thomas_nodal.cc fe_system.cc fe_tools.cc + fe_tools_interpolate.cc fe_values.cc fe_values_inst2.cc mapping_c1.cc @@ -80,6 +81,7 @@ SET(_inst fe_raviart_thomas_nodal.inst.in fe_system.inst.in fe_tools.inst.in + fe_tools_interpolate.inst.in fe_values.decl.1.inst.in fe_values.decl.2.inst.in fe_values.impl.1.inst.in diff --git a/deal.II/source/fe/fe.cc b/deal.II/source/fe/fe.cc index 501e7e0d81..1c4db8ffbc 100644 --- a/deal.II/source/fe/fe.cc +++ b/deal.II/source/fe/fe.cc @@ -190,16 +190,16 @@ FiniteElement<dim,spacedim>::FiniteElement ( system_to_component_table.resize(this->dofs_per_cell); face_system_to_component_table.resize(this->dofs_per_face); for (unsigned int j=0 ; j<this->dofs_per_cell ; ++j) - { - system_to_component_table[j] = std::pair<unsigned,unsigned>(0,j); - system_to_base_table[j] = std::make_pair(std::make_pair(0U,0U),j); - } + system_to_component_table[j] = std::pair<unsigned,unsigned>(0,j); for (unsigned int j=0 ; j<this->dofs_per_face ; ++j) - { - face_system_to_component_table[j] = std::pair<unsigned,unsigned>(0,j); - face_system_to_base_table[j] = std::make_pair(std::make_pair(0U,0U),j); - } + face_system_to_component_table[j] = std::pair<unsigned,unsigned>(0,j); } + + for (unsigned int j=0 ; j<this->dofs_per_cell ; ++j) + system_to_base_table[j] = std::make_pair(std::make_pair(0U,0U),j); + for (unsigned int j=0 ; j<this->dofs_per_face ; ++j) + face_system_to_base_table[j] = std::make_pair(std::make_pair(0U,0U),j); + // Fill with default value; may be changed by constructor of derived class. base_to_block_indices.reinit(1,1); diff --git a/deal.II/source/fe/fe_q_base.cc b/deal.II/source/fe/fe_q_base.cc index a43e3be528..6a73cb86ff 100644 --- a/deal.II/source/fe/fe_q_base.cc +++ b/deal.II/source/fe/fe_q_base.cc @@ -459,71 +459,90 @@ FE_Q_Base<POLY,dim,spacedim>:: get_interpolation_matrix (const FiniteElement<dim,spacedim> &x_source_fe, FullMatrix<double> &interpolation_matrix) const { - // this is only implemented, if the source FE is also a Q element - AssertThrow ((dynamic_cast<const FE_Q_Base<POLY,dim,spacedim> *>(&x_source_fe) != 0), - (typename FiniteElement<dim,spacedim>::ExcInterpolationNotImplemented())); + // go through the list of elements we can interpolate from + if (const FE_Q_Base<POLY,dim,spacedim> *source_fe + = dynamic_cast<const FE_Q_Base<POLY,dim,spacedim>*>(&x_source_fe)) + { + // ok, source is a Q element, so we will be able to do the work + Assert (interpolation_matrix.m() == this->dofs_per_cell, + ExcDimensionMismatch (interpolation_matrix.m(), + this->dofs_per_cell)); + Assert (interpolation_matrix.n() == x_source_fe.dofs_per_cell, + ExcDimensionMismatch (interpolation_matrix.m(), + x_source_fe.dofs_per_cell)); + + // only evaluate Q dofs + const unsigned int q_dofs_per_cell = Utilities::fixed_power<dim>(this->degree+1); + const unsigned int source_q_dofs_per_cell = Utilities::fixed_power<dim>(source_fe->degree+1); - Assert (interpolation_matrix.m() == this->dofs_per_cell, - ExcDimensionMismatch (interpolation_matrix.m(), - this->dofs_per_cell)); - Assert (interpolation_matrix.n() == x_source_fe.dofs_per_cell, - ExcDimensionMismatch (interpolation_matrix.m(), - x_source_fe.dofs_per_cell)); + // evaluation is simply done by evaluating the other FE's basis functions on + // the unit support points (FE_Q has the property that the cell + // interpolation matrix is a unit matrix, so no need to evaluate it and + // invert it) + for (unsigned int j=0; j<q_dofs_per_cell; ++j) + { + // read in a point on this cell and evaluate the shape functions there + const Point<dim> p = this->unit_support_points[j]; - // ok, source is a Q element, so we will be able to do the work - const FE_Q_Base<POLY,dim,spacedim> &source_fe - = dynamic_cast<const FE_Q_Base<POLY,dim,spacedim>&>(x_source_fe); + // FE_Q element evaluates to 1 in unit support point and to zero in all + // other points by construction + Assert(std::abs(this->poly_space.compute_value (j, p)-1.)<1e-13, + ExcInternalError()); - // only evaluate Q dofs - const unsigned int q_dofs_per_cell = Utilities::fixed_power<dim>(this->degree+1); - const unsigned int source_q_dofs_per_cell = Utilities::fixed_power<dim>(source_fe.degree+1); + for (unsigned int i=0; i<source_q_dofs_per_cell; ++i) + interpolation_matrix(j,i) = source_fe->poly_space.compute_value (i, p); + } - // evaluation is simply done by evaluating the other FE's basis functions on - // the unit support points (FE_Q has the property that the cell - // interpolation matrix is a unit matrix, so no need to evaluate it and - // invert it) - for (unsigned int j=0; j<q_dofs_per_cell; ++j) - { - // read in a point on this cell and evaluate the shape functions there - const Point<dim> p = this->unit_support_points[j]; + // for FE_Q_DG0, add one last row of identity + if (q_dofs_per_cell < this->dofs_per_cell) + { + AssertDimension(source_q_dofs_per_cell+1, source_fe->dofs_per_cell); + for (unsigned int i=0; i<source_q_dofs_per_cell; ++i) + interpolation_matrix(q_dofs_per_cell, i) = 0.; + for (unsigned int j=0; j<q_dofs_per_cell; ++j) + interpolation_matrix(j, source_q_dofs_per_cell) = 0.; + interpolation_matrix(q_dofs_per_cell, source_q_dofs_per_cell) = 1.; + } - // FE_Q element evaluates to 1 in unit support point and to zero in all - // other points by construction - Assert(std::abs(this->poly_space.compute_value (j, p)-1.)<1e-13, - ExcInternalError()); + // cut off very small values + const double eps = 2e-13*this->degree*dim; + for (unsigned int i=0; i<this->dofs_per_cell; ++i) + for (unsigned int j=0; j<source_fe->dofs_per_cell; ++j) + if (std::fabs(interpolation_matrix(i,j)) < eps) + interpolation_matrix(i,j) = 0.; - for (unsigned int i=0; i<source_q_dofs_per_cell; ++i) - interpolation_matrix(j,i) = source_fe.poly_space.compute_value (i, p); - } + // make sure that the row sum of each of the matrices is 1 at this + // point. this must be so since the shape functions sum up to 1 + for (unsigned int i=0; i<this->dofs_per_cell; ++i) + { + double sum = 0.; + for (unsigned int j=0; j<source_fe->dofs_per_cell; ++j) + sum += interpolation_matrix(i,j); - // for FE_Q_DG0, add one last row of identity - if (q_dofs_per_cell < this->dofs_per_cell) - { - AssertDimension(source_q_dofs_per_cell+1, source_fe.dofs_per_cell); - for (unsigned int i=0; i<source_q_dofs_per_cell; ++i) - interpolation_matrix(q_dofs_per_cell, i) = 0.; - for (unsigned int j=0; j<q_dofs_per_cell; ++j) - interpolation_matrix(j, source_q_dofs_per_cell) = 0.; - interpolation_matrix(q_dofs_per_cell, source_q_dofs_per_cell) = 1.; + Assert (std::fabs(sum-1) < eps, ExcInternalError()); + } } - - // cut off very small values - const double eps = 2e-13*this->degree*dim; - for (unsigned int i=0; i<this->dofs_per_cell; ++i) - for (unsigned int j=0; j<source_fe.dofs_per_cell; ++j) - if (std::fabs(interpolation_matrix(i,j)) < eps) - interpolation_matrix(i,j) = 0.; - - // make sure that the row sum of each of the matrices is 1 at this - // point. this must be so since the shape functions sum up to 1 - for (unsigned int i=0; i<this->dofs_per_cell; ++i) + else if (dynamic_cast<const FE_Nothing<dim>*>(&x_source_fe)) { - double sum = 0.; - for (unsigned int j=0; j<source_fe.dofs_per_cell; ++j) - sum += interpolation_matrix(i,j); + // the element we want to interpolate from is an FE_Nothing. this + // element represents a function that is constant zero and has no + // degrees of freedom, so the interpolation is simply a multiplication + // with a n_dofs x 0 matrix. there is nothing to do here + + // we would like to verify that the number of rows and columns of + // the matrix equals this->dofs_per_cell and zero. unfortunately, + // whenever we do FullMatrix::reinit(m,0), it sets both rows and + // columns to zero, instead of m and zero. thus, only test the + // number of columns + Assert (interpolation_matrix.n() == x_source_fe.dofs_per_cell, + ExcDimensionMismatch (interpolation_matrix.m(), + x_source_fe.dofs_per_cell)); - Assert (std::fabs(sum-1) < eps, ExcInternalError()); } + else + AssertThrow (false, + (typename FiniteElement<dim,spacedim>::ExcInterpolationNotImplemented())); + } diff --git a/deal.II/source/fe/fe_tools.cc b/deal.II/source/fe/fe_tools.cc index fe6be9fd8c..4ba84c5a43 100644 --- a/deal.II/source/fe/fe_tools.cc +++ b/deal.II/source/fe/fe_tools.cc @@ -21,15 +21,6 @@ #include <deal.II/base/utilities.h> #include <deal.II/lac/full_matrix.h> #include <deal.II/lac/householder.h> -#include <deal.II/lac/vector.h> -#include <deal.II/lac/block_vector.h> -#include <deal.II/lac/parallel_vector.h> -#include <deal.II/lac/parallel_block_vector.h> -#include <deal.II/lac/petsc_parallel_vector.h> -#include <deal.II/lac/petsc_block_vector.h> -#include <deal.II/lac/petsc_parallel_block_vector.h> -#include <deal.II/lac/trilinos_vector.h> -#include <deal.II/lac/trilinos_block_vector.h> #include <deal.II/lac/constraint_matrix.h> #include <deal.II/grid/tria.h> #include <deal.II/grid/tria_iterator.h> @@ -399,8 +390,7 @@ namespace FETools start_indices[i] = k; k += block_data[i]; } - -//TODO:[GK] This does not work for a single RT + for (unsigned int i=0; i<element.dofs_per_cell; ++i) { std::pair<unsigned int, types::global_dof_index> @@ -1271,703 +1261,6 @@ namespace FETools } - template <int dim, int spacedim, - template <int, int> class DH1, - template <int, int> class DH2, - class InVector, class OutVector> - void - interpolate(const DH1<dim, spacedim> &dof1, - const InVector &u1, - const DH2<dim, spacedim> &dof2, - OutVector &u2) - { - ConstraintMatrix dummy; - dummy.close(); - interpolate(dof1, u1, dof2, dummy, u2); - } - - - - template <int dim, int spacedim, - template <int, int> class DH1, - template <int, int> class DH2, - class InVector, class OutVector> - void - interpolate (const DH1<dim, spacedim> &dof1, - const InVector &u1, - const DH2<dim, spacedim> &dof2, - const ConstraintMatrix &constraints, - OutVector &u2) - { - Assert(&dof1.get_tria()==&dof2.get_tria(), ExcTriangulationMismatch()); - - Assert(u1.size()==dof1.n_dofs(), - ExcDimensionMismatch(u1.size(), dof1.n_dofs())); - Assert(u2.size()==dof2.n_dofs(), - ExcDimensionMismatch(u2.size(), dof2.n_dofs())); - -#ifdef DEAL_II_WITH_PETSC - if (dynamic_cast<const PETScWrappers::MPI::Vector *>(&u1) != 0) - if (dynamic_cast<const DoFHandler<dim>*>(&dof1) != 0) - { - // if u1 is a parallel distributed - // PETSc vector, we check the local - // size of u1 for safety - Assert(dynamic_cast<const PETScWrappers::MPI::Vector *>(&u1)->local_size() == dof1.locally_owned_dofs().n_elements(), - ExcDimensionMismatch(dynamic_cast<const PETScWrappers::MPI::Vector *>(&u1)->local_size(), dof1.locally_owned_dofs().n_elements())); - }; - - if (dynamic_cast<PETScWrappers::MPI::Vector *>(&u2) != 0) - if (dynamic_cast<const DoFHandler<dim>*>(&dof2) != 0) - { - Assert(dynamic_cast<PETScWrappers::MPI::Vector *>(&u2)->local_size() == dof2.locally_owned_dofs().n_elements(), - ExcDimensionMismatch(dynamic_cast<PETScWrappers::MPI::Vector *>(&u2)->local_size(), dof2.locally_owned_dofs().n_elements())); - }; -#endif - // allocate vectors at maximal - // size. will be reinited in inner - // cell, but Vector makes sure that - // this does not lead to - // reallocation of memory - Vector<typename OutVector::value_type> u1_local(DoFTools::max_dofs_per_cell(dof1)); - Vector<typename OutVector::value_type> u2_local(DoFTools::max_dofs_per_cell(dof2)); - - // have a map for interpolation - // matrices. shared_ptr make sure - // that memory is released again - std::map<const FiniteElement<dim,spacedim> *, - std::map<const FiniteElement<dim,spacedim> *, - std_cxx1x::shared_ptr<FullMatrix<double> > > > - interpolation_matrices; - - typename DH1<dim,spacedim>::active_cell_iterator cell1 = dof1.begin_active(), - endc1 = dof1.end(); - typename DH2<dim,spacedim>::active_cell_iterator cell2 = dof2.begin_active(), - endc2 = dof2.end(); - - std::vector<types::global_dof_index> dofs; - dofs.reserve (DoFTools::max_dofs_per_cell (dof2)); - - u2 = 0; - OutVector touch_count(u2); - touch_count = 0; - - // for distributed triangulations, - // we can only interpolate u1 on - // a cell, which this processor owns, - // so we have to know the subdomain_id - const types::subdomain_id subdomain_id = - dof1.get_tria().locally_owned_subdomain(); - - for (; cell1!=endc1; ++cell1, ++cell2) - if ((cell1->subdomain_id() == subdomain_id) - || - (subdomain_id == numbers::invalid_subdomain_id)) - { - Assert(cell1->get_fe().n_components() == cell2->get_fe().n_components(), - ExcDimensionMismatch (cell1->get_fe().n_components(), - cell2->get_fe().n_components())); - - // for continuous elements on - // grids with hanging nodes we - // need hanging node - // constraints. Consequentely, - // if there are no constraints - // then hanging nodes are not - // allowed. - const bool hanging_nodes_not_allowed - = ((cell2->get_fe().dofs_per_vertex != 0) && - (constraints.n_constraints() == 0)); - - if (hanging_nodes_not_allowed) - for (unsigned int face=0; face<GeometryInfo<dim>::faces_per_cell; ++face) - Assert (cell1->at_boundary(face) || - cell1->neighbor(face)->level() == cell1->level(), - ExcHangingNodesNotAllowed(0)); - - - const unsigned int dofs_per_cell1 = cell1->get_fe().dofs_per_cell; - const unsigned int dofs_per_cell2 = cell2->get_fe().dofs_per_cell; - u1_local.reinit (dofs_per_cell1); - u2_local.reinit (dofs_per_cell2); - - // check if interpolation - // matrix for this particular - // pair of elements is already - // there - if (interpolation_matrices[&cell1->get_fe()][&cell2->get_fe()].get() == 0) - { - std_cxx1x::shared_ptr<FullMatrix<double> > - interpolation_matrix (new FullMatrix<double> (dofs_per_cell2, - dofs_per_cell1)); - interpolation_matrices[&cell1->get_fe()][&cell2->get_fe()] - = interpolation_matrix; - - get_interpolation_matrix(cell1->get_fe(), - cell2->get_fe(), - *interpolation_matrix); - } - - cell1->get_dof_values(u1, u1_local); - interpolation_matrices[&cell1->get_fe()][&cell2->get_fe()] - ->vmult(u2_local, u1_local); - - dofs.resize (dofs_per_cell2); - cell2->get_dof_indices(dofs); - - for (unsigned int i=0; i<dofs_per_cell2; ++i) - { - u2(dofs[i])+=u2_local(i); - touch_count(dofs[i]) += 1; - } - } - // cell1 is at the end, so should - // be cell2 - Assert (cell2 == endc2, ExcInternalError()); - - u2.compress(VectorOperation::add); - touch_count.compress(VectorOperation::add); - - // if we work on parallel distributed - // vectors, we have to ensure, that we only - // work on dofs this processor owns. - IndexSet locally_owned_dofs = dof2.locally_owned_dofs(); - - // when a discontinuous element is - // interpolated to a continuous - // one, we take the mean values. - // for parallel vectors check, - // if this component is owned by - // this processor. - for (types::global_dof_index i=0; i<dof2.n_dofs(); ++i) - if (locally_owned_dofs.is_element(i)) - { - Assert(touch_count(i)!=0, ExcInternalError()); - u2(i) /= touch_count(i); - } - - // finish the work on parallel vectors - u2.compress(VectorOperation::insert); - // Apply hanging node constraints. - constraints.distribute(u2); - } - - - - template <int dim, class InVector, class OutVector, int spacedim> - void - back_interpolate(const DoFHandler<dim,spacedim> &dof1, - const InVector &u1, - const FiniteElement<dim,spacedim> &fe2, - OutVector &u1_interpolated) - { - Assert(dof1.get_fe().n_components() == fe2.n_components(), - ExcDimensionMismatch(dof1.get_fe().n_components(), fe2.n_components())); - Assert(u1.size()==dof1.n_dofs(), ExcDimensionMismatch(u1.size(), dof1.n_dofs())); - Assert(u1_interpolated.size()==dof1.n_dofs(), - ExcDimensionMismatch(u1_interpolated.size(), dof1.n_dofs())); - -#ifdef DEAL_II_WITH_PETSC - if (dynamic_cast<const PETScWrappers::MPI::Vector *>(&u1) != 0) - if (dynamic_cast<const DoFHandler<dim>*>(&dof1) != 0) - { - // if u1 is a parallel distributed - // PETSc vector, we check the local - // size of u1 for safety - Assert(dynamic_cast<const PETScWrappers::MPI::Vector *>(&u1)->local_size() == dof1.locally_owned_dofs().n_elements(), - ExcDimensionMismatch(dynamic_cast<const PETScWrappers::MPI::Vector *>(&u1)->local_size(), dof1.locally_owned_dofs().n_elements())); - }; - - if (dynamic_cast<PETScWrappers::MPI::Vector *>(&u1_interpolated) != 0) - if (dynamic_cast<const DoFHandler<dim>*>(&dof1) != 0) - { - Assert(dynamic_cast<PETScWrappers::MPI::Vector *>(&u1_interpolated)->local_size() == dof1.locally_owned_dofs().n_elements(), - ExcDimensionMismatch(dynamic_cast<PETScWrappers::MPI::Vector *>(&u1_interpolated)->local_size(), dof1.locally_owned_dofs().n_elements())); - }; -#endif - - // For continuous elements on grids - // with hanging nodes we need - // hanging node - // constraints. Consequently, when - // the elements are continuous no - // hanging node constraints are - // allowed. - const bool hanging_nodes_not_allowed= - (dof1.get_fe().dofs_per_vertex != 0) || (fe2.dofs_per_vertex != 0); - - const unsigned int dofs_per_cell1=dof1.get_fe().dofs_per_cell; - - Vector<typename OutVector::value_type> u1_local(dofs_per_cell1); - Vector<typename OutVector::value_type> u1_int_local(dofs_per_cell1); - - const types::subdomain_id subdomain_id = - dof1.get_tria().locally_owned_subdomain(); - - typename DoFHandler<dim,spacedim>::active_cell_iterator cell = dof1.begin_active(), - endc = dof1.end(); - - FullMatrix<double> interpolation_matrix(dofs_per_cell1, dofs_per_cell1); - get_back_interpolation_matrix(dof1.get_fe(), fe2, - interpolation_matrix); - for (; cell!=endc; ++cell) - if ((cell->subdomain_id() == subdomain_id) - || - (subdomain_id == numbers::invalid_subdomain_id)) - { - if (hanging_nodes_not_allowed) - for (unsigned int face=0; face<GeometryInfo<dim>::faces_per_cell; ++face) - Assert (cell->at_boundary(face) || - cell->neighbor(face)->level() == cell->level(), - ExcHangingNodesNotAllowed(0)); - - cell->get_dof_values(u1, u1_local); - interpolation_matrix.vmult(u1_int_local, u1_local); - cell->set_dof_values(u1_int_local, u1_interpolated); - } - - // if we work on a parallel PETSc vector - // we have to finish the work - u1_interpolated.compress(VectorOperation::insert); - } - - - - template <int dim, - template <int> class DH, - class InVector, class OutVector, int spacedim> - void - back_interpolate(const DH<dim> &dof1, - const InVector &u1, - const FiniteElement<dim,spacedim> &fe2, - OutVector &u1_interpolated) - { - Assert(u1.size() == dof1.n_dofs(), - ExcDimensionMismatch(u1.size(), dof1.n_dofs())); - Assert(u1_interpolated.size() == dof1.n_dofs(), - ExcDimensionMismatch(u1_interpolated.size(), dof1.n_dofs())); - -#ifdef DEAL_II_WITH_PETSC - if (dynamic_cast<const PETScWrappers::MPI::Vector *>(&u1) != 0) - if (dynamic_cast<const DoFHandler<dim>*>(&dof1) != 0) - { - // if u1 is a parallel distributed - // PETSc vector, we check the local - // size of u1 for safety - Assert(dynamic_cast<const PETScWrappers::MPI::Vector *>(&u1)->local_size() == dof1.locally_owned_dofs().n_elements(), - ExcDimensionMismatch(dynamic_cast<const PETScWrappers::MPI::Vector *>(&u1)->local_size(), dof1.locally_owned_dofs().n_elements())); - }; - - if (dynamic_cast<PETScWrappers::MPI::Vector *>(&u1_interpolated) != 0) - if (dynamic_cast<const DoFHandler<dim>*>(&dof1) != 0) - { - Assert(dynamic_cast<PETScWrappers::MPI::Vector *>(&u1_interpolated)->local_size() == dof1.locally_owned_dofs().n_elements(), - ExcDimensionMismatch(dynamic_cast<PETScWrappers::MPI::Vector *>(&u1_interpolated)->local_size(), dof1.locally_owned_dofs().n_elements())); - }; -#endif - - Vector<typename OutVector::value_type> u1_local(DoFTools::max_dofs_per_cell(dof1)); - Vector<typename OutVector::value_type> u1_int_local(DoFTools::max_dofs_per_cell(dof1)); - - const types::subdomain_id subdomain_id = - dof1.get_tria().locally_owned_subdomain(); - - typename DH<dim>::active_cell_iterator cell = dof1.begin_active(), - endc = dof1.end(); - - // map from possible fe objects in - // dof1 to the back_interpolation - // matrices - std::map<const FiniteElement<dim> *, - std_cxx1x::shared_ptr<FullMatrix<double> > > interpolation_matrices; - - for (; cell!=endc; ++cell) - if ((cell->subdomain_id() == subdomain_id) - || - (subdomain_id == numbers::invalid_subdomain_id)) - { - Assert(cell->get_fe().n_components() == fe2.n_components(), - ExcDimensionMismatch(cell->get_fe().n_components(), - fe2.n_components())); - - // For continuous elements on - // grids with hanging nodes we - // need hanging node - // constraints. Consequently, - // when the elements are - // continuous no hanging node - // constraints are allowed. - const bool hanging_nodes_not_allowed= - (cell->get_fe().dofs_per_vertex != 0) || (fe2.dofs_per_vertex != 0); - - if (hanging_nodes_not_allowed) - for (unsigned int face=0; face<GeometryInfo<dim>::faces_per_cell; ++face) - Assert (cell->at_boundary(face) || - cell->neighbor(face)->level() == cell->level(), - ExcHangingNodesNotAllowed(0)); - - const unsigned int dofs_per_cell1 = cell->get_fe().dofs_per_cell; - - // make sure back_interpolation - // matrix is available - if (interpolation_matrices[&cell->get_fe()] != 0) - { - interpolation_matrices[&cell->get_fe()] = - std_cxx1x::shared_ptr<FullMatrix<double> > - (new FullMatrix<double>(dofs_per_cell1, dofs_per_cell1)); - get_back_interpolation_matrix(dof1.get_fe(), fe2, - *interpolation_matrices[&cell->get_fe()]); - } - - u1_local.reinit (dofs_per_cell1); - u1_int_local.reinit (dofs_per_cell1); - - cell->get_dof_values(u1, u1_local); - interpolation_matrices[&cell->get_fe()]->vmult(u1_int_local, u1_local); - cell->set_dof_values(u1_int_local, u1_interpolated); - }; - - // if we work on a parallel PETSc vector - // we have to finish the work - u1_interpolated.compress(VectorOperation::insert); - } - - - - namespace internal - { - namespace - { - template <int dim, int spacedim, class InVector> - void back_interpolate (const DoFHandler<dim,spacedim> &dof1, - const ConstraintMatrix &constraints1, - const InVector &u1, - const DoFHandler<dim,spacedim> &dof2, - const ConstraintMatrix &constraints2, - InVector &u1_interpolated) - { - Vector<typename InVector::value_type> u2(dof2.n_dofs()); - interpolate(dof1, u1, dof2, constraints2, u2); - interpolate(dof2, u2, dof1, constraints1, u1_interpolated); - } - - // special version for PETSc -#ifdef DEAL_II_WITH_PETSC - template <int dim, int spacedim> - void back_interpolate (const DoFHandler<dim,spacedim> &dof1, - const ConstraintMatrix &constraints1, - const PETScWrappers::MPI::Vector &u1, - const DoFHandler<dim,spacedim> &dof2, - const ConstraintMatrix &constraints2, - PETScWrappers::MPI::Vector &u1_interpolated) - { - // if u1 is a parallel distributed PETSc vector, we create a - // vector u2 with based on the sets of locally owned and relevant - // dofs of dof2 - IndexSet dof2_locally_owned_dofs = dof2.locally_owned_dofs(); - IndexSet dof2_locally_relevant_dofs; - DoFTools::extract_locally_relevant_dofs (dof2, - dof2_locally_relevant_dofs); - - PETScWrappers::MPI::Vector u2_out (u1.get_mpi_communicator(), - dof2_locally_owned_dofs); - interpolate(dof1, u1, dof2, constraints2, u2_out); - PETScWrappers::MPI::Vector u2 (u1.get_mpi_communicator(), - dof2_locally_owned_dofs, - dof2_locally_relevant_dofs); - u2 = u2_out; - interpolate(dof2, u2, dof1, constraints1, u1_interpolated); - } -#endif - - // special version for parallel::distributed::Vector - template <int dim, int spacedim, typename Number> - void back_interpolate (const DoFHandler<dim,spacedim> &dof1, - const ConstraintMatrix &constraints1, - const parallel::distributed::Vector<Number> &u1, - const DoFHandler<dim,spacedim> &dof2, - const ConstraintMatrix &constraints2, - parallel::distributed::Vector<Number> &u1_interpolated) - { - IndexSet dof2_locally_owned_dofs = dof2.locally_owned_dofs(); - IndexSet dof2_locally_relevant_dofs; - DoFTools::extract_locally_relevant_dofs (dof2, - dof2_locally_relevant_dofs); - - parallel::distributed::Vector<Number> - u2 (dof2_locally_owned_dofs, - dof2_locally_relevant_dofs, - u1.get_mpi_communicator()); - - interpolate(dof1, u1, dof2, constraints2, u2); - u2.update_ghost_values (); - interpolate(dof2, u2, dof1, constraints1, u1_interpolated); - } - } - } - - - template <int dim, class InVector, class OutVector, int spacedim> - void back_interpolate(const DoFHandler<dim,spacedim> &dof1, - const ConstraintMatrix &constraints1, - const InVector &u1, - const DoFHandler<dim,spacedim> &dof2, - const ConstraintMatrix &constraints2, - OutVector &u1_interpolated) - { - // For discontinuous elements without constraints take the simpler version - // of the back_interpolate function. - if (dof1.get_fe().dofs_per_vertex==0 && dof2.get_fe().dofs_per_vertex==0 - && constraints1.n_constraints()==0 && constraints2.n_constraints()==0) - back_interpolate(dof1, u1, dof2.get_fe(), u1_interpolated); - else - { - Assert(dof1.get_fe().n_components() == dof2.get_fe().n_components(), - ExcDimensionMismatch(dof1.get_fe().n_components(), dof2.get_fe().n_components())); - Assert(u1.size()==dof1.n_dofs(), ExcDimensionMismatch(u1.size(), dof1.n_dofs())); - Assert(u1_interpolated.size()==dof1.n_dofs(), - ExcDimensionMismatch(u1_interpolated.size(), dof1.n_dofs())); - - // For continuous elements first interpolate to dof2, taking into - // account constraints2, and then interpolate back to dof1 taking into - // account constraints1 - internal::back_interpolate(dof1, constraints1, u1, dof2, constraints2, - u1_interpolated); - } - } - - - - template <int dim, class InVector, class OutVector, int spacedim> - void interpolation_difference (const DoFHandler<dim,spacedim> &dof1, - const InVector &u1, - const FiniteElement<dim,spacedim> &fe2, - OutVector &u1_difference) - { - Assert(dof1.get_fe().n_components() == fe2.n_components(), - ExcDimensionMismatch(dof1.get_fe().n_components(), fe2.n_components())); - Assert(u1.size()==dof1.n_dofs(), ExcDimensionMismatch(u1.size(), dof1.n_dofs())); - Assert(u1_difference.size()==dof1.n_dofs(), - ExcDimensionMismatch(u1_difference.size(), dof1.n_dofs())); - -#ifdef DEAL_II_WITH_PETSC - if (dynamic_cast<const PETScWrappers::MPI::Vector *>(&u1) != 0) - if (dynamic_cast<const DoFHandler<dim>*>(&dof1) != 0) - { - // if u1 is a parallel distributed - // PETSc vector, we check the local - // size of u1 for safety - Assert(dynamic_cast<const PETScWrappers::MPI::Vector *>(&u1)->local_size() == dof1.locally_owned_dofs().n_elements(), - ExcDimensionMismatch(dynamic_cast<const PETScWrappers::MPI::Vector *>(&u1)->local_size(), dof1.locally_owned_dofs().n_elements())); - }; - - if (dynamic_cast<PETScWrappers::MPI::Vector *>(&u1_difference) != 0) - if (dynamic_cast<const DoFHandler<dim>*>(&dof1) != 0) - { - Assert(dynamic_cast<PETScWrappers::MPI::Vector *>(&u1_difference)->local_size() == dof1.locally_owned_dofs().n_elements(), - ExcDimensionMismatch(dynamic_cast<PETScWrappers::MPI::Vector *>(&u1_difference)->local_size(), dof1.locally_owned_dofs().n_elements())); - }; -#endif - - // For continuous elements on grids - // with hanging nodes we need - // hanging node - // constraints. Consequently, when - // the elements are continuous no - // hanging node constraints are - // allowed. - const bool hanging_nodes_not_allowed= - (dof1.get_fe().dofs_per_vertex != 0) || (fe2.dofs_per_vertex != 0); - - const unsigned int dofs_per_cell=dof1.get_fe().dofs_per_cell; - - Vector<typename OutVector::value_type> u1_local(dofs_per_cell); - Vector<typename OutVector::value_type> u1_diff_local(dofs_per_cell); - - const types::subdomain_id subdomain_id = - dof1.get_tria().locally_owned_subdomain(); - - FullMatrix<double> difference_matrix(dofs_per_cell, dofs_per_cell); - get_interpolation_difference_matrix(dof1.get_fe(), fe2, - difference_matrix); - - typename DoFHandler<dim,spacedim>::active_cell_iterator cell = dof1.begin_active(), - endc = dof1.end(); - - for (; cell!=endc; ++cell) - if ((cell->subdomain_id() == subdomain_id) - || - (subdomain_id == numbers::invalid_subdomain_id)) - { - if (hanging_nodes_not_allowed) - for (unsigned int face=0; face<GeometryInfo<dim>::faces_per_cell; ++face) - Assert (cell->at_boundary(face) || - cell->neighbor(face)->level() == cell->level(), - ExcHangingNodesNotAllowed(0)); - - cell->get_dof_values(u1, u1_local); - difference_matrix.vmult(u1_diff_local, u1_local); - cell->set_dof_values(u1_diff_local, u1_difference); - } - - // if we work on a parallel PETSc vector - // we have to finish the work and - // update ghost values - u1_difference.compress(VectorOperation::insert); - } - - - - template <int dim, class InVector, class OutVector, int spacedim> - void interpolation_difference(const DoFHandler<dim,spacedim> &dof1, - const ConstraintMatrix &constraints1, - const InVector &u1, - const DoFHandler<dim,spacedim> &dof2, - const ConstraintMatrix &constraints2, - OutVector &u1_difference) - { - // For discontinuous elements - // without constraints take the - // cheaper version of the - // interpolation_difference function. - if (dof1.get_fe().dofs_per_vertex==0 && dof2.get_fe().dofs_per_vertex==0 - && constraints1.n_constraints()==0 && constraints2.n_constraints()==0) - interpolation_difference(dof1, u1, dof2.get_fe(), u1_difference); - else - { - back_interpolate(dof1, constraints1, u1, dof2, constraints2, u1_difference); - u1_difference.sadd(-1, u1); - } - } - - - - template <int dim, class InVector, class OutVector, int spacedim> - void project_dg(const DoFHandler<dim,spacedim> &dof1, - const InVector &u1, - const DoFHandler<dim,spacedim> &dof2, - OutVector &u2) - { - Assert(&dof1.get_tria()==&dof2.get_tria(), ExcTriangulationMismatch()); - Assert(dof1.get_fe().n_components() == dof2.get_fe().n_components(), - ExcDimensionMismatch(dof1.get_fe().n_components(), dof2.get_fe().n_components())); - Assert(u1.size()==dof1.n_dofs(), ExcDimensionMismatch(u1.size(), dof1.n_dofs())); - Assert(u2.size()==dof2.n_dofs(), ExcDimensionMismatch(u2.size(), dof2.n_dofs())); - - typename DoFHandler<dim,spacedim>::active_cell_iterator cell1 = dof1.begin_active(); - typename DoFHandler<dim,spacedim>::active_cell_iterator cell2 = dof2.begin_active(); - typename DoFHandler<dim,spacedim>::active_cell_iterator end = dof2.end(); - - const unsigned int n1 = dof1.get_fe().dofs_per_cell; - const unsigned int n2 = dof2.get_fe().dofs_per_cell; - - Vector<double> u1_local(n1); - Vector<double> u2_local(n2); - std::vector<types::global_dof_index> dofs(n2); - - FullMatrix<double> matrix(n2,n1); - get_projection_matrix(dof1.get_fe(), dof2.get_fe(), matrix); - - while (cell2 != end) - { - cell1->get_dof_values(u1, u1_local); - matrix.vmult(u2_local, u1_local); - cell2->get_dof_indices(dofs); - for (unsigned int i=0; i<n2; ++i) - { - u2(dofs[i])+=u2_local(i); - } - - ++cell1; - ++cell2; - } - } - - - template <int dim, class InVector, class OutVector, int spacedim> - void extrapolate(const DoFHandler<dim,spacedim> &dof1, - const InVector &u1, - const DoFHandler<dim,spacedim> &dof2, - OutVector &u2) - { - ConstraintMatrix dummy; - dummy.close(); - extrapolate(dof1, u1, dof2, dummy, u2); - } - - - - template <int dim, class InVector, class OutVector, int spacedim> - void extrapolate(const DoFHandler<dim,spacedim> &dof1, - const InVector &u1, - const DoFHandler<dim,spacedim> &dof2, - const ConstraintMatrix &constraints, - OutVector &u2) - { - Assert(dof1.get_fe().n_components() == dof2.get_fe().n_components(), - ExcDimensionMismatch(dof1.get_fe().n_components(), dof2.get_fe().n_components())); - Assert(&dof1.get_tria()==&dof2.get_tria(), ExcTriangulationMismatch()); - Assert(u1.size()==dof1.n_dofs(), ExcDimensionMismatch(u1.size(), dof1.n_dofs())); - Assert(u2.size()==dof2.n_dofs(), ExcDimensionMismatch(u2.size(), dof2.n_dofs())); - - OutVector u3; - u3.reinit(u2); - interpolate(dof1, u1, dof2, constraints, u3); - - const unsigned int dofs_per_cell = dof2.get_fe().dofs_per_cell; - Vector<typename OutVector::value_type> dof_values(dofs_per_cell); - - // make sure that each cell on the - // coarsest level is at least once - // refined. otherwise, we can't - // treat these cells and would - // generate a bogus result - { - typename DoFHandler<dim,spacedim>::cell_iterator cell = dof2.begin(0), - endc = dof2.end(0); - for (; cell!=endc; ++cell) - Assert (cell->has_children(), ExcGridNotRefinedAtLeastOnce()); - } - - // then traverse grid bottom up - for (unsigned int level=0; level<dof1.get_tria().n_levels()-1; ++level) - { - typename DoFHandler<dim,spacedim>::cell_iterator cell=dof2.begin(level), - endc=dof2.end(level); - - for (; cell!=endc; ++cell) - if (!cell->active()) - { - // check whether this - // cell has active - // children - bool active_children=false; - for (unsigned int child_n=0; child_n<cell->n_children(); ++child_n) - if (cell->child(child_n)->active()) - { - active_children=true; - break; - } - - // if there are active - // children, the we have - // to work on this - // cell. get the data - // from the one vector - // and set it on the - // other - if (active_children) - { - cell->get_interpolated_dof_values(u3, dof_values); - cell->set_dof_values_by_interpolation(dof_values, u2); - } - } - } - - // Apply hanging node constraints. - constraints.distribute(u2); - } - template <> void @@ -2850,7 +2143,7 @@ namespace FETools return Utilities::invert_permutation(hierarchic_to_lexicographic_numbering (fe)); } -} +} // end of namespace FETools diff --git a/deal.II/source/fe/fe_tools.inst.in b/deal.II/source/fe/fe_tools.inst.in index 081a327485..3809bdd380 100644 --- a/deal.II/source/fe/fe_tools.inst.in +++ b/deal.II/source/fe/fe_tools.inst.in @@ -15,26 +15,6 @@ // --------------------------------------------------------------------- - -for (deal_II_dimension : DIMENSIONS; deal_II_space_dimension : SPACE_DIMENSIONS; Vector : SERIAL_VECTORS) - { - namespace FETools - \{ -#if deal_II_dimension <= deal_II_space_dimension - template - void interpolate<deal_II_dimension,deal_II_space_dimension> - (const DoFHandler<deal_II_dimension,deal_II_space_dimension> &, const Vector &, - const DoFHandler<deal_II_dimension,deal_II_space_dimension> &, Vector &); - - template - void interpolate<deal_II_dimension,deal_II_space_dimension> - (const DoFHandler<deal_II_dimension,deal_II_space_dimension> &, const Vector &, - const DoFHandler<deal_II_dimension,deal_II_space_dimension> &, const ConstraintMatrix &, - Vector &); -#endif - \} - } - for (deal_II_dimension : DIMENSIONS; deal_II_space_dimension : SPACE_DIMENSIONS) { namespace FETools @@ -67,6 +47,15 @@ for (deal_II_dimension : DIMENSIONS; deal_II_space_dimension : SPACE_DIMENSIONS { namespace FETools \{ + +#if deal_II_dimension <= deal_II_space_dimension + template + void get_interpolation_matrix<deal_II_dimension,double,deal_II_space_dimension> + (const FiniteElement<deal_II_dimension,deal_II_space_dimension> &, + const FiniteElement<deal_II_dimension,deal_II_space_dimension> &, + FullMatrix<double> &); +#endif + #if deal_II_dimension == deal_II_space_dimension template class FEFactoryBase<deal_II_dimension>; @@ -80,12 +69,7 @@ for (deal_II_dimension : DIMENSIONS; deal_II_space_dimension : SPACE_DIMENSIONS void compute_component_wise( const FiniteElement<deal_II_dimension>& , std::vector<unsigned int>&, std::vector<std::vector<unsigned int> >&); - template - - void get_interpolation_matrix<deal_II_dimension> - (const FiniteElement<deal_II_dimension> &, - const FiniteElement<deal_II_dimension> &, - FullMatrix<double> &); + template void get_back_interpolation_matrix<deal_II_dimension> (const FiniteElement<deal_II_dimension> &, @@ -125,25 +109,6 @@ for (deal_II_dimension : DIMENSIONS; deal_II_space_dimension : SPACE_DIMENSIONS (const FiniteElement<deal_II_dimension> &, FullMatrix<double> (&)[GeometryInfo<deal_II_dimension>::max_children_per_face], unsigned int, unsigned int); - template - void interpolate<deal_II_dimension> - (const hp::DoFHandler<deal_II_dimension> &, const Vector<double> &, - const hp::DoFHandler<deal_II_dimension> &, Vector<double> &); - template - void interpolate<deal_II_dimension> - (const hp::DoFHandler<deal_II_dimension> &, const Vector<double> &, - const hp::DoFHandler<deal_II_dimension> &, const ConstraintMatrix &, - Vector<double> &); - template - void interpolate<deal_II_dimension> - (const hp::DoFHandler<deal_II_dimension> &, const Vector<float> &, - const hp::DoFHandler<deal_II_dimension> &, Vector<float> &); - template - void interpolate<deal_II_dimension> - (const hp::DoFHandler<deal_II_dimension> &, const Vector<float> &, - const hp::DoFHandler<deal_II_dimension> &, const ConstraintMatrix &, - Vector<float> &); - template FiniteElement<deal_II_dimension,deal_II_dimension> * get_fe_from_name<deal_II_dimension> (const std::string &); @@ -213,47 +178,3 @@ for (deal_II_dimension : DIMENSIONS; deal_II_space_dimension : SPACE_DIMENSIONS #endif \} } - - - -for (deal_II_dimension : DIMENSIONS; deal_II_space_dimension : SPACE_DIMENSIONS; VEC : SERIAL_VECTORS) - { - namespace FETools - \{ -#if deal_II_dimension == deal_II_space_dimension - template - void back_interpolate<deal_II_dimension> - (const DoFHandler<deal_II_dimension> &, const VEC &, - const FiniteElement<deal_II_dimension> &, VEC &); - template - void back_interpolate<deal_II_dimension> - (const DoFHandler<deal_II_dimension> &, const ConstraintMatrix &, - const VEC &, - const DoFHandler<deal_II_dimension> &, const ConstraintMatrix &, - VEC &); - template - void interpolation_difference<deal_II_dimension> - (const DoFHandler<deal_II_dimension> &, const VEC &, - const FiniteElement<deal_II_dimension> &, VEC &); - template - void interpolation_difference<deal_II_dimension> - (const DoFHandler<deal_II_dimension> &, const ConstraintMatrix &, - const VEC &, - const DoFHandler<deal_II_dimension> &, const ConstraintMatrix &, - VEC &); - template - void project_dg<deal_II_dimension> - (const DoFHandler<deal_II_dimension> &, const VEC &, - const DoFHandler<deal_II_dimension> &, VEC &); - template - void extrapolate<deal_II_dimension> - (const DoFHandler<deal_II_dimension> &, const VEC &, - const DoFHandler<deal_II_dimension> &, VEC &); - template - void extrapolate<deal_II_dimension> - (const DoFHandler<deal_II_dimension> &, const VEC &, - const DoFHandler<deal_II_dimension> &, const ConstraintMatrix &, - VEC &); -#endif - \} - } diff --git a/deal.II/source/fe/fe_tools_interpolate.cc b/deal.II/source/fe/fe_tools_interpolate.cc new file mode 100644 index 0000000000..8eef0c9e12 --- /dev/null +++ b/deal.II/source/fe/fe_tools_interpolate.cc @@ -0,0 +1,761 @@ +// --------------------------------------------------------------------- +// $Id$ +// +// Copyright (C) 2000 - 2013 by the deal.II authors +// +// This file is part of the deal.II library. +// +// The deal.II library is free software; you can use it, redistribute +// it, and/or modify it under the terms of the GNU Lesser General +// Public License as published by the Free Software Foundation; either +// version 2.1 of the License, or (at your option) any later version. +// The full text of the license can be found in the file LICENSE at +// the top level of the deal.II distribution. +// +// --------------------------------------------------------------------- + + +#include <deal.II/base/quadrature_lib.h> +#include <deal.II/base/qprojector.h> +#include <deal.II/base/thread_management.h> +#include <deal.II/base/utilities.h> +#include <deal.II/lac/vector.h> +#include <deal.II/lac/block_vector.h> +#include <deal.II/lac/parallel_vector.h> +#include <deal.II/lac/parallel_block_vector.h> +#include <deal.II/lac/petsc_parallel_vector.h> +#include <deal.II/lac/petsc_block_vector.h> +#include <deal.II/lac/petsc_parallel_block_vector.h> +#include <deal.II/lac/trilinos_vector.h> +#include <deal.II/lac/trilinos_block_vector.h> +#include <deal.II/lac/constraint_matrix.h> +#include <deal.II/grid/tria.h> +#include <deal.II/grid/tria_iterator.h> +#include <deal.II/grid/grid_generator.h> +#include <deal.II/fe/fe_tools.h> +#include <deal.II/fe/fe.h> +#include <deal.II/fe/fe_values.h> +#include <deal.II/dofs/dof_handler.h> +#include <deal.II/dofs/dof_accessor.h> +#include <deal.II/dofs/dof_tools.h> +#include <deal.II/hp/dof_handler.h> + +#include <deal.II/base/std_cxx1x/shared_ptr.h> + +#include <deal.II/base/index_set.h> + +#include <iostream> + + +DEAL_II_NAMESPACE_OPEN + +namespace FETools +{ + template <int dim, int spacedim, + template <int, int> class DH1, + template <int, int> class DH2, + class InVector, class OutVector> + void + interpolate(const DH1<dim, spacedim> &dof1, + const InVector &u1, + const DH2<dim, spacedim> &dof2, + OutVector &u2) + { + ConstraintMatrix dummy; + dummy.close(); + interpolate(dof1, u1, dof2, dummy, u2); + } + + + + template <int dim, int spacedim, + template <int, int> class DH1, + template <int, int> class DH2, + class InVector, class OutVector> + void + interpolate (const DH1<dim, spacedim> &dof1, + const InVector &u1, + const DH2<dim, spacedim> &dof2, + const ConstraintMatrix &constraints, + OutVector &u2) + { + Assert(&dof1.get_tria()==&dof2.get_tria(), ExcTriangulationMismatch()); + + Assert(u1.size()==dof1.n_dofs(), + ExcDimensionMismatch(u1.size(), dof1.n_dofs())); + Assert(u2.size()==dof2.n_dofs(), + ExcDimensionMismatch(u2.size(), dof2.n_dofs())); + +#ifdef DEAL_II_WITH_PETSC + if (dynamic_cast<const PETScWrappers::MPI::Vector *>(&u1) != 0) + if (dynamic_cast<const DoFHandler<dim>*>(&dof1) != 0) + { + // if u1 is a parallel distributed + // PETSc vector, we check the local + // size of u1 for safety + Assert(dynamic_cast<const PETScWrappers::MPI::Vector *>(&u1)->local_size() == dof1.locally_owned_dofs().n_elements(), + ExcDimensionMismatch(dynamic_cast<const PETScWrappers::MPI::Vector *>(&u1)->local_size(), dof1.locally_owned_dofs().n_elements())); + }; + + if (dynamic_cast<PETScWrappers::MPI::Vector *>(&u2) != 0) + if (dynamic_cast<const DoFHandler<dim>*>(&dof2) != 0) + { + Assert(dynamic_cast<PETScWrappers::MPI::Vector *>(&u2)->local_size() == dof2.locally_owned_dofs().n_elements(), + ExcDimensionMismatch(dynamic_cast<PETScWrappers::MPI::Vector *>(&u2)->local_size(), dof2.locally_owned_dofs().n_elements())); + }; +#endif + // allocate vectors at maximal + // size. will be reinited in inner + // cell, but Vector makes sure that + // this does not lead to + // reallocation of memory + Vector<typename OutVector::value_type> u1_local(DoFTools::max_dofs_per_cell(dof1)); + Vector<typename OutVector::value_type> u2_local(DoFTools::max_dofs_per_cell(dof2)); + + // have a map for interpolation + // matrices. shared_ptr make sure + // that memory is released again + std::map<const FiniteElement<dim,spacedim> *, + std::map<const FiniteElement<dim,spacedim> *, + std_cxx1x::shared_ptr<FullMatrix<double> > > > + interpolation_matrices; + + typename DH1<dim,spacedim>::active_cell_iterator cell1 = dof1.begin_active(), + endc1 = dof1.end(); + typename DH2<dim,spacedim>::active_cell_iterator cell2 = dof2.begin_active(), + endc2 = dof2.end(); + + std::vector<types::global_dof_index> dofs; + dofs.reserve (DoFTools::max_dofs_per_cell (dof2)); + + u2 = 0; + OutVector touch_count(u2); + touch_count = 0; + + // for distributed triangulations, + // we can only interpolate u1 on + // a cell, which this processor owns, + // so we have to know the subdomain_id + const types::subdomain_id subdomain_id = + dof1.get_tria().locally_owned_subdomain(); + + for (; cell1!=endc1; ++cell1, ++cell2) + if ((cell1->subdomain_id() == subdomain_id) + || + (subdomain_id == numbers::invalid_subdomain_id)) + { + Assert(cell1->get_fe().n_components() == cell2->get_fe().n_components(), + ExcDimensionMismatch (cell1->get_fe().n_components(), + cell2->get_fe().n_components())); + + // for continuous elements on + // grids with hanging nodes we + // need hanging node + // constraints. Consequentely, + // if there are no constraints + // then hanging nodes are not + // allowed. + const bool hanging_nodes_not_allowed + = ((cell2->get_fe().dofs_per_vertex != 0) && + (constraints.n_constraints() == 0)); + + if (hanging_nodes_not_allowed) + for (unsigned int face=0; face<GeometryInfo<dim>::faces_per_cell; ++face) + Assert (cell1->at_boundary(face) || + cell1->neighbor(face)->level() == cell1->level(), + ExcHangingNodesNotAllowed(0)); + + + const unsigned int dofs_per_cell1 = cell1->get_fe().dofs_per_cell; + const unsigned int dofs_per_cell2 = cell2->get_fe().dofs_per_cell; + u1_local.reinit (dofs_per_cell1); + u2_local.reinit (dofs_per_cell2); + + // check if interpolation + // matrix for this particular + // pair of elements is already + // there + if (interpolation_matrices[&cell1->get_fe()][&cell2->get_fe()].get() == 0) + { + std_cxx1x::shared_ptr<FullMatrix<double> > + interpolation_matrix (new FullMatrix<double> (dofs_per_cell2, + dofs_per_cell1)); + interpolation_matrices[&cell1->get_fe()][&cell2->get_fe()] + = interpolation_matrix; + + get_interpolation_matrix(cell1->get_fe(), + cell2->get_fe(), + *interpolation_matrix); + } + + cell1->get_dof_values(u1, u1_local); + interpolation_matrices[&cell1->get_fe()][&cell2->get_fe()] + ->vmult(u2_local, u1_local); + + dofs.resize (dofs_per_cell2); + cell2->get_dof_indices(dofs); + + for (unsigned int i=0; i<dofs_per_cell2; ++i) + { + u2(dofs[i])+=u2_local(i); + touch_count(dofs[i]) += 1; + } + } + // cell1 is at the end, so should + // be cell2 + Assert (cell2 == endc2, ExcInternalError()); + + u2.compress(VectorOperation::add); + touch_count.compress(VectorOperation::add); + + // if we work on parallel distributed + // vectors, we have to ensure, that we only + // work on dofs this processor owns. + IndexSet locally_owned_dofs = dof2.locally_owned_dofs(); + + // when a discontinuous element is + // interpolated to a continuous + // one, we take the mean values. + // for parallel vectors check, + // if this component is owned by + // this processor. + for (types::global_dof_index i=0; i<dof2.n_dofs(); ++i) + if (locally_owned_dofs.is_element(i)) + { + Assert(touch_count(i)!=0, ExcInternalError()); + u2(i) /= touch_count(i); + } + + // finish the work on parallel vectors + u2.compress(VectorOperation::insert); + // Apply hanging node constraints. + constraints.distribute(u2); + } + + + + template <int dim, class InVector, class OutVector, int spacedim> + void + back_interpolate(const DoFHandler<dim,spacedim> &dof1, + const InVector &u1, + const FiniteElement<dim,spacedim> &fe2, + OutVector &u1_interpolated) + { + Assert(dof1.get_fe().n_components() == fe2.n_components(), + ExcDimensionMismatch(dof1.get_fe().n_components(), fe2.n_components())); + Assert(u1.size()==dof1.n_dofs(), ExcDimensionMismatch(u1.size(), dof1.n_dofs())); + Assert(u1_interpolated.size()==dof1.n_dofs(), + ExcDimensionMismatch(u1_interpolated.size(), dof1.n_dofs())); + +#ifdef DEAL_II_WITH_PETSC + if (dynamic_cast<const PETScWrappers::MPI::Vector *>(&u1) != 0) + if (dynamic_cast<const DoFHandler<dim>*>(&dof1) != 0) + { + // if u1 is a parallel distributed + // PETSc vector, we check the local + // size of u1 for safety + Assert(dynamic_cast<const PETScWrappers::MPI::Vector *>(&u1)->local_size() == dof1.locally_owned_dofs().n_elements(), + ExcDimensionMismatch(dynamic_cast<const PETScWrappers::MPI::Vector *>(&u1)->local_size(), dof1.locally_owned_dofs().n_elements())); + }; + + if (dynamic_cast<PETScWrappers::MPI::Vector *>(&u1_interpolated) != 0) + if (dynamic_cast<const DoFHandler<dim>*>(&dof1) != 0) + { + Assert(dynamic_cast<PETScWrappers::MPI::Vector *>(&u1_interpolated)->local_size() == dof1.locally_owned_dofs().n_elements(), + ExcDimensionMismatch(dynamic_cast<PETScWrappers::MPI::Vector *>(&u1_interpolated)->local_size(), dof1.locally_owned_dofs().n_elements())); + }; +#endif + + // For continuous elements on grids + // with hanging nodes we need + // hanging node + // constraints. Consequently, when + // the elements are continuous no + // hanging node constraints are + // allowed. + const bool hanging_nodes_not_allowed= + (dof1.get_fe().dofs_per_vertex != 0) || (fe2.dofs_per_vertex != 0); + + const unsigned int dofs_per_cell1=dof1.get_fe().dofs_per_cell; + + Vector<typename OutVector::value_type> u1_local(dofs_per_cell1); + Vector<typename OutVector::value_type> u1_int_local(dofs_per_cell1); + + const types::subdomain_id subdomain_id = + dof1.get_tria().locally_owned_subdomain(); + + typename DoFHandler<dim,spacedim>::active_cell_iterator cell = dof1.begin_active(), + endc = dof1.end(); + + FullMatrix<double> interpolation_matrix(dofs_per_cell1, dofs_per_cell1); + get_back_interpolation_matrix(dof1.get_fe(), fe2, + interpolation_matrix); + for (; cell!=endc; ++cell) + if ((cell->subdomain_id() == subdomain_id) + || + (subdomain_id == numbers::invalid_subdomain_id)) + { + if (hanging_nodes_not_allowed) + for (unsigned int face=0; face<GeometryInfo<dim>::faces_per_cell; ++face) + Assert (cell->at_boundary(face) || + cell->neighbor(face)->level() == cell->level(), + ExcHangingNodesNotAllowed(0)); + + cell->get_dof_values(u1, u1_local); + interpolation_matrix.vmult(u1_int_local, u1_local); + cell->set_dof_values(u1_int_local, u1_interpolated); + } + + // if we work on a parallel PETSc vector + // we have to finish the work + u1_interpolated.compress(VectorOperation::insert); + } + + + + template <int dim, + template <int> class DH, + class InVector, class OutVector, int spacedim> + void + back_interpolate(const DH<dim> &dof1, + const InVector &u1, + const FiniteElement<dim,spacedim> &fe2, + OutVector &u1_interpolated) + { + Assert(u1.size() == dof1.n_dofs(), + ExcDimensionMismatch(u1.size(), dof1.n_dofs())); + Assert(u1_interpolated.size() == dof1.n_dofs(), + ExcDimensionMismatch(u1_interpolated.size(), dof1.n_dofs())); + +#ifdef DEAL_II_WITH_PETSC + if (dynamic_cast<const PETScWrappers::MPI::Vector *>(&u1) != 0) + if (dynamic_cast<const DoFHandler<dim>*>(&dof1) != 0) + { + // if u1 is a parallel distributed + // PETSc vector, we check the local + // size of u1 for safety + Assert(dynamic_cast<const PETScWrappers::MPI::Vector *>(&u1)->local_size() == dof1.locally_owned_dofs().n_elements(), + ExcDimensionMismatch(dynamic_cast<const PETScWrappers::MPI::Vector *>(&u1)->local_size(), dof1.locally_owned_dofs().n_elements())); + }; + + if (dynamic_cast<PETScWrappers::MPI::Vector *>(&u1_interpolated) != 0) + if (dynamic_cast<const DoFHandler<dim>*>(&dof1) != 0) + { + Assert(dynamic_cast<PETScWrappers::MPI::Vector *>(&u1_interpolated)->local_size() == dof1.locally_owned_dofs().n_elements(), + ExcDimensionMismatch(dynamic_cast<PETScWrappers::MPI::Vector *>(&u1_interpolated)->local_size(), dof1.locally_owned_dofs().n_elements())); + }; +#endif + + Vector<typename OutVector::value_type> u1_local(DoFTools::max_dofs_per_cell(dof1)); + Vector<typename OutVector::value_type> u1_int_local(DoFTools::max_dofs_per_cell(dof1)); + + const types::subdomain_id subdomain_id = + dof1.get_tria().locally_owned_subdomain(); + + typename DH<dim>::active_cell_iterator cell = dof1.begin_active(), + endc = dof1.end(); + + // map from possible fe objects in + // dof1 to the back_interpolation + // matrices + std::map<const FiniteElement<dim> *, + std_cxx1x::shared_ptr<FullMatrix<double> > > interpolation_matrices; + + for (; cell!=endc; ++cell) + if ((cell->subdomain_id() == subdomain_id) + || + (subdomain_id == numbers::invalid_subdomain_id)) + { + Assert(cell->get_fe().n_components() == fe2.n_components(), + ExcDimensionMismatch(cell->get_fe().n_components(), + fe2.n_components())); + + // For continuous elements on + // grids with hanging nodes we + // need hanging node + // constraints. Consequently, + // when the elements are + // continuous no hanging node + // constraints are allowed. + const bool hanging_nodes_not_allowed= + (cell->get_fe().dofs_per_vertex != 0) || (fe2.dofs_per_vertex != 0); + + if (hanging_nodes_not_allowed) + for (unsigned int face=0; face<GeometryInfo<dim>::faces_per_cell; ++face) + Assert (cell->at_boundary(face) || + cell->neighbor(face)->level() == cell->level(), + ExcHangingNodesNotAllowed(0)); + + const unsigned int dofs_per_cell1 = cell->get_fe().dofs_per_cell; + + // make sure back_interpolation + // matrix is available + if (interpolation_matrices[&cell->get_fe()] != 0) + { + interpolation_matrices[&cell->get_fe()] = + std_cxx1x::shared_ptr<FullMatrix<double> > + (new FullMatrix<double>(dofs_per_cell1, dofs_per_cell1)); + get_back_interpolation_matrix(dof1.get_fe(), fe2, + *interpolation_matrices[&cell->get_fe()]); + } + + u1_local.reinit (dofs_per_cell1); + u1_int_local.reinit (dofs_per_cell1); + + cell->get_dof_values(u1, u1_local); + interpolation_matrices[&cell->get_fe()]->vmult(u1_int_local, u1_local); + cell->set_dof_values(u1_int_local, u1_interpolated); + }; + + // if we work on a parallel PETSc vector + // we have to finish the work + u1_interpolated.compress(VectorOperation::insert); + } + + + + namespace internal + { + namespace + { + template <int dim, int spacedim, class InVector> + void back_interpolate (const DoFHandler<dim,spacedim> &dof1, + const ConstraintMatrix &constraints1, + const InVector &u1, + const DoFHandler<dim,spacedim> &dof2, + const ConstraintMatrix &constraints2, + InVector &u1_interpolated) + { + Vector<typename InVector::value_type> u2(dof2.n_dofs()); + interpolate(dof1, u1, dof2, constraints2, u2); + interpolate(dof2, u2, dof1, constraints1, u1_interpolated); + } + + // special version for PETSc +#ifdef DEAL_II_WITH_PETSC + template <int dim, int spacedim> + void back_interpolate (const DoFHandler<dim,spacedim> &dof1, + const ConstraintMatrix &constraints1, + const PETScWrappers::MPI::Vector &u1, + const DoFHandler<dim,spacedim> &dof2, + const ConstraintMatrix &constraints2, + PETScWrappers::MPI::Vector &u1_interpolated) + { + // if u1 is a parallel distributed PETSc vector, we create a + // vector u2 with based on the sets of locally owned and relevant + // dofs of dof2 + IndexSet dof2_locally_owned_dofs = dof2.locally_owned_dofs(); + IndexSet dof2_locally_relevant_dofs; + DoFTools::extract_locally_relevant_dofs (dof2, + dof2_locally_relevant_dofs); + + PETScWrappers::MPI::Vector u2_out (u1.get_mpi_communicator(), + dof2_locally_owned_dofs); + interpolate(dof1, u1, dof2, constraints2, u2_out); + PETScWrappers::MPI::Vector u2 (u1.get_mpi_communicator(), + dof2_locally_owned_dofs, + dof2_locally_relevant_dofs); + u2 = u2_out; + interpolate(dof2, u2, dof1, constraints1, u1_interpolated); + } +#endif + + // special version for parallel::distributed::Vector + template <int dim, int spacedim, typename Number> + void back_interpolate (const DoFHandler<dim,spacedim> &dof1, + const ConstraintMatrix &constraints1, + const parallel::distributed::Vector<Number> &u1, + const DoFHandler<dim,spacedim> &dof2, + const ConstraintMatrix &constraints2, + parallel::distributed::Vector<Number> &u1_interpolated) + { + IndexSet dof2_locally_owned_dofs = dof2.locally_owned_dofs(); + IndexSet dof2_locally_relevant_dofs; + DoFTools::extract_locally_relevant_dofs (dof2, + dof2_locally_relevant_dofs); + + parallel::distributed::Vector<Number> + u2 (dof2_locally_owned_dofs, + dof2_locally_relevant_dofs, + u1.get_mpi_communicator()); + + interpolate(dof1, u1, dof2, constraints2, u2); + u2.update_ghost_values (); + interpolate(dof2, u2, dof1, constraints1, u1_interpolated); + } + } + } + + + template <int dim, class InVector, class OutVector, int spacedim> + void back_interpolate(const DoFHandler<dim,spacedim> &dof1, + const ConstraintMatrix &constraints1, + const InVector &u1, + const DoFHandler<dim,spacedim> &dof2, + const ConstraintMatrix &constraints2, + OutVector &u1_interpolated) + { + // For discontinuous elements without constraints take the simpler version + // of the back_interpolate function. + if (dof1.get_fe().dofs_per_vertex==0 && dof2.get_fe().dofs_per_vertex==0 + && constraints1.n_constraints()==0 && constraints2.n_constraints()==0) + back_interpolate(dof1, u1, dof2.get_fe(), u1_interpolated); + else + { + Assert(dof1.get_fe().n_components() == dof2.get_fe().n_components(), + ExcDimensionMismatch(dof1.get_fe().n_components(), dof2.get_fe().n_components())); + Assert(u1.size()==dof1.n_dofs(), ExcDimensionMismatch(u1.size(), dof1.n_dofs())); + Assert(u1_interpolated.size()==dof1.n_dofs(), + ExcDimensionMismatch(u1_interpolated.size(), dof1.n_dofs())); + + // For continuous elements first interpolate to dof2, taking into + // account constraints2, and then interpolate back to dof1 taking into + // account constraints1 + internal::back_interpolate(dof1, constraints1, u1, dof2, constraints2, + u1_interpolated); + } + } + + + + template <int dim, class InVector, class OutVector, int spacedim> + void interpolation_difference (const DoFHandler<dim,spacedim> &dof1, + const InVector &u1, + const FiniteElement<dim,spacedim> &fe2, + OutVector &u1_difference) + { + Assert(dof1.get_fe().n_components() == fe2.n_components(), + ExcDimensionMismatch(dof1.get_fe().n_components(), fe2.n_components())); + Assert(u1.size()==dof1.n_dofs(), ExcDimensionMismatch(u1.size(), dof1.n_dofs())); + Assert(u1_difference.size()==dof1.n_dofs(), + ExcDimensionMismatch(u1_difference.size(), dof1.n_dofs())); + +#ifdef DEAL_II_WITH_PETSC + if (dynamic_cast<const PETScWrappers::MPI::Vector *>(&u1) != 0) + if (dynamic_cast<const DoFHandler<dim>*>(&dof1) != 0) + { + // if u1 is a parallel distributed + // PETSc vector, we check the local + // size of u1 for safety + Assert(dynamic_cast<const PETScWrappers::MPI::Vector *>(&u1)->local_size() == dof1.locally_owned_dofs().n_elements(), + ExcDimensionMismatch(dynamic_cast<const PETScWrappers::MPI::Vector *>(&u1)->local_size(), dof1.locally_owned_dofs().n_elements())); + }; + + if (dynamic_cast<PETScWrappers::MPI::Vector *>(&u1_difference) != 0) + if (dynamic_cast<const DoFHandler<dim>*>(&dof1) != 0) + { + Assert(dynamic_cast<PETScWrappers::MPI::Vector *>(&u1_difference)->local_size() == dof1.locally_owned_dofs().n_elements(), + ExcDimensionMismatch(dynamic_cast<PETScWrappers::MPI::Vector *>(&u1_difference)->local_size(), dof1.locally_owned_dofs().n_elements())); + }; +#endif + + // For continuous elements on grids + // with hanging nodes we need + // hanging node + // constraints. Consequently, when + // the elements are continuous no + // hanging node constraints are + // allowed. + const bool hanging_nodes_not_allowed= + (dof1.get_fe().dofs_per_vertex != 0) || (fe2.dofs_per_vertex != 0); + + const unsigned int dofs_per_cell=dof1.get_fe().dofs_per_cell; + + Vector<typename OutVector::value_type> u1_local(dofs_per_cell); + Vector<typename OutVector::value_type> u1_diff_local(dofs_per_cell); + + const types::subdomain_id subdomain_id = + dof1.get_tria().locally_owned_subdomain(); + + FullMatrix<double> difference_matrix(dofs_per_cell, dofs_per_cell); + get_interpolation_difference_matrix(dof1.get_fe(), fe2, + difference_matrix); + + typename DoFHandler<dim,spacedim>::active_cell_iterator cell = dof1.begin_active(), + endc = dof1.end(); + + for (; cell!=endc; ++cell) + if ((cell->subdomain_id() == subdomain_id) + || + (subdomain_id == numbers::invalid_subdomain_id)) + { + if (hanging_nodes_not_allowed) + for (unsigned int face=0; face<GeometryInfo<dim>::faces_per_cell; ++face) + Assert (cell->at_boundary(face) || + cell->neighbor(face)->level() == cell->level(), + ExcHangingNodesNotAllowed(0)); + + cell->get_dof_values(u1, u1_local); + difference_matrix.vmult(u1_diff_local, u1_local); + cell->set_dof_values(u1_diff_local, u1_difference); + } + + // if we work on a parallel PETSc vector + // we have to finish the work and + // update ghost values + u1_difference.compress(VectorOperation::insert); + } + + + + template <int dim, class InVector, class OutVector, int spacedim> + void interpolation_difference(const DoFHandler<dim,spacedim> &dof1, + const ConstraintMatrix &constraints1, + const InVector &u1, + const DoFHandler<dim,spacedim> &dof2, + const ConstraintMatrix &constraints2, + OutVector &u1_difference) + { + // For discontinuous elements + // without constraints take the + // cheaper version of the + // interpolation_difference function. + if (dof1.get_fe().dofs_per_vertex==0 && dof2.get_fe().dofs_per_vertex==0 + && constraints1.n_constraints()==0 && constraints2.n_constraints()==0) + interpolation_difference(dof1, u1, dof2.get_fe(), u1_difference); + else + { + back_interpolate(dof1, constraints1, u1, dof2, constraints2, u1_difference); + u1_difference.sadd(-1, u1); + } + } + + + + template <int dim, class InVector, class OutVector, int spacedim> + void project_dg(const DoFHandler<dim,spacedim> &dof1, + const InVector &u1, + const DoFHandler<dim,spacedim> &dof2, + OutVector &u2) + { + Assert(&dof1.get_tria()==&dof2.get_tria(), ExcTriangulationMismatch()); + Assert(dof1.get_fe().n_components() == dof2.get_fe().n_components(), + ExcDimensionMismatch(dof1.get_fe().n_components(), dof2.get_fe().n_components())); + Assert(u1.size()==dof1.n_dofs(), ExcDimensionMismatch(u1.size(), dof1.n_dofs())); + Assert(u2.size()==dof2.n_dofs(), ExcDimensionMismatch(u2.size(), dof2.n_dofs())); + + typename DoFHandler<dim,spacedim>::active_cell_iterator cell1 = dof1.begin_active(); + typename DoFHandler<dim,spacedim>::active_cell_iterator cell2 = dof2.begin_active(); + typename DoFHandler<dim,spacedim>::active_cell_iterator end = dof2.end(); + + const unsigned int n1 = dof1.get_fe().dofs_per_cell; + const unsigned int n2 = dof2.get_fe().dofs_per_cell; + + Vector<double> u1_local(n1); + Vector<double> u2_local(n2); + std::vector<types::global_dof_index> dofs(n2); + + FullMatrix<double> matrix(n2,n1); + get_projection_matrix(dof1.get_fe(), dof2.get_fe(), matrix); + + while (cell2 != end) + { + cell1->get_dof_values(u1, u1_local); + matrix.vmult(u2_local, u1_local); + cell2->get_dof_indices(dofs); + for (unsigned int i=0; i<n2; ++i) + { + u2(dofs[i])+=u2_local(i); + } + + ++cell1; + ++cell2; + } + } + + + template <int dim, class InVector, class OutVector, int spacedim> + void extrapolate(const DoFHandler<dim,spacedim> &dof1, + const InVector &u1, + const DoFHandler<dim,spacedim> &dof2, + OutVector &u2) + { + ConstraintMatrix dummy; + dummy.close(); + extrapolate(dof1, u1, dof2, dummy, u2); + } + + + + template <int dim, class InVector, class OutVector, int spacedim> + void extrapolate(const DoFHandler<dim,spacedim> &dof1, + const InVector &u1, + const DoFHandler<dim,spacedim> &dof2, + const ConstraintMatrix &constraints, + OutVector &u2) + { + Assert(dof1.get_fe().n_components() == dof2.get_fe().n_components(), + ExcDimensionMismatch(dof1.get_fe().n_components(), dof2.get_fe().n_components())); + Assert(&dof1.get_tria()==&dof2.get_tria(), ExcTriangulationMismatch()); + Assert(u1.size()==dof1.n_dofs(), ExcDimensionMismatch(u1.size(), dof1.n_dofs())); + Assert(u2.size()==dof2.n_dofs(), ExcDimensionMismatch(u2.size(), dof2.n_dofs())); + + OutVector u3; + u3.reinit(u2); + interpolate(dof1, u1, dof2, constraints, u3); + + const unsigned int dofs_per_cell = dof2.get_fe().dofs_per_cell; + Vector<typename OutVector::value_type> dof_values(dofs_per_cell); + + // make sure that each cell on the + // coarsest level is at least once + // refined. otherwise, we can't + // treat these cells and would + // generate a bogus result + { + typename DoFHandler<dim,spacedim>::cell_iterator cell = dof2.begin(0), + endc = dof2.end(0); + for (; cell!=endc; ++cell) + Assert (cell->has_children(), ExcGridNotRefinedAtLeastOnce()); + } + + // then traverse grid bottom up + for (unsigned int level=0; level<dof1.get_tria().n_levels()-1; ++level) + { + typename DoFHandler<dim,spacedim>::cell_iterator cell=dof2.begin(level), + endc=dof2.end(level); + + for (; cell!=endc; ++cell) + if (!cell->active()) + { + // check whether this + // cell has active + // children + bool active_children=false; + for (unsigned int child_n=0; child_n<cell->n_children(); ++child_n) + if (cell->child(child_n)->active()) + { + active_children=true; + break; + } + + // if there are active + // children, the we have + // to work on this + // cell. get the data + // from the one vector + // and set it on the + // other + if (active_children) + { + cell->get_interpolated_dof_values(u3, dof_values); + cell->set_dof_values_by_interpolation(dof_values, u2); + } + } + } + + // Apply hanging node constraints. + constraints.distribute(u2); + } + +} // end of namespace FETools + + + +/*-------------- Explicit Instantiations -------------------------------*/ +#include "fe_tools_interpolate.inst" + + +/*---------------------------- fe_tools.cc ---------------------------*/ + +DEAL_II_NAMESPACE_CLOSE diff --git a/deal.II/source/fe/fe_tools_interpolate.inst.in b/deal.II/source/fe/fe_tools_interpolate.inst.in new file mode 100644 index 0000000000..2c7fa67348 --- /dev/null +++ b/deal.II/source/fe/fe_tools_interpolate.inst.in @@ -0,0 +1,107 @@ +// --------------------------------------------------------------------- +// $Id$ +// +// Copyright (C) 1998 - 2013 by the deal.II authors +// +// This file is part of the deal.II library. +// +// The deal.II library is free software; you can use it, redistribute +// it, and/or modify it under the terms of the GNU Lesser General +// Public License as published by the Free Software Foundation; either +// version 2.1 of the License, or (at your option) any later version. +// The full text of the license can be found in the file LICENSE at +// the top level of the deal.II distribution. +// +// --------------------------------------------------------------------- + + + +for (deal_II_dimension : DIMENSIONS; deal_II_space_dimension : SPACE_DIMENSIONS; Vector : SERIAL_VECTORS) + { + namespace FETools + \{ +#if deal_II_dimension <= deal_II_space_dimension + template + void interpolate<deal_II_dimension,deal_II_space_dimension> + (const DoFHandler<deal_II_dimension,deal_II_space_dimension> &, const Vector &, + const DoFHandler<deal_II_dimension,deal_II_space_dimension> &, Vector &); + + template + void interpolate<deal_II_dimension,deal_II_space_dimension> + (const DoFHandler<deal_II_dimension,deal_II_space_dimension> &, const Vector &, + const DoFHandler<deal_II_dimension,deal_II_space_dimension> &, const ConstraintMatrix &, + Vector &); +#endif + \} + } + +for (deal_II_dimension : DIMENSIONS; deal_II_space_dimension : SPACE_DIMENSIONS) + { + namespace FETools + \{ +#if deal_II_dimension == deal_II_space_dimension + template + void interpolate<deal_II_dimension> + (const hp::DoFHandler<deal_II_dimension> &, const Vector<double> &, + const hp::DoFHandler<deal_II_dimension> &, Vector<double> &); + template + void interpolate<deal_II_dimension> + (const hp::DoFHandler<deal_II_dimension> &, const Vector<double> &, + const hp::DoFHandler<deal_II_dimension> &, const ConstraintMatrix &, + Vector<double> &); + template + void interpolate<deal_II_dimension> + (const hp::DoFHandler<deal_II_dimension> &, const Vector<float> &, + const hp::DoFHandler<deal_II_dimension> &, Vector<float> &); + template + void interpolate<deal_II_dimension> + (const hp::DoFHandler<deal_II_dimension> &, const Vector<float> &, + const hp::DoFHandler<deal_II_dimension> &, const ConstraintMatrix &, + Vector<float> &); +#endif + \} + } + + + +for (deal_II_dimension : DIMENSIONS; deal_II_space_dimension : SPACE_DIMENSIONS; VEC : SERIAL_VECTORS) + { + namespace FETools + \{ +#if deal_II_dimension == deal_II_space_dimension + template + void back_interpolate<deal_II_dimension> + (const DoFHandler<deal_II_dimension> &, const VEC &, + const FiniteElement<deal_II_dimension> &, VEC &); + template + void back_interpolate<deal_II_dimension> + (const DoFHandler<deal_II_dimension> &, const ConstraintMatrix &, + const VEC &, + const DoFHandler<deal_II_dimension> &, const ConstraintMatrix &, + VEC &); + template + void interpolation_difference<deal_II_dimension> + (const DoFHandler<deal_II_dimension> &, const VEC &, + const FiniteElement<deal_II_dimension> &, VEC &); + template + void interpolation_difference<deal_II_dimension> + (const DoFHandler<deal_II_dimension> &, const ConstraintMatrix &, + const VEC &, + const DoFHandler<deal_II_dimension> &, const ConstraintMatrix &, + VEC &); + template + void project_dg<deal_II_dimension> + (const DoFHandler<deal_II_dimension> &, const VEC &, + const DoFHandler<deal_II_dimension> &, VEC &); + template + void extrapolate<deal_II_dimension> + (const DoFHandler<deal_II_dimension> &, const VEC &, + const DoFHandler<deal_II_dimension> &, VEC &); + template + void extrapolate<deal_II_dimension> + (const DoFHandler<deal_II_dimension> &, const VEC &, + const DoFHandler<deal_II_dimension> &, const ConstraintMatrix &, + VEC &); +#endif + \} + } diff --git a/deal.II/source/fe/mapping_c1.cc b/deal.II/source/fe/mapping_c1.cc index 1873d9c737..5a6115220a 100644 --- a/deal.II/source/fe/mapping_c1.cc +++ b/deal.II/source/fe/mapping_c1.cc @@ -53,88 +53,46 @@ MappingC1<2>::add_line_support_points (const Triangulation<2>::cell_iterator &ce const unsigned int dim = 2; std::vector<Point<dim> > line_points (2); - // loop over each of the lines, - // and if it is at the - // boundary, then first get the - // boundary description and - // second compute the points on - // it. if not at the boundary, - // get the respective points - // from another function + // loop over each of the lines, and if it is at the boundary, then first get + // the boundary description and second compute the points on it. if not at + // the boundary, get the respective points from another function for (unsigned int line_no=0; line_no<GeometryInfo<dim>::lines_per_cell; ++line_no) { const Triangulation<dim>::line_iterator line = cell->line(line_no); if (line->at_boundary()) { - // first get the normal - // vectors at the two - // vertices of this line - // from the boundary - // description + // first get the normal vectors at the two vertices of this line + // from the boundary description const Boundary<dim> &boundary = line->get_triangulation().get_boundary(line->boundary_indicator()); Boundary<dim>::FaceVertexNormals face_vertex_normals; boundary.get_normals_at_vertices (line, face_vertex_normals); - // then transform them into - // interpolation points for - // a cubic polynomial + // then transform them into interpolation points for a cubic + // polynomial // - // for this, note that if - // we describe the boundary - // curve as a polynomial in - // tangential coordinate - // @p{t=0..1} (along the - // line) and @p{s} in - // normal direction, then - // the cubic mapping is - // such that @p{s = a*t**3 - // + b*t**2 + c*t + d}, and - // we want to determine the - // interpolation points at - // @p{t=1/3} and - // @p{t=2/3}. Since at - // @p{t=0,1} we want a - // vertex which is actually - // at the boundary, we know - // that @p{d=0} and - // @p{a=-b-c}. As - // side-conditions, we want - // that the derivatives at - // @p{t=0} and @p{t=1}, - // i.e. at the vertices - // match those returned by - // the boundary. We then - // have that - // @p{s(1/3)=1/27(2b+8c)} - // and - // @p{s(2/3)=4/27b+10/27c}. + // for this, note that if we describe the boundary curve as a + // polynomial in tangential coordinate @p{t=0..1} (along the line) + // and @p{s} in normal direction, then the cubic mapping is such + // that @p{s = a*t**3 + b*t**2 + c*t + d}, and we want to determine + // the interpolation points at @p{t=0.276} and @p{t=0.724} + // (Gauss-Lobatto points). Since at @p{t=0,1} we want a vertex which + // is actually at the boundary, we know that @p{d=0} and @p{a=-b-c}, + // which gives @p{s(0.276)} and @{s(0.726)} in terms of @p{b,c}. As + // side-conditions, we want that the derivatives at @p{t=0} and + // @p{t=1}, i.e. at the vertices match those returned by the + // boundary. // - // The task is then first - // to determine the - // coefficients from the - // tangentials. for that, - // first rotate the - // tangents of @p{s(t)} - // into the global - // coordinate system. they - // are @p{A (1,c)} and @p{A - // (1,-b-2c)} with @p{A} the - // rotation matrix, since - // the tangentials in the - // coordinate system - // relative to the line are - // @p{(1,c)} and @p{(1,-b-2c)} - // at the two vertices, - // respectively. We then - // have to make sure by - // matching @p{b,c} that - // these tangentials are - // orthogonal to the normals - // returned by the boundary - // object + // The task is then first to determine the coefficients from the + // tangentials. for that, first rotate the tangents of @p{s(t)} into + // the global coordinate system. they are @p{A (1,c)} and @p{A + // (1,-b-2c)} with @p{A} the rotation matrix, since the tangentials + // in the coordinate system relative to the line are @p{(1,c)} and + // @p{(1,-b-2c)} at the two vertices, respectively. We then have to + // make sure by matching @p{b,c} that these tangentials are + // orthogonal to the normals returned by the boundary object const Tensor<1,2> coordinate_vector = line->vertex(1) - line->vertex(0); const double h = std::sqrt(coordinate_vector * coordinate_vector); Tensor<1,2> coordinate_axis = coordinate_vector; @@ -151,18 +109,18 @@ MappingC1<2>::add_line_support_points (const Triangulation<2>::cell_iterator &ce -face_vertex_normals[1][0] * std::sin(alpha))) -2*c; + QGaussLobatto<1> quad_points(4); + const double t1 = quad_points.point(1)[0]; + const double t2 = quad_points.point(2)[0]; + const double s_t1 = (((-b-c)*t1+b)*t1+c)*t1; + const double s_t2 = (((-b-c)*t2+b)*t2+c)*t2; - // next evaluate the so - // determined cubic - // polynomial at the points - // 1/3 and 2/3, first in - // unit coordinates - const Point<2> new_unit_points[2] = { Point<2>(1./3., 1./27.*(2*b+8*c)), - Point<2>(2./3., 4./27.*b+10./27.*c) + // next evaluate the so determined cubic polynomial at the points + // 1/3 and 2/3, first in unit coordinates + const Point<2> new_unit_points[2] = { Point<2>(t1, s_t1), + Point<2>(t2, s_t2) }; - // then transform these - // points to real - // coordinates by rotating, + // then transform these points to real coordinates by rotating, // scaling and shifting for (unsigned int i=0; i<2; ++i) { diff --git a/deal.II/source/fe/mapping_q.cc b/deal.II/source/fe/mapping_q.cc index 18cb2b1110..4ee1d4374c 100644 --- a/deal.II/source/fe/mapping_q.cc +++ b/deal.II/source/fe/mapping_q.cc @@ -130,15 +130,11 @@ MappingQ<dim,spacedim>::MappingQ (const unsigned int p, || (dim != spacedim)), feq(degree) { - // Construct the tensor product - // polynomials used as shape - // functions for the Qp mapping of - // cells at the boundary. - std::vector<Polynomials::LagrangeEquidistant> v; - for (unsigned int i=0; i<=degree; ++i) - v.push_back(Polynomials::LagrangeEquidistant(degree,i)); - - tensor_pols = new TensorProductPolynomials<dim> (v); + // Construct the tensor product polynomials used as shape functions for the + // Qp mapping of cells at the boundary. + const QGaussLobatto<1> points(degree+1); + tensor_pols = new TensorProductPolynomials<dim> + (Polynomials::generate_complete_Lagrange_basis(points.get_points())); Assert (n_shape_functions==tensor_pols->n(), ExcInternalError()); Assert(n_inner+n_outer==n_shape_functions, ExcInternalError()); @@ -294,10 +290,8 @@ MappingQ<dim,spacedim>::get_subface_data (const UpdateFlags update_flags, } -// Note that the CellSimilarity flag is -// modifyable, since MappingQ can need to -// recalculate data even when cells are -// similar. +// Note that the CellSimilarity flag is modifyable, since MappingQ can need to +// recalculate data even when cells are similar. template<int dim, int spacedim> void MappingQ<dim,spacedim>::fill_fe_values ( @@ -312,35 +306,23 @@ MappingQ<dim,spacedim>::fill_fe_values ( std::vector<Point<spacedim> > &normal_vectors, CellSimilarity::Similarity &cell_similarity) const { - // convert data object to internal - // data for this class. fails with - // an exception if that is not - // possible + // convert data object to internal data for this class. fails with an + // exception if that is not possible Assert (dynamic_cast<InternalData *> (&mapping_data) != 0, ExcInternalError()); InternalData &data = static_cast<InternalData &> (mapping_data); - // check whether this cell needs - // the full mapping or can be - // treated by a reduced Q1 mapping, - // e.g. if the cell is in the - // interior of the domain + // check whether this cell needs the full mapping or can be treated by a + // reduced Q1 mapping, e.g. if the cell is in the interior of the domain data.use_mapping_q1_on_current_cell = !(use_mapping_q_on_all_cells || cell->has_boundary_lines()); - // depending on this result, use this or - // the other data object for the - // mapping. furthermore, we need to - // ensure that the flag indicating - // whether we can use some similarity has - // to be modified - for a general - // MappingQ, the data needs to be - // recomputed anyway since then the - // mapping changes the data. this needs - // to be known also for later operations, - // so modify the variable here. this also - // affects the calculation of the next - // cell -- if we use Q1 data on the next - // cell, the data will still be invalid. + // depending on this result, use this or the other data object for the + // mapping. furthermore, we need to ensure that the flag indicating whether + // we can use some similarity has to be modified - for a general MappingQ, + // the data needs to be recomputed anyway since then the mapping changes the + // data. this needs to be known also for later operations, so modify the + // variable here. this also affects the calculation of the next cell -- if + // we use Q1 data on the next cell, the data will still be invalid. typename MappingQ1<dim,spacedim>::InternalData *p_data=0; if (data.use_mapping_q1_on_current_cell) p_data=&data.mapping_q1_data; @@ -372,34 +354,23 @@ MappingQ<dim,spacedim>::fill_fe_face_values ( std::vector<Tensor<1,spacedim> > &exterior_forms, std::vector<Point<spacedim> > &normal_vectors) const { - // convert data object to internal - // data for this class. fails with - // an exception if that is not - // possible + // convert data object to internal data for this class. fails with an + // exception if that is not possible Assert (dynamic_cast<InternalData *> (&mapping_data) != 0, ExcInternalError()); InternalData &data = static_cast<InternalData &> (mapping_data); - // check whether this cell needs - // the full mapping or can be - // treated by a reduced Q1 mapping, - // e.g. if the cell is entirely in - // the interior of the domain. note - // that it is not sufficient to ask - // whether the present _face_ is in - // the interior, as the mapping on - // the face depends on the mapping - // of the cell, which in turn - // depends on the fact whether - // _any_ of the faces of this cell - // is at the boundary, not only the - // present face + // check whether this cell needs the full mapping or can be treated by a + // reduced Q1 mapping, e.g. if the cell is entirely in the interior of the + // domain. note that it is not sufficient to ask whether the present _face_ + // is in the interior, as the mapping on the face depends on the mapping of + // the cell, which in turn depends on the fact whether _any_ of the faces of + // this cell is at the boundary, not only the present face data.use_mapping_q1_on_current_cell=!(use_mapping_q_on_all_cells || cell->has_boundary_lines()); - // depending on this result, use - // this or the other data object - // for the mapping + // depending on this result, use this or the other data object for the + // mapping typename MappingQ1<dim,spacedim>::InternalData *p_data=0; if (data.use_mapping_q1_on_current_cell) p_data=&data.mapping_q1_data; @@ -434,34 +405,23 @@ MappingQ<dim,spacedim>::fill_fe_subface_values (const typename Triangulation<dim std::vector<Tensor<1,spacedim> > &exterior_forms, std::vector<Point<spacedim> > &normal_vectors) const { - // convert data object to internal - // data for this class. fails with - // an exception if that is not - // possible + // convert data object to internal data for this class. fails with an + // exception if that is not possible Assert (dynamic_cast<InternalData *> (&mapping_data) != 0, ExcInternalError()); InternalData &data = static_cast<InternalData &> (mapping_data); - // check whether this cell needs - // the full mapping or can be - // treated by a reduced Q1 mapping, - // e.g. if the cell is entirely in - // the interior of the domain. note - // that it is not sufficient to ask - // whether the present _face_ is in - // the interior, as the mapping on - // the face depends on the mapping - // of the cell, which in turn - // depends on the fact whether - // _any_ of the faces of this cell - // is at the boundary, not only the - // present face + // check whether this cell needs the full mapping or can be treated by a + // reduced Q1 mapping, e.g. if the cell is entirely in the interior of the + // domain. note that it is not sufficient to ask whether the present _face_ + // is in the interior, as the mapping on the face depends on the mapping of + // the cell, which in turn depends on the fact whether _any_ of the faces of + // this cell is at the boundary, not only the present face data.use_mapping_q1_on_current_cell=!(use_mapping_q_on_all_cells || cell->has_boundary_lines()); - // depending on this result, use - // this or the other data object - // for the mapping + // depending on this result, use this or the other data object for the + // mapping typename MappingQ1<dim,spacedim>::InternalData *p_data=0; if (data.use_mapping_q1_on_current_cell) p_data=&data.mapping_q1_data; @@ -503,25 +463,19 @@ MappingQ<dim,spacedim>::set_laplace_on_quad_vector(Table<2,double> &loqvs) const const unsigned int n_inner_2d=(degree-1)*(degree-1); const unsigned int n_outer_2d=4+4*(degree-1); - // first check whether we have precomputed - // the values for some polynomial degree; - // the sizes of arrays is - // n_inner_2d*n_outer_2d + // first check whether we have precomputed the values for some polynomial + // degree; the sizes of arrays is n_inner_2d*n_outer_2d double const *loqv_ptr=0; switch (degree) { - // for degree==1, we shouldn't have to - // compute any support points, since + // for degree==1, we shouldn't have to compute any support points, since // all of them are on the vertices case 2: { - // (checked these values against the - // output of compute_laplace_vector - // again, and found they're indeed - // right -- just in case someone - // wonders where they come from -- - // WB) + // (checked these values against the output of compute_laplace_vector + // again, and found they're indeed right -- just in case someone wonders + // where they come from -- WB) static const double loqv2[1*8] = {1/16., 1/16., 1/16., 1/16., 3/16., 3/16., 3/16., 3/16.}; loqv_ptr=&loqv2[0]; @@ -532,133 +486,14 @@ MappingQ<dim,spacedim>::set_laplace_on_quad_vector(Table<2,double> &loqvs) const break; } - case 3: - { - // (same as above) - static const double loqv3[4*12] - = {80/1053., 1/81., 1/81., 11/1053., 25/117., 44/351., - 7/117., 16/351., 25/117., 44/351., 7/117., 16/351., - 1/81., 80/1053., 11/1053., 1/81., 7/117., 16/351., - 25/117., 44/351., 44/351., 25/117., 16/351., 7/117., - 1/81., 11/1053., 80/1053., 1/81., 44/351., 25/117., - 16/351., 7/117., 7/117., 16/351., 25/117., 44/351., - 11/1053., 1/81., 1/81., 80/1053., 16/351., 7/117., - 44/351., 25/117., 16/351., 7/117., 44/351., 25/117. - }; - Assert (sizeof(loqv3)/sizeof(loqv3[0]) == - n_inner_2d * n_outer_2d, - ExcInternalError()); - - loqv_ptr=&loqv3[0]; - - break; - } - - - case 4: - { - static const double loqv4[9*16] - = {0.07405921850311571, -0.001075744628905992, - -0.001075744628906007, 0.001914292239071463, - 0.2231273865431892, 0.1346851306015187, - 0.03812914216116724, 0.02913160002633252, - 0.02200737428129396, 0.01600835564431224, - 0.2231273865431891, 0.1346851306015187, - 0.03812914216116723, 0.02913160002633253, - 0.02200737428129391, 0.01600835564431222, - - 0.00664803151334206, 0.006648031513342719, - 0.002873452861657458, 0.002873452861657626, - 0.07903572682584378, 0.05969238281250031, - 0.03619864817415824, 0.07903572682584187, - 0.0596923828124999, 0.03619864817415815, - 0.1527716818820237, 0.2348152760709273, - 0.152771681882024, 0.02496269311797778, - 0.04081948955407129, 0.02496269311797789, - - -0.001075744628906923, 0.07405921850311589, - 0.001914292239071339, -0.001075744628905884, - 0.02913160002633509, 0.02200737428129395, - 0.01600835564431229, 0.2231273865431878, - 0.1346851306015183, 0.0381291421611672, - 0.03812914216116729, 0.1346851306015185, - 0.2231273865431898, 0.01600835564431217, - 0.02200737428129394, 0.02913160002633262, - - 0.006648031513342073, 0.002873452861657473, - 0.006648031513342726, 0.002873452861657636, - 0.1527716818820238, 0.2348152760709273, - 0.152771681882024, 0.02496269311797779, - 0.04081948955407131, 0.0249626931179779, - 0.07903572682584376, 0.05969238281250026, - 0.03619864817415824, 0.07903572682584187, - 0.0596923828124998, 0.0361986481741581, - - 0.01106770833333302, 0.01106770833333336, - 0.01106770833333337, 0.01106770833333374, - 0.06770833333333424, 0.1035156250000011, - 0.0677083333333344, 0.06770833333333376, - 0.103515624999999, 0.06770833333333399, - 0.06770833333333422, 0.1035156250000009, - 0.06770833333333436, 0.0677083333333337, - 0.1035156249999988, 0.0677083333333339, - - 0.002873452861657185, 0.006648031513342362, - 0.002873452861657334, 0.006648031513343038, - 0.02496269311797779, 0.04081948955407401, - 0.02496269311797788, 0.1527716818820234, - 0.234815276070926, 0.1527716818820237, - 0.03619864817415819, 0.05969238281250028, - 0.07903572682584407, 0.03619864817415804, - 0.05969238281249986, 0.0790357268258422, - - -0.001075744628906913, 0.00191429223907134, - 0.07405921850311592, -0.001075744628905865, - 0.03812914216116729, 0.1346851306015185, - 0.2231273865431899, 0.01600835564431217, - 0.02200737428129396, 0.02913160002633264, - 0.02913160002633509, 0.02200737428129391, - 0.01600835564431228, 0.2231273865431878, - 0.1346851306015183, 0.03812914216116718, - - 0.002873452861657176, 0.002873452861657321, - 0.006648031513342374, 0.006648031513343037, - 0.03619864817415817, 0.05969238281250032, - 0.07903572682584409, 0.03619864817415805, - 0.05969238281249992, 0.07903572682584221, - 0.02496269311797776, 0.04081948955407392, - 0.02496269311797785, 0.1527716818820233, - 0.2348152760709258, 0.1527716818820236, - - 0.001914292239071237, -0.001075744628906803, - -0.001075744628906778, 0.07405921850311617, - 0.01600835564431228, 0.02200737428129401, - 0.02913160002633524, 0.03812914216116726, - 0.1346851306015182, 0.2231273865431886, - 0.01600835564431228, 0.02200737428129397, - 0.02913160002633523, 0.03812914216116726, - 0.1346851306015181, 0.2231273865431886, - }; - - Assert (sizeof(loqv4)/sizeof(loqv4[0]) == - n_inner_2d * n_outer_2d, - ExcInternalError()); - - loqv_ptr=&loqv4[0]; - - break; - } - - // no other cases implemented, - // so simply fall through + // no other cases implemented, so simply fall through default: break; } if (loqv_ptr!=0) { - // precomputed. copy values to - // the loqvs array + // precomputed. copy values to the loqvs array loqvs.reinit(n_inner_2d, n_outer_2d); for (unsigned int unit_point=0; unit_point<n_inner_2d; ++unit_point) for (unsigned int k=0; k<n_outer_2d; ++k) @@ -667,36 +502,20 @@ MappingQ<dim,spacedim>::set_laplace_on_quad_vector(Table<2,double> &loqvs) const else { // not precomputed, then do so now - if (dim==2) + if (dim == 2) compute_laplace_vector(loqvs); - else - // computing the Laplace vector for - // faces is not supported in 3d at - // present. presumably, doing so - // would not be so hard: we would - // only have to call the function in - // 2d, i.e. the quad(=face) values in - // 3d are equal to the quad(=cell) - // values in 2d. however, that would - // require us to link in the 2d - // library, which is kind of awkward - // (note that compute_laplace_vector - // really makes use of a lot of 2d - // stuff, such as FEValues etc). an - // alternative would be to precompute - // the values of this array for a - // couple of higher mapping orders, - // pin down their values and insert - // them into the array above. - Assert (false, ExcNotImplemented()); + else if (dim == 3) + { + MappingQ<2,2> mapping_2d(this->degree); + loqvs = mapping_2d.laplace_on_quad_vector; + } } - // the sum of weights of the points - // at the outer rim should be - // one. check this + // the sum of weights of the points at the outer rim should be one. check + // this for (unsigned int unit_point=0; unit_point<loqvs.n_rows(); ++unit_point) Assert(std::fabs(std::accumulate(loqvs[unit_point].begin(), - loqvs[unit_point].end(),0.)-1)<1e-12*this->degree*this->degree, + loqvs[unit_point].end(),0.)-1)<1e-13*this->degree, ExcInternalError()); } @@ -708,9 +527,8 @@ MappingQ<3>::set_laplace_on_hex_vector(Table<2,double> &lohvs) const { Assert(degree>1, ExcInternalError()); - // first check whether we have - // precomputed the values for some - // polynomial degree + // first check whether we have precomputed the values for some polynomial + // degree double const *lohv_ptr=0; if (degree==2) { @@ -726,8 +544,7 @@ MappingQ<3>::set_laplace_on_hex_vector(Table<2,double> &lohvs) const if (lohv_ptr!=0) { - // precomputed. copy values to - // the lohvs array + // precomputed. copy values to the lohvs array lohvs.reinit(n_inner, n_outer); for (unsigned int unit_point=0; unit_point<n_inner; ++unit_point) for (unsigned int k=0; k<n_outer; ++k) @@ -737,12 +554,11 @@ MappingQ<3>::set_laplace_on_hex_vector(Table<2,double> &lohvs) const // not precomputed, then do so now compute_laplace_vector(lohvs); - // the sum of weights of the points - // at the outer rim should be - // one. check this + // the sum of weights of the points at the outer rim should be one. check + // this for (unsigned int unit_point=0; unit_point<n_inner; ++unit_point) Assert(std::fabs(std::accumulate(lohvs[unit_point].begin(), - lohvs[unit_point].end(),0.) - 1)<1e-13, + lohvs[unit_point].end(),0.) - 1)<1e-12*this->degree*this->degree, ExcInternalError()); } @@ -773,14 +589,11 @@ MappingQ<dim,spacedim>::compute_laplace_vector(Table<2,double> &lvs) const Assert(lvs.n_rows()==0, ExcInternalError()); Assert(dim==2 || dim==3, ExcNotImplemented()); - // for degree==1, we shouldn't have to - // compute any support points, since all of - // them are on the vertices + // for degree==1, we shouldn't have to compute any support points, since all + // of them are on the vertices Assert(degree>1, ExcInternalError()); - // compute the shape - // gradients at the quadrature - // points on the unit cell + // compute the shape gradients at the quadrature points on the unit cell const QGauss<dim> quadrature(degree+1); const unsigned int n_q_points=quadrature.size(); @@ -788,37 +601,44 @@ MappingQ<dim,spacedim>::compute_laplace_vector(Table<2,double> &lvs) const quadrature_data.shape_derivatives.resize(n_shape_functions * n_q_points); this->compute_shapes(quadrature.get_points(), quadrature_data); - // Compute the stiffness matrix of - // the inner dofs - FullMatrix<double> S(n_inner); + // Compute the stiffness matrix of the inner dofs + FullMatrix<long double> S(n_inner); for (unsigned int point=0; point<n_q_points; ++point) for (unsigned int i=0; i<n_inner; ++i) for (unsigned int j=0; j<n_inner; ++j) - S(i,j) += contract(quadrature_data.derivative(point, n_outer+i), - quadrature_data.derivative(point, n_outer+j)) - * quadrature.weight(point); + { + long double res = 0.; + for (unsigned int l=0; l<dim; ++l) + res += (long double)quadrature_data.derivative(point, n_outer+i)[l] * + (long double)quadrature_data.derivative(point, n_outer+j)[l]; - // Compute the components of T to be the - // product of gradients of inner and + S(i,j) += res * (long double)quadrature.weight(point); + } + + // Compute the components of T to be the product of gradients of inner and // outer shape functions. - FullMatrix<double> T(n_inner, n_outer); + FullMatrix<long double> T(n_inner, n_outer); for (unsigned int point=0; point<n_q_points; ++point) for (unsigned int i=0; i<n_inner; ++i) for (unsigned int k=0; k<n_outer; ++k) - T(i,k) += contract(quadrature_data.derivative(point, n_outer+i), - quadrature_data.derivative(point, k)) - *quadrature.weight(point); + { + long double res = 0.; + for (unsigned int l=0; l<dim; ++l) + res += (long double)quadrature_data.derivative(point, n_outer+i)[l] * + (long double)quadrature_data.derivative(point, k)[l]; + + T(i,k) += res *(long double)quadrature.weight(point); + } - FullMatrix<double> S_1(n_inner); + FullMatrix<long double> S_1(n_inner); S_1.invert(S); - FullMatrix<double> S_1_T(n_inner, n_outer); + FullMatrix<long double> S_1_T(n_inner, n_outer); // S:=S_1*T S_1.mmult(S_1_T,T); - // Resize and initialize the - // lvs + // Resize and initialize the lvs lvs.reinit (n_inner, n_outer); for (unsigned int i=0; i<n_inner; ++i) for (unsigned int k=0; k<n_outer; ++k) @@ -832,16 +652,10 @@ void MappingQ<dim,spacedim>::apply_laplace_vector(const Table<2,double> &lvs, std::vector<Point<spacedim> > &a) const { - // check whether the data we need - // is really available. if you fail - // here and if - // lvs==laplace_on_quad_vector in - // the calling function, then we - // didn't compute the quad laplace - // vector. this is mentioned in the - // constructor of this class, - // although I don't understand the - // reason for not aborting there + // check whether the data we need is really available. if you fail here and + // if lvs==laplace_on_quad_vector in the calling function, then we didn't + // compute the quad laplace vector. this is mentioned in the constructor of + // this class, although I don't understand the reason for not aborting there // any more [WB] Assert(lvs.n_rows()!=0, ExcLaplaceVectorNotSet(degree)); @@ -852,12 +666,9 @@ MappingQ<dim,spacedim>::apply_laplace_vector(const Table<2,double> &lvs, Assert(a.size()==n_outer_apply, ExcDimensionMismatch(a.size(), n_outer_apply)); - // compute each inner point as - // linear combination of the outer - // points. the weights are given by - // the lvs entries, the outer - // points are the first (existing) - // elements of a + // compute each inner point as linear combination of the outer points. the + // weights are given by the lvs entries, the outer points are the first + // (existing) elements of a for (unsigned int unit_point=0; unit_point<n_inner_apply; ++unit_point) { Assert(lvs.n_cols()==n_outer_apply, ExcInternalError()); @@ -876,18 +687,13 @@ MappingQ<dim,spacedim>::compute_mapping_support_points( const typename Triangulation<dim,spacedim>::cell_iterator &cell, std::vector<Point<spacedim> > &a) const { - // if this is a cell for which we - // want to compute the full - // mapping, then get them from the - // following function + // if this is a cell for which we want to compute the full mapping, then get + // them from the following function if (use_mapping_q_on_all_cells || cell->has_boundary_lines()) compute_support_points_laplace(cell, a); else - // otherwise: use a Q1 mapping - // for which the mapping shape - // function support points are - // simply the vertices of the - // cell + // otherwise: use a Q1 mapping for which the mapping shape function + // support points are simply the vertices of the cell { a.resize(GeometryInfo<dim>::vertices_per_cell); @@ -902,8 +708,7 @@ void MappingQ<dim,spacedim>::compute_support_points_laplace(const typename Triangulation<dim,spacedim>::cell_iterator &cell, std::vector<Point<spacedim> > &a) const { - // in any case, we need the - // vertices first + // in any case, we need the vertices first a.resize(GeometryInfo<dim>::vertices_per_cell); for (unsigned int i=0; i<GeometryInfo<dim>::vertices_per_cell; ++i) a[i] = cell->vertex(i); @@ -915,11 +720,8 @@ MappingQ<dim,spacedim>::compute_support_points_laplace(const typename Triangulat add_line_support_points(cell, a); break; case 2: - // in 2d, add the - // points on the four - // bounding lines to - // the exterior (outer) - // points + // in 2d, add the points on the four bounding lines to the exterior + // (outer) points add_line_support_points (cell, a); if (dim != spacedim) add_quad_support_points(cell, a); @@ -929,9 +731,7 @@ MappingQ<dim,spacedim>::compute_support_points_laplace(const typename Triangulat case 3: { - // in 3d also add the - // points located on - // the boundary faces + // in 3d also add the points located on the boundary faces add_line_support_points (cell, a); add_quad_support_points (cell, a); apply_laplace_vector (laplace_on_hex_vector, a); @@ -950,8 +750,7 @@ void MappingQ<1>::add_line_support_points (const Triangulation<1>::cell_iterator &, std::vector<Point<1> > &) const { - // there are no points on bounding - // lines which are to be added + // there are no points on bounding lines which are to be added const unsigned int dim=1; Assert (dim > 1, ExcImpossibleInDim(dim)); } @@ -965,8 +764,7 @@ MappingQ<1,2>::add_line_support_points (const Triangulation<1,2>::cell_iterator { const unsigned int dim = 1; const unsigned int spacedim = 2; - // Ask for the mid point, if that's - // the only thing we need. + // Ask for the mid point, if that's the only thing we need. if (degree==2) { const Boundary<dim,spacedim> *const boundary @@ -974,10 +772,8 @@ MappingQ<1,2>::add_line_support_points (const Triangulation<1,2>::cell_iterator a.push_back(boundary->get_new_point_on_line(cell)); } else - // otherwise call the more - // complicated functions and ask - // for inner points from the - // boundary description + // otherwise call the more complicated functions and ask for inner points + // from the boundary description { std::vector<Point<spacedim> > line_points (degree-1); @@ -999,8 +795,7 @@ MappingQ<1,3>::add_line_support_points (const Triangulation<1,3>::cell_iterator { const unsigned int dim = 1; const unsigned int spacedim = 3; - // Ask for the mid point, if that's - // the only thing we need. + // Ask for the mid point, if that's the only thing we need. if (degree==2) { const Boundary<dim,spacedim> *const boundary @@ -1008,10 +803,8 @@ MappingQ<1,3>::add_line_support_points (const Triangulation<1,3>::cell_iterator a.push_back(boundary->get_new_point_on_line(cell)); } else - // otherwise call the more - // complicated functions and ask - // for inner points from the - // boundary description + // otherwise call the more complicated functions and ask for inner points + // from the boundary description { std::vector<Point<spacedim> > line_points (degree-1); @@ -1032,8 +825,7 @@ MappingQ<dim,spacedim>::add_line_support_points (const typename Triangulation<di std::vector<Point<spacedim> > &a) const { static const StraightBoundary<dim,spacedim> straight_boundary; - // if we only need the midpoint, - // then ask for it. + // if we only need the midpoint, then ask for it. if (degree==2) { for (unsigned int line_no=0; line_no<GeometryInfo<dim>::lines_per_cell; ++line_no) @@ -1050,19 +842,13 @@ MappingQ<dim,spacedim>::add_line_support_points (const typename Triangulation<di }; } else - // otherwise call the more - // complicated functions and ask - // for inner points from the - // boundary description + // otherwise call the more complicated functions and ask for inner points + // from the boundary description { std::vector<Point<spacedim> > line_points (degree-1); - // loop over each of the lines, - // and if it is at the - // boundary, then first get the - // boundary description and - // second compute the points on - // it + // loop over each of the lines, and if it is at the boundary, then first + // get the boundary description and second compute the points on it for (unsigned int line_no=0; line_no<GeometryInfo<dim>::lines_per_cell; ++line_no) { const typename Triangulation<dim,spacedim>::line_iterator line = cell->line(line_no); @@ -1077,8 +863,7 @@ MappingQ<dim,spacedim>::add_line_support_points (const typename Triangulation<di boundary->get_intermediate_points_on_line (line, line_points); if (dim==3) { - // in 3D, lines might be in wrong - // orientation. if so, reverse + // in 3D, lines might be in wrong orientation. if so, reverse // the vector if (cell->line_orientation(line_no)) a.insert (a.end(), line_points.begin(), line_points.end()); @@ -1086,9 +871,8 @@ MappingQ<dim,spacedim>::add_line_support_points (const typename Triangulation<di a.insert (a.end(), line_points.rbegin(), line_points.rend()); } else - // in 2D, lines always have the - // correct orientation. simply - // append all points + // in 2D, lines always have the correct orientation. simply append + // all points a.insert (a.end(), line_points.begin(), line_points.end()); } @@ -1109,23 +893,18 @@ add_quad_support_points(const Triangulation<3>::cell_iterator &cell, vertices_per_cell = GeometryInfo<3>::vertices_per_cell; static const StraightBoundary<3> straight_boundary; - // used if face quad at boundary or - // entirely in the interior of the - // domain + // used if face quad at boundary or entirely in the interior of the domain std::vector<Point<3> > quad_points ((degree-1)*(degree-1)); - // used if only one line of face - // quad is at boundary + // used if only one line of face quad is at boundary std::vector<Point<3> > b(4*degree); - // loop over all faces and collect - // points on them + // loop over all faces and collect points on them for (unsigned int face_no=0; face_no<faces_per_cell; ++face_no) { const Triangulation<3>::face_iterator face = cell->face(face_no); - // select the correct mappings - // for the present face + // select the correct mappings for the present face const bool face_orientation = cell->face_orientation(face_no), face_flip = cell->face_flip (face_no), face_rotation = cell->face_rotation (face_no); @@ -1140,9 +919,7 @@ add_quad_support_points(const Triangulation<3>::cell_iterator &cell, face_rotation)), ExcInternalError()); - // indices of the lines that - // bound a face are given by - // GeometryInfo<3>:: + // indices of the lines that bound a face are given by GeometryInfo<3>:: // face_to_cell_lines for (unsigned int i=0; i<lines_per_face; ++i) Assert(face->line(i)==cell->line(GeometryInfo<3>::face_to_cell_lines( @@ -1150,22 +927,16 @@ add_quad_support_points(const Triangulation<3>::cell_iterator &cell, ExcInternalError()); #endif - // if face at boundary, then - // ask boundary object to - // return intermediate points - // on it + // if face at boundary, then ask boundary object to return intermediate + // points on it if (face->at_boundary()) { face->get_triangulation().get_boundary(face->boundary_indicator()) .get_intermediate_points_on_quad (face, quad_points); - // in 3D, the orientation, flip and - // rotation of the face might not - // match what we expect here, namely - // the standard orientation. thus - // reorder points accordingly. since - // a Mapping uses the same shape - // function as an FEQ, we can ask a - // FEQ to do the reordering for us. + // in 3D, the orientation, flip and rotation of the face might not + // match what we expect here, namely the standard orientation. thus + // reorder points accordingly. since a Mapping uses the same shape + // function as an FEQ, we can ask a FEQ to do the reordering for us. for (unsigned int i=0; i<quad_points.size(); ++i) a.push_back(quad_points[feq.adjust_quad_dof_index_for_face_orientation(i, face_orientation, @@ -1174,9 +945,8 @@ add_quad_support_points(const Triangulation<3>::cell_iterator &cell, } else { - // face is not at boundary, - // but maybe some of its - // lines are. count them + // face is not at boundary, but maybe some of its lines are. count + // them unsigned int lines_at_boundary=0; for (unsigned int i=0; i<lines_per_face; ++i) if (face->line(i)->at_boundary()) @@ -1184,37 +954,23 @@ add_quad_support_points(const Triangulation<3>::cell_iterator &cell, Assert(lines_at_boundary<=lines_per_face, ExcInternalError()); - // if at least one of the - // lines bounding this quad - // is at the boundary, then - // collect points - // separately + // if at least one of the lines bounding this quad is at the + // boundary, then collect points separately if (lines_at_boundary>0) { - // call of function - // apply_laplace_vector - // increases size of b - // about 1. There - // resize b for the - // case the mentioned - // function was already - // called. + // call of function apply_laplace_vector increases size of b + // about 1. There resize b for the case the mentioned function + // was already called. b.resize(4*degree); - // b is of size - // 4*degree, make sure - // that this is the - // right size + // b is of size 4*degree, make sure that this is the right size Assert(b.size()==vertices_per_face+lines_per_face*(degree-1), ExcDimensionMismatch(b.size(), vertices_per_face+lines_per_face*(degree-1))); - // sort the points into b. We - // used access from the cell (not - // from the face) to fill b, so - // we can assume a standard face - // orientation. Doing so, the - // calculated points will be in + // sort the points into b. We used access from the cell (not + // from the face) to fill b, so we can assume a standard face + // orientation. Doing so, the calculated points will be in // standard orientation as well. for (unsigned int i=0; i<vertices_per_face; ++i) b[i]=a[GeometryInfo<3>::face_to_cell_vertices(face_no, i)]; @@ -1225,8 +981,7 @@ add_quad_support_points(const Triangulation<3>::cell_iterator &cell, a[vertices_per_cell + GeometryInfo<3>::face_to_cell_lines( face_no, i)*(degree-1)+j]; - // Now b includes the support - // points on the quad and we can + // Now b includes the support points on the quad and we can // apply the laplace vector apply_laplace_vector(laplace_on_quad_vector, b); Assert(b.size()==4*degree+(degree-1)*(degree-1), @@ -1237,22 +992,14 @@ add_quad_support_points(const Triangulation<3>::cell_iterator &cell, } else { - // face is entirely in - // the interior. get - // intermediate points - // from a straight - // boundary object + // face is entirely in the interior. get intermediate points + // from a straight boundary object straight_boundary.get_intermediate_points_on_quad (face, quad_points); - // in 3D, the orientation, flip - // and rotation of the face might - // not match what we expect here, - // namely the standard - // orientation. thus reorder - // points accordingly. since a - // Mapping uses the same shape - // function as an FEQ, we can ask - // a FEQ to do the reordering for - // us. + // in 3D, the orientation, flip and rotation of the face might + // not match what we expect here, namely the standard + // orientation. thus reorder points accordingly. since a Mapping + // uses the same shape function as an FEQ, we can ask a FEQ to + // do the reordering for us. for (unsigned int i=0; i<quad_points.size(); ++i) a.push_back(quad_points[feq.adjust_quad_dof_index_for_face_orientation(i, face_orientation, @@ -1301,31 +1048,24 @@ MappingQ<dim,spacedim>::transform ( const MappingType mapping_type) const { AssertDimension (input.size(), output.size()); - // The data object may be just a - // MappingQ1::InternalData, so we - // have to test for this first. + // The data object may be just a MappingQ1::InternalData, so we have to test + // for this first. const typename MappingQ1<dim,spacedim>::InternalData *q1_data = dynamic_cast<const typename MappingQ1<dim,spacedim>::InternalData *> (&mapping_data); Assert(q1_data!=0, ExcInternalError()); - // If it is a genuine - // MappingQ::InternalData, we have - // to test further + // If it is a genuine MappingQ::InternalData, we have to test further if (!q1_data->is_mapping_q1_data) { Assert (dynamic_cast<const InternalData *>(&mapping_data) != 0, ExcInternalError()); const InternalData &data = static_cast<const InternalData &>(mapping_data); - // If we only use the - // Q1-portion, we have to - // extract that data object + // If we only use the Q1-portion, we have to extract that data object if (data.use_mapping_q1_on_current_cell) q1_data = &data.mapping_q1_data; } - // Now, q1_data should have the - // right tensors in it and we call - // the base classes transform - // function + // Now, q1_data should have the right tensors in it and we call the base + // classes transform function MappingQ1<dim,spacedim>::transform(input, output, *q1_data, mapping_type); } @@ -1340,31 +1080,24 @@ MappingQ<dim,spacedim>::transform ( const MappingType mapping_type) const { AssertDimension (input.size(), output.size()); - // The data object may be just a - // MappingQ1::InternalData, so we - // have to test for this first. + // The data object may be just a MappingQ1::InternalData, so we have to test + // for this first. const typename MappingQ1<dim,spacedim>::InternalData *q1_data = dynamic_cast<const typename MappingQ1<dim,spacedim>::InternalData *> (&mapping_data); Assert(q1_data!=0, ExcInternalError()); - // If it is a genuine - // MappingQ::InternalData, we have - // to test further + // If it is a genuine MappingQ::InternalData, we have to test further if (!q1_data->is_mapping_q1_data) { Assert (dynamic_cast<const InternalData *>(&mapping_data) != 0, ExcInternalError()); const InternalData &data = static_cast<const InternalData &>(mapping_data); - // If we only use the - // Q1-portion, we have to - // extract that data object + // If we only use the Q1-portion, we have to extract that data object if (data.use_mapping_q1_on_current_cell) q1_data = &data.mapping_q1_data; } - // Now, q1_data should have the - // right tensors in it and we call - // the base classes transform - // function + // Now, q1_data should have the right tensors in it and we call the base + // classes transform function MappingQ1<dim,spacedim>::transform(input, output, *q1_data, mapping_type); } @@ -1377,31 +1110,24 @@ void MappingQ<dim,spacedim>::transform const MappingType mapping_type) const { AssertDimension (input.size(), output.size()); - // The data object may be just a - // MappingQ1::InternalData, so we - // have to test for this first. + // The data object may be just a MappingQ1::InternalData, so we have to test + // for this first. const typename MappingQ1<dim,spacedim>::InternalData *q1_data = dynamic_cast<const typename MappingQ1<dim,spacedim>::InternalData *> (&mapping_data); Assert(q1_data!=0, ExcInternalError()); - // If it is a genuine - // MappingQ::InternalData, we have - // to test further + // If it is a genuine MappingQ::InternalData, we have to test further if (!q1_data->is_mapping_q1_data) { Assert (dynamic_cast<const InternalData *>(&mapping_data) != 0, ExcInternalError()); const InternalData &data = static_cast<const InternalData &>(mapping_data); - // If we only use the - // Q1-portion, we have to - // extract that data object + // If we only use the Q1-portion, we have to extract that data object if (data.use_mapping_q1_on_current_cell) q1_data = &data.mapping_q1_data; } - // Now, q1_data should have the - // right tensors in it and we call - // the base classes transform - // function + // Now, q1_data should have the right tensors in it and we call the base + // classes transform function MappingQ1<dim,spacedim>::transform(input, output, *q1_data, mapping_type); } @@ -1412,11 +1138,9 @@ MappingQ<dim,spacedim>:: transform_unit_to_real_cell (const typename Triangulation<dim,spacedim>::cell_iterator &cell, const Point<dim> &p) const { - // Use the get_data function to - // create an InternalData with data - // vectors of the right size and - // transformation shape values - // already computed at point p. + // Use the get_data function to create an InternalData with data vectors of + // the right size and transformation shape values already computed at point + // p. const Quadrature<dim> point_quadrature(p); std::auto_ptr<InternalData> mdata (dynamic_cast<InternalData *> ( @@ -1431,8 +1155,7 @@ transform_unit_to_real_cell (const typename Triangulation<dim,spacedim>::cell_it &*mdata); compute_mapping_support_points(cell, p_data->mapping_support_points); - // If this should be Q1, ignore all - // other support points. + // If this should be Q1, ignore all other support points. if (p_data->shape_values.size()<p_data->mapping_support_points.size()) p_data->mapping_support_points.resize (GeometryInfo<dim>::vertices_per_cell); @@ -1449,24 +1172,15 @@ MappingQ<dim,spacedim>:: transform_real_to_unit_cell (const typename Triangulation<dim,spacedim>::cell_iterator &cell, const Point<spacedim> &p) const { - // first a Newton iteration based - // on a Q1 mapping to get a good - // starting point, the idea being - // that this is cheaper than trying - // to start with the real mapping - // and likely also more robust. + // first a Newton iteration based on a Q1 mapping to get a good starting + // point, the idea being that this is cheaper than trying to start with the + // real mapping and likely also more robust. // - // that said, this doesn't always - // work: there are cases where the - // point is outside the cell and - // the inverse mapping doesn't - // converge. in that case, use the - // center point of the cell as a - // starting point if we are to go - // on using the full mapping, or - // just propagate up the exception - // if we had no intention of - // continuing with the full mapping + // that said, this doesn't always work: there are cases where the point is + // outside the cell and the inverse mapping doesn't converge. in that case, + // use the center point of the cell as a starting point if we are to go on + // using the full mapping, or just propagate up the exception if we had no + // intention of continuing with the full mapping Point<dim> initial_p_unit; try { @@ -1475,11 +1189,8 @@ transform_real_to_unit_cell (const typename Triangulation<dim,spacedim>::cell_it } catch (const typename Mapping<dim,spacedim>::ExcTransformationFailed &) { - // mirror the conditions of the - // code below to determine if - // we need to use an arbitrary - // starting point or if we just - // need to rethrow the + // mirror the conditions of the code below to determine if we need to + // use an arbitrary starting point or if we just need to rethrow the // exception if (cell->has_boundary_lines() || @@ -1494,30 +1205,22 @@ transform_real_to_unit_cell (const typename Triangulation<dim,spacedim>::cell_it throw; } - // then a Newton iteration based on the - // full MappingQ if we need this. note that - // for interior cells with dim==spacedim, - // the mapping used is in fact a Q1 - // mapping, so there is nothing we need to - // do unless the iteration above failed + // then a Newton iteration based on the full MappingQ if we need this. note + // that for interior cells with dim==spacedim, the mapping used is in fact a + // Q1 mapping, so there is nothing we need to do unless the iteration above + // failed if (cell->has_boundary_lines() || use_mapping_q_on_all_cells || (dim!=spacedim) ) { - // use the full mapping. in case the - // function above should have given us - // something back that lies outside the - // unit cell (that might happen because - // we may have given a point 'p' that - // lies inside the cell with the higher - // order mapping, but outside the - // Q1-mapped reference cell), then - // project it back into the reference - // cell in hopes that this gives a - // better starting point to the - // following iteration + // use the full mapping. in case the function above should have given us + // something back that lies outside the unit cell (that might happen + // because we may have given a point 'p' that lies inside the cell with + // the higher order mapping, but outside the Q1-mapped reference cell), + // then project it back into the reference cell in hopes that this gives + // a better starting point to the following iteration initial_p_unit = GeometryInfo<dim>::project_to_unit_cell(initial_p_unit); const Quadrature<dim> point_quadrature(initial_p_unit); @@ -1533,13 +1236,11 @@ transform_real_to_unit_cell (const typename Triangulation<dim,spacedim>::cell_it compute_mapping_support_points (cell, mdata->mapping_support_points); - // If this is a q1 mapping, - // then only use the support - // points on the vertices. + // If this is a q1 mapping, then only use the support points on the + // vertices. if (mdata->shape_values.size() < mdata->mapping_support_points.size()) mdata->mapping_support_points.resize(GeometryInfo<dim>::vertices_per_cell); - return this->transform_real_to_unit_cell_internal(cell, p, initial_p_unit, *mdata); } else diff --git a/deal.II/source/fe/mapping_q_eulerian.cc b/deal.II/source/fe/mapping_q_eulerian.cc index c8ba737474..902c6cd359 100644 --- a/deal.II/source/fe/mapping_q_eulerian.cc +++ b/deal.II/source/fe/mapping_q_eulerian.cc @@ -71,20 +71,15 @@ SupportQuadrature (const unsigned int map_degree) : Quadrature<dim>(Utilities::fixed_power<dim>(map_degree+1)) { - // first we determine the support points - // on the unit cell in lexicographic order. - // for this purpose we can use an interated - // trapezoidal quadrature rule. - const QTrapez<1> q1d; - const QIterated<dim> q_iterated(q1d,map_degree); + // first we determine the support points on the unit cell in lexicographic + // order, which are (in accordance with MappingQ) the support points of + // QGaussLobatto. + const QGaussLobatto<dim> q_iterated(map_degree+1); const unsigned int n_q_points = q_iterated.size(); - // we then need to define a renumbering - // vector that allows us to go from a - // lexicographic numbering scheme to a hierarchic - // one. this fragment is taking almost verbatim - // from the MappingQ class. - + // we then need to define a renumbering vector that allows us to go from a + // lexicographic numbering scheme to a hierarchic one. this fragment is + // taking almost verbatim from the MappingQ class. std::vector<unsigned int> renumber(n_q_points); std::vector<unsigned int> dpo(dim+1, 1U); for (unsigned int i=1; i<dpo.size(); ++i) @@ -93,9 +88,7 @@ SupportQuadrature (const unsigned int map_degree) FETools::lexicographic_to_hierarchic_numbering ( FiniteElementData<dim> (dpo, 1, map_degree), renumber); - // finally we assign the quadrature points in the - // required order. - + // finally we assign the quadrature points in the required order. for (unsigned int q=0; q<n_q_points; ++q) this->quadrature_points[renumber[q]] = q_iterated.point(q); } @@ -112,43 +105,30 @@ compute_mapping_support_points std::vector<Point<spacedim> > &a) const { - // first, basic assertion - // with respect to vector size, + // first, basic assertion with respect to vector size, const types::global_dof_index n_dofs = euler_dof_handler->n_dofs(); const types::global_dof_index vector_size = euler_vector->size(); AssertDimension(vector_size,n_dofs); - // we then transform our tria iterator - // into a dof iterator so we can - // access data not associated with - // triangulations + // we then transform our tria iterator into a dof iterator so we can access + // data not associated with triangulations typename DoFHandler<dim,spacedim>::cell_iterator dof_cell(*cell, euler_dof_handler); Assert (dof_cell->active() == true, ExcInactiveCell()); - // our quadrature rule is chosen - // so that each quadrature point - // corresponds to a support point - // in the undeformed configuration. - // we can then query the given - // displacement field at these points - // to determine the shift vector that - // maps the support points to the - // deformed configuration. - - // we assume that the given field contains - // dim displacement components, but - // that there may be other solution - // components as well (e.g. pressures). - // this class therefore assumes that the - // first dim components represent the - // actual shift vector we need, and simply - // ignores any components after that. - // this implies that the user should order - // components appropriately, or create a - // separate dof handler for the displacements. + // our quadrature rule is chosen so that each quadrature point corresponds + // to a support point in the undeformed configuration. we can then query + // the given displacement field at these points to determine the shift + // vector that maps the support points to the deformed configuration. + + // we assume that the given field contains dim displacement components, but + // that there may be other solution components as well (e.g. pressures). + // this class therefore assumes that the first dim components represent the + // actual shift vector we need, and simply ignores any components after + // that. this implies that the user should order components appropriately, + // or create a separate dof handler for the displacements. const unsigned int n_support_pts = support_quadrature.size(); const unsigned int n_components = euler_dof_handler->get_fe().n_components(); @@ -157,20 +137,15 @@ compute_mapping_support_points std::vector<Vector<double> > shift_vector(n_support_pts,Vector<double>(n_components)); - // fill shift vector for each - // support point using an fe_values - // object. make sure that the - // fe_values variable isn't used - // simulatenously from different + // fill shift vector for each support point using an fe_values object. make + // sure that the fe_values variable isn't used simulatenously from different // threads Threads::Mutex::ScopedLock lock(fe_values_mutex); fe_values.reinit(dof_cell); fe_values.get_function_values(*euler_vector, shift_vector); - // and finally compute the positions of the - // support points in the deformed + // and finally compute the positions of the support points in the deformed // configuration. - a.resize(n_support_pts); for (unsigned int q=0; q<n_support_pts; ++q) { @@ -196,8 +171,7 @@ MappingQEulerian<dim,EulerVectorType,spacedim>::fill_fe_values ( std::vector<Point<spacedim> > &normal_vectors, CellSimilarity::Similarity &cell_similarity) const { - // disable any previously detected - // similarity and hand on to the respective + // disable any previously detected similarity and hand on to the respective // function of the base class. cell_similarity = CellSimilarity::invalid_next_cell; MappingQ<dim,spacedim>::fill_fe_values (cell, q, mapping_data, diff --git a/deal.II/source/grid/grid_out.cc b/deal.II/source/grid/grid_out.cc index 839f3ff04b..1a48929745 100644 --- a/deal.II/source/grid/grid_out.cc +++ b/deal.II/source/grid/grid_out.cc @@ -577,7 +577,7 @@ GridOut::declare_parameters(ParameterHandler ¶m) GridOutFlags::XFig::declare_parameters(param); param.leave_subsection(); - param.enter_subsection("MathGl"); + param.enter_subsection("MathGL"); GridOutFlags::MathGL::declare_parameters(param); param.leave_subsection(); } diff --git a/deal.II/source/grid/tria_boundary.cc b/deal.II/source/grid/tria_boundary.cc index f956c1d16c..65b3bafe7b 100644 --- a/deal.II/source/grid/tria_boundary.cc +++ b/deal.II/source/grid/tria_boundary.cc @@ -247,6 +247,33 @@ project_to_surface (const typename Triangulation<dim, spacedim>::hex_iterator &, } + +template <int dim, int spacedim> +const std::vector<Point<1> > & +Boundary<dim,spacedim>:: +get_line_support_points (const unsigned int n_intermediate_points) const +{ + if (points.size() <= n_intermediate_points || + points[n_intermediate_points].get() == 0) + { + Threads::Mutex::ScopedLock lock(mutex); + if (points.size() <= n_intermediate_points) + points.resize(n_intermediate_points+1); + + // another thread might have created points in the meantime + if (points[n_intermediate_points].get() == 0) + { + std_cxx1x::shared_ptr<QGaussLobatto<1> > + quadrature (new QGaussLobatto<1>(n_intermediate_points+2)); + points[n_intermediate_points] = quadrature; + } + } + return points[n_intermediate_points]->get_points(); +} + + + + /* -------------------------- StraightBoundary --------------------- */ @@ -394,15 +421,18 @@ get_intermediate_points_on_line (const Triangulation<1, 2>::line_iterator &line, const unsigned int n=points.size(); Assert(n>0, ExcInternalError()); - const double dx=1./(n+1); - double x=dx; - + // Use interior points of QGaussLobatto quadrature formula support points + // for consistency with MappingQ + const std::vector<Point<1> > &line_points = this->get_line_support_points(n); const Point<spacedim> vertices[2] = { line->vertex(0), line->vertex(1) }; - for (unsigned int i=0; i<n; ++i, x+=dx) - points[i] = (1-x)*vertices[0] + x*vertices[1]; + for (unsigned int i=0; i<n; ++i) + { + const double x = line_points[i+1][0]; + points[i] = (1-x)*vertices[0] + x*vertices[1]; + } } @@ -417,15 +447,19 @@ get_intermediate_points_on_line (const typename Triangulation<dim, spacedim>::li const unsigned int n=points.size(); Assert(n>0, ExcInternalError()); - const double dx=1./(n+1); - double x=dx; + // Use interior points of QGaussLobatto quadrature formula support points + // for consistency with MappingQ + const std::vector<Point<1> > &line_points = this->get_line_support_points(n); const Point<spacedim> vertices[2] = { line->vertex(0), line->vertex(1) }; - for (unsigned int i=0; i<n; ++i, x+=dx) - points[i] = (1-x)*vertices[0] + x*vertices[1]; + for (unsigned int i=0; i<n; ++i) + { + const double x = line_points[1+i][0]; + points[i] = (1-x)*vertices[0] + x*vertices[1]; + } } @@ -455,8 +489,7 @@ get_intermediate_points_on_quad (const Triangulation<3>::quad_iterator &quad, // is n a square number Assert(m*m==n, ExcInternalError()); - const double ds=1./(m+1); - double y=ds; + const std::vector<Point<1> > &line_points = this->get_line_support_points(m); const Point<spacedim> vertices[4] = { quad->vertex(0), quad->vertex(1), @@ -464,14 +497,17 @@ get_intermediate_points_on_quad (const Triangulation<3>::quad_iterator &quad, quad->vertex(3) }; - for (unsigned int i=0; i<m; ++i, y+=ds) + for (unsigned int i=0; i<m; ++i) { - double x=ds; - for (unsigned int j=0; j<m; ++j, x+=ds) - points[i*m+j]=((1-x) * vertices[0] + - x * vertices[1]) * (1-y) + - ((1-x) * vertices[2] + - x * vertices[3]) * y; + const double y=line_points[1+i][0]; + for (unsigned int j=0; j<m; ++j) + { + const double x=line_points[1+j][0]; + points[i*m+j]=((1-x) * vertices[0] + + x * vertices[1]) * (1-y) + + ((1-x) * vertices[2] + + x * vertices[3]) * y; + } } } @@ -490,8 +526,7 @@ get_intermediate_points_on_quad (const Triangulation<2,3>::quad_iterator &quad, // is n a square number Assert(m*m==n, ExcInternalError()); - const double ds=1./(m+1); - double y=ds; + const std::vector<Point<1> > &line_points = this->get_line_support_points(m); const Point<spacedim> vertices[4] = { quad->vertex(0), quad->vertex(1), @@ -499,14 +534,17 @@ get_intermediate_points_on_quad (const Triangulation<2,3>::quad_iterator &quad, quad->vertex(3) }; - for (unsigned int i=0; i<m; ++i, y+=ds) + for (unsigned int i=0; i<m; ++i) { - double x=ds; - for (unsigned int j=0; j<m; ++j, x+=ds) - points[i*m+j]=((1-x) * vertices[0] + - x * vertices[1]) * (1-y) + - ((1-x) * vertices[2] + - x * vertices[3]) * y; + const double y=line_points[1+i][0]; + for (unsigned int j=0; j<m; ++j) + { + const double x=line_points[1+j][0]; + points[i*m+j]=((1-x) * vertices[0] + + x * vertices[1]) * (1-y) + + ((1-x) * vertices[2] + + x * vertices[3]) * y; + } } } diff --git a/deal.II/source/grid/tria_boundary_lib.cc b/deal.II/source/grid/tria_boundary_lib.cc index df1f4e9911..1cbd41c77a 100644 --- a/deal.II/source/grid/tria_boundary_lib.cc +++ b/deal.II/source/grid/tria_boundary_lib.cc @@ -165,14 +165,14 @@ CylinderBoundary<dim,spacedim>::get_intermediate_points_between_points ( const unsigned int n=points.size(); Assert(n>0, ExcInternalError()); - // Do a simple linear interpolation - // followed by projection, using - // the same algorithm as above - const Point<spacedim> ds = (v1-v0) / (n+1); + // Do a simple linear interpolation followed by projection, using the same + // algorithm as above + const std::vector<Point<1> > &line_points = this->get_line_support_points(n); for (unsigned int i=0; i<n; ++i) { - const Point<spacedim> middle = v0 + (i+1)*ds; + const double x = line_points[i+1][0]; + const Point<spacedim> middle = (1-x)*v0 + x*v1; const Point<spacedim> vector_from_axis = (middle-point_on_axis) - ((middle-point_on_axis) * direction) * direction; @@ -307,24 +307,23 @@ get_intermediate_points_between_points (const Point<dim> &p0, { const unsigned int n = points.size (); const Point<dim> axis = x_1 - x_0; - const Point<dim> dx = (p1 - p0) / (n + 1); Assert (n > 0, ExcInternalError ()); - for (unsigned int i = 0; i < n; ++i) + const std::vector<Point<1> > &line_points = this->get_line_support_points(n); + + for (unsigned int i=0; i<n; ++i) { + const double x = line_points[i+1][0]; + // Compute the current point. - const Point<dim> x_i = p0 + (i + 1) * dx; - // To project this point on the - // boundary of the cone we first - // compute the orthogonal - // projection of this point onto - // the axis of the cone. + const Point<dim> x_i = (1-x)*p0 + x*p1; + // To project this point on the boundary of the cone we first compute + // the orthogonal projection of this point onto the axis of the cone. const double c = (x_i - x_0) * axis / axis.square (); const Point<dim> x_ip = x_0 + c * axis; - // Compute the projection of - // the middle point on the - // boundary of the cone. + // Compute the projection of the middle point on the boundary of the + // cone. points[i] = x_ip + get_radius (x_ip) * (x_i - x_ip) / (x_i - x_ip).norm (); } } @@ -337,16 +336,11 @@ get_new_point_on_line (const typename Triangulation<dim>::line_iterator &line) c const Point<dim> axis = x_1 - x_0; // Compute the middle point of the line. const Point<dim> middle = StraightBoundary<dim>::get_new_point_on_line (line); - // To project it on the boundary of - // the cone we first compute the - // orthogonal projection of the - // middle point onto the axis of - // the cone. + // To project it on the boundary of the cone we first compute the orthogonal + // projection of the middle point onto the axis of the cone. const double c = (middle - x_0) * axis / axis.square (); const Point<dim> middle_p = x_0 + c * axis; - // Compute the projection of the - // middle point on the boundary - // of the cone. + // Compute the projection of the middle point on the boundary of the cone. return middle_p + get_radius (middle_p) * (middle - middle_p) / (middle - middle_p).norm (); } @@ -360,20 +354,14 @@ get_new_point_on_quad (const Triangulation<3>::quad_iterator &quad) const const int dim = 3; const Point<dim> axis = x_1 - x_0; - // Compute the middle point of the - // quad. + // Compute the middle point of the quad. const Point<dim> middle = StraightBoundary<3>::get_new_point_on_quad (quad); - // Same algorithm as above: To - // project it on the boundary of - // the cone we first compute the - // orthogonal projection of the - // middle point onto the axis of - // the cone. + // Same algorithm as above: To project it on the boundary of the cone we + // first compute the orthogonal projection of the middle point onto the axis + // of the cone. const double c = (middle - x_0) * axis / axis.square (); const Point<dim> middle_p = x_0 + c * axis; - // Compute the projection of the - // middle point on the boundary - // of the cone. + // Compute the projection of the middle point on the boundary of the cone. return middle_p + get_radius (middle_p) * (middle - middle_p) / (middle - middle_p).norm (); } @@ -475,15 +463,12 @@ get_normals_at_vertices (const typename Triangulation<dim>::face_iterator &face, for (unsigned int vertex = 0; vertex < GeometryInfo<dim>::vertices_per_cell; ++vertex) { - // Compute the orthogonal - // projection of the vertex onto - // the axis of the cone. + // Compute the orthogonal projection of the vertex onto the axis of the + // cone. const double c = (face->vertex (vertex) - x_0) * axis / axis.square (); const Point<dim> vertex_p = x_0 + c * axis; - // Then compute the vector - // pointing from the point - // <tt>vertex_p</tt> on the axis - // to the vertex. + // Then compute the vector pointing from the point <tt>vertex_p</tt> on + // the axis to the vertex. const Point<dim> axis_to_vertex = face->vertex (vertex) - vertex_p; face_vertex_normals[vertex] = axis_to_vertex / axis_to_vertex.norm (); @@ -629,49 +614,28 @@ HyperBallBoundary<dim,spacedim>::get_intermediate_points_between_points ( Assert(std::fabs(v1.square()-r2)<eps*r2, ExcInternalError()); const double alpha=std::acos((v0*v1)/std::sqrt(v0.square()*v1.square())); - const double d_alpha=alpha/(n+1); const Point<spacedim> pm=0.5*(v0+v1); const double h=std::sqrt(pm.square()); - double beta=0; - unsigned int left_index=0, right_index=0; - if ((n+1)%2==0) - { - // if the number of - // parts is even insert - // the midpoint - left_index=(n-1)/2; - right_index=left_index; - points[left_index]=pm; - --left_index; - ++right_index; - beta=d_alpha; - } - else - { - beta=(n/2+1)*d_alpha-alpha/2.; - right_index=n/2; - left_index=n/2-1; - } - // n even: m=n/2, // n odd: m=(n-1)/2 + const std::vector<Point<1> > &line_points = this->get_line_support_points(n); const unsigned int m=n/2; - for (unsigned int i=0; i<m ; ++i, ++right_index, --left_index, beta+=d_alpha) + for (unsigned int i=0; i<m ; ++i) { - Assert(right_index<n, ExcInternalError()); - Assert(left_index+1>=1, ExcInternalError()); - - double d=h*std::tan(beta); - points[right_index]=pm+d/length*(v1-v0); - points[left_index]=pm-d/length*(v1-v0); + const double beta = alpha * (line_points[i+1][0]-0.5); + const double d=h*std::tan(beta); + points[i]=pm+d/length*(v1-v0); + points[n-1-i]=pm-d/length*(v1-v0); } + if ((n+1)%2==0) + // if the number of parts is even insert the midpoint + points[(n-1)/2]=pm; - // project the points from the - // straight line to the - // HyperBallBoundary + + // project the points from the straight line to the HyperBallBoundary for (unsigned int i=0; i<n; ++i) { points[i] *= r / std::sqrt(points[i].square()); @@ -885,10 +849,8 @@ HalfHyperBallBoundary<dim>:: get_intermediate_points_on_line (const typename Triangulation<dim>::line_iterator &line, std::vector<Point<dim> > &points) const { - // check whether center of object is - // at x==0, since then it belongs - // to the plane part of the - // boundary + // check whether center of object is at x==0, since then it belongs to the + // plane part of the boundary const Point<dim> line_center = line->center(); if (line_center(0) == this->center(0)) return StraightBoundary<dim>::get_intermediate_points_on_line (line, points); @@ -908,10 +870,8 @@ get_intermediate_points_on_quad (const typename Triangulation<dim>::quad_iterato points[0]=get_new_point_on_quad(quad); else { - // check whether center of - // object is at x==0, since - // then it belongs to the plane - // part of the boundary + // check whether center of object is at x==0, since then it belongs to + // the plane part of the boundary const Point<dim> quad_center = quad->center(); if (quad_center(0) == this->center(0)) StraightBoundary<dim>::get_intermediate_points_on_quad (quad, points); @@ -950,10 +910,8 @@ HalfHyperBallBoundary<dim>:: get_normals_at_vertices (const typename Triangulation<dim>::face_iterator &face, typename Boundary<dim>::FaceVertexNormals &face_vertex_normals) const { - // check whether center of object is - // at x==0, since then it belongs - // to the plane part of the - // boundary + // check whether center of object is at x==0, since then it belongs to the + // plane part of the boundary const Point<dim> quad_center = face->center(); if (quad_center(0) == this->center(0)) StraightBoundary<dim>::get_normals_at_vertices (face, face_vertex_normals); @@ -1005,10 +963,8 @@ get_new_point_on_line (const typename Triangulation<dim>::line_iterator &line) c { switch (dim) { - // in 2d, first check whether the two - // end points of the line are on the - // axis of symmetry. if so, then return - // the mid point + // in 2d, first check whether the two end points of the line are on the + // axis of symmetry. if so, then return the mid point case 2: { if ((line->vertex(0)(0) == this->center(0)) @@ -1016,17 +972,13 @@ get_new_point_on_line (const typename Triangulation<dim>::line_iterator &line) c (line->vertex(1)(0) == this->center(0))) return (line->vertex(0) + line->vertex(1))/2; else - // otherwise we are on the outer or - // inner part of the shell. proceed + // otherwise we are on the outer or inner part of the shell. proceed // as in the base class return HyperShellBoundary<dim>::get_new_point_on_line (line); } - // in 3d, a line is a straight - // line if it is on the symmetry - // plane and if not both of its - // end points are on either the - // inner or outer sphere + // in 3d, a line is a straight line if it is on the symmetry plane and if + // not both of its end points are on either the inner or outer sphere case 3: { @@ -1047,8 +999,7 @@ get_new_point_on_line (const typename Triangulation<dim>::line_iterator &line) c - outer_radius) < 1e-12 * outer_radius)))) return (line->vertex(0) + line->vertex(1))/2; else - // otherwise we are on the outer or - // inner part of the shell. proceed + // otherwise we are on the outer or inner part of the shell. proceed // as in the base class return HyperShellBoundary<dim>::get_new_point_on_line (line); } @@ -1079,10 +1030,8 @@ Point<dim> HalfHyperShellBoundary<dim>:: get_new_point_on_quad (const typename Triangulation<dim>::quad_iterator &quad) const { - // if this quad is on the symmetry plane, - // take the center point and project it - // outward to the same radius as the - // centers of the two radial lines + // if this quad is on the symmetry plane, take the center point and project + // it outward to the same radius as the centers of the two radial lines if ((quad->vertex(0)(0) == this->center(0)) && (quad->vertex(1)(0) == this->center(0)) && (quad->vertex(2)(0) == this->center(0)) && @@ -1119,9 +1068,8 @@ get_new_point_on_quad (const typename Triangulation<dim>::quad_iterator &quad) c Assert (false, ExcInternalError()); } - // otherwise we are on the outer or - // inner part of the shell. proceed - // as in the base class + // otherwise we are on the outer or inner part of the shell. proceed as in + // the base class return HyperShellBoundary<dim>::get_new_point_on_quad (quad); } @@ -1135,10 +1083,8 @@ get_intermediate_points_on_line (const typename Triangulation<dim>::line_iterato { switch (dim) { - // in 2d, first check whether the two - // end points of the line are on the - // axis of symmetry. if so, then return - // the mid point + // in 2d, first check whether the two end points of the line are on the + // axis of symmetry. if so, then return the mid point case 2: { if ((line->vertex(0)(0) == this->center(0)) @@ -1146,18 +1092,14 @@ get_intermediate_points_on_line (const typename Triangulation<dim>::line_iterato (line->vertex(1)(0) == this->center(0))) StraightBoundary<dim>::get_intermediate_points_on_line (line, points); else - // otherwise we are on the outer or - // inner part of the shell. proceed + // otherwise we are on the outer or inner part of the shell. proceed // as in the base class HyperShellBoundary<dim>::get_intermediate_points_on_line (line, points); break; } - // in 3d, a line is a straight - // line if it is on the symmetry - // plane and if not both of its - // end points are on either the - // inner or outer sphere + // in 3d, a line is a straight line if it is on the symmetry plane and if + // not both of its end points are on either the inner or outer sphere case 3: { if (((line->vertex(0)(0) == this->center(0)) @@ -1177,8 +1119,7 @@ get_intermediate_points_on_line (const typename Triangulation<dim>::line_iterato - outer_radius) < 1e-12 * outer_radius)))) StraightBoundary<dim>::get_intermediate_points_on_line (line, points); else - // otherwise we are on the outer or - // inner part of the shell. proceed + // otherwise we are on the outer or inner part of the shell. proceed // as in the base class HyperShellBoundary<dim>::get_intermediate_points_on_line (line, points); @@ -1200,10 +1141,8 @@ get_intermediate_points_on_quad (const typename Triangulation<dim>::quad_iterato { Assert (dim < 3, ExcNotImplemented()); - // check whether center of object is - // at x==0, since then it belongs - // to the plane part of the - // boundary + // check whether center of object is at x==0, since then it belongs to the + // plane part of the boundary const Point<dim> quad_center = quad->center(); if (quad_center(0) == this->center(0)) StraightBoundary<dim>::get_intermediate_points_on_quad (quad, points); @@ -1350,9 +1289,9 @@ TorusBoundary<2,3>::get_new_point_on_line (const Triangulation<2,3>::line_iterat Point<2> middle(0,0); - //Take care for periodic conditions, - //For instance phi0= 0, phi1= 3/2*Pi middle has to be 7/4*Pi not 3/4*Pi - //This also works for -Pi/2 + Pi, middle is 5/4*Pi + //Take care for periodic conditions, For instance phi0= 0, phi1= 3/2*Pi + //middle has to be 7/4*Pi not 3/4*Pi. This also works for -Pi/2 + Pi, middle + //is 5/4*Pi for (unsigned int i=0; i<2; i++) if (std::abs(p0(i)-p1(i))> numbers::PI) middle(i)=2*numbers::PI; @@ -1440,7 +1379,7 @@ TorusBoundary<2,3>:: get_intermediate_points_on_line (const Triangulation<2, 3>::line_iterator &line, std::vector< Point< 3 > > &points) const { - //Almost the same implementation as StraightBoundary<2,3> + //Almost the same implementation as StraightBoundary<2,3> unsigned int npoints=points.size(); if (npoints==0) return; @@ -1453,10 +1392,10 @@ get_intermediate_points_on_line (const Triangulation<2, 3>::line_iterator &lin offset[0]=0; offset[1]=0; - //Take care for periodic conditions & negative angles, - //see get_new_point_on_line() above - //Because we dont have a symmetric interpolation (just the middle) we need to - //add 2*Pi to each almost zero and negative angles. + //Take care for periodic conditions & negative angles, see + //get_new_point_on_line() above. Because we dont have a symmetric + //interpolation (just the middle) we need to add 2*Pi to each almost zero + //and negative angles. for (unsigned int i=0; i<2; i++) for (unsigned int j=1; j<2; j++) { @@ -1473,11 +1412,11 @@ get_intermediate_points_on_line (const Triangulation<2, 3>::line_iterator &lin p[j](i)+=2*numbers::PI*offset[i]; - double dx=1.0/(npoints+1); - double x=dx; Point<2> target; - for (unsigned int i=0; i<npoints; i++,x+=dx) + const std::vector<Point<1> > &line_points = this->get_line_support_points(npoints); + for (unsigned int i=0; i<npoints; i++) { + const double x = line_points[i+1][0]; target= (1-x)*p[0] + x*p[1]; points[i]=get_real_coord(target); } @@ -1497,9 +1436,6 @@ get_intermediate_points_on_quad (const Triangulation< 2, 3 >::quad_iterator &qua // is n a square number Assert(m*m==n, ExcInternalError()); - const double ds=1./(m+1); - double y=ds; - Point<2> p[4]; for (unsigned int i=0; i<4; i++) @@ -1510,10 +1446,10 @@ get_intermediate_points_on_quad (const Triangulation< 2, 3 >::quad_iterator &qua offset[0]=0; offset[1]=0; - //Take care for periodic conditions & negative angles, - //see get_new_point_on_line() above - //Because we dont have a symmetric interpolation (just the middle) we need to - //add 2*Pi to each almost zero and negative angles. + //Take care for periodic conditions & negative angles, see + //get_new_point_on_line() above. Because we dont have a symmetric + //interpolation (just the middle) we need to add 2*Pi to each almost zero + //and negative angles. for (unsigned int i=0; i<2; i++) for (unsigned int j=1; j<4; j++) { @@ -1529,11 +1465,13 @@ get_intermediate_points_on_quad (const Triangulation< 2, 3 >::quad_iterator &qua if (p[j](i)<1.E-12 ) //Take care for periodic conditions & negative angles p[j](i)+=2*numbers::PI*offset[i]; - for (unsigned int i=0; i<m; ++i, y+=ds) + const std::vector<Point<1> > &line_points = this->get_line_support_points(m); + for (unsigned int i=0; i<m; ++i) { - double x=ds; - for (unsigned int j=0; j<m; ++j, x+=ds) + const double y=line_points[i+1][0]; + for (unsigned int j=0; j<m; ++j) { + const double x=line_points[j+1][0]; target=((1-x) * p[0] + x * p[1]) * (1-y) + ((1-x) * p[2] + diff --git a/deal.II/source/lac/slepc_solver.cc b/deal.II/source/lac/slepc_solver.cc index e436edf79e..4e372994d1 100644 --- a/deal.II/source/lac/slepc_solver.cc +++ b/deal.II/source/lac/slepc_solver.cc @@ -50,7 +50,7 @@ namespace SLEPcWrappers : solver_control (cn), mpi_communicator (mpi_communicator), - target_eigenvalue (PETSC_NULL), + target_eigenvalue (0.), set_which (EPS_LARGEST_MAGNITUDE), set_problem (EPS_NHEP), opA (NULL), @@ -110,8 +110,8 @@ namespace SLEPcWrappers } void - SolverBase::solve (const size_type n_eigenpairs, - size_type *n_converged) + SolverBase::solve (const unsigned int n_eigenpairs, + unsigned int *n_converged) { int ierr; @@ -151,13 +151,17 @@ namespace SLEPcWrappers AssertThrow (ierr == 0, ExcSLEPcError(ierr)); } - // set transformation type if any + // if a spectral transformation is to be used, set the + // transformation and target the wanted eigenvalues if (transformation) - transformation->set_context (solver_data->eps); - - // set target eigenvalues to solve for - ierr = EPSSetTarget (solver_data->eps, target_eigenvalue); - AssertThrow (ierr == 0, ExcSLEPcError(ierr)); + { + // set transformation type if any + transformation->set_context (solver_data->eps); + + // set target eigenvalues to solve for + ierr = EPSSetTarget (solver_data->eps, target_eigenvalue); + AssertThrow (ierr == 0, ExcSLEPcError(ierr)); + } // set which portion of the eigenspectrum to solve for ierr = EPSSetWhichEigenpairs (solver_data->eps, set_which); @@ -187,11 +191,11 @@ namespace SLEPcWrappers // get number of converged eigenstates ierr = EPSGetConverged (solver_data->eps, - reinterpret_cast<PetscInt *>(n_converged)); + reinterpret_cast<PetscInt*>(n_converged)); AssertThrow (ierr == 0, ExcSLEPcError(ierr)); - PetscInt n_iterations = 0; - double residual_norm = 1e300; + PetscInt n_iterations = 0; + PetscReal residual_norm = 1.e300; // @todo Investigate elaborating on some of this to act on the // complete eigenspectrum @@ -200,9 +204,13 @@ namespace SLEPcWrappers ierr = EPSGetIterationNumber (solver_data->eps, &n_iterations); AssertThrow (ierr == 0, ExcSLEPcError(ierr)); - // get the residual norm of the most extreme eigenvalue - ierr = EPSComputeResidualNorm (solver_data->eps, 0, &residual_norm); - AssertThrow (ierr == 0, ExcSLEPcError(ierr)); + // get the residual norm of the most extreme eigenvalue if and + // only if at least one eigenvector has converged. + if ((*n_converged)>0) + { + ierr = EPSComputeResidualNorm (solver_data->eps, 0, &residual_norm); + AssertThrow (ierr == 0, ExcSLEPcError(ierr)); + } // check the solver state const SolverControl::State state @@ -219,7 +227,7 @@ namespace SLEPcWrappers } void - SolverBase::get_eigenpair (const size_type index, + SolverBase::get_eigenpair (const unsigned int index, PetscScalar &eigenvalues, PETScWrappers::VectorBase &eigenvectors) { diff --git a/deal.II/source/numerics/CMakeLists.txt b/deal.II/source/numerics/CMakeLists.txt index 855e2c6777..df05c2eb6c 100644 --- a/deal.II/source/numerics/CMakeLists.txt +++ b/deal.II/source/numerics/CMakeLists.txt @@ -22,6 +22,7 @@ FILE(GLOB _header SET(_src data_out.cc + data_out_dof_data.cc data_out_faces.cc data_out_rotation.cc data_out_stack.cc @@ -29,31 +30,50 @@ SET(_src derivative_approximation.cc dof_output_operator.cc error_estimator.cc + error_estimator_1d.cc fe_field_function.cc matrix_tools.cc histogram.cc point_value_history.cc solution_transfer.cc solution_transfer_inst2.cc + solution_transfer_inst3.cc + solution_transfer_inst4.cc time_dependent.cc - vector_tools.cc + vector_tools_boundary.cc + vector_tools_constraints.cc + vector_tools_integrate_difference.cc + vector_tools_interpolate.cc + vector_tools_mean_value.cc + vector_tools_point_value.cc + vector_tools_project.cc + vector_tools_rhs.cc ) SET(_inst - data_out_faces.inst.in data_out.inst.in + data_out_dof_data.inst.in + data_out_faces.inst.in data_out_rotation.inst.in data_out_stack.inst.in data_postprocessor.inst.in derivative_approximation.inst.in dof_output_operator.inst.in error_estimator.inst.in + error_estimator_1d.inst.in fe_field_function.inst.in matrix_tools.inst.in point_value_history.inst.in solution_transfer.inst.in time_dependent.inst.in - vector_tools.inst.in + vector_tools_boundary.inst.in + vector_tools_constraints.inst.in + vector_tools_integrate_difference.inst.in + vector_tools_interpolate.inst.in + vector_tools_mean_value.inst.in + vector_tools_point_value.inst.in + vector_tools_project.inst.in + vector_tools_rhs.inst.in ) DEAL_II_ADD_LIBRARY(obj_numerics OBJECT ${_src} ${_header} ${_inst}) diff --git a/deal.II/source/numerics/data_out.cc b/deal.II/source/numerics/data_out.cc index 79fd402ccb..03e0cce91a 100644 --- a/deal.II/source/numerics/data_out.cc +++ b/deal.II/source/numerics/data_out.cc @@ -14,17 +14,7 @@ // // --------------------------------------------------------------------- -#include <deal.II/base/quadrature_lib.h> #include <deal.II/base/work_stream.h> -#include <deal.II/base/memory_consumption.h> -#include <deal.II/lac/vector.h> -#include <deal.II/lac/block_vector.h> -#include <deal.II/lac/parallel_vector.h> -#include <deal.II/lac/parallel_block_vector.h> -#include <deal.II/lac/petsc_vector.h> -#include <deal.II/lac/petsc_block_vector.h> -#include <deal.II/lac/trilinos_vector.h> -#include <deal.II/lac/trilinos_block_vector.h> #include <deal.II/numerics/data_out.h> #include <deal.II/grid/tria.h> #include <deal.II/dofs/dof_handler.h> @@ -46,247 +36,6 @@ namespace internal { namespace DataOut { - template <int dim, int spacedim> - ParallelDataBase<dim,spacedim>:: - ParallelDataBase (const unsigned int n_datasets, - const unsigned int n_subdivisions, - const std::vector<unsigned int> &n_postprocessor_outputs, - const Mapping<dim,spacedim> &mapping, - const std::vector<std_cxx1x::shared_ptr<dealii::hp::FECollection<dim,spacedim> > > &finite_elements, - const UpdateFlags update_flags, - const bool use_face_values) - : - n_datasets (n_datasets), - n_subdivisions (n_subdivisions), - postprocessed_values (n_postprocessor_outputs.size()), - mapping_collection (mapping), - finite_elements (finite_elements), - update_flags (update_flags) - { - unsigned int n_q_points = 0; - if (use_face_values == false) - { - dealii::hp::QCollection<dim> - quadrature(QIterated<dim>(QTrapez<1>(), n_subdivisions)); - n_q_points = quadrature[0].size(); - x_fe_values.resize(this->finite_elements.size()); - for (unsigned int i=0; i<this->finite_elements.size(); ++i) - { - // check if there is a finite element that is equal to the - // present one, then we can re-use the FEValues object - for (unsigned int j=0; j<i; ++j) - if (this->finite_elements[i].get() == - this->finite_elements[j].get()) - { - x_fe_values[i] = x_fe_values[j]; - break; - } - if (x_fe_values[i].get() == 0) - x_fe_values[i].reset(new dealii::hp::FEValues<dim,spacedim> - (this->mapping_collection, - *this->finite_elements[i], - quadrature, - this->update_flags)); - } - } - else - { - dealii::hp::QCollection<dim-1> - quadrature(QIterated<dim-1>(QTrapez<1>(), n_subdivisions)); - n_q_points = quadrature[0].size(); - x_fe_face_values.resize(this->finite_elements.size()); - for (unsigned int i=0; i<this->finite_elements.size(); ++i) - { - // check if there is a finite element that is equal to the - // present one, then we can re-use the FEValues object - for (unsigned int j=0; j<i; ++j) - if (this->finite_elements[i].get() == - this->finite_elements[j].get()) - { - x_fe_face_values[i] = x_fe_face_values[j]; - break; - } - if (x_fe_face_values[i].get() == 0) - x_fe_face_values[i].reset(new dealii::hp::FEFaceValues<dim,spacedim> - (this->mapping_collection, - *this->finite_elements[i], - quadrature, - this->update_flags)); - } - } - - patch_values.resize (n_q_points); - patch_values_system.resize (n_q_points); - patch_gradients.resize (n_q_points); - patch_gradients_system.resize (n_q_points); - patch_hessians.resize (n_q_points); - patch_hessians_system.resize (n_q_points); - - for (unsigned int dataset=0; dataset<n_postprocessor_outputs.size(); ++dataset) - if (n_postprocessor_outputs[dataset] != 0) - postprocessed_values[dataset] - .resize(n_q_points, - dealii::Vector<double>(n_postprocessor_outputs[dataset])); - } - - - - - - // implement copy constructor to create a thread's own version of - // x_fe_values - template <int dim, int spacedim> - ParallelDataBase<dim,spacedim>:: - ParallelDataBase (const ParallelDataBase<dim,spacedim> &data) - : - n_datasets (data.n_datasets), - n_subdivisions (data.n_subdivisions), - patch_values (data.patch_values), - patch_values_system (data.patch_values_system), - patch_gradients (data.patch_gradients), - patch_gradients_system (data.patch_gradients_system), - patch_hessians (data.patch_hessians), - patch_hessians_system (data.patch_hessians_system), - postprocessed_values (data.postprocessed_values), - mapping_collection (data.mapping_collection), - finite_elements (data.finite_elements), - update_flags (data.update_flags) - { - if (data.x_fe_values.empty() == false) - { - Assert(data.x_fe_face_values.empty() == true, ExcInternalError()); - dealii::hp::QCollection<dim> - quadrature(QIterated<dim>(QTrapez<1>(), n_subdivisions)); - x_fe_values.resize(this->finite_elements.size()); - for (unsigned int i=0; i<this->finite_elements.size(); ++i) - { - // check if there is a finite element that is equal to the - // present one, then we can re-use the FEValues object - for (unsigned int j=0; j<i; ++j) - if (this->finite_elements[i].get() == - this->finite_elements[j].get()) - { - x_fe_values[i] = x_fe_values[j]; - break; - } - if (x_fe_values[i].get() == 0) - x_fe_values[i].reset(new dealii::hp::FEValues<dim,spacedim> - (this->mapping_collection, - *this->finite_elements[i], - quadrature, - this->update_flags)); - } - } - else - { - dealii::hp::QCollection<dim-1> - quadrature(QIterated<dim-1>(QTrapez<1>(), n_subdivisions)); - x_fe_face_values.resize(this->finite_elements.size()); - for (unsigned int i=0; i<this->finite_elements.size(); ++i) - { - // check if there is a finite element that is equal to the - // present one, then we can re-use the FEValues object - for (unsigned int j=0; j<i; ++j) - if (this->finite_elements[i].get() == - this->finite_elements[j].get()) - { - x_fe_face_values[i] = x_fe_face_values[j]; - break; - } - if (x_fe_face_values[i].get() == 0) - x_fe_face_values[i].reset(new dealii::hp::FEFaceValues<dim,spacedim> - (this->mapping_collection, - *this->finite_elements[i], - quadrature, - this->update_flags)); - } - } - } - - - - template <int dim, int spacedim> - template <typename DH> - void - ParallelDataBase<dim,spacedim>:: - reinit_all_fe_values(std::vector<std_cxx1x::shared_ptr<DataEntryBase<DH> > > &dof_data, - const typename dealii::Triangulation<dim,spacedim>::cell_iterator &cell, - const unsigned int face) - { - for (unsigned int dataset=0; dataset<dof_data.size(); ++dataset) - { - bool duplicate = false; - for (unsigned int j=0; j<dataset; ++j) - if (finite_elements[dataset].get() == finite_elements[j].get()) - duplicate = true; - if (duplicate == false) - { - typename DH::active_cell_iterator dh_cell(&cell->get_triangulation(), - cell->level(), - cell->index(), - dof_data[dataset]->dof_handler); - if (x_fe_values.empty()) - { - AssertIndexRange(face, - GeometryInfo<dim>::faces_per_cell); - x_fe_face_values[dataset]->reinit(dh_cell, face); - } - else - x_fe_values[dataset]->reinit (dh_cell); - } - } - if (dof_data.empty()) - { - if (x_fe_values.empty()) - { - AssertIndexRange(face, - GeometryInfo<dim>::faces_per_cell); - x_fe_face_values[0]->reinit(cell, face); - } - else - x_fe_values[0]->reinit (cell); - } - } - - - - template <int dim, int spacedim> - const FEValuesBase<dim,spacedim> & - ParallelDataBase<dim,spacedim>:: - get_present_fe_values(const unsigned int dataset) const - { - AssertIndexRange(dataset, finite_elements.size()); - if (x_fe_values.empty()) - return x_fe_face_values[dataset]->get_present_fe_values(); - else - return x_fe_values[dataset]->get_present_fe_values(); - } - - - - template <int dim, int spacedim> - void - ParallelDataBase<dim,spacedim>:: - resize_system_vectors(const unsigned int n_components) - { - Assert(patch_values_system.size() > 0, ExcInternalError()); - AssertDimension(patch_values_system.size(), - patch_gradients_system.size()); - AssertDimension(patch_values_system.size(), - patch_hessians_system.size()); - if (patch_values_system[0].size() == n_components) - return; - for (unsigned int k=0; k<patch_values_system.size(); ++k) - { - patch_values_system[k].reinit(n_components); - patch_gradients_system[k].resize(n_components); - patch_hessians_system[k].resize(n_components); - } - } - - - - template <int dim, int spacedim> ParallelData<dim,spacedim>:: ParallelData (const unsigned int n_datasets, @@ -309,7 +58,6 @@ namespace internal - /** * In a WorkStream context, use this function to append the patch computed * by the parallel stage to the array of patches. @@ -326,845 +74,6 @@ namespace internal } -namespace internal -{ - namespace DataOut - { - template <class DH> - DataEntryBase<DH>::DataEntryBase (const DH *dofs, - const std::vector<std::string> &names_in, - const std::vector<DataComponentInterpretation::DataComponentInterpretation> &data_component_interpretation) - : - dof_handler (dofs, typeid(dealii::DataOut_DoFData<DH,DH::dimension,DH::space_dimension>).name()), - names(names_in), - data_component_interpretation (data_component_interpretation), - postprocessor(0, typeid(*this).name()), - n_output_variables(names.size()) - { - Assert (names.size() == data_component_interpretation.size(), - ExcDimensionMismatch(data_component_interpretation.size(), - names.size())); - - // check that the names use only allowed characters - for (unsigned int i=0; i<names.size(); ++i) - Assert (names[i].find_first_not_of("abcdefghijklmnopqrstuvwxyz" - "ABCDEFGHIJKLMNOPQRSTUVWXYZ" - "0123456789_<>()") == std::string::npos, - typename dealii::DataOut<DH::dimension>:: - ExcInvalidCharacter (names[i], - names[i].find_first_not_of("abcdefghijklmnopqrstuvwxyz" - "ABCDEFGHIJKLMNOPQRSTUVWXYZ" - "0123456789_<>()"))); - } - - - - template <class DH> - DataEntryBase<DH>::DataEntryBase (const DH *dofs, - const DataPostprocessor<DH::space_dimension> *data_postprocessor) - : - dof_handler (dofs, typeid(dealii::DataOut_DoFData<DH,DH::dimension,DH::space_dimension>).name()), - names(data_postprocessor->get_names()), - data_component_interpretation (data_postprocessor->get_data_component_interpretation()), - postprocessor(data_postprocessor, typeid(*this).name()), - n_output_variables(names.size()) - { - Assert (data_postprocessor->get_names().size() - == - data_postprocessor->get_data_component_interpretation().size(), - ExcDimensionMismatch (data_postprocessor->get_names().size(), - data_postprocessor->get_data_component_interpretation().size())); - - // check that the names use only allowed characters - for (unsigned int i=0; i<names.size(); ++i) - Assert (names[i].find_first_not_of("abcdefghijklmnopqrstuvwxyz" - "ABCDEFGHIJKLMNOPQRSTUVWXYZ" - "0123456789_<>()") == std::string::npos, - typename dealii::DataOut<DH::dimension>:: - ExcInvalidCharacter (names[i], - names[i].find_first_not_of("abcdefghijklmnopqrstuvwxyz" - "ABCDEFGHIJKLMNOPQRSTUVWXYZ" - "0123456789_<>()"))); - } - - - - template <class DH> - DataEntryBase<DH>::~DataEntryBase () - {} - - - - /** - * Class that stores a pointer to a vector of type equal to the template - * argument, and provides the functions to extract data from it. - * - * @author Wolfgang Bangerth, 2004 - */ - template <class DH, typename VectorType> - class DataEntry : public DataEntryBase<DH> - { - public: - /** - * Constructor. Give a list of names for the individual components of - * the vector and their interpretation as scalar or vector data. This - * constructor assumes that no postprocessor is going to be used. - */ - DataEntry (const DH *dofs, - const VectorType *data, - const std::vector<std::string> &names, - const std::vector<DataComponentInterpretation::DataComponentInterpretation> &data_component_interpretation); - - /** - * Constructor when a data postprocessor is going to be used. In that - * case, the names and vector declarations are going to be acquired from - * the postprocessor. - */ - DataEntry (const DH *dofs, - const VectorType *data, - const DataPostprocessor<DH::space_dimension> *data_postprocessor); - - /** - * Assuming that the stored vector is a cell vector, extract the given - * element from it. - */ - virtual - double - get_cell_data_value (const unsigned int cell_number) const; - - /** - * Given a FEValuesBase object, extract the values on the present cell - * from the vector we actually store. - */ - virtual - void - get_function_values (const FEValuesBase<DH::dimension,DH::space_dimension> &fe_patch_values, - std::vector<double> &patch_values) const; - - /** - * Given a FEValuesBase object, extract the values on the present cell - * from the vector we actually store. This function does the same as the - * one above but for vector-valued finite elements. - */ - virtual - void - get_function_values (const FEValuesBase<DH::dimension,DH::space_dimension> &fe_patch_values, - std::vector<dealii::Vector<double> > &patch_values_system) const; - - /** - * Given a FEValuesBase object, extract the gradients on the present - * cell from the vector we actually store. - */ - virtual - void - get_function_gradients (const FEValuesBase<DH::dimension,DH::space_dimension> &fe_patch_values, - std::vector<Tensor<1,DH::space_dimension> > &patch_gradients) const; - - /** - * Given a FEValuesBase object, extract the gradients on the present - * cell from the vector we actually store. This function does the same - * as the one above but for vector-valued finite elements. - */ - virtual - void - get_function_gradients (const FEValuesBase<DH::dimension,DH::space_dimension> &fe_patch_values, - std::vector<std::vector<Tensor<1,DH::space_dimension> > > &patch_gradients_system) const; - - /** - * Given a FEValuesBase object, extract the second derivatives on the - * present cell from the vector we actually store. - */ - virtual - void - get_function_hessians (const FEValuesBase<DH::dimension,DH::space_dimension> &fe_patch_values, - std::vector<Tensor<2,DH::space_dimension> > &patch_hessians) const; - - /** - * Given a FEValuesBase object, extract the second derivatives on the - * present cell from the vector we actually store. This function does - * the same as the one above but for vector-valued finite elements. - */ - virtual - void - get_function_hessians (const FEValuesBase<DH::dimension,DH::space_dimension> &fe_patch_values, - std::vector<std::vector< Tensor<2,DH::space_dimension> > > &patch_hessians_system) const; - - /** - * Clear all references to the vectors. - */ - virtual void clear (); - - /** - * Determine an estimate for the memory consumption (in bytes) of this - * object. - */ - virtual std::size_t memory_consumption () const; - - private: - /** - * Pointer to the data vector. Note that ownership of the vector pointed - * to remains with the caller of this class. - */ - const VectorType *vector; - }; - - - - template <class DH, class VectorType> - DataEntry<DH,VectorType>:: - DataEntry (const DH *dofs, - const VectorType *data, - const std::vector<std::string> &names, - const std::vector<DataComponentInterpretation::DataComponentInterpretation> &data_component_interpretation) - : - DataEntryBase<DH> (dofs, names, data_component_interpretation), - vector (data) - {} - - - - template <class DH, class VectorType> - DataEntry<DH,VectorType>:: - DataEntry (const DH *dofs, - const VectorType *data, - const DataPostprocessor<DH::space_dimension> *data_postprocessor) - : - DataEntryBase<DH> (dofs, data_postprocessor), - vector (data) - {} - - - namespace - { - template <class VectorType> - double - get_vector_element (const VectorType &vector, - const unsigned int cell_number) - { - return vector[cell_number]; - } - - - double - get_vector_element (const IndexSet &is, - const unsigned int cell_number) - { - return (is.is_element(cell_number) ? 1 : 0); - } - } - - - - template <class DH, class VectorType> - double - DataEntry<DH,VectorType>:: - get_cell_data_value (const unsigned int cell_number) const - { - return get_vector_element(*vector, cell_number); - } - - - - template <class DH, class VectorType> - void - DataEntry<DH,VectorType>:: - get_function_values (const FEValuesBase<DH::dimension,DH::space_dimension> &fe_patch_values, - std::vector<dealii::Vector<double> > &patch_values_system) const - { - fe_patch_values.get_function_values (*vector, patch_values_system); - } - - - - template <class DH, typename VectorType> - void - DataEntry<DH,VectorType>:: - get_function_values (const FEValuesBase<DH::dimension,DH::space_dimension> &fe_patch_values, - std::vector<double> &patch_values) const - { - fe_patch_values.get_function_values (*vector, patch_values); - } - - - - template <class DH, class VectorType> - void - DataEntry<DH,VectorType>:: - get_function_gradients (const FEValuesBase<DH::dimension,DH::space_dimension> &fe_patch_values, - std::vector<std::vector<Tensor<1,DH::space_dimension> > > &patch_gradients_system) const - { - fe_patch_values.get_function_gradients (*vector, patch_gradients_system); - } - - - - template <class DH, typename VectorType> - void - DataEntry<DH,VectorType>:: - get_function_gradients (const FEValuesBase<DH::dimension,DH::space_dimension> &fe_patch_values, - std::vector<Tensor<1,DH::space_dimension> > &patch_gradients) const - { - fe_patch_values.get_function_gradients (*vector, patch_gradients); - } - - - - template <class DH, class VectorType> - void - DataEntry<DH,VectorType>:: - get_function_hessians (const FEValuesBase<DH::dimension,DH::space_dimension> &fe_patch_values, - std::vector<std::vector<Tensor<2,DH::space_dimension> > > &patch_hessians_system) const - { - fe_patch_values.get_function_hessians (*vector, patch_hessians_system); - } - - - - template <class DH, typename VectorType> - void - DataEntry<DH,VectorType>:: - get_function_hessians (const FEValuesBase<DH::dimension,DH::space_dimension> &fe_patch_values, - std::vector<Tensor<2,DH::space_dimension> > &patch_hessians) const - { - fe_patch_values.get_function_hessians (*vector, patch_hessians); - } - - - - template <class DH, typename VectorType> - std::size_t - DataEntry<DH,VectorType>::memory_consumption () const - { - return (sizeof (vector) + - MemoryConsumption::memory_consumption (this->names)); - } - - - - template <class DH, class VectorType> - void - DataEntry<DH,VectorType>::clear () - { - vector = 0; - this->dof_handler = 0; - } - } -} - - - -template <class DH, - int patch_dim, int patch_space_dim> -DataOut_DoFData<DH,patch_dim,patch_space_dim>::DataOut_DoFData () - : - triangulation(0,typeid(*this).name()), - dofs(0,typeid(*this).name()) -{} - - - -template <class DH, int patch_dim, int patch_space_dim> -DataOut_DoFData<DH,patch_dim,patch_space_dim>::~DataOut_DoFData () -{ - clear (); -} - - - -template <class DH, int patch_dim, int patch_space_dim> -void -DataOut_DoFData<DH,patch_dim,patch_space_dim>:: -attach_dof_handler (const DH &d) -{ - Assert (dof_data.size() == 0, ExcOldDataStillPresent()); - Assert (cell_data.size() == 0, ExcOldDataStillPresent()); - - triangulation = SmartPointer<const Triangulation<DH::dimension,DH::space_dimension> >(&d.get_tria(), typeid(*this).name()); - dofs = SmartPointer<const DH>(&d, typeid(*this).name()); -} - - - -template <class DH, int patch_dim, int patch_space_dim> -void -DataOut_DoFData<DH,patch_dim,patch_space_dim>:: -attach_triangulation (const Triangulation<DH::dimension,DH::space_dimension> &tria) -{ - Assert (dof_data.size() == 0, ExcOldDataStillPresent()); - Assert (cell_data.size() == 0, ExcOldDataStillPresent()); - - triangulation = SmartPointer<const Triangulation<DH::dimension,DH::space_dimension> >(&tria, typeid(*this).name()); -} - - - - -template <class DH, - int patch_dim, int patch_space_dim> -template <class VECTOR> -void -DataOut_DoFData<DH,patch_dim,patch_space_dim>:: -add_data_vector (const VECTOR &vec, - const std::string &name, - const DataVectorType type, - const std::vector<DataComponentInterpretation::DataComponentInterpretation> &data_component_interpretation) -{ - Assert (triangulation != 0, ExcNoTriangulationSelected ()); - const unsigned int n_components = - dofs != 0 ? dofs->get_fe().n_components () : 1; - - std::vector<std::string> names; - // if only one component or vector is cell vector: we only need one name - if ((n_components == 1) || - (vec.size() == triangulation->n_active_cells())) - { - names.resize (1, name); - } - else - // otherwise append _i to the given name - { - names.resize (n_components); - for (unsigned int i=0; i<n_components; ++i) - { - std::ostringstream namebuf; - namebuf << '_' << i; - names[i] = name + namebuf.str(); - } - } - - add_data_vector (vec, names, type, data_component_interpretation); -} - - - -template <class DH, - int patch_dim, int patch_space_dim> -template <class VECTOR> -void -DataOut_DoFData<DH,patch_dim,patch_space_dim>:: -add_data_vector (const VECTOR &vec, - const std::vector<std::string> &names, - const DataVectorType type, - const std::vector<DataComponentInterpretation::DataComponentInterpretation> &data_component_interpretation_) -{ - Assert (triangulation != 0, ExcNoTriangulationSelected ()); - - const std::vector<DataComponentInterpretation::DataComponentInterpretation> & - data_component_interpretation - = (data_component_interpretation_.size() != 0 - ? - data_component_interpretation_ - : - std::vector<DataComponentInterpretation::DataComponentInterpretation> - (names.size(), DataComponentInterpretation::component_is_scalar)); - - // either cell data and one name, - // or dof data and n_components names - DataVectorType actual_type = type; - if (type == type_automatic) - { - if (vec.size() == triangulation->n_active_cells()) - actual_type = type_cell_data; - else - actual_type = type_dof_data; - } - - switch (actual_type) - { - case type_cell_data: - Assert (vec.size() == triangulation->n_active_cells(), - ExcDimensionMismatch (vec.size(), - triangulation->n_active_cells())); - Assert (names.size() == 1, - ExcInvalidNumberOfNames (names.size(), 1)); - break; - - case type_dof_data: - Assert (dofs != 0, ExcNoDoFHandlerSelected ()); - Assert (vec.size() == dofs->n_dofs(), - ExcInvalidVectorSize (vec.size(), - dofs->n_dofs(), - triangulation->n_active_cells())); - Assert (names.size() == dofs->get_fe().n_components(), - ExcInvalidNumberOfNames (names.size(), dofs->get_fe().n_components())); - break; - - case type_automatic: - // this case should have been handled above... - Assert (false, ExcInternalError()); - } - - internal::DataOut::DataEntryBase<DH> *new_entry - = new internal::DataOut::DataEntry<DH,VECTOR>(dofs, &vec, names, - data_component_interpretation); - if (actual_type == type_dof_data) - dof_data.push_back (std_cxx1x::shared_ptr<internal::DataOut::DataEntryBase<DH> >(new_entry)); - else - cell_data.push_back (std_cxx1x::shared_ptr<internal::DataOut::DataEntryBase<DH> >(new_entry)); -} - - - -template <class DH, - int patch_dim, int patch_space_dim> -template <class VECTOR> -void -DataOut_DoFData<DH,patch_dim,patch_space_dim>:: -add_data_vector (const VECTOR &vec, - const DataPostprocessor<DH::space_dimension> &data_postprocessor) -{ - // this is a specialized version of the other function where we have a - // postprocessor. if we do, we know that we have type_dof_data, which makes - // things a bit simpler, we also don't need to deal with some of the other - // stuff and use a different constructor of DataEntry - - Assert (dofs != 0, ExcNoDoFHandlerSelected ()); - - Assert (vec.size() == dofs->n_dofs(), - ExcInvalidVectorSize (vec.size(), - dofs->n_dofs(), - dofs->get_tria().n_active_cells())); - - internal::DataOut::DataEntryBase<DH> *new_entry - = new internal::DataOut::DataEntry<DH,VECTOR>(dofs, &vec, &data_postprocessor); - dof_data.push_back (std_cxx1x::shared_ptr<internal::DataOut::DataEntryBase<DH> >(new_entry)); -} - - - -template <class DH, - int patch_dim, int patch_space_dim> -template <class VECTOR> -void -DataOut_DoFData<DH,patch_dim,patch_space_dim>:: -add_data_vector (const DH &dof_handler, - const VECTOR &vec, - const DataPostprocessor<DH::space_dimension> &data_postprocessor) -{ - // this is a specialized version of the other function where we have a - // postprocessor. if we do, we know that we have type_dof_data, which makes - // things a bit simpler, we also don't need to deal with some of the other - // stuff and use a different constructor of DataEntry - - AssertDimension (vec.size(), dof_handler.n_dofs()); - - internal::DataOut::DataEntryBase<DH> *new_entry - = new internal::DataOut::DataEntry<DH,VECTOR>(&dof_handler, &vec, &data_postprocessor); - dof_data.push_back (std_cxx1x::shared_ptr<internal::DataOut::DataEntryBase<DH> >(new_entry)); -} - - - -template <class DH, - int patch_dim, int patch_space_dim> -template <class VECTOR> -void -DataOut_DoFData<DH,patch_dim,patch_space_dim>:: -add_data_vector (const DH &dof_handler, - const VECTOR &data, - const std::string &name, - const std::vector<DataComponentInterpretation::DataComponentInterpretation> &data_component_interpretation) -{ - const unsigned int n_components = dof_handler.get_fe().n_components (); - - std::vector<std::string> names; - // if only one component: we only need one name - if (n_components == 1) - names.resize (1, name); - else - // otherwise append _i to the given name - { - names.resize (n_components); - for (unsigned int i=0; i<n_components; ++i) - { - std::ostringstream namebuf; - namebuf << '_' << i; - names[i] = name + namebuf.str(); - } - } - - add_data_vector (dof_handler, data, names, data_component_interpretation); -} - - - -template <class DH, - int patch_dim, int patch_space_dim> -template <class VECTOR> -void -DataOut_DoFData<DH,patch_dim,patch_space_dim>:: -add_data_vector (const DH &dof_handler, - const VECTOR &data, - const std::vector<std::string> &names, - const std::vector<DataComponentInterpretation::DataComponentInterpretation> &data_component_interpretation_) -{ - // this is an extended version of the other functions where we pass a vector - // together with its DoFHandler. if we do, we know that we have - // type_dof_data, which makes things a bit simpler - if (triangulation == 0) - triangulation = SmartPointer<const Triangulation<DH::dimension,DH::space_dimension> >(&dof_handler.get_tria(), typeid(*this).name()); - - Assert (&dof_handler.get_tria() == triangulation, - ExcMessage("The triangulation attached to the DoFHandler does not " - "match with the one set previously")); - - Assert (data.size() == dof_handler.n_dofs(), - ExcDimensionMismatch (data.size(), dof_handler.n_dofs())); - - const std::vector<DataComponentInterpretation::DataComponentInterpretation> & - data_component_interpretation - = (data_component_interpretation_.size() != 0 - ? - data_component_interpretation_ - : - std::vector<DataComponentInterpretation::DataComponentInterpretation> - (names.size(), DataComponentInterpretation::component_is_scalar)); - - internal::DataOut::DataEntryBase<DH> *new_entry - = new internal::DataOut::DataEntry<DH,VECTOR>(&dof_handler, &data, names, - data_component_interpretation); - dof_data.push_back (std_cxx1x::shared_ptr<internal::DataOut::DataEntryBase<DH> >(new_entry)); -} - - - -template <class DH, - int patch_dim, int patch_space_dim> -void DataOut_DoFData<DH,patch_dim,patch_space_dim>::clear_data_vectors () -{ - dof_data.erase (dof_data.begin(), dof_data.end()); - cell_data.erase (cell_data.begin(), cell_data.end()); - - // delete patches - std::vector<Patch> dummy; - patches.swap (dummy); -} - - - -template <class DH, - int patch_dim, int patch_space_dim> -void -DataOut_DoFData<DH,patch_dim,patch_space_dim>:: -clear_input_data_references () -{ - for (unsigned int i=0; i<dof_data.size(); ++i) - dof_data[i]->clear (); - - for (unsigned int i=0; i<cell_data.size(); ++i) - cell_data[i]->clear (); - - if (dofs != 0) - dofs = 0; -} - - - -template <class DH, - int patch_dim, int patch_space_dim> -void -DataOut_DoFData<DH,patch_dim,patch_space_dim>::clear () -{ - dof_data.erase (dof_data.begin(), dof_data.end()); - cell_data.erase (cell_data.begin(), cell_data.end()); - - if (dofs != 0) - dofs = 0; - - // delete patches - std::vector<Patch> dummy; - patches.swap (dummy); -} - - - -template <class DH, - int patch_dim, int patch_space_dim> -std::vector<std::string> -DataOut_DoFData<DH,patch_dim,patch_space_dim>:: -get_dataset_names () const -{ - std::vector<std::string> names; - // collect the names of dof - // and cell data - typedef - typename std::vector<std_cxx1x::shared_ptr<internal::DataOut::DataEntryBase<DH> > >::const_iterator - data_iterator; - - for (data_iterator d=dof_data.begin(); - d!=dof_data.end(); ++d) - for (unsigned int i=0; i<(*d)->names.size(); ++i) - names.push_back ((*d)->names[i]); - for (data_iterator d=cell_data.begin(); d!=cell_data.end(); ++d) - { - Assert ((*d)->names.size() == 1, ExcInternalError()); - names.push_back ((*d)->names[0]); - } - - return names; -} - - - -template <class DH, - int patch_dim, int patch_space_dim> -std::vector<std_cxx1x::tuple<unsigned int, unsigned int, std::string> > -DataOut_DoFData<DH,patch_dim,patch_space_dim>::get_vector_data_ranges () const -{ - std::vector<std_cxx1x::tuple<unsigned int, unsigned int, std::string> > - ranges; - - // collect the ranges of dof - // and cell data - typedef - typename std::vector<std_cxx1x::shared_ptr<internal::DataOut::DataEntryBase<DH> > >::const_iterator - data_iterator; - - unsigned int output_component = 0; - for (data_iterator d=dof_data.begin(); - d!=dof_data.end(); ++d) - for (unsigned int i=0; i<(*d)->n_output_variables; - ++i, ++output_component) - // see what kind of data we have - // here. note that for the purpose of - // the current function all we care - // about is vector data - if ((*d)->data_component_interpretation[i] == - DataComponentInterpretation::component_is_part_of_vector) - { - // ensure that there is a - // continuous number of next - // space_dim components that all - // deal with vectors - Assert (i+patch_space_dim <= - (*d)->n_output_variables, - ExcInvalidVectorDeclaration (i, - (*d)->names[i])); - for (unsigned int dd=1; dd<patch_space_dim; ++dd) - Assert ((*d)->data_component_interpretation[i+dd] - == - DataComponentInterpretation::component_is_part_of_vector, - ExcInvalidVectorDeclaration (i, - (*d)->names[i])); - - // all seems alright, so figure out - // whether there is a common name - // to these components. if not, - // leave the name empty and let the - // output format writer decide what - // to do here - std::string name = (*d)->names[i]; - for (unsigned int dd=1; dd<patch_space_dim; ++dd) - if (name != (*d)->names[i+dd]) - { - name = ""; - break; - } - - // finally add a corresponding - // range - std_cxx1x::tuple<unsigned int, unsigned int, std::string> - range (output_component, - output_component+patch_space_dim-1, - name); - - ranges.push_back (range); - - // increase the 'component' counter - // by the appropriate amount, same - // for 'i', since we have already - // dealt with all these components - output_component += patch_space_dim-1; - i += patch_space_dim-1; - } - - // note that we do not have to traverse the - // list of cell data here because cell data - // is one value per (logical) cell and - // therefore cannot be a vector - - // as a final check, the 'component' - // counter should be at the total number of - // components added up now -#ifdef DEBUG - unsigned int n_output_components = 0; - for (data_iterator d=dof_data.begin(); - d!=dof_data.end(); ++d) - n_output_components += (*d)->n_output_variables; - Assert (output_component == n_output_components, - ExcInternalError()); -#endif - - return ranges; -} - - - -template <class DH, - int patch_dim, int patch_space_dim> -const std::vector< dealii::DataOutBase::Patch<patch_dim, patch_space_dim> > & -DataOut_DoFData<DH,patch_dim,patch_space_dim>::get_patches () const -{ - return patches; -} - - - -template <class DH, - int patch_dim, int patch_space_dim> -std::vector<std_cxx1x::shared_ptr<dealii::hp::FECollection<DH::dimension,DH::space_dimension> > > -DataOut_DoFData<DH,patch_dim,patch_space_dim>::get_finite_elements() const -{ - const unsigned int dhdim = DH::dimension; - const unsigned int dhspacedim = DH::space_dimension; - std::vector<std_cxx1x::shared_ptr<dealii::hp::FECollection<dhdim,dhspacedim> > > - finite_elements(this->dof_data.size()); - for (unsigned int i=0; i<this->dof_data.size(); ++i) - { - Assert (dof_data[i]->dof_handler != 0, ExcNoDoFHandlerSelected ()); - - // avoid creating too many finite elements and doing a lot of work on - // initializing FEValues downstream: if two DoFHandlers are the same - // (checked by pointer comparison), we can re-use the shared_ptr object - // for the second one. We cannot check for finite element equalities - // because we need different FEValues objects for different dof - // handlers. - bool duplicate = false; - for (unsigned int j=0; j<i; ++j) - if (dof_data[i]->dof_handler == dof_data[j]->dof_handler) - { - finite_elements[i] = finite_elements[j]; - duplicate = true; - } - if (duplicate == false) - finite_elements[i].reset(new dealii::hp::FECollection<dhdim,dhspacedim> - (this->dof_data[i]->dof_handler->get_fe())); - } - if (this->dof_data.empty()) - { - finite_elements.resize(1); - finite_elements[0].reset(new dealii::hp::FECollection<dhdim,dhspacedim> - (FE_DGQ<dhdim,dhspacedim>(0))); - } - return finite_elements; -} - - - -template <class DH, - int patch_dim, int patch_space_dim> -std::size_t -DataOut_DoFData<DH,patch_dim,patch_space_dim>::memory_consumption () const -{ - return (DataOutInterface<patch_dim,patch_space_dim>::memory_consumption () + - MemoryConsumption::memory_consumption (dofs) + - MemoryConsumption::memory_consumption (patches)); -} - - - -/* ---------------------------------------------------------------------- */ - template <int dim, class DH> void diff --git a/deal.II/source/numerics/data_out.inst.in b/deal.II/source/numerics/data_out.inst.in index aa157920a1..07355823c9 100644 --- a/deal.II/source/numerics/data_out.inst.in +++ b/deal.II/source/numerics/data_out.inst.in @@ -15,321 +15,19 @@ // --------------------------------------------------------------------- -for (VEC : SERIAL_VECTORS; DH : DOFHANDLER_TEMPLATES; deal_II_dimension : DIMENSIONS) -{ -// codim=0 - - template void - DataOut_DoFData<DH<deal_II_dimension,deal_II_dimension>,deal_II_dimension,deal_II_dimension>:: - add_data_vector<VEC> (const VEC &, - const std::string &, - const DataVectorType, - const std::vector<DataComponentInterpretation::DataComponentInterpretation> &); - - template void - DataOut_DoFData<DH<deal_II_dimension,deal_II_dimension>,deal_II_dimension,deal_II_dimension>:: - add_data_vector<VEC> (const VEC &, - const std::vector<std::string> &, - const DataVectorType, - const std::vector<DataComponentInterpretation::DataComponentInterpretation> &); - - template void - DataOut_DoFData<DH<deal_II_dimension,deal_II_dimension>,deal_II_dimension,deal_II_dimension>:: - add_data_vector<VEC> (const VEC &, - const DataPostprocessor<DH<deal_II_dimension,deal_II_dimension>::space_dimension> &); - - template void - DataOut_DoFData<DH<deal_II_dimension,deal_II_dimension>,deal_II_dimension,deal_II_dimension>:: - add_data_vector<VEC> (const DH<deal_II_dimension,deal_II_dimension> &, - const VEC &, - const std::string &, - const std::vector<DataComponentInterpretation::DataComponentInterpretation> &); - - template void - DataOut_DoFData<DH<deal_II_dimension,deal_II_dimension>,deal_II_dimension,deal_II_dimension>:: - add_data_vector<VEC> (const DH<deal_II_dimension,deal_II_dimension> &, - const VEC &, - const std::vector<std::string> &, - const std::vector<DataComponentInterpretation::DataComponentInterpretation> &); - - template void - DataOut_DoFData<DH<deal_II_dimension,deal_II_dimension>,deal_II_dimension,deal_II_dimension>:: - add_data_vector<VEC> (const DH<deal_II_dimension,deal_II_dimension> &, - const VEC &, - const DataPostprocessor<DH<deal_II_dimension,deal_II_dimension>::space_dimension> &); - - - -// stuff needed for face data - - template void - DataOut_DoFData<DH<deal_II_dimension,deal_II_dimension>,deal_II_dimension-1,deal_II_dimension>:: - add_data_vector<VEC> (const VEC &, - const std::string &, - const DataVectorType, - const std::vector<DataComponentInterpretation::DataComponentInterpretation> &); - - template void - DataOut_DoFData<DH<deal_II_dimension,deal_II_dimension>,deal_II_dimension-1,deal_II_dimension>:: - add_data_vector<VEC> (const VEC &, - const std::vector<std::string> &, - const DataVectorType, - const std::vector<DataComponentInterpretation::DataComponentInterpretation> &); - - template void - DataOut_DoFData<DH<deal_II_dimension,deal_II_dimension>,deal_II_dimension-1,deal_II_dimension>:: - add_data_vector<VEC> (const VEC &, - const DataPostprocessor<DH<deal_II_dimension,deal_II_dimension>::space_dimension> &); - - template void - DataOut_DoFData<DH<deal_II_dimension,deal_II_dimension>,deal_II_dimension-1,deal_II_dimension>:: - add_data_vector<VEC> (const DH<deal_II_dimension,deal_II_dimension> &, - const VEC &, - const std::string &, - const std::vector<DataComponentInterpretation::DataComponentInterpretation> &); - - template void - DataOut_DoFData<DH<deal_II_dimension,deal_II_dimension>,deal_II_dimension-1,deal_II_dimension>:: - add_data_vector<VEC> (const DH<deal_II_dimension,deal_II_dimension> &, - const VEC &, - const std::vector<std::string> &, - const std::vector<DataComponentInterpretation::DataComponentInterpretation> &); - - template void - DataOut_DoFData<DH<deal_II_dimension,deal_II_dimension>,deal_II_dimension-1,deal_II_dimension>:: - add_data_vector<VEC> (const DH<deal_II_dimension,deal_II_dimension> &, - const VEC &, - const DataPostprocessor<DH<deal_II_dimension,deal_II_dimension>::space_dimension> &); - - - -// things for DataOutRotation - - template void - DataOut_DoFData<DH<deal_II_dimension,deal_II_dimension>,deal_II_dimension+1,deal_II_dimension+1>:: - add_data_vector<VEC> (const VEC &, - const std::string &, - const DataVectorType, - const std::vector<DataComponentInterpretation::DataComponentInterpretation> &); - - template void - DataOut_DoFData<DH<deal_II_dimension,deal_II_dimension>,deal_II_dimension+1,deal_II_dimension+1>:: - add_data_vector<VEC> (const VEC &, - const std::vector<std::string> &, - const DataVectorType, - const std::vector<DataComponentInterpretation::DataComponentInterpretation> &); - - template void - DataOut_DoFData<DH<deal_II_dimension,deal_II_dimension>,deal_II_dimension+1,deal_II_dimension+1>:: - add_data_vector<VEC> (const VEC &, - const DataPostprocessor<DH<deal_II_dimension,deal_II_dimension>::space_dimension> &); - - template void - DataOut_DoFData<DH<deal_II_dimension,deal_II_dimension>,deal_II_dimension+1,deal_II_dimension+1>:: - add_data_vector<VEC> (const DH<deal_II_dimension,deal_II_dimension> &, - const VEC &, - const std::string &, - const std::vector<DataComponentInterpretation::DataComponentInterpretation> &); - - template void - DataOut_DoFData<DH<deal_II_dimension,deal_II_dimension>,deal_II_dimension+1,deal_II_dimension+1>:: - add_data_vector<VEC> (const DH<deal_II_dimension,deal_II_dimension> &, - const VEC &, - const std::vector<std::string> &, - const std::vector<DataComponentInterpretation::DataComponentInterpretation> &); - - template void - DataOut_DoFData<DH<deal_II_dimension,deal_II_dimension>,deal_II_dimension+1,deal_II_dimension+1>:: - add_data_vector<VEC> (const DH<deal_II_dimension,deal_II_dimension> &, - const VEC &, - const DataPostprocessor<DH<deal_II_dimension,deal_II_dimension>::space_dimension> &); - - -// codim 1 - - #if deal_II_dimension < 3 - template void - DataOut_DoFData<DH<deal_II_dimension,deal_II_dimension+1>,deal_II_dimension,deal_II_dimension+1>:: - add_data_vector<VEC> (const VEC &, - const std::string &, - const DataVectorType, - const std::vector<DataComponentInterpretation::DataComponentInterpretation> &); - - template void - DataOut_DoFData<DH<deal_II_dimension,deal_II_dimension+1>,deal_II_dimension,deal_II_dimension+1>:: - add_data_vector<VEC> (const VEC &, - const std::vector<std::string> &, - const DataVectorType, - const std::vector<DataComponentInterpretation::DataComponentInterpretation> &); - - template void - DataOut_DoFData<DH<deal_II_dimension,deal_II_dimension+1>,deal_II_dimension,deal_II_dimension+1>:: - add_data_vector<VEC> (const VEC &, - const DataPostprocessor<DH<deal_II_dimension,deal_II_dimension+1>::space_dimension> &); - - template void - DataOut_DoFData<DH<deal_II_dimension,deal_II_dimension+1>,deal_II_dimension,deal_II_dimension+1>:: - add_data_vector<VEC> (const DH<deal_II_dimension,deal_II_dimension+1> &, - const VEC &, - const std::string &, - const std::vector<DataComponentInterpretation::DataComponentInterpretation> &); - - template void - DataOut_DoFData<DH<deal_II_dimension,deal_II_dimension+1>,deal_II_dimension,deal_II_dimension+1>:: - add_data_vector<VEC> (const DH<deal_II_dimension,deal_II_dimension+1> &, - const VEC &, - const std::vector<std::string> &, - const std::vector<DataComponentInterpretation::DataComponentInterpretation> &); - - template void - DataOut_DoFData<DH<deal_II_dimension,deal_II_dimension+1>,deal_II_dimension,deal_II_dimension+1>:: - add_data_vector<VEC> (const DH<deal_II_dimension,deal_II_dimension+1> &, - const VEC &, - const DataPostprocessor<DH<deal_II_dimension,deal_II_dimension+1>::space_dimension> &); - #endif - - - -// codim 2 - - #if deal_II_dimension == 3 - template void - DataOut_DoFData<DH<1,3>,1,3>:: - add_data_vector<VEC> (const VEC &, - const std::string &, - const DataVectorType, - const std::vector<DataComponentInterpretation::DataComponentInterpretation> &); - - template void - DataOut_DoFData<DH<1,3>,1,3>:: - add_data_vector<VEC> (const VEC &, - const std::vector<std::string> &, - const DataVectorType, - const std::vector<DataComponentInterpretation::DataComponentInterpretation> &); - - template void - DataOut_DoFData<DH<1,3>,1,3>:: - add_data_vector<VEC> (const VEC &, - const DataPostprocessor<DH<1,3>::space_dimension> &); - - template void - DataOut_DoFData<DH<1,3>,1,3>:: - add_data_vector<VEC> (const DH<1,3> &, - const VEC &, - const std::string &, - const std::vector<DataComponentInterpretation::DataComponentInterpretation> &); - - template void - DataOut_DoFData<DH<1,3>,1,3>:: - add_data_vector<VEC> (const DH<1,3> &, - const VEC &, - const std::vector<std::string> &, - const std::vector<DataComponentInterpretation::DataComponentInterpretation> &); - - template void - DataOut_DoFData<DH<1,3>,1,3>:: - add_data_vector<VEC> (const DH<1,3> &, - const VEC &, - const DataPostprocessor<DH<1,3>::space_dimension> &); - #endif - -} - - - -for (DH : DOFHANDLER_TEMPLATES; deal_II_dimension : DIMENSIONS) +for (deal_II_dimension : DIMENSIONS; deal_II_space_dimension : DIMENSIONS) { -// codim=0 - - template void - DataOut_DoFData<DH<deal_II_dimension,deal_II_dimension>,deal_II_dimension,deal_II_dimension>:: - add_data_vector<IndexSet> (const IndexSet &, - const std::string &, - const DataVectorType, - const std::vector<DataComponentInterpretation::DataComponentInterpretation> &); - - template void - DataOut_DoFData<DH<deal_II_dimension,deal_II_dimension>,deal_II_dimension,deal_II_dimension>:: - add_data_vector<IndexSet> (const IndexSet &, - const std::vector<std::string> &, - const DataVectorType, - const std::vector<DataComponentInterpretation::DataComponentInterpretation> &); - - template void - DataOut_DoFData<DH<deal_II_dimension,deal_II_dimension>,deal_II_dimension,deal_II_dimension>:: - add_data_vector<IndexSet> (const IndexSet &, - const DataPostprocessor<DH<deal_II_dimension,deal_II_dimension>::space_dimension> &); - -// stuff needed for face data - - template void - DataOut_DoFData<DH<deal_II_dimension,deal_II_dimension>,deal_II_dimension-1,deal_II_dimension>:: - add_data_vector<IndexSet> (const IndexSet &, - const std::string &, - const DataVectorType, - const std::vector<DataComponentInterpretation::DataComponentInterpretation> &); - - template void - DataOut_DoFData<DH<deal_II_dimension,deal_II_dimension>,deal_II_dimension-1,deal_II_dimension>:: - add_data_vector<IndexSet> (const IndexSet &, - const std::vector<std::string> &, - const DataVectorType, - const std::vector<DataComponentInterpretation::DataComponentInterpretation> &); - - template void - DataOut_DoFData<DH<deal_II_dimension,deal_II_dimension>,deal_II_dimension-1,deal_II_dimension>:: - add_data_vector<IndexSet> (const IndexSet &, - const DataPostprocessor<DH<deal_II_dimension,deal_II_dimension>::space_dimension> &); - -// things for DataOutRotation - - template void - DataOut_DoFData<DH<deal_II_dimension,deal_II_dimension>,deal_II_dimension+1,deal_II_dimension+1>:: - add_data_vector<IndexSet> (const IndexSet &, - const std::string &, - const DataVectorType, - const std::vector<DataComponentInterpretation::DataComponentInterpretation> &); - - template void - DataOut_DoFData<DH<deal_II_dimension,deal_II_dimension>,deal_II_dimension+1,deal_II_dimension+1>:: - add_data_vector<IndexSet> (const IndexSet &, - const std::vector<std::string> &, - const DataVectorType, - const std::vector<DataComponentInterpretation::DataComponentInterpretation> &); - - template void - DataOut_DoFData<DH<deal_II_dimension,deal_II_dimension>,deal_II_dimension+1,deal_II_dimension+1>:: - add_data_vector<IndexSet> (const IndexSet &, - const DataPostprocessor<DH<deal_II_dimension,deal_II_dimension>::space_dimension> &); - -// codim 1 - - #if deal_II_dimension < 3 - template void - DataOut_DoFData<DH<deal_II_dimension,deal_II_dimension+1>,deal_II_dimension,deal_II_dimension+1>:: - add_data_vector<IndexSet> (const IndexSet &, - const std::string &, - const DataVectorType, - const std::vector<DataComponentInterpretation::DataComponentInterpretation> &); - - template void - DataOut_DoFData<DH<deal_II_dimension,deal_II_dimension+1>,deal_II_dimension,deal_II_dimension+1>:: - add_data_vector<IndexSet> (const IndexSet &, - const std::vector<std::string> &, - const DataVectorType, - const std::vector<DataComponentInterpretation::DataComponentInterpretation> &); - - template void - DataOut_DoFData<DH<deal_II_dimension,deal_II_dimension+1>,deal_II_dimension,deal_II_dimension+1>:: - add_data_vector<IndexSet> (const IndexSet &, - const DataPostprocessor<DH<deal_II_dimension,deal_II_dimension+1>::space_dimension> &); - #endif - + namespace internal \{ + namespace DataOut \{ +#if deal_II_dimension <= deal_II_space_dimension + template struct ParallelData<deal_II_dimension,deal_II_space_dimension>; +#endif + \} + \} } - for (DH : DOFHANDLER_TEMPLATES; deal_II_dimension : DIMENSIONS) { template class DataOut_DoFData<DH<deal_II_dimension>,deal_II_dimension>; @@ -340,9 +38,6 @@ for (DH : DOFHANDLER_TEMPLATES; deal_II_dimension : DIMENSIONS) template class DataOut_DoFData<DH<deal_II_dimension,deal_II_dimension+1>,deal_II_dimension,deal_II_dimension+1>; #endif - #if deal_II_dimension >= 2 - template class DataOut_DoFData<DH<deal_II_dimension>,deal_II_dimension-1,deal_II_dimension>; - #endif template class DataOut<deal_II_dimension, DH<deal_II_dimension> >; #if deal_II_dimension < 3 @@ -350,40 +45,6 @@ for (DH : DOFHANDLER_TEMPLATES; deal_II_dimension : DIMENSIONS) #endif #if deal_II_dimension == 3 - template class DataOut_DoFData<DH<1>,1,3>; - template class DataOut_DoFData<DH<1,3>,1,3>; template class DataOut<1, DH<1,3> >; #endif - -} - - -for (deal_II_dimension : DIMENSIONS; deal_II_space_dimension : DIMENSIONS) -{ - namespace internal \{ - namespace DataOut \{ -#if deal_II_dimension <= deal_II_space_dimension - template struct ParallelDataBase<deal_II_dimension,deal_II_space_dimension>; - template struct ParallelData<deal_II_dimension,deal_II_space_dimension>; -#endif - \} - \} -} - - -for (DH : DOFHANDLER_TEMPLATES; deal_II_dimension : DIMENSIONS; deal_II_space_dimension : DIMENSIONS) -{ - namespace internal \{ - namespace DataOut \{ -#if deal_II_dimension <= deal_II_space_dimension - template - void - ParallelDataBase<deal_II_dimension,deal_II_space_dimension>:: - reinit_all_fe_values<dealii::DH<deal_II_dimension,deal_II_space_dimension> > - (std::vector<std_cxx1x::shared_ptr<DataEntryBase<dealii::DH<deal_II_dimension,deal_II_space_dimension> > > > &dof_data, - const dealii::Triangulation<deal_II_dimension,deal_II_space_dimension>::cell_iterator &cell, - const unsigned int face); -#endif - \} - \} -} +} \ No newline at end of file diff --git a/deal.II/source/numerics/data_out_dof_data.cc b/deal.II/source/numerics/data_out_dof_data.cc new file mode 100644 index 0000000000..37ff85b983 --- /dev/null +++ b/deal.II/source/numerics/data_out_dof_data.cc @@ -0,0 +1,1146 @@ +// --------------------------------------------------------------------- +// $Id$ +// +// Copyright (C) 1999 - 2013 by the deal.II authors +// +// This file is part of the deal.II library. +// +// The deal.II library is free software; you can use it, redistribute +// it, and/or modify it under the terms of the GNU Lesser General +// Public License as published by the Free Software Foundation; either +// version 2.1 of the License, or (at your option) any later version. +// The full text of the license can be found in the file LICENSE at +// the top level of the deal.II distribution. +// +// --------------------------------------------------------------------- + +#include <deal.II/base/quadrature_lib.h> +#include <deal.II/base/work_stream.h> +#include <deal.II/base/memory_consumption.h> +#include <deal.II/lac/vector.h> +#include <deal.II/lac/block_vector.h> +#include <deal.II/lac/parallel_vector.h> +#include <deal.II/lac/parallel_block_vector.h> +#include <deal.II/lac/petsc_vector.h> +#include <deal.II/lac/petsc_block_vector.h> +#include <deal.II/lac/trilinos_vector.h> +#include <deal.II/lac/trilinos_block_vector.h> +#include <deal.II/numerics/data_out.h> +#include <deal.II/numerics/data_out_dof_data.h> +#include <deal.II/dofs/dof_handler.h> +#include <deal.II/dofs/dof_accessor.h> +#include <deal.II/grid/tria.h> +#include <deal.II/grid/tria_iterator.h> +#include <deal.II/fe/fe.h> +#include <deal.II/fe/fe_dgq.h> +#include <deal.II/fe/fe_values.h> +#include <deal.II/hp/dof_handler.h> +#include <deal.II/hp/fe_values.h> +#include <deal.II/fe/mapping_q1.h> + +#include <sstream> + +DEAL_II_NAMESPACE_OPEN + + +namespace internal +{ + namespace DataOut + { + template <int dim, int spacedim> + ParallelDataBase<dim,spacedim>:: + ParallelDataBase (const unsigned int n_datasets, + const unsigned int n_subdivisions, + const std::vector<unsigned int> &n_postprocessor_outputs, + const Mapping<dim,spacedim> &mapping, + const std::vector<std_cxx1x::shared_ptr<dealii::hp::FECollection<dim,spacedim> > > &finite_elements, + const UpdateFlags update_flags, + const bool use_face_values) + : + n_datasets (n_datasets), + n_subdivisions (n_subdivisions), + postprocessed_values (n_postprocessor_outputs.size()), + mapping_collection (mapping), + finite_elements (finite_elements), + update_flags (update_flags) + { + unsigned int n_q_points = 0; + if (use_face_values == false) + { + dealii::hp::QCollection<dim> + quadrature(QIterated<dim>(QTrapez<1>(), n_subdivisions)); + n_q_points = quadrature[0].size(); + x_fe_values.resize(this->finite_elements.size()); + for (unsigned int i=0; i<this->finite_elements.size(); ++i) + { + // check if there is a finite element that is equal to the + // present one, then we can re-use the FEValues object + for (unsigned int j=0; j<i; ++j) + if (this->finite_elements[i].get() == + this->finite_elements[j].get()) + { + x_fe_values[i] = x_fe_values[j]; + break; + } + if (x_fe_values[i].get() == 0) + x_fe_values[i].reset(new dealii::hp::FEValues<dim,spacedim> + (this->mapping_collection, + *this->finite_elements[i], + quadrature, + this->update_flags)); + } + } + else + { + dealii::hp::QCollection<dim-1> + quadrature(QIterated<dim-1>(QTrapez<1>(), n_subdivisions)); + n_q_points = quadrature[0].size(); + x_fe_face_values.resize(this->finite_elements.size()); + for (unsigned int i=0; i<this->finite_elements.size(); ++i) + { + // check if there is a finite element that is equal to the + // present one, then we can re-use the FEValues object + for (unsigned int j=0; j<i; ++j) + if (this->finite_elements[i].get() == + this->finite_elements[j].get()) + { + x_fe_face_values[i] = x_fe_face_values[j]; + break; + } + if (x_fe_face_values[i].get() == 0) + x_fe_face_values[i].reset(new dealii::hp::FEFaceValues<dim,spacedim> + (this->mapping_collection, + *this->finite_elements[i], + quadrature, + this->update_flags)); + } + } + + patch_values.resize (n_q_points); + patch_values_system.resize (n_q_points); + patch_gradients.resize (n_q_points); + patch_gradients_system.resize (n_q_points); + patch_hessians.resize (n_q_points); + patch_hessians_system.resize (n_q_points); + + for (unsigned int dataset=0; dataset<n_postprocessor_outputs.size(); ++dataset) + if (n_postprocessor_outputs[dataset] != 0) + postprocessed_values[dataset] + .resize(n_q_points, + dealii::Vector<double>(n_postprocessor_outputs[dataset])); + } + + + + + + // implement copy constructor to create a thread's own version of + // x_fe_values + template <int dim, int spacedim> + ParallelDataBase<dim,spacedim>:: + ParallelDataBase (const ParallelDataBase<dim,spacedim> &data) + : + n_datasets (data.n_datasets), + n_subdivisions (data.n_subdivisions), + patch_values (data.patch_values), + patch_values_system (data.patch_values_system), + patch_gradients (data.patch_gradients), + patch_gradients_system (data.patch_gradients_system), + patch_hessians (data.patch_hessians), + patch_hessians_system (data.patch_hessians_system), + postprocessed_values (data.postprocessed_values), + mapping_collection (data.mapping_collection), + finite_elements (data.finite_elements), + update_flags (data.update_flags) + { + if (data.x_fe_values.empty() == false) + { + Assert(data.x_fe_face_values.empty() == true, ExcInternalError()); + dealii::hp::QCollection<dim> + quadrature(QIterated<dim>(QTrapez<1>(), n_subdivisions)); + x_fe_values.resize(this->finite_elements.size()); + for (unsigned int i=0; i<this->finite_elements.size(); ++i) + { + // check if there is a finite element that is equal to the + // present one, then we can re-use the FEValues object + for (unsigned int j=0; j<i; ++j) + if (this->finite_elements[i].get() == + this->finite_elements[j].get()) + { + x_fe_values[i] = x_fe_values[j]; + break; + } + if (x_fe_values[i].get() == 0) + x_fe_values[i].reset(new dealii::hp::FEValues<dim,spacedim> + (this->mapping_collection, + *this->finite_elements[i], + quadrature, + this->update_flags)); + } + } + else + { + dealii::hp::QCollection<dim-1> + quadrature(QIterated<dim-1>(QTrapez<1>(), n_subdivisions)); + x_fe_face_values.resize(this->finite_elements.size()); + for (unsigned int i=0; i<this->finite_elements.size(); ++i) + { + // check if there is a finite element that is equal to the + // present one, then we can re-use the FEValues object + for (unsigned int j=0; j<i; ++j) + if (this->finite_elements[i].get() == + this->finite_elements[j].get()) + { + x_fe_face_values[i] = x_fe_face_values[j]; + break; + } + if (x_fe_face_values[i].get() == 0) + x_fe_face_values[i].reset(new dealii::hp::FEFaceValues<dim,spacedim> + (this->mapping_collection, + *this->finite_elements[i], + quadrature, + this->update_flags)); + } + } + } + + + + template <int dim, int spacedim> + template <typename DH> + void + ParallelDataBase<dim,spacedim>:: + reinit_all_fe_values(std::vector<std_cxx1x::shared_ptr<DataEntryBase<DH> > > &dof_data, + const typename dealii::Triangulation<dim,spacedim>::cell_iterator &cell, + const unsigned int face) + { + for (unsigned int dataset=0; dataset<dof_data.size(); ++dataset) + { + bool duplicate = false; + for (unsigned int j=0; j<dataset; ++j) + if (finite_elements[dataset].get() == finite_elements[j].get()) + duplicate = true; + if (duplicate == false) + { + typename DH::active_cell_iterator dh_cell(&cell->get_triangulation(), + cell->level(), + cell->index(), + dof_data[dataset]->dof_handler); + if (x_fe_values.empty()) + { + AssertIndexRange(face, + GeometryInfo<dim>::faces_per_cell); + x_fe_face_values[dataset]->reinit(dh_cell, face); + } + else + x_fe_values[dataset]->reinit (dh_cell); + } + } + if (dof_data.empty()) + { + if (x_fe_values.empty()) + { + AssertIndexRange(face, + GeometryInfo<dim>::faces_per_cell); + x_fe_face_values[0]->reinit(cell, face); + } + else + x_fe_values[0]->reinit (cell); + } + } + + + + template <int dim, int spacedim> + const FEValuesBase<dim,spacedim> & + ParallelDataBase<dim,spacedim>:: + get_present_fe_values(const unsigned int dataset) const + { + AssertIndexRange(dataset, finite_elements.size()); + if (x_fe_values.empty()) + return x_fe_face_values[dataset]->get_present_fe_values(); + else + return x_fe_values[dataset]->get_present_fe_values(); + } + + + + template <int dim, int spacedim> + void + ParallelDataBase<dim,spacedim>:: + resize_system_vectors(const unsigned int n_components) + { + Assert(patch_values_system.size() > 0, ExcInternalError()); + AssertDimension(patch_values_system.size(), + patch_gradients_system.size()); + AssertDimension(patch_values_system.size(), + patch_hessians_system.size()); + if (patch_values_system[0].size() == n_components) + return; + for (unsigned int k=0; k<patch_values_system.size(); ++k) + { + patch_values_system[k].reinit(n_components); + patch_gradients_system[k].resize(n_components); + patch_hessians_system[k].resize(n_components); + } + } + + + + + /** + * In a WorkStream context, use this function to append the patch computed + * by the parallel stage to the array of patches. + */ + template <int dim, int spacedim> + void + append_patch_to_list (const DataOutBase::Patch<dim,spacedim> &patch, + std::vector<DataOutBase::Patch<dim,spacedim> > &patches) + { + patches.push_back (patch); + patches.back().patch_index = patches.size()-1; + } + } +} + +namespace internal +{ + namespace DataOut + { + template <class DH> + DataEntryBase<DH>::DataEntryBase (const DH *dofs, + const std::vector<std::string> &names_in, + const std::vector<DataComponentInterpretation::DataComponentInterpretation> &data_component_interpretation) + : + dof_handler (dofs, typeid(dealii::DataOut_DoFData<DH,DH::dimension,DH::space_dimension>).name()), + names(names_in), + data_component_interpretation (data_component_interpretation), + postprocessor(0, typeid(*this).name()), + n_output_variables(names.size()) + { + Assert (names.size() == data_component_interpretation.size(), + ExcDimensionMismatch(data_component_interpretation.size(), + names.size())); + + // check that the names use only allowed characters + for (unsigned int i=0; i<names.size(); ++i) + Assert (names[i].find_first_not_of("abcdefghijklmnopqrstuvwxyz" + "ABCDEFGHIJKLMNOPQRSTUVWXYZ" + "0123456789_<>()") == std::string::npos, + typename dealii::DataOut<DH::dimension>:: + ExcInvalidCharacter (names[i], + names[i].find_first_not_of("abcdefghijklmnopqrstuvwxyz" + "ABCDEFGHIJKLMNOPQRSTUVWXYZ" + "0123456789_<>()"))); + } + + + + template <class DH> + DataEntryBase<DH>::DataEntryBase (const DH *dofs, + const DataPostprocessor<DH::space_dimension> *data_postprocessor) + : + dof_handler (dofs, typeid(dealii::DataOut_DoFData<DH,DH::dimension,DH::space_dimension>).name()), + names(data_postprocessor->get_names()), + data_component_interpretation (data_postprocessor->get_data_component_interpretation()), + postprocessor(data_postprocessor, typeid(*this).name()), + n_output_variables(names.size()) + { + Assert (data_postprocessor->get_names().size() + == + data_postprocessor->get_data_component_interpretation().size(), + ExcDimensionMismatch (data_postprocessor->get_names().size(), + data_postprocessor->get_data_component_interpretation().size())); + + // check that the names use only allowed characters + for (unsigned int i=0; i<names.size(); ++i) + Assert (names[i].find_first_not_of("abcdefghijklmnopqrstuvwxyz" + "ABCDEFGHIJKLMNOPQRSTUVWXYZ" + "0123456789_<>()") == std::string::npos, + typename dealii::DataOut<DH::dimension>:: + ExcInvalidCharacter (names[i], + names[i].find_first_not_of("abcdefghijklmnopqrstuvwxyz" + "ABCDEFGHIJKLMNOPQRSTUVWXYZ" + "0123456789_<>()"))); + } + + + + template <class DH> + DataEntryBase<DH>::~DataEntryBase () + {} + + + + /** + * Class that stores a pointer to a vector of type equal to the template + * argument, and provides the functions to extract data from it. + * + * @author Wolfgang Bangerth, 2004 + */ + template <class DH, typename VectorType> + class DataEntry : public DataEntryBase<DH> + { + public: + /** + * Constructor. Give a list of names for the individual components of + * the vector and their interpretation as scalar or vector data. This + * constructor assumes that no postprocessor is going to be used. + */ + DataEntry (const DH *dofs, + const VectorType *data, + const std::vector<std::string> &names, + const std::vector<DataComponentInterpretation::DataComponentInterpretation> &data_component_interpretation); + + /** + * Constructor when a data postprocessor is going to be used. In that + * case, the names and vector declarations are going to be acquired from + * the postprocessor. + */ + DataEntry (const DH *dofs, + const VectorType *data, + const DataPostprocessor<DH::space_dimension> *data_postprocessor); + + /** + * Assuming that the stored vector is a cell vector, extract the given + * element from it. + */ + virtual + double + get_cell_data_value (const unsigned int cell_number) const; + + /** + * Given a FEValuesBase object, extract the values on the present cell + * from the vector we actually store. + */ + virtual + void + get_function_values (const FEValuesBase<DH::dimension,DH::space_dimension> &fe_patch_values, + std::vector<double> &patch_values) const; + + /** + * Given a FEValuesBase object, extract the values on the present cell + * from the vector we actually store. This function does the same as the + * one above but for vector-valued finite elements. + */ + virtual + void + get_function_values (const FEValuesBase<DH::dimension,DH::space_dimension> &fe_patch_values, + std::vector<dealii::Vector<double> > &patch_values_system) const; + + /** + * Given a FEValuesBase object, extract the gradients on the present + * cell from the vector we actually store. + */ + virtual + void + get_function_gradients (const FEValuesBase<DH::dimension,DH::space_dimension> &fe_patch_values, + std::vector<Tensor<1,DH::space_dimension> > &patch_gradients) const; + + /** + * Given a FEValuesBase object, extract the gradients on the present + * cell from the vector we actually store. This function does the same + * as the one above but for vector-valued finite elements. + */ + virtual + void + get_function_gradients (const FEValuesBase<DH::dimension,DH::space_dimension> &fe_patch_values, + std::vector<std::vector<Tensor<1,DH::space_dimension> > > &patch_gradients_system) const; + + /** + * Given a FEValuesBase object, extract the second derivatives on the + * present cell from the vector we actually store. + */ + virtual + void + get_function_hessians (const FEValuesBase<DH::dimension,DH::space_dimension> &fe_patch_values, + std::vector<Tensor<2,DH::space_dimension> > &patch_hessians) const; + + /** + * Given a FEValuesBase object, extract the second derivatives on the + * present cell from the vector we actually store. This function does + * the same as the one above but for vector-valued finite elements. + */ + virtual + void + get_function_hessians (const FEValuesBase<DH::dimension,DH::space_dimension> &fe_patch_values, + std::vector<std::vector< Tensor<2,DH::space_dimension> > > &patch_hessians_system) const; + + /** + * Clear all references to the vectors. + */ + virtual void clear (); + + /** + * Determine an estimate for the memory consumption (in bytes) of this + * object. + */ + virtual std::size_t memory_consumption () const; + + private: + /** + * Pointer to the data vector. Note that ownership of the vector pointed + * to remains with the caller of this class. + */ + const VectorType *vector; + }; + + + + template <class DH, class VectorType> + DataEntry<DH,VectorType>:: + DataEntry (const DH *dofs, + const VectorType *data, + const std::vector<std::string> &names, + const std::vector<DataComponentInterpretation::DataComponentInterpretation> &data_component_interpretation) + : + DataEntryBase<DH> (dofs, names, data_component_interpretation), + vector (data) + {} + + + + template <class DH, class VectorType> + DataEntry<DH,VectorType>:: + DataEntry (const DH *dofs, + const VectorType *data, + const DataPostprocessor<DH::space_dimension> *data_postprocessor) + : + DataEntryBase<DH> (dofs, data_postprocessor), + vector (data) + {} + + + namespace + { + template <class VectorType> + double + get_vector_element (const VectorType &vector, + const unsigned int cell_number) + { + return vector[cell_number]; + } + + + double + get_vector_element (const IndexSet &is, + const unsigned int cell_number) + { + return (is.is_element(cell_number) ? 1 : 0); + } + } + + + + template <class DH, class VectorType> + double + DataEntry<DH,VectorType>:: + get_cell_data_value (const unsigned int cell_number) const + { + return get_vector_element(*vector, cell_number); + } + + + + template <class DH, class VectorType> + void + DataEntry<DH,VectorType>:: + get_function_values (const FEValuesBase<DH::dimension,DH::space_dimension> &fe_patch_values, + std::vector<dealii::Vector<double> > &patch_values_system) const + { + fe_patch_values.get_function_values (*vector, patch_values_system); + } + + + + template <class DH, typename VectorType> + void + DataEntry<DH,VectorType>:: + get_function_values (const FEValuesBase<DH::dimension,DH::space_dimension> &fe_patch_values, + std::vector<double> &patch_values) const + { + fe_patch_values.get_function_values (*vector, patch_values); + } + + + + template <class DH, class VectorType> + void + DataEntry<DH,VectorType>:: + get_function_gradients (const FEValuesBase<DH::dimension,DH::space_dimension> &fe_patch_values, + std::vector<std::vector<Tensor<1,DH::space_dimension> > > &patch_gradients_system) const + { + fe_patch_values.get_function_gradients (*vector, patch_gradients_system); + } + + + + template <class DH, typename VectorType> + void + DataEntry<DH,VectorType>:: + get_function_gradients (const FEValuesBase<DH::dimension,DH::space_dimension> &fe_patch_values, + std::vector<Tensor<1,DH::space_dimension> > &patch_gradients) const + { + fe_patch_values.get_function_gradients (*vector, patch_gradients); + } + + + + template <class DH, class VectorType> + void + DataEntry<DH,VectorType>:: + get_function_hessians (const FEValuesBase<DH::dimension,DH::space_dimension> &fe_patch_values, + std::vector<std::vector<Tensor<2,DH::space_dimension> > > &patch_hessians_system) const + { + fe_patch_values.get_function_hessians (*vector, patch_hessians_system); + } + + + + template <class DH, typename VectorType> + void + DataEntry<DH,VectorType>:: + get_function_hessians (const FEValuesBase<DH::dimension,DH::space_dimension> &fe_patch_values, + std::vector<Tensor<2,DH::space_dimension> > &patch_hessians) const + { + fe_patch_values.get_function_hessians (*vector, patch_hessians); + } + + + + template <class DH, typename VectorType> + std::size_t + DataEntry<DH,VectorType>::memory_consumption () const + { + return (sizeof (vector) + + MemoryConsumption::memory_consumption (this->names)); + } + + + + template <class DH, class VectorType> + void + DataEntry<DH,VectorType>::clear () + { + vector = 0; + this->dof_handler = 0; + } + } +} + + + +template <class DH, + int patch_dim, int patch_space_dim> +DataOut_DoFData<DH,patch_dim,patch_space_dim>::DataOut_DoFData () + : + triangulation(0,typeid(*this).name()), + dofs(0,typeid(*this).name()) +{} + + + +template <class DH, int patch_dim, int patch_space_dim> +DataOut_DoFData<DH,patch_dim,patch_space_dim>::~DataOut_DoFData () +{ + clear (); +} + + + +template <class DH, int patch_dim, int patch_space_dim> +void +DataOut_DoFData<DH,patch_dim,patch_space_dim>:: +attach_dof_handler (const DH &d) +{ + Assert (dof_data.size() == 0, ExcOldDataStillPresent()); + Assert (cell_data.size() == 0, ExcOldDataStillPresent()); + + triangulation = SmartPointer<const Triangulation<DH::dimension,DH::space_dimension> >(&d.get_tria(), typeid(*this).name()); + dofs = SmartPointer<const DH>(&d, typeid(*this).name()); +} + + + +template <class DH, int patch_dim, int patch_space_dim> +void +DataOut_DoFData<DH,patch_dim,patch_space_dim>:: +attach_triangulation (const Triangulation<DH::dimension,DH::space_dimension> &tria) +{ + Assert (dof_data.size() == 0, ExcOldDataStillPresent()); + Assert (cell_data.size() == 0, ExcOldDataStillPresent()); + + triangulation = SmartPointer<const Triangulation<DH::dimension,DH::space_dimension> >(&tria, typeid(*this).name()); +} + + + + +template <class DH, + int patch_dim, int patch_space_dim> +template <class VECTOR> +void +DataOut_DoFData<DH,patch_dim,patch_space_dim>:: +add_data_vector (const VECTOR &vec, + const std::string &name, + const DataVectorType type, + const std::vector<DataComponentInterpretation::DataComponentInterpretation> &data_component_interpretation) +{ + Assert (triangulation != 0, ExcNoTriangulationSelected ()); + const unsigned int n_components = + dofs != 0 ? dofs->get_fe().n_components () : 1; + + std::vector<std::string> names; + // if only one component or vector is cell vector: we only need one name + if ((n_components == 1) || + (vec.size() == triangulation->n_active_cells())) + { + names.resize (1, name); + } + else + // otherwise append _i to the given name + { + names.resize (n_components); + for (unsigned int i=0; i<n_components; ++i) + { + std::ostringstream namebuf; + namebuf << '_' << i; + names[i] = name + namebuf.str(); + } + } + + add_data_vector (vec, names, type, data_component_interpretation); +} + + + +template <class DH, + int patch_dim, int patch_space_dim> +template <class VECTOR> +void +DataOut_DoFData<DH,patch_dim,patch_space_dim>:: +add_data_vector (const VECTOR &vec, + const std::vector<std::string> &names, + const DataVectorType type, + const std::vector<DataComponentInterpretation::DataComponentInterpretation> &data_component_interpretation_) +{ + Assert (triangulation != 0, ExcNoTriangulationSelected ()); + + const std::vector<DataComponentInterpretation::DataComponentInterpretation> & + data_component_interpretation + = (data_component_interpretation_.size() != 0 + ? + data_component_interpretation_ + : + std::vector<DataComponentInterpretation::DataComponentInterpretation> + (names.size(), DataComponentInterpretation::component_is_scalar)); + + // either cell data and one name, + // or dof data and n_components names + DataVectorType actual_type = type; + if (type == type_automatic) + { + if (vec.size() == triangulation->n_active_cells()) + actual_type = type_cell_data; + else + actual_type = type_dof_data; + } + + switch (actual_type) + { + case type_cell_data: + Assert (vec.size() == triangulation->n_active_cells(), + ExcDimensionMismatch (vec.size(), + triangulation->n_active_cells())); + Assert (names.size() == 1, + ExcInvalidNumberOfNames (names.size(), 1)); + break; + + case type_dof_data: + Assert (dofs != 0, ExcNoDoFHandlerSelected ()); + Assert (vec.size() == dofs->n_dofs(), + ExcInvalidVectorSize (vec.size(), + dofs->n_dofs(), + triangulation->n_active_cells())); + Assert (names.size() == dofs->get_fe().n_components(), + ExcInvalidNumberOfNames (names.size(), dofs->get_fe().n_components())); + break; + + case type_automatic: + // this case should have been handled above... + Assert (false, ExcInternalError()); + } + + internal::DataOut::DataEntryBase<DH> *new_entry + = new internal::DataOut::DataEntry<DH,VECTOR>(dofs, &vec, names, + data_component_interpretation); + if (actual_type == type_dof_data) + dof_data.push_back (std_cxx1x::shared_ptr<internal::DataOut::DataEntryBase<DH> >(new_entry)); + else + cell_data.push_back (std_cxx1x::shared_ptr<internal::DataOut::DataEntryBase<DH> >(new_entry)); +} + + + +template <class DH, + int patch_dim, int patch_space_dim> +template <class VECTOR> +void +DataOut_DoFData<DH,patch_dim,patch_space_dim>:: +add_data_vector (const VECTOR &vec, + const DataPostprocessor<DH::space_dimension> &data_postprocessor) +{ + // this is a specialized version of the other function where we have a + // postprocessor. if we do, we know that we have type_dof_data, which makes + // things a bit simpler, we also don't need to deal with some of the other + // stuff and use a different constructor of DataEntry + + Assert (dofs != 0, ExcNoDoFHandlerSelected ()); + + Assert (vec.size() == dofs->n_dofs(), + ExcInvalidVectorSize (vec.size(), + dofs->n_dofs(), + dofs->get_tria().n_active_cells())); + + internal::DataOut::DataEntryBase<DH> *new_entry + = new internal::DataOut::DataEntry<DH,VECTOR>(dofs, &vec, &data_postprocessor); + dof_data.push_back (std_cxx1x::shared_ptr<internal::DataOut::DataEntryBase<DH> >(new_entry)); +} + + + +template <class DH, + int patch_dim, int patch_space_dim> +template <class VECTOR> +void +DataOut_DoFData<DH,patch_dim,patch_space_dim>:: +add_data_vector (const DH &dof_handler, + const VECTOR &vec, + const DataPostprocessor<DH::space_dimension> &data_postprocessor) +{ + // this is a specialized version of the other function where we have a + // postprocessor. if we do, we know that we have type_dof_data, which makes + // things a bit simpler, we also don't need to deal with some of the other + // stuff and use a different constructor of DataEntry + + AssertDimension (vec.size(), dof_handler.n_dofs()); + + internal::DataOut::DataEntryBase<DH> *new_entry + = new internal::DataOut::DataEntry<DH,VECTOR>(&dof_handler, &vec, &data_postprocessor); + dof_data.push_back (std_cxx1x::shared_ptr<internal::DataOut::DataEntryBase<DH> >(new_entry)); +} + + + +template <class DH, + int patch_dim, int patch_space_dim> +template <class VECTOR> +void +DataOut_DoFData<DH,patch_dim,patch_space_dim>:: +add_data_vector (const DH &dof_handler, + const VECTOR &data, + const std::string &name, + const std::vector<DataComponentInterpretation::DataComponentInterpretation> &data_component_interpretation) +{ + const unsigned int n_components = dof_handler.get_fe().n_components (); + + std::vector<std::string> names; + // if only one component: we only need one name + if (n_components == 1) + names.resize (1, name); + else + // otherwise append _i to the given name + { + names.resize (n_components); + for (unsigned int i=0; i<n_components; ++i) + { + std::ostringstream namebuf; + namebuf << '_' << i; + names[i] = name + namebuf.str(); + } + } + + add_data_vector (dof_handler, data, names, data_component_interpretation); +} + + + +template <class DH, + int patch_dim, int patch_space_dim> +template <class VECTOR> +void +DataOut_DoFData<DH,patch_dim,patch_space_dim>:: +add_data_vector (const DH &dof_handler, + const VECTOR &data, + const std::vector<std::string> &names, + const std::vector<DataComponentInterpretation::DataComponentInterpretation> &data_component_interpretation_) +{ + // this is an extended version of the other functions where we pass a vector + // together with its DoFHandler. if we do, we know that we have + // type_dof_data, which makes things a bit simpler + if (triangulation == 0) + triangulation = SmartPointer<const Triangulation<DH::dimension,DH::space_dimension> >(&dof_handler.get_tria(), typeid(*this).name()); + + Assert (&dof_handler.get_tria() == triangulation, + ExcMessage("The triangulation attached to the DoFHandler does not " + "match with the one set previously")); + + Assert (data.size() == dof_handler.n_dofs(), + ExcDimensionMismatch (data.size(), dof_handler.n_dofs())); + + const std::vector<DataComponentInterpretation::DataComponentInterpretation> & + data_component_interpretation + = (data_component_interpretation_.size() != 0 + ? + data_component_interpretation_ + : + std::vector<DataComponentInterpretation::DataComponentInterpretation> + (names.size(), DataComponentInterpretation::component_is_scalar)); + + internal::DataOut::DataEntryBase<DH> *new_entry + = new internal::DataOut::DataEntry<DH,VECTOR>(&dof_handler, &data, names, + data_component_interpretation); + dof_data.push_back (std_cxx1x::shared_ptr<internal::DataOut::DataEntryBase<DH> >(new_entry)); +} + + + +template <class DH, + int patch_dim, int patch_space_dim> +void DataOut_DoFData<DH,patch_dim,patch_space_dim>::clear_data_vectors () +{ + dof_data.erase (dof_data.begin(), dof_data.end()); + cell_data.erase (cell_data.begin(), cell_data.end()); + + // delete patches + std::vector<Patch> dummy; + patches.swap (dummy); +} + + + +template <class DH, + int patch_dim, int patch_space_dim> +void +DataOut_DoFData<DH,patch_dim,patch_space_dim>:: +clear_input_data_references () +{ + for (unsigned int i=0; i<dof_data.size(); ++i) + dof_data[i]->clear (); + + for (unsigned int i=0; i<cell_data.size(); ++i) + cell_data[i]->clear (); + + if (dofs != 0) + dofs = 0; +} + + + +template <class DH, + int patch_dim, int patch_space_dim> +void +DataOut_DoFData<DH,patch_dim,patch_space_dim>::clear () +{ + dof_data.erase (dof_data.begin(), dof_data.end()); + cell_data.erase (cell_data.begin(), cell_data.end()); + + if (dofs != 0) + dofs = 0; + + // delete patches + std::vector<Patch> dummy; + patches.swap (dummy); +} + + + +template <class DH, + int patch_dim, int patch_space_dim> +std::vector<std::string> +DataOut_DoFData<DH,patch_dim,patch_space_dim>:: +get_dataset_names () const +{ + std::vector<std::string> names; + // collect the names of dof + // and cell data + typedef + typename std::vector<std_cxx1x::shared_ptr<internal::DataOut::DataEntryBase<DH> > >::const_iterator + data_iterator; + + for (data_iterator d=dof_data.begin(); + d!=dof_data.end(); ++d) + for (unsigned int i=0; i<(*d)->names.size(); ++i) + names.push_back ((*d)->names[i]); + for (data_iterator d=cell_data.begin(); d!=cell_data.end(); ++d) + { + Assert ((*d)->names.size() == 1, ExcInternalError()); + names.push_back ((*d)->names[0]); + } + + return names; +} + + + +template <class DH, + int patch_dim, int patch_space_dim> +std::vector<std_cxx1x::tuple<unsigned int, unsigned int, std::string> > +DataOut_DoFData<DH,patch_dim,patch_space_dim>::get_vector_data_ranges () const +{ + std::vector<std_cxx1x::tuple<unsigned int, unsigned int, std::string> > + ranges; + + // collect the ranges of dof + // and cell data + typedef + typename std::vector<std_cxx1x::shared_ptr<internal::DataOut::DataEntryBase<DH> > >::const_iterator + data_iterator; + + unsigned int output_component = 0; + for (data_iterator d=dof_data.begin(); + d!=dof_data.end(); ++d) + for (unsigned int i=0; i<(*d)->n_output_variables; + ++i, ++output_component) + // see what kind of data we have + // here. note that for the purpose of + // the current function all we care + // about is vector data + if ((*d)->data_component_interpretation[i] == + DataComponentInterpretation::component_is_part_of_vector) + { + // ensure that there is a + // continuous number of next + // space_dim components that all + // deal with vectors + Assert (i+patch_space_dim <= + (*d)->n_output_variables, + ExcInvalidVectorDeclaration (i, + (*d)->names[i])); + for (unsigned int dd=1; dd<patch_space_dim; ++dd) + Assert ((*d)->data_component_interpretation[i+dd] + == + DataComponentInterpretation::component_is_part_of_vector, + ExcInvalidVectorDeclaration (i, + (*d)->names[i])); + + // all seems alright, so figure out + // whether there is a common name + // to these components. if not, + // leave the name empty and let the + // output format writer decide what + // to do here + std::string name = (*d)->names[i]; + for (unsigned int dd=1; dd<patch_space_dim; ++dd) + if (name != (*d)->names[i+dd]) + { + name = ""; + break; + } + + // finally add a corresponding + // range + std_cxx1x::tuple<unsigned int, unsigned int, std::string> + range (output_component, + output_component+patch_space_dim-1, + name); + + ranges.push_back (range); + + // increase the 'component' counter + // by the appropriate amount, same + // for 'i', since we have already + // dealt with all these components + output_component += patch_space_dim-1; + i += patch_space_dim-1; + } + + // note that we do not have to traverse the + // list of cell data here because cell data + // is one value per (logical) cell and + // therefore cannot be a vector + + // as a final check, the 'component' + // counter should be at the total number of + // components added up now +#ifdef DEBUG + unsigned int n_output_components = 0; + for (data_iterator d=dof_data.begin(); + d!=dof_data.end(); ++d) + n_output_components += (*d)->n_output_variables; + Assert (output_component == n_output_components, + ExcInternalError()); +#endif + + return ranges; +} + + + +template <class DH, + int patch_dim, int patch_space_dim> +const std::vector< dealii::DataOutBase::Patch<patch_dim, patch_space_dim> > & +DataOut_DoFData<DH,patch_dim,patch_space_dim>::get_patches () const +{ + return patches; +} + + + +template <class DH, + int patch_dim, int patch_space_dim> +std::vector<std_cxx1x::shared_ptr<dealii::hp::FECollection<DH::dimension,DH::space_dimension> > > +DataOut_DoFData<DH,patch_dim,patch_space_dim>::get_finite_elements() const +{ + const unsigned int dhdim = DH::dimension; + const unsigned int dhspacedim = DH::space_dimension; + std::vector<std_cxx1x::shared_ptr<dealii::hp::FECollection<dhdim,dhspacedim> > > + finite_elements(this->dof_data.size()); + for (unsigned int i=0; i<this->dof_data.size(); ++i) + { + Assert (dof_data[i]->dof_handler != 0, ExcNoDoFHandlerSelected ()); + + // avoid creating too many finite elements and doing a lot of work on + // initializing FEValues downstream: if two DoFHandlers are the same + // (checked by pointer comparison), we can re-use the shared_ptr object + // for the second one. We cannot check for finite element equalities + // because we need different FEValues objects for different dof + // handlers. + bool duplicate = false; + for (unsigned int j=0; j<i; ++j) + if (dof_data[i]->dof_handler == dof_data[j]->dof_handler) + { + finite_elements[i] = finite_elements[j]; + duplicate = true; + } + if (duplicate == false) + finite_elements[i].reset(new dealii::hp::FECollection<dhdim,dhspacedim> + (this->dof_data[i]->dof_handler->get_fe())); + } + if (this->dof_data.empty()) + { + finite_elements.resize(1); + finite_elements[0].reset(new dealii::hp::FECollection<dhdim,dhspacedim> + (FE_DGQ<dhdim,dhspacedim>(0))); + } + return finite_elements; +} + + + +template <class DH, + int patch_dim, int patch_space_dim> +std::size_t +DataOut_DoFData<DH,patch_dim,patch_space_dim>::memory_consumption () const +{ + return (DataOutInterface<patch_dim,patch_space_dim>::memory_consumption () + + MemoryConsumption::memory_consumption (dofs) + + MemoryConsumption::memory_consumption (patches)); +} + + + +// explicit instantiations +#include "data_out_dof_data.inst" + +DEAL_II_NAMESPACE_CLOSE diff --git a/deal.II/source/numerics/data_out_dof_data.inst.in b/deal.II/source/numerics/data_out_dof_data.inst.in new file mode 100644 index 0000000000..08ee60879b --- /dev/null +++ b/deal.II/source/numerics/data_out_dof_data.inst.in @@ -0,0 +1,428 @@ +// --------------------------------------------------------------------- +// $Id$ +// +// Copyright (C) 2010 - 2013 by the deal.II authors +// +// This file is part of the deal.II library. +// +// The deal.II library is free software; you can use it, redistribute +// it, and/or modify it under the terms of the GNU Lesser General +// Public License as published by the Free Software Foundation; either +// version 2.1 of the License, or (at your option) any later version. +// The full text of the license can be found in the file LICENSE at +// the top level of the deal.II distribution. +// +// --------------------------------------------------------------------- + + +for (VEC : SERIAL_VECTORS; DH : DOFHANDLER_TEMPLATES; deal_II_dimension : DIMENSIONS) +{ +// codim=0 + + template void + DataOut_DoFData<DH<deal_II_dimension,deal_II_dimension>,deal_II_dimension,deal_II_dimension>:: + add_data_vector<VEC> (const VEC &, + const std::string &, + const DataVectorType, + const std::vector<DataComponentInterpretation::DataComponentInterpretation> &); + + template void + DataOut_DoFData<DH<deal_II_dimension,deal_II_dimension>,deal_II_dimension,deal_II_dimension>:: + add_data_vector<VEC> (const VEC &, + const std::vector<std::string> &, + const DataVectorType, + const std::vector<DataComponentInterpretation::DataComponentInterpretation> &); + + template void + DataOut_DoFData<DH<deal_II_dimension,deal_II_dimension>,deal_II_dimension,deal_II_dimension>:: + add_data_vector<VEC> (const VEC &, + const DataPostprocessor<DH<deal_II_dimension,deal_II_dimension>::space_dimension> &); + + template void + DataOut_DoFData<DH<deal_II_dimension,deal_II_dimension>,deal_II_dimension,deal_II_dimension>:: + add_data_vector<VEC> (const DH<deal_II_dimension,deal_II_dimension> &, + const VEC &, + const std::string &, + const std::vector<DataComponentInterpretation::DataComponentInterpretation> &); + + template void + DataOut_DoFData<DH<deal_II_dimension,deal_II_dimension>,deal_II_dimension,deal_II_dimension>:: + add_data_vector<VEC> (const DH<deal_II_dimension,deal_II_dimension> &, + const VEC &, + const std::vector<std::string> &, + const std::vector<DataComponentInterpretation::DataComponentInterpretation> &); + + template void + DataOut_DoFData<DH<deal_II_dimension,deal_II_dimension>,deal_II_dimension,deal_II_dimension>:: + add_data_vector<VEC> (const DH<deal_II_dimension,deal_II_dimension> &, + const VEC &, + const DataPostprocessor<DH<deal_II_dimension,deal_II_dimension>::space_dimension> &); + + + +// stuff needed for face data + + template void + DataOut_DoFData<DH<deal_II_dimension,deal_II_dimension>,deal_II_dimension-1,deal_II_dimension>:: + add_data_vector<VEC> (const VEC &, + const std::string &, + const DataVectorType, + const std::vector<DataComponentInterpretation::DataComponentInterpretation> &); + + template void + DataOut_DoFData<DH<deal_II_dimension,deal_II_dimension>,deal_II_dimension-1,deal_II_dimension>:: + add_data_vector<VEC> (const VEC &, + const std::vector<std::string> &, + const DataVectorType, + const std::vector<DataComponentInterpretation::DataComponentInterpretation> &); + + template void + DataOut_DoFData<DH<deal_II_dimension,deal_II_dimension>,deal_II_dimension-1,deal_II_dimension>:: + add_data_vector<VEC> (const VEC &, + const DataPostprocessor<DH<deal_II_dimension,deal_II_dimension>::space_dimension> &); + + template void + DataOut_DoFData<DH<deal_II_dimension,deal_II_dimension>,deal_II_dimension-1,deal_II_dimension>:: + add_data_vector<VEC> (const DH<deal_II_dimension,deal_II_dimension> &, + const VEC &, + const std::string &, + const std::vector<DataComponentInterpretation::DataComponentInterpretation> &); + + template void + DataOut_DoFData<DH<deal_II_dimension,deal_II_dimension>,deal_II_dimension-1,deal_II_dimension>:: + add_data_vector<VEC> (const DH<deal_II_dimension,deal_II_dimension> &, + const VEC &, + const std::vector<std::string> &, + const std::vector<DataComponentInterpretation::DataComponentInterpretation> &); + + template void + DataOut_DoFData<DH<deal_II_dimension,deal_II_dimension>,deal_II_dimension-1,deal_II_dimension>:: + add_data_vector<VEC> (const DH<deal_II_dimension,deal_II_dimension> &, + const VEC &, + const DataPostprocessor<DH<deal_II_dimension,deal_II_dimension>::space_dimension> &); + + + +// things for DataOutRotation + + template void + DataOut_DoFData<DH<deal_II_dimension,deal_II_dimension>,deal_II_dimension+1,deal_II_dimension+1>:: + add_data_vector<VEC> (const VEC &, + const std::string &, + const DataVectorType, + const std::vector<DataComponentInterpretation::DataComponentInterpretation> &); + + template void + DataOut_DoFData<DH<deal_II_dimension,deal_II_dimension>,deal_II_dimension+1,deal_II_dimension+1>:: + add_data_vector<VEC> (const VEC &, + const std::vector<std::string> &, + const DataVectorType, + const std::vector<DataComponentInterpretation::DataComponentInterpretation> &); + + template void + DataOut_DoFData<DH<deal_II_dimension,deal_II_dimension>,deal_II_dimension+1,deal_II_dimension+1>:: + add_data_vector<VEC> (const VEC &, + const DataPostprocessor<DH<deal_II_dimension,deal_II_dimension>::space_dimension> &); + + template void + DataOut_DoFData<DH<deal_II_dimension,deal_II_dimension>,deal_II_dimension+1,deal_II_dimension+1>:: + add_data_vector<VEC> (const DH<deal_II_dimension,deal_II_dimension> &, + const VEC &, + const std::string &, + const std::vector<DataComponentInterpretation::DataComponentInterpretation> &); + + template void + DataOut_DoFData<DH<deal_II_dimension,deal_II_dimension>,deal_II_dimension+1,deal_II_dimension+1>:: + add_data_vector<VEC> (const DH<deal_II_dimension,deal_II_dimension> &, + const VEC &, + const std::vector<std::string> &, + const std::vector<DataComponentInterpretation::DataComponentInterpretation> &); + + template void + DataOut_DoFData<DH<deal_II_dimension,deal_II_dimension>,deal_II_dimension+1,deal_II_dimension+1>:: + add_data_vector<VEC> (const DH<deal_II_dimension,deal_II_dimension> &, + const VEC &, + const DataPostprocessor<DH<deal_II_dimension,deal_II_dimension>::space_dimension> &); + + + +// codim 1 + + #if deal_II_dimension < 3 + template void + DataOut_DoFData<DH<deal_II_dimension,deal_II_dimension+1>,deal_II_dimension,deal_II_dimension+1>:: + add_data_vector<VEC> (const VEC &, + const std::string &, + const DataVectorType, + const std::vector<DataComponentInterpretation::DataComponentInterpretation> &); + + template void + DataOut_DoFData<DH<deal_II_dimension,deal_II_dimension+1>,deal_II_dimension,deal_II_dimension+1>:: + add_data_vector<VEC> (const VEC &, + const std::vector<std::string> &, + const DataVectorType, + const std::vector<DataComponentInterpretation::DataComponentInterpretation> &); + + template void + DataOut_DoFData<DH<deal_II_dimension,deal_II_dimension+1>,deal_II_dimension,deal_II_dimension+1>:: + add_data_vector<VEC> (const VEC &, + const DataPostprocessor<DH<deal_II_dimension,deal_II_dimension+1>::space_dimension> &); + + template void + DataOut_DoFData<DH<deal_II_dimension,deal_II_dimension+1>,deal_II_dimension,deal_II_dimension+1>:: + add_data_vector<VEC> (const DH<deal_II_dimension,deal_II_dimension+1> &, + const VEC &, + const std::string &, + const std::vector<DataComponentInterpretation::DataComponentInterpretation> &); + + template void + DataOut_DoFData<DH<deal_II_dimension,deal_II_dimension+1>,deal_II_dimension,deal_II_dimension+1>:: + add_data_vector<VEC> (const DH<deal_II_dimension,deal_II_dimension+1> &, + const VEC &, + const std::vector<std::string> &, + const std::vector<DataComponentInterpretation::DataComponentInterpretation> &); + + template void + DataOut_DoFData<DH<deal_II_dimension,deal_II_dimension+1>,deal_II_dimension,deal_II_dimension+1>:: + add_data_vector<VEC> (const DH<deal_II_dimension,deal_II_dimension+1> &, + const VEC &, + const DataPostprocessor<DH<deal_II_dimension,deal_II_dimension+1>::space_dimension> &); + #endif + + + +// codim 2 + + #if deal_II_dimension == 3 + template void + DataOut_DoFData<DH<1,3>,1,3>:: + add_data_vector<VEC> (const VEC &, + const std::string &, + const DataVectorType, + const std::vector<DataComponentInterpretation::DataComponentInterpretation> &); + + template void + DataOut_DoFData<DH<1,3>,1,3>:: + add_data_vector<VEC> (const VEC &, + const std::vector<std::string> &, + const DataVectorType, + const std::vector<DataComponentInterpretation::DataComponentInterpretation> &); + + template void + DataOut_DoFData<DH<1,3>,1,3>:: + add_data_vector<VEC> (const VEC &, + const DataPostprocessor<DH<1,3>::space_dimension> &); + + template void + DataOut_DoFData<DH<1,3>,1,3>:: + add_data_vector<VEC> (const DH<1,3> &, + const VEC &, + const std::string &, + const std::vector<DataComponentInterpretation::DataComponentInterpretation> &); + + template void + DataOut_DoFData<DH<1,3>,1,3>:: + add_data_vector<VEC> (const DH<1,3> &, + const VEC &, + const std::vector<std::string> &, + const std::vector<DataComponentInterpretation::DataComponentInterpretation> &); + + template void + DataOut_DoFData<DH<1,3>,1,3>:: + add_data_vector<VEC> (const DH<1,3> &, + const VEC &, + const DataPostprocessor<DH<1,3>::space_dimension> &); + #endif + +} + + + +for (DH : DOFHANDLER_TEMPLATES; deal_II_dimension : DIMENSIONS) +{ +// codim=0 + + template void + DataOut_DoFData<DH<deal_II_dimension,deal_II_dimension>,deal_II_dimension,deal_II_dimension>:: + add_data_vector<IndexSet> (const IndexSet &, + const std::string &, + const DataVectorType, + const std::vector<DataComponentInterpretation::DataComponentInterpretation> &); + + template void + DataOut_DoFData<DH<deal_II_dimension,deal_II_dimension>,deal_II_dimension,deal_II_dimension>:: + add_data_vector<IndexSet> (const IndexSet &, + const std::vector<std::string> &, + const DataVectorType, + const std::vector<DataComponentInterpretation::DataComponentInterpretation> &); + + template void + DataOut_DoFData<DH<deal_II_dimension,deal_II_dimension>,deal_II_dimension,deal_II_dimension>:: + add_data_vector<IndexSet> (const DH<deal_II_dimension,deal_II_dimension> &, + const IndexSet &, + const std::string &, + const std::vector<DataComponentInterpretation::DataComponentInterpretation> &); + + template void + DataOut_DoFData<DH<deal_II_dimension,deal_II_dimension>,deal_II_dimension,deal_II_dimension>:: + add_data_vector<IndexSet> (const DH<deal_II_dimension,deal_II_dimension> &, + const IndexSet &, + const std::vector<std::string> &, + const std::vector<DataComponentInterpretation::DataComponentInterpretation> &); + + template void + DataOut_DoFData<DH<deal_II_dimension,deal_II_dimension>,deal_II_dimension,deal_II_dimension>:: + add_data_vector<IndexSet> (const IndexSet &, + const DataPostprocessor<DH<deal_II_dimension,deal_II_dimension>::space_dimension> &); + + + +// stuff needed for face data + + template void + DataOut_DoFData<DH<deal_II_dimension,deal_II_dimension>,deal_II_dimension-1,deal_II_dimension>:: + add_data_vector<IndexSet> (const IndexSet &, + const std::string &, + const DataVectorType, + const std::vector<DataComponentInterpretation::DataComponentInterpretation> &); + + template void + DataOut_DoFData<DH<deal_II_dimension,deal_II_dimension>,deal_II_dimension-1,deal_II_dimension>:: + add_data_vector<IndexSet> (const IndexSet &, + const std::vector<std::string> &, + const DataVectorType, + const std::vector<DataComponentInterpretation::DataComponentInterpretation> &); + + template void + DataOut_DoFData<DH<deal_II_dimension,deal_II_dimension>,deal_II_dimension-1,deal_II_dimension>:: + add_data_vector<IndexSet> (const IndexSet &, + const DataPostprocessor<DH<deal_II_dimension,deal_II_dimension>::space_dimension> &); + + + template void + DataOut_DoFData<DH<deal_II_dimension,deal_II_dimension>,deal_II_dimension-1,deal_II_dimension>:: + add_data_vector<IndexSet> (const DH<deal_II_dimension,deal_II_dimension> &, + const IndexSet &, + const std::string &, + const std::vector<DataComponentInterpretation::DataComponentInterpretation> &); + + template void + DataOut_DoFData<DH<deal_II_dimension,deal_II_dimension>,deal_II_dimension-1,deal_II_dimension>:: + add_data_vector<IndexSet> (const DH<deal_II_dimension,deal_II_dimension> &, + const IndexSet &, + const std::vector<std::string> &, + const std::vector<DataComponentInterpretation::DataComponentInterpretation> &); + +// things for DataOutRotation + + template void + DataOut_DoFData<DH<deal_II_dimension,deal_II_dimension>,deal_II_dimension+1,deal_II_dimension+1>:: + add_data_vector<IndexSet> (const IndexSet &, + const std::string &, + const DataVectorType, + const std::vector<DataComponentInterpretation::DataComponentInterpretation> &); + + template void + DataOut_DoFData<DH<deal_II_dimension,deal_II_dimension>,deal_II_dimension+1,deal_II_dimension+1>:: + add_data_vector<IndexSet> (const IndexSet &, + const std::vector<std::string> &, + const DataVectorType, + const std::vector<DataComponentInterpretation::DataComponentInterpretation> &); + + template void + DataOut_DoFData<DH<deal_II_dimension,deal_II_dimension>,deal_II_dimension+1,deal_II_dimension+1>:: + add_data_vector<IndexSet> (const IndexSet &, + const DataPostprocessor<DH<deal_II_dimension,deal_II_dimension>::space_dimension> &); + + + template void + DataOut_DoFData<DH<deal_II_dimension,deal_II_dimension>,deal_II_dimension+1,deal_II_dimension+1>:: + add_data_vector<IndexSet> (const DH<deal_II_dimension,deal_II_dimension> &, + const IndexSet &, + const std::string &, + const std::vector<DataComponentInterpretation::DataComponentInterpretation> &); + + template void + DataOut_DoFData<DH<deal_II_dimension,deal_II_dimension>,deal_II_dimension+1,deal_II_dimension+1>:: + add_data_vector<IndexSet> (const DH<deal_II_dimension,deal_II_dimension> &, + const IndexSet &, + const std::vector<std::string> &, + const std::vector<DataComponentInterpretation::DataComponentInterpretation> &); + +// codim 1 + + #if deal_II_dimension < 3 + template void + DataOut_DoFData<DH<deal_II_dimension,deal_II_dimension+1>,deal_II_dimension,deal_II_dimension+1>:: + add_data_vector<IndexSet> (const IndexSet &, + const std::string &, + const DataVectorType, + const std::vector<DataComponentInterpretation::DataComponentInterpretation> &); + + template void + DataOut_DoFData<DH<deal_II_dimension,deal_II_dimension+1>,deal_II_dimension,deal_II_dimension+1>:: + add_data_vector<IndexSet> (const IndexSet &, + const std::vector<std::string> &, + const DataVectorType, + const std::vector<DataComponentInterpretation::DataComponentInterpretation> &); + + template void + DataOut_DoFData<DH<deal_II_dimension,deal_II_dimension+1>,deal_II_dimension,deal_II_dimension+1>:: + add_data_vector<IndexSet> (const IndexSet &, + const DataPostprocessor<DH<deal_II_dimension,deal_II_dimension+1>::space_dimension> &); + #endif + +} + + + +for (DH : DOFHANDLER_TEMPLATES; deal_II_dimension : DIMENSIONS) +{ + template class DataOut_DoFData<DH<deal_II_dimension>,deal_II_dimension>; + template class DataOut_DoFData<DH<deal_II_dimension>,deal_II_dimension+1>; + + #if deal_II_dimension < 3 + template class DataOut_DoFData<DH<deal_II_dimension>,deal_II_dimension,deal_II_dimension+1>; + template class DataOut_DoFData<DH<deal_II_dimension,deal_II_dimension+1>,deal_II_dimension,deal_II_dimension+1>; + #endif + + #if deal_II_dimension >= 2 + template class DataOut_DoFData<DH<deal_II_dimension>,deal_II_dimension-1,deal_II_dimension>; + #endif + + #if deal_II_dimension == 3 + template class DataOut_DoFData<DH<1>,1,3>; + template class DataOut_DoFData<DH<1,3>,1,3>; + #endif + +} + + +for (deal_II_dimension : DIMENSIONS; deal_II_space_dimension : DIMENSIONS) +{ + namespace internal \{ + namespace DataOut \{ +#if deal_II_dimension <= deal_II_space_dimension + template struct ParallelDataBase<deal_II_dimension,deal_II_space_dimension>; +#endif + \} + \} +} + + +for (DH : DOFHANDLER_TEMPLATES; deal_II_dimension : DIMENSIONS; deal_II_space_dimension : DIMENSIONS) +{ + namespace internal \{ + namespace DataOut \{ +#if deal_II_dimension <= deal_II_space_dimension + template + void + ParallelDataBase<deal_II_dimension,deal_II_space_dimension>:: + reinit_all_fe_values<dealii::DH<deal_II_dimension,deal_II_space_dimension> > + (std::vector<std_cxx1x::shared_ptr<DataEntryBase<dealii::DH<deal_II_dimension,deal_II_space_dimension> > > > &dof_data, + const dealii::Triangulation<deal_II_dimension,deal_II_space_dimension>::cell_iterator &cell, + const unsigned int face); +#endif + \} + \} +} diff --git a/deal.II/source/numerics/error_estimator.cc b/deal.II/source/numerics/error_estimator.cc index 46771ecc59..83e89a9afa 100644 --- a/deal.II/source/numerics/error_estimator.cc +++ b/deal.II/source/numerics/error_estimator.cc @@ -51,24 +51,14 @@ DEAL_II_NAMESPACE_OPEN namespace { - inline - double sqr (const double x) - { - return x*x; - } - - template <typename CellIterator> inline void advance_by_n (CellIterator &cell, const unsigned int n) { - // store a pointer to the end - // iterator, since we can't get at - // it any more once cell is already - // the end iterator (in that case - // dereferencing cell-> triggers an - // assertion) + // store a pointer to the end iterator, since we can't get at it any more + // once cell is already the end iterator (in that case dereferencing + // cell-> triggers an assertion) const CellIterator endc = cell->get_dof_handler().end(); for (unsigned int t=0; ((t<n) && (cell!=endc)); ++t, ++cell) ; @@ -81,60 +71,31 @@ namespace internal namespace { /** - * All small temporary data - * objects that are needed once - * per thread by the several - * functions of the error - * estimator are gathered in this - * struct. The reason for this - * structure is mainly that we - * have a number of functions - * that operate on cells or faces - * and need a number of small - * temporary data objects. Since - * these functions may run in - * parallel, we cannot make these - * objects member variables of - * the enclosing class. On the - * other hand, declaring them - * locally in each of these - * functions would require their - * reallocating every time we - * visit the next cell or face, - * which we found can take a - * significant amount of time if - * it happens often even in the - * single threaded case (10-20 - * per cent in our measurements); - * however, most importantly, - * memory allocation requires - * synchronisation in - * multithreaded mode. While that - * is done by the C++ library and - * has not to be handcoded, it - * nevertheless seriously damages - * the ability to efficiently run - * the functions of this class in - * parallel, since they are quite - * often blocked by these - * synchronisation points, - * slowing everything down by a - * factor of two or three. + * All small temporary data objects that are needed once per thread by the + * several functions of the error estimator are gathered in this + * struct. The reason for this structure is mainly that we have a number + * of functions that operate on cells or faces and need a number of small + * temporary data objects. Since these functions may run in parallel, we + * cannot make these objects member variables of the enclosing class. On + * the other hand, declaring them locally in each of these functions would + * require their reallocating every time we visit the next cell or face, + * which we found can take a significant amount of time if it happens + * often even in the single threaded case (10-20 per cent in our + * measurements); however, most importantly, memory allocation requires + * synchronisation in multithreaded mode. While that is done by the C++ + * library and has not to be handcoded, it nevertheless seriously damages + * the ability to efficiently run the functions of this class in parallel, + * since they are quite often blocked by these synchronisation points, + * slowing everything down by a factor of two or three. * - * Thus, every thread gets an - * instance of this class to work - * with and needs not allocate - * memory itself, or synchronise - * with other threads. + * Thus, every thread gets an instance of this class to work with and + * needs not allocate memory itself, or synchronise with other threads. * - * The sizes of the arrays are - * initialized with the maximal number of - * entries necessary for the hp - * case. Within the loop over individual - * cells, we then resize the arrays as - * necessary. Since for std::vector - * resizing to a smaller size doesn't - * imply memory allocation, this is fast. + * The sizes of the arrays are initialized with the maximal number of + * entries necessary for the hp case. Within the loop over individual + * cells, we then resize the arrays as necessary. Since for std::vector + * resizing to a smaller size doesn't imply memory allocation, this is + * fast. */ template <class DH> struct ParallelData @@ -148,14 +109,12 @@ namespace internal const dealii::hp::FECollection<dim,spacedim> finite_element; /** - * The quadrature formulas to be used for - * the faces. + * The quadrature formulas to be used for the faces. */ const dealii::hp::QCollection<dim-1> face_quadratures; /** - * FEFaceValues objects to integrate over - * the faces of the current and + * FEFaceValues objects to integrate over the faces of the current and * potentially of neighbor cells. */ dealii::hp::FEFaceValues<dim,spacedim> fe_face_values_cell; @@ -163,38 +122,22 @@ namespace internal dealii::hp::FESubfaceValues<dim,spacedim> fe_subface_values; /** - * A vector to store the jump - * of the normal vectors in - * the quadrature points for - * each of the solution - * vectors (i.e. a temporary - * value). This vector is not - * allocated inside the - * functions that use it, but - * rather globally, since - * memory allocation is slow, - * in particular in presence - * of multiple threads where - * synchronisation makes - * things even slower. + * A vector to store the jump of the normal vectors in the quadrature + * points for each of the solution vectors (i.e. a temporary + * value). This vector is not allocated inside the functions that use + * it, but rather globally, since memory allocation is slow, in + * particular in presence of multiple threads where synchronisation + * makes things even slower. */ std::vector<std::vector<std::vector<double> > > phi; /** - * A vector for the gradients of - * the finite element function - * on one cell + * A vector for the gradients of the finite element function on one cell * - * Let psi be a short name - * for <tt>a grad u_h</tt>, where - * the third index be the - * component of the finite - * element, and the second - * index the number of the - * quadrature point. The - * first index denotes the - * index of the solution - * vector. + * Let psi be a short name for <tt>a grad u_h</tt>, where the third + * index be the component of the finite element, and the second index + * the number of the quadrature point. The first index denotes the index + * of the solution vector. */ std::vector<std::vector<std::vector<Tensor<1,spacedim> > > > psi; @@ -204,43 +147,35 @@ namespace internal std::vector<std::vector<std::vector<Tensor<1,spacedim> > > > neighbor_psi; /** - * The normal vectors of the finite - * element function on one face + * The normal vectors of the finite element function on one face */ std::vector<Point<spacedim> > normal_vectors; /** - * Two arrays needed for the - * values of coefficients in - * the jumps, if they are - * given. + * Two arrays needed for the values of coefficients in the jumps, if + * they are given. */ std::vector<double> coefficient_values1; std::vector<dealii::Vector<double> > coefficient_values; /** - * Array for the products of - * Jacobian determinants and - * weights of quadraturs - * points. + * Array for the products of Jacobian determinants and weights of + * quadraturs points. */ std::vector<double> JxW_values; /** - * The subdomain id we are to care - * for. + * The subdomain id we are to care for. */ const types::subdomain_id subdomain_id; /** - * The material id we are to care - * for. + * The material id we are to care for. */ const types::material_id material_id; /** - * Some more references to input data to - * the KellyErrorEstimator::estimate() - * function. + * Some more references to input data to the + * KellyErrorEstimator::estimate() function. */ const typename FunctionMap<spacedim>::type *neumann_bc; const ComponentMask component_mask; @@ -262,10 +197,9 @@ namespace internal const Function<spacedim> *coefficients); /** - * Resize the arrays so that they fit the - * number of quadrature points associated - * with the given finite element index - * into the hp collections. + * Resize the arrays so that they fit the number of quadrature points + * associated with the given finite element index into the hp + * collections. */ void resize (const unsigned int active_fe_index); }; @@ -363,11 +297,9 @@ namespace internal /** - * Copy data from the - * local_face_integrals map of a single - * ParallelData object into a global such - * map. This is the copier stage of a - * WorkStream pipeline. + * Copy data from the local_face_integrals map of a single ParallelData + * object into a global such map. This is the copier stage of a WorkStream + * pipeline. */ template <class DH> void @@ -375,16 +307,14 @@ namespace internal std::map<typename DH::face_iterator,std::vector<double> > &face_integrals) { - // now copy locally computed elements - // into the global map + // now copy locally computed elements into the global map for (typename std::map<typename DH::face_iterator,std::vector<double> >::const_iterator p=local_face_integrals.begin(); p!=local_face_integrals.end(); ++p) { - // double check that the - // element does not already - // exists in the global map + // double check that the element does not already exists in the + // global map Assert (face_integrals.find (p->first) == face_integrals.end(), ExcInternalError()); @@ -400,105 +330,38 @@ namespace internal /** - * Actually do the computation on - * a face which has no hanging - * nodes (it is regular), i.e. - * either on the other side there - * is nirvana (face is at - * boundary), or the other side's - * refinement level is the same - * as that of this side, then - * handle the integration of - * these both cases together. + * Actually do the computation based on the evaluated gradients in + * ParallelData. */ - template <typename InputVector, class DH> - void - integrate_over_regular_face (const std::vector<const InputVector *> &solutions, - ParallelData<DH> ¶llel_data, - std::map<typename DH::face_iterator,std::vector<double> > &local_face_integrals, - const typename DH::active_cell_iterator &cell, - const unsigned int face_no, - dealii::hp::FEFaceValues<DH::dimension, DH::space_dimension> &fe_face_values_cell, - dealii::hp::FEFaceValues<DH::dimension, DH::space_dimension> &fe_face_values_neighbor) + template <class DH> + std::vector<double> + integrate_over_face (ParallelData<DH> ¶llel_data, + const typename DH::face_iterator &face, + dealii::hp::FEFaceValues<DH::dimension, DH::space_dimension> &fe_face_values_cell) { - const unsigned int dim = DH::dimension; - - const typename DH::face_iterator face = cell->face(face_no); - const unsigned int n_q_points = parallel_data.face_quadratures[cell->active_fe_index()].size(), + const unsigned int n_q_points = parallel_data.psi[0].size(), n_components = parallel_data.finite_element.n_components(), - n_solution_vectors = solutions.size(); - - - // initialize data of the restriction - // of this cell to the present face - fe_face_values_cell.reinit (cell, face_no, - cell->active_fe_index()); + n_solution_vectors = parallel_data.psi.size(); - // get gradients of the finite element - // function on this cell - for (unsigned int n=0; n<n_solution_vectors; ++n) - fe_face_values_cell.get_present_fe_values() - .get_function_gradients (*solutions[n], parallel_data.psi[n]); - - // now compute over the other side of - // the face if (face->at_boundary() == false) - // internal face; integrate jump - // of gradient across this face { - Assert (cell->neighbor(face_no).state() == IteratorState::valid, - ExcInternalError()); - - const typename DH::active_cell_iterator neighbor = cell->neighbor(face_no); - - // find which number the - // current face has relative to - // the neighboring cell - const unsigned int neighbor_neighbor - = cell->neighbor_of_neighbor (face_no); - Assert (neighbor_neighbor<GeometryInfo<dim>::faces_per_cell, - ExcInternalError()); - - // get restriction of finite element - // function of @p{neighbor} to the - // common face. in the hp case, use the - // quadrature formula that matches the - // one we would use for the present - // cell - fe_face_values_neighbor.reinit (neighbor, neighbor_neighbor, - cell->active_fe_index()); - - // get gradients on neighbor cell + // compute the jump in the gradients for (unsigned int n=0; n<n_solution_vectors; ++n) - { - fe_face_values_neighbor.get_present_fe_values() - .get_function_gradients (*solutions[n], - parallel_data.neighbor_psi[n]); - - // compute the jump in the gradients - for (unsigned int component=0; component<n_components; ++component) - for (unsigned int p=0; p<n_q_points; ++p) - parallel_data.psi[n][p][component] -= parallel_data.neighbor_psi[n][p][component]; - } + for (unsigned int component=0; component<n_components; ++component) + for (unsigned int p=0; p<n_q_points; ++p) + parallel_data.psi[n][p][component] -= parallel_data.neighbor_psi[n][p][component]; } - // now psi contains the following: // - for an internal face, psi=[grad u] - // - for a neumann boundary face, - // psi=grad u - // each component being the - // mentioned value at one of the - // quadrature points - - // next we have to multiply this with - // the normal vector. Since we have - // taken the difference of gradients - // for internal faces, we may chose - // the normal vector of one cell, - // taking that of the neighbor - // would only change the sign. We take - // the outward normal. + // - for a neumann boundary face, psi=grad u + // each component being the mentioned value at one of the quadrature + // points + + // next we have to multiply this with the normal vector. Since we have + // taken the difference of gradients for internal faces, we may chose + // the normal vector of one cell, taking that of the neighbor would only + // change the sign. We take the outward normal. parallel_data.normal_vectors = fe_face_values_cell.get_present_fe_values().get_normal_vectors(); @@ -510,14 +373,13 @@ namespace internal = (parallel_data.psi[n][point][component] * parallel_data.normal_vectors[point]); - // if a coefficient was given: use that - // to scale the jump in the gradient + // if a coefficient was given: use that to scale the jump in the + // gradient if (parallel_data.coefficients != 0) { // scalar coefficient if (parallel_data.coefficients->n_components == 1) { - parallel_data.coefficients ->value_list (fe_face_values_cell.get_present_fe_values() .get_quadrature_points(), @@ -545,18 +407,15 @@ namespace internal if (face->at_boundary() == true) - // neumann boundary face. compute - // difference between normal - // derivative and boundary function + // neumann boundary face. compute difference between normal derivative + // and boundary function { const types::boundary_id boundary_indicator = face->boundary_indicator(); Assert (parallel_data.neumann_bc->find(boundary_indicator) != parallel_data.neumann_bc->end(), ExcInternalError ()); - // get the values of the boundary - // function at the quadrature - // points + // get the values of the boundary function at the quadrature points if (n_components == 1) { std::vector<double> g(n_q_points); @@ -587,26 +446,94 @@ namespace internal // now phi contains the following: // - for an internal face, phi=[a du/dn] - // - for a neumann boundary face, - // phi=a du/dn-g - // each component being the - // mentioned value at one of the - // quadrature points + // - for a neumann boundary face, phi=a du/dn-g + // each component being the mentioned value at one of the quadrature + // points parallel_data.JxW_values = fe_face_values_cell.get_present_fe_values().get_JxW_values(); - // take the square of the phi[i] - // for integration, and sum up + // take the square of the phi[i] for integration, and sum up std::vector<double> face_integral (n_solution_vectors, 0); for (unsigned int n=0; n<n_solution_vectors; ++n) for (unsigned int component=0; component<n_components; ++component) if (parallel_data.component_mask[component] == true) for (unsigned int p=0; p<n_q_points; ++p) - face_integral[n] += dealii::sqr(parallel_data.phi[n][p][component]) * + face_integral[n] += Utilities::fixed_power<2>(parallel_data.phi[n][p][component]) * parallel_data.JxW_values[p]; - local_face_integrals[face] = face_integral; + return face_integral; + } + + + + /** + * Actually do the computation on a face which has no hanging nodes (it is + * regular), i.e. either on the other side there is nirvana (face is at + * boundary), or the other side's refinement level is the same as that of + * this side, then handle the integration of these both cases together. + */ + template <typename InputVector, class DH> + void + integrate_over_regular_face (const std::vector<const InputVector *> &solutions, + ParallelData<DH> ¶llel_data, + std::map<typename DH::face_iterator,std::vector<double> > &local_face_integrals, + const typename DH::active_cell_iterator &cell, + const unsigned int face_no, + dealii::hp::FEFaceValues<DH::dimension, DH::space_dimension> &fe_face_values_cell, + dealii::hp::FEFaceValues<DH::dimension, DH::space_dimension> &fe_face_values_neighbor) + { + const unsigned int dim = DH::dimension; + + const typename DH::face_iterator face = cell->face(face_no); + const unsigned int n_solution_vectors = solutions.size(); + + + // initialize data of the restriction + // of this cell to the present face + fe_face_values_cell.reinit (cell, face_no, + cell->active_fe_index()); + + // get gradients of the finite element + // function on this cell + for (unsigned int n=0; n<n_solution_vectors; ++n) + fe_face_values_cell.get_present_fe_values() + .get_function_gradients (*solutions[n], parallel_data.psi[n]); + + // now compute over the other side of the face + if (face->at_boundary() == false) + // internal face; integrate jump of gradient across this face + { + Assert (cell->neighbor(face_no).state() == IteratorState::valid, + ExcInternalError()); + + const typename DH::active_cell_iterator neighbor = cell->neighbor(face_no); + + // find which number the current face has relative to the + // neighboring cell + const unsigned int neighbor_neighbor + = cell->neighbor_of_neighbor (face_no); + Assert (neighbor_neighbor<GeometryInfo<dim>::faces_per_cell, + ExcInternalError()); + + // get restriction of finite element function of @p{neighbor} to the + // common face. in the hp case, use the quadrature formula that + // matches the one we would use for the present cell + fe_face_values_neighbor.reinit (neighbor, neighbor_neighbor, + cell->active_fe_index()); + + // get gradients on neighbor cell + for (unsigned int n=0; n<n_solution_vectors; ++n) + { + fe_face_values_neighbor.get_present_fe_values() + .get_function_gradients (*solutions[n], + parallel_data.neighbor_psi[n]); + } + } + + // now go to the generic function that does all the other things + local_face_integrals[face] = + integrate_over_face (parallel_data, face, fe_face_values_cell); } @@ -624,8 +551,8 @@ namespace internal */ template <typename InputVector, class DH> void - integrate_over_irregular_face (const std::vector<const InputVector *> &solutions, - ParallelData<DH> ¶llel_data, + integrate_over_irregular_face (const std::vector<const InputVector *> &solutions, + ParallelData<DH> ¶llel_data, std::map<typename DH::face_iterator,std::vector<double> > &local_face_integrals, const typename DH::active_cell_iterator &cell, const unsigned int face_no, @@ -635,28 +562,21 @@ namespace internal const unsigned int dim = DH::dimension; const typename DH::cell_iterator neighbor = cell->neighbor(face_no); - const unsigned int n_q_points = parallel_data.face_quadratures[cell->active_fe_index()].size(), - n_components = parallel_data.finite_element.n_components(), - n_solution_vectors = solutions.size(); + const unsigned int n_solution_vectors = solutions.size(); const typename DH::face_iterator face=cell->face(face_no); Assert (neighbor.state() == IteratorState::valid, ExcInternalError()); Assert (face->has_children(), ExcInternalError()); - // set up a vector of the gradients - // of the finite element function - // on this cell at the quadrature - // points + + // set up a vector of the gradients of the finite element function on + // this cell at the quadrature points // - // let psi be a short name for - // [a grad u_h], where the second - // index be the component of the - // finite element, and the first - // index the number of the - // quadrature point - - // store which number @p{cell} has - // in the list of neighbors of + // let psi be a short name for [a grad u_h], where the second index be + // the component of the finite element, and the first index the number + // of the quadrature point + + // store which number @p{cell} has in the list of neighbors of // @p{neighbor} const unsigned int neighbor_neighbor = cell->neighbor_of_neighbor (face_no); @@ -666,138 +586,38 @@ namespace internal // loop over all subfaces for (unsigned int subface_no=0; subface_no<face->n_children(); ++subface_no) { - // get an iterator pointing to the - // cell behind the present subface + // get an iterator pointing to the cell behind the present subface const typename DH::active_cell_iterator neighbor_child = cell->neighbor_child_on_subface (face_no, subface_no); Assert (!neighbor_child->has_children(), ExcInternalError()); - // restrict the finite element - // on the present cell to the - // subface + // restrict the finite element on the present cell to the subface fe_subface_values.reinit (cell, face_no, subface_no, cell->active_fe_index()); - // restrict the finite element - // on the neighbor cell to the - // common @p{subface}. + // restrict the finite element on the neighbor cell to the common + // @p{subface}. fe_face_values.reinit (neighbor_child, neighbor_neighbor, cell->active_fe_index()); - // store the gradient of the - // solution in psi + // store the gradient of the solution in psi for (unsigned int n=0; n<n_solution_vectors; ++n) fe_subface_values.get_present_fe_values() .get_function_gradients (*solutions[n], parallel_data.psi[n]); - // store the gradient from the - // neighbor's side in - // @p{neighbor_psi} + // store the gradient from the neighbor's side in @p{neighbor_psi} for (unsigned int n=0; n<n_solution_vectors; ++n) fe_face_values.get_present_fe_values() .get_function_gradients (*solutions[n], parallel_data.neighbor_psi[n]); - // compute the jump in the gradients - for (unsigned int n=0; n<n_solution_vectors; ++n) - for (unsigned int component=0; component<n_components; ++component) - for (unsigned int p=0; p<n_q_points; ++p) - parallel_data.psi[n][p][component] -= - parallel_data.neighbor_psi[n][p][component]; - - // note that unlike for the - // case of regular faces - // (treated in the other - // function of this class), we - // have not to take care of - // boundary faces here, since - // they always are regular. - - // next we have to multiply this with - // the normal vector. Since we have - // taken the difference of gradients - // for internal faces, we may chose - // the normal vector of one cell, - // taking that of the neighbor - // would only change the sign. We take - // the outward normal. - // - // let phi be the name of the integrand - - parallel_data.normal_vectors - = fe_face_values.get_present_fe_values().get_normal_vectors(); - - - for (unsigned int n=0; n<n_solution_vectors; ++n) - for (unsigned int component=0; component<n_components; ++component) - for (unsigned int point=0; point<n_q_points; ++point) - parallel_data.phi[n][point][component] = (parallel_data.psi[n][point][component]* - parallel_data.normal_vectors[point]); - - // if a coefficient was given: use that - // to scale the jump in the gradient - if (parallel_data.coefficients != 0) - { - // scalar coefficient - if (parallel_data.coefficients->n_components == 1) - { - parallel_data.coefficients - ->value_list (fe_face_values.get_present_fe_values() - .get_quadrature_points(), - parallel_data.coefficient_values1); - for (unsigned int n=0; n<n_solution_vectors; ++n) - for (unsigned int component=0; component<n_components; ++component) - for (unsigned int point=0; point<n_q_points; ++point) - parallel_data.phi[n][point][component] *= - parallel_data.coefficient_values1[point]; - } - else - // vector-valued coefficient - { - parallel_data.coefficients - ->vector_value_list (fe_face_values.get_present_fe_values() - .get_quadrature_points(), - parallel_data.coefficient_values); - for (unsigned int n=0; n<n_solution_vectors; ++n) - for (unsigned int component=0; component<n_components; ++component) - for (unsigned int point=0; point<n_q_points; ++point) - parallel_data.phi[n][point][component] *= - parallel_data.coefficient_values[point](component); - } - } - - // get the weights for the - // integration. note that it - // does not matter whether we - // take the JxW values from the - // fe_face_values or the - // fe_subface_values, as the - // first is on the small - // neighbor cell, while the - // latter is on the refined - // face of the big cell here - parallel_data.JxW_values - = fe_face_values.get_present_fe_values().get_JxW_values(); - - // take the square of the phi[i] - // for integration, and sum up - std::vector<double> face_integral (n_solution_vectors, 0); - for (unsigned int n=0; n<n_solution_vectors; ++n) - for (unsigned int component=0; component<n_components; ++component) - if (parallel_data.component_mask[component] == true) - for (unsigned int p=0; p<n_q_points; ++p) - face_integral[n] += dealii::sqr(parallel_data.phi[n][p][component]) * - parallel_data.JxW_values[p]; - - local_face_integrals[neighbor_child->face(neighbor_neighbor)] - = face_integral; + // call generic evaluate function + local_face_integrals[neighbor_child->face(neighbor_neighbor)] = + integrate_over_face (parallel_data, face, fe_face_values); } - - // finally loop over all subfaces to - // collect the contributions of the - // subfaces and store them with the - // mother face + // finally loop over all subfaces to collect the contributions of the + // subfaces and store them with the mother face std::vector<double> sum (n_solution_vectors, 0); for (unsigned int subface_no=0; subface_no<face->n_children(); ++subface_no) { @@ -816,29 +636,25 @@ namespace internal /** - * Computate the error on the faces of a - * single cell. + * Computate the error on the faces of a single cell. * - * This function is only needed - * in two or three dimensions. - * The error estimator in one - * dimension is implemented - * seperatly. + * This function is only needed in two or three dimensions. The error + * estimator in one dimension is implemented separately. */ - template <int dim, int spacedim, typename InputVector, class DH> + template <typename InputVector, class DH> void estimate_one_cell (const typename DH::active_cell_iterator &cell, ParallelData<DH> ¶llel_data, std::map<typename DH::face_iterator,std::vector<double> > &local_face_integrals, const std::vector<const InputVector *> &solutions) { + const unsigned int dim = DH::dimension; const unsigned int n_solution_vectors = solutions.size(); const types::subdomain_id subdomain_id = parallel_data.subdomain_id; const unsigned int material_id = parallel_data.material_id; - // empty our own copy of the local face - // integrals + // empty our own copy of the local face integrals local_face_integrals.clear(); // loop over all faces of this cell @@ -848,20 +664,11 @@ namespace internal const typename DH::face_iterator face=cell->face(face_no); - // make sure we do work - // only once: this face - // may either be regular - // or irregular. if it is - // regular and has a - // neighbor, then we - // visit the face twice, - // once from every - // side. let the one with - // the lower index do the - // work. if it is at the - // boundary, or if the - // face is irregular, - // then do the work below + // make sure we do work only once: this face may either be regular + // or irregular. if it is regular and has a neighbor, then we visit + // the face twice, once from every side. let the one with the lower + // index do the work. if it is at the boundary, or if the face is + // irregular, then do the work below if ((face->has_children() == false) && !cell->at_boundary(face_no) && (!cell->neighbor_is_coarser(face_no) && @@ -870,24 +677,17 @@ namespace internal cell->neighbor(face_no)->level() < cell->level())))) continue; - // if the neighboring cell is less - // refined than the present one, - // then do nothing since we - // integrate over the subfaces when - // we visit the coarse cells. + // if the neighboring cell is less refined than the present one, + // then do nothing since we integrate over the subfaces when we + // visit the coarse cells. if (face->at_boundary() == false) if (cell->neighbor_is_coarser(face_no)) continue; - // if this face is part of the - // boundary but not of the neumann - // boundary -> nothing to - // do. However, to make things - // easier when summing up the - // contributions of the faces of - // cells, we enter this face into - // the list of faces with - // contribution zero. + // if this face is part of the boundary but not of the neumann + // boundary -> nothing to do. However, to make things easier when + // summing up the contributions of the faces of cells, we enter this + // face into the list of faces with contribution zero. if (face->at_boundary() && (parallel_data.neumann_bc->find(face->boundary_indicator()) == @@ -898,12 +698,9 @@ namespace internal continue; } - // finally: note that we only have - // to do something if either the - // present cell is on the subdomain - // we care for (and the same for - // material_id), or if one of the - // neighbors behind the face is on + // finally: note that we only have to do something if either the + // present cell is on the subdomain we care for (and the same for + // material_id), or if one of the neighbors behind the face is on // the subdomain we care for if ( ! ( ((subdomain_id == numbers::invalid_subdomain_id) || @@ -913,11 +710,8 @@ namespace internal || (cell->material_id() == material_id))) ) { - // ok, cell is unwanted, but - // maybe its neighbor behind - // the face we presently work - // on? oh is there a face at - // all? + // ok, cell is unwanted, but maybe its neighbor behind the face + // we presently work on? oh is there a face at all? if (face->at_boundary()) continue; @@ -950,32 +744,24 @@ namespace internal } } - // so if none of the neighbors - // cares for this subdomain or - // material either, then try - // next face + // so if none of the neighbors cares for this subdomain or + // material either, then try next face if (care_for_cell == false) continue; } - // so now we know that we care for - // this face, let's do something - // about it. first re-size the - // arrays we may use to the correct + // so now we know that we care for this face, let's do something + // about it. first re-size the arrays we may use to the correct // size: parallel_data.resize (cell->active_fe_index()); // then do the actual integration if (face->has_children() == false) - // if the face is a regular one, - // i.e. either on the other side - // there is nirvana (face is at - // boundary), or the other side's - // refinement level is the same - // as that of this side, then - // handle the integration of - // these both cases together + // if the face is a regular one, i.e. either on the other side + // there is nirvana (face is at boundary), or the other side's + // refinement level is the same as that of this side, then handle + // the integration of these both cases together integrate_over_regular_face (solutions, parallel_data, local_face_integrals, @@ -984,10 +770,8 @@ namespace internal parallel_data.fe_face_values_neighbor); else - // otherwise we need to do some - // special computations which do - // not fit into the framework of - // the above function + // otherwise we need to do some special computations which do not + // fit into the framework of the above function integrate_over_irregular_face (solutions, parallel_data, local_face_integrals, @@ -1003,418 +787,6 @@ namespace internal - - -template <int spacedim> -template <typename InputVector, class DH> -void -KellyErrorEstimator<1,spacedim>:: -estimate (const Mapping<1,spacedim> &mapping, - const DH &dof_handler, - const Quadrature<0> &quadrature, - const typename FunctionMap<spacedim>::type &neumann_bc, - const InputVector &solution, - Vector<float> &error, - const ComponentMask &component_mask, - const Function<spacedim> *coefficients, - const unsigned int n_threads, - const types::subdomain_id subdomain_id, - const types::material_id material_id) -{ - // just pass on to the other function - const std::vector<const InputVector *> solutions (1, &solution); - std::vector<Vector<float>*> errors (1, &error); - estimate (mapping, dof_handler, quadrature, neumann_bc, solutions, errors, - component_mask, coefficients, n_threads, subdomain_id, material_id); -} - - - -template <int spacedim> -template <typename InputVector, class DH> -void -KellyErrorEstimator<1,spacedim>:: -estimate (const DH &dof_handler, - const Quadrature<0> &quadrature, - const typename FunctionMap<spacedim>::type &neumann_bc, - const InputVector &solution, - Vector<float> &error, - const ComponentMask &component_mask, - const Function<spacedim> *coefficients, - const unsigned int n_threads, - const types::subdomain_id subdomain_id, - const types::material_id material_id) -{ - estimate(StaticMappingQ1<1,spacedim>::mapping, dof_handler, quadrature, neumann_bc, solution, - error, component_mask, coefficients, n_threads, subdomain_id, material_id); -} - - - -template <int spacedim> -template <typename InputVector, class DH> -void -KellyErrorEstimator<1,spacedim>:: -estimate (const DH &dof_handler, - const Quadrature<0> &quadrature, - const typename FunctionMap<spacedim>::type &neumann_bc, - const std::vector<const InputVector *> &solutions, - std::vector<Vector<float>*> &errors, - const ComponentMask &component_mask, - const Function<spacedim> *coefficients, - const unsigned int n_threads, - const types::subdomain_id subdomain_id, - const types::material_id material_id) -{ - estimate(StaticMappingQ1<1,spacedim>::mapping, dof_handler, quadrature, neumann_bc, solutions, - errors, component_mask, coefficients, n_threads, subdomain_id, material_id); -} - - - -template <int spacedim> -template <typename InputVector, class DH> -void -KellyErrorEstimator<1,spacedim>:: -estimate (const Mapping<1,spacedim> &mapping, - const DH &dof_handler, - const hp::QCollection<0> &quadrature, - const typename FunctionMap<spacedim>::type &neumann_bc, - const InputVector &solution, - Vector<float> &error, - const ComponentMask &component_mask, - const Function<spacedim> *coefficients, - const unsigned int n_threads, - const types::subdomain_id subdomain_id, - const types::material_id material_id) -{ - // just pass on to the other function - const std::vector<const InputVector *> solutions (1, &solution); - std::vector<Vector<float>*> errors (1, &error); - estimate (mapping, dof_handler, quadrature, neumann_bc, solutions, errors, - component_mask, coefficients, n_threads, subdomain_id, material_id); -} - - -template <int spacedim> -template <typename InputVector, class DH> -void -KellyErrorEstimator<1,spacedim>:: -estimate (const DH &dof_handler, - const hp::QCollection<0> &quadrature, - const typename FunctionMap<spacedim>::type &neumann_bc, - const InputVector &solution, - Vector<float> &error, - const ComponentMask &component_mask, - const Function<spacedim> *coefficients, - const unsigned int n_threads, - const types::subdomain_id subdomain_id, - const types::material_id material_id) -{ - estimate(StaticMappingQ1<1,spacedim>::mapping, dof_handler, quadrature, neumann_bc, solution, - error, component_mask, coefficients, n_threads, subdomain_id, material_id); -} - - - -template <int spacedim> -template <typename InputVector, class DH> -void -KellyErrorEstimator<1,spacedim>:: -estimate (const DH &dof_handler, - const hp::QCollection<0> &quadrature, - const typename FunctionMap<spacedim>::type &neumann_bc, - const std::vector<const InputVector *> &solutions, - std::vector<Vector<float>*> &errors, - const ComponentMask &component_mask, - const Function<spacedim> *coefficients, - const unsigned int n_threads, - const types::subdomain_id subdomain_id, - const types::material_id material_id) -{ - estimate(StaticMappingQ1<1,spacedim>::mapping, dof_handler, quadrature, neumann_bc, solutions, - errors, component_mask, coefficients, n_threads, subdomain_id, material_id); -} - - - - -template <int spacedim> -template <typename InputVector, class DH> -void KellyErrorEstimator<1,spacedim>:: -estimate (const Mapping<1,spacedim> &/*mapping*/, - const DH &/*dof_handler*/, - const hp::QCollection<0> &, - const typename FunctionMap<spacedim>::type &/*neumann_bc*/, - const std::vector<const InputVector *> &/*solutions*/, - std::vector<Vector<float>*> &/*errors*/, - const ComponentMask &/*component_mask_*/, - const Function<spacedim> */*coefficient*/, - const unsigned int, - const types::subdomain_id /*subdomain_id*/, - const types::material_id /*material_id*/) -{ - Assert (false, ExcInternalError()); -} - - - -template <int spacedim> -template <typename InputVector, class DH> -void KellyErrorEstimator<1,spacedim>:: -estimate (const Mapping<1,spacedim> &mapping, - const DH &dof_handler, - const Quadrature<0> &, - const typename FunctionMap<spacedim>::type &neumann_bc, - const std::vector<const InputVector *> &solutions, - std::vector<Vector<float>*> &errors, - const ComponentMask &component_mask, - const Function<spacedim> *coefficient, - const unsigned int, - const types::subdomain_id subdomain_id_, - const types::material_id material_id) -{ -#ifdef DEAL_II_WITH_P4EST - if (dynamic_cast<const parallel::distributed::Triangulation<1,spacedim>*> - (&dof_handler.get_tria()) - != 0) - Assert ((subdomain_id_ == numbers::invalid_subdomain_id) - || - (subdomain_id_ == - dynamic_cast<const parallel::distributed::Triangulation<1,spacedim>&> - (dof_handler.get_tria()).locally_owned_subdomain()), - ExcMessage ("For parallel distributed triangulations, the only " - "valid subdomain_id that can be passed here is the " - "one that corresponds to the locally owned subdomain id.")); - - const types::subdomain_id subdomain_id - = ((dynamic_cast<const parallel::distributed::Triangulation<1,spacedim>*> - (&dof_handler.get_tria()) - != 0) - ? - dynamic_cast<const parallel::distributed::Triangulation<1,spacedim>&> - (dof_handler.get_tria()).locally_owned_subdomain() - : - subdomain_id_); -#else - const types::subdomain_id subdomain_id - = subdomain_id_; -#endif - - const unsigned int n_components = dof_handler.get_fe().n_components(); - const unsigned int n_solution_vectors = solutions.size(); - - // sanity checks - Assert (neumann_bc.find(numbers::internal_face_boundary_id) == neumann_bc.end(), - ExcInvalidBoundaryIndicator()); - - for (typename FunctionMap<spacedim>::type::const_iterator i=neumann_bc.begin(); - i!=neumann_bc.end(); ++i) - Assert (i->second->n_components == n_components, ExcInvalidBoundaryFunction()); - - Assert (component_mask.represents_n_components(n_components), - ExcInvalidComponentMask()); - Assert (component_mask.n_selected_components(n_components) > 0, - ExcInvalidComponentMask()); - - Assert ((coefficient == 0) || - (coefficient->n_components == n_components) || - (coefficient->n_components == 1), - ExcInvalidCoefficient()); - - Assert (solutions.size() > 0, - ExcNoSolutions()); - Assert (solutions.size() == errors.size(), - ExcIncompatibleNumberOfElements(solutions.size(), errors.size())); - for (unsigned int n=0; n<solutions.size(); ++n) - Assert (solutions[n]->size() == dof_handler.n_dofs(), - ExcInvalidSolutionVector()); - - Assert ((coefficient == 0) || - (coefficient->n_components == n_components) || - (coefficient->n_components == 1), - ExcInvalidCoefficient()); - - for (typename FunctionMap<spacedim>::type::const_iterator i=neumann_bc.begin(); - i!=neumann_bc.end(); ++i) - Assert (i->second->n_components == n_components, - ExcInvalidBoundaryFunction()); - - // reserve one slot for each cell and set - // it to zero - for (unsigned int n=0; n<n_solution_vectors; ++n) - (*errors[n]).reinit (dof_handler.get_tria().n_active_cells()); - - // fields to get the gradients on - // the present and the neighbor cell. - // - // for the neighbor gradient, we - // need several auxiliary fields, - // depending on the way we get it - // (see below) - std::vector<std::vector<std::vector<Tensor<1,spacedim> > > > - gradients_here (n_solution_vectors, - std::vector<std::vector<Tensor<1,spacedim> > >(2, std::vector<Tensor<1,spacedim> >(n_components))); - std::vector<std::vector<std::vector<Tensor<1,spacedim> > > > - gradients_neighbor (gradients_here); - std::vector<Vector<double> > - grad_neighbor (n_solution_vectors, Vector<double>(n_components)); - - // reserve some space for - // coefficient values at one point. - // if there is no coefficient, then - // we fill it by unity once and for - // all and don't set it any more - Vector<double> coefficient_values (n_components); - if (coefficient == 0) - for (unsigned int c=0; c<n_components; ++c) - coefficient_values(c) = 1; - - const QTrapez<1> quadrature; - const hp::QCollection<1> q_collection(quadrature); - - const hp::FECollection<1,spacedim> fe (dof_handler.get_fe()); - - hp::MappingCollection<1,spacedim> mapping_collection; - mapping_collection.push_back (mapping); - - hp::FEValues<1,spacedim> fe_values (mapping_collection, fe, q_collection, - update_gradients); - - // loop over all cells and do something on - // the cells which we're told to work - // on. note that the error indicator is - // only a sum over the two contributions - // from the two vertices of each cell. - typename DH::active_cell_iterator cell = dof_handler.begin_active(); - for (unsigned int cell_index=0; cell != dof_handler.end(); - ++cell, ++cell_index) - if (((subdomain_id == numbers::invalid_subdomain_id) - || - (cell->subdomain_id() == subdomain_id)) - && - ((material_id == numbers::invalid_material_id) - || - (cell->material_id() == material_id))) - { - for (unsigned int n=0; n<n_solution_vectors; ++n) - (*errors[n])(cell_index) = 0; - - // loop over the two points bounding - // this line. n==0 is left point, - // n==1 is right point - for (unsigned int n=0; n<2; ++n) - { - // find left or right active - // neighbor - typename DH::cell_iterator neighbor = cell->neighbor(n); - if (neighbor.state() == IteratorState::valid) - while (neighbor->has_children()) - neighbor = neighbor->child(n==0 ? 1 : 0); - - // now get the gradients on the - // both sides of the point - fe_values.reinit (cell); - - for (unsigned int s=0; s<n_solution_vectors; ++s) - fe_values.get_present_fe_values() - .get_function_gradients (*solutions[s], gradients_here[s]); - - if (neighbor.state() == IteratorState::valid) - { - fe_values.reinit (neighbor); - - for (unsigned int s=0; s<n_solution_vectors; ++s) - fe_values.get_present_fe_values() - .get_function_gradients (*solutions[s], - gradients_neighbor[s]); - - // extract the - // gradients of all the - // components. [0] - // means: x-derivative, - // which is the only - // one here - for (unsigned int s=0; s<n_solution_vectors; ++s) - for (unsigned int c=0; c<n_components; ++c) - grad_neighbor[s](c) - = gradients_neighbor[s][n==0 ? 1 : 0][c][0]; - } - else if (neumann_bc.find(n) != neumann_bc.end()) - // if Neumann b.c., then fill - // the gradients field which - // will be used later on. - { - if (n_components==1) - { - const double - v = neumann_bc.find(n)->second->value(cell->vertex(0)); - - for (unsigned int s=0; s<n_solution_vectors; ++s) - grad_neighbor[s](0) = v; - } - else - { - Vector<double> v(n_components); - neumann_bc.find(n)->second->vector_value(cell->vertex(0), v); - - for (unsigned int s=0; s<n_solution_vectors; ++s) - grad_neighbor[s] = v; - } - } - else - // fill with zeroes. - for (unsigned int s=0; s<n_solution_vectors; ++s) - grad_neighbor[s] = 0; - - // if there is a - // coefficient, then - // evaluate it at the - // present position. if - // there is none, reuse the - // preset values. - if (coefficient != 0) - { - if (coefficient->n_components == 1) - { - const double c_value = coefficient->value (cell->vertex(n)); - for (unsigned int c=0; c<n_components; ++c) - coefficient_values(c) = c_value; - } - else - coefficient->vector_value(cell->vertex(n), - coefficient_values); - } - - - for (unsigned int s=0; s<n_solution_vectors; ++s) - for (unsigned int component=0; component<n_components; ++component) - if (component_mask[component] == true) - { - // get gradient - // here. [0] means - // x-derivative - // (there is no - // other component - // in 1d) - const double grad_here = gradients_here[s][n][component][0]; - - const double jump = ((grad_here - grad_neighbor[s](component)) * - coefficient_values(component)); - (*errors[s])(cell_index) += jump*jump * cell->diameter(); - } - } - - for (unsigned int s=0; s<n_solution_vectors; ++s) - (*errors[s])(cell_index) = std::sqrt((*errors[s])(cell_index)); - } -} - - - - - - // the following function is still independent of dimension, but it // calls dimension dependent functions template <int dim, int spacedim> @@ -1581,20 +953,14 @@ estimate (const Mapping<dim, spacedim> &mapping, const unsigned int n_solution_vectors = solutions.size(); - // Map of integrals indexed by - // the corresponding face. In this map - // we store the integrated jump of the - // gradient for each face. - // At the end of the function, we again - // loop over the cells and collect the - // contributions of the different faces - // of the cell. + // Map of integrals indexed by the corresponding face. In this map we store + // the integrated jump of the gradient for each face. At the end of the + // function, we again loop over the cells and collect the contributions of + // the different faces of the cell. std::map<typename DH::face_iterator,std::vector<double> > face_integrals; - // all the data needed in the error - // estimator by each of the threads - // is gathered in the following - // stuctures + // all the data needed in the error estimator by each of the threads is + // gathered in the following structures const hp::MappingCollection<dim,spacedim> mapping_collection(mapping); const internal::ParallelData<DH> parallel_data (dof_handler.get_fe(), @@ -1612,18 +978,16 @@ estimate (const Mapping<dim, spacedim> &mapping, // now let's work on all those cells: WorkStream::run (dof_handler.begin_active(), static_cast<typename DH::active_cell_iterator>(dof_handler.end()), - std_cxx1x::bind (&internal::estimate_one_cell<dim,spacedim,InputVector,DH>, + std_cxx1x::bind (&internal::estimate_one_cell<InputVector,DH>, std_cxx1x::_1, std_cxx1x::_2, std_cxx1x::_3, std_cxx1x::ref(solutions)), std_cxx1x::bind (&internal::copy_local_to_global<DH>, std_cxx1x::_1, std_cxx1x::ref(face_integrals)), parallel_data, sample_local_face_integrals); - // finally add up the contributions of the - // faces for each cell + // finally add up the contributions of the faces for each cell - // reserve one slot for each cell and set - // it to zero + // reserve one slot for each cell and set it to zero for (unsigned int n=0; n<n_solution_vectors; ++n) { (*errors[n]).reinit (dof_handler.get_tria().n_active_cells()); @@ -1631,10 +995,8 @@ estimate (const Mapping<dim, spacedim> &mapping, (*errors[n])(i)=0; } - // now walk over all cells and collect - // information from the faces. only do - // something if this is a cell we care for - // based on the subdomain id + // now walk over all cells and collect information from the faces. only do + // something if this is a cell we care for based on the subdomain id unsigned int present_cell=0; for (typename DH::active_cell_iterator cell=dof_handler.begin_active(); cell!=dof_handler.end(); @@ -1658,9 +1020,8 @@ estimate (const Mapping<dim, spacedim> &mapping, for (unsigned int n=0; n<n_solution_vectors; ++n) { - // make sure that we have - // written a meaningful value - // into this slot + // make sure that we have written a meaningful value into this + // slot Assert (face_integrals[cell->face(face_no)][n] >= 0, ExcInternalError()); diff --git a/deal.II/source/numerics/error_estimator.inst.in b/deal.II/source/numerics/error_estimator.inst.in index 34b06e672b..8ca601fbcf 100644 --- a/deal.II/source/numerics/error_estimator.inst.in +++ b/deal.II/source/numerics/error_estimator.inst.in @@ -24,7 +24,7 @@ template class KellyErrorEstimator<deal_II_dimension, deal_II_space_dimension>; for (VEC : SERIAL_VECTORS ; deal_II_dimension : DIMENSIONS; deal_II_space_dimension : SPACE_DIMENSIONS; DH : DOFHANDLER_TEMPLATES ) { -#if deal_II_dimension <= deal_II_space_dimension +#if deal_II_dimension != 1 && deal_II_dimension <= deal_II_space_dimension template void diff --git a/deal.II/source/numerics/error_estimator_1d.cc b/deal.II/source/numerics/error_estimator_1d.cc new file mode 100644 index 0000000000..15b65d0bc8 --- /dev/null +++ b/deal.II/source/numerics/error_estimator_1d.cc @@ -0,0 +1,439 @@ +// --------------------------------------------------------------------- +// $Id$ +// +// Copyright (C) 1998 - 2013 by the deal.II authors +// +// This file is part of the deal.II library. +// +// The deal.II library is free software; you can use it, redistribute +// it, and/or modify it under the terms of the GNU Lesser General +// Public License as published by the Free Software Foundation; either +// version 2.1 of the License, or (at your option) any later version. +// The full text of the license can be found in the file LICENSE at +// the top level of the deal.II distribution. +// +// --------------------------------------------------------------------- + +#include <deal.II/base/thread_management.h> +#include <deal.II/base/quadrature.h> +#include <deal.II/base/quadrature_lib.h> +#include <deal.II/base/work_stream.h> +#include <deal.II/lac/vector.h> +#include <deal.II/lac/parallel_vector.h> +#include <deal.II/lac/block_vector.h> +#include <deal.II/lac/parallel_block_vector.h> +#include <deal.II/lac/petsc_vector.h> +#include <deal.II/lac/petsc_block_vector.h> +#include <deal.II/lac/trilinos_vector.h> +#include <deal.II/lac/trilinos_block_vector.h> +#include <deal.II/grid/tria_iterator.h> +#include <deal.II/base/geometry_info.h> +#include <deal.II/dofs/dof_handler.h> +#include <deal.II/dofs/dof_accessor.h> +#include <deal.II/fe/fe.h> +#include <deal.II/fe/fe_values.h> +#include <deal.II/hp/fe_values.h> +#include <deal.II/fe/fe_update_flags.h> +#include <deal.II/fe/mapping_q1.h> +#include <deal.II/hp/q_collection.h> +#include <deal.II/hp/mapping_collection.h> +#include <deal.II/numerics/error_estimator.h> + +#include <deal.II/base/std_cxx1x/bind.h> + +#include <numeric> +#include <algorithm> +#include <cmath> +#include <vector> + +DEAL_II_NAMESPACE_OPEN + + + +template <int spacedim> +template <typename InputVector, class DH> +void +KellyErrorEstimator<1,spacedim>:: +estimate (const Mapping<1,spacedim> &mapping, + const DH &dof_handler, + const Quadrature<0> &quadrature, + const typename FunctionMap<spacedim>::type &neumann_bc, + const InputVector &solution, + Vector<float> &error, + const ComponentMask &component_mask, + const Function<spacedim> *coefficients, + const unsigned int n_threads, + const types::subdomain_id subdomain_id, + const types::material_id material_id) +{ + // just pass on to the other function + const std::vector<const InputVector *> solutions (1, &solution); + std::vector<Vector<float>*> errors (1, &error); + estimate (mapping, dof_handler, quadrature, neumann_bc, solutions, errors, + component_mask, coefficients, n_threads, subdomain_id, material_id); +} + + + +template <int spacedim> +template <typename InputVector, class DH> +void +KellyErrorEstimator<1,spacedim>:: +estimate (const DH &dof_handler, + const Quadrature<0> &quadrature, + const typename FunctionMap<spacedim>::type &neumann_bc, + const InputVector &solution, + Vector<float> &error, + const ComponentMask &component_mask, + const Function<spacedim> *coefficients, + const unsigned int n_threads, + const types::subdomain_id subdomain_id, + const types::material_id material_id) +{ + estimate(StaticMappingQ1<1,spacedim>::mapping, dof_handler, quadrature, neumann_bc, solution, + error, component_mask, coefficients, n_threads, subdomain_id, material_id); +} + + + +template <int spacedim> +template <typename InputVector, class DH> +void +KellyErrorEstimator<1,spacedim>:: +estimate (const DH &dof_handler, + const Quadrature<0> &quadrature, + const typename FunctionMap<spacedim>::type &neumann_bc, + const std::vector<const InputVector *> &solutions, + std::vector<Vector<float>*> &errors, + const ComponentMask &component_mask, + const Function<spacedim> *coefficients, + const unsigned int n_threads, + const types::subdomain_id subdomain_id, + const types::material_id material_id) +{ + estimate(StaticMappingQ1<1,spacedim>::mapping, dof_handler, quadrature, neumann_bc, solutions, + errors, component_mask, coefficients, n_threads, subdomain_id, material_id); +} + + + +template <int spacedim> +template <typename InputVector, class DH> +void +KellyErrorEstimator<1,spacedim>:: +estimate (const Mapping<1,spacedim> &mapping, + const DH &dof_handler, + const hp::QCollection<0> &quadrature, + const typename FunctionMap<spacedim>::type &neumann_bc, + const InputVector &solution, + Vector<float> &error, + const ComponentMask &component_mask, + const Function<spacedim> *coefficients, + const unsigned int n_threads, + const types::subdomain_id subdomain_id, + const types::material_id material_id) +{ + // just pass on to the other function + const std::vector<const InputVector *> solutions (1, &solution); + std::vector<Vector<float>*> errors (1, &error); + estimate (mapping, dof_handler, quadrature, neumann_bc, solutions, errors, + component_mask, coefficients, n_threads, subdomain_id, material_id); +} + + +template <int spacedim> +template <typename InputVector, class DH> +void +KellyErrorEstimator<1,spacedim>:: +estimate (const DH &dof_handler, + const hp::QCollection<0> &quadrature, + const typename FunctionMap<spacedim>::type &neumann_bc, + const InputVector &solution, + Vector<float> &error, + const ComponentMask &component_mask, + const Function<spacedim> *coefficients, + const unsigned int n_threads, + const types::subdomain_id subdomain_id, + const types::material_id material_id) +{ + estimate(StaticMappingQ1<1,spacedim>::mapping, dof_handler, quadrature, neumann_bc, solution, + error, component_mask, coefficients, n_threads, subdomain_id, material_id); +} + + + +template <int spacedim> +template <typename InputVector, class DH> +void +KellyErrorEstimator<1,spacedim>:: +estimate (const DH &dof_handler, + const hp::QCollection<0> &quadrature, + const typename FunctionMap<spacedim>::type &neumann_bc, + const std::vector<const InputVector *> &solutions, + std::vector<Vector<float>*> &errors, + const ComponentMask &component_mask, + const Function<spacedim> *coefficients, + const unsigned int n_threads, + const types::subdomain_id subdomain_id, + const types::material_id material_id) +{ + estimate(StaticMappingQ1<1,spacedim>::mapping, dof_handler, quadrature, neumann_bc, solutions, + errors, component_mask, coefficients, n_threads, subdomain_id, material_id); +} + + + + +template <int spacedim> +template <typename InputVector, class DH> +void KellyErrorEstimator<1,spacedim>:: +estimate (const Mapping<1,spacedim> &/*mapping*/, + const DH &/*dof_handler*/, + const hp::QCollection<0> &, + const typename FunctionMap<spacedim>::type &/*neumann_bc*/, + const std::vector<const InputVector *> &/*solutions*/, + std::vector<Vector<float>*> &/*errors*/, + const ComponentMask &/*component_mask_*/, + const Function<spacedim> */*coefficient*/, + const unsigned int, + const types::subdomain_id /*subdomain_id*/, + const types::material_id /*material_id*/) +{ + Assert (false, ExcInternalError()); +} + + + +template <int spacedim> +template <typename InputVector, class DH> +void KellyErrorEstimator<1,spacedim>:: +estimate (const Mapping<1,spacedim> &mapping, + const DH &dof_handler, + const Quadrature<0> &, + const typename FunctionMap<spacedim>::type &neumann_bc, + const std::vector<const InputVector *> &solutions, + std::vector<Vector<float>*> &errors, + const ComponentMask &component_mask, + const Function<spacedim> *coefficient, + const unsigned int, + const types::subdomain_id subdomain_id_, + const types::material_id material_id) +{ +#ifdef DEAL_II_WITH_P4EST + if (dynamic_cast<const parallel::distributed::Triangulation<1,spacedim>*> + (&dof_handler.get_tria()) + != 0) + Assert ((subdomain_id_ == numbers::invalid_subdomain_id) + || + (subdomain_id_ == + dynamic_cast<const parallel::distributed::Triangulation<1,spacedim>&> + (dof_handler.get_tria()).locally_owned_subdomain()), + ExcMessage ("For parallel distributed triangulations, the only " + "valid subdomain_id that can be passed here is the " + "one that corresponds to the locally owned subdomain id.")); + + const types::subdomain_id subdomain_id + = ((dynamic_cast<const parallel::distributed::Triangulation<1,spacedim>*> + (&dof_handler.get_tria()) + != 0) + ? + dynamic_cast<const parallel::distributed::Triangulation<1,spacedim>&> + (dof_handler.get_tria()).locally_owned_subdomain() + : + subdomain_id_); +#else + const types::subdomain_id subdomain_id + = subdomain_id_; +#endif + + const unsigned int n_components = dof_handler.get_fe().n_components(); + const unsigned int n_solution_vectors = solutions.size(); + + // sanity checks + Assert (neumann_bc.find(numbers::internal_face_boundary_id) == neumann_bc.end(), + ExcInvalidBoundaryIndicator()); + + for (typename FunctionMap<spacedim>::type::const_iterator i=neumann_bc.begin(); + i!=neumann_bc.end(); ++i) + Assert (i->second->n_components == n_components, ExcInvalidBoundaryFunction()); + + Assert (component_mask.represents_n_components(n_components), + ExcInvalidComponentMask()); + Assert (component_mask.n_selected_components(n_components) > 0, + ExcInvalidComponentMask()); + + Assert ((coefficient == 0) || + (coefficient->n_components == n_components) || + (coefficient->n_components == 1), + ExcInvalidCoefficient()); + + Assert (solutions.size() > 0, + ExcNoSolutions()); + Assert (solutions.size() == errors.size(), + ExcIncompatibleNumberOfElements(solutions.size(), errors.size())); + for (unsigned int n=0; n<solutions.size(); ++n) + Assert (solutions[n]->size() == dof_handler.n_dofs(), + ExcInvalidSolutionVector()); + + Assert ((coefficient == 0) || + (coefficient->n_components == n_components) || + (coefficient->n_components == 1), + ExcInvalidCoefficient()); + + for (typename FunctionMap<spacedim>::type::const_iterator i=neumann_bc.begin(); + i!=neumann_bc.end(); ++i) + Assert (i->second->n_components == n_components, + ExcInvalidBoundaryFunction()); + + // reserve one slot for each cell and set it to zero + for (unsigned int n=0; n<n_solution_vectors; ++n) + (*errors[n]).reinit (dof_handler.get_tria().n_active_cells()); + + // fields to get the gradients on the present and the neighbor cell. + // + // for the neighbor gradient, we need several auxiliary fields, depending on + // the way we get it (see below) + std::vector<std::vector<std::vector<Tensor<1,spacedim> > > > + gradients_here (n_solution_vectors, + std::vector<std::vector<Tensor<1,spacedim> > >(2, std::vector<Tensor<1,spacedim> >(n_components))); + std::vector<std::vector<std::vector<Tensor<1,spacedim> > > > + gradients_neighbor (gradients_here); + std::vector<Vector<double> > + grad_neighbor (n_solution_vectors, Vector<double>(n_components)); + + // reserve some space for coefficient values at one point. if there is no + // coefficient, then we fill it by unity once and for all and don't set it + // any more + Vector<double> coefficient_values (n_components); + if (coefficient == 0) + for (unsigned int c=0; c<n_components; ++c) + coefficient_values(c) = 1; + + const QTrapez<1> quadrature; + const hp::QCollection<1> q_collection(quadrature); + + const hp::FECollection<1,spacedim> fe (dof_handler.get_fe()); + + hp::MappingCollection<1,spacedim> mapping_collection; + mapping_collection.push_back (mapping); + + hp::FEValues<1,spacedim> fe_values (mapping_collection, fe, q_collection, + update_gradients); + + // loop over all cells and do something on the cells which we're told to + // work on. note that the error indicator is only a sum over the two + // contributions from the two vertices of each cell. + typename DH::active_cell_iterator cell = dof_handler.begin_active(); + for (unsigned int cell_index=0; cell != dof_handler.end(); + ++cell, ++cell_index) + if (((subdomain_id == numbers::invalid_subdomain_id) + || + (cell->subdomain_id() == subdomain_id)) + && + ((material_id == numbers::invalid_material_id) + || + (cell->material_id() == material_id))) + { + for (unsigned int n=0; n<n_solution_vectors; ++n) + (*errors[n])(cell_index) = 0; + + // loop over the two points bounding this line. n==0 is left point, + // n==1 is right point + for (unsigned int n=0; n<2; ++n) + { + // find left or right active neighbor + typename DH::cell_iterator neighbor = cell->neighbor(n); + if (neighbor.state() == IteratorState::valid) + while (neighbor->has_children()) + neighbor = neighbor->child(n==0 ? 1 : 0); + + // now get the gradients on the both sides of the point + fe_values.reinit (cell); + + for (unsigned int s=0; s<n_solution_vectors; ++s) + fe_values.get_present_fe_values() + .get_function_gradients (*solutions[s], gradients_here[s]); + + if (neighbor.state() == IteratorState::valid) + { + fe_values.reinit (neighbor); + + for (unsigned int s=0; s<n_solution_vectors; ++s) + fe_values.get_present_fe_values() + .get_function_gradients (*solutions[s], + gradients_neighbor[s]); + + // extract the gradients of all the components. [0] means: + // x-derivative, which is the only one here + for (unsigned int s=0; s<n_solution_vectors; ++s) + for (unsigned int c=0; c<n_components; ++c) + grad_neighbor[s](c) + = gradients_neighbor[s][n==0 ? 1 : 0][c][0]; + } + else if (neumann_bc.find(n) != neumann_bc.end()) + // if Neumann b.c., then fill the gradients field which will be + // used later on. + { + if (n_components==1) + { + const double + v = neumann_bc.find(n)->second->value(cell->vertex(0)); + + for (unsigned int s=0; s<n_solution_vectors; ++s) + grad_neighbor[s](0) = v; + } + else + { + Vector<double> v(n_components); + neumann_bc.find(n)->second->vector_value(cell->vertex(0), v); + + for (unsigned int s=0; s<n_solution_vectors; ++s) + grad_neighbor[s] = v; + } + } + else + // fill with zeroes. + for (unsigned int s=0; s<n_solution_vectors; ++s) + grad_neighbor[s] = 0; + + // if there is a coefficient, then evaluate it at the present + // position. if there is none, reuse the preset values. + if (coefficient != 0) + { + if (coefficient->n_components == 1) + { + const double c_value = coefficient->value (cell->vertex(n)); + for (unsigned int c=0; c<n_components; ++c) + coefficient_values(c) = c_value; + } + else + coefficient->vector_value(cell->vertex(n), + coefficient_values); + } + + + for (unsigned int s=0; s<n_solution_vectors; ++s) + for (unsigned int component=0; component<n_components; ++component) + if (component_mask[component] == true) + { + // get gradient here. [0] means x-derivative (there is no + // other component in 1d) + const double grad_here = gradients_here[s][n][component][0]; + + const double jump = ((grad_here - grad_neighbor[s](component)) * + coefficient_values(component)); + (*errors[s])(cell_index) += jump*jump * cell->diameter(); + } + } + + for (unsigned int s=0; s<n_solution_vectors; ++s) + (*errors[s])(cell_index) = std::sqrt((*errors[s])(cell_index)); + } +} + + +// explicit instantiations +#include "error_estimator_1d.inst" + + +DEAL_II_NAMESPACE_CLOSE diff --git a/deal.II/source/numerics/error_estimator_1d.inst.in b/deal.II/source/numerics/error_estimator_1d.inst.in new file mode 100644 index 0000000000..66b0c787bc --- /dev/null +++ b/deal.II/source/numerics/error_estimator_1d.inst.in @@ -0,0 +1,143 @@ +// --------------------------------------------------------------------- +// $Id$ +// +// Copyright (C) 2010 - 2013 by the deal.II authors +// +// This file is part of the deal.II library. +// +// The deal.II library is free software; you can use it, redistribute +// it, and/or modify it under the terms of the GNU Lesser General +// Public License as published by the Free Software Foundation; either +// version 2.1 of the License, or (at your option) any later version. +// The full text of the license can be found in the file LICENSE at +// the top level of the deal.II distribution. +// +// --------------------------------------------------------------------- + + +for (VEC : SERIAL_VECTORS ; deal_II_dimension : DIMENSIONS; deal_II_space_dimension : SPACE_DIMENSIONS; DH : DOFHANDLER_TEMPLATES ) +{ +#if deal_II_dimension == 1 && deal_II_dimension <= deal_II_space_dimension + +template +void +KellyErrorEstimator<deal_II_dimension, deal_II_space_dimension>:: +estimate<VEC,DH<deal_II_dimension,deal_II_space_dimension> > (const Mapping<deal_II_dimension, deal_II_space_dimension> &, + const DH<deal_II_dimension,deal_II_space_dimension> &, + const Quadrature<deal_II_dimension-1> &, + const FunctionMap<deal_II_space_dimension>::type &, + const VEC &, + Vector<float> &, + const ComponentMask &, + const Function<deal_II_space_dimension> *, + const unsigned int , + const unsigned int , + const types::material_id); + +template +void +KellyErrorEstimator<deal_II_dimension, deal_II_space_dimension>:: +estimate<VEC,DH<deal_II_dimension,deal_II_space_dimension> > ( + const DH<deal_II_dimension,deal_II_space_dimension> &, + const Quadrature<deal_II_dimension-1> &, + const FunctionMap<deal_II_space_dimension>::type &, + const VEC &, + Vector<float> &, + const ComponentMask &, + const Function<deal_II_space_dimension> *, + const unsigned int , + const unsigned int , + const types::material_id); + +template +void +KellyErrorEstimator<deal_II_dimension, deal_II_space_dimension>:: +estimate<VEC,DH<deal_II_dimension,deal_II_space_dimension> > (const Mapping<deal_II_dimension, deal_II_space_dimension> &, + const DH<deal_II_dimension,deal_II_space_dimension> &, + const Quadrature<deal_II_dimension-1> &, + const FunctionMap<deal_II_space_dimension>::type &, + const std::vector<const VEC *> &, + std::vector<Vector<float> *> &, + const ComponentMask &, + const Function<deal_II_space_dimension> *, + const unsigned int , + const unsigned int , + const types::material_id); + +template +void +KellyErrorEstimator<deal_II_dimension, deal_II_space_dimension>:: +estimate<VEC,DH<deal_II_dimension,deal_II_space_dimension> > ( + const DH<deal_II_dimension,deal_II_space_dimension> &, + const Quadrature<deal_II_dimension-1> &, + const FunctionMap<deal_II_space_dimension>::type &, + const std::vector<const VEC *> &, + std::vector<Vector<float> *> &, + const ComponentMask &, + const Function<deal_II_space_dimension> *, + const unsigned int , + const unsigned int , + const types::material_id); + +template +void +KellyErrorEstimator<deal_II_dimension, deal_II_space_dimension>:: +estimate<VEC,DH<deal_II_dimension,deal_II_space_dimension> > (const Mapping<deal_II_dimension, deal_II_space_dimension> &, + const DH<deal_II_dimension,deal_II_space_dimension> &, + const hp::QCollection<deal_II_dimension-1> &, + const FunctionMap<deal_II_space_dimension>::type &, + const VEC &, + Vector<float> &, + const ComponentMask &, + const Function<deal_II_space_dimension> *, + const unsigned int , + const unsigned int , + const types::material_id); + +template +void +KellyErrorEstimator<deal_II_dimension, deal_II_space_dimension>:: +estimate<VEC,DH<deal_II_dimension,deal_II_space_dimension> > ( + const DH<deal_II_dimension,deal_II_space_dimension> &, + const hp::QCollection<deal_II_dimension-1> &, + const FunctionMap<deal_II_space_dimension>::type &, + const VEC &, + Vector<float> &, + const ComponentMask &, + const Function<deal_II_space_dimension> *, + const unsigned int , + const unsigned int , + const types::material_id); + +template +void +KellyErrorEstimator<deal_II_dimension, deal_II_space_dimension>:: +estimate<VEC,DH<deal_II_dimension,deal_II_space_dimension> > (const Mapping<deal_II_dimension, deal_II_space_dimension> &, + const DH<deal_II_dimension,deal_II_space_dimension> &, + const hp::QCollection<deal_II_dimension-1> &, + const FunctionMap<deal_II_space_dimension>::type &, + const std::vector<const VEC *> &, + std::vector<Vector<float> *> &, + const ComponentMask &, + const Function<deal_II_space_dimension> *, + const unsigned int , + const unsigned int , + const types::material_id); + +template +void +KellyErrorEstimator<deal_II_dimension, deal_II_space_dimension>:: +estimate<VEC,DH<deal_II_dimension,deal_II_space_dimension> > ( + const DH<deal_II_dimension,deal_II_space_dimension> &, + const hp::QCollection<deal_II_dimension-1> &, + const FunctionMap<deal_II_space_dimension>::type &, + const std::vector<const VEC *> &, + std::vector<Vector<float> *> &, + const ComponentMask &, + const Function<deal_II_space_dimension> *, + const unsigned int , + const unsigned int , + const types::material_id); + +#endif +} diff --git a/deal.II/source/numerics/solution_transfer.cc b/deal.II/source/numerics/solution_transfer.cc index 0a40a40830..beb4b0155d 100644 --- a/deal.II/source/numerics/solution_transfer.cc +++ b/deal.II/source/numerics/solution_transfer.cc @@ -188,24 +188,13 @@ namespace internal { matrices(i,j).reinit (fe[i].dofs_per_cell, fe[j].dofs_per_cell); - // see if we can get the - // interpolation matrices - // for this combination - // of elements. if not, - // reset the matrix sizes - // to zero to indicate - // that this particular - // combination isn't - // supported. this isn't - // an outright error - // right away since we - // may never need to - // actually interpolate - // between these two - // elements on actual - // cells; we simply have - // to trigger an error if - // someone actually tries + // see if we can get the interpolation matrices for this + // combination of elements. if not, reset the matrix sizes to zero + // to indicate that this particular combination isn't + // supported. this isn't an outright error right away since we may + // never need to actually interpolate between these two elements + // on actual cells; we simply have to trigger an error if someone + // actually tries try { fe[i].get_interpolation_matrix (fe[j], matrices(i,j)); @@ -574,12 +563,41 @@ interpolate (const std::vector<VECTOR> &all_in, local_values.reinit (cell->has_children() ? cell->child(0)->get_fe().dofs_per_cell : cell->get_fe().dofs_per_cell, true); - AssertDimension (local_values.size(), - interpolation_hp(new_fe_index,old_index).m()); + // do the interpolation. we get into trouble if the + // interpolation_hp(new,old) matrix hasn't been computed. + // this can happen if the respective elements don't support + // the corresponding interpolation; if that's the case, then + // the computation of the matrix simply sets the matrix + // back to size zero. so if we get here and that is + // the wrong size, then this may be because the elements + // haven't implemented the correct function yet + // + // there is one wrinkle. we would like to only error out if + // the size of the matrix is 0 times 0 but at least one + // of the elements has more than one dof per cell. the + // problem is that if you reinit a matrix to 4x0, it automatically + // sets its size to 0x0. so we can only execute the following + // test if *both* elements have dofs_per_cell>0, not if *at + // least one* have. + Assert (! ((interpolation_hp(new_fe_index,old_index).m() == 0) + && + (interpolation_hp(new_fe_index,old_index).n() == 0) + && + ((dof_handler->get_fe()[new_fe_index].dofs_per_cell > 0) + && + (dof_handler->get_fe()[old_index].dofs_per_cell > 0))), + ExcMessage ("The interpolation between two different " + "elements you are trying to use here has " + "not been implemented for this pair of " + "elements!")); + // simple case where all children have the // same FE index: just interpolate to their FE // first and then use the standard routines - interpolation_hp(new_fe_index,old_index).vmult (local_values, tmp); + if (tmp.size() > 0) + interpolation_hp(new_fe_index,old_index).vmult (local_values, tmp); + else + local_values = 0; } if (cell->has_children() == false) @@ -596,9 +614,24 @@ interpolate (const std::vector<VECTOR> &all_in, AssertDimension (tmp.size(), interpolation_hp(c_index,old_index).n()); local_values.reinit(cell->child(child)->get_fe().dofs_per_cell, true); - AssertDimension (local_values.size(), - interpolation_hp(c_index,old_index).m()); - interpolation_hp(c_index,old_index).vmult (local_values, tmp); + + // do the interpolation. same problem as above + Assert (! ((interpolation_hp(c_index,old_index).m() == 0) + && + (interpolation_hp(c_index,old_index).n() == 0) + && + ((dof_handler->get_fe()[c_index].dofs_per_cell > 0) + && + (dof_handler->get_fe()[old_index].dofs_per_cell > 0))), + ExcMessage ("The interpolation between two different " + "elements you are trying to use here has " + "not been implemented for this pair of " + "elements!")); + + if (tmp.size() > 0) + interpolation_hp(c_index,old_index).vmult (local_values, tmp); + else + local_values = 0; } else local_values = tmp; @@ -731,6 +764,8 @@ SolutionTransfer<dim, VECTOR, DH>::Pointerstruct::memory_consumption () const #define DIM_B 2 #endif +// This file compiles the first quarter of the instantiations from solution_transfer.cc +// to reduce the compilation unit (and memory consumption) #include "solution_transfer.inst" DEAL_II_NAMESPACE_CLOSE diff --git a/deal.II/source/numerics/solution_transfer.inst.in b/deal.II/source/numerics/solution_transfer.inst.in index fe64874d34..05f2760106 100644 --- a/deal.II/source/numerics/solution_transfer.inst.in +++ b/deal.II/source/numerics/solution_transfer.inst.in @@ -20,10 +20,13 @@ for (VEC : SERIAL_VECTORS; deal_II_dimension : DIMENSIONS; deal_II_space_dimensi #if deal_II_dimension <= deal_II_space_dimension #if (deal_II_space_dimension == DIM_A) || (deal_II_space_dimension == DIM_B) +#ifndef INSTANTIATE_HP_DH template class SolutionTransfer<deal_II_dimension, VEC, DoFHandler<deal_II_dimension, deal_II_space_dimension> >; +#else template class SolutionTransfer<deal_II_dimension, VEC, hp::DoFHandler<deal_II_dimension, deal_II_space_dimension> >; #endif #endif +#endif } diff --git a/deal.II/source/numerics/solution_transfer_inst2.cc b/deal.II/source/numerics/solution_transfer_inst2.cc index 09c0cde103..8292d039e6 100644 --- a/deal.II/source/numerics/solution_transfer_inst2.cc +++ b/deal.II/source/numerics/solution_transfer_inst2.cc @@ -14,9 +14,10 @@ // // --------------------------------------------------------------------- -// This file compiles the second half of the instantiations from solution_transfer.cc -// to get the memory consumption below 1.5gb with gcc (if compiling with PETSc and Trilinos). +// This file compiles the second quarter of the instantiations from solution_transfer.cc +// to reduce the compilation unit (and memory consumption) +//#define INSTANTIATE_HP_DH #define SOLUTION_TRANSFER_INSTANTIATE_PART_TWO #include "solution_transfer.cc" diff --git a/deal.II/source/numerics/solution_transfer_inst3.cc b/deal.II/source/numerics/solution_transfer_inst3.cc new file mode 100644 index 0000000000..5ba125b1d7 --- /dev/null +++ b/deal.II/source/numerics/solution_transfer_inst3.cc @@ -0,0 +1,23 @@ +// --------------------------------------------------------------------- +// $Id$ +// +// Copyright (C) 2013 by the deal.II authors +// +// This file is part of the deal.II library. +// +// The deal.II library is free software; you can use it, redistribute +// it, and/or modify it under the terms of the GNU Lesser General +// Public License as published by the Free Software Foundation; either +// version 2.1 of the License, or (at your option) any later version. +// The full text of the license can be found in the file LICENSE at +// the top level of the deal.II distribution. +// +// --------------------------------------------------------------------- + +// This file compiles the third quarter of the instantiations from solution_transfer.cc +// to reduce the compilation unit (and memory consumption) + +#define INSTANTIATE_HP_DH +//#define SOLUTION_TRANSFER_INSTANTIATE_PART_TWO + +#include "solution_transfer.cc" diff --git a/deal.II/source/numerics/solution_transfer_inst4.cc b/deal.II/source/numerics/solution_transfer_inst4.cc new file mode 100644 index 0000000000..f8c9518530 --- /dev/null +++ b/deal.II/source/numerics/solution_transfer_inst4.cc @@ -0,0 +1,23 @@ +// --------------------------------------------------------------------- +// $Id$ +// +// Copyright (C) 2013 by the deal.II authors +// +// This file is part of the deal.II library. +// +// The deal.II library is free software; you can use it, redistribute +// it, and/or modify it under the terms of the GNU Lesser General +// Public License as published by the Free Software Foundation; either +// version 2.1 of the License, or (at your option) any later version. +// The full text of the license can be found in the file LICENSE at +// the top level of the deal.II distribution. +// +// --------------------------------------------------------------------- + +// This file compiles the fourth quarter of the instantiations from solution_transfer.cc +// to reduce the compilation unit (and memory consumption) + +#define INSTANTIATE_HP_DH +#define SOLUTION_TRANSFER_INSTANTIATE_PART_TWO + +#include "solution_transfer.cc" diff --git a/deal.II/source/numerics/vector_tools.inst.in b/deal.II/source/numerics/vector_tools.inst.in deleted file mode 100644 index f7bbff340e..0000000000 --- a/deal.II/source/numerics/vector_tools.inst.in +++ /dev/null @@ -1,703 +0,0 @@ -// --------------------------------------------------------------------- -// $Id$ -// -// Copyright (C) 1998 - 2013 by the deal.II authors -// -// This file is part of the deal.II library. -// -// The deal.II library is free software; you can use it, redistribute -// it, and/or modify it under the terms of the GNU Lesser General -// Public License as published by the Free Software Foundation; either -// version 2.1 of the License, or (at your option) any later version. -// The full text of the license can be found in the file LICENSE at -// the top level of the deal.II distribution. -// -// --------------------------------------------------------------------- - - -for (VEC : SERIAL_VECTORS ; deal_II_dimension : DIMENSIONS; deal_II_space_dimension : SPACE_DIMENSIONS) - { -#if deal_II_dimension <= deal_II_space_dimension - namespace VectorTools \{ - - template - void integrate_difference<deal_II_dimension, VEC, Vector<float>, deal_II_space_dimension> - (const DoFHandler<deal_II_dimension, deal_II_space_dimension>&, - const VEC&, - const Function<deal_II_space_dimension>&, - Vector<float>&, - const Quadrature<deal_II_dimension>&, - const NormType&, - const Function<deal_II_space_dimension>*, - const double); - - template - void integrate_difference<deal_II_dimension, VEC, Vector<double>, deal_II_space_dimension > - (const DoFHandler<deal_II_dimension, deal_II_space_dimension>&, - const VEC&, - const Function<deal_II_space_dimension>&, - Vector<double>&, - const Quadrature<deal_II_dimension>&, - const NormType&, - const Function<deal_II_space_dimension>*, - const double); - - template - void integrate_difference<deal_II_dimension, VEC, Vector<float>, deal_II_space_dimension> - (const Mapping<deal_II_dimension, deal_II_space_dimension>&, - const DoFHandler<deal_II_dimension, deal_II_space_dimension>&, - const VEC&, - const Function<deal_II_space_dimension>&, - Vector<float>&, - const Quadrature<deal_II_dimension>&, - const NormType&, - const Function<deal_II_space_dimension>*, - const double); - - template - void integrate_difference<deal_II_dimension, VEC, Vector<double>, deal_II_space_dimension > - (const Mapping<deal_II_dimension, deal_II_space_dimension>&, - const DoFHandler<deal_II_dimension, deal_II_space_dimension>&, - const VEC&, - const Function<deal_II_space_dimension>&, - Vector<double>&, - const Quadrature<deal_II_dimension>&, - const NormType&, - const Function<deal_II_space_dimension>*, - const double); - - - - template - double compute_mean_value<deal_II_dimension> - (const Mapping<deal_II_dimension,deal_II_space_dimension>&, - const DoFHandler<deal_II_dimension,deal_II_space_dimension>&, - const Quadrature<deal_II_dimension>&, - const VEC&, - const unsigned int); - - template - double compute_mean_value<deal_II_dimension> - (const DoFHandler<deal_II_dimension,deal_II_space_dimension>&, - const Quadrature<deal_II_dimension>&, - const VEC&, - const unsigned int); - - template - void interpolate - (const Mapping<deal_II_dimension,deal_II_space_dimension>&, - const DoFHandler<deal_II_dimension,deal_II_space_dimension>&, - const Function<deal_II_space_dimension>&, - VEC&); - - template - void interpolate - (const DoFHandler<deal_II_dimension,deal_II_space_dimension>&, - const Function<deal_II_space_dimension>&, - VEC&); - - template - void project - (const Mapping<deal_II_dimension,deal_II_space_dimension> &, - const DoFHandler<deal_II_dimension,deal_II_space_dimension> &, - const ConstraintMatrix &, - const Quadrature<deal_II_dimension> &, - const Function<deal_II_space_dimension> &, - VEC &, - const bool, - const Quadrature<deal_II_dimension-1> &, - const bool); - - template - void project - (const DoFHandler<deal_II_dimension,deal_II_space_dimension> &, - const ConstraintMatrix &, - const Quadrature<deal_II_dimension> &, - const Function<deal_II_space_dimension> &, - VEC &, - const bool, - const Quadrature<deal_II_dimension-1> &, - const bool); - - template - void project - (const hp::MappingCollection<deal_II_dimension,deal_II_space_dimension> &, - const hp::DoFHandler<deal_II_dimension,deal_II_space_dimension> &, - const ConstraintMatrix &, - const hp::QCollection<deal_II_dimension> &, - const Function<deal_II_space_dimension> &, - VEC &, - const bool, - const hp::QCollection<deal_II_dimension-1> &, - const bool); - - template - void project - (const hp::DoFHandler<deal_II_dimension,deal_II_space_dimension> &, - const ConstraintMatrix &, - const hp::QCollection<deal_II_dimension> &, - const Function<deal_II_space_dimension> &, - VEC &, - const bool, - const hp::QCollection<deal_II_dimension-1> &, - const bool); - \} -#endif - } - - - -//TODO[SP]: replace <deal_II_dimension> by <deal_II_dimension, deal_II_space_dimension> -// where applicable and move to codimension cases above also when applicable -for (VEC : SERIAL_VECTORS ; deal_II_dimension : DIMENSIONS; deal_II_space_dimension : SPACE_DIMENSIONS) - { -#if deal_II_dimension == deal_II_space_dimension - - namespace VectorTools \{ - - template - void point_value<deal_II_dimension> ( - const hp::DoFHandler<deal_II_dimension>&, - const VEC&, - const Point<deal_II_dimension>&, - Vector<double>&); - - template - void interpolate - (const Mapping<deal_II_dimension>&, - const hp::DoFHandler<deal_II_dimension>&, - const Function<deal_II_dimension>&, - VEC&); - template - void interpolate - (const hp::DoFHandler<deal_II_dimension>&, - const Function<deal_II_dimension>&, - VEC&); - - template - double point_value<deal_II_dimension> ( - const hp::DoFHandler<deal_II_dimension>&, - const VEC&, - const Point<deal_II_dimension>&); - - template - void point_value<deal_II_dimension> ( - const hp::MappingCollection<deal_II_dimension>&, - const hp::DoFHandler<deal_II_dimension>&, - const VEC&, - const Point<deal_II_dimension>&, - Vector<double>&); - - template - void interpolate - (const DoFHandler<deal_II_dimension>&, - const DoFHandler<deal_II_dimension>&, - const FullMatrix<double>&, - const VEC&, - VEC&); - - template - double point_value<deal_II_dimension> ( - const hp::MappingCollection<deal_II_dimension>&, - const hp::DoFHandler<deal_II_dimension>&, - const VEC&, - const Point<deal_II_dimension>&); - - template - void integrate_difference<deal_II_dimension> - (const hp::DoFHandler<deal_II_dimension>&, - const VEC&, - const Function<deal_II_dimension>&, - Vector<double>&, - const hp::QCollection<deal_II_dimension>&, - const NormType&, - const Function<deal_II_dimension>*, - const double); - template - void integrate_difference<deal_II_dimension> - (const hp::DoFHandler<deal_II_dimension>&, - const VEC&, - const Function<deal_II_dimension>&, - Vector<float>&, - const hp::QCollection<deal_II_dimension>&, - const NormType&, - const Function<deal_II_dimension>*, - const double); - template - void integrate_difference<deal_II_dimension> - (const hp::MappingCollection<deal_II_dimension>&, - const hp::DoFHandler<deal_II_dimension>&, - const VEC&, - const Function<deal_II_dimension>&, - Vector<double>&, - const hp::QCollection<deal_II_dimension>&, - const NormType&, - const Function<deal_II_dimension>*, - const double); - template - void integrate_difference<deal_II_dimension> - (const hp::MappingCollection<deal_II_dimension>&, - const hp::DoFHandler<deal_II_dimension>&, - const VEC&, - const Function<deal_II_dimension>&, - Vector<float>&, - const hp::QCollection<deal_II_dimension>&, - const NormType&, - const Function<deal_II_dimension>*, - const double); - - template - void point_difference<deal_II_dimension> ( - const DoFHandler<deal_II_dimension>&, - const VEC&, - const Function<deal_II_dimension>&, - Vector<double>&, - const Point<deal_II_dimension>&); - - template - void point_difference<deal_II_dimension> ( - const Mapping<deal_II_dimension>&, - const DoFHandler<deal_II_dimension>&, - const VEC&, - const Function<deal_II_dimension>&, - Vector<double>&, - const Point<deal_II_dimension>&); - - template - void point_value<deal_II_dimension> ( - const DoFHandler<deal_II_dimension>&, - const VEC&, - const Point<deal_II_dimension>&, - Vector<double>&); - - template - double point_value<deal_II_dimension> ( - const DoFHandler<deal_II_dimension>&, - const VEC&, - const Point<deal_II_dimension>&); - - template - void point_value<deal_II_dimension> ( - const Mapping<deal_II_dimension>&, - const DoFHandler<deal_II_dimension>&, - const VEC&, - const Point<deal_II_dimension>&, - Vector<double>&); - - template - double point_value<deal_II_dimension> ( - const Mapping<deal_II_dimension>&, - const DoFHandler<deal_II_dimension>&, - const VEC&, - const Point<deal_II_dimension>&); - - \} -#endif - } - - -for (VEC : SERIAL_VECTORS) -{ - namespace VectorTools \{ - template - void subtract_mean_value(VEC &, const std::vector<bool> &); - \} -} - - -for (deal_II_dimension : DIMENSIONS) -{ - namespace VectorTools \{ - template - void interpolate_boundary_values ( - const MGDoFHandler<deal_II_dimension> &, - const types::boundary_id, - const Function<deal_II_dimension> &, - ConstraintMatrix&, - const ComponentMask &); - - template - void interpolate_boundary_values ( - const MGDoFHandler<deal_II_dimension> &, - const types::boundary_id, - const Function<deal_II_dimension> &, - std::map<types::global_dof_index,double> &, - const ComponentMask &); - \} -} - - -for (deal_II_dimension : DIMENSIONS; deal_II_space_dimension : SPACE_DIMENSIONS; DH : DOFHANDLER_TEMPLATES) - { -#if deal_II_dimension <= deal_II_space_dimension - namespace VectorTools \{ - template - void interpolate_boundary_values - (const Mapping<deal_II_dimension,deal_II_space_dimension> &, - const DH<deal_II_dimension,deal_II_space_dimension> &, - const FunctionMap<deal_II_space_dimension>::type &, - std::map<types::global_dof_index,double> &, - const ComponentMask &); - - template - void interpolate_boundary_values - (const Mapping<deal_II_dimension,deal_II_space_dimension> &, - const DH<deal_II_dimension,deal_II_space_dimension> &, - const types::boundary_id, - const Function<deal_II_space_dimension> &, - std::map<types::global_dof_index,double> &, - const ComponentMask &); - - template - void interpolate_boundary_values ( - const DH<deal_II_dimension,deal_II_space_dimension> &, - const types::boundary_id, - const Function<deal_II_space_dimension> &, - std::map<types::global_dof_index,double> &, - const ComponentMask &); - - template - void interpolate_boundary_values - (const DH<deal_II_dimension,deal_II_space_dimension> &, - const FunctionMap<deal_II_space_dimension>::type &, - std::map<types::global_dof_index,double> &, - const ComponentMask &); - - template - void interpolate_boundary_values ( - const Mapping<deal_II_dimension,deal_II_space_dimension> &, - const DH<deal_II_dimension,deal_II_space_dimension> &, - const FunctionMap<deal_II_space_dimension>::type &, - ConstraintMatrix &, - const ComponentMask &); - - template - void interpolate_boundary_values - (const Mapping<deal_II_dimension,deal_II_space_dimension> &, - const DH<deal_II_dimension,deal_II_space_dimension> &, - const types::boundary_id, - const Function<deal_II_space_dimension> &, - ConstraintMatrix &, - const ComponentMask &); - - template - void interpolate_boundary_values ( - const DH<deal_II_dimension,deal_II_space_dimension> &, - const types::boundary_id, - const Function<deal_II_space_dimension> &, - ConstraintMatrix &, - const ComponentMask &); - - template - void interpolate_boundary_values ( - const DH<deal_II_dimension,deal_II_space_dimension> &, - const FunctionMap<deal_II_space_dimension>::type &, - ConstraintMatrix &, - const ComponentMask &); - - \} -#endif - } - - -for (deal_II_dimension : DIMENSIONS; deal_II_space_dimension : SPACE_DIMENSIONS) - { -#if deal_II_dimension <= deal_II_space_dimension - namespace VectorTools \{ - template - void create_right_hand_side<deal_II_dimension,deal_II_space_dimension> - (const Mapping<deal_II_dimension,deal_II_space_dimension> &, - const DoFHandler<deal_II_dimension,deal_II_space_dimension> &, - const Quadrature<deal_II_dimension> &, - const Function<deal_II_space_dimension> &, - Vector<double> &); - - template - void create_right_hand_side<deal_II_dimension,deal_II_space_dimension> - (const DoFHandler<deal_II_dimension,deal_II_space_dimension> &, - const Quadrature<deal_II_dimension> &, - const Function<deal_II_space_dimension> &, - Vector<double> &); - - \} -#endif - } - -//TODO[SP]: replace <deal_II_dimension> by <deal_II_dimension, deal_II_space_dimension> -// where applicable and move to codimension cases above also when applicable -for (deal_II_dimension : DIMENSIONS; deal_II_space_dimension : SPACE_DIMENSIONS) - { - namespace VectorTools \{ - -#if deal_II_dimension <= deal_II_space_dimension - template - void project_boundary_values<deal_II_dimension,deal_II_space_dimension> - (const hp::MappingCollection<deal_II_dimension,deal_II_space_dimension> &, - const hp::DoFHandler<deal_II_dimension,deal_II_space_dimension> &, - const FunctionMap<deal_II_space_dimension>::type &, - const hp::QCollection<deal_II_dimension-1>&, - std::map<types::global_dof_index,double>&, - std::vector<unsigned int>); - - template - void project_boundary_values<deal_II_dimension,deal_II_space_dimension> - (const hp::DoFHandler<deal_II_dimension,deal_II_space_dimension> &, - const FunctionMap<deal_II_space_dimension>::type &, - const hp::QCollection<deal_II_dimension-1>&, - std::map<types::global_dof_index,double>&, - std::vector<unsigned int>); -#endif - -#if deal_II_dimension == deal_II_space_dimension - template - void create_right_hand_side<deal_II_dimension> - (const hp::MappingCollection<deal_II_dimension> &, - const hp::DoFHandler<deal_II_dimension> &, - const hp::QCollection<deal_II_dimension> &, - const Function<deal_II_dimension> &, - Vector<double> &); - - template - void create_right_hand_side<deal_II_dimension> - (const hp::DoFHandler<deal_II_dimension> &, - const hp::QCollection<deal_II_dimension> &, - const Function<deal_II_dimension> &, - Vector<double> &); - - template - void create_point_source_vector<deal_II_dimension> - (const Mapping<deal_II_dimension> &, - const DoFHandler<deal_II_dimension> &, - const Point<deal_II_dimension> &, - Vector<double> &); - template - void create_point_source_vector<deal_II_dimension> - (const DoFHandler<deal_II_dimension> &, - const Point<deal_II_dimension> &, - Vector<double> &); - - template - void create_point_source_vector<deal_II_dimension> - (const hp::MappingCollection<deal_II_dimension> &, - const hp::DoFHandler<deal_II_dimension> &, - const Point<deal_II_dimension> &, - Vector<double> &); - template - void create_point_source_vector<deal_II_dimension> - (const hp::DoFHandler<deal_II_dimension> &, - const Point<deal_II_dimension> &, - Vector<double> &); - template - void create_point_source_vector<deal_II_dimension> - (const Mapping<deal_II_dimension> &, - const DoFHandler<deal_II_dimension> &, - const Point<deal_II_dimension> &, - const Point<deal_II_dimension> &, - Vector<double> &); - template - void create_point_source_vector<deal_II_dimension> - (const DoFHandler<deal_II_dimension> &, - const Point<deal_II_dimension> &, - const Point<deal_II_dimension> &, - Vector<double> &); - - template - void create_point_source_vector<deal_II_dimension> - (const hp::MappingCollection<deal_II_dimension> &, - const hp::DoFHandler<deal_II_dimension> &, - const Point<deal_II_dimension> &, - const Point<deal_II_dimension> &, - Vector<double> &); - template - void create_point_source_vector<deal_II_dimension> - (const hp::DoFHandler<deal_II_dimension> &, - const Point<deal_II_dimension> &, - const Point<deal_II_dimension> &, - Vector<double> &); - -#if deal_II_dimension > 1 - template - void - create_boundary_right_hand_side<deal_II_dimension> - (const Mapping<deal_II_dimension> &, - const DoFHandler<deal_II_dimension> &, - const Quadrature<deal_II_dimension-1> &, - const Function<deal_II_dimension> &, - Vector<double> &, - const std::set<types::boundary_id> &); -#endif - - template - void - create_boundary_right_hand_side<deal_II_dimension> - (const DoFHandler<deal_II_dimension> &, - const Quadrature<deal_II_dimension-1> &, - const Function<deal_II_dimension> &, - Vector<double> &, - const std::set<types::boundary_id> &); - -#if deal_II_dimension > 1 - template - void - create_boundary_right_hand_side<deal_II_dimension> - (const hp::MappingCollection<deal_II_dimension> &, - const hp::DoFHandler<deal_II_dimension> &, - const hp::QCollection<deal_II_dimension-1> &, - const Function<deal_II_dimension> &, - Vector<double> &, - const std::set<types::boundary_id> &); -#endif - - template - void - create_boundary_right_hand_side<deal_II_dimension> - (const hp::DoFHandler<deal_II_dimension> &, - const hp::QCollection<deal_II_dimension-1> &, - const Function<deal_II_dimension> &, - Vector<double> &, - const std::set<types::boundary_id> &); - - - - - - template - void project_boundary_values<deal_II_dimension> - (const Mapping<deal_II_dimension> &, - const DoFHandler<deal_II_dimension> &, - const FunctionMap<deal_II_dimension>::type &, - const Quadrature<deal_II_dimension-1>&, - std::map<types::global_dof_index,double>&, std::vector<unsigned int>); - - template - void project_boundary_values<deal_II_dimension> - (const DoFHandler<deal_II_dimension> &, - const FunctionMap<deal_II_dimension>::type &, - const Quadrature<deal_II_dimension-1>&, - std::map<types::global_dof_index,double>&, - std::vector<unsigned int>); - - template - void project_boundary_values<deal_II_dimension> - (const Mapping<deal_II_dimension> &, - const DoFHandler<deal_II_dimension> &, - const FunctionMap<deal_II_dimension>::type &, - const Quadrature<deal_II_dimension-1>&, - ConstraintMatrix&, std::vector<unsigned int>); - - template - void project_boundary_values<deal_II_dimension> - (const DoFHandler<deal_II_dimension> &, - const FunctionMap<deal_II_dimension>::type &, - const Quadrature<deal_II_dimension-1>&, - ConstraintMatrix&, - std::vector<unsigned int>); - - - -#if deal_II_dimension != 1 - template - void project_boundary_values_curl_conforming<deal_II_dimension> - (const DoFHandler<deal_II_dimension>&, - const unsigned int, - const Function<deal_II_dimension>&, - const types::boundary_id, - ConstraintMatrix&, - const Mapping<deal_II_dimension>&); - template - void project_boundary_values_curl_conforming<deal_II_dimension> - (const hp::DoFHandler<deal_II_dimension>&, - const unsigned int, - const Function<deal_II_dimension>&, - const types::boundary_id, - ConstraintMatrix&, - const hp::MappingCollection<deal_II_dimension>&); - template - void project_boundary_values_div_conforming<deal_II_dimension> - (const DoFHandler<deal_II_dimension>&, - const unsigned int, - const Function<deal_II_dimension>&, - const types::boundary_id, - ConstraintMatrix&, - const Mapping<deal_II_dimension>&); - template - void project_boundary_values_div_conforming<deal_II_dimension> - (const hp::DoFHandler<deal_II_dimension>&, - const unsigned int, - const Function<deal_II_dimension>&, - const types::boundary_id, - ConstraintMatrix&, - const hp::MappingCollection<deal_II_dimension>&); - template - void - compute_no_normal_flux_constraints (const DoFHandler<deal_II_dimension> &dof_handler, - const unsigned int first_vector_component, - const std::set<types::boundary_id> &boundary_ids, - ConstraintMatrix &constraints, - const Mapping<deal_II_dimension> &mapping); - template - void - compute_no_normal_flux_constraints (const hp::DoFHandler<deal_II_dimension> &dof_handler, - const unsigned int first_vector_component, - const std::set<types::boundary_id> &boundary_ids, - ConstraintMatrix &constraints, - const Mapping<deal_II_dimension> &mapping); -#endif -#endif - \} - } - - - -for (deal_II_dimension : DIMENSIONS) -{ - namespace VectorTools \{ - - template - void interpolate_to_different_mesh - (const DoFHandler<deal_II_dimension> &, - const Vector<float> &, - const DoFHandler<deal_II_dimension> &, - Vector<float> &); - - template - void interpolate_to_different_mesh - (const DoFHandler<deal_II_dimension> &, - const Vector<float> &, - const DoFHandler<deal_II_dimension> &, - const ConstraintMatrix &, - Vector<float> &); - - template - void interpolate_to_different_mesh - (const InterGridMap<DoFHandler<deal_II_dimension> > &, - const Vector<float> &, - const ConstraintMatrix &, - Vector<float> &); - - template - void interpolate_to_different_mesh - (const DoFHandler<deal_II_dimension> &, - const Vector<double> &, - const DoFHandler<deal_II_dimension> &, - Vector<double> &); - - template - void interpolate_to_different_mesh - (const DoFHandler<deal_II_dimension> &, - const Vector<double> &, - const DoFHandler<deal_II_dimension> &, - const ConstraintMatrix &, - Vector<double> &); - - template - void interpolate_to_different_mesh - (const InterGridMap<DoFHandler<deal_II_dimension> > &, - const Vector<double> &, - const ConstraintMatrix &, - Vector<double> &); - - \} -} - - diff --git a/deal.II/source/numerics/vector_tools_boundary.cc b/deal.II/source/numerics/vector_tools_boundary.cc new file mode 100644 index 0000000000..6ecf213c9c --- /dev/null +++ b/deal.II/source/numerics/vector_tools_boundary.cc @@ -0,0 +1,25 @@ +// --------------------------------------------------------------------- +// $Id$ +// +// Copyright (C) 1998 - 2013 by the deal.II authors +// +// This file is part of the deal.II library. +// +// The deal.II library is free software; you can use it, redistribute +// it, and/or modify it under the terms of the GNU Lesser General +// Public License as published by the Free Software Foundation; either +// version 2.1 of the License, or (at your option) any later version. +// The full text of the license can be found in the file LICENSE at +// the top level of the deal.II distribution. +// +// --------------------------------------------------------------------- + + +#include <deal.II/numerics/vector_tools.templates.h> + +DEAL_II_NAMESPACE_OPEN + +// ---------------------------- explicit instantiations -------------------- +#include "vector_tools_boundary.inst" + +DEAL_II_NAMESPACE_CLOSE diff --git a/deal.II/source/numerics/vector_tools_boundary.inst.in b/deal.II/source/numerics/vector_tools_boundary.inst.in new file mode 100644 index 0000000000..813f195003 --- /dev/null +++ b/deal.II/source/numerics/vector_tools_boundary.inst.in @@ -0,0 +1,186 @@ +// --------------------------------------------------------------------- +// $Id$ +// +// Copyright (C) 1998 - 2013 by the deal.II authors +// +// This file is part of the deal.II library. +// +// The deal.II library is free software; you can use it, redistribute +// it, and/or modify it under the terms of the GNU Lesser General +// Public License as published by the Free Software Foundation; either +// version 2.1 of the License, or (at your option) any later version. +// The full text of the license can be found in the file LICENSE at +// the top level of the deal.II distribution. +// +// --------------------------------------------------------------------- + + +for (deal_II_dimension : DIMENSIONS) +{ + namespace VectorTools \{ + template + void interpolate_boundary_values ( + const MGDoFHandler<deal_II_dimension> &, + const types::boundary_id, + const Function<deal_II_dimension> &, + ConstraintMatrix&, + const ComponentMask &); + + template + void interpolate_boundary_values ( + const MGDoFHandler<deal_II_dimension> &, + const types::boundary_id, + const Function<deal_II_dimension> &, + std::map<types::global_dof_index,double> &, + const ComponentMask &); + \} +} + + +for (deal_II_dimension : DIMENSIONS; deal_II_space_dimension : SPACE_DIMENSIONS; DH : DOFHANDLER_TEMPLATES) + { +#if deal_II_dimension <= deal_II_space_dimension + namespace VectorTools \{ + template + void interpolate_boundary_values + (const Mapping<deal_II_dimension,deal_II_space_dimension> &, + const DH<deal_II_dimension,deal_II_space_dimension> &, + const FunctionMap<deal_II_space_dimension>::type &, + std::map<types::global_dof_index,double> &, + const ComponentMask &); + + template + void interpolate_boundary_values + (const Mapping<deal_II_dimension,deal_II_space_dimension> &, + const DH<deal_II_dimension,deal_II_space_dimension> &, + const types::boundary_id, + const Function<deal_II_space_dimension> &, + std::map<types::global_dof_index,double> &, + const ComponentMask &); + + template + void interpolate_boundary_values ( + const DH<deal_II_dimension,deal_II_space_dimension> &, + const types::boundary_id, + const Function<deal_II_space_dimension> &, + std::map<types::global_dof_index,double> &, + const ComponentMask &); + + template + void interpolate_boundary_values + (const DH<deal_II_dimension,deal_II_space_dimension> &, + const FunctionMap<deal_II_space_dimension>::type &, + std::map<types::global_dof_index,double> &, + const ComponentMask &); + + template + void interpolate_boundary_values ( + const Mapping<deal_II_dimension,deal_II_space_dimension> &, + const DH<deal_II_dimension,deal_II_space_dimension> &, + const FunctionMap<deal_II_space_dimension>::type &, + ConstraintMatrix &, + const ComponentMask &); + + template + void interpolate_boundary_values + (const Mapping<deal_II_dimension,deal_II_space_dimension> &, + const DH<deal_II_dimension,deal_II_space_dimension> &, + const types::boundary_id, + const Function<deal_II_space_dimension> &, + ConstraintMatrix &, + const ComponentMask &); + + template + void interpolate_boundary_values ( + const DH<deal_II_dimension,deal_II_space_dimension> &, + const types::boundary_id, + const Function<deal_II_space_dimension> &, + ConstraintMatrix &, + const ComponentMask &); + + template + void interpolate_boundary_values ( + const DH<deal_II_dimension,deal_II_space_dimension> &, + const FunctionMap<deal_II_space_dimension>::type &, + ConstraintMatrix &, + const ComponentMask &); + \} +#endif +} + +for (deal_II_dimension : DIMENSIONS; deal_II_space_dimension : SPACE_DIMENSIONS) + { + namespace VectorTools \{ +#if deal_II_dimension == deal_II_space_dimension + + template + void project_boundary_values<deal_II_dimension> + (const Mapping<deal_II_dimension> &, + const DoFHandler<deal_II_dimension> &, + const FunctionMap<deal_II_dimension>::type &, + const Quadrature<deal_II_dimension-1>&, + std::map<types::global_dof_index,double>&, std::vector<unsigned int>); + + template + void project_boundary_values<deal_II_dimension> + (const DoFHandler<deal_II_dimension> &, + const FunctionMap<deal_II_dimension>::type &, + const Quadrature<deal_II_dimension-1>&, + std::map<types::global_dof_index,double>&, + std::vector<unsigned int>); + + template + void project_boundary_values<deal_II_dimension> + (const Mapping<deal_II_dimension> &, + const DoFHandler<deal_II_dimension> &, + const FunctionMap<deal_II_dimension>::type &, + const Quadrature<deal_II_dimension-1>&, + ConstraintMatrix&, std::vector<unsigned int>); + + template + void project_boundary_values<deal_II_dimension> + (const DoFHandler<deal_II_dimension> &, + const FunctionMap<deal_II_dimension>::type &, + const Quadrature<deal_II_dimension-1>&, + ConstraintMatrix&, + std::vector<unsigned int>); + + + +#if deal_II_dimension != 1 + template + void project_boundary_values_curl_conforming<deal_II_dimension> + (const DoFHandler<deal_II_dimension>&, + const unsigned int, + const Function<deal_II_dimension>&, + const types::boundary_id, + ConstraintMatrix&, + const Mapping<deal_II_dimension>&); + template + void project_boundary_values_curl_conforming<deal_II_dimension> + (const hp::DoFHandler<deal_II_dimension>&, + const unsigned int, + const Function<deal_II_dimension>&, + const types::boundary_id, + ConstraintMatrix&, + const hp::MappingCollection<deal_II_dimension>&); + template + void project_boundary_values_div_conforming<deal_II_dimension> + (const DoFHandler<deal_II_dimension>&, + const unsigned int, + const Function<deal_II_dimension>&, + const types::boundary_id, + ConstraintMatrix&, + const Mapping<deal_II_dimension>&); + template + void project_boundary_values_div_conforming<deal_II_dimension> + (const hp::DoFHandler<deal_II_dimension>&, + const unsigned int, + const Function<deal_II_dimension>&, + const types::boundary_id, + ConstraintMatrix&, + const hp::MappingCollection<deal_II_dimension>&); +#endif +#endif + \} + } diff --git a/deal.II/source/numerics/vector_tools_constraints.cc b/deal.II/source/numerics/vector_tools_constraints.cc new file mode 100644 index 0000000000..1ec77ec3e5 --- /dev/null +++ b/deal.II/source/numerics/vector_tools_constraints.cc @@ -0,0 +1,25 @@ +// --------------------------------------------------------------------- +// $Id$ +// +// Copyright (C) 1998 - 2013 by the deal.II authors +// +// This file is part of the deal.II library. +// +// The deal.II library is free software; you can use it, redistribute +// it, and/or modify it under the terms of the GNU Lesser General +// Public License as published by the Free Software Foundation; either +// version 2.1 of the License, or (at your option) any later version. +// The full text of the license can be found in the file LICENSE at +// the top level of the deal.II distribution. +// +// --------------------------------------------------------------------- + + +#include <deal.II/numerics/vector_tools.templates.h> + +DEAL_II_NAMESPACE_OPEN + +// ---------------------------- explicit instantiations -------------------- +#include "vector_tools_constraints.inst" + +DEAL_II_NAMESPACE_CLOSE diff --git a/deal.II/source/numerics/vector_tools_constraints.inst.in b/deal.II/source/numerics/vector_tools_constraints.inst.in new file mode 100644 index 0000000000..f3bfa2a7d3 --- /dev/null +++ b/deal.II/source/numerics/vector_tools_constraints.inst.in @@ -0,0 +1,58 @@ +// --------------------------------------------------------------------- +// $Id$ +// +// Copyright (C) 1998 - 2013 by the deal.II authors +// +// This file is part of the deal.II library. +// +// The deal.II library is free software; you can use it, redistribute +// it, and/or modify it under the terms of the GNU Lesser General +// Public License as published by the Free Software Foundation; either +// version 2.1 of the License, or (at your option) any later version. +// The full text of the license can be found in the file LICENSE at +// the top level of the deal.II distribution. +// +// --------------------------------------------------------------------- + + +//TODO[SP]: replace <deal_II_dimension> by <deal_II_dimension, deal_II_space_dimension> +// where applicable and move to codimension cases above also when applicable +for (deal_II_dimension : DIMENSIONS; deal_II_space_dimension : SPACE_DIMENSIONS) + { + namespace VectorTools \{ + +#if deal_II_dimension == deal_II_space_dimension +#if deal_II_dimension != 1 + template + void + compute_no_normal_flux_constraints (const DoFHandler<deal_II_dimension> &dof_handler, + const unsigned int first_vector_component, + const std::set<types::boundary_id> &boundary_ids, + ConstraintMatrix &constraints, + const Mapping<deal_II_dimension> &mapping); + template + void + compute_no_normal_flux_constraints (const hp::DoFHandler<deal_II_dimension> &dof_handler, + const unsigned int first_vector_component, + const std::set<types::boundary_id> &boundary_ids, + ConstraintMatrix &constraints, + const Mapping<deal_II_dimension> &mapping); + + template + void + compute_normal_flux_constraints (const DoFHandler<deal_II_dimension> &dof_handler, + const unsigned int first_vector_component, + const std::set<types::boundary_id> &boundary_ids, + ConstraintMatrix &constraints, + const Mapping<deal_II_dimension> &mapping); + template + void + compute_normal_flux_constraints (const hp::DoFHandler<deal_II_dimension> &dof_handler, + const unsigned int first_vector_component, + const std::set<types::boundary_id> &boundary_ids, + ConstraintMatrix &constraints, + const Mapping<deal_II_dimension> &mapping); +#endif +#endif + \} + } diff --git a/deal.II/source/numerics/vector_tools_integrate_difference.cc b/deal.II/source/numerics/vector_tools_integrate_difference.cc new file mode 100644 index 0000000000..4e6e8e6888 --- /dev/null +++ b/deal.II/source/numerics/vector_tools_integrate_difference.cc @@ -0,0 +1,25 @@ +// --------------------------------------------------------------------- +// $Id$ +// +// Copyright (C) 1998 - 2013 by the deal.II authors +// +// This file is part of the deal.II library. +// +// The deal.II library is free software; you can use it, redistribute +// it, and/or modify it under the terms of the GNU Lesser General +// Public License as published by the Free Software Foundation; either +// version 2.1 of the License, or (at your option) any later version. +// The full text of the license can be found in the file LICENSE at +// the top level of the deal.II distribution. +// +// --------------------------------------------------------------------- + + +#include <deal.II/numerics/vector_tools.templates.h> + +DEAL_II_NAMESPACE_OPEN + +// ---------------------------- explicit instantiations -------------------- +#include "vector_tools_integrate_difference.inst" + +DEAL_II_NAMESPACE_CLOSE diff --git a/deal.II/source/numerics/vector_tools_integrate_difference.inst.in b/deal.II/source/numerics/vector_tools_integrate_difference.inst.in new file mode 100644 index 0000000000..4ad4fe0ec4 --- /dev/null +++ b/deal.II/source/numerics/vector_tools_integrate_difference.inst.in @@ -0,0 +1,117 @@ +// --------------------------------------------------------------------- +// $Id$ +// +// Copyright (C) 1998 - 2013 by the deal.II authors +// +// This file is part of the deal.II library. +// +// The deal.II library is free software; you can use it, redistribute +// it, and/or modify it under the terms of the GNU Lesser General +// Public License as published by the Free Software Foundation; either +// version 2.1 of the License, or (at your option) any later version. +// The full text of the license can be found in the file LICENSE at +// the top level of the deal.II distribution. +// +// --------------------------------------------------------------------- + + +for (VEC : SERIAL_VECTORS ; deal_II_dimension : DIMENSIONS; deal_II_space_dimension : SPACE_DIMENSIONS) + { +#if deal_II_dimension <= deal_II_space_dimension + namespace VectorTools \{ + + template + void integrate_difference<deal_II_dimension, VEC, Vector<float>, deal_II_space_dimension> + (const Mapping<deal_II_dimension, deal_II_space_dimension>&, + const DoFHandler<deal_II_dimension, deal_II_space_dimension>&, + const VEC&, + const Function<deal_II_space_dimension>&, + Vector<float>&, + const Quadrature<deal_II_dimension>&, + const NormType&, + const Function<deal_II_space_dimension>*, + const double); + + template + void integrate_difference<deal_II_dimension, VEC, Vector<float>, deal_II_space_dimension> + (const DoFHandler<deal_II_dimension, deal_II_space_dimension>&, + const VEC&, + const Function<deal_II_space_dimension>&, + Vector<float>&, + const Quadrature<deal_II_dimension>&, + const NormType&, + const Function<deal_II_space_dimension>*, + const double); + + template + void integrate_difference<deal_II_dimension, VEC, Vector<double>, deal_II_space_dimension > + (const Mapping<deal_II_dimension, deal_II_space_dimension>&, + const DoFHandler<deal_II_dimension, deal_II_space_dimension>&, + const VEC&, + const Function<deal_II_space_dimension>&, + Vector<double>&, + const Quadrature<deal_II_dimension>&, + const NormType&, + const Function<deal_II_space_dimension>*, + const double); + + template + void integrate_difference<deal_II_dimension, VEC, Vector<double>, deal_II_space_dimension > + (const DoFHandler<deal_II_dimension, deal_II_space_dimension>&, + const VEC&, + const Function<deal_II_space_dimension>&, + Vector<double>&, + const Quadrature<deal_II_dimension>&, + const NormType&, + const Function<deal_II_space_dimension>*, + const double); + + template + void integrate_difference<deal_II_dimension, VEC, Vector<double>, deal_II_space_dimension> + (const hp::MappingCollection<deal_II_dimension,deal_II_space_dimension>&, + const hp::DoFHandler<deal_II_dimension,deal_II_space_dimension>&, + const VEC&, + const Function<deal_II_space_dimension>&, + Vector<double>&, + const hp::QCollection<deal_II_dimension>&, + const NormType&, + const Function<deal_II_space_dimension>*, + const double); + + template + void integrate_difference<deal_II_dimension, VEC, Vector<double>, deal_II_space_dimension> + (const hp::DoFHandler<deal_II_dimension,deal_II_space_dimension>&, + const VEC&, + const Function<deal_II_space_dimension>&, + Vector<double>&, + const hp::QCollection<deal_II_dimension>&, + const NormType&, + const Function<deal_II_space_dimension>*, + const double); + + template + void integrate_difference<deal_II_dimension, VEC, Vector<float>, deal_II_space_dimension> + (const hp::MappingCollection<deal_II_dimension,deal_II_space_dimension>&, + const hp::DoFHandler<deal_II_dimension,deal_II_space_dimension>&, + const VEC&, + const Function<deal_II_space_dimension>&, + Vector<float>&, + const hp::QCollection<deal_II_dimension>&, + const NormType&, + const Function<deal_II_space_dimension>*, + const double); + + template + void integrate_difference<deal_II_dimension, VEC, Vector<float>, deal_II_space_dimension> + (const hp::DoFHandler<deal_II_dimension,deal_II_space_dimension>&, + const VEC&, + const Function<deal_II_space_dimension>&, + Vector<float>&, + const hp::QCollection<deal_II_dimension>&, + const NormType&, + const Function<deal_II_space_dimension>*, + const double); + + \} +#endif + } diff --git a/deal.II/source/numerics/vector_tools_interpolate.cc b/deal.II/source/numerics/vector_tools_interpolate.cc new file mode 100644 index 0000000000..3d57d8890c --- /dev/null +++ b/deal.II/source/numerics/vector_tools_interpolate.cc @@ -0,0 +1,25 @@ +// --------------------------------------------------------------------- +// $Id$ +// +// Copyright (C) 1998 - 2013 by the deal.II authors +// +// This file is part of the deal.II library. +// +// The deal.II library is free software; you can use it, redistribute +// it, and/or modify it under the terms of the GNU Lesser General +// Public License as published by the Free Software Foundation; either +// version 2.1 of the License, or (at your option) any later version. +// The full text of the license can be found in the file LICENSE at +// the top level of the deal.II distribution. +// +// --------------------------------------------------------------------- + + +#include <deal.II/numerics/vector_tools.templates.h> + +DEAL_II_NAMESPACE_OPEN + +// ---------------------------- explicit instantiations -------------------- +#include "vector_tools_interpolate.inst" + +DEAL_II_NAMESPACE_CLOSE diff --git a/deal.II/source/numerics/vector_tools_interpolate.inst.in b/deal.II/source/numerics/vector_tools_interpolate.inst.in new file mode 100644 index 0000000000..5eba56a30f --- /dev/null +++ b/deal.II/source/numerics/vector_tools_interpolate.inst.in @@ -0,0 +1,199 @@ +// --------------------------------------------------------------------- +// $Id$ +// +// Copyright (C) 1998 - 2013 by the deal.II authors +// +// This file is part of the deal.II library. +// +// The deal.II library is free software; you can use it, redistribute +// it, and/or modify it under the terms of the GNU Lesser General +// Public License as published by the Free Software Foundation; either +// version 2.1 of the License, or (at your option) any later version. +// The full text of the license can be found in the file LICENSE at +// the top level of the deal.II distribution. +// +// --------------------------------------------------------------------- + + +for (VEC : SERIAL_VECTORS ; deal_II_dimension : DIMENSIONS; deal_II_space_dimension : SPACE_DIMENSIONS) + { +#if deal_II_dimension <= deal_II_space_dimension + namespace VectorTools \{ + + template + void interpolate + (const Mapping<deal_II_dimension,deal_II_space_dimension>&, + const DoFHandler<deal_II_dimension,deal_II_space_dimension>&, + const Function<deal_II_space_dimension>&, + VEC&); + + template + void interpolate + (const DoFHandler<deal_II_dimension,deal_II_space_dimension>&, + const Function<deal_II_space_dimension>&, + VEC&); + \} +#endif + } + + + +//TODO[SP]: replace <deal_II_dimension> by <deal_II_dimension, deal_II_space_dimension> +// where applicable and move to codimension cases above also when applicable +for (VEC : SERIAL_VECTORS ; deal_II_dimension : DIMENSIONS; deal_II_space_dimension : SPACE_DIMENSIONS) + { +#if deal_II_dimension == deal_II_space_dimension + + namespace VectorTools \{ + + template + void interpolate + (const Mapping<deal_II_dimension>&, + const hp::DoFHandler<deal_II_dimension>&, + const Function<deal_II_dimension>&, + VEC&); + template + void interpolate + (const hp::DoFHandler<deal_II_dimension>&, + const Function<deal_II_dimension>&, + VEC&); + + template + void interpolate + (const DoFHandler<deal_II_dimension>&, + const DoFHandler<deal_II_dimension>&, + const FullMatrix<double>&, + const VEC&, + VEC&); + \} +#endif + } + + + +for (deal_II_dimension : DIMENSIONS; deal_II_space_dimension : SPACE_DIMENSIONS; DH : DOFHANDLER_TEMPLATES) + { +#if deal_II_dimension <= deal_II_space_dimension + namespace VectorTools \{ + template + void interpolate_boundary_values + (const Mapping<deal_II_dimension,deal_II_space_dimension> &, + const DH<deal_II_dimension,deal_II_space_dimension> &, + const FunctionMap<deal_II_space_dimension>::type &, + std::map<types::global_dof_index,double> &, + const ComponentMask &); + + template + void interpolate_boundary_values + (const Mapping<deal_II_dimension,deal_II_space_dimension> &, + const DH<deal_II_dimension,deal_II_space_dimension> &, + const types::boundary_id, + const Function<deal_II_space_dimension> &, + std::map<types::global_dof_index,double> &, + const ComponentMask &); + + template + void interpolate_boundary_values ( + const DH<deal_II_dimension,deal_II_space_dimension> &, + const types::boundary_id, + const Function<deal_II_space_dimension> &, + std::map<types::global_dof_index,double> &, + const ComponentMask &); + + template + void interpolate_boundary_values + (const DH<deal_II_dimension,deal_II_space_dimension> &, + const FunctionMap<deal_II_space_dimension>::type &, + std::map<types::global_dof_index,double> &, + const ComponentMask &); + + template + void interpolate_boundary_values ( + const Mapping<deal_II_dimension,deal_II_space_dimension> &, + const DH<deal_II_dimension,deal_II_space_dimension> &, + const FunctionMap<deal_II_space_dimension>::type &, + ConstraintMatrix &, + const ComponentMask &); + + template + void interpolate_boundary_values + (const Mapping<deal_II_dimension,deal_II_space_dimension> &, + const DH<deal_II_dimension,deal_II_space_dimension> &, + const types::boundary_id, + const Function<deal_II_space_dimension> &, + ConstraintMatrix &, + const ComponentMask &); + + template + void interpolate_boundary_values ( + const DH<deal_II_dimension,deal_II_space_dimension> &, + const types::boundary_id, + const Function<deal_II_space_dimension> &, + ConstraintMatrix &, + const ComponentMask &); + + template + void interpolate_boundary_values ( + const DH<deal_II_dimension,deal_II_space_dimension> &, + const FunctionMap<deal_II_space_dimension>::type &, + ConstraintMatrix &, + const ComponentMask &); + + \} +#endif + } + + + +for (deal_II_dimension : DIMENSIONS) +{ + namespace VectorTools \{ + + template + void interpolate_to_different_mesh + (const DoFHandler<deal_II_dimension> &, + const Vector<float> &, + const DoFHandler<deal_II_dimension> &, + Vector<float> &); + + template + void interpolate_to_different_mesh + (const DoFHandler<deal_II_dimension> &, + const Vector<float> &, + const DoFHandler<deal_II_dimension> &, + const ConstraintMatrix &, + Vector<float> &); + + template + void interpolate_to_different_mesh + (const InterGridMap<DoFHandler<deal_II_dimension> > &, + const Vector<float> &, + const ConstraintMatrix &, + Vector<float> &); + + template + void interpolate_to_different_mesh + (const DoFHandler<deal_II_dimension> &, + const Vector<double> &, + const DoFHandler<deal_II_dimension> &, + Vector<double> &); + + template + void interpolate_to_different_mesh + (const DoFHandler<deal_II_dimension> &, + const Vector<double> &, + const DoFHandler<deal_II_dimension> &, + const ConstraintMatrix &, + Vector<double> &); + + template + void interpolate_to_different_mesh + (const InterGridMap<DoFHandler<deal_II_dimension> > &, + const Vector<double> &, + const ConstraintMatrix &, + Vector<double> &); + + \} +} + + diff --git a/deal.II/source/numerics/vector_tools_mean_value.cc b/deal.II/source/numerics/vector_tools_mean_value.cc new file mode 100644 index 0000000000..a907916a06 --- /dev/null +++ b/deal.II/source/numerics/vector_tools_mean_value.cc @@ -0,0 +1,25 @@ +// --------------------------------------------------------------------- +// $Id$ +// +// Copyright (C) 1998 - 2013 by the deal.II authors +// +// This file is part of the deal.II library. +// +// The deal.II library is free software; you can use it, redistribute +// it, and/or modify it under the terms of the GNU Lesser General +// Public License as published by the Free Software Foundation; either +// version 2.1 of the License, or (at your option) any later version. +// The full text of the license can be found in the file LICENSE at +// the top level of the deal.II distribution. +// +// --------------------------------------------------------------------- + + +#include <deal.II/numerics/vector_tools.templates.h> + +DEAL_II_NAMESPACE_OPEN + +// ---------------------------- explicit instantiations -------------------- +#include "vector_tools_mean_value.inst" + +DEAL_II_NAMESPACE_CLOSE diff --git a/deal.II/source/numerics/vector_tools_mean_value.inst.in b/deal.II/source/numerics/vector_tools_mean_value.inst.in new file mode 100644 index 0000000000..89e5be1545 --- /dev/null +++ b/deal.II/source/numerics/vector_tools_mean_value.inst.in @@ -0,0 +1,50 @@ +// --------------------------------------------------------------------- +// $Id$ +// +// Copyright (C) 1998 - 2013 by the deal.II authors +// +// This file is part of the deal.II library. +// +// The deal.II library is free software; you can use it, redistribute +// it, and/or modify it under the terms of the GNU Lesser General +// Public License as published by the Free Software Foundation; either +// version 2.1 of the License, or (at your option) any later version. +// The full text of the license can be found in the file LICENSE at +// the top level of the deal.II distribution. +// +// --------------------------------------------------------------------- + + +for (VEC : SERIAL_VECTORS ; deal_II_dimension : DIMENSIONS; deal_II_space_dimension : SPACE_DIMENSIONS) + { +#if deal_II_dimension <= deal_II_space_dimension + namespace VectorTools \{ + + template + double compute_mean_value<deal_II_dimension> + (const Mapping<deal_II_dimension,deal_II_space_dimension>&, + const DoFHandler<deal_II_dimension,deal_II_space_dimension>&, + const Quadrature<deal_II_dimension>&, + const VEC&, + const unsigned int); + + template + double compute_mean_value<deal_II_dimension> + (const DoFHandler<deal_II_dimension,deal_II_space_dimension>&, + const Quadrature<deal_II_dimension>&, + const VEC&, + const unsigned int); + + \} +#endif + } + + + +for (VEC : SERIAL_VECTORS) +{ + namespace VectorTools \{ + template + void subtract_mean_value(VEC &, const std::vector<bool> &); + \} +} diff --git a/deal.II/source/numerics/vector_tools_point_value.cc b/deal.II/source/numerics/vector_tools_point_value.cc new file mode 100644 index 0000000000..e5a0c30edd --- /dev/null +++ b/deal.II/source/numerics/vector_tools_point_value.cc @@ -0,0 +1,25 @@ +// --------------------------------------------------------------------- +// $Id$ +// +// Copyright (C) 1998 - 2013 by the deal.II authors +// +// This file is part of the deal.II library. +// +// The deal.II library is free software; you can use it, redistribute +// it, and/or modify it under the terms of the GNU Lesser General +// Public License as published by the Free Software Foundation; either +// version 2.1 of the License, or (at your option) any later version. +// The full text of the license can be found in the file LICENSE at +// the top level of the deal.II distribution. +// +// --------------------------------------------------------------------- + + +#include <deal.II/numerics/vector_tools.templates.h> + +DEAL_II_NAMESPACE_OPEN + +// ---------------------------- explicit instantiations -------------------- +#include "vector_tools_point_value.inst" + +DEAL_II_NAMESPACE_CLOSE diff --git a/deal.II/source/numerics/vector_tools_point_value.inst.in b/deal.II/source/numerics/vector_tools_point_value.inst.in new file mode 100644 index 0000000000..8dd47f73e0 --- /dev/null +++ b/deal.II/source/numerics/vector_tools_point_value.inst.in @@ -0,0 +1,165 @@ +// --------------------------------------------------------------------- +// $Id$ +// +// Copyright (C) 1998 - 2013 by the deal.II authors +// +// This file is part of the deal.II library. +// +// The deal.II library is free software; you can use it, redistribute +// it, and/or modify it under the terms of the GNU Lesser General +// Public License as published by the Free Software Foundation; either +// version 2.1 of the License, or (at your option) any later version. +// The full text of the license can be found in the file LICENSE at +// the top level of the deal.II distribution. +// +// --------------------------------------------------------------------- + + +//TODO[SP]: replace <deal_II_dimension> by <deal_II_dimension, deal_II_space_dimension> +// where applicable and move to codimension cases above also when applicable +for (VEC : SERIAL_VECTORS ; deal_II_dimension : DIMENSIONS; deal_II_space_dimension : SPACE_DIMENSIONS) + { +#if deal_II_dimension == deal_II_space_dimension + + namespace VectorTools \{ + + template + void point_value<deal_II_dimension> ( + const hp::DoFHandler<deal_II_dimension>&, + const VEC&, + const Point<deal_II_dimension>&, + Vector<double>&); + + template + double point_value<deal_II_dimension> ( + const hp::DoFHandler<deal_II_dimension>&, + const VEC&, + const Point<deal_II_dimension>&); + + template + void point_value<deal_II_dimension> ( + const hp::MappingCollection<deal_II_dimension>&, + const hp::DoFHandler<deal_II_dimension>&, + const VEC&, + const Point<deal_II_dimension>&, + Vector<double>&); + + template + double point_value<deal_II_dimension> ( + const hp::MappingCollection<deal_II_dimension>&, + const hp::DoFHandler<deal_II_dimension>&, + const VEC&, + const Point<deal_II_dimension>&); + + template + void point_difference<deal_II_dimension> ( + const DoFHandler<deal_II_dimension>&, + const VEC&, + const Function<deal_II_dimension>&, + Vector<double>&, + const Point<deal_II_dimension>&); + + template + void point_difference<deal_II_dimension> ( + const Mapping<deal_II_dimension>&, + const DoFHandler<deal_II_dimension>&, + const VEC&, + const Function<deal_II_dimension>&, + Vector<double>&, + const Point<deal_II_dimension>&); + + template + void point_value<deal_II_dimension> ( + const DoFHandler<deal_II_dimension>&, + const VEC&, + const Point<deal_II_dimension>&, + Vector<double>&); + + template + double point_value<deal_II_dimension> ( + const DoFHandler<deal_II_dimension>&, + const VEC&, + const Point<deal_II_dimension>&); + + template + void point_value<deal_II_dimension> ( + const Mapping<deal_II_dimension>&, + const DoFHandler<deal_II_dimension>&, + const VEC&, + const Point<deal_II_dimension>&, + Vector<double>&); + + template + double point_value<deal_II_dimension> ( + const Mapping<deal_II_dimension>&, + const DoFHandler<deal_II_dimension>&, + const VEC&, + const Point<deal_II_dimension>&); + + \} +#endif + } + + + +//TODO[SP]: replace <deal_II_dimension> by <deal_II_dimension, deal_II_space_dimension> +// where applicable and move to codimension cases above also when applicable +for (deal_II_dimension : DIMENSIONS; deal_II_space_dimension : SPACE_DIMENSIONS) + { + namespace VectorTools \{ + +#if deal_II_dimension == deal_II_space_dimension + + template + void create_point_source_vector<deal_II_dimension> + (const Mapping<deal_II_dimension> &, + const DoFHandler<deal_II_dimension> &, + const Point<deal_II_dimension> &, + Vector<double> &); + template + void create_point_source_vector<deal_II_dimension> + (const DoFHandler<deal_II_dimension> &, + const Point<deal_II_dimension> &, + Vector<double> &); + + template + void create_point_source_vector<deal_II_dimension> + (const hp::MappingCollection<deal_II_dimension> &, + const hp::DoFHandler<deal_II_dimension> &, + const Point<deal_II_dimension> &, + Vector<double> &); + template + void create_point_source_vector<deal_II_dimension> + (const hp::DoFHandler<deal_II_dimension> &, + const Point<deal_II_dimension> &, + Vector<double> &); + template + void create_point_source_vector<deal_II_dimension> + (const Mapping<deal_II_dimension> &, + const DoFHandler<deal_II_dimension> &, + const Point<deal_II_dimension> &, + const Point<deal_II_dimension> &, + Vector<double> &); + template + void create_point_source_vector<deal_II_dimension> + (const DoFHandler<deal_II_dimension> &, + const Point<deal_II_dimension> &, + const Point<deal_II_dimension> &, + Vector<double> &); + + template + void create_point_source_vector<deal_II_dimension> + (const hp::MappingCollection<deal_II_dimension> &, + const hp::DoFHandler<deal_II_dimension> &, + const Point<deal_II_dimension> &, + const Point<deal_II_dimension> &, + Vector<double> &); + template + void create_point_source_vector<deal_II_dimension> + (const hp::DoFHandler<deal_II_dimension> &, + const Point<deal_II_dimension> &, + const Point<deal_II_dimension> &, + Vector<double> &); +#endif + \} + } diff --git a/deal.II/source/numerics/vector_tools.cc b/deal.II/source/numerics/vector_tools_project.cc similarity index 95% rename from deal.II/source/numerics/vector_tools.cc rename to deal.II/source/numerics/vector_tools_project.cc index fe9539c1d0..cd5ba6fb7a 100644 --- a/deal.II/source/numerics/vector_tools.cc +++ b/deal.II/source/numerics/vector_tools_project.cc @@ -20,6 +20,6 @@ DEAL_II_NAMESPACE_OPEN // ---------------------------- explicit instantiations -------------------- -#include "vector_tools.inst" +#include "vector_tools_project.inst" DEAL_II_NAMESPACE_CLOSE diff --git a/deal.II/source/numerics/vector_tools_project.inst.in b/deal.II/source/numerics/vector_tools_project.inst.in new file mode 100644 index 0000000000..3dc5d6b3e9 --- /dev/null +++ b/deal.II/source/numerics/vector_tools_project.inst.in @@ -0,0 +1,70 @@ +// --------------------------------------------------------------------- +// $Id$ +// +// Copyright (C) 1998 - 2013 by the deal.II authors +// +// This file is part of the deal.II library. +// +// The deal.II library is free software; you can use it, redistribute +// it, and/or modify it under the terms of the GNU Lesser General +// Public License as published by the Free Software Foundation; either +// version 2.1 of the License, or (at your option) any later version. +// The full text of the license can be found in the file LICENSE at +// the top level of the deal.II distribution. +// +// --------------------------------------------------------------------- + + +for (VEC : SERIAL_VECTORS ; deal_II_dimension : DIMENSIONS; deal_II_space_dimension : SPACE_DIMENSIONS) + { +#if deal_II_dimension <= deal_II_space_dimension + namespace VectorTools \{ + + template + void project + (const Mapping<deal_II_dimension,deal_II_space_dimension> &, + const DoFHandler<deal_II_dimension,deal_II_space_dimension> &, + const ConstraintMatrix &, + const Quadrature<deal_II_dimension> &, + const Function<deal_II_space_dimension> &, + VEC &, + const bool, + const Quadrature<deal_II_dimension-1> &, + const bool); + + template + void project + (const DoFHandler<deal_II_dimension,deal_II_space_dimension> &, + const ConstraintMatrix &, + const Quadrature<deal_II_dimension> &, + const Function<deal_II_space_dimension> &, + VEC &, + const bool, + const Quadrature<deal_II_dimension-1> &, + const bool); + + template + void project + (const hp::MappingCollection<deal_II_dimension,deal_II_space_dimension> &, + const hp::DoFHandler<deal_II_dimension,deal_II_space_dimension> &, + const ConstraintMatrix &, + const hp::QCollection<deal_II_dimension> &, + const Function<deal_II_space_dimension> &, + VEC &, + const bool, + const hp::QCollection<deal_II_dimension-1> &, + const bool); + + template + void project + (const hp::DoFHandler<deal_II_dimension,deal_II_space_dimension> &, + const ConstraintMatrix &, + const hp::QCollection<deal_II_dimension> &, + const Function<deal_II_space_dimension> &, + VEC &, + const bool, + const hp::QCollection<deal_II_dimension-1> &, + const bool); + \} +#endif + } diff --git a/deal.II/source/numerics/vector_tools_rhs.cc b/deal.II/source/numerics/vector_tools_rhs.cc new file mode 100644 index 0000000000..cb12d608e1 --- /dev/null +++ b/deal.II/source/numerics/vector_tools_rhs.cc @@ -0,0 +1,86 @@ +// --------------------------------------------------------------------- +// $Id$ +// +// Copyright (C) 1998 - 2013 by the deal.II authors +// +// This file is part of the deal.II library. +// +// The deal.II library is free software; you can use it, redistribute +// it, and/or modify it under the terms of the GNU Lesser General +// Public License as published by the Free Software Foundation; either +// version 2.1 of the License, or (at your option) any later version. +// The full text of the license can be found in the file LICENSE at +// the top level of the deal.II distribution. +// +// --------------------------------------------------------------------- + + +#include <deal.II/numerics/vector_tools.templates.h> + +DEAL_II_NAMESPACE_OPEN + + +namespace VectorTools +{ + +// separate implementation for 1D because otherwise we get linker errors since +// (hp::)FEFaceValues<1> is not compiled + template <> + void + create_boundary_right_hand_side (const Mapping<1,1> &, + const DoFHandler<1,1> &, + const Quadrature<0> &, + const Function<1> &, + Vector<double> &, + const std::set<types::boundary_id> &) + { + Assert (false, ExcImpossibleInDim(1)); + } + + + + template <> + void + create_boundary_right_hand_side (const Mapping<1,2> &, + const DoFHandler<1,2> &, + const Quadrature<0> &, + const Function<2> &, + Vector<double> &, + const std::set<types::boundary_id> &) + { + Assert (false, ExcImpossibleInDim(1)); + } + + + + template <> + void + create_boundary_right_hand_side (const hp::MappingCollection<1,1> &, + const hp::DoFHandler<1,1> &, + const hp::QCollection<0> &, + const Function<1> &, + Vector<double> &, + const std::set<types::boundary_id> &) + { + Assert (false, ExcImpossibleInDim(1)); + } + + + + template <> + void + create_boundary_right_hand_side (const hp::MappingCollection<1,2> &, + const hp::DoFHandler<1,2> &, + const hp::QCollection<0> &, + const Function<2> &, + Vector<double> &, + const std::set<types::boundary_id> &) + { + Assert (false, ExcImpossibleInDim(1)); + } +} + +// ---------------------------- explicit instantiations -------------------- +#include "vector_tools_rhs.inst" + +DEAL_II_NAMESPACE_CLOSE diff --git a/deal.II/source/numerics/vector_tools_rhs.inst.in b/deal.II/source/numerics/vector_tools_rhs.inst.in new file mode 100644 index 0000000000..aed42a76ec --- /dev/null +++ b/deal.II/source/numerics/vector_tools_rhs.inst.in @@ -0,0 +1,108 @@ +// --------------------------------------------------------------------- +// $Id$ +// +// Copyright (C) 1998 - 2013 by the deal.II authors +// +// This file is part of the deal.II library. +// +// The deal.II library is free software; you can use it, redistribute +// it, and/or modify it under the terms of the GNU Lesser General +// Public License as published by the Free Software Foundation; either +// version 2.1 of the License, or (at your option) any later version. +// The full text of the license can be found in the file LICENSE at +// the top level of the deal.II distribution. +// +// --------------------------------------------------------------------- + + +for (deal_II_dimension : DIMENSIONS; deal_II_space_dimension : SPACE_DIMENSIONS) + { +#if deal_II_dimension <= deal_II_space_dimension + namespace VectorTools \{ + template + void create_right_hand_side<deal_II_dimension,deal_II_space_dimension> + (const Mapping<deal_II_dimension,deal_II_space_dimension> &, + const DoFHandler<deal_II_dimension,deal_II_space_dimension> &, + const Quadrature<deal_II_dimension> &, + const Function<deal_II_space_dimension> &, + Vector<double> &); + + template + void create_right_hand_side<deal_II_dimension,deal_II_space_dimension> + (const DoFHandler<deal_II_dimension,deal_II_space_dimension> &, + const Quadrature<deal_II_dimension> &, + const Function<deal_II_space_dimension> &, + Vector<double> &); + + \} +#endif + } + +//TODO[SP]: replace <deal_II_dimension> by <deal_II_dimension, deal_II_space_dimension> +// where applicable and move to codimension cases above also when applicable +for (deal_II_dimension : DIMENSIONS; deal_II_space_dimension : SPACE_DIMENSIONS) + { + namespace VectorTools \{ + +#if deal_II_dimension == deal_II_space_dimension + template + void create_right_hand_side<deal_II_dimension> + (const hp::MappingCollection<deal_II_dimension> &, + const hp::DoFHandler<deal_II_dimension> &, + const hp::QCollection<deal_II_dimension> &, + const Function<deal_II_dimension> &, + Vector<double> &); + + template + void create_right_hand_side<deal_II_dimension> + (const hp::DoFHandler<deal_II_dimension> &, + const hp::QCollection<deal_II_dimension> &, + const Function<deal_II_dimension> &, + Vector<double> &); + +#if deal_II_dimension > 1 + template + void + create_boundary_right_hand_side<deal_II_dimension> + (const Mapping<deal_II_dimension> &, + const DoFHandler<deal_II_dimension> &, + const Quadrature<deal_II_dimension-1> &, + const Function<deal_II_dimension> &, + Vector<double> &, + const std::set<types::boundary_id> &); +#endif + + template + void + create_boundary_right_hand_side<deal_II_dimension> + (const DoFHandler<deal_II_dimension> &, + const Quadrature<deal_II_dimension-1> &, + const Function<deal_II_dimension> &, + Vector<double> &, + const std::set<types::boundary_id> &); + +#if deal_II_dimension > 1 + template + void + create_boundary_right_hand_side<deal_II_dimension> + (const hp::MappingCollection<deal_II_dimension> &, + const hp::DoFHandler<deal_II_dimension> &, + const hp::QCollection<deal_II_dimension-1> &, + const Function<deal_II_dimension> &, + Vector<double> &, + const std::set<types::boundary_id> &); +#endif + + template + void + create_boundary_right_hand_side<deal_II_dimension> + (const hp::DoFHandler<deal_II_dimension> &, + const hp::QCollection<deal_II_dimension-1> &, + const Function<deal_II_dimension> &, + Vector<double> &, + const std::set<types::boundary_id> &); + + +#endif + \} + } -- 2.39.5