From: heltai Date: Sun, 25 Aug 2013 14:20:31 +0000 (+0000) Subject: Merged from trunk X-Git-Url: https://gitweb.dealii.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=6dc7faf4b5d9218755a7bbb16e9f429b1da62624;p=dealii-svn.git Merged from trunk git-svn-id: https://svn.dealii.org/branches/branch_manifold_id@30480 0785d39b-7218-0410-832d-ea1e28bc413d --- 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() # -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 @@ The deal.II Online Documentation - + + + +

Online documentation

+ + + + +
Table of contents
+ +
+ +

deal.II comes with quite extensive online documentation, which falls into several categories. They are @@ -21,7 +41,7 @@

-

README

+

ReadMe

First, there is the README file of @@ -29,7 +49,7 @@ installation, and copyright.

-

Tutorials

+

Tutorials

The -

Programming interface

+

Programming interface

The programming @@ -81,7 +101,7 @@

-

Development information

+

Development information

If you plan to -

Reports

+

Reports

There are a number of papers that describe the overall design or @@ -183,7 +203,7 @@ -

Publications

+

Publications

A list of @@ -193,7 +213,7 @@

-

Copyright and License

+

Copyright and License

deal.II is copyright of the deal.II authors. 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.
(Wolfgang Bangerth, 2013/08/09) + +

  • + 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. +
    + (Martin Kronbichler, 2013/07/24) +
  • @@ -56,6 +68,77 @@ inconvenience this causes.

    Specific improvements

      +
    1. + Fixed: The ParameterHandler class can now deal with including one parameter + file from another. +
      + (Wolfgang Bangerth, 2013/08/25) +
    2. + +
    3. + New: The method VectorTools::compute_normal_flux_constraints can be used to + force a vector finite element function to be normal to the boundary. +
      + (Martin Kronbichler, 2013/08/23) +
    4. + +
    5. + 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). +
      + (Martin Kronbichler, 2013/08/23) +
    6. + +
    7. + 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. +
      + (Martin Kronbichler, 2013/08/22) +
    8. + +
    9. + 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. +
      + (Wolfgang Bangerth, 2013/08/21) +
    10. + +
    11. + 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. +
      + (Wolfgang Bangerth, 2013/08/21) +
    12. + +
    13. + 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). +
      + (Juan Carlos Araujo Cabarcas, 2013/08/20) +
    14. + +
    15. + Fixed: The SLEPcWrappers classes could not be compiled for 64-bit + indices. This is now fixed. +
      + (Denis Davydov, Wolfgang Bangerth, 2013/08/20) +
    16. + +
    17. + 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. +
      + (Krzyszof Bzowski, Wolfgang Bangerth, 2013/08/18) +
    18. +
    19. 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 p, it uses support points +that are based on the p+1 point Gauss-Lobatto quadrature rule that +selects the support points in such a way that the quadrature rule converges at +order 2p. Even though these points are here only used for interpolation +of a pth 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::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 void Input::read_obstacle(const char* name) { @@ -244,11 +244,11 @@ void Input::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 class ConstitutiveLaw { public: @@ -312,7 +312,8 @@ ConstitutiveLaw::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 inline SymmetricTensor<2, dim> ConstitutiveLaw::get_strain( const FEValues &fe_values, const unsigned int shape_func, @@ -331,7 +332,9 @@ inline SymmetricTensor<2, dim> ConstitutiveLaw::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 void ConstitutiveLaw::plast_linear_hardening( SymmetricTensor<4, dim> &stress_strain_tensor, @@ -364,8 +367,16 @@ void ConstitutiveLaw::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 void ConstitutiveLaw::linearized_plast_linear_hardening( SymmetricTensor<4, dim> &stress_strain_tensor_linearized, @@ -426,7 +437,7 @@ double RightHandSide::value(const Point &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 fe; DoFHandler 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 > soltrans; @@ -1755,10 +1769,24 @@ void PlasticityContactProblem::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 -void PlasticityContactProblem::output_for_benchmark( +void PlasticityContactProblem::output_contact_force( const unsigned int cycle) { Functions::FEFieldFunction, TrilinosWrappers::MPI::Vector> solution_function(dof_handler, @@ -1819,7 +1847,7 @@ void PlasticityContactProblem::output_for_benchmark( typename DoFHandler::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. +

      Reducing the size of the linear system

      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.
    20. Use the local element solutions to construct the global problem for the trace values. These are the only globally coupled unknowns. -
    21. Modify the local solutions from the computed trace values. +
    22. Reconstruct the local solutions from the computed trace values.
    +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 U 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 U 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 +
      +
    1. constructing the Schur complement matrix $D-C A^{-1} B$ and right hand side $G - C A^{-1} F$, +
    2. solving the Schur complement system for $\Lambda$, and +
    3. solving the equation for U using the second equation which uses $\Lambda$. +
    + +The important ingredient from the linear algebra point of view is that the +matrix A 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 +B and C over the skeleton variable. The block-diagonality of +A and the structure in B and C allow us to invert the +matrix A element by element (the local solution of the Dirichelt +problem) and subtract $CA^{-1}B$ from $D$. + +

    Solution quality and rates of convergence

    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 #include #include -#include +#include #include #include #include @@ -738,9 +738,11 @@ Step51::assemble_system_one_cell (const typename DoFHandler::active_ce for (unsigned int q=0; q quadrature_point = + scratch.fe_face_values.quadrature_point(q); const Point 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::assemble_system_one_cell (const typename DoFHandler::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::assemble_system_one_cell (const typename DoFHandler::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 void Step51::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::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 estimated_error_per_cell (triangulation.n_active_cells()); + { + Vector estimated_error_per_cell (triangulation.n_active_cells()); - FEValuesExtractors::Scalar scalar(dim); - typename FunctionMap::type neumann_boundary; - KellyErrorEstimator::estimate (dof_handler_local, - QGauss(3), - neumann_boundary, - solution_local, - estimated_error_per_cell, - fe_local.component_mask(scalar)); + FEValuesExtractors::Scalar scalar(dim); + typename FunctionMap::type neumann_boundary; + KellyErrorEstimator::estimate (dof_handler_local, + QGauss(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::cell_iterator + cell = triangulation.begin (), + endc = triangulation.end(); + for (; cell!=endc; ++cell) + for (unsigned int face=0; face::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 dim space + * Data structure describing a patch of data in dim space * dimensions. * * A patch consists of the following data: *
      *
    • the corner #vertices, - *
    • the number - * #n_subdivisions of the number - * of cells the Patch has in each - * space direction, - *
    • the #data attached to - * each vertex, in the usual + *
    • the number #n_subdivisions of the number of cells the Patch + * has in each space direction, + *
    • the #data attached to each vertex, in the usual * lexicographic ordering, *
    • Information on #neighbors. *
    * - * 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 n_subdivision = 4 - * because the number of (sub)cells - * within each patch is equal to - * 2^dim. + * 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 + * n_subdivision = 4 because the number of (sub)cells + * within each patch is equal to 2dim. * * @ingroup output * @@ -255,34 +246,23 @@ public: struct Patch { /** - * Make the spacedim template - * parameter available. + * Make the spacedim 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 vertices[GeometryInfo::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. 1 means no - * subdivision, 2 means - * bisection, 3 trisection, - * etc. + * Number of subdivisions with which this patch is to be + * written. 1 means no subdivision, 2 means + * bisection, 3 trisection, etc. */ unsigned int n_subdivisions; /** - * Data vectors. The format is - * as follows: - * data(i,.) denotes the data - * belonging to the ith data - * vector. data.n() - * therefore equals the number - * of output points; this - * number is (subdivisions+1)^{dim}. - * data.m() equals the number of - * data vectors. + * Data vectors. The format is as follows: data(i,.) + * denotes the data belonging to the ith data + * vector. data.n() therefore equals the number of output + * points; this number is (subdivisions+1)^{dim}. + * data.m() equals the number of data vectors. * - * Within each column, - * data(.,j) are the - * data values at the output - * point j, where - * j denotes the - * usual lexicographic - * ordering in deal.II. This - * is also the order of - * points as provided by the - * QIterated class - * when used with the - * QTrapez class as - * subquadrature. + * Within each column, data(.,j) are the data values at + * the output point j, where j denotes the usual + * lexicographic ordering in deal.II. This is also the order of + * points as provided by the QIterated class when used + * with the QTrapez class as subquadrature. * - * Since the number of data vectors - * is usually the same for all - * patches to be printed, - * data.size() 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, data.size() 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 - * n_subdivisions 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 std::map 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 std::map 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 - * declare_parameters 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: false. */ @@ -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 - * declare_parameters 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 std::map 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 std::map 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 - * private 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 private 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 - * declare_parameters 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 std::map 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 std::map 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 - * declare_parameters 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 std::map 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 std::map 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. height_vector==0, 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. height_vector==0, 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 - * height_vector. + * 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 size equals - * the width or the height of - * the resulting picture. + * Enum denoting the possibilities whether the scaling should be + * done such that the given size 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 - * 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 size_type. * - * 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 1.0. */ 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: true. */ 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 false and draw_mesh - * is false as well, nothing will be - * printed. + * If this flag is false and #draw_mesh is false + * as well, nothing will be printed. * - * If this flag is true, then the cells - * will be drawn either colored by one - * of the data sets (if shade_cells is - * true), or pure white (if - * shade_cells is false or if there are - * no data sets). + * If this flag is true, then the cells will be drawn + * either colored by one of the data sets (if #shade_cells is + * true), or pure white (if #shade_cells is false or if + * there are no data sets). * * Default is true. */ bool draw_cells; /** - * 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 - * draw_cells==true. Colorization is - * done through the color_function. + * 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 + * #draw_cells==true. Colorization is done through + * #color_function. * * Default is true. */ 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 true if the - * color represented by - * the three color values - * is a grey scale, - * i.e. all components - * are equal. + * Return true 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 default_color_function - * 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 - * color_function 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 - * color_function - * 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 - * declare_parameters 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 std::map 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 std::map 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 - * private 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 private 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 - * declare_parameters 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 std::map 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 std::map 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 - * declare_parameters 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 std::map 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 std::map 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::min(). + * unless it is at its default value of + * std::numeric_limits::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::min(). + * unless it is at its default value of + * std::numeric_limits::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 true. */ @@ -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 - * declare_parameters 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 std::map 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 std::map 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. height_vector==0, 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. #height_vector==0, 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 std::map 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 std::map 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 - * private 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 private 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 - * declare_parameters 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 std::map 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 std::map 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 dim and spacedim - * 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 dim and + * spacedim 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 determine_intermediate_format_dimensions (std::istream &input); /** - * 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 + * 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 (`|') - * as used by the + * Return a list of implemented output formats. The different names + * are separated by vertical bar signs (`|') 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: *
      *
    • dx: .dx *
    • ucd: .inp @@ -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 std::map 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 std::map 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 static void write_nodes (const std::vector > &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 static void write_cells (const std::vector > &patches, STREAM &out); /** - * Write data in the desired - * format. + * Write data in the desired format. */ template static void write_data (const std::vector > &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 EpsFlags class. + * Data value from which the actual colors will be computed by the + * colorization function stated in the EpsFlags 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 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. + * 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 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, - * get_patches and get_dataset_names 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 > ×_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 &piece_names) const; /** - * Obtain data through get_patches() - * and write it to out - * in SVG format. See - * DataOutBase::write_svg. + * Obtain data through get_patches() and write it to out in + * SVG format. See DataOutBase::write_svg. */ void write_svg(std::ostream &out) const; /** - * Obtain data through get_patches() - * and write it to out - * in deal.II intermediate - * format. See + * Obtain data through get_patches() and write it to out 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 - * default_format is - * requested. + * Set the default format. The value set here is used anytime, + * output for format default_format 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 - * declare_parameters - * 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 declare_parameters 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 declare_parameters 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 std::map 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 std::map 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 > & 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 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 set_format 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 + * set_format function or in a parameter file. */ OutputFormat default_fmt; /** - * Flags to be used upon output - * of OpenDX data. Can be changed by - * using the set_flags - * function. + * Flags to be used upon output of OpenDX data. Can be changed by + * using the set_flags function. */ DXFlags dx_flags; /** - * Flags to be used upon output - * of UCD data. Can be changed by - * using the set_flags - * function. + * Flags to be used upon output of UCD data. Can be changed by using + * the set_flags function. */ UcdFlags ucd_flags; /** - * Flags to be used upon output - * of GNUPLOT data. Can be - * changed by using the - * set_flags function. + * Flags to be used upon output of GNUPLOT data. Can be changed by + * using the set_flags function. */ GnuplotFlags gnuplot_flags; /** - * Flags to be used upon output - * of POVRAY data. Can be changed - * by using the set_flags - * function. + * Flags to be used upon output of POVRAY data. Can be changed by + * using the set_flags function. */ PovrayFlags povray_flags; /** - * Flags to be used upon output - * of EPS data in one space - * dimension. Can be changed by - * using the set_flags + * Flags to be used upon output of EPS data in one space + * dimension. Can be changed by using the set_flags * function. */ EpsFlags eps_flags; /** - * Flags to be used upon output - * of gmv data in one space - * dimension. Can be changed by - * using the set_flags + * Flags to be used upon output of gmv data in one space + * dimension. Can be changed by using the set_flags * function. */ GmvFlags gmv_flags; /** - * Flags to be used upon output - * of Tecplot data in one space - * dimension. Can be changed by - * using the set_flags + * Flags to be used upon output of Tecplot data in one space + * dimension. Can be changed by using the set_flags * function. */ TecplotFlags tecplot_flags; /** - * Flags to be used upon output - * of vtk data in one space - * dimension. Can be changed by - * using the set_flags + * Flags to be used upon output of vtk data in one space + * dimension. Can be changed by using the set_flags * function. */ VtkFlags vtk_flags; /** - * Flags to be used upon output - * of svg data in one space - * dimension. Can be changed by - * using the set_flags + * Flags to be used upon output of svg data in one space + * dimension. Can be changed by using the set_flags * 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 - * set_flags function. + * Flags to be used upon output of deal.II intermediate data in one + * space dimension. Can be changed by using the set_flags + * function. */ Deal_II_IntermediateFlags deal_II_intermediate_flags; }; @@ -3118,60 +2657,36 @@ class DataOutReader : public DataOutInterface { public: /** - * Read a sequence of patches as - * written previously by - * DataOutBase::write_deal_II_intermediate - * and store them in the present - * object. This overwrites any - * previous content. + * Read a sequence of patches as written previously by + * DataOutBase::write_deal_II_intermediate 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 &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 > & 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 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 > patches; std::vector 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 > 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 key: value. In * other words, a map is described in the form - * key1: value1, key2: value2, key3: value3, .... + * key1: value1, key2: value2, key3: value3, .... 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 * = sign. * * + *

      Including other input files

      + * + * 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). + * + * *

      Reading data from input sources

      * - * In order to read input you can use three possibilities: reading from + * In order to read input there are three possibilities: reading from * an std::istream 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 @\n characters. These possibilities are used as @@ -1559,12 +1589,15 @@ public: virtual ~ParameterHandler (); /** - * Read input from a stream until stream returns eof condition - * or error. + * Read input from a stream until the stream returns the eof 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 after + * 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. lineno is the number of the line + * Scan one line of input. input_filename and lineno + * are the name of the input file and the current number of the line * presently scanned (for the logs if there are messages). Return * false if line contained stuff that could not be understood, * the uppermost subsection was to be left by an END 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 +inline TriaIterator > DoFCellAccessor::face (const unsigned int i) const { @@ -3519,6 +3520,7 @@ DoFCellAccessor::get_dof_indices (std::vector & } + template inline void DoFCellAccessor::get_mg_dof_indices (std::vector &dof_indices) const @@ -3526,6 +3528,8 @@ void DoFCellAccessor::get_mg_dof_indices (std::vector::get_mg_dof_indices (this->level (), dof_indices); } + + template inline void DoFCellAccessor::set_mg_dof_indices (const std::vector &dof_indices) @@ -3534,6 +3538,7 @@ void DoFCellAccessor::set_mg_dof_indices (const std::vector inline void DoFCellAccessor::get_active_or_mg_dof_indices (std::vector &dof_indices) const @@ -3548,6 +3553,7 @@ void DoFCellAccessor::get_active_or_mg_dof_indices (std::vector template +inline void DoFCellAccessor::get_dof_values (const InputVector &values, Vector &local_values) const @@ -3564,6 +3570,7 @@ DoFCellAccessor::get_dof_values (const InputVector &values, template template +inline void DoFCellAccessor::get_dof_values (const InputVector &values, ForwardIterator local_values_begin, @@ -3579,6 +3586,7 @@ DoFCellAccessor::get_dof_values (const InputVector &values, template template +inline void DoFCellAccessor::get_dof_values (const ConstraintMatrix &constraints, const InputVector &values, @@ -3596,6 +3604,7 @@ DoFCellAccessor::get_dof_values (const ConstraintMatrix &constraints, template template +inline void DoFCellAccessor::set_dof_values (const Vector &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 renumbering 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 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 spacedim template parameter * check the documentation of FiniteElement or the one of @@ -50,71 +50,46 @@ class MappingC1 : public MappingQ { 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 *clone () const; protected: /** - * For dim=2,3. 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 dim=2,3. 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 - * compute_support_points_simple(laplace) - * functions. For dim=1 this - * function is empty. + * Needed by the compute_support_points_simple(laplace) + * functions. For dim=1 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::cell_iterator &cell, std::vector > &a) const; /** - * For dim=3. 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 dim=3. 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 dim=1 and 2 - * this function is empty. + * Needed by the @p compute_support_points_laplace function. For + * dim=1 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::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 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 * deal.II/doc/reports/mapping_q/index.html in the `Reports' @@ -44,6 +46,10 @@ template 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 @@ -51,41 +57,25 @@ class MappingQ : public MappingQ1 { 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 false (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 false (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 &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 transform_unit_to_real_cell ( @@ -106,46 +94,25 @@ public: const Point &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 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 *clone () const; /** - * Storage for internal data of - * Q_degree transformation. + * Storage for internal data of Q_degree transformation. */ class InternalData : public MappingQ1::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 > > unit_normals; /** - * Flag that is set by the - * fill_fe_[[sub]face]_values - * function. + * Flag that is set by the fill_fe_[[sub]face]_values 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::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::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::cell_iterator &cell, @@ -272,8 +220,7 @@ protected: typename std::vector > &normal_vectors) const ; /** - * Implementation of the interface in - * Mapping. + * Implementation of the interface in Mapping. */ virtual void fill_fe_subface_values (const typename Triangulation::cell_iterator &cell, @@ -287,55 +234,32 @@ protected: typename std::vector > &normal_vectors) const ; /** - * For dim=2,3. 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 dim=2,3. 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 dim=1 this - * function is empty. + * Needed by the @p compute_support_points_laplace function . For + * dim=1 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::cell_iterator &cell, std::vector > &a) const; /** - * For dim=3. 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 dim=3. 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 dim=1 and - * dim=2 this function is - * empty. + * Needed by the @p compute_support_points_laplace function. For + * dim=1 and dim=2 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::cell_iterator &cell, @@ -359,145 +283,99 @@ private: const Quadrature& quadrature) const; /** - * Compute shape values and/or - * derivatives. + * Compute shape values and/or derivatives. */ virtual void compute_shapes_virtual (const std::vector > &unit_points, typename MappingQ1::InternalData &data) const; /** - * This function is needed by the - * constructor of MappingQ - * for dim= 2 and 3. + * This function is needed by the constructor of + * MappingQ for dim= 2 and 3. * - * For degree<4 this function - * sets the - * @p laplace_on_quad_vector to - * the hardcoded data. For - * degree>=4 and MappingQ<2> - * this vector is computed. + * For degree<4 this function sets the @p laplace_on_quad_vector to + * the hardcoded data. For degree>=4 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 MappingQ<3>. + * This function is needed by the constructor of MappingQ<3>. * - * For degree==2 this function - * sets the - * @p laplace_on_hex_vector to - * the hardcoded data. For - * degree>2 this vector is - * computed. + * For degree==2 this function sets the @p laplace_on_hex_vector to + * the hardcoded data. For degree>2 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 - * laplace_on_quad(hex)_vector. + * Computes the laplace_on_quad(hex)_vector. * - * Called by the - * set_laplace_on_quad(hex)_vector - * functions if the data is not - * yet hardcoded. + * Called by the set_laplace_on_quad(hex)_vector functions if the + * data is not yet hardcoded. * - * For the definition of the - * laplace_on_quad(hex)_vector - * please refer to equation (8) - * of the `mapping' report. + * For the definition of the laplace_on_quad(hex)_vector please + * refer to equation (8) of the `mapping' report. */ void compute_laplace_vector(Table<2,double> &lvs) const; /** - * Takes a - * laplace_on_hex(quad)_vector - * and applies it to the vector - * @p a to compute the inner - * support points as a linear - * combination of the exterior - * points. + * Takes a laplace_on_hex(quad)_vector 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 > &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::cell_iterator &cell, std::vector > &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::cell_iterator &cell, std::vector > &a) const; /** - * Needed by the - * @p laplace_on_quad function - * (for dim==2). Filled by the - * constructor. + * Needed by the @p laplace_on_quad function (for dim==2). 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 dim==3). Filled by the - * constructor. + * Needed by the @p laplace_on_hex function (for dim==3). 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 *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 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 feq; + + /** + * Declare other MappingQ classes friends. + */ + template 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 { public: /** - * Constructor. The first argument is - * the polynomical degree of the desired - * Qp mapping. It then takes a - * Vector & 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 Vector & 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 * DoFAccessor::set_dof_values(). */ @@ -122,20 +111,16 @@ public: const DoFHandler &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 *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::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 > 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,MappingQEulerian > 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 { 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 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::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 &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 #include +#include +#include #include #include @@ -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 - * GeometryInfo::vertices_per_face - * 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 GeometryInfo::vertices_per_face + * 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::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 get_new_point_on_line (const typename Triangulation::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 - * quad->line(i)->child(j), - * i=0...3, j=0,1. + * 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 + * quad->line(i)->child(j), i=0...3, j=0,1. * - * 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 get_new_point_on_quad (const typename Triangulation::quad_iterator &quad) const; /** - * Depending on dim=2 or - * dim=3 this function - * calls the - * get_new_point_on_line or the - * get_new_point_on_quad - * function. It throws an - * exception for - * dim=1. This wrapper - * allows dimension independent + * Depending on dim=2 or dim=3 this function calls the + * get_new_point_on_line or the get_new_point_on_quad function. It throws an + * exception for dim=1. This wrapper allows dimension independent * programming. */ Point get_new_point_on_face (const typename Triangulation::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 > &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. n=points.size()=m*m. It - * is the task of the derived - * classes to arrange the points - * such they split the quad into - * (m+1)(m+1) 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. n=points.size()=m*m. It is the task of the derived classes + * to arrange the points such they split the quad into (m+1)(m+1) + * approximately equal-sized subquads. * - * This function is called by the - * MappingQ<3> 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 MappingQ<3> 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 > &points) const; /** - * Depending on dim=2 or - * dim=3 this function - * calls the - * get_intermediate_points_on_line - * or the - * get_intermediate_points_on_quad - * function. It throws an - * exception for - * dim=1. This wrapper - * allows dimension independent - * programming. + * Depending on dim=2 or dim=3 this function calls the + * get_intermediate_points_on_line or the get_intermediate_points_on_quad + * function. It throws an exception for dim=1. This wrapper allows + * dimension independent programming. */ void get_intermediate_points_on_face (const typename Triangulation::face_iterator &face, std::vector > &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 &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 @@ -367,19 +263,12 @@ public: const Point &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 @@ -387,24 +276,40 @@ public: const Point &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 project_to_surface (const typename Triangulation::hex_iterator &hex, const Point &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 > & + get_line_support_points (const unsigned int n_intermediate_points) const; + +private: + /** + * Point generator for the intermediate points on a boundary. + */ + mutable std::vector > > points; + + /** + * Mutex for protecting the points array. + */ + mutable Threads::Mutex mutex; }; @@ -429,56 +334,37 @@ class StraightBoundary : public Boundary { 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 get_new_point_on_line (const typename Triangulation::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 get_new_point_on_quad (const typename Triangulation::quad_iterator &quad) const; /** - * Gives n=points.size() - * points that splits the - * StraightBoundary line into - * $n+1$ partitions of equal - * lengths. + * Gives n=points.size() 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 > &points) const; /** - * Gives n=points.size()=m*m - * points that splits the - * StraightBoundary quad into - * $(m+1)(m+1)$ subquads of equal - * size. + * Gives n=points.size()=m*m 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 > &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 &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::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 @@ -565,26 +425,15 @@ public: const Point &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 @@ -592,26 +441,16 @@ public: const Point &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 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 & get_fe_collection () const; + /** + * Get a reference to the collection of mapping objects used + * here. + */ + const dealii::hp::MappingCollection & + get_mapping_collection () const; + + /** + * Get a reference to the collection of quadrature objects used + * here. + */ + const dealii::hp::QCollection & + 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 + inline + const dealii::hp::MappingCollection & + FEValuesBase::get_mapping_collection () const + { + return *mapping_collection; + } + + + + template + inline + const dealii::hp::QCollection & + FEValuesBase::get_quadrature_collection () const + { + return q_collection; + } + + + + template + inline + dealii::UpdateFlags + FEValuesBase::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 + void ip_tangential_matrix ( + FullMatrix &M11, + FullMatrix &M12, + FullMatrix &M21, + FullMatrix &M22, + const FEValuesBase &fe1, + const FEValuesBase &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 &n = fe1.normal_vector(k); + for (unsigned int i=0; i 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 &eigenvalues, std::vector &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 &eigenvalues, std::vector &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 n_eigenpairs * eigenstates. Parameter n_converged 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 &eigenvalues, std::vector &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 &eigenvalues, std::vector &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 &imag_eigenvalues, std::vector &real_eigenvectors, std::vector &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 &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 void initialize(const FiniteElement &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 > &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 &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 &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 > > 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 > > > 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 > > > hessians; /** - * Reinitialize internal data - * structures for use on a cell. + * Reinitialize internal data structures for use on a cell. */ template void reinit(const DoFInfo &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 void fill_local_data(const DoFInfo &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 > 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 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 &el, const Mapping &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 void initialize(const FiniteElement &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 void initialize(const FiniteElement &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 - * neighbor_geometry - * 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 neighbor_geometry 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 - * force is true, then - * all quadrature sets are - * filled with new quadrature - * ruels. If it is false, then + * If the parameter force 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 cell_quadrature; /** - * The quadrature rule used - * on boundary faces. + * The quadrature rule used on boundary faces. */ Quadrature boundary_quadrature; /** - * The quadrature rule used - * on interior faces. + * The quadrature rule used on interior faces. */ Quadrature 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 - * boundary_worker or - * face_worker - * arguments of loop() should - * be nonzero. Additionally, - * cells_first should - * be true. If - * cells_first 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 boundary_worker or + * face_worker arguments of loop() should be + * nonzero. Additionally, cells_first should be true. If + * cells_first 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 void post_cell(const DoFInfoBox &); /** - * 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 * cells_first is false). * - * In order for this function - * to have a reasonable effect, - * at least either of the - * arguments - * boundary_worker or - * face_worker - * arguments of loop() should - * be nonzero. Additionally, - * cells_first should - * be false. + * In order for this function to have a reasonable effect, at + * least either of the arguments boundary_worker or + * face_worker arguments of loop() should be + * nonzero. Additionally, cells_first 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 @@ -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 &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= 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= 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= threshold) - G.add(i1[j], i2[k], M(j,k)); - } - else - { - for (unsigned int j=0; j= 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= 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 inline void MGMatrixSimple::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= threshold) - G.add(i1[j], i2[k], M(k,j)); - } - else - { - for (unsigned int j=0; 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= 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 template @@ -1189,7 +1174,15 @@ namespace MeshWorker ResidualSimple::initialize(data); } + template + inline void + SystemSimple::initialize(const ConstraintMatrix &c) + { + MatrixSimple::initialize(c); + ResidualSimple::initialize(c); + } + template template 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 +#include +#include +#include +#include +#include +#include +#include + +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 + class SparseMatrixCollection : public Subscriptor + { + public: + void resize(const unsigned int minlevel, const unsigned int maxlevel); + + template + void reinit(const DH& dof_handler); + + void set_zero(); + + MGLevelObject sparsity; + MGLevelObject sparsity_edge; + + MGLevelObject > matrix; + MGLevelObject > matrix_down; + MGLevelObject > matrix_up; + MGLevelObject > matrix_in; + MGLevelObject > matrix_out; + }; + + + template + void + SparseMatrixCollection::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 + template + void + SparseMatrixCollection::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 + void + SparseMatrixCollection::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 -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include +#include #include @@ -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 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 &names, - const std::vector &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 *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 &fe_patch_values, - std::vector &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 &fe_patch_values, - std::vector > &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 &fe_patch_values, - std::vector > &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 &fe_patch_values, - std::vector > > &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 &fe_patch_values, - std::vector > &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 &fe_patch_values, - std::vector > > &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 dof_handler; - - /** - * Names of the components of this data vector. - */ - const std::vector 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 - data_component_interpretation; - - /** - * Pointer to a DataPostprocessing object which shall be applied to this - * data vector. - */ - SmartPointer > 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 names.size(). - */ - 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 cell_to_patch_index_map is an array that stores for - * index [i][j] 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 - struct ParallelDataBase - { - ParallelDataBase (const unsigned int n_datasets, - const unsigned int n_subdivisions, - const std::vector &n_postprocessor_outputs, - const Mapping &mapping, - const std::vector > > &finite_elements, - const UpdateFlags update_flags, - const bool use_face_values); - - ParallelDataBase (const ParallelDataBase &data); - - template - void reinit_all_fe_values(std::vector > > &dof_data, - const typename dealii::Triangulation::cell_iterator &cell, - const unsigned int face = numbers::invalid_unsigned_int); - - const FEValuesBase & - 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 patch_values; - std::vector > patch_values_system; - std::vector > patch_gradients; - std::vector > > patch_gradients_system; - std::vector > patch_hessians; - std::vector > > patch_hessians_system; - std::vector > > postprocessed_values; - - const dealii::hp::MappingCollection mapping_collection; - const std::vector > > finite_elements; - const UpdateFlags update_flags; - - std::vector > > x_fe_values; - std::vector > > 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. - * - * - *

      User visible interface

      - * - * 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 solution_names; - * solution_names.push_back ("x-displacement"); - * solution_names.push_back ("y-displacement"); - * - * DataOut 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 vector 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 vector. - * - * 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 - * if () ... else ... clauses yourself), and also functions - * and classes offering ways to control the appearance of the output - * by setting flags for each output format. - * - * - *

      Information for derived classes

      - * - * 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 DataOut_DoFData : public DataOutInterface -{ -public: - - /** - * Typedef to the iterator type of the dof handler class under - * consideration. - */ - typedef typename Triangulation::cell_iterator cell_iterator; - typedef typename Triangulation::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 &); - - /** - * 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 write_* - * 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 - void add_data_vector (const VECTOR &data, - const std::vector &names, - const DataVectorType type = type_automatic, - const std::vector &data_component_interpretation - = std::vector()); - - /** - * 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 - void add_data_vector (const VECTOR &data, - const std::string &name, - const DataVectorType type = type_automatic, - const std::vector &data_component_interpretation - = std::vector()); - - /** - * 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 - void add_data_vector (const DH &dof_handler, - const VECTOR &data, - const std::vector &names, - const std::vector &data_component_interpretation - = std::vector()); - - - /** - * This function is an abbreviation of the function above with only a scalar - * @p dof_handler given and a single data name. - */ - template - void add_data_vector (const DH &dof_handler, - const VECTOR &data, - const std::string &name, - const std::vector &data_component_interpretation - = std::vector()); - - /** - * 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 - void add_data_vector (const VECTOR &data, - const DataPostprocessor &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 - void add_data_vector (const DH &dof_handler, - const VECTOR &data, - const DataPostprocessor &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 - void merge_patches (const DataOut_DoFData &source, - const Point &shift = Point()); - - /** - * 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 \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; - - /** - * Pointer to the triangulation object. - */ - SmartPointer > triangulation; - - /** - * Pointer to the optional handler object. - */ - SmartPointer dofs; - - /** - * List of data elements with vectors of values for each degree of freedom. - */ - std::vector > > dof_data; - - /** - * List of data elements with vectors of values for each cell. - */ - std::vector > > 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 patches; - - /** - * Function by which the base class's functions get to know what patches - * they shall write to a file. - */ - virtual - const std::vector &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 get_dataset_names () const; - - /** - * Extracts the finite elements stored in the dof_data object, including a - * dummy object of FE_DGQ(0) in case only the triangulation is used. - */ - std::vector > > - get_finite_elements() const; - - /** - * Overload of the respective DataOutInterface::get_vector_data_ranges() - * function. See there for a more extensive documentation. - */ - virtual - std::vector > - get_vector_data_ranges () const; - - /** - * Make all template siblings friends. Needed for the merge_patches() - * function. - */ - template - 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 -template -void -DataOut_DoFData:: -merge_patches (const DataOut_DoFData &source, - const Point &shift) -{ - const std::vector 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()[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()) - for (unsigned int i=old_n_patches; i::vertices_per_cell; ++v) - patches[i].vertices[v] += shift; - - // adjust patch numbers - for (unsigned int i=old_n_patches; i::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 +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +DEAL_II_NAMESPACE_OPEN + +template 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 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 &names, + const std::vector &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 *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 &fe_patch_values, + std::vector &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 &fe_patch_values, + std::vector > &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 &fe_patch_values, + std::vector > &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 &fe_patch_values, + std::vector > > &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 &fe_patch_values, + std::vector > &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 &fe_patch_values, + std::vector > > &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 dof_handler; + + /** + * Names of the components of this data vector. + */ + const std::vector 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 + data_component_interpretation; + + /** + * Pointer to a DataPostprocessing object which shall be applied to this + * data vector. + */ + SmartPointer > 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 names.size(). + */ + 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 cell_to_patch_index_map is an array that stores for + * index [i][j] 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 + struct ParallelDataBase + { + ParallelDataBase (const unsigned int n_datasets, + const unsigned int n_subdivisions, + const std::vector &n_postprocessor_outputs, + const Mapping &mapping, + const std::vector > > &finite_elements, + const UpdateFlags update_flags, + const bool use_face_values); + + ParallelDataBase (const ParallelDataBase &data); + + template + void reinit_all_fe_values(std::vector > > &dof_data, + const typename dealii::Triangulation::cell_iterator &cell, + const unsigned int face = numbers::invalid_unsigned_int); + + const FEValuesBase & + 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 patch_values; + std::vector > patch_values_system; + std::vector > patch_gradients; + std::vector > > patch_gradients_system; + std::vector > patch_hessians; + std::vector > > patch_hessians_system; + std::vector > > postprocessed_values; + + const dealii::hp::MappingCollection mapping_collection; + const std::vector > > finite_elements; + const UpdateFlags update_flags; + + std::vector > > x_fe_values; + std::vector > > 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. + * + * + *

      User visible interface

      + * + * 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 solution_names; + * solution_names.push_back ("x-displacement"); + * solution_names.push_back ("y-displacement"); + * + * DataOut 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 vector 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 vector. + * + * 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 + * if () ... else ... clauses yourself), and also functions + * and classes offering ways to control the appearance of the output + * by setting flags for each output format. + * + * + *

      Information for derived classes

      + * + * 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 DataOut_DoFData : public DataOutInterface +{ +public: + + /** + * Typedef to the iterator type of the dof handler class under + * consideration. + */ + typedef typename Triangulation::cell_iterator cell_iterator; + typedef typename Triangulation::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 &); + + /** + * 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 write_* + * 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 + void add_data_vector (const VECTOR &data, + const std::vector &names, + const DataVectorType type = type_automatic, + const std::vector &data_component_interpretation + = std::vector()); + + /** + * 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 + void add_data_vector (const VECTOR &data, + const std::string &name, + const DataVectorType type = type_automatic, + const std::vector &data_component_interpretation + = std::vector()); + + /** + * 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 + void add_data_vector (const DH &dof_handler, + const VECTOR &data, + const std::vector &names, + const std::vector &data_component_interpretation + = std::vector()); + + + /** + * This function is an abbreviation of the function above with only a scalar + * @p dof_handler given and a single data name. + */ + template + void add_data_vector (const DH &dof_handler, + const VECTOR &data, + const std::string &name, + const std::vector &data_component_interpretation + = std::vector()); + + /** + * 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 + void add_data_vector (const VECTOR &data, + const DataPostprocessor &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 + void add_data_vector (const DH &dof_handler, + const VECTOR &data, + const DataPostprocessor &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 + void merge_patches (const DataOut_DoFData &source, + const Point &shift = Point()); + + /** + * 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 \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; + + /** + * Pointer to the triangulation object. + */ + SmartPointer > triangulation; + + /** + * Pointer to the optional handler object. + */ + SmartPointer dofs; + + /** + * List of data elements with vectors of values for each degree of freedom. + */ + std::vector > > dof_data; + + /** + * List of data elements with vectors of values for each cell. + */ + std::vector > > 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 patches; + + /** + * Function by which the base class's functions get to know what patches + * they shall write to a file. + */ + virtual + const std::vector &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 get_dataset_names () const; + + /** + * Extracts the finite elements stored in the dof_data object, including a + * dummy object of FE_DGQ(0) in case only the triangulation is used. + */ + std::vector > > + get_finite_elements() const; + + /** + * Overload of the respective DataOutInterface::get_vector_data_ranges() + * function. See there for a more extensive documentation. + */ + virtual + std::vector > + get_vector_data_ranges () const; + + /** + * Make all template siblings friends. Needed for the merge_patches() + * function. + */ + template + friend class DataOut_DoFData; +}; + + + +// -------------------- template and inline functions ------------------------ + + +template +template +void +DataOut_DoFData:: +merge_patches (const DataOut_DoFData &source, + const Point &shift) +{ + const std::vector 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()[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()) + for (unsigned int i=old_n_patches; i::vertices_per_cell; ++v) + patches[i].vertices[v] += shift; + + // adjust patch numbers + for (unsigned int i=old_n_patches; i::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 -#include +#include #include #include 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, - * numbers::invalid_unsigned_int), - * 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, + * numbers::invalid_unsigned_int), 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 @@ -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 * mapping=MappingQ1@(). */ template @@ -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 static void estimate (const Mapping &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 * mapping=MappingQ1@(). */ template @@ -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 static void estimate (const Mapping &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 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 static void estimate (const Mapping &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 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 - * multithread_info.n_default_threads - * (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 + * multithread_info.n_default_threads (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 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 * mapping=MappingQ1<1>(). */ template @@ -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 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 * mapping=MappingQ1<1>(). */ template @@ -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 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 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 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 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 - * dim 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 - * [first_vector_component,first_vector_component+dim) - * come from the same base finite - * element. For example, in the - * Stokes example above, it would - * not make sense to use a - * FESystem@(FE_Q@(2), - * 1, FE_Q@(1), dim) - * (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 dim 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 + * [first_vector_component,first_vector_component+dim) come + * from the same base finite element. For example, in the Stokes example + * above, it would not make sense to use a + * FESystem@(FE_Q@(2), 1, FE_Q@(1), dim) + * (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 . * * *

      Computing constraints in 2d

      * - * Computing these constraints requires - * some smarts. The main question - * revolves around the question what the - * normal vector is. Consider the - * following situation: - *

      - * @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:

      @image html no_normal_flux_1.png *

      * - * 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. all 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 each of these normal - * vectors but only for the - * average 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. all 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 each of these normal + * vectors but only for the average 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: * *

      * @image html no_normal_flux_2.png *

      * - * 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 different 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 different 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: * *

      * @image html no_normal_flux_3.png *

      * - * 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. * * *

      Computing constraints in 3d

      * - * 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: * *

      * @image html no_normal_flux_4.png *

      * - * 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. * * *

      Results

      * - * 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: * *

      @@ -1705,16 +1578,10 @@ namespace VectorTools * @image html no_normal_flux_6.png *

      * - * 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 &mapping = StaticMappingQ1::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 class DH, int spacedim> + void + compute_normal_flux_constraints (const DH &dof_handler, + const unsigned int first_vector_component, + const std::set &boundary_ids, + ConstraintMatrix &constraints, + const Mapping &mapping = StaticMappingQ1::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 #include +#include #include #include #include @@ -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 &, - const std::set &) - { - 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 &, - const std::set &) - { - Assert (false, ExcImpossibleInDim(1)); - } - - - template void create_boundary_right_hand_side (const Mapping &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 &, - const std::set &) - { - 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 &, - const std::set &) - { - Assert (false, ExcImpossibleInDim(1)); - } - - - template void create_boundary_right_hand_side (const hp::MappingCollection &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 &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 degree * (degree + - // 1) 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 + // degree * (degree + 1) to obtain the values for the + // corresponding degrees of freedom. const unsigned int superdegree = dof_handler.get_fe ().degree; const QGauss 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::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*> (&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*> (&cell->get_fe ()) == 0) { typedef FiniteElement FEL; @@ -3749,19 +3656,12 @@ namespace VectorTools for (unsigned int face = 0; face < GeometryInfo::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*> (&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*> (&cell->get_fe ()) == 0) { typedef FiniteElement 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 void compute_face_projection_div_conforming (const cell_iterator &cell, @@ -3846,13 +3741,9 @@ namespace VectorTools const std::vector > &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 > &normals = fe_values.get_normal_vectors (); @@ -3862,9 +3753,7 @@ namespace VectorTools values (fe_values.n_quadrature_points, Vector (2)); Vector 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 > & 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 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 void compute_face_projection_div_conforming (const cell_iterator &cell, @@ -3939,13 +3822,9 @@ namespace VectorTools std::vector &dof_values, std::vector &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 > &normals = fe_values.get_normal_vectors (); @@ -4771,12 +4650,452 @@ namespace VectorTools + namespace + { + template + struct PointComparator + { + bool operator ()(const std_cxx1x::array &p1, + const std_cxx1x::array &p2) + { + for (unsigned int d=0; d class DH, int spacedim> + void + compute_normal_flux_constraints (const DH&dof_handler, + const unsigned int first_vector_component, + const std::set &boundary_ids, + ConstraintMatrix &constraints, + const Mapping &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, PointComparator > vector_dofs; + std::vector face_dofs; + + std::vector > cell_vector_dofs; + for (typename DH::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::faces_per_cell; + ++face_no) + if (boundary_ids.find(cell->face(face_no)->boundary_indicator()) + != boundary_ids.end()) + { + const FiniteElement &fe = cell->get_fe(); + typename DH::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= 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,PointComparator >:: + 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 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 normal; + unsigned constrained_index = -1; + for (unsigned int d=0; d >* 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; csize(); ++c) + { + int index = -1; + for (unsigned int d=0; 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 + struct IDScratchData + { + IDScratchData (const dealii::hp::MappingCollection &mapping, + const dealii::hp::FECollection &fe, + const dealii::hp::QCollection &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 > function_values; + std::vector > > function_grads; + std::vector weight_values; + std::vector > weight_vectors; + + std::vector > psi_values; + std::vector > > psi_grads; + std::vector psi_scalar; + + std::vector tmp_values; + std::vector > tmp_gradients; + + dealii::hp::FEValues x_fe_values; + }; + + + template + IDScratchData + ::IDScratchData(const dealii::hp::MappingCollection &mapping, + const dealii::hp::FECollection &fe, + const dealii::hp::QCollection &q, + const UpdateFlags update_flags) + : + x_fe_values(mapping, fe, q, update_flags) + {} + + template + IDScratchData::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 + void + IDScratchData::resize_vectors (const unsigned int n_q_points, + const unsigned int n_components) + { + function_values.resize (n_q_points, + dealii::Vector(n_components)); + function_grads.resize (n_q_points, + std::vector >(n_components)); + + weight_values.resize (n_q_points); + weight_vectors.resize (n_q_points, + dealii::Vector(n_components)); + + psi_values.resize (n_q_points, + dealii::Vector(n_components)); + psi_grads.resize (n_q_points, + std::vector >(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 + double + integrate_difference_inner (const Function &exact_solution, + const NormType &norm, + const Function *weight, + const UpdateFlags update_flags, + const double exponent, + const unsigned int n_components, + IDScratchData &data) + { + const bool fe_is_system = (n_components != 1); + const dealii::FEValues &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 static void - do_integrate_difference (const dealii::hp::MappingCollection &mapping, + do_integrate_difference (const dealii::hp::MappingCollection &mapping, const DH &dof, const InVector &fe_function, const Function &exact_solution, @@ -4786,13 +5105,9 @@ namespace VectorTools const Function *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 fe_collection (dof.get_fe()); - dealii::hp::FEValues 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 > - function_values (max_n_q_points, dealii::Vector(n_components)); - std::vector > > - function_grads (max_n_q_points, std::vector >(n_components)); - - std::vector - weight_values (max_n_q_points); - std::vector > - weight_vectors (max_n_q_points, dealii::Vector(n_components)); - - std::vector > - psi_values (max_n_q_points, dealii::Vector(n_components)); - std::vector > > - psi_grads (max_n_q_points, std::vector >(n_components)); - std::vector - psi_scalar (max_n_q_points); - - // tmp vector when we use the - // Function functions for - // scalar functions - std::vector tmp_values (max_n_q_points); - std::vector > tmp_gradients (max_n_q_points); + IDScratchData 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 &fe_values = x_fe_values.get_present_fe_values (); + const dealii::FEValues &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(n_components)); - function_grads.resize (n_q_points, - std::vector >(n_components)); - - weight_values.resize (n_q_points); - weight_vectors.resize (n_q_points, - dealii::Vector(n_components)); - - psi_values.resize (n_q_points, - dealii::Vector(n_components)); - psi_grads.resize (n_q_points, - std::vector >(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::mapping_collection, + ::do_integrate_difference(hp::StaticMappingQ1::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 > &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 > &patches, } } } - + // write the svg file - width = static_cast(.5 + height * (x_dimension_perspective / y_dimension_perspective)); + if (width==0) + width = static_cast(.5 + height * (x_dimension_perspective / y_dimension_perspective)); unsigned int additional_width = 0; if (flags.draw_colorbar) additional_width = static_cast(.5 + height * .3); // additional width for colorbar @@ -6494,7 +6498,7 @@ void DataOutInterface::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(filename), + MPI_File_open(comm, const_cast(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 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 pairs")); } @@ -597,7 +617,6 @@ namespace Patterns { std::string tmp = test_string_list; std::vector 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 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 (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 << " 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 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 send_buffer (n_procs, 0); std::vector 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 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 > 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 -#include -#include -#include -#include -#include -#include -#include -#include - #include #include #include @@ -97,174 +87,6 @@ DoFCellAccessor::neighbor_child_on_subface (const unsigned int face, -template -template -void -DoFCellAccessor:: -get_interpolated_dof_values (const InputVector &values, - Vector &interpolated_values) const -{ - const FiniteElement &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 tmp1(dofs_per_cell); - Vector 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 restriction_is_additive (dofs_per_cell); - for (unsigned int i=0; in_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 -template -void -DoFCellAccessor:: -set_dof_values_by_interpolation (const Vector &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 tmp(dofs_per_cell); - - for (unsigned int child=0; childn_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, lda>::get_interpolated_dof_values - (const VEC&, Vector&) const; - template - void - DoFCellAccessor, lda>::set_dof_values_by_interpolation - (const Vector&, VEC&) const; - -#if deal_II_dimension != 3 - - template - void - DoFCellAccessor, lda>::get_interpolated_dof_values - (const VEC&, Vector&) const; - template - void - DoFCellAccessor, lda>::set_dof_values_by_interpolation - (const Vector&, VEC&) const; - -#endif - -#if deal_II_dimension == 3 - - template - void - DoFCellAccessor, lda>::get_interpolated_dof_values - (const VEC&, Vector&) const; - template - void - DoFCellAccessor, lda>::set_dof_values_by_interpolation - (const Vector&, VEC&) const; - -#endif - - } - - -for (VEC : SERIAL_VECTORS; SCALAR : REAL_SCALARS; deal_II_dimension : DIMENSIONS; lda : BOOL) - { - template - void - DoFCellAccessor, lda>::get_interpolated_dof_values - (const VEC&, Vector&) const; - template - void - DoFCellAccessor, lda>::set_dof_values_by_interpolation - (const Vector&, VEC&) const; - -#if deal_II_dimension != 3 - - template - void - DoFCellAccessor, lda>::get_interpolated_dof_values - (const VEC&, Vector&) const; - template - void - DoFCellAccessor, lda>::set_dof_values_by_interpolation - (const Vector&, VEC&) const; - -#endif - -#if deal_II_dimension == 3 - - template - void - DoFCellAccessor, lda>::get_interpolated_dof_values - (const VEC&, Vector&) const; - template - void - DoFCellAccessor, lda>::set_dof_values_by_interpolation - (const Vector&, 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 +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +DEAL_II_NAMESPACE_OPEN + + +template +template +void +DoFCellAccessor:: +get_interpolated_dof_values (const InputVector &values, + Vector &interpolated_values) const +{ + const FiniteElement &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 tmp1(dofs_per_cell); + Vector 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 restriction_is_additive (dofs_per_cell); + for (unsigned int i=0; in_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, lda>::get_interpolated_dof_values + (const VEC&, Vector&) const; + +#if deal_II_dimension != 3 + + template + void + DoFCellAccessor, lda>::get_interpolated_dof_values + (const VEC&, Vector&) const; + +#endif + +#if deal_II_dimension == 3 + + template + void + DoFCellAccessor, lda>::get_interpolated_dof_values + (const VEC&, Vector&) const; + +#endif + + } + + +for (VEC : SERIAL_VECTORS; SCALAR : REAL_SCALARS; deal_II_dimension : DIMENSIONS; lda : BOOL) + { + template + void + DoFCellAccessor, lda>::get_interpolated_dof_values + (const VEC&, Vector&) const; + +#if deal_II_dimension != 3 + + template + void + DoFCellAccessor, lda>::get_interpolated_dof_values + (const VEC&, Vector&) const; + +#endif + +#if deal_II_dimension == 3 + + template + void + DoFCellAccessor, lda>::get_interpolated_dof_values + (const VEC&, Vector&) 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 +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +DEAL_II_NAMESPACE_OPEN + + + +template +template +void +DoFCellAccessor:: +set_dof_values_by_interpolation (const Vector &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 tmp(dofs_per_cell); + + for (unsigned int child=0; childn_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, lda>::set_dof_values_by_interpolation + (const Vector&, VEC&) const; + +#if deal_II_dimension != 3 + + template + void + DoFCellAccessor, lda>::set_dof_values_by_interpolation + (const Vector&, VEC&) const; + +#endif + +#if deal_II_dimension == 3 + + template + void + DoFCellAccessor, lda>::set_dof_values_by_interpolation + (const Vector&, VEC&) const; + +#endif + + } + + +for (VEC : SERIAL_VECTORS; SCALAR : REAL_SCALARS; deal_II_dimension : DIMENSIONS; lda : BOOL) + { + template + void + DoFCellAccessor, lda>::set_dof_values_by_interpolation + (const Vector&, VEC&) const; + +#if deal_II_dimension != 3 + + template + void + DoFCellAccessor, lda>::set_dof_values_by_interpolation + (const Vector&, VEC&) const; + +#endif + +#if deal_II_dimension == 3 + + template + void + DoFCellAccessor, lda>::set_dof_values_by_interpolation + (const Vector&, 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 #include #include -#include #include @@ -54,3212 +53,6 @@ DEAL_II_NAMESPACE_OPEN namespace DoFTools { - - template - 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 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 - 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 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 > 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 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 - 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 > - cell_list - = GridTools::get_finest_common_cells (dof_row, dof_col); - - - typename std::list >::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 - local_dof_indices_row(dofs_per_cell_row); - std::vector - 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; ihas_children()) - { - const std::vector - child_cells = GridTools::get_active_child_cells (cell_row); - for (unsigned int i=0; iget_fe().dofs_per_cell; - const unsigned int dofs_per_cell_col = - cell_col->get_fe().dofs_per_cell; - std::vector - local_dof_indices_row(dofs_per_cell_row); - std::vector - 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 - child_cells = GridTools::get_active_child_cells (cell_col); - for (unsigned int i=0; iget_fe().dofs_per_cell; - const unsigned int dofs_per_cell_col = - cell_col_child->get_fe().dofs_per_cell; - std::vector - local_dof_indices_row(dofs_per_cell_row); - std::vector - 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 - void - make_boundary_sparsity_pattern ( - const DH &dof, - const std::vector &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 (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::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 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::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 - void make_boundary_sparsity_pattern ( - const DH &dof, - const typename FunctionMap::type &boundary_indicators, - const std::vector &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 boundary_dof_boundary_indices (dofs_per_vertex); - - // next get boundary mapped dof indices of boundary dofs - for (unsigned int i=0; ivertex_dof_index(direction,i)]; - - for (unsigned int i=0; i::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 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::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 - 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 dofs_on_this_cell; - std::vector 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::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 - void - make_flux_sparsity_pattern (const DH &dof, - SparsityPattern &sparsity) - { - ConstraintMatrix constraints; - make_flux_sparsity_pattern (dof, sparsity, constraints); - } - - - - template - Table<2,Coupling> - dof_couplings_from_component_couplings (const FiniteElement &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 - std::vector > - dof_couplings_from_component_couplings - (const hp::FECollection &fe, - const Table<2,Coupling> &component_couplings) - { - std::vector > return_value (fe.size()); - for (unsigned int i=0; i - void - make_flux_sparsity_pattern (const DH &dof, - SparsityPattern &sparsity, - const Table<2,Coupling> &int_mask, - const Table<2,Coupling> &flux_mask) - { - const FiniteElement &fe = dof.get_fe(); - - std::vector dofs_on_this_cell(fe.dofs_per_cell); - std::vector 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::faces_per_cell); - for (unsigned int i=0; i::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::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; ineighbor(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; iface(neighbor_face)->set_user_flag (); - } - } - else - { - neighbor->get_dof_indices (dofs_on_other_cell); - for (unsigned int i=0; iface(neighbor_face)->set_user_flag (); - } - } - } - } - } - - - // implementation of the same function in namespace DoFTools for - // non-hp DoFHandlers - template - void - make_flux_sparsity_pattern (const dealii::hp::DoFHandler &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 &fe = dof.get_fe(); - - std::vector dofs_on_this_cell(DoFTools::max_dofs_per_cell(dof)); - std::vector dofs_on_other_cell(DoFTools::max_dofs_per_cell(dof)); - - const std::vector > - int_dof_mask - = dof_couplings_from_component_couplings(fe, int_mask); - - typename dealii::hp::DoFHandler::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; iget_fe().dofs_per_cell; ++i) - for (unsigned int j=0; jget_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::faces_per_cell; - ++face) - { - const typename dealii::hp::DoFHandler::face_iterator - cell_face = cell->face(face); - if (cell_face->user_flag_set ()) - continue; - - if (cell->at_boundary (face) ) - { - for (unsigned int i=0; iget_fe().dofs_per_cell; ++i) - for (unsigned int j=0; jget_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::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::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::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; iget_fe().dofs_per_cell; ++i) - { - for (unsigned int j=0; jget_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; iget_fe().dofs_per_cell; ++i) - { - for (unsigned int j=0; jget_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 - 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 user_flags; - dof.get_tria().save_user_flags(user_flags); - const_cast &>(dof.get_tria()).clear_user_flags (); - - internal::make_flux_sparsity_pattern (dof, sparsity, - int_mask, flux_mask); - - // finally restore the user flags - const_cast &>(dof.get_tria()).load_user_flags(user_flags); - } - - - - - namespace internal - { - namespace - { - inline bool - check_master_dof_list (const FullMatrix &face_interpolation_matrix, - const std::vector &master_dof_list) - { - const unsigned int N = master_dof_list.size(); - - FullMatrix tmp (N,N); - for (unsigned int i=0; i p(N); - for (unsigned int i=0; i 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 - void - select_master_dofs_for_face_restriction (const FiniteElement &fe1, - const FiniteElement &fe2, - const FullMatrix &face_interpolation_matrix, - std::vector &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 master_dof_list; - unsigned int index = 0; - for (int v=0; - v(GeometryInfo::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(GeometryInfo::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(GeometryInfo::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::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 - void - ensure_existence_of_master_dof_mask (const FiniteElement &fe1, - const FiniteElement &fe2, - const FullMatrix &face_interpolation_matrix, - std_cxx1x::shared_ptr > &master_dof_mask) - { - if (master_dof_mask == std_cxx1x::shared_ptr >()) - { - master_dof_mask = std_cxx1x::shared_ptr > - (new std::vector (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 - void - ensure_existence_of_face_matrix (const FiniteElement &fe1, - const FiniteElement &fe2, - std_cxx1x::shared_ptr > &matrix) - { - if (matrix == std_cxx1x::shared_ptr >()) - { - matrix = std_cxx1x::shared_ptr > - (new FullMatrix (fe2.dofs_per_face, - fe1.dofs_per_face)); - fe1.get_face_interpolation_matrix (fe2, - *matrix); - } - } - - - - /** - * Same, but for subface interpolation matrices. - */ - template - void - ensure_existence_of_subface_matrix (const FiniteElement &fe1, - const FiniteElement &fe2, - const unsigned int subface, - std_cxx1x::shared_ptr > &matrix) - { - if (matrix == std_cxx1x::shared_ptr >()) - { - matrix = std_cxx1x::shared_ptr > - (new FullMatrix (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 &face_interpolation_matrix, - const std::vector &master_dof_mask, - std_cxx1x::shared_ptr,FullMatrix > > &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(face_interpolation_matrix.n()), - ExcInternalError()); - - if (split_matrix == - std_cxx1x::shared_ptr,FullMatrix > >()) - { - split_matrix - = std_cxx1x::shared_ptr,FullMatrix > > - (new std::pair,FullMatrix >()); - - 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; ifirst(nth_master_dof,j) - = face_interpolation_matrix(i,j); - ++nth_master_dof; - } - else - { - for (unsigned int j=0; jsecond(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 - struct DoFHandlerSupportsDifferentFEs - { - static const bool value = true; - }; - - - template - struct DoFHandlerSupportsDifferentFEs< dealii::DoFHandler > - { - static const bool value = false; - }; - - - template - struct DoFHandlerSupportsDifferentFEs< dealii::MGDoFHandler > - { - 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 - unsigned int - n_finite_elements (const dealii::hp::DoFHandler &dof_handler) - { - return dof_handler.get_fe().size(); - } - - - template - 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 - 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_non_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 & - 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; sfn_children(); ++sf) - if (sf != dominating_subface_no) - { - const FiniteElement & - 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 &master_dofs, - const std::vector &slave_dofs, - const FullMatrix &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= 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 - 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 dofs_on_mother; - std::vector 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::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; cface(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; cface(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 &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 - void - make_oldstyle_hanging_node_constraints (const DH &dof_handler, - ConstraintMatrix &constraints, - dealii::internal::int2type<3>) - { - const unsigned int dim = 3; - - std::vector dofs_on_mother; - std::vector 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::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::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; cface(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; cface(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 &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; dofchild(0)->line(1)->dof_index(dof, fe_index); - for (unsigned int dof=0; dofchild(2)->line(1)->dof_index(dof, fe_index); - for (unsigned int dof=0; dofchild(0)->line(3)->dof_index(dof, fe_index); - for (unsigned int dof=0; dofchild(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 - 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 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 master_dofs; - std::vector slave_dofs; - std::vector 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 > > - face_interpolation_matrices (n_finite_elements (dof_handler), - n_finite_elements (dof_handler)); - Table<3,std_cxx1x::shared_ptr > > - subface_interpolation_matrices (n_finite_elements (dof_handler), - n_finite_elements (dof_handler), - GeometryInfo::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,FullMatrix > > > - 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 > > - 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::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::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; cface(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::value == true) - for (unsigned int c=0; cface(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; cface(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; iget_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::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 &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 &restrict_mother_to_virtual_master_inv - = (split_face_interpolation_matrices - [dominating_fe_index][cell->active_fe_index()]->first); - - const FullMatrix &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; iget_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; - sfface(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 &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 &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::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 - 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()); - } - - - - 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 - void - set_periodicity_constraints (const FaceIterator &face_1, - const typename identity::type &face_2, - const FullMatrix &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::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 child_transformation (dofs_per_face, dofs_per_face); - FullMatrix subface_interpolation (dofs_per_face, dofs_per_face); - for (unsigned int c=0; cn_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 &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 dofs_1(dofs_per_face); - std::vector 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 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 - void - make_periodicity_constraints (const FaceIterator &face_1, - const typename identity::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::max_children_per_face && - face_2->n_children() == GeometryInfo::max_children_per_face, - ExcNotImplemented()); - - for (unsigned int i = 0; i < GeometryInfo::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(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(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 - 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 - 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 PTRIA; - const PTRIA *ptria_p = dynamic_cast (&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 > > 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 - 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 - 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 PTRIA; - const PTRIA *ptria_p = dynamic_cast (&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 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 - void - compute_intergrid_weights_3 ( - const dealii::DoFHandler &coarse_grid, - const unsigned int coarse_component, - const InterGridMap > &coarse_to_fine_grid_map, - const std::vector > ¶meter_dofs, - const std::vector &weight_mapping, - std::vector > &weights, - const typename dealii::DoFHandler::active_cell_iterator &begin, - const typename dealii::DoFHandler::active_cell_iterator &end) - { - // aliases to the finite elements used by the dof handlers: - const FiniteElement &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 global_parameter_representation (n_fine_dofs); - - typename dealii::DoFHandler::active_cell_iterator cell; - std::vector 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 - 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 - void - compute_intergrid_weights_2 ( - const dealii::DoFHandler &coarse_grid, - const unsigned int coarse_component, - const InterGridMap > &coarse_to_fine_grid_map, - const std::vector > ¶meter_dofs, - const std::vector &weight_mapping, - std::vector > &weights) - { - // simply distribute the range of cells to different threads - typedef typename dealii::DoFHandler::active_cell_iterator active_cell_iterator; - std::vector > - cell_intervals = Threads::split_range (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 &, - const unsigned int , - const InterGridMap > &, - const std::vector > &, - const std::vector &, - std::vector > &, - const typename dealii::DoFHandler::active_cell_iterator &, - const typename dealii::DoFHandler::active_cell_iterator &) - = &compute_intergrid_weights_3; - for (unsigned int i=0; i - unsigned int - compute_intergrid_weights_1 ( - const dealii::DoFHandler &coarse_grid, - const unsigned int coarse_component, - const dealii::DoFHandler &fine_grid, - const unsigned int fine_component, - const InterGridMap > &coarse_to_fine_grid_map, - std::vector > &weights, - std::vector &weight_mapping) - { - // aliases to the finite elements used by the dof handlers: - const FiniteElement &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::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 > - parameter_dofs (coarse_dofs_per_cell_component, - dealii::Vector(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 dof_is_interesting (fine_grid.n_dofs(), false); - std::vector local_dof_indices (fine_fe.dofs_per_cell); - - for (typename dealii::DoFHandler::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 local_dof_indices(fine_fe.dofs_per_cell); - unsigned int next_free_index=0; - for (typename dealii::DoFHandler::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; i1) && (sum==0)), ExcInternalError()); - }; -#endif - - - return n_parameters_on_fine_grid; - } - - - } - } - - - - template - void - compute_intergrid_constraints ( - const DoFHandler &coarse_grid, - const unsigned int coarse_component, - const DoFHandler &fine_grid, - const unsigned int fine_component, - const InterGridMap > &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 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 > 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 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 coarse_dof_is_parameter (coarse_grid.n_dofs()); - if (true) - { - std::vector 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 representants(n_coarse_dofs, numbers::invalid_dof_index); - for (types::global_dof_index parameter_dof=0; parameter_dof 0, ExcInternalError()); - - // find the column where the representant is mentioned - std::map::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(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 > constraint_line; - for (types::global_dof_index global_dof=0; global_dof 0, ExcInternalError()); - std::map::const_iterator - col_entry = weights[0].end(); - for (; first_used_rowsecond == 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::const_iterator - j = weights[row].find(col); - if ((j != weights[row].end()) && (j->second != 0)) - constraint_line.push_back (std::pair(representants[row], - j->second)); - }; - - constraints.add_entries (global_dof, constraint_line); - }; - } - - - - template - void - compute_intergrid_transfer_representation ( - const DoFHandler &coarse_grid, - const unsigned int coarse_component, - const DoFHandler &fine_grid, - const unsigned int fine_component, - const InterGridMap > &coarse_to_fine_grid_map, - std::vector > &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 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 > 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 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 (), numbers::invalid_dof_index)); - - // first construct the inverse mapping of weight_mapping - std::vector inverse_weight_mapping (n_global_parm_dofs, - DoFHandler::invalid_dof_index); - for (types::global_dof_index i=0; i::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::const_iterator j = weights[i].begin(); - for (; j!=weights[i].end(); ++j) - { - const types::global_dof_index p = inverse_weight_mapping[j->first]; - Assert (psecond; - }; - }; - } - - - template void map_dof_to_boundary_indices (const DH &dof_handler, @@ -5689,87 +1811,6 @@ namespace DoFTools - template class DH> - void - make_zero_boundary_constraints (const DH &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 face_dofs; - face_dofs.reserve (max_dofs_per_face(dof)); - - typename DH::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::faces_per_cell; - ++face_no) - { - const FiniteElement &fe = cell->get_fe(); - - const typename DH::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; iget_fe().get_nonzero_components (i); - bool nonzero = false; - for (unsigned int c=0; c class DH> - void - make_zero_boundary_constraints (const DH &dof, - ConstraintMatrix &zero_boundary_constraints, - const ComponentMask &component_mask) - { - make_zero_boundary_constraints(dof, numbers::invalid_boundary_id, - zero_boundary_constraints, component_mask); - } - - template 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, SP> - (const DoFHandler &dof, - SP &sparsity, - const ConstraintMatrix &, - const bool, - const unsigned int); - - template void - DoFTools::make_sparsity_pattern, SP> - (const hp::DoFHandler &dof, - SP &sparsity, - const ConstraintMatrix &, - const bool, - const unsigned int); - - template void - DoFTools::make_sparsity_pattern, SP> - (const MGDoFHandler &dof, - SP &sparsity, - const ConstraintMatrix &, - const bool, - const unsigned int); - - template void - DoFTools::make_sparsity_pattern, SP> - (const DoFHandler&, - const Table<2,Coupling>&, - SP &, - const ConstraintMatrix &, - const bool, - const unsigned int); - - template void - DoFTools::make_sparsity_pattern, SP> - (const hp::DoFHandler&, - const Table<2,Coupling>&, - SP &, - const ConstraintMatrix &, - const bool, - const unsigned int); - - template void - DoFTools::make_sparsity_pattern, SP> - (const MGDoFHandler&, - const Table<2,Coupling>&, - SP &, - const ConstraintMatrix &, - const bool, - const unsigned int); - - template void - DoFTools::make_sparsity_pattern, SP> - (const DoFHandler &dof_row, - const DoFHandler &dof_col, - SP &sparsity); - - template void - DoFTools::make_sparsity_pattern, SP> - (const hp::DoFHandler &dof_row, - const hp::DoFHandler &dof_col, - SP &sparsity); - - template void - DoFTools::make_boundary_sparsity_pattern,SP> - (const DoFHandler& dof, - const std::vector &, - SP &); - - template void - DoFTools::make_boundary_sparsity_pattern,SP> - (const hp::DoFHandler& dof, - const std::vector &, - SP &); - - template void - DoFTools::make_boundary_sparsity_pattern,SP> - (const DoFHandler& dof, - const FunctionMap::type &boundary_indicators, - const std::vector &dof_to_boundary_mapping, - SP &sparsity); - - template void - DoFTools::make_boundary_sparsity_pattern,SP> - (const hp::DoFHandler& dof, - const FunctionMap::type &boundary_indicators, - const std::vector &dof_to_boundary_mapping, - SP &sparsity); - -#if deal_II_dimension < 3 - template void - DoFTools::make_boundary_sparsity_pattern,SP> - (const hp::DoFHandler& dof, - const FunctionMap::type &boundary_indicators, - const std::vector &dof_to_boundary_mapping, - SP &sparsity); - #endif - - template void - DoFTools::make_flux_sparsity_pattern,SP> - (const DoFHandler &dof, - SP &sparsity); - - template void - DoFTools::make_flux_sparsity_pattern,SP> - (const hp::DoFHandler &dof, - SP &sparsity); - - template void - DoFTools::make_cell_patches,SP> - (SP&, const DoFHandler&, const unsigned int, const std::vector&, types::global_dof_index); - - template void - DoFTools::make_cell_patches,SP> - (SP&, const MGDoFHandler&, const unsigned int, const std::vector&, types::global_dof_index); - -#if deal_II_dimension > 1 - - template void - DoFTools::make_flux_sparsity_pattern,SP> - (const DoFHandler &dof, - SP &, - const Table<2,Coupling>&, - const Table<2,Coupling>&); - - template void - DoFTools::make_flux_sparsity_pattern,SP> - (const DoFHandler &dof, - SP &sparsity, - const ConstraintMatrix &constraints, - const bool, const unsigned int); - - template void - DoFTools::make_flux_sparsity_pattern,SP> - (const hp::DoFHandler &dof, - SP &sparsity, - const ConstraintMatrix &constraints, - const bool, const unsigned int); - - template void - DoFTools::make_flux_sparsity_pattern,SP> - (const hp::DoFHandler &dof, - SP &, - const Table<2,Coupling>&, - const Table<2,Coupling>&); -#endif - -#if deal_II_dimension < 3 - - template void - DoFTools::make_sparsity_pattern, SP> - (const DoFHandler &dof, - SP &sparsity, - const ConstraintMatrix &, - const bool, - const unsigned int); - - template void - DoFTools::make_sparsity_pattern, SP> - (const hp::DoFHandler &dof, - SP &sparsity, - const ConstraintMatrix &, - const bool, - const unsigned int); - - template void - DoFTools::make_sparsity_pattern, SP> - (const DoFHandler&, - const Table<2,Coupling>&, - SP &, - const ConstraintMatrix &, - const bool, - const unsigned int); - - template void - DoFTools::make_sparsity_pattern, SP> - (const hp::DoFHandler&, - const Table<2,Coupling>&, - SP &, - const ConstraintMatrix &, - const bool, - const unsigned int); - - template void - DoFTools::make_sparsity_pattern, SP> - (const DoFHandler &dof_row, - const DoFHandler &dof_col, - SP &sparsity); - - template void - DoFTools::make_sparsity_pattern, SP> - (const hp::DoFHandler &dof_row, - const hp::DoFHandler &dof_col, - SP &sparsity); - - template void - DoFTools::make_boundary_sparsity_pattern,SP> - (const DoFHandler& dof, - const std::vector &, - SP &); - - //template void - //DoFTools::make_boundary_sparsity_pattern,SP> - //(const hp::DoFHandler& dof, - // const std::vector &, - // SP &); - - template void - DoFTools::make_boundary_sparsity_pattern,SP> - (const DoFHandler& dof, - const FunctionMap::type &boundary_indicators, - const std::vector &dof_to_boundary_mapping, - SP &sparsity); - - //template void - //DoFTools::make_boundary_sparsity_pattern,SP> - //(const hp::DoFHandler& dof, - // const FunctionMap::type &boundary_indicators, - // const std::vector &dof_to_boundary_mapping, - // SP &sparsity); - -#endif - - -#if deal_II_dimension == 3 - - template void - DoFTools::make_sparsity_pattern, SP> - (const DoFHandler<1,3> &dof, - SP &sparsity, - const ConstraintMatrix &, - const bool, - const unsigned int); - - template void - DoFTools::make_sparsity_pattern, SP> - (const hp::DoFHandler<1,3> &dof, - SP &sparsity, - const ConstraintMatrix &, - const bool, - const unsigned int); - - template void - DoFTools::make_sparsity_pattern, SP> - (const DoFHandler<1,3>&, - const Table<2,Coupling>&, - SP &, - const ConstraintMatrix &, - const bool, - const unsigned int); - - template void - DoFTools::make_sparsity_pattern, SP> - (const hp::DoFHandler<1,3>&, - const Table<2,Coupling>&, - SP &, - const ConstraintMatrix &, - const bool, - const unsigned int); - - template void - DoFTools::make_sparsity_pattern, SP> - (const DoFHandler<1,3> &dof_row, - const DoFHandler<1,3> &dof_col, - SP &sparsity); - - template void - DoFTools::make_sparsity_pattern, SP> - (const hp::DoFHandler<1,3> &dof_row, - const hp::DoFHandler<1,3> &dof_col, - SP &sparsity); - - template void - DoFTools::make_boundary_sparsity_pattern,SP> - (const DoFHandler<1,3>& dof, - const std::vector &, - SP &); - - template void - DoFTools::make_boundary_sparsity_pattern,SP> - (const hp::DoFHandler<1,3>& dof, - const std::vector &, - SP &); - - template void - DoFTools::make_boundary_sparsity_pattern,SP> - (const DoFHandler<1,3>& dof, - const FunctionMap<3>::type &boundary_indicators, - const std::vector &dof_to_boundary_mapping, - SP &sparsity); - - template void - DoFTools::make_boundary_sparsity_pattern,SP> - (const hp::DoFHandler<1,3>& dof, - const FunctionMap<3>::type &boundary_indicators, - const std::vector &dof_to_boundary_mapping, - SP &sparsity); - -#endif - - } - + template void + DoFTools::make_cell_patches,SP> + (SP&, const DoFHandler&, const unsigned int, const std::vector&, 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,SP> + (SP&, const MGDoFHandler&, const unsigned int, const std::vector&, types::global_dof_index); } -for (deal_II_dimension : DIMENSIONS) -{ -#if deal_II_dimension != 1 - template - void - DoFTools::make_hanging_node_constraints (const MGDoFHandler &dof_handler, - ConstraintMatrix &constraints); - -#endif - } for (deal_II_dimension : DIMENSIONS) { - template - Table<2,DoFTools::Coupling> - DoFTools::dof_couplings_from_component_couplings - (const FiniteElement &fe, - const Table<2,DoFTools::Coupling> &component_couplings); - template void DoFTools::make_vertex_patches (SparsityPattern&, const DoFHandler&, unsigned int, bool, bool, bool, bool); @@ -427,22 +54,6 @@ for (deal_II_dimension : DIMENSIONS) void DoFTools::make_child_patches(SparsityPattern&, const MGDoFHandler&, unsigned int, bool, bool); -#if deal_II_dimension < 3 -template -void -DoFTools:: -make_hanging_node_constraints (const DoFHandler &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 ( const DoFHandler&, std::vector&, std::vector); -template -void -DoFTools::compute_intergrid_constraints ( - const DoFHandler &, const unsigned int, - const DoFHandler &, const unsigned int, - const InterGridMap > &, - ConstraintMatrix&); - -template -void -DoFTools::compute_intergrid_transfer_representation -(const DoFHandler &, const unsigned int, - const DoFHandler &, const unsigned int, - const InterGridMap > &, - std::vector > &); - - template void DoFTools::map_dof_to_boundary_indices > @@ -1089,36 +683,6 @@ DoFTools::convert_couplings_to_blocks ( const hp::DoFHandler&, const Table<2, Coupling>&, std::vector >&); -template -void -DoFTools::make_zero_boundary_constraints -(const DoFHandler &, - ConstraintMatrix &, - const ComponentMask &); - -template -void -DoFTools::make_zero_boundary_constraints -(const DoFHandler &, - const types::boundary_id , - ConstraintMatrix &, - const ComponentMask &); - -template -void -DoFTools::make_zero_boundary_constraints -(const hp::DoFHandler &, - ConstraintMatrix &, - const ComponentMask &); - -template -void -DoFTools::make_zero_boundary_constraints -(const hp::DoFHandler &, - 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 +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +#include +#include + +DEAL_II_NAMESPACE_OPEN + + + +namespace DoFTools +{ + namespace internal + { + namespace + { + inline bool + check_master_dof_list (const FullMatrix &face_interpolation_matrix, + const std::vector &master_dof_list) + { + const unsigned int N = master_dof_list.size(); + + FullMatrix tmp (N,N); + for (unsigned int i=0; i p(N); + for (unsigned int i=0; i 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 + void + select_master_dofs_for_face_restriction (const FiniteElement &fe1, + const FiniteElement &fe2, + const FullMatrix &face_interpolation_matrix, + std::vector &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 master_dof_list; + unsigned int index = 0; + for (int v=0; + v(GeometryInfo::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(GeometryInfo::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(GeometryInfo::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::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 + void + ensure_existence_of_master_dof_mask (const FiniteElement &fe1, + const FiniteElement &fe2, + const FullMatrix &face_interpolation_matrix, + std_cxx1x::shared_ptr > &master_dof_mask) + { + if (master_dof_mask == std_cxx1x::shared_ptr >()) + { + master_dof_mask = std_cxx1x::shared_ptr > + (new std::vector (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 + void + ensure_existence_of_face_matrix (const FiniteElement &fe1, + const FiniteElement &fe2, + std_cxx1x::shared_ptr > &matrix) + { + if (matrix == std_cxx1x::shared_ptr >()) + { + matrix = std_cxx1x::shared_ptr > + (new FullMatrix (fe2.dofs_per_face, + fe1.dofs_per_face)); + fe1.get_face_interpolation_matrix (fe2, + *matrix); + } + } + + + + /** + * Same, but for subface interpolation matrices. + */ + template + void + ensure_existence_of_subface_matrix (const FiniteElement &fe1, + const FiniteElement &fe2, + const unsigned int subface, + std_cxx1x::shared_ptr > &matrix) + { + if (matrix == std_cxx1x::shared_ptr >()) + { + matrix = std_cxx1x::shared_ptr > + (new FullMatrix (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 &face_interpolation_matrix, + const std::vector &master_dof_mask, + std_cxx1x::shared_ptr,FullMatrix > > &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(face_interpolation_matrix.n()), + ExcInternalError()); + + if (split_matrix == + std_cxx1x::shared_ptr,FullMatrix > >()) + { + split_matrix + = std_cxx1x::shared_ptr,FullMatrix > > + (new std::pair,FullMatrix >()); + + 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; ifirst(nth_master_dof,j) + = face_interpolation_matrix(i,j); + ++nth_master_dof; + } + else + { + for (unsigned int j=0; jsecond(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 + struct DoFHandlerSupportsDifferentFEs + { + static const bool value = true; + }; + + + template + struct DoFHandlerSupportsDifferentFEs< dealii::DoFHandler > + { + 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 + unsigned int + n_finite_elements (const dealii::hp::DoFHandler &dof_handler) + { + return dof_handler.get_fe().size(); + } + + + template + 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 + 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_non_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 & + 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; sfn_children(); ++sf) + if (sf != dominating_subface_no) + { + const FiniteElement & + 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 &master_dofs, + const std::vector &slave_dofs, + const FullMatrix &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= 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 + 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 dofs_on_mother; + std::vector 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::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; cface(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; cface(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 &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 + void + make_oldstyle_hanging_node_constraints (const DH &dof_handler, + ConstraintMatrix &constraints, + dealii::internal::int2type<3>) + { + const unsigned int dim = 3; + + std::vector dofs_on_mother; + std::vector 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::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::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; cface(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; cface(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 &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; dofchild(0)->line(1)->dof_index(dof, fe_index); + for (unsigned int dof=0; dofchild(2)->line(1)->dof_index(dof, fe_index); + for (unsigned int dof=0; dofchild(0)->line(3)->dof_index(dof, fe_index); + for (unsigned int dof=0; dofchild(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 + 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 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 master_dofs; + std::vector slave_dofs; + std::vector 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 > > + face_interpolation_matrices (n_finite_elements (dof_handler), + n_finite_elements (dof_handler)); + Table<3,std_cxx1x::shared_ptr > > + subface_interpolation_matrices (n_finite_elements (dof_handler), + n_finite_elements (dof_handler), + GeometryInfo::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,FullMatrix > > > + 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 > > + 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::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::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; cface(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::value == true) + for (unsigned int c=0; cface(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; cface(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; iget_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::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 &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 &restrict_mother_to_virtual_master_inv + = (split_face_interpolation_matrices + [dominating_fe_index][cell->active_fe_index()]->first); + + const FullMatrix &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; iget_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; + sfface(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 &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 &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::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 + 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()); + } + + + + 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 + void + set_periodicity_constraints (const FaceIterator &face_1, + const typename identity::type &face_2, + const FullMatrix &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::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 child_transformation (dofs_per_face, dofs_per_face); + FullMatrix subface_interpolation (dofs_per_face, dofs_per_face); + for (unsigned int c=0; cn_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 &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 dofs_1(dofs_per_face); + std::vector 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 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 + void + make_periodicity_constraints (const FaceIterator &face_1, + const typename identity::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::max_children_per_face && + face_2->n_children() == GeometryInfo::max_children_per_face, + ExcNotImplemented()); + + for (unsigned int i = 0; i < GeometryInfo::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(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(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 + 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 + 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 PTRIA; + const PTRIA *ptria_p = dynamic_cast (&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 > > 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 + 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 + 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 PTRIA; + const PTRIA *ptria_p = dynamic_cast (&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 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 + void + compute_intergrid_weights_3 ( + const dealii::DoFHandler &coarse_grid, + const unsigned int coarse_component, + const InterGridMap > &coarse_to_fine_grid_map, + const std::vector > ¶meter_dofs, + const std::vector &weight_mapping, + std::vector > &weights, + const typename dealii::DoFHandler::active_cell_iterator &begin, + const typename dealii::DoFHandler::active_cell_iterator &end) + { + // aliases to the finite elements used by the dof handlers: + const FiniteElement &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 global_parameter_representation (n_fine_dofs); + + typename dealii::DoFHandler::active_cell_iterator cell; + std::vector 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 + 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 + void + compute_intergrid_weights_2 ( + const dealii::DoFHandler &coarse_grid, + const unsigned int coarse_component, + const InterGridMap > &coarse_to_fine_grid_map, + const std::vector > ¶meter_dofs, + const std::vector &weight_mapping, + std::vector > &weights) + { + // simply distribute the range of cells to different threads + typedef typename dealii::DoFHandler::active_cell_iterator active_cell_iterator; + std::vector > + cell_intervals = Threads::split_range (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 &, + const unsigned int , + const InterGridMap > &, + const std::vector > &, + const std::vector &, + std::vector > &, + const typename dealii::DoFHandler::active_cell_iterator &, + const typename dealii::DoFHandler::active_cell_iterator &) + = &compute_intergrid_weights_3; + for (unsigned int i=0; i + unsigned int + compute_intergrid_weights_1 ( + const dealii::DoFHandler &coarse_grid, + const unsigned int coarse_component, + const dealii::DoFHandler &fine_grid, + const unsigned int fine_component, + const InterGridMap > &coarse_to_fine_grid_map, + std::vector > &weights, + std::vector &weight_mapping) + { + // aliases to the finite elements used by the dof handlers: + const FiniteElement &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::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 > + parameter_dofs (coarse_dofs_per_cell_component, + dealii::Vector(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 dof_is_interesting (fine_grid.n_dofs(), false); + std::vector local_dof_indices (fine_fe.dofs_per_cell); + + for (typename dealii::DoFHandler::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 local_dof_indices(fine_fe.dofs_per_cell); + unsigned int next_free_index=0; + for (typename dealii::DoFHandler::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; i1) && (sum==0)), ExcInternalError()); + }; +#endif + + + return n_parameters_on_fine_grid; + } + + + } + } + + + + template + void + compute_intergrid_constraints ( + const DoFHandler &coarse_grid, + const unsigned int coarse_component, + const DoFHandler &fine_grid, + const unsigned int fine_component, + const InterGridMap > &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 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 > 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 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 coarse_dof_is_parameter (coarse_grid.n_dofs()); + if (true) + { + std::vector 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 representants(n_coarse_dofs, numbers::invalid_dof_index); + for (types::global_dof_index parameter_dof=0; parameter_dof 0, ExcInternalError()); + + // find the column where the representant is mentioned + std::map::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(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 > constraint_line; + for (types::global_dof_index global_dof=0; global_dof 0, ExcInternalError()); + std::map::const_iterator + col_entry = weights[0].end(); + for (; first_used_rowsecond == 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::const_iterator + j = weights[row].find(col); + if ((j != weights[row].end()) && (j->second != 0)) + constraint_line.push_back (std::pair(representants[row], + j->second)); + }; + + constraints.add_entries (global_dof, constraint_line); + }; + } + + + + template + void + compute_intergrid_transfer_representation ( + const DoFHandler &coarse_grid, + const unsigned int coarse_component, + const DoFHandler &fine_grid, + const unsigned int fine_component, + const InterGridMap > &coarse_to_fine_grid_map, + std::vector > &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 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 > 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 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 (), numbers::invalid_dof_index)); + + // first construct the inverse mapping of weight_mapping + std::vector inverse_weight_mapping (n_global_parm_dofs, + DoFHandler::invalid_dof_index); + for (types::global_dof_index i=0; i::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::const_iterator j = weights[i].begin(); + for (; j!=weights[i].end(); ++j) + { + const types::global_dof_index p = inverse_weight_mapping[j->first]; + Assert (psecond; + }; + }; + } + + + + template class DH> + void + make_zero_boundary_constraints (const DH &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 face_dofs; + face_dofs.reserve (max_dofs_per_face(dof)); + + typename DH::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::faces_per_cell; + ++face_no) + { + const FiniteElement &fe = cell->get_fe(); + + const typename DH::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; iget_fe().get_nonzero_components (i); + bool nonzero = false; + for (unsigned int c=0; c class DH> + void + make_zero_boundary_constraints (const DH &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 &dof_handler, + ConstraintMatrix &constraints); + +#endif + +#if deal_II_dimension < 3 + +template +void +DoFTools:: +make_hanging_node_constraints (const DoFHandler &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 &, + ConstraintMatrix &, + const ComponentMask &); + +template +void +DoFTools::make_zero_boundary_constraints +(const DoFHandler &, + const types::boundary_id , + ConstraintMatrix &, + const ComponentMask &); + +template +void +DoFTools::make_zero_boundary_constraints +(const hp::DoFHandler &, + ConstraintMatrix &, + const ComponentMask &); + +template +void +DoFTools::make_zero_boundary_constraints +(const hp::DoFHandler &, + const types::boundary_id , + ConstraintMatrix &, + const ComponentMask &); + +template +void +DoFTools::compute_intergrid_constraints ( + const DoFHandler &, const unsigned int, + const DoFHandler &, const unsigned int, + const InterGridMap > &, + ConstraintMatrix&); + +template +void +DoFTools::compute_intergrid_transfer_representation +(const DoFHandler &, const unsigned int, + const DoFHandler &, const unsigned int, + const InterGridMap > &, + std::vector > &); + +} 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 +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +#include +#include + +DEAL_II_NAMESPACE_OPEN + + + +namespace DoFTools +{ + + template + 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 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 + 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 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 > 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 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 + 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 > + cell_list + = GridTools::get_finest_common_cells (dof_row, dof_col); + + + typename std::list >::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 + local_dof_indices_row(dofs_per_cell_row); + std::vector + 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; ihas_children()) + { + const std::vector + child_cells = GridTools::get_active_child_cells (cell_row); + for (unsigned int i=0; iget_fe().dofs_per_cell; + const unsigned int dofs_per_cell_col = + cell_col->get_fe().dofs_per_cell; + std::vector + local_dof_indices_row(dofs_per_cell_row); + std::vector + 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 + child_cells = GridTools::get_active_child_cells (cell_col); + for (unsigned int i=0; iget_fe().dofs_per_cell; + const unsigned int dofs_per_cell_col = + cell_col_child->get_fe().dofs_per_cell; + std::vector + local_dof_indices_row(dofs_per_cell_row); + std::vector + 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 + void + make_boundary_sparsity_pattern ( + const DH &dof, + const std::vector &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 (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::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 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::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 + void make_boundary_sparsity_pattern ( + const DH &dof, + const typename FunctionMap::type &boundary_indicators, + const std::vector &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 boundary_dof_boundary_indices (dofs_per_vertex); + + // next get boundary mapped dof indices of boundary dofs + for (unsigned int i=0; ivertex_dof_index(direction,i)]; + + for (unsigned int i=0; i::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 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::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 + 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 dofs_on_this_cell; + std::vector 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::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 + void + make_flux_sparsity_pattern (const DH &dof, + SparsityPattern &sparsity) + { + ConstraintMatrix constraints; + make_flux_sparsity_pattern (dof, sparsity, constraints); + } + + template + Table<2,Coupling> + dof_couplings_from_component_couplings (const FiniteElement &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 + std::vector > + dof_couplings_from_component_couplings + (const hp::FECollection &fe, + const Table<2,Coupling> &component_couplings) + { + std::vector > return_value (fe.size()); + for (unsigned int i=0; i + void + make_flux_sparsity_pattern (const DH &dof, + SparsityPattern &sparsity, + const Table<2,Coupling> &int_mask, + const Table<2,Coupling> &flux_mask) + { + const FiniteElement &fe = dof.get_fe(); + + std::vector dofs_on_this_cell(fe.dofs_per_cell); + std::vector 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::faces_per_cell); + for (unsigned int i=0; i::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::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; ineighbor(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; iface(neighbor_face)->set_user_flag (); + } + } + else + { + neighbor->get_dof_indices (dofs_on_other_cell); + for (unsigned int i=0; iface(neighbor_face)->set_user_flag (); + } + } + } + } + } + + + // implementation of the same function in namespace DoFTools for + // non-hp DoFHandlers + template + void + make_flux_sparsity_pattern (const dealii::hp::DoFHandler &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 &fe = dof.get_fe(); + + std::vector dofs_on_this_cell(DoFTools::max_dofs_per_cell(dof)); + std::vector dofs_on_other_cell(DoFTools::max_dofs_per_cell(dof)); + + const std::vector > + int_dof_mask + = dof_couplings_from_component_couplings(fe, int_mask); + + typename dealii::hp::DoFHandler::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; iget_fe().dofs_per_cell; ++i) + for (unsigned int j=0; jget_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::faces_per_cell; + ++face) + { + const typename dealii::hp::DoFHandler::face_iterator + cell_face = cell->face(face); + if (cell_face->user_flag_set ()) + continue; + + if (cell->at_boundary (face) ) + { + for (unsigned int i=0; iget_fe().dofs_per_cell; ++i) + for (unsigned int j=0; jget_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::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::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::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; iget_fe().dofs_per_cell; ++i) + { + for (unsigned int j=0; jget_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; iget_fe().dofs_per_cell; ++i) + { + for (unsigned int j=0; jget_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 + 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 user_flags; + dof.get_tria().save_user_flags(user_flags); + const_cast &>(dof.get_tria()).clear_user_flags (); + + internal::make_flux_sparsity_pattern (dof, sparsity, + int_mask, flux_mask); + + // finally restore the user flags + const_cast &>(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, SP> + (const DoFHandler &dof, + SP &sparsity, + const ConstraintMatrix &, + const bool, + const unsigned int); + + template void + DoFTools::make_sparsity_pattern, SP> + (const hp::DoFHandler &dof, + SP &sparsity, + const ConstraintMatrix &, + const bool, + const unsigned int); + + template void + DoFTools::make_sparsity_pattern, SP> + (const MGDoFHandler &dof, + SP &sparsity, + const ConstraintMatrix &, + const bool, + const unsigned int); + + template void + DoFTools::make_sparsity_pattern, SP> + (const DoFHandler&, + const Table<2,Coupling>&, + SP &, + const ConstraintMatrix &, + const bool, + const unsigned int); + + template void + DoFTools::make_sparsity_pattern, SP> + (const hp::DoFHandler&, + const Table<2,Coupling>&, + SP &, + const ConstraintMatrix &, + const bool, + const unsigned int); + + template void + DoFTools::make_sparsity_pattern, SP> + (const MGDoFHandler&, + const Table<2,Coupling>&, + SP &, + const ConstraintMatrix &, + const bool, + const unsigned int); + + template void + DoFTools::make_sparsity_pattern, SP> + (const DoFHandler &dof_row, + const DoFHandler &dof_col, + SP &sparsity); + + template void + DoFTools::make_sparsity_pattern, SP> + (const hp::DoFHandler &dof_row, + const hp::DoFHandler &dof_col, + SP &sparsity); + + template void + DoFTools::make_boundary_sparsity_pattern,SP> + (const DoFHandler& dof, + const std::vector &, + SP &); + + template void + DoFTools::make_boundary_sparsity_pattern,SP> + (const hp::DoFHandler& dof, + const std::vector &, + SP &); + + template void + DoFTools::make_boundary_sparsity_pattern,SP> + (const DoFHandler& dof, + const FunctionMap::type &boundary_indicators, + const std::vector &dof_to_boundary_mapping, + SP &sparsity); + + template void + DoFTools::make_boundary_sparsity_pattern,SP> + (const hp::DoFHandler& dof, + const FunctionMap::type &boundary_indicators, + const std::vector &dof_to_boundary_mapping, + SP &sparsity); + +#if deal_II_dimension < 3 + template void + DoFTools::make_boundary_sparsity_pattern,SP> + (const hp::DoFHandler& dof, + const FunctionMap::type &boundary_indicators, + const std::vector &dof_to_boundary_mapping, + SP &sparsity); + #endif + + template void + DoFTools::make_flux_sparsity_pattern,SP> + (const DoFHandler &dof, + SP &sparsity); + + template void + DoFTools::make_flux_sparsity_pattern,SP> + (const hp::DoFHandler &dof, + SP &sparsity); + +#if deal_II_dimension > 1 + + template void + DoFTools::make_flux_sparsity_pattern,SP> + (const DoFHandler &dof, + SP &, + const Table<2,Coupling>&, + const Table<2,Coupling>&); + + template void + DoFTools::make_flux_sparsity_pattern,SP> + (const DoFHandler &dof, + SP &sparsity, + const ConstraintMatrix &constraints, + const bool, const unsigned int); + + template void + DoFTools::make_flux_sparsity_pattern,SP> + (const hp::DoFHandler &dof, + SP &sparsity, + const ConstraintMatrix &constraints, + const bool, const unsigned int); + + template void + DoFTools::make_flux_sparsity_pattern,SP> + (const hp::DoFHandler &dof, + SP &, + const Table<2,Coupling>&, + const Table<2,Coupling>&); +#endif + +#if deal_II_dimension < 3 + + template void + DoFTools::make_sparsity_pattern, SP> + (const DoFHandler &dof, + SP &sparsity, + const ConstraintMatrix &, + const bool, + const unsigned int); + + template void + DoFTools::make_sparsity_pattern, SP> + (const hp::DoFHandler &dof, + SP &sparsity, + const ConstraintMatrix &, + const bool, + const unsigned int); + + template void + DoFTools::make_sparsity_pattern, SP> + (const DoFHandler&, + const Table<2,Coupling>&, + SP &, + const ConstraintMatrix &, + const bool, + const unsigned int); + + template void + DoFTools::make_sparsity_pattern, SP> + (const hp::DoFHandler&, + const Table<2,Coupling>&, + SP &, + const ConstraintMatrix &, + const bool, + const unsigned int); + + template void + DoFTools::make_sparsity_pattern, SP> + (const DoFHandler &dof_row, + const DoFHandler &dof_col, + SP &sparsity); + + template void + DoFTools::make_sparsity_pattern, SP> + (const hp::DoFHandler &dof_row, + const hp::DoFHandler &dof_col, + SP &sparsity); + + template void + DoFTools::make_boundary_sparsity_pattern,SP> + (const DoFHandler& dof, + const std::vector &, + SP &); + + //template void + //DoFTools::make_boundary_sparsity_pattern,SP> + //(const hp::DoFHandler& dof, + // const std::vector &, + // SP &); + + template void + DoFTools::make_boundary_sparsity_pattern,SP> + (const DoFHandler& dof, + const FunctionMap::type &boundary_indicators, + const std::vector &dof_to_boundary_mapping, + SP &sparsity); + + //template void + //DoFTools::make_boundary_sparsity_pattern,SP> + //(const hp::DoFHandler& dof, + // const FunctionMap::type &boundary_indicators, + // const std::vector &dof_to_boundary_mapping, + // SP &sparsity); + +#endif + + +#if deal_II_dimension == 3 + + template void + DoFTools::make_sparsity_pattern, SP> + (const DoFHandler<1,3> &dof, + SP &sparsity, + const ConstraintMatrix &, + const bool, + const unsigned int); + + template void + DoFTools::make_sparsity_pattern, SP> + (const hp::DoFHandler<1,3> &dof, + SP &sparsity, + const ConstraintMatrix &, + const bool, + const unsigned int); + + template void + DoFTools::make_sparsity_pattern, SP> + (const DoFHandler<1,3>&, + const Table<2,Coupling>&, + SP &, + const ConstraintMatrix &, + const bool, + const unsigned int); + + template void + DoFTools::make_sparsity_pattern, SP> + (const hp::DoFHandler<1,3>&, + const Table<2,Coupling>&, + SP &, + const ConstraintMatrix &, + const bool, + const unsigned int); + + template void + DoFTools::make_sparsity_pattern, SP> + (const DoFHandler<1,3> &dof_row, + const DoFHandler<1,3> &dof_col, + SP &sparsity); + + template void + DoFTools::make_sparsity_pattern, SP> + (const hp::DoFHandler<1,3> &dof_row, + const hp::DoFHandler<1,3> &dof_col, + SP &sparsity); + + template void + DoFTools::make_boundary_sparsity_pattern,SP> + (const DoFHandler<1,3>& dof, + const std::vector &, + SP &); + + template void + DoFTools::make_boundary_sparsity_pattern,SP> + (const hp::DoFHandler<1,3>& dof, + const std::vector &, + SP &); + + template void + DoFTools::make_boundary_sparsity_pattern,SP> + (const DoFHandler<1,3>& dof, + const FunctionMap<3>::type &boundary_indicators, + const std::vector &dof_to_boundary_mapping, + SP &sparsity); + + template void + DoFTools::make_boundary_sparsity_pattern,SP> + (const hp::DoFHandler<1,3>& dof, + const FunctionMap<3>::type &boundary_indicators, + const std::vector &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 &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::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 ; jdofs_per_cell ; ++j) - { - system_to_component_table[j] = std::pair(0,j); - system_to_base_table[j] = std::make_pair(std::make_pair(0U,0U),j); - } + system_to_component_table[j] = std::pair(0,j); for (unsigned int j=0 ; jdofs_per_face ; ++j) - { - face_system_to_component_table[j] = std::pair(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(0,j); } + + for (unsigned int j=0 ; jdofs_per_cell ; ++j) + system_to_base_table[j] = std::make_pair(std::make_pair(0U,0U),j); + for (unsigned int j=0 ; jdofs_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:: get_interpolation_matrix (const FiniteElement &x_source_fe, FullMatrix &interpolation_matrix) const { - // this is only implemented, if the source FE is also a Q element - AssertThrow ((dynamic_cast *>(&x_source_fe) != 0), - (typename FiniteElement::ExcInterpolationNotImplemented())); + // go through the list of elements we can interpolate from + if (const FE_Q_Base *source_fe + = dynamic_cast*>(&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(this->degree+1); + const unsigned int source_q_dofs_per_cell = Utilities::fixed_power(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 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 &source_fe - = dynamic_cast&>(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(this->degree+1); - const unsigned int source_q_dofs_per_cell = Utilities::fixed_power(source_fe.degree+1); + for (unsigned int i=0; ipoly_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 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; ipoly_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; idofs_per_cell; ++i) + for (unsigned int j=0; jdofs_per_cell; ++j) + if (std::fabs(interpolation_matrix(i,j)) < eps) + interpolation_matrix(i,j) = 0.; - for (unsigned int i=0; idofs_per_cell; ++i) + { + double sum = 0.; + for (unsigned int j=0; jdofs_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; idegree*dim; - for (unsigned int i=0; idofs_per_cell; ++i) - for (unsigned int j=0; jdofs_per_cell; ++i) + else if (dynamic_cast*>(&x_source_fe)) { - double sum = 0.; - for (unsigned int j=0; jdofs_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::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 #include #include -#include -#include -#include -#include -#include -#include -#include -#include -#include #include #include #include @@ -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 @@ -1271,703 +1261,6 @@ namespace FETools } - template class DH1, - template class DH2, - class InVector, class OutVector> - void - interpolate(const DH1 &dof1, - const InVector &u1, - const DH2 &dof2, - OutVector &u2) - { - ConstraintMatrix dummy; - dummy.close(); - interpolate(dof1, u1, dof2, dummy, u2); - } - - - - template class DH1, - template class DH2, - class InVector, class OutVector> - void - interpolate (const DH1 &dof1, - const InVector &u1, - const DH2 &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(&u1) != 0) - if (dynamic_cast*>(&dof1) != 0) - { - // if u1 is a parallel distributed - // PETSc vector, we check the local - // size of u1 for safety - Assert(dynamic_cast(&u1)->local_size() == dof1.locally_owned_dofs().n_elements(), - ExcDimensionMismatch(dynamic_cast(&u1)->local_size(), dof1.locally_owned_dofs().n_elements())); - }; - - if (dynamic_cast(&u2) != 0) - if (dynamic_cast*>(&dof2) != 0) - { - Assert(dynamic_cast(&u2)->local_size() == dof2.locally_owned_dofs().n_elements(), - ExcDimensionMismatch(dynamic_cast(&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 u1_local(DoFTools::max_dofs_per_cell(dof1)); - Vector 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 *, - std::map *, - std_cxx1x::shared_ptr > > > - interpolation_matrices; - - typename DH1::active_cell_iterator cell1 = dof1.begin_active(), - endc1 = dof1.end(); - typename DH2::active_cell_iterator cell2 = dof2.begin_active(), - endc2 = dof2.end(); - - std::vector 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::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 > - interpolation_matrix (new FullMatrix (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 - void - back_interpolate(const DoFHandler &dof1, - const InVector &u1, - const FiniteElement &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(&u1) != 0) - if (dynamic_cast*>(&dof1) != 0) - { - // if u1 is a parallel distributed - // PETSc vector, we check the local - // size of u1 for safety - Assert(dynamic_cast(&u1)->local_size() == dof1.locally_owned_dofs().n_elements(), - ExcDimensionMismatch(dynamic_cast(&u1)->local_size(), dof1.locally_owned_dofs().n_elements())); - }; - - if (dynamic_cast(&u1_interpolated) != 0) - if (dynamic_cast*>(&dof1) != 0) - { - Assert(dynamic_cast(&u1_interpolated)->local_size() == dof1.locally_owned_dofs().n_elements(), - ExcDimensionMismatch(dynamic_cast(&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 u1_local(dofs_per_cell1); - Vector u1_int_local(dofs_per_cell1); - - const types::subdomain_id subdomain_id = - dof1.get_tria().locally_owned_subdomain(); - - typename DoFHandler::active_cell_iterator cell = dof1.begin_active(), - endc = dof1.end(); - - FullMatrix 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::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 class DH, - class InVector, class OutVector, int spacedim> - void - back_interpolate(const DH &dof1, - const InVector &u1, - const FiniteElement &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(&u1) != 0) - if (dynamic_cast*>(&dof1) != 0) - { - // if u1 is a parallel distributed - // PETSc vector, we check the local - // size of u1 for safety - Assert(dynamic_cast(&u1)->local_size() == dof1.locally_owned_dofs().n_elements(), - ExcDimensionMismatch(dynamic_cast(&u1)->local_size(), dof1.locally_owned_dofs().n_elements())); - }; - - if (dynamic_cast(&u1_interpolated) != 0) - if (dynamic_cast*>(&dof1) != 0) - { - Assert(dynamic_cast(&u1_interpolated)->local_size() == dof1.locally_owned_dofs().n_elements(), - ExcDimensionMismatch(dynamic_cast(&u1_interpolated)->local_size(), dof1.locally_owned_dofs().n_elements())); - }; -#endif - - Vector u1_local(DoFTools::max_dofs_per_cell(dof1)); - Vector u1_int_local(DoFTools::max_dofs_per_cell(dof1)); - - const types::subdomain_id subdomain_id = - dof1.get_tria().locally_owned_subdomain(); - - typename DH::active_cell_iterator cell = dof1.begin_active(), - endc = dof1.end(); - - // map from possible fe objects in - // dof1 to the back_interpolation - // matrices - std::map *, - std_cxx1x::shared_ptr > > 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::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 > - (new FullMatrix(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 - void back_interpolate (const DoFHandler &dof1, - const ConstraintMatrix &constraints1, - const InVector &u1, - const DoFHandler &dof2, - const ConstraintMatrix &constraints2, - InVector &u1_interpolated) - { - Vector 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 - void back_interpolate (const DoFHandler &dof1, - const ConstraintMatrix &constraints1, - const PETScWrappers::MPI::Vector &u1, - const DoFHandler &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 - void back_interpolate (const DoFHandler &dof1, - const ConstraintMatrix &constraints1, - const parallel::distributed::Vector &u1, - const DoFHandler &dof2, - const ConstraintMatrix &constraints2, - parallel::distributed::Vector &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 - 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 - void back_interpolate(const DoFHandler &dof1, - const ConstraintMatrix &constraints1, - const InVector &u1, - const DoFHandler &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 - void interpolation_difference (const DoFHandler &dof1, - const InVector &u1, - const FiniteElement &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(&u1) != 0) - if (dynamic_cast*>(&dof1) != 0) - { - // if u1 is a parallel distributed - // PETSc vector, we check the local - // size of u1 for safety - Assert(dynamic_cast(&u1)->local_size() == dof1.locally_owned_dofs().n_elements(), - ExcDimensionMismatch(dynamic_cast(&u1)->local_size(), dof1.locally_owned_dofs().n_elements())); - }; - - if (dynamic_cast(&u1_difference) != 0) - if (dynamic_cast*>(&dof1) != 0) - { - Assert(dynamic_cast(&u1_difference)->local_size() == dof1.locally_owned_dofs().n_elements(), - ExcDimensionMismatch(dynamic_cast(&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 u1_local(dofs_per_cell); - Vector u1_diff_local(dofs_per_cell); - - const types::subdomain_id subdomain_id = - dof1.get_tria().locally_owned_subdomain(); - - FullMatrix difference_matrix(dofs_per_cell, dofs_per_cell); - get_interpolation_difference_matrix(dof1.get_fe(), fe2, - difference_matrix); - - typename DoFHandler::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::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 - void interpolation_difference(const DoFHandler &dof1, - const ConstraintMatrix &constraints1, - const InVector &u1, - const DoFHandler &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 - void project_dg(const DoFHandler &dof1, - const InVector &u1, - const DoFHandler &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::active_cell_iterator cell1 = dof1.begin_active(); - typename DoFHandler::active_cell_iterator cell2 = dof2.begin_active(); - typename DoFHandler::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 u1_local(n1); - Vector u2_local(n2); - std::vector dofs(n2); - - FullMatrix 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 - void extrapolate(const DoFHandler &dof1, - const InVector &u1, - const DoFHandler &dof2, - OutVector &u2) - { - ConstraintMatrix dummy; - dummy.close(); - extrapolate(dof1, u1, dof2, dummy, u2); - } - - - - template - void extrapolate(const DoFHandler &dof1, - const InVector &u1, - const DoFHandler &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 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::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::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_nn_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 - (const DoFHandler &, const Vector &, - const DoFHandler &, Vector &); - - template - void interpolate - (const DoFHandler &, const Vector &, - const DoFHandler &, 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 + (const FiniteElement &, + const FiniteElement &, + FullMatrix &); +#endif + #if deal_II_dimension == deal_II_space_dimension template class FEFactoryBase; @@ -80,12 +69,7 @@ for (deal_II_dimension : DIMENSIONS; deal_II_space_dimension : SPACE_DIMENSIONS void compute_component_wise( const FiniteElement& , std::vector&, std::vector >&); - template - - void get_interpolation_matrix - (const FiniteElement &, - const FiniteElement &, - FullMatrix &); + template void get_back_interpolation_matrix (const FiniteElement &, @@ -125,25 +109,6 @@ for (deal_II_dimension : DIMENSIONS; deal_II_space_dimension : SPACE_DIMENSIONS (const FiniteElement &, FullMatrix (&)[GeometryInfo::max_children_per_face], unsigned int, unsigned int); - template - void interpolate - (const hp::DoFHandler &, const Vector &, - const hp::DoFHandler &, Vector &); - template - void interpolate - (const hp::DoFHandler &, const Vector &, - const hp::DoFHandler &, const ConstraintMatrix &, - Vector &); - template - void interpolate - (const hp::DoFHandler &, const Vector &, - const hp::DoFHandler &, Vector &); - template - void interpolate - (const hp::DoFHandler &, const Vector &, - const hp::DoFHandler &, const ConstraintMatrix &, - Vector &); - template FiniteElement * get_fe_from_name (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 - (const DoFHandler &, const VEC &, - const FiniteElement &, VEC &); - template - void back_interpolate - (const DoFHandler &, const ConstraintMatrix &, - const VEC &, - const DoFHandler &, const ConstraintMatrix &, - VEC &); - template - void interpolation_difference - (const DoFHandler &, const VEC &, - const FiniteElement &, VEC &); - template - void interpolation_difference - (const DoFHandler &, const ConstraintMatrix &, - const VEC &, - const DoFHandler &, const ConstraintMatrix &, - VEC &); - template - void project_dg - (const DoFHandler &, const VEC &, - const DoFHandler &, VEC &); - template - void extrapolate - (const DoFHandler &, const VEC &, - const DoFHandler &, VEC &); - template - void extrapolate - (const DoFHandler &, const VEC &, - const DoFHandler &, 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 +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +#include + +#include + + +DEAL_II_NAMESPACE_OPEN + +namespace FETools +{ + template class DH1, + template class DH2, + class InVector, class OutVector> + void + interpolate(const DH1 &dof1, + const InVector &u1, + const DH2 &dof2, + OutVector &u2) + { + ConstraintMatrix dummy; + dummy.close(); + interpolate(dof1, u1, dof2, dummy, u2); + } + + + + template class DH1, + template class DH2, + class InVector, class OutVector> + void + interpolate (const DH1 &dof1, + const InVector &u1, + const DH2 &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(&u1) != 0) + if (dynamic_cast*>(&dof1) != 0) + { + // if u1 is a parallel distributed + // PETSc vector, we check the local + // size of u1 for safety + Assert(dynamic_cast(&u1)->local_size() == dof1.locally_owned_dofs().n_elements(), + ExcDimensionMismatch(dynamic_cast(&u1)->local_size(), dof1.locally_owned_dofs().n_elements())); + }; + + if (dynamic_cast(&u2) != 0) + if (dynamic_cast*>(&dof2) != 0) + { + Assert(dynamic_cast(&u2)->local_size() == dof2.locally_owned_dofs().n_elements(), + ExcDimensionMismatch(dynamic_cast(&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 u1_local(DoFTools::max_dofs_per_cell(dof1)); + Vector 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 *, + std::map *, + std_cxx1x::shared_ptr > > > + interpolation_matrices; + + typename DH1::active_cell_iterator cell1 = dof1.begin_active(), + endc1 = dof1.end(); + typename DH2::active_cell_iterator cell2 = dof2.begin_active(), + endc2 = dof2.end(); + + std::vector 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::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 > + interpolation_matrix (new FullMatrix (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 + void + back_interpolate(const DoFHandler &dof1, + const InVector &u1, + const FiniteElement &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(&u1) != 0) + if (dynamic_cast*>(&dof1) != 0) + { + // if u1 is a parallel distributed + // PETSc vector, we check the local + // size of u1 for safety + Assert(dynamic_cast(&u1)->local_size() == dof1.locally_owned_dofs().n_elements(), + ExcDimensionMismatch(dynamic_cast(&u1)->local_size(), dof1.locally_owned_dofs().n_elements())); + }; + + if (dynamic_cast(&u1_interpolated) != 0) + if (dynamic_cast*>(&dof1) != 0) + { + Assert(dynamic_cast(&u1_interpolated)->local_size() == dof1.locally_owned_dofs().n_elements(), + ExcDimensionMismatch(dynamic_cast(&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 u1_local(dofs_per_cell1); + Vector u1_int_local(dofs_per_cell1); + + const types::subdomain_id subdomain_id = + dof1.get_tria().locally_owned_subdomain(); + + typename DoFHandler::active_cell_iterator cell = dof1.begin_active(), + endc = dof1.end(); + + FullMatrix 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::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 class DH, + class InVector, class OutVector, int spacedim> + void + back_interpolate(const DH &dof1, + const InVector &u1, + const FiniteElement &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(&u1) != 0) + if (dynamic_cast*>(&dof1) != 0) + { + // if u1 is a parallel distributed + // PETSc vector, we check the local + // size of u1 for safety + Assert(dynamic_cast(&u1)->local_size() == dof1.locally_owned_dofs().n_elements(), + ExcDimensionMismatch(dynamic_cast(&u1)->local_size(), dof1.locally_owned_dofs().n_elements())); + }; + + if (dynamic_cast(&u1_interpolated) != 0) + if (dynamic_cast*>(&dof1) != 0) + { + Assert(dynamic_cast(&u1_interpolated)->local_size() == dof1.locally_owned_dofs().n_elements(), + ExcDimensionMismatch(dynamic_cast(&u1_interpolated)->local_size(), dof1.locally_owned_dofs().n_elements())); + }; +#endif + + Vector u1_local(DoFTools::max_dofs_per_cell(dof1)); + Vector u1_int_local(DoFTools::max_dofs_per_cell(dof1)); + + const types::subdomain_id subdomain_id = + dof1.get_tria().locally_owned_subdomain(); + + typename DH::active_cell_iterator cell = dof1.begin_active(), + endc = dof1.end(); + + // map from possible fe objects in + // dof1 to the back_interpolation + // matrices + std::map *, + std_cxx1x::shared_ptr > > 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::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 > + (new FullMatrix(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 + void back_interpolate (const DoFHandler &dof1, + const ConstraintMatrix &constraints1, + const InVector &u1, + const DoFHandler &dof2, + const ConstraintMatrix &constraints2, + InVector &u1_interpolated) + { + Vector 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 + void back_interpolate (const DoFHandler &dof1, + const ConstraintMatrix &constraints1, + const PETScWrappers::MPI::Vector &u1, + const DoFHandler &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 + void back_interpolate (const DoFHandler &dof1, + const ConstraintMatrix &constraints1, + const parallel::distributed::Vector &u1, + const DoFHandler &dof2, + const ConstraintMatrix &constraints2, + parallel::distributed::Vector &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 + 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 + void back_interpolate(const DoFHandler &dof1, + const ConstraintMatrix &constraints1, + const InVector &u1, + const DoFHandler &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 + void interpolation_difference (const DoFHandler &dof1, + const InVector &u1, + const FiniteElement &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(&u1) != 0) + if (dynamic_cast*>(&dof1) != 0) + { + // if u1 is a parallel distributed + // PETSc vector, we check the local + // size of u1 for safety + Assert(dynamic_cast(&u1)->local_size() == dof1.locally_owned_dofs().n_elements(), + ExcDimensionMismatch(dynamic_cast(&u1)->local_size(), dof1.locally_owned_dofs().n_elements())); + }; + + if (dynamic_cast(&u1_difference) != 0) + if (dynamic_cast*>(&dof1) != 0) + { + Assert(dynamic_cast(&u1_difference)->local_size() == dof1.locally_owned_dofs().n_elements(), + ExcDimensionMismatch(dynamic_cast(&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 u1_local(dofs_per_cell); + Vector u1_diff_local(dofs_per_cell); + + const types::subdomain_id subdomain_id = + dof1.get_tria().locally_owned_subdomain(); + + FullMatrix difference_matrix(dofs_per_cell, dofs_per_cell); + get_interpolation_difference_matrix(dof1.get_fe(), fe2, + difference_matrix); + + typename DoFHandler::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::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 + void interpolation_difference(const DoFHandler &dof1, + const ConstraintMatrix &constraints1, + const InVector &u1, + const DoFHandler &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 + void project_dg(const DoFHandler &dof1, + const InVector &u1, + const DoFHandler &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::active_cell_iterator cell1 = dof1.begin_active(); + typename DoFHandler::active_cell_iterator cell2 = dof2.begin_active(); + typename DoFHandler::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 u1_local(n1); + Vector u2_local(n2); + std::vector dofs(n2); + + FullMatrix 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 + void extrapolate(const DoFHandler &dof1, + const InVector &u1, + const DoFHandler &dof2, + OutVector &u2) + { + ConstraintMatrix dummy; + dummy.close(); + extrapolate(dof1, u1, dof2, dummy, u2); + } + + + + template + void extrapolate(const DoFHandler &dof1, + const InVector &u1, + const DoFHandler &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 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::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::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_nn_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 + (const DoFHandler &, const Vector &, + const DoFHandler &, Vector &); + + template + void interpolate + (const DoFHandler &, const Vector &, + const DoFHandler &, 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 + (const hp::DoFHandler &, const Vector &, + const hp::DoFHandler &, Vector &); + template + void interpolate + (const hp::DoFHandler &, const Vector &, + const hp::DoFHandler &, const ConstraintMatrix &, + Vector &); + template + void interpolate + (const hp::DoFHandler &, const Vector &, + const hp::DoFHandler &, Vector &); + template + void interpolate + (const hp::DoFHandler &, const Vector &, + const hp::DoFHandler &, const ConstraintMatrix &, + Vector &); +#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 + (const DoFHandler &, const VEC &, + const FiniteElement &, VEC &); + template + void back_interpolate + (const DoFHandler &, const ConstraintMatrix &, + const VEC &, + const DoFHandler &, const ConstraintMatrix &, + VEC &); + template + void interpolation_difference + (const DoFHandler &, const VEC &, + const FiniteElement &, VEC &); + template + void interpolation_difference + (const DoFHandler &, const ConstraintMatrix &, + const VEC &, + const DoFHandler &, const ConstraintMatrix &, + VEC &); + template + void project_dg + (const DoFHandler &, const VEC &, + const DoFHandler &, VEC &); + template + void extrapolate + (const DoFHandler &, const VEC &, + const DoFHandler &, VEC &); + template + void extrapolate + (const DoFHandler &, const VEC &, + const DoFHandler &, 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 > 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::lines_per_cell; ++line_no) { const Triangulation::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 &boundary = line->get_triangulation().get_boundary(line->boundary_indicator()); Boundary::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::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 v; - for (unsigned int i=0; i<=degree; ++i) - v.push_back(Polynomials::LagrangeEquidistant(degree,i)); - - tensor_pols = new TensorProductPolynomials (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 + (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::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 void MappingQ::fill_fe_values ( @@ -312,35 +306,23 @@ MappingQ::fill_fe_values ( std::vector > &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 (&mapping_data) != 0, ExcInternalError()); InternalData &data = static_cast (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::InternalData *p_data=0; if (data.use_mapping_q1_on_current_cell) p_data=&data.mapping_q1_data; @@ -372,34 +354,23 @@ MappingQ::fill_fe_face_values ( std::vector > &exterior_forms, std::vector > &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 (&mapping_data) != 0, ExcInternalError()); InternalData &data = static_cast (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::InternalData *p_data=0; if (data.use_mapping_q1_on_current_cell) p_data=&data.mapping_q1_data; @@ -434,34 +405,23 @@ MappingQ::fill_fe_subface_values (const typename Triangulation > &exterior_forms, std::vector > &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 (&mapping_data) != 0, ExcInternalError()); InternalData &data = static_cast (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::InternalData *p_data=0; if (data.use_mapping_q1_on_current_cell) p_data=&data.mapping_q1_data; @@ -503,25 +463,19 @@ MappingQ::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::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::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_pointdegree*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::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_pointdegree*this->degree, ExcInternalError()); } @@ -773,14 +589,11 @@ MappingQ::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 quadrature(degree+1); const unsigned int n_q_points=quadrature.size(); @@ -788,37 +601,44 @@ MappingQ::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 S(n_inner); + // Compute the stiffness matrix of the inner dofs + FullMatrix S(n_inner); for (unsigned int point=0; point T(n_inner, n_outer); + FullMatrix T(n_inner, n_outer); for (unsigned int point=0; point S_1(n_inner); + FullMatrix S_1(n_inner); S_1.invert(S); - FullMatrix S_1_T(n_inner, n_outer); + FullMatrix 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::apply_laplace_vector(const Table<2,double> &lvs, std::vector > &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::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::compute_mapping_support_points( const typename Triangulation::cell_iterator &cell, std::vector > &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::vertices_per_cell); @@ -902,8 +708,7 @@ void MappingQ::compute_support_points_laplace(const typename Triangulation::cell_iterator &cell, std::vector > &a) const { - // in any case, we need the - // vertices first + // in any case, we need the vertices first a.resize(GeometryInfo::vertices_per_cell); for (unsigned int i=0; i::vertices_per_cell; ++i) a[i] = cell->vertex(i); @@ -915,11 +720,8 @@ MappingQ::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::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 > &) 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 *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 > 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 *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 > line_points (degree-1); @@ -1032,8 +825,7 @@ MappingQ::add_line_support_points (const typename Triangulation > &a) const { static const StraightBoundary 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::lines_per_cell; ++line_no) @@ -1050,19 +842,13 @@ MappingQ::add_line_support_points (const typename Triangulation > 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::lines_per_cell; ++line_no) { const typename Triangulation::line_iterator line = cell->line(line_no); @@ -1077,8 +863,7 @@ MappingQ::add_line_support_points (const typename Triangulationget_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::add_line_support_points (const typename Triangulation::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 > 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 > 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::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; iline(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::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; iline(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::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::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::InternalData *q1_data = dynamic_cast::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(&mapping_data) != 0, ExcInternalError()); const InternalData &data = static_cast(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::transform(input, output, *q1_data, mapping_type); } @@ -1340,31 +1080,24 @@ MappingQ::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::InternalData *q1_data = dynamic_cast::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(&mapping_data) != 0, ExcInternalError()); const InternalData &data = static_cast(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::transform(input, output, *q1_data, mapping_type); } @@ -1377,31 +1110,24 @@ void MappingQ::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::InternalData *q1_data = dynamic_cast::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(&mapping_data) != 0, ExcInternalError()); const InternalData &data = static_cast(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::transform(input, output, *q1_data, mapping_type); } @@ -1412,11 +1138,9 @@ MappingQ:: transform_unit_to_real_cell (const typename Triangulation::cell_iterator &cell, const Point &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 point_quadrature(p); std::auto_ptr mdata (dynamic_cast ( @@ -1431,8 +1155,7 @@ transform_unit_to_real_cell (const typename Triangulation::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()mapping_support_points.size()) p_data->mapping_support_points.resize (GeometryInfo::vertices_per_cell); @@ -1449,24 +1172,15 @@ MappingQ:: transform_real_to_unit_cell (const typename Triangulation::cell_iterator &cell, const Point &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 initial_p_unit; try { @@ -1475,11 +1189,8 @@ transform_real_to_unit_cell (const typename Triangulation::cell_it } catch (const typename Mapping::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::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::project_to_unit_cell(initial_p_unit); const Quadrature point_quadrature(initial_p_unit); @@ -1533,13 +1236,11 @@ transform_real_to_unit_cell (const typename Triangulation::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::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(Utilities::fixed_power(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 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 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 renumber(n_q_points); std::vector dpo(dim+1, 1U); for (unsigned int i=1; i (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; qquadrature_points[renumber[q]] = q_iterated.point(q); } @@ -112,43 +105,30 @@ compute_mapping_support_points std::vector > &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::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 > shift_vector(n_support_pts,Vector(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::fill_fe_values ( std::vector > &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::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::hex_iterator &, } + +template +const std::vector > & +Boundary:: +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 > + 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 > &line_points = this->get_line_support_points(n); const Point vertices[2] = { line->vertex(0), line->vertex(1) }; - for (unsigned int i=0; i::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 > &line_points = this->get_line_support_points(n); const Point vertices[2] = { line->vertex(0), line->vertex(1) }; - for (unsigned int i=0; i::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 > &line_points = this->get_line_support_points(m); const Point 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::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 > &line_points = this->get_line_support_points(m); const Point 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::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 ds = (v1-v0) / (n+1); + // Do a simple linear interpolation followed by projection, using the same + // algorithm as above + const std::vector > &line_points = this->get_line_support_points(n); for (unsigned int i=0; i middle = v0 + (i+1)*ds; + const double x = line_points[i+1][0]; + const Point middle = (1-x)*v0 + x*v1; const Point vector_from_axis = (middle-point_on_axis) - ((middle-point_on_axis) * direction) * direction; @@ -307,24 +307,23 @@ get_intermediate_points_between_points (const Point &p0, { const unsigned int n = points.size (); const Point axis = x_1 - x_0; - const Point dx = (p1 - p0) / (n + 1); Assert (n > 0, ExcInternalError ()); - for (unsigned int i = 0; i < n; ++i) + const std::vector > &line_points = this->get_line_support_points(n); + + for (unsigned int i=0; i 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 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 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::line_iterator &line) c const Point axis = x_1 - x_0; // Compute the middle point of the line. const Point middle = StraightBoundary::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 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 axis = x_1 - x_0; - // Compute the middle point of the - // quad. + // Compute the middle point of the quad. const Point 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 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::face_iterator &face, for (unsigned int vertex = 0; vertex < GeometryInfo::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 vertex_p = x_0 + c * axis; - // Then compute the vector - // pointing from the point - // vertex_p on the axis - // to the vertex. + // Then compute the vector pointing from the point vertex_p on + // the axis to the vertex. const Point axis_to_vertex = face->vertex (vertex) - vertex_p; face_vertex_normals[vertex] = axis_to_vertex / axis_to_vertex.norm (); @@ -629,49 +614,28 @@ HyperBallBoundary::get_intermediate_points_between_points ( Assert(std::fabs(v1.square()-r2) 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 > &line_points = this->get_line_support_points(n); const unsigned int m=n/2; - for (unsigned int i=0; i=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:: get_intermediate_points_on_line (const typename Triangulation::line_iterator &line, std::vector > &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 line_center = line->center(); if (line_center(0) == this->center(0)) return StraightBoundary::get_intermediate_points_on_line (line, points); @@ -908,10 +870,8 @@ get_intermediate_points_on_quad (const typename Triangulation::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 quad_center = quad->center(); if (quad_center(0) == this->center(0)) StraightBoundary::get_intermediate_points_on_quad (quad, points); @@ -950,10 +910,8 @@ HalfHyperBallBoundary:: get_normals_at_vertices (const typename Triangulation::face_iterator &face, typename Boundary::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 quad_center = face->center(); if (quad_center(0) == this->center(0)) StraightBoundary::get_normals_at_vertices (face, face_vertex_normals); @@ -1005,10 +963,8 @@ get_new_point_on_line (const typename Triangulation::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::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::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::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::get_new_point_on_line (line); } @@ -1079,10 +1030,8 @@ Point HalfHyperShellBoundary:: get_new_point_on_quad (const typename Triangulation::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::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::get_new_point_on_quad (quad); } @@ -1135,10 +1083,8 @@ get_intermediate_points_on_line (const typename Triangulation::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::line_iterato (line->vertex(1)(0) == this->center(0))) StraightBoundary::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::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::line_iterato - outer_radius) < 1e-12 * outer_radius)))) StraightBoundary::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::get_intermediate_points_on_line (line, points); @@ -1200,10 +1141,8 @@ get_intermediate_points_on_quad (const typename Triangulation::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 quad_center = quad->center(); if (quad_center(0) == this->center(0)) StraightBoundary::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 > &line_points = this->get_line_support_points(npoints); + for (unsigned int i=0; i::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 > &line_points = this->get_line_support_points(m); + for (unsigned int i=0; iset_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(n_converged)); + reinterpret_cast(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 #include -#include -#include -#include -#include -#include -#include -#include -#include -#include #include #include #include @@ -46,247 +36,6 @@ namespace internal { namespace DataOut { - template - ParallelDataBase:: - ParallelDataBase (const unsigned int n_datasets, - const unsigned int n_subdivisions, - const std::vector &n_postprocessor_outputs, - const Mapping &mapping, - const std::vector > > &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 - quadrature(QIterated(QTrapez<1>(), n_subdivisions)); - n_q_points = quadrature[0].size(); - x_fe_values.resize(this->finite_elements.size()); - for (unsigned int i=0; ifinite_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; jfinite_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 - (this->mapping_collection, - *this->finite_elements[i], - quadrature, - this->update_flags)); - } - } - else - { - dealii::hp::QCollection - quadrature(QIterated(QTrapez<1>(), n_subdivisions)); - n_q_points = quadrature[0].size(); - x_fe_face_values.resize(this->finite_elements.size()); - for (unsigned int i=0; ifinite_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; jfinite_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 - (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[dataset])); - } - - - - - - // implement copy constructor to create a thread's own version of - // x_fe_values - template - ParallelDataBase:: - ParallelDataBase (const ParallelDataBase &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 - quadrature(QIterated(QTrapez<1>(), n_subdivisions)); - x_fe_values.resize(this->finite_elements.size()); - for (unsigned int i=0; ifinite_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; jfinite_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 - (this->mapping_collection, - *this->finite_elements[i], - quadrature, - this->update_flags)); - } - } - else - { - dealii::hp::QCollection - quadrature(QIterated(QTrapez<1>(), n_subdivisions)); - x_fe_face_values.resize(this->finite_elements.size()); - for (unsigned int i=0; ifinite_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; jfinite_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 - (this->mapping_collection, - *this->finite_elements[i], - quadrature, - this->update_flags)); - } - } - } - - - - template - template - void - ParallelDataBase:: - reinit_all_fe_values(std::vector > > &dof_data, - const typename dealii::Triangulation::cell_iterator &cell, - const unsigned int face) - { - for (unsigned int dataset=0; datasetget_triangulation(), - cell->level(), - cell->index(), - dof_data[dataset]->dof_handler); - if (x_fe_values.empty()) - { - AssertIndexRange(face, - GeometryInfo::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::faces_per_cell); - x_fe_face_values[0]->reinit(cell, face); - } - else - x_fe_values[0]->reinit (cell); - } - } - - - - template - const FEValuesBase & - ParallelDataBase:: - 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 - void - ParallelDataBase:: - 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 ParallelData:: 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 - DataEntryBase::DataEntryBase (const DH *dofs, - const std::vector &names_in, - const std::vector &data_component_interpretation) - : - dof_handler (dofs, typeid(dealii::DataOut_DoFData).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()") == std::string::npos, - typename dealii::DataOut:: - ExcInvalidCharacter (names[i], - names[i].find_first_not_of("abcdefghijklmnopqrstuvwxyz" - "ABCDEFGHIJKLMNOPQRSTUVWXYZ" - "0123456789_<>()"))); - } - - - - template - DataEntryBase::DataEntryBase (const DH *dofs, - const DataPostprocessor *data_postprocessor) - : - dof_handler (dofs, typeid(dealii::DataOut_DoFData).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()") == std::string::npos, - typename dealii::DataOut:: - ExcInvalidCharacter (names[i], - names[i].find_first_not_of("abcdefghijklmnopqrstuvwxyz" - "ABCDEFGHIJKLMNOPQRSTUVWXYZ" - "0123456789_<>()"))); - } - - - - template - DataEntryBase::~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 DataEntry : public 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. - */ - DataEntry (const DH *dofs, - const VectorType *data, - const std::vector &names, - const std::vector &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 *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 &fe_patch_values, - std::vector &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 &fe_patch_values, - std::vector > &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 &fe_patch_values, - std::vector > &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 &fe_patch_values, - std::vector > > &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 &fe_patch_values, - std::vector > &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 &fe_patch_values, - std::vector > > &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 - DataEntry:: - DataEntry (const DH *dofs, - const VectorType *data, - const std::vector &names, - const std::vector &data_component_interpretation) - : - DataEntryBase (dofs, names, data_component_interpretation), - vector (data) - {} - - - - template - DataEntry:: - DataEntry (const DH *dofs, - const VectorType *data, - const DataPostprocessor *data_postprocessor) - : - DataEntryBase (dofs, data_postprocessor), - vector (data) - {} - - - namespace - { - template - 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 - double - DataEntry:: - get_cell_data_value (const unsigned int cell_number) const - { - return get_vector_element(*vector, cell_number); - } - - - - template - void - DataEntry:: - get_function_values (const FEValuesBase &fe_patch_values, - std::vector > &patch_values_system) const - { - fe_patch_values.get_function_values (*vector, patch_values_system); - } - - - - template - void - DataEntry:: - get_function_values (const FEValuesBase &fe_patch_values, - std::vector &patch_values) const - { - fe_patch_values.get_function_values (*vector, patch_values); - } - - - - template - void - DataEntry:: - get_function_gradients (const FEValuesBase &fe_patch_values, - std::vector > > &patch_gradients_system) const - { - fe_patch_values.get_function_gradients (*vector, patch_gradients_system); - } - - - - template - void - DataEntry:: - get_function_gradients (const FEValuesBase &fe_patch_values, - std::vector > &patch_gradients) const - { - fe_patch_values.get_function_gradients (*vector, patch_gradients); - } - - - - template - void - DataEntry:: - get_function_hessians (const FEValuesBase &fe_patch_values, - std::vector > > &patch_hessians_system) const - { - fe_patch_values.get_function_hessians (*vector, patch_hessians_system); - } - - - - template - void - DataEntry:: - get_function_hessians (const FEValuesBase &fe_patch_values, - std::vector > &patch_hessians) const - { - fe_patch_values.get_function_hessians (*vector, patch_hessians); - } - - - - template - std::size_t - DataEntry::memory_consumption () const - { - return (sizeof (vector) + - MemoryConsumption::memory_consumption (this->names)); - } - - - - template - void - DataEntry::clear () - { - vector = 0; - this->dof_handler = 0; - } - } -} - - - -template -DataOut_DoFData::DataOut_DoFData () - : - triangulation(0,typeid(*this).name()), - dofs(0,typeid(*this).name()) -{} - - - -template -DataOut_DoFData::~DataOut_DoFData () -{ - clear (); -} - - - -template -void -DataOut_DoFData:: -attach_dof_handler (const DH &d) -{ - Assert (dof_data.size() == 0, ExcOldDataStillPresent()); - Assert (cell_data.size() == 0, ExcOldDataStillPresent()); - - triangulation = SmartPointer >(&d.get_tria(), typeid(*this).name()); - dofs = SmartPointer(&d, typeid(*this).name()); -} - - - -template -void -DataOut_DoFData:: -attach_triangulation (const Triangulation &tria) -{ - Assert (dof_data.size() == 0, ExcOldDataStillPresent()); - Assert (cell_data.size() == 0, ExcOldDataStillPresent()); - - triangulation = SmartPointer >(&tria, typeid(*this).name()); -} - - - - -template -template -void -DataOut_DoFData:: -add_data_vector (const VECTOR &vec, - const std::string &name, - const DataVectorType type, - const std::vector &data_component_interpretation) -{ - Assert (triangulation != 0, ExcNoTriangulationSelected ()); - const unsigned int n_components = - dofs != 0 ? dofs->get_fe().n_components () : 1; - - std::vector 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 -template -void -DataOut_DoFData:: -add_data_vector (const VECTOR &vec, - const std::vector &names, - const DataVectorType type, - const std::vector &data_component_interpretation_) -{ - Assert (triangulation != 0, ExcNoTriangulationSelected ()); - - const std::vector & - data_component_interpretation - = (data_component_interpretation_.size() != 0 - ? - data_component_interpretation_ - : - std::vector - (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 *new_entry - = new internal::DataOut::DataEntry(dofs, &vec, names, - data_component_interpretation); - if (actual_type == type_dof_data) - dof_data.push_back (std_cxx1x::shared_ptr >(new_entry)); - else - cell_data.push_back (std_cxx1x::shared_ptr >(new_entry)); -} - - - -template -template -void -DataOut_DoFData:: -add_data_vector (const VECTOR &vec, - const DataPostprocessor &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 *new_entry - = new internal::DataOut::DataEntry(dofs, &vec, &data_postprocessor); - dof_data.push_back (std_cxx1x::shared_ptr >(new_entry)); -} - - - -template -template -void -DataOut_DoFData:: -add_data_vector (const DH &dof_handler, - const VECTOR &vec, - const DataPostprocessor &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 *new_entry - = new internal::DataOut::DataEntry(&dof_handler, &vec, &data_postprocessor); - dof_data.push_back (std_cxx1x::shared_ptr >(new_entry)); -} - - - -template -template -void -DataOut_DoFData:: -add_data_vector (const DH &dof_handler, - const VECTOR &data, - const std::string &name, - const std::vector &data_component_interpretation) -{ - const unsigned int n_components = dof_handler.get_fe().n_components (); - - std::vector 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 -template -void -DataOut_DoFData:: -add_data_vector (const DH &dof_handler, - const VECTOR &data, - const std::vector &names, - const std::vector &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 >(&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 & - data_component_interpretation - = (data_component_interpretation_.size() != 0 - ? - data_component_interpretation_ - : - std::vector - (names.size(), DataComponentInterpretation::component_is_scalar)); - - internal::DataOut::DataEntryBase *new_entry - = new internal::DataOut::DataEntry(&dof_handler, &data, names, - data_component_interpretation); - dof_data.push_back (std_cxx1x::shared_ptr >(new_entry)); -} - - - -template -void DataOut_DoFData::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 dummy; - patches.swap (dummy); -} - - - -template -void -DataOut_DoFData:: -clear_input_data_references () -{ - for (unsigned int i=0; iclear (); - - for (unsigned int i=0; iclear (); - - if (dofs != 0) - dofs = 0; -} - - - -template -void -DataOut_DoFData::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 dummy; - patches.swap (dummy); -} - - - -template -std::vector -DataOut_DoFData:: -get_dataset_names () const -{ - std::vector names; - // collect the names of dof - // and cell data - typedef - typename std::vector > >::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 -std::vector > -DataOut_DoFData::get_vector_data_ranges () const -{ - std::vector > - ranges; - - // collect the ranges of dof - // and cell data - typedef - typename std::vector > >::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; dddata_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; ddnames[i+dd]) - { - name = ""; - break; - } - - // finally add a corresponding - // range - std_cxx1x::tuple - 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 -const std::vector< dealii::DataOutBase::Patch > & -DataOut_DoFData::get_patches () const -{ - return patches; -} - - - -template -std::vector > > -DataOut_DoFData::get_finite_elements() const -{ - const unsigned int dhdim = DH::dimension; - const unsigned int dhspacedim = DH::space_dimension; - std::vector > > - finite_elements(this->dof_data.size()); - for (unsigned int i=0; idof_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; jdof_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 - (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 - (FE_DGQ(0))); - } - return finite_elements; -} - - - -template -std::size_t -DataOut_DoFData::memory_consumption () const -{ - return (DataOutInterface::memory_consumption () + - MemoryConsumption::memory_consumption (dofs) + - MemoryConsumption::memory_consumption (patches)); -} - - - -/* ---------------------------------------------------------------------- */ - template 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,deal_II_dimension,deal_II_dimension>:: - add_data_vector (const VEC &, - const std::string &, - const DataVectorType, - const std::vector &); - - template void - DataOut_DoFData,deal_II_dimension,deal_II_dimension>:: - add_data_vector (const VEC &, - const std::vector &, - const DataVectorType, - const std::vector &); - - template void - DataOut_DoFData,deal_II_dimension,deal_II_dimension>:: - add_data_vector (const VEC &, - const DataPostprocessor::space_dimension> &); - - template void - DataOut_DoFData,deal_II_dimension,deal_II_dimension>:: - add_data_vector (const DH &, - const VEC &, - const std::string &, - const std::vector &); - - template void - DataOut_DoFData,deal_II_dimension,deal_II_dimension>:: - add_data_vector (const DH &, - const VEC &, - const std::vector &, - const std::vector &); - - template void - DataOut_DoFData,deal_II_dimension,deal_II_dimension>:: - add_data_vector (const DH &, - const VEC &, - const DataPostprocessor::space_dimension> &); - - - -// stuff needed for face data - - template void - DataOut_DoFData,deal_II_dimension-1,deal_II_dimension>:: - add_data_vector (const VEC &, - const std::string &, - const DataVectorType, - const std::vector &); - - template void - DataOut_DoFData,deal_II_dimension-1,deal_II_dimension>:: - add_data_vector (const VEC &, - const std::vector &, - const DataVectorType, - const std::vector &); - - template void - DataOut_DoFData,deal_II_dimension-1,deal_II_dimension>:: - add_data_vector (const VEC &, - const DataPostprocessor::space_dimension> &); - - template void - DataOut_DoFData,deal_II_dimension-1,deal_II_dimension>:: - add_data_vector (const DH &, - const VEC &, - const std::string &, - const std::vector &); - - template void - DataOut_DoFData,deal_II_dimension-1,deal_II_dimension>:: - add_data_vector (const DH &, - const VEC &, - const std::vector &, - const std::vector &); - - template void - DataOut_DoFData,deal_II_dimension-1,deal_II_dimension>:: - add_data_vector (const DH &, - const VEC &, - const DataPostprocessor::space_dimension> &); - - - -// things for DataOutRotation - - template void - DataOut_DoFData,deal_II_dimension+1,deal_II_dimension+1>:: - add_data_vector (const VEC &, - const std::string &, - const DataVectorType, - const std::vector &); - - template void - DataOut_DoFData,deal_II_dimension+1,deal_II_dimension+1>:: - add_data_vector (const VEC &, - const std::vector &, - const DataVectorType, - const std::vector &); - - template void - DataOut_DoFData,deal_II_dimension+1,deal_II_dimension+1>:: - add_data_vector (const VEC &, - const DataPostprocessor::space_dimension> &); - - template void - DataOut_DoFData,deal_II_dimension+1,deal_II_dimension+1>:: - add_data_vector (const DH &, - const VEC &, - const std::string &, - const std::vector &); - - template void - DataOut_DoFData,deal_II_dimension+1,deal_II_dimension+1>:: - add_data_vector (const DH &, - const VEC &, - const std::vector &, - const std::vector &); - - template void - DataOut_DoFData,deal_II_dimension+1,deal_II_dimension+1>:: - add_data_vector (const DH &, - const VEC &, - const DataPostprocessor::space_dimension> &); - - -// codim 1 - - #if deal_II_dimension < 3 - template void - DataOut_DoFData,deal_II_dimension,deal_II_dimension+1>:: - add_data_vector (const VEC &, - const std::string &, - const DataVectorType, - const std::vector &); - - template void - DataOut_DoFData,deal_II_dimension,deal_II_dimension+1>:: - add_data_vector (const VEC &, - const std::vector &, - const DataVectorType, - const std::vector &); - - template void - DataOut_DoFData,deal_II_dimension,deal_II_dimension+1>:: - add_data_vector (const VEC &, - const DataPostprocessor::space_dimension> &); - - template void - DataOut_DoFData,deal_II_dimension,deal_II_dimension+1>:: - add_data_vector (const DH &, - const VEC &, - const std::string &, - const std::vector &); - - template void - DataOut_DoFData,deal_II_dimension,deal_II_dimension+1>:: - add_data_vector (const DH &, - const VEC &, - const std::vector &, - const std::vector &); - - template void - DataOut_DoFData,deal_II_dimension,deal_II_dimension+1>:: - add_data_vector (const DH &, - const VEC &, - const DataPostprocessor::space_dimension> &); - #endif - - - -// codim 2 - - #if deal_II_dimension == 3 - template void - DataOut_DoFData,1,3>:: - add_data_vector (const VEC &, - const std::string &, - const DataVectorType, - const std::vector &); - - template void - DataOut_DoFData,1,3>:: - add_data_vector (const VEC &, - const std::vector &, - const DataVectorType, - const std::vector &); - - template void - DataOut_DoFData,1,3>:: - add_data_vector (const VEC &, - const DataPostprocessor::space_dimension> &); - - template void - DataOut_DoFData,1,3>:: - add_data_vector (const DH<1,3> &, - const VEC &, - const std::string &, - const std::vector &); - - template void - DataOut_DoFData,1,3>:: - add_data_vector (const DH<1,3> &, - const VEC &, - const std::vector &, - const std::vector &); - - template void - DataOut_DoFData,1,3>:: - add_data_vector (const DH<1,3> &, - const VEC &, - const DataPostprocessor::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,deal_II_dimension,deal_II_dimension>:: - add_data_vector (const IndexSet &, - const std::string &, - const DataVectorType, - const std::vector &); - - template void - DataOut_DoFData,deal_II_dimension,deal_II_dimension>:: - add_data_vector (const IndexSet &, - const std::vector &, - const DataVectorType, - const std::vector &); - - template void - DataOut_DoFData,deal_II_dimension,deal_II_dimension>:: - add_data_vector (const IndexSet &, - const DataPostprocessor::space_dimension> &); - -// stuff needed for face data - - template void - DataOut_DoFData,deal_II_dimension-1,deal_II_dimension>:: - add_data_vector (const IndexSet &, - const std::string &, - const DataVectorType, - const std::vector &); - - template void - DataOut_DoFData,deal_II_dimension-1,deal_II_dimension>:: - add_data_vector (const IndexSet &, - const std::vector &, - const DataVectorType, - const std::vector &); - - template void - DataOut_DoFData,deal_II_dimension-1,deal_II_dimension>:: - add_data_vector (const IndexSet &, - const DataPostprocessor::space_dimension> &); - -// things for DataOutRotation - - template void - DataOut_DoFData,deal_II_dimension+1,deal_II_dimension+1>:: - add_data_vector (const IndexSet &, - const std::string &, - const DataVectorType, - const std::vector &); - - template void - DataOut_DoFData,deal_II_dimension+1,deal_II_dimension+1>:: - add_data_vector (const IndexSet &, - const std::vector &, - const DataVectorType, - const std::vector &); - - template void - DataOut_DoFData,deal_II_dimension+1,deal_II_dimension+1>:: - add_data_vector (const IndexSet &, - const DataPostprocessor::space_dimension> &); - -// codim 1 - - #if deal_II_dimension < 3 - template void - DataOut_DoFData,deal_II_dimension,deal_II_dimension+1>:: - add_data_vector (const IndexSet &, - const std::string &, - const DataVectorType, - const std::vector &); - - template void - DataOut_DoFData,deal_II_dimension,deal_II_dimension+1>:: - add_data_vector (const IndexSet &, - const std::vector &, - const DataVectorType, - const std::vector &); - - template void - DataOut_DoFData,deal_II_dimension,deal_II_dimension+1>:: - add_data_vector (const IndexSet &, - const DataPostprocessor::space_dimension> &); - #endif - + namespace internal \{ + namespace DataOut \{ +#if deal_II_dimension <= deal_II_space_dimension + template struct ParallelData; +#endif + \} + \} } - for (DH : DOFHANDLER_TEMPLATES; deal_II_dimension : DIMENSIONS) { template class DataOut_DoFData,deal_II_dimension>; @@ -340,9 +38,6 @@ for (DH : DOFHANDLER_TEMPLATES; deal_II_dimension : DIMENSIONS) template class DataOut_DoFData,deal_II_dimension,deal_II_dimension+1>; #endif - #if deal_II_dimension >= 2 - template class DataOut_DoFData,deal_II_dimension-1,deal_II_dimension>; - #endif template class DataOut >; #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,1,3>; - template class DataOut_DoFData,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; - template struct ParallelData; -#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:: - reinit_all_fe_values > - (std::vector > > > &dof_data, - const dealii::Triangulation::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 +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +DEAL_II_NAMESPACE_OPEN + + +namespace internal +{ + namespace DataOut + { + template + ParallelDataBase:: + ParallelDataBase (const unsigned int n_datasets, + const unsigned int n_subdivisions, + const std::vector &n_postprocessor_outputs, + const Mapping &mapping, + const std::vector > > &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 + quadrature(QIterated(QTrapez<1>(), n_subdivisions)); + n_q_points = quadrature[0].size(); + x_fe_values.resize(this->finite_elements.size()); + for (unsigned int i=0; ifinite_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; jfinite_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 + (this->mapping_collection, + *this->finite_elements[i], + quadrature, + this->update_flags)); + } + } + else + { + dealii::hp::QCollection + quadrature(QIterated(QTrapez<1>(), n_subdivisions)); + n_q_points = quadrature[0].size(); + x_fe_face_values.resize(this->finite_elements.size()); + for (unsigned int i=0; ifinite_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; jfinite_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 + (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[dataset])); + } + + + + + + // implement copy constructor to create a thread's own version of + // x_fe_values + template + ParallelDataBase:: + ParallelDataBase (const ParallelDataBase &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 + quadrature(QIterated(QTrapez<1>(), n_subdivisions)); + x_fe_values.resize(this->finite_elements.size()); + for (unsigned int i=0; ifinite_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; jfinite_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 + (this->mapping_collection, + *this->finite_elements[i], + quadrature, + this->update_flags)); + } + } + else + { + dealii::hp::QCollection + quadrature(QIterated(QTrapez<1>(), n_subdivisions)); + x_fe_face_values.resize(this->finite_elements.size()); + for (unsigned int i=0; ifinite_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; jfinite_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 + (this->mapping_collection, + *this->finite_elements[i], + quadrature, + this->update_flags)); + } + } + } + + + + template + template + void + ParallelDataBase:: + reinit_all_fe_values(std::vector > > &dof_data, + const typename dealii::Triangulation::cell_iterator &cell, + const unsigned int face) + { + for (unsigned int dataset=0; datasetget_triangulation(), + cell->level(), + cell->index(), + dof_data[dataset]->dof_handler); + if (x_fe_values.empty()) + { + AssertIndexRange(face, + GeometryInfo::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::faces_per_cell); + x_fe_face_values[0]->reinit(cell, face); + } + else + x_fe_values[0]->reinit (cell); + } + } + + + + template + const FEValuesBase & + ParallelDataBase:: + 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 + void + ParallelDataBase:: + 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 + void + append_patch_to_list (const DataOutBase::Patch &patch, + std::vector > &patches) + { + patches.push_back (patch); + patches.back().patch_index = patches.size()-1; + } + } +} + +namespace internal +{ + namespace DataOut + { + template + DataEntryBase::DataEntryBase (const DH *dofs, + const std::vector &names_in, + const std::vector &data_component_interpretation) + : + dof_handler (dofs, typeid(dealii::DataOut_DoFData).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()") == std::string::npos, + typename dealii::DataOut:: + ExcInvalidCharacter (names[i], + names[i].find_first_not_of("abcdefghijklmnopqrstuvwxyz" + "ABCDEFGHIJKLMNOPQRSTUVWXYZ" + "0123456789_<>()"))); + } + + + + template + DataEntryBase::DataEntryBase (const DH *dofs, + const DataPostprocessor *data_postprocessor) + : + dof_handler (dofs, typeid(dealii::DataOut_DoFData).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()") == std::string::npos, + typename dealii::DataOut:: + ExcInvalidCharacter (names[i], + names[i].find_first_not_of("abcdefghijklmnopqrstuvwxyz" + "ABCDEFGHIJKLMNOPQRSTUVWXYZ" + "0123456789_<>()"))); + } + + + + template + DataEntryBase::~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 DataEntry : public 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. + */ + DataEntry (const DH *dofs, + const VectorType *data, + const std::vector &names, + const std::vector &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 *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 &fe_patch_values, + std::vector &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 &fe_patch_values, + std::vector > &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 &fe_patch_values, + std::vector > &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 &fe_patch_values, + std::vector > > &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 &fe_patch_values, + std::vector > &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 &fe_patch_values, + std::vector > > &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 + DataEntry:: + DataEntry (const DH *dofs, + const VectorType *data, + const std::vector &names, + const std::vector &data_component_interpretation) + : + DataEntryBase (dofs, names, data_component_interpretation), + vector (data) + {} + + + + template + DataEntry:: + DataEntry (const DH *dofs, + const VectorType *data, + const DataPostprocessor *data_postprocessor) + : + DataEntryBase (dofs, data_postprocessor), + vector (data) + {} + + + namespace + { + template + 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 + double + DataEntry:: + get_cell_data_value (const unsigned int cell_number) const + { + return get_vector_element(*vector, cell_number); + } + + + + template + void + DataEntry:: + get_function_values (const FEValuesBase &fe_patch_values, + std::vector > &patch_values_system) const + { + fe_patch_values.get_function_values (*vector, patch_values_system); + } + + + + template + void + DataEntry:: + get_function_values (const FEValuesBase &fe_patch_values, + std::vector &patch_values) const + { + fe_patch_values.get_function_values (*vector, patch_values); + } + + + + template + void + DataEntry:: + get_function_gradients (const FEValuesBase &fe_patch_values, + std::vector > > &patch_gradients_system) const + { + fe_patch_values.get_function_gradients (*vector, patch_gradients_system); + } + + + + template + void + DataEntry:: + get_function_gradients (const FEValuesBase &fe_patch_values, + std::vector > &patch_gradients) const + { + fe_patch_values.get_function_gradients (*vector, patch_gradients); + } + + + + template + void + DataEntry:: + get_function_hessians (const FEValuesBase &fe_patch_values, + std::vector > > &patch_hessians_system) const + { + fe_patch_values.get_function_hessians (*vector, patch_hessians_system); + } + + + + template + void + DataEntry:: + get_function_hessians (const FEValuesBase &fe_patch_values, + std::vector > &patch_hessians) const + { + fe_patch_values.get_function_hessians (*vector, patch_hessians); + } + + + + template + std::size_t + DataEntry::memory_consumption () const + { + return (sizeof (vector) + + MemoryConsumption::memory_consumption (this->names)); + } + + + + template + void + DataEntry::clear () + { + vector = 0; + this->dof_handler = 0; + } + } +} + + + +template +DataOut_DoFData::DataOut_DoFData () + : + triangulation(0,typeid(*this).name()), + dofs(0,typeid(*this).name()) +{} + + + +template +DataOut_DoFData::~DataOut_DoFData () +{ + clear (); +} + + + +template +void +DataOut_DoFData:: +attach_dof_handler (const DH &d) +{ + Assert (dof_data.size() == 0, ExcOldDataStillPresent()); + Assert (cell_data.size() == 0, ExcOldDataStillPresent()); + + triangulation = SmartPointer >(&d.get_tria(), typeid(*this).name()); + dofs = SmartPointer(&d, typeid(*this).name()); +} + + + +template +void +DataOut_DoFData:: +attach_triangulation (const Triangulation &tria) +{ + Assert (dof_data.size() == 0, ExcOldDataStillPresent()); + Assert (cell_data.size() == 0, ExcOldDataStillPresent()); + + triangulation = SmartPointer >(&tria, typeid(*this).name()); +} + + + + +template +template +void +DataOut_DoFData:: +add_data_vector (const VECTOR &vec, + const std::string &name, + const DataVectorType type, + const std::vector &data_component_interpretation) +{ + Assert (triangulation != 0, ExcNoTriangulationSelected ()); + const unsigned int n_components = + dofs != 0 ? dofs->get_fe().n_components () : 1; + + std::vector 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 +template +void +DataOut_DoFData:: +add_data_vector (const VECTOR &vec, + const std::vector &names, + const DataVectorType type, + const std::vector &data_component_interpretation_) +{ + Assert (triangulation != 0, ExcNoTriangulationSelected ()); + + const std::vector & + data_component_interpretation + = (data_component_interpretation_.size() != 0 + ? + data_component_interpretation_ + : + std::vector + (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 *new_entry + = new internal::DataOut::DataEntry(dofs, &vec, names, + data_component_interpretation); + if (actual_type == type_dof_data) + dof_data.push_back (std_cxx1x::shared_ptr >(new_entry)); + else + cell_data.push_back (std_cxx1x::shared_ptr >(new_entry)); +} + + + +template +template +void +DataOut_DoFData:: +add_data_vector (const VECTOR &vec, + const DataPostprocessor &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 *new_entry + = new internal::DataOut::DataEntry(dofs, &vec, &data_postprocessor); + dof_data.push_back (std_cxx1x::shared_ptr >(new_entry)); +} + + + +template +template +void +DataOut_DoFData:: +add_data_vector (const DH &dof_handler, + const VECTOR &vec, + const DataPostprocessor &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 *new_entry + = new internal::DataOut::DataEntry(&dof_handler, &vec, &data_postprocessor); + dof_data.push_back (std_cxx1x::shared_ptr >(new_entry)); +} + + + +template +template +void +DataOut_DoFData:: +add_data_vector (const DH &dof_handler, + const VECTOR &data, + const std::string &name, + const std::vector &data_component_interpretation) +{ + const unsigned int n_components = dof_handler.get_fe().n_components (); + + std::vector 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 +template +void +DataOut_DoFData:: +add_data_vector (const DH &dof_handler, + const VECTOR &data, + const std::vector &names, + const std::vector &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 >(&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 & + data_component_interpretation + = (data_component_interpretation_.size() != 0 + ? + data_component_interpretation_ + : + std::vector + (names.size(), DataComponentInterpretation::component_is_scalar)); + + internal::DataOut::DataEntryBase *new_entry + = new internal::DataOut::DataEntry(&dof_handler, &data, names, + data_component_interpretation); + dof_data.push_back (std_cxx1x::shared_ptr >(new_entry)); +} + + + +template +void DataOut_DoFData::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 dummy; + patches.swap (dummy); +} + + + +template +void +DataOut_DoFData:: +clear_input_data_references () +{ + for (unsigned int i=0; iclear (); + + for (unsigned int i=0; iclear (); + + if (dofs != 0) + dofs = 0; +} + + + +template +void +DataOut_DoFData::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 dummy; + patches.swap (dummy); +} + + + +template +std::vector +DataOut_DoFData:: +get_dataset_names () const +{ + std::vector names; + // collect the names of dof + // and cell data + typedef + typename std::vector > >::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 +std::vector > +DataOut_DoFData::get_vector_data_ranges () const +{ + std::vector > + ranges; + + // collect the ranges of dof + // and cell data + typedef + typename std::vector > >::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; dddata_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; ddnames[i+dd]) + { + name = ""; + break; + } + + // finally add a corresponding + // range + std_cxx1x::tuple + 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 +const std::vector< dealii::DataOutBase::Patch > & +DataOut_DoFData::get_patches () const +{ + return patches; +} + + + +template +std::vector > > +DataOut_DoFData::get_finite_elements() const +{ + const unsigned int dhdim = DH::dimension; + const unsigned int dhspacedim = DH::space_dimension; + std::vector > > + finite_elements(this->dof_data.size()); + for (unsigned int i=0; idof_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; jdof_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 + (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 + (FE_DGQ(0))); + } + return finite_elements; +} + + + +template +std::size_t +DataOut_DoFData::memory_consumption () const +{ + return (DataOutInterface::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,deal_II_dimension,deal_II_dimension>:: + add_data_vector (const VEC &, + const std::string &, + const DataVectorType, + const std::vector &); + + template void + DataOut_DoFData,deal_II_dimension,deal_II_dimension>:: + add_data_vector (const VEC &, + const std::vector &, + const DataVectorType, + const std::vector &); + + template void + DataOut_DoFData,deal_II_dimension,deal_II_dimension>:: + add_data_vector (const VEC &, + const DataPostprocessor::space_dimension> &); + + template void + DataOut_DoFData,deal_II_dimension,deal_II_dimension>:: + add_data_vector (const DH &, + const VEC &, + const std::string &, + const std::vector &); + + template void + DataOut_DoFData,deal_II_dimension,deal_II_dimension>:: + add_data_vector (const DH &, + const VEC &, + const std::vector &, + const std::vector &); + + template void + DataOut_DoFData,deal_II_dimension,deal_II_dimension>:: + add_data_vector (const DH &, + const VEC &, + const DataPostprocessor::space_dimension> &); + + + +// stuff needed for face data + + template void + DataOut_DoFData,deal_II_dimension-1,deal_II_dimension>:: + add_data_vector (const VEC &, + const std::string &, + const DataVectorType, + const std::vector &); + + template void + DataOut_DoFData,deal_II_dimension-1,deal_II_dimension>:: + add_data_vector (const VEC &, + const std::vector &, + const DataVectorType, + const std::vector &); + + template void + DataOut_DoFData,deal_II_dimension-1,deal_II_dimension>:: + add_data_vector (const VEC &, + const DataPostprocessor::space_dimension> &); + + template void + DataOut_DoFData,deal_II_dimension-1,deal_II_dimension>:: + add_data_vector (const DH &, + const VEC &, + const std::string &, + const std::vector &); + + template void + DataOut_DoFData,deal_II_dimension-1,deal_II_dimension>:: + add_data_vector (const DH &, + const VEC &, + const std::vector &, + const std::vector &); + + template void + DataOut_DoFData,deal_II_dimension-1,deal_II_dimension>:: + add_data_vector (const DH &, + const VEC &, + const DataPostprocessor::space_dimension> &); + + + +// things for DataOutRotation + + template void + DataOut_DoFData,deal_II_dimension+1,deal_II_dimension+1>:: + add_data_vector (const VEC &, + const std::string &, + const DataVectorType, + const std::vector &); + + template void + DataOut_DoFData,deal_II_dimension+1,deal_II_dimension+1>:: + add_data_vector (const VEC &, + const std::vector &, + const DataVectorType, + const std::vector &); + + template void + DataOut_DoFData,deal_II_dimension+1,deal_II_dimension+1>:: + add_data_vector (const VEC &, + const DataPostprocessor::space_dimension> &); + + template void + DataOut_DoFData,deal_II_dimension+1,deal_II_dimension+1>:: + add_data_vector (const DH &, + const VEC &, + const std::string &, + const std::vector &); + + template void + DataOut_DoFData,deal_II_dimension+1,deal_II_dimension+1>:: + add_data_vector (const DH &, + const VEC &, + const std::vector &, + const std::vector &); + + template void + DataOut_DoFData,deal_II_dimension+1,deal_II_dimension+1>:: + add_data_vector (const DH &, + const VEC &, + const DataPostprocessor::space_dimension> &); + + + +// codim 1 + + #if deal_II_dimension < 3 + template void + DataOut_DoFData,deal_II_dimension,deal_II_dimension+1>:: + add_data_vector (const VEC &, + const std::string &, + const DataVectorType, + const std::vector &); + + template void + DataOut_DoFData,deal_II_dimension,deal_II_dimension+1>:: + add_data_vector (const VEC &, + const std::vector &, + const DataVectorType, + const std::vector &); + + template void + DataOut_DoFData,deal_II_dimension,deal_II_dimension+1>:: + add_data_vector (const VEC &, + const DataPostprocessor::space_dimension> &); + + template void + DataOut_DoFData,deal_II_dimension,deal_II_dimension+1>:: + add_data_vector (const DH &, + const VEC &, + const std::string &, + const std::vector &); + + template void + DataOut_DoFData,deal_II_dimension,deal_II_dimension+1>:: + add_data_vector (const DH &, + const VEC &, + const std::vector &, + const std::vector &); + + template void + DataOut_DoFData,deal_II_dimension,deal_II_dimension+1>:: + add_data_vector (const DH &, + const VEC &, + const DataPostprocessor::space_dimension> &); + #endif + + + +// codim 2 + + #if deal_II_dimension == 3 + template void + DataOut_DoFData,1,3>:: + add_data_vector (const VEC &, + const std::string &, + const DataVectorType, + const std::vector &); + + template void + DataOut_DoFData,1,3>:: + add_data_vector (const VEC &, + const std::vector &, + const DataVectorType, + const std::vector &); + + template void + DataOut_DoFData,1,3>:: + add_data_vector (const VEC &, + const DataPostprocessor::space_dimension> &); + + template void + DataOut_DoFData,1,3>:: + add_data_vector (const DH<1,3> &, + const VEC &, + const std::string &, + const std::vector &); + + template void + DataOut_DoFData,1,3>:: + add_data_vector (const DH<1,3> &, + const VEC &, + const std::vector &, + const std::vector &); + + template void + DataOut_DoFData,1,3>:: + add_data_vector (const DH<1,3> &, + const VEC &, + const DataPostprocessor::space_dimension> &); + #endif + +} + + + +for (DH : DOFHANDLER_TEMPLATES; deal_II_dimension : DIMENSIONS) +{ +// codim=0 + + template void + DataOut_DoFData,deal_II_dimension,deal_II_dimension>:: + add_data_vector (const IndexSet &, + const std::string &, + const DataVectorType, + const std::vector &); + + template void + DataOut_DoFData,deal_II_dimension,deal_II_dimension>:: + add_data_vector (const IndexSet &, + const std::vector &, + const DataVectorType, + const std::vector &); + + template void + DataOut_DoFData,deal_II_dimension,deal_II_dimension>:: + add_data_vector (const DH &, + const IndexSet &, + const std::string &, + const std::vector &); + + template void + DataOut_DoFData,deal_II_dimension,deal_II_dimension>:: + add_data_vector (const DH &, + const IndexSet &, + const std::vector &, + const std::vector &); + + template void + DataOut_DoFData,deal_II_dimension,deal_II_dimension>:: + add_data_vector (const IndexSet &, + const DataPostprocessor::space_dimension> &); + + + +// stuff needed for face data + + template void + DataOut_DoFData,deal_II_dimension-1,deal_II_dimension>:: + add_data_vector (const IndexSet &, + const std::string &, + const DataVectorType, + const std::vector &); + + template void + DataOut_DoFData,deal_II_dimension-1,deal_II_dimension>:: + add_data_vector (const IndexSet &, + const std::vector &, + const DataVectorType, + const std::vector &); + + template void + DataOut_DoFData,deal_II_dimension-1,deal_II_dimension>:: + add_data_vector (const IndexSet &, + const DataPostprocessor::space_dimension> &); + + + template void + DataOut_DoFData,deal_II_dimension-1,deal_II_dimension>:: + add_data_vector (const DH &, + const IndexSet &, + const std::string &, + const std::vector &); + + template void + DataOut_DoFData,deal_II_dimension-1,deal_II_dimension>:: + add_data_vector (const DH &, + const IndexSet &, + const std::vector &, + const std::vector &); + +// things for DataOutRotation + + template void + DataOut_DoFData,deal_II_dimension+1,deal_II_dimension+1>:: + add_data_vector (const IndexSet &, + const std::string &, + const DataVectorType, + const std::vector &); + + template void + DataOut_DoFData,deal_II_dimension+1,deal_II_dimension+1>:: + add_data_vector (const IndexSet &, + const std::vector &, + const DataVectorType, + const std::vector &); + + template void + DataOut_DoFData,deal_II_dimension+1,deal_II_dimension+1>:: + add_data_vector (const IndexSet &, + const DataPostprocessor::space_dimension> &); + + + template void + DataOut_DoFData,deal_II_dimension+1,deal_II_dimension+1>:: + add_data_vector (const DH &, + const IndexSet &, + const std::string &, + const std::vector &); + + template void + DataOut_DoFData,deal_II_dimension+1,deal_II_dimension+1>:: + add_data_vector (const DH &, + const IndexSet &, + const std::vector &, + const std::vector &); + +// codim 1 + + #if deal_II_dimension < 3 + template void + DataOut_DoFData,deal_II_dimension,deal_II_dimension+1>:: + add_data_vector (const IndexSet &, + const std::string &, + const DataVectorType, + const std::vector &); + + template void + DataOut_DoFData,deal_II_dimension,deal_II_dimension+1>:: + add_data_vector (const IndexSet &, + const std::vector &, + const DataVectorType, + const std::vector &); + + template void + DataOut_DoFData,deal_II_dimension,deal_II_dimension+1>:: + add_data_vector (const IndexSet &, + const DataPostprocessor::space_dimension> &); + #endif + +} + + + +for (DH : DOFHANDLER_TEMPLATES; deal_II_dimension : DIMENSIONS) +{ + template class DataOut_DoFData,deal_II_dimension>; + template class DataOut_DoFData,deal_II_dimension+1>; + + #if deal_II_dimension < 3 + template class DataOut_DoFData,deal_II_dimension,deal_II_dimension+1>; + template class DataOut_DoFData,deal_II_dimension,deal_II_dimension+1>; + #endif + + #if deal_II_dimension >= 2 + template class DataOut_DoFData,deal_II_dimension-1,deal_II_dimension>; + #endif + + #if deal_II_dimension == 3 + template class DataOut_DoFData,1,3>; + template class DataOut_DoFData,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; +#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:: + reinit_all_fe_values > + (std::vector > > > &dof_data, + const dealii::Triangulation::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 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 struct ParallelData @@ -148,14 +109,12 @@ namespace internal const dealii::hp::FECollection finite_element; /** - * The quadrature formulas to be used for - * the faces. + * The quadrature formulas to be used for the faces. */ const dealii::hp::QCollection 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 fe_face_values_cell; @@ -163,38 +122,22 @@ namespace internal dealii::hp::FESubfaceValues 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 > > 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 a grad u_h, 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 a grad u_h, 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 > > > psi; @@ -204,43 +147,35 @@ namespace internal std::vector > > > 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 > 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 coefficient_values1; std::vector > 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 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::type *neumann_bc; const ComponentMask component_mask; @@ -262,10 +197,9 @@ namespace internal const Function *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 void @@ -375,16 +307,14 @@ namespace internal std::map > &face_integrals) { - // now copy locally computed elements - // into the global map + // now copy locally computed elements into the global map for (typename std::map >::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 - void - integrate_over_regular_face (const std::vector &solutions, - ParallelData ¶llel_data, - std::map > &local_face_integrals, - const typename DH::active_cell_iterator &cell, - const unsigned int face_no, - dealii::hp::FEFaceValues &fe_face_values_cell, - dealii::hp::FEFaceValues &fe_face_values_neighbor) + template + std::vector + integrate_over_face (ParallelData ¶llel_data, + const typename DH::face_iterator &face, + dealii::hp::FEFaceValues &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; nat_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::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; nn_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 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 face_integral (n_solution_vectors, 0); for (unsigned int n=0; n(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 + void + integrate_over_regular_face (const std::vector &solutions, + ParallelData ¶llel_data, + std::map > &local_face_integrals, + const typename DH::active_cell_iterator &cell, + const unsigned int face_no, + dealii::hp::FEFaceValues &fe_face_values_cell, + dealii::hp::FEFaceValues &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; nat_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::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 void - integrate_over_irregular_face (const std::vector &solutions, - ParallelData ¶llel_data, + integrate_over_irregular_face (const std::vector &solutions, + ParallelData ¶llel_data, std::map > &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_non_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; nn_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; nvector_value_list (fe_face_values.get_present_fe_values() - .get_quadrature_points(), - parallel_data.coefficient_values); - for (unsigned int n=0; n face_integral (n_solution_vectors, 0); - for (unsigned int n=0; nface(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 sum (n_solution_vectors, 0); for (unsigned int subface_no=0; subface_non_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 + template void estimate_one_cell (const typename DH::active_cell_iterator &cell, ParallelData ¶llel_data, std::map > &local_face_integrals, const std::vector &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 -template -void -KellyErrorEstimator<1,spacedim>:: -estimate (const Mapping<1,spacedim> &mapping, - const DH &dof_handler, - const Quadrature<0> &quadrature, - const typename FunctionMap::type &neumann_bc, - const InputVector &solution, - Vector &error, - const ComponentMask &component_mask, - const Function *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 solutions (1, &solution); - std::vector*> errors (1, &error); - estimate (mapping, dof_handler, quadrature, neumann_bc, solutions, errors, - component_mask, coefficients, n_threads, subdomain_id, material_id); -} - - - -template -template -void -KellyErrorEstimator<1,spacedim>:: -estimate (const DH &dof_handler, - const Quadrature<0> &quadrature, - const typename FunctionMap::type &neumann_bc, - const InputVector &solution, - Vector &error, - const ComponentMask &component_mask, - const Function *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 -template -void -KellyErrorEstimator<1,spacedim>:: -estimate (const DH &dof_handler, - const Quadrature<0> &quadrature, - const typename FunctionMap::type &neumann_bc, - const std::vector &solutions, - std::vector*> &errors, - const ComponentMask &component_mask, - const Function *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 -template -void -KellyErrorEstimator<1,spacedim>:: -estimate (const Mapping<1,spacedim> &mapping, - const DH &dof_handler, - const hp::QCollection<0> &quadrature, - const typename FunctionMap::type &neumann_bc, - const InputVector &solution, - Vector &error, - const ComponentMask &component_mask, - const Function *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 solutions (1, &solution); - std::vector*> errors (1, &error); - estimate (mapping, dof_handler, quadrature, neumann_bc, solutions, errors, - component_mask, coefficients, n_threads, subdomain_id, material_id); -} - - -template -template -void -KellyErrorEstimator<1,spacedim>:: -estimate (const DH &dof_handler, - const hp::QCollection<0> &quadrature, - const typename FunctionMap::type &neumann_bc, - const InputVector &solution, - Vector &error, - const ComponentMask &component_mask, - const Function *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 -template -void -KellyErrorEstimator<1,spacedim>:: -estimate (const DH &dof_handler, - const hp::QCollection<0> &quadrature, - const typename FunctionMap::type &neumann_bc, - const std::vector &solutions, - std::vector*> &errors, - const ComponentMask &component_mask, - const Function *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 -template -void KellyErrorEstimator<1,spacedim>:: -estimate (const Mapping<1,spacedim> &/*mapping*/, - const DH &/*dof_handler*/, - const hp::QCollection<0> &, - const typename FunctionMap::type &/*neumann_bc*/, - const std::vector &/*solutions*/, - std::vector*> &/*errors*/, - const ComponentMask &/*component_mask_*/, - const Function */*coefficient*/, - const unsigned int, - const types::subdomain_id /*subdomain_id*/, - const types::material_id /*material_id*/) -{ - Assert (false, ExcInternalError()); -} - - - -template -template -void KellyErrorEstimator<1,spacedim>:: -estimate (const Mapping<1,spacedim> &mapping, - const DH &dof_handler, - const Quadrature<0> &, - const typename FunctionMap::type &neumann_bc, - const std::vector &solutions, - std::vector*> &errors, - const ComponentMask &component_mask, - const Function *coefficient, - const unsigned int, - const types::subdomain_id subdomain_id_, - const types::material_id material_id) -{ -#ifdef DEAL_II_WITH_P4EST - if (dynamic_cast*> - (&dof_handler.get_tria()) - != 0) - Assert ((subdomain_id_ == numbers::invalid_subdomain_id) - || - (subdomain_id_ == - dynamic_cast&> - (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*> - (&dof_handler.get_tria()) - != 0) - ? - dynamic_cast&> - (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::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; nsize() == dof_handler.n_dofs(), - ExcInvalidSolutionVector()); - - Assert ((coefficient == 0) || - (coefficient->n_components == n_components) || - (coefficient->n_components == 1), - ExcInvalidCoefficient()); - - for (typename FunctionMap::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 > > > - gradients_here (n_solution_vectors, - std::vector > >(2, std::vector >(n_components))); - std::vector > > > - gradients_neighbor (gradients_here); - std::vector > - grad_neighbor (n_solution_vectors, Vector(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 coefficient_values (n_components); - if (coefficient == 0) - for (unsigned int c=0; c 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; nneighbor(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; ssecond->value(cell->vertex(0)); - - for (unsigned int s=0; s v(n_components); - neumann_bc.find(n)->second->vector_value(cell->vertex(0), v); - - for (unsigned int s=0; sn_components == 1) - { - const double c_value = coefficient->value (cell->vertex(n)); - for (unsigned int c=0; cvector_value(cell->vertex(n), - coefficient_values); - } - - - for (unsigned int s=0; sdiameter(); - } - } - - for (unsigned int s=0; s @@ -1581,20 +953,14 @@ estimate (const Mapping &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 > 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 mapping_collection(mapping); const internal::ParallelData parallel_data (dof_handler.get_fe(), @@ -1612,18 +978,16 @@ estimate (const Mapping &mapping, // now let's work on all those cells: WorkStream::run (dof_handler.begin_active(), static_cast(dof_handler.end()), - std_cxx1x::bind (&internal::estimate_one_cell, + std_cxx1x::bind (&internal::estimate_one_cell, std_cxx1x::_1, std_cxx1x::_2, std_cxx1x::_3, std_cxx1x::ref(solutions)), std_cxx1x::bind (&internal::copy_local_to_global, 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 &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 &mapping, for (unsigned int n=0; nface(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; 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 +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +#include +#include +#include +#include + +DEAL_II_NAMESPACE_OPEN + + + +template +template +void +KellyErrorEstimator<1,spacedim>:: +estimate (const Mapping<1,spacedim> &mapping, + const DH &dof_handler, + const Quadrature<0> &quadrature, + const typename FunctionMap::type &neumann_bc, + const InputVector &solution, + Vector &error, + const ComponentMask &component_mask, + const Function *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 solutions (1, &solution); + std::vector*> errors (1, &error); + estimate (mapping, dof_handler, quadrature, neumann_bc, solutions, errors, + component_mask, coefficients, n_threads, subdomain_id, material_id); +} + + + +template +template +void +KellyErrorEstimator<1,spacedim>:: +estimate (const DH &dof_handler, + const Quadrature<0> &quadrature, + const typename FunctionMap::type &neumann_bc, + const InputVector &solution, + Vector &error, + const ComponentMask &component_mask, + const Function *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 +template +void +KellyErrorEstimator<1,spacedim>:: +estimate (const DH &dof_handler, + const Quadrature<0> &quadrature, + const typename FunctionMap::type &neumann_bc, + const std::vector &solutions, + std::vector*> &errors, + const ComponentMask &component_mask, + const Function *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 +template +void +KellyErrorEstimator<1,spacedim>:: +estimate (const Mapping<1,spacedim> &mapping, + const DH &dof_handler, + const hp::QCollection<0> &quadrature, + const typename FunctionMap::type &neumann_bc, + const InputVector &solution, + Vector &error, + const ComponentMask &component_mask, + const Function *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 solutions (1, &solution); + std::vector*> errors (1, &error); + estimate (mapping, dof_handler, quadrature, neumann_bc, solutions, errors, + component_mask, coefficients, n_threads, subdomain_id, material_id); +} + + +template +template +void +KellyErrorEstimator<1,spacedim>:: +estimate (const DH &dof_handler, + const hp::QCollection<0> &quadrature, + const typename FunctionMap::type &neumann_bc, + const InputVector &solution, + Vector &error, + const ComponentMask &component_mask, + const Function *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 +template +void +KellyErrorEstimator<1,spacedim>:: +estimate (const DH &dof_handler, + const hp::QCollection<0> &quadrature, + const typename FunctionMap::type &neumann_bc, + const std::vector &solutions, + std::vector*> &errors, + const ComponentMask &component_mask, + const Function *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 +template +void KellyErrorEstimator<1,spacedim>:: +estimate (const Mapping<1,spacedim> &/*mapping*/, + const DH &/*dof_handler*/, + const hp::QCollection<0> &, + const typename FunctionMap::type &/*neumann_bc*/, + const std::vector &/*solutions*/, + std::vector*> &/*errors*/, + const ComponentMask &/*component_mask_*/, + const Function */*coefficient*/, + const unsigned int, + const types::subdomain_id /*subdomain_id*/, + const types::material_id /*material_id*/) +{ + Assert (false, ExcInternalError()); +} + + + +template +template +void KellyErrorEstimator<1,spacedim>:: +estimate (const Mapping<1,spacedim> &mapping, + const DH &dof_handler, + const Quadrature<0> &, + const typename FunctionMap::type &neumann_bc, + const std::vector &solutions, + std::vector*> &errors, + const ComponentMask &component_mask, + const Function *coefficient, + const unsigned int, + const types::subdomain_id subdomain_id_, + const types::material_id material_id) +{ +#ifdef DEAL_II_WITH_P4EST + if (dynamic_cast*> + (&dof_handler.get_tria()) + != 0) + Assert ((subdomain_id_ == numbers::invalid_subdomain_id) + || + (subdomain_id_ == + dynamic_cast&> + (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*> + (&dof_handler.get_tria()) + != 0) + ? + dynamic_cast&> + (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::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; nsize() == dof_handler.n_dofs(), + ExcInvalidSolutionVector()); + + Assert ((coefficient == 0) || + (coefficient->n_components == n_components) || + (coefficient->n_components == 1), + ExcInvalidCoefficient()); + + for (typename FunctionMap::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 > > > + gradients_here (n_solution_vectors, + std::vector > >(2, std::vector >(n_components))); + std::vector > > > + gradients_neighbor (gradients_here); + std::vector > + grad_neighbor (n_solution_vectors, Vector(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 coefficient_values (n_components); + if (coefficient == 0) + for (unsigned int c=0; c 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; nneighbor(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; ssecond->value(cell->vertex(0)); + + for (unsigned int s=0; s v(n_components); + neumann_bc.find(n)->second->vector_value(cell->vertex(0), v); + + for (unsigned int s=0; sn_components == 1) + { + const double c_value = coefficient->value (cell->vertex(n)); + for (unsigned int c=0; cvector_value(cell->vertex(n), + coefficient_values); + } + + + for (unsigned int s=0; sdiameter(); + } + } + + for (unsigned int s=0; s:: +estimate > (const Mapping &, + const DH &, + const Quadrature &, + const FunctionMap::type &, + const VEC &, + Vector &, + const ComponentMask &, + const Function *, + const unsigned int , + const unsigned int , + const types::material_id); + +template +void +KellyErrorEstimator:: +estimate > ( + const DH &, + const Quadrature &, + const FunctionMap::type &, + const VEC &, + Vector &, + const ComponentMask &, + const Function *, + const unsigned int , + const unsigned int , + const types::material_id); + +template +void +KellyErrorEstimator:: +estimate > (const Mapping &, + const DH &, + const Quadrature &, + const FunctionMap::type &, + const std::vector &, + std::vector *> &, + const ComponentMask &, + const Function *, + const unsigned int , + const unsigned int , + const types::material_id); + +template +void +KellyErrorEstimator:: +estimate > ( + const DH &, + const Quadrature &, + const FunctionMap::type &, + const std::vector &, + std::vector *> &, + const ComponentMask &, + const Function *, + const unsigned int , + const unsigned int , + const types::material_id); + +template +void +KellyErrorEstimator:: +estimate > (const Mapping &, + const DH &, + const hp::QCollection &, + const FunctionMap::type &, + const VEC &, + Vector &, + const ComponentMask &, + const Function *, + const unsigned int , + const unsigned int , + const types::material_id); + +template +void +KellyErrorEstimator:: +estimate > ( + const DH &, + const hp::QCollection &, + const FunctionMap::type &, + const VEC &, + Vector &, + const ComponentMask &, + const Function *, + const unsigned int , + const unsigned int , + const types::material_id); + +template +void +KellyErrorEstimator:: +estimate > (const Mapping &, + const DH &, + const hp::QCollection &, + const FunctionMap::type &, + const std::vector &, + std::vector *> &, + const ComponentMask &, + const Function *, + const unsigned int , + const unsigned int , + const types::material_id); + +template +void +KellyErrorEstimator:: +estimate > ( + const DH &, + const hp::QCollection &, + const FunctionMap::type &, + const std::vector &, + std::vector *> &, + const ComponentMask &, + const Function *, + 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 &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 &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::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 >; +#else template class SolutionTransfer >; #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_space_dimension> - (const DoFHandler&, - const VEC&, - const Function&, - Vector&, - const Quadrature&, - const NormType&, - const Function*, - const double); - - template - void integrate_difference, deal_II_space_dimension > - (const DoFHandler&, - const VEC&, - const Function&, - Vector&, - const Quadrature&, - const NormType&, - const Function*, - const double); - - template - void integrate_difference, deal_II_space_dimension> - (const Mapping&, - const DoFHandler&, - const VEC&, - const Function&, - Vector&, - const Quadrature&, - const NormType&, - const Function*, - const double); - - template - void integrate_difference, deal_II_space_dimension > - (const Mapping&, - const DoFHandler&, - const VEC&, - const Function&, - Vector&, - const Quadrature&, - const NormType&, - const Function*, - const double); - - - - template - double compute_mean_value - (const Mapping&, - const DoFHandler&, - const Quadrature&, - const VEC&, - const unsigned int); - - template - double compute_mean_value - (const DoFHandler&, - const Quadrature&, - const VEC&, - const unsigned int); - - template - void interpolate - (const Mapping&, - const DoFHandler&, - const Function&, - VEC&); - - template - void interpolate - (const DoFHandler&, - const Function&, - VEC&); - - template - void project - (const Mapping &, - const DoFHandler &, - const ConstraintMatrix &, - const Quadrature &, - const Function &, - VEC &, - const bool, - const Quadrature &, - const bool); - - template - void project - (const DoFHandler &, - const ConstraintMatrix &, - const Quadrature &, - const Function &, - VEC &, - const bool, - const Quadrature &, - const bool); - - template - void project - (const hp::MappingCollection &, - const hp::DoFHandler &, - const ConstraintMatrix &, - const hp::QCollection &, - const Function &, - VEC &, - const bool, - const hp::QCollection &, - const bool); - - template - void project - (const hp::DoFHandler &, - const ConstraintMatrix &, - const hp::QCollection &, - const Function &, - VEC &, - const bool, - const hp::QCollection &, - const bool); - \} -#endif - } - - - -//TODO[SP]: replace by -// 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 ( - const hp::DoFHandler&, - const VEC&, - const Point&, - Vector&); - - template - void interpolate - (const Mapping&, - const hp::DoFHandler&, - const Function&, - VEC&); - template - void interpolate - (const hp::DoFHandler&, - const Function&, - VEC&); - - template - double point_value ( - const hp::DoFHandler&, - const VEC&, - const Point&); - - template - void point_value ( - const hp::MappingCollection&, - const hp::DoFHandler&, - const VEC&, - const Point&, - Vector&); - - template - void interpolate - (const DoFHandler&, - const DoFHandler&, - const FullMatrix&, - const VEC&, - VEC&); - - template - double point_value ( - const hp::MappingCollection&, - const hp::DoFHandler&, - const VEC&, - const Point&); - - template - void integrate_difference - (const hp::DoFHandler&, - const VEC&, - const Function&, - Vector&, - const hp::QCollection&, - const NormType&, - const Function*, - const double); - template - void integrate_difference - (const hp::DoFHandler&, - const VEC&, - const Function&, - Vector&, - const hp::QCollection&, - const NormType&, - const Function*, - const double); - template - void integrate_difference - (const hp::MappingCollection&, - const hp::DoFHandler&, - const VEC&, - const Function&, - Vector&, - const hp::QCollection&, - const NormType&, - const Function*, - const double); - template - void integrate_difference - (const hp::MappingCollection&, - const hp::DoFHandler&, - const VEC&, - const Function&, - Vector&, - const hp::QCollection&, - const NormType&, - const Function*, - const double); - - template - void point_difference ( - const DoFHandler&, - const VEC&, - const Function&, - Vector&, - const Point&); - - template - void point_difference ( - const Mapping&, - const DoFHandler&, - const VEC&, - const Function&, - Vector&, - const Point&); - - template - void point_value ( - const DoFHandler&, - const VEC&, - const Point&, - Vector&); - - template - double point_value ( - const DoFHandler&, - const VEC&, - const Point&); - - template - void point_value ( - const Mapping&, - const DoFHandler&, - const VEC&, - const Point&, - Vector&); - - template - double point_value ( - const Mapping&, - const DoFHandler&, - const VEC&, - const Point&); - - \} -#endif - } - - -for (VEC : SERIAL_VECTORS) -{ - namespace VectorTools \{ - template - void subtract_mean_value(VEC &, const std::vector &); - \} -} - - -for (deal_II_dimension : DIMENSIONS) -{ - namespace VectorTools \{ - template - void interpolate_boundary_values ( - const MGDoFHandler &, - const types::boundary_id, - const Function &, - ConstraintMatrix&, - const ComponentMask &); - - template - void interpolate_boundary_values ( - const MGDoFHandler &, - const types::boundary_id, - const Function &, - std::map &, - 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 &, - const DH &, - const FunctionMap::type &, - std::map &, - const ComponentMask &); - - template - void interpolate_boundary_values - (const Mapping &, - const DH &, - const types::boundary_id, - const Function &, - std::map &, - const ComponentMask &); - - template - void interpolate_boundary_values ( - const DH &, - const types::boundary_id, - const Function &, - std::map &, - const ComponentMask &); - - template - void interpolate_boundary_values - (const DH &, - const FunctionMap::type &, - std::map &, - const ComponentMask &); - - template - void interpolate_boundary_values ( - const Mapping &, - const DH &, - const FunctionMap::type &, - ConstraintMatrix &, - const ComponentMask &); - - template - void interpolate_boundary_values - (const Mapping &, - const DH &, - const types::boundary_id, - const Function &, - ConstraintMatrix &, - const ComponentMask &); - - template - void interpolate_boundary_values ( - const DH &, - const types::boundary_id, - const Function &, - ConstraintMatrix &, - const ComponentMask &); - - template - void interpolate_boundary_values ( - const DH &, - const FunctionMap::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 - (const Mapping &, - const DoFHandler &, - const Quadrature &, - const Function &, - Vector &); - - template - void create_right_hand_side - (const DoFHandler &, - const Quadrature &, - const Function &, - Vector &); - - \} -#endif - } - -//TODO[SP]: replace by -// 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 - (const hp::MappingCollection &, - const hp::DoFHandler &, - const FunctionMap::type &, - const hp::QCollection&, - std::map&, - std::vector); - - template - void project_boundary_values - (const hp::DoFHandler &, - const FunctionMap::type &, - const hp::QCollection&, - std::map&, - std::vector); -#endif - -#if deal_II_dimension == deal_II_space_dimension - template - void create_right_hand_side - (const hp::MappingCollection &, - const hp::DoFHandler &, - const hp::QCollection &, - const Function &, - Vector &); - - template - void create_right_hand_side - (const hp::DoFHandler &, - const hp::QCollection &, - const Function &, - Vector &); - - template - void create_point_source_vector - (const Mapping &, - const DoFHandler &, - const Point &, - Vector &); - template - void create_point_source_vector - (const DoFHandler &, - const Point &, - Vector &); - - template - void create_point_source_vector - (const hp::MappingCollection &, - const hp::DoFHandler &, - const Point &, - Vector &); - template - void create_point_source_vector - (const hp::DoFHandler &, - const Point &, - Vector &); - template - void create_point_source_vector - (const Mapping &, - const DoFHandler &, - const Point &, - const Point &, - Vector &); - template - void create_point_source_vector - (const DoFHandler &, - const Point &, - const Point &, - Vector &); - - template - void create_point_source_vector - (const hp::MappingCollection &, - const hp::DoFHandler &, - const Point &, - const Point &, - Vector &); - template - void create_point_source_vector - (const hp::DoFHandler &, - const Point &, - const Point &, - Vector &); - -#if deal_II_dimension > 1 - template - void - create_boundary_right_hand_side - (const Mapping &, - const DoFHandler &, - const Quadrature &, - const Function &, - Vector &, - const std::set &); -#endif - - template - void - create_boundary_right_hand_side - (const DoFHandler &, - const Quadrature &, - const Function &, - Vector &, - const std::set &); - -#if deal_II_dimension > 1 - template - void - create_boundary_right_hand_side - (const hp::MappingCollection &, - const hp::DoFHandler &, - const hp::QCollection &, - const Function &, - Vector &, - const std::set &); -#endif - - template - void - create_boundary_right_hand_side - (const hp::DoFHandler &, - const hp::QCollection &, - const Function &, - Vector &, - const std::set &); - - - - - - template - void project_boundary_values - (const Mapping &, - const DoFHandler &, - const FunctionMap::type &, - const Quadrature&, - std::map&, std::vector); - - template - void project_boundary_values - (const DoFHandler &, - const FunctionMap::type &, - const Quadrature&, - std::map&, - std::vector); - - template - void project_boundary_values - (const Mapping &, - const DoFHandler &, - const FunctionMap::type &, - const Quadrature&, - ConstraintMatrix&, std::vector); - - template - void project_boundary_values - (const DoFHandler &, - const FunctionMap::type &, - const Quadrature&, - ConstraintMatrix&, - std::vector); - - - -#if deal_II_dimension != 1 - template - void project_boundary_values_curl_conforming - (const DoFHandler&, - const unsigned int, - const Function&, - const types::boundary_id, - ConstraintMatrix&, - const Mapping&); - template - void project_boundary_values_curl_conforming - (const hp::DoFHandler&, - const unsigned int, - const Function&, - const types::boundary_id, - ConstraintMatrix&, - const hp::MappingCollection&); - template - void project_boundary_values_div_conforming - (const DoFHandler&, - const unsigned int, - const Function&, - const types::boundary_id, - ConstraintMatrix&, - const Mapping&); - template - void project_boundary_values_div_conforming - (const hp::DoFHandler&, - const unsigned int, - const Function&, - const types::boundary_id, - ConstraintMatrix&, - const hp::MappingCollection&); - template - void - compute_no_normal_flux_constraints (const DoFHandler &dof_handler, - const unsigned int first_vector_component, - const std::set &boundary_ids, - ConstraintMatrix &constraints, - const Mapping &mapping); - template - void - compute_no_normal_flux_constraints (const hp::DoFHandler &dof_handler, - const unsigned int first_vector_component, - const std::set &boundary_ids, - ConstraintMatrix &constraints, - const Mapping &mapping); -#endif -#endif - \} - } - - - -for (deal_II_dimension : DIMENSIONS) -{ - namespace VectorTools \{ - - template - void interpolate_to_different_mesh - (const DoFHandler &, - const Vector &, - const DoFHandler &, - Vector &); - - template - void interpolate_to_different_mesh - (const DoFHandler &, - const Vector &, - const DoFHandler &, - const ConstraintMatrix &, - Vector &); - - template - void interpolate_to_different_mesh - (const InterGridMap > &, - const Vector &, - const ConstraintMatrix &, - Vector &); - - template - void interpolate_to_different_mesh - (const DoFHandler &, - const Vector &, - const DoFHandler &, - Vector &); - - template - void interpolate_to_different_mesh - (const DoFHandler &, - const Vector &, - const DoFHandler &, - const ConstraintMatrix &, - Vector &); - - template - void interpolate_to_different_mesh - (const InterGridMap > &, - const Vector &, - const ConstraintMatrix &, - Vector &); - - \} -} - - 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_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 &, + const types::boundary_id, + const Function &, + ConstraintMatrix&, + const ComponentMask &); + + template + void interpolate_boundary_values ( + const MGDoFHandler &, + const types::boundary_id, + const Function &, + std::map &, + 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 &, + const DH &, + const FunctionMap::type &, + std::map &, + const ComponentMask &); + + template + void interpolate_boundary_values + (const Mapping &, + const DH &, + const types::boundary_id, + const Function &, + std::map &, + const ComponentMask &); + + template + void interpolate_boundary_values ( + const DH &, + const types::boundary_id, + const Function &, + std::map &, + const ComponentMask &); + + template + void interpolate_boundary_values + (const DH &, + const FunctionMap::type &, + std::map &, + const ComponentMask &); + + template + void interpolate_boundary_values ( + const Mapping &, + const DH &, + const FunctionMap::type &, + ConstraintMatrix &, + const ComponentMask &); + + template + void interpolate_boundary_values + (const Mapping &, + const DH &, + const types::boundary_id, + const Function &, + ConstraintMatrix &, + const ComponentMask &); + + template + void interpolate_boundary_values ( + const DH &, + const types::boundary_id, + const Function &, + ConstraintMatrix &, + const ComponentMask &); + + template + void interpolate_boundary_values ( + const DH &, + const FunctionMap::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 + (const Mapping &, + const DoFHandler &, + const FunctionMap::type &, + const Quadrature&, + std::map&, std::vector); + + template + void project_boundary_values + (const DoFHandler &, + const FunctionMap::type &, + const Quadrature&, + std::map&, + std::vector); + + template + void project_boundary_values + (const Mapping &, + const DoFHandler &, + const FunctionMap::type &, + const Quadrature&, + ConstraintMatrix&, std::vector); + + template + void project_boundary_values + (const DoFHandler &, + const FunctionMap::type &, + const Quadrature&, + ConstraintMatrix&, + std::vector); + + + +#if deal_II_dimension != 1 + template + void project_boundary_values_curl_conforming + (const DoFHandler&, + const unsigned int, + const Function&, + const types::boundary_id, + ConstraintMatrix&, + const Mapping&); + template + void project_boundary_values_curl_conforming + (const hp::DoFHandler&, + const unsigned int, + const Function&, + const types::boundary_id, + ConstraintMatrix&, + const hp::MappingCollection&); + template + void project_boundary_values_div_conforming + (const DoFHandler&, + const unsigned int, + const Function&, + const types::boundary_id, + ConstraintMatrix&, + const Mapping&); + template + void project_boundary_values_div_conforming + (const hp::DoFHandler&, + const unsigned int, + const Function&, + const types::boundary_id, + ConstraintMatrix&, + const hp::MappingCollection&); +#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_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 by +// 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 &dof_handler, + const unsigned int first_vector_component, + const std::set &boundary_ids, + ConstraintMatrix &constraints, + const Mapping &mapping); + template + void + compute_no_normal_flux_constraints (const hp::DoFHandler &dof_handler, + const unsigned int first_vector_component, + const std::set &boundary_ids, + ConstraintMatrix &constraints, + const Mapping &mapping); + + template + void + compute_normal_flux_constraints (const DoFHandler &dof_handler, + const unsigned int first_vector_component, + const std::set &boundary_ids, + ConstraintMatrix &constraints, + const Mapping &mapping); + template + void + compute_normal_flux_constraints (const hp::DoFHandler &dof_handler, + const unsigned int first_vector_component, + const std::set &boundary_ids, + ConstraintMatrix &constraints, + const Mapping &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_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_space_dimension> + (const Mapping&, + const DoFHandler&, + const VEC&, + const Function&, + Vector&, + const Quadrature&, + const NormType&, + const Function*, + const double); + + template + void integrate_difference, deal_II_space_dimension> + (const DoFHandler&, + const VEC&, + const Function&, + Vector&, + const Quadrature&, + const NormType&, + const Function*, + const double); + + template + void integrate_difference, deal_II_space_dimension > + (const Mapping&, + const DoFHandler&, + const VEC&, + const Function&, + Vector&, + const Quadrature&, + const NormType&, + const Function*, + const double); + + template + void integrate_difference, deal_II_space_dimension > + (const DoFHandler&, + const VEC&, + const Function&, + Vector&, + const Quadrature&, + const NormType&, + const Function*, + const double); + + template + void integrate_difference, deal_II_space_dimension> + (const hp::MappingCollection&, + const hp::DoFHandler&, + const VEC&, + const Function&, + Vector&, + const hp::QCollection&, + const NormType&, + const Function*, + const double); + + template + void integrate_difference, deal_II_space_dimension> + (const hp::DoFHandler&, + const VEC&, + const Function&, + Vector&, + const hp::QCollection&, + const NormType&, + const Function*, + const double); + + template + void integrate_difference, deal_II_space_dimension> + (const hp::MappingCollection&, + const hp::DoFHandler&, + const VEC&, + const Function&, + Vector&, + const hp::QCollection&, + const NormType&, + const Function*, + const double); + + template + void integrate_difference, deal_II_space_dimension> + (const hp::DoFHandler&, + const VEC&, + const Function&, + Vector&, + const hp::QCollection&, + const NormType&, + const Function*, + 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_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&, + const DoFHandler&, + const Function&, + VEC&); + + template + void interpolate + (const DoFHandler&, + const Function&, + VEC&); + \} +#endif + } + + + +//TODO[SP]: replace by +// 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&, + const hp::DoFHandler&, + const Function&, + VEC&); + template + void interpolate + (const hp::DoFHandler&, + const Function&, + VEC&); + + template + void interpolate + (const DoFHandler&, + const DoFHandler&, + const FullMatrix&, + 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 &, + const DH &, + const FunctionMap::type &, + std::map &, + const ComponentMask &); + + template + void interpolate_boundary_values + (const Mapping &, + const DH &, + const types::boundary_id, + const Function &, + std::map &, + const ComponentMask &); + + template + void interpolate_boundary_values ( + const DH &, + const types::boundary_id, + const Function &, + std::map &, + const ComponentMask &); + + template + void interpolate_boundary_values + (const DH &, + const FunctionMap::type &, + std::map &, + const ComponentMask &); + + template + void interpolate_boundary_values ( + const Mapping &, + const DH &, + const FunctionMap::type &, + ConstraintMatrix &, + const ComponentMask &); + + template + void interpolate_boundary_values + (const Mapping &, + const DH &, + const types::boundary_id, + const Function &, + ConstraintMatrix &, + const ComponentMask &); + + template + void interpolate_boundary_values ( + const DH &, + const types::boundary_id, + const Function &, + ConstraintMatrix &, + const ComponentMask &); + + template + void interpolate_boundary_values ( + const DH &, + const FunctionMap::type &, + ConstraintMatrix &, + const ComponentMask &); + + \} +#endif + } + + + +for (deal_II_dimension : DIMENSIONS) +{ + namespace VectorTools \{ + + template + void interpolate_to_different_mesh + (const DoFHandler &, + const Vector &, + const DoFHandler &, + Vector &); + + template + void interpolate_to_different_mesh + (const DoFHandler &, + const Vector &, + const DoFHandler &, + const ConstraintMatrix &, + Vector &); + + template + void interpolate_to_different_mesh + (const InterGridMap > &, + const Vector &, + const ConstraintMatrix &, + Vector &); + + template + void interpolate_to_different_mesh + (const DoFHandler &, + const Vector &, + const DoFHandler &, + Vector &); + + template + void interpolate_to_different_mesh + (const DoFHandler &, + const Vector &, + const DoFHandler &, + const ConstraintMatrix &, + Vector &); + + template + void interpolate_to_different_mesh + (const InterGridMap > &, + const Vector &, + const ConstraintMatrix &, + Vector &); + + \} +} + + 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_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 + (const Mapping&, + const DoFHandler&, + const Quadrature&, + const VEC&, + const unsigned int); + + template + double compute_mean_value + (const DoFHandler&, + const Quadrature&, + const VEC&, + const unsigned int); + + \} +#endif + } + + + +for (VEC : SERIAL_VECTORS) +{ + namespace VectorTools \{ + template + void subtract_mean_value(VEC &, const std::vector &); + \} +} 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_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 by +// 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 ( + const hp::DoFHandler&, + const VEC&, + const Point&, + Vector&); + + template + double point_value ( + const hp::DoFHandler&, + const VEC&, + const Point&); + + template + void point_value ( + const hp::MappingCollection&, + const hp::DoFHandler&, + const VEC&, + const Point&, + Vector&); + + template + double point_value ( + const hp::MappingCollection&, + const hp::DoFHandler&, + const VEC&, + const Point&); + + template + void point_difference ( + const DoFHandler&, + const VEC&, + const Function&, + Vector&, + const Point&); + + template + void point_difference ( + const Mapping&, + const DoFHandler&, + const VEC&, + const Function&, + Vector&, + const Point&); + + template + void point_value ( + const DoFHandler&, + const VEC&, + const Point&, + Vector&); + + template + double point_value ( + const DoFHandler&, + const VEC&, + const Point&); + + template + void point_value ( + const Mapping&, + const DoFHandler&, + const VEC&, + const Point&, + Vector&); + + template + double point_value ( + const Mapping&, + const DoFHandler&, + const VEC&, + const Point&); + + \} +#endif + } + + + +//TODO[SP]: replace by +// 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 + (const Mapping &, + const DoFHandler &, + const Point &, + Vector &); + template + void create_point_source_vector + (const DoFHandler &, + const Point &, + Vector &); + + template + void create_point_source_vector + (const hp::MappingCollection &, + const hp::DoFHandler &, + const Point &, + Vector &); + template + void create_point_source_vector + (const hp::DoFHandler &, + const Point &, + Vector &); + template + void create_point_source_vector + (const Mapping &, + const DoFHandler &, + const Point &, + const Point &, + Vector &); + template + void create_point_source_vector + (const DoFHandler &, + const Point &, + const Point &, + Vector &); + + template + void create_point_source_vector + (const hp::MappingCollection &, + const hp::DoFHandler &, + const Point &, + const Point &, + Vector &); + template + void create_point_source_vector + (const hp::DoFHandler &, + const Point &, + const Point &, + Vector &); +#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 &, + const DoFHandler &, + const ConstraintMatrix &, + const Quadrature &, + const Function &, + VEC &, + const bool, + const Quadrature &, + const bool); + + template + void project + (const DoFHandler &, + const ConstraintMatrix &, + const Quadrature &, + const Function &, + VEC &, + const bool, + const Quadrature &, + const bool); + + template + void project + (const hp::MappingCollection &, + const hp::DoFHandler &, + const ConstraintMatrix &, + const hp::QCollection &, + const Function &, + VEC &, + const bool, + const hp::QCollection &, + const bool); + + template + void project + (const hp::DoFHandler &, + const ConstraintMatrix &, + const hp::QCollection &, + const Function &, + VEC &, + const bool, + const hp::QCollection &, + 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_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 &, + const std::set &) + { + 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 &, + const std::set &) + { + 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 &, + const std::set &) + { + 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 &, + const std::set &) + { + 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 + (const Mapping &, + const DoFHandler &, + const Quadrature &, + const Function &, + Vector &); + + template + void create_right_hand_side + (const DoFHandler &, + const Quadrature &, + const Function &, + Vector &); + + \} +#endif + } + +//TODO[SP]: replace by +// 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 + (const hp::MappingCollection &, + const hp::DoFHandler &, + const hp::QCollection &, + const Function &, + Vector &); + + template + void create_right_hand_side + (const hp::DoFHandler &, + const hp::QCollection &, + const Function &, + Vector &); + +#if deal_II_dimension > 1 + template + void + create_boundary_right_hand_side + (const Mapping &, + const DoFHandler &, + const Quadrature &, + const Function &, + Vector &, + const std::set &); +#endif + + template + void + create_boundary_right_hand_side + (const DoFHandler &, + const Quadrature &, + const Function &, + Vector &, + const std::set &); + +#if deal_II_dimension > 1 + template + void + create_boundary_right_hand_side + (const hp::MappingCollection &, + const hp::DoFHandler &, + const hp::QCollection &, + const Function &, + Vector &, + const std::set &); +#endif + + template + void + create_boundary_right_hand_side + (const hp::DoFHandler &, + const hp::QCollection &, + const Function &, + Vector &, + const std::set &); + + +#endif + \} + }