What is deal.II?
- deal.II is a C++ program library targeted at the computational solution of
- partial differential equations using adaptive finite elements. It uses
- state-of-the-art programming techniques to offer you a modern interface to
- the complex data structures and algorithms required.
+ deal.II is a C++ program library targeted at the computational solution
+ of partial differential equations using adaptive finite elements. It uses
+ state-of-the-art programming techniques to offer you a modern interface
+ to the complex data structures and algorithms required.
For the impatient:
Please see the file LICENSE for details
-For further information have a look at ./doc/readme.html or at
-http://www.dealii.org.
+Further information:
+
+ For further information have a look at ./doc/readme.html or at
+ http://www.dealii.org.
"
HAVE_GLIBC_STACKTRACE)
-#
-# On Mac OS X, -rdynamic is accepted by the compiler (i.e.
-# it doesn't produce an error) but we always get a warning
-# that it isn't supported. So, only enable -rdynamic on non-Darwin
-# platforms.
-#
-# - Matthias Maier, rewritten 2012
-#
-IF(HAVE_GLIBC_STACKTRACE AND NOT CMAKE_SYSTEM_NAME MATCHES "Darwin")
+IF(HAVE_GLIBC_STACKTRACE)
ENABLE_IF_SUPPORTED(CMAKE_SHARED_LINKER_FLAGS "-rdynamic")
ENDIF()
# per email by John Fowkes on the mailing list in Feb 2012,
# so don't run the test on cygwin.
#
-# - Matthias Maier, rewritten 2012
+# Finally, Intel's icpc compiler complains about the flag
+# but apparently only if the file to be compiled contains
+# particular content. See bug #46 in the Google Code bug
+# data base (http://code.google.com/p/dealii/issues/detail?id=46).
+# It proved impossible to track down under which circumstances
+# this happens, and so it was disabled for icpc.
+#
+# - Matthias Maier, rewritten 2012, 2013
#
IF( (NOT CMAKE_SYSTEM_NAME MATCHES "CYGWIN") AND
- (NOT CMAKE_SYSTEM_NAME MATCHES "Windows") )
+ (NOT CMAKE_SYSTEM_NAME MATCHES "Windows") AND
+ (NOT CMAKE_CXX_COMPILER_ID MATCHES "Intel") )
ENABLE_IF_SUPPORTED(DEAL_II_CXX_FLAGS_DEBUG "-Wa,--compress-debug-sections")
ENDIF()
# this flag any more, so check whether we can indeed do this
#
ENABLE_IF_SUPPORTED(CMAKE_CXX_FLAGS "-Wno-long-double")
+
+ #
+ # On Mac OS X, -rdynamic is accepted by the compiler (i.e.
+ # it doesn't produce an error) but we always get a warning
+ # that it isn't supported.
+ #
+ # TODO: MM: Check whether this is still necessary...
+ #
+ STRIP_FLAG(CMAKE_SHARED_LINKER_FLAGS "-rdynamic")
ENDIF()
+
###########################################################################
# #
# Windows and CYGWIN specific setup: #
${DEAL_II_EXTERNAL_LIBRARIES}
${DEAL_II_EXTERNAL_LIBRARIES_${build}}
)
- IF(_lib MATCHES "^/")
+ IF(_lib MATCHES "^\\s*/")
LIST(APPEND _libs "${_lib}")
ENDIF()
ENDFOREACH()
${_libs}
)
+ MESSAGE("\n\nDEBUG:")
+
SET(_paths)
FOREACH(_lib
$(D)/${DEAL_II_LIBRARY_RELDIR}/${CONFIG_LIBRARY_${build}}
${DEAL_II_EXTERNAL_LIBRARIES}
${DEAL_II_EXTERNAL_LIBRARIES_${build}}
)
- LIST(APPEND MAKEFILE_LIBS_${build} ${_lib})
+
#
- # Extract library paths where possible:
+ # Strip leading and trailing whitespace
#
+ MESSAGE("--> \"${_lib}\"")
+ STRING(STRIP "${_lib}" _lib)
+ MESSAGE(" stripped: \"${_lib}\"")
+
IF(_lib MATCHES "^(/|\\$\\(D\\))")
+ # Full path: /path/to/libfoo.so:
+
+ # Extract library paths:
GET_FILENAME_COMPONENT(_path ${_lib} PATH)
LIST(APPEND _paths ${_path})
+
+ MESSAGE(" appended: \"${_lib}\"")
+ LIST(APPEND MAKEFILE_LIBS_${build} ${_lib})
+
+ ELSEIF(_lib MATCHES "^-")
+ # Library is of the form "-lflag", don't touch it:
+ MESSAGE(" appended: \"${_lib}\"")
+ LIST(APPEND MAKEFILE_LIBS_${build} ${_lib})
+
+ ELSEIF(NOT "${_lib}" STREQUAL "")
+ # Well in this case we just assume that we have to append an "-l"
+ # Note: This won't cover case where a relative library name, such as
+ # libfoo.so, libfoo.dylib, etc. is specified...
+ MESSAGE(" appended: \"-l${_lib}\"")
+ LIST(APPEND MAKEFILE_LIBS_${build} "-l${_lib}")
+
ENDIF()
ENDFOREACH()
+# MESSAGE(FATAL_ERROR "bailout")
+
#
# And build up an rpath:
#
FOREACH(_flag
CXX_FLAGS_RELEASE
CXX_FLAGS_DEBUG
+ SHARED_LINKER_FLAGS_RELEASE
+ SHARED_LINKER_FLAGS_DEBUG
)
IF(NOT "${CMAKE_${_flag}}" STREQUAL "")
MESSAGE(FATAL_ERROR
CMAKE_C_FLAGS_DEBUG
CMAKE_C_FLAGS_MINSIZEREL
CMAKE_C_FLAGS_RELWITHDEBINFO
+ CMAKE_SHARED_LINKER_FLAGS_DEBUG
+ CMAKE_SHARED_LINKER_FLAGS_MINSIZEREL
+ CMAKE_SHARED_LINKER_FLAGS_RELEASE
+ CMAKE_SHARED_LINKER_FLAGS_RELWITHDEBINFO
)
# Go away...
SET(${_flag} "" CACHE INTERNAL "" FORCE)
MARK_AS_ADVANCED(${_flag})
ENDFOREACH()
-
#
# Finally, read in CFLAGS, CXXFLAGS and LDFLAGS from environment and
# prepend them to the saved variables:
#
SET(CMAKE_C_FLAGS_SAVED "$ENV{CFLAGS} ${CMAKE_C_FLAGS_SAVED}")
SET(CMAKE_CXX_FLAGS_SAVED "$ENV{CXXFLAGS} ${CMAKE_CXX_FLAGS_SAVED}")
-SET(CMAKE_SHARED_LINKER_FLAGS_SAVED "$ENV{LDFLAGS} ${CMAKE_SHARED_LINKER_FLAGS}")
+SET(CMAKE_SHARED_LINKER_FLAGS_SAVED "$ENV{LDFLAGS} ${CMAKE_SHARED_LINKER_FLAGS_SAVED}")
UNSET(ENV{CFLAGS})
UNSET(ENV{CXXFLAGS})
UNSET(ENV{LDFLAGS})
#####
##
-## Copyright (C) 2012 by the deal.II authors
+## Copyright (C) 2012, 2013 by the deal.II authors
##
## This file is part of the deal.II library.
##
# -w175 subscript out of range
# -w177 declared but not referenced
# -w279 controlling expression is constant
+# -w383 value copied to temporary, reference to temporary used
+# -w981 operands are evaluated in unspecified order
+# -w1418 external function definition with no prior declaration
+# (happens in boost)
# -w1478 deprecation warning
# -w1572 floating-point equality and inequality comparisons are unreliable
#
ENABLE_IF_SUPPORTED(CMAKE_CXX_FLAGS "-wd175")
ENABLE_IF_SUPPORTED(CMAKE_CXX_FLAGS "-wd177")
ENABLE_IF_SUPPORTED(CMAKE_CXX_FLAGS "-wd279")
+ENABLE_IF_SUPPORTED(CMAKE_CXX_FLAGS "-wd383")
+ENABLE_IF_SUPPORTED(CMAKE_CXX_FLAGS "-wd981")
+ENABLE_IF_SUPPORTED(CMAKE_CXX_FLAGS "-wd1418")
ENABLE_IF_SUPPORTED(CMAKE_CXX_FLAGS "-wd1478")
ENABLE_IF_SUPPORTED(CMAKE_CXX_FLAGS "-wd1572")
SET_IF_EMPTY(DEAL_II_PACKAGE_NAME "deal.II")
-SET_IF_EMPTY(DEAL_II_PACKAGE_VERSION "8.0.pre") # TODO: Get this value from somewhere else
+FILE(STRINGS "${CMAKE_SOURCE_DIR}/VERSION" _version LIMIT_COUNT 1)
+SET_IF_EMPTY(DEAL_II_PACKAGE_VERSION "${_version}")
SET_IF_EMPTY(DEAL_II_PACKAGE_VENDOR
"The deal.II Authors <http://www.dealii.org/>"
<li><em>Christophe Trophime:</em>
Packaging and configuration issues.
+ <li><em>Bruno Turcksin:</em>
+ Extending deal.ii for 64-bit integer support.
+
+ <li><em>Kainan Wang:</em>
+ Extending deal.ii for 64-bit integer support.
+
<li><em>Yaqi Wang:</em>
The step-28 tutorial program;
DEPENDS ${CMAKE_BINARY_DIR}/doxygen.log
)
+
INSTALL(FILES
+ ${CMAKE_CURRENT_BINARY_DIR}/deal.tag
${CMAKE_CURRENT_SOURCE_DIR}/stylesheet.css
DESTINATION ${DEAL_II_DOCHTML_RELDIR}/doxygen
COMPONENT documentation
"http://www.w3.org/TR/REC-html40/frameset.dtd">
<html>
<head>
-<!-- deal.II tutorial template
- Wolfgang Bangerth <bangerth@dealii.org> 1999
--->
<title>Step-by-Step Examples</title>
<link href="../../screen.css" rel="StyleSheet" type="text/css">
<title>The deal.II License</title>
<link href="screen.css" rel="StyleSheet">
<meta name="author" content="the deal.II authors <authors@dealii.org>">
- <meta name="copyright" content="Copyright (C) 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2011, 2012 by the deal.II authors">
+ <meta name="copyright" content="Copyright (C) 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2011, 2012, 2013 by the deal.II authors">
<meta name="date" content="$Date$">
<meta name="svn_id" content="$Id$">
<meta name="keywords" content="deal.II license">
<p>
The <acronym>deal.II</acronym> library has been placed under an Open
Source license, in the sense advocated by the <a
- href="http://www.opensource.org" target="_top">Open Source
- Initiative</a>. You are thus free to copy and use it, and you have
- free access to all source codes. However, <acronym>deal.II</acronym>
- is not in the public domain, it is property of and copyrighted by
- the <acronym>deal.II</acronym> authors, and there are restrictions
- on its use. We will give some hints on license issues first. The
- legally binding license is the <a href="#license-text">Q Public
- License (QPL)</a> at the bottom of this page. Furthermore, deal.II
- distributions come bundled with some third party software for which
- the deal.II authors do not own the copyright. The licenses of these
- parts are discussed <a href="#3rdparty">below</a>.
+ href="http://www.opensource.org" target="_top">Open Source
+ Initiative</a>. You are thus free to copy and use it, and you have
+ free access to all source code.
+ </p>
+ <p>
+ <b>However, <acronym>deal.II</acronym> is not in the public domain, it
+ is property of and copyrighted by the
+ <a href="authors.html"><acronym>deal.II</acronym> authors</a>, and
+ there are restrictions on its use:</b>
+ The legally binding license is the <a href="#license-text">GNU Lesser
+ General Public License</a> (LGPL) as published by the Free Software
+ Foundation; either version 2.1 of the License, or (at your option)
+ any later version.
+ </p>
+
+ <p>
+ Furthermore, the deal.II distribution comes bundled with some third
+ party software for which the deal.II authors do not own the
+ copyright. The licenses of these parts are discussed
+ <a href="#3rdparty">below</a>.
+ </p>
<p>
In this document, as well as in the program files, the terms
Kanschat and a <i>long</i> list of contributors.
</p>
-
-
- <h3>Restrictions on and commercial use of the library</h3>
-
- <p>
-
- <acronym>deal.II</acronym> is distributed under the <a
- href="http://www.opensource.org/osd.html" target="_top">Open Source
- license</a> called the <em>Q Public License</em> (or "QPL") listed
- in full below. Essentially, an interpretation of this license is
- that you can use the library free of charge for developing your own
- programs. However, if you plan to distribute these programs to others,
- certain restrictions are imposed by the QPL.
+ <h3>Contributions</h3>
<p>
-
- In non-legal terms, the license stipulates that if you want
- to give your program to someone else in whatever form (including as
- a binary executable), you have to make the entire source code of
- your own program and all modifications to the deal.II library
- available free of charge as well.
-
+ <b>As a contributor to this project, you agree that any of your
+ contributions be licensed under the same terms and conditions as
+ the license of the deal.II project granted to you.</b>
+ </p>
<p>
-
- We recognize that giving away the source code may be an
- unacceptable restriction in a commercial setting. As the owners of
- the sources, we are able to grant you a differently licensed version
- of the deal.II library that does not contain this
- requirement, and we are very much willing to negotiate the terms of
- such a license. Please contact the authors of the library if you are
- interested in commercial use of deal.II.
-
+ We, <a href="authors.html">the deal.II authors</a>, do not require
+ copyright assignments for contributions. This means that the
+ copyright for code contributions in the deal.II project is held by
+ its respective contributors who have each agreed to release their
+ contributed code under the terms of the LGPL v2.1 or later.
+ </p>
- <h3>Referencing the library</h3>
+ <h3>Referencing the library</h3>
<p>
- In addition to the terms imposed by the QPL, we ask for the
- following courtesy:
- </p>
+ In addition to the terms imposed by the LGPL v2.1 or later, we ask
+ for the following courtesy:
<ul>
- <li> Every publication presenting numerical results obtained with
- the help of <acronym>deal.II</acronym> should state the name of
- the library and cite
- the canonical deal.II reference listed at the top of <a
- href="publications/index.html">the publications page</a>.
+ <li> Every publication presenting numerical results obtained with the
+ help of <acronym>deal.II</acronym> should state the name of the
+ library and cite the canonical deal.II reference listed at the top of
+ <a href="publications/index.html">the publications page</a>.
</ul>
- This is the usual, fair way of giving credit to contributors to a
- scientific result. In addition, it helps us justify our effort in
- developing deal.II as an academic undertaking.
-
+ </p>
+ <p>
+ This is the usual, fair way of giving credit to contributors to a
+ scientific result. In addition, it helps us justify our effort in
+ developing deal.II as an academic undertaking.
+ </p>
<p>
-
We keep a <a href="publications/index.html">list of publications
using deal.II</a>. Feel free to let us know about your publications.
-
-
- <a name="3rdparty">
- <h3>Parts of the deal.II distribution under a separate license</h3>
- </a>
-
- Some of the files in the <code>contrib/</code> subdirectory are by
- other people, and are distributed under separate licenses. These
- files are not part of the <acronym>deal.II</acronym> library, but
- they are part of our distribution. They are generally available for
- use in non-commercial academic settings. For commercial use and if
- you want to distribute your codes, please consult the licenses of
- these parts of the deal.II distribution. We made sure that those parts of the
- distribution for which the license is not entirely free for all uses can be
- disabled upon configuration of <acronym>deal.II</acronym> without
- unduly restricting the functionality of the rest of the
- library.
-
- <p>
-
- In particular, these are libraries that we distribute in the
- <code>contrib/</code> subdirectory, courtesy of their authors:
- <ul>
- <li> Parts of the <a href="http://www.boost.org/" target="_top">BOOST</a>
- library.
- <li> <a
- href="http://www.cise.ufl.edu/research/sparse/umfpack/"
- target="_top">UMFPACK</a>. For the license, see <a
- href="http://www.cise.ufl.edu/research/sparse/umfpack/"
- target="_top">UMFPACK</a>.
- <li> <a href="http://warp.povusers.org/FunctionParser/"
- target="_top">FunctionParser</a>. For the license see <a
- href="http://warp.povusers.org/FunctionParser/"
- target="_top">FunctionParser</a>.
- </ul>
-
- <p>
-
- <acronym>deal.II</acronym> can interface with a number of <a
- href="readme.html#external-libs">other packages</a> that you have to install
- yourself. They are, of course, covered by their own licenses.
</p>
-
- <h3>About the license</h3>
+ <a name="3rdparty">
+ <h3>Parts of the deal.II distribution under a separate license</h3>
+ </a>
<p>
- The QPL was originally developed by
- <a href="http://www.troll.no" target="_top">Troll Tech</a> for their
- Qt program library, but has since gained some support by other
- library authors as well.
- For more information on the QPL, please follow
- <a href="http://doc.trolltech.com/4.0/qpl.html" target="_top">this link</a>.
+ <acronym>deal.II</acronym> comes bundled with copies of
+ <a href="http://www.cise.ufl.edu/research/sparse/umfpack/"
+ target="_top">UMFPACK</a>,
+ <a href="http://threadingbuildingblocks.org/"
+ target="_top">Threading Building Blocks</a>,
+ <a href="http://www.boost.org/" target="_top">BOOST</a> and
+ <a href="http://warp.povusers.org/FunctionParser/"
+ target="_top">FunctionParser</a>.
+ These projects reside in the subdirectory "bundled/". <b>Please note
+ that these projects are copyrighted by others than the deal.II
+ authors</b> and are covered by different licenses. For details,
+ consult the respective webpage.
</p>
-
-
-
- <hr>
- <a name="license-text">
- <h1 align=center>
- </a>
- THE Q PUBLIC LICENSE
- version 1.0
- <br>
- <br>
- <small>
- Copyright (C) 1999 Troll Tech AS, Norway.
- <br>
- <small>
- Everyone is permitted to copy and
- <br>
- distribute this license document.
- </small>
- </small>
- </h1>
<p>
- The intent of this license is to establish freedom to share and change the
- software regulated by this license under the open source model.
- <p>
- This license applies to any software containing a notice placed by the
- copyright holder saying that it may be distributed under the terms of
- the Q Public License version 1.0. Such software is herein referred to as
- the Software. This license covers modification and distribution of the
- Software, use of third-party application programs based on the Software,
- and development of free software which uses the Software.
- <h2 align=center>
- Granted Rights
- </h2>
- <p>
- 1. You are granted the non-exclusive rights set forth in this license
- provided you agree to and comply with any and all conditions in this
- license. Whole or partial distribution of the Software, or software
- items that link with the Software, in any form signifies acceptance of
- this license.
- <p>
- 2. You may copy and distribute the Software in unmodified form provided
- that the entire package, including - but not restricted to - copyright,
- trademark notices and disclaimers, as released by the initial developer
- of the Software, is distributed.
- <p>
- 3. You may make modifications to the Software and distribute your
- modifications, in a form that is separate from the Software, such as
- patches. The following restrictions apply to modifications:
- <blockquote>
- <p>
- a. Modifications must not alter or remove any copyright notices in
- the Software.
- <p>
- b. When modifications to the Software are released under this
- license, a non-exclusive royalty-free right is granted to the
- initial developer of the Software to distribute your modification
- in future versions of the Software provided such versions remain
- available under these terms in addition to any other license(s) of
- the initial developer.
- </blockquote>
- <p>
- 4. You may distribute machine-executable forms of the Software or
- machine-executable forms of modified versions of the Software, provided
- that you meet these restrictions:
- <blockquote>
- <p>
- a. You must include this license document in the distribution.
- <p>
- b. You must ensure that all recipients of the machine-executable forms
- are also able to receive the complete machine-readable source code
- to the distributed Software, including all modifications, without
- any charge beyond the costs of data transfer, and place prominent
- notices in the distribution explaining this.
- <p>
- c. You must ensure that all modifications included in the
- machine-executable forms are available under the terms of this
- license.
- </blockquote>
- <p>
- 5. You may use the original or modified versions of the Software to
- compile, link and run application programs legally developed by you
- or by others.
- <p>
- 6. You may develop application programs, reusable components and other
- software items that link with the original or modified versions of the
- Software. These items, when distributed, are subject to the following
- requirements:
- <blockquote>
- <p>
- a. You must ensure that all recipients of machine-executable forms of
- these items are also able to receive and use the complete
- machine-readable source code to the items without any charge
- beyond the costs of data transfer.
- <p>
- b. You must explicitly license all recipients of your items to use
- and re-distribute original and modified versions of the items in
- both machine-executable and source code forms. The recipients must
- be able to do so without any charges whatsoever, and they must be
- able to re-distribute to anyone they choose.
- <p>
- c. If the items are not available to the general public, and the
- initial developer of the Software requests a copy of the items,
- then you must supply one.
- </blockquote>
- <h2 align=center>
- Limitations of Liability
- </h2>
- In no event shall the initial developers or copyright holders be liable
- for any damages whatsoever, including - but not restricted to - lost
- revenue or profits or other direct, indirect, special, incidental or
- consequential damages, even if they have been advised of the possibility
- of such damages, except to the extent invariable law, if any, provides
- otherwise.
- <h2 align=center>
- No Warranty
- </h2>
+ The libraries listed above are all open source and as such place few
+ restrictions on their use. However, if you want to <i>distribute</i>
+ software developed with deal.II (in source or binary form) and you
+ are using the packages above (with source code in
+ <code>bundled/</code>), then they may impose different terms. Please
+ consult the licenses of these packages for more information.
+ </p>
<p>
- The Software and this license document are provided AS IS with NO WARRANTY
- OF ANY KIND, INCLUDING THE WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS
- FOR A PARTICULAR PURPOSE.
- <h2 align=center>
- Choice of Law
- </h2>
+ Alternatively, the configuration process of deal.II allows you to
+ disable the use of all of these bundled libraries. In that case, you
+ can not use their functionality but you also are not restricted by
+ their license.
<p>
- This license is governed by the Laws of Germany. Disputes shall be settled
- by Amtsgericht Heidelberg.
+
+ <h3>Contact</h3>
+ <p>
+ For further questions regarding licensing and commercial use please
+ contact the deal.II maintainers directly via one of the following mail
+ addresses:
+ <ul>
+ <li>
+ TODO
+ </li>
+ <li>
+ Wolfgang Bangerth < bangerth@gmail.com >
+ </li>
+ <li>
+ Timo Heister < heister@math.tamu.edu >
+ </li>
+ <li>
+ Guido Kanschat < dr.guido.kanschat@gmail.com >
+ </li>
+ </ul>
</p>
+ <h3>Full license text</h3>
+
+ <pre>
+
+ GNU LESSER GENERAL PUBLIC LICENSE
+ Version 2.1, February 1999
+
+ Copyright (C) 1991, 1999 Free Software Foundation, Inc.
+ 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ Everyone is permitted to copy and distribute verbatim copies
+ of this license document, but changing it is not allowed.
+
+ [This is the first released version of the Lesser GPL. It also counts
+ as the successor of the GNU Library Public License, version 2, hence
+ the version number 2.1.]
+
+ Preamble
+
+ The licenses for most software are designed to take away your
+ freedom to share and change it. By contrast, the GNU General Public
+ Licenses are intended to guarantee your freedom to share and change
+ free software--to make sure the software is free for all its users.
+
+ This license, the Lesser General Public License, applies to some
+ specially designated software packages--typically libraries--of the
+ Free Software Foundation and other authors who decide to use it. You
+ can use it too, but we suggest you first think carefully about whether
+ this license or the ordinary General Public License is the better
+ strategy to use in any particular case, based on the explanations below.
+
+ When we speak of free software, we are referring to freedom of use,
+ not price. Our General Public Licenses are designed to make sure that
+ you have the freedom to distribute copies of free software (and charge
+ for this service if you wish); that you receive source code or can get
+ it if you want it; that you can change the software and use pieces of
+ it in new free programs; and that you are informed that you can do
+ these things.
+
+ To protect your rights, we need to make restrictions that forbid
+ distributors to deny you these rights or to ask you to surrender these
+ rights. These restrictions translate to certain responsibilities for
+ you if you distribute copies of the library or if you modify it.
+
+ For example, if you distribute copies of the library, whether gratis
+ or for a fee, you must give the recipients all the rights that we gave
+ you. You must make sure that they, too, receive or can get the source
+ code. If you link other code with the library, you must provide
+ complete object files to the recipients, so that they can relink them
+ with the library after making changes to the library and recompiling
+ it. And you must show them these terms so they know their rights.
+
+ We protect your rights with a two-step method: (1) we copyright the
+ library, and (2) we offer you this license, which gives you legal
+ permission to copy, distribute and/or modify the library.
+
+ To protect each distributor, we want to make it very clear that
+ there is no warranty for the free library. Also, if the library is
+ modified by someone else and passed on, the recipients should know
+ that what they have is not the original version, so that the original
+ author's reputation will not be affected by problems that might be
+ introduced by others.
+
+ Finally, software patents pose a constant threat to the existence of
+ any free program. We wish to make sure that a company cannot
+ effectively restrict the users of a free program by obtaining a
+ restrictive license from a patent holder. Therefore, we insist that
+ any patent license obtained for a version of the library must be
+ consistent with the full freedom of use specified in this license.
+
+ Most GNU software, including some libraries, is covered by the
+ ordinary GNU General Public License. This license, the GNU Lesser
+ General Public License, applies to certain designated libraries, and
+ is quite different from the ordinary General Public License. We use
+ this license for certain libraries in order to permit linking those
+ libraries into non-free programs.
+
+ When a program is linked with a library, whether statically or using
+ a shared library, the combination of the two is legally speaking a
+ combined work, a derivative of the original library. The ordinary
+ General Public License therefore permits such linking only if the
+ entire combination fits its criteria of freedom. The Lesser General
+ Public License permits more lax criteria for linking other code with
+ the library.
+
+ We call this license the "Lesser" General Public License because it
+ does Less to protect the user's freedom than the ordinary General
+ Public License. It also provides other free software developers Less
+ of an advantage over competing non-free programs. These disadvantages
+ are the reason we use the ordinary General Public License for many
+ libraries. However, the Lesser license provides advantages in certain
+ special circumstances.
+
+ For example, on rare occasions, there may be a special need to
+ encourage the widest possible use of a certain library, so that it becomes
+ a de-facto standard. To achieve this, non-free programs must be
+ allowed to use the library. A more frequent case is that a free
+ library does the same job as widely used non-free libraries. In this
+ case, there is little to gain by limiting the free library to free
+ software only, so we use the Lesser General Public License.
+
+ In other cases, permission to use a particular library in non-free
+ programs enables a greater number of people to use a large body of
+ free software. For example, permission to use the GNU C Library in
+ non-free programs enables many more people to use the whole GNU
+ operating system, as well as its variant, the GNU/Linux operating
+ system.
+
+ Although the Lesser General Public License is Less protective of the
+ users' freedom, it does ensure that the user of a program that is
+ linked with the Library has the freedom and the wherewithal to run
+ that program using a modified version of the Library.
+
+ The precise terms and conditions for copying, distribution and
+ modification follow. Pay close attention to the difference between a
+ "work based on the library" and a "work that uses the library". The
+ former contains code derived from the library, whereas the latter must
+ be combined with the library in order to run.
+
+ GNU LESSER GENERAL PUBLIC LICENSE
+ TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
+
+ 0. This License Agreement applies to any software library or other
+ program which contains a notice placed by the copyright holder or
+ other authorized party saying it may be distributed under the terms of
+ this Lesser General Public License (also called "this License").
+ Each licensee is addressed as "you".
+
+ A "library" means a collection of software functions and/or data
+ prepared so as to be conveniently linked with application programs
+ (which use some of those functions and data) to form executables.
+
+ The "Library", below, refers to any such software library or work
+ which has been distributed under these terms. A "work based on the
+ Library" means either the Library or any derivative work under
+ copyright law: that is to say, a work containing the Library or a
+ portion of it, either verbatim or with modifications and/or translated
+ straightforwardly into another language. (Hereinafter, translation is
+ included without limitation in the term "modification".)
+
+ "Source code" for a work means the preferred form of the work for
+ making modifications to it. For a library, complete source code means
+ all the source code for all modules it contains, plus any associated
+ interface definition files, plus the scripts used to control compilation
+ and installation of the library.
+
+ Activities other than copying, distribution and modification are not
+ covered by this License; they are outside its scope. The act of
+ running a program using the Library is not restricted, and output from
+ such a program is covered only if its contents constitute a work based
+ on the Library (independent of the use of the Library in a tool for
+ writing it). Whether that is true depends on what the Library does
+ and what the program that uses the Library does.
+
+ 1. You may copy and distribute verbatim copies of the Library's
+ complete source code as you receive it, in any medium, provided that
+ you conspicuously and appropriately publish on each copy an
+ appropriate copyright notice and disclaimer of warranty; keep intact
+ all the notices that refer to this License and to the absence of any
+ warranty; and distribute a copy of this License along with the
+ Library.
+
+ You may charge a fee for the physical act of transferring a copy,
+ and you may at your option offer warranty protection in exchange for a
+ fee.
+
+ 2. You may modify your copy or copies of the Library or any portion
+ of it, thus forming a work based on the Library, and copy and
+ distribute such modifications or work under the terms of Section 1
+ above, provided that you also meet all of these conditions:
+
+ a) The modified work must itself be a software library.
+
+ b) You must cause the files modified to carry prominent notices
+ stating that you changed the files and the date of any change.
+
+ c) You must cause the whole of the work to be licensed at no
+ charge to all third parties under the terms of this License.
+
+ d) If a facility in the modified Library refers to a function or a
+ table of data to be supplied by an application program that uses
+ the facility, other than as an argument passed when the facility
+ is invoked, then you must make a good faith effort to ensure that,
+ in the event an application does not supply such function or
+ table, the facility still operates, and performs whatever part of
+ its purpose remains meaningful.
+
+ (For example, a function in a library to compute square roots has
+ a purpose that is entirely well-defined independent of the
+ application. Therefore, Subsection 2d requires that any
+ application-supplied function or table used by this function must
+ be optional: if the application does not supply it, the square
+ root function must still compute square roots.)
+
+ These requirements apply to the modified work as a whole. If
+ identifiable sections of that work are not derived from the Library,
+ and can be reasonably considered independent and separate works in
+ themselves, then this License, and its terms, do not apply to those
+ sections when you distribute them as separate works. But when you
+ distribute the same sections as part of a whole which is a work based
+ on the Library, the distribution of the whole must be on the terms of
+ this License, whose permissions for other licensees extend to the
+ entire whole, and thus to each and every part regardless of who wrote
+ it.
+
+ Thus, it is not the intent of this section to claim rights or contest
+ your rights to work written entirely by you; rather, the intent is to
+ exercise the right to control the distribution of derivative or
+ collective works based on the Library.
+
+ In addition, mere aggregation of another work not based on the Library
+ with the Library (or with a work based on the Library) on a volume of
+ a storage or distribution medium does not bring the other work under
+ the scope of this License.
+
+ 3. You may opt to apply the terms of the ordinary GNU General Public
+ License instead of this License to a given copy of the Library. To do
+ this, you must alter all the notices that refer to this License, so
+ that they refer to the ordinary GNU General Public License, version 2,
+ instead of to this License. (If a newer version than version 2 of the
+ ordinary GNU General Public License has appeared, then you can specify
+ that version instead if you wish.) Do not make any other change in
+ these notices.
+
+ Once this change is made in a given copy, it is irreversible for
+ that copy, so the ordinary GNU General Public License applies to all
+ subsequent copies and derivative works made from that copy.
+
+ This option is useful when you wish to copy part of the code of
+ the Library into a program that is not a library.
+
+ 4. You may copy and distribute the Library (or a portion or
+ derivative of it, under Section 2) in object code or executable form
+ under the terms of Sections 1 and 2 above provided that you accompany
+ it with the complete corresponding machine-readable source code, which
+ must be distributed under the terms of Sections 1 and 2 above on a
+ medium customarily used for software interchange.
+
+ If distribution of object code is made by offering access to copy
+ from a designated place, then offering equivalent access to copy the
+ source code from the same place satisfies the requirement to
+ distribute the source code, even though third parties are not
+ compelled to copy the source along with the object code.
+
+ 5. A program that contains no derivative of any portion of the
+ Library, but is designed to work with the Library by being compiled or
+ linked with it, is called a "work that uses the Library". Such a
+ work, in isolation, is not a derivative work of the Library, and
+ therefore falls outside the scope of this License.
+
+ However, linking a "work that uses the Library" with the Library
+ creates an executable that is a derivative of the Library (because it
+ contains portions of the Library), rather than a "work that uses the
+ library". The executable is therefore covered by this License.
+ Section 6 states terms for distribution of such executables.
+
+ When a "work that uses the Library" uses material from a header file
+ that is part of the Library, the object code for the work may be a
+ derivative work of the Library even though the source code is not.
+ Whether this is true is especially significant if the work can be
+ linked without the Library, or if the work is itself a library. The
+ threshold for this to be true is not precisely defined by law.
+
+ If such an object file uses only numerical parameters, data
+ structure layouts and accessors, and small macros and small inline
+ functions (ten lines or less in length), then the use of the object
+ file is unrestricted, regardless of whether it is legally a derivative
+ work. (Executables containing this object code plus portions of the
+ Library will still fall under Section 6.)
+
+ Otherwise, if the work is a derivative of the Library, you may
+ distribute the object code for the work under the terms of Section 6.
+ Any executables containing that work also fall under Section 6,
+ whether or not they are linked directly with the Library itself.
+
+ 6. As an exception to the Sections above, you may also combine or
+ link a "work that uses the Library" with the Library to produce a
+ work containing portions of the Library, and distribute that work
+ under terms of your choice, provided that the terms permit
+ modification of the work for the customer's own use and reverse
+ engineering for debugging such modifications.
+
+ You must give prominent notice with each copy of the work that the
+ Library is used in it and that the Library and its use are covered by
+ this License. You must supply a copy of this License. If the work
+ during execution displays copyright notices, you must include the
+ copyright notice for the Library among them, as well as a reference
+ directing the user to the copy of this License. Also, you must do one
+ of these things:
+
+ a) Accompany the work with the complete corresponding
+ machine-readable source code for the Library including whatever
+ changes were used in the work (which must be distributed under
+ Sections 1 and 2 above); and, if the work is an executable linked
+ with the Library, with the complete machine-readable "work that
+ uses the Library", as object code and/or source code, so that the
+ user can modify the Library and then relink to produce a modified
+ executable containing the modified Library. (It is understood
+ that the user who changes the contents of definitions files in the
+ Library will not necessarily be able to recompile the application
+ to use the modified definitions.)
+
+ b) Use a suitable shared library mechanism for linking with the
+ Library. A suitable mechanism is one that (1) uses at run time a
+ copy of the library already present on the user's computer system,
+ rather than copying library functions into the executable, and (2)
+ will operate properly with a modified version of the library, if
+ the user installs one, as long as the modified version is
+ interface-compatible with the version that the work was made with.
+
+ c) Accompany the work with a written offer, valid for at
+ least three years, to give the same user the materials
+ specified in Subsection 6a, above, for a charge no more
+ than the cost of performing this distribution.
+
+ d) If distribution of the work is made by offering access to copy
+ from a designated place, offer equivalent access to copy the above
+ specified materials from the same place.
+
+ e) Verify that the user has already received a copy of these
+ materials or that you have already sent this user a copy.
+
+ For an executable, the required form of the "work that uses the
+ Library" must include any data and utility programs needed for
+ reproducing the executable from it. However, as a special exception,
+ the materials to be distributed need not include anything that is
+ normally distributed (in either source or binary form) with the major
+ components (compiler, kernel, and so on) of the operating system on
+ which the executable runs, unless that component itself accompanies
+ the executable.
+
+ It may happen that this requirement contradicts the license
+ restrictions of other proprietary libraries that do not normally
+ accompany the operating system. Such a contradiction means you cannot
+ use both them and the Library together in an executable that you
+ distribute.
+
+ 7. You may place library facilities that are a work based on the
+ Library side-by-side in a single library together with other library
+ facilities not covered by this License, and distribute such a combined
+ library, provided that the separate distribution of the work based on
+ the Library and of the other library facilities is otherwise
+ permitted, and provided that you do these two things:
+
+ a) Accompany the combined library with a copy of the same work
+ based on the Library, uncombined with any other library
+ facilities. This must be distributed under the terms of the
+ Sections above.
+
+ b) Give prominent notice with the combined library of the fact
+ that part of it is a work based on the Library, and explaining
+ where to find the accompanying uncombined form of the same work.
+
+ 8. You may not copy, modify, sublicense, link with, or distribute
+ the Library except as expressly provided under this License. Any
+ attempt otherwise to copy, modify, sublicense, link with, or
+ distribute the Library is void, and will automatically terminate your
+ rights under this License. However, parties who have received copies,
+ or rights, from you under this License will not have their licenses
+ terminated so long as such parties remain in full compliance.
+
+ 9. You are not required to accept this License, since you have not
+ signed it. However, nothing else grants you permission to modify or
+ distribute the Library or its derivative works. These actions are
+ prohibited by law if you do not accept this License. Therefore, by
+ modifying or distributing the Library (or any work based on the
+ Library), you indicate your acceptance of this License to do so, and
+ all its terms and conditions for copying, distributing or modifying
+ the Library or works based on it.
+
+ 10. Each time you redistribute the Library (or any work based on the
+ Library), the recipient automatically receives a license from the
+ original licensor to copy, distribute, link with or modify the Library
+ subject to these terms and conditions. You may not impose any further
+ restrictions on the recipients' exercise of the rights granted herein.
+ You are not responsible for enforcing compliance by third parties with
+ this License.
+
+ 11. If, as a consequence of a court judgment or allegation of patent
+ infringement or for any other reason (not limited to patent issues),
+ conditions are imposed on you (whether by court order, agreement or
+ otherwise) that contradict the conditions of this License, they do not
+ excuse you from the conditions of this License. If you cannot
+ distribute so as to satisfy simultaneously your obligations under this
+ License and any other pertinent obligations, then as a consequence you
+ may not distribute the Library at all. For example, if a patent
+ license would not permit royalty-free redistribution of the Library by
+ all those who receive copies directly or indirectly through you, then
+ the only way you could satisfy both it and this License would be to
+ refrain entirely from distribution of the Library.
+
+ If any portion of this section is held invalid or unenforceable under any
+ particular circumstance, the balance of the section is intended to apply,
+ and the section as a whole is intended to apply in other circumstances.
+
+ It is not the purpose of this section to induce you to infringe any
+ patents or other property right claims or to contest validity of any
+ such claims; this section has the sole purpose of protecting the
+ integrity of the free software distribution system which is
+ implemented by public license practices. Many people have made
+ generous contributions to the wide range of software distributed
+ through that system in reliance on consistent application of that
+ system; it is up to the author/donor to decide if he or she is willing
+ to distribute software through any other system and a licensee cannot
+ impose that choice.
+
+ This section is intended to make thoroughly clear what is believed to
+ be a consequence of the rest of this License.
+
+ 12. If the distribution and/or use of the Library is restricted in
+ certain countries either by patents or by copyrighted interfaces, the
+ original copyright holder who places the Library under this License may add
+ an explicit geographical distribution limitation excluding those countries,
+ so that distribution is permitted only in or among countries not thus
+ excluded. In such case, this License incorporates the limitation as if
+ written in the body of this License.
+
+ 13. The Free Software Foundation may publish revised and/or new
+ versions of the Lesser General Public License from time to time.
+ Such new versions will be similar in spirit to the present version,
+ but may differ in detail to address new problems or concerns.
+
+ Each version is given a distinguishing version number. If the Library
+ specifies a version number of this License which applies to it and
+ "any later version", you have the option of following the terms and
+ conditions either of that version or of any later version published by
+ the Free Software Foundation. If the Library does not specify a
+ license version number, you may choose any version ever published by
+ the Free Software Foundation.
+
+ 14. If you wish to incorporate parts of the Library into other free
+ programs whose distribution conditions are incompatible with these,
+ write to the author to ask for permission. For software which is
+ copyrighted by the Free Software Foundation, write to the Free
+ Software Foundation; we sometimes make exceptions for this. Our
+ decision will be guided by the two goals of preserving the free status
+ of all derivatives of our free software and of promoting the sharing
+ and reuse of software generally.
+
+ NO WARRANTY
+
+ 15. BECAUSE THE LIBRARY IS LICENSED FREE OF CHARGE, THERE IS NO
+ WARRANTY FOR THE LIBRARY, TO THE EXTENT PERMITTED BY APPLICABLE LAW.
+ EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR
+ OTHER PARTIES PROVIDE THE LIBRARY "AS IS" WITHOUT WARRANTY OF ANY
+ KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE
+ IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE
+ LIBRARY IS WITH YOU. SHOULD THE LIBRARY PROVE DEFECTIVE, YOU ASSUME
+ THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION.
+
+ 16. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN
+ WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY
+ AND/OR REDISTRIBUTE THE LIBRARY AS PERMITTED ABOVE, BE LIABLE TO YOU
+ FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR
+ CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE
+ LIBRARY (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING
+ RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A
+ FAILURE OF THE LIBRARY TO OPERATE WITH ANY OTHER SOFTWARE), EVEN IF
+ SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
+ DAMAGES.
+
+ END OF TERMS AND CONDITIONS
+
+ How to Apply These Terms to Your New Libraries
+
+ If you develop a new library, and you want it to be of the greatest
+ possible use to the public, we recommend making it free software that
+ everyone can redistribute and change. You can do so by permitting
+ redistribution under these terms (or, alternatively, under the terms of the
+ ordinary General Public License).
+
+ To apply these terms, attach the following notices to the library. It is
+ safest to attach them to the start of each source file to most effectively
+ convey the exclusion of warranty; and each file should have at least the
+ "copyright" line and a pointer to where the full notice is found.
+
+ <one line to give the library's name and a brief idea of what it does.>
+ Copyright (C) <year> <name of author>
+
+ This library is free software; you can 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.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with this library; if not, write to the Free Software
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+
+ Also add information on how to contact you by electronic and paper mail.
+
+ You should also get your employer (if you work as a programmer) or your
+ school, if any, to sign a "copyright disclaimer" for the library, if
+ necessary. Here is a sample; alter the names:
+
+ Yoyodyne, Inc., hereby disclaims all copyright interest in the
+ library `Frob' (a library for tweaking knobs) written by James Random Hacker.
+
+ <signature of Ty Coon>, 1 April 1990
+ Ty Coon, President of Vice
+
+ That's all there is to it!
+ </pre>
+
<hr>
<address>
<title>deal.II Communications</title>
<link href="screen.css" rel="StyleSheet">
<meta name="author" content="the deal.II authors <authors at dealii.org>">
- <meta name="copyright" content="Copyright (C) 2001, 2002, 2003, 2004, 2005, 2006, 2008, 2011, 2012 by the deal.II authors">
+ <meta name="copyright" content="Copyright (C) 2001, 2002, 2003, 2004, 2005, 2006, 2008, 2011, 2012, 2013 by the deal.II authors">
<meta name="date" content="$Date$">
<meta name="svn_id" content="$Id$">
<meta name="keywords" content="deal.II">
<p>
All <acronym>deal.II</acronym> users (and everybody interested)
are encouraged to join the <acronym>deal.II</acronym>
- Discussion group on Google Groups.
+ Discussion Group on Google Groups.
</p>
<ul>
<li>
the
the <a href="https://groups.google.com/d/forum/dealii">deal.II
Discussion Group page</a> and click on the corresponding
- button (preferred), or you can send email
+ button, or you can send email
to <a href="mailto:dealii@googlegroups.com">dealii@googlegroups.com</a>. Or
just post from the window below. Note that you have to be a
group member with your specific sender address in order to be
flaming them on missing items) should be sent to one of
<ul>
<li>
- <b>authors</b> at <b>dealii.org</b>
+ TODO
</li>
<li>
- <b>Wolfgang.Bangerth</b> at <b>dealii.org</b>
+ Wolfgang Bangerth < bangerth@gmail.com >
</li>
<li>
- <b>Timo.Heister</b> at <b>dealii.org</b>
+ Timo Heister < heister@math.tamu.edu >
</li>
<li>
- <b>Guido.Kanschat</b> at <b>dealii.org</b>
+ Guido Kanschat < dr.guido.kanschat@gmail.com >
</li>
</ul>
Everything, that is not directly related to the library is to be considered
<p>
<a href="index.html" target="_top">Home</a><br />
- <a href="http://www.dealii.org"target="_top"><tt>dealii.org</tt></a><br />
+ <a href="http://www.dealii.org"target="_top">dealii.org</a><br />
+ <a href="readme.html" target="body">README</a><br />
+ </p>
+
+ <hr>
+
+ <p>
+ <a href="doxygen/tutorial/index.html" target="_top">Tutorial</a><br />
+ <a href="doxygen/deal.II/index.html" target="_top">Manual</a><br />
+ <a href="http://www.math.tamu.edu/~bangerth/videos.html"
+ target="_top">Video lectures</a><br />
</p>
<hr>
<p>
- <a href="readme.html" target="body">README</a><br />
<a href="https://code.google.com/p/dealii/wiki/FrequentlyAskedQuestions" target="_top">FAQ</a><br />
<a href="news/news.html" target="body">News</a><br />
<a href="http://www.dealii.org/download/" target="body">Download</a><br />
<hr>
- <p>
- <a href="doxygen/tutorial/index.html" target="_top">Tutorial</a><br />
- <a href="doxygen/deal.II/index.html" target="_top">Manual</a><br />
- </p>
-
- <hr>
-
<p>
<a href="development/index.html" target="_top">Development</a><br />
<a href="publications/index.html" target="body">Publications</a><br />
<ol>
+
+ <li> New: All vector classes now have a member function
+ <code>locally_owned_elements</code> that returns an index
+ set indicating which elements of this vector the current
+ processor owns.
+ <br>
+ (Wolfgang Bangerth, 2013/05/24)
+ </li>
+
+
+ <li> New: A new element FE_Q_iso_Q1 has been implemented that is defined by
+ a subdivision of the element into smaller Q1 elements. An element of order
+ @p p is similar to FE_Q of degree @p p with the same numbering of degrees of
+ freedom. The element is useful e.g. for defining a sparser preconditioner
+ matrix for AMG at higher order FE_Q elements or for representing a component
+ of a system of PDEs where higher resolution is preferred over high order.
+ <br>
+ (Martin Kronbichler, 2013/05/14)
+ </li>
+
<li> New: The step-49 tutorial program now also has a discussion on
what to do once you have a coarse mesh and want to refine it.
<br>
<h3>Specific improvements</h3>
<ol>
+<li> New: ConstraintMatrix::distribute is now also implemented for
+arguments of type PETScWrappers::MPI::BlockVector.
+<br>
+(Wolfgang Bangerth, 2013/05/25)
+</li>
+
+<li> Fixed: IndexSet::operator== returned the wrong results
+in some cases.
+<br>
+(Wolfgang Bangerth, 2013/05/25)
+</li>
+
+<li> New: The global function <code>complete_index_set()</code>
+creates and returns an index set of given size that contains
+every single index with this range.
+<br>
+(Wolfgang Bangerth, 2013/05/24)
+</li>
+
+<li> New: All vector classes now have a static member variable
+<code>supports_distributed_data</code> that indicates whether the
+vector class supports data that is distributed across multiple
+processors. This variable is provided as a <i>traits variable</i>
+to allow generic algorithms working on general vector types to
+query the capabilities of the vector class at compile time.
+<br>
+(Wolfgang Bangerth, 2013/05/23)
+</li>
+
+<li> Fixed: FETools::back_interpolate has been revised to work correctly
+also with parallel::distributed::Vector.
+<br>
+(Martin Steigemann, 2013/05/23)
+</li>
+
+<li> Removed: The file <code>mesh_worker/vector_info.h</code> was unused and
+untested. It has thus been removed.
+<br>
+(Wolfgang Bangerth, Guido Kanschat, 2013/05/21)
+</li>
+
+<li> Fixed: The method parallel::distributed::Vector::compress
+(VectorOperation::insert) previously set the elements of ghost elements
+unconditionally on the owning processor, even if they had not been touched.
+This led to a problem in certain library functions where vector entries became
+zero in a spurious way. This is now fixed by discarding the elements in ghost
+entries for the VectorOperation::insert operation. This is legitimate since we
+assume consistency of set elements across processors, so the owning processor
+sets the element already.
+<br>
+(Martin Kronbichler, 2013/05/21)
+</li>
+
+<li> Improved: DoFTools::make_periodicity_constraints now also works
+for meshes where the refinement level of the two sides of the domain
+is not the same, i.e., one side is more refined than the other.
+<br>
+(Wolfgang Bangerth, 2013/05/20)
+</li>
+
+<li> Improved: Through the fields DataOutBase::VtkFlags::time and
+DataOutBase::VtkFlags::cycle, it is now possible to encode the time and/or
+cycle within a nonlinear or other iteration in VTK and VTU files written
+via DataOutBase::write_vtk and DataOutBase::write_vtu.
+<br>
+(Wolfgang Bangerth, 2013/05/12)
+</li>
+
+<li> Fixed: The method ConvergenceTable::evaluate_convergence_rates with
+ reference column did not take the dimension of the reference column into
+ account, leading to wrong logarithmic rates for dim!=2. This can now be fixed
+ by specifying the dimension as a last argument.
+<br>
+(Martin Kronbichler, 2013/05/10)
+</li>
+
+<li> Improved: The functions MatrixTools::create_mass_matrix and
+MatrixTools::create_laplace_matrix take now an optional ConstraintMatrix
+argument that allows to directly apply the constraints. This also helps
+VectorTools::project. Note that not providing constraints remains the default
+and recommended way to ensure consistency when several matrices are combined.
+<br>
+(Martin Kronbichler, 2013/05/08)
+</li>
+
+<li> New: The classes TrilinosWrappers::SparseMatrix and
+TrilinosWrappers::BlockSparseMatrix now fully implement vmult and Tvmult with
+deal.II's own vector classes Vector<double> and
+parallel::distributed::Vector<double>.
+<br>
+(Martin Kronbichler, 2013/05/08)
+</li>
+
+<li> Improved: The matrix-vector product ChunkSparseMatrix::vmult now runs in
+parallel in shared memory.
+<br>
+(Martin Kronbichler, 2013/05/07)
+</li>
+
+<li> New: The class ChunkSparseMatrix and the associated
+ChunkSparsityPattern now offer iterator classes to iterate over rows of the
+matrix in an STL-like way.
+<br>
+(Martin Kronbichler, 2013/05/07)
+</li>
+
+<li> Fixed: The stopping criterion for early exit in SolverBicgstab did not
+work properly for systems with large values, leading to premature exit. This
+is now fixed.
+<br>
+(Martin Kronbichler, 2013/05/07)
+</li>
+
+<li> Changed: The SolverGMRES implementation previously applied two
+iterations of the modified Gram–Schmidt algorithm for
+orthogonalization. In many situations one iteration is enough. The algorithm
+can now detect loss of orthogonality and enables re-orthogonalization only if
+necessary. The second iteration (and, hence, old behavior) can be forced by
+the flag SolverGMRES::AdditionalData::force_re_orthogonalization.
+<br>
+(Martin Kronbichler, 2013/05/06)
+</li>
+
+<li> Changed: FETools::interpolate is now instantiated for all
+vector types, not just dealii::Vector and dealii::BlockVector.
+<br>
+(Wolfgang Bangerth, 2013/05/06)
+</li>
+
+<li> Fixed: setting values in TrilinosWrappers::SparseMatrix
+in parallel was adding the values instead.
+<br>
+(Bruno Turcksin, Timo Heister, 2013/05/03)
+</li>
+
+<li> Fixed: Generate an error if the user tries to refine a cell
+that is already on the maximum level in a distributed triangulation.
+<br>
+(Timo Heister, 2013/05/01)
+</li>
+
+<li> Fixed: The version of ParameterHandler::set that takes a boolean
+as second argument was broken and did not work. This is now fixed.
+<br>
+(Ashkan Dorostkar, Wolfgang Bangerth, 2013/04/30)
+</li>
<li> Fixed: PETScWrappers::VectorBase::print now saves and restores
the precision
(Guido Kanschat, 2013/03/21)
</li>
-<li> Added GridOut::write_svg to allow for the output of two-dimensional
-triangulations in two space dimensions in the SVG format (Scalable Vector
-Graphics, an XML-based vector image format recommended by the World
-Wide Web Consortium W3C). This function also provides cell coloring
-and cell labeling for the visualization of basic cell properties.
+<li> Added GridOut::write_svg() to allow for the output of
+two-dimensional triangulations in two space dimensions in the SVG
+format (Scalable Vector Graphics, an generic XML-based vector image
+format developed and maintained by the World Wide Web Consortium W3C).
+This function also provides cell coloring and cell labeling for the
+visualization of basic cell properties. Pespective view is further
+possible and the cell level number may be converted into altitude,
+revealing the inactive cells lying below.
<br>
(Christian Wülker, 2013/03/21)
+</li>
<li> Added TimerOutput::reset to remove the collected information so far and
added a new frequency TimerOutput::never to only output information if
(Timo Heister, 2013/03/01)
</li>
+<li> Added DataOutBase::write_svg() to allow for the output of a given
+list of patches in two space dimensions in the SVG format (Scalable Vector
+Graphics, an generic XML-based vector image format developed and maintained
+by the World Wide Web Consortium W3C). An additional dimension (z-direction)
+is employed for the visualization of data values taken from a data vector.
+This function also provides patch coloring for the visual enhancement.
+<br>
+(Christian Wülker, 2013/05/10)
+</li>
+
</ol>
@Manual{DealIIReference,
title = {{\tt deal.{I}{I}} Differential Equations Analysis Library,
Technical Reference},
- author = {W. Bangerth and T. Heister and G. Kanschat},
+ author = {W. Bangerth and T. Heister and G. Kanschat and others},
note = {\texttt{http://www.dealii.org}},
url = {http://www.dealii.org}
}</pre>
<!-- http://www.math.kit.edu/ianm2/~doerfler/seite/pub/de -->
</li>
+ <li> K. Dugan
+ <br>
+ <strong>Dynamic adaptive multimesh refinement for coupled
+ physics applicable to nuclear engineering
+ </strong>
+ <br>
+ MSc thesis, Texas A&M University, 2013.
+ </li>
+
<li> Y. Efendiev, J. Galvis, S. Pauletti
<br>
<strong>Multiscale finite element methods for flows on rough
Series, pp. 79-86, 2013.
</li>
+ <li> J. Reinhardt, F. Weysser, J. M. Brader
+ <br>
+ <strong>Density functional approach to nonlinear rheology</strong>
+ <br>
+ Europhysics Letters, vol. 102, article 28011, 2013.
+ </li>
+
<li> S. Rudraraju, K. L. Mills, R. Kemkemer, K. Garikipati
<br>
<strong>Multiphysics Modeling of Reactions, Mass Transport and Mechanics of Tumor Growth
(eds.), Spinger Verlag, pp. 293-303, 2013.
</li>
+ <li> N. Vakulin, R. Shaw, T. Livingston
+ <br>
+ <strong>ELEC 490, final report: High performance computing with GPUs
+ </strong>
+ <br>
+ Semester project for ELEC 490, final report. Queen's University,
+ 2013
+ </li>
+
<li> S. Yoon, Y. T. Kang
<br>
<strong>Mass transfer enhancement in non-Brownian particle
<h2>License</h2>
<p>
- We have placed <acronym>deal.II</acronym> under an <a
- href="http://www.opensource.org" target="_top">Open Source</a>
- license, which allows you to use the library free of charge. You
- are guaranteed full access to the source code and are encouraged
- to help in the further development of the library. Follow <a
- href="license.html" target="body">this link</a> to read the full
- text of the license,
+ The deal.II library is free software; you can use it, redistribute
+ it, and/or modify it under the terms of the
+ <a href="http://www.gnu.org/licenses/lgpl-2.1.html">GNU Lesser General
+ Public License</a> (LGPL) as published by the Free Software
+ Foundation; either version 2.1 of the License, or (at your option)
+ any later version.
+ </p>
+ <p>
+ This allows you to use the library free of charge for private,
+ academic, or commercial use (under the terms of the LGPL v2.1 or
+ later). You are guaranteed full access to the source code and are
+ encouraged to help in the further development of the library. Follow
+ <a href="license.html" target="body">this link</a> for detailed
+ information.
</p>
-
<p>
- The basics of the license are in short:
+ Please note:
<ul>
<li>
- The library comes free of charge for all users, but
- we keep a copyright in it. We will grant everyone access to
- the library and its source code, provided they keep to the
- <a href="license.html" target="body">license</a>.
-
+ Detailed license information can be found following
+ <a href="license.html" target="body">this link</a>.
<li>
- The libraries may not be stripped of our copyright. We would
- appreciate being contacted if you want to use the library
- commercially.
-
+ <b>As a contributor to this project, you agree that any of your
+ contributions be licensed under the same terms and conditions as
+ the license of the deal.II project granted to you.</b>
+ <li>
+ We, <a href="authors.html">the deal.II authors</a>, do not require
+ copyright assignments for contributions. This means that the
+ copyright for code contributions in the deal.II project is held by
+ its respective contributors who have each agreed to release their
+ contributed code under the terms of the LGPL v2.1 or later.
+ <li>
+ In addition to the terms imposed by the LGPL (version 2.1 or
+ later), we ask for the courtesy that scientific publications
+ presenting results obtained with this libraries acknowledge its
+ use. Please cite one of the papers referenced
+ <a href="publications/index.html">here</a>.
<li>
- We ask that scientific publications presenting results obtained with this
- libraries acknowledge its use. Please cite one of the papers referenced
- <a href="publications/index.html">here</a>.
+ <acronym>deal.II</acronym> can interface with a number of <a
+ href="#optional-software">other packages</a> that you either
+ have to install yourself. They are, of course, covered by their
+ own licenses. In addition, deal.II comes bundled with copies of
+ <a href="http://www.cise.ufl.edu/research/sparse/umfpack/"
+ target="_top">UMFPACK</a>,
+ <a href="http://threadingbuildingblocks.org/"
+ target="_top">Threading Building Blocks</a>,
+ <a href="http://www.boost.org/" target="_top">BOOST</a> and
+ <a href="http://warp.povusers.org/FunctionParser/"
+ target="_top">FunctionParser</a>, courtesy of their authors.
+ These are also covered by their own licenses; please refer to
+ their webpages for more information.
</ul>
- <p>
- <acronym>deal.II</acronym> can interface with a number of
- <a href="#optional-software">other packages</a> that you have to install
- yourself. They are, of course, covered by their own licenses. In addition,
- deal.II comes bundled with copies of
- <a href="http://www.cise.ufl.edu/research/sparse/umfpack/"
- target="_top">UMFPACK</a>,
- <a href="http://threadingbuildingblocks.org/"
- target="_top">Threading Building Blocks</a>,
- <a href="http://www.boost.org/" target="_top">BOOST</a>
- and
- <a href="http://warp.povusers.org/FunctionParser/" target="_top">FunctionParser</a>,
- courtesy of their authors. These are also covered by their
- own licenses; please refer to their webpages for more information.
-
<hr>
<address>
#include <deal.II/base/logstream.h>
#include <deal.II/lac/vector.h>
#include <deal.II/lac/full_matrix.h>
+#include <deal.II/lac/compressed_sparsity_pattern.h>
#include <deal.II/lac/sparse_matrix.h>
#include <deal.II/lac/solver_cg.h>
#include <deal.II/lac/precondition.h>
template<int dim>
void HeatEquation<dim>::setup_system()
{
-//TODO: we need to take care of constraints here! :-)
-
dof_handler.distribute_dofs(fe);
std::cout << std::endl
<< std::endl
<< std::endl;
- sparsity_pattern.reinit(dof_handler.n_dofs(),
- dof_handler.n_dofs(),
- dof_handler.max_couplings_between_dofs());
+ constraints.clear ();
+ DoFTools::make_hanging_node_constraints (dof_handler,
+ constraints);
+ constraints.close();
+
+ CompressedSparsityPattern c_sparsity(dof_handler.n_dofs());
DoFTools::make_sparsity_pattern(dof_handler,
- sparsity_pattern);
- sparsity_pattern.compress();
+ c_sparsity,
+ constraints,
+ /*keep_constrained_dofs = */ true);
+ sparsity_pattern.copy_from(c_sparsity);
mass_matrix.reinit(sparsity_pattern);
laplace_matrix.reinit(sparsity_pattern);
MatrixCreator::create_mass_matrix(dof_handler,
QGauss<dim>(fe.degree+1),
- mass_matrix);
+ mass_matrix,
+ (const Function<dim>*)0,
+ constraints);
MatrixCreator::create_laplace_matrix(dof_handler,
QGauss<dim>(fe.degree+1),
- laplace_matrix);
+ laplace_matrix,
+ (const Function<dim>*)0,
+ constraints);
solution.reinit(dof_handler.n_dofs());
old_solution.reinit(dof_handler.n_dofs());
system_rhs.reinit(dof_handler.n_dofs());
-
- constraints.close();
}
cg.solve(system_matrix, solution, system_rhs, preconditioner);
+ constraints.distribute(solution);
+
std::cout << " " << solver_control.last_step()
<< " CG iterations." << std::endl;
}
template<int dim>
void HeatEquation<dim>::run()
{
- const unsigned int initial_global_refinement = (dim == 2 ? 4 : 2);
- const unsigned int n_adaptive_pre_refinement_steps = 3;
+ const unsigned int initial_global_refinement = (dim == 2 ? 1 : 2);
+ const unsigned int n_adaptive_pre_refinement_steps = 1;
GridGenerator::hyper_L (triangulation);
triangulation.refine_global (initial_global_refinement);
system_rhs);
}
+ constraints.condense (system_rhs);
+
solve_time_step();
output_results();
{
pcout << "Read the obstacle from a file." << std::endl;
input_obstacle.reset (new Input<dim>("obstacle_file.pbm"));
- pcout << "Ostacle is available now." << std::endl;
+ pcout << "Obstacle is available now." << std::endl;
}
const unsigned int n_cycles = 6;
/* $Id$ */
/* */
-/* Copyright (C) 2011-2012 by the deal.II authors */
+/* Copyright (C) 2011-2013 by the deal.II authors */
/* */
/* This file is subject to QPL and may not be distributed */
/* without copyright and license information. Please refer */
// @sect3{The <code>main</code> function}
-// This is as in all other programs:
+// As in step-40, we initialize MPI at the start of the program. Since we will
+// in general mix MPI parallelization with threads, we also set the third
+// argument in MPI_InitFinalize that controls the number of threads to an
+// invalid number, which means that the TBB library chooses the number of
+// threads automatically, typically to the number of available cores in the
+// system. As an alternative, you can also set this number manually if you
+// want to set a specific number of threads (e.g. when MPI-only is required).
int main (int argc, char **argv)
{
using namespace Step48;
using namespace dealii;
- Utilities::System::MPI_InitFinalize mpi_initialization(argc, argv);
+ Utilities::System::MPI_InitFinalize mpi_initialization(argc, argv,
+ numbers::invalid_unsigned_int);
try
{
--- /dev/null
+##
+# CMake script for the step-32 tutorial program:
+##
+
+# Set the name of the project and target:
+SET(TARGET "step-50")
+
+# Declare all source files the target consists of:
+SET(TARGET_SRC
+ ${TARGET}.cc
+ # You can specify additional files here!
+ )
+
+# A custom command line to run the program
+SET(TARGET_RUN mpirun -np 2 ${TARGET})
+
+# Define the output that should be cleaned:
+SET(CLEAN_UP_FILES *.vtu *.pvtu *.visit)
+
+# Usually, you will not need to modify anything beyond this point...
+
+CMAKE_MINIMUM_REQUIRED(VERSION 2.8.8)
+
+FIND_PACKAGE(deal.II 8.0 QUIET
+ HINTS ${deal.II_DIR} ${DEAL_II_DIR} ../ ../../ $ENV{DEAL_II_DIR}
+ )
+IF(NOT ${deal.II_FOUND})
+ MESSAGE(FATAL_ERROR "\n"
+ "*** Could not locate deal.II. ***\n\n"
+ "You may want to either pass a flag -DDEAL_II_DIR=/path/to/deal.II to cmake\n"
+ "or set an environment variable \"DEAL_II_DIR\" that contains this path."
+ )
+ENDIF()
+
+#
+# Are all dependencies fullfilled?
+#
+IF( NOT DEAL_II_WITH_MPI OR
+ NOT DEAL_II_WITH_P4EST OR
+ NOT DEAL_II_WITH_TRILINOS )
+ MESSAGE(FATAL_ERROR "
+Error! The deal.II library found at ${DEAL_II_PATH} was not configured with
+ DEAL_II_WITH_MPI = ON
+ DEAL_II_WITH_P4EST = ON
+ DEAL_II_WITH_TRILINOS = ON
+which is required for this tutorial step."
+ )
+ENDIF()
+
+DEAL_II_INITIALIZE_CACHED_VARIABLES()
+PROJECT(${TARGET})
+DEAL_II_INVOKE_AUTOPILOT()
/* to the file deal.II/doc/license.html for the text and */
/* further information on this license. */
+// parallel geometric multi-grid. work in progress!
+
// As discussed in the introduction, most of
// this program is copied almost verbatim
// from step-6, which itself is only a slight
#include <deal.II/grid/tria_accessor.h>
#include <deal.II/grid/tria_iterator.h>
#include <deal.II/grid/grid_generator.h>
+#include <deal.II/grid/grid_out.h>
#include <deal.II/grid/grid_refinement.h>
#include <deal.II/grid/tria_boundary_lib.h>
typedef TrilinosWrappers::SparseMatrix matrix_t;
typedef TrilinosWrappers::MPI::Vector vector_t;
- SparsityPattern sparsity_pattern;
matrix_t system_matrix;
// We need an additional object for the
// transpose of the other, and so we only
// have to build one; we choose the one
// from coarse to fine.
- MGLevelObject<SparsityPattern> mg_sparsity_patterns;
MGLevelObject<matrix_t> mg_matrices;
MGLevelObject<matrix_t> mg_interface_matrices;
MGConstrainedDoFs mg_constrained_dofs;
LaplaceProblem<dim>::LaplaceProblem (const unsigned int degree)
:
triangulation (MPI_COMM_WORLD,Triangulation<dim>::
- limit_level_difference_at_vertices),
+ limit_level_difference_at_vertices,
+ parallel::distributed::Triangulation<dim>::construct_multigrid_hierarchy),
fe (degree),
mg_dof_handler (triangulation),
degree(degree)
template <int dim>
void LaplaceProblem<dim>::setup_system ()
{
+ std::string filename = "grid-"
+ + Utilities::int_to_string(triangulation.n_levels(), 2)
+ + "-"
+ + Utilities::int_to_string (Utilities::MPI::this_mpi_process(MPI_COMM_WORLD), 3)
+ + ".svg";
+
+ std::ofstream out (filename.c_str());
+ GridOut grid_out;
+ GridOutFlags::Svg svg_flags;
+ svg_flags.polar_angle = 60;
+ svg_flags.label_level_subdomain_id = true;
+ svg_flags.convert_level_number_to_height = true;
+ grid_out.set_flags(svg_flags);
+ grid_out.write_svg (triangulation, out);
+
mg_dof_handler.distribute_dofs (fe);
mg_dof_handler.distribute_mg_dofs (fe);
<< mg_dof_handler.n_dofs(l);
deallog << std::endl;
- sparsity_pattern.reinit (mg_dof_handler.n_dofs(),
- mg_dof_handler.n_dofs(),
- mg_dof_handler.max_couplings_between_dofs());
- DoFTools::make_sparsity_pattern (mg_dof_handler, sparsity_pattern);
-
//solution.reinit (mg_dof_handler.n_dofs());
//system_rhs.reinit (mg_dof_handler.n_dofs());
constraints);
constraints.close ();
hanging_node_constraints.close ();
- constraints.condense (sparsity_pattern);
- sparsity_pattern.compress();
- system_matrix.reinit (sparsity_pattern);
+
+ CompressedSimpleSparsityPattern csp(mg_dof_handler.n_dofs(), mg_dof_handler.n_dofs());
+ DoFTools::make_sparsity_pattern (mg_dof_handler, csp, constraints);
+ system_matrix.reinit (mg_dof_handler.locally_owned_dofs(), csp, MPI_COMM_WORLD, true);
// The multigrid constraints have to be
// initialized. They need to know about
mg_interface_matrices.clear ();
mg_matrices.resize(0, n_levels-1);
mg_matrices.clear ();
- mg_sparsity_patterns.resize(0, n_levels-1);
// Now, we have to provide a matrix on each
// level. To this end, we first use the
mg_dof_handler.n_dofs(level));
MGTools::make_sparsity_pattern(mg_dof_handler, csp, level);
- mg_sparsity_patterns[level].copy_from (csp);
-
- mg_matrices[level].reinit(mg_sparsity_patterns[level]);
- mg_interface_matrices[level].reinit(mg_sparsity_patterns[level]);
+ mg_matrices[level].reinit(mg_dof_handler.locally_owned_mg_dofs(level),
+ mg_dof_handler.locally_owned_mg_dofs(level),
+ csp,
+ MPI_COMM_WORLD, true);
}
}
if (cycle == 0)
{
- GridGenerator::hyper_ball (triangulation);
+ GridGenerator::hyper_cube (triangulation);
- static const HyperBallBoundary<dim> boundary;
- triangulation.set_boundary (0, boundary);
+ // static const HyperBallBoundary<dim> boundary;
+ // triangulation.set_boundary (0, boundary);
- triangulation.refine_global (1);
+ triangulation.refine_global (2);
}
else
refine_grid ();
*/
none,
/**
- * Quotient of values in
- * the previous row and in
- * this row.
+ * Quotient of values in the previous row and in this row.
*/
reduction_rate,
/**
- * Logarithm of
- * #reduction_rate to the
- * base 2 representing the
- * order of convergence
- * when halving the grid
- * size, e.g. from h to
- * h/2.
+ * Logarithm of #reduction_rate to the base 2 representing the order of
+ * convergence when halving the grid size, e.g. from h to h/2.
*/
reduction_rate_log2
};
/**
- * Evaluates the convergence rates of the
- * data column <tt>data_column_key</tt>
- * due to the #RateMode in relation to
- * the reference column <tt>reference_column_key</tt>.
- * Be sure that the value types of the
- * table entries of the
- * data column and the reference data column
- * is a number, i.e. double, float,
- * (unsigned) int, and so on.
+ * Evaluates the convergence rates of the data column
+ * <tt>data_column_key</tt> due to the #RateMode in relation to the
+ * reference column <tt>reference_column_key</tt>. Be sure that the value
+ * types of the table entries of the data column and the reference data
+ * column is a number, i.e. double, float, (unsigned) int, and so on.
*
- * The new rate column and the data column
- * will be merged to a supercolumn. The
- * tex caption of the supercolumn will be
- * (by default) the same as the one of the
- * data column. This may be changed by using
- * the <tt>set_tex_supercaption (...)</tt> function
- * of the base class TableHandler.
+ * As this class has no information on the space dimension upon which the
+ * reference column vs. the value column is based upon, it needs to be
+ * passed as last argument to this method. The <i>default dimension for the
+ * reference column</i> is 2, which is appropriate for the number of cells
+ * in 2D. If you work in 3D, set the number to 3. If the reference column is
+ * $1/h$, remember to set the dimension to 1 also when working in 3D to get
+ * correct rates.
*
- * This method behaves in the following way:
+ * The new rate column and the data column will be merged to a
+ * supercolumn. The tex caption of the supercolumn will be (by default) the
+ * same as the one of the data column. This may be changed by using the
+ * <tt>set_tex_supercaption (...)</tt> function of the base class
+ * TableHandler.
*
- * If RateMode is reduction_rate, then the computed
- * output is
- * $ \frac{e_{n-1}/k_{n-1}}{e_n/k_n} $.
+ * This method behaves in the following way:
*
- * Where $k$ is the reference column.
+ * If RateMode is reduction_rate, then the computed output is
+ * $ \frac{e_{n-1}/k_{n-1}}{e_n/k_n}, $
+ * where $k$ is the reference column (no dimension dependence!).
*
- * If RateMode is reduction_rate_log2, then the
- * computed output is
+ * If RateMode is reduction_rate_log2, then the computed output is
* $
- * 2\frac{\log |e_{n-1}/e_{n}|}{\log |k_n/k_{n-1}|}
+ * dim \frac{\log |e_{n-1}/e_{n}|}{\log |k_n/k_{n-1}|}
* $.
*
- * This is useful, for example, if we use as
- * reference key the number of degrees of freedom.
- * Assuming that the error is proportional to
- * $ C (1/\sqrt{k})^r $, then this method will
- * produce the rate $r$ as a result.
+ * This is useful, for example, if we use as reference key the number of
+ * degrees of freedom or better, the number of cells. Assuming that the
+ * error is proportional to $ C (1/\sqrt{k})^r $ in 2D, then this method
+ * will produce the rate $r$ as a result. For general dimension, as described
+ * by the last parameter of this function, the formula needs to be
+ * $ C (1/\sqrt[dim]{k})^r $.
*
- * @note Since this function adds columns
- * to the table after several rows have
- * already been filled, it switches off
- * the auto fill mode of the TableHandler
- * base class. If you intend to add
- * further data with auto fill, you will
- * have to re-enable it after calling
- * this function.
+ * @note Since this function adds columns to the table after several rows
+ * have already been filled, it switches off the auto fill mode of the
+ * TableHandler base class. If you intend to add further data with auto
+ * fill, you will have to re-enable it after calling this function.
*/
void
evaluate_convergence_rates (const std::string &data_column_key,
const std::string &reference_column_key,
- const RateMode rate_mode);
+ const RateMode rate_mode,
+ const unsigned int dim = 2);
/**
- * Evaluates the convergence rates of the
- * data column <tt>data_column_key</tt>
- * due to the #RateMode.
- * Be sure that the value types of the
- * table entries of the data column
- * is a number, i.e. double, float,
- * (unsigned) int, and so on.
+ * Evaluates the convergence rates of the data column
+ * <tt>data_column_key</tt> due to the #RateMode. Be sure that the value
+ * types of the table entries of the data column is a number, i.e. double,
+ * float, (unsigned) int, and so on.
*
- * The new rate column and the data column
- * will be merged to a supercolumn. The
- * tex caption of the supercolumn will be
- * (by default) the same as the one of the
- * data column. This may be changed by using
- * the set_tex_supercaption() function
- * of the base class TableHandler.
+ * The new rate column and the data column will be merged to a
+ * supercolumn. The tex caption of the supercolumn will be (by default) the
+ * same as the one of the data column. This may be changed by using the
+ * set_tex_supercaption() function of the base class TableHandler.
*
- * @note Since this function adds columns
- * to the table after several rows have
- * already been filled, it switches off
- * the auto fill mode of the TableHandler
- * base class. If you intend to add
- * further data with auto fill, you will
- * have to re-enable it after calling
- * this function.
+ * @note Since this function adds columns to the table after several rows
+ * have already been filled, it switches off the auto fill mode of the
+ * TableHandler base class. If you intend to add further data with auto
+ * fill, you will have to re-enable it after calling this function.
*/
void
evaluate_convergence_rates (const std::string &data_column_key,
const RateMode rate_mode);
/**
- * Omit this column <tt>key</tt>
- * (not supercolumn!) from the
- * evaluation of the convergence rates
- * of `all' columns (see the following
- * two functions).
+ * Omit this column <tt>key</tt> (not supercolumn!) from the evaluation of
+ * the convergence rates of `all' columns (see the following two functions).
*
- * The Column::flag==1 is reserved for
- * omitting the column from convergence
+ * The Column::flag==1 is reserved for omitting the column from convergence
* rate evalution.
*/
void
omit_column_from_convergence_rate_evaluation(const std::string &key);
/**
- * Evaluates convergence rates
- * due to the <tt>rate_mode</tt>
- * in relation to the reference
- * column
- * <tt>reference_column_key</tt>. This
- * function evaluates the rates
- * of ALL columns except of the
- * columns that are to be omitted
- * (see previous function) and
- * execpt of the columns that are
- * previously evaluated rate
- * columns. This function allows
- * to evaluate the convergence
- * rate for almost all columns of
- * a table without calling
- * evaluate_convergence_rates()
- * for each column separately.
+ * Evaluates convergence rates due to the <tt>rate_mode</tt> in relation to
+ * the reference column <tt>reference_column_key</tt>. This function
+ * evaluates the rates of ALL columns except of the columns that are to be
+ * omitted (see previous function) and execpt of the columns that are
+ * previously evaluated rate columns. This function allows to evaluate the
+ * convergence rate for almost all columns of a table without calling
+ * evaluate_convergence_rates() for each column separately.
*
* Example:
- * Columns like <tt>n cells</tt> or
- * <tt>n dofs</tt> columns may be wanted
- * to be omitted in the evaluation
- * of the convergence rates. Hence they
- * should omitted by calling the
- * omit_column_from_convergence_rate_evaluation().
+ * Columns like <tt>n cells</tt> or <tt>n dofs</tt> columns may be wanted to
+ * be omitted in the evaluation of the convergence rates. Hence they should
+ * omitted by calling the omit_column_from_convergence_rate_evaluation().
*/
void
evaluate_all_convergence_rates(const std::string &reference_column_key,
const RateMode rate_mode);
/**
- * Evaluates convergence rates
- * due to the <tt>rate_mode</tt>. This
- * function evaluates the rates of
- * ALL columns except of the
- * columns that are to be omitted
- * (see previous function)
- * and execpt of the columns that are
- * previously
- * evaluated rate columns.
- * This function allows to evaluate
- * the convergence rate for almost all
- * columns of a table without calling
- * evaluate_convergence_rates()
- * for each column seperately.
+ * Evaluates convergence rates due to the <tt>rate_mode</tt>. This function
+ * evaluates the rates of ALL columns except of the columns that are to be
+ * omitted (see previous function) and execpt of the columns that are
+ * previously evaluated rate columns. This function allows to evaluate the
+ * convergence rate for almost all columns of a table without calling
+ * evaluate_convergence_rates() for each column seperately.
*
* Example:
- * Columns like <tt>n cells</tt> or
- * <tt>n dofs</tt> columns may be wanted
- * to be omitted in the evaluation
- * of the convergence rates. Hence they
- * should omitted by calling the
- * omit_column_from_convergence_rate_evaluation().
+ * Columns like <tt>n cells</tt> or <tt>n dofs</tt> columns may be wanted to
+ * be omitted in the evaluation of the convergence rates. Hence they should
+ * omitted by calling the omit_column_from_convergence_rate_evaluation().
*/
void
evaluate_all_convergence_rates(const RateMode rate_mode);
#include <vector>
#include <string>
+#include <limits>
#include <deal.II/base/mpi.h>
/**
* Flags controlling the details
* of output in VTK
- * format. At present no flags
- * are implemented.
+ * format.
*
* @ingroup output
*/
struct VtkFlags
{
- private:
+ public:
/**
- * Dummy entry to suppress compiler
- * warnings when copying an empty
- * structure. Remove this member
- * when adding the first flag to
- * this structure (and remove the
- * <tt>private</tt> as well).
+ * 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
+ * http://www.visitusers.org/index.php?title=Time_and_Cycle_in_VTK_files
+ * unless it is at its default value of std::numeric_limits<double>::min().
*/
- int dummy;
+ 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
+ * iteration.
+ *
+ * The value of this variable is written into the output file according
+ * to the instructions provided in
+ * http://www.visitusers.org/index.php?title=Time_and_Cycle_in_VTK_files
+ * unless it is at its default value of std::numeric_limits<unsigned int>::min().
+ */
+ unsigned int cycle;
- public:
/**
* Default constructor.
*/
- VtkFlags ();
+ VtkFlags (const double time = std::numeric_limits<double>::min(),
+ const unsigned int cycle = std::numeric_limits<unsigned int>::min());
/**
- * Declare all flags with name
+ * 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
+ * of this class. The reason is that there wouldn't appear to be a case where
+ * one would want to declare these parameters in an input file. Rather, these
+ * are typically values that change during the course of a simulation and
+ * can only reasonably be set as part of the execution of a program, rather
+ * than a priori by a user who runs this program.
*/
static void declare_parameters (ParameterHandler &prm);
*/
std::size_t memory_consumption () const;
};
+
+
+ /**
+ * Flags for SVG output.
+ */
+ struct SvgFlags
+ {
+ public:
+ /**
+ * This denotes the number of the
+ * data vector which shall be used
+ * for generating the height
+ * information. By default, the
+ * first data vector is taken,
+ * i.e. <tt>height_vector==0</tt>, if
+ * there is any data vector. If there
+ * is no data vector, no height
+ * information is generated.
+ */
+ 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,
+ const int azimuth_angle = 37,
+ const int polar_angle = 45,
+ const unsigned int line_thickness = 1,
+ const bool margin = true,
+ const bool draw_colorbar = true);
+
+ /**
+ * Determine an estimate for
+ * the memory consumption (in
+ * bytes) of this
+ * object. Since sometimes
+ * the size of objects can
+ * not be determined exactly
+ * (for example: what is the
+ * memory consumption of an
+ * STL <tt>std::map</tt> type with a
+ * certain number of
+ * elements?), this is only
+ * an estimate. however often
+ * quite close to the true
+ * value.
+ */
+ std::size_t memory_consumption () const;
+
+ private:
+
+ };
+
+
/**
* Flags controlling the details
* of output in deal.II
*/
vtu,
+ /**
+ * Output in
+ * SVG format.
+ */
+ svg,
+
/**
* Output in deal.II
* intermediate format.
* provisions that allow these components to be output by a single
* name rather than having to group several scalar fields into a
* vector later on in the visualization program.
+ *
+ * @note VTK is a legacy format and has largely been supplanted by the VTU
+ * format (an XML-structured version of VTK). In particular, VTU allows for
+ * the compression of data and consequently leads to much smaller file
+ * sizes that equivalent VTK files for large files. Since all visualization
+ * programs that support VTK also support VTU, you should consider using the
+ * latter file format instead, by using the write_vtu() function.
*/
template <int dim, int spacedim>
static void write_vtk (const std::vector<Patch<dim,spacedim> > &patches,
/**
- * Write the given list of patches to the output stream in VTK
+ * Write the given list of patches to the output stream in VTU
* format. The data is written in the XML-based VTK format as opposed to the
* traditional format that write_vtk() produces.
*
const std::vector<std_cxx1x::tuple<unsigned int, unsigned int, std::string> > &vector_data_ranges,
const VtkFlags &flags,
std::ostream &out);
-
+
+ /**
+ * Write the given list of patches to the output stream in SVG format.
+ *
+ * SVG (Scalable Vector Graphics) is an XML-based vector image format
+ * developed and maintained by the World Wide Web Consortium (W3C).
+ * This function conforms to the latest specification SVG 1.1,
+ * released on August 16, 2011. Controlling the graphic output is
+ * possible by setting or clearing the respective flags (see the
+ * SvgFlags struct). At present, this format only supports output
+ * for two-dimensional data, with values in the third direction
+ * taken from a data vector.
+ *
+ * For the output, each patch is subdivided into four triangles
+ * which are then written as polygons and filled with a linear
+ * color gradient. The arising coloring of the patches visualizes
+ * the data values at the vertices taken from the specified data
+ * vector. A colorbar can be drawn to encode the coloring.
+ *
+ * @note Yet only implemented for two dimensions with an additional
+ * dimension reserved for data information.
+ */
+ template <int dim, int spacedim>
+ static void write_svg (const std::vector<Patch<dim,spacedim> > &patches,
+ const std::vector<std::string> &data_names,
+ const std::vector<std_cxx1x::tuple<unsigned int, unsigned int, std::string> > &vector_data_ranges,
+ const SvgFlags &flags,
+ std::ostream &out);
+
/**
* Write the given list of patches to the output stream in deal.II
* intermediate format. This is not a format understood by any other
* <li> <tt>tecplot_binary</tt>: <tt>.plt</tt>
* <li> <tt>vtk</tt>: <tt>.vtk</tt>
* <li> <tt>vtu</tt>: <tt>.vtu</tt>
+ * <li> <tt>svg</tt>: <tt>.svg</tt>
* <li> <tt>deal_II_intermediate</tt>: <tt>.d2</tt>.
* </ul>
*/
const bool double_precision,
STREAM &out);
+
+ /**
+ * This function projects a three-dimensional point (Point<3> point)
+ * onto a two-dimensional image plane, specified by the position of
+ * the camera viewing system (Point<3> camera_position), camera
+ * direction (Point<3> camera_position), camera horizontal (Point<3>
+ * camera_horizontal, necessary for the correct alignment of the
+ * later images), and the focus of the camera (float camera_focus).
+ *
+ * For SVG output.
+ */
+ static Point<2> svg_project_point(Point<3> point,
+ Point<3> camera_position,
+ Point<3> camera_direction,
+ Point<3> camera_horizontal,
+ float camera_focus);
+ /**
+ * Function to compute the gradient parameters for
+ * a triangle with given values for the vertices.
+ *
+ * Used for svg output.
+ */
+ static Point<6> svg_get_gradient_parameters(Point<3> points[]);
+
+ /**
+ * 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 SvgCell
+ {
+ public:
+
+ // Center of the cell (three-dimensional)
+ Point<3> center;
+
+ /**
+ * Vector of vertices of this cell (three-dimensional)
+ */
+ 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.
+ */
+ float depth;
+
+ /**
+ * Vector of vertices of this cell (projected, two-dimensional).
+ */
+ Point<2> projected_vertices[4];
+
+ // Center of the cell (projected, two-dimensional)
+ Point<2> projected_center;
+
+ /**
+ * Comparison operator for
+ * sorting.
+ */
+ bool operator < (const SvgCell &) const;
+ };
+
+
/**
* Class holding the data of one
* cell of a patch in two space
* and write it to <tt>out</tt>
* in Vtk format. See
* DataOutBase::write_vtk.
+ *
+ * @note VTK is a legacy format and has largely been supplanted by the VTU
+ * format (an XML-structured version of VTK). In particular, VTU allows for
+ * the compression of data and consequently leads to much smaller file
+ * sizes that equivalent VTK files for large files. Since all visualization
+ * programs that support VTK also support VTU, you should consider using the
+ * latter file format instead, by using the write_vtu() function.
*/
void write_vtk (std::ostream &out) const;
void write_visit_record (std::ostream &out,
const std::vector<std::string> &piece_names) const;
+ /**
+ * Obtain data through get_patches()
+ * and write it to <tt>out</tt>
+ * in SVG format. See
+ * DataOutBase::write_svg.
+ */
+ void write_svg(std::ostream &out) const;
+
/**
* Obtain data through get_patches()
* and write it to <tt>out</tt>
*/
void set_flags (const VtkFlags &vtk_flags);
+ /**
+ * 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.
*/
VtkFlags vtk_flags;
+ /**
+ * Flags to be used upon output
+ * of svg data in one space
+ * dimension. Can be changed by
+ * using the <tt>set_flags</tt>
+ * function.
+ */
+ SvgFlags svg_flags;
+
/**
* Flags to be used upon output of
* deal.II intermediate data in one space
const Range &range_2)
{
return ((range_1.begin == range_2.begin)
- ||
- (range_1.begin == range_2.begin));
+ &&
+ (range_1.end == range_2.end));
}
std::size_t memory_consumption () const
};
+/**
+ * Create and return an index set of size $N$ that contains every
+ * single index within this range. In essence, this function
+ * returns an index set created by
+ * @code
+ * IndexSet is (N);
+ * is.add_range(0, N);
+ * @endcode
+ * This function exists so that one can create and initialize
+ * index sets that are complete in one step, or so one can write
+ * code like
+ * @code
+ * if (my_index_set == complete_index_set(my_index_set.size())
+ * ...
+ * @endcode
+ *
+ * @relates IndexSet
+ */
+inline
+IndexSet complete_index_set (const unsigned int N)
+{
+ IndexSet is (N);
+ is.add_range(0, N);
+ return is;
+}
+
/* ------------------ inline functions ------------------ */
inline
* <code>MPI_Allreduce</code> function, i.e. all processors receive
* the result of this operation.
*
+ * @note Sometimes, not all processors need a results and in that case
+ * one would call the <code>MPI_Reduce</code> function instead of the
+ * <code>MPI_Allreduce</code> function. The latter is at most twice as
+ * expensive, so if you are concerned about performance, it may be
+ * worthwhile investigating whether your algorithm indeed needs the
+ * result everywhere or whether you could get away with calling the
+ * current function and getting the result everywhere.
+ *
* @note This function is only implemented for certain template
* arguments <code>T</code>, namely <code>float, double, int,
* unsigned int</code>.
* <code>MPI_Allreduce</code> function, i.e. all processors receive
* the result of this operation.
*
+ * @note Sometimes, not all processors need a results and in that case
+ * one would call the <code>MPI_Reduce</code> function instead of the
+ * <code>MPI_Allreduce</code> function. The latter is at most twice as
+ * expensive, so if you are concerned about performance, it may be
+ * worthwhile investigating whether your algorithm indeed needs the
+ * result everywhere or whether you could get away with calling the
+ * current function and getting the result everywhere.
+ *
* @note This function is only implemented for certain template
* arguments <code>T</code>, namely <code>float, double, int,
* unsigned int</code>.
* Returns sum, average, minimum,
* maximum, processor id of minimum and
* maximum as a collective operation of
- * on the given MPI communicator @param
+ * on the given MPI communicator @p
* mpi_communicator . Each processor's
- * value is given in @param my_value and
- * the result will be returned in @p
- * result . The result is available on all
+ * value is given in @p my_value and
+ * the result will be returned.
+ * The result is available on all
* machines.
+ *
+ * @note Sometimes, not all processors need a results and in that case
+ * one would call the <code>MPI_Reduce</code> function instead of the
+ * <code>MPI_Allreduce</code> function. The latter is at most twice as
+ * expensive, so if you are concerned about performance, it may be
+ * worthwhile investigating whether your algorithm indeed needs the
+ * result everywhere or whether you could get away with calling the
+ * current function and getting the result everywhere.
*/
MinMaxAvg
min_max_avg (const double my_value,
* Returns the MPI communicator underlying the
* partitioner object.
*/
- MPI_Comm get_communicator() const;
+ const MPI_Comm& get_communicator() const;
/**
* Computes the memory consumption of this
inline
- MPI_Comm
+ const MPI_Comm&
Partitioner::get_communicator() const
{
return communicator;
public:
/**
* Standard constructor. Creates
- * an origin.
+ * an object that corresponds to the origin, i.e., all coordinates
+ * are set to zero.
*/
Point ();
/**
* Constructor. Initialize all
* entries to zero if
- * <tt>initialize==true</tt>.
+ * <tt>initialize==true</tt> (in which case it is equivalent to the default
+ * constructor) or leaves the elements uninitialized if
+ * <tt>initialize==false</tt>.
*/
explicit Point (const bool initialize);
/**
- * Convert a tensor to a point. Since no
- * additional data is inside a point,
- * this is ok.
+ * Convert a tensor to a point.
*/
Point (const Tensor<1,dim,Number> &);
* points. This function is only
* implemented for <tt>dim==1</tt> since
* the usage is considered unsafe for
- * points with <tt>dim!=1</tt>.
+ * points with <tt>dim!=1</tt> as it would leave some components
+ * of the point coordinates uninitialized.
*/
explicit Point (const Number x);
* points. This function is only
* implemented for <tt>dim==2</tt> since
* the usage is considered unsafe for
- * points with <tt>dim!=2</tt>.
+ * points with <tt>dim!=2</tt> as it would leave some components
+ * of the point coordinates uninitialized (if dim>2) or would
+ * not use some arguments (if dim<2).
*/
- Point (const Number x, const Number y);
+ Point (const Number x,
+ const Number y);
/**
* Constructor for three dimensional
* points. This function is only
* implemented for <tt>dim==3</tt> since
* the usage is considered unsafe for
- * points with <tt>dim!=3</tt>.
+ * points with <tt>dim!=3</tt> as it would leave some components
+ * of the point coordinates uninitialized (if dim>3) or would
+ * not use some arguments (if dim<3).
*/
- Point (const Number x, const Number y, const Number z);
+ Point (const Number x,
+ const Number y,
+ const Number z);
/**
* Return a unit vector in
*/
/**
- * A namespace in which classes relating to the description of
- * 1d polynomial spaces are declared.
+ * A namespace in which classes relating to the description of 1d polynomial
+ * spaces are declared.
*/
namespace Polynomials
{
{
public:
/**
- * Constructor. The
- * coefficients of the
- * polynomial are passed as
- * arguments, and denote the
- * polynomial $\sum_i a[i]
- * x^i$, i.e. the first element
- * of the array denotes the
- * constant term, the second
- * the linear one, and so
- * on. The degree of the
- * polynomial represented by
- * this object is thus the
- * number of elements in the
- * <tt>coefficient</tt> array
- * minus one.
+ * Constructor. The coefficients of the polynomial are passed as
+ * arguments, and denote the polynomial $\sum_i a[i] x^i$, i.e. the first
+ * element of the array denotes the constant term, the second the linear
+ * one, and so on. The degree of the polynomial represented by this object
+ * is thus the number of elements in the <tt>coefficient</tt> array minus
+ * one.
*/
Polynomial (const std::vector<number> &coefficients);
/**
- * Constructor creating a zero
- * polynomial of degree @p n.
+ * Constructor creating a zero polynomial of degree @p n.
*/
Polynomial (const unsigned int n);
/**
- * Constructor for Lagrange polynomial and its
- * point of evaluation. The idea is to
- * construct $\prod_{i\neq j}
- * \frac{x-x_i}{x_j-x_i}$, where j is the
- * evaluation point specified as argument and
- * the support points contain all points
- * (including x_j, which will internally not
- * be stored).
+ * Constructor for Lagrange polynomial and its point of evaluation. The
+ * idea is to construct $\prod_{i\neq j} \frac{x-x_i}{x_j-x_i}$, where j
+ * is the evaluation point specified as argument and the support points
+ * contain all points (including x_j, which will internally not be
+ * stored).
*/
Polynomial (const std::vector<Point<1> > &lagrange_support_points,
const unsigned int evaluation_point);
/**
- * Default constructor creating
- * an illegal object.
+ * Default constructor creating an illegal object.
*/
Polynomial ();
/**
- * Return the value of this
- * polynomial at the given point.
+ * Return the value of this polynomial at the given point.
*
- * This function uses the Horner
- * scheme for numerical stability
- * of the evaluation.
+ * This function uses the Horner scheme for numerical stability of the
+ * evaluation.
*/
number value (const number x) const;
/**
- * Return the values and the
- * derivatives of the
- * Polynomial at point <tt>x</tt>.
- * <tt>values[i],
- * i=0,...,values.size()-1</tt>
- * includes the <tt>i</tt>th
- * derivative. The number of
- * derivatives to be computed is
- * thus determined by the size of
- * the array passed.
+ * Return the values and the derivatives of the Polynomial at point
+ * <tt>x</tt>. <tt>values[i], i=0,...,values.size()-1</tt> includes the
+ * <tt>i</tt>th derivative. The number of derivatives to be computed is
+ * thus determined by the size of the array passed.
*
- * This function uses the Horner
- * scheme for numerical stability
- * of the evaluation.
+ * This function uses the Horner scheme for numerical stability of the
+ * evaluation.
*/
void value (const number x,
std::vector<number> &values) const;
/**
- * Degree of the polynomial. This
- * is the degree reflected by the
- * number of coefficients
- * provided by the
- * constructor. Leading non-zero
- * coefficients are not treated
- * separately.
+ * Degree of the polynomial. This is the degree reflected by the number of
+ * coefficients provided by the constructor. Leading non-zero coefficients
+ * are not treated separately.
*/
unsigned int degree () const;
/**
- * Scale the abscissa of the
- * polynomial. Given the
- * polynomial <i>p(t)</i> and the
- * scaling <i>t = ax</i>, then the
- * result of this operation is
- * the polynomial <i>q</i>, such that
- * <i>q(x) = p(t)</i>.
+ * Scale the abscissa of the polynomial. Given the polynomial <i>p(t)</i>
+ * and the scaling <i>t = ax</i>, then the result of this operation is the
+ * polynomial <i>q</i>, such that <i>q(x) = p(t)</i>.
*
- * The operation is performed in
- * place.
+ * The operation is performed in place.
*/
void scale (const number factor);
/**
- * Shift the abscissa oft the
- * polynomial. Given the
- * polynomial <i>p(t)</i> and the
- * shift <i>t = x + a</i>, then the
- * result of this operation is
- * the polynomial <i>q</i>, such that
- * <i>q(x) = p(t)</i>.
+ * Shift the abscissa oft the polynomial. Given the polynomial
+ * <i>p(t)</i> and the shift <i>t = x + a</i>, then the result of this
+ * operation is the polynomial <i>q</i>, such that <i>q(x) = p(t)</i>.
*
- * The template parameter allows
- * to compute the new
- * coefficients with higher
- * accuracy, since all
- * computations are performed
- * with type <tt>number2</tt>. This
- * may be necessary, since this
- * operation involves a big
- * number of additions. On a Sun
- * Sparc Ultra with Solaris 2.8,
- * the difference between
- * <tt>double</tt> and <tt>long double</tt>
- * was not significant, though.
+ * The template parameter allows to compute the new coefficients with
+ * higher accuracy, since all computations are performed with type
+ * <tt>number2</tt>. This may be necessary, since this operation involves
+ * a big number of additions. On a Sun Sparc Ultra with Solaris 2.8, the
+ * difference between <tt>double</tt> and <tt>long double</tt> was not
+ * significant, though.
*
- * The operation is performed in
- * place, i.e. the coefficients
- * of the present object are
- * changed.
+ * The operation is performed in place, i.e. the coefficients of the
+ * present object are changed.
*/
template <typename number2>
void shift (const number2 offset);
/**
- * Compute the derivative of a
- * polynomial.
+ * Compute the derivative of a polynomial.
*/
Polynomial<number> derivative () const;
/**
- * Compute the primitive of a
- * polynomial. the coefficient
- * of the zero order term of
- * the polynomial is zero.
+ * Compute the primitive of a polynomial. the coefficient of the zero
+ * order term of the polynomial is zero.
*/
Polynomial<number> primitive () const;
Polynomial<number> &operator -= (const Polynomial<number> &p);
/**
- * Test for equality of two polynomials.
- */
+ * Test for equality of two polynomials.
+ */
bool operator == (const Polynomial<number> &p) const;
/**
void print(std::ostream &out) const;
/**
- * Write or read the data of this object to or
- * from a stream for the purpose of serialization.
+ * Write or read the data of this object to or from a stream for the
+ * purpose of serialization.
*/
template <class Archive>
void serialize (Archive &ar, const unsigned int version);
protected:
/**
- * This function performs the
- * actual scaling.
+ * This function performs the actual scaling.
*/
static void scale (std::vector<number> &coefficients,
const number factor);
/**
- * This function performs the
- * actual shift
+ * This function performs the actual shift
*/
template <typename number2>
static void shift (std::vector<number> &coefficients,
const number factor);
/**
- * Transforms polynomial form of
- * product of linear factors into
- * standard form, $\sum_i a_i
- * x^i$. Deletes all data structures
- * related to the product form.
+ * Transforms polynomial form of product of linear factors into standard
+ * form, $\sum_i a_i x^i$. Deletes all data structures related to the
+ * product form.
*/
void transform_into_standard_form ();
/**
- * Coefficients of the polynomial
- * $\sum_i a_i x^i$. This vector
- * is filled by the constructor
- * of this class and may be
- * passed down by derived
+ * Coefficients of the polynomial $\sum_i a_i x^i$. This vector is filled
+ * by the constructor of this class and may be passed down by derived
* classes.
*
- * This vector cannot be constant
- * since we want to allow copying
- * of polynomials.
+ * This vector cannot be constant since we want to allow copying of
+ * polynomials.
*/
std::vector<number> coefficients;
/**
- * Stores whether the polynomial is in
- * Lagrange product form, i.e.,
- * constructed as a product $(x-x_0)
- * (x-x_1) \ldots (x-x_n)/c$, or not.
+ * Stores whether the polynomial is in Lagrange product form, i.e.,
+ * constructed as a product $(x-x_0) (x-x_1) \ldots (x-x_n)/c$, or not.
*/
bool in_lagrange_product_form;
/**
- * If the polynomial is in Lagrange
- * product form, i.e., constructed as a
- * product $(x-x_0) (x-x_1) \ldots
- * (x-x_n)/c$, store the shifts $x_i$.
+ * If the polynomial is in Lagrange product form, i.e., constructed as a
+ * product $(x-x_0) (x-x_1) \ldots (x-x_n)/c$, store the shifts $x_i$.
*/
std::vector<number> lagrange_support_points;
/**
- * If the polynomial is in Lagrange
- * product form, i.e., constructed as a
- * product $(x-x_0) (x-x_1) \ldots
- * (x-x_n)/c$, store the weight c.
+ * If the polynomial is in Lagrange product form, i.e., constructed as a
+ * product $(x-x_0) (x-x_1) \ldots (x-x_n)/c$, store the weight c.
*/
number lagrange_weight;
};
{
public:
/**
- * Constructor. Takes the degree
- * <tt>n</tt> of the Lagrangian
- * polynom and the index
- * <tt>support_point</tt> of the
- * support point. Fills the
- * <tt>coefficients</tt> of the base
- * class Polynomial.
+ * Constructor. Takes the degree <tt>n</tt> of the Lagrangian polynom and
+ * the index <tt>support_point</tt> of the support point. Fills the
+ * <tt>coefficients</tt> of the base class Polynomial.
*/
LagrangeEquidistant (const unsigned int n,
const unsigned int support_point);
/**
- * Return a vector of polynomial
- * objects of degree <tt>degree</tt>,
- * which then spans the full
- * space of polynomials up to the
- * given degree. The polynomials
- * are generated by calling the
- * constructor of this class with
- * the same degree but support
- * point running from zero to
- * <tt>degree</tt>. This function may
- * be used to initialize the
- * TensorProductPolynomials
- * and PolynomialSpace
- * classes.
+ * Return a vector of polynomial objects of degree <tt>degree</tt>, which
+ * then spans the full space of polynomials up to the given degree. The
+ * polynomials are generated by calling the constructor of this class with
+ * the same degree but support point running from zero to
+ * <tt>degree</tt>. This function may be used to initialize the
+ * TensorProductPolynomials and PolynomialSpace classes.
*/
static
std::vector<Polynomial<double> >
private:
/**
- * Computes the <tt>coefficients</tt>
- * of the base class
- * Polynomial. This function
- * is <tt>static</tt> to allow to be
- * called in the
- * constructor.
+ * Computes the <tt>coefficients</tt> of the base class Polynomial. This
+ * function is <tt>static</tt> to allow to be called in the constructor.
*/
static
void
};
+
/**
- * Given a set of points along the
- * real axis, this function returns
- * all Lagrange polynomials for
- * interpolation of these
- * points. The number of
- * polynomials is equal to the
- * number of points and the maximum
- * degree is one less.
+ * Given a set of points along the real axis, this function returns all
+ * Lagrange polynomials for interpolation of these points. The number of
+ * polynomials is equal to the number of points and the maximum degree is
+ * one less.
*/
std::vector<Polynomial<double> >
generate_complete_Lagrange_basis (const std::vector<Point<1> > &points);
void
Polynomial<number>::serialize (Archive &ar, const unsigned int)
{
- // forward to serialization
- // function in the base class.
+ // forward to serialization function in the base class.
ar &static_cast<Subscriptor &>(*this);
ar &coefficients;
ar &in_lagrange_product_form;
--- /dev/null
+//---------------------------------------------------------------------------
+// $Id$
+//
+// Copyright (C) 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2009, 2010, 2011, 2012 by the deal.II authors
+//
+// This file is subject to QPL and may not be distributed
+// without copyright and license information. Please refer
+// to the file deal.II/doc/license.html for the text and
+// further information on this license.
+//
+//---------------------------------------------------------------------------
+#ifndef __deal2__polynomials_piecewise_h
+#define __deal2__polynomials_piecewise_h
+
+
+
+#include <deal.II/base/config.h>
+#include <deal.II/base/exceptions.h>
+#include <deal.II/base/subscriptor.h>
+#include <deal.II/base/polynomial.h>
+#include <deal.II/base/point.h>
+
+#include <vector>
+
+DEAL_II_NAMESPACE_OPEN
+
+/**
+ * @addtogroup Polynomials
+ * @{
+ */
+
+/**
+ * A namespace in which classes relating to the description of 1d polynomial
+ * spaces are declared.
+ */
+namespace Polynomials
+{
+
+ /**
+ * Definition of piecewise 1D polynomials for the unit interval. This space
+ * allows the description of interpolating polynomials on parts of the unit
+ * interval, similarly to the definition of finite element basis functions
+ * on the subdivided elements. This primary purpose of this class is to
+ * allow constructing FE_Q_iso_Q1 elements that put additional degrees of
+ * freedom into an equivalent of a refined mesh instead of higher order
+ * polynomials, which is useful when using mixed finite elements.
+ *
+ * @author Martin Kronbichler, 2013
+ */
+ template <typename number>
+ class PiecewisePolynomial : public Subscriptor
+ {
+ public:
+ /**
+ * Constructor for Lagrange polynomial on an interval that is a subset of
+ * the unit interval. It uses a polynomial description that is scaled to
+ * the size of the subinterval compared to the unit interval, the total
+ * number of intervals (subdivisions), the current index of the interval
+ * as well as if the polynomial spans onto the next interval (e.g., if it
+ * lives on two neighboring intervals).
+ *
+ * If the number of intervals is one, the piecewise polynomial behaves
+ * exactly like a usual polynomial.
+ */
+ PiecewisePolynomial (const Polynomial<number> &coefficients_on_interval,
+ const unsigned int n_intervals,
+ const unsigned int interval,
+ const bool spans_next_interval);
+
+ /**
+ * Return the value of this polynomial at the given point, evaluating the
+ * underlying polynomial. The polynomial evaluates to zero when outside of
+ * the given interval (and possible the next one to the right when it
+ * spans over that range).
+ */
+ number value (const number x) const;
+
+ /**
+ * Return the values and the derivatives of the Polynomial at point
+ * <tt>x</tt>. <tt>values[i], i=0,...,values.size()-1</tt> includes the
+ * <tt>i</tt>th derivative. The number of derivatives to be computed is
+ * thus determined by the size of the array passed.
+ *
+ * Note that all the derivatives evaluate to zero at the border between
+ * intervals (assuming exact arithmetics) in the interior of the unit
+ * interval, as there is no unique gradient value in that case for a
+ * piecewise polynomial. This is not always desired (e.g., when evaluating
+ * jumps of gradients on the element boundary), but it is the user's
+ * responsibility to avoid evaluation at these points when it does not
+ * make sense.
+ */
+ void value (const number x,
+ std::vector<number> &values) const;
+
+ /**
+ * Degree of the polynomial. This is the degree of the underlying base
+ * polynomial.
+ */
+ unsigned int degree () const;
+
+ /**
+ * Write or read the data of this object to or from a stream for the
+ * purpose of serialization.
+ */
+ template <class Archive>
+ void serialize (Archive &ar, const unsigned int version);
+
+ protected:
+
+ /**
+ * Underlying polynomial object that is scaled to a subinterval and
+ * concatenated accordingly.
+ */
+ Polynomial<number> polynomial;
+
+ /**
+ * Stores the number of intervals that the unit interval is divided into.
+ */
+ unsigned int n_intervals;
+
+ /**
+ * Stores the index of the current polynomial in the range of
+ * intervals.
+ */
+ unsigned int interval;
+
+ /**
+ * Store if the polynomial spans over two adjacent intervals, i.e., the
+ * one given in subinterval and the next one.
+ */
+ bool spans_two_intervals;
+ };
+
+
+
+ /**
+ * Generates a complete Lagrange basis on a subdivision of the unit interval
+ * in smaller intervals for a given degree on the subintervals and number of
+ * intervals.
+ */
+ std::vector<PiecewisePolynomial<double> >
+ generate_complete_Lagrange_basis_on_subdivisions (const unsigned int n_subdivisions,
+ const unsigned int base_degree);
+
+}
+
+
+/** @} */
+
+/* -------------------------- inline functions --------------------- */
+
+namespace Polynomials
+{
+ template <typename number>
+ inline
+ unsigned int
+ PiecewisePolynomial<number>::degree () const
+ {
+ return polynomial.degree();
+ }
+
+
+
+ template <typename number>
+ inline
+ number
+ PiecewisePolynomial<number>::value (const number x) const
+ {
+ AssertIndexRange (interval, n_intervals);
+ number y = x;
+ // shift polynomial if necessary
+ if (n_intervals > 1)
+ {
+ const number step = 1./n_intervals;
+
+ // polynomial spans over two intervals
+ if (spans_two_intervals == true)
+ {
+ const number offset = step * interval;
+ if (x<offset)
+ return 0;
+ else if (x>offset+step+step)
+ return 0;
+ else if (x<offset+step)
+ y = x-offset;
+ else
+ y = offset+step+step-x;
+ }
+ else
+ {
+ const number offset = step * interval;
+ if (x<offset || x>offset+step)
+ return 0;
+ else
+ y = x-offset;
+ }
+
+ return polynomial.value(y);
+ }
+ else
+ return polynomial.value(x);
+ }
+
+
+
+ template <typename number>
+ template <class Archive>
+ inline
+ void
+ PiecewisePolynomial<number>::serialize (Archive &ar, const unsigned int)
+ {
+ // forward to serialization function in the base class.
+ ar &static_cast<Subscriptor &>(*this);
+ ar &polynomial;
+ ar &n_intervals;
+ ar &interval;
+ ar &spans_two_intervals;
+ }
+
+}
+
+DEAL_II_NAMESPACE_CLOSE
+
+#endif
*
* @author Ralf Hartmann, 2000, 2004, Guido Kanschat, 2000, Wolfgang Bangerth 2003
*/
-template <int dim>
+template <int dim, typename POLY=Polynomials::Polynomial<double> >
class TensorProductPolynomials
{
public:
/**
- * Access to the dimension of
- * this object, for checking and
- * automatic setting of dimension
- * in other classes.
+ * Access to the dimension of this object, for checking and automatic
+ * setting of dimension in other classes.
*/
static const unsigned int dimension = dim;
/**
- * Constructor. <tt>pols</tt> is
- * a vector of objects that
- * should be derived or otherwise
- * convertible to one-dimensional
- * polynomial objects. It will be
- * copied element by element into
- * a private variable.
+ * Constructor. <tt>pols</tt> is a vector of objects that should be derived
+ * or otherwise convertible to one-dimensional polynomial objects of type @p
+ * POLY (template argument of class). It will be copied element by element
+ * into a private variable.
*/
template <class Pol>
TensorProductPolynomials (const std::vector<Pol> &pols);
/**
- * Prints the list of the indices
- * to <tt>out</tt>.
+ * Prints the list of the indices to <tt>out</tt>.
*/
void output_indices(std::ostream &out) const;
/**
- * Sets the ordering of the
- * polynomials. Requires
- * <tt>renumber.size()==n()</tt>.
- * Stores a copy of
- * <tt>renumber</tt>.
+ * Sets the ordering of the polynomials. Requires
+ * <tt>renumber.size()==n()</tt>. Stores a copy of <tt>renumber</tt>.
*/
void set_numbering(const std::vector<unsigned int> &renumber);
/**
- * Gives read access to the
- * renumber vector.
+ * Gives read access to the renumber vector.
*/
const std::vector<unsigned int> &get_numbering() const;
/**
- * Gives read access to the
- * inverse renumber vector.
+ * Gives read access to the inverse renumber vector.
*/
const std::vector<unsigned int> &get_numbering_inverse() const;
/**
- * Computes the value and the
- * first and second derivatives
- * of each tensor product
- * polynomial at <tt>unit_point</tt>.
+ * Computes the value and the first and second derivatives of each tensor
+ * product polynomial at <tt>unit_point</tt>.
*
- * The size of the vectors must
- * either be equal 0 or equal
- * n(). In the first case, the
- * function will not compute
- * these values.
+ * The size of the vectors must either be equal 0 or equal n(). In the first
+ * case, the function will not compute these values.
*
- * If you need values or
- * derivatives of all tensor
- * product polynomials then use
- * this function, rather than
- * using any of the
- * compute_value(),
- * compute_grad() or
- * compute_grad_grad()
- * functions, see below, in a
- * loop over all tensor product
- * polynomials.
+ * If you need values or derivatives of all tensor product polynomials then
+ * use this function, rather than using any of the compute_value(),
+ * compute_grad() or compute_grad_grad() functions, see below, in a loop
+ * over all tensor product polynomials.
*/
void compute (const Point<dim> &unit_point,
std::vector<double> &values,
std::vector<Tensor<2,dim> > &grad_grads) const;
/**
- * Computes the value of the
- * <tt>i</tt>th tensor product
- * polynomial at
- * <tt>unit_point</tt>. Here <tt>i</tt> is
- * given in tensor product
+ * Computes the value of the <tt>i</tt>th tensor product polynomial at
+ * <tt>unit_point</tt>. Here <tt>i</tt> is given in tensor product
* numbering.
*
- * Note, that using this function
- * within a loop over all tensor
- * product polynomials is not
- * efficient, because then each
- * point value of the underlying
- * (one-dimensional) polynomials
- * is (unnecessarily) computed
- * several times. Instead use
- * the compute() function with
- * <tt>values.size()==</tt>n()
- * to get the point values of all
- * tensor polynomials all at once
- * and in a much more efficient
- * way.
+ * Note, that using this function within a loop over all tensor product
+ * polynomials is not efficient, because then each point value of the
+ * underlying (one-dimensional) polynomials is (unnecessarily) computed
+ * several times. Instead use the compute() function with
+ * <tt>values.size()==</tt>n() to get the point values of all tensor
+ * polynomials all at once and in a much more efficient way.
*/
double compute_value (const unsigned int i,
const Point<dim> &p) const;
/**
- * Computes the grad of the
- * <tt>i</tt>th tensor product
- * polynomial at
- * <tt>unit_point</tt>. Here <tt>i</tt> is
- * given in tensor product
+ * Computes the grad of the <tt>i</tt>th tensor product polynomial at
+ * <tt>unit_point</tt>. Here <tt>i</tt> is given in tensor product
* numbering.
*
- * Note, that using this function
- * within a loop over all tensor
- * product polynomials is not
- * efficient, because then each
- * derivative value of the
- * underlying (one-dimensional)
- * polynomials is (unnecessarily)
- * computed several times.
- * Instead use the compute()
- * function, see above, with
- * <tt>grads.size()==</tt>n()
- * to get the point value of all
- * tensor polynomials all at once
- * and in a much more efficient
- * way.
+ * Note, that using this function within a loop over all tensor product
+ * polynomials is not efficient, because then each derivative value of the
+ * underlying (one-dimensional) polynomials is (unnecessarily) computed
+ * several times. Instead use the compute() function, see above, with
+ * <tt>grads.size()==</tt>n() to get the point value of all tensor
+ * polynomials all at once and in a much more efficient way.
*/
Tensor<1,dim> compute_grad (const unsigned int i,
const Point<dim> &p) const;
/**
- * Computes the second
- * derivative (grad_grad) of the
- * <tt>i</tt>th tensor product
- * polynomial at
- * <tt>unit_point</tt>. Here <tt>i</tt> is
- * given in tensor product
- * numbering.
+ * Computes the second derivative (grad_grad) of the <tt>i</tt>th tensor
+ * product polynomial at <tt>unit_point</tt>. Here <tt>i</tt> is given in
+ * tensor product numbering.
*
- * Note, that using this function
- * within a loop over all tensor
- * product polynomials is not
- * efficient, because then each
- * derivative value of the
- * underlying (one-dimensional)
- * polynomials is (unnecessarily)
- * computed several times.
- * Instead use the compute()
- * function, see above, with
- * <tt>grad_grads.size()==</tt>n()
- * to get the point value of all
- * tensor polynomials all at once
- * and in a much more efficient
- * way.
+ * Note, that using this function within a loop over all tensor product
+ * polynomials is not efficient, because then each derivative value of the
+ * underlying (one-dimensional) polynomials is (unnecessarily) computed
+ * several times. Instead use the compute() function, see above, with
+ * <tt>grad_grads.size()==</tt>n() to get the point value of all tensor
+ * polynomials all at once and in a much more efficient way.
*/
Tensor<2,dim> compute_grad_grad (const unsigned int i,
const Point<dim> &p) const;
/**
- * Returns the number of tensor
- * product polynomials. For <i>n</i>
- * 1d polynomials this is <i>n<sup>dim</sup></i>.
+ * Returns the number of tensor product polynomials. For <i>n</i> 1d
+ * polynomials this is <i>n<sup>dim</sup></i>.
*/
unsigned int n () const;
-private:
+protected:
/**
- * Copy of the vector <tt>pols</tt> of
- * polynomials given to the
- * constructor.
+ * Copy of the vector <tt>pols</tt> of polynomials given to the constructor.
*/
- std::vector<Polynomials::Polynomial<double> > polynomials;
+ std::vector<POLY> polynomials;
/**
- * Number of tensor product
- * polynomials. See n().
+ * Number of tensor product polynomials. See n().
*/
unsigned int n_tensor_pols;
/**
- * Index map for reordering the
- * polynomials.
+ * Index map for reordering the polynomials.
*/
std::vector<unsigned int> index_map;
/**
- * Index map for reordering the
- * polynomials.
+ * Index map for reordering the polynomials.
*/
std::vector<unsigned int> index_map_inverse;
/**
- * Each tensor product polynomial
- * <i>i</i> is a product of
- * one-dimensional polynomials in
- * each space direction. Compute
- * the indices of these
- * one-dimensional polynomials
- * for each space direction,
- * given the index <i>i</i>.
+ * Each tensor product polynomial <i>i</i> is a product of one-dimensional
+ * polynomials in each space direction. Compute the indices of these
+ * one-dimensional polynomials for each space direction, given the index
+ * <i>i</i>.
*/
- // fix to avoid compiler warnings about zero
- // length arrays
+ // fix to avoid compiler warnings about zero length arrays
void compute_index (const unsigned int i,
unsigned int (&indices)[(dim>0?dim:1)]) const;
};
-#ifndef DOXYGEN
-
-template <int dim>
-inline
-const std::vector<unsigned int> &
-TensorProductPolynomials<dim>::get_numbering() const
-{
- return index_map;
-}
-
-
-template <int dim>
-inline
-const std::vector<unsigned int> &
-TensorProductPolynomials<dim>::get_numbering_inverse() const
-{
- return index_map_inverse;
-}
-
-
-#endif // DOXYGEN
/**
{
public:
/**
- * Constructor. <tt>pols</tt> is a
- * table of one-dimensional
- * polynomials. The number of
- * rows in this table should be
- * equal to the space dimension,
- * with the elements of each row
- * giving the polynomials that
- * shall be used in this
- * particular coordinate
- * direction. These polynomials
- * may vary between coordinates,
- * as well as their number.
+ * Constructor. <tt>pols</tt> is a table of one-dimensional polynomials. The
+ * number of rows in this table should be equal to the space dimension, with
+ * the elements of each row giving the polynomials that shall be used in
+ * this particular coordinate direction. These polynomials may vary between
+ * coordinates, as well as their number.
*/
AnisotropicPolynomials (const std::vector<std::vector<Polynomials::Polynomial<double> > > &pols);
/**
- * Computes the value and the
- * first and second derivatives
- * of each tensor product
- * polynomial at <tt>unit_point</tt>.
+ * Computes the value and the first and second derivatives of each tensor
+ * product polynomial at <tt>unit_point</tt>.
*
- * The size of the vectors must
- * either be equal <tt>0</tt> or equal
- * <tt>n_tensor_pols</tt>. In the
- * first case, the function will
- * not compute these values.
+ * The size of the vectors must either be equal <tt>0</tt> or equal
+ * <tt>n_tensor_pols</tt>. In the first case, the function will not compute
+ * these values.
*
- * If you need values or
- * derivatives of all tensor
- * product polynomials then use
- * this function, rather than
- * using any of the
- * <tt>compute_value</tt>,
- * <tt>compute_grad</tt> or
- * <tt>compute_grad_grad</tt>
- * functions, see below, in a
- * loop over all tensor product
- * polynomials.
+ * If you need values or derivatives of all tensor product polynomials then
+ * use this function, rather than using any of the <tt>compute_value</tt>,
+ * <tt>compute_grad</tt> or <tt>compute_grad_grad</tt> functions, see below,
+ * in a loop over all tensor product polynomials.
*/
void compute (const Point<dim> &unit_point,
std::vector<double> &values,
std::vector<Tensor<2,dim> > &grad_grads) const;
/**
- * Computes the value of the
- * <tt>i</tt>th tensor product
- * polynomial at
- * <tt>unit_point</tt>. Here <tt>i</tt> is
- * given in tensor product
+ * Computes the value of the <tt>i</tt>th tensor product polynomial at
+ * <tt>unit_point</tt>. Here <tt>i</tt> is given in tensor product
* numbering.
*
- * Note, that using this function
- * within a loop over all tensor
- * product polynomials is not
- * efficient, because then each
- * point value of the underlying
- * (one-dimensional) polynomials
- * is (unnecessarily) computed
- * several times. Instead use
- * the <tt>compute</tt> function, see
- * above, with
- * <tt>values.size()==n_tensor_pols</tt>
- * to get the point values of all
- * tensor polynomials all at once
- * and in a much more efficient
- * way.
+ * Note, that using this function within a loop over all tensor product
+ * polynomials is not efficient, because then each point value of the
+ * underlying (one-dimensional) polynomials is (unnecessarily) computed
+ * several times. Instead use the <tt>compute</tt> function, see above,
+ * with <tt>values.size()==n_tensor_pols</tt> to get the point values of all
+ * tensor polynomials all at once and in a much more efficient way.
*/
double compute_value (const unsigned int i,
const Point<dim> &p) const;
/**
- * Computes the grad of the
- * <tt>i</tt>th tensor product
- * polynomial at
- * <tt>unit_point</tt>. Here <tt>i</tt> is
- * given in tensor product
+ * Computes the grad of the <tt>i</tt>th tensor product polynomial at
+ * <tt>unit_point</tt>. Here <tt>i</tt> is given in tensor product
* numbering.
*
- * Note, that using this function
- * within a loop over all tensor
- * product polynomials is not
- * efficient, because then each
- * derivative value of the
- * underlying (one-dimensional)
- * polynomials is (unnecessarily)
- * computed several times.
- * Instead use the <tt>compute</tt>
- * function, see above, with
- * <tt>grads.size()==n_tensor_pols</tt>
- * to get the point value of all
- * tensor polynomials all at once
- * and in a much more efficient
- * way.
+ * Note, that using this function within a loop over all tensor product
+ * polynomials is not efficient, because then each derivative value of the
+ * underlying (one-dimensional) polynomials is (unnecessarily) computed
+ * several times. Instead use the <tt>compute</tt> function, see above,
+ * with <tt>grads.size()==n_tensor_pols</tt> to get the point value of all
+ * tensor polynomials all at once and in a much more efficient way.
*/
Tensor<1,dim> compute_grad (const unsigned int i,
const Point<dim> &p) const;
/**
- * Computes the second
- * derivative (grad_grad) of the
- * <tt>i</tt>th tensor product
- * polynomial at
- * <tt>unit_point</tt>. Here <tt>i</tt> is
- * given in tensor product
- * numbering.
+ * Computes the second derivative (grad_grad) of the <tt>i</tt>th tensor
+ * product polynomial at <tt>unit_point</tt>. Here <tt>i</tt> is given in
+ * tensor product numbering.
*
- * Note, that using this function
- * within a loop over all tensor
- * product polynomials is not
- * efficient, because then each
- * derivative value of the
- * underlying (one-dimensional)
- * polynomials is (unnecessarily)
- * computed several times.
- * Instead use the <tt>compute</tt>
- * function, see above, with
- * <tt>grad_grads.size()==n_tensor_pols</tt>
- * to get the point value of all
- * tensor polynomials all at once
- * and in a much more efficient
- * way.
+ * Note, that using this function within a loop over all tensor product
+ * polynomials is not efficient, because then each derivative value of the
+ * underlying (one-dimensional) polynomials is (unnecessarily) computed
+ * several times. Instead use the <tt>compute</tt> function, see above,
+ * with <tt>grad_grads.size()==n_tensor_pols</tt> to get the point value of
+ * all tensor polynomials all at once and in a much more efficient way.
*/
Tensor<2,dim> compute_grad_grad (const unsigned int i,
const Point<dim> &p) const;
/**
- * Returns the number of tensor
- * product polynomials. It is the
- * product of the number of
- * polynomials in each coordinate
- * direction.
+ * Returns the number of tensor product polynomials. It is the product of
+ * the number of polynomials in each coordinate direction.
*/
unsigned int n () const;
private:
/**
- * Copy of the vector <tt>pols</tt> of
- * polynomials given to the
- * constructor.
+ * Copy of the vector <tt>pols</tt> of polynomials given to the constructor.
*/
std::vector<std::vector<Polynomials::Polynomial<double> > > polynomials;
/**
- * Number of tensor product
- * polynomials. This is
- * <tt>Nx*Ny*Nz</tt>, or with terms
- * dropped if the number of space
- * dimensions is less than 3.
+ * Number of tensor product polynomials. This is <tt>Nx*Ny*Nz</tt>, or with
+ * terms dropped if the number of space dimensions is less than 3.
*/
unsigned int n_tensor_pols;
/**
- * Each tensor product polynomial
- * @þ{i} is a product of
- * one-dimensional polynomials in
- * each space direction. Compute
- * the indices of these
- * one-dimensional polynomials
- * for each space direction,
- * given the index <tt>i</tt>.
+ * Each tensor product polynomial @þ{i} is a product of one-dimensional
+ * polynomials in each space direction. Compute the indices of these
+ * one-dimensional polynomials for each space direction, given the index
+ * <tt>i</tt>.
*/
void compute_index (const unsigned int i,
unsigned int (&indices)[dim]) const;
/**
- * Given the input to the
- * constructor, compute
- * <tt>n_tensor_pols</tt>.
+ * Given the input to the constructor, compute <tt>n_tensor_pols</tt>.
*/
static
unsigned int
#ifndef DOXYGEN
-/* -------------- declaration of explicit specializations --- */
-
-template <>
-void
-TensorProductPolynomials<1>::compute_index(const unsigned int n,
- unsigned int (&index)[1]) const;
-template <>
-void
-TensorProductPolynomials<2>::compute_index(const unsigned int n,
- unsigned int (&index)[2]) const;
-template <>
-void
-TensorProductPolynomials<3>::compute_index(const unsigned int n,
- unsigned int (&index)[3]) const;
-
/* ---------------- template and inline functions ---------- */
-template <int dim>
+template <int dim, typename POLY>
template <class Pol>
-TensorProductPolynomials<dim>::
+inline
+TensorProductPolynomials<dim,POLY>::
TensorProductPolynomials(const std::vector<Pol> &pols)
:
polynomials (pols.begin(), pols.end()),
index_map(n_tensor_pols),
index_map_inverse(n_tensor_pols)
{
- // per default set this index map
- // to identity. This map can be
- // changed by the user through the
- // set_numbering() function
+ // per default set this index map to identity. This map can be changed by
+ // the user through the set_numbering() function
for (unsigned int i=0; i<n_tensor_pols; ++i)
{
index_map[i]=i;
-template <>
-void
-AnisotropicPolynomials<1>::compute_index(const unsigned int n,
- unsigned int (&index)[1]) const;
-template <>
-void
-AnisotropicPolynomials<2>::compute_index(const unsigned int n,
- unsigned int (&index)[2]) const;
-template <>
-void
-AnisotropicPolynomials<3>::compute_index(const unsigned int n,
- unsigned int (&index)[3]) const;
+template <int dim, typename POLY>
+inline
+unsigned int
+TensorProductPolynomials<dim,POLY>::n() const
+{
+ if (dim == 0)
+ return numbers::invalid_unsigned_int;
+ else
+ return n_tensor_pols;
+}
+
+
+
+template <int dim, typename POLY>
+inline
+const std::vector<unsigned int> &
+TensorProductPolynomials<dim,POLY>::get_numbering() const
+{
+ return index_map;
+}
+
+
+template <int dim, typename POLY>
+inline
+const std::vector<unsigned int> &
+TensorProductPolynomials<dim,POLY>::get_numbering_inverse() const
+{
+ return index_map_inverse;
+}
+
+
#endif // DOXYGEN
DEAL_II_NAMESPACE_CLOSE
#include <deal.II/base/tensor.h>
#include <deal.II/base/point.h>
#include <deal.II/base/polynomial.h>
+#include <deal.II/base/tensor_product_polynomials.h>
#include <deal.II/base/utilities.h>
#include <vector>
DEAL_II_NAMESPACE_OPEN
-//TODO: This class is an almost exact copy of the TensorProductPolynomials class. They should be unified. A simple way to do that would be to derive this one from the other and in the implemented member functions simply defer to the corresponding function in the base class whenever appropriate.
-
/**
* @addtogroup Polynomials
* @{
*/
/**
- * Tensor product of given polynomials.
- *
- * Given a vector of <i>n</i> one-dimensional polynomials
- * <i>P<sub>1</sub></i> to <i>P<sub>n</sub></i>, this class generates
- * <i>n<sup>dim</sup></i> polynomials of the form
- * <i>Q<sub>ijk</sub>(x,y,z) =
- * P<sub>i</sub>(x)P<sub>j</sub>(y)P<sub>k</sub>(z)</i>and a locally
- * constant function. If the base polynomials are mutually orthogonal
- * on the interval [-1,1] or [0,1], then the tensor product
- * polynomials are orthogonal on [-1,1]<sup>dim</sup> or [0,1]
- * <sup>dim</sup>, respectively.
- *
- * Indexing is as follows: the order of dim-dimensional polynomials is
- * x-coordinates running fastest, then y-coordinate, etc. The first
- * few polynomials are thus <i>P<sub>1</sub>(x)P<sub>1</sub>(y),
- * P<sub>2</sub>(x)P<sub>1</sub>(y), P<sub>3</sub>(x)P<sub>1</sub>(y),
- * ..., P<sub>1</sub>(x)P<sub>2</sub>(y),
- * P<sub>2</sub>(x)P<sub>2</sub>(y), P<sub>3</sub>(x)P<sub>2</sub>(y),
- * ...</i> and likewise in 3d. The locally constant function has the last index
- *
- * The output_indices() function prints the ordering of the
- * dim-dimensional polynomials, i.e. for each polynomial in the
- * polynomial space it gives the indices i,j,k of the one-dimensional
- * polynomials in x,y and z direction. The ordering of the
- * dim-dimensional polynomials can be changed by using the
- * set_numbering() function.
+ * Tensor product of given polynomials and a locally constant function. This
+ * class inherits most of its functionality from TensorProductPolynomials. It
+ * works similarly to that class but adds a constant function for the last
+ * index.
*
- * @author Ralf Hartmann, 2000, 2004, Guido Kanschat, 2000, Wolfgang Bangerth 2003
+ * @author Timo Heister, 2012
*/
template <int dim>
-class TensorProductPolynomialsConst
+class TensorProductPolynomialsConst : public TensorProductPolynomials<dim>
{
public:
/**
static const unsigned int dimension = dim;
/**
- * Constructor. <tt>pols</tt> is
- * a vector of objects that
- * should be derived or otherwise
- * convertible to one-dimensional
- * polynomial objects. It will be
- * copied element by element into
- * a private variable.
+ * Constructor. <tt>pols</tt> is a vector of objects that should be derived
+ * or otherwise convertible to one-dimensional polynomial objects. It will
+ * be copied element by element into a private variable.
*/
template <class Pol>
TensorProductPolynomialsConst (const std::vector<Pol> &pols);
/**
- * Prints the list of the indices
- * to <tt>out</tt>.
- */
- void output_indices(std::ostream &out) const;
-
- /**
- * Sets the ordering of the
- * polynomials. Requires
- * <tt>renumber.size()==n()</tt>.
- * Stores a copy of
- * <tt>renumber</tt>.
- */
- void set_numbering(const std::vector<unsigned int> &renumber);
-
- /**
- * Gives read access to the
- * renumber vector.
- */
- const std::vector<unsigned int> &get_numbering() const;
-
- /**
- * Gives read access to the
- * inverse renumber vector.
- */
- const std::vector<unsigned int> &get_numbering_inverse() const;
-
- /**
- * Computes the value and the
- * first and second derivatives
- * of each tensor product
- * polynomial at <tt>unit_point</tt>.
+ * Computes the value and the first and second derivatives of each tensor
+ * product polynomial at <tt>unit_point</tt>.
*
- * The size of the vectors must
- * either be equal 0 or equal
- * n(). In the first case, the
- * function will not compute
- * these values.
+ * The size of the vectors must either be equal 0 or equal n(). In the first
+ * case, the function will not compute these values.
*
- * If you need values or
- * derivatives of all tensor
- * product polynomials then use
- * this function, rather than
- * using any of the
- * compute_value(),
- * compute_grad() or
- * compute_grad_grad()
- * functions, see below, in a
- * loop over all tensor product
- * polynomials.
+ * If you need values or derivatives of all tensor product polynomials then
+ * use this function, rather than using any of the compute_value(),
+ * compute_grad() or compute_grad_grad() functions, see below, in a loop
+ * over all tensor product polynomials.
*/
void compute (const Point<dim> &unit_point,
std::vector<double> &values,
std::vector<Tensor<2,dim> > &grad_grads) const;
/**
- * Computes the value of the
- * <tt>i</tt>th tensor product
- * polynomial at
- * <tt>unit_point</tt>. Here <tt>i</tt> is
- * given in tensor product
+ * Computes the value of the <tt>i</tt>th tensor product polynomial at
+ * <tt>unit_point</tt>. Here <tt>i</tt> is given in tensor product
* numbering.
*
- * Note, that using this function
- * within a loop over all tensor
- * product polynomials is not
- * efficient, because then each
- * point value of the underlying
- * (one-dimensional) polynomials
- * is (unnecessarily) computed
- * several times. Instead use
- * the compute() function with
- * <tt>values.size()==</tt>n()
- * to get the point values of all
- * tensor polynomials all at once
- * and in a much more efficient
- * way.
+ * Note, that using this function within a loop over all tensor product
+ * polynomials is not efficient, because then each point value of the
+ * underlying (one-dimensional) polynomials is (unnecessarily) computed
+ * several times. Instead use the compute() function with
+ * <tt>values.size()==</tt>n() to get the point values of all tensor
+ * polynomials all at once and in a much more efficient way.
*/
double compute_value (const unsigned int i,
const Point<dim> &p) const;
/**
- * Computes the grad of the
- * <tt>i</tt>th tensor product
- * polynomial at
- * <tt>unit_point</tt>. Here <tt>i</tt> is
- * given in tensor product
+ * Computes the grad of the <tt>i</tt>th tensor product polynomial at
+ * <tt>unit_point</tt>. Here <tt>i</tt> is given in tensor product
* numbering.
*
- * Note, that using this function
- * within a loop over all tensor
- * product polynomials is not
- * efficient, because then each
- * derivative value of the
- * underlying (one-dimensional)
- * polynomials is (unnecessarily)
- * computed several times.
- * Instead use the compute()
- * function, see above, with
- * <tt>grads.size()==</tt>n()
- * to get the point value of all
- * tensor polynomials all at once
- * and in a much more efficient
- * way.
+ * Note, that using this function within a loop over all tensor product
+ * polynomials is not efficient, because then each derivative value of the
+ * underlying (one-dimensional) polynomials is (unnecessarily) computed
+ * several times. Instead use the compute() function, see above, with
+ * <tt>grads.size()==</tt>n() to get the point value of all tensor
+ * polynomials all at once and in a much more efficient way.
*/
Tensor<1,dim> compute_grad (const unsigned int i,
const Point<dim> &p) const;
/**
- * Computes the second
- * derivative (grad_grad) of the
- * <tt>i</tt>th tensor product
- * polynomial at
- * <tt>unit_point</tt>. Here <tt>i</tt> is
- * given in tensor product
- * numbering.
+ * Computes the second derivative (grad_grad) of the <tt>i</tt>th tensor
+ * product polynomial at <tt>unit_point</tt>. Here <tt>i</tt> is given in
+ * tensor product numbering.
*
- * Note, that using this function
- * within a loop over all tensor
- * product polynomials is not
- * efficient, because then each
- * derivative value of the
- * underlying (one-dimensional)
- * polynomials is (unnecessarily)
- * computed several times.
- * Instead use the compute()
- * function, see above, with
- * <tt>grad_grads.size()==</tt>n()
- * to get the point value of all
- * tensor polynomials all at once
- * and in a much more efficient
- * way.
+ * Note, that using this function within a loop over all tensor product
+ * polynomials is not efficient, because then each derivative value of the
+ * underlying (one-dimensional) polynomials is (unnecessarily) computed
+ * several times. Instead use the compute() function, see above, with
+ * <tt>grad_grads.size()==</tt>n() to get the point value of all tensor
+ * polynomials all at once and in a much more efficient way.
*/
Tensor<2,dim> compute_grad_grad (const unsigned int i,
const Point<dim> &p) const;
/**
- * Returns the number of tensor
- * product polynomials plus the constant
- * function. For <i>n</i> 1d polynomials
- * this is <i>n<sup>dim</sup>+1</i>.
+ * Returns the number of tensor product polynomials plus the constant
+ * function. For <i>n</i> 1d polynomials this is <i>n<sup>dim</sup>+1</i>.
*/
unsigned int n () const;
-
-
-private:
- /**
- * Copy of the vector <tt>pols</tt> of
- * polynomials given to the
- * constructor.
- */
- std::vector<Polynomials::Polynomial<double> > polynomials;
-
- /**
- * Number of tensor product
- * polynomials. See n().
- */
- unsigned int n_tensor_pols;
-
- /**
- * Index map for reordering the
- * polynomials.
- */
- std::vector<unsigned int> index_map;
-
- /**
- * Index map for reordering the
- * polynomials.
- */
- std::vector<unsigned int> index_map_inverse;
-
- /**
- * Each tensor product polynomial
- * <i>i</i> is a product of
- * one-dimensional polynomials in
- * each space direction. Compute
- * the indices of these
- * one-dimensional polynomials
- * for each space direction,
- * given the index <i>i</i>.
- */
- // fix to avoid compiler warnings about zero
- // length arrays
- void compute_index (const unsigned int i,
- unsigned int (&indices)[(dim>0?dim:1)]) const;
};
/** @} */
+
+/* ---------------- template and inline functions ---------- */
+
#ifndef DOXYGEN
template <int dim>
+template <class Pol>
inline
-const std::vector<unsigned int> &
-TensorProductPolynomialsConst<dim>::get_numbering() const
+TensorProductPolynomialsConst<dim>::
+TensorProductPolynomialsConst(const std::vector<Pol> &pols)
+ :
+ TensorProductPolynomials<dim>(pols)
{
- return index_map;
+ // append index for renumbering
+ this->index_map.push_back(this->n_tensor_pols);
+ this->index_map_inverse.push_back(this->n_tensor_pols);
}
+
template <int dim>
inline
-const std::vector<unsigned int> &
-TensorProductPolynomialsConst<dim>::get_numbering_inverse() const
+unsigned int
+TensorProductPolynomialsConst<dim>::n() const
{
- return index_map_inverse;
+ return this->n_tensor_pols+1;
}
-#endif // DOXYGEN
-
-#ifndef DOXYGEN
-/* -------------- declaration of explicit specializations --- */
-
-template <>
-void
-TensorProductPolynomialsConst<1>::compute_index(const unsigned int n,
- unsigned int (&index)[1]) const;
template <>
-void
-TensorProductPolynomialsConst<2>::compute_index(const unsigned int n,
- unsigned int (&index)[2]) const;
-template <>
-void
-TensorProductPolynomialsConst<3>::compute_index(const unsigned int n,
- unsigned int (&index)[3]) const;
-
-
-/* ---------------- template and inline functions ---------- */
-
-template <int dim>
-template <class Pol>
-TensorProductPolynomialsConst<dim>::
-TensorProductPolynomialsConst(const std::vector<Pol> &pols)
- :
- polynomials (pols.begin(), pols.end()),
- n_tensor_pols(Utilities::fixed_power<dim>(pols.size())+1),
- index_map(n_tensor_pols),
- index_map_inverse(n_tensor_pols)
+inline
+unsigned int
+TensorProductPolynomialsConst<0>::n() const
{
- // per default set this index map
- // to identity. This map can be
- // changed by the user through the
- // set_numbering() function
- for (unsigned int i=0; i<n_tensor_pols; ++i)
- {
- index_map[i]=i;
- index_map_inverse[i]=i;
- }
+ return numbers::invalid_unsigned_int;
}
+
#endif // DOXYGEN
DEAL_II_NAMESPACE_CLOSE
// $Id$
// Version: $Name$
//
-// Copyright (C) 2011, 2012 by the deal.II authors
+// Copyright (C) 2011, 2012, 2013 by the deal.II authors
//
// This file is subject to QPL and may not be distributed
// without copyright and license information. Please refer
operator [] (const unsigned int comp) const
{
AssertIndexRange (comp, 4);
- return *(reinterpret_cast<const float *>(&data)+comp);;
+ return *(reinterpret_cast<const float *>(&data)+comp);
}
/**
*
* Otherwise, if @p face_1 and @p face_2 are not active faces, this
* function loops recursively over the children of @p face_1 and @p face_2.
- *
- * For this to work @p face_1 and @p face_2 must have the same
- * refinement history, i.e. either @p face_1 and @p face_2 must be active
- * faces or must be isotropically refined and have the same number of
- * child faces that recursively obey this rule. (The anisotropic case
- * is not yet implemented.)
+ * If only one of the two faces is active, then we recursively iterate
+ * over the children of the non-active ones and make sure that the
+ * solution function on the refined side equals that on the non-refined
+ * face in much the same way as we enforce hanging node constraints
+ * at places where differently refined cells come together. (However,
+ * unlike hanging nodes, we do not enforce the requirement that there
+ * be only a difference of one refinement level between the two sides
+ * of the domain you would like to be periodic).
*
* This routine only constrains DoFs that are not already constrained.
* If this routine encounters a DoF that already is constrained (for
* constraint (dofs the entry is constrained to, inhomogeneities) is
* kept and nothing happens.
*
- * Furthermore, no DoFs belonging to (or belonging to any descendant
- * of) @p face_2 get constrained or get marked as being constrained.
- *
* The flags in the @p component_mask (see @ref GlossComponentMask)
* denote which components of the finite element space shall be
* constrained with periodic boundary conditions. If it is left as
* boundary with faces belonging to the second boundary with the help
* of @p orthogonal_equality.
*
- * If this matching is successfull it constrains all DoFs associated
+ * If this matching is successful it constrains all DoFs associated
* with the 'first' boundary to the respective DoFs of the 'second'
* boundary respecting the relative orientation of the two faces.
*
* constraint (dofs the entry is constrained to, inhomogeneities) is
* kept and nothing happens.
*
- * Furthermore, no DoFs belonging to the 'second' boundary get
- * constrained or get marked as being constrained.
- *
* The flags in the last parameter, @p component_mask (see @ref
* GlossComponentMask) denote which components of the finite element space
* shall be constrained with periodic boundary conditions. If it is left
{
public:
/**
- * Base class for internal data.
- * Adds data for second derivatives to
+ * Base class for internal data. Adds data for second derivatives to
* Mapping::InternalDataBase()
*
- * For information about the
- * general purpose of this class,
- * see the documentation of the
- * base class.
+ * For information about the general purpose of this class, see the
+ * documentation of the base class.
*
* @author Guido Kanschat, 2001
*/
{
public:
/**
- * Destructor. Needed to
- * avoid memory leaks with
- * difference quotients.
+ * Destructor. Needed to avoid memory leaks with difference quotients.
*/
virtual ~InternalDataBase ();
/**
- * Initialize some pointers
- * used in the computation of
- * second derivatives by
- * finite differencing of
- * gradients.
+ * Initialize some pointers used in the computation of second derivatives
+ * by finite differencing of gradients.
*/
void initialize_2nd (const FiniteElement<dim,spacedim> *element,
const Mapping<dim,spacedim> &mapping,
const Quadrature<dim> &quadrature);
/**
- * Storage for FEValues
- * objects needed to
- * approximate second
- * derivatives.
+ * Storage for FEValues objects needed to approximate second derivatives.
*
- * The ordering is <i>p+hx</i>,
- * <i>p+hy</i>, <i>p+hz</i>,
- * <i>p-hx</i>, <i>p-hy</i>,
- * <i>p-hz</i>, where unused
- * entries in lower dimensions
- * are missing.
+ * The ordering is <i>p+hx</i>, <i>p+hy</i>, <i>p+hz</i>, <i>p-hx</i>,
+ * <i>p-hy</i>, <i>p-hz</i>, where unused entries in lower dimensions are
+ * missing.
*/
std::vector<FEValues<dim,spacedim>*> differences;
};
const std::vector<ComponentMask> &nonzero_components);
/**
- * Virtual destructor. Makes sure
- * that pointers to this class
- * are deleted properly.
+ * Virtual destructor. Makes sure that pointers to this class are deleted
+ * properly.
*/
virtual ~FiniteElement ();
/**
- * Return a string that uniquely
- * identifies a finite
- * element. The general
- * convention is that this is the
- * class name, followed by the
- * dimension in angle
- * brackets, and the polynomial
- * degree and whatever else is
- * necessary in parentheses. For
- * example, <tt>FE_Q<2>(3)</tt> is the
- * value returned for a cubic
- * element in 2d.
+ * Return a string that uniquely identifies a finite element. The general
+ * convention is that this is the class name, followed by the dimension in
+ * angle brackets, and the polynomial degree and whatever else is necessary
+ * in parentheses. For example, <tt>FE_Q<2>(3)</tt> is the value returned
+ * for a cubic element in 2d.
*
- * Systems of elements have their
- * own naming convention, see the
- * FESystem class.
+ * Systems of elements have their own naming convention, see the FESystem
+ * class.
*/
virtual std::string get_name () const = 0;
/**
- * This operator returns a
- * reference to the present
- * object if the argument given
- * equals to zero. While this
- * does not seem particularly
- * useful, it is helpful in
- * writing code that works with
- * both ::DoFHandler and the hp
- * version hp::DoFHandler, since
- * one can then write code like
- * this:
+ * This operator returns a reference to the present object if the argument
+ * given equals to zero. While this does not seem particularly useful, it is
+ * helpful in writing code that works with both ::DoFHandler and the hp
+ * version hp::DoFHandler, since one can then write code like this:
* @code
* dofs_per_cell
* = dof_handler->get_fe()[cell->active_fe_index()].dofs_per_cell;
* @endcode
*
- * This code doesn't work in both
- * situations without the present
- * operator because
- * DoFHandler::get_fe() returns a
- * finite element, whereas
- * hp::DoFHandler::get_fe()
- * returns a collection of finite
- * elements that doesn't offer a
- * <code>dofs_per_cell</code>
- * member variable: one first has
- * to select which finite element
- * to work on, which is done
- * using the
- * operator[]. Fortunately,
- * <code>cell-@>active_fe_index()</code>
- * also works for non-hp classes
- * and simply returns zero in
- * that case. The present
- * operator[] accepts this zero
- * argument, by returning the
- * finite element with index zero
- * within its collection (that,
- * of course, consists only of
- * the present finite element
- * anyway).
+ * This code doesn't work in both situations without the present operator
+ * because DoFHandler::get_fe() returns a finite element, whereas
+ * hp::DoFHandler::get_fe() returns a collection of finite elements that
+ * doesn't offer a <code>dofs_per_cell</code> member variable: one first has
+ * to select which finite element to work on, which is done using the
+ * operator[]. Fortunately, <code>cell-@>active_fe_index()</code> also works
+ * for non-hp classes and simply returns zero in that case. The present
+ * operator[] accepts this zero argument, by returning the finite element
+ * with index zero within its collection (that, of course, consists only of
+ * the present finite element anyway).
*/
const FiniteElement<dim,spacedim> &operator[] (const unsigned int fe_index) const;
*/
/**
- * Return the value of the
- * @p ith shape function at the
- * point @p p. @p p is a point
- * on the reference element. If
- * the finite element is
- * vector-valued, then return the
- * value of the only non-zero
- * component of the vector value
- * of this shape function. If the
- * shape function has more than
- * one non-zero component (which
- * we refer to with the term
- * non-primitive), then derived
- * classes implementing this
- * function should throw an
- * exception of type
- * ExcShapeFunctionNotPrimitive. In
- * that case, use the
- * shape_value_component()
- * function.
+ * Return the value of the @p ith shape function at the point @p p. @p p is
+ * a point on the reference element. If the finite element is vector-valued,
+ * then return the value of the only non-zero component of the vector value
+ * of this shape function. If the shape function has more than one non-zero
+ * component (which we refer to with the term non-primitive), then derived
+ * classes implementing this function should throw an exception of type
+ * ExcShapeFunctionNotPrimitive. In that case, use the
+ * shape_value_component() function.
*
- * An
- * ExcUnitShapeValuesDoNotExist
- * is thrown if the shape values
- * of the FiniteElement under
- * consideration depends on the
- * shape of the cell in real
- * space.
+ * An ExcUnitShapeValuesDoNotExist is thrown if the shape values of the
+ * FiniteElement under consideration depends on the shape of the cell in
+ * real space.
*/
virtual double shape_value (const unsigned int i,
const Point<dim> &p) const;
/**
- * Just like for shape_value(),
- * but this function will be
- * called when the shape function
- * has more than one non-zero
- * vector component. In that
- * case, this function should
- * return the value of the
- * @p component-th vector
- * component of the @p ith shape
- * function at point @p p.
+ * Just like for shape_value(), but this function will be called when the
+ * shape function has more than one non-zero vector component. In that case,
+ * this function should return the value of the @p component-th vector
+ * component of the @p ith shape function at point @p p.
*/
virtual double shape_value_component (const unsigned int i,
const Point<dim> &p,
const unsigned int component) const;
/**
- * Return the gradient of the
- * @p ith shape function at the
- * point @p p. @p p is a point
- * on the reference element, and
- * likewise the gradient is the
- * gradient on the unit cell with
- * respect to unit cell
- * coordinates. If
- * the finite element is
- * vector-valued, then return the
- * value of the only non-zero
- * component of the vector value
- * of this shape function. If the
- * shape function has more than
- * one non-zero component (which
- * we refer to with the term
- * non-primitive), then derived
- * classes implementing this
- * function should throw an
- * exception of type
- * ExcShapeFunctionNotPrimitive. In
- * that case, use the
- * shape_grad_component()
- * function.
+ * Return the gradient of the @p ith shape function at the point @p p. @p p
+ * is a point on the reference element, and likewise the gradient is the
+ * gradient on the unit cell with respect to unit cell coordinates. If the
+ * finite element is vector-valued, then return the value of the only
+ * non-zero component of the vector value of this shape function. If the
+ * shape function has more than one non-zero component (which we refer to
+ * with the term non-primitive), then derived classes implementing this
+ * function should throw an exception of type
+ * ExcShapeFunctionNotPrimitive. In that case, use the
+ * shape_grad_component() function.
*
- * An
- * ExcUnitShapeValuesDoNotExist
- * is thrown if the shape values
- * of the FiniteElement under
- * consideration depends on the
- * shape of the cell in real
- * space.
+ * An ExcUnitShapeValuesDoNotExist is thrown if the shape values of the
+ * FiniteElement under consideration depends on the shape of the cell in
+ * real space.
*/
virtual Tensor<1,dim> shape_grad (const unsigned int i,
const Point<dim> &p) const;
/**
- * Just like for shape_grad(),
- * but this function will be
- * called when the shape function
- * has more than one non-zero
- * vector component. In that
- * case, this function should
- * return the gradient of the
- * @p component-th vector
- * component of the @p ith shape
- * function at point @p p.
+ * Just like for shape_grad(), but this function will be called when the
+ * shape function has more than one non-zero vector component. In that case,
+ * this function should return the gradient of the @p component-th vector
+ * component of the @p ith shape function at point @p p.
*/
virtual Tensor<1,dim> shape_grad_component (const unsigned int i,
const Point<dim> &p,
const unsigned int component) const;
/**
- * Return the tensor of second
- * derivatives of the @p ith
- * shape function at point @p p
- * on the unit cell. The
- * derivatives are derivatives on
- * the unit cell with respect to
- * unit cell coordinates. If
- * the finite element is
- * vector-valued, then return the
- * value of the only non-zero
- * component of the vector value
- * of this shape function. If the
- * shape function has more than
- * one non-zero component (which
- * we refer to with the term
- * non-primitive), then derived
- * classes implementing this
- * function should throw an
- * exception of type
- * ExcShapeFunctionNotPrimitive. In
- * that case, use the
- * shape_grad_grad_component()
- * function.
+ * Return the tensor of second derivatives of the @p ith shape function at
+ * point @p p on the unit cell. The derivatives are derivatives on the unit
+ * cell with respect to unit cell coordinates. If the finite element is
+ * vector-valued, then return the value of the only non-zero component of
+ * the vector value of this shape function. If the shape function has more
+ * than one non-zero component (which we refer to with the term
+ * non-primitive), then derived classes implementing this function should
+ * throw an exception of type ExcShapeFunctionNotPrimitive. In that case,
+ * use the shape_grad_grad_component() function.
*
- * An
- * ExcUnitShapeValuesDoNotExist
- * is thrown if the shape values
- * of the FiniteElement under
- * consideration depends on the
- * shape of the cell in real
- * space.
+ * An ExcUnitShapeValuesDoNotExist is thrown if the shape values of the
+ * FiniteElement under consideration depends on the shape of the cell in
+ * real space.
*/
virtual Tensor<2,dim> shape_grad_grad (const unsigned int i,
const Point<dim> &p) const;
const Point<dim> &p,
const unsigned int component) const;
/**
- * Check for non-zero values on a
- * face in order to optimize out
- * matrix elements.
+ * Check for non-zero values on a face in order to optimize out matrix
+ * elements.
*
- * This function returns
- * @p true, if the shape
- * function @p shape_index has
- * non-zero values on the face
- * @p face_index.
+ * This function returns @p true, if the shape function @p shape_index has
+ * non-zero values on the face @p face_index.
*
- * A default implementation is
- * provided in this basis class
- * which always returns @p
- * true. This is the safe way to
- * go.
+ * A default implementation is provided in this basis class which always
+ * returns @p true. This is the safe way to go.
*/
virtual bool has_support_on_face (const unsigned int shape_index,
const unsigned int face_index) const;
*/
/**
- * Projection from a fine grid
- * space onto a coarse grid
- * space. If this projection
- * operator is associated with a
- * matrix @p P, then the
- * restriction of this matrix
- * @p P_i to a single child cell
- * is returned here.
- *
- * The matrix @p P is the
- * concatenation or the sum of
- * the cell matrices @p P_i,
- * depending on the
- * #restriction_is_additive_flags. This
- * distinguishes interpolation
- * (concatenation) and projection
- * with respect to scalar
+ * Projection from a fine grid space onto a coarse grid space. If this
+ * projection operator is associated with a matrix @p P, then the
+ * restriction of this matrix @p P_i to a single child cell is returned
+ * here.
+ *
+ * The matrix @p P is the concatenation or the sum of the cell matrices @p
+ * P_i, depending on the #restriction_is_additive_flags. This distinguishes
+ * interpolation (concatenation) and projection with respect to scalar
* products (summation).
*
- * Row and column indices are
- * related to coarse grid and
- * fine grid spaces,
- * respectively, consistent with
- * the definition of the
- * associated operator.
- *
- * If projection matrices are not
- * implemented in the derived
- * finite element class, this
- * function aborts with
- * ExcProjectionVoid. You can
- * check whether this is the case
- * by calling the
- * restriction_is_implemented()
- * or the
- * isotropic_restriction_is_implemented()
- * function.
+ * Row and column indices are related to coarse grid and fine grid spaces,
+ * respectively, consistent with the definition of the associated operator.
+ *
+ * If projection matrices are not implemented in the derived finite element
+ * class, this function aborts with ExcProjectionVoid. You can check whether
+ * this is the case by calling the restriction_is_implemented() or the
+ * isotropic_restriction_is_implemented() function.
*/
- const FullMatrix<double> &
+ virtual const FullMatrix<double> &
get_restriction_matrix (const unsigned int child,
const RefinementCase<dim> &refinement_case=RefinementCase<dim>::isotropic_refinement) const;
/**
* Embedding matrix between grids.
*
- * The identity operator from a
- * coarse grid space into a fine
- * grid space is associated with
- * a matrix @p P. The
- * restriction of this matrix @p P_i to
- * a single child cell is
- * returned here.
- *
- * The matrix @p P is the
- * concatenation, not the sum of
- * the cell matrices
- * @p P_i. That is, if the same
- * non-zero entry <tt>j,k</tt> exists
- * in in two different child
- * matrices @p P_i, the value
- * should be the same in both
- * matrices and it is copied into
- * the matrix @p P only once.
- *
- * Row and column indices are
- * related to fine grid and
- * coarse grid spaces,
- * respectively, consistent with
- * the definition of the
- * associated operator.
- *
- * These matrices are used by
- * routines assembling the
- * prolongation matrix for
- * multi-level methods. Upon
- * assembling the transfer matrix
- * between cells using this
- * matrix array, zero elements in
- * the prolongation matrix are
- * discarded and will not fill up
- * the transfer matrix.
- *
- * If projection matrices are not
- * implemented in the derived
- * finite element class, this
- * function aborts with
- * ExcEmbeddingVoid. You can
- * check whether this is the case
- * by calling the
- * prolongation_is_implemented()
- * or the
- * isotropic_prolongation_is_implemented()
- * function.
+ * The identity operator from a coarse grid space into a fine grid space is
+ * associated with a matrix @p P. The restriction of this matrix @p P_i to a
+ * single child cell is returned here.
+ *
+ * The matrix @p P is the concatenation, not the sum of the cell matrices @p
+ * P_i. That is, if the same non-zero entry <tt>j,k</tt> exists in in two
+ * different child matrices @p P_i, the value should be the same in both
+ * matrices and it is copied into the matrix @p P only once.
+ *
+ * Row and column indices are related to fine grid and coarse grid spaces,
+ * respectively, consistent with the definition of the associated operator.
+ *
+ * These matrices are used by routines assembling the prolongation matrix
+ * for multi-level methods. Upon assembling the transfer matrix between
+ * cells using this matrix array, zero elements in the prolongation matrix
+ * are discarded and will not fill up the transfer matrix.
+ *
+ * If projection matrices are not implemented in the derived finite element
+ * class, this function aborts with ExcEmbeddingVoid. You can check whether
+ * this is the case by calling the prolongation_is_implemented() or the
+ * isotropic_prolongation_is_implemented() function.
*/
- const FullMatrix<double> &
+ virtual const FullMatrix<double> &
get_prolongation_matrix (const unsigned int child,
const RefinementCase<dim> &refinement_case=RefinementCase<dim>::isotropic_refinement) const;
/**
- * Return whether this element implements
- * its prolongation matrices. The return
- * value also indicates whether a call to
- * the get_prolongation_matrix()
- * function will generate an error or
- * not.
- *
- * Note, that this function
- * returns <code>true</code> only
- * if the prolongation matrices of
- * the isotropic and all
- * anisotropic refinement cases
- * are implemented. If you are
- * interested in the prolongation
- * matrices for isotropic
- * refinement only, use the
- * isotropic_prolongation_is_implemented
- * function instead.
- *
- * This function is mostly here in order
- * to allow us to write more efficient
- * test programs which we run on all
- * kinds of weird elements, and for which
- * we simply need to exclude certain
- * tests in case something is not
- * implemented. It will in general
- * probably not be a great help in
- * applications, since there is not much
- * one can do if one needs these features
- * and they are not implemented. This
- * function could be used to check
- * whether a call to
- * <tt>get_prolongation_matrix()</tt> will
- * succeed; however, one then still needs
- * to cope with the lack of information
- * this just expresses.
+ * Return whether this element implements its prolongation matrices. The
+ * return value also indicates whether a call to the
+ * get_prolongation_matrix() function will generate an error or not.
+ *
+ * Note, that this function returns <code>true</code> only if the
+ * prolongation matrices of the isotropic and all anisotropic refinement
+ * cases are implemented. If you are interested in the prolongation matrices
+ * for isotropic refinement only, use the
+ * isotropic_prolongation_is_implemented function instead.
+ *
+ * This function is mostly here in order to allow us to write more efficient
+ * test programs which we run on all kinds of weird elements, and for which
+ * we simply need to exclude certain tests in case something is not
+ * implemented. It will in general probably not be a great help in
+ * applications, since there is not much one can do if one needs these
+ * features and they are not implemented. This function could be used to
+ * check whether a call to <tt>get_prolongation_matrix()</tt> will succeed;
+ * however, one then still needs to cope with the lack of information this
+ * just expresses.
*/
bool prolongation_is_implemented () const;
/**
- * Return whether this element implements
- * its prolongation matrices for isotropic
- * children. The return value also
- * indicates whether a call to the @p
- * get_prolongation_matrix function will
- * generate an error or not.
- *
- * This function is mostly here in order
- * to allow us to write more efficient
- * test programs which we run on all
- * kinds of weird elements, and for which
- * we simply need to exclude certain
- * tests in case something is not
- * implemented. It will in general
- * probably not be a great help in
- * applications, since there is not much
- * one can do if one needs these features
- * and they are not implemented. This
- * function could be used to check
- * whether a call to
- * <tt>get_prolongation_matrix()</tt> will
- * succeed; however, one then still needs
- * to cope with the lack of information
- * this just expresses.
+ * Return whether this element implements its prolongation matrices for
+ * isotropic children. The return value also indicates whether a call to the
+ * @p get_prolongation_matrix function will generate an error or not.
+ *
+ * This function is mostly here in order to allow us to write more efficient
+ * test programs which we run on all kinds of weird elements, and for which
+ * we simply need to exclude certain tests in case something is not
+ * implemented. It will in general probably not be a great help in
+ * applications, since there is not much one can do if one needs these
+ * features and they are not implemented. This function could be used to
+ * check whether a call to <tt>get_prolongation_matrix()</tt> will succeed;
+ * however, one then still needs to cope with the lack of information this
+ * just expresses.
*/
bool isotropic_prolongation_is_implemented () const;
/**
- * Return whether this element implements
- * its restriction matrices. The return
- * value also indicates whether a call to
- * the get_restriction_matrix()
- * function will generate an error or
- * not.
- *
- * Note, that this function
- * returns <code>true</code> only
- * if the restriction matrices of
- * the isotropic and all
- * anisotropic refinement cases
- * are implemented. If you are
- * interested in the restriction
- * matrices for isotropic
- * refinement only, use the
- * isotropic_restriction_is_implemented
- * function instead.
- *
- * This function is mostly here in order
- * to allow us to write more efficient
- * test programs which we run on all
- * kinds of weird elements, and for which
- * we simply need to exclude certain
- * tests in case something is not
- * implemented. It will in general
- * probably not be a great help in
- * applications, since there is not much
- * one can do if one needs these features
- * and they are not implemented. This
- * function could be used to check
- * whether a call to
- * <tt>get_restriction_matrix()</tt> will
- * succeed; however, one then still needs
- * to cope with the lack of information
- * this just expresses.
+ * Return whether this element implements its restriction matrices. The
+ * return value also indicates whether a call to the
+ * get_restriction_matrix() function will generate an error or not.
+ *
+ * Note, that this function returns <code>true</code> only if the
+ * restriction matrices of the isotropic and all anisotropic refinement
+ * cases are implemented. If you are interested in the restriction matrices
+ * for isotropic refinement only, use the
+ * isotropic_restriction_is_implemented function instead.
+ *
+ * This function is mostly here in order to allow us to write more efficient
+ * test programs which we run on all kinds of weird elements, and for which
+ * we simply need to exclude certain tests in case something is not
+ * implemented. It will in general probably not be a great help in
+ * applications, since there is not much one can do if one needs these
+ * features and they are not implemented. This function could be used to
+ * check whether a call to <tt>get_restriction_matrix()</tt> will succeed;
+ * however, one then still needs to cope with the lack of information this
+ * just expresses.
*/
bool restriction_is_implemented () const;
/**
- * Return whether this element implements
- * its restriction matrices for isotropic
- * children. The return value also
- * indicates whether a call to the @p
- * get_restriction_matrix function will
- * generate an error or not.
- *
- * This function is mostly here in order
- * to allow us to write more efficient
- * test programs which we run on all
- * kinds of weird elements, and for which
- * we simply need to exclude certain
- * tests in case something is not
- * implemented. It will in general
- * probably not be a great help in
- * applications, since there is not much
- * one can do if one needs these features
- * and they are not implemented. This
- * function could be used to check
- * whether a call to
- * <tt>get_restriction_matrix()</tt> will
- * succeed; however, one then still needs
- * to cope with the lack of information
- * this just expresses.
+ * Return whether this element implements its restriction matrices for
+ * isotropic children. The return value also indicates whether a call to the
+ * @p get_restriction_matrix function will generate an error or not.
+ *
+ * This function is mostly here in order to allow us to write more efficient
+ * test programs which we run on all kinds of weird elements, and for which
+ * we simply need to exclude certain tests in case something is not
+ * implemented. It will in general probably not be a great help in
+ * applications, since there is not much one can do if one needs these
+ * features and they are not implemented. This function could be used to
+ * check whether a call to <tt>get_restriction_matrix()</tt> will succeed;
+ * however, one then still needs to cope with the lack of information this
+ * just expresses.
*/
bool isotropic_restriction_is_implemented () const;
/**
- * Access the
- * #restriction_is_additive_flags
- * field. See there for more
+ * Access the #restriction_is_additive_flags field. See there for more
* information on its contents.
*
- * The index must be between zero
- * and the number of shape
- * functions of this element.
+ * The index must be between zero and the number of shape functions of this
+ * element.
*/
bool restriction_is_additive (const unsigned int index) const;
/**
- * Return a readonly reference to
- * the matrix which describes the
- * constraints at the interface
- * between a refined and an
- * unrefined cell.
- *
- * The matrix is obviously empty
- * in only one dimension,
- * since there are no constraints
- * then.
- *
- * Note that some finite elements
- * do not (yet) implement hanging
- * node constraints. If this is
- * the case, then this function
- * will generate an exception,
- * since no useful return value
- * can be generated. If you
- * should have a way to live with
- * this, then you might want to
- * use the
- * constraints_are_implemented()
- * function to check up front
- * whethehr this function will
- * succeed or generate the
- * exception.
+ * Return a read only reference to the matrix which describes the
+ * constraints at the interface between a refined and an unrefined cell.
+ *
+ * The matrix is obviously empty in only one dimension, since there are no
+ * constraints then.
+ *
+ * Note that some finite elements do not (yet) implement hanging node
+ * constraints. If this is the case, then this function will generate an
+ * exception, since no useful return value can be generated. If you should
+ * have a way to live with this, then you might want to use the
+ * constraints_are_implemented() function to check up front whether this
+ * function will succeed or generate the exception.
*/
const FullMatrix<double> &constraints (const dealii::internal::SubfaceCase<dim> &subface_case=dealii::internal::SubfaceCase<dim>::case_isotropic) const;
/**
- * Return whether this element
- * implements its hanging node
- * constraints. The return value
- * also indicates whether a call
- * to the constraints() function
+ * Return whether this element implements its hanging node constraints. The
+ * return value also indicates whether a call to the constraints() function
* will generate an error or not.
*
- * This function is mostly here
- * in order to allow us to write
- * more efficient test programs
- * which we run on all kinds of
- * weird elements, and for which
- * we simply need to exclude
- * certain tests in case hanging
- * node constraints are not
- * implemented. It will in
- * general probably not be a
- * great help in applications,
- * since there is not much one
- * can do if one needs hanging
- * node constraints and they are
- * not implemented. This function
- * could be used to check whether
- * a call to <tt>constraints()</tt>
- * will succeed; however, one
- * then still needs to cope with
- * the lack of information this
+ * This function is mostly here in order to allow us to write more efficient
+ * test programs which we run on all kinds of weird elements, and for which
+ * we simply need to exclude certain tests in case hanging node constraints
+ * are not implemented. It will in general probably not be a great help in
+ * applications, since there is not much one can do if one needs hanging
+ * node constraints and they are not implemented. This function could be
+ * used to check whether a call to <tt>constraints()</tt> will succeed;
+ * however, one then still needs to cope with the lack of information this
* just expresses.
*/
bool constraints_are_implemented (const dealii::internal::SubfaceCase<dim> &subface_case=dealii::internal::SubfaceCase<dim>::case_isotropic) const;
/**
- * Return whether this element
- * implements its hanging node
- * constraints in the new way,
- * which has to be used to make
- * elements "hp compatible".
- * That means, the element properly
- * implements the
- * get_face_interpolation_matrix
- * and get_subface_interpolation_matrix
- * methods. Therefore the return
- * value also indicates whether a call
- * to the get_face_interpolation_matrix()
- * method and the get_subface_interpolation_matrix()
- * method will generate an error or not.
- *
- * Currently the main purpose of this
- * function is to allow the
- * make_hanging_node_constraints method
- * to decide whether the new procedures,
- * which are supposed to work in the hp
- * framework can be used, or if the old
- * well verified but not hp capable
- * functions should be used. Once the
- * transition to the new scheme for
- * computing the interface constraints is
- * complete, this function will be
- * superfluous and will probably go away.
- *
- * Derived classes should implement this
- * function accordingly. The default
- * assumption is that a finite element
- * does not provide hp capable face
- * interpolation, and the default
- * implementation therefore returns @p
- * false.
+ * Return whether this element implements its hanging node constraints in
+ * the new way, which has to be used to make elements "hp compatible". That
+ * means, the element properly implements the get_face_interpolation_matrix
+ * and get_subface_interpolation_matrix methods. Therefore the return value
+ * also indicates whether a call to the get_face_interpolation_matrix()
+ * method and the get_subface_interpolation_matrix() method will generate an
+ * error or not.
+ *
+ * Currently the main purpose of this function is to allow the
+ * make_hanging_node_constraints method to decide whether the new
+ * procedures, which are supposed to work in the hp framework can be used,
+ * or if the old well verified but not hp capable functions should be used.
+ * Once the transition to the new scheme for computing the interface
+ * constraints is complete, this function will be superfluous and will
+ * probably go away.
+ *
+ * Derived classes should implement this function accordingly. The default
+ * assumption is that a finite element does not provide hp capable face
+ * interpolation, and the default implementation therefore returns @p false.
*/
virtual bool hp_constraints_are_implemented () const;
/**
- * Return the matrix
- * interpolating from the given
- * finite element to the present
- * one. The size of the matrix is
- * then #dofs_per_cell times
+ * Return the matrix interpolating from the given finite element to the
+ * present one. The size of the matrix is then #dofs_per_cell times
* <tt>source.#dofs_per_cell</tt>.
*
- * Derived elements will have to
- * implement this function. They
- * may only provide interpolation
- * matrices for certain source
- * finite elements, for example
- * those from the same family. If
- * they don't implement
- * interpolation from a given
- * element, then they must throw
- * an exception of type
+ * Derived elements will have to implement this function. They may only
+ * provide interpolation matrices for certain source finite elements, for
+ * example those from the same family. If they don't implement interpolation
+ * from a given element, then they must throw an exception of type
* ExcInterpolationNotImplemented.
*/
virtual void
/**
- * Return the matrix
- * interpolating from a face of
- * of one element to the face of
- * the neighboring element.
- * The size of the matrix is
- * then <tt>source.#dofs_per_face</tt> times
- * <tt>this->#dofs_per_face</tt>.
+ * Return the matrix interpolating from a face of of one element to the face
+ * of the neighboring element. The size of the matrix is then
+ * <tt>source.#dofs_per_face</tt> times <tt>this->#dofs_per_face</tt>.
*
- * Derived elements will have to
- * implement this function. They
- * may only provide interpolation
- * matrices for certain source
- * finite elements, for example
- * those from the same family. If
- * they don't implement
- * interpolation from a given
- * element, then they must throw
- * an exception of type
+ * Derived elements will have to implement this function. They may only
+ * provide interpolation matrices for certain source finite elements, for
+ * example those from the same family. If they don't implement interpolation
+ * from a given element, then they must throw an exception of type
* ExcInterpolationNotImplemented.
*/
virtual void
/**
- * Return the matrix
- * interpolating from a face of
- * of one element to the subface of
- * the neighboring element.
- * The size of the matrix is
- * then <tt>source.#dofs_per_face</tt> times
- * <tt>this->#dofs_per_face</tt>.
- *
- * Derived elements will have to
- * implement this function. They
- * may only provide interpolation
- * matrices for certain source
- * finite elements, for example
- * those from the same family. If
- * they don't implement
- * interpolation from a given
- * element, then they must throw
- * an exception of type
+ * Return the matrix interpolating from a face of of one element to the
+ * subface of the neighboring element. The size of the matrix is then
+ * <tt>source.#dofs_per_face</tt> times <tt>this->#dofs_per_face</tt>.
+ *
+ * Derived elements will have to implement this function. They may only
+ * provide interpolation matrices for certain source finite elements, for
+ * example those from the same family. If they don't implement interpolation
+ * from a given element, then they must throw an exception of type
* ExcInterpolationNotImplemented.
*/
virtual void
hp_quad_dof_identities (const FiniteElement<dim,spacedim> &fe_other) const;
/**
- * Return whether this element dominates
- * the one given as argument when they
- * meet at a common face,
- * whether it is the other way around,
- * whether neither dominates, or if
- * either could dominate.
+ * Return whether this element dominates the one given as argument when they
+ * meet at a common face, whether it is the other way around, whether
+ * neither dominates, or if either could dominate.
*
- * For a definition of domination, see
- * FiniteElementBase::Domination and in
+ * For a definition of domination, see FiniteElementBase::Domination and in
* particular the @ref hp_paper "hp paper".
*/
virtual
//@}
/**
- * Comparison operator. We also
- * check for equality of the
- * constraint matrix, which is
- * quite an expensive operation.
- * Do therefore use this function
- * with care, if possible only
- * for debugging purposes.
+ * Comparison operator. We also check for equality of the constraint matrix,
+ * which is quite an expensive operation. Do therefore use this function
+ * with care, if possible only for debugging purposes.
*
- * Since this function is not
- * that important, we avoid an
- * implementational question
- * about comparing arrays and do
- * not compare the matrix arrays
- * #restriction and
- * #prolongation.
+ * Since this function is not that important, we avoid an implementational
+ * question about comparing arrays and do not compare the matrix arrays
+ * #restriction and #prolongation.
*/
bool operator == (const FiniteElement<dim,spacedim> &) const;
* @{
*/
/**
- * Compute vector component and
- * index of this shape function
- * within the shape functions
- * corresponding to this
- * component from the index of a
- * shape function within this
- * finite element.
+ * Compute vector component and index of this shape function within the
+ * shape functions corresponding to this component from the index of a shape
+ * function within this finite element.
*
- * If the element is scalar, then
- * the component is always zero,
- * and the index within this
- * component is equal to the
- * overall index.
- *
- * If the shape function
- * referenced has more than one
- * non-zero component, then it
- * cannot be associated with one
- * vector component, and an
- * exception of type
- * ExcShapeFunctionNotPrimitive
- * will be raised.
- *
- * Note that if the element is
- * composed of other (base)
- * elements, and a base element
- * has more than one component
- * but all its shape functions
- * are primitive (i.e. are
- * non-zero in only one
- * component), then this mapping
- * contains valid
- * information. However, the
- * index of a shape function of
- * this element within one
- * component (i.e. the second
- * number of the respective entry
- * of this array) does not
- * indicate the index of the
- * respective shape function
- * within the base element (since
- * that has more than one
- * vector-component). For this
- * information, refer to the
- * #system_to_base_table field
- * and the
- * system_to_base_index()
- * function.
+ * If the element is scalar, then the component is always zero, and the
+ * index within this component is equal to the overall index.
+ *
+ * If the shape function referenced has more than one non-zero component,
+ * then it cannot be associated with one vector component, and an exception
+ * of type ExcShapeFunctionNotPrimitive will be raised.
+ *
+ * Note that if the element is composed of other (base) elements, and a base
+ * element has more than one component but all its shape functions are
+ * primitive (i.e. are non-zero in only one component), then this mapping
+ * contains valid information. However, the index of a shape function of
+ * this element within one component (i.e. the second number of the
+ * respective entry of this array) does not indicate the index of the
+ * respective shape function within the base element (since that has more
+ * than one vector-component). For this information, refer to the
+ * #system_to_base_table field and the system_to_base_index() function.
*
- * The use of this function is
- * explained extensively in the
- * step-8 and @ref
- * step_20 "step-20" tutorial
- * programs as well as in the
- * @ref vector_valued module.
+ * The use of this function is explained extensively in the step-8 and @ref
+ * step_20 "step-20" tutorial programs as well as in the @ref vector_valued
+ * module.
*/
std::pair<unsigned int, unsigned int>
system_to_component_index (const unsigned int index) const;
/**
- * Compute the shape function for
- * the given vector component and
- * index.
+ * Compute the shape function for the given vector component and index.
*
- * If the element is scalar, then
- * the component must be zero,
- * and the index within this
- * component is equal to the
- * overall index.
+ * If the element is scalar, then the component must be zero, and the index
+ * within this component is equal to the overall index.
*
- * This is the opposite operation
- * from the system_to_component_index()
+ * This is the opposite operation from the system_to_component_index()
* function.
*/
unsigned int component_to_system_index(const unsigned int component,
const unsigned int index) const;
/**
- * Same as
- * system_to_component_index(),
- * but do it for shape functions
- * and their indices on a
- * face. The range of allowed
- * indices is therefore
+ * Same as system_to_component_index(), but do it for shape functions and
+ * their indices on a face. The range of allowed indices is therefore
* 0..#dofs_per_face.
*
- * You will rarely need this
- * function in application
- * programs, since almost all
- * application codes only need to
- * deal with cell indices, not
- * face indices. The function is
- * mainly there for use inside
- * the library.
+ * You will rarely need this function in application programs, since almost
+ * all application codes only need to deal with cell indices, not face
+ * indices. The function is mainly there for use inside the library.
*/
std::pair<unsigned int, unsigned int>
face_system_to_component_index (const unsigned int index) const;
/**
- * For faces with non-standard
- * face_orientation in 3D, the dofs on
- * faces (quads) have to be permuted in
- * order to be combined with the correct
- * shape functions. Given a local dof @p
- * index on a quad, return the local index,
- * if the face has non-standard
- * face_orientation, face_flip or
- * face_rotation. In 2D and 1D there is no
- * need for permutation and consequently
- * an exception is thrown.
+ * For faces with non-standard face_orientation in 3D, the dofs on faces
+ * (quads) have to be permuted in order to be combined with the correct
+ * shape functions. Given a local dof @p index on a quad, return the local
+ * index, if the face has non-standard face_orientation, face_flip or
+ * face_rotation. In 2D and 1D there is no need for permutation and
+ * consequently an exception is thrown.
*/
unsigned int adjust_quad_dof_index_for_face_orientation (const unsigned int index,
const bool face_orientation,
const bool face_rotation) const;
/**
- * For lines with non-standard
- * line_orientation in 3D, the dofs on
- * lines have to be permuted in order to be
- * combined with the correct shape
- * functions. Given a local dof @p index on
- * a line, return the local index, if the
- * line has non-standard
- * line_orientation. In 2D and 1D there is
- * no need for permutation, so the given
- * index is simply returned.
+ * For lines with non-standard line_orientation in 3D, the dofs on lines
+ * have to be permuted in order to be combined with the correct shape
+ * functions. Given a local dof @p index on a line, return the local index,
+ * if the line has non-standard line_orientation. In 2D and 1D there is no
+ * need for permutation, so the given index is simply returned.
*/
unsigned int adjust_line_dof_index_for_line_orientation (const unsigned int index,
const bool line_orientation) const;
/**
- * Return in which of the vector
- * components of this finite
- * element the @p ith shape
- * function is non-zero. The
- * length of the returned array
- * is equal to the number of
- * vector components of this
- * element.
+ * Return in which of the vector components of this finite element the @p
+ * ith shape function is non-zero. The length of the returned array is equal
+ * to the number of vector components of this element.
+ *
+ * For most finite element spaces, the result of this function will be a
+ * vector with exactly one element being @p true, since for most spaces the
+ * individual vector components are independent. In that case, the component
+ * with the single zero is also the first element of what
+ * system_to_component_index() returns.
*
- * For most finite element
- * spaces, the result of this
- * function will be a vector with
- * exactly one element being
- * @p true, since for most
- * spaces the individual vector
- * components are independent. In
- * that case, the component with
- * the single zero is also the
- * first element of what
- * system_to_component_index()
- * returns.
- *
- * Only for those spaces that couple the
- * components, for example to make a
- * shape function divergence free, will
- * there be more than one @p true entry.
- * Elements for which this is true are
- * called non-primitive (see
- * @ref GlossPrimitive).
+ * Only for those spaces that couple the components, for example to make a
+ * shape function divergence free, will there be more than one @p true
+ * entry. Elements for which this is true are called non-primitive (see
+ * @ref GlossPrimitive).
*/
const ComponentMask &
get_nonzero_components (const unsigned int i) const;
/**
- * Return in how many vector
- * components the @p ith shape
- * function is non-zero. This
- * value equals the number of
- * entries equal to @p true in
- * the result of the
- * get_nonzero_components()
- * function.
+ * Return in how many vector components the @p ith shape function is
+ * non-zero. This value equals the number of entries equal to @p true in the
+ * result of the get_nonzero_components() function.
*
- * For most finite element
- * spaces, the result will be
- * equal to one. It is not equal
- * to one only for those ansatz
- * spaces for which vector-valued
- * shape functions couple the
- * individual components, for
- * example in order to make them
- * divergence-free.
+ * For most finite element spaces, the result will be equal to one. It is
+ * not equal to one only for those ansatz spaces for which vector-valued
+ * shape functions couple the individual components, for example in order to
+ * make them divergence-free.
*/
unsigned int
n_nonzero_components (const unsigned int i) const;
/**
- * Return whether the @p ith
- * shape function is primitive in
- * the sense that the shape
- * function is non-zero in only
- * one vector
- * component. Non-primitive shape
- * functions would then, for
- * example, be those of
- * divergence free ansatz spaces,
- * in which the individual vector
+ * Return whether the @p ith shape function is primitive in the sense that
+ * the shape function is non-zero in only one vector
+ * component. Non-primitive shape functions would then, for example, be
+ * those of divergence free ansatz spaces, in which the individual vector
* components are coupled.
*
- * The result of the function is
- * @p true if and only if the
- * result of
- * <tt>n_nonzero_components(i)</tt> is
- * equal to one.
+ * The result of the function is @p true if and only if the result of
+ * <tt>n_nonzero_components(i)</tt> is equal to one.
*/
bool
is_primitive (const unsigned int i) const;
/**
- * Import function that is overloaded
- * by the one above and would otherwise
+ * Import function that is overloaded by the one above and would otherwise
* be hidden.
*/
using FiniteElementData<dim>::is_primitive;
/**
- * Number of base elements in a
- * mixed discretization.
- *
- * Note that even for vector
- * valued finite elements, the
- * number of components needs not
- * coincide with the number of
- * base elements, since they may
- * be reused. For example, if you
- * create a FESystem with
- * three identical finite element
- * classes by using the
- * constructor that takes one
- * finite element and a
- * multiplicity, then the number
- * of base elements is still one,
- * although the number of
- * components of the finite
- * element is equal to the
- * multiplicity.
+ * Number of base elements in a mixed discretization.
+ *
+ * Note that even for vector valued finite elements, the number of
+ * components needs not coincide with the number of base elements, since
+ * they may be reused. For example, if you create a FESystem with three
+ * identical finite element classes by using the constructor that takes one
+ * finite element and a multiplicity, then the number of base elements is
+ * still one, although the number of components of the finite element is
+ * equal to the multiplicity.
*/
unsigned int n_base_elements () const;
/**
- * Access to base element
- * objects. If the element is
- * atomic, then
- * <code>base_element(0)</code> is
- * @p this.
+ * Access to base element objects. If the element is atomic, then
+ * <code>base_element(0)</code> is @p this.
*/
virtual
const FiniteElement<dim,spacedim> &
base_element (const unsigned int index) const;
/**
- * This index denotes how often
- * the base element @p index is
- * used in a composed element. If
- * the element is atomic, then
- * the result is always equal to
- * one. See the documentation for
- * the n_base_elements()
- * function for more details.
+ * This index denotes how often the base element @p index is used in a
+ * composed element. If the element is atomic, then the result is always
+ * equal to one. See the documentation for the n_base_elements() function
+ * for more details.
*/
unsigned int
element_multiplicity (const unsigned int index) const;
/**
- * Return for shape function
- * @p index the base element it
- * belongs to, the number of the
- * copy of this base element
- * (which is between zero and the
- * multiplicity of this element),
- * and the index of this shape
- * function within this base
- * element.
+ * Return for shape function @p index the base element it belongs to, the
+ * number of the copy of this base element (which is between zero and the
+ * multiplicity of this element), and the index of this shape function
+ * within this base element.
*
- * If the element is not composed of
- * others, then base and instance
- * are always zero, and the index
- * is equal to the number of the
- * shape function. If the element
- * is composed of single
- * instances of other elements
- * (i.e. all with multiplicity
- * one) all of which are scalar,
- * then base values and dof
- * indices within this element
- * are equal to the
- * #system_to_component_table. It
- * differs only in case the
- * element is composed of other
- * elements and at least one of
- * them is vector-valued itself.
- *
- * This function returns valid
- * values also in the case of
- * vector-valued
- * (i.e. non-primitive) shape
- * functions, in contrast to the
- * system_to_component_index()
- * function.
+ * If the element is not composed of others, then base and instance are
+ * always zero, and the index is equal to the number of the shape
+ * function. If the element is composed of single instances of other
+ * elements (i.e. all with multiplicity one) all of which are scalar, then
+ * base values and dof indices within this element are equal to the
+ * #system_to_component_table. It differs only in case the element is
+ * composed of other elements and at least one of them is vector-valued
+ * itself.
+ *
+ * This function returns valid values also in the case of vector-valued
+ * (i.e. non-primitive) shape functions, in contrast to the
+ * system_to_component_index() function.
*/
std::pair<std::pair<unsigned int, unsigned int>, unsigned int>
system_to_base_index (const unsigned int index) const;
/**
- * Same as
- * system_to_base_index(), but
- * for degrees of freedom located
- * on a face. The range of allowed
- * indices is therefore
- * 0..#dofs_per_face.
+ * Same as system_to_base_index(), but for degrees of freedom located on a
+ * face. The range of allowed indices is therefore 0..#dofs_per_face.
*
- * You will rarely need this
- * function in application
- * programs, since almost all
- * application codes only need to
- * deal with cell indices, not
- * face indices. The function is
- * mainly there for use inside
- * the library.
+ * You will rarely need this function in application programs, since almost
+ * all application codes only need to deal with cell indices, not face
+ * indices. The function is mainly there for use inside the library.
*/
std::pair<std::pair<unsigned int, unsigned int>, unsigned int>
face_system_to_base_index (const unsigned int index) const;
/**
- * Given a base element number,
- * return the first block of a
- * BlockVector it would generate.
+ * Given a base element number, return the first block of a BlockVector it
+ * would generate.
*/
unsigned int first_block_of_base (const unsigned int b) const;
/**
- * For each vector component,
- * return which base
- * element implements this
- * component and which vector
- * component in this base element
- * this is. This information is
- * only of interest for
- * vector-valued finite elements
- * which are composed of several
- * sub-elements. In that case,
- * one may want to obtain
- * information about the element
- * implementing a certain vector
- * component, which can be done
- * using this function and the
- * FESystem::base_element()
- * function.
+ * For each vector component, return which base element implements this
+ * component and which vector component in this base element this is. This
+ * information is only of interest for vector-valued finite elements which
+ * are composed of several sub-elements. In that case, one may want to
+ * obtain information about the element implementing a certain vector
+ * component, which can be done using this function and the
+ * FESystem::base_element() function.
*
- * If this is a scalar finite
- * element, then the return value
- * is always equal to a pair of
- * zeros.
+ * If this is a scalar finite element, then the return value is always equal
+ * to a pair of zeros.
*/
std::pair<unsigned int, unsigned int>
component_to_base_index (const unsigned int component) const;
/**
- * Return the base element for
- * this block and the number of
- * the copy of the base element.
+ * Return the base element for this block and the number of the copy of the
+ * base element.
*/
std::pair<unsigned int,unsigned int>
block_to_base_index (const unsigned int block) const;
/**
- * The vector block and the index
- * inside the block for this
- * shape function.
+ * The vector block and the index inside the block for this shape function.
*/
std::pair<unsigned int,unsigned int>
system_to_block_index (const unsigned int component) const;
/**
- * The vector block for this
- * component.
+ * The vector block for this component.
*/
unsigned int
component_to_block_index (const unsigned int component) const;
*/
/**
- * Return a component mask with as many elements as this
- * object has vector components and of which exactly the
- * one component is true that corresponds to the given
- * argument. See @ref GlossComponentMask "the glossary"
- * for more information.
+ * Return a component mask with as many elements as this object has vector
+ * components and of which exactly the one component is true that
+ * corresponds to the given argument. See @ref GlossComponentMask "the
+ * glossary" for more information.
*
- * @param scalar An object that represents a single scalar
- * vector component of this finite element.
- * @return A component mask that is false in all components
- * except for the one that corresponds to the argument.
+ * @param scalar An object that represents a single scalar vector component
+ * of this finite element.
+ * @return A component mask that is false in all components except for the
+ * one that corresponds to the argument.
*/
ComponentMask
component_mask (const FEValuesExtractors::Scalar &scalar) const;
/**
- * Return a component mask with as many elements as this
- * object has vector components and of which exactly the
- * <code>dim</code> components are true that correspond to the given
- * argument. See @ref GlossComponentMask "the glossary"
- * for more information.
+ * Return a component mask with as many elements as this object has vector
+ * components and of which exactly the <code>dim</code> components are true
+ * that correspond to the given argument. See @ref GlossComponentMask "the
+ * glossary" for more information.
*
- * @param vector An object that represents dim
- * vector components of this finite element.
- * @return A component mask that is false in all components
- * except for the ones that corresponds to the argument.
+ * @param vector An object that represents dim vector components of this
+ * finite element.
+ * @return A component mask that is false in all components except for the
+ * ones that corresponds to the argument.
*/
ComponentMask
component_mask (const FEValuesExtractors::Vector &vector) const;
/**
- * Return a component mask with as many elements as this
- * object has vector components and of which exactly the
- * <code>dim*(dim+1)/2</code> components are true that
- * correspond to the given argument. See @ref GlossComponentMask "the glossary"
- * for more information.
+ * Return a component mask with as many elements as this object has vector
+ * components and of which exactly the <code>dim*(dim+1)/2</code> components
+ * are true that correspond to the given argument. See @ref
+ * GlossComponentMask "the glossary" for more information.
*
- * @param sym_tensor An object that represents dim*(dim+1)/2
- * components of this finite element that are jointly to be
- * interpreted as forming a symmetric tensor.
- * @return A component mask that is false in all components
- * except for the ones that corresponds to the argument.
+ * @param sym_tensor An object that represents dim*(dim+1)/2 components of
+ * this finite element that are jointly to be interpreted as forming a
+ * symmetric tensor. @return A component mask that is false in all
+ * components except for the ones that corresponds to the argument.
*/
ComponentMask
component_mask (const FEValuesExtractors::SymmetricTensor<2> &sym_tensor) const;
/**
* Given a block mask (see @ref GlossBlockMask "this glossary entry"),
- * produce a component mask (see @ref GlossComponentMask "this glossary entry")
- * that represents the components that correspond to the blocks selected in
- * the input argument. This is essentially a conversion operator from
- * BlockMask to ComponentMask.
+ * produce a component mask (see @ref GlossComponentMask "this glossary
+ * entry") that represents the components that correspond to the blocks
+ * selected in the input argument. This is essentially a conversion operator
+ * from BlockMask to ComponentMask.
*
* @param block_mask The mask that selects individual blocks of the finite
* element
component_mask (const BlockMask &block_mask) const;
/**
- * Return a block mask with as many elements as this
- * object has blocks and of which exactly the
- * one component is true that corresponds to the given
- * argument. See @ref GlossBlockMask "the glossary"
- * for more information.
+ * Return a block mask with as many elements as this object has blocks and
+ * of which exactly the one component is true that corresponds to the given
+ * argument. See @ref GlossBlockMask "the glossary" for more information.
*
- * @note This function will only succeed if the scalar referenced
- * by the argument encompasses a complete block. In other words,
- * if, for example, you pass an extractor for the single
- * $x$ velocity and this object represents an FE_RaviartThomas
- * object, then the single scalar object you selected is part
- * of a larger block and consequently there is no block mask that
- * would represent it. The function will then produce an exception.
+ * @note This function will only succeed if the scalar referenced by the
+ * argument encompasses a complete block. In other words, if, for example,
+ * you pass an extractor for the single $x$ velocity and this object
+ * represents an FE_RaviartThomas object, then the single scalar object you
+ * selected is part of a larger block and consequently there is no block
+ * mask that would represent it. The function will then produce an
+ * exception.
*
- * @param scalar An object that represents a single scalar
- * vector component of this finite element.
- * @return A component mask that is false in all components
- * except for the one that corresponds to the argument.
+ * @param scalar An object that represents a single scalar vector component
+ * of this finite element.
+ * @return A component mask that is false in all components except for the
+ * one that corresponds to the argument.
*/
BlockMask
block_mask (const FEValuesExtractors::Scalar &scalar) const;
/**
- * Return a component mask with as many elements as this
- * object has vector components and of which exactly the
- * <code>dim</code> components are true that correspond to the given
- * argument. See @ref GlossBlockMask "the glossary"
- * for more information.
+ * Return a component mask with as many elements as this object has vector
+ * components and of which exactly the <code>dim</code> components are true
+ * that correspond to the given argument. See @ref GlossBlockMask "the
+ * glossary" for more information.
*
* @note The same caveat applies as to the version of the function above:
- * The extractor object passed as argument must be so that it corresponds
- * to full blocks and does not split blocks of this element.
+ * The extractor object passed as argument must be so that it corresponds to
+ * full blocks and does not split blocks of this element.
*
- * @param vector An object that represents dim
- * vector components of this finite element.
- * @return A component mask that is false in all components
- * except for the ones that corresponds to the argument.
+ * @param vector An object that represents dim vector components of this
+ * finite element.
+ * @return A component mask that is false in all components except for the
+ * ones that corresponds to the argument.
*/
BlockMask
block_mask (const FEValuesExtractors::Vector &vector) const;
/**
- * Return a component mask with as many elements as this
- * object has vector components and of which exactly the
- * <code>dim*(dim+1)/2</code> components are true that
- * correspond to the given argument. See @ref GlossBlockMask "the glossary"
- * for more information.
+ * Return a component mask with as many elements as this object has vector
+ * components and of which exactly the <code>dim*(dim+1)/2</code> components
+ * are true that correspond to the given argument. See @ref GlossBlockMask
+ * "the glossary" for more information.
*
* @note The same caveat applies as to the version of the function above:
- * The extractor object passed as argument must be so that it corresponds
- * to full blocks and does not split blocks of this element.
+ * The extractor object passed as argument must be so that it corresponds to
+ * full blocks and does not split blocks of this element.
*
- * @param sym_tensor An object that represents dim*(dim+1)/2
- * components of this finite element that are jointly to be
- * interpreted as forming a symmetric tensor.
- * @return A component mask that is false in all components
- * except for the ones that corresponds to the argument.
+ * @param sym_tensor An object that represents dim*(dim+1)/2 components of
+ * this finite element that are jointly to be interpreted as forming a
+ * symmetric tensor.
+ * @return A component mask that is false in all components except for the
+ * ones that corresponds to the argument.
*/
BlockMask
block_mask (const FEValuesExtractors::SymmetricTensor<2> &sym_tensor) const;
/**
- * Given a component mask (see @ref GlossComponentMask "this glossary entry"),
- * produce a block mask (see @ref GlossBlockMask "this glossary entry")
- * that represents the blocks that correspond to the components selected in
- * the input argument. This is essentially a conversion operator from
- * ComponentMask to BlockMask.
+ * Given a component mask (see @ref GlossComponentMask "this glossary
+ * entry"), produce a block mask (see @ref GlossBlockMask "this glossary
+ * entry") that represents the blocks that correspond to the components
+ * selected in the input argument. This is essentially a conversion operator
+ * from ComponentMask to BlockMask.
*
- * @note This function will only succeed if the components referenced
- * by the argument encompasses complete blocks. In other words,
- * if, for example, you pass an component mask for the single
- * $x$ velocity and this object represents an FE_RaviartThomas
- * object, then the single component you selected is part
- * of a larger block and consequently there is no block mask that
- * would represent it. The function will then produce an exception.
+ * @note This function will only succeed if the components referenced by the
+ * argument encompasses complete blocks. In other words, if, for example,
+ * you pass an component mask for the single $x$ velocity and this object
+ * represents an FE_RaviartThomas object, then the single component you
+ * selected is part of a larger block and consequently there is no block
+ * mask that would represent it. The function will then produce an
+ * exception.
*
- * @param component_mask The mask that selects individual components of the finite
- * element
+ * @param component_mask The mask that selects individual components of the
+ * finite element
* @return A mask that selects those blocks corresponding to the selected
* blocks of the input argument.
*/
*/
/**
- * Return the support points of
- * the trial functions on the
- * unit cell, if the derived
- * finite element defines some.
- * Finite elements that allow
- * some kind of interpolation
- * operation usually have support
- * points. On the other hand,
- * elements that define their
- * degrees of freedom by, for
- * example, moments on faces, or
- * as derivatives, don't have
- * support points. In that case,
- * the returned field is empty.
- *
- * If the finite element defines
- * support points, then their
- * number equals the number of
- * degrees of freedom of the
- * element. The order of points
- * in the array matches that
- * returned by the
- * <tt>cell->get_dof_indices</tt>
+ * Return the support points of the trial functions on the unit cell, if the
+ * derived finite element defines some. Finite elements that allow some
+ * kind of interpolation operation usually have support points. On the other
+ * hand, elements that define their degrees of freedom by, for example,
+ * moments on faces, or as derivatives, don't have support points. In that
+ * case, the returned field is empty.
+ *
+ * If the finite element defines support points, then their number equals
+ * the number of degrees of freedom of the element. The order of points in
+ * the array matches that returned by the <tt>cell->get_dof_indices</tt>
* function.
*
- * See the class documentation
- * for details on support points.
+ * See the class documentation for details on support points.
*/
const std::vector<Point<dim> > &
get_unit_support_points () const;
/**
- * Return whether a finite
- * element has defined support
- * points. If the result is true,
- * then a call to the
- * get_unit_support_points()
- * yields a non-empty array.
+ * Return whether a finite element has defined support points. If the result
+ * is true, then a call to the get_unit_support_points() yields a non-empty
+ * array.
*
- * The result may be false if an
- * element is not defined by
- * interpolating shape functions,
- * for example by P-elements on
- * quadrilaterals. It will
- * usually only be true if the
- * element constructs its shape
- * functions by the requirement
- * that they be one at a certain
- * point and zero at all the
- * points associated with the
- * other shape functions.
- *
- * In composed elements (i.e. for
- * the FESystem class, the
- * result will be true if all all
- * the base elements have defined
- * support points.
+ * The result may be false if an element is not defined by interpolating
+ * shape functions, for example by P-elements on quadrilaterals. It will
+ * usually only be true if the element constructs its shape functions by the
+ * requirement that they be one at a certain point and zero at all the
+ * points associated with the other shape functions.
+ *
+ * In composed elements (i.e. for the FESystem class, the result will be
+ * true if all all the base elements have defined support points.
*/
bool has_support_points () const;
/**
- * Return the position of the
- * support point of the
- * @p indexth shape function. If
- * it does not exist, raise an
- * exception.
+ * Return the position of the support point of the @p indexth shape
+ * function. If it does not exist, raise an exception.
*
- * The default implementation
- * simply returns the respective
- * element from the array you get
- * from
- * get_unit_support_points(),
- * but derived elements may
- * overload this function. In
- * particular, note that the
- * FESystem class overloads
- * it so that it can return the
- * support points of individual
- * base elements, if not all the
- * base elements define support
- * points. In this way, you can
- * still ask for certain support
- * points, even if
- * get_unit_support_points()
- * only returns an empty array.
+ * The default implementation simply returns the respective element from the
+ * array you get from get_unit_support_points(), but derived elements may
+ * overload this function. In particular, note that the FESystem class
+ * overloads it so that it can return the support points of individual base
+ * elements, if not all the base elements define support points. In this
+ * way, you can still ask for certain support points, even if
+ * get_unit_support_points() only returns an empty array.
*/
virtual
Point<dim>
unit_support_point (const unsigned int index) const;
/**
- * Return the support points of
- * the trial functions on the
- * unit face, if the derived
- * finite element defines some.
- * Finite elements that allow
- * some kind of interpolation
- * operation usually have support
- * points. On the other hand,
- * elements that define their
- * degrees of freedom by, for
- * example, moments on faces, or
- * as derivatives, don't have
- * support points. In that case,
- * the returned field is empty
- *
- * Note that elements that have
- * support points need not
- * necessarily have some on the
- * faces, even if the
- * interpolation points are
- * located physically on a
- * face. For example, the
- * discontinuous elements have
- * interpolation points on the
- * vertices, and for higher
- * degree elements also on the
- * faces, but they are not
- * defined to be on faces since
- * in that case degrees of
- * freedom from both sides of a
- * face (or from all adjacent
- * elements to a vertex) would be
- * identified with each other,
- * which is not what we would
- * like to have). Logically,
- * these degrees of freedom are
- * therefore defined to belong to
- * the cell, rather than the face
- * or vertex. In that case, the
- * returned element would
- * therefore have length zero.
- *
- * If the finite element defines
- * support points, then their
- * number equals the number of
- * degrees of freedom on the face
- * (#dofs_per_face). The order
- * of points in the array matches
- * that returned by the
- * <tt>cell->get_dof_indices</tt>
- * function.
- *
- * See the class documentation
- * for details on support points.
+ * Return the support points of the trial functions on the unit face, if the
+ * derived finite element defines some. Finite elements that allow some
+ * kind of interpolation operation usually have support points. On the other
+ * hand, elements that define their degrees of freedom by, for example,
+ * moments on faces, or as derivatives, don't have support points. In that
+ * case, the returned field is empty
+ *
+ * Note that elements that have support points need not necessarily have
+ * some on the faces, even if the interpolation points are located
+ * physically on a face. For example, the discontinuous elements have
+ * interpolation points on the vertices, and for higher degree elements also
+ * on the faces, but they are not defined to be on faces since in that case
+ * degrees of freedom from both sides of a face (or from all adjacent
+ * elements to a vertex) would be identified with each other, which is not
+ * what we would like to have). Logically, these degrees of freedom are
+ * therefore defined to belong to the cell, rather than the face or
+ * vertex. In that case, the returned element would therefore have length
+ * zero.
+ *
+ * If the finite element defines support points, then their number equals
+ * the number of degrees of freedom on the face (#dofs_per_face). The order
+ * of points in the array matches that returned by the
+ * <tt>cell->get_dof_indices</tt> function.
+ *
+ * See the class documentation for details on support points.
*/
const std::vector<Point<dim-1> > &
get_unit_face_support_points () const;
/**
- * Return whether a finite
- * element has defined support
- * points on faces. If the result
- * is true, then a call to the
- * get_unit_face_support_points()
+ * Return whether a finite element has defined support points on faces. If
+ * the result is true, then a call to the get_unit_face_support_points()
* yields a non-empty array.
*
- * For more information, see the
- * documentation for the
- * has_support_points()
+ * For more information, see the documentation for the has_support_points()
* function.
*/
bool has_face_support_points () const;
/**
- * The function corresponding to
- * the unit_support_point()
- * function, but for faces. See
- * there for more information.
+ * The function corresponding to the unit_support_point() function, but for
+ * faces. See there for more information.
*/
virtual
Point<dim-1>
unit_face_support_point (const unsigned int index) const;
/**
- * Return a support point vector
- * for generalized interpolation.
- *
- * See the @ref GlossGeneralizedSupport "glossary entry on generalized support points"
- * for more information.
+ * Return a support point vector for generalized interpolation.
+ *
+ * See the @ref GlossGeneralizedSupport "glossary entry on generalized
+ * support points" for more information.
*/
const std::vector<Point<dim> > &
get_generalized_support_points () const;
/**
- * Returns <tt>true</tt> if the
- * class provides nonempty
- * vectors either from
- * get_unit_support_points() or
- * get_generalized_support_points().
- *
- * See the @ref GlossGeneralizedSupport "glossary entry on generalized support points"
- * for more information.
+ * Returns <tt>true</tt> if the class provides nonempty vectors either from
+ * get_unit_support_points() or get_generalized_support_points().
+ *
+ * See the @ref GlossGeneralizedSupport "glossary entry on generalized
+ * support points" for more information.
*/
bool has_generalized_support_points () const;
get_generalized_face_support_points () const;
/**
- * Return whether a finite
- * element has defined
- * generalized support
- * points on faces. If the result
- * is true, then a call to the
- * get_generalized_face_support_points
- * yields a non-empty array.
+ * Return whether a finite element has defined generalized support points on
+ * faces. If the result is true, then a call to the
+ * get_generalized_face_support_points yields a non-empty array.
*
- * For more information, see the
- * documentation for the
- * has_support_points()
+ * For more information, see the documentation for the has_support_points()
* function.
*/
bool has_generalized_face_support_points () const;
/**
- * Interpolate a set of scalar
- * values, computed in the
- * generalized support points.
+ * Interpolate a set of scalar values, computed in the generalized support
+ * points.
*
- * @note This function is
- * implemented in
- * FiniteElement for the case
- * that the element has support
- * points. In this case, the
- * resulting coefficients are
- * just the values in the suport
- * points. All other elements
- * must reimplement it.
+ * @note This function is implemented in FiniteElement for the case that the
+ * element has support points. In this case, the resulting coefficients are
+ * just the values in the suport points. All other elements must reimplement
+ * it.
*/
virtual void interpolate(std::vector<double> &local_dofs,
const std::vector<double> &values) const;
/**
- * Interpolate a set of vector
- * values, computed in the
- * generalized support points.
+ * Interpolate a set of vector values, computed in the generalized support
+ * points.
*
- * Since a finite element often
- * only interpolates part of a
- * vector, <tt>offset</tt> is
- * used to determine the first
- * component of the vector to be
- * interpolated. Maybe consider
- * changing your data structures
- * to use the next function.
+ * Since a finite element often only interpolates part of a vector,
+ * <tt>offset</tt> is used to determine the first component of the vector to
+ * be interpolated. Maybe consider changing your data structures to use the
+ * next function.
*/
virtual void interpolate(std::vector<double> &local_dofs,
const std::vector<Vector<double> > &values,
unsigned int offset = 0) const;
/**
- * Interpolate a set of vector
- * values, computed in the
- * generalized support points.
+ * Interpolate a set of vector values, computed in the generalized support
+ * points.
*/
virtual void interpolate(
std::vector<double> &local_dofs,
//@}
/**
- * Determine an estimate for the
- * memory consumption (in bytes)
- * of this object.
+ * Determine an estimate for the memory consumption (in bytes) of this
+ * object.
*
- * This function is made virtual,
- * since finite element objects
- * are usually accessed through
- * pointers to their base class,
- * rather than the class itself.
+ * This function is made virtual, since finite element objects are usually
+ * accessed through pointers to their base class, rather than the class
+ * itself.
*/
virtual std::size_t memory_consumption () const;
/**
DeclException0 (ExcUnitShapeValuesDoNotExist);
/**
- * Attempt to access support
- * points of a finite element
- * which is not Lagrangian.
+ * Attempt to access support points of a finite element which is not
+ * Lagrangian.
*
* @ingroup Exceptions
*/
DeclException0 (ExcFEHasNoSupportPoints);
/**
- * Attempt to access embedding
- * matrices of a finite element
- * which did not implement these
- * matrices.
+ * Attempt to access embedding matrices of a finite element which did not
+ * implement these matrices.
*
* @ingroup Exceptions
*/
DeclException0 (ExcEmbeddingVoid);
/**
- * Attempt to access restriction
- * matrices of a finite element
- * which did not implement these
- * matrices.
+ * Attempt to access restriction matrices of a finite element which did not
+ * implement these matrices.
*
* Exception
* @ingroup Exceptions
DeclException0 (ExcProjectionVoid);
/**
- * Attempt to access constraint
- * matrices of a finite element
- * which did not implement these
- * matrices.
+ * Attempt to access constraint matrices of a finite element which did not
+ * implement these matrices.
*
* Exception
* @ingroup Exceptions
protected:
/**
- * Reinit the vectors of
- * restriction and prolongation
- * matrices to the right sizes:
- * For every refinement case,
- * except for
- * RefinementCase::no_refinement,
- * and for every child of that
- * refinement case the space of
- * one restriction and
- * prolongation matrix is
- * allocated, see the
- * documentation of the
- * restriction and prolongation
- * vectors for more detail on the
- * actual vector sizes.
- *
- * @param
- * isotropic_restriction_only
- * only the restriction matrices
- * required for isotropic
- * refinement are reinited to the
- * right size.
- * @param
- * isotropic_prolongation_only
- * only the prolongation matrices
- * required for isotropic
- * refinement are reinited to the
- * right size.
+ * Reinit the vectors of restriction and prolongation matrices to the right
+ * sizes: For every refinement case, except for
+ * RefinementCase::no_refinement, and for every child of that refinement
+ * case the space of one restriction and prolongation matrix is allocated,
+ * see the documentation of the restriction and prolongation vectors for
+ * more detail on the actual vector sizes.
+ *
+ * @param isotropic_restriction_only only the restriction matrices required
+ * for isotropic refinement are reinited to the right size.
+ * @param isotropic_prolongation_only only the prolongation matrices
+ * required for isotropic refinement are reinited to the right size.
*/
void reinit_restriction_and_prolongation_matrices(const bool isotropic_restriction_only=false,
const bool isotropic_prolongation_only=false);
/**
- * Vector of projection
- * matrices. See
- * get_restriction_matrix()
- * above. The constructor
- * initializes these matrices to
- * zero dimensions, which can be
- * changed by derived classes
- * implementing them.
- *
- * Note, that
- * <code>restriction[refinement_case-1][child]</code>
- * includes the restriction
- * matrix of child
- * <code>child</code> for the
- * RefinementCase
- * <code>refinement_case</code>. Here,
- * we use
- * <code>refinement_case-1</code>
- * instead of
- * <code>refinement_case</code>
- * as for
- * RefinementCase::no_refinement(=0)
- * there are no restriction
- * matrices available.
+ * Vector of projection matrices. See get_restriction_matrix() above. The
+ * constructor initializes these matrices to zero dimensions, which can be
+ * changed by derived classes implementing them.
+ *
+ * Note, that <code>restriction[refinement_case-1][child]</code> includes
+ * the restriction matrix of child <code>child</code> for the RefinementCase
+ * <code>refinement_case</code>. Here, we use <code>refinement_case-1</code>
+ * instead of <code>refinement_case</code> as for
+ * RefinementCase::no_refinement(=0) there are no restriction matrices
+ * available.
*/
std::vector<std::vector<FullMatrix<double> > > restriction;
/**
- * Vector of embedding
- * matrices. See
- * <tt>get_prolongation_matrix()</tt>
- * above. The constructor
- * initializes these matrices to
- * zero dimensions, which can be
- * changed by derived classes
- * implementing them.
- *
- * Note, that
- * <code>prolongation[refinement_case-1][child]</code>
- * includes the prolongation
- * matrix of child
- * <code>child</code> for the
- * RefinementCase
- * <code>refinement_case</code>. Here,
- * we use
- * <code>refinement_case-1</code>
- * instead of
- * <code>refinement_case</code>
- * as for
- * RefinementCase::no_refinement(=0)
- * there are no prolongation
- * matrices available.
+ * Vector of embedding matrices. See <tt>get_prolongation_matrix()</tt>
+ * above. The constructor initializes these matrices to zero dimensions,
+ * which can be changed by derived classes implementing them.
+ *
+ * Note, that <code>prolongation[refinement_case-1][child]</code> includes
+ * the prolongation matrix of child <code>child</code> for the
+ * RefinementCase <code>refinement_case</code>. Here, we use
+ * <code>refinement_case-1</code> instead of <code>refinement_case</code> as
+ * for RefinementCase::no_refinement(=0) there are no prolongation matrices
+ * available.
*/
std::vector<std::vector<FullMatrix<double> > > prolongation;
/**
- * Specify the constraints which
- * the dofs on the two sides of a
- * cell interface underly if the
- * line connects two cells of
- * which one is refined once.
+ * Specify the constraints which the dofs on the two sides of a cell
+ * interface underly if the line connects two cells of which one is refined
+ * once.
*
- * For further details see the
- * general description of the
- * derived class.
+ * For further details see the general description of the derived class.
*
- * This field is obviously
- * useless in one dimension
- * and has there a zero size.
+ * This field is obviously useless in one dimension and has there a zero
+ * size.
*/
FullMatrix<double> interface_constraints;
/**
- * List of support points on the
- * unit cell, in case the finite
- * element has any. The
- * constructor leaves this field
- * empty, derived classes may
- * write in some contents.
- *
- * Finite elements that allow
- * some kind of interpolation
- * operation usually have support
- * points. On the other hand,
- * elements that define their
- * degrees of freedom by, for
- * example, moments on faces, or
- * as derivatives, don't have
- * support points. In that case,
- * this field remains empty.
+ * List of support points on the unit cell, in case the finite element has
+ * any. The constructor leaves this field empty, derived classes may write
+ * in some contents.
+ *
+ * Finite elements that allow some kind of interpolation operation usually
+ * have support points. On the other hand, elements that define their
+ * degrees of freedom by, for example, moments on faces, or as derivatives,
+ * don't have support points. In that case, this field remains empty.
*/
std::vector<Point<dim> > unit_support_points;
/**
- * Same for the faces. See the
- * description of the
- * get_unit_face_support_points()
- * function for a discussion of
- * what contributes a face
- * support point.
+ * Same for the faces. See the description of the
+ * get_unit_face_support_points() function for a discussion of what
+ * contributes a face support point.
*/
std::vector<Point<dim-1> > unit_face_support_points;
/**
- * Support points used for
- * interpolation functions of
- * non-Lagrangian elements.
+ * Support points used for interpolation functions of non-Lagrangian
+ * elements.
*/
std::vector<Point<dim> > generalized_support_points;
/**
- * Face support points used for
- * interpolation functions of
- * non-Lagrangian elements.
+ * Face support points used for interpolation functions of non-Lagrangian
+ * elements.
*/
std::vector<Point<dim-1> > generalized_face_support_points;
/**
- * For faces with non-standard
- * face_orientation in 3D, the dofs on
- * faces (quads) have to be permuted in
- * order to be combined with the correct
- * shape functions. Given a local dof @p
- * index on a quad, return the shift in the
- * local index, if the face has
- * non-standard face_orientation,
- * i.e. <code>old_index + shift =
- * new_index</code>. In 2D and 1D there is
- * no need for permutation so the vector is
- * empty. In 3D it has the size of <code>
- * #dofs_per_quad * 8 </code>, where 8 is
- * the number of orientations, a face can
- * be in (all combinations of the three
- * bool flags face_orientation, face_flip
- * and face_rotation).
- *
- * The standard implementation fills this
- * with zeros, i.e. no permuatation at
- * all. Derived finite element classes have
- * to fill this Table with the correct
- * values.
+ * For faces with non-standard face_orientation in 3D, the dofs on faces
+ * (quads) have to be permuted in order to be combined with the correct
+ * shape functions. Given a local dof @p index on a quad, return the shift
+ * in the local index, if the face has non-standard face_orientation,
+ * i.e. <code>old_index + shift = new_index</code>. In 2D and 1D there is no
+ * need for permutation so the vector is empty. In 3D it has the size of
+ * <code> #dofs_per_quad * 8 </code>, where 8 is the number of orientations,
+ * a face can be in (all combinations of the three bool flags
+ * face_orientation, face_flip and face_rotation).
+ *
+ * The standard implementation fills this with zeros, i.e. no permuatation
+ * at all. Derived finite element classes have to fill this Table with the
+ * correct values.
*/
Table<2,int> adjust_quad_dof_index_for_face_orientation_table;
/**
- * For lines with non-standard
- * line_orientation in 3D, the dofs on
- * lines have to be permuted in
- * order to be combined with the correct
- * shape functions. Given a local dof @p
- * index on a line, return the shift in the
- * local index, if the line has
- * non-standard line_orientation,
- * i.e. <code>old_index + shift =
- * new_index</code>. In 2D and 1D there is
- * no need for permutation so the vector is
- * empty. In 3D it has the size of
+ * For lines with non-standard line_orientation in 3D, the dofs on lines
+ * have to be permuted in order to be combined with the correct shape
+ * functions. Given a local dof @p index on a line, return the shift in the
+ * local index, if the line has non-standard line_orientation,
+ * i.e. <code>old_index + shift = new_index</code>. In 2D and 1D there is no
+ * need for permutation so the vector is empty. In 3D it has the size of
* #dofs_per_line.
*
- * The standard implementation fills this
- * with zeros, i.e. no permutation at
- * all. Derived finite element classes have
- * to fill this vector with the correct
- * values.
+ * The standard implementation fills this with zeros, i.e. no permutation at
+ * all. Derived finite element classes have to fill this vector with the
+ * correct values.
*/
std::vector<int> adjust_line_dof_index_for_line_orientation_table;
/**
- * Return the size of interface
- * constraint matrices. Since
- * this is needed in every
- * derived finite element class
- * when initializing their size,
- * it is placed into this
- * function, to avoid having to
- * recompute the
- * dimension-dependent size of
- * these matrices each time.
- *
- * Note that some elements do not
- * implement the interface
- * constraints for certain
- * polynomial degrees. In this
- * case, this function still
- * returns the size these
- * matrices should have when
- * implemented, but the actual
- * matrices are empty.
+ * Return the size of interface constraint matrices. Since this is needed in
+ * every derived finite element class when initializing their size, it is
+ * placed into this function, to avoid having to recompute the
+ * dimension-dependent size of these matrices each time.
+ *
+ * Note that some elements do not implement the interface constraints for
+ * certain polynomial degrees. In this case, this function still returns the
+ * size these matrices should have when implemented, but the actual matrices
+ * are empty.
*/
TableIndices<2>
interface_constraints_size () const;
/**
- * Compute second derivatives by
- * finite differences of
- * gradients.
+ * Compute second derivatives by finite differences of gradients.
*/
void compute_2nd (const Mapping<dim,spacedim> &mapping,
const typename Triangulation<dim,spacedim>::cell_iterator &cell,
FEValuesData<dim,spacedim> &data) const;
/**
- * Given the pattern of nonzero
- * components for each shape
- * function, compute for each
- * entry how many components are
- * non-zero for each shape
- * function. This function is
- * used in the constructor of
- * this class.
+ * Given the pattern of nonzero components for each shape function, compute
+ * for each entry how many components are non-zero for each shape
+ * function. This function is used in the constructor of this class.
*/
static
std::vector<unsigned int>
compute_n_nonzero_components (const std::vector<ComponentMask> &nonzero_components);
/**
- * Determine the values a finite
- * element should compute on
- * initialization of data for
- * FEValues.
- *
- * Given a set of flags
- * indicating what quantities are
- * requested from a FEValues
- * object, update_once() and
- * update_each() compute which
- * values must really be
- * computed. Then, the
- * <tt>fill_*_values</tt> functions
- * are called with the result of
- * these.
- *
- * Furthermore, values must be
- * computed either on the unit
- * cell or on the physical
- * cell. For instance, the
- * function values of FE_Q do
- * only depend on the quadrature
- * points on the unit
- * cell. Therefore, this flags
- * will be returned by
- * update_once(). The gradients
- * require computation of the
- * covariant transformation
- * matrix. Therefore,
- * @p update_covariant_transformation
- * and @p update_gradients will
- * be returned by
- * update_each().
- *
- * For an example see the same
- * function in the derived class
- * FE_Q.
+ * Determine the values a finite element should compute on initialization of
+ * data for FEValues.
+ *
+ * Given a set of flags indicating what quantities are requested from a
+ * FEValues object, update_once() and update_each() compute which values
+ * must really be computed. Then, the <tt>fill_*_values</tt> functions are
+ * called with the result of these.
+ *
+ * Furthermore, values must be computed either on the unit cell or on the
+ * physical cell. For instance, the function values of FE_Q do only depend
+ * on the quadrature points on the unit cell. Therefore, this flags will be
+ * returned by update_once(). The gradients require computation of the
+ * covariant transformation matrix. Therefore, @p
+ * update_covariant_transformation and @p update_gradients will be returned
+ * by update_each().
+ *
+ * For an example see the same function in the derived class FE_Q.
*/
virtual UpdateFlags update_once (const UpdateFlags flags) const = 0;
/**
- * Complementary function for
- * update_once().
+ * Complementary function for update_once().
*
- * While update_once() returns
- * the values to be computed on
- * the unit cell for yielding the
- * required data, this function
- * determines the values that
- * must be recomputed on each
- * cell.
+ * While update_once() returns the values to be computed on the unit cell
+ * for yielding the required data, this function determines the values that
+ * must be recomputed on each cell.
*
- * Refer to update_once() for
- * more details.
+ * Refer to update_once() for more details.
*/
virtual UpdateFlags update_each (const UpdateFlags flags) const = 0;
/**
- * A sort of virtual copy
- * constructor. Some places in
- * the library, for example the
- * constructors of FESystem as
- * well as the hp::FECollection
- * class, need to make copies of
- * finite elements without
- * knowing their exact type. They
- * do so through this function.
+ * A sort of virtual copy constructor. Some places in the library, for
+ * example the constructors of FESystem as well as the hp::FECollection
+ * class, need to make copies of finite elements without knowing their exact
+ * type. They do so through this function.
*/
virtual FiniteElement<dim,spacedim> *clone() const = 0;
private:
/**
- * Store what
- * system_to_component_index()
- * will return.
+ * Store what system_to_component_index() will return.
*/
std::vector< std::pair<unsigned int, unsigned int> > system_to_component_table;
/**
- * Map between linear dofs and
- * component dofs on face. This
- * is filled with default values
- * in the constructor, but
- * derived classes will have to
- * overwrite the information if
- * necessary.
+ * Map between linear dofs and component dofs on face. This is filled with
+ * default values in the constructor, but derived classes will have to
+ * overwrite the information if necessary.
*
- * By component, we mean the
- * vector component, not the base
- * element. The information thus
- * makes only sense if a shape
- * function is non-zero in only
+ * By component, we mean the vector component, not the base element. The
+ * information thus makes only sense if a shape function is non-zero in only
* one component.
*/
std::vector< std::pair<unsigned int, unsigned int> > face_system_to_component_table;
/**
- * For each shape function, store
- * to which base element and
- * which instance of this base
- * element (in case its
- * multiplicity is greater than
- * one) it belongs, and its index
- * within this base element. If
- * the element is not composed of
- * others, then base and instance
- * are always zero, and the index
- * is equal to the number of the
- * shape function. If the element
- * is composed of single
- * instances of other elements
- * (i.e. all with multiplicity
- * one) all of which are scalar,
- * then base values and dof
- * indices within this element
- * are equal to the
- * #system_to_component_table. It
- * differs only in case the
- * element is composed of other
- * elements and at least one of
- * them is vector-valued itself.
- *
- * This array has valid values
- * also in the case of
- * vector-valued
- * (i.e. non-primitive) shape
- * functions, in contrast to the
+ * For each shape function, store to which base element and which instance
+ * of this base element (in case its multiplicity is greater than one) it
+ * belongs, and its index within this base element. If the element is not
+ * composed of others, then base and instance are always zero, and the index
+ * is equal to the number of the shape function. If the element is composed
+ * of single instances of other elements (i.e. all with multiplicity one)
+ * all of which are scalar, then base values and dof indices within this
+ * element are equal to the #system_to_component_table. It differs only in
+ * case the element is composed of other elements and at least one of them
+ * is vector-valued itself.
+ *
+ * This array has valid values also in the case of vector-valued
+ * (i.e. non-primitive) shape functions, in contrast to the
* #system_to_component_table.
*/
std::vector<std::pair<std::pair<unsigned int,unsigned int>,unsigned int> >
system_to_base_table;
/**
- * Likewise for the indices on
- * faces.
+ * Likewise for the indices on faces.
*/
std::vector<std::pair<std::pair<unsigned int,unsigned int>,unsigned int> >
face_system_to_base_table;
/**
- * For each base element, store
- * the number of blocks generated
- * by the base and the first block in a block
- * vector it will generate.
+ * For each base element, store the number of blocks generated by the base
+ * and the first block in a block vector it will generate.
*/
BlockIndices base_to_block_indices;
/**
- * The base element establishing
- * a component.
+ * The base element establishing a component.
*
- * For each component number
- * <tt>c</tt>, the entries have
- * the following meaning:
+ * For each component number <tt>c</tt>, the entries have the following
+ * meaning:
* <dl>
* <dt><tt>table[c].first.first</tt></dt>
* <dd>Number of the base element for <tt>c</tt>.</dd>
* <dd>Multiple of the base element for <tt>c</tt>.</dd>
* </dl>
*
- * This variable is set to the
- * correct size by the
- * constructor of this class, but
- * needs to be initialized by
- * derived classes, unless its
- * size is one and the only entry
- * is a zero, which is the case
- * for scalar elements. In that
- * case, the initialization by
- * the base class is sufficient.
+ * This variable is set to the correct size by the constructor of this
+ * class, but needs to be initialized by derived classes, unless its size is
+ * one and the only entry is a zero, which is the case for scalar
+ * elements. In that case, the initialization by the base class is
+ * sufficient.
*/
std::vector<std::pair<std::pair<unsigned int, unsigned int>, unsigned int> >
component_to_base_table;
/**
- * Projection matrices are
- * concatenated or summed up.
- *
- * This flags decides on how the
- * projection matrices of the
- * children of the same father
- * are put together to one
- * operator. The possible modes
- * are concatenation and
- * summation.
- *
- * If the projection is defined
- * by an interpolation operator,
- * the child matrices are
- * concatenated, i.e. values
- * belonging to the same node
- * functional are identified and
- * enter the interpolated value
- * only once. In this case, the
- * flag must be @p false.
- *
- * For projections with respect
- * to scalar products, the child
- * matrices must be summed up to
- * build the complete matrix. The
- * flag should be @p true.
- *
- * For examples of use of these
- * flags, see the places in the
- * library where it is queried.
- *
- * There is one flag per shape
- * function, indicating whether
- * it belongs to the class of
- * shape functions that are
- * additive in the restriction or
- * not.
- *
- * Note that in previous versions
- * of the library, there was one
- * flag per vector component of
- * the element. This is based on
- * the fact that all the shape
- * functions that belong to the
- * same vector component must
- * necessarily behave in the same
- * way, to make things
- * reasonable. However, the
- * problem is that it is
- * sometimes impossible to query
- * this flag in the vector-valued
- * case: this used to be done
- * with the
- * #system_to_component_index
- * function that returns which
- * vector component a shape
- * function is associated
- * with. The point is that since
- * we now support shape functions
- * that are associated with more
- * than one vector component (for
- * example the shape functions of
- * Raviart-Thomas, or Nedelec
- * elements), that function can
- * no more be used, so it can be
- * difficult to find out which
- * for vector component we would
- * like to query the
+ * Projection matrices are concatenated or summed up.
+ *
+ * This flags decides on how the projection matrices of the children of the
+ * same father are put together to one operator. The possible modes are
+ * concatenation and summation.
+ *
+ * If the projection is defined by an interpolation operator, the child
+ * matrices are concatenated, i.e. values belonging to the same node
+ * functional are identified and enter the interpolated value only once. In
+ * this case, the flag must be @p false.
+ *
+ * For projections with respect to scalar products, the child matrices must
+ * be summed up to build the complete matrix. The flag should be @p true.
+ *
+ * For examples of use of these flags, see the places in the library where
+ * it is queried.
+ *
+ * There is one flag per shape function, indicating whether it belongs to
+ * the class of shape functions that are additive in the restriction or not.
+ *
+ * Note that in previous versions of the library, there was one flag per
+ * vector component of the element. This is based on the fact that all the
+ * shape functions that belong to the same vector component must necessarily
+ * behave in the same way, to make things reasonable. However, the problem
+ * is that it is sometimes impossible to query this flag in the
+ * vector-valued case: this used to be done with the
+ * #system_to_component_index function that returns which vector component a
+ * shape function is associated with. The point is that since we now support
+ * shape functions that are associated with more than one vector component
+ * (for example the shape functions of Raviart-Thomas, or Nedelec elements),
+ * that function can no more be used, so it can be difficult to find out
+ * which for vector component we would like to query the
* restriction-is-additive flags.
*/
const std::vector<bool> restriction_is_additive_flags;
/**
- * For each shape function, give
- * a vector of bools (with size
- * equal to the number of vector
- * components which this finite
- * element has) indicating in
- * which component each of these
- * shape functions is non-zero.
+ * For each shape function, give a vector of bools (with size equal to the
+ * number of vector components which this finite element has) indicating in
+ * which component each of these shape functions is non-zero.
*
- * For primitive elements, there
- * is only one non-zero
- * component.
+ * For primitive elements, there is only one non-zero component.
*/
const std::vector<ComponentMask> nonzero_components;
/**
- * This array holds how many
- * values in the respective entry
- * of the #nonzero_components
- * element are non-zero. The
- * array is thus a short-cut to
- * allow faster access to this
- * information than if we had to
- * count the non-zero entries
- * upon each request for this
- * information. The field is
- * initialized in the constructor
- * of this class.
+ * This array holds how many values in the respective entry of the
+ * #nonzero_components element are non-zero. The array is thus a short-cut
+ * to allow faster access to this information than if we had to count the
+ * non-zero entries upon each request for this information. The field is
+ * initialized in the constructor of this class.
*/
const std::vector<unsigned int> n_nonzero_components_table;
/**
- * Second derivatives of shapes
- * functions are not computed
- * analytically, but by finite
- * differences of the
- * gradients. This static
- * variable denotes the step
- * length to be used for
- * that. It's value is set to
- * 1e-6.
+ * Second derivatives of shapes functions are not computed analytically, but
+ * by finite differences of the gradients. This static variable denotes the
+ * step length to be used for that. It's value is set to 1e-6.
*/
static const double fd_step_length;
/**
- * Prepare internal data
- * structures and fill in values
- * independent of the
- * cell. Returns a pointer to an
- * object of which the caller of
- * this function then has to
- * assume ownership (which
- * includes destruction when it
- * is no more needed).
+ * Prepare internal data structures and fill in values independent of the
+ * cell. Returns a pointer to an object of which the caller of this function
+ * then has to assume ownership (which includes destruction when it is no
+ * more needed).
*/
virtual typename Mapping<dim,spacedim>::InternalDataBase *
get_data (const UpdateFlags flags,
const Quadrature<dim> &quadrature) const = 0;
/**
- * Prepare internal data
- * structure for transformation
- * of faces and fill in values
- * independent of the
- * cell. Returns a pointer to an
- * object of which the caller of
- * this function then has to
- * assume ownership (which
- * includes destruction when it
- * is no more needed).
+ * Prepare internal data structure for transformation of faces and fill in
+ * values independent of the cell. Returns a pointer to an object of which
+ * the caller of this function then has to assume ownership (which includes
+ * destruction when it is no more needed).
*/
virtual typename Mapping<dim,spacedim>::InternalDataBase *
get_face_data (const UpdateFlags flags,
const Quadrature<dim-1> &quadrature) const;
/**
- * Prepare internal data
- * structure for transformation
- * of children of faces and fill
- * in values independent of the
- * cell. Returns a pointer to an
- * object of which the caller of
- * this function then has to
- * assume ownership (which
- * includes destruction when it
- * is no more needed).
+ * Prepare internal data structure for transformation of children of faces
+ * and fill in values independent of the cell. Returns a pointer to an
+ * object of which the caller of this function then has to assume ownership
+ * (which includes destruction when it is no more needed).
*/
virtual typename Mapping<dim,spacedim>::InternalDataBase *
get_subface_data (const UpdateFlags flags,
const Quadrature<dim-1> &quadrature) const;
/**
- * Fill the fields of
- * FEValues. This function
- * performs all the operations
- * needed to compute the data of an
- * FEValues object.
+ * Fill the fields of FEValues. This function performs all the operations
+ * needed to compute the data of an FEValues object.
*
- * The same function in
- * @p mapping must have been
- * called for the same cell first!
+ * The same function in @p mapping must have been called for the same cell
+ * first!
*/
virtual void
fill_fe_values (const Mapping<dim,spacedim> &mapping,
CellSimilarity::Similarity &cell_similarity) const = 0;
/**
- * Fill the fields of
- * FEFaceValues. This function
- * performs all the operations
- * needed to compute the data of an
- * FEFaceValues object.
+ * Fill the fields of FEFaceValues. This function performs all the
+ * operations needed to compute the data of an FEFaceValues object.
*
- * The same function in
- * @p mapping must have been
- * called for the same cell first!
+ * The same function in @p mapping must have been called for the same cell
+ * first!
*/
virtual void
fill_fe_face_values (const Mapping<dim,spacedim> &mapping,
FEValuesData<dim,spacedim> &data) const = 0;
/**
- * Fill the fields of
- * FESubfaceValues. This function
- * performs all the operations
- * needed to compute the data of an
- * FESubfaceValues object.
+ * Fill the fields of FESubfaceValues. This function performs all the
+ * operations needed to compute the data of an FESubfaceValues object.
*
- * The same function in
- * @p mapping must have been
- * called for the same cell first!
+ * The same function in @p mapping must have been called for the same cell
+ * first!
*/
virtual void
fill_fe_subface_values (const Mapping<dim,spacedim> &mapping,
{
public:
/**
- * Constructor for tensor product
- * polynomials of degree
- * <tt>p</tt>. The shape
- * functions created using this
- * constructor correspond to
- * Legendre polynomials in each
- * coordinate direction.
+ * Constructor for tensor product polynomials of degree <tt>p</tt>. The
+ * shape functions created using this constructor correspond to Lagrange
+ * polynomials in each coordinate direction.
*/
FE_FaceQ(unsigned int p);
virtual FiniteElement<dim,spacedim> *clone() const;
/**
- * Return a string that uniquely
- * identifies a finite
- * element. This class returns
- * <tt>FE_FaceQ<dim>(degree)</tt>, with
- * <tt>dim</tt> and <tt>degree</tt>
- * replaced by appropriate
- * values.
+ * Return a string that uniquely identifies a finite element. This class
+ * returns <tt>FE_FaceQ<dim>(degree)</tt>, with <tt>dim</tt> and
+ * <tt>degree</tt> replaced by appropriate values.
*/
virtual std::string get_name () const;
/**
* Check for non-zero values on a face.
*
- * This function returns
- * @p true, if the shape
- * function @p shape_index has
- * non-zero values on the face
- * @p face_index.
+ * This function returns @p true, if the shape function @p shape_index has
+ * non-zero values on the face @p face_index.
*
- * Implementation of the
- * interface in
- * FiniteElement
+ * Implementation of the interface in FiniteElement
*/
virtual bool has_support_on_face (const unsigned int shape_index,
const unsigned int face_index) const;
private:
/**
- * Return vector with dofs per
- * vertex, line, quad, hex.
+ * Return vector with dofs per vertex, line, quad, hex.
*/
static std::vector<unsigned int> get_dpo_vector (const unsigned int deg);
};
const std::vector<ComponentMask> &nonzero_components);
/**
- * Return the polynomial degree
- * of this finite element,
- * i.e. the value passed to the
- * constructor.
+ * Return the polynomial degree of this finite element, i.e. the value
+ * passed to the constructor.
*/
unsigned int get_degree () const;
/**
- * Return the numbering of the underlying
- * polynomial space compared to
- * lexicographic ordering of the basis
- * functions. Returns
+ * Return the numbering of the underlying polynomial space compared to
+ * lexicographic ordering of the basis functions. Returns
* POLY::get_numbering().
*/
std::vector<unsigned int> get_poly_space_numbering() const;
/**
- * Return the inverse numbering of the
- * underlying polynomial space. Returns
+ * Return the inverse numbering of the underlying polynomial space. Returns
* POLY::get_numbering_inverse().
*/
std::vector<unsigned int> get_poly_space_numbering_inverse() const;
/**
- * Return the value of the
- * <tt>i</tt>th shape function at
- * the point <tt>p</tt>. See the
- * FiniteElement base class
- * for more information about the
- * semantics of this function.
+ * Return the value of the <tt>i</tt>th shape function at the point
+ * <tt>p</tt>. See the FiniteElement base class for more information about
+ * the semantics of this function.
*/
virtual double shape_value (const unsigned int i,
const Point<dim> &p) const;
/**
- * Return the value of the
- * <tt>component</tt>th vector
- * component of the <tt>i</tt>th
- * shape function at the point
- * <tt>p</tt>. See the
- * FiniteElement base class
- * for more information about the
- * semantics of this function.
+ * Return the value of the <tt>component</tt>th vector component of the
+ * <tt>i</tt>th shape function at the point <tt>p</tt>. See the
+ * FiniteElement base class for more information about the semantics of this
+ * function.
*
- * Since this element is scalar,
- * the returned value is the same
- * as if the function without the
- * <tt>_component</tt> suffix
- * were called, provided that the
- * specified component is zero.
+ * Since this element is scalar, the returned value is the same as if the
+ * function without the <tt>_component</tt> suffix were called, provided
+ * that the specified component is zero.
*/
virtual double shape_value_component (const unsigned int i,
const Point<dim> &p,
const unsigned int component) const;
/**
- * Return the gradient of the
- * <tt>i</tt>th shape function at
- * the point <tt>p</tt>. See the
- * FiniteElement base class
- * for more information about the
- * semantics of this function.
+ * Return the gradient of the <tt>i</tt>th shape function at the point
+ * <tt>p</tt>. See the FiniteElement base class for more information about
+ * the semantics of this function.
*/
virtual Tensor<1,dim> shape_grad (const unsigned int i,
const Point<dim> &p) const;
/**
- * Return the gradient of the
- * <tt>component</tt>th vector
- * component of the <tt>i</tt>th
- * shape function at the point
- * <tt>p</tt>. See the
- * FiniteElement base class
- * for more information about the
- * semantics of this function.
+ * Return the gradient of the <tt>component</tt>th vector component of the
+ * <tt>i</tt>th shape function at the point <tt>p</tt>. See the
+ * FiniteElement base class for more information about the semantics of this
+ * function.
*
- * Since this element is scalar,
- * the returned value is the same
- * as if the function without the
- * <tt>_component</tt> suffix
- * were called, provided that the
- * specified component is zero.
+ * Since this element is scalar, the returned value is the same as if the
+ * function without the <tt>_component</tt> suffix were called, provided
+ * that the specified component is zero.
*/
virtual Tensor<1,dim> shape_grad_component (const unsigned int i,
const Point<dim> &p,
const unsigned int component) const;
/**
- * Return the tensor of second
- * derivatives of the
- * <tt>i</tt>th shape function at
- * point <tt>p</tt> on the unit
- * cell. See the
- * FiniteElement base class
- * for more information about the
- * semantics of this function.
+ * Return the tensor of second derivatives of the <tt>i</tt>th shape
+ * function at point <tt>p</tt> on the unit cell. See the FiniteElement base
+ * class for more information about the semantics of this function.
*/
virtual Tensor<2,dim> shape_grad_grad (const unsigned int i,
const Point<dim> &p) const;
/**
- * Return the second derivative
- * of the <tt>component</tt>th
- * vector component of the
- * <tt>i</tt>th shape function at
- * the point <tt>p</tt>. See the
- * FiniteElement base class
- * for more information about the
- * semantics of this function.
+ * Return the second derivative of the <tt>component</tt>th vector component
+ * of the <tt>i</tt>th shape function at the point <tt>p</tt>. See the
+ * FiniteElement base class for more information about the semantics of this
+ * function.
*
- * Since this element is scalar,
- * the returned value is the same
- * as if the function without the
- * <tt>_component</tt> suffix
- * were called, provided that the
- * specified component is zero.
+ * Since this element is scalar, the returned value is the same as if the
+ * function without the <tt>_component</tt> suffix were called, provided
+ * that the specified component is zero.
*/
virtual Tensor<2,dim> shape_grad_grad_component (const unsigned int i,
const Point<dim> &p,
/**
- * Determine the values that need
- * to be computed on the unit
- * cell to be able to compute all
- * values required by
- * <tt>flags</tt>.
+ * Determine the values that need to be computed on the unit cell to be able
+ * to compute all values required by <tt>flags</tt>.
*
- * For the purpuse of this
- * function, refer to the
- * documentation in
+ * For the purpuse of this function, refer to the documentation in
* FiniteElement.
*
- * This class assumes that shape
- * functions of this
- * FiniteElement do <em>not</em>
- * depend on the actual shape of
- * the cells in real
- * space. Therefore, the effect
- * in this element is as follows:
- * if <tt>update_values</tt> is
- * set in <tt>flags</tt>, copy it
- * to the result. All other flags
- * of the result are cleared,
- * since everything else must be
- * computed for each cell.
+ * This class assumes that shape functions of this FiniteElement do
+ * <em>not</em> depend on the actual shape of the cells in real
+ * space. Therefore, the effect in this element is as follows: if
+ * <tt>update_values</tt> is set in <tt>flags</tt>, copy it to the
+ * result. All other flags of the result are cleared, since everything else
+ * must be computed for each cell.
*/
virtual UpdateFlags update_once (const UpdateFlags flags) const;
/**
- * Determine the values that need
- * to be computed on every cell
- * to be able to compute all
- * values required by
- * <tt>flags</tt>.
+ * Determine the values that need to be computed on every cell to be able to
+ * compute all values required by <tt>flags</tt>.
*
- * For the purpuse of this
- * function, refer to the
- * documentation in
+ * For the purpuse of this function, refer to the documentation in
* FiniteElement.
*
- * This class assumes that shape
- * functions of this
- * FiniteElement do <em>not</em>
- * depend on the actual shape of
- * the cells in real
- * space.
+ * This class assumes that shape functions of this FiniteElement do
+ * <em>not</em> depend on the actual shape of the cells in real space.
*
- * The effect in this element is
- * as follows:
+ * The effect in this element is as follows:
* <ul>
-
- * <li> if
- * <tt>update_gradients</tt> is
- * set, the result will contain
- * <tt>update_gradients</tt> and
- * <tt>update_covariant_transformation</tt>.
- * The latter is required to
- * transform the gradient on the
- * unit cell to the real
- * cell. Remark, that the action
- * required by
- * <tt>update_covariant_transformation</tt>
- * is actually performed by the
- * Mapping object used in
- * conjunction with this finite
- * element. <li> if
- * <tt>update_hessians</tt>
- * is set, the result will
- * contain
- * <tt>update_hessians</tt>
- * and
- * <tt>update_covariant_transformation</tt>.
- * The rationale is the same as
- * above and no higher
- * derivatives of the
- * transformation are required,
- * since we use difference
- * quotients for the actual
- * computation.
+ *
+ * <li> if <tt>update_gradients</tt> is set, the result will contain
+ * <tt>update_gradients</tt> and <tt>update_covariant_transformation</tt>.
+ * The latter is required to transform the gradient on the unit cell to the
+ * real cell. Remark, that the action required by
+ * <tt>update_covariant_transformation</tt> is actually performed by the
+ * Mapping object used in conjunction with this finite element.
+ *
+ * <li> if <tt>update_hessians</tt> is set, the result will contain
+ * <tt>update_hessians</tt> and <tt>update_covariant_transformation</tt>.
+ * The rationale is the same as above and no higher derivatives of the
+ * transformation are required, since we use difference quotients for the
+ * actual computation.
*
* </ul>
*/
/**
* Fields of cell-independent data.
*
- * For information about the
- * general purpose of this class,
- * see the documentation of the
- * base class.
+ * For information about the general purpose of this class, see the
+ * documentation of the base class.
*/
class InternalData : public FiniteElement<dim,spacedim>::InternalDataBase
{
public:
/**
- * Array with shape function
- * values in quadrature
- * points. There is one
- * row for each shape
- * function, containing
- * values for each quadrature
- * point.
+ * Array with shape function values in quadrature points. There is one row
+ * for each shape function, containing values for each quadrature point.
*
- * In this array, we store
- * the values of the shape
- * function in the quadrature
- * points on the unit
- * cell. Since these values
- * do not change under
- * transformation to the real
- * cell, we only need to copy
- * them over when visiting a
- * concrete cell.
+ * In this array, we store the values of the shape function in the
+ * quadrature points on the unit cell. Since these values do not change
+ * under transformation to the real cell, we only need to copy them over
+ * when visiting a concrete cell.
*/
std::vector<std::vector<double> > shape_values;
/**
- * Array with shape function
- * gradients in quadrature
- * points. There is one
- * row for each shape
- * function, containing
- * values for each quadrature
+ * Array with shape function gradients in quadrature points. There is one
+ * row for each shape function, containing values for each quadrature
* point.
*
- * We store the gradients in
- * the quadrature points on
- * the unit cell. We then
- * only have to apply the
- * transformation (which is a
- * matrix-vector
- * multiplication) when
- * visiting an actual cell.
+ * We store the gradients in the quadrature points on the unit cell. We
+ * then only have to apply the transformation (which is a matrix-vector
+ * multiplication) when visiting an actual cell.
*/
std::vector<std::vector<Tensor<1,dim> > > shape_gradients;
};
/**
- * The polynomial space. Its type
- * is given by the template
- * parameter POLY.
+ * The polynomial space. Its type is given by the template parameter POLY.
*/
POLY poly_space;
};
return std::vector<unsigned int>();
}
- template <int dim>
+ template <int dim, typename POLY>
inline
std::vector<unsigned int>
- get_poly_space_numbering (const TensorProductPolynomials<dim> &poly)
+ get_poly_space_numbering (const TensorProductPolynomials<dim,POLY> &poly)
{
return poly.get_numbering();
}
- template <int dim>
+ template <int dim, typename POLY>
inline
std::vector<unsigned int>
- get_poly_space_numbering_inverse (const TensorProductPolynomials<dim> &poly)
+ get_poly_space_numbering_inverse (const TensorProductPolynomials<dim,POLY> &poly)
{
return poly.get_numbering_inverse();
}
#include <deal.II/base/config.h>
#include <deal.II/base/tensor_product_polynomials.h>
-#include <deal.II/fe/fe_poly.h>
+#include <deal.II/fe/fe_q_base.h>
DEAL_II_NAMESPACE_OPEN
* @author Wolfgang Bangerth, 1998, 2003; Guido Kanschat, 2001; Ralf Hartmann, 2001, 2004, 2005; Oliver Kayser-Herold, 2004; Katharina Kormann, 2008; Martin Kronbichler, 2008
*/
template <int dim, int spacedim=dim>
-class FE_Q : public FE_Poly<TensorProductPolynomials<dim>,dim,spacedim>
+class FE_Q : public FE_Q_Base<TensorProductPolynomials<dim>,dim,spacedim>
{
public:
/**
- * Constructor for tensor product
- * polynomials of degree @p p.
+ * Constructor for tensor product polynomials of degree @p p.
*/
FE_Q (const unsigned int p);
/**
- * Constructor for tensor product
- * polynomials with support
- * points @p points based on a
- * one-dimensional quadrature
- * formula. The degree of the
- * finite element is
- * <tt>points.size()-1</tt>.
- * Note that the first point has
- * to be 0 and the last one 1. If
- * <tt>FE_Q<dim>(QGaussLobatto<1>(fe_degree+1))</tt>
- * is specified, so-called
- * Gauss-Lobatto elements are
- * obtained which can give a
- * diagonal mass matrix if
- * combined with Gauss-Lobatto
- * quadrature on the same
- * points. Their use is shown in
- * step-48.
+ * Constructor for tensor product polynomials with support points @p points
+ * based on a one-dimensional quadrature formula. The degree of the finite
+ * element is <tt>points.size()-1</tt>. Note that the first point has to be
+ * 0 and the last one 1. If
+ * <tt>FE_Q<dim>(QGaussLobatto<1>(fe_degree+1))</tt> is specified, so-called
+ * Gauss-Lobatto elements are obtained which can give a diagonal mass matrix
+ * if combined with Gauss-Lobatto quadrature on the same points. Their use
+ * is shown in step-48.
*/
FE_Q (const Quadrature<1> &points);
/**
- * Return a string that uniquely
- * identifies a finite
- * element. This class returns
- * <tt>FE_Q<dim>(degree)</tt>, with
- * @p dim and @p degree
- * replaced by appropriate
- * values.
+ * Constructs a FE_Q_isoQ1 element. That element shares large parts of code
+ * with FE_Q so most of the construction work is done in this routine,
+ * whereas the public constructor is in the class FE_Q_isoQ1.
*/
- virtual std::string get_name () const;
-
- /**
- * Return the matrix
- * interpolating from the given
- * finite element to the present
- * one. The size of the matrix is
- * then @p dofs_per_cell times
- * <tt>source.dofs_per_cell</tt>.
- *
- * These matrices are only
- * available if the source
- * element is also a @p FE_Q
- * element. Otherwise, an
- * exception of type
- * FiniteElement<dim,spacedim>::ExcInterpolationNotImplemented
- * is thrown.
- */
- virtual void
- get_interpolation_matrix (const FiniteElement<dim,spacedim> &source,
- FullMatrix<double> &matrix) const;
-
-
- /**
- * Return the matrix
- * interpolating from a face of
- * of one element to the face of
- * the neighboring element.
- * The size of the matrix is
- * then <tt>source.dofs_per_face</tt> times
- * <tt>this->dofs_per_face</tt>.
- *
- * Derived elements will have to
- * implement this function. They
- * may only provide interpolation
- * matrices for certain source
- * finite elements, for example
- * those from the same family. If
- * they don't implement
- * interpolation from a given
- * element, then they must throw
- * an exception of type
- * FiniteElement<dim,spacedim>::ExcInterpolationNotImplemented.
- */
- virtual void
- get_face_interpolation_matrix (const FiniteElement<dim,spacedim> &source,
- FullMatrix<double> &matrix) const;
-
- /**
- * Return the matrix
- * interpolating from a face of
- * of one element to the face of
- * the neighboring element.
- * The size of the matrix is
- * then <tt>source.dofs_per_face</tt> times
- * <tt>this->dofs_per_face</tt>.
- *
- * Derived elements will have to
- * implement this function. They
- * may only provide interpolation
- * matrices for certain source
- * finite elements, for example
- * those from the same family. If
- * they don't implement
- * interpolation from a given
- * element, then they must throw
- * an exception of type
- * FiniteElement<dim,spacedim>::ExcInterpolationNotImplemented.
- */
- virtual void
- get_subface_interpolation_matrix (const FiniteElement<dim,spacedim> &source,
- const unsigned int subface,
- FullMatrix<double> &matrix) const;
-
- /**
- * Check for non-zero values on a face.
- *
- * This function returns
- * @p true, if the shape
- * function @p shape_index has
- * non-zero values on the face
- * @p face_index.
- *
- * Implementation of the
- * interface in
- * FiniteElement
- */
- virtual bool has_support_on_face (const unsigned int shape_index,
- const unsigned int face_index) const;
-
- /**
- * @name Functions to support hp
- * @{
- */
-
- /**
- * Return whether this element
- * implements its hanging node
- * constraints in the new way,
- * which has to be used to make
- * elements "hp compatible".
- *
- * For the FE_Q class the result is
- * always true (independent of the degree
- * of the element), as it implements the
- * complete set of functions necessary
- * for hp capability.
- */
- virtual bool hp_constraints_are_implemented () const;
-
- /**
- * If, on a vertex, several finite elements are active, the hp code
- * first assigns the degrees of freedom of each of these FEs
- * different global indices. It then calls this function to find out
- * which of them should get identical values, and consequently can
- * receive the same global DoF index. This function therefore
- * returns a list of identities between DoFs of the present finite
- * element object with the DoFs of @p fe_other, which is a reference
- * to a finite element object representing one of the other finite
- * elements active on this particular vertex. The function computes
- * which of the degrees of freedom of the two finite element objects
- * are equivalent, both numbered between zero and the corresponding
- * value of dofs_per_vertex of the two finite elements. The first
- * index of each pair denotes one of the vertex dofs of the present
- * element, whereas the second is the corresponding index of the
- * other finite element.
- */
- virtual
- std::vector<std::pair<unsigned int, unsigned int> >
- hp_vertex_dof_identities (const FiniteElement<dim,spacedim> &fe_other) const;
+ FE_Q(const unsigned int subdivisions_per_dimension,
+ const unsigned int base_degree);
/**
- * Same as hp_vertex_dof_indices(), except that the function treats
- * degrees of freedom on lines.
+ * Return a string that uniquely identifies a finite element. This class
+ * returns <tt>FE_Q<dim>(degree)</tt>, with @p dim and @p degree replaced by
+ * appropriate values.
*/
- virtual
- std::vector<std::pair<unsigned int, unsigned int> >
- hp_line_dof_identities (const FiniteElement<dim,spacedim> &fe_other) const;
-
- /**
- * Same as hp_vertex_dof_indices(), except that the function treats
- * degrees of freedom on quads.
- */
- virtual
- std::vector<std::pair<unsigned int, unsigned int> >
- hp_quad_dof_identities (const FiniteElement<dim,spacedim> &fe_other) const;
-
- /**
- * Return whether this element dominates
- * the one given as argument when they
- * meet at a common face,
- * whether it is the other way around,
- * whether neither dominates, or if
- * either could dominate.
- *
- * For a definition of domination, see
- * FiniteElementBase::Domination and in
- * particular the @ref hp_paper "hp paper".
- */
- virtual
- FiniteElementDomination::Domination
- compare_for_face_domination (const FiniteElement<dim,spacedim> &fe_other) const;
- //@}
-
- /**
- * Determine an estimate for the
- * memory consumption (in bytes)
- * of this object.
- *
- * This function is made virtual,
- * since finite element objects
- * are usually accessed through
- * pointers to their base class,
- * rather than the class itself.
- */
- virtual std::size_t memory_consumption () const;
+ virtual std::string get_name () const;
protected:
- /**
- * @p clone function instead of
- * a copy constructor.
- *
- * This function is needed by the
- * constructors of @p FESystem.
- */
- virtual FiniteElement<dim,spacedim> *clone() const;
-
-private:
/**
- * Only for internal use. Its
- * full name is
- * @p get_dofs_per_object_vector
- * function and it creates the
- * @p dofs_per_object vector that is
- * needed within the constructor to
- * be passed to the constructor of
- * @p FiniteElementData.
- */
- static std::vector<unsigned int> get_dpo_vector(const unsigned int degree);
-
- /**
- * This is an analogon to the
- * FETools::lexicographic_to_hierarchic_numbering
- * function, but working on
- * faces. Called from the
- * constructor.
- */
- static
- std::vector<unsigned int>
- face_lexicographic_to_hierarchic_numbering (const unsigned int degree);
-
- /**
- * Initialize the hanging node
- * constraints matrices. Called
- * from the constructor.
- */
- void initialize_constraints ();
-
- /**
- * Initialize the embedding
- * matrices. Called from the
- * constructor.
- */
- void initialize_embedding ();
-
- /**
- * Initialize the restriction
- * matrices. Called from the
- * constructor.
- */
- void initialize_restriction ();
-
- /**
- * Initialize the
- * @p unit_support_points field
- * of the FiniteElement
- * class. Called from the
- * constructor.
- */
- void initialize_unit_support_points ();
-
- /**
- * Initialize the @p unit_support_points
- * field of the FiniteElement
- * class. Called from the constructor in
- * case the finite element is based on
- * quadrature points.
- */
- void initialize_unit_support_points (const Quadrature<1> &points);
-
- /**
- * Initialize the
- * @p unit_face_support_points field
- * of the FiniteElement
- * class. Called from the
- * constructor.
- */
- void initialize_unit_face_support_points ();
-
- /**
- * Initialize the @p
- * unit_face_support_points field of the
- * FiniteElement class. Called from the
- * constructor in case the finite element
- * is based on quadrature points.
- */
- void initialize_unit_face_support_points (const Quadrature<1> &points);
-
- /**
- * Initialize the
- * @p adjust_quad_dof_index_for_face_orientation_table field
- * of the FiniteElement
- * class. Called from the
- * constructor.
- */
- void initialize_quad_dof_index_permutation ();
-
- /**
- * Mapping from hierarchic to
- * lexicographic numbering on
- * first face. Hierarchic is the
- * numbering of the shape
- * functions.
- */
- const std::vector<unsigned int> face_index_map;
-
-
- /**
- * Forward declaration of a class
- * into which we put significant
- * parts of the implementation.
+ * @p clone function instead of a copy constructor.
*
- * See the .cc file for more
- * information.
- */
- struct Implementation;
-
- /**
- * Allow access from other
- * dimensions. We need this since
- * we want to call the functions
- * @p get_dpo_vector and
- * @p lexicographic_to_hierarchic_numbering
- * for the faces of the finite
- * element of dimension dim+1.
+ * This function is needed by the constructors of @p FESystem.
*/
- template <int, int> friend class FE_Q;
-
- friend struct FE_Q<dim,spacedim>::Implementation;
+ virtual FiniteElement<dim,spacedim> *clone() const;
};
/*@}*/
-/* -------------- declaration of explicit specializations ------------- */
-
-template <>
-void FE_Q<1>::initialize_unit_face_support_points ();
-
-template <>
-std::vector<unsigned int>
-FE_Q<1>::face_lexicographic_to_hierarchic_numbering (const unsigned int);
-
-
-template <>
-void FE_Q<1,2>::initialize_unit_face_support_points ();
-
-template <>
-std::vector<unsigned int>
-FE_Q<1,2>::face_lexicographic_to_hierarchic_numbering (const unsigned int);
-
-template <>
-void FE_Q<1,3>::initialize_unit_face_support_points ();
-
-template <>
-std::vector<unsigned int>
-FE_Q<1,3>::face_lexicographic_to_hierarchic_numbering (const unsigned int);
-
DEAL_II_NAMESPACE_CLOSE
#endif
--- /dev/null
+//---------------------------------------------------------------------------
+// $Id$
+//
+// Copyright (C) 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010, 2011, 2012, 2013 by the deal.II authors
+//
+// This file is subject to QPL and may not be distributed
+// without copyright and license information. Please refer
+// to the file deal.II/doc/license.html for the text and
+// further information on this license.
+//
+//---------------------------------------------------------------------------
+#ifndef __deal2__fe_q_base_h
+#define __deal2__fe_q_base_h
+
+#include <deal.II/base/config.h>
+#include <deal.II/fe/fe_poly.h>
+#include <deal.II/base/thread_management.h>
+
+DEAL_II_NAMESPACE_OPEN
+
+
+/*!@addtogroup fe */
+/*@{*/
+
+/**
+ * This class collects the basic methods used in FE_Q and FE_Q_DG0. There is
+ * no public constructor for this class as it is not functional as a
+ * stand-alone. The completion of definitions is left to the derived classes.
+ *
+ * @author Wolfgang Bangerth, 1998, 2003; Guido Kanschat, 2001; Ralf Hartmann, 2001, 2004, 2005; Oliver Kayser-Herold, 2004; Katharina Kormann, 2008; Martin Kronbichler, 2008, 2013
+ */
+template <class POLY, int dim=POLY::dimension, int spacedim=dim>
+class FE_Q_Base : public FE_Poly<POLY,dim,spacedim>
+{
+public:
+ /**
+ * Constructor.
+ */
+ FE_Q_Base (const POLY &poly_space,
+ const FiniteElementData<dim> &fe_data,
+ const std::vector<bool> &restriction_is_additive_flags);
+
+ /**
+ * Return the matrix interpolating from the given finite element to the
+ * present one. The size of the matrix is then @p dofs_per_cell times
+ * <tt>source.dofs_per_cell</tt>.
+ *
+ * These matrices are only available if the source element is also a @p FE_Q
+ * element. Otherwise, an exception of type
+ * FiniteElement<dim,spacedim>::ExcInterpolationNotImplemented is thrown.
+ */
+ virtual void
+ get_interpolation_matrix (const FiniteElement<dim,spacedim> &source,
+ FullMatrix<double> &matrix) const;
+
+
+ /**
+ * Return the matrix interpolating from a face of of one element to the face
+ * of the neighboring element. The size of the matrix is then
+ * <tt>source.dofs_per_face</tt> times <tt>this->dofs_per_face</tt>.
+ *
+ * Derived elements will have to implement this function. They may only
+ * provide interpolation matrices for certain source finite elements, for
+ * example those from the same family. If they don't implement interpolation
+ * from a given element, then they must throw an exception of type
+ * FiniteElement<dim,spacedim>::ExcInterpolationNotImplemented.
+ */
+ virtual void
+ get_face_interpolation_matrix (const FiniteElement<dim,spacedim> &source,
+ FullMatrix<double> &matrix) const;
+
+ /**
+ * Return the matrix interpolating from a face of of one element to the face
+ * of the neighboring element. The size of the matrix is then
+ * <tt>source.dofs_per_face</tt> times <tt>this->dofs_per_face</tt>.
+ *
+ * Derived elements will have to implement this function. They may only
+ * provide interpolation matrices for certain source finite elements, for
+ * example those from the same family. If they don't implement interpolation
+ * from a given element, then they must throw an exception of type
+ * FiniteElement<dim,spacedim>::ExcInterpolationNotImplemented.
+ */
+ virtual void
+ get_subface_interpolation_matrix (const FiniteElement<dim,spacedim> &source,
+ const unsigned int subface,
+ FullMatrix<double> &matrix) const;
+
+ /**
+ * Check for non-zero values on a face.
+ *
+ * This function returns @p true, if the shape function @p shape_index has
+ * non-zero values on the face @p face_index.
+ *
+ * Implementation of the interface in FiniteElement
+ */
+ virtual bool has_support_on_face (const unsigned int shape_index,
+ const unsigned int face_index) const;
+
+ /**
+ * Projection from a fine grid space onto a coarse grid space. Overrides the
+ * respective method in FiniteElement, implementing lazy evaluation
+ * (initialize when requested).
+ *
+ * If this projection operator is associated with a matrix @p P, then the
+ * restriction of this matrix @p P_i to a single child cell is returned
+ * here.
+ *
+ * The matrix @p P is the concatenation or the sum of the cell matrices @p
+ * P_i, depending on the #restriction_is_additive_flags. This distinguishes
+ * interpolation (concatenation) and projection with respect to scalar
+ * products (summation).
+ *
+ * Row and column indices are related to coarse grid and fine grid spaces,
+ * respectively, consistent with the definition of the associated operator.
+ *
+ * If projection matrices are not implemented in the derived finite element
+ * class, this function aborts with ExcProjectionVoid. You can check whether
+ * this is the case by calling the restriction_is_implemented() or the
+ * isotropic_restriction_is_implemented() function.
+ */
+ virtual const FullMatrix<double> &
+ get_restriction_matrix (const unsigned int child,
+ const RefinementCase<dim> &refinement_case=RefinementCase<dim>::isotropic_refinement) const;
+
+ /**
+ * Embedding matrix between grids. Overrides the respective method in
+ * FiniteElement, implementing lazy evaluation (initialize when queried).
+ *
+ * The identity operator from a coarse grid space into a fine grid space is
+ * associated with a matrix @p P. The restriction of this matrix @p P_i to a
+ * single child cell is returned here.
+ *
+ * The matrix @p P is the concatenation, not the sum of the cell matrices @p
+ * P_i. That is, if the same non-zero entry <tt>j,k</tt> exists in in two
+ * different child matrices @p P_i, the value should be the same in both
+ * matrices and it is copied into the matrix @p P only once.
+ *
+ * Row and column indices are related to fine grid and coarse grid spaces,
+ * respectively, consistent with the definition of the associated operator.
+ *
+ * These matrices are used by routines assembling the prolongation matrix
+ * for multi-level methods. Upon assembling the transfer matrix between
+ * cells using this matrix array, zero elements in the prolongation matrix
+ * are discarded and will not fill up the transfer matrix.
+ *
+ * If projection matrices are not implemented in the derived finite element
+ * class, this function aborts with ExcEmbeddingVoid. You can check whether
+ * this is the case by calling the prolongation_is_implemented() or the
+ * isotropic_prolongation_is_implemented() function.
+ */
+ virtual const FullMatrix<double> &
+ get_prolongation_matrix (const unsigned int child,
+ const RefinementCase<dim> &refinement_case=RefinementCase<dim>::isotropic_refinement) const;
+
+ /**
+ * @name Functions to support hp
+ * @{
+ */
+
+ /**
+ * Return whether this element implements its hanging node constraints in
+ * the new way, which has to be used to make elements "hp compatible".
+ *
+ * For the FE_Q class the result is always true (independent of the degree
+ * of the element), as it implements the complete set of functions necessary
+ * for hp capability.
+ */
+ virtual bool hp_constraints_are_implemented () const;
+
+ /**
+ * If, on a vertex, several finite elements are active, the hp code
+ * first assigns the degrees of freedom of each of these FEs
+ * different global indices. It then calls this function to find out
+ * which of them should get identical values, and consequently can
+ * receive the same global DoF index. This function therefore
+ * returns a list of identities between DoFs of the present finite
+ * element object with the DoFs of @p fe_other, which is a reference
+ * to a finite element object representing one of the other finite
+ * elements active on this particular vertex. The function computes
+ * which of the degrees of freedom of the two finite element objects
+ * are equivalent, both numbered between zero and the corresponding
+ * value of dofs_per_vertex of the two finite elements. The first
+ * index of each pair denotes one of the vertex dofs of the present
+ * element, whereas the second is the corresponding index of the
+ * other finite element.
+ */
+ virtual
+ std::vector<std::pair<unsigned int, unsigned int> >
+ hp_vertex_dof_identities (const FiniteElement<dim,spacedim> &fe_other) const;
+
+ /**
+ * Same as hp_vertex_dof_indices(), except that the function treats
+ * degrees of freedom on lines.
+ */
+ virtual
+ std::vector<std::pair<unsigned int, unsigned int> >
+ hp_line_dof_identities (const FiniteElement<dim,spacedim> &fe_other) const;
+
+ /**
+ * Same as hp_vertex_dof_indices(), except that the function treats
+ * degrees of freedom on quads.
+ */
+ virtual
+ std::vector<std::pair<unsigned int, unsigned int> >
+ hp_quad_dof_identities (const FiniteElement<dim,spacedim> &fe_other) const;
+
+ /**
+ * Return whether this element dominates the one given as argument when they
+ * meet at a common face, whether it is the other way around, whether
+ * neither dominates, or if either could dominate.
+ *
+ * For a definition of domination, see FiniteElementBase::Domination and in
+ * particular the @ref hp_paper "hp paper".
+ */
+ virtual
+ FiniteElementDomination::Domination
+ compare_for_face_domination (const FiniteElement<dim,spacedim> &fe_other) const;
+ //@}
+
+protected:
+ /**
+ * Only for internal use. Its full name is @p get_dofs_per_object_vector
+ * function and it creates the @p dofs_per_object vector that is needed
+ * within the constructor to be passed to the constructor of @p
+ * FiniteElementData.
+ */
+ static std::vector<unsigned int> get_dpo_vector(const unsigned int degree);
+
+ /**
+ * Performs the initialization of the element based on 1D support points,
+ * i.e., sets renumbering, initializes unit support points, initializes
+ * constraints as well as restriction and prolongation matrices.
+ */
+ void initialize (const std::vector<Point<1> > &support_points_1d);
+
+ /**
+ * Initialize the hanging node constraints matrices. Called from
+ * initialize().
+ */
+ void initialize_constraints (const std::vector<Point<1> > &points);
+
+ /**
+ * Initialize the @p unit_support_points field of the FiniteElement
+ * class. Called from initialize().
+ */
+ void initialize_unit_support_points (const std::vector<Point<1> > &points);
+
+ /**
+ * Initialize the @p unit_face_support_points field of the FiniteElement
+ * class. Called from initialize().
+ */
+ void initialize_unit_face_support_points (const std::vector<Point<1> > &points);
+
+ /**
+ * Initialize the @p adjust_quad_dof_index_for_face_orientation_table field
+ * of the FiniteElement class. Called from initialize().
+ */
+ void initialize_quad_dof_index_permutation ();
+
+ /**
+ * Forward declaration of a class into which we put significant parts of the
+ * implementation.
+ *
+ * See the .cc file for more information.
+ */
+ struct Implementation;
+
+ /*
+ * Declare implementation friend.
+ */
+ friend struct FE_Q_Base<POLY,dim,spacedim>::Implementation;
+
+private:
+ /*
+ * Mutex for protecting initialization of restriction and embedding matrix.
+ */
+ mutable Threads::Mutex mutex;
+};
+
+
+/*@}*/
+
+DEAL_II_NAMESPACE_CLOSE
+
+#endif
+//---------------------------------------------------------------------------
+// $Id: fe_q.h 29043 2013-03-26 19:51:19Z bangerth $
+//
+// Copyright (C) 2012, 2013 by the deal.II authors
+//
+// This file is subject to QPL and may not be distributed
+// without copyright and license information. Please refer
+// to the file deal.II/doc/license.html for the text and
+// further information on this license.
+//
+//---------------------------------------------------------------------------
+
#ifndef __deal2__fe_q_dg0_h
#define __deal2__fe_q_dg0_h
#include <deal.II/base/config.h>
#include <deal.II/base/tensor_product_polynomials_const.h>
-#include <deal.II/fe/fe_poly.h>
+#include <deal.II/fe/fe_q_base.h>
DEAL_II_NAMESPACE_OPEN
*
*/
template <int dim, int spacedim=dim>
-class FE_Q_DG0 : public FE_Poly<TensorProductPolynomialsConst<dim>,dim,spacedim>
+class FE_Q_DG0 : public FE_Q_Base<TensorProductPolynomialsConst<dim>,dim,spacedim>
{
public:
/**
- * Constructor for tensor product
- * polynomials of degree @p p plus locally
+ * Constructor for tensor product polynomials of degree @p p plus locally
* constant functions.
*/
FE_Q_DG0 (const unsigned int p);
/**
- * Constructor for tensor product
- * polynomials with support
- * points @p points plus locally constant
- * functions based on a one-dimensional
- * quadrature formula. The degree of the
- * finite element is
- * <tt>points.size()-1</tt>.
- * Note that the first point has
- * to be 0 and the last one 1.
+ * Constructor for tensor product polynomials with support points @p points
+ * plus locally constant functions based on a one-dimensional quadrature
+ * formula. The degree of the finite element is <tt>points.size()-1</tt>.
+ * Note that the first point has to be 0 and the last one 1.
*/
FE_Q_DG0 (const Quadrature<1> &points);
/**
- * Return a string that uniquely
- * identifies a finite
- * element. This class returns
- * <tt>FE_Q_DG0<dim>(degree)</tt>, with
- * @p dim and @p degree
- * replaced by appropriate
- * values.
+ * Return a string that uniquely identifies a finite element. This class
+ * returns <tt>FE_Q_DG0<dim>(degree)</tt>, with @p dim and @p degree
+ * replaced by appropriate values.
*/
virtual std::string get_name () const;
/**
- * Interpolate a set of scalar
- * values, computed in the
- * generalized support points.
+ * Interpolate a set of scalar values, computed in the generalized support
+ * points.
*/
virtual void interpolate(std::vector<double> &local_dofs,
const std::vector<double> &values) const;
/**
- * Interpolate a set of vector
- * values, computed in the
- * generalized support points.
+ * Interpolate a set of vector values, computed in the generalized support
+ * points.
*
- * Since a finite element often
- * only interpolates part of a
- * vector, <tt>offset</tt> is
- * used to determine the first
- * component of the vector to be
- * interpolated. Maybe consider
- * changing your data structures
- * to use the next function.
+ * Since a finite element often only interpolates part of a vector,
+ * <tt>offset</tt> is used to determine the first component of the vector to
+ * be interpolated. Maybe consider changing your data structures to use the
+ * next function.
*/
virtual void interpolate(std::vector<double> &local_dofs,
const std::vector<Vector<double> > &values,
unsigned int offset = 0) const;
/**
- * Interpolate a set of vector
- * values, computed in the
- * generalized support points.
+ * Interpolate a set of vector values, computed in the generalized support
+ * points.
*/
virtual void interpolate(
std::vector<double> &local_dofs,
const VectorSlice<const std::vector<std::vector<double> > > &values) const;
/**
- * Return the matrix interpolating from the
- * given finite element to the present one.
- * The size of the matrix is then @p
- * dofs_per_cell times
+ * Return the matrix interpolating from the given finite element to the
+ * present one. The size of the matrix is then @p dofs_per_cell times
* <tt>source.dofs_per_cell</tt>.
*
- * These matrices are only available if the
- * source element is also a @p FE_Q_DG0
- * element. Otherwise, an exception of type
- * FiniteElement<dim,spacedim>::ExcInterpolationNotImplemented
- * is thrown.
+ * These matrices are only available if the source element is also a @p
+ * FE_Q_DG0 element. Otherwise, an exception of type
+ * FiniteElement<dim,spacedim>::ExcInterpolationNotImplemented is thrown.
*/
virtual void
get_interpolation_matrix (const FiniteElement<dim,spacedim> &source,
FullMatrix<double> &matrix) const;
- /**
- * Return the matrix
- * interpolating from a face of
- * of one element to the face of
- * the neighboring element.
- * The size of the matrix is
- * then <tt>source.dofs_per_face</tt> times
- * <tt>this->dofs_per_face</tt>.
- *
- * Derived elements will have to
- * implement this function. They
- * may only provide interpolation
- * matrices for certain source
- * finite elements, for example
- * those from the same family. If
- * they don't implement
- * interpolation from a given
- * element, then they must throw
- * an exception of type
- * FiniteElement<dim,spacedim>::ExcInterpolationNotImplemented.
- */
- virtual void
- get_face_interpolation_matrix (const FiniteElement<dim,spacedim> &source,
- FullMatrix<double> &matrix) const;
-
- /**
- * Return the matrix
- * interpolating from a face of
- * of one element to the face of
- * the neighboring element.
- * The size of the matrix is
- * then <tt>source.dofs_per_face</tt> times
- * <tt>this->dofs_per_face</tt>.
- *
- * Derived elements will have to
- * implement this function. They
- * may only provide interpolation
- * matrices for certain source
- * finite elements, for example
- * those from the same family. If
- * they don't implement
- * interpolation from a given
- * element, then they must throw
- * an exception of type
- * FiniteElement<dim,spacedim>::ExcInterpolationNotImplemented.
- */
- virtual void
- get_subface_interpolation_matrix (const FiniteElement<dim,spacedim> &source,
- const unsigned int subface,
- FullMatrix<double> &matrix) const;
-
/**
* Check for non-zero values on a face.
*
- * This function returns
- * @p true, if the shape
- * function @p shape_index has
- * non-zero values on the face
- * @p face_index.
+ * This function returns @p true, if the shape function @p shape_index has
+ * non-zero values on the face @p face_index.
*
- * Implementation of the
- * interface in
- * FiniteElement
+ * Implementation of the interface in FiniteElement
*/
virtual bool has_support_on_face (const unsigned int shape_index,
const unsigned int face_index) const;
- /**
- * @name Functions to support hp
- * @{
- */
-
- /**
- * Return whether this element
- * implements its hanging node
- * constraints in the new way,
- * which has to be used to make
- * elements "hp compatible".
- *
- * For the FE_Q_DG0 class the result is
- * always true (independent of the degree
- * of the element), as it implements the
- * complete set of functions necessary
- * for hp capability.
- */
- virtual bool hp_constraints_are_implemented () const;
-
- /**
- * If, on a vertex, several finite elements are active, the hp code
- * first assigns the degrees of freedom of each of these FEs
- * different global indices. It then calls this function to find out
- * which of them should get identical values, and consequently can
- * receive the same global DoF index. This function therefore
- * returns a list of identities between DoFs of the present finite
- * element object with the DoFs of @p fe_other, which is a reference
- * to a finite element object representing one of the other finite
- * elements active on this particular vertex. The function computes
- * which of the degrees of freedom of the two finite element objects
- * are equivalent, both numbered between zero and the corresponding
- * value of dofs_per_vertex of the two finite elements. The first
- * index of each pair denotes one of the vertex dofs of the present
- * element, whereas the second is the corresponding index of the
- * other finite element.
- */
- virtual
- std::vector<std::pair<unsigned int, unsigned int> >
- hp_vertex_dof_identities (const FiniteElement<dim,spacedim> &fe_other) const;
-
- /**
- * Same as
- * hp_vertex_dof_indices(),
- * except that the function
- * treats degrees of freedom on
- * lines.
- */
- virtual
- std::vector<std::pair<unsigned int, unsigned int> >
- hp_line_dof_identities (const FiniteElement<dim,spacedim> &fe_other) const;
-
- /**
- * Same as
- * hp_vertex_dof_indices(),
- * except that the function
- * treats degrees of freedom on
- * quads.
- */
- virtual
- std::vector<std::pair<unsigned int, unsigned int> >
- hp_quad_dof_identities (const FiniteElement<dim,spacedim> &fe_other) const;
-
- /**
- * Return whether this element dominates
- * the one given as argument when they
- * meet at a common face,
- * whether it is the other way around,
- * whether neither dominates, or if
- * either could dominate.
- *
- * For a definition of domination, see
- * FiniteElementBase::Domination and in
- * particular the @ref hp_paper "hp paper".
- */
- virtual
- FiniteElementDomination::Domination
- compare_for_face_domination (const FiniteElement<dim,spacedim> &fe_other) const;
- //@}
-
- /**
- * Determine an estimate for the
- * memory consumption (in bytes)
- * of this object.
- *
- * This function is made virtual,
- * since finite element objects
- * are usually accessed through
- * pointers to their base class,
- * rather than the class itself.
- */
- virtual std::size_t memory_consumption () const;
-
protected:
/**
- * @p clone function instead of
- * a copy constructor.
+ * @p clone function instead of a copy constructor.
*
- * This function is needed by the
- * constructors of @p FESystem.
+ * This function is needed by the constructors of @p FESystem.
*/
virtual FiniteElement<dim,spacedim> *clone() const;
private:
+
/**
* Returns the restriction_is_additive flags.
* Only the last component is true.
static std::vector<bool> get_riaf_vector(const unsigned int degree);
/**
- * Only for internal use. Its
- * full name is
- * @p get_dofs_per_object_vector
- * function and it creates the
- * @p dofs_per_object vector that is
- * needed within the constructor to
- * be passed to the constructor of
- * @p FiniteElementData.
+ * Only for internal use. Its full name is @p get_dofs_per_object_vector
+ * function and it creates the @p dofs_per_object vector that is needed
+ * within the constructor to be passed to the constructor of @p
+ * FiniteElementData.
*/
static std::vector<unsigned int> get_dpo_vector(const unsigned int degree);
-
- /**
- * Only for internal use. Its
- * full name is
- * @p get_dofs_per_object_vector_q
- * function and it creates the
- * @p dofs_per_object vector that is
- * needed within the constructor to
- * be passed to the constructor of
- * @p FiniteElementData for FE_Q_DG0
- * objects.
- */
- static std::vector<unsigned int> get_dpo_vector_q(const unsigned int degree);
-
- /**
- * This is an analogon to the
- * FETools::lexicographic_to_hierarchic_numbering
- * function, but working on
- * faces. Called from the
- * constructor.
- */
- static
- std::vector<unsigned int>
- face_lexicographic_to_hierarchic_numbering (const unsigned int degree);
-
- /**
- * Initialize the hanging node
- * constraints matrices. Called
- * from the constructor.
- */
- void initialize_constraints ();
-
- /**
- * Initialize the embedding
- * matrices. Called from the
- * constructor.
- */
- void initialize_embedding ();
-
- /**
- * Initialize the restriction
- * matrices. Called from the
- * constructor.
- */
- void initialize_restriction ();
-
- /**
- * Initialize the
- * @p unit_support_points field
- * of the FiniteElement
- * class. Called from the
- * constructor.
- */
- void initialize_unit_support_points ();
-
- /**
- * Initialize the @p unit_support_points
- * field of the FiniteElement
- * class. Called from the constructor in
- * case the finite element is based on
- * quadrature points.
- */
- void initialize_unit_support_points (const Quadrature<1> &points);
-
- /**
- * Initialize the
- * @p unit_face_support_points field
- * of the FiniteElement
- * class. Called from the
- * constructor.
- */
- void initialize_unit_face_support_points ();
-
- /**
- * Initialize the @p
- * unit_face_support_points field of the
- * FiniteElement class. Called from the
- * constructor in case the finite element
- * is based on quadrature points.
- */
- void initialize_unit_face_support_points (const Quadrature<1> &points);
-
- /**
- * Initialize the
- * @p adjust_quad_dof_index_for_face_orientation_table field
- * of the FiniteElement
- * class. Called from the
- * constructor.
- */
- void initialize_quad_dof_index_permutation ();
-
- /**
- * Mapping from hierarchic to
- * lexicographic numbering on
- * first face. Hierarchic is the
- * numbering of the shape
- * functions.
- */
- const std::vector<unsigned int> face_index_map;
-
-
- /**
- * Forward declaration of a class
- * into which we put significant
- * parts of the implementation.
- *
- * See the .cc file for more
- * information.
- */
- struct Implementation;
-
- /**
- * Allow access from other
- * dimensions. We need this since
- * we want to call the functions
- * @p get_dpo_vector and
- * @p lexicographic_to_hierarchic_numbering
- * for the faces of the finite
- * element of dimension dim+1.
- */
- template <int, int> friend class FE_Q_DG0;
-
- friend struct FE_Q_DG0<dim,spacedim>::Implementation;
};
/*@}*/
-/* -------------- declaration of explicit specializations ------------- */
-
-template <>
-void FE_Q_DG0<1>::initialize_unit_face_support_points ();
-
-template <>
-std::vector<unsigned int>
-FE_Q_DG0<1>::face_lexicographic_to_hierarchic_numbering (const unsigned int);
-
-
-template <>
-void FE_Q_DG0<1,2>::initialize_unit_face_support_points ();
-
-template <>
-std::vector<unsigned int>
-FE_Q_DG0<1,2>::face_lexicographic_to_hierarchic_numbering (const unsigned int);
-
-template <>
-void FE_Q_DG0<1,3>::initialize_unit_face_support_points ();
-
-template <>
-std::vector<unsigned int>
-FE_Q_DG0<1,3>::face_lexicographic_to_hierarchic_numbering (const unsigned int);
DEAL_II_NAMESPACE_CLOSE
--- /dev/null
+//---------------------------------------------------------------------------
+// $Id$
+//
+// Copyright (C) 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010, 2011, 2012, 2013 by the deal.II authors
+//
+// This file is subject to QPL and may not be distributed
+// without copyright and license information. Please refer
+// to the file deal.II/doc/license.html for the text and
+// further information on this license.
+//
+//---------------------------------------------------------------------------
+#ifndef __deal2__fe_q_iso_q1_h
+#define __deal2__fe_q_iso_q1_h
+
+#include <deal.II/base/config.h>
+#include <deal.II/base/tensor_product_polynomials.h>
+#include <deal.II/base/polynomials_piecewise.h>
+#include <deal.II/fe/fe_q_base.h>
+
+DEAL_II_NAMESPACE_OPEN
+
+
+/*!@addtogroup fe */
+/*@{*/
+
+/**
+ * Implementation of a scalar Lagrange finite element @p Qp-iso-Q1 that
+ * defines the finite element space of continuous, piecewise linear elements
+ * with @p p subdivisions in each coordinate direction. It yields an element
+ * with the same number of degrees of freedom as the @p Qp elements but using
+ * linear interpolation instead of higher order one. This type of element is
+ * also called macro element in the literature as it really consists of several
+ * smaller elements, namely <i>p</i><tt><sup>dim</sup></tt>.
+ *
+ * The numbering of degrees of freedom is done in exactly the same way as in
+ * FE_Q of degree @p p. See there for a detailed description on how degrees of
+ * freedom are numbered within one element.
+ *
+ * This element represents a Q-linear finite element space on a reduced mesh
+ * size <i>h/p</i>. Its effect is equivalent to using FE_Q of degree one on a
+ * finer mesh by a factor @p p if an equivalent quadrature is used. However,
+ * this element reduces the flexibility in the choice of (adaptive) mesh size
+ * by exactly this factor @p p, which typically reduces efficiency. On the
+ * other hand, comparing this element with @p p subdivisions to the FE_Q
+ * element of degree @p p on the same mesh shows that the convergence is
+ * typically much worse for smooth problems. In particular, @p Qp elements
+ * achieve interpolation orders of <i>h<sup>p+1</sup></i> in the L2 norm,
+ * whereas these elements reach only <i>(h/p)<sup>2</sup></i>. For these two
+ * reasons, this element is usually not very useful as a standalone. In
+ * addition, any evaluation of face terms on the boundaries within the
+ * elements becomes impossible with this element.
+ *
+ * Nonetheless, there are a few use cases where this element actually is
+ * useful:
+ * <ol>
+ *
+ * <li> Systems of PDEs where certain variables demand for higher resolutions
+ * than the others and the additional degrees of freedom should be spend on
+ * increasing the resolution of linears instead of higher order polynomials,
+ * and you do not want to use two different meshes for the different
+ * components. This can be the case when irregularities (shocks) appear in the
+ * solution and stabilization techniques are used that work for linears but
+ * not higher order elements. </li>
+ *
+ * <li> Stokes/Navier Stokes systems as the one discussed in step-22 could be
+ * solved with Q2-iso-Q1 elements for velocities instead of Q2
+ * elements. Combined with Q1 pressures they give a stable mixed element
+ * pair. However, they perform worse than the standard approach in most
+ * situations. </li>
+ *
+ * <li> Preconditioning systems of FE_Q systems of higher order @p p with a
+ * preconditioner based on @p Qp-iso-Q1 elements: Some preconditioners like
+ * algebraic multigrid perform much better with linear elements than with higher
+ * order elements because they often implicitly assume a sparse connectivity
+ * between entries. Then, creating a preconditioner matrix based on these
+ * elements yields the same number of degrees of freedom (and a spectrally
+ * equivalent linear system), which can be combined with a (high order) system
+ * matrix in an iterative solver like CG. </li>
+ * </ol>
+ *
+ * <h3>Appropriate integration</h3>
+ *
+ * Due to the nature of these elements as a concatenation of linears, care
+ * must be taken when selecting quadrature formulas for this element. The
+ * standard choice for an element of @p p subelements is a formula
+ * <tt>QIterated<dim>(QGauss<1>(2), p)</tt>, which corresponds to the formula
+ * that would be used for integrating functions on a finer mesh. This is in
+ * contrast with FE_Q(p) where QGauss<dim>(p+1) is the default choice. In
+ * particular, care must be taken to not use a quadrature formula that
+ * evaluates the basis functions (and their derivatives) on sub-element
+ * boundaries as the gradients of piecewiese functions on internal boundaries
+ * are set to zero. No checks are performed internally to ensure that this is
+ * not the case - it is the user's responsibility to avoid these situations.
+ *
+ * Also note that the usual deal.II routines for setting up sparsity patterns
+ * and assembling matrices do not make use of the increased sparsity in this
+ * element compared to FE_Q. This is because DoFTools::make_sparsity_pattern
+ * assumes coupling between all degrees of freedom within the element, whereas
+ * FE_Q_iso_Q1 with more than one subdivision does have less coupling.
+ *
+ * @author Martin Kronbichler, 2013
+ */
+template <int dim, int spacedim=dim>
+class FE_Q_iso_Q1 : public FE_Q_Base<TensorProductPolynomials<dim, Polynomials::PiecewisePolynomial<double> >,dim,spacedim>
+{
+public:
+ /**
+ * Constructs a FE_Q_iso_Q1 element with a given number of subdivisions. The
+ * number of subdivision is similar to the degree in FE_Q in the sense that
+ * both elements produce the same number of degrees of freedom.
+ */
+ FE_Q_iso_Q1(const unsigned int n_subdivisions);
+
+ /**
+ * Return a string that uniquely identifies a finite element. This class
+ * returns <tt>FE_Q_iso_q1<dim>(equivalent_degree)</tt>, with @p dim and @p
+ * equivalent_degree replaced by appropriate values.
+ */
+ virtual std::string get_name () const;
+
+ /**
+ * @name Functions to support hp
+ * @{
+ */
+
+ /**
+ * Return whether this element dominates the one given as argument when they
+ * meet at a common face, whether it is the other way around, whether
+ * neither dominates, or if either could dominate.
+ *
+ * For a definition of domination, see FiniteElementBase::Domination and in
+ * particular the @ref hp_paper "hp paper".
+ */
+ virtual
+ FiniteElementDomination::Domination
+ compare_for_face_domination (const FiniteElement<dim,spacedim> &fe_other) const;
+ //@}
+
+protected:
+
+ /**
+ * @p clone function instead of a copy constructor.
+ *
+ * This function is needed by the constructors of @p FESystem.
+ */
+ virtual FiniteElement<dim,spacedim> *clone() const;
+};
+
+
+
+/*@}*/
+
+DEAL_II_NAMESPACE_CLOSE
+
+#endif
#include <deal.II/base/config.h>
+#include <deal.II/base/thread_management.h>
#include <deal.II/fe/fe.h>
#include <vector>
#include <utility>
public:
/**
- * Constructor. Take a finite element type
- * and the number of elements you want to
- * group together using this class.
+ * Constructor. Take a finite element type and the number of elements you
+ * want to group together using this class.
*
- * In fact, the object @p fe is not used,
- * apart from getting the number of dofs
- * per vertex, line, etc for that finite
- * element class. The objects creates its
- * own copy of the finite element object
- * at construction time (but after
- * the initialization of the base class
- * @p FiniteElement, which is why we need
- * a valid finite element object passed
- * to the constructor).
+ * In fact, the object @p fe is not used, apart from getting the number of
+ * dofs per vertex, line, etc for that finite element class. The objects
+ * creates its own copy of the finite element object at construction time
+ * (but after the initialization of the base class @p FiniteElement, which
+ * is why we need a valid finite element object passed to the constructor).
*
- * Obviously, the template finite element
- * class needs to be of the same dimension
- * as is this object.
+ * Obviously, the template finite element class needs to be of the same
+ * dimension as is this object.
*/
FESystem (const FiniteElement<dim,spacedim> &fe,
const unsigned int n_elements);
/**
- * Constructor for mixed
- * discretizations with two
- * base elements.
+ * Constructor for mixed discretizations with two base elements.
*
* See the other constructor.
*/
const FiniteElement<dim,spacedim> &fe2, const unsigned int n2);
/**
- * Constructor for mixed
- * discretizations with three
- * base elements.
+ * Constructor for mixed discretizations with three base elements.
*
* See the other constructor.
*/
const FiniteElement<dim,spacedim> &fe3, const unsigned int n3);
/**
- * Constructor for mixed
- * discretizations with four
- * base elements.
+ * Constructor for mixed discretizations with four base elements.
*
* See the other constructor.
*/
const FiniteElement<dim,spacedim> &fe4, const unsigned int n4);
/**
- * Constructor for mixed
- * discretizations with five
- * base elements.
+ * Constructor for mixed discretizations with five base elements.
*
* See the other constructor.
*/
const FiniteElement<dim,spacedim> &fe5, const unsigned int n5);
/**
- * Same as above but for any
- * number of base
- * elements. Pointers to the base
- * elements and their
- * multiplicities are passed as
- * vectors to this
- * constructor. The length of
- * these vectors is assumed to be
- * equal.
+ * Same as above but for any number of base elements. Pointers to the base
+ * elements and their multiplicities are passed as vectors to this
+ * constructor. The length of these vectors is assumed to be equal.
*/
FESystem (const std::vector<const FiniteElement<dim,spacedim>*> &fes,
virtual ~FESystem ();
/**
- * Return a string that uniquely
- * identifies a finite
- * element. This element returns
- * a string that is composed of
- * the strings
- * @p name1...@p nameN returned
- * by the basis elements. From
- * these, we create a sequence
- * <tt>FESystem<dim>[name1^m1-name2^m2-...-nameN^mN]</tt>,
- * where @p mi are the
- * multiplicities of the basis
- * elements. If a multiplicity is
- * equal to one, then the
- * superscript is omitted.
+ * Return a string that uniquely identifies a finite element. This element
+ * returns a string that is composed of the strings @p name1...@p nameN
+ * returned by the basis elements. From these, we create a sequence
+ * <tt>FESystem<dim>[name1^m1-name2^m2-...-nameN^mN]</tt>, where @p mi are
+ * the multiplicities of the basis elements. If a multiplicity is equal to
+ * one, then the superscript is omitted.
*/
virtual std::string get_name () const;
/**
- * Return the value of the
- * @p ith shape function at the
- * point @p p. @p p is a point
- * on the reference element. Since
- * this finite element is always
- * vector-valued, we return the
- * value of the only non-zero
- * component of the vector value
- * of this shape function. If the
- * shape function has more than
- * one non-zero component (which
- * we refer to with the term
- * non-primitive), then throw an
- * exception of type
- * @p ExcShapeFunctionNotPrimitive.
+ * Return the value of the @p ith shape function at the point @p p. @p p is
+ * a point on the reference element. Since this finite element is always
+ * vector-valued, we return the value of the only non-zero component of the
+ * vector value of this shape function. If the shape function has more than
+ * one non-zero component (which we refer to with the term non-primitive),
+ * then throw an exception of type @p ExcShapeFunctionNotPrimitive.
*
- * An
- * @p ExcUnitShapeValuesDoNotExist
- * is thrown if the shape values
- * of the @p FiniteElement
- * (corresponding to the @p ith
- * shape function) depend on the
- * shape of the cell in real
- * space.
+ * An @p ExcUnitShapeValuesDoNotExist is thrown if the shape values of the
+ * @p FiniteElement (corresponding to the @p ith shape function) depend on
+ * the shape of the cell in real space.
*/
virtual double shape_value (const unsigned int i,
const Point<dim> &p) const;
/**
- * Return the value of the
- * @p componentth vector
- * component of the @p ith shape
- * function at the point
- * @p p. See the
- * FiniteElement base
- * class for more information
- * about the semantics of this
- * function.
+ * Return the value of the @p componentth vector component of the @p ith
+ * shape function at the point @p p. See the FiniteElement base class for
+ * more information about the semantics of this function.
*
- * Since this element is vector
- * valued in general, it relays
- * the computation of these
- * values to the base elements.
+ * Since this element is vector valued in general, it relays the computation
+ * of these values to the base elements.
*/
virtual double shape_value_component (const unsigned int i,
const Point<dim> &p,
const unsigned int component) const;
/**
- * Return the gradient of the
- * @p ith shape function at the
- * point @p p. @p p is a point
- * on the reference element, and
- * likewise the gradient is the
- * gradient on the unit cell with
- * respect to unit cell
- * coordinates. Since
- * this finite element is always
- * vector-valued, we return the
- * value of the only non-zero
- * component of the vector value
- * of this shape function. If the
- * shape function has more than
- * one non-zero component (which
- * we refer to with the term
- * non-primitive), then throw an
- * exception of type
- * @p ExcShapeFunctionNotPrimitive.
+ * Return the gradient of the @p ith shape function at the point @p p. @p p
+ * is a point on the reference element, and likewise the gradient is the
+ * gradient on the unit cell with respect to unit cell coordinates. Since
+ * this finite element is always vector-valued, we return the value of the
+ * only non-zero component of the vector value of this shape function. If
+ * the shape function has more than one non-zero component (which we refer
+ * to with the term non-primitive), then throw an exception of type @p
+ * ExcShapeFunctionNotPrimitive.
*
- * An
- * @p ExcUnitShapeValuesDoNotExist
- * is thrown if the shape values
- * of the @p FiniteElement
- * (corresponding to the @p ith
- * shape function) depend on the
- * shape of the cell in real
- * space.
+ * An @p ExcUnitShapeValuesDoNotExist is thrown if the shape values of the
+ * @p FiniteElement (corresponding to the @p ith shape function) depend on
+ * the shape of the cell in real space.
*/
virtual Tensor<1,dim> shape_grad (const unsigned int i,
const Point<dim> &p) const;
/**
- * Return the gradient of the
- * @p componentth vector
- * component of the @p ith shape
- * function at the point
- * @p p. See the
- * FiniteElement base
- * class for more information
- * about the semantics of this
- * function.
+ * Return the gradient of the @p componentth vector component of the @p ith
+ * shape function at the point @p p. See the FiniteElement base class for
+ * more information about the semantics of this function.
*
- * Since this element is vector
- * valued in general, it relays
- * the computation of these
- * values to the base elements.
+ * Since this element is vector valued in general, it relays the computation
+ * of these values to the base elements.
*/
virtual Tensor<1,dim> shape_grad_component (const unsigned int i,
const Point<dim> &p,
const unsigned int component) const;
/**
- * Return the tensor of second
- * derivatives of the @p ith
- * shape function at point @p p
- * on the unit cell. The
- * derivatives are derivatives on
- * the unit cell with respect to
- * unit cell coordinates. Since
- * this finite element is always
- * vector-valued, we return the
- * value of the only non-zero
- * component of the vector value
- * of this shape function. If the
- * shape function has more than
- * one non-zero component (which
- * we refer to with the term
- * non-primitive), then throw an
- * exception of type
- * @p ExcShapeFunctionNotPrimitive.
+ * Return the tensor of second derivatives of the @p ith shape function at
+ * point @p p on the unit cell. The derivatives are derivatives on the unit
+ * cell with respect to unit cell coordinates. Since this finite element is
+ * always vector-valued, we return the value of the only non-zero component
+ * of the vector value of this shape function. If the shape function has
+ * more than one non-zero component (which we refer to with the term
+ * non-primitive), then throw an exception of type @p
+ * ExcShapeFunctionNotPrimitive.
*
- * An
- * @p ExcUnitShapeValuesDoNotExist
- * is thrown if the shape values
- * of the @p FiniteElement
- * (corresponding to the @p ith
- * shape function) depend on the
- * shape of the cell in real
- * space.
+ * An @p ExcUnitShapeValuesDoNotExist is thrown if the shape values of the
+ * @p FiniteElement (corresponding to the @p ith shape function) depend on
+ * the shape of the cell in real space.
*/
virtual Tensor<2,dim> shape_grad_grad (const unsigned int i,
const Point<dim> &p) const;
/**
- * Return the second derivatives
- * of the @p componentth vector
- * component of the @p ith shape
- * function at the point
- * @p p. See the
- * FiniteElement base
- * class for more information
- * about the semantics of this
- * function.
+ * Return the second derivatives of the @p componentth vector component of
+ * the @p ith shape function at the point @p p. See the FiniteElement base
+ * class for more information about the semantics of this function.
*
- * Since this element is vector
- * valued in general, it relays
- * the computation of these
- * values to the base elements.
+ * Since this element is vector valued in general, it relays the computation
+ * of these values to the base elements.
*/
virtual
Tensor<2,dim>
const unsigned int component) const;
/**
- * Return the matrix
- * interpolating from the given
- * finite element to the present
- * one. The size of the matrix is
- * then @p dofs_per_cell times
+ * Return the matrix interpolating from the given finite element to the
+ * present one. The size of the matrix is then @p dofs_per_cell times
* <tt>source.dofs_per_cell</tt>.
*
- * These matrices are available
- * if source and destination
- * element are both @p FESystem
- * elements, have the same number
- * of base elements with same
- * element multiplicity, and if
- * these base elements also
- * implement their
- * @p get_interpolation_matrix
- * functions. Otherwise, an
- * exception of type
- * FiniteElement<dim,spacedim>::ExcInterpolationNotImplemented
- * is thrown.
+ * These matrices are available if source and destination element are both
+ * @p FESystem elements, have the same number of base elements with same
+ * element multiplicity, and if these base elements also implement their @p
+ * get_interpolation_matrix functions. Otherwise, an exception of type
+ * FiniteElement<dim,spacedim>::ExcInterpolationNotImplemented is thrown.
*/
virtual void
get_interpolation_matrix (const FiniteElement<dim,spacedim> &source,
FullMatrix<double> &matrix) const;
/**
- * Access to a composing
- * element. The index needs to be
- * smaller than the number of
- * base elements. Note that the
- * number of base elements may in
- * turn be smaller than the
- * number of components of the
- * system element, if the
- * multiplicities are greater
- * than one.
+ * Access to a composing element. The index needs to be smaller than the
+ * number of base elements. Note that the number of base elements may in
+ * turn be smaller than the number of components of the system element, if
+ * the multiplicities are greater than one.
*/
virtual const FiniteElement<dim,spacedim> &
base_element (const unsigned int index) const;
/**
- * Check for non-zero values on a
- * face.
+ * Check for non-zero values on a face.
*
- * This function returns
- * @p true, if the shape
- * function @p shape_index has
- * non-zero values on the face
- * @p face_index.
+ * This function returns @p true, if the shape function @p shape_index has
+ * non-zero values on the face @p face_index.
*
- * Implementation of the
- * interface in
- * FiniteElement
+ * Implementation of the interface in FiniteElement
*/
virtual bool has_support_on_face (const unsigned int shape_index,
const unsigned int face_index) const;
/**
- * Implementation of the
- * respective function in the
- * base class.
+ * Projection from a fine grid space onto a coarse grid space. Overrides the
+ * respective method in FiniteElement, implementing lazy evaluation
+ * (initialize when requested).
+ *
+ * If this projection operator is associated with a matrix @p P, then the
+ * restriction of this matrix @p P_i to a single child cell is returned
+ * here.
+ *
+ * The matrix @p P is the concatenation or the sum of the cell matrices @p
+ * P_i, depending on the #restriction_is_additive_flags. This distinguishes
+ * interpolation (concatenation) and projection with respect to scalar
+ * products (summation).
+ *
+ * Row and column indices are related to coarse grid and fine grid spaces,
+ * respectively, consistent with the definition of the associated operator.
+ *
+ * If projection matrices are not implemented in the derived finite element
+ * class, this function aborts with ExcProjectionVoid. You can check whether
+ * this is the case by calling the restriction_is_implemented() or the
+ * isotropic_restriction_is_implemented() function.
+ */
+ virtual const FullMatrix<double> &
+ get_restriction_matrix (const unsigned int child,
+ const RefinementCase<dim> &refinement_case=RefinementCase<dim>::isotropic_refinement) const;
+
+ /**
+ * Embedding matrix between grids. Overrides the respective method in
+ * FiniteElement, implementing lazy evaluation (initialize when queried).
+ *
+ * The identity operator from a coarse grid space into a fine grid space is
+ * associated with a matrix @p P. The restriction of this matrix @p P_i to a
+ * single child cell is returned here.
+ *
+ * The matrix @p P is the concatenation, not the sum of the cell matrices @p
+ * P_i. That is, if the same non-zero entry <tt>j,k</tt> exists in in two
+ * different child matrices @p P_i, the value should be the same in both
+ * matrices and it is copied into the matrix @p P only once.
+ *
+ * Row and column indices are related to fine grid and coarse grid spaces,
+ * respectively, consistent with the definition of the associated operator.
+ *
+ * These matrices are used by routines assembling the prolongation matrix
+ * for multi-level methods. Upon assembling the transfer matrix between
+ * cells using this matrix array, zero elements in the prolongation matrix
+ * are discarded and will not fill up the transfer matrix.
+ *
+ * If projection matrices are not implemented in the derived finite element
+ * class, this function aborts with ExcEmbeddingVoid. You can check whether
+ * this is the case by calling the prolongation_is_implemented() or the
+ * isotropic_prolongation_is_implemented() function.
+ */
+ virtual const FullMatrix<double> &
+ get_prolongation_matrix (const unsigned int child,
+ const RefinementCase<dim> &refinement_case=RefinementCase<dim>::isotropic_refinement) const;
+
+ /**
+ * Implementation of the respective function in the base class.
*/
virtual
Point<dim>
unit_support_point (const unsigned int index) const;
/**
- * Implementation of the
- * respective function in the
- * base class.
+ * Implementation of the respective function in the base class.
*/
virtual
Point<dim-1>
*/
/**
- * Return whether this element
- * implements its hanging node
- * constraints in the new way,
- * which has to be used to make
- * elements "hp compatible".
+ * Return whether this element implements its hanging node constraints in
+ * the new way, which has to be used to make elements "hp compatible".
*
- * This function returns @p true iff all
- * its base elements return @p true for
- * this function.
+ * This function returns @p true iff all its base elements return @p true
+ * for this function.
*/
virtual bool hp_constraints_are_implemented () const;
/**
- * Return the matrix
- * interpolating from a face of
- * of one element to the face of
- * the neighboring element.
- * The size of the matrix is
- * then <tt>source.dofs_per_face</tt> times
- * <tt>this->dofs_per_face</tt>.
+ * Return the matrix interpolating from a face of of one element to the face
+ * of the neighboring element. The size of the matrix is then
+ * <tt>source.dofs_per_face</tt> times <tt>this->dofs_per_face</tt>.
*
- * Base elements of this element will
- * have to implement this function. They
- * may only provide interpolation
- * matrices for certain source finite
- * elements, for example those from the
- * same family. If they don't implement
- * interpolation from a given element,
- * then they must throw an exception of
- * type
- * FiniteElement<dim,spacedim>::ExcInterpolationNotImplemented,
- * which will get propagated out from
- * this element.
+ * Base elements of this element will have to implement this function. They
+ * may only provide interpolation matrices for certain source finite
+ * elements, for example those from the same family. If they don't implement
+ * interpolation from a given element, then they must throw an exception of
+ * type FiniteElement<dim,spacedim>::ExcInterpolationNotImplemented, which
+ * will get propagated out from this element.
*/
virtual void
get_face_interpolation_matrix (const FiniteElement<dim,spacedim> &source,
/**
- * Return the matrix
- * interpolating from a face of
- * of one element to the subface of
- * the neighboring element.
- * The size of the matrix is
- * then <tt>source.dofs_per_face</tt> times
- * <tt>this->dofs_per_face</tt>.
+ * Return the matrix interpolating from a face of of one element to the
+ * subface of the neighboring element. The size of the matrix is then
+ * <tt>source.dofs_per_face</tt> times <tt>this->dofs_per_face</tt>.
*
- * Base elements of this element will
- * have to implement this function. They
- * may only provide interpolation
- * matrices for certain source finite
- * elements, for example those from the
- * same family. If they don't implement
- * interpolation from a given element,
- * then they must throw an exception of
- * type
- * FiniteElement<dim,spacedim>::ExcInterpolationNotImplemented,
- * which will get propagated out from
- * this element.
+ * Base elements of this element will have to implement this function. They
+ * may only provide interpolation matrices for certain source finite
+ * elements, for example those from the same family. If they don't implement
+ * interpolation from a given element, then they must throw an exception of
+ * type FiniteElement<dim,spacedim>::ExcInterpolationNotImplemented, which
+ * will get propagated out from this element.
*/
virtual void
get_subface_interpolation_matrix (const FiniteElement<dim,spacedim> &source,
hp_quad_dof_identities (const FiniteElement<dim,spacedim> &fe_other) const;
/**
- * Return whether this element dominates
- * the one given as argument when they
- * meet at a common face,
- * whether it is the other way around,
- * whether neither dominates, or if
- * either could dominate.
+ * Return whether this element dominates the one given as argument when they
+ * meet at a common face, whether it is the other way around, whether
+ * neither dominates, or if either could dominate.
*
- * For a definition of domination, see
- * FiniteElementBase::Domination and in
+ * For a definition of domination, see FiniteElementBase::Domination and in
* particular the @ref hp_paper "hp paper".
*/
virtual
//@}
/**
- * Determine an estimate for the
- * memory consumption (in bytes)
- * of this object.
+ * Determine an estimate for the memory consumption (in bytes) of this
+ * object.
*
- * This function is made virtual,
- * since finite element objects
- * are usually accessed through
- * pointers to their base class,
- * rather than the class itself.
+ * This function is made virtual, since finite element objects are usually
+ * accessed through pointers to their base class, rather than the class
+ * itself.
*/
virtual std::size_t memory_consumption () const;
protected:
/**
- * Compute flags for initial
- * update only.
+ * Compute flags for initial update only.
*/
virtual UpdateFlags update_once (const UpdateFlags flags) const;
/**
- * Compute flags for update on
- * each cell.
+ * Compute flags for update on each cell.
*/
virtual UpdateFlags update_each (const UpdateFlags flags) const;
/**
- * @p clone function instead of
- * a copy constructor.
+ * @p clone function instead of a copy constructor.
*
- * This function is needed by the
- * constructors of @p FESystem.
+ * This function is needed by the constructors of @p FESystem.
*/
virtual FiniteElement<dim,spacedim> *clone() const;
const Quadrature<dim-1> &quadrature) const ;
/**
- * Implementation of the same
- * function in
- * FiniteElement.
+ * Implementation of the same function in FiniteElement.
*
- * Passes on control to
- * @p compute_fill that does the
- * work for all three
- * <tt>fill_fe*_values</tt>
- * functions.
+ * Passes on control to @p compute_fill that does the work for all three
+ * <tt>fill_fe*_values</tt> functions.
*/
virtual void
fill_fe_values (const Mapping<dim,spacedim> &mapping,
CellSimilarity::Similarity &cell_similarity) const;
/**
- * Implementation of the same
- * function in
- * FiniteElement.
+ * Implementation of the same function in FiniteElement.
*
- * Passes on control to
- * @p compute_fill that does the
- * work for all three
+ * Passes on control to @p compute_fill that does the work for all three
* <tt>fill_fe*_values</tt> functions.
*/
virtual void
FEValuesData<dim,spacedim> &data) const ;
/**
- * Implementation of the same
- * function in
- * FiniteElement.
+ * Implementation of the same function in FiniteElement.
*
- * Passes on control to
- * @p compute_fill that does the
- * work for all three
+ * Passes on control to @p compute_fill that does the work for all three
* <tt>fill_fe*_values</tt> functions.
*/
virtual void
/**
- * Do the work for the three
- * <tt>fill_fe*_values</tt> functions.
+ * Do the work for the three <tt>fill_fe*_values</tt> functions.
*
- * Calls (among other things)
- * <tt>fill_fe_([sub]face)_values</tt>
- * of the base elements. Calls
- * @p fill_fe_values if
- * <tt>face_no==invalid_face_no</tt>
- * and
- * <tt>sub_no==invalid_face_no</tt>;
- * calls @p fill_fe_face_values
- * if
- * <tt>face_no==invalid_face_no</tt>
- * and
- * <tt>sub_no!=invalid_face_no</tt>;
- * and calls
- * @p fill_fe_subface_values if
- * <tt>face_no!=invalid_face_no</tt>
- * and
- * <tt>sub_no!=invalid_face_no</tt>.
+ * Calls (among other things) <tt>fill_fe_([sub]face)_values</tt> of the
+ * base elements. Calls @p fill_fe_values if
+ * <tt>face_no==invalid_face_no</tt> and <tt>sub_no==invalid_face_no</tt>;
+ * calls @p fill_fe_face_values if <tt>face_no==invalid_face_no</tt> and
+ * <tt>sub_no!=invalid_face_no</tt>; and calls @p fill_fe_subface_values if
+ * <tt>face_no!=invalid_face_no</tt> and <tt>sub_no!=invalid_face_no</tt>.
*/
template <int dim_1>
void compute_fill (const Mapping<dim,spacedim> &mapping,
private:
/**
- * Value to indicate that a given
- * face or subface number is
- * invalid.
+ * Value to indicate that a given face or subface number is invalid.
*/
static const unsigned int invalid_face_number = numbers::invalid_unsigned_int;
/**
- * Initialize the
- * @p unit_support_points field
- * of the FiniteElement
- * class. Called from the
- * constructor.
+ * Initialize the @p unit_support_points field of the FiniteElement
+ * class. Called from the constructor.
*/
void initialize_unit_support_points ();
/**
- * Initialize the
- * @p unit_face_support_points field
- * of the FiniteElement
- * class. Called from the
- * constructor.
+ * Initialize the @p unit_face_support_points field of the FiniteElement
+ * class. Called from the constructor.
*/
void initialize_unit_face_support_points ();
/**
- * Initialize the
- * @p adjust_quad_dof_index_for_face_orientation_table field
- * of the FiniteElement
- * class. Called from the
- * constructor.
+ * Initialize the @p adjust_quad_dof_index_for_face_orientation_table field
+ * of the FiniteElement class. Called from the constructor.
*/
void initialize_quad_dof_index_permutation ();
/**
- * Helper function used in the constructor:
- * take a @p FiniteElementData object
- * and return an object of the same type
- * with the number of degrees of
- * freedom per vertex, line, etc.
- * multiplied by @p n. Don't touch the
- * number of functions for the
- * transformation from unit to real
- * cell.
+ * Helper function used in the constructor: take a @p FiniteElementData
+ * object and return an object of the same type with the number of degrees
+ * of freedom per vertex, line, etc. multiplied by @p n. Don't touch the
+ * number of functions for the transformation from unit to real cell.
*/
static FiniteElementData<dim>
multiply_dof_numbers (const FiniteElement<dim,spacedim> *fe1,
const unsigned int N5=0);
/**
- * Same as above but for
- * any number of sub-elements.
+ * Same as above but for any number of sub-elements.
*/
static FiniteElementData<dim>
multiply_dof_numbers (const std::vector<const FiniteElement<dim,spacedim>*> &fes,
/**
- * Helper function used in the
- * constructor: takes a
- * @p FiniteElement object and
- * returns an boolean vector
- * including the
- * @p restriction_is_additive_flags
- * of the mixed element
- * consisting of @p N elements
- * of the sub-element @p fe.
+ * Helper function used in the constructor: takes a @p FiniteElement object
+ * and returns an boolean vector including the @p
+ * restriction_is_additive_flags of the mixed element consisting of @p N
+ * elements of the sub-element @p fe.
*/
static std::vector<bool>
compute_restriction_is_additive_flags (
const unsigned int N5=0);
/**
- * Compute the named flags for a
- * list of finite elements with
- * multiplicities given in the
- * second argument. This function
- * is called from all the above
+ * Compute the named flags for a list of finite elements with multiplicities
+ * given in the second argument. This function is called from all the above
* functions.
*/
static std::vector<bool>
/**
- * Compute the non-zero vector
- * components of a composed
- * finite element.
+ * Compute the non-zero vector components of a composed finite element.
*/
static std::vector<ComponentMask>
compute_nonzero_components (const FiniteElement<dim,spacedim> *fe1,
const unsigned int N5=0);
/**
- * Compute the nonzero components
- * of a list of finite elements
- * with multiplicities given in
- * the second argument. This
- * function is called from all
- * the above functions.
+ * Compute the nonzero components of a list of finite elements with
+ * multiplicities given in the second argument. This function is called from
+ * all the above functions.
*/
static std::vector<ComponentMask>
compute_nonzero_components (const std::vector<const FiniteElement<dim,spacedim>*> &fes,
const std::vector<unsigned int> &multiplicities);
/**
- * This function is simply
- * singled out of the
- * constructors since there are
- * several of them. It sets up
- * the index table for the system
- * as well as @p restriction and
- * @p prolongation
- * matrices.
+ * This function is simply singled out of the constructors since there are
+ * several of them. It sets up the index table for the system as well as @p
+ * restriction and @p prolongation matrices.
*/
void initialize (const std::vector<const FiniteElement<dim,spacedim>*> &fes,
const std::vector<unsigned int> &multiplicities);
void build_interface_constraints ();
/**
- * A function that computes the
- * hp_vertex_dof_identities(),
- * hp_line_dof_identities(), or
- * hp_quad_dof_identities(), depending on
- * the value of the template parameter.
+ * A function that computes the hp_vertex_dof_identities(),
+ * hp_line_dof_identities(), or hp_quad_dof_identities(), depending on the
+ * value of the template parameter.
*/
template <int structdim>
std::vector<std::pair<unsigned int, unsigned int> >
hp_object_dof_identities (const FiniteElement<dim,spacedim> &fe_other) const;
/**
- * Usually: Fields of
- * cell-independent data.
+ * Usually: Fields of cell-independent data.
*
- * However, here, this class does
- * not itself store the data but
- * only pointers to
- * @p InternalData objects for
- * each of the base elements.
+ * However, here, this class does not itself store the data but only
+ * pointers to @p InternalData objects for each of the base elements.
*/
class InternalData : public FiniteElement<dim,spacedim>::InternalDataBase
{
public:
/**
- * Constructor. Is called by
- * the @p get_data
- * function. Sets the size of
- * the @p base_fe_datas
- * vector to
- * @p n_base_elements.
+ * Constructor. Is called by the @p get_data function. Sets the size of
+ * the @p base_fe_datas vector to @p n_base_elements.
*/
InternalData (const unsigned int n_base_elements);
/**
- * Destructor. Deletes all
- * @p InternalDatas whose
- * pointers are stored by the
- * @p base_fe_datas
- * vector.
+ * Destructor. Deletes all @p InternalDatas whose pointers are stored by
+ * the @p base_fe_datas vector.
*/
~InternalData();
/**
- * Flag indicating whether
- * second derivatives shall
- * be computed.
+ * Flag indicating whether second derivatives shall be computed.
*/
bool compute_hessians;
/**
- * Gives write-access to the
- * pointer to a
- * @p InternalData of the
- * @p base_noth base
- * element.
+ * Gives write-access to the pointer to a @p InternalData of the @p
+ * base_noth base element.
*/
void set_fe_data(const unsigned int base_no,
typename FiniteElement<dim,spacedim>::InternalDataBase *);
/**
- * Gives read-access to the
- * pointer to a
- * @p InternalData of the
- * @p base_noth base element.
+ * Gives read-access to the pointer to a @p InternalData of the @p
+ * base_noth base element.
*/
typename FiniteElement<dim,spacedim>::InternalDataBase &
get_fe_data (const unsigned int base_no) const;
/**
- * Gives write-access to the
- * pointer to a
- * @p FEValuesData for the
- * @p base_noth base
- * element.
+ * Gives write-access to the pointer to a @p FEValuesData for the @p
+ * base_noth base element.
*/
void set_fe_values_data (const unsigned int base_no,
FEValuesData<dim,spacedim> *);
/**
- * Gives read-access to the
- * pointer to a
- * @p FEValuesData for the
- * @p base_noth base element.
+ * Gives read-access to the pointer to a @p FEValuesData for the @p
+ * base_noth base element.
*/
FEValuesData<dim,spacedim> &get_fe_values_data (const unsigned int base_no) const;
/**
- * Deletes the
- * @p FEValuesData the
- * <tt>fe_datas[base_no]</tt>
- * pointer is pointing
- * to. Sets
- * <tt>fe_datas[base_no]</tt> to
- * zero.
+ * Deletes the @p FEValuesData the <tt>fe_datas[base_no]</tt> pointer is
+ * pointing to. Sets <tt>fe_datas[base_no]</tt> to zero.
*
- * This function is used to
- * delete @p FEValuesData
- * that are needed only on
- * the first cell but not any
- * more afterwards. This is
- * the case for
- * e.g. Lagrangian elements
- * (see e.g. @p FE_Q
- * classes).
+ * This function is used to delete @p FEValuesData that are needed only on
+ * the first cell but not any more afterwards. This is the case for
+ * e.g. Lagrangian elements (see e.g. @p FE_Q classes).
*/
void delete_fe_values_data (const unsigned int base_no);
/**
- * Set the @p first_cell
- * flag to @p false. Used by
- * the @p FEValues class to
- * indicate that we have
- * already done the work on
- * the first cell.
+ * Set the @p first_cell flag to @p false. Used by the @p FEValues class
+ * to indicate that we have already done the work on the first cell.
*
- * In addition to calling the
- * respective function of the
- * base class, this function
- * also calls the functions
- * of the sub-data objects.
+ * In addition to calling the respective function of the base class, this
+ * function also calls the functions of the sub-data objects.
*/
virtual void clear_first_cell ();
private:
/**
- * Pointers to
- * @p InternalData objects
- * for each of the base
- * elements. They are
- * accessed to by the
- * @p set_ and
- * @p get_fe_data functions.
+ * Pointers to @p InternalData objects for each of the base elements. They
+ * are accessed to by the @p set_ and @p get_fe_data functions.
*
- * The size of this vector is
- * set to @p n_base_elements
- * by the InternalData
- * constructor. It is filled
- * by the @p get_data
- * function. Note that since
- * the data for each instance
- * of a base class is
- * necessarily the same, we
- * only need as many of these
- * objects as there are base
- * elements, irrespective of
- * their multiplicity.
+ * The size of this vector is set to @p n_base_elements by the
+ * InternalData constructor. It is filled by the @p get_data
+ * function. Note that since the data for each instance of a base class is
+ * necessarily the same, we only need as many of these objects as there
+ * are base elements, irrespective of their multiplicity.
*/
typename std::vector<typename FiniteElement<dim,spacedim>::InternalDataBase *> base_fe_datas;
/**
- * Pointers to the
- * @p FEValuesData objects
- * that are given to the
- * @p fill_fe_values
- * function of the base
- * elements. They are
- * accessed to by the
- * @p set_ and
- * @p get_fe_values_data
- * functions.
+ * Pointers to the @p FEValuesData objects that are given to the @p
+ * fill_fe_values function of the base elements. They are accessed to by
+ * the @p set_ and @p get_fe_values_data functions.
*
- * The size of this vector is
- * set to @p n_base_elements
- * by the InternalData
- * constructor.
+ * The size of this vector is set to @p n_base_elements by the
+ * InternalData constructor.
*/
std::vector<FEValuesData<dim,spacedim> *> base_fe_values_datas;
};
+
+ /*
+ * Mutex for protecting initialization of restriction and embedding matrix.
+ */
+ mutable Threads::Mutex mutex;
};
#include <deal.II/base/symmetric_tensor.h>
#include <vector>
+#include <string>
+
DEAL_II_NAMESPACE_OPEN
}
template <int dim> class FiniteElementData;
class ConstraintMatrix;
-namespace PETScWrappers
-{
- namespace MPI
- {
- class Vector;
- }
-}
-#include <deal.II/base/config.h>
-#include <deal.II/base/exceptions.h>
-#include <vector>
-#include <string>
/*!@addtogroup feall */
/*@{*/
* course Q1 on each cell.
*
* For this case (continuous elements on grids with hanging nodes), please
- * use the @p interpolate function with an additional @p ConstraintMatrix
+ * use the @p interpolate() function with an additional ConstraintMatrix
* argument, see below, or make the field conforming yourself by calling the
* @p distribute function of your hanging node constraints object.
*/
* interpolation. The same is true if @p fe1 is a continuous and @p fe2 is a
* discontinuous finite element. For the case that @p fe1 is a discontinuous
* and @p fe2 is a continuous finite element there is no point interpolation
- * defined at the discontinuities. Therefore the meanvalue is taken at the
- * DoF values on the discontinuities.
+ * defined at the discontinuities. Therefore the mean value is taken at the
+ * DoF values at the discontinuities.
*/
template <int dim, int spacedim,
template <int, int> class DH1,
DEAL_II_NAMESPACE_OPEN
-template <int dim> class TensorProductPolynomials;
+template <int dim, typename POLY> class TensorProductPolynomials;
/*!@addtogroup mapping */
* This class implements an input mechanism for grid data. It allows to read a
* grid structure into a triangulation object. At present, UCD (unstructured
* cell data), DB Mesh, XDA, Gmsh, Tecplot, NetCDF, UNV, and Cubit are supported as
- * input format for grid data. Any numerical data after the block of geometric
+ * input format for grid data. Any numerical data other than geometric
* (vertex locations) and topological (how vertices form cells) information is
- * ignored. Notice also that at the moment in the codimension 1 case only UCD
- * and Gmsh format are accepted.
+ * ignored.
*
- * Since the coarse mesh fed into a @p Triangulation object cannot have
- * hanging nodes, strange things will happen if the input file has them. This
+ * @note Since deal.II only supports line, quadrilateral and hexahedral meshes,
+ * the functions in this class can only read meshes that consist exclusively
+ * of such cells. If you absolutely need to work with a mesh that uses triangles
+ * or tetrahedra, then your only option is to convert the mesh to quadrilaterals
+ * and hexahedra. A tool that can do this is tethex, see
+ * http://code.google.com/p/tethex/wiki/Tethex .
+ *
+ * The mesh you read will form the coarsest level of a @p Triangulation object.
+ * As such, it must not contain hanging nodes or other forms or adaptive
+ * refinement and strange things will happen if the mesh represented by the
+ * input file does in fact have them. This
* is due to the fact that most mesh description formats do not store
* neighborship information between cells, so the grid reading functions have
* to regenerate it. They do so by checking whether two cells have a common
* common (complete) face, so the grid reader concludes that the adjacent
* cells have no neighbors along these faces and must therefore be at the
* boundary. In effect, an internal crack of the domain is introduced this
- * way. Since such cases are very hard to detect, the library does not make
- * any attempt to abort on such situations, and you will get a triangulation
- * that probably does not do what you want. A solution to this problem is the
+ * way. Since such cases are very hard to detect (how is GridIn supposed to
+ * decide whether a place where the faces of two small cells coincide with
+ * the face or a larger cell is in fact a hanging node associated with local
+ * refinement, or is indeed meant to be a crack in the domain?), the library
+ * does not make any attempt to catch such situations, and you will get a triangulation
+ * that probably does not do what you want. If your goal is to save and later
+ * read again a triangulation that has been adaptively refined, then this
+ * class is not your solution; rather take a look at the
* PersistentTriangulation class.
*
- * Note: if you experience unexpected problems with the use of this
- * class, be sure to read the documentation right until the end, and
+ * @note It is not uncommon to experience unexpected problems when reading
+ * generated meshes for the first time using this class. If this applies to
+ * you, be sure to read the documentation right until the end, and
* also read the documentation of the GridReordering class.
*
* To read grid data, the triangulation to be fed with has to be empty.
Background background;
// View angles for the perspective view of the grid; Default is 0, 0 (top view).
- int azimuth_angle, polar_angle;
+ /**
+ * The azimuth angle measured from ??? in degrees. Default is 0.
+ */
+ int azimuth_angle;
+ /**
+ * The angle from vertically above the xy-plane. Default is 0.
+ */
+ int polar_angle;
/**
* Cell coloring.
/// Convert the level number into the cell color
level_number,
/// Convert the subdomain id into the cell color
- subdomain_id};
+ subdomain_id,
+ /// Convert the level subdomain id into the cell color
+ level_subdomain_id};
Coloring coloring;
- // Interpret the level number of the cells as altitude over the x-y-plane (may be useful in the perpspective view).
+ /// Interpret the level number of the cells as altitude over the x-y-plane (useful in the perpspective view).
bool convert_level_number_to_height;
/**
* The following booleans determine which properties of the cell
* shall be displayed as text in the middle of each cell.
*/
- bool label_level_number; /// default: true
- bool label_cell_index; /// default: true
- bool label_material_id; /// default: false
- bool label_subdomain_id; /// default: false
- //bool label_level_subdomain_id; // TODO [CW]: not yet implemented ...
+ bool label_level_number; // default: true
+ bool label_cell_index; // default: true
+ bool label_material_id; // default: false
+ bool label_subdomain_id; // default: false
+ bool label_level_subdomain_id; // default: false
/// Draw a colorbar next to the plotted grid with respect to the chosen coloring of the cells
bool draw_colorbar;
/**
* Constructor.
*/
- Svg(const unsigned int line_thickness = 3,
- const unsigned int boundary_line_thickness = 7,
+ Svg(const unsigned int line_thickness = 2,
+ const unsigned int boundary_line_thickness = 4,
bool margin = true,
- const Background background = dealii,
+ const Background background = white,
const int azimuth_angle = 0,
const int polar_angle = 0,
- const Coloring coloring = material_id,
+ const Coloring coloring = level_number,
const bool convert_level_number_to_height = false,
const bool label_level_number = true,
const bool label_cell_index = true,
/**
- * This function projects a three-dimensional
- * point (Point<3> point) onto a two-dimensional
- * image plane, specified by the position of
- * the camera viewing system
- * (Point<3> camera_position),
- * camera direction
- * (Point<3> camera_position),
- * camera horizontal
- * (Point<3> camera_horizontal, necessary for
- * the correct alignment of the later images),
- * and the focus of the camera
- * (float camera_focus).
+ * This function projects a three-dimensional point (Point<3> point)
+ * onto a two-dimensional image plane, specified by the position of
+ * the camera viewing system (Point<3> camera_position), camera
+ * direction (Point<3> camera_position), camera horizontal (Point<3>
+ * camera_horizontal, necessary for the correct alignment of the
+ * later images), and the focus of the camera (float camera_focus).
*
* For SVG output of grids.
*/
- Point<2> svg_project_point(Point<3> point,
- Point<3> camera_position,
- Point<3> camera_direction,
- Point<3> camera_horizontal,
- float camera_focus) const;
+ static Point<2> svg_project_point(Point<3> point,
+ Point<3> camera_position,
+ Point<3> camera_direction,
+ Point<3> camera_horizontal,
+ float camera_focus);
/**
* Return the number of faces in the triangulation which have a
*
* See the @ref GlossSubdomainId
* "glossary" for more
- * information. This function
- * should not be called if you
- * use a
- * parallel::distributed::Triangulation
- * object.
+ * information.
*/
types::subdomain_id subdomain_id () const;
TriaAccessor<0, 1, spacedim>::vertex_index (const unsigned int i) const
{
Assert(i==0, ExcIndexRange(i, 0, 1));
+ (void)i;
return global_vertex_index;
}
TriaAccessor<0, 1, spacedim>::vertex (const unsigned int i) const
{
Assert(i==0, ExcIndexRange(i, 0, 1));
+ (void)i;
return const_cast<Point<spacedim> &> (this->tria->vertices[global_vertex_index]);
}
#define __deal2__arpack_solver_h
#include <deal.II/base/config.h>
+#include <deal.II/base/smartpointer.h>
+#include <deal.II/lac/solver_control.h>
#ifdef DEAL_II_WITH_ARPACK
}
else if (info == 3)
{
- Assert (false, ExcArpackNoShifts(1));;
+ Assert (false, ExcArpackNoShifts(1));
}
else if (info!=0)
{
ExcDimensionMismatch(src.n_blocks(), n_block_cols()));
for (unsigned int row=0; row<n_block_rows(); ++row)
- {
- block(row,0).vmult_add (dst.block(row),
- src.block(0));
- for (unsigned int col=1; col<n_block_cols(); ++col)
- block(row,col).vmult_add (dst.block(row),
- src.block(col));
- };
+ for (unsigned int col=0; col<n_block_cols(); ++col)
+ block(row,col).vmult_add (dst.block(row),
+ src.block(col));
}
ExcDimensionMismatch(src.n_blocks(), n_block_rows()));
for (unsigned int row=0; row<n_block_rows(); ++row)
- {
- for (unsigned int col=0; col<n_block_cols(); ++col)
- block(row,col).Tvmult_add (dst.block(col),
- src.block(row));
- };
+ for (unsigned int col=0; col<n_block_cols(); ++col)
+ block(row,col).Tvmult_add (dst.block(col),
+ src.block(row));
}
*/
typedef typename BlockType::real_type real_type;
+ /**
+ * A variable that indicates whether this vector
+ * supports distributed data storage. If true, then
+ * this vector also needs an appropriate compress()
+ * function that allows communicating recent set or
+ * add operations to individual elements to be communicated
+ * to other processors.
+ *
+ * For the current class, the variable equals the
+ * value declared for the type of the individual blocks.
+ */
+ static const bool supports_distributed_data = BlockType::supports_distributed_data;
+
/**
* Default constructor.
*/
*/
unsigned int size () const;
+ /**
+ * Return an index set that describes which elements of this vector
+ * are owned by the current processor. Note that this index set does
+ * not include elements this vector may store locally as ghost
+ * elements but that are in fact owned by another processor.
+ * As a consequence, the index sets returned on different
+ * processors if this is a distributed vector will form disjoint
+ * sets that add up to the complete index set.
+ * Obviously, if a vector is created on only one processor, then
+ * the result would satisfy
+ * @code
+ * vec.locally_owned_elements() == complete_index_set (vec.size())
+ * @endcode
+ *
+ * For block vectors, this function returns the union of the
+ * locally owned elements of the individual blocks, shifted by
+ * their respective index offsets.
+ */
+ IndexSet locally_owned_elements () const;
+
/**
* Return an iterator pointing to
* the first element.
+template <class VectorType>
+inline
+IndexSet
+BlockVectorBase<VectorType>::locally_owned_elements () const
+{
+ IndexSet is (size());
+
+ // copy index sets from blocks into the global one
+ for (unsigned int b=0; b<n_blocks(); ++b)
+ {
+ IndexSet x = block(b).locally_owned_elements();
+
+ //TODO: This can surely be made more efficient by just shifting
+ // x
+ for (unsigned int i=0; i<block(b).size(); ++i)
+ if (x.is_element(i))
+ is.add_index(block_indices.local_to_global(b,i));
+ }
+
+ is.compress();
+
+ return is;
+}
+
+
+
template <class VectorType>
inline
unsigned int
*@{
*/
+/**
+ * A namespace in which we declare iterators over the elements of sparse
+ * matrices.
+ */
+namespace ChunkSparseMatrixIterators
+{
+ // forward declaration
+ template <typename number, bool Constness>
+ class Iterator;
+
+ /**
+ * General template for sparse matrix accessors. The first template argument
+ * denotes the underlying numeric type, the second the constness of the
+ * matrix.
+ *
+ * The general template is not implemented, only the specializations for the
+ * two possible values of the second template argument. Therefore, the
+ * interface listed here only serves as a template provided since doxygen
+ * does not link the specializations.
+ */
+ template <typename number, bool Constness>
+ class Accessor : public ChunkSparsityPatternIterators::Accessor
+ {
+ public:
+ /**
+ * Value of this matrix entry.
+ */
+ number value() const;
+
+ /**
+ * Value of this matrix entry.
+ */
+ number &value();
+
+ /**
+ * Return a reference to the matrix into which this accessor points. Note
+ * that in the present case, this is a constant reference.
+ */
+ const ChunkSparseMatrix<number> &get_matrix () const;
+ };
+
+
+
+ /**
+ * Accessor class for constant matrices, used in the const_iterators. This
+ * class builds on the accessor classes used for sparsity patterns to loop
+ * over all nonzero entries, and only adds the accessor functions to gain
+ * access to the actual value stored at a certain location.
+ */
+ template <typename number>
+ class Accessor<number,true> : public ChunkSparsityPatternIterators::Accessor
+ {
+ public:
+ /**
+ * Typedef for the type (including constness) of the matrix to be used
+ * here.
+ */
+ typedef const ChunkSparseMatrix<number> MatrixType;
+
+ /**
+ * Constructor.
+ */
+ Accessor (MatrixType *matrix,
+ const unsigned int row);
+
+ /**
+ * Constructor. Construct the end accessor for the given matrix.
+ */
+ Accessor (MatrixType *matrix);
+
+ /**
+ * Copy constructor to get from a non-const accessor to a const accessor.
+ */
+ Accessor (const ChunkSparseMatrixIterators::Accessor<number,false> &a);
+
+ /**
+ * Value of this matrix entry.
+ */
+ number value() const;
+
+ /**
+ * Return a reference to the matrix into which this accessor points. Note
+ * that in the present case, this is a constant reference.
+ */
+ MatrixType &get_matrix () const;
+
+ private:
+ /**
+ * Pointer to the matrix we use.
+ */
+ MatrixType *matrix;
+
+ /**
+ * Make the advance function of the base class available.
+ */
+ using ChunkSparsityPatternIterators::Accessor::advance;
+
+ /**
+ * Make iterator class a friend.
+ */
+ template <typename, bool>
+ friend class Iterator;
+ };
+
+
+ /**
+ * Accessor class for non-constant matrices, used in the iterators. This
+ * class builds on the accessor classes used for sparsity patterns to loop
+ * over all nonzero entries, and only adds the accessor functions to gain
+ * access to the actual value stored at a certain location.
+ */
+ template <typename number>
+ class Accessor<number,false> : public ChunkSparsityPatternIterators::Accessor
+ {
+ private:
+ /**
+ * Reference class. This is what the accessor class returns when you call
+ * the value() function. The reference acts just as if it were a reference
+ * to the actual value of a matrix entry, i.e. you can read and write it,
+ * you can add and multiply to it, etc, but since the matrix does not give
+ * away the address of this matrix entry, we have to go through functions
+ * to do all this.
+ *
+ * The constructor takes a pointer to an accessor object that describes
+ * which element of the matrix it points to. This creates an ambiguity
+ * when one writes code like iterator->value()=0 (instead of
+ * iterator->value()=0.0), since the right hand side is an integer that
+ * can both be converted to a <tt>number</tt> (i.e., most commonly a
+ * double) or to another object of type <tt>Reference</tt>. The compiler
+ * then complains about not knowing which conversion to take.
+ *
+ * For some reason, adding another overload operator=(int) doesn't seem to
+ * cure the problem. We avoid it, however, by adding a second, dummy
+ * argument to the Reference constructor, that is unused, but makes sure
+ * there is no second matching conversion sequence using a one-argument
+ * right hand side.
+ */
+ class Reference
+ {
+ public:
+ /**
+ * Constructor. For the second argument, see the general class
+ * documentation.
+ */
+ Reference (const Accessor *accessor,
+ const bool dummy);
+
+ /**
+ * Conversion operator to the data type of the matrix.
+ */
+ operator number () const;
+
+ /**
+ * Set the element of the matrix we presently point to to @p n.
+ */
+ const Reference &operator = (const number n) const;
+
+ /**
+ * Add @p n to the element of the matrix we presently point to.
+ */
+ const Reference &operator += (const number n) const;
+
+ /**
+ * Subtract @p n from the element of the matrix we presently point to.
+ */
+ const Reference &operator -= (const number n) const;
+
+ /**
+ * Multiply the element of the matrix we presently point to by @p n.
+ */
+ const Reference &operator *= (const number n) const;
+
+ /**
+ * Divide the element of the matrix we presently point to by @p n.
+ */
+ const Reference &operator /= (const number n) const;
+
+ private:
+ /**
+ * Pointer to the accessor that denotes which element we presently point
+ * to.
+ */
+ const Accessor *accessor;
+ };
+
+ public:
+ /**
+ * Typedef for the type (including constness) of the matrix to be used
+ * here.
+ */
+ typedef ChunkSparseMatrix<number> MatrixType;
+
+ /**
+ * Constructor.
+ */
+ Accessor (MatrixType *matrix,
+ const unsigned int row);
+
+ /**
+ * Constructor. Construct the end accessor for the given matrix.
+ */
+ Accessor (MatrixType *matrix);
+
+ /**
+ * Value of this matrix entry, returned as a read- and writable reference.
+ */
+ Reference value() const;
+
+ /**
+ * Return a reference to the matrix into which this accessor points. Note
+ * that in the present case, this is a non-constant reference.
+ */
+ MatrixType &get_matrix () const;
+
+ private:
+ /**
+ * Pointer to the matrix we use.
+ */
+ MatrixType *matrix;
+
+ /**
+ * Make the advance function of the base class available.
+ */
+ using ChunkSparsityPatternIterators::Accessor::advance;
+
+ /**
+ * Make iterator class a friend.
+ */
+ template <typename, bool>
+ friend class Iterator;
+
+ /**
+ * Make the inner reference class a friend if the compiler has a bug and
+ * requires this.
+ */
+ };
+
+
+
+ /**
+ * STL conforming iterator for constant and non-constant matrices.
+ *
+ * The first template argument denotes the underlying numeric type, the
+ * second the constness of the matrix.
+ *
+ * Since there is a specialization of this class for
+ * <tt>Constness=false</tt>, this class is for iterators to constant
+ * matrices.
+ */
+ template <typename number, bool Constness>
+ class Iterator
+ {
+ public:
+ /**
+ * Typedef for the matrix type (including constness) we are to operate on.
+ */
+ typedef
+ typename Accessor<number,Constness>::MatrixType
+ MatrixType;
+
+ /**
+ * A typedef for the type you get when you dereference an iterator
+ * of the current kind.
+ */
+ typedef
+ const Accessor<number,Constness> & value_type;
+
+ /**
+ * Constructor. Create an iterator into the matrix @p matrix for the given
+ * row and the index within it.
+ */
+ Iterator (MatrixType *matrix,
+ const unsigned int row);
+
+ /**
+ * Constructor. Create the end iterator for the given matrix.
+ */
+ Iterator (MatrixType *matrix);
+
+ /**
+ * Conversion constructor to get from a non-const iterator to a const
+ * iterator.
+ */
+ Iterator (const ChunkSparseMatrixIterators::Iterator<number,false> &i);
+
+ /**
+ * Prefix increment.
+ */
+ Iterator &operator++ ();
+
+ /**
+ * Postfix increment.
+ */
+ Iterator operator++ (int);
+
+ /**
+ * Dereferencing operator.
+ */
+ const Accessor<number,Constness> &operator* () const;
+
+ /**
+ * Dereferencing operator.
+ */
+ const Accessor<number,Constness> *operator-> () const;
+
+ /**
+ * Comparison. True, if both iterators point to the same matrix position.
+ */
+ bool operator == (const Iterator &) const;
+
+ /**
+ * Inverse of <tt>==</tt>.
+ */
+ bool operator != (const Iterator &) const;
+
+ /**
+ * Comparison operator. Result is true if either the first row number is
+ * smaller or if the row numbers are equal and the first index is smaller.
+ *
+ * This function is only valid if both iterators point into the same
+ * matrix.
+ */
+ bool operator < (const Iterator &) const;
+
+ /**
+ * Comparison operator. Works in the same way as above operator, just the
+ * other way round.
+ */
+ bool operator > (const Iterator &) const;
+
+ /**
+ * Return the distance between the current iterator and the argument.
+ * The distance is given by how many times one has to apply operator++
+ * to the current iterator to get the argument (for a positive return
+ * value), or operator-- (for a negative return value).
+ */
+ int operator - (const Iterator &p) const;
+
+ /**
+ * Return an iterator that is @p n ahead of the current one.
+ */
+ Iterator operator + (const unsigned int n) const;
+
+ private:
+ /**
+ * Store an object of the accessor class.
+ */
+ Accessor<number,Constness> accessor;
+ };
+
+}
+
+
/**
* Sparse matrix. This class implements the function to store values
typedef number value_type;
/**
- * Declare a type that has holds
- * real-valued numbers with the
- * same precision as the template
- * argument to this class. If the
- * template argument of this
- * class is a real data type,
- * then real_type equals the
- * template argument. If the
- * template argument is a
- * std::complex type then
- * real_type equals the type
- * underlying the complex
- * numbers.
+ * Declare a type that has holds real-valued numbers with the same precision
+ * as the template argument to this class. If the template argument of this
+ * class is a real data type, then real_type equals the template
+ * argument. If the template argument is a std::complex type then real_type
+ * equals the type underlying the complex numbers.
*
- * This typedef is used to
- * represent the return type of
- * norms.
+ * This typedef is used to represent the return type of norms.
*/
typedef typename numbers::NumberTraits<number>::real_type real_type;
/**
- * A structure that describes some of the
- * traits of this class in terms of its
- * run-time behavior. Some other classes
- * (such as the block matrix classes)
- * that take one or other of the matrix
- * classes as its template parameters can
- * tune their behavior based on the
- * variables in this class.
+ * Typedef of an STL conforming iterator class walking over all the nonzero
+ * entries of this matrix. This iterator cannot change the values of the
+ * matrix.
+ */
+ typedef
+ ChunkSparseMatrixIterators::Iterator<number,true>
+ const_iterator;
+
+ /**
+ * Typedef of an STL conforming iterator class walking over all the nonzero
+ * entries of this matrix. This iterator @em can change the values of the
+ * matrix, but of course can't change the sparsity pattern as this is fixed
+ * once a sparse matrix is attached to it.
+ */
+ typedef
+ ChunkSparseMatrixIterators::Iterator<number,false>
+ iterator;
+
+ /**
+ * A structure that describes some of the traits of this class in terms of
+ * its run-time behavior. Some other classes (such as the block matrix
+ * classes) that take one or other of the matrix classes as its template
+ * parameters can tune their behavior based on the variables in this class.
*/
struct Traits
{
/**
- * It is safe to elide additions of
- * zeros to individual elements of
- * this matrix.
+ * It is safe to elide additions of zeros to individual elements of this
+ * matrix.
*/
static const bool zero_addition_can_be_elided = true;
};
*/
//@{
/**
- * Constructor; initializes the matrix to
- * be empty, without any structure, i.e.
- * the matrix is not usable at all. This
- * constructor is therefore only useful
- * for matrices which are members of a
- * class. All other matrices should be
- * created at a point in the data flow
- * where all necessary information is
- * available.
+ * Constructor; initializes the matrix to be empty, without any structure,
+ * i.e. the matrix is not usable at all. This constructor is therefore only
+ * useful for matrices which are members of a class. All other matrices
+ * should be created at a point in the data flow where all necessary
+ * information is available.
*
- * You have to initialize
- * the matrix before usage with
- * reinit(const ChunkSparsityPattern&).
+ * You have to initialize the matrix before usage with reinit(const
+ * ChunkSparsityPattern&).
*/
ChunkSparseMatrix ();
/**
- * Copy constructor. This constructor is
- * only allowed to be called if the matrix
- * to be copied is empty. This is for the
- * same reason as for the
- * ChunkSparsityPattern, see there for the
- * details.
+ * Copy constructor. This constructor is only allowed to be called if the
+ * matrix to be copied is empty. This is for the same reason as for the
+ * ChunkSparsityPattern, see there for the details.
*
- * If you really want to copy a whole
- * matrix, you can do so by using the
+ * If you really want to copy a whole matrix, you can do so by using the
* copy_from() function.
*/
ChunkSparseMatrix (const ChunkSparseMatrix &);
/**
- * Constructor. Takes the given
- * matrix sparsity structure to
- * represent the sparsity pattern
- * of this matrix. You can change
- * the sparsity pattern later on
- * by calling the reinit(const
- * ChunkSparsityPattern&) function.
+ * Constructor. Takes the given matrix sparsity structure to represent the
+ * sparsity pattern of this matrix. You can change the sparsity pattern
+ * later on by calling the reinit(const ChunkSparsityPattern&) function.
*
- * You have to make sure that the
- * lifetime of the sparsity
- * structure is at least as long
- * as that of this matrix or as
- * long as reinit(const
- * ChunkSparsityPattern&) is not
- * called with a new sparsity
- * pattern.
+ * You have to make sure that the lifetime of the sparsity structure is at
+ * least as long as that of this matrix or as long as reinit(const
+ * ChunkSparsityPattern&) is not called with a new sparsity pattern.
*
- * The constructor is marked
- * explicit so as to disallow
- * that someone passes a sparsity
- * pattern in place of a sparse
- * matrix to some function, where
- * an empty matrix would be
- * generated then.
+ * The constructor is marked explicit so as to disallow that someone passes
+ * a sparsity pattern in place of a sparse matrix to some function, where an
+ * empty matrix would be generated then.
*/
explicit ChunkSparseMatrix (const ChunkSparsityPattern &sparsity);
/**
- * Copy constructor: initialize
- * the matrix with the identity
- * matrix. This constructor will
- * throw an exception if the
- * sizes of the sparsity pattern
- * and the identity matrix do not
- * coincide, or if the sparsity
- * pattern does not provide for
- * nonzero entries on the entire
- * diagonal.
+ * Copy constructor: initialize the matrix with the identity matrix. This
+ * constructor will throw an exception if the sizes of the sparsity pattern
+ * and the identity matrix do not coincide, or if the sparsity pattern does
+ * not provide for nonzero entries on the entire diagonal.
*/
ChunkSparseMatrix (const ChunkSparsityPattern &sparsity,
const IdentityMatrix &id);
/**
- * Destructor. Free all memory, but do not
- * release the memory of the sparsity
- * structure.
+ * Destructor. Free all memory, but do not release the memory of the
+ * sparsity structure.
*/
virtual ~ChunkSparseMatrix ();
/**
- * Copy operator. Since copying
- * entire sparse matrices is a
- * very expensive operation, we
- * disallow doing so except for
- * the special case of empty
- * matrices of size zero. This
- * doesn't seem particularly
- * useful, but is exactly what
- * one needs if one wanted to
- * have a
- * <code>std::vector@<ChunkSparseMatrix@<double@>
- * @></code>: in that case, one
- * can create a vector (which
- * needs the ability to copy
- * objects) of empty matrices
- * that are then later filled
- * with something useful.
+ * Copy operator. Since copying entire sparse matrices is a very expensive
+ * operation, we disallow doing so except for the special case of empty
+ * matrices of size zero. This doesn't seem particularly useful, but is
+ * exactly what one needs if one wanted to have a
+ * <code>std::vector@<ChunkSparseMatrix@<double@> @></code>: in that case,
+ * one can create a vector (which needs the ability to copy objects) of
+ * empty matrices that are then later filled with something useful.
*/
ChunkSparseMatrix<number> &operator = (const ChunkSparseMatrix<number> &);
/**
- * Copy operator: initialize
- * the matrix with the identity
- * matrix. This operator will
- * throw an exception if the
- * sizes of the sparsity pattern
- * and the identity matrix do not
- * coincide, or if the sparsity
- * pattern does not provide for
- * nonzero entries on the entire
- * diagonal.
+ * Copy operator: initialize the matrix with the identity matrix. This
+ * operator will throw an exception if the sizes of the sparsity pattern and
+ * the identity matrix do not coincide, or if the sparsity pattern does not
+ * provide for nonzero entries on the entire diagonal.
*/
ChunkSparseMatrix<number> &
operator= (const IdentityMatrix &id);
/**
- * This operator assigns a scalar to
- * a matrix. Since this does usually
- * not make much sense (should we set
- * all matrix entries to this value?
- * Only the nonzero entries of the
- * sparsity pattern?), this operation
- * is only allowed if the actual
- * value to be assigned is zero. This
- * operator only exists to allow for
- * the obvious notation
- * <tt>matrix=0</tt>, which sets all
- * elements of the matrix to zero,
- * but keep the sparsity pattern
+ * This operator assigns a scalar to a matrix. Since this does usually not
+ * make much sense (should we set all matrix entries to this value? Only
+ * the nonzero entries of the sparsity pattern?), this operation is only
+ * allowed if the actual value to be assigned is zero. This operator only
+ * exists to allow for the obvious notation <tt>matrix=0</tt>, which sets
+ * all elements of the matrix to zero, but keep the sparsity pattern
* previously used.
*/
ChunkSparseMatrix &operator = (const double d);
/**
- * Reinitialize the sparse matrix
- * with the given sparsity
- * pattern. The latter tells the
- * matrix how many nonzero
- * elements there need to be
+ * Reinitialize the sparse matrix with the given sparsity pattern. The
+ * latter tells the matrix how many nonzero elements there need to be
* reserved.
*
- * Regarding memory allocation,
- * the same applies as said
- * above.
+ * Regarding memory allocation, the same applies as said above.
*
- * You have to make sure that the
- * lifetime of the sparsity
- * structure is at least as long
- * as that of this matrix or as
- * long as reinit(const
- * ChunkSparsityPattern &) is not
- * called with a new sparsity
- * structure.
+ * You have to make sure that the lifetime of the sparsity structure is at
+ * least as long as that of this matrix or as long as reinit(const
+ * ChunkSparsityPattern &) is not called with a new sparsity structure.
*
- * The elements of the matrix are
- * set to zero by this function.
+ * The elements of the matrix are set to zero by this function.
*/
virtual void reinit (const ChunkSparsityPattern &sparsity);
/**
- * Release all memory and return
- * to a state just like after
- * having called the default
- * constructor. It also forgets
- * the sparsity pattern it was
+ * Release all memory and return to a state just like after having called
+ * the default constructor. It also forgets the sparsity pattern it was
* previously tied to.
*/
virtual void clear ();
*/
//@{
/**
- * Return whether the object is
- * empty. It is empty if either
- * both dimensions are zero or no
- * ChunkSparsityPattern is
- * associated.
+ * Return whether the object is empty. It is empty if either both dimensions
+ * are zero or no ChunkSparsityPattern is associated.
*/
bool empty () const;
/**
- * Return the dimension of the
- * image space. To remember: the
- * matrix is of dimension
- * $m \times n$.
+ * Return the dimension of the image space. To remember: the matrix is of
+ * dimension $m \times n$.
*/
unsigned int m () const;
/**
- * Return the dimension of the
- * range space. To remember: the
- * matrix is of dimension
- * $m \times n$.
+ * Return the dimension of the range space. To remember: the matrix is of
+ * dimension $m \times n$.
*/
unsigned int n () const;
/**
- * Return the number of nonzero
- * elements of this
- * matrix. Actually, it returns
- * the number of entries in the
- * sparsity pattern; if any of
- * the entries should happen to
- * be zero, it is counted anyway.
+ * Return the number of nonzero elements of this matrix. Actually, it
+ * returns the number of entries in the sparsity pattern; if any of the
+ * entries should happen to be zero, it is counted anyway.
*/
unsigned int n_nonzero_elements () const;
/**
- * Return the number of actually
- * nonzero elements of this
- * matrix.
+ * Return the number of actually nonzero elements of this matrix.
*
- * Note, that this function does
- * (in contrary to
- * n_nonzero_elements()) not
- * count all entries of the
- * sparsity pattern but only the
- * ones that are nonzero.
+ * Note, that this function does (in contrary to n_nonzero_elements()) not
+ * count all entries of the sparsity pattern but only the ones that are
+ * nonzero.
*/
unsigned int n_actually_nonzero_elements () const;
/**
- * Return a (constant) reference
- * to the underlying sparsity
- * pattern of this matrix.
+ * Return a (constant) reference to the underlying sparsity pattern of this
+ * matrix.
*
- * Though the return value is
- * declared <tt>const</tt>, you
- * should be aware that it may
- * change if you call any
- * nonconstant function of
- * objects which operate on it.
+ * Though the return value is declared <tt>const</tt>, you should be aware
+ * that it may change if you call any nonconstant function of objects which
+ * operate on it.
*/
const ChunkSparsityPattern &get_sparsity_pattern () const;
/**
- * Determine an estimate for the
- * memory consumption (in bytes)
- * of this object. See
- * MemoryConsumption.
+ * Determine an estimate for the memory consumption (in bytes) of this
+ * object. See MemoryConsumption.
*/
std::size_t memory_consumption () const;
*/
//@{
/**
- * Set the element (<i>i,j</i>)
- * to <tt>value</tt>. Throws an
- * error if the entry does not
- * exist or if <tt>value</tt> is
- * not a finite number. Still, it
- * is allowed to store zero
- * values in non-existent fields.
+ * Set the element (<i>i,j</i>) to <tt>value</tt>. Throws an error if the
+ * entry does not exist or if <tt>value</tt> is not a finite number. Still,
+ * it is allowed to store zero values in non-existent fields.
*/
void set (const unsigned int i,
const unsigned int j,
const number value);
/**
- * Add <tt>value</tt> to the
- * element (<i>i,j</i>). Throws
- * an error if the entry does not
- * exist or if <tt>value</tt> is
- * not a finite number. Still, it
- * is allowed to store zero
- * values in non-existent fields.
+ * Add <tt>value</tt> to the element (<i>i,j</i>). Throws an error if the
+ * entry does not exist or if <tt>value</tt> is not a finite number. Still,
+ * it is allowed to store zero values in non-existent fields.
*/
void add (const unsigned int i,
const unsigned int j,
const number value);
/**
- * Add an array of values given by
- * <tt>values</tt> in the given
- * global matrix row at columns
- * specified by col_indices in the
- * sparse matrix.
+ * Add an array of values given by <tt>values</tt> in the given global
+ * matrix row at columns specified by col_indices in the sparse matrix.
*
- * The optional parameter
- * <tt>elide_zero_values</tt> can be
- * used to specify whether zero
- * values should be added anyway or
- * these should be filtered away and
- * only non-zero data is added. The
- * default value is <tt>true</tt>,
- * i.e., zero values won't be added
- * into the matrix.
+ * The optional parameter <tt>elide_zero_values</tt> can be used to specify
+ * whether zero values should be added anyway or these should be filtered
+ * away and only non-zero data is added. The default value is <tt>true</tt>,
+ * i.e., zero values won't be added into the matrix.
*/
template <typename number2>
void add (const unsigned int row,
const bool col_indices_are_sorted = false);
/**
- * Multiply the entire matrix by a
- * fixed factor.
+ * Multiply the entire matrix by a fixed factor.
*/
ChunkSparseMatrix &operator *= (const number factor);
/**
- * Divide the entire matrix by a
- * fixed factor.
+ * Divide the entire matrix by a fixed factor.
*/
ChunkSparseMatrix &operator /= (const number factor);
/**
- * Symmetrize the matrix by
- * forming the mean value between
- * the existing matrix and its
- * transpose, $A = \frac 12(A+A^T)$.
+ * Symmetrize the matrix by forming the mean value between the existing
+ * matrix and its transpose, $A = \frac 12(A+A^T)$.
*
- * This operation assumes that
- * the underlying sparsity
- * pattern represents a symmetric
- * object. If this is not the
- * case, then the result of this
- * operation will not be a
- * symmetric matrix, since it
- * only explicitly symmetrizes
- * by looping over the lower left
- * triangular part for efficiency
- * reasons; if there are entries
- * in the upper right triangle,
- * then these elements are missed
- * in the
- * symmetrization. Symmetrization
- * of the sparsity pattern can be
- * obtain by
- * ChunkSparsityPattern::symmetrize().
+ * This operation assumes that the underlying sparsity pattern represents a
+ * symmetric object. If this is not the case, then the result of this
+ * operation will not be a symmetric matrix, since it only explicitly
+ * symmetrizes by looping over the lower left triangular part for efficiency
+ * reasons; if there are entries in the upper right triangle, then these
+ * elements are missed in the symmetrization. Symmetrization of the sparsity
+ * pattern can be obtain by ChunkSparsityPattern::symmetrize().
*/
void symmetrize ();
/**
- * Copy the given matrix to this
- * one. The operation throws an
- * error if the sparsity patterns
- * of the two involved matrices
- * do not point to the same
- * object, since in this case the
- * copy operation is
- * cheaper. Since this operation
- * is notheless not for free, we
- * do not make it available
- * through <tt>operator =</tt>,
- * since this may lead to
- * unwanted usage, e.g. in copy
- * arguments to functions, which
- * should really be arguments by
- * reference.
+ * Copy the given matrix to this one. The operation throws an error if the
+ * sparsity patterns of the two involved matrices do not point to the same
+ * object, since in this case the copy operation is cheaper. Since this
+ * operation is notheless not for free, we do not make it available through
+ * <tt>operator =</tt>, since this may lead to unwanted usage, e.g. in copy
+ * arguments to functions, which should really be arguments by reference.
*
- * The source matrix may be a matrix
- * of arbitrary type, as long as its
- * data type is convertible to the
- * data type of this matrix.
+ * The source matrix may be a matrix of arbitrary type, as long as its data
+ * type is convertible to the data type of this matrix.
*
- * The function returns a reference to
- * <tt>*this</tt>.
+ * The function returns a reference to <tt>*this</tt>.
*/
template <typename somenumber>
ChunkSparseMatrix<number> &
copy_from (const ChunkSparseMatrix<somenumber> &source);
/**
- * This function is complete
- * analogous to the
- * ChunkSparsityPattern::copy_from()
- * function in that it allows to
- * initialize a whole matrix in
- * one step. See there for more
- * information on argument types
- * and their meaning. You can
- * also find a small example on
- * how to use this function
- * there.
+ * This function is complete analogous to the
+ * ChunkSparsityPattern::copy_from() function in that it allows to
+ * initialize a whole matrix in one step. See there for more information on
+ * argument types and their meaning. You can also find a small example on
+ * how to use this function there.
*
- * The only difference to the
- * cited function is that the
- * objects which the inner
- * iterator points to need to be
- * of type <tt>std::pair<unsigned
- * int, value</tt>, where
- * <tt>value</tt> needs to be
- * convertible to the element
- * type of this class, as
- * specified by the
- * <tt>number</tt> template
+ * The only difference to the cited function is that the objects which the
+ * inner iterator points to need to be of type <tt>std::pair<unsigned int,
+ * value</tt>, where <tt>value</tt> needs to be convertible to the element
+ * type of this class, as specified by the <tt>number</tt> template
* argument.
*
- * Previous content of the matrix
- * is overwritten. Note that the
- * entries specified by the input
- * parameters need not
- * necessarily cover all elements
- * of the matrix. Elements not
- * covered remain untouched.
+ * Previous content of the matrix is overwritten. Note that the entries
+ * specified by the input parameters need not necessarily cover all elements
+ * of the matrix. Elements not covered remain untouched.
*/
template <typename ForwardIterator>
void copy_from (const ForwardIterator begin,
const ForwardIterator end);
/**
- * Copy the nonzero entries of a
- * full matrix into this
- * object. Previous content is
- * deleted. Note that the
- * underlying sparsity pattern
- * must be appropriate to hold
- * the nonzero entries of the
- * full matrix.
+ * Copy the nonzero entries of a full matrix into this object. Previous
+ * content is deleted. Note that the underlying sparsity pattern must be
+ * appropriate to hold the nonzero entries of the full matrix.
*/
template <typename somenumber>
void copy_from (const FullMatrix<somenumber> &matrix);
/**
- * Add <tt>matrix</tt> scaled by
- * <tt>factor</tt> to this matrix,
- * i.e. the matrix <tt>factor*matrix</tt>
- * is added to <tt>this</tt>. This
- * function throws an error if the
- * sparsity patterns of the two involved
- * matrices do not point to the same
- * object, since in this case the
- * operation is cheaper.
+ * Add <tt>matrix</tt> scaled by <tt>factor</tt> to this matrix, i.e. the
+ * matrix <tt>factor*matrix</tt> is added to <tt>this</tt>. This function
+ * throws an error if the sparsity patterns of the two involved matrices do
+ * not point to the same object, since in this case the operation is
+ * cheaper.
*
- * The source matrix may be a sparse
- * matrix over an arbitrary underlying
- * scalar type, as long as its data type
- * is convertible to the data type of
+ * The source matrix may be a sparse matrix over an arbitrary underlying
+ * scalar type, as long as its data type is convertible to the data type of
* this matrix.
*/
template <typename somenumber>
//@{
/**
- * Return the value of the entry
- * (<i>i,j</i>). This may be an
- * expensive operation and you
- * should always take care where
- * to call this function. In
- * order to avoid abuse, this
- * function throws an exception
- * if the required element does
- * not exist in the matrix.
+ * Return the value of the entry (<i>i,j</i>). This may be an expensive
+ * operation and you should always take care where to call this function.
+ * In order to avoid abuse, this function throws an exception if the
+ * required element does not exist in the matrix.
*
- * In case you want a function
- * that returns zero instead (for
- * entries that are not in the
- * sparsity pattern of the
- * matrix), use the el()
- * function.
+ * In case you want a function that returns zero instead (for entries that
+ * are not in the sparsity pattern of the matrix), use the el() function.
*
- * If you are looping over all elements,
- * consider using one of the iterator
- * classes instead, since they are
- * tailored better to a sparse matrix
+ * If you are looping over all elements, consider using one of the iterator
+ * classes instead, since they are tailored better to a sparse matrix
* structure.
*/
number operator () (const unsigned int i,
const unsigned int j) const;
/**
- * This function is mostly like
- * operator()() in that it
- * returns the value of the
- * matrix entry (<i>i,j</i>). The
- * only difference is that if
- * this entry does not exist in
- * the sparsity pattern, then
- * instead of raising an
- * exception, zero is
- * returned. While this may be
- * convenient in some cases, note
- * that it is simple to write
- * algorithms that are slow
- * compared to an optimal
- * solution, since the sparsity
- * of the matrix is not used.
+ * This function is mostly like operator()() in that it returns the value of
+ * the matrix entry (<i>i,j</i>). The only difference is that if this entry
+ * does not exist in the sparsity pattern, then instead of raising an
+ * exception, zero is returned. While this may be convenient in some cases,
+ * note that it is simple to write algorithms that are slow compared to an
+ * optimal solution, since the sparsity of the matrix is not used.
*
- * If you are looping over all elements,
- * consider using one of the iterator
- * classes instead, since they are
- * tailored better to a sparse matrix
+ * If you are looping over all elements, consider using one of the iterator
+ * classes instead, since they are tailored better to a sparse matrix
* structure.
*/
number el (const unsigned int i,
* error if the matrix is not
* quadratic.
*
- * This function is considerably
- * faster than the operator()(),
- * since for quadratic matrices, the
- * diagonal entry may be the
- * first to be stored in each row
- * and access therefore does not
- * involve searching for the
- * right column number.
+ * This function is considerably faster than the operator()(), since for
+ * quadratic matrices, the diagonal entry may be the first to be stored in
+ * each row and access therefore does not involve searching for the right
+ * column number.
*/
number diag_element (const unsigned int i) const;
/**
- * Same as above, but return a
- * writeable reference. You're
- * sure you know what you do?
+ * Same as above, but return a writeable reference. You're sure you know
+ * what you do?
*/
number &diag_element (const unsigned int i);
*/
//@{
/**
- * Matrix-vector multiplication:
- * let <i>dst = M*src</i> with
- * <i>M</i> being this matrix.
+ * Matrix-vector multiplication: let <i>dst = M*src</i> with <i>M</i> being
+ * this matrix.
*
- * Note that while this function can
- * operate on all vectors that offer
- * iterator classes, it is only really
- * effective for objects of type @ref
- * Vector. For all classes for which
- * iterating over elements, or random
- * member access is expensive, this
- * function is not efficient. In
- * particular, if you want to multiply
- * with BlockVector objects, you should
- * consider using a BlockChunkSparseMatrix as
- * well.
+ * Note that while this function can operate on all vectors that offer
+ * iterator classes, it is only really effective for objects of type @ref
+ * Vector. For all classes for which iterating over elements, or random
+ * member access is expensive, this function is not efficient. In
+ * particular, if you want to multiply with BlockVector objects, you should
+ * consider using a BlockChunkSparseMatrix as well.
*
- * Source and destination must
- * not be the same vector.
+ * Source and destination must not be the same vector.
*/
template <class OutVector, class InVector>
void vmult (OutVector &dst,
const InVector &src) const;
/**
- * Matrix-vector multiplication:
- * let <i>dst = M<sup>T</sup>*src</i> with
- * <i>M</i> being this
- * matrix. This function does the
- * same as vmult() but takes
- * the transposed matrix.
+ * Matrix-vector multiplication: let <i>dst = M<sup>T</sup>*src</i> with
+ * <i>M</i> being this matrix. This function does the same as vmult() but
+ * takes the transposed matrix.
*
- * Note that while this function can
- * operate on all vectors that offer
- * iterator classes, it is only really
- * effective for objects of type @ref
- * Vector. For all classes for which
- * iterating over elements, or random
- * member access is expensive, this
- * function is not efficient. In
- * particular, if you want to multiply
- * with BlockVector objects, you should
- * consider using a BlockChunkSparseMatrix as
- * well.
+ * Note that while this function can operate on all vectors that offer
+ * iterator classes, it is only really effective for objects of type @ref
+ * Vector. For all classes for which iterating over elements, or random
+ * member access is expensive, this function is not efficient. In
+ * particular, if you want to multiply with BlockVector objects, you should
+ * consider using a BlockChunkSparseMatrix as well.
*
- * Source and destination must
- * not be the same vector.
+ * Source and destination must not be the same vector.
*/
template <class OutVector, class InVector>
void Tvmult (OutVector &dst,
const InVector &src) const;
/**
- * Adding Matrix-vector
- * multiplication. Add
- * <i>M*src</i> on <i>dst</i>
- * with <i>M</i> being this
- * matrix.
+ * Adding Matrix-vector multiplication. Add <i>M*src</i> on <i>dst</i> with
+ * <i>M</i> being this matrix.
*
- * Note that while this function can
- * operate on all vectors that offer
- * iterator classes, it is only really
- * effective for objects of type @ref
- * Vector. For all classes for which
- * iterating over elements, or random
- * member access is expensive, this
- * function is not efficient. In
- * particular, if you want to multiply
- * with BlockVector objects, you should
- * consider using a BlockChunkSparseMatrix as
- * well.
+ * Note that while this function can operate on all vectors that offer
+ * iterator classes, it is only really effective for objects of type @ref
+ * Vector. For all classes for which iterating over elements, or random
+ * member access is expensive, this function is not efficient. In
+ * particular, if you want to multiply with BlockVector objects, you should
+ * consider using a BlockChunkSparseMatrix as well.
*
- * Source and destination must
- * not be the same vector.
+ * Source and destination must not be the same vector.
*/
template <class OutVector, class InVector>
void vmult_add (OutVector &dst,
const InVector &src) const;
/**
- * Adding Matrix-vector
- * multiplication. Add
- * <i>M<sup>T</sup>*src</i> to
- * <i>dst</i> with <i>M</i> being
- * this matrix. This function
- * does the same as vmult_add()
- * but takes the transposed
- * matrix.
+ * Adding Matrix-vector multiplication. Add <i>M<sup>T</sup>*src</i> to
+ * <i>dst</i> with <i>M</i> being this matrix. This function does the same
+ * as vmult_add() but takes the transposed matrix.
*
- * Note that while this function can
- * operate on all vectors that offer
- * iterator classes, it is only really
- * effective for objects of type @ref
- * Vector. For all classes for which
- * iterating over elements, or random
- * member access is expensive, this
- * function is not efficient. In
- * particular, if you want to multiply
- * with BlockVector objects, you should
- * consider using a BlockChunkSparseMatrix as
- * well.
+ * Note that while this function can operate on all vectors that offer
+ * iterator classes, it is only really effective for objects of type @ref
+ * Vector. For all classes for which iterating over elements, or random
+ * member access is expensive, this function is not efficient. In
+ * particular, if you want to multiply with BlockVector objects, you should
+ * consider using a BlockChunkSparseMatrix as well.
*
- * Source and destination must
- * not be the same vector.
+ * Source and destination must not be the same vector.
*/
template <class OutVector, class InVector>
void Tvmult_add (OutVector &dst,
const InVector &src) const;
/**
- * Return the square of the norm
- * of the vector $v$ with respect
- * to the norm induced by this
- * matrix,
- * i.e. $\left(v,Mv\right)$. This
- * is useful, e.g. in the finite
- * element context, where the
- * $L_2$ norm of a function
- * equals the matrix norm with
- * respect to the mass matrix of
- * the vector representing the
- * nodal values of the finite
- * element function.
+ * Return the square of the norm of the vector $v$ with respect to the norm
+ * induced by this matrix, i.e. $\left(v,Mv\right)$. This is useful, e.g. in
+ * the finite element context, where the $L_2$ norm of a function equals the
+ * matrix norm with respect to the mass matrix of the vector representing
+ * the nodal values of the finite element function.
*
- * Obviously, the matrix needs to be
- * quadratic for this operation, and for
- * the result to actually be a norm it
- * also needs to be either real symmetric
- * or complex hermitian.
+ * Obviously, the matrix needs to be quadratic for this operation, and for
+ * the result to actually be a norm it also needs to be either real
+ * symmetric or complex hermitian.
*
- * The underlying template types of both
- * this matrix and the given vector
- * should either both be real or
- * complex-valued, but not mixed, for
- * this function to make sense.
+ * The underlying template types of both this matrix and the given vector
+ * should either both be real or complex-valued, but not mixed, for this
+ * function to make sense.
*/
template <typename somenumber>
somenumber matrix_norm_square (const Vector<somenumber> &v) const;
/**
- * Compute the matrix scalar
- * product $\left(u,Mv\right)$.
+ * Compute the matrix scalar product $\left(u,Mv\right)$.
*/
template <typename somenumber>
somenumber matrix_scalar_product (const Vector<somenumber> &u,
const Vector<somenumber> &v) const;
/**
- * Compute the residual of an
- * equation <i>Mx=b</i>, where
- * the residual is defined to be
- * <i>r=b-Mx</i>. Write the
- * residual into
- * <tt>dst</tt>. The
- * <i>l<sub>2</sub></i> norm of
- * the residual vector is
- * returned.
+ * Compute the residual of an equation <i>Mx=b</i>, where the residual is
+ * defined to be <i>r=b-Mx</i>. Write the residual into <tt>dst</tt>. The
+ * <i>l<sub>2</sub></i> norm of the residual vector is returned.
*
- * Source <i>x</i> and destination
- * <i>dst</i> must not be the same
- * vector.
+ * Source <i>x</i> and destination <i>dst</i> must not be the same vector.
*/
template <typename somenumber>
somenumber residual (Vector<somenumber> &dst,
//@{
/**
- * Return the l1-norm of the matrix, that is
- * $|M|_1=max_{all columns j}\sum_{all
- * rows i} |M_ij|$,
- * (max. sum of columns).
- * This is the
- * natural matrix norm that is compatible
- * to the l1-norm for vectors, i.e.
- * $|Mv|_1\leq |M|_1 |v|_1$.
- * (cf. Haemmerlin-Hoffmann : Numerische Mathematik)
+ * Return the l1-norm of the matrix, that is $|M|_1=max_{all columns
+ * j}\sum_{all rows i} |M_ij|$, (max. sum of columns). This is the natural
+ * matrix norm that is compatible to the l1-norm for vectors, i.e.
+ * $|Mv|_1\leq |M|_1 |v|_1$. (cf. Haemmerlin-Hoffmann : Numerische
+ * Mathematik)
*/
real_type l1_norm () const;
/**
- * Return the linfty-norm of the
- * matrix, that is
- * $|M|_infty=max_{all rows i}\sum_{all
- * columns j} |M_ij|$,
- * (max. sum of rows).
- * This is the
- * natural matrix norm that is compatible
- * to the linfty-norm of vectors, i.e.
- * $|Mv|_infty \leq |M|_infty |v|_infty$.
- * (cf. Haemmerlin-Hoffmann : Numerische Mathematik)
+ * Return the linfty-norm of the matrix, that is $|M|_infty=max_{all rows
+ * i}\sum_{all columns j} |M_ij|$, (max. sum of rows). This is the natural
+ * matrix norm that is compatible to the linfty-norm of vectors, i.e.
+ * $|Mv|_infty \leq |M|_infty |v|_infty$. (cf. Haemmerlin-Hoffmann :
+ * Numerische Mathematik)
*/
real_type linfty_norm () const;
/**
- * Return the frobenius norm of the
- * matrix, i.e. the square root of the
- * sum of squares of all entries in the
- * matrix.
+ * Return the frobenius norm of the matrix, i.e. the square root of the sum
+ * of squares of all entries in the matrix.
*/
real_type frobenius_norm () const;
//@}
//@{
/**
- * Apply the Jacobi
- * preconditioner, which
- * multiplies every element of
- * the <tt>src</tt> vector by the
- * inverse of the respective
- * diagonal element and
- * multiplies the result with the
- * relaxation factor <tt>omega</tt>.
+ * Apply the Jacobi preconditioner, which multiplies every element of the
+ * <tt>src</tt> vector by the inverse of the respective diagonal element and
+ * multiplies the result with the relaxation factor <tt>omega</tt>.
*/
template <typename somenumber>
void precondition_Jacobi (Vector<somenumber> &dst,
const number omega = 1.) const;
/**
- * Apply SSOR preconditioning to
- * <tt>src</tt>.
+ * Apply SSOR preconditioning to <tt>src</tt>.
*/
template <typename somenumber>
void precondition_SSOR (Vector<somenumber> &dst,
const number om = 1.) const;
/**
- * Apply SOR preconditioning
- * matrix to <tt>src</tt>.
+ * Apply SOR preconditioning matrix to <tt>src</tt>.
*/
template <typename somenumber>
void precondition_SOR (Vector<somenumber> &dst,
const number om = 1.) const;
/**
- * Apply transpose SOR
- * preconditioning matrix to
- * <tt>src</tt>.
+ * Apply transpose SOR preconditioning matrix to <tt>src</tt>.
*/
template <typename somenumber>
void precondition_TSOR (Vector<somenumber> &dst,
const number om = 1.) const;
/**
- * Perform SSOR preconditioning
- * in-place. Apply the
- * preconditioner matrix without
- * copying to a second vector.
- * <tt>omega</tt> is the relaxation
+ * Perform SSOR preconditioning in-place. Apply the preconditioner matrix
+ * without copying to a second vector. <tt>omega</tt> is the relaxation
* parameter.
*/
template <typename somenumber>
const number omega = 1.) const;
/**
- * Perform an SOR preconditioning
- * in-place. <tt>omega</tt> is
- * the relaxation parameter.
+ * Perform an SOR preconditioning in-place. <tt>omega</tt> is the
+ * relaxation parameter.
*/
template <typename somenumber>
void SOR (Vector<somenumber> &v,
const number om = 1.) const;
/**
- * Perform a transpose SOR
- * preconditioning in-place.
- * <tt>omega</tt> is the
+ * Perform a transpose SOR preconditioning in-place. <tt>omega</tt> is the
* relaxation parameter.
*/
template <typename somenumber>
const number om = 1.) const;
/**
- * Perform a permuted SOR
- * preconditioning in-place.
+ * Perform a permuted SOR preconditioning in-place.
*
- * The standard SOR method is
- * applied in the order
- * prescribed by <tt>permutation</tt>,
- * that is, first the row
- * <tt>permutation[0]</tt>, then
- * <tt>permutation[1]</tt> and so
- * on. For efficiency reasons,
- * the permutation as well as its
- * inverse are required.
+ * The standard SOR method is applied in the order prescribed by
+ * <tt>permutation</tt>, that is, first the row <tt>permutation[0]</tt>,
+ * then <tt>permutation[1]</tt> and so on. For efficiency reasons, the
+ * permutation as well as its inverse are required.
*
- * <tt>omega</tt> is the
- * relaxation parameter.
+ * <tt>omega</tt> is the relaxation parameter.
*/
template <typename somenumber>
void PSOR (Vector<somenumber> &v,
const number om = 1.) const;
/**
- * Perform a transposed permuted SOR
- * preconditioning in-place.
+ * Perform a transposed permuted SOR preconditioning in-place.
*
- * The transposed SOR method is
- * applied in the order
- * prescribed by
- * <tt>permutation</tt>, that is,
- * first the row
- * <tt>permutation[m()-1]</tt>,
- * then
- * <tt>permutation[m()-2]</tt>
- * and so on. For efficiency
- * reasons, the permutation as
- * well as its inverse are
- * required.
+ * The transposed SOR method is applied in the order prescribed by
+ * <tt>permutation</tt>, that is, first the row <tt>permutation[m()-1]</tt>,
+ * then <tt>permutation[m()-2]</tt> and so on. For efficiency reasons, the
+ * permutation as well as its inverse are required.
*
- * <tt>omega</tt> is the
- * relaxation parameter.
+ * <tt>omega</tt> is the relaxation parameter.
*/
template <typename somenumber>
void TPSOR (Vector<somenumber> &v,
const number om = 1.) const;
/**
- * Do one SOR step on <tt>v</tt>.
- * Performs a direct SOR step
- * with right hand side
- * <tt>b</tt>.
+ * Do one SOR step on <tt>v</tt>. Performs a direct SOR step with right
+ * hand side <tt>b</tt>.
*/
template <typename somenumber>
void SOR_step (Vector<somenumber> &v,
const number om = 1.) const;
/**
- * Do one adjoint SOR step on
- * <tt>v</tt>. Performs a direct
- * TSOR step with right hand side
- * <tt>b</tt>.
+ * Do one adjoint SOR step on <tt>v</tt>. Performs a direct TSOR step with
+ * right hand side <tt>b</tt>.
*/
template <typename somenumber>
void TSOR_step (Vector<somenumber> &v,
const number om = 1.) const;
/**
- * Do one SSOR step on
- * <tt>v</tt>. Performs a direct
- * SSOR step with right hand side
- * <tt>b</tt> by performing TSOR
- * after SOR.
+ * Do one SSOR step on <tt>v</tt>. Performs a direct SSOR step with right
+ * hand side <tt>b</tt> by performing TSOR after SOR.
*/
template <typename somenumber>
void SSOR_step (Vector<somenumber> &v,
const Vector<somenumber> &b,
const number om = 1.) const;
+//@}
+ /**
+ * @name Iterators
+ */
+//@{
+
+ /**
+ * STL-like iterator with the first entry of the matrix. This is the version
+ * for constant matrices.
+ *
+ * Note that due to the layout in ChunkSparseMatrix, iterating over matrix
+ * entries is considerably slower than for a sparse matrix, as the iterator
+ * is travels row-by-row, whereas data is stored in chunks of several rows
+ * and columns.
+ */
+ const_iterator begin () const;
+
+ /**
+ * Final iterator. This is the version for constant matrices.
+ *
+ * Note that due to the layout in ChunkSparseMatrix, iterating over matrix
+ * entries is considerably slower than for a sparse matrix, as the iterator
+ * is travels row-by-row, whereas data is stored in chunks of several rows
+ * and columns.
+ */
+ const_iterator end () const;
+
+ /**
+ * STL-like iterator with the first entry of the matrix. This is the version
+ * for non-constant matrices.
+ *
+ * Note that due to the layout in ChunkSparseMatrix, iterating over matrix
+ * entries is considerably slower than for a sparse matrix, as the iterator
+ * is travels row-by-row, whereas data is stored in chunks of several rows
+ * and columns.
+ */
+ iterator begin ();
+
+ /**
+ * Final iterator. This is the version for non-constant matrices.
+ *
+ * Note that due to the layout in ChunkSparseMatrix, iterating over matrix
+ * entries is considerably slower than for a sparse matrix, as the iterator
+ * is travels row-by-row, whereas data is stored in chunks of several rows
+ * and columns.
+ */
+ iterator end ();
+
+ /**
+ * STL-like iterator with the first entry of row <tt>r</tt>. This is the
+ * version for constant matrices.
+ *
+ * Note that if the given row is empty, i.e. does not contain any nonzero
+ * entries, then the iterator returned by this function equals
+ * <tt>end(r)</tt>. Note also that the iterator may not be dereferencable in
+ * that case.
+ *
+ * Note that due to the layout in ChunkSparseMatrix, iterating over matrix
+ * entries is considerably slower than for a sparse matrix, as the iterator
+ * is travels row-by-row, whereas data is stored in chunks of several rows
+ * and columns.
+ */
+ const_iterator begin (const unsigned int r) const;
+
+ /**
+ * Final iterator of row <tt>r</tt>. It points to the first element past the
+ * end of line @p r, or past the end of the entire sparsity pattern. This is
+ * the version for constant matrices.
+ *
+ * Note that the end iterator is not necessarily dereferencable. This is in
+ * particular the case if it is the end iterator for the last row of a
+ * matrix.
+ *
+ * Note that due to the layout in ChunkSparseMatrix, iterating over matrix
+ * entries is considerably slower than for a sparse matrix, as the iterator
+ * is travels row-by-row, whereas data is stored in chunks of several rows
+ * and columns.
+ */
+ const_iterator end (const unsigned int r) const;
+
+ /**
+ * STL-like iterator with the first entry of row <tt>r</tt>. This is the
+ * version for non-constant matrices.
+ *
+ * Note that if the given row is empty, i.e. does not contain any nonzero
+ * entries, then the iterator returned by this function equals
+ * <tt>end(r)</tt>. Note also that the iterator may not be dereferencable in
+ * that case.
+ *
+ * Note that due to the layout in ChunkSparseMatrix, iterating over matrix
+ * entries is considerably slower than for a sparse matrix, as the iterator
+ * is travels row-by-row, whereas data is stored in chunks of several rows
+ * and columns.
+ */
+ iterator begin (const unsigned int r);
+
+ /**
+ * Final iterator of row <tt>r</tt>. It points to the first element past the
+ * end of line @p r, or past the end of the entire sparsity pattern. This is
+ * the version for non-constant matrices.
+ *
+ * Note that the end iterator is not necessarily dereferencable. This is in
+ * particular the case if it is the end iterator for the last row of a
+ * matrix.
+ *
+ * Note that due to the layout in ChunkSparseMatrix, iterating over matrix
+ * entries is considerably slower than for a sparse matrix, as the iterator
+ * is travels row-by-row, whereas data is stored in chunks of several rows
+ * and columns.
+ */
+ iterator end (const unsigned int r);
//@}
/**
* @name Input/Output
//@{
/**
- * Print the matrix to the given
- * stream, using the format
- * <tt>(line,col) value</tt>,
- * i.e. one nonzero entry of the
- * matrix per line.
+ * Print the matrix to the given stream, using the format <tt>(line,col)
+ * value</tt>, i.e. one nonzero entry of the matrix per line.
*/
void print (std::ostream &out) const;
/**
- * Print the matrix in the usual
- * format, i.e. as a matrix and
- * not as a list of nonzero
- * elements. For better
- * readability, elements not in
- * the matrix are displayed as
- * empty space, while matrix
- * elements which are explicitly
- * set to zero are displayed as
- * such.
+ * Print the matrix in the usual format, i.e. as a matrix and not as a list
+ * of nonzero elements. For better readability, elements not in the matrix
+ * are displayed as empty space, while matrix elements which are explicitly
+ * set to zero are displayed as such.
*
- * The parameters allow for a
- * flexible setting of the output
- * format: <tt>precision</tt> and
- * <tt>scientific</tt> are used
- * to determine the number
- * format, where <tt>scientific =
- * false</tt> means fixed point
- * notation. A zero entry for
- * <tt>width</tt> makes the
- * function compute a width, but
- * it may be changed to a
- * positive value, if output is
- * crude.
+ * The parameters allow for a flexible setting of the output format:
+ * <tt>precision</tt> and <tt>scientific</tt> are used to determine the
+ * number format, where <tt>scientific = false</tt> means fixed point
+ * notation. A zero entry for <tt>width</tt> makes the function compute a
+ * width, but it may be changed to a positive value, if output is crude.
*
- * Additionally, a character for
- * an empty value may be
- * specified.
+ * Additionally, a character for an empty value may be specified.
*
- * Finally, the whole matrix can
- * be multiplied with a common
- * denominator to produce more
- * readable output, even
- * integers.
+ * Finally, the whole matrix can be multiplied with a common denominator to
+ * produce more readable output, even integers.
*
- * @attention This function may
- * produce <b>large</b> amounts
- * of output if applied to a
- * large matrix!
+ * @attention This function may produce <b>large</b> amounts of output if
+ * applied to a large matrix!
*/
void print_formatted (std::ostream &out,
const unsigned int precision = 3,
const double denominator = 1.) const;
/**
- * Print the actual pattern of
- * the matrix. For each entry
- * with an absolute value larger
- * than threshold, a '*' is
- * printed, a ':' for every value
- * smaller and a '.' for every
- * entry not allocated.
+ * Print the actual pattern of the matrix. For each entry with an absolute
+ * value larger than threshold, a '*' is printed, a ':' for every value
+ * smaller and a '.' for every entry not allocated.
*/
void print_pattern(std::ostream &out,
const double threshold = 0.) const;
/**
- * Write the data of this object
- * en bloc to a file. This is
- * done in a binary mode, so the
- * output is neither readable by
- * humans nor (probably) by other
- * computers using a different
- * operating system of number
- * format.
+ * Write the data of this object en bloc to a file. This is done in a binary
+ * mode, so the output is neither readable by humans nor (probably) by other
+ * computers using a different operating system or number format.
*
- * The purpose of this function
- * is that you can swap out
- * matrices and sparsity pattern
- * if you are short of memory,
- * want to communicate between
- * different programs, or allow
- * objects to be persistent
- * across different runs of the
- * program.
+ * The purpose of this function is that you can swap out matrices and
+ * sparsity pattern if you are short of memory, want to communicate between
+ * different programs, or allow objects to be persistent across different
+ * runs of the program.
*/
void block_write (std::ostream &out) const;
/**
- * Read data that has previously
- * been written by block_write()
- * from a file. This is done
- * using the inverse operations
- * to the above function, so it
- * is reasonably fast because the
- * bitstream is not interpreted
- * except for a few numbers up
- * front.
+ * Read data that has previously been written by block_write() from a
+ * file. This is done using the inverse operations to the above function, so
+ * it is reasonably fast because the bitstream is not interpreted except for
+ * a few numbers up front.
*
- * The object is resized on this
- * operation, and all previous
- * contents are lost. Note,
- * however, that no checks are
- * performed whether new data and
- * the underlying ChunkSparsityPattern
- * object fit together. It is
- * your responsibility to make
- * sure that the sparsity pattern
- * and the data to be read match.
+ * The object is resized on this operation, and all previous contents are
+ * lost. Note, however, that no checks are performed whether new data and
+ * the underlying ChunkSparsityPattern object fit together. It is your
+ * responsibility to make sure that the sparsity pattern and the data to be
+ * read match.
*
- * A primitive form of error
- * checking is performed which
- * will recognize the bluntest
- * attempts to interpret some
- * data as a matrix stored
- * bitwise to a file that wasn't
- * actually created that way, but
- * not more.
+ * A primitive form of error checking is performed which will recognize the
+ * bluntest attempts to interpret some data as a matrix stored bitwise to a
+ * file that wasn't actually created that way, but not more.
*/
void block_read (std::istream &in);
//@}
//@}
private:
/**
- * Pointer to the sparsity
- * pattern used for this
- * matrix. In order to guarantee
- * that it is not deleted while
- * still in use, we subscribe to
- * it using the SmartPointer
- * class.
+ * Pointer to the sparsity pattern used for this matrix. In order to
+ * guarantee that it is not deleted while still in use, we subscribe to it
+ * using the SmartPointer class.
*/
SmartPointer<const ChunkSparsityPattern,ChunkSparseMatrix<number> > cols;
/**
- * Array of values for all the
- * nonzero entries. The position
- * within the matrix, i.e. the
- * row and column number for a
- * given entry can only be
- * deduced using the sparsity
- * pattern. The same holds for
- * the more common operation of
- * finding an entry by its
- * coordinates.
+ * Array of values for all the nonzero entries. The position within the
+ * matrix, i.e. the row and column number for a given entry can only be
+ * deduced using the sparsity pattern. The same holds for the more common
+ * operation of finding an entry by its coordinates.
*/
number *val;
/**
- * Allocated size of #val. This
- * can be larger than the
- * actually used part if the size
- * of the matrix was reduced
- * somewhen in the past by
- * associating a sparsity pattern
- * with a smaller size to this
- * object, using the reinit()
+ * Allocated size of #val. This can be larger than the actually used part if
+ * the size of the matrix was reduced somewhen in the past by associating a
+ * sparsity pattern with a smaller size to this object, using the reinit()
* function.
*/
unsigned int max_len;
/**
- * Return the location of entry
- * $(i,j)$ within the val array.
+ * Return the location of entry $(i,j)$ within the val array.
*/
unsigned int compute_location (const unsigned int i,
const unsigned int j) const;
- // make all other sparse matrices
- // friends
+ // make all other sparse matrices friends
template <typename somenumber> friend class ChunkSparseMatrix;
+
+ /**
+ * Also give access to internal details to the iterator/accessor
+ * classes.
+ */
+ template <typename,bool> friend class ChunkSparseMatrixIterators::Iterator;
+ template <typename,bool> friend class ChunkSparseMatrixIterators::Accessor;
};
/*@}*/
+template <typename number>
+inline
+const ChunkSparsityPattern &
+ChunkSparseMatrix<number>::get_sparsity_pattern () const
+{
+ Assert (cols != 0, ExcNotInitialized());
+ return *cols;
+}
+
+
+
template <typename number>
inline
unsigned int
{
const unsigned int chunk_size = cols->get_chunk_size();
const unsigned int chunk_index
- = cols->sparsity_pattern(i/chunk_size, j/chunk_size);
+ = cols->sparsity_pattern(i/chunk_size, j/chunk_size);
if (chunk_index == ChunkSparsityPattern::invalid_entry)
return ChunkSparsityPattern::invalid_entry;
Assert (numbers::is_finite(value), ExcNumberNotFinite());
Assert (cols != 0, ExcNotInitialized());
- // it is allowed to set elements of
- // the matrix that are not part of
- // the sparsity pattern, if the
- // value to which we set it is zero
+ // it is allowed to set elements of the matrix that are not part of the
+ // sparsity pattern, if the value to which we set it is zero
const unsigned int index = compute_location(i,j);
Assert ((index != SparsityPattern::invalid_entry) ||
(value == 0.),
const unsigned int chunk_size = cols->get_chunk_size();
- // multiply all elements of the matrix with
- // the given factor. this includes the
- // padding elements in chunks that overlap
- // the boundaries of the actual matrix --
- // but since multiplication with a number
- // does not violate the invariant of
- // keeping these elements at zero nothing
- // can happen
+ // multiply all elements of the matrix with the given factor. this includes
+ // the padding elements in chunks that overlap the boundaries of the actual
+ // matrix -- but since multiplication with a number does not violate the
+ // invariant of keeping these elements at zero nothing can happen
number *val_ptr = val;
const number *const end_ptr = val +
cols->sparsity_pattern.n_nonzero_elements()
const unsigned int chunk_size = cols->get_chunk_size();
- // multiply all elements of the matrix with
- // the given factor. this includes the
- // padding elements in chunks that overlap
- // the boundaries of the actual matrix --
- // but since multiplication with a number
- // does not violate the invariant of
- // keeping these elements at zero nothing
- // can happen
+ // multiply all elements of the matrix with the given factor. this includes
+ // the padding elements in chunks that overlap the boundaries of the actual
+ // matrix -- but since multiplication with a number does not violate the
+ // invariant of keeping these elements at zero nothing can happen
number *val_ptr = val;
const number *const end_ptr = val +
cols->sparsity_pattern.n_nonzero_elements()
Assert (m() == n(), ExcNotQuadratic());
Assert (i<m(), ExcInvalidIndex1(i));
- // Use that the first element in each row
- // of a quadratic matrix is the main
- // diagonal of the chunk sparsity pattern
- const unsigned int chunk_size = cols->get_chunk_size();
- return val[cols->sparsity_pattern.rowstart[i/chunk_size]
- *
- chunk_size * chunk_size
- +
- (i % chunk_size) * chunk_size
- +
- (i % chunk_size)];
-}
-
-
-
-template <typename number>
-inline
-number &ChunkSparseMatrix<number>::diag_element (const unsigned int i)
-{
- Assert (cols != 0, ExcNotInitialized());
- Assert (m() == n(), ExcNotQuadratic());
- Assert (i<m(), ExcInvalidIndex1(i));
-
- // Use that the first element in each row
- // of a quadratic matrix is the main
+ // Use that the first element in each row of a quadratic matrix is the main
// diagonal of the chunk sparsity pattern
const unsigned int chunk_size = cols->get_chunk_size();
return val[cols->sparsity_pattern.rowstart[i/chunk_size]
template <typename number>
template <typename ForwardIterator>
+inline
void
ChunkSparseMatrix<number>::copy_from (const ForwardIterator begin,
const ForwardIterator end)
Assert (static_cast<unsigned int>(std::distance (begin, end)) == m(),
ExcIteratorRange (std::distance (begin, end), m()));
- // for use in the inner loop, we
- // define a typedef to the type of
- // the inner iterators
+ // for use in the inner loop, we define a typedef to the type of the inner
+ // iterators
typedef typename std::iterator_traits<ForwardIterator>::value_type::const_iterator inner_iterator;
unsigned int row=0;
for (ForwardIterator i=begin; i!=end; ++i, ++row)
}
+
+//---------------------------------------------------------------------------
+
+
+namespace ChunkSparseMatrixIterators
+{
+ template <typename number>
+ inline
+ Accessor<number,true>::
+ Accessor (const MatrixType *matrix,
+ const unsigned int row)
+ :
+ ChunkSparsityPatternIterators::Accessor (&matrix->get_sparsity_pattern(),
+ row),
+ matrix (matrix)
+ {}
+
+
+
+ template <typename number>
+ inline
+ Accessor<number,true>::
+ Accessor (const MatrixType *matrix)
+ :
+ ChunkSparsityPatternIterators::Accessor (&matrix->get_sparsity_pattern()),
+ matrix (matrix)
+ {}
+
+
+
+ template <typename number>
+ inline
+ Accessor<number,true>::
+ Accessor (const ChunkSparseMatrixIterators::Accessor<number,false> &a)
+ :
+ ChunkSparsityPatternIterators::Accessor (a),
+ matrix (&a.get_matrix())
+ {}
+
+
+
+ template <typename number>
+ inline
+ number
+ Accessor<number, true>::value () const
+ {
+ const unsigned int chunk_size = matrix->get_sparsity_pattern().get_chunk_size();
+ return matrix->val[reduced_index() * chunk_size * chunk_size
+ +
+ chunk_row * chunk_size
+ +
+ chunk_col];
+ }
+
+
+
+ template <typename number>
+ inline
+ typename Accessor<number, true>::MatrixType &
+ Accessor<number, true>::get_matrix () const
+ {
+ return *matrix;
+ }
+
+
+
+ template <typename number>
+ inline
+ Accessor<number, false>::Reference::Reference (
+ const Accessor *accessor,
+ const bool)
+ :
+ accessor (accessor)
+ {}
+
+
+ template <typename number>
+ inline
+ Accessor<number, false>::Reference::operator number() const
+ {
+ const unsigned int chunk_size = accessor->matrix->get_sparsity_pattern().get_chunk_size();
+ return accessor->matrix->val[accessor->reduced_index() * chunk_size * chunk_size
+ +
+ accessor->chunk_row * chunk_size
+ +
+ accessor->chunk_col];
+ }
+
+
+
+ template <typename number>
+ inline
+ const typename Accessor<number, false>::Reference &
+ Accessor<number, false>::Reference::operator = (const number n) const
+ {
+ const unsigned int chunk_size = accessor->matrix->get_sparsity_pattern().get_chunk_size();
+ accessor->matrix->val[accessor->reduced_index() * chunk_size * chunk_size
+ +
+ accessor->chunk_row * chunk_size
+ +
+ accessor->chunk_col] = n;
+ return *this;
+ }
+
+
+
+ template <typename number>
+ inline
+ const typename Accessor<number, false>::Reference &
+ Accessor<number, false>::Reference::operator += (const number n) const
+ {
+ const unsigned int chunk_size = accessor->matrix->get_sparsity_pattern().get_chunk_size();
+ accessor->matrix->val[accessor->reduced_index() * chunk_size * chunk_size
+ +
+ accessor->chunk_row * chunk_size
+ +
+ accessor->chunk_col] += n;
+ return *this;
+ }
+
+
+
+ template <typename number>
+ inline
+ const typename Accessor<number, false>::Reference &
+ Accessor<number, false>::Reference::operator -= (const number n) const
+ {
+ const unsigned int chunk_size = accessor->matrix->get_sparsity_pattern().get_chunk_size();
+ accessor->matrix->val[accessor->reduced_index() * chunk_size * chunk_size
+ +
+ accessor->chunk_row * chunk_size
+ +
+ accessor->chunk_col] -= n;
+ return *this;
+ }
+
+
+
+ template <typename number>
+ inline
+ const typename Accessor<number, false>::Reference &
+ Accessor<number, false>::Reference::operator *= (const number n) const
+ {
+ const unsigned int chunk_size = accessor->matrix->get_sparsity_pattern().get_chunk_size();
+ accessor->matrix->val[accessor->reduced_index() * chunk_size * chunk_size
+ +
+ accessor->chunk_row * chunk_size
+ +
+ accessor->chunk_col] *= n;
+ return *this;
+ }
+
+
+
+ template <typename number>
+ inline
+ const typename Accessor<number, false>::Reference &
+ Accessor<number, false>::Reference::operator /= (const number n) const
+ {
+ const unsigned int chunk_size = accessor->matrix->get_sparsity_pattern().get_chunk_size();
+ accessor->matrix->val[accessor->reduced_index() * chunk_size * chunk_size
+ +
+ accessor->chunk_row * chunk_size
+ +
+ accessor->chunk_col] /= n;
+ return *this;
+ }
+
+
+
+ template <typename number>
+ inline
+ Accessor<number,false>::
+ Accessor (MatrixType *matrix,
+ const unsigned int row)
+ :
+ ChunkSparsityPatternIterators::Accessor (&matrix->get_sparsity_pattern(),
+ row),
+ matrix (matrix)
+ {}
+
+
+
+ template <typename number>
+ inline
+ Accessor<number,false>::
+ Accessor (MatrixType *matrix)
+ :
+ ChunkSparsityPatternIterators::Accessor (&matrix->get_sparsity_pattern()),
+ matrix (matrix)
+ {}
+
+
+
+ template <typename number>
+ inline
+ typename Accessor<number, false>::Reference
+ Accessor<number, false>::value() const
+ {
+ return Reference(this,true);
+ }
+
+
+
+
+ template <typename number>
+ inline
+ typename Accessor<number, false>::MatrixType &
+ Accessor<number, false>::get_matrix () const
+ {
+ return *matrix;
+ }
+
+
+
+ template <typename number, bool Constness>
+ inline
+ Iterator<number, Constness>::
+ Iterator (MatrixType *matrix,
+ const unsigned int row)
+ :
+ accessor(matrix, row)
+ {}
+
+
+
+ template <typename number, bool Constness>
+ inline
+ Iterator<number, Constness>::
+ Iterator (MatrixType *matrix)
+ :
+ accessor(matrix)
+ {}
+
+
+
+ template <typename number, bool Constness>
+ inline
+ Iterator<number, Constness>::
+ Iterator (const ChunkSparseMatrixIterators::Iterator<number,false> &i)
+ :
+ accessor(*i)
+ {}
+
+
+
+ template <typename number, bool Constness>
+ inline
+ Iterator<number, Constness> &
+ Iterator<number,Constness>::operator++ ()
+ {
+ accessor.advance ();
+ return *this;
+ }
+
+
+ template <typename number, bool Constness>
+ inline
+ Iterator<number,Constness>
+ Iterator<number,Constness>::operator++ (int)
+ {
+ const Iterator iter = *this;
+ accessor.advance ();
+ return iter;
+ }
+
+
+ template <typename number, bool Constness>
+ inline
+ const Accessor<number,Constness> &
+ Iterator<number,Constness>::operator* () const
+ {
+ return accessor;
+ }
+
+
+ template <typename number, bool Constness>
+ inline
+ const Accessor<number,Constness> *
+ Iterator<number,Constness>::operator-> () const
+ {
+ return &accessor;
+ }
+
+
+ template <typename number, bool Constness>
+ inline
+ bool
+ Iterator<number,Constness>::
+ operator == (const Iterator &other) const
+ {
+ return (accessor == other.accessor);
+ }
+
+
+ template <typename number, bool Constness>
+ inline
+ bool
+ Iterator<number,Constness>::
+ operator != (const Iterator &other) const
+ {
+ return ! (*this == other);
+ }
+
+
+ template <typename number, bool Constness>
+ inline
+ bool
+ Iterator<number,Constness>::
+ operator < (const Iterator &other) const
+ {
+ Assert (&accessor.get_matrix() == &other.accessor.get_matrix(),
+ ExcInternalError());
+
+ return (accessor < other.accessor);
+ }
+
+
+ template <typename number, bool Constness>
+ inline
+ bool
+ Iterator<number,Constness>::
+ operator > (const Iterator &other) const
+ {
+ return (other < *this);
+ }
+
+
+ template <typename number, bool Constness>
+ inline
+ int
+ Iterator<number,Constness>::
+ operator - (const Iterator &other) const
+ {
+ Assert (&accessor.get_matrix() == &other.accessor.get_matrix(),
+ ExcInternalError());
+
+ // TODO: can be optimized
+ int difference = 0;
+ if (*this < other)
+ {
+ Iterator copy = *this;
+ while (copy != other)
+ {
+ ++copy;
+ --difference;
+ }
+ }
+ else
+ {
+ Iterator copy = other;
+ while (copy != *this)
+ {
+ ++copy;
+ ++difference;
+ }
+ }
+ return difference;
+ }
+
+
+
+ template <typename number, bool Constness>
+ inline
+ Iterator<number,Constness>
+ Iterator<number,Constness>::
+ operator + (const unsigned int n) const
+ {
+ Iterator x = *this;
+ for (unsigned int i=0; i<n; ++i)
+ ++x;
+
+ return x;
+ }
+
+}
+
+
+
+template <typename number>
+inline
+typename ChunkSparseMatrix<number>::const_iterator
+ChunkSparseMatrix<number>::begin () const
+{
+ return const_iterator(this, 0);
+}
+
+
+template <typename number>
+inline
+typename ChunkSparseMatrix<number>::const_iterator
+ChunkSparseMatrix<number>::end () const
+{
+ return const_iterator(this);
+}
+
+
+template <typename number>
+inline
+typename ChunkSparseMatrix<number>::iterator
+ChunkSparseMatrix<number>::begin ()
+{
+ return iterator(this, 0);
+}
+
+
+template <typename number>
+inline
+typename ChunkSparseMatrix<number>::iterator
+ChunkSparseMatrix<number>::end ()
+{
+ return iterator(this);
+}
+
+
+template <typename number>
+inline
+typename ChunkSparseMatrix<number>::const_iterator
+ChunkSparseMatrix<number>::begin (const unsigned int r) const
+{
+ Assert (r<m(), ExcIndexRange(r,0,m()));
+ return const_iterator(this, r);
+}
+
+
+
+template <typename number>
+inline
+typename ChunkSparseMatrix<number>::const_iterator
+ChunkSparseMatrix<number>::end (const unsigned int r) const
+{
+ Assert (r<m(), ExcIndexRange(r,0,m()));
+ return const_iterator(this, r+1);
+}
+
+
+
+template <typename number>
+inline
+typename ChunkSparseMatrix<number>::iterator
+ChunkSparseMatrix<number>::begin (const unsigned int r)
+{
+ Assert (r<m(), ExcIndexRange(r,0,m()));
+ return iterator(this, r);
+}
+
+
+
+template <typename number>
+inline
+typename ChunkSparseMatrix<number>::iterator
+ChunkSparseMatrix<number>::end (const unsigned int r)
+{
+ Assert (r<m(), ExcIndexRange(r,0,m()));
+ return iterator(this, r+1);
+}
+
+
+
+
#endif // DOXYGEN
#include <deal.II/base/template_constraints.h>
+#include <deal.II/base/parallel.h>
#include <deal.II/lac/chunk_sparse_matrix.h>
#include <deal.II/lac/vector.h>
#include <deal.II/lac/full_matrix.h>
namespace ChunkSparseMatrix
{
/**
- * Add the result of multiplying a chunk
- * of size chunk_size times chunk_size by
- * a source vector fragment of size
- * chunk_size to the destination vector
- * fragment.
+ * Add the result of multiplying a chunk of size chunk_size times
+ * chunk_size by a source vector fragment of size chunk_size to the
+ * destination vector fragment.
*/
template <typename MatrixIterator,
typename SrcIterator,
/**
- * Like the previous function, but
- * subtract. We need this for computing
+ * Like the previous function, but subtract. We need this for computing
* the residual.
*/
template <typename MatrixIterator,
/**
- * Add the result of multiplying the
- * transpose of a chunk of size
- * chunk_size times chunk_size by a
- * source vector fragment of size
- * chunk_size to the destination vector
- * fragment.
+ * Add the result of multiplying the transpose of a chunk of size
+ * chunk_size times chunk_size by a source vector fragment of size
+ * chunk_size to the destination vector fragment.
*/
template <typename MatrixIterator,
typename SrcIterator,
/**
- * Produce the result of the matrix
- * scalar product $u^TMv$ for an
+ * Produce the result of the matrix scalar product $u^TMv$ for an
* individual chunk.
*/
template <typename result_type,
return result;
}
+
+
+
+ /**
+ * Perform a vmult_add using the ChunkSparseMatrix data structures, but
+ * only using a subinterval of the matrix rows.
+ *
+ * In the sequential case, this function is called on all rows, in the
+ * parallel case it may be called on a subrange, at the discretion of the
+ * task scheduler.
+ */
+ template <typename number,
+ typename InVector,
+ typename OutVector>
+ void vmult_add_on_subrange (const ChunkSparsityPattern &cols,
+ const unsigned int begin_row,
+ const unsigned int end_row,
+ const number *values,
+ const std::size_t *rowstart,
+ const unsigned int *colnums,
+ const InVector &src,
+ OutVector &dst)
+ {
+ const unsigned int m = cols.n_rows();
+ const unsigned int n = cols.n_cols();
+ const unsigned int chunk_size = cols.get_chunk_size();
+
+ // loop over all chunks. note that we need to treat the last chunk row
+ // and column differently if they have padding elements
+ const unsigned int n_filled_last_rows = m % chunk_size;
+ const unsigned int n_filled_last_cols = n % chunk_size;
+
+ const unsigned int last_regular_row = n_filled_last_rows > 0 ?
+ std::min(m/chunk_size, end_row) : end_row;
+ const unsigned int irregular_col = n/chunk_size;
+
+ typename OutVector::iterator dst_ptr = dst.begin()+chunk_size*begin_row;
+ const number *val_ptr= &values[rowstart[begin_row]*chunk_size*chunk_size];
+ const unsigned int *colnum_ptr = &colnums[rowstart[begin_row]];
+ for (unsigned int chunk_row=begin_row; chunk_row<last_regular_row;
+ ++chunk_row)
+ {
+ const number *const val_end_of_row = &values[rowstart[chunk_row+1] *
+ chunk_size * chunk_size];
+ while (val_ptr != val_end_of_row)
+ {
+ if (*colnum_ptr != irregular_col)
+ chunk_vmult_add (chunk_size,
+ val_ptr,
+ src.begin() + *colnum_ptr * chunk_size,
+ dst_ptr);
+ else
+ // we're at a chunk column that has padding
+ for (unsigned int r=0; r<chunk_size; ++r)
+ for (unsigned int c=0; c<n_filled_last_cols; ++c)
+ dst_ptr[r] += (val_ptr[r*chunk_size + c] *
+ src(*colnum_ptr * chunk_size + c));
+
+ ++colnum_ptr;
+ val_ptr += chunk_size * chunk_size;
+ }
+
+ dst_ptr += chunk_size;
+ }
+
+ // now deal with last chunk row if necessary
+ if (n_filled_last_rows > 0 && end_row == (m/chunk_size+1))
+ {
+ const unsigned int chunk_row = last_regular_row;
+
+ const number *const val_end_of_row = &values[rowstart[chunk_row+1] *
+ chunk_size * chunk_size];
+ while (val_ptr != val_end_of_row)
+ {
+ if (*colnum_ptr != irregular_col)
+ {
+ // we're at a chunk row but not column that has padding
+ for (unsigned int r=0; r<n_filled_last_rows; ++r)
+ for (unsigned int c=0; c<chunk_size; ++c)
+ dst_ptr[r]
+ += (val_ptr[r*chunk_size + c] *
+ src(*colnum_ptr * chunk_size + c));
+ }
+ else
+ // we're at a chunk row and column that has padding
+ for (unsigned int r=0; r<n_filled_last_rows; ++r)
+ for (unsigned int c=0; c<n_filled_last_cols; ++c)
+ dst_ptr[r]
+ += (val_ptr[r*chunk_size + c] *
+ src(*colnum_ptr * chunk_size + c));
+
+ ++colnum_ptr;
+ val_ptr += chunk_size * chunk_size;
+ }
+ }
+ Assert(std::size_t(colnum_ptr-&colnums[0]) == rowstart[end_row],
+ ExcInternalError());
+ Assert(std::size_t(val_ptr-&values[0]) ==
+ rowstart[end_row] * chunk_size * chunk_size,
+ ExcInternalError());
+ }
}
}
+namespace internal
+{
+ namespace ChunkSparseMatrix
+ {
+ template<typename T>
+ void zero_subrange (const unsigned int begin,
+ const unsigned int end,
+ T *dst)
+ {
+ std::memset (dst+begin,0,(end-begin)*sizeof(T));
+ }
+ }
+}
+
+
+
template <typename number>
ChunkSparseMatrix<number> &
ChunkSparseMatrix<number>::operator = (const double d)
Assert (cols->sparsity_pattern.compressed || cols->empty(),
ChunkSparsityPattern::ExcNotCompressed());
- if (val)
- {
- const unsigned int chunk_size = cols->get_chunk_size();
- std::fill_n (val,
- cols->sparsity_pattern.n_nonzero_elements() *
- chunk_size * chunk_size,
- 0.);
- }
+ // do initial zeroing of elements in parallel. Try to achieve a similar
+ // layout as when doing matrix-vector products, as on some NUMA systems, a
+ // memory block is assigned to memory banks where the first access is
+ // generated. For sparse matrices, the first operations is usually the
+ // operator=. The grain size is chosen to reflect the number of rows in
+ // minimum_parallel_grain_size, weighted by the number of nonzero entries
+ // per row on average.
+ const unsigned int matrix_size = cols->sparsity_pattern.n_nonzero_elements()
+ * cols->chunk_size * cols->chunk_size;
+ const unsigned int grain_size =
+ internal::SparseMatrix::minimum_parallel_grain_size *
+ (matrix_size+m()) / m();
+ if (matrix_size>grain_size)
+ parallel::apply_to_subranges (0U, matrix_size,
+ std_cxx1x::bind(&internal::ChunkSparseMatrix::template
+ zero_subrange<number>,
+ std_cxx1x::_1, std_cxx1x::_2,
+ val),
+ grain_size);
+ else if (matrix_size > 0)
+ std::memset (&val[0], 0, matrix_size*sizeof(number));
return *this;
}
return;
}
- // allocate not just m() * n() elements but
- // enough so that we can store full
- // chunks. this entails some padding
- // elements
+ // allocate not just m() * n() elements but enough so that we can store full
+ // chunks. this entails some padding elements
const unsigned int chunk_size = cols->get_chunk_size();
const unsigned int N = cols->sparsity_pattern.n_nonzero_elements() *
chunk_size * chunk_size;
max_len = N;
}
- // fill with zeros. do not just fill N
- // elements but all that we allocated to
- // ensure that also the padding elements
- // are zero and not left at previous values
- if (val != 0)
- std::fill_n (&val[0], max_len, 0);
+ // fill with zeros. do not just fill N elements but all that we allocated to
+ // ensure that also the padding elements are zero and not left at previous
+ // values
+ this->operator=(0.);
}
{
Assert (cols != 0, ExcNotInitialized());
- // count those elements that are nonzero,
- // even if they lie in the padding around
- // the matrix. since we have the invariant
- // that padding elements are zero, nothing
- // bad can happen here
+ // count those elements that are nonzero, even if they lie in the padding
+ // around the matrix. since we have the invariant that padding elements are
+ // zero, nothing bad can happen here
const unsigned int chunk_size = cols->get_chunk_size();
return std::count_if(&val[0],
&val[cols->sparsity_pattern.n_nonzero_elements () *
Assert (val != 0, ExcNotInitialized());
Assert (cols == matrix.cols, ExcDifferentChunkSparsityPatterns());
- // copy everything, including padding
- // elements
+ // copy everything, including padding elements
const unsigned int chunk_size = cols->get_chunk_size();
std::copy (&matrix.val[0],
&matrix.val[cols->sparsity_pattern.n_nonzero_elements()
Assert (val != 0, ExcNotInitialized());
Assert (cols == matrix.cols, ExcDifferentChunkSparsityPatterns());
- // add everything, including padding
- // elements
+ // add everything, including padding elements
const unsigned int chunk_size = cols->get_chunk_size();
number *val_ptr = &val[0];
const somenumber *matrix_ptr = &matrix.val[0];
Assert (!PointerComparison::equal(&src, &dst), ExcSourceEqualsDestination());
- // set the output vector to zero and then
- // add to it the contributions of vmults
- // from individual chunks. this is what
- // vmult_add does
+ // set the output vector to zero and then add to it the contributions of
+ // vmults from individual chunks. this is what vmult_add does
dst = 0;
vmult_add (dst, src);
}
Assert (!PointerComparison::equal(&src, &dst), ExcSourceEqualsDestination());
- // set the output vector to zero and then
- // add to it the contributions of vmults
- // from individual chunks. this is what
- // vmult_add does
+ // set the output vector to zero and then add to it the contributions of
+ // vmults from individual chunks. this is what vmult_add does
dst = 0;
Tvmult_add (dst, src);
}
Assert(n() == src.size(), ExcDimensionMismatch(n(),src.size()));
Assert (!PointerComparison::equal(&src, &dst), ExcSourceEqualsDestination());
+ parallel::apply_to_subranges (0U, cols->sparsity_pattern.n_rows(),
+ std_cxx1x::bind (&internal::ChunkSparseMatrix::vmult_add_on_subrange
+ <number,InVector,OutVector>,
+ std_cxx1x::cref(*cols),
+ std_cxx1x::_1, std_cxx1x::_2,
+ val,
+ cols->sparsity_pattern.rowstart,
+ cols->sparsity_pattern.colnums,
+ std_cxx1x::cref(src),
+ std_cxx1x::ref(dst)),
+ internal::SparseMatrix::minimum_parallel_grain_size/cols->chunk_size+1);
- const unsigned int n_chunk_rows = cols->sparsity_pattern.n_rows();
-
- // loop over all chunks. note that we need
- // to treat the last chunk row and column
- // differently if they have padding
- // elements
- const bool rows_have_padding = (m() % cols->chunk_size != 0),
- cols_have_padding = (n() % cols->chunk_size != 0);
-
- const unsigned int n_regular_chunk_rows
- = (rows_have_padding ?
- n_chunk_rows-1 :
- n_chunk_rows);
-
- const number *val_ptr = val;
- const unsigned int *colnum_ptr = cols->sparsity_pattern.colnums;
- typename OutVector::iterator dst_ptr = dst.begin();
-
- for (unsigned int chunk_row=0; chunk_row<n_regular_chunk_rows; ++chunk_row)
- {
- const number *const val_end_of_row = &val[cols->sparsity_pattern.rowstart[chunk_row+1]
- * cols->chunk_size
- * cols->chunk_size];
- while (val_ptr != val_end_of_row)
- {
- if ((cols_have_padding == false)
- ||
- (*colnum_ptr != cols->sparsity_pattern.n_cols()-1))
- internal::ChunkSparseMatrix::chunk_vmult_add
- (cols->chunk_size,
- val_ptr,
- src.begin() + *colnum_ptr * cols->chunk_size,
- dst_ptr);
- else
- // we're at a chunk column that
- // has padding
- for (unsigned int r=0; r<cols->chunk_size; ++r)
- for (unsigned int c=0; c<n() % cols->chunk_size; ++c)
- dst(chunk_row * cols->chunk_size + r)
- += (val_ptr[r*cols->chunk_size + c] *
- src(*colnum_ptr * cols->chunk_size + c));
-
- ++colnum_ptr;
- val_ptr += cols->chunk_size * cols->chunk_size;
- }
-
-
- dst_ptr += cols->chunk_size;
- }
-
- // now deal with last chunk row if
- // necessary
- if (rows_have_padding)
- {
- const unsigned int chunk_row = n_chunk_rows - 1;
-
- const number *const val_end_of_row = &val[cols->sparsity_pattern.rowstart[chunk_row+1]
- * cols->chunk_size
- * cols->chunk_size];
- while (val_ptr != val_end_of_row)
- {
- if ((cols_have_padding == false)
- ||
- (*colnum_ptr != cols->sparsity_pattern.n_cols()-1))
- {
- // we're at a chunk row but not
- // column that has padding
- for (unsigned int r=0; r<m() % cols->chunk_size; ++r)
- for (unsigned int c=0; c<cols->chunk_size; ++c)
- dst(chunk_row * cols->chunk_size + r)
- += (val_ptr[r*cols->chunk_size + c] *
- src(*colnum_ptr * cols->chunk_size + c));
- }
- else
- // we're at a chunk row and
- // column that has padding
- for (unsigned int r=0; r<m() % cols->chunk_size; ++r)
- for (unsigned int c=0; c<n() % cols->chunk_size; ++c)
- dst(chunk_row * cols->chunk_size + r)
- += (val_ptr[r*cols->chunk_size + c] *
- src(*colnum_ptr * cols->chunk_size + c));
-
- ++colnum_ptr;
- val_ptr += cols->chunk_size * cols->chunk_size;
- }
- }
}
const unsigned int n_chunk_rows = cols->sparsity_pattern.n_rows();
- // loop over all chunks. note that we need
- // to treat the last chunk row and column
- // differently if they have padding
- // elements
+ // loop over all chunks. note that we need to treat the last chunk row and
+ // column differently if they have padding elements
const bool rows_have_padding = (m() % cols->chunk_size != 0),
cols_have_padding = (n() % cols->chunk_size != 0);
n_chunk_rows-1 :
n_chunk_rows);
- // like in vmult_add, but don't keep an
- // iterator into dst around since we're not
- // traversing it sequentially this time
+ // like in vmult_add, but don't keep an iterator into dst around since we're
+ // not traversing it sequentially this time
const number *val_ptr = val;
const unsigned int *colnum_ptr = cols->sparsity_pattern.colnums;
src.begin() + chunk_row * cols->chunk_size,
dst.begin() + *colnum_ptr * cols->chunk_size);
else
- // we're at a chunk column that
- // has padding
+ // we're at a chunk column that has padding
for (unsigned int r=0; r<cols->chunk_size; ++r)
for (unsigned int c=0; c<n() % cols->chunk_size; ++c)
dst(*colnum_ptr * cols->chunk_size + c)
}
}
- // now deal with last chunk row if
- // necessary
+ // now deal with last chunk row if necessary
if (rows_have_padding)
{
const unsigned int chunk_row = n_chunk_rows - 1;
||
(*colnum_ptr != cols->sparsity_pattern.n_cols()-1))
{
- // we're at a chunk row but not
- // column that has padding
+ // we're at a chunk row but not column that has padding
for (unsigned int r=0; r<m() % cols->chunk_size; ++r)
for (unsigned int c=0; c<cols->chunk_size; ++c)
dst(*colnum_ptr * cols->chunk_size + c)
src(chunk_row * cols->chunk_size + r));
}
else
- // we're at a chunk row and
- // column that has padding
+ // we're at a chunk row and column that has padding
for (unsigned int r=0; r<m() % cols->chunk_size; ++r)
for (unsigned int c=0; c<n() % cols->chunk_size; ++c)
dst(*colnum_ptr * cols->chunk_size + c)
somenumber result = 0;
////////////////
- // like matrix_scalar_product, except that
- // the two vectors are now the same
+ // like matrix_scalar_product, except that the two vectors are now the same
const unsigned int n_chunk_rows = cols->sparsity_pattern.n_rows();
- // loop over all chunks. note that we need
- // to treat the last chunk row and column
- // differently if they have padding
- // elements
+ // loop over all chunks. note that we need to treat the last chunk row and
+ // column differently if they have padding elements
const bool rows_have_padding = (m() % cols->chunk_size != 0),
cols_have_padding = (n() % cols->chunk_size != 0);
v_ptr,
v.begin() + *colnum_ptr * cols->chunk_size);
else
- // we're at a chunk column that
- // has padding
+ // we're at a chunk column that has padding
for (unsigned int r=0; r<cols->chunk_size; ++r)
for (unsigned int c=0; c<n() % cols->chunk_size; ++c)
result
v_ptr += cols->chunk_size;
}
- // now deal with last chunk row if
- // necessary
+ // now deal with last chunk row if necessary
if (rows_have_padding)
{
const unsigned int chunk_row = n_chunk_rows - 1;
||
(*colnum_ptr != cols->sparsity_pattern.n_cols()-1))
{
- // we're at a chunk row but not
- // column that has padding
+ // we're at a chunk row but not column that has padding
for (unsigned int r=0; r<m() % cols->chunk_size; ++r)
for (unsigned int c=0; c<cols->chunk_size; ++c)
result
v(*colnum_ptr * cols->chunk_size + c));
}
else
- // we're at a chunk row and
- // column that has padding
+ // we're at a chunk row and column that has padding
for (unsigned int r=0; r<m() % cols->chunk_size; ++r)
for (unsigned int c=0; c<n() % cols->chunk_size; ++c)
result
Assert(m() == u.size(), ExcDimensionMismatch(m(),u.size()));
Assert(n() == v.size(), ExcDimensionMismatch(n(),v.size()));
- // the following works like the vmult_add
- // function
+ // the following works like the vmult_add function
somenumber result = 0;
const unsigned int n_chunk_rows = cols->sparsity_pattern.n_rows();
- // loop over all chunks. note that we need
- // to treat the last chunk row and column
- // differently if they have padding
- // elements
+ // loop over all chunks. note that we need to treat the last chunk row and
+ // column differently if they have padding elements
const bool rows_have_padding = (m() % cols->chunk_size != 0),
cols_have_padding = (n() % cols->chunk_size != 0);
u_ptr,
v.begin() + *colnum_ptr * cols->chunk_size);
else
- // we're at a chunk column that
- // has padding
+ // we're at a chunk column that has padding
for (unsigned int r=0; r<cols->chunk_size; ++r)
for (unsigned int c=0; c<n() % cols->chunk_size; ++c)
result
u_ptr += cols->chunk_size;
}
- // now deal with last chunk row if
- // necessary
+ // now deal with last chunk row if necessary
if (rows_have_padding)
{
const unsigned int chunk_row = n_chunk_rows - 1;
||
(*colnum_ptr != cols->sparsity_pattern.n_cols()-1))
{
- // we're at a chunk row but not
- // column that has padding
+ // we're at a chunk row but not column that has padding
for (unsigned int r=0; r<m() % cols->chunk_size; ++r)
for (unsigned int c=0; c<cols->chunk_size; ++c)
result
v(*colnum_ptr * cols->chunk_size + c));
}
else
- // we're at a chunk row and
- // column that has padding
+ // we're at a chunk row and column that has padding
for (unsigned int r=0; r<m() % cols->chunk_size; ++r)
for (unsigned int c=0; c<n() % cols->chunk_size; ++c)
result
const unsigned int n_chunk_rows = cols->sparsity_pattern.n_rows();
- // loop over all rows and columns; it is
- // safe to also loop over the padding
- // elements (they are zero) if we make sure
- // that the vector into which we sum column
- // sums is large enough
+ // loop over all rows and columns; it is safe to also loop over the padding
+ // elements (they are zero) if we make sure that the vector into which we
+ // sum column sums is large enough
Vector<real_type> column_sums(cols->sparsity_pattern.n_cols() *
cols->chunk_size);
Assert (cols != 0, ExcNotInitialized());
Assert (val != 0, ExcNotInitialized());
- // this function works like l1_norm(). it
- // can be made more efficient (without
- // allocating a temporary vector) as is
- // done in the SparseMatrix class but since
- // it is rarely called in time critical
- // places it is probably not worth it
+ // this function works like l1_norm(). it can be made more efficient
+ // (without allocating a temporary vector) as is done in the SparseMatrix
+ // class but since it is rarely called in time critical places it is
+ // probably not worth it
const unsigned int n_chunk_rows = cols->sparsity_pattern.n_rows();
- // loop over all rows and columns; it is
- // safe to also loop over the padding
- // elements (they are zero) if we make sure
- // that the vector into which we sum column
- // sums is large enough
+ // loop over all rows and columns; it is safe to also loop over the padding
+ // elements (they are zero) if we make sure that the vector into which we
+ // sum column sums is large enough
Vector<real_type> row_sums(cols->sparsity_pattern.n_rows() *
cols->chunk_size);
typename ChunkSparseMatrix<number>::real_type
ChunkSparseMatrix<number>::frobenius_norm () const
{
- // simply add up all entries in the
- // sparsity pattern, without taking any
+ // simply add up all entries in the sparsity pattern, without taking any
// reference to rows or columns
//
- // padding elements are zero, so we can add
- // them up as well
+ // padding elements are zero, so we can add them up as well
real_type norm_sqr = 0;
for (const number *ptr = &val[0]; ptr != &val[max_len]; ++ptr)
norm_sqr += numbers::NumberTraits<number>::abs_square(*ptr);
Assert (&u != &dst, ExcSourceEqualsDestination());
- // set dst=b, then subtract the result of
- // A*u from it. since the purpose of the
- // current class is to promote streaming of
- // data rather than more random access
- // patterns, breaking things up into two
- // loops may be reasonable
+ // set dst=b, then subtract the result of A*u from it. since the purpose of
+ // the current class is to promote streaming of data rather than more random
+ // access patterns, breaking things up into two loops may be reasonable
dst = b;
/////////
- // the rest of this function is like
- // vmult_add, except that we subtract
+ // the rest of this function is like vmult_add, except that we subtract
// rather than add A*u
/////////
const unsigned int n_chunk_rows = cols->sparsity_pattern.n_rows();
- // loop over all chunks. note that we need
- // to treat the last chunk row and column
- // differently if they have padding
- // elements
+ // loop over all chunks. note that we need to treat the last chunk row and
+ // column differently if they have padding elements
const bool rows_have_padding = (m() % cols->chunk_size != 0),
cols_have_padding = (n() % cols->chunk_size != 0);
u.begin() + *colnum_ptr * cols->chunk_size,
dst_ptr);
else
- // we're at a chunk column that
- // has padding
+ // we're at a chunk column that has padding
for (unsigned int r=0; r<cols->chunk_size; ++r)
for (unsigned int c=0; c<n() % cols->chunk_size; ++c)
dst(chunk_row * cols->chunk_size + r)
dst_ptr += cols->chunk_size;
}
- // now deal with last chunk row if
- // necessary
+ // now deal with last chunk row if necessary
if (rows_have_padding)
{
const unsigned int chunk_row = n_chunk_rows - 1;
||
(*colnum_ptr != cols->sparsity_pattern.n_cols()-1))
{
- // we're at a chunk row but not
- // column that has padding
+ // we're at a chunk row but not column that has padding
for (unsigned int r=0; r<m() % cols->chunk_size; ++r)
for (unsigned int c=0; c<cols->chunk_size; ++c)
dst(chunk_row * cols->chunk_size + r)
u(*colnum_ptr * cols->chunk_size + c));
}
else
- // we're at a chunk row and
- // column that has padding
+ // we're at a chunk row and column that has padding
for (unsigned int r=0; r<m() % cols->chunk_size; ++r)
for (unsigned int c=0; c<n() % cols->chunk_size; ++c)
dst(chunk_row * cols->chunk_size + r)
const Vector<somenumber> &src,
const number /*om*/) const
{
- // to understand how this function works
- // you may want to take a look at the CVS
- // archives to see the original version
- // which is much clearer...
+ // to understand how this function works you may want to take a look at the
+ // CVS archives to see the original version which is much clearer...
Assert (cols != 0, ExcNotInitialized());
Assert (val != 0, ExcNotInitialized());
Assert (m() == n(), ExcMessage("This operation is only valid on square matrices."));
-template <typename number>
-const ChunkSparsityPattern &
-ChunkSparseMatrix<number>::get_sparsity_pattern () const
-{
- Assert (cols != 0, ExcNotInitialized());
- return *cols;
-}
-
-
-
template <typename number>
void ChunkSparseMatrix<number>::print (std::ostream &out) const
{
const unsigned int chunk_size = cols->get_chunk_size();
- // loop over all chunk rows and columns,
- // and each time we find something repeat
- // it chunk_size times in both directions
+ // loop over all chunk rows and columns, and each time we find something
+ // repeat it chunk_size times in both directions
for (unsigned int i=0; i<cols->sparsity_pattern.n_rows(); ++i)
{
for (unsigned int d=0; d<chunk_size; ++d)
{
AssertThrow (out, ExcIO());
- // first the simple objects,
- // bracketed in [...]
+ // first the simple objects, bracketed in [...]
out << '[' << max_len << "][";
// then write out real data
out.write (reinterpret_cast<const char *>(&val[0]),
*/
+
+/**
+ * Iterators on sparsity patterns
+ */
+namespace ChunkSparsityPatternIterators
+{
+ // forward declaration
+ class Iterator;
+
+ /**
+ * Accessor class for iterators into sparsity patterns. This class is
+ * also the base class for both const and non-const accessor classes
+ * into sparse matrices.
+ *
+ * Note that this class only allows read access to elements, providing
+ * their row and column number. It does not allow modifying the
+ * sparsity pattern itself.
+ *
+ * @author Martin Kronbichler
+ * @date 2013
+ */
+ class Accessor
+ {
+ public:
+ /**
+ * Constructor.
+ */
+ Accessor (const ChunkSparsityPattern *matrix,
+ const unsigned int row);
+
+ /**
+ * Constructor. Construct the end accessor for the given sparsity pattern.
+ */
+ Accessor (const ChunkSparsityPattern *matrix);
+
+ /**
+ * Row number of the element represented by this object. This function can
+ * only be called for entries for which is_valid_entry() is true.
+ */
+ unsigned int row () const;
+
+ /**
+ * Returns the global index from the reduced sparsity pattern.
+ */
+ std::size_t reduced_index() const;
+
+ /**
+ * Column number of the element represented by this object. This function
+ * can only be called for entries for which is_valid_entry() is true.
+ */
+ unsigned int column () const;
+
+ /**
+ * Return whether the sparsity pattern entry pointed to by this iterator
+ * is valid or not. Note that after compressing the sparsity pattern, all
+ * entries are valid. However, before compression, the sparsity pattern
+ * allocated some memory to be used while still adding new nonzero
+ * entries; if you create iterators in this phase of the sparsity
+ * pattern's lifetime, you will iterate over elements that are not
+ * valid. If this is so, then this function will return false.
+ */
+ bool is_valid_entry () const;
+
+
+ /**
+ * Comparison. True, if both iterators point to the same matrix position.
+ */
+ bool operator == (const Accessor &) const;
+
+
+ /**
+ * Comparison operator. Result is true if either the first row number is
+ * smaller or if the row numbers are equal and the first index is smaller.
+ *
+ * This function is only valid if both iterators point into the same
+ * sparsity pattern.
+ */
+ bool operator < (const Accessor &) const;
+
+ protected:
+ /**
+ * The sparsity pattern we operate on accessed.
+ */
+ const ChunkSparsityPattern *sparsity_pattern;
+
+ /**
+ * The accessor of the (reduced) sparsity pattern.
+ */
+ SparsityPatternIterators::Accessor reduced_accessor;
+
+ /**
+ * Current chunk row number.
+ */
+ unsigned int chunk_row;
+
+ /**
+ * Current chunk col number.
+ */
+ unsigned int chunk_col;
+
+ /**
+ * Move the accessor to the next nonzero entry in the matrix.
+ */
+ void advance ();
+
+ /**
+ * Grant access to iterator class.
+ */
+ friend class Iterator;
+ };
+
+
+
+ /**
+ * STL conforming iterator walking over the elements of a sparsity pattern.
+ */
+ class Iterator
+ {
+ public:
+ /**
+ * Constructor. Create an iterator into the sparsity pattern @p sp for the
+ * given row and the index within it.
+ */
+ Iterator (const ChunkSparsityPattern *sp,
+ const unsigned int row);
+
+ /**
+ * Prefix increment.
+ */
+ Iterator &operator++ ();
+
+ /**
+ * Postfix increment.
+ */
+ Iterator operator++ (int);
+
+ /**
+ * Dereferencing operator.
+ */
+ const Accessor &operator* () const;
+
+ /**
+ * Dereferencing operator.
+ */
+ const Accessor *operator-> () const;
+
+ /**
+ * Comparison. True, if both iterators point to the same matrix position.
+ */
+ bool operator == (const Iterator &) const;
+
+ /**
+ * Inverse of <tt>==</tt>.
+ */
+ bool operator != (const Iterator &) const;
+
+ /**
+ * Comparison operator. Result is true if either the first row number is
+ * smaller or if the row numbers are equal and the first index is smaller.
+ *
+ * This function is only valid if both iterators point into the same
+ * matrix.
+ */
+ bool operator < (const Iterator &) const;
+
+ private:
+ /**
+ * Store an object of the accessor class.
+ */
+ Accessor accessor;
+ };
+}
+
+
+
/**
* Structure representing the sparsity pattern of a sparse matrix.
*
class ChunkSparsityPattern : public Subscriptor
{
public:
+ /**
+ * Typedef an iterator class that allows to walk over all nonzero elements
+ * of a sparsity pattern.
+ */
+ typedef ChunkSparsityPatternIterators::Iterator const_iterator;
+
+ /**
+ * Typedef an iterator class that allows to walk over all nonzero elements
+ * of a sparsity pattern.
+ *
+ * Since the iterator does not allow to modify the sparsity pattern, this
+ * type is the same as that for @p const_iterator.
+ */
+ typedef ChunkSparsityPatternIterators::Iterator iterator;
/**
- * Define a value which is used
- * to indicate that a certain
- * value in the colnums array
- * is unused, i.e. does not
- * represent a certain column
- * number index.
+ * Define a value which is used to indicate that a certain value in the
+ * colnums array is unused, i.e. does not represent a certain column number
+ * index.
*
- * Indices with this invalid
- * value are used to insert new
- * entries to the sparsity
- * pattern using the add() member
- * function, and are removed when
+ * Indices with this invalid value are used to insert new entries to the
+ * sparsity pattern using the add() member function, and are removed when
* calling compress().
*
- * You should not assume that the
- * variable declared here has a
- * certain value. The
- * initialization is given here
- * only to enable the compiler to
- * perform some optimizations,
- * but the actual value of the
- * variable may change over time.
+ * You should not assume that the variable declared here has a certain
+ * value. The initialization is given here only to enable the compiler to
+ * perform some optimizations, but the actual value of the variable may
+ * change over time.
*/
static const unsigned int invalid_entry = SparsityPattern::invalid_entry;
/**
- * Initialize the matrix empty,
- * that is with no memory
- * allocated. This is useful if
- * you want such objects as
- * member variables in other
- * classes. You can make the
- * structure usable by calling
- * the reinit() function.
+ * Initialize the matrix empty, that is with no memory allocated. This is
+ * useful if you want such objects as member variables in other classes. You
+ * can make the structure usable by calling the reinit() function.
*/
ChunkSparsityPattern ();
/**
- * Copy constructor. This
- * constructor is only allowed to
- * be called if the matrix
- * structure to be copied is
- * empty. This is so in order to
- * prevent involuntary copies of
- * objects for temporaries, which
- * can use large amounts of
- * computing time. However, copy
- * constructors are needed if yo
- * want to use the STL data types
- * on classes like this, e.g. to
- * write such statements like
- * <tt>v.push_back
- * (ChunkSparsityPattern());</tt>,
- * with <tt>v</tt> a vector of
- * ChunkSparsityPattern objects.
- *
- * Usually, it is sufficient to
- * use the explicit keyword to
- * disallow unwanted temporaries,
- * but for the STL vectors, this
- * does not work. Since copying a
- * structure like this is not
- * useful anyway because multiple
- * matrices can use the same
- * sparsity structure, copies are
- * only allowed for empty
- * objects, as described above.
+ * Copy constructor. This constructor is only allowed to be called if the
+ * matrix structure to be copied is empty. This is so in order to prevent
+ * involuntary copies of objects for temporaries, which can use large
+ * amounts of computing time. However, copy constructors are needed if yo
+ * want to use the STL data types on classes like this, e.g. to write such
+ * statements like <tt>v.push_back (ChunkSparsityPattern());</tt>, with
+ * <tt>v</tt> a vector of ChunkSparsityPattern objects.
+ *
+ * Usually, it is sufficient to use the explicit keyword to disallow
+ * unwanted temporaries, but for the STL vectors, this does not work. Since
+ * copying a structure like this is not useful anyway because multiple
+ * matrices can use the same sparsity structure, copies are only allowed for
+ * empty objects, as described above.
*/
ChunkSparsityPattern (const ChunkSparsityPattern &);
/**
- * Initialize a rectangular
- * matrix.
+ * Initialize a rectangular matrix.
*
* @arg m number of rows
* @arg n number of columns
- * @arg max_per_row maximum
- * number of nonzero entries per row
+ * @arg max_per_row maximum number of nonzero entries per row
*/
ChunkSparsityPattern (const unsigned int m,
const unsigned int n,
const bool optimize_diagonal) DEAL_II_DEPRECATED;
/**
- * Initialize a rectangular
- * matrix.
+ * Initialize a rectangular matrix.
*
* @arg m number of rows
* @arg n number of columns
- *
- * @arg row_lengths possible
- * number of nonzero entries for
- * each row. This vector must
- * have one entry for each row.
+ * @arg row_lengths possible number of nonzero entries for each row. This
+ * vector must have one entry for each row.
*/
ChunkSparsityPattern (const unsigned int m,
const unsigned int n,
const bool optimize_diagonal) DEAL_II_DEPRECATED;
/**
- * Initialize a quadratic matrix
- * of dimension <tt>n</tt> with
- * at most <tt>max_per_row</tt>
- * nonzero entries per row.
+ * Initialize a quadratic matrix of dimension <tt>n</tt> with at most
+ * <tt>max_per_row</tt> nonzero entries per row.
*
- * This constructor automatically
- * enables optimized storage of
- * diagonal elements. To avoid
- * this, use the constructor
- * taking row and column numbers
- * separately.
+ * This constructor automatically enables optimized storage of diagonal
+ * elements. To avoid this, use the constructor taking row and column
+ * numbers separately.
*/
ChunkSparsityPattern (const unsigned int n,
const unsigned int max_per_row,
* Initialize a quadratic matrix.
*
* @arg m number of rows and columns
- *
- * @arg row_lengths possible
- * number of nonzero entries for
- * each row. This vector must
- * have one entry for each row.
+ * @arg row_lengths possible number of nonzero entries for each row. This
+ * vector must have one entry for each row.
*/
ChunkSparsityPattern (const unsigned int m,
const std::vector<unsigned int> &row_lengths,
~ChunkSparsityPattern ();
/**
- * Copy operator. For this the
- * same holds as for the copy
- * constructor: it is declared,
- * defined and fine to be called,
- * but the latter only for empty
+ * Copy operator. For this the same holds as for the copy constructor: it is
+ * declared, defined and fine to be called, but the latter only for empty
* objects.
*/
ChunkSparsityPattern &operator = (const ChunkSparsityPattern &);
/**
- * Reallocate memory and set up data
- * structures for a new matrix with
- * <tt>m </tt>rows and <tt>n</tt> columns,
- * with at most <tt>max_per_row</tt>
+ * Reallocate memory and set up data structures for a new matrix with <tt>m
+ * </tt>rows and <tt>n</tt> columns, with at most <tt>max_per_row</tt>
* nonzero entries per row.
*
- * This function simply maps its
- * operations to the other
- * <tt>reinit</tt> function.
+ * This function simply maps its operations to the other <tt>reinit</tt>
+ * function.
*/
void reinit (const unsigned int m,
const unsigned int n,
const bool optimize_diagonal) DEAL_II_DEPRECATED;
/**
- * Reallocate memory for a matrix
- * of size <tt>m x n</tt>. The
- * number of entries for each row
- * is taken from the array
- * <tt>row_lengths</tt> which has to
- * give this number of each row
- * <tt>i=1...m</tt>.
+ * Reallocate memory for a matrix of size <tt>m x n</tt>. The number of
+ * entries for each row is taken from the array <tt>row_lengths</tt> which
+ * has to give this number of each row <tt>i=1...m</tt>.
*
- * If <tt>m*n==0</tt> all memory is freed,
- * resulting in a total reinitialization
- * of the object. If it is nonzero, new
- * memory is only allocated if the new
- * size extends the old one. This is done
- * to save time and to avoid fragmentation
- * of the heap.
+ * If <tt>m*n==0</tt> all memory is freed, resulting in a total
+ * reinitialization of the object. If it is nonzero, new memory is only
+ * allocated if the new size extends the old one. This is done to save time
+ * and to avoid fragmentation of the heap.
*
* If the number of rows equals
* the number of columns then
const bool optimize_diagonal) DEAL_II_DEPRECATED;
/**
- * Same as above, but with a
- * VectorSlice argument instead.
+ * Same as above, but with a VectorSlice argument instead.
*/
void reinit (const unsigned int m,
const unsigned int n,
const bool optimize_diagonal) DEAL_II_DEPRECATED;
/**
- * This function compresses the sparsity
- * structure that this object represents.
- * It does so by eliminating unused
- * entries and sorting the remaining ones
- * to allow faster access by usage of
- * binary search algorithms. A special
- * sorting scheme is used for the
- * diagonal entry of quadratic matrices,
- * which is always the first entry of
- * each row.
+ * This function compresses the sparsity structure that this object
+ * represents. It does so by eliminating unused entries and sorting the
+ * remaining ones to allow faster access by usage of binary search
+ * algorithms. A special sorting scheme is used for the diagonal entry of
+ * quadratic matrices, which is always the first entry of each row.
*
- * The memory which is no more
- * needed is released.
+ * The memory which is no more needed is released.
*
- * SparseMatrix objects require the
- * ChunkSparsityPattern objects they are
- * initialized with to be compressed, to
- * reduce memory requirements.
+ * SparseMatrix objects require the ChunkSparsityPattern objects they are
+ * initialized with to be compressed, to reduce memory requirements.
*/
void compress ();
/**
- * This function can be used as a
- * replacement for reinit(),
- * subsequent calls to add() and
- * a final call to close() if you
- * know exactly in advance the
- * entries that will form the
- * matrix sparsity pattern.
- *
- * The first two parameters
- * determine the size of the
- * matrix. For the two last ones,
- * note that a sparse matrix can
- * be described by a sequence of
- * rows, each of which is
- * represented by a sequence of
- * pairs of column indices and
- * values. In the present
- * context, the begin() and
- * end() parameters designate
- * iterators (of forward iterator
- * type) into a container, one
- * representing one row. The
- * distance between begin()
- * and end() should therefore
- * be equal to
- * n_rows(). These iterators
- * may be iterators of
- * <tt>std::vector</tt>,
- * <tt>std::list</tt>, pointers into a
- * C-style array, or any other
- * iterator satisfying the
- * requirements of a forward
- * iterator. The objects pointed
- * to by these iterators
- * (i.e. what we get after
- * applying <tt>operator*</tt> or
- * <tt>operator-></tt> to one of these
- * iterators) must be a container
- * itself that provides functions
- * <tt>begin</tt> and <tt>end</tt>
- * designating a range of
- * iterators that describe the
- * contents of one
- * line. Dereferencing these
- * inner iterators must either
- * yield a pair of an unsigned
- * integer as column index and a
- * value of arbitrary type (such
- * a type would be used if we
- * wanted to describe a sparse
- * matrix with one such object),
- * or simply an unsigned integer
- * (of we only wanted to describe
- * a sparsity pattern). The
- * function is able to determine
- * itself whether an unsigned
- * integer or a pair is what we
- * get after dereferencing the
- * inner iterators, through some
- * template magic.
- *
- * While the order of the outer
- * iterators denotes the
- * different rows of the matrix,
- * the order of the inner
- * iterator denoting the columns
- * does not matter, as they are
- * sorted internal to this
- * function anyway.
- *
- * Since that all sounds very
- * complicated, consider the
- * following example code, which
- * may be used to fill a sparsity
- * pattern:
+ * This function can be used as a replacement for reinit(), subsequent calls
+ * to add() and a final call to close() if you know exactly in advance the
+ * entries that will form the matrix sparsity pattern.
+ *
+ * The first two parameters determine the size of the matrix. For the two
+ * last ones, note that a sparse matrix can be described by a sequence of
+ * rows, each of which is represented by a sequence of pairs of column
+ * indices and values. In the present context, the begin() and end()
+ * parameters designate iterators (of forward iterator type) into a
+ * container, one representing one row. The distance between begin() and
+ * end() should therefore be equal to n_rows(). These iterators may be
+ * iterators of <tt>std::vector</tt>, <tt>std::list</tt>, pointers into a
+ * C-style array, or any other iterator satisfying the requirements of a
+ * forward iterator. The objects pointed to by these iterators (i.e. what we
+ * get after applying <tt>operator*</tt> or <tt>operator-></tt> to one of
+ * these iterators) must be a container itself that provides functions
+ * <tt>begin</tt> and <tt>end</tt> designating a range of iterators that
+ * describe the contents of one line. Dereferencing these inner iterators
+ * must either yield a pair of an unsigned integer as column index and a
+ * value of arbitrary type (such a type would be used if we wanted to
+ * describe a sparse matrix with one such object), or simply an unsigned
+ * integer (of we only wanted to describe a sparsity pattern). The function
+ * is able to determine itself whether an unsigned integer or a pair is what
+ * we get after dereferencing the inner iterators, through some template
+ * magic.
+ *
+ * While the order of the outer iterators denotes the different rows of the
+ * matrix, the order of the inner iterator denoting the columns does not
+ * matter, as they are sorted internal to this function anyway.
+ *
+ * Since that all sounds very complicated, consider the following example
+ * code, which may be used to fill a sparsity pattern:
* @code
* std::vector<std::vector<unsigned int> > column_indices (n_rows);
* for (unsigned int row=0; row<n_rows; ++row)
* column_indices.end());
* @endcode
*
- * Note that this example works
- * since the iterators
- * dereferenced yield containers
- * with functions <tt>begin</tt> and
- * <tt>end</tt> (namely
- * <tt>std::vector</tt>s), and the
- * inner iterators dereferenced
- * yield unsigned integers as
- * column indices. Note that we
- * could have replaced each of
- * the two <tt>std::vector</tt>
- * occurrences by <tt>std::list</tt>,
- * and the inner one by
- * <tt>std::set</tt> as well.
- *
- * Another example would be as
- * follows, where we initialize a
- * whole matrix, not only a
- * sparsity pattern:
+ * Note that this example works since the iterators dereferenced yield
+ * containers with functions <tt>begin</tt> and <tt>end</tt> (namely
+ * <tt>std::vector</tt>s), and the inner iterators dereferenced yield
+ * unsigned integers as column indices. Note that we could have replaced
+ * each of the two <tt>std::vector</tt> occurrences by <tt>std::list</tt>,
+ * and the inner one by <tt>std::set</tt> as well.
+ *
+ * Another example would be as follows, where we initialize a whole matrix,
+ * not only a sparsity pattern:
* @code
* std::vector<std::map<unsigned int,double> > entries (n_rows);
* for (unsigned int row=0; row<n_rows; ++row)
* column_indices.end());
* @endcode
*
- * This example works because
- * dereferencing iterators of the
- * inner type yields a pair of
- * unsigned integers and a value,
- * the first of which we take as
- * column index. As previously,
- * the outer <tt>std::vector</tt>
- * could be replaced by
- * <tt>std::list</tt>, and the inner
- * <tt>std::map<unsigned int,double></tt>
- * could be replaced by
- * <tt>std::vector<std::pair<unsigned int,double> ></tt>,
- * or a list or set of such
- * pairs, as they all return
- * iterators that point to such
- * pairs.
+ * This example works because dereferencing iterators of the inner type
+ * yields a pair of unsigned integers and a value, the first of which we
+ * take as column index. As previously, the outer <tt>std::vector</tt> could
+ * be replaced by <tt>std::list</tt>, and the inner <tt>std::map<unsigned
+ * int,double></tt> could be replaced by <tt>std::vector<std::pair<unsigned
+ * int,double> ></tt>, or a list or set of such pairs, as they all return
+ * iterators that point to such pairs.
*/
template <typename ForwardIterator>
void copy_from (const unsigned int n_rows,
const bool optimize_diagonal) DEAL_II_DEPRECATED;
/**
- * Copy data from an object of type
- * CompressedSparsityPattern,
- * CompressedSetSparsityPattern or
- * CompressedSimpleSparsityPattern.
- * Previous content of this object is
- * lost, and the sparsity pattern is in
+ * Copy data from an object of type CompressedSparsityPattern,
+ * CompressedSetSparsityPattern or CompressedSimpleSparsityPattern.
+ * Previous content of this object is lost, and the sparsity pattern is in
* compressed mode afterwards.
*/
template <typename SparsityType>
const bool optimize_diagonal) DEAL_II_DEPRECATED;
/**
- * Take a full matrix and use its
- * nonzero entries to generate a
- * sparse matrix entry pattern
- * for this object.
+ * Take a full matrix and use its nonzero entries to generate a sparse
+ * matrix entry pattern for this object.
*
- * Previous content of this
- * object is lost, and the
- * sparsity pattern is in
+ * Previous content of this object is lost, and the sparsity pattern is in
* compressed mode afterwards.
*/
template <typename number>
const bool optimize_diagonal) DEAL_II_DEPRECATED;
/**
- * Return whether the object is empty. It
- * is empty if no memory is allocated,
- * which is the same as that both
- * dimensions are zero.
+ * Set the sparsity pattern of the chunk sparsity pattern to be given by
+ * <tt>chunk_size*chunksize</tt> blocks of the sparsity pattern for chunks
+ * specified. Note that the final number of rows <tt>m</tt> of the sparsity
+ * pattern will be approximately <tt>sparsity_pattern_for_chunks.n_rows() *
+ * chunk_size</tt> (modulo padding elements in the last chunk) and similarly
+ * for the number of columns <tt>n</tt>.
+ *
+ * This is a special initialization option in case you can tell the position
+ * of the chunk already from the beginning without generating the sparsity
+ * pattern using <tt>make_sparsity_pattern</tt> calls. This bypasses the
+ * search for chunks but of course needs to be handled with care in order to
+ * give a correct sparsity pattern.
+ *
+ * Previous content of this object is lost, and the sparsity pattern is in
+ * compressed mode afterwards.
+ */
+ template <typename Sparsity>
+ void create_from (const unsigned int m,
+ const unsigned int n,
+ const Sparsity &sparsity_pattern_for_chunks,
+ const unsigned int chunk_size,
+ const bool optimize_diagonal = true);
+
+ /**
+ * Return whether the object is empty. It is empty if no memory is
+ * allocated, which is the same as that both dimensions are zero.
*/
bool empty () const;
/**
- * Return the chunk size given as
- * argument when constructing this
- * object.
+ * Return the chunk size given as argument when constructing this object.
*/
unsigned int get_chunk_size () const;
/**
- * Return the maximum number of entries per
- * row. Before compression, this equals the
- * number given to the constructor, while
- * after compression, it equals the maximum
- * number of entries actually allocated by
- * the user.
+ * Return the maximum number of entries per row. Before compression, this
+ * equals the number given to the constructor, while after compression, it
+ * equals the maximum number of entries actually allocated by the user.
*/
unsigned int max_entries_per_row () const;
/**
- * Add a nonzero entry to the matrix.
- * This function may only be called
- * for non-compressed sparsity patterns.
+ * Add a nonzero entry to the matrix. This function may only be called for
+ * non-compressed sparsity patterns.
*
- * If the entry already exists, nothing
- * bad happens.
+ * If the entry already exists, nothing bad happens.
*/
void add (const unsigned int i,
const unsigned int j);
/**
- * Make the sparsity pattern
- * symmetric by adding the
- * sparsity pattern of the
+ * Make the sparsity pattern symmetric by adding the sparsity pattern of the
* transpose object.
*
- * This function throws an
- * exception if the sparsity
- * pattern does not represent a
- * quadratic matrix.
+ * This function throws an exception if the sparsity pattern does not
+ * represent a quadratic matrix.
*/
void symmetrize ();
/**
- * Return number of rows of this
- * matrix, which equals the dimension
- * of the image space.
+ * Return number of rows of this matrix, which equals the dimension of the
+ * image space.
*/
- inline unsigned int n_rows () const;
+ unsigned int n_rows () const;
/**
- * Return number of columns of this
- * matrix, which equals the dimension
- * of the range space.
+ * Return number of columns of this matrix, which equals the dimension of
+ * the range space.
*/
- inline unsigned int n_cols () const;
+ unsigned int n_cols () const;
/**
- * Check if a value at a certain
- * position may be non-zero.
+ * Check if a value at a certain position may be non-zero.
*/
bool exists (const unsigned int i,
const unsigned int j) const;
unsigned int row_length (const unsigned int row) const;
/**
- * Compute the bandwidth of the matrix
- * represented by this structure. The
- * bandwidth is the maximum of $|i-j|$
- * for which the index pair $(i,j)$
- * represents a nonzero entry of the
- * matrix. Consequently, the maximum
- * bandwidth a $n\times m$ matrix can
- * have is $\max\{n-1,m-1\}$.
+ * Compute the bandwidth of the matrix represented by this structure. The
+ * bandwidth is the maximum of $|i-j|$ for which the index pair $(i,j)$
+ * represents a nonzero entry of the matrix. Consequently, the maximum
+ * bandwidth a $n\times m$ matrix can have is $\max\{n-1,m-1\}$.
*/
unsigned int bandwidth () const;
/**
- * Return the number of nonzero elements of
- * this matrix. Actually, it returns the
- * number of entries in the sparsity
- * pattern; if any of the entries should
- * happen to be zero, it is counted
- * anyway.
+ * Return the number of nonzero elements of this matrix. Actually, it
+ * returns the number of entries in the sparsity pattern; if any of the
+ * entries should happen to be zero, it is counted anyway.
*
- * This function may only be called if the
- * matrix struct is compressed. It does not
- * make too much sense otherwise anyway.
+ * This function may only be called if the matrix struct is compressed. It
+ * does not make too much sense otherwise anyway.
*/
unsigned int n_nonzero_elements () const;
/**
- * Return whether the structure is
- * compressed or not.
+ * Return whether the structure is compressed or not.
*/
bool is_compressed () const;
bool stores_only_added_elements () const;
/**
- * Write the data of this object
- * en bloc to a file. This is
- * done in a binary mode, so the
- * output is neither readable by
- * humans nor (probably) by other
- * computers using a different
- * operating system of number
- * format.
- *
- * The purpose of this function
- * is that you can swap out
- * matrices and sparsity pattern
- * if you are short of memory,
- * want to communicate between
- * different programs, or allow
- * objects to be persistent
- * across different runs of the
- * program.
+ * STL-like iterator with the first entry of the matrix. The resulting
+ * iterator can be used to walk over all nonzero entries of the sparsity
+ * pattern.
+ */
+ iterator begin () const;
+
+ /**
+ * Final iterator.
+ */
+ iterator end () const;
+
+ /**
+ * STL-like iterator with the first entry of row <tt>r</tt>.
+ *
+ * Note that if the given row is empty, i.e. does not contain any nonzero
+ * entries, then the iterator returned by this function equals
+ * <tt>end(r)</tt>. Note also that the iterator may not be dereferencable in
+ * that case.
+ */
+ iterator begin (const unsigned int r) const;
+
+ /**
+ * Final iterator of row <tt>r</tt>. It points to the first element past the
+ * end of line @p r, or past the end of the entire sparsity pattern.
+ *
+ * Note that the end iterator is not necessarily dereferencable. This is in
+ * particular the case if it is the end iterator for the last row of a
+ * matrix.
+ */
+ iterator end (const unsigned int r) const;
+
+ /**
+ * Write the data of this object en bloc to a file. This is done in a binary
+ * mode, so the output is neither readable by humans nor (probably) by other
+ * computers using a different operating system of number format.
+ *
+ * The purpose of this function is that you can swap out matrices and
+ * sparsity pattern if you are short of memory, want to communicate between
+ * different programs, or allow objects to be persistent across different
+ * runs of the program.
*/
void block_write (std::ostream &out) const;
/**
- * Read data that has previously
- * been written by block_write()
- * from a file. This is done
- * using the inverse operations
- * to the above function, so it
- * is reasonably fast because the
- * bitstream is not interpreted
- * except for a few numbers up
- * front.
- *
- * The object is resized on this
- * operation, and all previous
- * contents are lost.
- *
- * A primitive form of error
- * checking is performed which
- * will recognize the bluntest
- * attempts to interpret some
- * data as a vector stored
- * bitwise to a file, but not
- * more.
+ * Read data that has previously been written by block_write() from a
+ * file. This is done using the inverse operations to the above function, so
+ * it is reasonably fast because the bitstream is not interpreted except for
+ * a few numbers up front.
+ *
+ * The object is resized on this operation, and all previous contents are
+ * lost.
+ *
+ * A primitive form of error checking is performed which will recognize the
+ * bluntest attempts to interpret some data as a vector stored bitwise to a
+ * file, but not more.
*/
void block_read (std::istream &in);
/**
- * Print the sparsity of the
- * matrix. The output consists of
- * one line per row of the format
- * <tt>[i,j1,j2,j3,...]</tt>. <i>i</i>
- * is the row number and
- * <i>jn</i> are the allocated
- * columns in this row.
+ * Print the sparsity of the matrix. The output consists of one line per row
+ * of the format <tt>[i,j1,j2,j3,...]</tt>. <i>i</i> is the row number and
+ * <i>jn</i> are the allocated columns in this row.
*/
void print (std::ostream &out) const;
/**
- * Print the sparsity of the matrix
- * in a format that <tt>gnuplot</tt> understands
- * and which can be used to plot the
- * sparsity pattern in a graphical
- * way. The format consists of pairs
- * <tt>i j</tt> of nonzero elements, each
- * representing one entry of this
- * matrix, one per line of the output
- * file. Indices are counted from
- * zero on, as usual. Since sparsity
- * patterns are printed in the same
- * way as matrices are displayed, we
- * print the negative of the column
- * index, which means that the
- * <tt>(0,0)</tt> element is in the top left
- * rather than in the bottom left
- * corner.
- *
- * Print the sparsity pattern in
- * gnuplot by setting the data style
- * to dots or points and use the
- * <tt>plot</tt> command.
+ * Print the sparsity of the matrix in a format that <tt>gnuplot</tt>
+ * understands and which can be used to plot the sparsity pattern in a
+ * graphical way. The format consists of pairs <tt>i j</tt> of nonzero
+ * elements, each representing one entry of this matrix, one per line of the
+ * output file. Indices are counted from zero on, as usual. Since sparsity
+ * patterns are printed in the same way as matrices are displayed, we print
+ * the negative of the column index, which means that the <tt>(0,0)</tt>
+ * element is in the top left rather than in the bottom left corner.
+ *
+ * Print the sparsity pattern in gnuplot by setting the data style to dots
+ * or points and use the <tt>plot</tt> command.
*/
void print_gnuplot (std::ostream &out) const;
/**
- * Determine an estimate for the
- * memory consumption (in bytes)
- * of this object. See
- * MemoryConsumption.
+ * Determine an estimate for the memory consumption (in bytes) of this
+ * object. See MemoryConsumption.
*/
std::size_t memory_consumption () const;
//@}
private:
/**
- * Number of rows that this sparsity
- * structure shall represent.
+ * Number of rows that this sparsity structure shall represent.
*/
unsigned int rows;
/**
- * Number of columns that this sparsity
- * structure shall represent.
+ * Number of columns that this sparsity structure shall represent.
*/
unsigned int cols;
unsigned int chunk_size;
/**
- * The reduced sparsity pattern. We store
- * only which chunks exist, with each
- * chunk a block in the matrix of size
- * chunk_size by chunk_size.
+ * The reduced sparsity pattern. We store only which chunks exist, with each
+ * chunk a block in the matrix of size chunk_size by chunk_size.
*/
SparsityPattern sparsity_pattern;
/**
- * Make all the chunk sparse matrix kinds
- * friends.
+ * Make all the chunk sparse matrix kinds friends.
*/
template <typename> friend class ChunkSparseMatrix;
+
+ /**
+ * Make the accessor class a friend.
+ */
+ friend class ChunkSparsityPatternIterators::Accessor;
};
#ifndef DOXYGEN
+namespace ChunkSparsityPatternIterators
+{
+ inline
+ Accessor::
+ Accessor (const ChunkSparsityPattern *sparsity_pattern,
+ const unsigned int row)
+ :
+ sparsity_pattern(sparsity_pattern),
+ reduced_accessor(row==sparsity_pattern->n_rows() ?
+ *sparsity_pattern->sparsity_pattern.end() :
+ *sparsity_pattern->sparsity_pattern.
+ begin(row/sparsity_pattern->get_chunk_size())),
+ chunk_row (row==sparsity_pattern->n_rows() ? 0 :
+ row%sparsity_pattern->get_chunk_size()),
+ chunk_col (0)
+ {}
+
+
+
+ inline
+ Accessor::
+ Accessor (const ChunkSparsityPattern *sparsity_pattern)
+ :
+ sparsity_pattern(sparsity_pattern),
+ reduced_accessor(*sparsity_pattern->sparsity_pattern.end()),
+ chunk_row (0),
+ chunk_col (0)
+ {}
+
+
+
+ inline
+ bool
+ Accessor::is_valid_entry () const
+ {
+ return reduced_accessor.is_valid_entry()
+ &&
+ sparsity_pattern->get_chunk_size()*reduced_accessor.row()+chunk_row <
+ sparsity_pattern->n_rows()
+ &&
+ sparsity_pattern->get_chunk_size()*reduced_accessor.column()+chunk_col <
+ sparsity_pattern->n_cols();
+ }
+
+
+
+ inline
+ unsigned int
+ Accessor::row() const
+ {
+ Assert (is_valid_entry() == true, ExcInvalidIterator());
+
+ return sparsity_pattern->get_chunk_size()*reduced_accessor.row() +
+ chunk_row;
+ }
+
+
+
+ inline
+ unsigned int
+ Accessor::column() const
+ {
+ Assert (is_valid_entry() == true, ExcInvalidIterator());
+
+ return sparsity_pattern->get_chunk_size()*reduced_accessor.column() +
+ chunk_col;
+ }
+
+
+
+ inline
+ std::size_t
+ Accessor::reduced_index() const
+ {
+ Assert (is_valid_entry() == true, ExcInvalidIterator());
+
+ return reduced_accessor.index_within_sparsity;
+ }
+
+
+
+
+ inline
+ bool
+ Accessor::operator == (const Accessor &other) const
+ {
+ // no need to check for equality of sparsity patterns as this is done in
+ // the reduced case already and every ChunkSparsityPattern has its own
+ // reduced sparsity pattern
+ return (reduced_accessor == other.reduced_accessor &&
+ chunk_row == other.chunk_row &&
+ chunk_col == other.chunk_col);
+ }
+
+
+
+ inline
+ bool
+ Accessor::operator < (const Accessor &other) const
+ {
+ Assert (sparsity_pattern == other.sparsity_pattern,
+ ExcInternalError());
+
+ if (chunk_row != other.chunk_row)
+ {
+ if (reduced_accessor.index_within_sparsity ==
+ reduced_accessor.sparsity_pattern->n_nonzero_elements())
+ return false;
+ if (other.reduced_accessor.index_within_sparsity ==
+ reduced_accessor.sparsity_pattern->n_nonzero_elements())
+ return true;
+
+ const unsigned int
+ global_row = sparsity_pattern->get_chunk_size()*reduced_accessor.row()
+ +chunk_row,
+ other_global_row = sparsity_pattern->get_chunk_size()*
+ other.reduced_accessor.row()+other.chunk_row;
+ if (global_row < other_global_row)
+ return true;
+ else if (global_row > other_global_row)
+ return false;
+ }
+
+ return (reduced_accessor.index_within_sparsity <
+ other.reduced_accessor.index_within_sparsity ||
+ (reduced_accessor.index_within_sparsity ==
+ other.reduced_accessor.index_within_sparsity &&
+ chunk_col < other.chunk_col));
+ }
+
+
+ inline
+ void
+ Accessor::advance ()
+ {
+ const unsigned int chunk_size = sparsity_pattern->get_chunk_size();
+ Assert (chunk_row < chunk_size && chunk_col < chunk_size,
+ ExcIteratorPastEnd());
+ Assert (reduced_accessor.row() * chunk_size + chunk_row <
+ sparsity_pattern->n_rows()
+ &&
+ reduced_accessor.column() * chunk_size + chunk_col <
+ sparsity_pattern->n_cols(),
+ ExcIteratorPastEnd());
+ if (chunk_size == 1)
+ {
+ reduced_accessor.advance();
+ return;
+ }
+
+ ++chunk_col;
+
+ // end of chunk
+ if (chunk_col == chunk_size
+ ||
+ reduced_accessor.column() * chunk_size + chunk_col ==
+ sparsity_pattern->n_cols())
+ {
+ const unsigned int reduced_row = reduced_accessor.row();
+ // end of row
+ if (reduced_accessor.index_within_sparsity + 1 ==
+ reduced_accessor.sparsity_pattern->rowstart[reduced_row+1])
+ {
+ ++chunk_row;
+
+ chunk_col = 0;
+
+ // end of chunk rows or end of matrix
+ if (chunk_row == chunk_size ||
+ (reduced_row * chunk_size + chunk_row ==
+ sparsity_pattern->n_rows()))
+ {
+ chunk_row = 0;
+ reduced_accessor.advance();
+ }
+ // go back to the beginning of the same reduced row but with
+ // chunk_row increased by one
+ else
+ reduced_accessor.index_within_sparsity =
+ reduced_accessor.sparsity_pattern->rowstart[reduced_row];
+ }
+ // advance within chunk
+ else
+ {
+ reduced_accessor.advance();
+ chunk_col = 0;
+ }
+ }
+ }
+
+
+
+ inline
+ Iterator::Iterator (const ChunkSparsityPattern *sparsity_pattern,
+ const unsigned int row)
+ :
+ accessor(sparsity_pattern, row)
+ {}
+
+
+
+ inline
+ Iterator &
+ Iterator::operator++ ()
+ {
+ accessor.advance ();
+ return *this;
+ }
+
+
+
+ inline
+ Iterator
+ Iterator::operator++ (int)
+ {
+ const Iterator iter = *this;
+ accessor.advance ();
+ return iter;
+ }
+
+
+
+ inline
+ const Accessor &
+ Iterator::operator* () const
+ {
+ return accessor;
+ }
+
+
+
+ inline
+ const Accessor *
+ Iterator::operator-> () const
+ {
+ return &accessor;
+ }
+
+
+ inline
+ bool
+ Iterator::operator == (const Iterator &other) const
+ {
+ return (accessor == other.accessor);
+ }
+
+
+
+ inline
+ bool
+ Iterator::operator != (const Iterator &other) const
+ {
+ return ! (accessor == other.accessor);
+ }
+
+
+ inline
+ bool
+ Iterator::operator < (const Iterator &other) const
+ {
+ return accessor < other.accessor;
+ }
+
+}
+
+
+
+inline
+ChunkSparsityPattern::iterator
+ChunkSparsityPattern::begin () const
+{
+ return iterator(this, 0);
+}
+
+
+inline
+ChunkSparsityPattern::iterator
+ChunkSparsityPattern::end () const
+{
+ return iterator(this, n_rows());
+}
+
+
+
+inline
+ChunkSparsityPattern::iterator
+ChunkSparsityPattern::begin (const unsigned int r) const
+{
+ Assert (r<n_rows(), ExcIndexRange(r,0,n_rows()));
+ return iterator(this, r);
+}
+
+
+
+inline
+ChunkSparsityPattern::iterator
+ChunkSparsityPattern::end (const unsigned int r) const
+{
+ Assert (r<n_rows(), ExcIndexRange(r,0,n_rows()))
+ return iterator(this, r+1);
+}
+
+
inline
unsigned int
}
+
inline
bool
ChunkSparsityPattern::optimize_diagonal () const
template <typename ForwardIterator>
+inline
void
ChunkSparsityPattern::copy_from (const unsigned int n_rows,
const unsigned int n_cols,
Assert (static_cast<unsigned int>(std::distance (begin, end)) == n_rows,
ExcIteratorRange (std::distance (begin, end), n_rows));
- // first determine row lengths for
- // each row. if the matrix is
- // quadratic, then we might have to
- // add an additional entry for the
- // diagonal, if that is not yet
- // present. as we have to call
- // compress anyway later on, don't
- // bother to check whether that
- // diagonal entry is in a certain
- // row or not
+ // first determine row lengths for each row. if the matrix is quadratic,
+ // then we might have to add an additional entry for the diagonal, if that
+ // is not yet present. as we have to call compress anyway later on, don't
+ // bother to check whether that diagonal entry is in a certain row or not
const bool is_square = (n_rows == n_cols);
std::vector<unsigned int> row_lengths;
row_lengths.reserve(n_rows);
(is_square ? 1 : 0));
reinit (n_rows, n_cols, row_lengths, chunk_size);
- // now enter all the elements into
- // the matrix
+ // now enter all the elements into the matrix
unsigned int row = 0;
typedef typename std::iterator_traits<ForwardIterator>::value_type::const_iterator inner_iterator;
for (ForwardIterator i=begin; i!=end; ++i, ++row)
for (inner_iterator j=i->begin(); j!=end_of_row; ++j)
{
const unsigned int col
- = internal::SparsityPatternTools::get_column_index_from_iterator(*j);
+ = internal::SparsityPatternTools::get_column_index_from_iterator(*j);
Assert (col < n_cols, ExcInvalidIndex(col,n_cols));
add (row, col);
}
}
- // finally compress
- // everything. this also sorts the
- // entries within each row
+ // finally compress everything. this also sorts the entries within each row
compress ();
}
<< " should not be stored by this object, but a constraint "
<< "is being added.");
+ /**
+ * Exception
+ *
+ * @ingroup Exceptions
+ */
+ DeclException2 (ExcIncorrectConstraint,
+ int, int,
+ << "While distributing the constraint for DoF "
+ << arg1 << ", it turns out that one of the processors "
+ << "who own the " << arg2
+ << " degrees of freedom that x_" << arg1
+ << " is constrained against does not know about "
+ << "the constraint on x_" << arg1
+ << ". Did you not initialize the ConstraintMatrix "
+ << "with the appropriate locally_relevant set so "
+ << "that every processor who owns a DoF that constrains "
+ << "another DoF also knows about this constraint?");
+
private:
/**
void
ConstraintMatrix::distribute (VectorType &vec) const
{
- Assert (sorted == true, ExcMatrixNotClosed());
+ Assert (sorted==true, ExcMatrixIsClosed());
+
+ // if the vector type supports parallel storage and if the
+ // vector actually does it, we need to be a bit more
+ // careful about how we do things
+ if ((vec.supports_distributed_data == true)
+ &&
+ (vec.locally_owned_elements() != complete_index_set(vec.size())))
+ {
+ const IndexSet vec_owned_elements = vec.locally_owned_elements();
- std::vector<ConstraintLine>::const_iterator next_constraint = lines.begin();
- for (; next_constraint != lines.end(); ++next_constraint)
+ typedef std::vector<ConstraintLine>::const_iterator constraint_iterator;
+
+#ifdef DEBUG
+ {
+ // the algorithm below pushes contributions c_ij x_j to a constrained
+ // DoF x_j *from the side of the owner of x_j*, as opposed to pulling
+ // it from the owner of the target side x_i. this relies on the
+ // assumption that both target and source know about the constraint
+ // on x_i.
+ //
+ // the disadvantage is that it is incredibly difficult to find out what
+ // is happening if the assumption is not satisfied. to help debug
+ // problems of this kind, we do the following in a first step if
+ // debugging is enabled:
+ // - every processor who owns an x_j where c_ij!=0 sends a one
+ // to the owner of x_i to add up
+ // - the owner of x_i knows how many nonzero entries exist, so can
+ // verify that the correct number of ones has been added
+ // - if the sum is not correct, then apparently one of the owners
+ // of the x_j's did not know to send its one and, consequently,
+ // will also not know to send the correct c_ij*x_j later on,
+ // leading to a bug
+ set_zero (vec);
+ for (constraint_iterator it = lines.begin();
+ it != lines.end(); ++it)
+ for (unsigned int i=0; i<it->entries.size(); ++i)
+ if (vec_owned_elements.is_element (it->entries[i].first))
+ vec(it->line) += 1;
+ vec.compress (VectorOperation::add);
+
+ for (constraint_iterator it = lines.begin();
+ it != lines.end(); ++it)
+ if (vec_owned_elements.is_element(it->line))
+ Assert (vec(it->line) == it->entries.size(),
+ ExcIncorrectConstraint(it->line, it->entries.size()));
+ }
+#endif
+
+ // set the values of all constrained DoFs to zero, then add the
+ // contributions for each constrained DoF of all the ones we
+ // own locally
+ set_zero (vec);
+
+ for (constraint_iterator it = lines.begin();
+ it != lines.end(); ++it)
+ for (unsigned int i=0; i<it->entries.size(); ++i)
+ if (vec_owned_elements.is_element(it->entries[i].first))
+ vec(it->line) += it->entries[i].second *
+ vec(it->entries[i].first);
+
+ // in a final step, add the inhomogeneities to the elements we
+ // own locally
+ for (constraint_iterator it = lines.begin();
+ it != lines.end(); ++it)
+ if (vec_owned_elements.is_element(it->line))
+ vec(it->line) += it->inhomogeneity;
+
+ // now compress to communicate the entries that we added to
+ // and that weren't to local processors to the owner
+ vec.compress (VectorOperation::add);
+ }
+ else
+ // purely sequential vector (either because the type doesn't
+ // support anything else or because it's completely stored
+ // locally
{
- // fill entry in line
- // next_constraint.line by adding the
- // different contributions
- typename VectorType::value_type
- new_value = next_constraint->inhomogeneity;
- for (unsigned int i=0; i<next_constraint->entries.size(); ++i)
- new_value += (static_cast<typename VectorType::value_type>
- (vec(next_constraint->entries[i].first)) *
- next_constraint->entries[i].second);
- Assert(numbers::is_finite(new_value), ExcNumberNotFinite());
- vec(next_constraint->line) = new_value;
+ std::vector<ConstraintLine>::const_iterator next_constraint = lines.begin();
+ for (; next_constraint != lines.end(); ++next_constraint)
+ {
+ // fill entry in line
+ // next_constraint.line by adding the
+ // different contributions
+ typename VectorType::value_type
+ new_value = next_constraint->inhomogeneity;
+ for (unsigned int i=0; i<next_constraint->entries.size(); ++i)
+ new_value += (static_cast<typename VectorType::value_type>
+ (vec(next_constraint->entries[i].first)) *
+ next_constraint->entries[i].second);
+ Assert(numbers::is_finite(new_value), ExcNumberNotFinite());
+ vec(next_constraint->line) = new_value;
+ }
}
}
Assert (dst.n() == src.n(), ExcDimensionMismatch(dst.n(), src.n()));
Assert (dst.m() == m(), ExcDimensionMismatch(m(), dst.m()));
- // see if we can use BLAS algorithms
- // for this and if the type for 'number'
- // works for us (it is usually not
- // efficient to use BLAS for very small
+ // see if we can use BLAS algorithms for this and if the type for 'number'
+ // works for us (it is usually not efficient to use BLAS for very small
// matrices):
#if defined(HAVE_DGEMM_) && defined (HAVE_SGEMM_)
if ((types_are_equal<number,double>::value
types_are_equal<number,number2>::value)
if (this->n()*this->m()*src.n() > 300)
{
- // In case we have the BLAS
- // function gemm detected at
- // configure, we use that algorithm
- // for matrix-matrix multiplication
- // since it provides better
- // performance than the deal.II
- // native function (it uses cache
- // and register blocking in order to
- // access local data).
+ // In case we have the BLAS function gemm detected at configure, we
+ // use that algorithm for matrix-matrix multiplication since it
+ // provides better performance than the deal.II native function (it
+ // uses cache and register blocking in order to access local data).
//
- // Note that BLAS/LAPACK stores
- // matrix elements column-wise (i.e.,
- // all values in one column, then all
- // in the next, etc.), whereas the
- // FullMatrix stores them row-wise.
- // We ignore that difference, and
- // give our row-wise data to BLAS,
- // let BLAS build the product of
- // transpose matrices, and read the
- // result as if it were row-wise
- // again. In other words, we calculate
- // (B^T A^T)^T, which is AB.
+ // Note that BLAS/LAPACK stores matrix elements column-wise (i.e., all
+ // values in one column, then all in the next, etc.), whereas the
+ // FullMatrix stores them row-wise. We ignore that difference, and
+ // give our row-wise data to BLAS, let BLAS build the product of
+ // transpose matrices, and read the result as if it were row-wise
+ // again. In other words, we calculate (B^T A^T)^T, which is AB.
const int m = src.n();
const int n = this->m();
const unsigned int m = this->m(), n = src.n(), l = this->n();
- // arrange the loops in a way that
- // we keep write operations low,
- // (writing is usually more costly
- // than reading), even though we
- // need to access the data in src
- // not in a contiguous way.
+ // arrange the loops in a way that we keep write operations low, (writing is
+ // usually more costly than reading), even though we need to access the data
+ // in src not in a contiguous way.
for (unsigned int i=0; i<m; i++)
for (unsigned int j=0; j<n; j++)
{
Assert (src.n() == dst.n(), ExcDimensionMismatch(src.n(), dst.n()));
- // see if we can use BLAS algorithms
- // for this and if the type for 'number'
- // works for us (it is usually not
- // efficient to use BLAS for very small
+ // see if we can use BLAS algorithms for this and if the type for 'number'
+ // works for us (it is usually not efficient to use BLAS for very small
// matrices):
#if defined(HAVE_DGEMM_) && defined (HAVE_SGEMM_)
if ((types_are_equal<number,double>::value
types_are_equal<number,number2>::value)
if (this->n()*this->m()*src.n() > 300)
{
- // In case we have the BLAS
- // function gemm detected at
- // configure, we use that algorithm
- // for matrix-matrix multiplication
- // since it provides better
- // performance than the deal.II
- // native function (it uses cache
- // and register blocking in order to
- // access local data).
+ // In case we have the BLAS function gemm detected at configure, we
+ // use that algorithm for matrix-matrix multiplication since it
+ // provides better performance than the deal.II native function (it
+ // uses cache and register blocking in order to access local data).
//
- // Note that BLAS/LAPACK stores
- // matrix elements column-wise (i.e.,
- // all values in one column, then all
- // in the next, etc.), whereas the
- // FullMatrix stores them row-wise.
- // We ignore that difference, and
- // give our row-wise data to BLAS,
- // let BLAS build the product of
- // transpose matrices, and read the
- // result as if it were row-wise
- // again. In other words, we calculate
- // (B^T A)^T, which is A^T B.
+ // Note that BLAS/LAPACK stores matrix elements column-wise (i.e., all
+ // values in one column, then all in the next, etc.), whereas the
+ // FullMatrix stores them row-wise. We ignore that difference, and
+ // give our row-wise data to BLAS, let BLAS build the product of
+ // transpose matrices, and read the result as if it were row-wise
+ // again. In other words, we calculate (B^T A)^T, which is A^T B.
const int m = src.n();
const int n = this->n();
const number alpha = 1.;
const number beta = (adding == true) ? 1. : 0.;
- // Use the BLAS function gemm for
- // calculating the matrix-matrix
+ // Use the BLAS function gemm for calculating the matrix-matrix
// product.
gemm(notrans, trans, &m, &n, &k, &alpha, &src(0,0), &m,
&this->values[0], &n, &beta, &dst(0,0), &m);
const unsigned int m = n(), n = src.n(), l = this->m();
- // arrange the loops in a way that
- // we keep write operations low,
- // (writing is usually more costly
- // than reading), even though we
- // need to access the data in src
- // not in a contiguous way. However,
- // we should usually end up in the
- // optimized gemm operation in case
- // the matrix is big, so this
- // shouldn't be too bad.
- for (unsigned int i=0; i<m; i++)
- for (unsigned int j=0; j<n; j++)
- {
- number2 add_value = adding ? dst(i,j) : 0.;
- for (unsigned int k=0; k<l; k++)
- add_value += (number2)(*this)(k,i) * (number2)(src(k,j));
- dst(i,j) = add_value;
- }
+ // symmetric matrix if the two matrices are the same
+ if (PointerComparison::equal(this, &src))
+ for (unsigned int i=0; i<m; ++i)
+ for (unsigned int j=i; j<m; ++j)
+ {
+ number2 add_value = 0.;
+ for (unsigned int k=0; k<l; ++k)
+ add_value += (number2)(*this)(k,i) * (number2)(*this)(k,j);
+ if (adding)
+ {
+ dst(i,j) += add_value;
+ if (i<j)
+ dst(j,i) += add_value;
+ }
+ else
+ dst(i,j) = dst(j,i) = add_value;
+ }
+ // arrange the loops in a way that we keep write operations low, (writing is
+ // usually more costly than reading), even though we need to access the data
+ // in src not in a contiguous way. However, we should usually end up in the
+ // optimized gemm operation in case the matrix is big, so this shouldn't be
+ // too bad.
+ else
+ for (unsigned int i=0; i<m; i++)
+ for (unsigned int j=0; j<n; j++)
+ {
+ number2 add_value = adding ? dst(i,j) : 0.;
+ for (unsigned int k=0; k<l; k++)
+ add_value += (number2)(*this)(k,i) * (number2)(src(k,j));
+ dst(i,j) = add_value;
+ }
}
Assert (dst.n() == src.m(), ExcDimensionMismatch(dst.n(), src.m()));
Assert (dst.m() == m(), ExcDimensionMismatch(m(), dst.m()));
- // see if we can use BLAS algorithms
- // for this and if the type for 'number'
- // works for us (it is usually not
- // efficient to use BLAS for very small
+ // see if we can use BLAS algorithms for this and if the type for 'number'
+ // works for us (it is usually not efficient to use BLAS for very small
// matrices):
#if defined(HAVE_DGEMM_) && defined (HAVE_SGEMM_)
if ((types_are_equal<number,double>::value
types_are_equal<number,number2>::value)
if (this->n()*this->m()*src.m() > 300)
{
- // In case we have the BLAS
- // function gemm detected at
- // configure, we use that algorithm
- // for matrix-matrix multiplication
- // since it provides better
- // performance than the deal.II
- // native function (it uses cache
- // and register blocking in order to
- // access local data).
+ // In case we have the BLAS function gemm detected at configure, we
+ // use that algorithm for matrix-matrix multiplication since it
+ // provides better performance than the deal.II native function (it
+ // uses cache and register blocking in order to access local data).
//
- // Note that BLAS/LAPACK stores
- // matrix elements column-wise (i.e.,
- // all values in one column, then all
- // in the next, etc.), whereas the
- // FullMatrix stores them row-wise.
- // We ignore that difference, and
- // give our row-wise data to BLAS,
- // let BLAS build the product of
- // transpose matrices, and read the
- // result as if it were row-wise
- // again. In other words, we calculate
- // (B A^T)^T, which is AB^T.
+ // Note that BLAS/LAPACK stores matrix elements column-wise (i.e., all
+ // values in one column, then all in the next, etc.), whereas the
+ // FullMatrix stores them row-wise. We ignore that difference, and
+ // give our row-wise data to BLAS, let BLAS build the product of
+ // transpose matrices, and read the result as if it were row-wise
+ // again. In other words, we calculate (B A^T)^T, which is AB^T.
const int m = src.m();
const int n = this->m();
const number alpha = 1.;
const number beta = (adding == true) ? 1. : 0.;
- // Use the BLAS function gemm for
- // calculating the matrix-matrix
+ // Use the BLAS function gemm for calculating the matrix-matrix
// product.
gemm(trans, notrans, &m, &n, &k, &alpha, &src(0,0), &k,
&this->values[0], &k, &beta, &dst(0,0), &m);
const unsigned int m = this->m(), n = src.m(), l = this->n();
- // arrange the loops in a way that
- // we keep write operations low,
- // (writing is usually more costly
- // than reading).
- for (unsigned int i=0; i<m; i++)
- for (unsigned int j=0; j<n; j++)
- {
- number2 add_value = adding ? dst(i,j) : 0.;
- for (unsigned int k=0; k<l; k++)
- add_value += (number2)(*this)(i,k) * (number2)(src(j,k));
- dst(i,j) = add_value;
- }
+ // symmetric matrix if the two matrices are the same
+ if (PointerComparison::equal(this, &src))
+ for (unsigned int i=0; i<m; ++i)
+ for (unsigned int j=i; j<m; ++j)
+ {
+ number2 add_value = 0.;
+ for (unsigned int k=0; k<l; ++k)
+ add_value += (number2)(*this)(i,k) * (number2)(*this)(j,k);
+ if (adding)
+ {
+ dst(i,j) += add_value;
+ if (i<j)
+ dst(j,i) += add_value;
+ }
+ else
+ dst(i,j) = dst(j,i) = add_value;
+ }
+ else
+ // arrange the loops in a way that we keep write operations low, (writing is
+ // usually more costly than reading).
+ for (unsigned int i=0; i<m; i++)
+ for (unsigned int j=0; j<n; j++)
+ {
+ number2 add_value = adding ? dst(i,j) : 0.;
+ for (unsigned int k=0; k<l; k++)
+ add_value += (number2)(*this)(i,k) * (number2)(src(j,k));
+ dst(i,j) = add_value;
+ }
}
Assert (src.m() == dst.n(), ExcDimensionMismatch(src.m(), dst.n()));
- // see if we can use BLAS algorithms
- // for this and if the type for 'number'
- // works for us (it is usually not
- // efficient to use BLAS for very small
+ // see if we can use BLAS algorithms for this and if the type for 'number'
+ // works for us (it is usually not efficient to use BLAS for very small
// matrices):
#if defined(HAVE_DGEMM_) && defined (HAVE_SGEMM_)
if ((types_are_equal<number,double>::value
types_are_equal<number,number2>::value)
if (this->n()*this->m()*src.m() > 300)
{
- // In case we have the BLAS
- // function gemm detected at
- // configure, we use that algorithm
- // for matrix-matrix multiplication
- // since it provides better
- // performance than the deal.II
- // native function (it uses cache
- // and register blocking in order to
- // access local data).
+ // In case we have the BLAS function gemm detected at configure, we
+ // use that algorithm for matrix-matrix multiplication since it
+ // provides better performance than the deal.II native function (it
+ // uses cache and register blocking in order to access local data).
//
- // Note that BLAS/LAPACK stores
- // matrix elements column-wise (i.e.,
- // all values in one column, then all
- // in the next, etc.), whereas the
- // FullMatrix stores them row-wise.
- // We ignore that difference, and
- // give our row-wise data to BLAS,
- // let BLAS build the product of
- // transpose matrices, and read the
- // result as if it were row-wise
- // again. In other words, we calculate
- // (B A)^T, which is A^T B^T.
+ // Note that BLAS/LAPACK stores matrix elements column-wise (i.e., all
+ // values in one column, then all in the next, etc.), whereas the
+ // FullMatrix stores them row-wise. We ignore that difference, and
+ // give our row-wise data to BLAS, let BLAS build the product of
+ // transpose matrices, and read the result as if it were row-wise
+ // again. In other words, we calculate (B A)^T, which is A^T B^T.
const int m = src.n();
const int n = this->n();
const number alpha = 1.;
const number beta = (adding == true) ? 1. : 0.;
- // Use the BLAS function gemm for
- // calculating the matrix-matrix
+ // Use the BLAS function gemm for calculating the matrix-matrix
// product.
gemm(trans, trans, &m, &n, &k, &alpha, &src(0,0), &k,
&this->values[0], &n, &beta, &dst(0,0), &m);
const unsigned int m = n(), n = src.m(), l = this->m();
- // arrange the loops in a way that
- // we keep write operations low,
- // (writing is usually more costly
- // than reading), even though we
- // need to access the data in the
- // calling matrix not in a
- // contiguous way. However, we
- // should usually end up in the
- // optimized gemm operation in case
- // the matrix is big, so this
- // shouldn't be too bad.
+ // arrange the loops in a way that we keep write operations low, (writing is
+ // usually more costly than reading), even though we need to access the data
+ // in the calling matrix in a non-contiguous way, possibly leading to cache
+ // misses. However, we should usually end up in the optimized gemm operation
+ // in case the matrix is big, so this shouldn't be too bad.
for (unsigned int i=0; i<m; i++)
for (unsigned int j=0; j<n; j++)
{
//---------------------------------------------------------------------------
// $Id$
//
-// Copyright (C) 2002, 2003, 2004, 2005, 2006, 2007, 2009, 2012 by the deal.II authors
+// Copyright (C) 2002, 2003, 2004, 2005, 2006, 2007, 2009, 2012, 2013 by the deal.II authors
//
// This file is subject to QPL and may not be distributed
// without copyright and license information. Please refer
matrix = new PointerMatrix<MATRIX, VECTOR>(&m);
if (precondition != 0)
delete precondition;
- precondition = new PointerMatrix<PRECONDITION, VECTOR>(&p);;
+ precondition = new PointerMatrix<PRECONDITION, VECTOR>(&p);
}
//---------------------------------------------------------------------------
// $Id$
//
-// Copyright (C) 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010, 2012 by the deal.II authors
+// Copyright (C) 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010, 2012, 2013 by the deal.II authors
//
// This file is subject to QPL and may not be distributed
// without copyright and license information. Please refer
#include <deal.II/base/exceptions.h>
#include <deal.II/lac/block_indices.h>
#include <deal.II/lac/block_vector_base.h>
+#include <deal.II/lac/parallel_vector.h>
#include <cstdio>
#include <vector>
DEAL_II_NAMESPACE_OPEN
-// TODO: global reduction operations (operator *, {l1,l2,lp,linfty}norm, mean
-// value) should use one MPI communication with several Number values, not use
-// the parallel::distributed::Vector operation directly.
namespace parallel
{
{
public:
/**
- * Typedef the base class for simpler
- * access to its own typedefs.
+ * Typedef the base class for simpler access to its own typedefs.
*/
typedef BlockVectorBase<Vector<Number> > BaseClass;
/**
- * Typedef the type of the underlying
- * vector.
+ * Typedef the type of the underlying vector.
*/
typedef typename BaseClass::BlockType BlockType;
/**
- * Import the typedefs from the base
- * class.
+ * Import the typedefs from the base class.
*/
typedef typename BaseClass::value_type value_type;
typedef typename BaseClass::real_type real_type;
typedef typename BaseClass::const_iterator const_iterator;
/**
- * Constructor. There are three
- * ways to use this
- * constructor. First, without
- * any arguments, it generates
- * an object with no
- * blocks. Given one argument,
- * it initializes <tt>num_blocks</tt>
- * blocks, but these blocks have
- * size zero. The third variant
- * finally initializes all
- * blocks to the same size
- * <tt>block_size</tt>.
+ * Constructor. There are three ways to use this constructor. First,
+ * without any arguments, it generates an object with no blocks. Given
+ * one argument, it initializes <tt>num_blocks</tt> blocks, but these
+ * blocks have size zero. The third variant finally initializes all
+ * blocks to the same size <tt>block_size</tt>.
*
- * Confer the other constructor
- * further down if you intend to
- * use blocks of different
- * sizes.
+ * Confer the other constructor further down if you intend to use
+ * blocks of different sizes.
*/
explicit BlockVector (const unsigned int num_blocks = 0,
const unsigned int block_size = 0);
/**
- * Copy-Constructor. Dimension set to
- * that of V, all components are copied
- * from V
+ * Copy-Constructor. Dimension set to that of V, all components are
+ * copied from V
*/
BlockVector (const BlockVector<Number> &V);
#ifndef DEAL_II_EXPLICIT_CONSTRUCTOR_BUG
/**
- * Copy constructor taking a BlockVector of
- * another data type. This will fail if
- * there is no conversion path from
- * <tt>OtherNumber</tt> to <tt>Number</tt>. Note that
- * you may lose accuracy when copying
- * to a BlockVector with data elements with
- * less accuracy.
+ * Copy constructor taking a BlockVector of another data type. This will
+ * fail if there is no conversion path from <tt>OtherNumber</tt> to
+ * <tt>Number</tt>. Note that you may lose accuracy when copying to a
+ * BlockVector with data elements with less accuracy.
*
- * Older versions of gcc did not honor
- * the @p explicit keyword on template
- * constructors. In such cases, it is
- * easy to accidentally write code that
- * can be very inefficient, since the
- * compiler starts performing hidden
- * conversions. To avoid this, this
- * function is disabled if we have
- * detected a broken compiler during
- * configuration.
+ * Older versions of gcc did not honor the @p explicit keyword on
+ * template constructors. In such cases, it is easy to accidentally
+ * write code that can be very inefficient, since the compiler starts
+ * performing hidden conversions. To avoid this, this function is
+ * disabled if we have detected a broken compiler during configuration.
*/
template <typename OtherNumber>
explicit
#endif
/**
- * Constructor. Set the number of
- * blocks to
- * <tt>block_sizes.size()</tt> and
- * initialize each block with
- * <tt>block_sizes[i]</tt> zero
- * elements.
+ * Constructor. Set the number of blocks to <tt>block_sizes.size()</tt>
+ * and initialize each block with <tt>block_sizes[i]</tt> zero elements.
*/
BlockVector (const std::vector<unsigned int> &block_sizes);
/**
- * Destructor. Clears memory
+ * Destructor. Clears memory.
*/
~BlockVector ();
/**
- * Copy operator: fill all components of
- * the vector with the given scalar
- * value.
+ * Copy operator: fill all components of the vector with the given
+ * scalar value.
*/
BlockVector &operator = (const value_type s);
/**
- * Copy operator for arguments of the
- * same type. Resize the
- * present vector if necessary.
+ * Copy operator for arguments of the same type. Resize the present
+ * vector if necessary.
*/
BlockVector &
operator= (const BlockVector &V);
/**
- * Copy operator for template arguments
- * of different types. Resize the
+ * Copy operator for template arguments of different types. Resize the
* present vector if necessary.
*/
template <class Number2>
operator= (const BlockVector<Number2> &V);
/**
- * Copy a regular vector into a
- * block vector.
+ * Copy a regular vector into a block vector.
*/
BlockVector &
operator= (const Vector<Number> &V);
/**
- * Reinitialize the BlockVector to
- * contain <tt>num_blocks</tt> blocks of
+ * Reinitialize the BlockVector to contain <tt>num_blocks</tt> blocks of
* size <tt>block_size</tt> each.
*
- * If the second argument is left
- * at its default value, then the
- * block vector allocates the
- * specified number of blocks but
- * leaves them at zero size. You
- * then need to later
- * reinitialize the individual
- * blocks, and call
- * collect_sizes() to update the
- * block system's knowledge of
+ * If the second argument is left at its default value, then the block
+ * vector allocates the specified number of blocks but leaves them at
+ * zero size. You then need to later reinitialize the individual blocks,
+ * and call collect_sizes() to update the block system's knowledge of
* its individual block's sizes.
*
- * If <tt>fast==false</tt>, the vector
- * is filled with zeros.
+ * If <tt>fast==false</tt>, the vector is filled with zeros.
*/
void reinit (const unsigned int num_blocks,
const unsigned int block_size = 0,
const bool fast = false);
/**
- * Reinitialize the BlockVector such that
- * it contains
- * <tt>block_sizes.size()</tt>
- * blocks. Each block is reinitialized to
+ * Reinitialize the BlockVector such that it contains
+ * <tt>block_sizes.size()</tt> blocks. Each block is reinitialized to
* dimension <tt>block_sizes[i]</tt>.
*
- * If the number of blocks is the
- * same as before this function
- * was called, all vectors remain
- * the same and reinit() is
- * called for each vector.
+ * If the number of blocks is the same as before this function was
+ * called, all vectors remain the same and reinit() is called for each
+ * vector.
*
- * If <tt>fast==false</tt>, the vector
- * is filled with zeros.
+ * If <tt>fast==false</tt>, the vector is filled with zeros.
*
- * Note that you must call this
- * (or the other reinit()
- * functions) function, rather
- * than calling the reinit()
- * functions of an individual
- * block, to allow the block
- * vector to update its caches of
- * vector sizes. If you call
- * reinit() on one of the
- * blocks, then subsequent
- * actions on this object may
- * yield unpredictable results
- * since they may be routed to
- * the wrong block.
+ * Note that you must call this (or the other reinit() functions)
+ * function, rather than calling the reinit() functions of an individual
+ * block, to allow the block vector to update its caches of vector
+ * sizes. If you call reinit() on one of the blocks, then subsequent
+ * actions on this object may yield unpredictable results since they may
+ * be routed to the wrong block.
*/
void reinit (const std::vector<unsigned int> &N,
const bool fast=false);
/**
- * Change the dimension to that
- * of the vector <tt>V</tt>. The same
- * applies as for the other
- * reinit() function.
+ * Change the dimension to that of the vector <tt>V</tt>. The same
+ * applies as for the other reinit() function.
*
- * The elements of <tt>V</tt> are not
- * copied, i.e. this function is
- * the same as calling <tt>reinit
- * (V.size(), fast)</tt>.
+ * The elements of <tt>V</tt> are not copied, i.e. this function is the
+ * same as calling <tt>reinit (V.size(), fast)</tt>.
*
- * Note that you must call this
- * (or the other reinit()
- * functions) function, rather
- * than calling the reinit()
- * functions of an individual
- * block, to allow the block
- * vector to update its caches of
- * vector sizes. If you call
- * reinit() of one of the
- * blocks, then subsequent
- * actions of this object may
- * yield unpredictable results
- * since they may be routed to
- * the wrong block.
+ * Note that you must call this (or the other reinit() functions)
+ * function, rather than calling the reinit() functions of an individual
+ * block, to allow the block vector to update its caches of vector
+ * sizes. If you call reinit() of one of the blocks, then subsequent
+ * actions of this object may yield unpredictable results since they may
+ * be routed to the wrong block.
*/
template <typename Number2>
void reinit (const BlockVector<Number2> &V,
const bool fast=false);
/**
- * Scale each element of the
- * vector by the given factor.
+ * Return whether the vector contains only elements with value
+ * zero. This function is mainly for internal consistency checks and
+ * should seldom be used when not in debug mode since it uses quite some
+ * time.
+ */
+ bool all_zero () const;
+
+ /**
+ * Return @p true if the vector has no negative entries, i.e. all
+ * entries are zero or positive. This function is used, for example, to
+ * check whether refinement indicators are really all positive (or
+ * zero).
+ *
+ * The function obviously only makes sense if the template argument of
+ * this class is a real type. If it is a complex type, then an exception
+ * is thrown.
+ */
+ bool is_non_negative () const;
+
+ /**
+ * Checks for equality of the two vectors.
+ */
+ template <typename Number2>
+ bool operator == (const BlockVector<Number2> &v) const;
+
+ /**
+ * Checks for inequality of the two vectors.
+ */
+ template <typename Number2>
+ bool operator != (const BlockVector<Number2> &v) const;
+
+ /**
+ * Perform the inner product of two vectors.
+ */
+ template <typename Number2>
+ Number operator * (const BlockVector<Number2> &V) const;
+
+ /**
+ * Computes the square of the l<sub>2</sub> norm of the vector (i.e.,
+ * the sum of the squares of all entries among all processors).
+ */
+ real_type norm_sqr () const;
+
+ /**
+ * Computes the mean value of all the entries in the vector.
+ */
+ Number mean_value () const;
+
+ /**
+ * Returns the l<sub>1</sub> norm of the vector (i.e., the sum of the
+ * absolute values of all entries among all processors).
+ */
+ real_type l1_norm () const;
+
+ /**
+ * Returns the l<sub>2</sub> norm of the vector (i.e., square root of
+ * the sum of the square of all entries among all processors).
+ */
+ real_type l2_norm () const;
+
+ /**
+ * Returns the l<sub>p</sub> norm with real @p p of the vector (i.e.,
+ * the pth root of sum of the pth power of all entries among all
+ * processors).
+ */
+ real_type lp_norm (const real_type p) const;
+
+ /**
+ * Returns the maximum norm of the vector (i.e., maximum absolute value
+ * among all entries among all processors).
+ */
+ real_type linfty_norm () const;
+
+ /**
+ * Scale each element of the vector by the given factor.
*
- * This function is deprecated
- * and will be removed in a
- * future version. Use
- * <tt>operator *=</tt> and
- * <tt>operator /=</tt> instead.
+ * This function is deprecated and will be removed in a future
+ * version. Use <tt>operator *=</tt> and <tt>operator /=</tt> instead.
*
- * @deprecated Use <tt>operator*=</tt>
- * instead.
+ * @deprecated Use <tt>operator*=</tt> instead.
*/
void scale (const value_type factor) DEAL_II_DEPRECATED;
/**
- * Multiply each element of this
- * vector by the corresponding
- * element of <tt>v</tt>.
+ * Multiply each element of this vector by the corresponding element of
+ * <tt>v</tt>.
*/
template <class BlockVector2>
void scale (const BlockVector2 &v);
/**
- * Swap the contents of this
- * vector and the other vector
- * <tt>v</tt>. One could do this
- * operation with a temporary
- * variable and copying over the
- * data elements, but this
- * function is significantly more
- * efficient since it only swaps
- * the pointers to the data of
- * the two vectors and therefore
- * does not need to allocate
- * temporary storage and move
- * data around.
+ * Swap the contents of this vector and the other vector <tt>v</tt>. One
+ * could do this operation with a temporary variable and copying over
+ * the data elements, but this function is significantly more efficient
+ * since it only swaps the pointers to the data of the two vectors and
+ * therefore does not need to allocate temporary storage and move data
+ * around.
*
- * Limitation: right now this
- * function only works if both
- * vectors have the same number
- * of blocks. If needed, the
- * numbers of blocks should be
+ * Limitation: right now this function only works if both vectors have
+ * the same number of blocks. If needed, the numbers of blocks should be
* exchanged, too.
*
- * This function is analog to the
- * the swap() function of all C++
- * standard containers. Also,
- * there is a global function
- * swap(u,v) that simply calls
- * <tt>u.swap(v)</tt>, again in analogy
- * to standard functions.
+ * This function is analog to the the swap() function of all C++
+ * standard containers. Also, there is a global function swap(u,v) that
+ * simply calls <tt>u.swap(v)</tt>, again in analogy to standard
+ * functions.
*/
void swap (BlockVector<Number> &v);
}
+ template <typename Number>
+ inline
+ bool
+ BlockVector<Number>::all_zero () const
+ {
+ Assert (this->n_blocks() > 0, ExcEmptyObject());
+
+ // use int instead of bool. in order to make global reduction operations
+ // work also when MPI_Init was not called, only call MPI_Allreduce
+ // commands when there is more than one processor (note that reinit()
+ // functions handle this case correctly through the job_supports_mpi()
+ // query). this is the same in all the functions below
+ int local_result = -1;
+ for (unsigned int i=0; i<this->n_blocks(); ++i)
+ local_result = std::max(local_result,
+ -static_cast<int>(this->block(i).all_zero_local()));
+
+ if (this->block(0).partitioner->n_mpi_processes() > 1)
+ return -Utilities::MPI::max(local_result,
+ this->block(0).partitioner->get_communicator());
+ else
+ return local_result;
+ }
+
+
+
+ template <typename Number>
+ inline
+ bool
+ BlockVector<Number>::is_non_negative () const
+ {
+ Assert (this->n_blocks() > 0, ExcEmptyObject());
+ int local_result = -1;
+ for (unsigned int i=0; i<this->n_blocks(); ++i)
+ local_result = std::max(local_result,
+ -static_cast<int>(this->block(i).is_non_negative_local()));
+ if (this->block(0).partitioner->n_mpi_processes() > 1)
+ return Utilities::MPI::max(local_result,
+ this->block(0).partitioner->get_communicator());
+ else
+ return local_result;
+ }
+
+
+
+ template <typename Number>
+ template <typename Number2>
+ inline
+ bool
+ BlockVector<Number>::operator == (const BlockVector<Number2> &v) const
+ {
+ Assert (this->n_blocks() > 0, ExcEmptyObject());
+ AssertDimension (this->n_blocks(), v.n_blocks());
+
+ // MPI does not support bools, so use unsigned int instead. Two vectors
+ // are equal if the check for non-equal fails on all processors
+ unsigned int local_result = 0;
+ for (unsigned int i=0; i<this->n_blocks(); ++i)
+ local_result = std::max(local_result,
+ static_cast<unsigned int>(!this->block(i).vectors_equal_local(v.block(i))));
+ unsigned int result =
+ this->block(0).partitioner->n_mpi_processes() > 1
+ ?
+ Utilities::MPI::max(local_result, this->block(0).partitioner->get_communicator())
+ :
+ local_result;
+ return result==0;
+ }
+
+
+
+ template <typename Number>
+ template <typename Number2>
+ inline
+ bool
+ BlockVector<Number>::operator != (const BlockVector<Number2> &v) const
+ {
+ return !(operator == (v));
+ }
+
+
+
+ template <typename Number>
+ template <typename Number2>
+ inline
+ Number
+ BlockVector<Number>::operator * (const BlockVector<Number2> &v) const
+ {
+ Assert (this->n_blocks() > 0, ExcEmptyObject());
+ AssertDimension (this->n_blocks(), v.n_blocks());
+
+ Number local_result = Number();
+ for (unsigned int i=0; i<this->n_blocks(); ++i)
+ local_result += this->block(i).inner_product_local(v.block(i));
+
+ if (this->block(0).partitioner->n_mpi_processes() > 1)
+ return Utilities::MPI::sum (local_result,
+ this->block(0).partitioner->get_communicator());
+ else
+ return local_result;
+ }
+
+
+
+ template <typename Number>
+ inline
+ typename BlockVector<Number>::real_type
+ BlockVector<Number>::norm_sqr () const
+ {
+ Assert (this->n_blocks() > 0, ExcEmptyObject());
+
+ real_type local_result = real_type();
+ for (unsigned int i=0; i<this->n_blocks(); ++i)
+ local_result += this->block(i).norm_sqr_local();
+
+ if (this->block(0).partitioner->n_mpi_processes() > 1)
+ return Utilities::MPI::sum (local_result,
+ this->block(0).partitioner->get_communicator());
+ else
+ return local_result;
+ }
+
+
+
+ template <typename Number>
+ inline
+ Number
+ BlockVector<Number>::mean_value () const
+ {
+ Assert (this->n_blocks() > 0, ExcEmptyObject());
+
+ Number local_result = Number();
+ for (unsigned int i=0; i<this->n_blocks(); ++i)
+ local_result += this->block(i).mean_value_local()*(real_type)this->block(i).partitioner->local_size();
+
+ if (this->block(0).partitioner->n_mpi_processes() > 1)
+ return Utilities::MPI::sum (local_result,
+ this->block(0).partitioner->get_communicator())/
+ (real_type)this->size();
+ else
+ return local_result/(real_type)this->size();
+ }
+
+
+
+ template <typename Number>
+ inline
+ typename BlockVector<Number>::real_type
+ BlockVector<Number>::l1_norm () const
+ {
+ Assert (this->n_blocks() > 0, ExcEmptyObject());
+
+ real_type local_result = real_type();
+ for (unsigned int i=0; i<this->n_blocks(); ++i)
+ local_result += this->block(i).l1_norm_local();
+
+ if (this->block(0).partitioner->n_mpi_processes() > 1)
+ return Utilities::MPI::sum (local_result,
+ this->block(0).partitioner->get_communicator());
+ else
+ return local_result;
+ }
+
+
+
+ template <typename Number>
+ inline
+ typename BlockVector<Number>::real_type
+ BlockVector<Number>::l2_norm () const
+ {
+ return std::sqrt(norm_sqr());
+ }
+
+
+
+ template <typename Number>
+ inline
+ typename BlockVector<Number>::real_type
+ BlockVector<Number>::lp_norm (const real_type p) const
+ {
+ Assert (this->n_blocks() > 0, ExcEmptyObject());
+
+ real_type local_result = real_type();
+ for (unsigned int i=0; i<this->n_blocks(); ++i)
+ local_result += std::pow(this->block(i).lp_norm_local(p), p);
+
+ if (this->block(0).partitioner->n_mpi_processes() > 1)
+ return std::pow (Utilities::MPI::sum(local_result,
+ this->block(0).partitioner->get_communicator()),
+ static_cast<real_type>(1.0/p));
+ else
+ return std::pow (local_result, static_cast<real_type>(1.0/p));
+ }
+
+
+
+ template <typename Number>
+ inline
+ typename BlockVector<Number>::real_type
+ BlockVector<Number>::linfty_norm () const
+ {
+ Assert (this->n_blocks() > 0, ExcEmptyObject());
+
+ real_type local_result = real_type();
+ for (unsigned int i=0; i<this->n_blocks(); ++i)
+ local_result = std::max(local_result, this->block(i).linfty_norm_local());
+
+ if (this->block(0).partitioner->n_mpi_processes() > 1)
+ return Utilities::MPI::max (local_result,
+ this->block(0).partitioner->get_communicator());
+ else
+ return local_result;
+ }
+
+
template <typename Number>
inline
{
namespace distributed
{
+ template <typename Number> class BlockVector;
/*! @addtogroup Vectors
*@{
* access vector entries in the local index space with the function @p
* local_element(). Locally owned indices are placed first, [0,
* local_size()), and then all ghost indices follow after them
- * contiguously, [local_size(), local_size()+n_ghost_indices()).
+ * contiguously, [local_size(), local_size()+n_ghost_entries()).
*
* Functions related to parallel functionality:
* - The function <code>compress()</code> goes through the data associated
* with ghost indices and communicates it to the owner process, which can
* then add/set it to the correct position. This can be used e.g. after
* having run an assembly routine involving ghosts that fill this vector.
- * - The <code>update_ghost_values()</code> function imports the data from the owning
- * processor to the ghost indices in order to provide read access to the
- * data associated with ghosts.
- * - It is possible to split the above functions into two phases, where the first
- * initiates the communication and the second one finishes it. These
- * functions can be used to overlap communication with computations in
- * other parts of the code.
+ * - The <code>update_ghost_values()</code> function imports the data from
+ * the owning processor to the ghost indices in order to provide read
+ * access to the data associated with ghosts.
+ * - It is possible to split the above functions into two phases, where
+ * the first initiates the communication and the second one finishes
+ * it. These functions can be used to overlap communication with
+ * computations in other parts of the code.
* - Of course, reduction operations (like norms) make use of collective
* all-to-all MPI communications.
*
{
public:
/**
- * Declare standard types used in all
- * containers. These types parallel those in
- * the <tt>C++</tt> standard libraries
- * <tt>vector<...></tt> class.
+ * Declare standard types used in all containers. These types parallel
+ * those in the <tt>C++</tt> standard libraries <tt>vector<...></tt>
+ * class.
*/
typedef Number value_type;
typedef value_type *pointer;
typedef size_t size_type;
typedef typename numbers::NumberTraits<Number>::real_type real_type;
+ /**
+ * A variable that indicates whether this vector
+ * supports distributed data storage. If true, then
+ * this vector also needs an appropriate compress()
+ * function that allows communicating recent set or
+ * add operations to individual elements to be communicated
+ * to other processors.
+ *
+ * For the current class, the variable equals
+ * true, since it does support parallel data storage.
+ */
+ static const bool supports_distributed_data = true;
+
/**
* @name 1: Basic Object-handling
*/
Vector ();
/**
- * Copy constructor. Uses the parallel
- * partitioning of @p in_vector.
+ * Copy constructor. Uses the parallel partitioning of @p in_vector.
*/
Vector (const Vector<Number> &in_vector);
/**
- * Constructs a parallel vector of the given
- * global size without any actual parallel
- * distribution.
+ * Constructs a parallel vector of the given global size without any
+ * actual parallel distribution.
*/
Vector (const unsigned int size);
/**
- * Constructs a parallel vector. The local
- * range is specified by @p locally_owned_set
- * (note that this must be a contiguous
- * interval, multiple intervals are not
- * possible). The IndexSet @p ghost_indices
- * specifies ghost indices, i.e., indices
- * which one might need to read data from or
- * accumulate data from. It is allowed that
- * the set of ghost indices also contains the
- * local range, but it does not need to.
+ * Constructs a parallel vector. The local range is specified by @p
+ * locally_owned_set (note that this must be a contiguous interval,
+ * multiple intervals are not possible). The IndexSet @p ghost_indices
+ * specifies ghost indices, i.e., indices which one might need to read
+ * data from or accumulate data from. It is allowed that the set of
+ * ghost indices also contains the local range, but it does not need to.
*
- * This function involves global
- * communication, so it should only be called
- * once for a given layout. Use the
- * constructor with Vector<Number> argument to
- * create additional vectors with the same
+ * This function involves global communication, so it should only be
+ * called once for a given layout. Use the constructor with
+ * Vector<Number> argument to create additional vectors with the same
* parallel layout.
*/
Vector (const IndexSet &local_range,
const MPI_Comm communicator);
/**
- * Create the vector based on the parallel
- * partitioning described in @p
- * partitioner. The input argument is a shared
- * pointer, which store the partitioner data
- * only once and share it between several
- * vectors with the same layout.
+ * Create the vector based on the parallel partitioning described in @p
+ * partitioner. The input argument is a shared pointer, which store the
+ * partitioner data only once and share it between several vectors with
+ * the same layout.
*/
Vector (const std_cxx1x::shared_ptr<const Utilities::MPI::Partitioner> &partitioner);
~Vector ();
/**
- * Sets the global size of the vector to @p
- * size without any actual parallel
- * distribution.
+ * Sets the global size of the vector to @p size without any actual
+ * parallel distribution.
*/
void reinit (const unsigned int size,
const bool fast = false);
/**
- * Uses the parallel layout of the input
- * vector @p in_vector and allocates memory
- * for this vector. Recommended initialization
- * function when several vectors with the same
- * layout should be created.
+ * Uses the parallel layout of the input vector @p in_vector and
+ * allocates memory for this vector. Recommended initialization function
+ * when several vectors with the same layout should be created.
*
- * If the flag @p fast is set to false, the
- * memory will be initialized with zero,
- * otherwise the memory will be untouched (and
- * the user must make sure to fill it with
- * reasonable data before using it).
+ * If the flag @p fast is set to false, the memory will be initialized
+ * with zero, otherwise the memory will be untouched (and the user must
+ * make sure to fill it with reasonable data before using it).
*/
template <typename Number2>
void reinit(const Vector<Number2> &in_vector,
const bool fast = false);
/**
- * Initialize the vector. The local range is
- * specified by @p locally_owned_set (note
- * that this must be a contiguous interval,
- * multiple intervals are not possible). The
- * IndexSet @p ghost_indices specifies ghost
- * indices, i.e., indices which one might need
- * to read data from or accumulate data
- * from. It is allowed that the set of ghost
- * indices also contains the local range, but
- * it does not need to.
+ * Initialize the vector. The local range is specified by @p
+ * locally_owned_set (note that this must be a contiguous interval,
+ * multiple intervals are not possible). The IndexSet @p ghost_indices
+ * specifies ghost indices, i.e., indices which one might need to read
+ * data from or accumulate data from. It is allowed that the set of
+ * ghost indices also contains the local range, but it does not need to.
*
- * This function involves global
- * communication, so it should only be called
- * once for a given layout. Use the @p reinit
- * function with Vector<Number> argument to
- * create additional vectors with the same
+ * This function involves global communication, so it should only be
+ * called once for a given layout. Use the @p reinit function with
+ * Vector<Number> argument to create additional vectors with the same
* parallel layout.
*/
void reinit (const IndexSet &local_range,
const MPI_Comm communicator);
/**
- * Initialize the vector given to the parallel
- * partitioning described in @p
- * partitioner. The input argument is a shared
- * pointer, which store the partitioner data
- * only once and share it between several
- * vectors with the same layout.
+ * Initialize the vector given to the parallel partitioning described in
+ * @p partitioner. The input argument is a shared pointer, which store
+ * the partitioner data only once and share it between several vectors
+ * with the same layout.
*/
void reinit (const std_cxx1x::shared_ptr<const Utilities::MPI::Partitioner> &partitioner);
/**
- * Swap the contents of this
- * vector and the other vector
- * @p v. One could do this
- * operation with a temporary
- * variable and copying over the
- * data elements, but this
- * function is significantly more
- * efficient since it only swaps
- * the pointers to the data of
- * the two vectors and therefore
- * does not need to allocate
- * temporary storage and move
- * data around.
+ * Swap the contents of this vector and the other vector @p v. One could
+ * do this operation with a temporary variable and copying over the data
+ * elements, but this function is significantly more efficient since it
+ * only swaps the pointers to the data of the two vectors and therefore
+ * does not need to allocate temporary storage and move data around.
*
- * This function is analog to the
- * the @p swap function of all C++
- * standard containers. Also,
- * there is a global function
- * <tt>swap(u,v)</tt> that simply calls
- * <tt>u.swap(v)</tt>, again in analogy
- * to standard functions.
+ * This function is analog to the the @p swap function of all C++
+ * standard containers. Also, there is a global function
+ * <tt>swap(u,v)</tt> that simply calls <tt>u.swap(v)</tt>, again in
+ * analogy to standard functions.
*
- * This function is virtual in
- * order to allow for derived
- * classes to handle memory
- * separately.
+ * This function is virtual in order to allow for derived classes to
+ * handle memory separately.
*/
void swap (Vector<Number> &v);
/**
- * Assigns the vector to the parallel
- * partitioning of the input vector @p
- * in_vector, and copies all the data.
+ * Assigns the vector to the parallel partitioning of the input vector
+ * @p in_vector, and copies all the data.
*/
Vector<Number> &
operator = (const Vector<Number> &in_vector);
/**
- * Assigns the vector to the parallel
- * partitioning of the input vector @p
- * in_vector, and copies all the data.
+ * Assigns the vector to the parallel partitioning of the input vector
+ * @p in_vector, and copies all the data.
*/
template <typename Number2>
Vector<Number> &
operator = (const Vector<Number2> &in_vector);
/**
- * This method copies the local range from
- * another vector with the same local range,
- * but possibly different layout of ghost
- * indices.
+ * This method copies the local range from another vector with the same
+ * local range, but possibly different layout of ghost indices.
*/
void copy_from (const Vector<Number> &in_vector,
const bool call_update_ghost_values = false);
/**
- * Sets all elements of the vector to the
- * scalar @p s. If the scalar is zero, also
- * ghost elements are set to zero, otherwise
- * they remain unchanged.
+ * Sets all elements of the vector to the scalar @p s. If the scalar is
+ * zero, also ghost elements are set to zero, otherwise they remain
+ * unchanged.
*/
Vector<Number> &operator = (const Number s);
/**
- * This function copies the data that has
- * accumulated in the data buffer for ghost
- * indices to the owning processor.
+ * This function copies the data that has accumulated in the data buffer
+ * for ghost indices to the owning processor. For the meaning of the
+ * argument @p operation, see the entry on @ref GlossCompress
+ * "Compressing distributed vectors and matrices" in the glossary.
+ *
+ * There are two variants for this function. If called with argument @p
+ * VectorOperation::add adds all the data accumulated in ghost elements
+ * to the respective elements on the owning processor and clears the
+ * ghost array afterwards. If called with argument @p
+ * VectorOperation::insert, a set operation is performed. Since setting
+ * elements in a vector with ghost elements is ambiguous (as one can set
+ * both the element on the ghost site as well as the owning site), this
+ * operation makes the assumption that all data is set correctly on the
+ * owning processor. Upon call of compress(VectorOperation::insert), all
+ * ghost entries are therefore simply zeroed out (using
+ * zero_ghost_values()). In debug mode, a check is performed that makes
+ * sure that the data set is actually consistent between processors,
+ * i.e., whenever a non-zero ghost element is found, it is compared to
+ * the value on the owning processor and an exception is thrown if these
+ * elements do not agree.
*
- * For the meaning of this argument,
- * see the entry on @ref
- * GlossCompress "Compressing
- * distributed vectors and matrices"
- * in the glossary.
*/
void compress (::dealii::VectorOperation::values operation);
void compress () DEAL_II_DEPRECATED;
/**
- * Fills the data field for ghost indices with
- * the values stored in the respective
- * positions of the owning processor. This
- * function is needed before reading from
- * ghosts. The function is @p const even
- * though ghost data is changed. This is
- * needed to allow functions with a @p const
- * vector to perform the data exchange without
- * creating temporaries.
+ * Fills the data field for ghost indices with the values stored in the
+ * respective positions of the owning processor. This function is needed
+ * before reading from ghosts. The function is @p const even though
+ * ghost data is changed. This is needed to allow functions with a @p
+ * const vector to perform the data exchange without creating
+ * temporaries.
*/
void update_ghost_values () const;
/**
- * Initiates communication for the @p
- * compress() function with non-blocking
- * communication. This function does not wait
- * for the transfer to finish, in order to
- * allow for other computations during the
- * time it takes until all data arrives.
+ * Initiates communication for the @p compress() function with
+ * non-blocking communication. This function does not wait for the
+ * transfer to finish, in order to allow for other computations during
+ * the time it takes until all data arrives.
*
- * Before the data is actually exchanged, the
- * function must be followed by a call to @p
- * compress_finish().
+ * Before the data is actually exchanged, the function must be followed
+ * by a call to @p compress_finish().
*
- * In case this function is called for more
- * than one vector before @p
- * compress_finish() is invoked, it is
- * mandatory to specify a unique
- * communication channel to each such call, in
- * order to avoid several messages with the
- * same ID that will corrupt this operation.
- */
- void compress_start (const unsigned int communication_channel = 0);
-
- /**
- * For all requests that have been initiated
- * in compress_start, wait for the
- * communication to finish. Once it is
- * finished, add or set the data (depending on
- * whether @p add_ghost_data is @p true or @p
- * false) to the respective positions in the
- * owning processor, and clear the contents in
- * the ghost data fields. The meaning of
- * this argument is the same as in compress().
+ * In case this function is called for more than one vector before @p
+ * compress_finish() is invoked, it is mandatory to specify a unique
+ * communication channel to each such call, in order to avoid several
+ * messages with the same ID that will corrupt this operation.
+ */
+ void compress_start (const unsigned int communication_channel = 0,
+ ::dealii::VectorOperation::values operation = VectorOperation::add);
+
+ /**
+ * For all requests that have been initiated in compress_start, wait for
+ * the communication to finish. Once it is finished, add or set the data
+ * (depending on the flag operation) to the respective positions in the
+ * owning processor, and clear the contents in the ghost data
+ * fields. The meaning of this argument is the same as in compress().
*
- * Must follow a call to the @p compress_start
- * function.
+ * Must follow a call to the @p compress_start function.
*/
- void compress_finish (const bool add_ghost_data = true);
+ void compress_finish (::dealii::VectorOperation::values operation);
+ /**
+ * @deprecated: use compress_finish(VectorOperation::values) instead.
+ */
+ void compress_finish (const bool add_ghost_data = true) DEAL_II_DEPRECATED;
/**
- * Initiates communication for the @p
- * update_ghost_values() function with non-blocking
- * communication. This function does not wait
- * for the transfer to finish, in order to
- * allow for other computations during the
- * time it takes until all data arrives.
+ * Initiates communication for the @p update_ghost_values() function
+ * with non-blocking communication. This function does not wait for the
+ * transfer to finish, in order to allow for other computations during
+ * the time it takes until all data arrives.
*
- * Before the data is actually exchanged, the
- * function must be followed by a call to @p
- * update_ghost_values_finish().
+ * Before the data is actually exchanged, the function must be followed
+ * by a call to @p update_ghost_values_finish().
*
- * In case this function is called for more
- * than one vector before @p
- * update_ghost_values_finish() is invoked, it is
- * mandatory to specify a unique communication
- * channel to each such call, in order to
- * avoid several messages with the same ID
- * that will corrupt this operation.
+ * In case this function is called for more than one vector before @p
+ * update_ghost_values_finish() is invoked, it is mandatory to specify a
+ * unique communication channel to each such call, in order to avoid
+ * several messages with the same ID that will corrupt this operation.
*/
void update_ghost_values_start (const unsigned int communication_channel = 0) const;
/**
- * For all requests that have been started in
- * update_ghost_values_start, wait for the communication
- * to finish.
+ * For all requests that have been started in update_ghost_values_start,
+ * wait for the communication to finish.
*
- * Must follow a call to the @p
- * update_ghost_values_start function before reading
- * data from ghost indices.
+ * Must follow a call to the @p update_ghost_values_start function
+ * before reading data from ghost indices.
*/
void update_ghost_values_finish () const;
/**
- * This method zeros the entries on ghost
- * dofs, but does not touch locally owned
- * DoFs.
+ * This method zeros the entries on ghost dofs, but does not touch
+ * locally owned DoFs.
*/
void zero_out_ghosts ();
/**
- * Return whether the vector contains only
- * elements with value zero. This function
- * is mainly for internal consistency
- * checks and should seldom be used when
- * not in debug mode since it uses quite
- * some time.
+ * Return whether the vector contains only elements with value
+ * zero. This function is mainly for internal consistency checks and
+ * should seldom be used when not in debug mode since it uses quite some
+ * time.
*/
bool all_zero () const;
/**
- * Return @p true if the vector has no
- * negative entries, i.e. all entries are
- * zero or positive. This function is
- * used, for example, to check whether
- * refinement indicators are really all
- * positive (or zero).
+ * Return @p true if the vector has no negative entries, i.e. all
+ * entries are zero or positive. This function is used, for example, to
+ * check whether refinement indicators are really all positive (or
+ * zero).
*
- * The function obviously only makes
- * sense if the template argument of this
- * class is a real type. If it is a
- * complex type, then an exception is
- * thrown.
+ * The function obviously only makes sense if the template argument of
+ * this class is a real type. If it is a complex type, then an exception
+ * is thrown.
*/
bool is_non_negative () const;
Number operator * (const Vector<Number2> &V) const;
/**
- * Computes the square of the l<sub>2</sub>
- * norm of the vector (i.e., the sum of the
- * squares of all entries among all
- * processors).
+ * Computes the square of the l<sub>2</sub> norm of the vector (i.e.,
+ * the sum of the squares of all entries among all processors).
*/
real_type norm_sqr () const;
/**
- * Computes the mean value of all the entries
- * in the vector.
+ * Computes the mean value of all the entries in the vector.
*/
Number mean_value () const;
/**
- * Returns the l<sub>1</sub> norm of the
- * vector (i.e., the sum of the absolute
- * values of all entries among all
- * processors).
+ * Returns the l<sub>1</sub> norm of the vector (i.e., the sum of the
+ * absolute values of all entries among all processors).
*/
real_type l1_norm () const;
/**
- * Returns the l<sub>2</sub> norm of the
- * vector (i.e., square root of the sum of the
- * square of all entries among all
- * processors).
+ * Returns the l<sub>2</sub> norm of the vector (i.e., square root of
+ * the sum of the square of all entries among all processors).
*/
real_type l2_norm () const;
/**
- * Returns the l<sub>p</sub> norm with real @p
- * p of the vector (i.e., the pth root of sum
- * of the pth power of all entries among all
+ * Returns the l<sub>p</sub> norm with real @p p of the vector (i.e.,
+ * the pth root of sum of the pth power of all entries among all
* processors).
*/
real_type lp_norm (const real_type p) const;
/**
- * Returns the maximum norm of the vector
- * (i.e., maximum absolute value among all
- * entries among all processors).
+ * Returns the maximum norm of the vector (i.e., maximum absolute value
+ * among all entries among all processors).
*/
real_type linfty_norm () const;
/**
- * Returns the global size of the vector,
- * equal to the sum of the number of locally
- * owned indices among all the processors.
+ * Returns the global size of the vector, equal to the sum of the number
+ * of locally owned indices among all the processors.
*/
types::global_dof_index size () const;
/**
- * Returns the local size of the vector, i.e.,
- * the number of indices owned locally.
+ * Returns the local size of the vector, i.e., the number of indices
+ * owned locally.
*/
unsigned int local_size() const;
/**
- * Returns the half-open interval that
- * specifies the locally owned range of the
- * vector. Note that <code>local_size() ==
- * local_range().second -
+ * Returns the half-open interval that specifies the locally owned range
+ * of the vector. Note that <code>local_size() == local_range().second -
* local_range().first</code>.
*/
std::pair<types::global_dof_index, types::global_dof_index> local_range () const;
/**
- * Returns true if the given global index is
- * in the local range of this processor.
+ * Returns true if the given global index is in the local range of this
+ * processor.
*/
bool in_local_range (const types::global_dof_index global_index) const;
/**
- * Returns the number of ghost elements
- * present on the vector.
+ * Return an index set that describes which elements of this vector
+ * are owned by the current processor. Note that this index set does
+ * not include elements this vector may store locally as ghost
+ * elements but that are in fact owned by another processor.
+ * As a consequence, the index sets returned on different
+ * processors if this is a distributed vector will form disjoint
+ * sets that add up to the complete index set.
+ * Obviously, if a vector is created on only one processor, then
+ * the result would satisfy
+ * @code
+ * vec.locally_owned_elements() == complete_index_set (vec.size())
+ * @endcode
+ */
+ IndexSet locally_owned_elements () const;
+
+ /**
+ * Returns the number of ghost elements present on the vector.
*/
unsigned int n_ghost_entries () const;
/**
- * Returns whether the given global index is a
- * ghost index on the present
- * processor. Returns false for indices that
- * are owned locally and for indices not
- * present at all.
+ * Returns whether the given global index is a ghost index on the
+ * present processor. Returns false for indices that are owned locally
+ * and for indices not present at all.
*/
bool is_ghost_entry (const types::global_dof_index global_index) const;
/**
- * Make the @p Vector class a bit like
- * the <tt>vector<></tt> class of the C++
- * standard library by returning
- * iterators to the start and end of the
- * locally owned elements of this vector.
+ * Make the @p Vector class a bit like the <tt>vector<></tt> class of
+ * the C++ standard library by returning iterators to the start and end
+ * of the <i>locally owned</i> elements of this vector.
+ *
+ * It holds that end() - begin() == local_size().
*/
iterator begin ();
/**
- * Return constant iterator to the start of
- * the vector.
+ * Return constant iterator to the start of the locally owned elements
+ * of the vector.
*/
const_iterator begin () const;
/**
- * Return an iterator pointing to the
- * element past the end of the array of
- * locally owned entries.
+ * Return an iterator pointing to the element past the end of the array
+ * of locally owned entries.
*/
iterator end ();
/**
- * Return a constant iterator pointing to
- * the element past the end of the array
- * of the locally owned entries.
+ * Return a constant iterator pointing to the element past the end of
+ * the array of the locally owned entries.
*/
const_iterator end () const;
//@}
//@{
/**
- * Read access to the data in the
- * position corresponding to @p
- * global_index. The index must be
- * either in the local range of the
- * vector or be specified as a ghost
- * index at construction.
+ * Read access to the data in the position corresponding to @p
+ * global_index. The index must be either in the local range of the
+ * vector or be specified as a ghost index at construction.
+ *
+ * Performance: <tt>O(1)</tt> for locally owned elements that represent
+ * a contiguous range and <tt>O(log(n<sub>ranges</sub>))</tt> for ghost
+ * elements (quite fast, but slower than local_element()).
*/
Number operator () (const types::global_dof_index global_index) const;
/**
- * Read and write access to the data
- * in the position corresponding to
- * @p global_index. The index must be
- * either in the local range of the
- * vector or be specified as a ghost
- * index at construction.
+ * Read and write access to the data in the position corresponding to @p
+ * global_index. The index must be either in the local range of the
+ * vector or be specified as a ghost index at construction.
+ *
+ * Performance: <tt>O(1)</tt> for locally owned elements that represent
+ * a contiguous range and <tt>O(log(n<sub>ranges</sub>))</tt> for ghost
+ * elements (quite fast, but slower than local_element()).
*/
Number &operator () (const types::global_dof_index global_index);
/**
- * Read access to the data in the
- * position corresponding to @p
- * global_index. The index must be
- * either in the local range of the
- * vector or be specified as a ghost
- * index at construction.
+ * Read access to the data in the position corresponding to @p
+ * global_index. The index must be either in the local range of the
+ * vector or be specified as a ghost index at construction.
*
- * This function does the same thing
- * as operator().
+ * This function does the same thing as operator().
*/
Number operator [] (const types::global_dof_index global_index) const;
/**
- * Read and write access to the data
- * in the position corresponding to
- * @p global_index. The index must be
- * either in the local range of the
- * vector or be specified as a ghost
- * index at construction.
+ * Read and write access to the data in the position corresponding to @p
+ * global_index. The index must be either in the local range of the
+ * vector or be specified as a ghost index at construction.
*
- * This function does the same thing
- * as operator().
+ * This function does the same thing as operator().
*/
Number &operator [] (const types::global_dof_index global_index);
/**
- * Read access to the data field specified by
- * @p local_index. Locally owned indices can
- * be accessed with indices
- * <code>[0,local_size)</code>, and ghost
- * indices with indices
- * <code>[local_size,local_size+
- * n_ghost_entries]</code>.
+ * Read access to the data field specified by @p local_index. Locally
+ * owned indices can be accessed with indices
+ * <code>[0,local_size)</code>, and ghost indices with indices
+ * <code>[local_size,local_size+ n_ghost_entries]</code>.
+ *
+ * Performance: Direct array access (fast).
*/
Number local_element (const unsigned int local_index) const;
/**
- * Read and write access to the data field
- * specified by @p local_index. Locally owned
- * indices can be accessed with indices
- * <code>[0,local_size)</code>, and ghost
- * indices with indices
+ * Read and write access to the data field specified by @p
+ * local_index. Locally owned indices can be accessed with indices
+ * <code>[0,local_size)</code>, and ghost indices with indices
* <code>[local_size,local_size+n_ghosts]</code>.
+ *
+ * Performance: Direct array access (fast).
*/
Number &local_element (const unsigned int local_index);
//@}
//@{
/**
- * Add the given vector to the present
- * one.
+ * Add the given vector to the present one.
*/
Vector<Number> &operator += (const Vector<Number> &V);
/**
- * Subtract the given vector from the
- * present one.
+ * Subtract the given vector from the present one.
*/
Vector<Number> &operator -= (const Vector<Number> &V);
/**
- * A collective add operation:
- * This funnction adds a whole
- * set of values stored in @p
- * values to the vector
- * components specified by @p
- * indices.
+ * A collective add operation: This funnction adds a whole set of values
+ * stored in @p values to the vector components specified by @p indices.
*/
template <typename OtherNumber>
void add (const std::vector<unsigned int> &indices,
const std::vector<OtherNumber> &values);
/**
- * This is a second collective
- * add operation. As a
- * difference, this function
- * takes a deal.II vector of
- * values.
+ * This is a second collective add operation. As a difference, this
+ * function takes a deal.II vector of values.
*/
template <typename OtherNumber>
void add (const std::vector<unsigned int> &indices,
const ::dealii::Vector<OtherNumber> &values);
/**
- * Take an address where
- * <tt>n_elements</tt> are stored
- * contiguously and add them into
- * the vector. Handles all cases
- * which are not covered by the
- * other two <tt>add()</tt>
- * functions above.
+ * Take an address where <tt>n_elements</tt> are stored contiguously and
+ * add them into the vector. Handles all cases which are not covered by
+ * the other two <tt>add()</tt> functions above.
*/
template <typename OtherNumber>
void add (const unsigned int n_elements,
const OtherNumber *values);
/**
- * Addition of @p s to all
- * components. Note that @p s is a
- * scalar and not a vector.
+ * Addition of @p s to all components. Note that @p s is a scalar and
+ * not a vector.
*/
void add (const Number s);
/**
- * Simple vector addition, equal to the
- * <tt>operator +=</tt>.
+ * Simple vector addition, equal to the <tt>operator +=</tt>.
*/
void add (const Vector<Number> &V);
/**
- * Simple addition of a multiple of a
- * vector, i.e. <tt>*this += a*V</tt>.
+ * Simple addition of a multiple of a vector, i.e. <tt>*this +=
+ * a*V</tt>.
*/
void add (const Number a, const Vector<Number> &V);
/**
- * Multiple addition of scaled vectors,
- * i.e. <tt>*this += a*V+b*W</tt>.
+ * Multiple addition of scaled vectors, i.e. <tt>*this += a*V+b*W</tt>.
*/
void add (const Number a, const Vector<Number> &V,
const Number b, const Vector<Number> &W);
/**
- * Scaling and simple vector addition,
- * i.e.
- * <tt>*this = s*(*this)+V</tt>.
+ * Scaling and simple vector addition, i.e. <tt>*this =
+ * s*(*this)+V</tt>.
*/
void sadd (const Number s,
const Vector<Number> &V);
/**
- * Scaling and simple addition, i.e.
- * <tt>*this = s*(*this)+a*V</tt>.
+ * Scaling and simple addition, i.e. <tt>*this = s*(*this)+a*V</tt>.
*/
void sadd (const Number s,
const Number a,
const Vector<Number> &W);
/**
- * Scaling and multiple addition.
- * <tt>*this = s*(*this)+a*V + b*W + c*X</tt>.
+ * Scaling and multiple addition. <tt>*this = s*(*this)+a*V + b*W +
+ * c*X</tt>.
*/
void sadd (const Number s,
const Number a,
const Vector<Number> &X);
/**
- * Scale each element of the
- * vector by the given factor.
+ * Scale each element of the vector by the given factor.
*
- * @deprecated This function is deprecated
- * and will be removed in a
- * future version. Use
- * <tt>operator *=</tt> and
- * <tt>operator /=</tt> instead.
+ * @deprecated This function is deprecated and will be removed in a
+ * future version. Use <tt>operator *=</tt> and <tt>operator /=</tt>
+ * instead.
*/
void scale (const Number factor) DEAL_II_DEPRECATED;
-
/**
- * Scale each element of the
- * vector by a constant
- * value.
+ * Scale each element of the vector by a constant value.
*/
Vector<Number> &operator *= (const Number factor);
/**
- * Scale each element of the
- * vector by the inverse of the
- * given value.
+ * Scale each element of the vector by the inverse of the given value.
*/
Vector<Number> &operator /= (const Number factor);
/**
- * Scale each element of this
- * vector by the corresponding
- * element in the argument. This
- * function is mostly meant to
- * simulate multiplication (and
- * immediate re-assignment) by a
- * diagonal scaling matrix.
+ * Scale each element of this vector by the corresponding element in the
+ * argument. This function is mostly meant to simulate multiplication
+ * (and immediate re-assignment) by a diagonal scaling matrix.
*/
void scale (const Vector<Number> &scaling_factors);
/**
- * Scale each element of this
- * vector by the corresponding
- * element in the argument. This
- * function is mostly meant to
- * simulate multiplication (and
- * immediate re-assignment) by a
- * diagonal scaling matrix.
+ * Scale each element of this vector by the corresponding element in the
+ * argument. This function is mostly meant to simulate multiplication
+ * (and immediate re-assignment) by a diagonal scaling matrix.
*/
template <typename Number2>
void scale (const Vector<Number2> &scaling_factors);
const Number c, const Vector<Number> &w);
/**
- * Compute the elementwise ratio of the
- * two given vectors, that is let
- * <tt>this[i] = a[i]/b[i]</tt>. This is
- * useful for example if you want to
- * compute the cellwise ratio of true to
- * estimated error.
+ * Compute the elementwise ratio of the two given vectors, that is let
+ * <tt>this[i] = a[i]/b[i]</tt>. This is useful for example if you want
+ * to compute the cellwise ratio of true to estimated error.
*
- * This vector is appropriately
- * scaled to hold the result.
+ * This vector is appropriately scaled to hold the result.
*
- * If any of the <tt>b[i]</tt> is
- * zero, the result is
- * undefined. No attempt is made
- * to catch such situations.
+ * If any of the <tt>b[i]</tt> is zero, the result is undefined. No
+ * attempt is made to catch such situations.
*/
void ratio (const Vector<Number> &a,
const Vector<Number> &b);
*/
//@{
/**
- * Checks whether the given
- * partitioner is compatible with the
- * partitioner used for this
- * vector. Two partitioners are
- * compatible if the have the same
- * local size and the same ghost
- * indices. They do not necessarily
- * need to be the same data
- * field. This is a local operation
- * only, i.e., if only some
- * processors decide that the
- * partitioning is not compatible,
- * only these processors will return
- * @p false, whereas the other
- * processors will return @p true.
+ * Return a reference to the MPI communicator object in use with this
+ * vector.
+ */
+ const MPI_Comm &get_mpi_communicator () const;
+
+ /**
+ * Checks whether the given partitioner is compatible with the
+ * partitioner used for this vector. Two partitioners are compatible if
+ * the have the same local size and the same ghost indices. They do not
+ * necessarily need to be the same data field. This is a local operation
+ * only, i.e., if only some processors decide that the partitioning is
+ * not compatible, only these processors will return @p false, whereas
+ * the other processors will return @p true.
*/
bool
partitioners_are_compatible (const Utilities::MPI::Partitioner &part) const;
/**
- * Prints the vector to the output stream @p
- * out.
+ * Prints the vector to the output stream @p out.
*/
void print (std::ostream &out,
const unsigned int precision = 3,
const bool across = true) const;
/**
- * Returns the memory consumption of this
- * class in bytes.
+ * Returns the memory consumption of this class in bytes.
*/
std::size_t memory_consumption () const;
//@}
private:
/**
- * Shared pointer to store the parallel
- * partitioning information. This information
- * can be shared between several vectors that
- * have the same partitioning.
+ * Local part of all_zero().
+ */
+ bool all_zero_local () const;
+
+ /**
+ * Local part of is_non_negative().
+ */
+ bool is_non_negative_local () const;
+
+ /**
+ * Local part of operator==.
+ */
+ template <typename Number2>
+ bool vectors_equal_local (const Vector<Number2> &v) const;
+
+ /**
+ * Local part of the inner product of two vectors.
+ */
+ template <typename Number2>
+ Number inner_product_local (const Vector<Number2> &V) const;
+
+ /**
+ * Local part of norm_sqr().
+ */
+ real_type norm_sqr_local () const;
+
+ /**
+ * Local part of mean_value().
+ */
+ Number mean_value_local () const;
+
+ /**
+ * Local part of l1_norm().
+ */
+ real_type l1_norm_local () const;
+
+ /**
+ * Local part of lp_norm().
+ */
+ real_type lp_norm_local (const real_type p) const;
+
+ /**
+ * Local part of linfty_norm().
+ */
+ real_type linfty_norm_local () const;
+
+ /**
+ * Shared pointer to store the parallel partitioning information. This
+ * information can be shared between several vectors that have the same
+ * partitioning.
*/
std_cxx1x::shared_ptr<const Utilities::MPI::Partitioner> partitioner;
/**
- * The size that is currently allocated in the
- * val array.
+ * The size that is currently allocated in the val array.
*/
unsigned int allocated_size;
/**
- * Pointer to the array of
- * local elements of this vector.
+ * Pointer to the array of local elements of this vector.
*/
Number *val;
/**
- * Temporary storage that holds the data that
- * is sent to this processor in @p compress()
- * or sent from this processor in @p
+ * Temporary storage that holds the data that is sent to this processor
+ * in @p compress() or sent from this processor in @p
* update_ghost_values.
*/
mutable Number *import_data;
/**
- * Provide this class with all functionality
- * of ::dealii::Vector by creating a
- * VectorView object.
+ * Provide this class with all functionality of ::dealii::Vector by
+ * creating a VectorView object.
*/
VectorView<Number> vector_view;
#ifdef DEAL_II_WITH_MPI
/**
- * A vector that collects all requests from @p
- * compress() operations. This class uses
- * persistent MPI communicators, i.e., the
- * communication channels are stored during
- * successive calls to a given function. This
- * reduces the overhead involved with setting
- * up the MPI machinery, but it does not
- * remove the need for a receive operation to
- * be posted before the data can actually be
- * sent.
+ * A vector that collects all requests from @p compress()
+ * operations. This class uses persistent MPI communicators, i.e., the
+ * communication channels are stored during successive calls to a given
+ * function. This reduces the overhead involved with setting up the MPI
+ * machinery, but it does not remove the need for a receive operation to
+ * be posted before the data can actually be sent.
*/
std::vector<MPI_Request> compress_requests;
/**
- * A vector that collects all requests from @p
- * update_ghost_values() operations. This class uses
- * persistent MPI communicators.
+ * A vector that collects all requests from @p update_ghost_values()
+ * operations. This class uses persistent MPI communicators.
*/
mutable std::vector<MPI_Request> update_ghost_values_requests;
#endif
/**
- * A lock that makes sure that
- * the @p compress and @p
- * update_ghost_values functions
- * give reasonable results also
- * when used with several
- * threads.
+ * A lock that makes sure that the @p compress and @p
+ * update_ghost_values functions give reasonable results also when used
+ * with several threads.
*/
mutable Threads::Mutex mutex;
/**
- * A helper function that clears the
- * compress_requests and update_ghost_values_requests
- * field. Used in reinit functions.
+ * A helper function that clears the compress_requests and
+ * update_ghost_values_requests field. Used in reinit functions.
*/
void clear_mpi_requests ();
/**
- * A helper function that is used to resize
- * the val array.
+ * A helper function that is used to resize the val array.
*/
void resize_val (const unsigned int new_allocated_size);
/*
- * Make all other vector types
- * friends.
+ * Make all other vector types friends.
*/
template <typename Number2> friend class Vector;
+
+ /**
+ * Make BlockVector type friends.
+ */
+ template <typename Number2> friend class BlockVector;
};
/*@}*/
void
Vector<Number>::compress (::dealii::VectorOperation::values operation)
{
- compress_start ();
- if (operation == ::dealii::VectorOperation::insert)
- compress_finish (false);
- else
- compress_finish (true);
+ compress_start (0, operation);
+ compress_finish(operation);
}
+
+
template <typename Number>
inline
void
}
+
+ template <typename Number>
+ inline
+ void
+ Vector<Number>::compress_finish (const bool add_value)
+ {
+ if (add_value)
+ compress_finish(VectorOperation::add);
+ else
+ compress_finish(VectorOperation::insert);
+ }
+
+
+
template <typename Number>
inline
void
+ template <typename Number>
+ inline
+ bool
+ Vector<Number>::all_zero_local () const
+ {
+ return partitioner->local_size()>0 ? vector_view.all_zero () : true;
+ }
+
+
+
template <typename Number>
inline
bool
Vector<Number>::all_zero () const
{
- // use int instead of bool
- int local_result = (partitioner->local_size()>0 ?
- -vector_view.all_zero () : -1);
+ // use int instead of bool. in order to make global reduction operations
+ // work also when MPI_Init was not called, only call MPI_Allreduce
+ // commands when there is more than one processor (note that reinit()
+ // functions handle this case correctly through the job_supports_mpi()
+ // query). this is the same in all the functions below
+ int local_result = -static_cast<int>(all_zero_local());
if (partitioner->n_mpi_processes() > 1)
return -Utilities::MPI::max(local_result,
partitioner->get_communicator());
else
- return local_result;
+ return -local_result;
+ }
+
+
+
+ template <typename Number>
+ inline
+ bool
+ Vector<Number>::is_non_negative_local () const
+ {
+ return partitioner->local_size()>0 ? vector_view.is_non_negative () : true;
}
bool
Vector<Number>::is_non_negative () const
{
- // use int instead of bool. in order to make this operation work also
- // when MPI_Init was not called, only call MPI_Allreduce commands when
- // there is more than one processor (note that reinit() functions handle
- // this case correctly through the job_supports_mpi() query)
- int local_result = (partitioner->local_size()>0 ?
- -vector_view.is_non_negative () : -1);
+ int local_result = -static_cast<int>(is_non_negative_local());
if (partitioner->n_mpi_processes() > 1)
- return -Utilities::MPI::max(local_result,
- partitioner->get_communicator());
+ return -Utilities::MPI::max(local_result,
+ partitioner->get_communicator());
else
- return local_result;
+ return -local_result;
}
template <typename Number2>
inline
bool
- Vector<Number>::operator == (const Vector<Number2> &v) const
+ Vector<Number>::vectors_equal_local (const Vector<Number2> &v) const
{
- AssertDimension (local_size(), v.local_size());
+ return partitioner->local_size()>0 ?
+ vector_view.template operator == <Number2>(v.vector_view)
+ : true;
+ }
+
+
+ template <typename Number>
+ template <typename Number2>
+ inline
+ bool
+ Vector<Number>::operator == (const Vector<Number2> &v) const
+ {
// MPI does not support bools, so use unsigned int instead. Two vectors
// are equal if the check for non-equal fails on all processors
- unsigned int local_result = (partitioner->local_size()>0 ?
- vector_view.template operator !=
- <Number2>(v.vector_view)
- : 0 );
+ unsigned int local_result = static_cast<int>(!vectors_equal_local(v));
unsigned int result =
partitioner->n_mpi_processes() > 1
?
+ template <typename Number>
+ template <typename Number2>
+ inline
+ Number
+ Vector<Number>::inner_product_local(const Vector<Number2> &V) const
+ {
+ // on some processors, the size might be zero, which is not allowed by
+ // the dealii::Vector class. Therefore, insert a check here
+ return (partitioner->local_size()>0 ?
+ vector_view.operator* (V.vector_view)
+ : Number());
+ }
+
+
+
template <typename Number>
template <typename Number2>
inline
Number
Vector<Number>::operator * (const Vector<Number2> &V) const
{
- Number local_result = (partitioner->local_size()>0 ?
- vector_view.operator* (V.vector_view)
- : 0);
+ Number local_result = inner_product_local(V);
if (partitioner->n_mpi_processes() > 1)
return Utilities::MPI::sum (local_result,
partitioner->get_communicator());
+ template <typename Number>
+ inline
+ typename Vector<Number>::real_type
+ Vector<Number>::norm_sqr_local () const
+ {
+ return partitioner->local_size()>0 ? vector_view.norm_sqr() : real_type();
+ }
+
+
+
template <typename Number>
inline
typename Vector<Number>::real_type
Vector<Number>::norm_sqr () const
{
- // on some processors, the size might be zero,
- // which is not allowed by the base
- // class. Therefore, insert a check here
- real_type local_result = (partitioner->local_size()>0 ?
- vector_view.norm_sqr()
- : 0);
+ real_type local_result = norm_sqr_local();
if (partitioner->n_mpi_processes() > 1)
return Utilities::MPI::sum(local_result,
partitioner->get_communicator());
+ template <typename Number>
+ inline
+ Number
+ Vector<Number>::mean_value_local () const
+ {
+ Assert (partitioner->size()!=0, ExcEmptyObject());
+ return (partitioner->local_size()>0 ?
+ vector_view.mean_value()
+ : Number());
+ }
+
+
+
template <typename Number>
inline
Number
Vector<Number>::mean_value () const
{
- Number local_result =
- (partitioner->local_size()>0 ?
- vector_view.mean_value()
- : 0)
- *((real_type)partitioner->local_size()/(real_type)partitioner->size());
+ Number local_result = mean_value_local();
if (partitioner->n_mpi_processes() > 1)
- return Utilities::MPI::sum (local_result,
- partitioner->get_communicator());
+ return Utilities::MPI::sum (local_result *
+ (real_type)partitioner->local_size(),
+ partitioner->get_communicator())
+ /(real_type)partitioner->size();
else
return local_result;
}
+ template <typename Number>
+ inline
+ typename Vector<Number>::real_type
+ Vector<Number>::l1_norm_local () const
+ {
+ return partitioner->local_size()>0 ? vector_view.l1_norm() : real_type();
+ }
+
+
+
template <typename Number>
inline
typename Vector<Number>::real_type
Vector<Number>::l1_norm () const
{
- real_type local_result = (partitioner->local_size()>0 ?
- vector_view.l1_norm()
- : 0);
+ real_type local_result = l1_norm_local();
if (partitioner->n_mpi_processes() > 1)
return Utilities::MPI::sum(local_result,
partitioner->get_communicator());
+ template <typename Number>
+ inline
+ typename Vector<Number>::real_type
+ Vector<Number>::lp_norm_local (const real_type p) const
+ {
+ return partitioner->local_size()>0 ? vector_view.lp_norm(p) : real_type();
+ }
+
+
+
template <typename Number>
inline
typename Vector<Number>::real_type
Vector<Number>::lp_norm (const real_type p) const
{
- const real_type local_result = (partitioner->local_size()>0 ?
- vector_view.lp_norm(p)
- : 0);
+ const real_type local_result = lp_norm_local(p);
if (partitioner->n_mpi_processes() > 1)
return std::pow (Utilities::MPI::sum(std::pow(local_result,p),
partitioner->get_communicator()),
+ template <typename Number>
+ inline
+ typename Vector<Number>::real_type
+ Vector<Number>::linfty_norm_local () const
+ {
+ return partitioner->local_size()>0 ? vector_view.linfty_norm() : real_type();
+ }
+
+
+
template <typename Number>
inline
typename Vector<Number>::real_type
Vector<Number>::linfty_norm () const
{
- const real_type local_result = (partitioner->local_size()>0 ?
- vector_view.linfty_norm()
- : 0);
+ const real_type local_result = linfty_norm_local();
if (partitioner->n_mpi_processes() > 1)
return Utilities::MPI::max (local_result,
partitioner->get_communicator());
}
+ template <typename Number>
+ inline
+ IndexSet
+ Vector<Number>::locally_owned_elements() const
+ {
+ IndexSet is (size());
+
+ const std::pair<types::global_dof_index,types::global_dof_index> x = local_range();
+ is.add_range (x.first, x.second);
+
+ return is;
+ }
+
+
template <typename Number>
inline
+ template <typename Number>
+ inline
+ const MPI_Comm&
+ Vector<Number>::get_mpi_communicator() const
+ {
+ return partitioner->get_communicator();
+ }
+
+
+
template <typename Number>
inline
bool
//----------%-----------------------------------------------------------------
// $Id$
//
-// Copyright (C) 2011, 2012 by the deal.II authors
+// Copyright (C) 2011, 2012, 2013 by the deal.II authors
//
// This file is subject to QPL and may not be distributed
// without copyright and license information. Please refer
{
delete [] import_data;
- // do not reallocate import_data directly, but
- // only upon request. It is only used as
- // temporary storage for compress() and
- // update_ghost_values, and we might have vectors where
- // we never call these methods and hence do
- // not need to have the storage.
+ // do not reallocate import_data directly, but only upon request. It
+ // is only used as temporary storage for compress() and
+ // update_ghost_values, and we might have vectors where we never
+ // call these methods and hence do not need to have the storage.
import_data = 0;
}
}
{
delete [] import_data;
- // do not reallocate import_data directly, but
- // only upon request. It is only used as
- // temporary storage for compress() and
- // update_ghost_values, and we might have vectors where
- // we never call these methods and hence do
- // not need to have the storage.
+ // do not reallocate import_data directly, but only upon request. It
+ // is only used as temporary storage for compress() and
+ // update_ghost_values, and we might have vectors where we never
+ // call these methods and hence do not need to have the storage.
import_data = 0;
}
}
template <typename Number>
void
- Vector<Number>::compress_start (const unsigned int counter)
+ Vector<Number>::compress_start (const unsigned int counter,
+ ::dealii::VectorOperation::values operation)
{
#ifdef DEAL_II_WITH_MPI
+
+ // nothing to do for insert (only need to zero ghost entries in
+ // compress_finish(). in debug mode we still want to check consistency
+ // of the inserted data, therefore the communication is still
+ // initialized
+#ifndef DEBUG
+ if (operation == VectorOperation::insert)
+ return;
+#endif
+
const Utilities::MPI::Partitioner &part = *partitioner;
// nothing to do when we neither have import
ierr = MPI_Startall(compress_requests.size(),&compress_requests[0]);
Assert (ierr == MPI_SUCCESS, ExcInternalError());
}
-#else
+
+#else // ifdef DEAL_II_WITH_MPI
(void)counter;
+ (void)operation;
#endif
+
}
template <typename Number>
void
- Vector<Number>::compress_finish (const bool add_ghost_data)
+ Vector<Number>::compress_finish (::dealii::VectorOperation::values operation)
{
#ifdef DEAL_II_WITH_MPI
+
const Utilities::MPI::Partitioner &part = *partitioner;
// nothing to do when we neither have import
const unsigned int n_import_targets = part.import_targets().size();
const unsigned int n_ghost_targets = part.ghost_targets().size();
- AssertDimension (n_ghost_targets+n_import_targets,
- compress_requests.size());
+ if (operation != dealii::VectorOperation::insert)
+ AssertDimension (n_ghost_targets+n_import_targets,
+ compress_requests.size());
// first wait for the receive to complete
- if (n_import_targets > 0)
+ if (compress_requests.size() > 0 && n_import_targets > 0)
{
int ierr;
ierr = MPI_Waitall (n_import_targets, &compress_requests[0],
std::vector<std::pair<unsigned int, unsigned int> >::const_iterator
my_imports = part.import_indices().begin();
- // If add_ghost_data is set, add the imported
- // data to the local values. If not, set the
- // vector entries.
- if (add_ghost_data == true)
+ // If the operation is no insertion, add the imported data to the
+ // local values. For insert, nothing is done here (but in debug mode
+ // we assert that the specified value is either zero or matches with
+ // the ones already present
+ if (operation != dealii::VectorOperation::insert)
for ( ; my_imports!=part.import_indices().end(); ++my_imports)
for (unsigned int j=my_imports->first; j<my_imports->second; j++)
local_element(j) += *read_position++;
else
for ( ; my_imports!=part.import_indices().end(); ++my_imports)
- for (unsigned int j=my_imports->first; j<my_imports->second; j++)
- local_element(j) = *read_position++;
+ for (unsigned int j=my_imports->first; j<my_imports->second;
+ j++, read_position++)
+ Assert(*read_position == 0. ||
+ std::abs(local_element(j) - *read_position) <
+ std::abs(local_element(j)) * 100. *
+ std::numeric_limits<Number>::epsilon(),
+ ExcMessage("Inserted elements do not match."));
AssertDimension(read_position-import_data,part.n_import_indices());
}
- if (n_ghost_targets > 0)
+ if (compress_requests.size() > 0 && n_ghost_targets > 0)
{
int ierr;
ierr = MPI_Waitall (n_ghost_targets,
&compress_requests[n_import_targets],
MPI_STATUSES_IGNORE);
Assert (ierr == MPI_SUCCESS, ExcInternalError());
- zero_out_ghosts ();
}
else
AssertDimension (part.n_ghost_indices(), 0);
+
+ zero_out_ghosts ();
#else
- (void)add_ghost_data;
+ (void)operation;
#endif
}
{
public:
/**
+ * A variable that indicates whether this vector
+ * supports distributed data storage. If true, then
+ * this vector also needs an appropriate compress()
+ * function that allows communicating recent set or
+ * add operations to individual elements to be communicated
+ * to other processors.
+ *
+ * For the current class, the variable equals
+ * true, since it does support parallel data storage.
+ */
+ static const bool supports_distributed_data = true;
+
+ /**
* Default constructor. Initialize the
* vector as empty.
*/
class Vector : public VectorBase
{
public:
+ /**
+ * A variable that indicates whether this vector
+ * supports distributed data storage. If true, then
+ * this vector also needs an appropriate compress()
+ * function that allows communicating recent set or
+ * add operations to individual elements to be communicated
+ * to other processors.
+ *
+ * For the current class, the variable equals
+ * false, since it does not support parallel data storage.
+ * If you do need parallel data storage, use
+ * PETScWrappers::MPI::Vector.
+ */
+ static const bool supports_distributed_data = false;
+
/**
* Default constructor. Initialize the
* vector as empty.
*/
bool in_local_range (const unsigned int index) const;
+ /**
+ * Return an index set that describes which elements of this vector
+ * are owned by the current processor. Note that this index set does
+ * not include elements this vector may store locally as ghost
+ * elements but that are in fact owned by another processor.
+ * As a consequence, the index sets returned on different
+ * processors if this is a distributed vector will form disjoint
+ * sets that add up to the complete index set.
+ * Obviously, if a vector is created on only one processor, then
+ * the result would satisfy
+ * @code
+ * vec.locally_owned_elements() == complete_index_set (vec.size())
+ * @endcode
+ */
+ IndexSet locally_owned_elements () const;
+
/**
* Return if the vector contains ghost
* elements.
(index < static_cast<unsigned int>(end)));
}
+
+ inline
+ IndexSet
+ VectorBase::locally_owned_elements() const
+ {
+ IndexSet is (size());
+
+ // PETSc only allows for contiguous local ranges, so this is simple
+ const std::pair<unsigned int, unsigned int> x = local_range();
+ is.add_range (x.first, x.second);
+ return is;
+ }
+
+
+
inline
bool
VectorBase::has_ghost_elements() const
#include <deal.II/base/parallel.h>
#include <deal.II/base/template_constraints.h>
#include <deal.II/lac/tridiagonal_matrix.h>
+#include <deal.II/lac/solver_cg.h>
#include <deal.II/lac/vector_memory.h>
DEAL_II_NAMESPACE_OPEN
+// forward declarations
+
template <typename number> class Vector;
template <typename number> class SparseMatrix;
namespace parallel
template <typename number> class Vector;
}
}
+template <typename> class SolverCG;
+
+
/*! @addtogroup Preconditioners
*@{
{
public:
/**
- * Standardized data struct to
- * pipe additional parameters
- * to the preconditioner.
+ * Standardized data struct to pipe additional parameters to the
+ * preconditioner.
*/
struct AdditionalData
{
const double smoothing_range = 0.,
const bool nonzero_starting = false,
const unsigned int eig_cg_n_iterations = 8,
- const double eig_cg_residual = 1e-2);
+ const double eig_cg_residual = 1e-2,
+ const double max_eigenvalue = 1);
/**
- * This determines the degree of the
- * Chebyshev polynomial. The degree
- * of the polynomial gives the number
- * of matrix-vector products to be
- * performed for one application of
- * the vmult() operation. Degree zero
- * corresponds to a damped Jacobi
- * method.
+ * This determines the degree of the Chebyshev polynomial. The degree of
+ * the polynomial gives the number of matrix-vector products to be
+ * performed for one application of the vmult() operation. Degree zero
+ * corresponds to a damped Jacobi method.
*/
unsigned int degree;
/**
- * This sets the range between the
- * largest eigenvalue in the matrix
- * and the smallest eigenvalue to be
- * treated. If the parameter is zero,
- * an estimate for the largest and
- * for the smallest eigenvalue will
- * be calculated
- * internally. Otherwise, the
- * Chebyshev polynomial will act in
- * the interval
- * $[\lambda_\mathrm{max}/
- * \tt{smoothing\_range},
- * \lambda_\mathrm{max}]$, where
- * $\lambda_\mathrm{max}$ is an
- * estimate of the maximum eigenvalue
- * of the matrix. A choice of
- * <tt>smoothing_range</tt> between 5
- * and 20 is useful in case the
- * preconditioner is used as a
- * smoother in multigrid.
+ * This sets the range between the largest eigenvalue in the matrix and
+ * the smallest eigenvalue to be treated. If the parameter is zero, an
+ * estimate for the largest and for the smallest eigenvalue will be
+ * calculated internally. Otherwise, the Chebyshev polynomial will act in
+ * the interval $[\lambda_\mathrm{max}/ \tt{smoothing\_range},
+ * \lambda_\mathrm{max}]$, where $\lambda_\mathrm{max}$ is an estimate of
+ * the maximum eigenvalue of the matrix. A choice of
+ * <tt>smoothing_range</tt> between 5 and 20 is useful in case the
+ * preconditioner is used as a smoother in multigrid.
*/
double smoothing_range;
/**
- * When this flag is set to
- * <tt>true</tt>, it enables the
- * method <tt>vmult(dst, src)</tt> to
- * use non-zero data in the vector
- * <tt>dst</tt>, appending to it the
- * Chebyshev corrections. This can be
- * useful in some situations
- * (e.g. when used for high-frequency
- * error smoothing in a multigrid
- * algorithm), but not the way the
- * solver classes expect a
- * preconditioner to work (where one
- * ignores the content in
- * <tt>dst</tt> for the
- * preconditioner application).
+ * When this flag is set to <tt>true</tt>, it enables the method
+ * <tt>vmult(dst, src)</tt> to use non-zero data in the vector
+ * <tt>dst</tt>, appending to it the Chebyshev corrections. This can be
+ * useful in some situations (e.g. when used for high-frequency error
+ * smoothing in a multigrid algorithm), but not the way the solver classes
+ * expect a preconditioner to work (where one ignores the content in
+ * <tt>dst</tt> for the preconditioner application).
*/
bool nonzero_starting;
/**
- * Maximum number of CG iterations
- * performed for finding the maximum
- * eigenvalue.
+ * Maximum number of CG iterations performed for finding the maximum
+ * eigenvalue. If set to zero, no computations are performed and the
+ * eigenvalues according to the given input are used instead.
*/
unsigned int eig_cg_n_iterations;
/**
- * Tolerance for CG iterations
- * performed for finding the maximum
+ * Tolerance for CG iterations performed for finding the maximum
* eigenvalue.
*/
double eig_cg_residual;
/**
- * Stores the inverse of the diagonal
- * of the underlying matrix.
+ * Maximum eigenvalue to work with. Only in effect if @p
+ * eig_cg_n_iterations is set to zero, otherwise this parameter is
+ * ignored.
+ */
+ double max_eigenvalue;
+
+ /**
+ * Stores the inverse of the diagonal of the underlying matrix.
*/
VECTOR matrix_diagonal_inverse;
};
PreconditionChebyshev ();
/**
- * Initialize function. Takes the
- * matrix which is used to form the
- * preconditioner, and additional
- * flags if there are any. This
- * function works only if the input
- * matrix has an operator
- * <tt>el(i,i)</tt> for accessing all
- * the elements in the
- * diagonal. Alternatively, the
- * diagonal can be supplied with the
- * help of the AdditionalData field.
+ * Initialize function. Takes the matrix which is used to form the
+ * preconditioner, and additional flags if there are any. This function
+ * works only if the input matrix has an operator <tt>el(i,i)</tt> for
+ * accessing all the elements in the diagonal. Alternatively, the diagonal
+ * can be supplied with the help of the AdditionalData field.
*
- * This function calculates an
- * estimate of the eigenvalue range
- * of the matrix weighted by its
- * diagonal using a modified CG
- * iteration.
+ * This function calculates an estimate of the eigenvalue range of the
+ * matrix weighted by its diagonal using a modified CG iteration in case the
+ * given number of iterations is positive.
*/
void initialize (const MATRIX &matrix,
const AdditionalData &additional_data = AdditionalData());
/**
- * Computes the action of the
- * preconditioner on <tt>src</tt>,
- * storing the result in
- * <tt>dst</tt>.
+ * Computes the action of the preconditioner on <tt>src</tt>, storing the
+ * result in <tt>dst</tt>.
*/
void vmult (VECTOR &dst,
const VECTOR &src) const;
/**
- * Computes the action of the
- * transposed preconditioner on
- * <tt>src</tt>, storing the result
- * in <tt>dst</tt>.
+ * Computes the action of the transposed preconditioner on <tt>src</tt>,
+ * storing the result in <tt>dst</tt>.
*/
void Tvmult (VECTOR &dst,
const VECTOR &src) const;
private:
/**
- * A pointer to the underlying
- * matrix.
+ * A pointer to the underlying matrix.
*/
SmartPointer<const MATRIX,PreconditionChebyshev<MATRIX,VECTOR> > matrix_ptr;
/**
- * Internal vector used for the
- * <tt>vmult</tt> operation.
+ * Internal vector used for the <tt>vmult</tt> operation.
*/
mutable VECTOR update1;
/**
- * Internal vector used for the
- * <tt>vmult</tt> operation.
+ * Internal vector used for the <tt>vmult</tt> operation.
*/
mutable VECTOR update2;
/**
- * Stores the additional data
- * provided to the initialize
- * function.
+ * Stores the additional data provided to the initialize function.
*/
AdditionalData data;
/**
- * Average of the largest and
- * smallest eigenvalue under
- * consideration.
+ * Average of the largest and smallest eigenvalue under consideration.
*/
double theta;
/**
- * Half the interval length between
- * the largest and smallest
- * eigenvalue under consideration.
+ * Half the interval length between the largest and smallest eigenvalue
+ * under consideration.
*/
double delta;
/**
- * Stores whether the preconditioner
- * has been set up.
+ * Stores whether the preconditioner has been set up.
*/
bool is_initialized;
};
//---------------------------------------------------------------------------
-template <class MATRIX, class VECTOR>
-inline
-PreconditionChebyshev<MATRIX,VECTOR>::AdditionalData::
-AdditionalData (const unsigned int degree,
- const double smoothing_range,
- const bool nonzero_starting,
- const unsigned int eig_cg_n_iterations,
- const double eig_cg_residual)
- :
- degree (degree),
- smoothing_range (smoothing_range),
- nonzero_starting (nonzero_starting),
- eig_cg_n_iterations (eig_cg_n_iterations),
- eig_cg_residual (eig_cg_residual)
-{}
-
-
-
-template <class MATRIX, class VECTOR>
-inline
-PreconditionChebyshev<MATRIX,VECTOR>::PreconditionChebyshev ()
- :
- is_initialized (false)
-{}
-
-
-
-template <class MATRIX, class VECTOR>
-inline
-void
-PreconditionChebyshev<MATRIX,VECTOR>::initialize (const MATRIX &matrix,
- const AdditionalData &additional_data)
-{
- Assert (matrix.m() == matrix.n(), ExcMessage("Matrix not quadratic."));
- Assert (additional_data.eig_cg_n_iterations > 2,
- ExcMessage ("Need to set at least two iterations to find eigenvalues."));
- matrix_ptr = &matrix;
- data = additional_data;
- if (data.matrix_diagonal_inverse.size() != matrix.m())
- {
- data.matrix_diagonal_inverse.reinit(matrix.m());
- for (unsigned int i=0; i<matrix.m(); ++i)
- data.matrix_diagonal_inverse(i) = 1./matrix.el(i,i);
- }
- update1.reinit (data.matrix_diagonal_inverse, true);
- update2.reinit (data.matrix_diagonal_inverse, true);
-
-
- // calculate largest eigenvalue using a
- // hand-tuned CG iteration on the matrix
- // weighted by its diagonal. we start
- // with a vector that consists of ones
- // only, weighted by the length.
- //
- // TODO: can we obtain this with the
- // regular CG implementation? we would need
- // to read the logfile in that case, which
- // does not seem feasible.
- double max_eigenvalue, min_eigenvalue;
- {
- double eigen_beta_alpha = 0;
-
- std::vector<double> diagonal;
- std::vector<double> offdiagonal;
-
- VECTOR rhs, g;
- rhs.reinit(data.matrix_diagonal_inverse, true);
- rhs = 1./std::sqrt(static_cast<double>(matrix.m()));
- g.reinit(data.matrix_diagonal_inverse, true);
-
- unsigned int it=0;
- double res,gh,alpha,beta;
-
- g.equ(-1.,rhs);
- res = g.l2_norm();
- update2.equ (-1., g);
- gh = res*res;
-
- while (true)
- {
- it++;
- matrix.vmult (update1, update2);
- update1.scale (data.matrix_diagonal_inverse);
- alpha = update2 * update1;
- alpha = gh/alpha;
- g.add (alpha, update1);
- res = g.l2_norm();
-
- // need at least two iterations to have
- // maximum and minimum eigenvalue
- if (res == 0. ||
- it > data.eig_cg_n_iterations || (it > 2 &&
- res < data.eig_cg_residual))
- break;
-
- beta = gh;
- gh = res*res;
- beta = gh/beta;
- update2.sadd (beta, -1., g);
-
- diagonal.push_back (1./alpha + eigen_beta_alpha);
- eigen_beta_alpha = beta/alpha;
- offdiagonal.push_back(std::sqrt(beta)/alpha);
- }
-
- if (diagonal.size() == 0)
- min_eigenvalue = max_eigenvalue = 1.;
- else
- {
- TridiagonalMatrix<double> T(diagonal.size(), true);
- for (unsigned int i=0; i<diagonal.size(); ++i)
- {
- T(i,i) = diagonal[i];
- if (i< diagonal.size()-1)
- T(i,i+1) = offdiagonal[i];
- }
- T.compute_eigenvalues();
- min_eigenvalue = T.eigenvalue(0);
- if (diagonal.size() > 1)
- max_eigenvalue = T.eigenvalue(T.n()-1);
- else
- max_eigenvalue = min_eigenvalue;
- }
- }
-
- // include a safety factor since the CG
- // method will in general not be converged
- const double beta = 1.2 * max_eigenvalue;
- const double alpha = (data.smoothing_range > 0 ?
- max_eigenvalue / data.smoothing_range :
- max_eigenvalue / min_eigenvalue);
- delta = (beta-alpha)*0.5;
- theta = (beta+alpha)*0.5;
- is_initialized = true;
-}
-
-
-
namespace internal
{
namespace PreconditionChebyshev
start_zero, factor1, factor2,
update1.begin(), update2.begin(), dst.begin());
}
+
+ template <typename VECTOR>
+ struct DiagonalPreconditioner
+ {
+ DiagonalPreconditioner (const VECTOR &vector)
+ :
+ diagonal_vector(vector)
+ {}
+
+ void vmult (VECTOR &dst,
+ const VECTOR &src) const
+ {
+ dst = src;
+ dst.scale(diagonal_vector);
+ }
+
+ const VECTOR &diagonal_vector;
+ };
}
}
+template <class MATRIX, class VECTOR>
+inline
+PreconditionChebyshev<MATRIX,VECTOR>::AdditionalData::
+AdditionalData (const unsigned int degree,
+ const double smoothing_range,
+ const bool nonzero_starting,
+ const unsigned int eig_cg_n_iterations,
+ const double eig_cg_residual,
+ const double max_eigenvalue)
+ :
+ degree (degree),
+ smoothing_range (smoothing_range),
+ nonzero_starting (nonzero_starting),
+ eig_cg_n_iterations (eig_cg_n_iterations),
+ eig_cg_residual (eig_cg_residual),
+ max_eigenvalue (max_eigenvalue)
+{}
+
+
+
+template <class MATRIX, class VECTOR>
+inline
+PreconditionChebyshev<MATRIX,VECTOR>::PreconditionChebyshev ()
+ :
+ is_initialized (false)
+{}
+
+
+
+template <class MATRIX, class VECTOR>
+inline
+void
+PreconditionChebyshev<MATRIX,VECTOR>::initialize (const MATRIX &matrix,
+ const AdditionalData &additional_data)
+{
+ matrix_ptr = &matrix;
+ data = additional_data;
+ if (data.matrix_diagonal_inverse.size() != matrix.m())
+ {
+ Assert(data.matrix_diagonal_inverse.size() == 0,
+ ExcMessage("Matrix diagonal vector set but not sized correctly"));
+ data.matrix_diagonal_inverse.reinit(matrix.m());
+ for (unsigned int i=0; i<matrix.m(); ++i)
+ data.matrix_diagonal_inverse(i) = 1./matrix.el(i,i);
+ }
+
+
+ // calculate largest eigenvalue using a hand-tuned CG iteration on the
+ // matrix weighted by its diagonal. we start with a vector that consists of
+ // ones only, weighted by the length.
+ double max_eigenvalue, min_eigenvalue;
+ if (data.eig_cg_n_iterations > 0)
+ {
+ Assert (additional_data.eig_cg_n_iterations > 2,
+ ExcMessage ("Need to set at least two iterations to find eigenvalues."));
+
+ // attach stream to SolverCG, run it with log report for eigenvalues
+ std::ostream *old_stream = deallog.has_file() ? &deallog.get_file_stream() :
+ static_cast<std::ostream *>(0);
+ if (old_stream)
+ deallog.detach();
+
+ std::ostringstream log_msg;
+ deallog.attach(log_msg);
+
+ // set a very strict tolerance to force at least two iterations
+ ReductionControl control (data.eig_cg_n_iterations, 1e-20, 1e-20);
+ GrowingVectorMemory<VECTOR> memory;
+ VECTOR *rhs = memory.alloc();
+ VECTOR *dummy = memory.alloc();
+ rhs->reinit(data.matrix_diagonal_inverse, true);
+ dummy->reinit(data.matrix_diagonal_inverse);
+ *rhs = 1./std::sqrt(static_cast<double>(matrix.m()));
+
+ typename SolverCG<VECTOR>::AdditionalData cg_data;
+ cg_data.compute_eigenvalues = true;
+ SolverCG<VECTOR> solver (control, memory, cg_data);
+ internal::PreconditionChebyshev::DiagonalPreconditioner<VECTOR>
+ preconditioner(data.matrix_diagonal_inverse);
+ try
+ {
+ solver.solve(matrix, *dummy, *rhs, preconditioner);
+ }
+ catch (SolverControl::NoConvergence &)
+ {
+ }
+ Assert(control.last_step() >= 2,
+ ExcMessage("Could not find eigenvalues"));
+
+ memory.free(dummy);
+ memory.free(rhs);
+
+ // read the log stream: grab the first and last eigenvalue
+ std::string cg_message = log_msg.str();
+ const std::size_t pos = cg_message.find("cg:: ");
+ Assert(pos < std::string::npos, ExcInternalError());
+ cg_message.erase(0, pos+5);
+ std::istringstream os1(cg_message);
+ os1 >> min_eigenvalue;
+ for (unsigned int i=0; i<control.last_step()-1; ++i)
+ cg_message.erase(0, cg_message.find_first_of(" ")+1);
+ std::istringstream os2(cg_message);
+ os2 >> max_eigenvalue;
+
+ // reset deal.II stream
+ deallog.detach();
+ if (old_stream)
+ deallog.attach(*old_stream, false);
+
+ // include a safety factor since the CG method will in general not be
+ // converged
+ max_eigenvalue *= 1.2;
+ }
+ else
+ {
+ max_eigenvalue = data.max_eigenvalue;
+ min_eigenvalue = data.max_eigenvalue/data.smoothing_range;
+ }
+
+ const double alpha = (data.smoothing_range > 0 ?
+ max_eigenvalue / data.smoothing_range :
+ max_eigenvalue / min_eigenvalue);
+ delta = (max_eigenvalue-alpha)*0.5;
+ theta = (max_eigenvalue+alpha)*0.5;
+
+ update1.reinit (data.matrix_diagonal_inverse, true);
+ update2.reinit (data.matrix_diagonal_inverse, true);
+
+ is_initialized = true;
+}
+
+
+
template <class MATRIX, class VECTOR>
inline
void
* calling sequence requires calling several of SolverBase functions
* rather than just one. This freedom is intended for use of the
* SLEPcWrappers that require a greater handle on the eigenvalue
- * problem solver context. See also the API of:
+ * problem solver context. See also the API of, for example:
@code
template <typename OutputVector>
void
SolverBase::solve (const PETScWrappers::MatrixBase &A,
const PETScWrappers::MatrixBase &B,
- std::vector<double> &kr,
- std::vector<OutputVector> &vr,
- const unsigned int n_eigenvectors)
+ std::vector<double> &eigenvalues,
+ std::vector<OutputVector> &eigenvectors,
+ const unsigned int n_eigenpairs)
{ ... }
@endcode
* as an example on how to do this.
* that we can use as a template when resizing, since we do not
* know the parameters of the specific vector class used
* (i.e. local_dofs for MPI vectors). However, while copying
- * eigenvectors, at least twice the memory size of <tt>vr</tt> is
- * being used (and can be more). To avoid doing this, the fairly
- * standard calling sequence executed here is used: Initialise;
- * Set up matrices for solving; Actually solve the system; Gather
- * the solution(s); and reset.
+ * eigenvectors, at least twice the memory size of
+ * <tt>eigenvectors</tt> is being used (and can be more). To avoid
+ * doing this, the fairly standard calling sequence executed here
+ * is used: Initialise; Set up matrices for solving; Actually
+ * solve the system; Gather the solution(s); and reset.
*
* @note Note that the number of converged eigenvectors can be
* larger than the number of eigenvectors requested; this is due
template <typename OutputVector>
void
solve (const PETScWrappers::MatrixBase &A,
- std::vector<double> &kr,
- std::vector<OutputVector> &vr,
- const unsigned int n_eigenvectors = 1);
+ std::vector<double> &eigenvalues,
+ std::vector<OutputVector> &eigenvectors,
+ const unsigned int n_eigenpairs = 1);
/**
* Same as above, but here a composite method for solving the
- * system $A x=\lambda B x$.
+ * system $A x=\lambda B x$, for real matrices, vectors, and
+ * values $A, B, x, \lambda$.
*/
template <typename OutputVector>
void
solve (const PETScWrappers::MatrixBase &A,
const PETScWrappers::MatrixBase &B,
- std::vector<double> &kr,
- std::vector<OutputVector> &vr,
- const unsigned int n_eigenvectors = 1);
+ std::vector<double> &eigenvalues,
+ std::vector<OutputVector> &eigenvectors,
+ const unsigned int n_eigenpairs = 1);
+
+ /**
+ * Same as above, but here a composite method for solving the
+ * system $A x=\lambda B x$ with real matrices $A, B$ and
+ * imaginary eigenpairs $x, \lamda$.
+ */
+ template <typename OutputVector>
+ void
+ solve (const PETScWrappers::MatrixBase &A,
+ const PETScWrappers::MatrixBase &B,
+ std::vector<double> &real_eigenvalues,
+ std::vector<double> &imag_eigenvalues,
+ std::vector<OutputVector> &real_eigenvectors,
+ std::vector<OutputVector> &imag_eigenvectors,
+ const unsigned int n_eigenpairs = 1);
/**
* Set the initial vector for the solver.
EPS *get_eps ();
/**
- * Solve the linear system for n_eigenvectors
+ * Solve the linear system for </code>n_eigenpairs</code>
* eigenstates. Parameter <code>n_converged</code> contains the
* actual number of eigenstates that have . converged; this can
- * be both fewer or more than n_eigenvectors, depending on the
+ * be both fewer or more than n_eigenpairs, depending on the
* SLEPc eigensolver used.
*/
void
- solve (const unsigned int n_eigenvectors, unsigned int *n_converged);
+ solve (const unsigned int n_eigenpairs, unsigned int *n_converged);
/**
- * Access the solutions for a solved eigenvector problem, pair
- * index solutions, $\text{index}\,\in\,0\hdots
+ * Access the real parts of solutions for a solved eigenvector
+ * problem, pair index solutions, $\text{index}\,\in\,0\hdots
* \text{n\_converged}-1$.
*/
void
- get_eigenpair (const unsigned int index,
-#ifndef PETSC_USE_COMPLEX
- double &kr,
-#else
- std::complex<double> &kr,
-#endif
- PETScWrappers::VectorBase &vr);
+ get_eigenpair (const unsigned int index,
+ double &eigenvalues,
+ PETScWrappers::VectorBase &eigenvectors);
+
+ /**
+ * Access the real and imaginary parts of solutions for a solved
+ * eigenvector problem, pair index solutions,
+ * $\text{index}\,\in\,0\hdots \text{n\_converged}-1$.
+ */
+ void
+ get_eigenpair (const unsigned int index,
+ double &real_eigenvalues,
+ double &imag_eigenvalues,
+ PETScWrappers::VectorBase &real_eigenvectors,
+ PETScWrappers::VectorBase &imag_eigenvectors);
/**
* Initialize solver for the linear system $Ax=\lambda x$. (Note:
static
int
convergence_test (EPS eps,
- PetscScalar kr,
- PetscScalar ki,
+ PetscScalar real_eigenvalue,
+ PetscScalar imag_eigenvalue,
PetscReal residual_norm,
PetscReal *estimated_error,
void *solver_control);
* This is declared here to make it possible to take a std::vector
* of different PETScWrappers vector types
*/
+ // todo: The logic of these functions can be simplified without breaking backward compatibility...
template <typename OutputVector>
- void
- SolverBase::solve (const PETScWrappers::MatrixBase &A,
- std::vector<double> &kr,
- std::vector<OutputVector> &vr,
- const unsigned int n_eigenvectors)
- {
- // Panic if no eigenpairs are wanted.
- AssertThrow (n_eigenvectors != 0, ExcSLEPcWrappersUsageError());
-
- unsigned int n_converged = 0;
-
- // Set the matrices of the problem
- set_matrices (A);
-
- // and solve
- solve (n_eigenvectors, &n_converged);
-
- if (n_converged > n_eigenvectors)
- n_converged = n_eigenvectors;
- AssertThrow (n_converged == n_eigenvectors,
- ExcSLEPcEigenvectorConvergenceMismatchError(n_converged, n_eigenvectors));
-
- AssertThrow (vr.size() != 0, ExcSLEPcWrappersUsageError());
- vr.resize (n_converged, vr.front());
- kr.resize (n_converged);
-
- for (unsigned int index=0; index<n_converged; ++index)
- get_eigenpair (index, kr[index], vr[index]);
- }
-
+ void
+ SolverBase::solve (const PETScWrappers::MatrixBase &A,
+ std::vector<double> &eigenvalues,
+ std::vector<OutputVector> &eigenvectors,
+ const unsigned int n_eigenpairs)
+ {
+ // Panic if the number of eigenpairs wanted is out of bounds.
+ AssertThrow ((n_eigenpairs > 0) && (n_eigenpairs <= A.m ()),
+ ExcSLEPcWrappersUsageError());
+
+ // Set the matrices of the problem
+ set_matrices (A);
+
+ // and solve
+ unsigned int n_converged = 0;
+ solve (n_eigenpairs, &n_converged);
+
+ if (n_converged > n_eigenpairs)
+ n_converged = n_eigenpairs;
+ AssertThrow (n_converged == n_eigenpairs,
+ ExcSLEPcEigenvectorConvergenceMismatchError(n_converged, n_eigenpairs));
+
+ AssertThrow (eigenvectors.size() != 0, ExcSLEPcWrappersUsageError());
+ eigenvectors.resize (n_converged, eigenvectors.front());
+ eigenvalues.resize (n_converged);
+
+ for (unsigned int index=0; index<n_converged; ++index)
+ get_eigenpair (index, eigenvalues[index], eigenvectors[index]);
+ }
+
template <typename OutputVector>
- void
+ void
SolverBase::solve (const PETScWrappers::MatrixBase &A,
const PETScWrappers::MatrixBase &B,
- std::vector<double> &kr,
- std::vector<OutputVector> &vr,
- const unsigned int n_eigenvectors)
- {
- // Panic if no eigenpairs are wanted.
- AssertThrow (n_eigenvectors != 0, ExcSLEPcWrappersUsageError());
+ std::vector<double> &eigenvalues,
+ std::vector<OutputVector> &eigenvectors,
+ const unsigned int n_eigenpairs)
+ {
+ // Guard against incompatible matrix sizes:
+ AssertThrow (A.m() == B.m (), ExcDimensionMismatch(A.m(), B.m()));
+ AssertThrow (A.n() == B.n (), ExcDimensionMismatch(A.n(), B.n()));
+
+ // Panic if the number of eigenpairs wanted is out of bounds.
+ AssertThrow ((n_eigenpairs>0) && (n_eigenpairs<=A.m ()),
+ ExcSLEPcWrappersUsageError());
+
+ // Set the matrices of the problem
+ set_matrices (A, B);
+
+ // and solve
+ unsigned int n_converged = 0;
+ solve (n_eigenpairs, &n_converged);
+
+ if (n_converged>=n_eigenpairs)
+ n_converged = n_eigenpairs;
+
+ AssertThrow (n_converged==n_eigenpairs,
+ ExcSLEPcEigenvectorConvergenceMismatchError(n_converged, n_eigenpairs));
+ AssertThrow (eigenvectors.size() != 0, ExcSLEPcWrappersUsageError());
+
+ eigenvectors.resize (n_converged, eigenvectors.front());
+ eigenvalues.resize (n_converged);
+
+ for (unsigned int index=0; index<n_converged; ++index)
+ get_eigenpair (index, eigenvalues[index], eigenvectors[index]);
+ }
- unsigned int n_converged = 0;
-
- // Set the matrices of the problem
- set_matrices (A, B);
-
- // and solve
- solve (n_eigenvectors, &n_converged);
-
- if (n_converged >= n_eigenvectors)
- n_converged = n_eigenvectors;
-
- AssertThrow (n_converged == n_eigenvectors,
- ExcSLEPcEigenvectorConvergenceMismatchError(n_converged, n_eigenvectors));
- AssertThrow (vr.size() != 0, ExcSLEPcWrappersUsageError());
-
- vr.resize (n_converged, vr.front());
- kr.resize (n_converged);
+ template <typename OutputVector>
+ void
+ SolverBase::solve (const PETScWrappers::MatrixBase &A,
+ const PETScWrappers::MatrixBase &B,
+ std::vector<double> &real_eigenvalues,
+ std::vector<double> &imag_eigenvalues,
+ std::vector<OutputVector> &real_eigenvectors,
+ std::vector<OutputVector> &imag_eigenvectors,
+ const unsigned int n_eigenpairs)
+ {
+ // Guard against incompatible matrix sizes:
+ AssertThrow (A.m() == B.m (), ExcDimensionMismatch(A.m(), B.m()));
+ AssertThrow (A.n() == B.n (), ExcDimensionMismatch(A.n(), B.n()));
+
+ // and incompatible eigenvalue/eigenvector sizes
+ AssertThrow (real_eigenvalues.size() == imag_eigenvalues.size(),
+ ExcDimensionMismatch(real_eigenvalues.size(), imag_eigenvalues.size()));
+ AssertThrow (real_eigenvectors.size() == imag_eigenvectors.n (),
+ ExcDimensionMismatch(real_eigenvectors.size(), imag_eigenvectors.size()));
+
+ // Panic if the number of eigenpairs wanted is out of bounds.
+ AssertThrow ((n_eigenpairs>0) && (n_eigenpairs<=A.m ()),
+ ExcSLEPcWrappersUsageError());
+
+ // Set the matrices of the problem
+ set_matrices (A, B);
+
+ // and solve
+ unsigned int n_converged = 0;
+ solve (n_eigenpairs, &n_converged);
+
+ if (n_converged>=n_eigenpairs)
+ n_converged = n_eigenpairs;
+
+ AssertThrow (n_converged==n_eigenpairs,
+ ExcSLEPcEigenvectorConvergenceMismatchError(n_converged, n_eigenpairs));
+ AssertThrow ((real_eigenvectors.size()!=0) && (imag_eigenvectors.size()!=0),
+ ExcSLEPcWrappersUsageError());
+
+ real_eigenvectors.resize (n_converged, real_eigenvectors.front());
+ imag_eigenvectors.resize (n_converged, imag_eigenvectors.front());
+ real_eigenvalues.resize (n_converged);
+ imag_eigenvalues.resize (n_converged);
+
+ for (unsigned int index=0; index<n_converged; ++index)
+ get_eigenpair (index,
+ real_eigenvalues[index], imag_eigenvalues[index],
+ real_eigenvectors[index], imag_eigenvectors[index]);
+ }
- for (unsigned int index=0; index<n_converged; ++index)
- get_eigenpair (index, kr[index], vr[index]);
- }
}
DEAL_II_NAMESPACE_CLOSE
//---------------------------------------------------------------------------
// $Id$
//
-// Copyright (C) 1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2009, 2012 by the deal.II authors
+// Copyright (C) 1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2009, 2012, 2013 by the deal.II authors
//
// This file is subject to QPL and may not be distributed
// without copyright and license information. Please refer
{
public:
/**
- * There are two possibilities to
- * compute the residual: one is an
- * estimate using the computed value @p
- * tau. The other is exact computation
- * using another matrix vector
- * multiplication. This increases the
- * costs of the algorithm, so it is
- * should be set to false whenever the
- * problem allows it.
+ * There are two possibilities to compute the residual: one is an estimate
+ * using the computed value @p tau. The other is exact computation using
+ * another matrix vector multiplication. This increases the costs of the
+ * algorithm, so it is should be set to false whenever the problem allows
+ * it.
*
- * Bicgstab is susceptible to breakdowns, so
- * we need a parameter telling us, which
- * numbers are considered zero.
+ * Bicgstab is susceptible to breakdowns, so we need a parameter telling us,
+ * which numbers are considered zero.
*/
struct AdditionalData
{
/**
* Constructor.
*
- * The default is to perform an
- * exact residual computation and
- * breakdown parameter 1e-10.
+ * The default is to perform an exact residual computation and breakdown
+ * parameter 1e-10.
*/
AdditionalData(const bool exact_residual = true,
const double breakdown = 1.e-10) :
const AdditionalData &data=AdditionalData());
/**
- * Constructor. Use an object of
- * type GrowingVectorMemory as
- * a default to allocate memory.
+ * Constructor. Use an object of type GrowingVectorMemory as a default to
+ * allocate memory.
*/
SolverBicgstab (SolverControl &cn,
const AdditionalData &data=AdditionalData());
double criterion (const MATRIX &A, const VECTOR &x, const VECTOR &b);
/**
- * Interface for derived class.
- * This function gets the current
- * iteration vector, the residual
- * and the update vector in each
- * step. It can be used for a
- * graphical output of the
- * convergence history.
+ * Interface for derived class. This function gets the current iteration
+ * vector, the residual and the update vector in each step. It can be used
+ * for a graphical output of the convergence history.
*/
virtual void print_vectors(const unsigned int step,
const VECTOR &x,
* Auxiliary vector.
*/
VECTOR *Vz;
- /**
- * Auxiliary vector.
- */
- VECTOR *Vs;
/**
* Auxiliary vector.
*/
SolverBicgstab<VECTOR>::criterion (const MATRIX &A, const VECTOR &x, const VECTOR &b)
{
A.vmult(*Vt, x);
- Vt->sadd(-1.,1.,b);
+ Vt->add(-1.,b);
res = Vt->l2_norm();
return res;
Vr->sadd(-1.,1.,*Vb);
res = Vr->l2_norm();
- Vp->reinit(*Vx);
- Vv->reinit(*Vx);
- *Vrbar = *Vr;
return this->control().check(step, res);
}
VECTOR &p = *Vp;
VECTOR &y = *Vy;
VECTOR &z = *Vz;
- VECTOR &s = *Vs;
VECTOR &t = *Vt;
VECTOR &v = *Vv;
+ rbar = r;
+ bool startup = true;
+
do
{
++step;
rhobar = r*rbar;
beta = rhobar * alpha / (rho * omega);
rho = rhobar;
- p.sadd(beta, 1., r, -beta*omega, v);
+ if (startup == true)
+ {
+ p = r;
+ startup = false;
+ }
+ else
+ p.sadd(beta, 1., r, -beta*omega, v);
+
precondition.vmult(y,p);
A.vmult(v,y);
rhobar = rbar * v;
if (std::fabs(alpha) > 1.e10)
return true;
- s.equ(1., r, -alpha, v);
+ r.add(-alpha, v);
- // check for early success, see
- // the lac/bicgstab_early
- // testcase as to why this is
- // necessary
- if (this->control().check(step, s.l2_norm()/Vb->l2_norm())
- == SolverControl::success)
+ // check for early success, see the lac/bicgstab_early testcase as to
+ // why this is necessary
+ if (this->control().check(step, r.l2_norm()) == SolverControl::success)
{
Vx->add(alpha, y);
print_vectors(step, *Vx, r, y);
return false;
}
- precondition.vmult(z,s);
+ precondition.vmult(z,r);
A.vmult(t,z);
- rhobar = t*s;
+ rhobar = t*r;
omega = rhobar/(t*t);
Vx->add(alpha, y, omega, z);
- r.equ(1., s, -omega, t);
+ r.add(-omega, t);
if (additional_data.exact_residual)
res = criterion(A, *Vx, *Vb);
{
deallog.push("Bicgstab");
Vr = this->memory.alloc();
- Vr->reinit(x);
+ Vr->reinit(x, true);
Vrbar = this->memory.alloc();
- Vrbar->reinit(x);
+ Vrbar->reinit(x, true);
Vp = this->memory.alloc();
+ Vp->reinit(x, true);
Vy = this->memory.alloc();
- Vy->reinit(x);
+ Vy->reinit(x, true);
Vz = this->memory.alloc();
- Vz->reinit(x);
- Vs = this->memory.alloc();
- Vs->reinit(x);
+ Vz->reinit(x, true);
Vt = this->memory.alloc();
- Vt->reinit(x);
+ Vt->reinit(x, true);
Vv = this->memory.alloc();
+ Vv->reinit(x, true);
Vx = &x;
Vb = &b;
this->memory.free(Vp);
this->memory.free(Vy);
this->memory.free(Vz);
- this->memory.free(Vs);
this->memory.free(Vt);
this->memory.free(Vv);
deallog.pop();
- // in case of failure: throw
- // exception
+ // in case of failure: throw exception
if (this->control().last_check() != SolverControl::success)
throw SolverControl::NoConvergence (this->control().last_step(),
this->control().last_value());
namespace internal
{
/**
- * A namespace for a helper class
- * to the GMRES solver.
+ * A namespace for a helper class to the GMRES solver.
*/
namespace SolverGMRES
{
/**
- * Class to hold temporary
- * vectors. This class
- * automatically allocates a new
- * vector, once it is needed.
+ * Class to hold temporary vectors. This class automatically allocates a
+ * new vector, once it is needed.
*
- * A future version should also
- * be able to shift through
- * vectors automatically,
- * avoiding restart.
+ * A future version should also be able to shift through vectors
+ * automatically, avoiding restart.
*/
template <class VECTOR>
{
public:
/**
- * Constructor. Prepares an
- * array of @p VECTOR of
- * length @p max_size.
+ * Constructor. Prepares an array of @p VECTOR of length @p max_size.
*/
TmpVectors(const unsigned int max_size,
VectorMemory<VECTOR> &vmem);
~TmpVectors();
/**
- * Get vector number
- * @p i. If this vector was
- * unused before, an error
+ * Get vector number @p i. If this vector was unused before, an error
* occurs.
*/
VECTOR &operator[] (const unsigned int i) const;
/**
- * Get vector number
- * @p i. Allocate it if
- * necessary.
+ * Get vector number @p i. Allocate it if necessary.
*
- * If a vector must be
- * allocated, @p temp is
- * used to reinit it to the
+ * If a vector must be allocated, @p temp is used to reinit it to the
* proper dimensions.
*/
VECTOR &operator() (const unsigned int i,
private:
/**
- * Pool were vectors are
- * obtained from.
+ * Pool were vectors are obtained from.
*/
VectorMemory<VECTOR> &mem;
/**
- * Field for storing the
- * vectors.
+ * Field for storing the vectors.
*/
std::vector<VECTOR *> data;
/**
- * Offset of the first
- * vector. This is for later
- * when vector rotation will
- * be implemented.
+ * Offset of the first vector. This is for later when vector rotation
+ * will be implemented.
*/
unsigned int offset;
};
{
public:
/**
- * Standardized data struct to
- * pipe additional data to the
- * solver.
+ * Standardized data struct to pipe additional data to the solver.
*/
struct AdditionalData
{
/**
- * Constructor. By default, set the
- * number of temporary vectors to 30,
- * i.e. do a restart every
- * 28 iterations. Also
- * set preconditioning from left and
- * the residual of the stopping
- * criterion to the default residual.
+ * Constructor. By default, set the number of temporary vectors to 30,
+ * i.e. do a restart every 28 iterations. Also set preconditioning from
+ * left, the residual of the stopping criterion to the default
+ * residual, and re-orthogonalization only if necessary.
*/
AdditionalData (const unsigned int max_n_tmp_vectors = 30,
const bool right_preconditioning = false,
- const bool use_default_residual = true);
+ const bool use_default_residual = true,
+ const bool force_re_orthogonalization = false);
/**
- * Maximum number of
- * temporary vectors. This
- * parameter controls the
- * size of the Arnoldi basis,
- * which for historical
- * reasons is
+ * Maximum number of temporary vectors. This parameter controls the size
+ * of the Arnoldi basis, which for historical reasons is
* #max_n_tmp_vectors-2.
*/
unsigned int max_n_tmp_vectors;
/**
- * Flag for right
- * preconditioning.
+ * Flag for right preconditioning.
*
- * @note Change between left
- * and right preconditioning
- * will also change the way
- * residuals are
- * evaluated. See the
- * corresponding section in
- * the SolverGMRES.
+ * @note Change between left and right preconditioning will also change
+ * the way residuals are evaluated. See the corresponding section in the
+ * SolverGMRES.
*/
bool right_preconditioning;
/**
- * Flag for the default
- * residual that is used to
- * measure convergence.
+ * Flag for the default residual that is used to measure convergence.
*/
bool use_default_residual;
+
+ /**
+ * Flag to force re-orthogonalization of orthonormal basis in every
+ * step. If set to false, the solver automatically checks for loss of
+ * orthogonality every 5 iterations and enables re-orthogonalization only
+ * if necessary.
+ */
+ bool force_re_orthogonalization;
};
/**
const AdditionalData &data=AdditionalData());
/**
- * Constructor. Use an object of
- * type GrowingVectorMemory as
- * a default to allocate memory.
+ * Constructor. Use an object of type GrowingVectorMemory as a default to
+ * allocate memory.
*/
SolverGMRES (SolverControl &cn,
const AdditionalData &data=AdditionalData());
/**
- * Solve the linear system $Ax=b$
- * for x.
+ * Solve the linear system $Ax=b$ for x.
*/
template<class MATRIX, class PRECONDITIONER>
void
protected:
/**
- * Includes the maximum number of
- * tmp vectors.
+ * Includes the maximum number of tmp vectors.
*/
AdditionalData additional_data;
/**
- * Implementation of the computation of
- * the norm of the residual.
+ * Implementation of the computation of the norm of the residual.
*/
virtual double criterion();
/**
- * Transformation of an upper
- * Hessenberg matrix into
- * tridiagonal structure by givens
- * rotation of the last column
+ * Transformation of an upper Hessenberg matrix into tridiagonal structure
+ * by givens rotation of the last column
*/
void givens_rotation (Vector<double> &h, Vector<double> &b,
Vector<double> &ci, Vector<double> &si,
int col) const;
+
+ /**
+ * Orthogonalize the vector @p vv against the @p dim (orthogonal) vectors
+ * given by the first argument using the modified Gram-Schmidt
+ * algorithm. The factors used for orthogonalization are stored in @p h. The
+ * boolean @p re_orthogonalize specifies whether the modified Gram-Schmidt
+ * algorithm should be applied twice. The algorithm checks loss of
+ * orthogonality in the procedure every fifth step and sets the flag to true
+ * in that case. All subsequent iterations use re-orthogonalization.
+ */
+ static double
+ modified_gram_schmidt (const internal::SolverGMRES::TmpVectors<VECTOR> &orthogonal_vectors,
+ const unsigned int dim,
+ const unsigned int accumulated_iterations,
+ VECTOR &vv,
+ Vector<double> &h,
+ bool &re_orthogonalize);
+
/**
* Projected system matrix
*/
FullMatrix<double> H;
+
/**
* Auxiliary matrix for inverting @p H
*/
FullMatrix<double> H1;
+
private:
/**
* No copy constructor.
{
public:
/**
- * Standardized data struct to
- * pipe additional data to the
- * solver.
+ * Standardized data struct to pipe additional data to the solver.
*/
struct AdditionalData
{
/**
- * Constructor. By default,
- * set the number of
- * temporary vectors to 30,
- * preconditioning from left
- * and the residual of the
- * stopping criterion to the
- * default residual
- * (cf. class documentation).
+ * Constructor. By default, set the number of temporary vectors to 30,
+ * preconditioning from left and the residual of the stopping criterion to
+ * the default residual (cf. class documentation).
*/
AdditionalData(const unsigned int max_basis_size = 30,
const bool /*use_default_residual*/ = true)
{}
/**
- * Maximum number of
- * tmp vectors.
+ * Maximum number of tmp vectors.
*/
unsigned int max_basis_size;
};
const AdditionalData &data=AdditionalData());
/**
- * Constructor. Use an object of
- * type GrowingVectorMemory as
- * a default to allocate memory.
+ * Constructor. Use an object of type GrowingVectorMemory as a default to
+ * allocate memory.
*/
SolverFGMRES (SolverControl &cn,
const AdditionalData &data=AdditionalData());
/**
- * Solve the linear system $Ax=b$
- * for x.
+ * Solve the linear system $Ax=b$ for x.
*/
template<class MATRIX, class PRECONDITIONER>
void
SolverGMRES<VECTOR>::AdditionalData::
AdditionalData (const unsigned int max_n_tmp_vectors,
const bool right_preconditioning,
- const bool use_default_residual)
+ const bool use_default_residual,
+ const bool force_re_orthogonalization)
:
max_n_tmp_vectors(max_n_tmp_vectors),
right_preconditioning(right_preconditioning),
- use_default_residual(use_default_residual)
+ use_default_residual(use_default_residual),
+ force_re_orthogonalization(force_re_orthogonalization)
{}
+template <class VECTOR>
+inline
+double
+SolverGMRES<VECTOR>::modified_gram_schmidt (const internal::SolverGMRES::TmpVectors<VECTOR> &orthogonal_vectors,
+ const unsigned int dim,
+ const unsigned int accumulated_iterations,
+ VECTOR &vv,
+ Vector<double> &h,
+ bool &re_orthogonalize)
+{
+ const unsigned int inner_iteration = dim - 1;
+
+ // need initial norm for detection of re-orthogonalization, see below
+ double norm_vv_start = 0;
+ if (re_orthogonalize == false && inner_iteration % 5 == 4)
+ norm_vv_start = vv.l2_norm();
+
+ // Orthogonalization
+ for (unsigned int i=0 ; i<dim ; ++i)
+ {
+ h(i) = vv * orthogonal_vectors[i];
+ vv.add(-h(i), orthogonal_vectors[i]);
+ };
+
+ // Re-orthogonalization if loss of orthogonality detected. For the test, use
+ // a strategy discussed in C. T. Kelley, Iterative Methods for Linear and
+ // Nonlinear Equations, SIAM, Philadelphia, 1995: Compare the norm of vv
+ // after orthogonalization with its norm when starting the
+ // orthogonalization. If vv became very small (here: less than the square
+ // root of the machine precision times 10), it is almost in the span of the
+ // previous vectors, which indicates loss of precision.
+ if (re_orthogonalize == false && inner_iteration % 5 == 4)
+ {
+ const double norm_vv = vv.l2_norm();
+ if (norm_vv > 10. * norm_vv_start *
+ std::sqrt(std::numeric_limits<typename VECTOR::value_type>::epsilon()))
+ return norm_vv;
+
+ else
+ {
+ re_orthogonalize = true;
+ deallog << "Re-orthogonalization enabled at step "
+ << accumulated_iterations << std::endl;
+ }
+ }
+
+ if (re_orthogonalize == true)
+ for (unsigned int i=0 ; i<dim ; ++i)
+ {
+ double htmp = vv * orthogonal_vectors[i];
+ h(i) += htmp;
+ vv.add(-htmp, orthogonal_vectors[i]);
+ }
+
+ return vv.l2_norm();
+}
+
+
+
template<class VECTOR>
template<class MATRIX, class PRECONDITIONER>
void
const VECTOR &b,
const PRECONDITIONER &precondition)
{
- // this code was written a very
- // long time ago by people not
- // associated with deal.II. we
- // don't make any guarantees to its
- // optimality or that it even works
- // as expected...
+ // this code was written a very long time ago by people not associated with
+ // deal.II. we don't make any guarantees to its optimality or that it even
+ // works as expected...
//TODO:[?] Check, why there are two different start residuals.
//TODO:[GK] Make sure the parameter in the constructor means maximum basis size
deallog.push("GMRES");
const unsigned int n_tmp_vectors = additional_data.max_n_tmp_vectors;
- // Generate an object where basis
- // vectors are stored.
+ // Generate an object where basis vectors are stored.
internal::SolverGMRES::TmpVectors<VECTOR> tmp_vectors (n_tmp_vectors, this->memory);
// number of the present iteration; this
// restart
unsigned int accumulated_iterations = 0;
- // matrix used for the orthogonalization
- // process later
+ // matrix used for the orthogonalization process later
H.reinit(n_tmp_vectors, n_tmp_vectors-1);
- // some additional vectors, also used
- // in the orthogonalization
+ // some additional vectors, also used in the orthogonalization
dealii::Vector<double>
gamma(n_tmp_vectors),
ci (n_tmp_vectors-1),
SolverControl::State iteration_state = SolverControl::iterate;
- // switch to determine whether we want a
- // left or a right preconditioner. at
- // present, left is default, but both
- // ways are implemented
+ // switch to determine whether we want a left or a right preconditioner. at
+ // present, left is default, but both ways are implemented
const bool left_precondition = !additional_data.right_preconditioning;
- // Per default the left
- // preconditioned GMRes uses the
- // preconditioned residual and the
- // right preconditioned GMRes uses
- // the unpreconditioned residual as
- // stopping criterion.
+
+ // Per default the left preconditioned GMRes uses the preconditioned
+ // residual and the right preconditioned GMRes uses the unpreconditioned
+ // residual as stopping criterion.
const bool use_default_residual = additional_data.use_default_residual;
// define two aliases
gamma_ = new dealii::Vector<double> (gamma.size());
}
- ///////////////////////////////////
- // outer iteration: loop until we
- // either reach convergence or the
- // maximum number of iterations is
- // exceeded. each cycle of this
- // loop amounts to one restart
+ bool re_orthogonalize = additional_data.force_re_orthogonalization;
+
+ ///////////////////////////////////////////////////////////////////////////
+ // outer iteration: loop until we either reach convergence or the maximum
+ // number of iterations is exceeded. each cycle of this loop amounts to one
+ // restart
do
{
- // reset this vector to the
- // right size
+ // reset this vector to the right size
h.reinit (n_tmp_vectors-1);
if (left_precondition)
double rho = v.l2_norm();
- // check the residual here as
- // well since it may be that we
- // got the exact (or an almost
- // exact) solution vector at
- // the outset. if we wouldn't
- // check here, the next scaling
- // operation would produce
- // garbage
+ // check the residual here as well since it may be that we got the exact
+ // (or an almost exact) solution vector at the outset. if we wouldn't
+ // check here, the next scaling operation would produce garbage
if (use_default_residual)
{
iteration_state = this->control().check (
v *= 1./rho;
- // inner iteration doing at
- // most as many steps as there
- // are temporary vectors. the
- // number of steps actually
- // been done is propagated
- // outside through the @p dim
- // variable
+ // inner iteration doing at most as many steps as there are temporary
+ // vectors. the number of steps actually been done is propagated outside
+ // through the @p dim variable
for (unsigned int inner_iteration=0;
((inner_iteration < n_tmp_vectors-2)
&&
precondition.vmult(vv,p);
}
else
- {
+ {
precondition.vmult(p, tmp_vectors[inner_iteration]);
A.vmult(vv,p);
};
dim = inner_iteration+1;
- /* Orthogonalization */
- for (unsigned int i=0 ; i<dim ; ++i)
- {
- h(i) = vv * tmp_vectors[i];
- vv.add(-h(i), tmp_vectors[i]);
- };
-
- /* Re-orthogonalization */
- for (unsigned int i=0 ; i<dim ; ++i)
- {
- double htmp = vv * tmp_vectors[i];
- h(i) += htmp;
- vv.add(-htmp, tmp_vectors[i]);
- }
-
- const double s = vv.l2_norm();
+ const double s = modified_gram_schmidt(tmp_vectors, dim,
+ accumulated_iterations,
+ vv, h, re_orthogonalize);
h(inner_iteration+1) = s;
+
//s=0 is a lucky breakdown, the solver will reach convergence,
//but we must not divide by zero here.
if (numbers::is_finite(1./s))
vv *= 1./s;
- /* Transformation into
- triagonal structure */
+ // Transformation into triagonal structure
givens_rotation(h,gamma,ci,si,inner_iteration);
- /* append vector on matrix */
+ // append vector on matrix
for (unsigned int i=0; i<dim; ++i)
H(i,inner_iteration) = h(i);
- /* default residual */
+ // default residual
rho = std::fabs(gamma(dim));
if (use_default_residual)
};
A.vmult(*r,*x_);
r->sadd(-1.,1.,b);
- // Now *r contains the
- // unpreconditioned
- // residual!!
+ // Now *r contains the unpreconditioned residual!!
if (left_precondition)
{
const double res=r->l2_norm();
}
}
};
- // end of inner iteration. now
- // calculate the solution from
- // the temporary vectors
+ // end of inner iteration. now calculate the solution from the temporary
+ // vectors
h.reinit(dim);
H1.reinit(dim+1,dim);
precondition.vmult(v,p);
x.add(1.,v);
};
- // end of outer iteration. restart if
- // no convergence and the number of
+ // end of outer iteration. restart if no convergence and the number of
// iterations is not exceeded
}
while (iteration_state == SolverControl::iterate);
}
deallog.pop();
- // in case of failure: throw
- // exception
+ // in case of failure: throw exception
if (this->control().last_check() != SolverControl::success)
throw SolverControl::NoConvergence (this->control().last_step(),
this->control().last_value());
double
SolverGMRES<VECTOR>::criterion ()
{
- // dummy implementation. this function is
- // not needed for the present implementation
- // of gmres
+ // dummy implementation. this function is not needed for the present
+ // implementation of gmres
Assert (false, ExcInternalError());
return 0;
}
const unsigned int basis_size = additional_data.max_basis_size;
- // Generate an object where basis
- // vectors are stored.
+ // Generate an object where basis vectors are stored.
typename internal::SolverGMRES::TmpVectors<VECTOR> v (basis_size, this->memory);
typename internal::SolverGMRES::TmpVectors<VECTOR> z (basis_size, this->memory);
- // number of the present iteration; this
- // number is not reset to zero upon a
+ // number of the present iteration; this number is not reset to zero upon a
// restart
unsigned int accumulated_iterations = 0;
- // matrix used for the orthogonalization
- // process later
+ // matrix used for the orthogonalization process later
H.reinit(basis_size+1, basis_size);
// Vectors for projected system
this->memory.free(aux);
deallog.pop();
- // in case of failure: throw
- // exception
+ // in case of failure: throw exception
if (this->control().last_check() != SolverControl::success)
throw SolverControl::NoConvergence (this->control().last_step(),
this->control().last_value());
*/
friend class SparsityPatternIterators::Iterator;
friend class SparsityPatternIterators::Accessor;
+ friend class ChunkSparsityPatternIterators::Accessor;
};
#ifdef DEAL_II_WITH_TRILINOS
# include <deal.II/base/table.h>
+# include <deal.II/base/template_constraints.h>
# include <deal.II/lac/block_matrix_base.h>
# include <deal.II/lac/trilinos_sparse_matrix.h>
# include <deal.II/lac/trilinos_block_vector.h>
unsigned int n_nonzero_elements () const;
/**
- * Matrix-vector multiplication:
- * let $dst = M*src$ with $M$
- * being this matrix.
+ * Matrix-vector multiplication: let $dst = M*src$ with $M$ being this
+ * matrix. The vector types can be block vectors or non-block vectors
+ * (only if the matrix has only one row or column, respectively), and need
+ * to define TrilinosWrappers::SparseMatrix::vmult.
*/
- void vmult (MPI::BlockVector &dst,
- const MPI::BlockVector &src) const;
-
-
- /**
- * Matrix-vector multiplication:
- * let $dst = M*src$ with $M$
- * being this matrix, now applied
- * to localized block vectors
- * (works only when run on one
- * processor).
- */
- void vmult (BlockVector &dst,
- const BlockVector &src) const;
-
- /**
- * Matrix-vector
- * multiplication. Just like the
- * previous function, but only
- * applicable if the matrix has
- * only one block column.
- */
- void vmult (MPI::BlockVector &dst,
- const MPI::Vector &src) const;
-
- /**
- * Matrix-vector
- * multiplication. Just like the
- * previous function, but only
- * applicable if the matrix has
- * only one block column, now
- * applied to localized vectors
- * (works only when run on one
- * processor).
- */
- void vmult (BlockVector &dst,
- const Vector &src) const;
-
- /**
- * Matrix-vector
- * multiplication. Just like the
- * previous function, but only
- * applicable if the matrix has
- * only one block row.
- */
- void vmult (MPI::Vector &dst,
- const MPI::BlockVector &src) const;
-
- /**
- * Matrix-vector
- * multiplication. Just like the
- * previous function, but only
- * applicable if the matrix has
- * only one block row, now
- * applied to localized vectors
- * (works only when run on one
- * processor).
- */
- void vmult (Vector &dst,
- const BlockVector &src) const;
-
- /**
- * Matrix-vector
- * multiplication. Just like the
- * previous function, but only
- * applicable if the matrix has
- * only one block.
- */
- void vmult (VectorBase &dst,
- const VectorBase &src) const;
-
- /**
- * Matrix-vector multiplication:
- * let $dst = M^T*src$ with $M$
- * being this matrix. This
- * function does the same as
- * vmult() but takes the
- * transposed matrix.
- */
- void Tvmult (MPI::BlockVector &dst,
- const MPI::BlockVector &src) const;
-
- /**
- * Matrix-vector multiplication:
- * let $dst = M^T*src$ with $M$
- * being this matrix. This
- * function does the same as
- * vmult() but takes the
- * transposed matrix, now applied
- * to localized Trilinos vectors
- * (works only when run on one
- * processor).
- */
- void Tvmult (BlockVector &dst,
- const BlockVector &src) const;
-
- /**
- * Matrix-vector
- * multiplication. Just like the
- * previous function, but only
- * applicable if the matrix has
- * only one block row.
- */
- void Tvmult (MPI::BlockVector &dst,
- const MPI::Vector &src) const;
+ template <typename VectorType1, typename VectorType2>
+ void vmult (VectorType1 &dst,
+ const VectorType2 &src) const;
/**
- * Matrix-vector
- * multiplication. Just like the
- * previous function, but only
- * applicable if the matrix has
- * only one block row, now
- * applied to localized Trilinos
- * vectors (works only when run
- * on one processor).
- */
- void Tvmult (BlockVector &dst,
- const Vector &src) const;
-
- /**
- * Matrix-vector
- * multiplication. Just like the
- * previous function, but only
- * applicable if the matrix has
- * only one block column.
- */
- void Tvmult (MPI::Vector &dst,
- const MPI::BlockVector &src) const;
-
- /**
- * Matrix-vector
- * multiplication. Just like the
- * previous function, but only
- * applicable if the matrix has
- * only one block column, now
- * applied to localized Trilinos
- * vectors (works only when run
- * on one processor).
- */
- void Tvmult (Vector &dst,
- const BlockVector &src) const;
-
- /**
- * Matrix-vector
- * multiplication. Just like the
- * previous function, but only
- * applicable if the matrix has
- * only one block.
+ * Matrix-vector multiplication: let $dst = M^T*src$ with $M$ being this
+ * matrix. This function does the same as vmult() but takes the transposed
+ * matrix.
*/
- void Tvmult (VectorBase &dst,
- const VectorBase &src) const;
+ template <typename VectorType1, typename VectorType2>
+ void Tvmult (VectorType1 &dst,
+ const VectorType2 &src) const;
/**
* Compute the residual of an
<< "The blocks [" << arg1 << ',' << arg2 << "] and ["
<< arg3 << ',' << arg4 << "] have differing column numbers.");
///@}
+
+ private:
+ /**
+ * Internal version of (T)vmult with two block vectors
+ */
+ template <typename VectorType1, typename VectorType2>
+ void vmult (VectorType1 &dst,
+ const VectorType2 &src,
+ const bool transpose,
+ const dealii::internal::bool2type<true>,
+ const dealii::internal::bool2type<true>) const;
+
+ /**
+ * Internal version of (T)vmult where the source vector is a block vector
+ * but the destination vector is a non-block vector
+ */
+ template <typename VectorType1, typename VectorType2>
+ void vmult (VectorType1 &dst,
+ const VectorType2 &src,
+ const bool transpose,
+ const dealii::internal::bool2type<false>,
+ const dealii::internal::bool2type<true>) const;
+
+ /**
+ * Internal version of (T)vmult where the source vector is a non-block
+ * vector but the destination vector is a block vector
+ */
+ template <typename VectorType1, typename VectorType2>
+ void vmult (VectorType1 &dst,
+ const VectorType2 &src,
+ const bool transpose,
+ const dealii::internal::bool2type<true>,
+ const dealii::internal::bool2type<false>) const;
+
+ /**
+ * Internal version of (T)vmult where both source vector and the
+ * destination vector are non-block vectors (only defined if the matrix
+ * consists of only one block)
+ */
+ template <typename VectorType1, typename VectorType2>
+ void vmult (VectorType1 &dst,
+ const VectorType2 &src,
+ const bool transpose,
+ const dealii::internal::bool2type<false>,
+ const dealii::internal::bool2type<false>) const;
};
+ template <typename VectorType1, typename VectorType2>
inline
void
- BlockSparseMatrix::vmult (MPI::BlockVector &dst,
- const MPI::BlockVector &src) const
+ BlockSparseMatrix::vmult (VectorType1 &dst,
+ const VectorType2 &src) const
{
- BaseClass::vmult_block_block (dst, src);
+ vmult(dst, src, false,
+ dealii::internal::bool2type<IsBlockVector<VectorType1>::value>(),
+ dealii::internal::bool2type<IsBlockVector<VectorType2>::value>());
}
+ template <typename VectorType1, typename VectorType2>
inline
void
- BlockSparseMatrix::vmult (BlockVector &dst,
- const BlockVector &src) const
+ BlockSparseMatrix::Tvmult (VectorType1 &dst,
+ const VectorType2 &src) const
{
- BaseClass::vmult_block_block (dst, src);
+ vmult(dst, src, true,
+ dealii::internal::bool2type<IsBlockVector<VectorType1>::value>(),
+ dealii::internal::bool2type<IsBlockVector<VectorType2>::value>());
}
+ template <typename VectorType1, typename VectorType2>
inline
void
- BlockSparseMatrix::vmult (MPI::BlockVector &dst,
- const MPI::Vector &src) const
+ BlockSparseMatrix::vmult (VectorType1 &dst,
+ const VectorType2 &src,
+ const bool transpose,
+ dealii::internal::bool2type<true>,
+ dealii::internal::bool2type<true>) const
{
- BaseClass::vmult_block_nonblock (dst, src);
+ if (transpose == true)
+ BaseClass::Tvmult_block_block (dst, src);
+ else
+ BaseClass::vmult_block_block (dst, src);
}
- inline
- void
- BlockSparseMatrix::vmult (BlockVector &dst,
- const Vector &src) const
- {
- BaseClass::vmult_block_nonblock (dst, src);
- }
-
-
-
- inline
- void
- BlockSparseMatrix::vmult (MPI::Vector &dst,
- const MPI::BlockVector &src) const
- {
- BaseClass::vmult_nonblock_block (dst, src);
- }
-
-
-
- inline
- void
- BlockSparseMatrix::vmult (Vector &dst,
- const BlockVector &src) const
- {
- BaseClass::vmult_nonblock_block (dst, src);
- }
-
-
-
- inline
- void
- BlockSparseMatrix::vmult (VectorBase &dst,
- const VectorBase &src) const
- {
- BaseClass::vmult_nonblock_nonblock (dst, src);
- }
-
-
-
- inline
- void
- BlockSparseMatrix::Tvmult (MPI::BlockVector &dst,
- const MPI::BlockVector &src) const
- {
- BaseClass::Tvmult_block_block (dst, src);
- }
-
-
-
- inline
- void
- BlockSparseMatrix::Tvmult (BlockVector &dst,
- const BlockVector &src) const
- {
- BaseClass::Tvmult_block_block (dst, src);
- }
-
-
-
- inline
- void
- BlockSparseMatrix::Tvmult (MPI::BlockVector &dst,
- const MPI::Vector &src) const
- {
- BaseClass::Tvmult_block_nonblock (dst, src);
- }
-
-
-
- inline
- void
- BlockSparseMatrix::Tvmult (BlockVector &dst,
- const Vector &src) const
- {
- BaseClass::Tvmult_block_nonblock (dst, src);
- }
-
-
+ template <typename VectorType1, typename VectorType2>
inline
void
- BlockSparseMatrix::Tvmult (MPI::Vector &dst,
- const MPI::BlockVector &src) const
+ BlockSparseMatrix::vmult (VectorType1 &dst,
+ const VectorType2 &src,
+ const bool transpose,
+ dealii::internal::bool2type<false>,
+ dealii::internal::bool2type<true>) const
{
- BaseClass::Tvmult_nonblock_block (dst, src);
+ if (transpose == true)
+ BaseClass::Tvmult_nonblock_block (dst, src);
+ else
+ BaseClass::vmult_nonblock_block (dst, src);
}
+ template <typename VectorType1, typename VectorType2>
inline
void
- BlockSparseMatrix::Tvmult (Vector &dst,
- const BlockVector &src) const
+ BlockSparseMatrix::vmult (VectorType1 &dst,
+ const VectorType2 &src,
+ const bool transpose,
+ dealii::internal::bool2type<true>,
+ dealii::internal::bool2type<false>) const
{
- BaseClass::Tvmult_nonblock_block (dst, src);
+ if (transpose == true)
+ BaseClass::Tvmult_block_nonblock (dst, src);
+ else
+ BaseClass::vmult_block_nonblock (dst, src);
}
+ template <typename VectorType1, typename VectorType2>
inline
void
- BlockSparseMatrix::Tvmult (VectorBase &dst,
- const VectorBase &src) const
+ BlockSparseMatrix::vmult (VectorType1 &dst,
+ const VectorType2 &src,
+ const bool transpose,
+ dealii::internal::bool2type<false>,
+ dealii::internal::bool2type<false>) const
{
- BaseClass::Tvmult_nonblock_nonblock (dst, src);
+ if (transpose == true)
+ BaseClass::Tvmult_nonblock_nonblock (dst, src);
+ else
+ BaseClass::vmult_nonblock_nonblock (dst, src);
}
}
# include <deal.II/base/index_set.h>
# include <deal.II/lac/full_matrix.h>
# include <deal.II/lac/exceptions.h>
-# include <deal.II/lac/trilinos_vector_base.h>
-# include <deal.II/lac/parallel_vector.h>
+# include <deal.II/lac/trilinos_vector.h>
+# include <deal.II/lac/vector_view.h>
# include <vector>
# include <cmath>
# include <Epetra_FECrsMatrix.h>
# include <Epetra_Map.h>
# include <Epetra_CrsGraph.h>
-# include <Epetra_Vector.h>
+# include <Epetra_MultiVector.h>
# ifdef DEAL_II_WITH_MPI
# include <Epetra_MpiComm.h>
# include "mpi.h"
namespace TrilinosWrappers
{
// forward declarations
- class VectorBase;
class SparseMatrix;
class SparsityPattern;
typedef TrilinosScalar value_type;
/**
- * @name Constructors and initalization.
+ * @name Constructors and initialization.
*/
//@{
/**
* they might be spread out. The
* second Epetra_Map is only used to
* specify the number of columns and
- * for internal arragements when
+ * for internal arrangements when
* doing matrix-vector products with
* vectors based on that column map.
*
//@{
/**
- * Matrix-vector multiplication:
- * let <i>dst = M*src</i> with
- * <i>M</i> being this matrix.
+ * Matrix-vector multiplication: let <i>dst = M*src</i> with <i>M</i>
+ * being this matrix.
*
- * Source and destination must
- * not be the same vector.
+ * Source and destination must not be the same vector.
*
- * Note that both vectors have to
- * be distributed vectors
- * generated using the same Map
- * as was used for the matrix in
- * case you work on a distributed
- * memory architecture, using the
- * interface in the
- * TrilinosWrappers::VectorBase
- * class (or one of the two
- * derived classes Vector and
- * MPI::Vector).
+ * This function can be called with several different vector objects,
+ * namely TrilinosWrappers::Vector, TrilinosWrappers::MPI::Vector as well
+ * as deal.II's own vector classes Vector<double> and
+ * parallel::distributed::Vector<double>.
*
- * In case of a localized Vector,
- * this function will only work
- * when running on one processor,
- * since the matrix object is
- * inherently
- * distributed. Otherwise, and
- * exception will be thrown.
- */
- void vmult (VectorBase &dst,
- const VectorBase &src) const;
-
- /**
- * Same as before, but working with
- * deal.II's own distributed vector
- * class.
- */
- void vmult (parallel::distributed::Vector<TrilinosScalar> &dst,
- const parallel::distributed::Vector<TrilinosScalar> &src) const;
-
- /**
- * Same as before, but working with
- * deal.II's own vector
- * class.
+ * Note that both vectors have to be distributed vectors generated using
+ * the same Map as was used for the matrix in case you work on a
+ * distributed memory architecture, using the interface in the
+ * TrilinosWrappers::VectorBase class (or one of the two derived classes
+ * Vector and MPI::Vector).
+ *
+ * In case of a localized Vector, this function will only work when
+ * running on one processor, since the matrix object is inherently
+ * distributed. Otherwise, and exception will be thrown.
*/
- void vmult (dealii::Vector<TrilinosScalar> &dst,
- const dealii::Vector<TrilinosScalar> &src) const;
+ template<typename VectorType>
+ void vmult (VectorType &dst,
+ const VectorType &src) const;
/**
- * Matrix-vector multiplication:
- * let <i>dst =
- * M<sup>T</sup>*src</i> with
- * <i>M</i> being this
- * matrix. This function does the
- * same as vmult() but takes the
- * transposed matrix.
+ * Matrix-vector multiplication: let <i>dst = M<sup>T</sup>*src</i> with
+ * <i>M</i> being this matrix. This function does the same as vmult() but
+ * takes the transposed matrix.
*
- * Source and destination must
- * not be the same vector.
+ * Source and destination must not be the same vector.
*
- * Note that both vectors have to
- * be distributed vectors
- * generated using the same Map
- * as was used for the matrix in
- * case you work on a distributed
- * memory architecture, using the
- * interface in the
- * TrilinosWrappers::VectorBase
- * class (or one of the two
- * derived classes Vector and
- * MPI::Vector).
+ * This function can be called with several different vector objects,
+ * namely TrilinosWrappers::Vector, TrilinosWrappers::MPI::Vector as well
+ * as deal.II's own vector classes Vector<double> and
+ * parallel::distributed::Vector<double>.
*
- * In case of a localized Vector,
- * this function will only work
- * when running on one processor,
- * since the matrix object is
- * inherently
- * distributed. Otherwise, and
- * exception will be thrown.
- */
- void Tvmult (VectorBase &dst,
- const VectorBase &src) const;
-
- /**
- * Same as before, but working with
- * deal.II's own distributed vector
- * class.
- */
- void Tvmult (parallel::distributed::Vector<TrilinosScalar> &dst,
- const parallel::distributed::Vector<TrilinosScalar> &src) const;
-
- /**
- * Same as before, but working with
- * deal.II's own vector
- * class.
+ * Note that both vectors have to be distributed vectors generated using
+ * the same Map as was used for the matrix in case you work on a
+ * distributed memory architecture, using the interface in the
+ * TrilinosWrappers::VectorBase class (or one of the two derived classes
+ * Vector and MPI::Vector).
+ *
+ * In case of a localized Vector, this function will only work when
+ * running on one processor, since the matrix object is inherently
+ * distributed. Otherwise, and exception will be thrown.
*/
- void Tvmult (dealii::Vector<TrilinosScalar> &dst,
- const dealii::Vector<TrilinosScalar> &src) const;
+ template <typename VectorType>
+ void Tvmult (VectorType &dst,
+ const VectorType &src) const;
/**
- * Adding Matrix-vector
- * multiplication. Add
- * <i>M*src</i> on <i>dst</i>
- * with <i>M</i> being this
- * matrix.
+ * Adding matrix-vector multiplication. Add <i>M*src</i> on <i>dst</i>
+ * with <i>M</i> being this matrix.
*
- * Source and destination must
- * not be the same vector.
+ * Source and destination must not be the same vector.
*
- * Note that both vectors have to
- * be distributed vectors
- * generated using the same Map
- * as was used for the matrix in
- * case you work on a distributed
- * memory architecture, using the
- * interface in the
- * TrilinosWrappers::VectorBase
- * class (or one of the two
- * derived classes Vector and
- * MPI::Vector).
+ * This function can be called with several different vector objects,
+ * namely TrilinosWrappers::Vector, TrilinosWrappers::MPI::Vector as well
+ * as deal.II's own vector classes Vector<double> and
+ * parallel::distributed::Vector<double>.
+ *
+ * When using a vector of type TrilinosWrappers::MPI::Vector, both vectors
+ * have to be distributed vectors generated using the same Map as was used
+ * for the matrix rows and columns in case you work on a distributed
+ * memory architecture, using the interface in the
+ * TrilinosWrappers::VectorBase class.
+ *
+ * In case of a localized Vector (i.e., TrilinosWrappers::Vector or
+ * Vector<double>), this function will only work when running on one
+ * processor, since the matrix object is inherently
+ * distributed. Otherwise, and exception will be thrown.
*
- * In case of a localized Vector,
- * this function will only work
- * when running on one processor,
- * since the matrix object is
- * inherently
- * distributed. Otherwise, and
- * exception will be thrown.
*/
- void vmult_add (VectorBase &dst,
- const VectorBase &src) const;
+ template<typename VectorType>
+ void vmult_add (VectorType &dst,
+ const VectorType &src) const;
/**
- * Adding Matrix-vector
- * multiplication. Add
- * <i>M<sup>T</sup>*src</i> to
- * <i>dst</i> with <i>M</i> being
- * this matrix. This function
- * does the same as vmult_add()
- * but takes the transposed
- * matrix.
+ * Adding matrix-vector multiplication. Add <i>M<sup>T</sup>*src</i> to
+ * <i>dst</i> with <i>M</i> being this matrix. This function does the same
+ * as vmult_add() but takes the transposed matrix.
*
- * Source and destination must
- * not be the same vector.
+ * Source and destination must not be the same vector.
*
- * Note that both vectors have to
- * be distributed vectors
- * generated using the same Map
- * as was used for the matrix in
- * case you work on a distributed
- * memory architecture, using the
- * interface in the
- * TrilinosWrappers::VectorBase
- * class (or one of the two
- * derived classes Vector and
- * MPI::Vector).
+ * This function can be called with several different vector objects,
+ * namely TrilinosWrappers::Vector, TrilinosWrappers::MPI::Vector as well
+ * as deal.II's own vector classes Vector<double> and
+ * parallel::distributed::Vector<double>.
*
- * In case of a localized Vector,
- * this function will only work
- * when running on one processor,
- * since the matrix object is
- * inherently
- * distributed. Otherwise, and
- * exception will be thrown.
+ * When using a vector of type TrilinosWrappers::MPI::Vector, both vectors
+ * have to be distributed vectors generated using the same Map as was used
+ * for the matrix rows and columns in case you work on a distributed
+ * memory architecture, using the interface in the
+ * TrilinosWrappers::VectorBase class.
+ *
+ * In case of a localized Vector (i.e., TrilinosWrappers::Vector or
+ * Vector<double>), this function will only work when running on one
+ * processor, since the matrix object is inherently
+ * distributed. Otherwise, and exception will be thrown.
*/
- void Tvmult_add (VectorBase &dst,
- const VectorBase &src) const;
+ template <typename VectorType>
+ void Tvmult_add (VectorType &dst,
+ const VectorType &src) const;
/**
* Return the square of the norm
*/
bool compressed;
- /**
- * An internal Trilinos vector that
- * is used for accelerating vmult_add
- * functions (in order not to need to
- * recreate temporary vectors every
- * time that function is called).
- */
- mutable VectorBase temp_vector;
-
- /**
- * An internal array of integer
- * values that is used to store the
- * column indices when
- * adding/inserting local data into
- * the (large) sparse matrix.
- */
- std::vector<unsigned int> column_indices;
-
- /**
- * An internal array of double values
- * that is used to store the column
- * indices when adding/inserting
- * local data into the (large) sparse
- * matrix.
- */
- std::vector<TrilinosScalar> column_values;
-
/**
* To allow calling protected
* prepare_add() and
inline
void
- SparseMatrix::compress (::dealii::VectorOperation::values /*operation*/)
+ SparseMatrix::compress (::dealii::VectorOperation::values operation)
{
+
+ Epetra_CombineMode mode = last_action;
+ if (last_action == Zero)
+ {
+ if ((operation==::dealii::VectorOperation::add) ||
+ (operation==::dealii::VectorOperation::unknown))
+ mode = Add;
+ else if (operation==::dealii::VectorOperation::insert)
+ mode = Insert;
+ }
+ else
+ {
+ Assert(
+ ((last_action == Add) && (operation!=::dealii::VectorOperation::insert))
+ ||
+ ((last_action == Insert) && (operation!=::dealii::VectorOperation::add)),
+ ExcMessage("operation and argument to compress() do not match"));
+ }
+
// flush buffers
int ierr;
ierr = matrix->GlobalAssemble (*column_space_map, matrix->RowMap(),
- true);
+ true, mode);
AssertThrow (ierr == 0, ExcTrilinosError(ierr));
last_action = Insert;
int *col_index_ptr;
- TrilinosScalar const *col_value_ptr;
+ TrilinosScalar *col_value_ptr;
int n_columns;
- // If we don't elide zeros, the pointers
- // are already available...
+ TrilinosScalar short_val_array[100];
+ int short_index_array[100];
+ std::vector<TrilinosScalar> long_val_array;
+ std::vector<int> long_index_array;
+
+
+ // If we don't elide zeros, the pointers are already available... need to
+ // cast to non-const pointers as that is the format taken by Trilinos (but
+ // we will not modify const data)
if (elide_zero_values == false)
{
col_index_ptr = (int *)col_indices;
- col_value_ptr = values;
+ col_value_ptr = const_cast<TrilinosScalar*>(values);
n_columns = n_cols;
}
else
{
- // Otherwise, extract nonzero values in
- // each row and get the respective
- // indices.
- if (column_indices.size() < n_cols)
+ // Otherwise, extract nonzero values in each row and get the
+ // respective indices.
+ if (n_cols > 100)
+ {
+ long_val_array.resize(n_cols);
+ long_index_array.resize(n_cols);
+ col_index_ptr = &long_index_array[0];
+ col_value_ptr = &long_val_array[0];
+ }
+ else
{
- column_indices.resize(n_cols);
- column_values.resize(n_cols);
+ col_index_ptr = &short_index_array[0];
+ col_value_ptr = &short_val_array[0];
}
n_columns = 0;
Assert (numbers::is_finite(value), ExcNumberNotFinite());
if (value != 0)
{
- column_indices[n_columns] = col_indices[j];
- column_values[n_columns] = value;
+ col_index_ptr[n_columns] = col_indices[j];
+ col_value_ptr[n_columns] = value;
n_columns++;
}
}
Assert(n_columns <= (int)n_cols, ExcInternalError());
-
- col_index_ptr = (int *)&column_indices[0];
- col_value_ptr = &column_values[0];
}
- // If the calling matrix owns the row to
- // which we want to insert values, we
- // can directly call the Epetra_CrsMatrix
- // input function, which is much faster
- // than the Epetra_FECrsMatrix
- // function. We distinguish between two
- // cases: the first one is when the matrix
- // is not filled (i.e., it is possible to
- // add new elements to the sparsity pattern),
- // and the second one is when the pattern is
- // already fixed. In the former case, we
- // add the possibility to insert new values,
- // and in the second we just replace
+ // If the calling matrix owns the row to which we want to insert values,
+ // we can directly call the Epetra_CrsMatrix input function, which is much
+ // faster than the Epetra_FECrsMatrix function. We distinguish between two
+ // cases: the first one is when the matrix is not filled (i.e., it is
+ // possible to add new elements to the sparsity pattern), and the second
+ // one is when the pattern is already fixed. In the former case, we add
+ // the possibility to insert new values, and in the second we just replace
// data.
if (row_partitioner().MyGID(static_cast<int>(row)) == true)
{
if (matrix->Filled() == false)
{
ierr = matrix->Epetra_CrsMatrix::InsertGlobalValues(row, n_columns,
- const_cast<double *>(col_value_ptr),
+ col_value_ptr,
col_index_ptr);
- // When inserting elements, we do
- // not want to create exceptions in
- // the case when inserting non-local
- // data (since that's what we want
- // to do right now).
+ // When inserting elements, we do not want to create exceptions in
+ // the case when inserting non-local data (since that's what we
+ // want to do right now).
if (ierr > 0)
ierr = 0;
}
else
ierr = matrix->Epetra_CrsMatrix::ReplaceGlobalValues(row, n_columns,
- const_cast<double *>(col_value_ptr),
+ col_value_ptr,
col_index_ptr);
}
else
{
- // When we're at off-processor data, we
- // have to stick with the standard
- // Insert/ReplaceGlobalValues
- // function. Nevertheless, the way we
- // call it is the fastest one (any other
- // will lead to repeated allocation and
- // deallocation of memory in order to
- // call the function we already use,
- // which is very unefficient if writing
- // one element at a time).
+ // When we're at off-processor data, we have to stick with the
+ // standard Insert/ReplaceGlobalValues function. Nevertheless, the way
+ // we call it is the fastest one (any other will lead to repeated
+ // allocation and deallocation of memory in order to call the function
+ // we already use, which is very unefficient if writing one element at
+ // a time).
compressed = false;
if (matrix->Filled() == false)
if (value == 0)
{
- // we have to do checkings on Insert/Add
- // in any case
- // to be consistent with the MPI
- // communication model (see the comments
- // in the documentation of
- // TrilinosWrappers::Vector), but we can
- // save some work if the addend is
- // zero. However, these actions are done
- // in case we pass on to the other
- // function.
+ // we have to do checkings on Insert/Add in any case to be consistent
+ // with the MPI communication model (see the comments in the
+ // documentation of TrilinosWrappers::Vector), but we can save some
+ // work if the addend is zero. However, these actions are done in case
+ // we pass on to the other function.
+
+ // TODO: fix this (do not run compress here, but fail)
if (last_action == Insert)
{
int ierr;
last_action = Add;
int *col_index_ptr;
- TrilinosScalar const *col_value_ptr;
+ TrilinosScalar *col_value_ptr;
int n_columns;
- // If we don't elide zeros, the pointers
- // are already available...
+ double short_val_array[100];
+ int short_index_array[100];
+ std::vector<TrilinosScalar> long_val_array;
+ std::vector<int> long_index_array;
+
+ // If we don't elide zeros, the pointers are already available... need to
+ // cast to non-const pointers as that is the format taken by Trilinos (but
+ // we will not modify const data)
if (elide_zero_values == false)
{
col_index_ptr = (int *)col_indices;
- col_value_ptr = values;
+ col_value_ptr = const_cast<TrilinosScalar*>(values);
n_columns = n_cols;
#ifdef DEBUG
for (unsigned int j=0; j<n_cols; ++j)
}
else
{
- // Otherwise, extract nonzero values in
- // each row and the corresponding index.
- if (column_indices.size() < n_cols)
+ // Otherwise, extract nonzero values in each row and the corresponding
+ // index.
+ if (n_cols > 100)
+ {
+ long_val_array.resize(n_cols);
+ long_index_array.resize(n_cols);
+ col_index_ptr = &long_index_array[0];
+ col_value_ptr = &long_val_array[0];
+ }
+ else
{
- column_indices.resize(n_cols);
- column_values.resize(n_cols);
+ col_index_ptr = &short_index_array[0];
+ col_value_ptr = &short_val_array[0];
}
n_columns = 0;
for (unsigned int j=0; j<n_cols; ++j)
{
const double value = values[j];
+
Assert (numbers::is_finite(value), ExcNumberNotFinite());
if (value != 0)
{
- column_indices[n_columns] = col_indices[j];
- column_values[n_columns] = value;
+ col_index_ptr[n_columns] = col_indices[j];
+ col_value_ptr[n_columns] = value;
n_columns++;
}
}
Assert(n_columns <= (int)n_cols, ExcInternalError());
- col_index_ptr = (int *)&column_indices[0];
- col_value_ptr = &column_values[0];
}
- // If the calling matrix owns the row to
- // which we want to add values, we
- // can directly call the Epetra_CrsMatrix
- // input function, which is much faster
- // than the Epetra_FECrsMatrix function.
+ // If the calling matrix owns the row to which we want to add values, we
+ // can directly call the Epetra_CrsMatrix input function, which is much
+ // faster than the Epetra_FECrsMatrix function.
if (row_partitioner().MyGID(static_cast<int>(row)) == true)
{
ierr = matrix->Epetra_CrsMatrix::SumIntoGlobalValues(row, n_columns,
- const_cast<double *>(col_value_ptr),
+ col_value_ptr,
col_index_ptr);
}
else
{
- // When we're at off-processor data, we
- // have to stick with the standard
- // SumIntoGlobalValues
- // function. Nevertheless, the way we
- // call it is the fastest one (any other
- // will lead to repeated allocation and
- // deallocation of memory in order to
- // call the function we already use,
- // which is very unefficient if writing
- // one element at a time).
+ // When we're at off-processor data, we have to stick with the
+ // standard SumIntoGlobalValues function. Nevertheless, the way we
+ // call it is the fastest one (any other will lead to repeated
+ // allocation and deallocation of memory in order to call the function
+ // we already use, which is very inefficient if writing one element at
+ // a time).
compressed = false;
ierr = matrix->SumIntoGlobalValues (1, (int *)&row, n_columns,
- inline
- void
- SparseMatrix::vmult (VectorBase &dst,
- const VectorBase &src) const
- {
- Assert (&src != &dst, ExcSourceEqualsDestination());
- Assert (matrix->Filled(), ExcMatrixNotCompressed());
-
- Assert (src.vector_partitioner().SameAs(matrix->DomainMap()) == true,
- ExcMessage ("Column map of matrix does not fit with vector map!"));
- Assert (dst.vector_partitioner().SameAs(matrix->RangeMap()) == true,
- ExcMessage ("Row map of matrix does not fit with vector map!"));
-
- const int ierr = matrix->Multiply (false, src.trilinos_vector(),
- dst.trilinos_vector());
- Assert (ierr == 0, ExcTrilinosError(ierr));
- (void)ierr; // removes -Wunused-variable in optimized mode
- }
-
-
-
- inline
- void
- SparseMatrix::vmult (parallel::distributed::Vector<TrilinosScalar> &dst,
- const parallel::distributed::Vector<TrilinosScalar> &src) const
+ namespace internal
{
- Assert (&src != &dst, ExcSourceEqualsDestination());
- Assert (matrix->Filled(), ExcMatrixNotCompressed());
-
- AssertDimension (dst.local_size(), static_cast<unsigned int>(matrix->RangeMap().NumMyElements()));
- AssertDimension (src.local_size(), static_cast<unsigned int>(matrix->DomainMap().NumMyElements()));
-
- Epetra_Vector tril_dst (View, matrix->RangeMap(), dst.begin());
- Epetra_Vector tril_src (View, matrix->DomainMap(),
- const_cast<double *>(src.begin()));
+ namespace SparseMatrix
+ {
+ template <typename VectorType>
+ inline
+ void check_vector_map_equality(const Epetra_CrsMatrix &,
+ const VectorType &,
+ const VectorType &)
+ {
+ }
- const int ierr = matrix->Multiply (false, tril_src, tril_dst);
- Assert (ierr == 0, ExcTrilinosError(ierr));
- (void)ierr; // removes -Wunused-variable in optimized mode
+ inline
+ void check_vector_map_equality(const Epetra_CrsMatrix &m,
+ const TrilinosWrappers::MPI::Vector &in,
+ const TrilinosWrappers::MPI::Vector &out)
+ {
+ Assert (in.vector_partitioner().SameAs(m.DomainMap()) == true,
+ ExcMessage ("Column map of matrix does not fit with vector map!"));
+ Assert (out.vector_partitioner().SameAs(m.RangeMap()) == true,
+ ExcMessage ("Row map of matrix does not fit with vector map!"));
+ }
+ }
}
-
+ template <typename VectorType>
inline
void
- SparseMatrix::vmult (dealii::Vector<TrilinosScalar> &dst,
- const dealii::Vector<TrilinosScalar> &src) const
+ SparseMatrix::vmult (VectorType &dst,
+ const VectorType &src) const
{
Assert (&src != &dst, ExcSourceEqualsDestination());
Assert (matrix->Filled(), ExcMatrixNotCompressed());
- AssertDimension (static_cast<unsigned int>(matrix->DomainMap().NumMyElements()),
- static_cast<unsigned int>(matrix->DomainMap().NumGlobalElements()));
- AssertDimension (dst.size(), static_cast<unsigned int>(matrix->RangeMap().NumMyElements()));
- AssertDimension (src.size(), static_cast<unsigned int>(matrix->DomainMap().NumMyElements()));
+ internal::SparseMatrix::check_vector_map_equality(*matrix, src, dst);
+ const int dst_local_size = dst.end() - dst.begin();
+ AssertDimension (dst_local_size, matrix->RangeMap().NumMyElements());
+ const int src_local_size = src.end() - src.begin();
+ AssertDimension (src_local_size, matrix->DomainMap().NumMyElements());
- Epetra_Vector tril_dst (View, matrix->RangeMap(), dst.begin());
- Epetra_Vector tril_src (View, matrix->DomainMap(),
- const_cast<double *>(src.begin()));
+ Epetra_MultiVector tril_dst (View, matrix->RangeMap(), dst.begin(),
+ matrix->DomainMap().NumMyPoints(), 1);
+ Epetra_MultiVector tril_src (View, matrix->DomainMap(),
+ const_cast<TrilinosScalar *>(src.begin()),
+ matrix->DomainMap().NumMyPoints(), 1);
const int ierr = matrix->Multiply (false, tril_src, tril_dst);
Assert (ierr == 0, ExcTrilinosError(ierr));
}
-
- inline
- void
- SparseMatrix::Tvmult (VectorBase &dst,
- const VectorBase &src) const
- {
- Assert (&src != &dst, ExcSourceEqualsDestination());
- Assert (matrix->Filled(), ExcMatrixNotCompressed());
-
- Assert (src.vector_partitioner().SameAs(matrix->RangeMap()) == true,
- ExcMessage ("Column map of matrix does not fit with vector map!"));
- Assert (dst.vector_partitioner().SameAs(matrix->DomainMap()) == true,
- ExcMessage ("Row map of matrix does not fit with vector map!"));
-
- const int ierr = matrix->Multiply (true, src.trilinos_vector(),
- dst.trilinos_vector());
- Assert (ierr == 0, ExcTrilinosError(ierr));
- (void)ierr; // removes -Wunused-variable in optimized mode
- }
-
-
-
+
+ template <typename VectorType>
inline
void
- SparseMatrix::Tvmult (parallel::distributed::Vector<TrilinosScalar> &dst,
- const parallel::distributed::Vector<TrilinosScalar> &src) const
+ SparseMatrix::Tvmult (VectorType &dst,
+ const VectorType &src) const
{
Assert (&src != &dst, ExcSourceEqualsDestination());
Assert (matrix->Filled(), ExcMatrixNotCompressed());
- AssertDimension (dst.local_size(), static_cast<unsigned int>(matrix->DomainMap().NumMyElements()));
- AssertDimension (src.local_size(), static_cast<unsigned int>(matrix->RangeMap().NumMyElements()));
+ internal::SparseMatrix::check_vector_map_equality(*matrix, dst, src);
+ const int dst_local_size = dst.end() - dst.begin();
+ AssertDimension (dst_local_size, matrix->DomainMap().NumMyElements());
+ const int src_local_size = src.end() - src.begin();
+ AssertDimension (src_local_size, matrix->RangeMap().NumMyElements());
- Epetra_Vector tril_dst (View, matrix->DomainMap(), dst.begin());
- Epetra_Vector tril_src (View, matrix->RangeMap(),
- const_cast<double *>(src.begin()));
+ Epetra_MultiVector tril_dst (View, matrix->DomainMap(), dst.begin(),
+ matrix->DomainMap().NumMyPoints(), 1);
+ Epetra_MultiVector tril_src (View, matrix->RangeMap(),
+ const_cast<double *>(src.begin()),
+ matrix->DomainMap().NumMyPoints(), 1);
const int ierr = matrix->Multiply (true, tril_src, tril_dst);
Assert (ierr == 0, ExcTrilinosError(ierr));
+ template <typename VectorType>
inline
void
- SparseMatrix::Tvmult (dealii::Vector<TrilinosScalar> &dst,
- const dealii::Vector<TrilinosScalar> &src) const
+ SparseMatrix::vmult_add (VectorType &dst,
+ const VectorType &src) const
{
Assert (&src != &dst, ExcSourceEqualsDestination());
- Assert (matrix->Filled(), ExcMatrixNotCompressed());
-
- AssertDimension (static_cast<unsigned int>(matrix->DomainMap().NumMyElements()),
- static_cast<unsigned int>(matrix->DomainMap().NumGlobalElements()));
- AssertDimension (dst.size(), static_cast<unsigned int>(matrix->DomainMap().NumMyElements()));
- AssertDimension (src.size(), static_cast<unsigned int>(matrix->RangeMap().NumMyElements()));
-
- Epetra_Vector tril_dst (View, matrix->DomainMap(), dst.begin());
- Epetra_Vector tril_src (View, matrix->RangeMap(),
- const_cast<double *>(src.begin()));
- const int ierr = matrix->Multiply (true, tril_src, tril_dst);
- Assert (ierr == 0, ExcTrilinosError(ierr));
- (void)ierr; // removes -Wunused-variable in optimized mode
+ // Reinit a temporary vector with fast argument set, which does not
+ // overwrite the content (to save time). However, the
+ // TrilinosWrappers::Vector classes do not support this, so create a
+ // deal.II local vector that has this fast setting. It will be accepted in
+ // vmult because it only checks the local size.
+ dealii::Vector<TrilinosScalar> temp_vector;
+ temp_vector.reinit(dst.end()-dst.begin(), true);
+ dealii::VectorView<TrilinosScalar> src_view(src.end()-src.begin(), src.begin());
+ dealii::VectorView<TrilinosScalar> dst_view(dst.end()-dst.begin(), dst.begin());
+ vmult (temp_vector, static_cast<const dealii::Vector<TrilinosScalar>&>(src_view));
+ if (dst_view.size() > 0)
+ dst_view += temp_vector;
}
+ template <typename VectorType>
inline
void
- SparseMatrix::vmult_add (VectorBase &dst,
- const VectorBase &src) const
+ SparseMatrix::Tvmult_add (VectorType &dst,
+ const VectorType &src) const
{
Assert (&src != &dst, ExcSourceEqualsDestination());
- // Choose to reinit the vector with fast
- // argument set, which does not overwrite
- // the content -- this is what we need
- // since we're going to overwrite that
- // anyway in the vmult operation.
- temp_vector.reinit(dst, true);
-
- vmult (temp_vector, src);
- dst += temp_vector;
- }
-
-
-
- inline
- void
- SparseMatrix::Tvmult_add (VectorBase &dst,
- const VectorBase &src) const
- {
- Assert (&src != &dst, ExcSourceEqualsDestination());
-
- temp_vector.reinit(dst, true);
-
- Tvmult (temp_vector, src);
- dst += temp_vector;
+ // Reinit a temporary vector with fast argument set, which does not
+ // overwrite the content (to save time). However, the
+ // TrilinosWrappers::Vector classes do not support this, so create a
+ // deal.II local vector that has this fast setting. It will be accepted in
+ // vmult because it only checks the local size.
+ dealii::Vector<TrilinosScalar> temp_vector;
+ temp_vector.reinit(dst.end()-dst.begin(), true);
+ dealii::VectorView<TrilinosScalar> src_view(src.end()-src.begin(), src.begin());
+ dealii::VectorView<TrilinosScalar> dst_view(dst.end()-dst.begin(), dst.begin());
+ Tvmult (temp_vector, static_cast<const dealii::Vector<TrilinosScalar>&>(src_view));
+ if (dst_view.size() > 0)
+ dst_view += temp_vector;
}
Assert (row_partitioner().SameAs(domain_partitioner()),
ExcNotQuadratic());
- temp_vector.reinit(v);
+ VectorBase temp_vector;
+ temp_vector.reinit(v, true);
vmult (temp_vector, v);
return temp_vector*v;
Assert (row_partitioner().SameAs(domain_partitioner()),
ExcNotQuadratic());
- temp_vector.reinit(v);
+ VectorBase temp_vector;
+ temp_vector.reinit(v, true);
vmult (temp_vector, v);
return u*temp_vector;
class Vector : public VectorBase
{
public:
+ /**
+ * A variable that indicates whether this vector
+ * supports distributed data storage. If true, then
+ * this vector also needs an appropriate compress()
+ * function that allows communicating recent set or
+ * add operations to individual elements to be communicated
+ * to other processors.
+ *
+ * For the current class, the variable equals
+ * true, since it does support parallel data storage.
+ */
+ static const bool supports_distributed_data = true;
+
/**
* @name Basic constructors and initalization.
*/
-//@{
+ //@{
/**
* Default constructor that
* generates an empty (zero size)
class Vector : public VectorBase
{
public:
+ /**
+ * A variable that indicates whether this vector
+ * supports distributed data storage. If true, then
+ * this vector also needs an appropriate compress()
+ * function that allows communicating recent set or
+ * add operations to individual elements to be communicated
+ * to other processors.
+ *
+ * For the current class, the variable equals
+ * false, since it does not support parallel data storage.
+ * If you do need parallel data storage, use
+ * TrilinosWrappers::MPI::Vector.
+ */
+ static const bool supports_distributed_data = false;
+
/**
* Default constructor that
* generates an empty (zero size)
//---------------------------------------------------------------------------
// $Id$
//
-// Copyright (C) 2008, 2009, 2010, 2011, 2012 by the deal.II authors
+// Copyright (C) 2008, 2009, 2010, 2011, 2012, 2013 by the deal.II authors
//
// This file is subject to QPL and may not be distributed
// without copyright and license information. Please refer
* <tt>C</tt> standard libraries
* <tt>vector<...></tt> class.
*/
- typedef TrilinosScalar value_type;
- typedef TrilinosScalar real_type;
- typedef std::size_t size_type;
- typedef internal::VectorReference reference;
+ typedef TrilinosScalar value_type;
+ typedef TrilinosScalar real_type;
+ typedef std::size_t size_type;
+ typedef value_type *iterator;
+ typedef const value_type *const_iterator;
+ typedef internal::VectorReference reference;
typedef const internal::VectorReference const_reference;
/**
*/
bool in_local_range (const unsigned int index) const;
+ /**
+ * Return an index set that describes which elements of this vector
+ * are owned by the current processor. Note that this index set does
+ * not include elements this vector may store locally as ghost
+ * elements but that are in fact owned by another processor.
+ * As a consequence, the index sets returned on different
+ * processors if this is a distributed vector will form disjoint
+ * sets that add up to the complete index set.
+ * Obviously, if a vector is created on only one processor, then
+ * the result would satisfy
+ * @code
+ * vec.locally_owned_elements() == complete_index_set (vec.size())
+ * @endcode
+ */
+ IndexSet locally_owned_elements () const;
+
/**
* Return if the vector contains ghost
* elements. This answer is true if there
*/
TrilinosScalar el (const unsigned int index) const;
+ /**
+ * Make the Vector class a bit like the <tt>vector<></tt> class of
+ * the C++ standard library by returning iterators to the start and end
+ * of the locally owned elements of this vector. The ordering of local elements corresponds to the one given
+ *
+ * It holds that end() - begin() == local_size().
+ */
+ iterator begin ();
+
+ /**
+ * Return constant iterator to the start of the locally owned elements
+ * of the vector.
+ */
+ const_iterator begin () const;
+
+ /**
+ * Return an iterator pointing to the element past the end of the array
+ * of locally owned entries.
+ */
+ iterator end ();
+
+ /**
+ * Return a constant iterator pointing to the element past the end of
+ * the array of the locally owned entries.
+ */
+ const_iterator end () const;
+
/**
* A collective set operation:
* instead of setting individual
+ inline
+ IndexSet
+ VectorBase::locally_owned_elements() const
+ {
+ IndexSet is (size());
+
+ // TODO: Trilinos does allow non-contiguous ranges for locally
+ // owned elements. if that is the case for the current
+ // vector, local_range() will throw an exception. Fix this.
+ const std::pair<unsigned int, unsigned int> x = local_range();
+ is.add_range (x.first, x.second);
+
+ return is;
+ }
+
+
+
inline
bool
VectorBase::has_ghost_elements() const
+ inline
+ VectorBase::iterator
+ VectorBase::begin()
+ {
+ return (*vector)[0];
+ }
+
+
+
+ inline
+ VectorBase::iterator
+ VectorBase::end()
+ {
+ return (*vector)[0]+local_size();
+ }
+
+
+
+ inline
+ VectorBase::const_iterator
+ VectorBase::begin() const
+ {
+ return (*vector)[0];
+ }
+
+
+
+ inline
+ VectorBase::const_iterator
+ VectorBase::end() const
+ {
+ return (*vector)[0]+local_size();
+ }
+
+
+
inline
void
VectorBase::reinit (const VectorBase &v,
#include <deal.II/base/logstream.h>
#include <deal.II/base/exceptions.h>
#include <deal.II/base/subscriptor.h>
+#include <deal.II/base/index_set.h>
#include <boost/serialization/array.hpp>
#include <boost/serialization/split_member.hpp>
*/
typedef typename numbers::NumberTraits<Number>::real_type real_type;
+ /**
+ * A variable that indicates whether this vector
+ * supports distributed data storage. If true, then
+ * this vector also needs an appropriate compress()
+ * function that allows communicating recent set or
+ * add operations to individual elements to be communicated
+ * to other processors.
+ *
+ * For the current class, the variable equals
+ * false, since it does not support parallel data storage.
+ */
+ static const bool supports_distributed_data = false;
+
public:
/**
*/
bool in_local_range (const types::global_dof_index global_index) const;
+ /**
+ * Return an index set that describes which elements of this vector
+ * are owned by the current processor. Note that this index set does
+ * not include elements this vector may store locally as ghost
+ * elements but that are in fact owned by another processor.
+ * As a consequence, the index sets returned on different
+ * processors if this is a distributed vector will form disjoint
+ * sets that add up to the complete index set.
+ * Obviously, if a vector is created on only one processor, then
+ * the result would satisfy
+ * @code
+ * vec.locally_owned_elements() == complete_index_set (vec.size())
+ * @endcode
+ *
+ * Since the current data type does not support parallel data storage
+ * across different processors, the returned index set is the
+ * complete index set.
+ */
+ IndexSet locally_owned_elements () const;
+
/**
* Return dimension of the vector.
*/
}
template<typename T>
- void copy_subrange (const unsigned int begin,
- const unsigned int end,
+ void copy_subrange (const unsigned int begin,
+ const unsigned int end,
const dealii::Vector<T> &src,
- dealii::Vector<T> &dst)
+ dealii::Vector<T> &dst)
{
memcpy(&*(dst.begin()+begin), &*(src.begin()+begin),
(end-begin)*sizeof(T));
}
template<typename T, typename U>
- void copy_subrange (const unsigned int begin,
- const unsigned int end,
+ void copy_subrange (const unsigned int begin,
+ const unsigned int end,
const dealii::Vector<T> &src,
- dealii::Vector<U> &dst)
+ dealii::Vector<U> &dst)
{
const T *q = src.begin()+begin;
const T *const end_q = src.begin()+end;
}
template<typename T, typename U>
- void copy_subrange_wrap (const unsigned int begin,
- const unsigned int end,
+ void copy_subrange_wrap (const unsigned int begin,
+ const unsigned int end,
const dealii::Vector<T> &src,
- dealii::Vector<U> &dst)
+ dealii::Vector<U> &dst)
{
copy_subrange (begin, end, src, dst);
}
template <typename T, typename U>
void copy_vector (const dealii::Vector<T> &src,
- dealii::Vector<U> &dst)
+ dealii::Vector<U> &dst)
{
+ if (PointerComparison::equal(&src, &dst))
+ return;
+
const unsigned int vec_size = src.size();
const unsigned int dst_size = dst.size();
if (dst_size != vec_size)
+template <typename Number>
+IndexSet
+Vector<Number>::locally_owned_elements() const
+{
+ return complete_index_set(size());
+}
+
+
+
template <typename Number>
std::size_t
Vector<Number>::memory_consumption () const
*/
std::vector<unsigned int> plain_dof_indices;
+ /**
+ * Stores the dimension of the underlying DoFHandler. Since the indices
+ * are not templated, this is the variable that makes the dimension
+ * accessible in the (rare) cases it is needed inside this class.
+ */
+ unsigned int dimension;
+
/**
* Stores the number of components in the DoFHandler where the indices
* have been read from.
constrained_dofs (dof_info_in.constrained_dofs),
row_starts_plain_indices (dof_info_in.row_starts_plain_indices),
plain_dof_indices (dof_info_in.plain_dof_indices),
+ dimension (dof_info_in.dimension),
n_components (dof_info_in.n_components),
dofs_per_cell (dof_info_in.dofs_per_cell),
dofs_per_face (dof_info_in.dofs_per_face),
ghost_dofs.clear();
dofs_per_cell.clear();
dofs_per_face.clear();
+ dimension = 2;
n_components = 0;
row_starts_plain_indices.clear();
plain_dof_indices.clear();
*/
unsigned int cell_data_number;
- /**
- * If the present cell chunk for vectorization is not completely filled up
- * with data, this field stores how many physical cells are underlying. Is
- * between 1 and VectorizedArray<Number>::n_array_elements-1 (inclusive).
- */
- unsigned int n_irreg_components_filled;
-
- /**
- * Stores whether the present cell chunk used in vectorization is not
- * completely filled up with physical cells. E.g. if vectorization dictates
- * that four cells should be worked with but only three physical cells are
- * left, this flag will be set to true, otherwise to false. Mainly used for
- * internal checking when reading from vectors or writing to vectors.
- */
- bool at_irregular_cell;
-
/**
* Debug information to track whether dof values have been initialized
* before accessed. Used to control exceptions when uninitialized data is
jacobian_grad_upper(0),
cell (numbers::invalid_unsigned_int),
cell_type (internal::MatrixFreeFunctions::undefined),
- cell_data_number (0),
- n_irreg_components_filled (0),
- at_irregular_cell (false)
+ cell_data_number (0)
{
- Assert (matrix_info.indices_initialized() == true,
- ExcNotInitialized());
Assert (matrix_info.mapping_initialized() == true,
ExcNotInitialized());
AssertDimension (matrix_info.get_size_info().vectorization_length,
VectorizedArray<Number>::n_array_elements);
Assert (n_fe_components == 1 ||
+ n_components == 1 ||
n_components == n_fe_components,
ExcMessage ("The underlying FE is vector-valued. In this case, the "
"template argument n_components must be a the same "
}
}
- n_irreg_components_filled =
- std_cxx1x::get<2>(dof_info.row_starts[cell_in]);
- at_irregular_cell = n_irreg_components_filled > 0;
#ifdef DEBUG
dof_values_initialized = false;
values_quad_initialized = false;
// into the local data field or write local data into the vector. Certain
// operations are no-ops for the given use case.
+ Assert (matrix_info.indices_initialized() == true,
+ ExcNotInitialized());
Assert (cell != numbers::invalid_unsigned_int, ExcNotInitialized());
// loop over all local dofs. ind_local holds local number on cell, index
dof_info.end_indicators(cell);
unsigned int ind_local = 0;
+ const unsigned int n_irreg_components_filled =
+ std_cxx1x::get<2>(dof_info.row_starts[cell]);
+ const bool at_irregular_cell = n_irreg_components_filled > 0;
+
// scalar case (or case when all components have the same degrees of freedom
// and sit on a different vector each)
if (n_fe_components == 1)
{
// this is different from the other three operations because we do not use
// constraints here, so this is a separate function.
+ Assert (matrix_info.indices_initialized() == true,
+ ExcNotInitialized());
Assert (cell != numbers::invalid_unsigned_int, ExcNotInitialized());
Assert (dof_info.store_plain_indices == true, ExcNotInitialized());
// points to the global indices stored in index_local_to_global
const unsigned int *dof_indices = dof_info.begin_indices_plain(cell);
+ const unsigned int n_irreg_components_filled =
+ std_cxx1x::get<2>(dof_info.row_starts[cell]);
+ const bool at_irregular_cell = n_irreg_components_filled > 0;
+
// scalar case (or case when all components have the same degrees of freedom
// and sit on a different vector each)
if (n_fe_components == 1)
inline
void compress_finish (parallel::distributed::Vector<Number> &vec)
{
- vec.compress_finish();
+ vec.compress_finish(::dealii::VectorOperation::add);
}
#include <deal.II/base/utilities.h>
#include <deal.II/base/memory_consumption.h>
#include <deal.II/base/tensor_product_polynomials.h>
+#include <deal.II/base/polynomials_piecewise.h>
#include <deal.II/base/mpi.h>
#include <deal.II/dofs/dof_accessor.h>
#include <deal.II/fe/fe_poly.h>
initialize_indices (constraint, locally_owned_set);
}
+ // initialize bare structures
+ else if (dof_info.size() != dof_handler.size())
+ {
+ initialize_dof_handlers(dof_handler, additional_data.level_mg_handler);
+ std::vector<unsigned int> dummy;
+ size_info.make_layout (cell_level_index.size(),
+ VectorizedArray<Number>::n_array_elements,
+ dummy, dummy);
+ for (unsigned int i=0; i<dof_info.size(); ++i)
+ {
+ dof_info[i].dimension = dim;
+ dof_info[i].n_components = dof_handler[i]->get_fe().element_multiplicity(0);
+ dof_info[i].dofs_per_cell.push_back(dof_handler[i]->get_fe().dofs_per_cell);
+ dof_info[i].row_starts.resize(size_info.n_macro_cells+1);
+ std_cxx1x::get<2>(dof_info[i].row_starts.back()) =
+ cell_level_index.size() % VectorizedArray<Number>::n_array_elements;
+
+ // if indices are not initialized, the cell_level_index might not be
+ // divisible by the vectorization length. But it must be for
+ // mapping_info...
+ while (cell_level_index.size() % VectorizedArray<Number>::n_array_elements
+ != 0)
+ cell_level_index.push_back(cell_level_index.back());
+ }
+ }
+
// Reads out the FE information and stores the shape function values,
// gradients and Hessians for quadrature points.
const unsigned int n_fe = dof_handler.size();
initialize_indices (constraint, locally_owned_set);
}
+ // initialize bare structures
+ else if (dof_info.size() != dof_handler.size())
+ {
+ initialize_dof_handlers(dof_handler, additional_data.level_mg_handler);
+ std::vector<unsigned int> dummy;
+ size_info.make_layout (cell_level_index.size(),
+ VectorizedArray<Number>::n_array_elements,
+ dummy, dummy);
+ for (unsigned int i=0; i<dof_info.size(); ++i)
+ {
+ Assert(dof_handler[i]->get_fe().size() == 1, ExcNotImplemented());
+ dof_info[i].dimension = dim;
+ dof_info[i].n_components = dof_handler[i]->get_fe()[0].element_multiplicity(0);
+ dof_info[i].dofs_per_cell.push_back(dof_handler[i]->get_fe()[0].dofs_per_cell);
+ dof_info[i].row_starts.resize(size_info.n_macro_cells+1);
+ std_cxx1x::get<2>(dof_info[i].row_starts.back()) =
+ cell_level_index.size() % VectorizedArray<Number>::n_array_elements;
+
+ // if indices are not initialized, the cell_level_index might not be
+ // divisible by the vectorization length. But it must be for
+ // mapping_info...
+ while (cell_level_index.size() % VectorizedArray<Number>::n_array_elements
+ != 0)
+ cell_level_index.push_back(cell_level_index.back());
+ }
+ }
+
// Reads out the FE information and stores the shape function values,
// gradients and Hessians for quadrature points.
const unsigned int n_components = dof_handler.size();
// cache number of finite elements and dofs_per_cell
dof_info[no].dofs_per_cell.push_back (fe.dofs_per_cell);
dof_info[no].dofs_per_face.push_back (fe.dofs_per_face);
- dof_info[no].n_components = n_fe_components;
-
+ dof_info[no].dimension = dim;
+ dof_info[no].n_components = n_fe_components;
// get permutation that gives lexicographic renumbering of the cell
// dofs renumber (this is necessary for FE_Q, for example, since
const FE_Poly<TensorProductPolynomials<dim>,dim,dim> *fe_poly =
dynamic_cast<const FE_Poly<TensorProductPolynomials<dim>,dim,dim>*>
(&fe.base_element(0));
+ const FE_Poly<TensorProductPolynomials<dim,Polynomials::
+ PiecewisePolynomial<double> >,dim,dim> *fe_poly_piece =
+ dynamic_cast<const FE_Poly<TensorProductPolynomials<dim,
+ Polynomials::PiecewisePolynomial<double> >,dim,dim>*>
+ (&fe.base_element(0));
// This class currently only works for elements derived from
- // FE_Poly<TensorProductPolynomials<dim>,dim,dim>. For any other
- // element, the dynamic cast above will fail and give fe_poly == 0.
- Assert (fe_poly != 0, ExcNotImplemented());
+ // FE_Poly<TensorProductPolynomials<dim>,dim,dim> or piecewise
+ // polynomials. For any other element, the dynamic casts above will
+ // fail and give fe_poly == 0.
+ Assert (fe_poly != 0 || fe_poly_piece != 0, ExcNotImplemented());
if (n_fe_components == 1)
{
- lexicographic_inv[no][fe_index] =
- fe_poly->get_poly_space_numbering_inverse();
+ if (fe_poly != 0)
+ lexicographic_inv[no][fe_index] =
+ fe_poly->get_poly_space_numbering_inverse();
+ else
+ lexicographic_inv[no][fe_index] =
+ fe_poly_piece->get_poly_space_numbering_inverse();
AssertDimension (lexicographic_inv[no][fe_index].size(),
dof_info[no].dofs_per_cell[fe_index]);
}
// ok, we have more than one component
Assert (n_fe_components > 1, ExcInternalError());
std::vector<unsigned int> scalar_lex =
- fe_poly->get_poly_space_numbering();
+ fe_poly != 0 ? fe_poly->get_poly_space_numbering() :
+ fe_poly_piece->get_poly_space_numbering();
AssertDimension (scalar_lex.size() * n_fe_components,
dof_info[no].dofs_per_cell[fe_index]);
std::vector<unsigned int> lexicographic (dof_info[no].dofs_per_cell[fe_index]);
cell_level_index.clear();
size_info.clear();
task_info.clear();
+ dof_handlers.dof_handler.clear();
+ dof_handlers.hp_dof_handler.clear();
indices_are_initialized = false;
mapping_is_initialized = false;
}
// $Id$
// Version: $Name$
//
-// Copyright (C) 2011 by the deal.II authors
+// Copyright (C) 2011, 2013 by the deal.II authors
//
// This file is subject to QPL and may not be distributed
// without copyright and license information. Please refer
#include <deal.II/base/memory_consumption.h>
#include <deal.II/base/polynomial.h>
#include <deal.II/base/tensor_product_polynomials.h>
+#include <deal.II/base/polynomials_piecewise.h>
#include <deal.II/fe/fe_poly.h>
-#include <deal.II/fe/fe_tools.h>
#include <deal.II/matrix_free/shape_info.h>
{
const FE_Poly<TensorProductPolynomials<dim>,dim,dim> *fe_poly =
dynamic_cast<const FE_Poly<TensorProductPolynomials<dim>,dim,dim>*>(&fe);
- Assert (fe_poly != 0, ExcNotImplemented());
- lexicographic = fe_poly->get_poly_space_numbering_inverse();
+ const FE_Poly<TensorProductPolynomials<dim,Polynomials::
+ PiecewisePolynomial<double> >,dim,dim> *fe_poly_piece =
+ dynamic_cast<const FE_Poly<TensorProductPolynomials<dim,
+ Polynomials::PiecewisePolynomial<double> >,dim,dim>*> (&fe);
+ Assert (fe_poly != 0 || fe_poly_piece, ExcNotImplemented());
+ lexicographic = fe_poly != 0 ?
+ fe_poly->get_poly_space_numbering_inverse() :
+ fe_poly_piece->get_poly_space_numbering_inverse();
// to evaluate 1D polynomials, evaluate along the line where y=z=0,
// assuming that shape_value(0,Point<dim>()) == 1. otherwise, need
+++ /dev/null
-//---------------------------------------------------------------------------
-// $Id$
-//
-// Copyright (C) 2006, 2007, 2008, 2009, 2010, 2011, 2012 by the deal.II authors
-//
-// This file is subject to QPL and may not be distributed
-// without copyright and license information. Please refer
-// to the file deal.II/doc/license.html for the text and
-// further information on this license.
-//
-//---------------------------------------------------------------------------
-
-#ifndef __deal2__mesh_worker_vector_info_h
-#define __deal2__mesh_worker_vector_info_h
-
-#include <deal.II/base/named_data.h>
-#include <deal.II/lac/block_indices.h>
-#include <deal.II/numerics/mesh_worker_info.h>
-
-DEAL_II_NAMESPACE_OPEN
-
-namespace MeshWorker
-{
- /**
- * This class is a simple object that can be used in
- * MeshWorker::loop(). For all vectors provided in the argument to
- * initialize_data(), this class generates the local data vector on a
- * cell specified by reinit().
- *
- * This objects of class as part of VectorInfoBox conform to the
- * interface for INFOBOX laid out in the documentation of MeshWorker.
- *
- * See IntegrationInfo for an alternative.
- *
- * @author Guido Kanschat
- * @date 2012
- */
- class VectorInfo
- {
- public:
- /**
- * Initialize the data
- * vector and cache the
- * selector.
- */
- void initialize_data(const NamedData<BlockVector<double>*> &data);
-
- /**
- * Reinitialize the local data
- * vectors to represent the
- * information on the given cell.
- */
- template<int dim, int spacedim>
- void reinit(const MeshWorker::DoFInfo<dim, spacedim> &cell);
-
- /**
- * Return local data vector
- * <i>i</i>, which selects the
- * local data from vector
- * <i>i</i> of the
- * <code>data</code> object
- * used in initialize_data().
- */
- BlockVector<double> &operator() (unsigned int i);
-
- private:
- std::vector<BlockVector<double> > local_data;
- /**
- * The global data vector
- * used to compute function
- * values in quadrature
- * points.
- */
- SmartPointer<const NamedData<BlockVector<double>*> > global_data;
- };
-
-
- /**
- * A class conforming to the INFOBOX interface in the documentation of
- * MeshWorker. This class provides local operators in
- * MeshWorker::loop() with the local values of the degrees of freedom
- * of global vectors, for instance for calculations based on cell
- * matrices.
- *
- * For an alternative providing the values in quadrature points see
- * IntegrationInfoBox.
- *
- * @author Guido Kanschat
- * @date 2012
- */
- class VectorInfoBox
- {
- public:
- typedef VectorInfo CellInfo;
-
- void initialize_data(const NamedData<BlockVector<double>*> &data);
-
- template <int dim, class DOFINFO>
- void post_cell(const MeshWorker::DoFInfoBox<dim, DOFINFO> &)
- {}
-
- template <int dim, class DOFINFO>
- void post_faces(const MeshWorker::DoFInfoBox<dim, DOFINFO> &)
- {}
-
- VectorInfo cell;
- VectorInfo boundary;
- VectorInfo face;
- VectorInfo subface;
- VectorInfo neighbor;
- };
-
-
- inline
- void
- VectorInfo::initialize_data(const NamedData<BlockVector<double>*> &data)
- {
- global_data = &data;
- local_data.resize(global_data->size());
- }
-
-
- template<int dim, int spacedim>
- inline
- void
- VectorInfo::reinit(const MeshWorker::DoFInfo<dim, spacedim> &i)
- {
- const NamedData<BlockVector<double>*> &gd = *global_data;
-
- for (unsigned int k=0; k<local_data.size(); ++k)
- {
- const BlockVector<double> &v = *gd(k);
-
- local_data[k].reinit(i.block_info->local());
- for (unsigned int j=0; j<local_data[k].size(); ++j)
- local_data[k](j) = v(i.indices[j]);
- }
- }
-
-
- inline
- BlockVector<double> &
- VectorInfo::operator() (unsigned int i)
- {
- AssertIndexRange(i, local_data.size());
- return local_data[i];
- }
-
-
- inline
- void
- VectorInfoBox::initialize_data(const NamedData<BlockVector<double>*> &data)
- {
- cell.initialize_data(data);
- boundary.initialize_data(data);
- face.initialize_data(data);
- subface.initialize_data(data);
- neighbor.initialize_data(data);
- }
-
-}
-
-DEAL_II_NAMESPACE_CLOSE
-
-#endif
{
deallog.push("Smooth");
- unsigned int maxlevel = matrices.get_maxlevel();
+ unsigned int maxlevel = matrices.max_level();
unsigned int steps2 = steps;
if (variable)
//---------------------------------------------------------------------------
// $Id$
//
-// Copyright (C) 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2009, 2010, 2012 by the deal.II authors
+// Copyright (C) 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2009, 2010, 2012, 2013 by the deal.II authors
//
// This file is subject to QPL and may not be distributed
// without copyright and license information. Please refer
{
typedef ::dealii::SparsityPattern Sparsity;
typedef ::dealii::SparseMatrix<typename VECTOR::value_type> Matrix;
+
+ template <class CSP, class DH>
+ static void reinit(Matrix& matrix, Sparsity& sparsity, int level, const CSP& csp, const DH&)
+ {
+ sparsity.copy_from (csp);
+ matrix.reinit (sparsity);
+ }
};
#ifdef DEAL_II_WITH_TRILINOS
{
typedef ::dealii::TrilinosWrappers::SparsityPattern Sparsity;
typedef ::dealii::TrilinosWrappers::SparseMatrix Matrix;
+
+ template <class CSP, class DH>
+ static void reinit(Matrix& matrix, Sparsity& sparsity, int level, const CSP& csp, DH& dh)
+ {
+ matrix.reinit(dh.locally_owned_mg_dofs(level+1),
+ dh.locally_owned_mg_dofs(level),
+ csp, MPI_COMM_WORLD, true);
+ }
+
};
template <>
{
typedef ::dealii::TrilinosWrappers::SparsityPattern Sparsity;
typedef ::dealii::TrilinosWrappers::SparseMatrix Matrix;
+
+ template <class CSP, class DH>
+ static void reinit(Matrix& matrix, Sparsity& sparsity, int level, const CSP& csp, DH& dh)
+ {
+ }
};
#endif
}
set_component_to_block_map (const std::vector<unsigned int> &map);
/**
- * Finite element does not
- * provide prolongation matrices.
+ * Finite element does not provide prolongation matrices.
*/
DeclException0(ExcNoProlongation);
/**
- * Call @p build_matrices
- * function first.
+ * You have to call build_matrices() before using this object.
*/
DeclException0(ExcMatricesNotBuilt);
* Memory used by this object.
*/
std::size_t memory_consumption () const;
-
+
+ /**
+ * Print all the matrices for debugging purposes.
+ */
+ void print_matrices(std::ostream& os) const;
private:
// forward declarations
template <int dim> class Quadrature;
+class ConstraintMatrix;
+
template<typename number> class Vector;
template<typename number> class FullMatrix;
template<typename number> class SparseMatrix;
* the matrix wasn't empty before. Therefore you may want to clear the matrix
* before assemblage.
*
- * All created matrices are `raw': they are not condensed,
+ * By default, all created matrices are `raw': they are not condensed,
* i.e. hanging nodes are not eliminated. The reason is that you may
* want to add several matrices and could then condense afterwards
* only once, instead of for every matrix. To actually do computations
* with these matrices, you have to condense the matrix using the
* ConstraintMatrix::condense function; you also have to
* condense the right hand side accordingly and distribute the
- * solution afterwards.
+ * solution afterwards. Alternatively, you can give an optional argument
+ * ConstraintMatrix that writes cell matrix (and vector) entries with
+ * distribute_local_to_global into the global matrix and vector. This way,
+ * adding several matrices from different sources is more complicated and
+ * you should make sure that you do not mix different ways of applying
+ * constraints. Particular caution is necessary when the given
+ * constraint matrix contains inhomogeneous constraints: In that case, the
+ * matrix assembled this way must be the only matrix (or you need to
+ * assemble the <b>same</b> right hand side for <b>every</b> matrix
+ * you generate and add together).
*
* If you want to use boundary conditions with the matrices generated
- * by the functions of this class, you have to use a function like
+ * by the functions of this class in addition to the ones in a possible
+ * constraint matrix, you have to use a function like
* <tt>ProblemBase<>::apply_dirichlet_bc</tt> to matrix and right hand
* side.
*
namespace MatrixCreator
{
/**
- * Assemble the mass matrix. If no
- * coefficient is given, it is assumed
- * to be unity.
+ * Assemble the mass matrix. If no coefficient is given, it is assumed to be
+ * unity.
+ *
+ * If the library is configured to use multithreading, this function works
+ * in parallel.
*
- * If the library is configured
- * to use multithreading, this
- * function works in parallel.
+ * The optional argument @p constraints allows to apply constraints on the
+ * resulting matrix directly. Be careful when combining several matrices and
+ * using inhomogeneous constraints.
*
- * See the general doc of this class
- * for more information.
+ * See the general doc of this class for more information.
*/
template <int dim, typename number, int spacedim>
void create_mass_matrix (const Mapping<dim, spacedim> &mapping,
const DoFHandler<dim,spacedim> &dof,
const Quadrature<dim> &q,
SparseMatrix<number> &matrix,
- const Function<spacedim> *const a = 0);
+ const Function<spacedim> *const a = 0,
+ const ConstraintMatrix &constraints = ConstraintMatrix());
/**
- * Calls the create_mass_matrix()
- * function, see above, with
+ * Calls the create_mass_matrix() function, see above, with
* <tt>mapping=MappingQ1@<dim@>()</tt>.
*/
template <int dim, typename number, int spacedim>
void create_mass_matrix (const DoFHandler<dim,spacedim> &dof,
const Quadrature<dim> &q,
SparseMatrix<number> &matrix,
- const Function<spacedim> *const a = 0);
+ const Function<spacedim> *const a = 0,
+ const ConstraintMatrix &constraints = ConstraintMatrix());
/**
- * Assemble the mass matrix and a
- * right hand side vector. If no
- * coefficient is given, it is
- * assumed to be unity.
+ * Assemble the mass matrix and a right hand side vector. If no coefficient
+ * is given, it is assumed to be unity.
+ *
+ * If the library is configured to use multithreading, this function works
+ * in parallel.
*
- * If the library is configured
- * to use multithreading, this
- * function works in parallel.
+ * The optional argument @p constraints allows to apply constraints on the
+ * resulting matrix directly. Be careful when combining several matrices and
+ * using inhomogeneous constraints.
*
- * See the general doc of this
- * class for more information.
+ * See the general doc of this class for more information.
*/
template <int dim, typename number, int spacedim>
- void create_mass_matrix (const Mapping<dim, spacedim> &mapping,
- const DoFHandler<dim,spacedim> &dof,
+ void create_mass_matrix (const Mapping<dim, spacedim> &mapping,
+ const DoFHandler<dim,spacedim> &dof,
const Quadrature<dim> &q,
SparseMatrix<number> &matrix,
- const Function<spacedim> &rhs,
+ const Function<spacedim> &rhs,
Vector<double> &rhs_vector,
- const Function<spacedim> *const a = 0);
+ const Function<spacedim> *const a = 0,
+ const ConstraintMatrix &constraints = ConstraintMatrix());
/**
- * Calls the create_mass_matrix()
- * function, see above, with
+ * Calls the create_mass_matrix() function, see above, with
* <tt>mapping=MappingQ1@<dim@>()</tt>.
*/
template <int dim, typename number, int spacedim>
- void create_mass_matrix (const DoFHandler<dim,spacedim> &dof,
+ void create_mass_matrix (const DoFHandler<dim,spacedim> &dof,
const Quadrature<dim> &q,
SparseMatrix<number> &matrix,
- const Function<spacedim> &rhs,
+ const Function<spacedim> &rhs,
Vector<double> &rhs_vector,
- const Function<spacedim> *const a = 0);
+ const Function<spacedim> *const a = 0,
+ const ConstraintMatrix &constraints = ConstraintMatrix());
+
/**
- * Same function as above, but for hp
- * objects.
+ * Same function as above, but for hp objects.
*/
template <int dim, typename number, int spacedim>
void create_mass_matrix (const hp::MappingCollection<dim,spacedim> &mapping,
const hp::DoFHandler<dim,spacedim> &dof,
const hp::QCollection<dim> &q,
SparseMatrix<number> &matrix,
- const Function<spacedim> *const a = 0);
+ const Function<spacedim> *const a = 0,
+ const ConstraintMatrix &constraints = ConstraintMatrix());
/**
- * Same function as above, but for hp
- * objects.
+ * Same function as above, but for hp objects.
*/
template <int dim, typename number, int spacedim>
void create_mass_matrix (const hp::DoFHandler<dim,spacedim> &dof,
const hp::QCollection<dim> &q,
SparseMatrix<number> &matrix,
- const Function<spacedim> *const a = 0);
+ const Function<spacedim> *const a = 0,
+ const ConstraintMatrix &constraints = ConstraintMatrix());
/**
- * Same function as above, but for hp
- * objects.
+ * Same function as above, but for hp objects.
*/
template <int dim, typename number, int spacedim>
- void create_mass_matrix (const hp::MappingCollection<dim,spacedim> &mapping,
- const hp::DoFHandler<dim,spacedim> &dof,
- const hp::QCollection<dim> &q,
+ void create_mass_matrix (const hp::MappingCollection<dim,spacedim> &mapping,
+ const hp::DoFHandler<dim,spacedim> &dof,
+ const hp::QCollection<dim> &q,
SparseMatrix<number> &matrix,
- const Function<spacedim> &rhs,
+ const Function<spacedim> &rhs,
Vector<double> &rhs_vector,
- const Function<spacedim> *const a = 0);
+ const Function<spacedim> *const a = 0,
+ const ConstraintMatrix &constraints = ConstraintMatrix());
/**
- * Same function as above, but for hp
- * objects.
+ * Same function as above, but for hp objects.
*/
template <int dim, typename number, int spacedim>
- void create_mass_matrix (const hp::DoFHandler<dim,spacedim> &dof,
- const hp::QCollection<dim> &q,
+ void create_mass_matrix (const hp::DoFHandler<dim,spacedim> &dof,
+ const hp::QCollection<dim> &q,
SparseMatrix<number> &matrix,
- const Function<spacedim> &rhs,
+ const Function<spacedim> &rhs,
Vector<double> &rhs_vector,
- const Function<spacedim> *const a = 0);
+ const Function<spacedim> *const a = 0,
+ const ConstraintMatrix &constraints = ConstraintMatrix());
/**
- * Assemble the mass matrix and a
- * right hand side vector along
- * the boundary.
+ * Assemble the mass matrix and a right hand side vector along the boundary.
*
- * The matrix is assumed to
- * already be initialized with a
- * suiting sparsity pattern (the
- * DoFHandler provides an
- * appropriate function).
+ * The matrix is assumed to already be initialized with a suiting sparsity
+ * pattern (the DoFHandler provides an appropriate function).
*
- * If the library is configured
- * to use multithreading, this
- * function works in parallel.
+ * If the library is configured to use multithreading, this function works
+ * in parallel.
*
- * @arg @p weight: an optional
- * weight for the computation of
- * the mass matrix. If no weight
- * is given, it is set to one.
+ * @arg @p weight: an optional weight for the computation of the mass
+ * matrix. If no weight is given, it is set to one.
*
- * @arg @p component_mapping: if
- * the components in @p
- * boundary_functions and @p dof
- * do not coincide, this vector
- * allows them to be remapped. If
- * the vector is not empty, it
- * has to have one entry for each
- * component in @p dof. This
- * entry is the component number
- * in @p boundary_functions that
- * should be used for this
- * component in @p dof. By
- * default, no remapping is
+ * @arg @p component_mapping: if the components in @p boundary_functions and
+ * @p dof do not coincide, this vector allows them to be remapped. If the
+ * vector is not empty, it has to have one entry for each component in @p
+ * dof. This entry is the component number in @p boundary_functions that
+ * should be used for this component in @p dof. By default, no remapping is
* applied.
*
- * @todo This function does not
- * work for finite elements with
- * cell-dependent shape functions.
+ * @todo This function does not work for finite elements with cell-dependent
+ * shape functions.
*/
template <int dim, int spacedim>
/**
- * Calls the
- * create_boundary_mass_matrix()
- * function, see above, with
+ * Calls the create_boundary_mass_matrix() function, see above, with
* <tt>mapping=MappingQ1@<dim@>()</tt>.
*/
template <int dim, int spacedim>
std::vector<unsigned int> component_mapping = std::vector<unsigned int>());
/**
- * Same function as above, but for hp
- * objects.
+ * Same function as above, but for hp objects.
*/
template <int dim, int spacedim>
std::vector<unsigned int> component_mapping = std::vector<unsigned int>());
/**
- * Same function as above, but for hp
- * objects.
+ * Same function as above, but for hp objects.
*/
//
// void create_boundary_mass_matrix (const hp::MappingCollection<1,1> &mapping,
// const Function<1> * const a = 0);
/**
- * Same function as above, but for hp
- * objects.
+ * Same function as above, but for hp objects.
*/
template <int dim, int spacedim>
std::vector<unsigned int> component_mapping = std::vector<unsigned int>());
/**
- * Assemble the Laplace
- * matrix. If no coefficient is
- * given, it is assumed to be
- * constant one.
+ * Assemble the Laplace matrix. If no coefficient is given, it is assumed to
+ * be constant one.
+ *
+ * If the library is configured to use multithreading, this function works
+ * in parallel.
*
- * If the library is configured
- * to use multithreading, this
- * function works in parallel.
+ * The optional argument @p constraints allows to apply constraints on the
+ * resulting matrix directly. Be careful when combining several matrices and
+ * using inhomogeneous constraints.
*
- * See the general doc of this
- * class for more information.
+ * See the general doc of this class for more information.
*/
template <int dim, int spacedim>
- void create_laplace_matrix (const Mapping<dim, spacedim> &mapping,
- const DoFHandler<dim,spacedim> &dof,
+ void create_laplace_matrix (const Mapping<dim, spacedim> &mapping,
+ const DoFHandler<dim,spacedim> &dof,
const Quadrature<dim> &q,
SparseMatrix<double> &matrix,
- const Function<spacedim> *const a = 0);
+ const Function<spacedim> *const a = 0,
+ const ConstraintMatrix &constraints = ConstraintMatrix());
/**
- * Calls the
- * create_laplace_matrix()
- * function, see above, with
+ * Calls the create_laplace_matrix() function, see above, with
* <tt>mapping=MappingQ1@<dim@>()</tt>.
*/
template <int dim, int spacedim>
- void create_laplace_matrix (const DoFHandler<dim,spacedim> &dof,
+ void create_laplace_matrix (const DoFHandler<dim,spacedim> &dof,
const Quadrature<dim> &q,
SparseMatrix<double> &matrix,
- const Function<spacedim> *const a = 0);
+ const Function<spacedim> *const a = 0,
+ const ConstraintMatrix &constraints = ConstraintMatrix());
/**
- * Assemble the Laplace matrix
- * and a right hand side
- * vector. If no coefficient is
- * given, it is assumed to be
- * constant one.
+ * Assemble the Laplace matrix and a right hand side vector. If no
+ * coefficient is given, it is assumed to be constant one.
+ *
+ * If the library is configured to use multithreading, this function works
+ * in parallel.
*
- * If the library is configured
- * to use multithreading, this
- * function works in parallel.
+ * The optional argument @p constraints allows to apply constraints on the
+ * resulting matrix directly. Be careful when combining several matrices and
+ * using inhomogeneous constraints.
*
- * See the general doc of this
- * class for more information.
+ * See the general doc of this class for more information.
*/
template <int dim, int spacedim>
- void create_laplace_matrix (const Mapping<dim, spacedim> &mapping,
- const DoFHandler<dim,spacedim> &dof,
+ void create_laplace_matrix (const Mapping<dim, spacedim> &mapping,
+ const DoFHandler<dim,spacedim> &dof,
const Quadrature<dim> &q,
SparseMatrix<double> &matrix,
- const Function<spacedim> &rhs,
+ const Function<spacedim> &rhs,
Vector<double> &rhs_vector,
- const Function<spacedim> *const a = 0);
+ const Function<spacedim> *const a = 0,
+ const ConstraintMatrix &constraints = ConstraintMatrix());
/**
- * Calls the
- * create_laplace_matrix()
- * function, see above, with
+ * Calls the create_laplace_matrix() function, see above, with
* <tt>mapping=MappingQ1@<dim@>()</tt>.
*/
template <int dim, int spacedim>
- void create_laplace_matrix (const DoFHandler<dim,spacedim> &dof,
+ void create_laplace_matrix (const DoFHandler<dim,spacedim> &dof,
const Quadrature<dim> &q,
SparseMatrix<double> &matrix,
- const Function<spacedim> &rhs,
+ const Function<spacedim> &rhs,
Vector<double> &rhs_vector,
- const Function<spacedim> *const a = 0);
+ const Function<spacedim> *const a = 0,
+ const ConstraintMatrix &constraints = ConstraintMatrix());
/**
- * Like the functions above, but for hp
- * dof handlers, mappings, and quadrature
- * collections.
+ * Like the functions above, but for hp dof handlers, mappings, and
+ * quadrature collections.
*/
template <int dim, int spacedim>
- void create_laplace_matrix (const hp::MappingCollection<dim,spacedim> &mapping,
- const hp::DoFHandler<dim,spacedim> &dof,
+ void create_laplace_matrix (const hp::MappingCollection<dim,spacedim> &mapping,
+ const hp::DoFHandler<dim,spacedim> &dof,
const hp::QCollection<dim> &q,
SparseMatrix<double> &matrix,
- const Function<spacedim> *const a = 0);
+ const Function<spacedim> *const a = 0,
+ const ConstraintMatrix &constraints = ConstraintMatrix());
/**
- * Like the functions above, but for hp
- * dof handlers, mappings, and quadrature
- * collections.
+ * Like the functions above, but for hp dof handlers, mappings, and
+ * quadrature collections.
*/
template <int dim, int spacedim>
- void create_laplace_matrix (const hp::DoFHandler<dim,spacedim> &dof,
+ void create_laplace_matrix (const hp::DoFHandler<dim,spacedim> &dof,
const hp::QCollection<dim> &q,
SparseMatrix<double> &matrix,
- const Function<spacedim> *const a = 0);
+ const Function<spacedim> *const a = 0,
+ const ConstraintMatrix &constraints = ConstraintMatrix());
/**
- * Like the functions above, but for hp
- * dof handlers, mappings, and quadrature
- * collections.
+ * Like the functions above, but for hp dof handlers, mappings, and
+ * quadrature collections.
*/
template <int dim, int spacedim>
- void create_laplace_matrix (const hp::MappingCollection<dim,spacedim> &mapping,
- const hp::DoFHandler<dim,spacedim> &dof,
+ void create_laplace_matrix (const hp::MappingCollection<dim,spacedim> &mapping,
+ const hp::DoFHandler<dim,spacedim> &dof,
const hp::QCollection<dim> &q,
SparseMatrix<double> &matrix,
const Function<spacedim> &rhs,
Vector<double> &rhs_vector,
- const Function<spacedim> *const a = 0);
+ const Function<spacedim> *const a = 0,
+ const ConstraintMatrix &constraints = ConstraintMatrix());
/**
- * Like the functions above, but for hp
- * dof handlers, mappings, and quadrature
- * collections.
+ * Like the functions above, but for hp dof handlers, mappings, and
+ * quadrature collections.
*/
template <int dim, int spacedim>
- void create_laplace_matrix (const hp::DoFHandler<dim,spacedim> &dof,
+ void create_laplace_matrix (const hp::DoFHandler<dim,spacedim> &dof,
const hp::QCollection<dim> &q,
SparseMatrix<double> &matrix,
const Function<spacedim> &rhs,
Vector<double> &rhs_vector,
- const Function<spacedim> *const a = 0);
+ const Function<spacedim> *const a = 0,
+ const ConstraintMatrix &constraints = ConstraintMatrix());
/**
* Exception
* respect for fixed degrees of freedom, and in a second step eliminate them
* again from the linear system. The inclusion into the assembly process is as
* follows: when the matrix and vectors are set up, a list of nodes subject to
- * dirichlet bc is made and matrix and vectors are modified accordingly. This
+ * Dirichlet bc is made and matrix and vectors are modified accordingly. This
* is done by deleting all entries in the matrix in the line of this degree of
* freedom, setting the main diagonal entry to a suitable positive value and
* the right hand side element to a value so that the solution of the linear
using namespace MatrixCreator;
/**
- * Apply dirichlet boundary conditions
+ * Apply Dirichlet boundary conditions
* to the system matrix and vectors
* as described in the general
* documentation.
const bool eliminate_columns = true);
/**
- * Apply dirichlet boundary
+ * Apply Dirichlet boundary
* conditions to the system
* matrix and vectors as
* described in the general
#ifdef DEAL_II_WITH_PETSC
/**
- * Apply dirichlet boundary conditions to
+ * Apply Dirichlet boundary conditions to
* the system matrix and vectors as
* described in the general
* documentation. This function works on
#ifdef DEAL_II_WITH_TRILINOS
/**
- * Apply dirichlet boundary
+ * Apply Dirichlet boundary
* conditions to the system matrix
* and vectors as described in the
* general documentation. This
const bool eliminate_columns = true);
/**
- * Apply dirichlet boundary
+ * Apply Dirichlet boundary
* conditions to the system matrix
* and vectors as described in the
* general documentation. This
const bool project_to_boundary_first = false);
/**
- * Prepare Dirichlet boundary
- * conditions. Make up the list
+ * Compute Dirichlet boundary
+ * conditions. This function makes up a map
* of degrees of freedom subject
* to Dirichlet boundary
- * conditions and the values to
+ * conditions and the corresponding values to
* be assigned to them, by
* interpolation around the
* boundary. If the
- * @p boundary_values contained
+ * @p boundary_values object contained
* values before, the new ones
* are added, or the old ones
* overwritten if a node of the
* boundary function will be used
* for which the respective flag
* was set in the component mask.
- * See also @ref GlossComponentMask.
- *
- * It is assumed that the number
- * of components of the function
- * in @p boundary_function matches that
+ * See also @ref GlossComponentMask. As an example, assume that you are
+ * solving the Stokes equations in 2d, with variables $(u,v,p)$ and that
+ * you only want to interpolate boundary values for the pressure, then
+ * the component mask should correspond to <code>(true,true,false)</code>.
+ *
+ * @note Whether a component mask has been specified or not, the number
+ * of components of the functions
+ * in @p function_map must match that
* of the finite element used by
- * @p dof.
+ * @p dof. In other words, for the example above, you need to provide a
+ * Function object that has 3 components (the two velocities and the
+ * pressure), even though you are only
+ * interested in the first two of them. interpolate_boundary_values()
+ * will then call this function to obtain a vector of 3 values at each
+ * interpolation point but only take the first two and discard the third.
+ * In other words, you are free to return whatever you like in the third
+ * component of the vector returned by Function::vector_value, but the
+ * Function object must state that it has 3 components.
*
* If the finite element used has
* shape functions that are
* non-primitive shape functions
* must be @p false.
*
- * See the general doc for more
+ * See the general documentation of this class for more
* information.
*/
template <class DH>
* taking only one pair of
* boundary indicator and
* corresponding boundary
- * function. Calls the other
- * function with remapped
- * arguments.
+ * function. The same comments apply as for the previous function, in particular
+ * about the use of the component mask and the requires size of the function
+ * object.
*
* @see @ref GlossBoundaryIndicator "Glossary entry on boundary indicators"
*/
* interpolate_boundary_values()
* function, see above, with
* <tt>mapping=MappingQ1@<dim@>()</tt>.
+ * The same comments apply as for the previous function, in particular
+ * about the use of the component mask and the requires size of the function
+ * object.
*
* @see @ref GlossBoundaryIndicator "Glossary entry on boundary indicators"
*/
* interpolate_boundary_values()
* function, see above, with
* <tt>mapping=MappingQ1@<dim@>()</tt>.
+ * The same comments apply as for the previous function, in particular
+ * about the use of the component mask and the requires size of the function
+ * object.
*/
template <class DH>
void
* The parameter @p boundary_component
* corresponds to the number @p
* boundary_indicator of the face.
- * numbers::internal_face_boundary_id
- * is an illegal value, since it is
- * reserved for interior faces.
*
- * The flags in the last parameter, @p
- * component_mask (see @ref GlossComponentMask)
- * denote which
- * components of the finite element
- * space shall be interpolated. If it
- * is left as specified by the default
- * value (i.e. an empty array), all
- * components are interpolated. If it
- * is different from the default value,
- * it is assumed that the number of
- * entries equals the number of
- * components in the boundary functions
- * and the finite element, and those
- * components in the given boundary
- * function will be used for which the
- * respective flag was set in the
- * component mask.
- *
- * It is assumed that the number of
- * components of the function in @p
- * boundary_function matches that of
- * the finite element used by @p dof.
+ * The flags in the last
+ * parameter, @p component_mask
+ * denote which components of the
+ * finite element space shall be
+ * interpolated. If it is left as
+ * specified by the default value
+ * (i.e. an empty array), all
+ * components are
+ * interpolated. If it is
+ * different from the default
+ * value, it is assumed that the
+ * number of entries equals the
+ * number of components in the
+ * boundary functions and the
+ * finite element, and those
+ * components in the given
+ * boundary function will be used
+ * for which the respective flag
+ * was set in the component mask.
+ * See also @ref GlossComponentMask. As an example, assume that you are
+ * solving the Stokes equations in 2d, with variables $(u,v,p)$ and that
+ * you only want to interpolate boundary values for the pressure, then
+ * the component mask should correspond to <code>(true,true,false)</code>.
+ *
+ * @note Whether a component mask has been specified or not, the number
+ * of components of the functions
+ * in @p function_map must match that
+ * of the finite element used by
+ * @p dof. In other words, for the example above, you need to provide a
+ * Function object that has 3 components (the two velocities and the
+ * pressure), even though you are only
+ * interested in the first two of them. interpolate_boundary_values()
+ * will then call this function to obtain a vector of 3 values at each
+ * interpolation point but only take the first two and discard the third.
+ * In other words, you are free to return whatever you like in the third
+ * component of the vector returned by Function::vector_value, but the
+ * Function object must state that it has 3 components.
*
* If the finite element used has shape
* functions that are non-zero in more
* components of these non-primitive
* shape functions must be @p false.
*
- * See the general doc for more
+ * See the general documentation of this class for more
* information.
*
* @ingroup constraints
* Same function as above, but taking
* only one pair of boundary indicator
* and corresponding boundary
- * function. Calls the other function
- * with remapped arguments.
+ * function.
+ * The same comments apply as for the previous function, in particular
+ * about the use of the component mask and the requires size of the function
+ * object.
*
* @ingroup constraints
*
* interpolate_boundary_values()
* function, see above, with
* <tt>mapping=MappingQ1@<dim@>()</tt>.
+ * The same comments apply as for the previous function, in particular
+ * about the use of the component mask and the requires size of the function
+ * object.
*
* @ingroup constraints
*
* interpolate_boundary_values()
* function, see above, with
* <tt>mapping=MappingQ1@<dim@>()</tt>.
+ * The same comments apply as for the previous function, in particular
+ * about the use of the component mask and the requires size of the function
+ * object.
*
* @ingroup constraints
*/
//@{
/**
- * Compute the error of the
- * finite element solution.
- * Integrate the difference
- * between a reference function
- * which is given as a continuous
- * function object, and a finite
- * element function.
- *
- * The value of @p exponent is
- * used for computing $L^p$-norms
- * and $W^{1,p}$-norms.
- *
- * The additional argument @p
- * weight allows to evaluate
- * weighted norms. The weight
- * function may be scalar,
- * establishing a weight in the
- * domain for all components
- * equally. This may be used, for
- * instance, to only integrates
- * over parts of the domain.
- *
- * The weight function may also
- * be vector-valued, with as many
- * components as the finite
- * element function: Then,
- * different components get
- * different weights. A typical
- * application is when the error
- * with respect to only one or a
- * subset of the solution
- * variables is to be computed,
- * in which the other components
- * would have weight values equal
- * to zero. The
- * ComponentSelectFunction class
- * is particularly useful for
- * this purpose.
- *
- * The weight function is
- * expected to be positive, but
- * negative values are not
- * filtered. By default, no
- * weighting function is given,
- * i.e. weight=1 in the whole
- * domain for all vector
- * components uniformly. Note that
- * one often wants to compute the
- * error in only one component of
- * a solution vector (e.g. for the
- * pressure in the Stokes system,
- * when the solution vector also
- * contains the velocity components).
- * In these cases, the weight should
- * be a <i>mask</i>, i.e., be a
- * vector function for which individual
- * components are either zero or one.
- * This can easily be achieved using
- * the ComponentSelectFunction
- * class.
- *
- * It is assumed that the number
- * of components of the function
- * @p exact_solution matches that
- * of the finite element used by
- * @p dof.
+ * Compute the error of the finite element solution. Integrate the
+ * difference between a reference function which is given as a
+ * continuous function object, and a finite element function. The
+ * result of this function is the vector @p difference that contains
+ * one value per active cell $K$ of the triangulation. Each of the values
+ * of this vector $d$ equals
+ * @f{align*}
+ * d_K = \| u-u_h \|_X
+ * @f}
+ * where $X$ denotes the norm chosen and $u$ represents the exact solution.
+ *
+ * It is assumed that the number of components of the function
+ * @p exact_solution matches that of the finite element used by @p dof.
+ *
+ * @param[in] mapping The mapping that is used when integrating the
+ * difference $u-u_h$.
+ * @param[in] dof The DoFHandler object that describes the finite
+ * element space in which the solution vector lives.
+ * @param[in] fe_function A vector with nodal values representing the
+ * numerical approximation $u_h$. This vector needs to correspond
+ * to the finite element space represented by @p dof
+ * @param[out] difference The vector of values $d_K$ computed as above.
+ * @param[in] q The quadrature formula used to approximate the integral
+ * shown above. Note that some quadrature formulas are more useful
+ * than other in integrating $u-u_h$. For example, it is known that
+ * the $Q_1$ approximation $u_h$ to the exact solution $u$ of a Laplace
+ * equation is particularly accurate (in fact, superconvergent, i.e.
+ * accurate to higher order) at the 4 Gauss points of a cell in 2d
+ * (or 8 points in 3d) that correspond to a QGauss(2) object. Consequently,
+ * because a QGauss(2) formula only evaluates the two solutions at these
+ * particular points, choosing this quadrature formula may indicate an error
+ * far smaller than it actually is.
+ * @param[in] norm The norm $X$ shown above that should be computed.
+ * @param[in] weight The additional argument @p weight allows to evaluate weighted
+ * norms. The weight function may be scalar, establishing a weight
+ * in the domain for all components equally. This may be used, for
+ * instance, to only integrate over parts of the domain. The weight function
+ * may also be vector-valued, with as many components as the finite element:
+ * Then, different components get different weights. A typical application is when
+ * the error with respect to only one or a subset of the solution
+ * variables is to be computed, in which the other components would
+ * have weight values equal to zero. The ComponentSelectFunction
+ * class is particularly useful for this purpose as it provides
+ * such as "mask" weight..
+ * The weight function is expected to be positive, but negative
+ * values are not filtered. By default, no weighting function is
+ * given, i.e. weight=1 in the whole domain for all vector
+ * components uniformly.
+ * @param[in] exponent This value denotes the $p$ used in computing
+ * $L^p$-norms and $W^{1,p}$-norms. The value is ignores if a @p norm
+ * other than NormType::Lp_norm or NormType::W1p_norm is chosen.
+ *
*
* See the general documentation of this
* class for more information.
*
- * @note Instantiations for this template
+ * @note If the integration here happens over the cells of a
+ * parallel::distribute::Triangulation object, then this function
+ * computes the vector elements $d_K$ for an output vector with as
+ * many cells as there are active cells of the triangulation object
+ * of the current processor. However, not all active cells are in
+ * fact locally owned: some may be ghost or artificial cells (see
+ * @ref GlossGhostCell "here" and @ref GlossArtificialCell
+ * "here"). The vector computed will, in the case of a distributed
+ * triangulation, contain zeros for cells that are not locally
+ * owned. As a consequence, in order to compute the <i>global</i>
+ * $L_2$ error (for example), the errors from different processors
+ * need to be combined, but this is simple because every processor
+ * only computes contributions for those cells of the global
+ * triangulation it locally owns (and these sets are, by definition,
+ * mutually disjoint). Consequently, the following piece of code
+ * computes the global $L_2$ error across multiple processors
+ * sharing a parallel::distribute::Triangulation:
+ * @code
+ * Vector<double> local_errors (tria.n_active_cells());
+ * VectorTools::integrate_difference (mapping, dof,
+ * solution, exact_solution,
+ * local_errors,
+ * QGauss<dim>(fe.degree+2),
+ * NormType::L2_norm);
+ * const double total_local_error = local_errors.l2_norm();
+ * const double total_global_error
+ * = std::sqrt (Utilities::MPI::sum (total_local_error * total_local_error, MPI_COMM_WORLD));
+ * @endcode
+ * The squaring and taking the square root is necessary in order to
+ * compute the sum of squares of norms over all all cells in the definition
+ * of the $L_2$ norm:
+ * @f{align*}
+ * \textrm{error} = \sqrt{\sum_K \|u-u_h\|_{L_2(K)}^2}
+ * @f}
+ * Obviously, if you are interested in computing the $L_1$ norm of the
+ * error, the correct form of the last two lines would have been
+ * @code
+ * const double total_local_error = local_errors.l1_norm();
+ * const double total_global_error
+ * = Utilities::MPI::sum (total_local_error, MPI_COMM_WORLD);
+ * @endcode
+ * instead, and similar considerations hold when computing the $L_\infty$
+ * norm of the error.
+ *
+ * Instantiations for this template
* are provided for some vector types
* (see the general documentation of the
* class), but only for InVectors as in
const double exponent = 2.);
/**
- * Same as above for hp.
- */
+ * Same as above for hp.
+ */
template <int dim, class InVector, class OutVector, int spacedim>
void integrate_difference (const hp::MappingCollection<dim,spacedim> &mapping,
const hp::DoFHandler<dim,spacedim> &dof,
namespace VectorTools
{
- namespace
- {
- template <typename VEC>
- void perform_compress_insert (VEC &vec)
- {
- vec.compress(::dealii::VectorOperation::insert);
- }
-
- template <typename Number>
- void perform_compress_insert (::dealii::parallel::distributed::Vector<Number> &vec)
- {
- // should not do compress when inserting
- // elements as the ghosts are fixed and some
- // will not be set at all. Instead, zero the
- // ghost data afterwards to get consistent
- // data. Otherwise, at least with the layout
- // in r27671 the tests/mpi/step-48/ncpu_10
- // will signal incorrect results because of
- // incorrect interpolation.
- vec.zero_out_ghosts();
- }
-
- }
-
template <class VECTOR, class DH>
void interpolate (const Mapping<DH::dimension,DH::space_dimension> &mapping,
= function_values_scalar[fe_index][dof_to_rep_index_table[fe_index][i]];
}
}
- perform_compress_insert(vec);
+ vec.compress(VectorOperation::insert);
}
template <int dim, class VECTOR, int spacedim>
- void project (const Mapping<dim, spacedim> &mapping,
- const DoFHandler<dim,spacedim> &dof,
+ void project (const Mapping<dim, spacedim> &mapping,
+ const DoFHandler<dim,spacedim> &dof,
const ConstraintMatrix &constraints,
const Quadrature<dim> &quadrature,
- const Function<spacedim> &function,
+ const Function<spacedim> &function,
VECTOR &vec_result,
const bool enforce_zero_boundary,
const Quadrature<dim-1> &q_boundary,
Vector<double> vec (dof.n_dofs());
SparsityPattern sparsity;
+ // check if constraints are compatible (see below)
+ bool constraints_are_compatible = true;
+ {
+ for (std::map<unsigned int,double>::iterator it=boundary_values.begin();
+ it != boundary_values.end(); ++it)
+ if (constraints.is_constrained(it->first))
+ if (!(constraints.get_constraint_entries(it->first)->size() > 0
+ ||
+ (constraints.get_inhomogeneity(it->first) == it->second)))
+ {
+ constraints_are_compatible = false;
+ break;
+ }
+ }
+
// use csp to consume less memory and to
// still be fast
{
CompressedSimpleSparsityPattern csp (dof.n_dofs(), dof.n_dofs());
- DoFTools::make_sparsity_pattern (dof, csp, constraints);
+ DoFTools::make_sparsity_pattern (dof, csp, constraints,
+ !constraints_are_compatible);
sparsity.copy_from (csp);
}
SparseMatrix<double> mass_matrix (sparsity);
Vector<double> tmp (mass_matrix.n());
- // create mass matrix and rhs at once,
- // which is faster.
- MatrixCreator::create_mass_matrix (mapping, dof, quadrature, mass_matrix,
- function, tmp);
-
- constraints.condense (mass_matrix);
- constraints.condense (tmp);
- if (boundary_values.size() != 0)
- MatrixTools::apply_boundary_values (boundary_values,
- mass_matrix, vec, tmp,
- true);
- // Allow for a maximum of 5*n
- // steps to reduce the residual by
- // 10^-12. n steps may not be
- // sufficient, since roundoff
- // errors may accumulate for badly
- // conditioned matrices
- ReductionControl control(5*tmp.size(), 0., 1e-12, false, false);
+ // If the constraint matrix does not conflict with the given boundary
+ // values (i.e., it either does not contain boundary values or it contains
+ // the same as boundary_values), we can let it call
+ // distribute_local_to_global straight away, otherwise we need to first
+ // interpolate the boundary values and then condense the matrix and vector
+ if (constraints_are_compatible)
+ {
+ const Function<spacedim>* dummy = 0;
+ MatrixCreator::create_mass_matrix (mapping, dof, quadrature,
+ mass_matrix, function, tmp,
+ dummy, constraints);
+ if (boundary_values.size() > 0)
+ MatrixTools::apply_boundary_values (boundary_values,
+ mass_matrix, vec, tmp,
+ true);
+ }
+ else
+ {
+ // create mass matrix and rhs at once, which is faster.
+ MatrixCreator::create_mass_matrix (mapping, dof, quadrature,
+ mass_matrix, function, tmp);
+ MatrixTools::apply_boundary_values (boundary_values,
+ mass_matrix, vec, tmp,
+ true);
+ constraints.condense(mass_matrix, tmp);
+ }
+
+ // Allow for a maximum of 5*n steps to reduce the residual by 10^-12. n
+ // steps may not be sufficient, since roundoff errors may accumulate for
+ // badly conditioned matrices
+ ReductionControl control(5*tmp.size(), 0., 1e-12, false, false);
GrowingVectorMemory<> memory;
- SolverCG<> cg(control,memory);
+ SolverCG<> cg(control,memory);
PreconditionSSOR<> prec;
prec.initialize(mass_matrix, 1.2);
- // solve
+
cg.solve (mass_matrix, vec, tmp, prec);
- // distribute solution
constraints.distribute (vec);
- // copy vec into vec_result. we
- // can't use ve_result itself
- // above, since it may be of
- // another type than Vector<double>
- // and that wouldn't necessarily go
- // together with the matrix and
- // other functions
+ // copy vec into vec_result. we can't use vec_result itself above, since
+ // it may be of another type than Vector<double> and that wouldn't
+ // necessarily go together with the matrix and other functions
for (unsigned int i=0; i<vec.size(); ++i)
vec_result(i) = vec(i);
}
template <int dim, class VECTOR, int spacedim>
- void project (const DoFHandler<dim,spacedim> &dof,
+ void project (const DoFHandler<dim,spacedim> &dof,
const ConstraintMatrix &constraints,
const Quadrature<dim> &quadrature,
- const Function<spacedim> &function,
+ const Function<spacedim> &function,
VECTOR &vec,
const bool enforce_zero_boundary,
const Quadrature<dim-1> &q_boundary,
{ 0, 1 }
};
- // The projection is
- // divided into two steps.
- // In the first step we
- // project the boundary
- // function on the
- // horizontal shape
- // functions. Then the
- // bounary function is
- // projected on the
- // vertical shape
- // functions. We begin
- // with the horizontal
- // shape functions and
- // set up a linear system
- // of equations to get
- // the values for degrees
- // of freedom associated
- // with the interior of
- // the face.
+ // The projection is divided into two steps. In the first step we
+ // project the boundary function on the horizontal shape functions.
+ // Then the boundary function is projected on the vertical shape
+ // functions. We begin with the horizontal shape functions and set
+ // up a linear system of equations to get the values for degrees of
+ // freedom associated with the interior of the face.
for (unsigned int q_point = 0;
q_point < fe_values.n_quadrature_points; ++q_point)
{
std::vector<unsigned int> face_dofs;
- // create FE and mapping
- // collections for all elements in
- // use by this DoFHandler
+ // create FE and mapping collections for all elements in use by this
+ // DoFHandler
hp::FECollection<dim,spacedim> fe_collection (dof_handler.get_fe());
hp::MappingCollection<dim,spacedim> mapping_collection;
for (unsigned int i=0; i<fe_collection.size(); ++i)
mapping_collection.push_back (mapping);
- // now also create a quadrature
- // collection for the faces of a
- // cell. fill it with a quadrature
- // formula with the support points
- // on faces for each FE
+ // now also create a quadrature collection for the faces of a cell. fill
+ // it with a quadrature formula with the support points on faces for each
+ // FE
hp::QCollection<dim-1> face_quadrature_collection;
for (unsigned int i=0; i<fe_collection.size(); ++i)
{
.push_back (Quadrature<dim-1> (unit_support_points));
}
- // now create the object with which
- // we will generate the normal
- // vectors
+ // now create the object with which we will generate the normal vectors
hp::FEFaceValues<dim,spacedim> x_fe_face_values (mapping_collection,
fe_collection,
face_quadrature_collection,
update_q_points);
- // have a map that stores normal
- // vectors for each vector-dof
- // tuple we want to
- // constrain. since we can get at
- // the same vector dof tuple more
- // than once (for example if it is
- // located at a vertex that we
- // visit from all adjacent cells),
- // we will want to average later on
- // the normal vectors computed on
- // different cells as described in
- // the documentation of this
- // function. however, we can only
- // average if the contributions
- // came from different cells,
- // whereas we want to constrain
- // twice or more in case the
- // contributions came from
- // different faces of the same cell
- // (i.e. constrain not just the
- // *average normal direction* but
- // *all normal directions* we
- // find). consequently, we also
- // have to store which cell a
+ // have a map that stores normal vectors for each vector-dof tuple we want
+ // to constrain. since we can get at the same vector dof tuple more than
+ // once (for example if it is located at a vertex that we visit from all
+ // adjacent cells), we will want to average later on the normal vectors
+ // computed on different cells as described in the documentation of this
+ // function. however, we can only average if the contributions came from
+ // different cells, whereas we want to constrain twice or more in case the
+ // contributions came from different faces of the same cell
+ // (i.e. constrain not just the *average normal direction* but *all normal
+ // directions* we find). consequently, we also have to store which cell a
// normal vector was computed on
typedef
std::multimap<internal::VectorDoFTuple<dim>,
const FiniteElement<dim> &fe = cell->get_fe ();
typename DH<dim,spacedim>::face_iterator face = cell->face(face_no);
- // get the indices of the
- // dofs on this cell...
+ // 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());
x_fe_face_values.reinit (cell, face_no);
const FEFaceValues<dim> &fe_values = x_fe_face_values.get_present_fe_values();
- // then identify which of
- // them correspond to the
- // selected set of vector
- // components
+ // then identify which of them correspond to the selected set of
+ // vector components
for (unsigned int i=0; i<face_dofs.size(); ++i)
if (fe.face_system_to_component_index(i).first ==
first_vector_component)
{
- // find corresponding other
- // components of vector
+ // find corresponding other components of vector
internal::VectorDoFTuple<dim> vector_dofs;
vector_dofs.dof_indices[0] = face_dofs[i];
Assert (vector_dofs.dof_indices[d] < dof_handler.n_dofs(),
ExcInternalError());
- // we need the normal
- // vector on this face. we
- // know that it is a vector
- // of length 1 but at least
- // with higher order
- // mappings it isn't always
- // possible to guarantee
- // that each component is
- // exact up to zero
- // tolerance. in
- // particular, as shown in
- // the deal.II/no_flux_06
- // test, if we just take
- // the normal vector as
- // given by the fe_values
- // object, we can get
- // entries in the normal
- // vectors of the unit cube
- // that have entries up to
+ // we need the normal vector on this face. we know that it
+ // is a vector of length 1 but at least with higher order
+ // mappings it isn't always possible to guarantee that
+ // each component is exact up to zero tolerance. in
+ // particular, as shown in the deal.II/no_flux_06 test, if
+ // we just take the normal vector as given by the
+ // fe_values object, we can get entries in the normal
+ // vectors of the unit cube that have entries up to
// several times 1e-14.
//
- // the problem with this is
- // that this later yields
- // constraints that are
- // circular (e.g., in the
- // testcase, we get
- // constraints of the form
+ // the problem with this is that this later yields
+ // constraints that are circular (e.g., in the testcase,
+ // we get constraints of the form
//
// x22 = 2.93099e-14*x21 + 2.93099e-14*x23
// x21 = -2.93099e-14*x22 + 2.93099e-14*x21
//
- // in both of these
- // constraints, the small
- // numbers should be zero
- // and the constraints
- // should simply be
- // x22 = x21 = 0
+ // in both of these constraints, the small numbers should
+ // be zero and the constraints should simply be
+ // x22 = x21 = 0
//
- // to achieve this, we
- // utilize that we know
- // that the normal vector
- // has (or should have)
- // length 1 and that we can
- // simply set small
- // elements to zero
- // (without having to check
- // that they are small
- // *relative to something
- // else*). we do this and
- // then normalize the
- // length of the vector
- // back to one, just to be
- // on the safe side
+ // to achieve this, we utilize that we know that the
+ // normal vector has (or should have) length 1 and that we
+ // can simply set small elements to zero (without having
+ // to check that they are small *relative to something
+ // else*). we do this and then normalize the length of the
+ // vector back to one, just to be on the safe side
Point<dim> normal_vector
= (cell->face(face_no)->get_boundary()
.normal_vector (cell->face(face_no),
normal_vector[d] = 0;
normal_vector /= normal_vector.norm();
- // now enter the
- // (dofs,(normal_vector,cell))
- // entry into the map
+ // now enter the (dofs,(normal_vector,cell)) entry into
+ // the map
dof_to_normals_map
.insert (std::make_pair (vector_dofs,
std::make_pair (normal_vector,
}
}
- // Now do something with the
- // collected information. To this
- // end, loop through all sets of
- // pairs (dofs,normal_vector) and
- // identify which entries belong to
- // the same set of dofs and then do
- // as described in the
- // documentation, i.e. either
- // average the normal vector or
- // don't for this particular set of
- // dofs
+ // Now do something with the collected information. To this end, loop
+ // through all sets of pairs (dofs,normal_vector) and identify which
+ // entries belong to the same set of dofs and then do as described in the
+ // documentation, i.e. either average the normal vector or don't for this
+ // particular set of dofs
typename DoFToNormalsMap::const_iterator
p = dof_to_normals_map.begin();
while (p != dof_to_normals_map.end())
{
- // first find the range of entries in
- // the multimap that corresponds to the
- // same vector-dof tuple. as usual, we
- // define the range half-open. the
- // first entry of course is 'p'
+ // first find the range of entries in the multimap that corresponds to
+ // the same vector-dof tuple. as usual, we define the range
+ // half-open. the first entry of course is 'p'
typename DoFToNormalsMap::const_iterator same_dof_range[2]
= { p };
for (++p; p != dof_to_normals_map.end(); ++p)
if (p == dof_to_normals_map.end())
same_dof_range[1] = dof_to_normals_map.end();
- // now compute the reverse mapping: for
- // each of the cells that contributed
- // to the current set of vector dofs,
- // add up the normal vectors. the
- // values of the map are pairs of
- // normal vectors and number of cells
- // that have contributed
+ // now compute the reverse mapping: for each of the cells that
+ // contributed to the current set of vector dofs, add up the normal
+ // vectors. the values of the map are pairs of normal vectors and
+ // number of cells that have contributed
typedef
std::map
<typename DH<dim,spacedim>::active_cell_iterator,
Assert (old_count > 0, ExcInternalError());
- // in the same entry,
- // store again the now
- // averaged normal vector
+ // in the same entry, store again the now averaged normal vector
// and the new count
cell_to_normals_map[q->second.second]
= std::make_pair ((old_normal * old_count + q->second.first) / (old_count + 1),
Assert (cell_to_normals_map.size() >= 1, ExcInternalError());
- // count the maximum number of
- // contributions from each cell
+ // count the maximum number of contributions from each cell
unsigned int max_n_contributions_per_cell = 1;
for (typename CellToNormalsMap::const_iterator
x = cell_to_normals_map.begin();
= std::max (max_n_contributions_per_cell,
x->second.second);
- // verify that each cell can have only
- // contributed at most dim times, since
- // that is the maximum number of faces
- // that come together at a single place
+ // verify that each cell can have only contributed at most dim times,
+ // since that is the maximum number of faces that come together at a
+ // single place
Assert (max_n_contributions_per_cell <= dim, ExcInternalError());
switch (max_n_contributions_per_cell)
{
- // first deal with the case that a
- // number of cells all have
- // registered that they have a
- // normal vector defined at the
- // location of a given vector dof,
- // and that each of them have
- // encountered this vector dof
- // exactly once while looping over
- // all their faces. as stated in
- // the documentation, this is the
- // case where we want to simply
- // average over all normal vectors
+ // first deal with the case that a number of cells all have
+ // registered that they have a normal vector defined at the
+ // location of a given vector dof, and that each of them have
+ // encountered this vector dof exactly once while looping over all
+ // their faces. as stated in the documentation, this is the case
+ // where we want to simply average over all normal vectors
case 1:
{
- // compute the average
- // normal vector from all
- // the ones that have the
- // same set of dofs. we
- // could add them up and
- // divide them by the
- // number of additions,
- // or simply normalize
- // them right away since
- // we want them to have
- // unit length anyway
+ // compute the average normal vector from all the ones that have
+ // the same set of dofs. we could add them up and divide them by
+ // the number of additions, or simply normalize them right away
+ // since we want them to have unit length anyway
Tensor<1,dim> normal;
for (typename CellToNormalsMap::const_iterator
x = cell_to_normals_map.begin();
normal[d] = 0;
normal /= normal.norm();
- // then construct constraints
- // from this:
+ // then construct constraints from this:
const internal::VectorDoFTuple<dim> &
dof_indices = same_dof_range[0]->first;
internal::add_constraint (dof_indices, normal,
}
- // this is the slightly
- // more complicated case
- // that a single cell has
- // contributed with exactly
- // DIM normal vectors to
- // the same set of vector
- // dofs. this is what
- // happens in a corner in
- // 2d and 3d (but not on an
- // edge in 3d, where we
- // have only 2, i.e. <DIM,
- // contributions. Here we
- // do not want to average
- // the normal
- // vectors. Since we have
- // DIM contributions, let's
- // assume (and verify) that
- // they are in fact all
- // linearly independent; in
- // that case, all vector
- // components are
- // constrained and we need
- // to set them to zero
+ // this is the slightly more complicated case that a single cell has
+ // contributed with exactly DIM normal vectors to the same set of
+ // vector dofs. this is what happens in a corner in 2d and 3d (but
+ // not on an edge in 3d, where we have only 2, i.e. <DIM,
+ // contributions. Here we do not want to average the normal
+ // vectors. Since we have DIM contributions, let's assume (and
+ // verify) that they are in fact all linearly independent; in that
+ // case, all vector components are constrained and we need to set
+ // them to zero
case dim:
{
- // assert that indeed
- // only a single cell has
- // contributed
+ // assert that indeed only a single cell has contributed
Assert (cell_to_normals_map.size() == 1,
ExcInternalError());
- // check linear
- // independence by
- // computing the
- // determinant of the
- // matrix created from
- // all the normal
- // vectors. if they are
- // linearly independent,
- // then the determinant
- // is nonzero. if they
- // are orthogonal, then
- // the matrix is in fact
- // equal to 1 (since they
- // are all unit vectors);
- // make sure the
- // determinant is larger
- // than 1e-3 to avoid
- // cases where cells are
- // degenerate
+ // check linear independence by computing the determinant of the
+ // matrix created from all the normal vectors. if they are
+ // linearly independent, then the determinant is nonzero. if they
+ // are orthogonal, then the matrix is in fact equal to 1 (since
+ // they are all unit vectors); make sure the determinant is larger
+ // than 1e-3 to avoid cases where cells are degenerate
{
Tensor<2,dim> t;
ExcMessage("Found a set of normal vectors that are nearly collinear."));
}
- // so all components of
- // this vector dof are
- // constrained. enter
- // this into the
- // constraint matrix
+ // so all components of this vector dof are constrained. enter
+ // this into the constraint matrix
//
- // ignore dofs already
- // constrained
+ // ignore dofs already constrained
for (unsigned int i=0; i<dim; ++i)
if (!constraints.is_constrained (same_dof_range[0]
->first.dof_indices[i])
}
- // this is the case of an
- // edge contribution in 3d,
- // i.e. the vector is
- // constrained in two
- // directions but not the
- // third.
+ // this is the case of an edge contribution in 3d, i.e. the vector
+ // is constrained in two directions but not the third.
default:
{
Assert (dim >= 3, ExcNotImplemented());
Assert (max_n_contributions_per_cell == 2, ExcInternalError());
- // as described in the
- // documentation, let us
- // first collect what
- // each of the cells
- // contributed at the
- // current point. we use
- // a std::list instead of
- // a std::set (which
- // would be more natural)
- // because std::set
- // requires that the
- // stored elements are
- // comparable with
- // operator<
+ // as described in the documentation, let us first collect what
+ // each of the cells contributed at the current point. we use a
+ // std::list instead of a std::set (which would be more natural)
+ // because std::set requires that the stored elements are
+ // comparable with operator<
typedef
std::map<typename DH<dim,spacedim>::active_cell_iterator, std::list<Tensor<1,dim> > >
CellContributions;
cell_contributions[q->second.second].push_back (q->second.first);
Assert (cell_contributions.size() >= 1, ExcInternalError());
- // now for each cell that
- // has contributed
- // determine the number
- // of normal vectors it
- // has contributed. we
- // currently only
- // implement if this is
- // dim-1 for all cells
- // (if a single cell has
- // contributed dim, or if
- // all adjacent cells
- // have contributed 1
- // normal vector, this is
- // already handled above)
+ // now for each cell that has contributed determine the number of
+ // normal vectors it has contributed. we currently only implement
+ // if this is dim-1 for all cells (if a single cell has
+ // contributed dim, or if all adjacent cells have contributed 1
+ // normal vector, this is already handled above)
//
- // for each contributing
- // cell compute the
- // tangential vector that
+ // for each contributing cell compute the tangential vector that
// remains unconstrained
std::list<Tensor<1,dim> > tangential_vectors;
for (typename CellContributions::const_iterator
Assert (index == dim-1, ExcInternalError());
}
- // calculate the
- // tangent as the
- // outer product of
- // the normal
- // vectors. since
- // these vectors do
- // not need to be
- // orthogonal (think,
- // for example, the
- // case of the
- // deal.II/no_flux_07
- // test: a sheared
- // cube in 3d, with
- // Q2 elements, where
- // we have
- // constraints from
- // the two normal
- // vectors of two
- // faces of the
- // sheared cube that
- // are not
- // perpendicular to
- // each other), we
- // have to normalize
- // the outer product
+ // calculate the tangent as the outer product of the normal
+ // vectors. since these vectors do not need to be orthogonal
+ // (think, for example, the case of the deal.II/no_flux_07
+ // test: a sheared cube in 3d, with Q2 elements, where we have
+ // constraints from the two normal vectors of two faces of the
+ // sheared cube that are not perpendicular to each other), we
+ // have to normalize the outer product
Tensor<1,dim> tangent;
switch (dim)
{
case 3:
- // take
- // cross
- // product
- // between
- // normals[0]
- // and
- // normals[1]. write
- // it in
- // the
- // current
- // form
- // (with
- // [dim-2])
- // to make
- // sure
- // that
- // compilers
- // don't
- // warn
- // about
- // out-of-bounds
- // accesses
- // -- the
- // warnings
- // are
- // bogus
- // since we
- // get here
- // only for
- // dim==3,
- // but at
- // least
- // one
- // isn't
- // quite
- // smart
- // enough
- // to
- // notice
- // this and
- // warns
- // when
- // compiling
- // the
- // function
- // in 2d
+ // take cross product between normals[0] and
+ // normals[1]. write it in the current form (with [dim-2])
+ // to make sure that compilers don't warn about
+ // out-of-bounds accesses -- the warnings are bogus since
+ // we get here only for dim==3, but at least one isn't
+ // quite smart enough to notice this and warns when
+ // compiling the function in 2d
cross_product (tangent, normals[0], normals[dim-2]);
break;
default:
tangential_vectors.push_back (tangent);
}
- // go through the list of
- // tangents and make sure
- // that they all roughly
- // point in the same
- // direction as the first
- // one (i.e. have an
- // angle less than 90
- // degrees); if they
- // don't then flip their
+ // go through the list of tangents and make sure that they all
+ // roughly point in the same direction as the first one (i.e. have
+ // an angle less than 90 degrees); if they don't then flip their
// sign
{
const Tensor<1,dim> first_tangent = tangential_vectors.front();
*t *= -1;
}
- // now compute the
- // average tangent and
- // normalize it
+ // now compute the average tangent and normalize it
Tensor<1,dim> average_tangent;
for (typename std::list<Tensor<1,dim> >::const_iterator
t = tangential_vectors.begin();
average_tangent += *t;
average_tangent /= average_tangent.norm();
- // now all that is left
- // is that we add the
- // constraints that the
- // vector is parallel
- // to the tangent
+ // now all that is left is that we add the constraints that the
+ // vector is parallel to the tangent
const internal::VectorDoFTuple<dim> &
dof_indices = same_dof_range[0]->first;
internal::add_tangentiality_constraints (dof_indices,
polynomials_adini.cc
polynomials_bdm.cc
polynomials_nedelec.cc
+ polynomials_piecewise.cc
polynomial_space.cc
polynomials_p.cc
polynomials_raviart_thomas.cc
void ConvergenceTable::evaluate_convergence_rates(const std::string &data_column_key,
const std::string &reference_column_key,
- const RateMode rate_mode)
+ const RateMode rate_mode,
+ const unsigned int dim)
{
Assert(columns.count(data_column_key),
ExcColumnNotExistent(data_column_key));
std::vector<internal::TableEntry> &entries=columns[data_column_key].entries;
std::vector<internal::TableEntry> &ref_entries=columns[reference_column_key].entries;
- std::string rate_key = data_column_key;
+ std::string rate_key = data_column_key+"...";
const unsigned int n = entries.size();
const unsigned int n_ref = ref_entries.size();
}
break;
case reduction_rate_log2:
- rate_key += "red.rate";
+ rate_key += "red.rate.log2";
no_rate_entries = columns[rate_key].entries.size();
// Calculate all missing rate values:
for (unsigned int i = no_rate_entries; i<n; ++i)
}
else
{
- add_value(rate_key, 2*std::log(std::fabs(values[i-1]/values[i])) /
+ add_value(rate_key, dim*std::log(std::fabs(values[i-1]/values[i])) /
std::log(std::fabs(ref_values[i]/ref_values[i-1])));
}
}
}
+std::size_t
+DataOutBase::SvgFlags::memory_consumption () const
+{
+ // only simple data elements, so
+ // use sizeof operator
+ return sizeof (*this);
+}
+
+
void DataOutBase::PovrayFlags::declare_parameters (ParameterHandler &prm)
-DataOutBase::VtkFlags::VtkFlags ()
+DataOutBase::VtkFlags::VtkFlags (const double time,
+ const unsigned int cycle)
+ :
+ time (time),
+ cycle (cycle)
{}
}
+DataOutBase::SvgFlags::SvgFlags (const unsigned int height_vector,
+ const int azimuth_angle,
+ 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)
+{}
+
DataOutBase::Deal_II_IntermediateFlags::Deal_II_IntermediateFlags ()
:
std::string
DataOutBase::get_output_format_names ()
{
- return "none|dx|ucd|gnuplot|povray|eps|gmv|tecplot|tecplot_binary|vtk|vtu|hdf5|deal.II intermediate";
+ return "none|dx|ucd|gnuplot|povray|eps|gmv|tecplot|tecplot_binary|vtk|vtu|hdf5|svg|deal.II intermediate";
}
return ".d2";
case hdf5:
return ".h5";
+ case svg:
+ return ".svg";
default:
Assert (false, ExcNotImplemented());
return "";
}
+Point<2> DataOutBase::svg_project_point(Point<3> point, Point<3> camera_position, Point<3> camera_direction, Point<3> camera_horizontal, float camera_focus)
+{
+ Point<3> camera_vertical;
+ camera_vertical[0] = camera_horizontal[1] * camera_direction[2] - camera_horizontal[2] * camera_direction[1];
+ camera_vertical[1] = camera_horizontal[2] * camera_direction[0] - camera_horizontal[0] * camera_direction[2];
+ camera_vertical[2] = camera_horizontal[0] * camera_direction[1] - camera_horizontal[1] * camera_direction[0];
+
+ float phi;
+ phi = camera_focus;
+ phi /= (point[0] - camera_position[0]) * camera_direction[0] + (point[1] - camera_position[1]) * camera_direction[1] + (point[2] - camera_position[2]) * camera_direction[2];
+
+ Point<3> projection;
+ projection[0] = camera_position[0] + phi * (point[0] - camera_position[0]);
+ projection[1] = camera_position[1] + phi * (point[1] - camera_position[1]);
+ projection[2] = camera_position[2] + phi * (point[2] - camera_position[2]);
+
+ Point<2> projection_decomposition;
+ projection_decomposition[0] = (projection[0] - camera_position[0] - camera_focus * camera_direction[0]) * camera_horizontal[0];
+ projection_decomposition[0] += (projection[1] - camera_position[1] - camera_focus * camera_direction[1]) * camera_horizontal[1];
+ projection_decomposition[0] += (projection[2] - camera_position[2] - camera_focus * camera_direction[2]) * camera_horizontal[2];
+
+ projection_decomposition[1] = (projection[0] - camera_position[0] - camera_focus * camera_direction[0]) * camera_vertical[0];
+ projection_decomposition[1] += (projection[1] - camera_position[1] - camera_focus * camera_direction[1]) * camera_vertical[1];
+ projection_decomposition[1] += (projection[2] - camera_position[2] - camera_focus * camera_direction[2]) * camera_vertical[2];
+
+ return projection_decomposition;
+}
+
+Point<6> DataOutBase::svg_get_gradient_parameters(Point<3> points[])
+{
+ Point<3> v_min, v_max, v_inter;
+
+ // Use the Bubblesort algorithm to sort the points with respect to the third coordinate
+ int i, j;
+
+ for (i = 0; i < 2; ++i)
+ {
+ for (j = 0; j < 2-i; ++j)
+ {
+ if (points[j][2] > points[j + 1][2])
+ {
+ Point<3> temp = points[j];
+ points[j] = points[j+1];
+ points[j+1] = temp;
+ }
+ }
+ }
+
+ // save the related three-dimensional vectors v_min, v_inter, and v_max
+ v_min = points[0];
+ v_inter = points[1];
+ v_max = points[2];
+
+ Point<2> A[2];
+ Point<2> b, gradient;
+
+ // determine the plane offset c
+ A[0][0] = v_max[0] - v_min[0];
+ A[0][1] = v_inter[0] - v_min[0];
+ A[1][0] = v_max[1] - v_min[1];
+ A[1][1] = v_inter[1] - v_min[1];
+
+ b[0] = - v_min[0];
+ b[1] = - v_min[1];
+
+ double x, sum;
+ bool col_change = false;
+
+ if (A[0][0] == 0)
+ {
+ col_change = true;
+
+ A[0][0] = A[0][1];
+ A[0][1] = 0;
+
+ double temp = A[1][0];
+ A[1][0] = A[1][1];
+ A[1][1] = temp;
+ }
+
+ for (unsigned int k = 0; k < 1; k++)
+ {
+ for (unsigned int i = k+1; i < 2; i++)
+ {
+ x = A[i][k] / A[k][k];
+
+ for (unsigned int j = k+1; j < 2; j++) A[i][j] = A[i][j] - A[k][j] * x;
+
+ b[i] = b[i] - b[k]*x;
+
+ }
+ }
+
+ b[1] = b[1] / A[1][1];
+
+ for (int i = 0; i >= 0; i--)
+ {
+ sum = b[i];
+
+ for (unsigned int j = i+1; j < 2; j++) sum = sum - A[i][j] * b[j];
+
+ b[i] = sum / A[i][i];
+ }
+
+ if (col_change)
+ {
+ double temp = b[0];
+ b[0] = b[1];
+ b[1] = temp;
+ }
+
+ double c = b[0] * (v_max[2] - v_min[2]) + b[1] * (v_inter[2] - v_min[2]) + v_min[2];
+
+ // Determine the first entry of the gradient (phi, cf. documentation)
+ A[0][0] = v_max[0] - v_min[0];
+ A[0][1] = v_inter[0] - v_min[0];
+ A[1][0] = v_max[1] - v_min[1];
+ A[1][1] = v_inter[1] - v_min[1];
+
+ b[0] = 1.0 - v_min[0];
+ b[1] = - v_min[1];
+
+ col_change = false;
+
+ if (A[0][0] == 0)
+ {
+ col_change = true;
+
+ A[0][0] = A[0][1];
+ A[0][1] = 0;
+
+ double temp = A[1][0];
+ A[1][0] = A[1][1];
+ A[1][1] = temp;
+ }
+
+ for (unsigned int k = 0; k < 1; k++)
+ {
+ for (unsigned int i = k+1; i < 2; i++)
+ {
+ x = A[i][k] / A[k][k];
+
+ for (unsigned int j = k+1; j < 2; j++) A[i][j] = A[i][j] - A[k][j] * x;
+
+ b[i] = b[i] - b[k] * x;
+
+ }
+ }
+
+ b[1]=b[1] / A[1][1];
+
+ for (int i = 0; i >= 0; i--)
+ {
+ sum = b[i];
+
+ for (unsigned int j = i+1; j < 2; j++) sum = sum - A[i][j]*b[j];
+
+ b[i] = sum / A[i][i];
+ }
+
+ if (col_change)
+ {
+ double temp = b[0];
+ b[0] = b[1];
+ b[1] = temp;
+ }
+
+ gradient[0] = b[0] * (v_max[2] - v_min[2]) + b[1] * (v_inter[2] - v_min[2]) - c + v_min[2];
+
+ // determine the second entry of the gradient
+ A[0][0] = v_max[0] - v_min[0];
+ A[0][1] = v_inter[0] - v_min[0];
+ A[1][0] = v_max[1] - v_min[1];
+ A[1][1] = v_inter[1] - v_min[1];
+
+ b[0] = - v_min[0];
+ b[1] = 1.0 - v_min[1];
+
+ col_change = false;
+
+ if (A[0][0] == 0)
+ {
+ col_change = true;
+
+ A[0][0] = A[0][1];
+ A[0][1] = 0;
+
+ double temp = A[1][0];
+ A[1][0] = A[1][1];
+ A[1][1] = temp;
+ }
+
+ for (unsigned int k = 0; k < 1; k++)
+ {
+ for (unsigned int i = k+1; i < 2; i++)
+ {
+ x = A[i][k] / A[k][k];
+
+ for (unsigned int j = k+1; j < 2; j++) A[i][j] = A[i][j] - A[k][j] * x;
+
+ b[i] = b[i] - b[k] * x;
+ }
+ }
+
+ b[1] = b[1] / A[1][1];
+
+ for (int i = 0; i >= 0; i--)
+ {
+ sum = b[i];
+
+ for (unsigned int j = i+1; j < 2; j++) sum = sum - A[i][j] * b[j];
+
+ b[i] = sum / A[i][i];
+ }
+
+ if (col_change)
+ {
+ double temp = b[0];
+ b[0] = b[1];
+ b[1] = temp;
+ }
+
+ gradient[1] = b[0] * (v_max[2] - v_min[2]) + b[1] * (v_inter[2] - v_min[2]) - c + v_min[2];
+
+ // normalize the gradient
+ double gradient_norm = sqrt(pow(gradient[0], 2.0) + pow(gradient[1], 2.0));
+ gradient[0] /= gradient_norm;
+ gradient[1] /= gradient_norm;
+
+ double lambda = - gradient[0] * (v_min[0] - v_max[0]) - gradient[1] * (v_min[1] - v_max[1]);
+
+ Point<6> gradient_parameters(true);
+
+ gradient_parameters[0] = v_min[0];
+ gradient_parameters[1] = v_min[1];
+
+ gradient_parameters[2] = v_min[0] + lambda * gradient[0];
+ gradient_parameters[3] = v_min[1] + lambda * gradient[1];
+
+ gradient_parameters[4] = v_min[2];
+ gradient_parameters[5] = v_max[2];
+
+ return gradient_parameters;
+}
+
+
+bool DataOutBase::SvgCell::operator < (const SvgCell &e) const
+{
+ // note the "wrong" order in
+ // which we sort the elements
+ return depth > e.depth;
+}
+
+
+
template <int dim, int spacedim>
void DataOutBase::write_ucd (const std::vector<Patch<dim,spacedim> > &patches,
const std::vector<std::string> &data_names,
patch->data.n_rows()));
const double color_values[4]
= { patch->data.n_rows() != 0 ?
- patch->data(flags.color_vector,i1*d1 + i2*d2) : 1,
+ patch->data(flags.color_vector,i1 *d1 + i2 *d2) : 1,
patch->data.n_rows() != 0 ?
- patch->data(flags.color_vector,(i1+1)*d1 + i2*d2) : 1,
+ patch->data(flags.color_vector,(i1+1)*d1 + i2 *d2) : 1,
patch->data.n_rows() != 0 ?
- patch->data(flags.color_vector,i1*d1 + (i2+1)*d2) : 1,
+ patch->data(flags.color_vector,i1 *d1 + (i2+1)*d2) : 1,
patch->data.n_rows() != 0 ?
patch->data(flags.color_vector,(i1+1)*d1 + (i2+1)*d2) : 1
///////////////////////
// preamble
- if (true)
- {
- std::time_t time1= std::time (0);
- std::tm *time = std::localtime(&time1);
- out << "# vtk DataFile Version 3.0"
- << '\n'
- << "#This file was generated by the deal.II library on "
- << time->tm_year+1900 << "/"
- << time->tm_mon+1 << "/"
- << time->tm_mday << " at "
- << time->tm_hour << ":"
- << std::setw(2) << time->tm_min << ":"
- << std::setw(2) << time->tm_sec
- << '\n'
- << "ASCII"
- << '\n'
- << "DATASET UNSTRUCTURED_GRID\n"
- << '\n';
- }
+ {
+ std::time_t time1= std::time (0);
+ std::tm *time = std::localtime(&time1);
+ out << "# vtk DataFile Version 3.0"
+ << '\n'
+ << "#This file was generated by the deal.II library on "
+ << time->tm_year+1900 << "/"
+ << time->tm_mon+1 << "/"
+ << time->tm_mday << " at "
+ << time->tm_hour << ":"
+ << std::setw(2) << time->tm_min << ":"
+ << std::setw(2) << time->tm_sec
+ << '\n'
+ << "ASCII"
+ << '\n';
+ // now output the data header
+ out << "DATASET UNSTRUCTURED_GRID\n"
+ << '\n';
+ }
+ // if desired, output time and cycle of the simulation, following
+ // the instructions at
+ // http://www.visitusers.org/index.php?title=Time_and_Cycle_in_VTK_files
+ {
+ const unsigned int
+ n_metadata = ((flags.cycle != std::numeric_limits<unsigned int>::min() ? 1 : 0)
+ +
+ (flags.time != std::numeric_limits<double>::min() ? 1 : 0));
+ if (n_metadata > 0)
+ out << "FIELD FieldData " << n_metadata << "\n";
+
+ if (flags.cycle != std::numeric_limits<unsigned int>::min())
+ {
+ out << "CYCLE 1 1 int\n"
+ << flags.cycle << "\n";
+ }
+ if (flags.time != std::numeric_limits<double>::min())
+ {
+ out << "TIME 1 1 double\n"
+ << flags.time << "\n";
+ }
+ }
// first count the number of cells
// and cells for later use
}
#endif
+ // first up: metadata
+ //
+ // if desired, output time and cycle of the simulation, following
+ // the instructions at
+ // http://www.visitusers.org/index.php?title=Time_and_Cycle_in_VTK_files
+ {
+ const unsigned int
+ n_metadata = ((flags.cycle != std::numeric_limits<unsigned int>::min() ? 1 : 0)
+ +
+ (flags.time != std::numeric_limits<double>::min() ? 1 : 0));
+ if (n_metadata > 0)
+ out << "<FieldData>\n";
+
+ if (flags.cycle != std::numeric_limits<unsigned int>::min())
+ {
+ out << "<DataArray type=\"Float32\" Name=\"CYCLE\" NumberOfTuples=\"1\" format=\"ascii\">"
+ << flags.cycle
+ << "</DataArray>\n";
+ }
+ if (flags.time != std::numeric_limits<double>::min())
+ {
+ out << "<DataArray type=\"Float32\" Name=\"TIME\" NumberOfTuples=\"1\" format=\"ascii\">"
+ << flags.time
+ << "</DataArray>\n";
+ }
+
+ if (n_metadata > 0)
+ out << "</FieldData>\n";
+}
+
+
VtuStream vtu_out(out, flags);
const unsigned int n_data_sets = data_names.size();
}
+template <int dim, int spacedim>
+void DataOutBase::write_svg (const std::vector<Patch<dim,spacedim> > &patches,
+ const std::vector<std::string> &data_names,
+ const std::vector<std_cxx1x::tuple<unsigned int, unsigned int, std::string> > &vector_data_ranges,
+ const SvgFlags &flags,
+ std::ostream &out)
+{
+ // do not allow volume rendering
+ AssertThrow (dim==2, ExcNotImplemented());
+
+ const unsigned int height = 4000;
+ unsigned int width;
+
+ // margin around the plotted area
+ unsigned int margin_in_percent = 0;
+ if(flags.margin) margin_in_percent = 5;
+
+
+// determine the bounding box in the model space
+ double x_min, y_min, z_min;
+ double x_max, y_max, z_max;
+ double x_dimension, y_dimension, z_dimension;
+
+ typename std::vector<Patch<dim,spacedim> >::const_iterator patch = patches.begin();
+
+ unsigned int n_subdivisions = patch->n_subdivisions;
+ unsigned int n = n_subdivisions + 1;
+ const unsigned int d1 = 1;
+ const unsigned int d2 = n;
+
+ Point<spacedim> projected_point;
+ Point<spacedim> projected_points[4];
+
+ Point<2> projection_decomposition;
+ Point<2> projection_decompositions[4];
+
+ compute_node(projected_point, &*patch, 0, 0, 0, n_subdivisions);
+
+ Assert ((flags.height_vector < patch->data.n_rows()) ||
+ patch->data.n_rows() == 0,
+ ExcIndexRange (flags.height_vector, 0, patch->data.n_rows()));
+
+ x_min = projected_point[0];
+ x_max = x_min;
+ y_min = projected_point[1];
+ y_max = y_min;
+ z_min = patch->data.n_rows() != 0 ? patch->data(flags.height_vector,0) : 0;
+ z_max = z_min;
+
+ // iterate over the patches
+ for (; patch != patches.end(); ++patch)
+ {
+ n_subdivisions = patch->n_subdivisions;
+ n = n_subdivisions + 1;
+
+ for (unsigned int i2 = 0; i2 < n_subdivisions; ++i2)
+ {
+ for (unsigned int i1 = 0; i1 < n_subdivisions; ++i1)
+ {
+ compute_node(projected_points[0], &*patch, i1, i2, 0, n_subdivisions);
+ compute_node(projected_points[1], &*patch, i1+1, i2, 0, n_subdivisions);
+ compute_node(projected_points[2], &*patch, i1, i2+1, 0, n_subdivisions);
+ compute_node(projected_points[3], &*patch, i1+1, i2+1, 0, n_subdivisions);
+
+ x_min = std::min(x_min, (double)projected_points[0][0]);
+ x_min = std::min(x_min, (double)projected_points[1][0]);
+ x_min = std::min(x_min, (double)projected_points[2][0]);
+ x_min = std::min(x_min, (double)projected_points[3][0]);
+
+ x_max = std::max(x_max, (double)projected_points[0][0]);
+ x_max = std::max(x_max, (double)projected_points[1][0]);
+ x_max = std::max(x_max, (double)projected_points[2][0]);
+ x_max = std::max(x_max, (double)projected_points[3][0]);
+
+ y_min = std::min(y_min, (double)projected_points[0][1]);
+ y_min = std::min(y_min, (double)projected_points[1][1]);
+ y_min = std::min(y_min, (double)projected_points[2][1]);
+ y_min = std::min(y_min, (double)projected_points[3][1]);
+
+ y_max = std::max(y_max, (double)projected_points[0][1]);
+ y_max = std::max(y_max, (double)projected_points[1][1]);
+ y_max = std::max(y_max, (double)projected_points[2][1]);
+ y_max = std::max(y_max, (double)projected_points[3][1]);
+
+ Assert ((flags.height_vector < patch->data.n_rows()) ||
+ patch->data.n_rows() == 0,
+ ExcIndexRange (flags.height_vector, 0, patch->data.n_rows()));
+
+ z_min = std::min(z_min, (double)patch->data(flags.height_vector, i1*d1 + i2*d2));
+ z_min = std::min(z_min, (double)patch->data(flags.height_vector, (i1+1)*d1 + i2*d2));
+ z_min = std::min(z_min, (double)patch->data(flags.height_vector, i1*d1 + (i2+1)*d2));
+ z_min = std::min(z_min, (double)patch->data(flags.height_vector, (i1+1)*d1 + (i2+1)*d2));
+
+ z_max = std::max(z_max, (double)patch->data(flags.height_vector, i1*d1 + i2*d2));
+ z_max = std::max(z_max, (double)patch->data(flags.height_vector, (i1+1)*d1 + i2*d2));
+ z_max = std::max(z_max, (double)patch->data(flags.height_vector, i1*d1 + (i2+1)*d2));
+ z_max = std::max(z_max, (double)patch->data(flags.height_vector, (i1+1)*d1 + (i2+1)*d2));
+ }
+ }
+ }
+
+ x_dimension = x_max - x_min;
+ y_dimension = y_max - y_min;
+ z_dimension = z_max - z_min;
+
+
+// set initial camera position
+ Point<3> camera_position(true);
+ Point<3> camera_direction(true);
+ Point<3> camera_horizontal(true);
+ float camera_focus = 0;
+
+ // translate camera from the origin to the initial position
+ camera_position[0] = 0.;
+ camera_position[1] = 0.;
+ camera_position[2] = z_min + 2. * z_dimension;
+
+ camera_direction[0] = 0.;
+ camera_direction[1] = 0.;
+ camera_direction[2] = - 1.;
+
+ camera_horizontal[0] = 1.;
+ camera_horizontal[1] = 0.;
+ camera_horizontal[2] = 0.;
+
+ camera_focus = .5 * z_dimension;
+
+ Point<3> camera_position_temp(true);
+ Point<3> camera_direction_temp(true);
+ Point<3> camera_horizontal_temp(true);
+
+ const float angle_factor = 3.14159265 / 180.;
+
+ // (I) rotate the camera to the chosen polar angle
+ camera_position_temp[1] = cos(angle_factor * flags.polar_angle) * camera_position[1] - sin(angle_factor * flags.polar_angle) * camera_position[2];
+ camera_position_temp[2] = sin(angle_factor * flags.polar_angle) * camera_position[1] + cos(angle_factor * flags.polar_angle) * camera_position[2];
+
+ camera_direction_temp[1] = cos(angle_factor * flags.polar_angle) * camera_direction[1] - sin(angle_factor * flags.polar_angle) * camera_direction[2];
+ camera_direction_temp[2] = sin(angle_factor * flags.polar_angle) * camera_direction[1] + cos(angle_factor * flags.polar_angle) * camera_direction[2];
+
+ camera_horizontal_temp[1] = cos(angle_factor * flags.polar_angle) * camera_horizontal[1] - sin(angle_factor * flags.polar_angle) * camera_horizontal[2];
+ camera_horizontal_temp[2] = sin(angle_factor * flags.polar_angle) * camera_horizontal[1] + cos(angle_factor * flags.polar_angle) * camera_horizontal[2];
+
+ camera_position[1] = camera_position_temp[1];
+ camera_position[2] = camera_position_temp[2];
+
+ camera_direction[1] = camera_direction_temp[1];
+ camera_direction[2] = camera_direction_temp[2];
+
+ camera_horizontal[1] = camera_horizontal_temp[1];
+ camera_horizontal[2] = camera_horizontal_temp[2];
+
+ // (II) rotate the camera to the chosen azimuth angle
+ camera_position_temp[0] = cos(angle_factor * flags.azimuth_angle) * camera_position[0] - sin(angle_factor * flags.azimuth_angle) * camera_position[1];
+ camera_position_temp[1] = sin(angle_factor * flags.azimuth_angle) * camera_position[0] + cos(angle_factor * flags.azimuth_angle) * camera_position[1];
+
+ camera_direction_temp[0] = cos(angle_factor * flags.azimuth_angle) * camera_direction[0] - sin(angle_factor * flags.azimuth_angle) * camera_direction[1];
+ camera_direction_temp[1] = sin(angle_factor * flags.azimuth_angle) * camera_direction[0] + cos(angle_factor * flags.azimuth_angle) * camera_direction[1];
+
+ camera_horizontal_temp[0] = cos(angle_factor * flags.azimuth_angle) * camera_horizontal[0] - sin(angle_factor * flags.azimuth_angle) * camera_horizontal[1];
+ camera_horizontal_temp[1] = sin(angle_factor * flags.azimuth_angle) * camera_horizontal[0] + cos(angle_factor * flags.azimuth_angle) * camera_horizontal[1];
+
+ camera_position[0] = camera_position_temp[0];
+ camera_position[1] = camera_position_temp[1];
+
+ camera_direction[0] = camera_direction_temp[0];
+ camera_direction[1] = camera_direction_temp[1];
+
+ camera_horizontal[0] = camera_horizontal_temp[0];
+ camera_horizontal[1] = camera_horizontal_temp[1];
+
+ // (III) translate the camera
+ camera_position[0] = x_min + .5 * x_dimension;
+ camera_position[1] = y_min + .5 * y_dimension;
+
+ camera_position[0] += (z_min + 2. * z_dimension) * sin(angle_factor * flags.polar_angle) * sin(angle_factor * flags.azimuth_angle);
+ camera_position[1] -= (z_min + 2. * z_dimension) * sin(angle_factor * flags.polar_angle) * cos(angle_factor * flags.azimuth_angle);
+
+
+// determine the bounding box on the projection plane
+ double x_min_perspective, y_min_perspective;
+ double x_max_perspective, y_max_perspective;
+ double x_dimension_perspective, y_dimension_perspective;
+
+ patch = patches.begin();
+
+ n_subdivisions = patch->n_subdivisions;
+ n = n_subdivisions + 1;
+
+ Point<3> point(true);
+
+ compute_node(projected_point, &*patch, 0, 0, 0, n_subdivisions);
+
+ Assert ((flags.height_vector < patch->data.n_rows()) ||
+ patch->data.n_rows() == 0,
+ ExcIndexRange (flags.height_vector, 0, patch->data.n_rows()));
+
+ point[0] = projected_point[0];
+ point[1] = projected_point[1];
+ point[2] = patch->data.n_rows() != 0 ? patch->data(flags.height_vector, 0) : 0;
+
+ projection_decomposition = svg_project_point(point, camera_position, camera_direction, camera_horizontal, camera_focus);
+
+ x_min_perspective = projection_decomposition[0];
+ x_max_perspective = projection_decomposition[0];
+ y_min_perspective = projection_decomposition[1];
+ y_max_perspective = projection_decomposition[1];
+
+ // iterate over the patches
+ for (; patch != patches.end(); ++patch)
+ {
+ n_subdivisions = patch->n_subdivisions;
+ n = n_subdivisions + 1;
+
+ for (unsigned int i2 = 0; i2 < n_subdivisions; ++i2)
+ {
+ for (unsigned int i1 = 0; i1 < n_subdivisions; ++i1)
+ {
+ Point<spacedim> projected_vertices[4];
+ Point<3> vertices[4];
+
+ compute_node(projected_vertices[0], &*patch, i1, i2, 0, n_subdivisions);
+ compute_node(projected_vertices[1], &*patch, i1+1, i2, 0, n_subdivisions);
+ compute_node(projected_vertices[2], &*patch, i1, i2+1, 0, n_subdivisions);
+ compute_node(projected_vertices[3], &*patch, i1+1, i2+1, 0, n_subdivisions);
+
+ Assert ((flags.height_vector < patch->data.n_rows()) ||
+ patch->data.n_rows() == 0,
+ ExcIndexRange (flags.height_vector, 0, patch->data.n_rows()));
+
+ vertices[0][0] = projected_vertices[0][0];
+ vertices[0][1] = projected_vertices[0][1];
+ vertices[0][2] = patch->data.n_rows() != 0 ? patch->data(0,i1*d1 + i2*d2) : 0;
+
+ vertices[1][0] = projected_vertices[1][0];
+ vertices[1][1] = projected_vertices[1][1];
+ vertices[1][2] = patch->data.n_rows() != 0 ? patch->data(0,(i1+1)*d1 + i2*d2) : 0;
+
+ vertices[2][0] = projected_vertices[2][0];
+ vertices[2][1] = projected_vertices[2][1];
+ vertices[2][2] = patch->data.n_rows() != 0 ? patch->data(0,i1*d1 + (i2+1)*d2) : 0;
+
+ vertices[3][0] = projected_vertices[3][0];
+ vertices[3][1] = projected_vertices[3][1];
+ vertices[3][2] = patch->data.n_rows() != 0 ? patch->data(0,(i1+1)*d1 + (i2+1)*d2) : 0;
+
+ projection_decompositions[0] = svg_project_point(vertices[0], camera_position, camera_direction, camera_horizontal, camera_focus);
+ projection_decompositions[1] = svg_project_point(vertices[1], camera_position, camera_direction, camera_horizontal, camera_focus);
+ projection_decompositions[2] = svg_project_point(vertices[2], camera_position, camera_direction, camera_horizontal, camera_focus);
+ projection_decompositions[3] = svg_project_point(vertices[3], camera_position, camera_direction, camera_horizontal, camera_focus);
+
+ x_min_perspective = std::min(x_min_perspective, (double)projection_decompositions[0][0]);
+ x_min_perspective = std::min(x_min_perspective, (double)projection_decompositions[1][0]);
+ x_min_perspective = std::min(x_min_perspective, (double)projection_decompositions[2][0]);
+ x_min_perspective = std::min(x_min_perspective, (double)projection_decompositions[3][0]);
+
+ x_max_perspective = std::max(x_max_perspective, (double)projection_decompositions[0][0]);
+ x_max_perspective = std::max(x_max_perspective, (double)projection_decompositions[1][0]);
+ x_max_perspective = std::max(x_max_perspective, (double)projection_decompositions[2][0]);
+ x_max_perspective = std::max(x_max_perspective, (double)projection_decompositions[3][0]);
+
+ y_min_perspective = std::min(y_min_perspective, (double)projection_decompositions[0][1]);
+ y_min_perspective = std::min(y_min_perspective, (double)projection_decompositions[1][1]);
+ y_min_perspective = std::min(y_min_perspective, (double)projection_decompositions[2][1]);
+ y_min_perspective = std::min(y_min_perspective, (double)projection_decompositions[3][1]);
+
+ y_max_perspective = std::max(y_max_perspective, (double)projection_decompositions[0][1]);
+ y_max_perspective = std::max(y_max_perspective, (double)projection_decompositions[1][1]);
+ y_max_perspective = std::max(y_max_perspective, (double)projection_decompositions[2][1]);
+ y_max_perspective = std::max(y_max_perspective, (double)projection_decompositions[3][1]);
+ }
+ }
+ }
+
+ x_dimension_perspective = x_max_perspective - x_min_perspective;
+ y_dimension_perspective = y_max_perspective - y_min_perspective;
+
+ std::multiset<SvgCell> cells;
+
+ // iterate over the patches
+ for (patch = patches.begin(); patch != patches.end(); ++patch)
+ {
+ n_subdivisions = patch->n_subdivisions;
+ n = n_subdivisions + 1;
+
+ for (unsigned int i2 = 0; i2 < n_subdivisions; ++i2)
+ {
+ for (unsigned int i1 = 0; i1 < n_subdivisions; ++i1)
+ {
+ Point<spacedim> projected_vertices[4];
+ SvgCell cell;
+
+ compute_node(projected_vertices[0], &*patch, i1, i2, 0, n_subdivisions);
+ compute_node(projected_vertices[1], &*patch, i1+1, i2, 0, n_subdivisions);
+ compute_node(projected_vertices[2], &*patch, i1, i2+1, 0, n_subdivisions);
+ compute_node(projected_vertices[3], &*patch, i1+1, i2+1, 0, n_subdivisions);
+
+ Assert ((flags.height_vector < patch->data.n_rows()) ||
+ patch->data.n_rows() == 0,
+ ExcIndexRange (flags.height_vector, 0, patch->data.n_rows()));
+
+ cell.vertices[0][0] = projected_vertices[0][0];
+ cell.vertices[0][1] = projected_vertices[0][1];
+ cell.vertices[0][2] = patch->data.n_rows() != 0 ? patch->data(0,i1*d1 + i2*d2) : 0;
+
+ cell.vertices[1][0] = projected_vertices[1][0];
+ cell.vertices[1][1] = projected_vertices[1][1];
+ cell.vertices[1][2] = patch->data.n_rows() != 0 ? patch->data(0,(i1+1)*d1 + i2*d2) : 0;
+
+ cell.vertices[2][0] = projected_vertices[2][0];
+ cell.vertices[2][1] = projected_vertices[2][1];
+ cell.vertices[2][2] = patch->data.n_rows() != 0 ? patch->data(0,i1*d1 + (i2+1)*d2) : 0;
+
+ cell.vertices[3][0] = projected_vertices[3][0];
+ cell.vertices[3][1] = projected_vertices[3][1];
+ cell.vertices[3][2] = patch->data.n_rows() != 0 ? patch->data(0,(i1+1)*d1 + (i2+1)*d2) : 0;
+
+ cell.projected_vertices[0] = svg_project_point(cell.vertices[0], camera_position, camera_direction, camera_horizontal, camera_focus);
+ cell.projected_vertices[1] = svg_project_point(cell.vertices[1], camera_position, camera_direction, camera_horizontal, camera_focus);
+ cell.projected_vertices[2] = svg_project_point(cell.vertices[2], camera_position, camera_direction, camera_horizontal, camera_focus);
+ cell.projected_vertices[3] = svg_project_point(cell.vertices[3], camera_position, camera_direction, camera_horizontal, camera_focus);
+
+ cell.center = .25 * (cell.vertices[0] + cell.vertices[1] + cell.vertices[2] + cell.vertices[3]);
+ cell.projected_center = svg_project_point(cell.center, camera_position, camera_direction, camera_horizontal, camera_focus);
+
+ cell.depth = cell.center.distance(camera_position);
+
+ cells.insert(cell);
+ }
+ }
+ }
+
+
+// write the svg file
+ width = static_cast<unsigned int>(.5 + height * (x_dimension_perspective / y_dimension_perspective));
+ unsigned int additional_width = 0;
+
+ if(flags.draw_colorbar) additional_width = static_cast<unsigned int>(.5 + height * .3); // additional width for colorbar
+
+ // basic svg header and background rectangle
+ out << "<svg width=\"" << width + additional_width << "\" height=\"" << height << "\" xmlns=\"http://www.w3.org/2000/svg\" version=\"1.1\">" << '\n'
+ << " <rect width=\"" << width + additional_width << "\" height=\"" << height << "\" style=\"fill:white\"/>" << '\n' << '\n';
+
+ unsigned int triangle_counter = 0;
+
+ // write the cells in the correct order
+ for (typename std::multiset<SvgCell>::const_iterator cell = cells.begin(); cell != cells.end(); ++cell)
+ {
+ Point<3> points3d_triangle[3];
+
+ for (unsigned int triangle_index = 0; triangle_index < 4; triangle_index++)
+ {
+ switch (triangle_index)
+ {
+ case 0: points3d_triangle[0] = cell->vertices[0], points3d_triangle[1] = cell->vertices[1], points3d_triangle[2] = cell->center; break;
+ case 1: points3d_triangle[0] = cell->vertices[1], points3d_triangle[1] = cell->vertices[3], points3d_triangle[2] = cell->center; break;
+ case 2: points3d_triangle[0] = cell->vertices[3], points3d_triangle[1] = cell->vertices[2], points3d_triangle[2] = cell->center; break;
+ case 3: points3d_triangle[0] = cell->vertices[2], points3d_triangle[1] = cell->vertices[0], points3d_triangle[2] = cell->center; break;
+ default: break;
+ }
+
+ Point<6> gradient_param = svg_get_gradient_parameters(points3d_triangle);
+
+ double start_h = .667 - ((gradient_param[4] - z_min) / z_dimension) * .667;
+ double stop_h = .667 - ((gradient_param[5] - z_min) / z_dimension) * .667;
+
+ unsigned int start_r = 0;
+ unsigned int start_g = 0;
+ unsigned int start_b = 0;
+
+ unsigned int stop_r = 0;
+ unsigned int stop_g = 0;
+ unsigned int stop_b = 0;
+
+ unsigned int start_i = static_cast<unsigned int>(start_h * 6.);
+ unsigned int stop_i = static_cast<unsigned int>(stop_h * 6.);
+
+ double start_f = start_h * 6. - start_i;
+ double start_q = 1. - start_f;
+
+ double stop_f = stop_h * 6. - stop_i;
+ double stop_q = 1. - stop_f;
+
+ switch (start_i % 6)
+ {
+ case 0: start_r = 255, start_g = static_cast<unsigned int>(.5 + 255. * start_f); break;
+ case 1: start_r = static_cast<unsigned int>(.5 + 255. * start_q), start_g = 255; break;
+ case 2: start_g = 255, start_b = static_cast<unsigned int>(.5 + 255. * start_f); break;
+ case 3: start_g = static_cast<unsigned int>(.5 + 255. * start_q), start_b = 255; break;
+ case 4: start_r = static_cast<unsigned int>(.5 + 255. * start_f), start_b = 255; break;
+ case 5: start_r = 255, start_b = static_cast<unsigned int>(.5 + 255. * start_q); break;
+ default: break;
+ }
+
+ switch (stop_i % 6)
+ {
+ case 0: stop_r = 255, stop_g = static_cast<unsigned int>(.5 + 255. * stop_f); break;
+ case 1: stop_r = static_cast<unsigned int>(.5 + 255. * stop_q), stop_g = 255; break;
+ case 2: stop_g = 255, stop_b = static_cast<unsigned int>(.5 + 255. * stop_f); break;
+ case 3: stop_g = static_cast<unsigned int>(.5 + 255. * stop_q), stop_b = 255; break;
+ case 4: stop_r = static_cast<unsigned int>(.5 + 255. * stop_f), stop_b = 255; break;
+ case 5: stop_r = 255, stop_b = static_cast<unsigned int>(.5 + 255. * stop_q); break;
+ default: break;
+ }
+
+ Point<3> gradient_start_point_3d, gradient_stop_point_3d;
+
+ gradient_start_point_3d[0] = gradient_param[0];
+ gradient_start_point_3d[1] = gradient_param[1];
+ gradient_start_point_3d[2] = gradient_param[4];
+
+ gradient_stop_point_3d[0] = gradient_param[2];
+ gradient_stop_point_3d[1] = gradient_param[3];
+ gradient_stop_point_3d[2] = gradient_param[5];
+
+ Point<2> gradient_start_point = svg_project_point(gradient_start_point_3d, camera_position, camera_direction, camera_horizontal, camera_focus);
+ Point<2> gradient_stop_point = svg_project_point(gradient_stop_point_3d, camera_position, camera_direction, camera_horizontal, camera_focus);
+
+ // define linear gradient
+ out << " <linearGradient id=\"" << triangle_counter << "\" gradientUnits=\"userSpaceOnUse\" "
+ << "x1=\""
+ << static_cast<unsigned int>(.5 + ((gradient_start_point[0] - x_min_perspective) / x_dimension_perspective) * (width - (width/100.) * 2. * margin_in_percent) + ((width/100.) * margin_in_percent))
+ << "\" "
+ << "y1=\""
+ << static_cast<unsigned int>(.5 + height - (height/100.) * margin_in_percent - ((gradient_start_point[1] - y_min_perspective) / y_dimension_perspective) * (height - (height/100.) * 2. * margin_in_percent))
+ << "\" "
+ << "x2=\""
+ << static_cast<unsigned int>(.5 + ((gradient_stop_point[0] - x_min_perspective) / x_dimension_perspective) * (width - (width/100.) * 2. * margin_in_percent) + ((width/100.) * margin_in_percent))
+ << "\" "
+ << "y2=\""
+ << static_cast<unsigned int>(.5 + height - (height/100.) * margin_in_percent - ((gradient_stop_point[1] - y_min_perspective) / y_dimension_perspective) * (height - (height/100.) * 2. * margin_in_percent))
+ << "\""
+ << ">" << '\n'
+ << " <stop offset=\"0\" style=\"stop-color:rgb(" << start_r << "," << start_g << "," << start_b << ")\"/>" << '\n'
+ << " <stop offset=\"1\" style=\"stop-color:rgb(" << stop_r << "," << stop_g << "," << stop_b << ")\"/>" << '\n'
+ << " </linearGradient>" << '\n';
+
+ // draw current triangle
+ double x1 = 0, y1 = 0, x2 = 0, y2 = 0;
+ double x3 = cell->projected_center[0];
+ double y3 = cell->projected_center[1];
+
+ switch (triangle_index)
+ {
+ case 0: x1 = cell->projected_vertices[0][0], y1 = cell->projected_vertices[0][1], x2 = cell->projected_vertices[1][0], y2 = cell->projected_vertices[1][1]; break;
+ case 1: x1 = cell->projected_vertices[1][0], y1 = cell->projected_vertices[1][1], x2 = cell->projected_vertices[3][0], y2 = cell->projected_vertices[3][1]; break;
+ case 2: x1 = cell->projected_vertices[3][0], y1 = cell->projected_vertices[3][1], x2 = cell->projected_vertices[2][0], y2 = cell->projected_vertices[2][1]; break;
+ case 3: x1 = cell->projected_vertices[2][0], y1 = cell->projected_vertices[2][1], x2 = cell->projected_vertices[0][0], y2 = cell->projected_vertices[0][1]; break;
+ default: break;
+ }
+
+ out << " <path d=\"M "
+ << static_cast<unsigned int>(.5 + ((x1 - x_min_perspective) / x_dimension_perspective) * (width - (width/100.) * 2. * margin_in_percent) + ((width/100.) * margin_in_percent))
+ << ' '
+ << static_cast<unsigned int>(.5 + height - (height/100.) * margin_in_percent - ((y1 - y_min_perspective) / y_dimension_perspective) * (height - (height/100.) * 2. * margin_in_percent))
+ << " L "
+ << static_cast<unsigned int>(.5 + ((x2 - x_min_perspective) / x_dimension_perspective) * (width - (width/100.) * 2. * margin_in_percent) + ((width/100.) * margin_in_percent))
+ << ' '
+ << static_cast<unsigned int>(.5 + height - (height/100.) * margin_in_percent - ((y2 - y_min_perspective) / y_dimension_perspective) * (height - (height/100.) * 2. * margin_in_percent))
+ << " L "
+ << static_cast<unsigned int>(.5 + ((x3 - x_min_perspective) / x_dimension_perspective) * (width - (width/100.) * 2. * margin_in_percent) + ((width/100.) * margin_in_percent))
+ << ' '
+ << static_cast<unsigned int>(.5 + height - (height/100.) * margin_in_percent - ((y3 - y_min_perspective) / y_dimension_perspective) * (height - (height/100.) * 2. * margin_in_percent))
+ << " L "
+ << static_cast<unsigned int>(.5 + ((x1 - x_min_perspective) / x_dimension_perspective) * (width - (width/100.) * 2. * margin_in_percent) + ((width/100.) * margin_in_percent))
+ << ' '
+ << static_cast<unsigned int>(.5 + height - (height/100.) * margin_in_percent - ((y1 - y_min_perspective) / y_dimension_perspective) * (height - (height/100.) * 2. * margin_in_percent))
+ << "\" style=\"stroke:black; fill:url(#" << triangle_counter << "); stroke-width:" << flags.line_thickness << "\"/>" << '\n';
+
+ triangle_counter++;
+ }
+ }
+
+
+// draw the colorbar
+ if (flags.draw_colorbar)
+ {
+ out << '\n' << " <!-- colorbar -->" << '\n';
+
+ unsigned int element_height = static_cast<unsigned int>(((height/100.) * (71. - 2.*margin_in_percent)) / 4);
+ unsigned int element_width = static_cast<unsigned int>(.5 + (height/100.) * 2.5);
+
+ additional_width = 0;
+ if (!flags.margin) additional_width = static_cast<unsigned int>(.5 + (height/100.) * 2.5);
+
+ for (unsigned int index = 0; index < 4; index++)
+ {
+ double start_h = .667 - ((index+1) / 4.) * .667;
+ double stop_h = .667 - (index / 4.) * .667;
+
+ unsigned int start_r = 0;
+ unsigned int start_g = 0;
+ unsigned int start_b = 0;
+
+ unsigned int stop_r = 0;
+ unsigned int stop_g = 0;
+ unsigned int stop_b = 0;
+
+ unsigned int start_i = static_cast<unsigned int>(start_h * 6.);
+ unsigned int stop_i = static_cast<unsigned int>(stop_h * 6.);
+
+ double start_f = start_h * 6. - start_i;
+ double start_q = 1. - start_f;
+
+ double stop_f = stop_h * 6. - stop_i;
+ double stop_q = 1. - stop_f;
+
+ switch (start_i % 6)
+ {
+ case 0: start_r = 255, start_g = static_cast<unsigned int>(.5 + 255. * start_f); break;
+ case 1: start_r = static_cast<unsigned int>(.5 + 255. * start_q), start_g = 255; break;
+ case 2: start_g = 255, start_b = static_cast<unsigned int>(.5 + 255. * start_f); break;
+ case 3: start_g = static_cast<unsigned int>(.5 + 255. * start_q), start_b = 255; break;
+ case 4: start_r = static_cast<unsigned int>(.5 + 255. * start_f), start_b = 255; break;
+ case 5: start_r = 255, start_b = static_cast<unsigned int>(.5 + 255. * start_q); break;
+ default: break;
+ }
+
+ switch (stop_i % 6)
+ {
+ case 0: stop_r = 255, stop_g = static_cast<unsigned int>(.5 + 255. * stop_f); break;
+ case 1: stop_r = static_cast<unsigned int>(.5 + 255. * stop_q), stop_g = 255; break;
+ case 2: stop_g = 255, stop_b = static_cast<unsigned int>(.5 + 255. * stop_f); break;
+ case 3: stop_g = static_cast<unsigned int>(.5 + 255. * stop_q), stop_b = 255; break;
+ case 4: stop_r = static_cast<unsigned int>(.5 + 255. * stop_f), stop_b = 255; break;
+ case 5: stop_r = 255, stop_b = static_cast<unsigned int>(.5 + 255. * stop_q); break;
+ default: break;
+ }
+
+ // define gradient
+ out << " <linearGradient id=\"colorbar_" << index << "\" gradientUnits=\"userSpaceOnUse\" "
+ << "x1=\"" << width + additional_width << "\" "
+ << "y1=\"" << static_cast<unsigned int>(.5 + (height/100.) * (margin_in_percent + 29)) + (3-index) * element_height << "\" "
+ << "x2=\"" << width + additional_width << "\" "
+ << "y2=\"" << static_cast<unsigned int>(.5 + (height/100.) * (margin_in_percent + 29)) + (4-index) * element_height << "\""
+ << ">" << '\n'
+ << " <stop offset=\"0\" style=\"stop-color:rgb(" << start_r << "," << start_g << "," << start_b << ")\"/>" << '\n'
+ << " <stop offset=\"1\" style=\"stop-color:rgb(" << stop_r << "," << stop_g << "," << stop_b << ")\"/>" << '\n'
+ << " </linearGradient>" << '\n';
+
+ // draw box corresponding to the gradient above
+ out << " <rect"
+ << " x=\"" << width + additional_width
+ << "\" y=\"" << static_cast<unsigned int>(.5 + (height/100.) * (margin_in_percent + 29)) + (3-index) * element_height
+ << "\" width=\"" << element_width
+ << "\" height=\"" << element_height
+ << "\" style=\"stroke:black; stroke-width:2; fill:url(#colorbar_" << index << ")\"/>" << '\n';
+ }
+
+ for (unsigned int index = 0; index < 5; index++)
+ {
+ out << " <text x=\"" << width + additional_width + static_cast<unsigned int>(1.5 * element_width)
+ << "\" y=\"" << static_cast<unsigned int>(.5 + (height/100.) * (margin_in_percent + 29) + (4.-index) * element_height + 30.) << "\""
+ << " style=\"text-anchor:start; font-size:80; font-family:Helvetica";
+
+ if (index == 0 || index == 4) out << "; font-weight:bold";
+
+ out << "\">" << (float)(((int)((z_min + index * (z_dimension / 4.))*10000))/10000.);
+
+ if (index == 4) out << " max";
+ if (index == 0) out << " min";
+
+ out << "</text>" << '\n';
+ }
+ }
+
+ // finalize the svg file
+ out << '\n' << "</svg>";
+ out.flush();
+
+}
+
+
template <int dim, int spacedim>
void
vtk_flags, out);
}
+template <int dim, int spacedim>
+void DataOutInterface<dim,spacedim>::write_svg (std::ostream &out) const
+{
+ DataOutBase::write_svg (get_patches(), get_dataset_names(),
+ get_vector_data_ranges(),
+ svg_flags, out);
+}
+
template <int dim, int spacedim>
void DataOutInterface<dim,spacedim>::write_vtu_in_parallel (const char *filename, MPI_Comm comm) const
{
#ifndef DEAL_II_COMPILER_SUPPORTS_MPI
// verify that there are indeed
// patches to be written out. most
- // of the times, people just forget
+ // of the times, people just forget
// to call build_patches when there
// are no patches, so a warning is
// in order. that said, the
#endif
#endif
- if (empty_proc) {
- local_node_cell_count[0] = local_node_cell_count[1] = 0;
- } else {
- compute_sizes<dim,spacedim>(patches, local_node_cell_count[0], local_node_cell_count[1]);
+ if (empty_proc)
+ {
+ local_node_cell_count[0] = local_node_cell_count[1] = 0;
+ }
+ else
+ {
+ compute_sizes<dim,spacedim>(patches, local_node_cell_count[0], local_node_cell_count[1]);
- data_vectors = Table<2,double> (n_data_sets, local_node_cell_count[0]);
- void (*fun_ptr) (const std::vector<Patch<dim,spacedim> > &, Table<2,double> &) = &DataOutBase::template write_gmv_reorder_data_vectors<dim,spacedim>;
- reorder_task = Threads::new_task (fun_ptr, patches, data_vectors);
- }
+ data_vectors = Table<2,double> (n_data_sets, local_node_cell_count[0]);
+ void (*fun_ptr) (const std::vector<Patch<dim,spacedim> > &, Table<2,double> &) = &DataOutBase::template write_gmv_reorder_data_vectors<dim,spacedim>;
+ reorder_task = Threads::new_task (fun_ptr, patches, data_vectors);
+ }
// Create file access properties
plist_id = H5Pcreate(H5P_FILE_ACCESS);
break;
case eps:
- write_eps(out);
+ write_eps (out);
break;
case gmv:
write_vtu (out);
break;
+ case svg:
+ write_svg (out);
+ break;
+
case deal_II_intermediate:
write_deal_II_intermediate (out);
break;
+template <int dim, int spacedim>
+void
+DataOutInterface<dim,spacedim>::set_flags (const SvgFlags &flags)
+{
+ svg_flags = flags;
+}
+
+
+
template <int dim, int spacedim>
void
DataOutInterface<dim,spacedim>::set_flags (const Deal_II_IntermediateFlags &flags)
MemoryConsumption::memory_consumption (gmv_flags) +
MemoryConsumption::memory_consumption (tecplot_flags) +
MemoryConsumption::memory_consumption (vtk_flags) +
+ MemoryConsumption::memory_consumption (svg_flags) +
MemoryConsumption::memory_consumption (deal_II_intermediate_flags));
}
// Verify that the Tensor<1,dim> will fit in the given length selected_components
// and not hang over the end of the vector.
- Assert (0 <= selected_component,
- ExcIndexRange (selected_component,0,0));
Assert (selected_component + dim - 1 < this->n_components,
ExcIndexRange (selected_component, 0, this->n_components));
}
void
-LogStream::attach(std::ostream &o)
+LogStream::attach(std::ostream &o,
+ const bool print_job_id)
{
Threads::Mutex::ScopedLock lock(log_lock);
file = &o;
o.setf(std::ios::showpoint | std::ios::left);
- o << dealjobid();
+ if (print_job_id)
+ o << dealjobid();
}
ParameterHandler::set (const std::string &entry_string,
const bool &new_value)
{
- std::ostringstream s;
- s << new_value;
-
// hand this off to the function that
// actually sets the value as a string
- set (entry_string, s.str());
+ set (entry_string,
+ (new_value ? "true" : "false"));
}
Assert (values.size() > 0, ExcZero());
const unsigned int values_size=values.size();
- // evaluate Lagrange polynomial and
- // derivatives
+ // evaluate Lagrange polynomial and derivatives
if (in_lagrange_product_form == true)
{
- // to compute the value and all derivatives of
- // a polynomial of the form
- // (x-x_1)*(x-x_2)*...*(x-x_n), expand the
- // derivatives like automatic differentiation
- // does.
+ // to compute the value and all derivatives of a polynomial of the
+ // form (x-x_1)*(x-x_2)*...*(x-x_n), expand the derivatives like
+ // automatic differentiation does.
const unsigned int n_supp = lagrange_support_points.size();
switch (values_size)
{
{
const number v = x-lagrange_support_points[i];
- // multiply by (x-x_i) and compute action on
- // all derivatives, too (inspired from
- // automatic differentiation: implement the
- // product rule for the old value and the new
- // variable 'v', i.e., expand value v and
- // derivative one). since we reuse a value
- // from the next lower derivative from the
- // steps before, need to start from the
- // highest derivative
+ // multiply by (x-x_i) and compute action on all derivatives,
+ // too (inspired from automatic differentiation: implement the
+ // product rule for the old value and the new variable 'v',
+ // i.e., expand value v and derivative one). since we reuse a
+ // value from the next lower derivative from the steps before,
+ // need to start from the highest derivative
for (unsigned int k=values_size-1; k>0; --k)
values[k] = (values[k] * v + values[k-1]);
values[0] *= v;
}
- // finally, multiply by the weight in the
- // Lagrange denominator. Could be done instead
- // of setting values[0] = 1 above, but that
- // gives different accumulation of round-off
- // errors (multiplication is not associative)
- // compared to when we computed the weight,
- // and hence a basis function might not be
- // exactly one at the center point, which is
- // nice to have. We also multiply derivatives
- // by k! to transform the product p_n =
- // p^(n)(x)/k! into the actual form of the
- // derivative
+ // finally, multiply by the weight in the Lagrange
+ // denominator. Could be done instead of setting values[0] = 1
+ // above, but that gives different accumulation of round-off
+ // errors (multiplication is not associative) compared to when we
+ // computed the weight, and hence a basis function might not be
+ // exactly one at the center point, which is nice to have. We also
+ // multiply derivatives by k! to transform the product p_n =
+ // p^(n)(x)/k! into the actual form of the derivative
{
number k_faculty = 1;
for (unsigned int k=0; k<values_size; ++k)
}
break;
- // manually implement size 1 (values only),
- // size 2 (value + first derivative), and size
- // 3 (up to second derivative) since they
- // might be called often. then, we can unroll
- // the loop.
+ // manually implement size 1 (values only), size 2 (value + first
+ // derivative), and size 3 (up to second derivative) since they
+ // might be called often. then, we can unroll the loop.
case 1:
values[0] = 1;
for (unsigned int i=0; i<n_supp; ++i)
Assert (coefficients.size() > 0, ExcEmptyObject());
- // if we only need the value, then
- // call the other function since
- // that is significantly faster
- // (there is no need to allocate
- // and free memory, which is really
- // expensive compared to all the
- // other operations!)
+ // if we only need the value, then call the other function since that is
+ // significantly faster (there is no need to allocate and free memory,
+ // which is really expensive compared to all the other operations!)
if (values_size == 1)
{
values[0] = value(x);
return;
};
- // if there are derivatives needed,
- // then do it properly by the
- // full Horner scheme
+ // if there are derivatives needed, then do it properly by the full Horner
+ // scheme
const unsigned int m=coefficients.size();
std::vector<number> a(coefficients);
unsigned int j_faculty=1;
- // loop over all requested
- // derivatives. note that
- // derivatives @p{j>m} are
- // necessarily zero, as they
- // differentiate the polynomial
- // more often than the highest
- // power is
+ // loop over all requested derivatives. note that derivatives @p{j>m} are
+ // necessarily zero, as they differentiate the polynomial more often than
+ // the highest power is
const unsigned int min_valuessize_m=std::min(values_size, m);
for (unsigned int j=0; j<min_valuessize_m; ++j)
{
void
Polynomial<number>::transform_into_standard_form ()
{
- // should only be called when the product form
- // is active
+ // should only be called when the product form is active
Assert (in_lagrange_product_form == true, ExcInternalError());
Assert (coefficients.size() == 0, ExcInternalError());
- // compute coefficients by expanding the
- // product (x-x_i) term by term
+ // compute coefficients by expanding the product (x-x_i) term by term
coefficients.resize (lagrange_support_points.size()+1);
if (lagrange_support_points.size() == 0)
coefficients[0] = 1.;
{
Assert (coefficients.size() == 0, ExcInternalError());
- // For polynomial order up to 3, we have
- // precomputed weights. Use these weights
- // instead of the product form
+ // For polynomial order up to 3, we have precomputed weights. Use these
+ // weights instead of the product form
if (n <= 3)
{
this->in_lagrange_product_form = false;
--- /dev/null
+//---------------------------------------------------------------------------
+// $Id$
+// Version: $Name$
+//
+// Copyright (C) 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2010, 2011, 2012 by the deal.II authors
+//
+// This file is subject to QPL and may not be distributed
+// without copyright and license information. Please refer
+// to the file deal.II/doc/license.html for the text and
+// further information on this license.
+//
+//---------------------------------------------------------------------------
+
+
+#include <deal.II/base/polynomials_piecewise.h>
+
+
+DEAL_II_NAMESPACE_OPEN
+
+
+
+namespace Polynomials
+{
+
+ template <typename number>
+ PiecewisePolynomial<number>::PiecewisePolynomial (const Polynomial<number> &coefficients_on_interval,
+ const unsigned int n_intervals,
+ const unsigned int interval,
+ const bool spans_next_interval)
+ :
+ polynomial (coefficients_on_interval),
+ n_intervals (n_intervals),
+ interval (interval),
+ spans_two_intervals (spans_next_interval)
+ {
+ Assert (n_intervals > 0, ExcMessage ("No intervals given"));
+ AssertIndexRange (interval, n_intervals);
+ }
+
+
+
+ template <typename number>
+ void
+ PiecewisePolynomial<number>::value (const number x,
+ std::vector<number> &values) const
+ {
+ Assert (values.size() > 0, ExcZero());
+ const unsigned int values_size=values.size();
+
+ // shift polynomial if necessary
+ number y = x;
+ double derivative_change_sign = 1.;
+ if (n_intervals > 0)
+ {
+ const number step = 1./n_intervals;
+ // polynomial spans over two intervals
+ if (spans_two_intervals)
+ {
+ const double offset = step * interval;
+ if (x<offset || x>offset+step+step)
+ {
+ for (unsigned int k=0; k<values.size(); ++k)
+ values[k] = 0;
+ return;
+ }
+ else if (x<offset+step)
+ y = x-offset;
+ else
+ {
+ derivative_change_sign = -1.;
+ y = offset+step+step-x;
+ }
+ }
+ else
+ {
+ const double offset = step * interval;
+ if (x<offset || x>offset+step)
+ {
+ for (unsigned int k=0; k<values.size(); ++k)
+ values[k] = 0;
+ return;
+ }
+ else
+ y = x-offset;
+ }
+
+ // on subinterval boundaries, cannot evaluate derivatives properly, so
+ // set them to zero
+ if ((std::abs(y)<1e-14 && (interval > 0 ||
+ derivative_change_sign == -1.))
+ ||
+ (std::abs(y-step)<1e-14 &&
+ (interval < n_intervals-1 || derivative_change_sign == -1.)))
+ {
+ values[0] = value(x);
+ for (unsigned int d=1; d<values_size; ++d)
+ values[d] = 0;
+ return;
+ }
+ }
+
+ polynomial.value(y, values);
+
+ // change sign if necessary
+ for (unsigned int j=1; j<values_size; j+=2)
+ values[j] *= derivative_change_sign;
+ }
+
+
+
+ std::vector<PiecewisePolynomial<double> >
+ generate_complete_Lagrange_basis_on_subdivisions (const unsigned int n_subdivisions,
+ const unsigned int base_degree)
+ {
+ std::vector<Polynomial<double> > p_base =
+ LagrangeEquidistant::generate_complete_basis(base_degree);
+ for (unsigned int i=0; i<p_base.size(); ++i)
+ p_base[i].scale(n_subdivisions);
+
+ std::vector<PiecewisePolynomial<double> > p;
+ p.reserve (n_subdivisions * base_degree + 1);
+
+ p.push_back (PiecewisePolynomial<double> (p_base[0], n_subdivisions, 0,
+ false));
+ for (unsigned int s=0; s<n_subdivisions; ++s)
+ for (unsigned int i=0; i<base_degree; ++i)
+ p.push_back (PiecewisePolynomial<double> (p_base[i+1], n_subdivisions,
+ s,
+ i==(base_degree-1) &&
+ s<n_subdivisions-1));
+ return p;
+ }
+
+}
+
+// ------------------ explicit instantiations --------------- //
+
+namespace Polynomials
+{
+ template class PiecewisePolynomial<float>;
+ template class PiecewisePolynomial<double>;
+ template class PiecewisePolynomial<long double>;
+}
+
+DEAL_II_NAMESPACE_CLOSE
// $Id$
// Version: $Name$
//
-// Copyright (C) 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2009, 2011, 2012 by the deal.II authors
+// Copyright (C) 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2009, 2011, 2012, 2013 by the deal.II authors
//
// This file is subject to QPL and may not be distributed
// without copyright and license information. Please refer
{
// i.e. key is a supercolumn key
const unsigned int n_subcolumns=super_iter->second.size();
- for (unsigned int j=0; j<n_subcolumns; ++j)
+ for (unsigned int k=0; k<n_subcolumns; ++k)
{
- const std::string subkey=super_iter->second[j];
+ const std::string subkey=super_iter->second[k];
Assert(columns.count(subkey), ExcInternalError());
sel_columns.push_back(subkey);
}
#include <deal.II/base/tensor_product_polynomials.h>
+#include <deal.II/base/polynomials_piecewise.h>
#include <deal.II/base/exceptions.h>
#include <deal.II/base/table.h>
/* ------------------- TensorProductPolynomials -------------- */
-template <>
-inline
-void
-TensorProductPolynomials<1>::
-compute_index (const unsigned int i,
- unsigned int (&indices)[1]) const
-{
- Assert (i<polynomials.size(), ExcInternalError());
- indices[0] = index_map[i];
-}
+namespace internal
+{
+ namespace
+ {
+ template <int dim>
+ inline
+ void compute_tensor_index(const unsigned int,
+ const unsigned int,
+ const unsigned int,
+ unsigned int (&)[dim])
+ {
+ Assert(false, ExcNotImplemented());
+ }
+ inline
+ void compute_tensor_index(const unsigned int n,
+ const unsigned int ,
+ const unsigned int ,
+ unsigned int (&indices)[1])
+ {
+ indices[0] = n;
+ }
-template <>
-inline
-void
-TensorProductPolynomials<2>::
-compute_index (const unsigned int i,
- unsigned int (&indices)[2]) const
-{
- const unsigned int n_pols = polynomials.size();
- Assert (i<n_pols*n_pols, ExcInternalError());
- const unsigned int n=index_map[i];
+ inline
+ void compute_tensor_index(const unsigned int n,
+ const unsigned int n_pols_0,
+ const unsigned int ,
+ unsigned int (&indices)[2])
+ {
+ indices[0] = n % n_pols_0;
+ indices[1] = n / n_pols_0;
+ }
- indices[0] = n % n_pols;
- indices[1] = n / n_pols;
+ inline
+ void compute_tensor_index(const unsigned int n,
+ const unsigned int n_pols_0,
+ const unsigned int n_pols_1,
+ unsigned int (&indices)[3])
+ {
+ indices[0] = n % n_pols_0;
+ indices[1] = (n/n_pols_0) % n_pols_1;
+ indices[2] = n / (n_pols_0*n_pols_1);
+ }
+ }
}
-template <>
+template <int dim, typename POLY>
inline
void
-TensorProductPolynomials<3>::
+TensorProductPolynomials<dim,POLY>::
compute_index (const unsigned int i,
- unsigned int (&indices)[3]) const
+ unsigned int (&indices)[(dim > 0 ? dim : 1)]) const
{
- const unsigned int n_pols = polynomials.size();
- Assert (i<n_pols*n_pols*n_pols, ExcInternalError());
- const unsigned int n=index_map[i];
-
- indices[0] = n % n_pols;
- indices[1] = (n/n_pols) % n_pols;
- indices[2] = n / (n_pols*n_pols);
+ Assert (i<Utilities::fixed_power<dim>(polynomials.size()),ExcInternalError());
+ internal::compute_tensor_index(index_map[i], polynomials.size(),
+ polynomials.size(), indices);
}
-template <int dim>
+
+template <int dim, typename POLY>
void
-TensorProductPolynomials<dim>::output_indices(std::ostream &out) const
+TensorProductPolynomials<dim,POLY>::output_indices(std::ostream &out) const
{
unsigned int ix[dim];
for (unsigned int i=0; i<n_tensor_pols; ++i)
-template <int dim>
+template <int dim, typename POLY>
void
-TensorProductPolynomials<dim>::set_numbering(
+TensorProductPolynomials<dim,POLY>::set_numbering(
const std::vector<unsigned int> &renumber)
{
Assert(renumber.size()==index_map.size(),
-template <int dim>
+template <>
+double
+TensorProductPolynomials<0,Polynomials::Polynomial<double> >
+::compute_value(const unsigned int,
+ const Point<0> &) const
+{
+ Assert (false, ExcNotImplemented());
+ return 0;
+}
+
+
+
+template <int dim, typename POLY>
double
-TensorProductPolynomials<dim>::compute_value (const unsigned int i,
- const Point<dim> &p) const
+TensorProductPolynomials<dim,POLY>::compute_value (const unsigned int i,
+ const Point<dim> &p) const
{
+ Assert(dim>0, ExcNotImplemented());
+
unsigned int indices[dim];
compute_index (i, indices);
-template <>
-double
-TensorProductPolynomials<0>::compute_value (const unsigned int ,
- const Point<0> &) const
-{
- Assert (false, ExcNotImplemented());
- return 0.;
-}
-
-
-
-template <int dim>
+template <int dim, typename POLY>
Tensor<1,dim>
-TensorProductPolynomials<dim>::compute_grad (const unsigned int i,
- const Point<dim> &p) const
+TensorProductPolynomials<dim,POLY>::compute_grad (const unsigned int i,
+ const Point<dim> &p) const
{
unsigned int indices[dim];
compute_index (i, indices);
}
-template <int dim>
+
+template <int dim, typename POLY>
Tensor<2,dim>
-TensorProductPolynomials<dim>::compute_grad_grad (const unsigned int i,
- const Point<dim> &p) const
+TensorProductPolynomials<dim,POLY>::compute_grad_grad (const unsigned int i,
+ const Point<dim> &p) const
{
unsigned int indices[dim];
compute_index (i, indices);
-template <int dim>
+template <int dim, typename POLY>
void
-TensorProductPolynomials<dim>::
+TensorProductPolynomials<dim,POLY>::
compute (const Point<dim> &p,
std::vector<double> &values,
std::vector<Tensor<1,dim> > &grads,
-template <int dim>
-unsigned int
-TensorProductPolynomials<dim>::n() const
-{
- return n_tensor_pols;
-}
-
-
-
-template <>
-unsigned int
-TensorProductPolynomials<0>::n() const
-{
- return numbers::invalid_unsigned_int;
-}
-
-
-
/* ------------------- AnisotropicPolynomials -------------- */
-template <>
-void
-AnisotropicPolynomials<1>::
-compute_index (const unsigned int i,
- unsigned int (&indices)[1]) const
-{
- Assert (i<polynomials[0].size(), ExcInternalError());
- indices[0] = i;
-}
-
-
-
-template <>
-void
-AnisotropicPolynomials<2>::
-compute_index (const unsigned int i,
- unsigned int (&indices)[2]) const
-{
- Assert (i < polynomials[0].size()*polynomials[1].size(),
- ExcInternalError());
-
- indices[0] = i % polynomials[0].size();
- indices[1] = i / polynomials[0].size();
-}
-
-
-
-template <>
+template <int dim>
void
-AnisotropicPolynomials<3>::
+AnisotropicPolynomials<dim>::
compute_index (const unsigned int i,
- unsigned int (&indices)[3]) const
+ unsigned int (&indices)[dim]) const
{
- Assert (i < polynomials[0].size()*polynomials[1].size()*polynomials[2].size(),
- ExcInternalError());
+ unsigned int n_poly = 1;
+ for (unsigned int d=0; d<dim; ++d)
+ n_poly *= polynomials[d].size();
+ Assert (i < n_poly, ExcInternalError());
- indices[0] = i % polynomials[0].size();
- indices[1] = (i/polynomials[0].size()) % polynomials[1].size();
- indices[2] = i / (polynomials[0].size()*polynomials[1].size());
+ internal::compute_tensor_index(i, polynomials[0].size(),
+ polynomials[1].size(), indices);
}
/* ------------------- explicit instantiations -------------- */
-template class TensorProductPolynomials<1>;
-template class TensorProductPolynomials<2>;
-template class TensorProductPolynomials<3>;
+template class TensorProductPolynomials<1,Polynomials::Polynomial<double> >;
+template class TensorProductPolynomials<2,Polynomials::Polynomial<double> >;
+template class TensorProductPolynomials<3,Polynomials::Polynomial<double> >;
+
+template class TensorProductPolynomials<1,Polynomials::PiecewisePolynomial<double> >;
+template class TensorProductPolynomials<2,Polynomials::PiecewisePolynomial<double> >;
+template class TensorProductPolynomials<3,Polynomials::PiecewisePolynomial<double> >;
template class AnisotropicPolynomials<1>;
template class AnisotropicPolynomials<2>;
/* ------------------- TensorProductPolynomialsConst -------------- */
-template <>
-inline
-void
-TensorProductPolynomialsConst<1>::
-compute_index (const unsigned int i,
- unsigned int (&indices)[1]) const
-{
- Assert (i<polynomials.size(), ExcInternalError());
- indices[0] = index_map[i];
-}
-
-template <>
-inline
-void
-TensorProductPolynomialsConst<2>::
-compute_index (const unsigned int i,
- unsigned int (&indices)[2]) const
-{
- const unsigned int n_pols = polynomials.size();
- Assert (i<n_pols*n_pols, ExcInternalError());
- const unsigned int n=index_map[i];
-
- indices[0] = n % n_pols;
- indices[1] = n / n_pols;
-}
-
-template <>
-inline
-void
-TensorProductPolynomialsConst<3>::
-compute_index (const unsigned int i,
- unsigned int (&indices)[3]) const
-{
- const unsigned int n_pols = polynomials.size();
- Assert (i<n_pols*n_pols*n_pols, ExcInternalError());
- const unsigned int n=index_map[i];
-
- indices[0] = n % n_pols;
- indices[1] = (n/n_pols) % n_pols;
- indices[2] = n / (n_pols*n_pols);
-}
-
-
-template <int dim>
-void
-TensorProductPolynomialsConst<dim>::output_indices(std::ostream &out) const
-{
- unsigned int ix[dim];
- //ouput without constant locally constant function
- for (unsigned int i=0; i<n_tensor_pols-1; ++i)
- {
- compute_index(i,ix);
- out << i << "\t";
- for (unsigned int d=0; d<dim; ++d)
- out << ix[d] << " ";
- out << std::endl;
- }
-}
-
-
-
-template <int dim>
-void
-TensorProductPolynomialsConst<dim>::set_numbering(
- const std::vector<unsigned int> &renumber)
-{
- Assert(renumber.size()==index_map.size(),
- ExcDimensionMismatch(renumber.size(), index_map.size()));
-
- index_map=renumber;
- for (unsigned int i=0; i<index_map.size(); ++i)
- index_map_inverse[index_map[i]]=i;
-}
template <int dim>
double
TensorProductPolynomialsConst<dim>::compute_value (const unsigned int i,
const Point<dim> &p) const
{
- const unsigned int max_indices = Utilities::fixed_power<dim>(polynomials.size());
-
+ const unsigned int max_indices = this->n_tensor_pols;
Assert (i<=max_indices, ExcInternalError());
// treat the regular basis functions
if (i<max_indices)
- {
- unsigned int indices[dim];
- compute_index (i, indices);
-
- double value=1.;
- for (unsigned int d=0; d<dim; ++d)
- value *= polynomials[indices[d]].value(p(d));
-
- return value;
- }
+ return this->TensorProductPolynomials<dim>::compute_value(i,p);
else
// this is for the constant function
return 1.;
}
+
+
template <>
double
TensorProductPolynomialsConst<0>::compute_value (const unsigned int ,
TensorProductPolynomialsConst<dim>::compute_grad (const unsigned int i,
const Point<dim> &p) const
{
- const unsigned int max_indices = Utilities::fixed_power<dim>(polynomials.size());
-
+ const unsigned int max_indices = this->n_tensor_pols;
Assert (i<=max_indices, ExcInternalError());
// treat the regular basis functions
if (i<max_indices)
- {
- Tensor<1,dim> grad;
-
- unsigned int indices[dim];
- compute_index (i, indices);
-
- // compute values and
- // uni-directional derivatives at
- // the given point in each
- // co-ordinate direction
- double v [dim][2];
- {
- std::vector<double> tmp (2);
- for (unsigned int d=0; d<dim; ++d)
- {
- polynomials[indices[d]].value (p(d), tmp);
- v[d][0] = tmp[0];
- v[d][1] = tmp[1];
- }
- }
-
- for (unsigned int d=0; d<dim; ++d)
- {
- grad[d] = 1.;
- for (unsigned int x=0; x<dim; ++x)
- grad[d] *= v[x][d==x];
- }
-
- return grad; //return 0 for q0 node
- }
+ return this->TensorProductPolynomials<dim>::compute_grad(i,p);
else
// this is for the constant function
return Tensor<1,dim>();
TensorProductPolynomialsConst<dim>::compute_grad_grad (const unsigned int i,
const Point<dim> &p) const
{
- const unsigned int max_indices = Utilities::fixed_power<dim>(polynomials.size());
-
+ const unsigned int max_indices = this->n_tensor_pols;
Assert (i<=max_indices, ExcInternalError());
// treat the regular basis functions
if (i<max_indices)
- {
- Tensor<2,dim> grad_grad;
-
- unsigned int indices[dim];
- compute_index (i, indices);
-
- double v [dim][3];
- {
- std::vector<double> tmp (3);
- for (unsigned int d=0; d<dim; ++d)
- {
- polynomials[indices[d]].value (p(d), tmp);
- v[d][0] = tmp[0];
- v[d][1] = tmp[1];
- v[d][2] = tmp[2];
- }
- }
- for (unsigned int d1=0; d1<dim; ++d1)
- for (unsigned int d2=0; d2<dim; ++d2)
- {
- grad_grad[d1][d2] = 1.;
- for (unsigned int x=0; x<dim; ++x)
- {
- unsigned int derivative=0;
- if (d1==x || d2==x)
- {
- if (d1==d2)
- derivative=2;
- else
- derivative=1;
- }
- grad_grad[d1][d2] *= v[x][derivative];
- }
- }
- return grad_grad; //return 0 for q0 node
- }
+ return this->TensorProductPolynomials<dim>::compute_grad_grad(i,p);
else
// this is for the constant function
return Tensor<2,dim>();
std::vector<Tensor<1,dim> > &grads,
std::vector<Tensor<2,dim> > &grad_grads) const
{
- Assert (values.size()==n_tensor_pols || values.size()==0,
- ExcDimensionMismatch2(values.size(), n_tensor_pols, 0));
- Assert (grads.size()==n_tensor_pols || grads.size()==0,
- ExcDimensionMismatch2(grads.size(), n_tensor_pols, 0));
- Assert (grad_grads.size()==n_tensor_pols|| grad_grads.size()==0,
- ExcDimensionMismatch2(grad_grads.size(), n_tensor_pols, 0));
-
- const bool update_values = (values.size() == n_tensor_pols),
- update_grads = (grads.size()==n_tensor_pols),
- update_grad_grads = (grad_grads.size()==n_tensor_pols);
-
- // check how many
- // values/derivatives we have to
- // compute
- unsigned int n_values_and_derivatives = 0;
- if (update_values)
- n_values_and_derivatives = 1;
- if (update_grads)
- n_values_and_derivatives = 2;
- if (update_grad_grads)
- n_values_and_derivatives = 3;
-
-
- // compute the values (and derivatives, if
- // necessary) of all polynomials at this
- // evaluation point. to avoid many
- // reallocation, use one std::vector for
- // polynomial evaluation and store the
- // result as Tensor<1,3> (that has enough
- // fields for any evaluation of values and
- // derivatives)
- Table<2,Tensor<1,3> > v(dim, polynomials.size()+1);
- {
- std::vector<double> tmp (n_values_and_derivatives);
- for (unsigned int d=0; d<dim; ++d)
- for (unsigned int i=0; i<polynomials.size(); ++i)
- {
- polynomials[i].value(p(d), tmp);
- for (unsigned int e=0; e<n_values_and_derivatives; ++e)
- v(d,i)[e] = tmp[e];
- };
- }
-
- for (unsigned int i=0; i<n_tensor_pols-1; ++i)
+ Assert (values.size()==this->n_tensor_pols+1 || values.size()==0,
+ ExcDimensionMismatch2(values.size(), this->n_tensor_pols+1, 0));
+ Assert (grads.size()==this->n_tensor_pols+1 || grads.size()==0,
+ ExcDimensionMismatch2(grads.size(), this->n_tensor_pols+1, 0));
+ Assert (grad_grads.size()==this->n_tensor_pols+1 || grad_grads.size()==0,
+ ExcDimensionMismatch2(grad_grads.size(), this->n_tensor_pols+1, 0));
+
+ // remove slot for const value, go into the base class compute method and
+ // finally append the const value again
+ bool do_values = false, do_grads = false, do_grad_grads = false;
+ if (values.empty() == false)
{
- // first get the
- // one-dimensional indices of
- // this particular tensor
- // product polynomial
- unsigned int indices[dim];
- compute_index (i, indices);
-
- if (update_values)
- {
- values[i] = 1;
- for (unsigned int x=0; x<dim; ++x)
- values[i] *= v(x,indices[x])[0];
- }
-
- if (update_grads)
- for (unsigned int d=0; d<dim; ++d)
- {
- grads[i][d] = 1.;
- for (unsigned int x=0; x<dim; ++x)
- grads[i][d] *= v(x,indices[x])[d==x];
- }
-
- if (update_grad_grads)
- for (unsigned int d1=0; d1<dim; ++d1)
- for (unsigned int d2=0; d2<dim; ++d2)
- {
- grad_grads[i][d1][d2] = 1.;
- for (unsigned int x=0; x<dim; ++x)
- {
- unsigned int derivative=0;
- if (d1==x || d2==x)
- {
- if (d1==d2)
- derivative=2;
- else
- derivative=1;
- }
- grad_grads[i][d1][d2]
- *= v(x,indices[x])[derivative];
- }
- }
+ values.pop_back();
+ do_values = true;
+ }
+ if (grads.empty() == false)
+ {
+ grads.pop_back();
+ do_grads = true;
+ }
+ if (grad_grads.empty() == false)
+ {
+ grad_grads.pop_back();
+ do_grad_grads = true;
}
- //for dgq node: values =1, grads=0, grads_grads=0
- if (update_values)
- values[n_tensor_pols-1]=1;
-}
-
+ this->TensorProductPolynomials<dim>::compute(p, values, grads, grad_grads);
-template <int dim>
-unsigned int
-TensorProductPolynomialsConst<dim>::n() const
-{
- return n_tensor_pols;
+ //for dgq node: values =1, grads=0, grads_grads=0
+ if (do_values)
+ values.push_back(1.);
+ if (do_grads)
+ grads.push_back(Tensor<1,dim>());
+ if (do_grad_grads)
+ grad_grads.push_back(Tensor<2,dim>());
}
-
-template <>
-unsigned int
-TensorProductPolynomialsConst<0>::n() const
-{
- return numbers::invalid_unsigned_int;
-}
-
/* ------------------- explicit instantiations -------------- */
template class TensorProductPolynomialsConst<1>;
template class TensorProductPolynomialsConst<2>;
static
size_t (&connectivity_memory_used) (types<2>::connectivity *p4est);
+
+ static const unsigned max_level;
};
int (&functions<2>::quadrant_compare) (const void *v1, const void *v2)
size_t (&functions<2>::connectivity_memory_used) (types<2>::connectivity *p4est)
= p4est_connectivity_memory_used;
+ const unsigned int functions<2>::max_level = P4EST_MAXLEVEL;
template <> struct functions<3>
{
static
size_t (&connectivity_memory_used) (types<3>::connectivity *p4est);
+
+ static const unsigned max_level;
};
size_t (&functions<3>::connectivity_memory_used) (types<3>::connectivity *p4est)
= p8est_connectivity_memory_used;
+ const unsigned int functions<3>::max_level = P8EST_MAXLEVEL;
template <int dim>
#endif
+ // safety check: p4est has an upper limit on the level of a cell
+ if (this->n_levels()==dealii::internal::p4est::functions<dim>::max_level)
+ {
+ for (typename Triangulation<dim,spacedim>::active_cell_iterator
+ cell = this->begin_active(dealii::internal::p4est::functions<dim>::max_level-1);
+ cell != this->end(dealii::internal::p4est::functions<dim>::max_level-1); ++cell)
+ {
+ AssertThrow(!(cell->refine_flag_set()),
+ ExcMessage("Fatal Error: maximum refinement level of p4est reached."));
+ }
+ }
+
// now do the work we're
// supposed to do when we are
// in charge
MPI_Isend(&(*buffer)[0], buffer->size(),
MPI_BYTE, it->first,
123, tr->get_communicator(), &requests[idx]);
- std::cout << "send ghostdata: " << tr->locally_owned_subdomain() << "->" << it->first << std::endl;
}
MPI_Get_count(&status, MPI_BYTE, &len);
receive.resize(len);
- std::cout << "receive ghostdata: " << status.MPI_SOURCE << "->" << tr->locally_owned_subdomain() << std::endl;
-
char *ptr = &receive[0];
MPI_Recv(ptr, len, MPI_BYTE, status.MPI_SOURCE, status.MPI_TAG,
tr->get_communicator(), &status);
unsigned int sent=needs_to_get_cells.size();
unsigned int recv=senders.size();
- std::cout << tr->locally_owned_subdomain() << " " << sent << " " << recv << std::endl;
-
MPI_Reduce(&sent, &sum_send, 1, MPI_UNSIGNED, MPI_SUM, 0, tr->get_communicator());
MPI_Reduce(&recv, &sum_recv, 1, MPI_UNSIGNED, MPI_SUM, 0, tr->get_communicator());
Assert(sum_send==sum_recv, ExcInternalError());
for (unsigned int level = 0; level < n_levels; ++level)
{
- std::cout << tr->locally_owned_subdomain() << ": on level " << level << std::endl;
NumberCache &number_cache = number_caches[level];
//* 1. distribute on own
endc = dof_handler.end(level);
for (; cell != endc; ++cell)
- if (!cell->is_artificial() &&
+ if (cell->level_subdomain_id()!=numbers::artificial_subdomain_id &&
(cell->level_subdomain_id() < tr->locally_owned_subdomain()))
{
// we found a
- template<typename FaceIterator>
+ 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
+ template <typename FaceIterator>
+ void
+ set_periodicity_constraints (const FaceIterator &face_1,
+ const typename identity<FaceIterator>::type &face_2,
+ const FullMatrix<double> &transformation,
+ dealii::ConstraintMatrix &constraint_matrix,
+ const ComponentMask &component_mask,
+ const bool face_orientation,
+ const bool face_flip,
+ const bool face_rotation)
+ {
+ static const int dim = FaceIterator::AccessorType::dimension;
+ static const int spacedim = FaceIterator::AccessorType::space_dimension;
+
+ // we should be in the case where face_1 is active, i.e. has no children:
+ Assert (!face_1->has_children(),
+ ExcInternalError());
+
+ Assert (face_1->n_active_fe_indices() == 1,
+ ExcInternalError());
+
+ // if face_2 does have children, then we need to iterate over them
+ if (face_2->has_children())
+ {
+ Assert (face_2->n_children() == GeometryInfo<dim>::max_children_per_face,
+ ExcNotImplemented());
+ const unsigned int dofs_per_face
+ = face_1->get_fe(face_1->nth_active_fe_index(0)).dofs_per_face;
+ FullMatrix<double> child_transformation (dofs_per_face, dofs_per_face);
+ FullMatrix<double> subface_interpolation (dofs_per_face, dofs_per_face);
+ for (unsigned int c=0; c<face_2->n_children(); ++c)
+ {
+ // get the interpolation matrix recursively from the one that
+ // interpolated from face_1 to face_2 by multiplying from the
+ // left with the one that interpolates from face_2 to
+ // its child
+ face_1->get_fe(face_1->nth_active_fe_index(0))
+ .get_subface_interpolation_matrix (face_1->get_fe(face_1->nth_active_fe_index(0)),
+ c,
+ subface_interpolation);
+ subface_interpolation.mmult (child_transformation, transformation);
+ set_periodicity_constraints(face_1, face_2->child(c),
+ child_transformation,
+ constraint_matrix, component_mask,
+ face_orientation, face_flip, face_rotation);
+ }
+ }
+ else
+ // both faces are active. we need to match the corresponding DoFs of both faces
+ {
+ const unsigned int face_1_index = face_1->nth_active_fe_index(0);
+ const unsigned int face_2_index = face_2->nth_active_fe_index(0);
+ Assert(face_1->get_fe(face_1_index) == face_2->get_fe(face_1_index),
+ ExcMessage ("Matching periodic cells need to use the same finite element"));
+
+ const FiniteElement<dim, spacedim> &fe = face_1->get_fe(face_1_index);
+
+ Assert(component_mask.represents_n_components(fe.n_components()),
+ ExcMessage ("The number of components in the mask has to be either "
+ "zero or equal to the number of components in the finite " "element."));
+
+ const unsigned int dofs_per_face = fe.dofs_per_face;
+
+ std::vector<unsigned int> dofs_1(dofs_per_face);
+ std::vector<unsigned int> dofs_2(dofs_per_face);
+
+ face_1->get_dof_indices(dofs_1, face_1_index);
+ face_2->get_dof_indices(dofs_2, face_2_index);
+
+ // Well, this is a hack:
+ //
+ // There is no
+ // face_to_face_index(face_index,
+ // face_orientation,
+ // face_flip,
+ // face_rotation)
+ // function in FiniteElementData, so we have to use
+ // face_to_cell_index(face_index, face
+ // face_orientation,
+ // face_flip,
+ // face_rotation)
+ // But this will give us an index on a cell - something we cannot work
+ // with directly. But luckily we can match them back :-]
+
+ std::map<unsigned int, unsigned int> cell_to_rotated_face_index;
+
+ // Build up a cell to face index for face_2:
+ for (unsigned int i = 0; i < dofs_per_face; ++i)
+ {
+ const unsigned int cell_index = fe.face_to_cell_index(i, 0, /* It doesn't really matter, just assume
+ * we're on the first face...
+ */
+ true, false, false // default orientation
+ );
+ cell_to_rotated_face_index[cell_index] = i;
+ }
+
+ // loop over all dofs on face 2 and constrain them again the ones on face 1
+ for (unsigned int i=0; i<dofs_per_face; ++i)
+ if (!constraint_matrix.is_constrained(dofs_2[i]))
+ if ((component_mask.n_selected_components(fe.n_components())
+ == fe.n_components())
+ ||
+ component_mask[fe.face_system_to_component_index(i).first])
+ {
+ constraint_matrix.add_line(dofs_2[i]);
+ for (unsigned int jj=0; jj<dofs_per_face; ++jj)
+ {
+ // Query the correct face_index on face_2 respecting the given
+ // orientation:
+ const unsigned int j =
+ cell_to_rotated_face_index[fe.face_to_cell_index(jj, 0, /* It doesn't really matter, just assume
+ * we're on the first face...
+ */
+ face_orientation, face_flip, face_rotation)];
+
+ // And finally constrain the two DoFs respecting component_mask:
+ if (transformation(i,j) != 0)
+ constraint_matrix.add_entry(dofs_2[i], dofs_1[j],
+ transformation(i,j));
+ }
+ }
+ }
+ }
+ }
+
+
+ template <typename FaceIterator>
void
make_periodicity_constraints (const FaceIterator &face_1,
const typename identity<FaceIterator>::type &face_2,
face_flip,
face_rotation);
}
- return;
}
-
- // .. otherwise we should be in the case were both faces are active
- // and have no children ..
- Assert (!face_1->has_children() && !face_2->has_children(),
- ExcNotImplemented());
-
- Assert (face_1->n_active_fe_indices() == 1 && face_2->n_active_fe_indices() == 1,
- ExcInternalError());
-
- // .. then we 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 dealii::FiniteElement<dim> &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<unsigned int> dofs_1(dofs_per_face);
- std::vector<unsigned int> dofs_2(dofs_per_face);
-
- face_1->get_dof_indices(dofs_1, face_1_index);
- face_2->get_dof_indices(dofs_2, face_2_index);
-
-
- // Well, this is a hack:
- //
- // There is no
- // face_to_face_index(face_index,
- // face_orientation,
- // face_flip,
- // face_rotation)
- // function in FiniteElementData, so we have to use
- // face_to_cell_index(face_index, face
- // face_orientation,
- // face_flip,
- // face_rotation)
- // But this will give us an index on a cell - something we cannot work
- // with directly. But luckily we can match them back :-]
-
- std::map<unsigned int, unsigned int> cell_to_rotated_face_index;
-
- // Build up a cell to face index for face_2:
- for (unsigned int i = 0; i < dofs_per_face; ++i)
- {
- const unsigned int cell_index =
- fe.face_to_cell_index(i,
- 0, /* It doesn't really matter, just assume
- * we're on the first face...
- */
- true, false, false // default orientation
- );
- cell_to_rotated_face_index[cell_index] = i;
- }
-
- for (unsigned int i = 0; i < dofs_per_face; ++i)
+ else
+ // otherwise at least one of the two faces is active and
+ // we need to enter the constraints
{
- // Query the correct face_index on face_2 respecting the given
- // orientation:
- const unsigned int j =
- cell_to_rotated_face_index[fe.face_to_cell_index(i,
- 0, /* It doesn't really matter, just assume
- * we're on the first face...
- */
- face_orientation,
- face_flip,
- face_rotation)];
-
- // And finally constrain the two DoFs respecting component_mask:
- if (component_mask.n_selected_components(fe.n_components()) == fe.n_components()
- || component_mask[fe.face_system_to_component_index(i).first])
- {
- if (!constraint_matrix.is_constrained(dofs_1[i]))
- {
- constraint_matrix.add_line(dofs_1[i]);
- constraint_matrix.add_entry(dofs_1[i], dofs_2[j], 1.0);
- }
- }
+ if (face_2->has_children() == false)
+ set_periodicity_constraints(face_2, face_1,
+ FullMatrix<double>(IdentityMatrix(face_1->get_fe(face_1->nth_active_fe_index(0)).dofs_per_face)),
+ constraint_matrix,
+ component_mask,
+ face_orientation, face_flip, face_rotation);
+ else
+ set_periodicity_constraints(face_1, face_2,
+ FullMatrix<double>(IdentityMatrix(face_1->get_fe(face_1->nth_active_fe_index(0)).dofs_per_face)),
+ constraint_matrix,
+ component_mask,
+ face_orientation, face_flip, face_rotation);
}
}
fe_poly.cc
fe_poly_tensor.cc
fe_q.cc
+ fe_q_base.cc
fe_q_dg0.cc
fe_q_hierarchical.cc
+ fe_q_iso_q1.cc
fe_raviart_thomas.cc
fe_raviart_thomas_nodal.cc
fe_system.cc
fe_nothing.inst.in
fe_poly.inst.in
fe_poly_tensor.inst.in
+ fe_q_base.inst.in
fe_q_dg0.inst.in
fe_q_hierarchical.inst.in
fe_q.inst.in
+ fe_q_iso_q1.inst.in
fe_raviart_thomas.inst.in
fe_raviart_thomas_nodal.inst.in
fe_system.inst.in
ExcInternalError());
};
- // initialize some tables in the
- // default way, i.e. if there is
- // only one (vector-)component; if
- // the element is not primitive,
- // leave these tables empty.
+ // initialize some tables in the default way, i.e. if there is only one
+ // (vector-)component; if the element is not primitive, leave these tables
+ // empty.
if (this->is_primitive())
{
system_to_component_table.resize(this->dofs_per_cell);
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.
+ // Fill with default value; may be changed by constructor of derived class.
base_to_block_indices.reinit(1,1);
- // initialize the restriction and
- // prolongation matrices. the default
- // contructur of FullMatrix<dim> initializes
- // them with size zero
+ // initialize the restriction and prolongation matrices. the default
+ // contructur of FullMatrix<dim> initializes them with size zero
prolongation.resize(RefinementCase<dim>::isotropic_refinement);
restriction.resize(RefinementCase<dim>::isotropic_refinement);
for (unsigned int ref=RefinementCase<dim>::cut_x;
ExcMessage("Restriction matrices are only available for refined cells!"));
Assert (child<GeometryInfo<dim>::n_children(RefinementCase<dim>(refinement_case)),
ExcIndexRange(child,0,GeometryInfo<dim>::n_children(RefinementCase<dim>(refinement_case))));
- // we use refinement_case-1 here. the -1 takes care
- // of the origin of the vector, as for
- // RefinementCase<dim>::no_refinement (=0) there is no
- // data available and so the vector indices
- // are shifted
+ // we use refinement_case-1 here. the -1 takes care of the origin of the
+ // vector, as for RefinementCase<dim>::no_refinement (=0) there is no data
+ // available and so the vector indices are shifted
Assert (restriction[refinement_case-1][child].n() == this->dofs_per_cell, ExcProjectionVoid());
return restriction[refinement_case-1][child];
}
for (unsigned int c=0;
c<GeometryInfo<dim>::n_children(RefinementCase<dim>(ref_case)); ++c)
{
+ // make sure also the lazily initialized matrices are created
+ get_prolongation_matrix(c, RefinementCase<dim>(ref_case));
Assert ((prolongation[ref_case-1][c].m() == this->dofs_per_cell) ||
(prolongation[ref_case-1][c].m() == 0),
ExcInternalError());
for (unsigned int c=0;
c<GeometryInfo<dim>::n_children(RefinementCase<dim>(ref_case)); ++c)
{
+ // make sure also the lazily initialized matrices are created
+ get_restriction_matrix(c, RefinementCase<dim>(ref_case));
Assert ((restriction[ref_case-1][c].m() == this->dofs_per_cell) ||
(restriction[ref_case-1][c].m() == 0),
ExcInternalError());
for (unsigned int c=0;
c<GeometryInfo<dim>::n_children(RefinementCase<dim>(ref_case)); ++c)
{
+ // make sure also the lazily initialized matrices are created
+ get_prolongation_matrix(c, RefinementCase<dim>(ref_case));
Assert ((prolongation[ref_case-1][c].m() == this->dofs_per_cell) ||
(prolongation[ref_case-1][c].m() == 0),
ExcInternalError());
for (unsigned int c=0;
c<GeometryInfo<dim>::n_children(RefinementCase<dim>(ref_case)); ++c)
{
+ // make sure also the lazily initialized matrices are created
+ get_restriction_matrix(c, RefinementCase<dim>(ref_case));
Assert ((restriction[ref_case-1][c].m() == this->dofs_per_cell) ||
(restriction[ref_case-1][c].m() == 0),
ExcInternalError());
#include <deal.II/base/tensor_product_polynomials.h>
#include <deal.II/base/tensor_product_polynomials_const.h>
#include <deal.II/base/polynomials_p.h>
+#include <deal.II/base/polynomials_piecewise.h>
#include <deal.II/fe/fe_poly.h>
#include <deal.II/fe/fe_values.h>
for (deal_II_dimension : DIMENSIONS; deal_II_space_dimension : SPACE_DIMENSIONS)
{
-#if deal_II_dimension <= deal_II_space_dimension
+#if deal_II_dimension <= deal_II_space_dimension
template class FE_Poly<TensorProductPolynomials<deal_II_dimension>, deal_II_dimension, deal_II_space_dimension>;
template class FE_Poly<TensorProductPolynomialsConst<deal_II_dimension>, deal_II_dimension, deal_II_space_dimension>;
+ template class FE_Poly<TensorProductPolynomials<deal_II_dimension,Polynomials::PiecewisePolynomial<double> >, deal_II_dimension, deal_II_space_dimension>;
template class FE_Poly<PolynomialSpace<deal_II_dimension>, deal_II_dimension, deal_II_space_dimension>;
template class FE_Poly<PolynomialsP<deal_II_dimension>, deal_II_dimension, deal_II_space_dimension>;
#endif
// $Id$
// Version: $Name$
//
-// Copyright (C) 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010, 2011, 2012 by the deal.II authors
+// Copyright (C) 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010, 2011, 2012, 2013 by the deal.II authors
//
// This file is subject to QPL and may not be distributed
// without copyright and license information. Please refer
//
//---------------------------------------------------------------------------
-#include <deal.II/base/quadrature.h>
-#include <deal.II/base/qprojector.h>
-#include <deal.II/base/template_constraints.h>
-#include <deal.II/fe/fe_q.h>
-#include <deal.II/fe/fe_nothing.h>
-#include <deal.II/fe/fe_tools.h>
#include <deal.II/base/quadrature_lib.h>
+#include <deal.II/fe/fe_q.h>
#include <vector>
#include <sstream>
DEAL_II_NAMESPACE_OPEN
-// namespace for some functions that are used in this file. they are
-// specific to numbering conventions used for the FE_Q element, and
-// are thus not very interesting to the outside world. we'd like to
-// simply put them into an anonymous namespace, but that triggers an
-// odd error with icc which can't compile this small snippet if the
-// function is static:
-// --------------------
-// template <int> struct int2type {};
-//
-// namespace {
-// static void SYMBOL (const int2type<1> & ) {}
-// }
-//
-// template <int dim, int spacedim> void g() {
-// SYMBOL(int2type<dim>());
-// }
-//
-// template void g<1>();
-// --------------------
-// the function needs to be static because of another icc bug, though.
-// work around this by packing everything into a namespace of its own
-// and have the anonymous namespace inside
-//
-// this is now intel icc issue 216082
-namespace FE_Q_Helper
-{
- namespace
- {
- // given a permutation array,
- // compute and return the inverse
- // permutation
- inline
- std::vector<unsigned int>
- invert_numbering (const std::vector<unsigned int> &in)
- {
- std::vector<unsigned int> out (in.size());
- for (unsigned int i=0; i<in.size(); ++i)
- out[in[i]]=i;
- return out;
- }
-
-
-
- // in initialize_embedding() and
- // initialize_restriction(), want to undo
- // tensorization on inner loops for
- // performance reasons. this clears a
- // dim-array
- template <int dim>
- inline
- void
- zero_indices (unsigned int indices[dim])
- {
- for (unsigned int d=0; d<dim; ++d)
- indices[d] = 0;
- }
-
-
-
- // in initialize_embedding() and
- // initialize_restriction(), want to undo
- // tensorization on inner loops for
- // performance reasons. this increments tensor
- // product indices
- template <int dim>
- inline
- void
- increment_indices (unsigned int indices[dim],
- const unsigned int dofs1d)
- {
- ++indices[0];
- for (int d=0; d<dim-1; ++d)
- if (indices[d]==dofs1d)
- {
- indices[d] = 0;
- indices[d+1]++;
- }
- }
-
-
-
- // in initialize_embedding() and
- // initialize_restriction(), want to undo
- // tensorization on inner loops for
- // performance reasons, and we need to again
- // access 1D polynomials. This function
- // creates them from dim-dimensional support
- // points.
- template <int dim>
- inline
- std::vector<Polynomials::Polynomial<double> >
- generate_poly_space1d (const std::vector<Point<dim> > &unit_support_points,
- const std::vector<unsigned int> &index_map_inverse,
- const unsigned int dofs1d)
- {
- AssertDimension (Utilities::fixed_power<dim> (dofs1d),
- unit_support_points.size());
- std::vector<Point<1> > points1d (dofs1d);
- for (unsigned int i=0; i<dofs1d; ++i)
- {
- const unsigned int j = index_map_inverse[i];
- points1d[i] = Point<1>(unit_support_points[j](0));
- for (unsigned int d=1; d<dim; ++d)
- Assert (unit_support_points[j][d] == 0.,
- ExcInternalError());
- }
- return Polynomials::generate_complete_Lagrange_basis (points1d);
- }
- }
-}
-
-
-
-/**
- * A class with the same purpose as the similarly named class of the
- * Triangulation class. See there for more information.
- */
-template <int xdim, int xspacedim>
-struct FE_Q<xdim,xspacedim>::Implementation
-{
- /**
- * Initialize the hanging node
- * constraints matrices. Called from the
- * constructor in case the finite element
- * is based on quadrature points.
- */
- template <int spacedim>
- static
- void initialize_constraints (const Quadrature<1> &,
- FE_Q<1,spacedim> &)
- {
- // no constraints in 1d
- }
-
-
- template <int spacedim>
- static
- void initialize_constraints (const Quadrature<1> &points,
- FE_Q<2,spacedim> &fe)
- {
- const unsigned int dim = 2;
-
- // restricted to each face, the
- // traces of the shape functions is
- // an element of P_{k} (in 2d), or
- // Q_{k} (in 3d), where k is the
- // degree of the element. from
- // this, we interpolate between
- // mother and cell face.
-
- // the interpolation process works
- // as follows: on each subface,
- // we want that finite element
- // solutions from both sides
- // coincide. i.e. if a and b are
- // expansion coefficients for the
- // shape functions from both sides,
- // we seek a relation between a and
- // b such that
- // sum_j a_j phi^c_j(x)
- // == sum_j b_j phi_j(x)
- // for all points x on the
- // interface. here, phi^c_j are the
- // shape functions on the small
- // cell on one side of the face,
- // and phi_j those on the big cell
- // on the other side. To get this
- // relation, it suffices to look at
- // a sufficient number of points
- // for which this has to hold. if
- // there are n functions, then we
- // need n evaluation points, and we
- // choose them equidistantly.
- //
- // we obtain the matrix system
- // A a == B b
- // where
- // A_ij = phi^c_j(x_i)
- // B_ij = phi_j(x_i)
- // and the relation we are looking
- // for is
- // a = A^-1 B b
- //
- // for the special case of Lagrange
- // interpolation polynomials, A_ij
- // reduces to delta_ij, and
- // a_i = B_ij b_j
- // Hence,
- // interface_constraints(i,j)=B_ij.
- //
- // for the general case, where we
- // don't have Lagrange
- // interpolation polynomials, this
- // is a little more
- // complicated. Then we would
- // evaluate at a number of points
- // and invert the interpolation
- // matrix A.
- //
- // Note, that we build up these
- // matrices for all subfaces at
- // once, rather than considering
- // them separately. the reason is
- // that we finally will want to
- // have them in this order anyway,
- // as this is the format we need
- // inside deal.II
-
- // In the following the points x_i
- // are constructed in following
- // order (n=degree-1)
- // *----------*---------*
- // 1..n 0 n+1..2n
- // i.e. first the midpoint of the
- // line, then the support points on
- // subface 0 and on subface 1
- std::vector<Point<dim-1> > constraint_points;
- // Add midpoint
- constraint_points.push_back (Point<dim-1> (0.5));
-
- if (fe.degree>1)
- {
- const unsigned int n=fe.degree-1;
- const double step=1./fe.degree;
- // subface 0
- for (unsigned int i=1; i<=n; ++i)
- constraint_points.push_back (
- GeometryInfo<dim-1>::child_to_cell_coordinates(Point<dim-1>(i*step),0));
- // subface 1
- for (unsigned int i=1; i<=n; ++i)
- constraint_points.push_back (
- GeometryInfo<dim-1>::child_to_cell_coordinates(Point<dim-1>(i*step),1));
- }
-
- // Now construct relation between
- // destination (child) and source (mother)
- // dofs.
- const std::vector<Polynomials::Polynomial<double> > polynomials=
- Polynomials::generate_complete_Lagrange_basis(points.get_points());
-
- fe.interface_constraints
- .TableBase<2,double>::reinit (fe.interface_constraints_size());
-
- for (unsigned int i=0; i<constraint_points.size(); ++i)
- for (unsigned int j=0; j<fe.degree+1; ++j)
- {
- fe.interface_constraints(i,j) =
- polynomials[fe.face_index_map[j]].value (constraint_points[i](0));
-
- // if the value is small up
- // to round-off, then
- // simply set it to zero to
- // avoid unwanted fill-in
- // of the constraint
- // matrices (which would
- // then increase the number
- // of other DoFs a
- // constrained DoF would
- // couple to)
- if (std::fabs(fe.interface_constraints(i,j)) < 1e-14)
- fe.interface_constraints(i,j) = 0;
- }
- }
-
-
- template <int spacedim>
- static
- void initialize_constraints (const Quadrature<1> &points,
- FE_Q<3,spacedim> &fe)
- {
- const unsigned int dim = 3;
-
- // For a detailed documentation of
- // the interpolation see the
- // FE_Q<2>::initialize_constraints
- // function.
-
- // In the following the points x_i
- // are constructed in the order as
- // described in the documentation
- // of the FiniteElement class
- // (fe_base.h), i.e.
- // *--15--4--16--*
- // | | |
- // 10 19 6 20 12
- // | | |
- // 1--7---0--8---2
- // | | |
- // 9 17 5 18 11
- // | | |
- // *--13--3--14--*
- std::vector<Point<dim-1> > constraint_points;
-
- // Add midpoint
- constraint_points.push_back (Point<dim-1> (0.5, 0.5));
-
- // Add midpoints of lines of
- // "mother-face"
- constraint_points.push_back (Point<dim-1> (0, 0.5));
- constraint_points.push_back (Point<dim-1> (1, 0.5));
- constraint_points.push_back (Point<dim-1> (0.5, 0));
- constraint_points.push_back (Point<dim-1> (0.5, 1));
-
- if (fe.degree>1)
- {
- const unsigned int n=fe.degree-1;
- const double step=1./fe.degree;
- std::vector<Point<dim-2> > line_support_points(n);
- for (unsigned int i=0; i<n; ++i)
- line_support_points[i](0)=(i+1)*step;
- Quadrature<dim-2> qline(line_support_points);
-
- // auxiliary points in 2d
- std::vector<Point<dim-1> > p_line(n);
-
- // Add nodes of lines interior
- // in the "mother-face"
-
- // line 5: use line 9
- QProjector<dim-1>::project_to_subface(qline, 0, 0, p_line);
- for (unsigned int i=0; i<n; ++i)
- constraint_points.push_back (p_line[i] + Point<dim-1> (0.5, 0));
- // line 6: use line 10
- QProjector<dim-1>::project_to_subface(qline, 0, 1, p_line);
- for (unsigned int i=0; i<n; ++i)
- constraint_points.push_back (p_line[i] + Point<dim-1> (0.5, 0));
- // line 7: use line 13
- QProjector<dim-1>::project_to_subface(qline, 2, 0, p_line);
- for (unsigned int i=0; i<n; ++i)
- constraint_points.push_back (p_line[i] + Point<dim-1> (0, 0.5));
- // line 8: use line 14
- QProjector<dim-1>::project_to_subface(qline, 2, 1, p_line);
- for (unsigned int i=0; i<n; ++i)
- constraint_points.push_back (p_line[i] + Point<dim-1> (0, 0.5));
-
- // DoFs on bordering lines
- // lines 9-16
- for (unsigned int face=0; face<GeometryInfo<dim-1>::faces_per_cell; ++face)
- for (unsigned int subface=0;
- subface<GeometryInfo<dim-1>::max_children_per_face; ++subface)
- {
- QProjector<dim-1>::project_to_subface(qline, face, subface, p_line);
- constraint_points.insert(constraint_points.end(),
- p_line.begin(), p_line.end());
- }
-
- // Create constraints for
- // interior nodes
- std::vector<Point<dim-1> > inner_points(n*n);
- for (unsigned int i=0, iy=1; iy<=n; ++iy)
- for (unsigned int ix=1; ix<=n; ++ix)
- inner_points[i++] = Point<dim-1> (ix*step, iy*step);
-
- // at the moment do this for
- // isotropic face refinement only
- for (unsigned int child=0;
- child<GeometryInfo<dim-1>::max_children_per_cell; ++child)
- for (unsigned int i=0; i<inner_points.size(); ++i)
- constraint_points.push_back (
- GeometryInfo<dim-1>::child_to_cell_coordinates(inner_points[i], child));
- }
-
- // Now construct relation between
- // destination (child) and source (mother)
- // dofs.
- const unsigned int pnts=(fe.degree+1)*(fe.degree+1);
- const std::vector<Polynomials::Polynomial<double> > polynomial_basis=
- Polynomials::generate_complete_Lagrange_basis(points.get_points());
-
- const TensorProductPolynomials<dim-1> face_polynomials(polynomial_basis);
-
- fe.interface_constraints
- .TableBase<2,double>::reinit (fe.interface_constraints_size());
-
- for (unsigned int i=0; i<constraint_points.size(); ++i)
- {
- const double interval = (double) (fe.degree * 2);
- bool mirror[dim - 1];
- Point<dim-1> constraint_point;
-
- // Eliminate FP errors in constraint
- // points. Due to their origin, they
- // must all be fractions of the unit
- // interval. If we have polynomial
- // degree 4, the refined element has 8
- // intervals. Hence the coordinates
- // must be 0, 0.125, 0.25, 0.375 etc.
- // Now the coordinates of the
- // constraint points will be multiplied
- // by the inverse of the interval size
- // (in the example by 8). After that
- // the coordinates must be integral
- // numbers. Hence a normal truncation
- // is performed and the coordinates
- // will be scaled back. The equal
- // treatment of all coordinates should
- // eliminate any FP errors.
- for (unsigned int k=0; k<dim-1; ++k)
- {
- const int coord_int =
- static_cast<int> (constraint_points[i](k) * interval + 0.25);
- constraint_point(k) = 1.*coord_int / interval;
-
- // The following lines of code
- // should eliminate the problems
- // with the Constraint-Matrix,
- // which appeared for P>=4. The
- // Constraint-Matrix class
- // complained about different
- // constraints for the same entry
- // of the Constraint-Matrix.
- // Actually this difference could
- // be attributed to FP errors, as
- // it was in the range of
- // 1.0e-16. These errors originate
- // in the loss of symmetry in the
- // FP approximation of the
- // shape-functions. Considering a
- // 3rd order shape function in 1D,
- // we have N0(x)=N3(1-x) and
- // N1(x)=N2(1-x). For higher order
- // polynomials the FP
- // approximations of the shape
- // functions do not satisfy these
- // equations any more! Thus in the
- // following code everything is
- // computed in the interval x \in
- // [0..0.5], which is sufficient to
- // express all values that could
- // come out from a computation of
- // any shape function in the full
- // interval [0..1]. If x > 0.5 the
- // computation is done for 1-x with
- // the shape function N_{p-n}
- // instead of N_n. Hence symmetry
- // is preserved and everything
- // works fine...
- //
- // For a different explanation of
- // the problem, see the discussion
- // in the FiniteElement class
- // for constraint matrices in 3d.
- mirror[k] = (constraint_point(k) > 0.5);
- if (mirror[k])
- constraint_point(k) = 1.0 - constraint_point(k);
- }
-
- for (unsigned int j=0; j<pnts; ++j)
- {
- unsigned int indices[2]
- = { fe.face_index_map[j] % (fe.degree + 1),
- fe.face_index_map[j] / (fe.degree + 1)
- };
-
- for (unsigned int k = 0; k<2; ++k)
- if (mirror[k])
- indices[k] = fe.degree - indices[k];
-
- const unsigned int
- new_index = indices[1] * (fe.degree + 1) + indices[0];
-
- fe.interface_constraints(i,j) =
- face_polynomials.compute_value (new_index, constraint_point);
-
- // if the value is small up
- // to round-off, then
- // simply set it to zero to
- // avoid unwanted fill-in
- // of the constraint
- // matrices (which would
- // then increase the number
- // of other DoFs a
- // constrained DoF would
- // couple to)
- if (std::fabs(fe.interface_constraints(i,j)) < 1e-14)
- fe.interface_constraints(i,j) = 0;
- }
- }
- }
-};
-
-
-
-
template <int dim, int spacedim>
FE_Q<dim,spacedim>::FE_Q (const unsigned int degree)
:
- FE_Poly<TensorProductPolynomials<dim>, dim, spacedim> (
+ FE_Q_Base<TensorProductPolynomials<dim>, dim, spacedim> (
TensorProductPolynomials<dim>(Polynomials::LagrangeEquidistant::generate_complete_basis(degree)),
- FiniteElementData<dim>(get_dpo_vector(degree),
+ FiniteElementData<dim>(this->get_dpo_vector(degree),
1, degree,
FiniteElementData<dim>::H1),
- std::vector<bool> (1, false),
- std::vector<ComponentMask>(1, std::vector<bool>(1,true))),
- face_index_map(FE_Q_Helper::invert_numbering(face_lexicographic_to_hierarchic_numbering (degree)))
+ std::vector<bool> (1, false))
{
Assert (degree > 0,
ExcMessage ("This element can only be used for polynomial degrees "
"greater than zero"));
+ std::vector<Point<1> > support_points_1d(degree+1);
+ for (unsigned int i=0; i<=degree; ++i)
+ support_points_1d[i][0] = static_cast<double>(i)/degree;
- std::vector<unsigned int> renumber (this->dofs_per_cell);
- FETools::hierarchic_to_lexicographic_numbering (*this, renumber);
- this->poly_space.set_numbering(renumber);
-
- // finally fill in support points
- // on cell and face
- initialize_unit_support_points ();
- initialize_unit_face_support_points ();
-
- // reinit constraints
- initialize_constraints ();
-
- // Reinit the vectors of restriction and
- // prolongation matrices to the right sizes
- // and compute the matrices
- this->reinit_restriction_and_prolongation_matrices();
- initialize_embedding();
- initialize_restriction();
-
- initialize_quad_dof_index_permutation();
+ this->initialize(support_points_1d);
}
template <int dim, int spacedim>
FE_Q<dim,spacedim>::FE_Q (const Quadrature<1> &points)
:
- FE_Poly<TensorProductPolynomials<dim>, dim, spacedim> (
+ FE_Q_Base<TensorProductPolynomials<dim>, dim, spacedim> (
TensorProductPolynomials<dim>(Polynomials::generate_complete_Lagrange_basis(points.get_points())),
- FiniteElementData<dim>(get_dpo_vector(points.size()-1),
+ FiniteElementData<dim>(this->get_dpo_vector(points.size()-1),
1, points.size()-1,
FiniteElementData<dim>::H1),
- std::vector<bool> (1, false),
- std::vector<ComponentMask>(1, std::vector<bool>(1,true))),
- face_index_map(FE_Q_Helper::invert_numbering(face_lexicographic_to_hierarchic_numbering (points.size()-1)))
+ std::vector<bool> (1, false))
{
- const int degree = points.size()-1;
-
+ const unsigned int degree = points.size()-1;
Assert (degree > 0,
ExcMessage ("This element can only be used for polynomial degrees "
"at least zero"));
- Assert (points.point(0)(0) == 0,
- ExcMessage ("The first support point has to be zero."));
- Assert (points.point(degree)(0) == 1,
- ExcMessage ("The last support point has to be one."));
-
- std::vector<unsigned int> renumber (this->dofs_per_cell);
- FETools::hierarchic_to_lexicographic_numbering (*this, renumber);
- this->poly_space.set_numbering(renumber);
-
- // finally fill in support points
- // on cell and face
- initialize_unit_support_points (points);
- initialize_unit_face_support_points (points);
- // reinit constraints
- Implementation::initialize_constraints (points, *this);
-
- // Reinit the vectors of restriction and
- // prolongation matrices to the right sizes
- // and compute the matrices
- this->reinit_restriction_and_prolongation_matrices();
- initialize_embedding();
- initialize_restriction();
-
- initialize_quad_dof_index_permutation();
+ this->initialize(points.get_points());
}
std::string
FE_Q<dim,spacedim>::get_name () const
{
- // note that the
- // FETools::get_fe_from_name
- // function depends on the
- // particular format of the string
- // this function returns, so they
- // have to be kept in synch
+ // note that the FETools::get_fe_from_name function depends on the
+ // particular format of the string this function returns, so they have to be
+ // kept in synch
std::ostringstream namebuf;
bool type = true;
const std::vector<Point<dim> > &unit_support_points = this->unit_support_points;
unsigned int index = 0;
- // Decode the support points
- // in one coordinate direction.
+ // Decode the support points in one coordinate direction.
for (unsigned int j=0; j<dofs_per_cell; j++)
{
if ((dim>1) ? (unit_support_points[j](1)==0 &&
Assert (index == n_points,
ExcMessage ("Could not decode support points in one coordinate direction."));
- // Check whether the support
- // points are equidistant.
+ // Check whether the support points are equidistant.
for (unsigned int j=0; j<n_points; j++)
if (std::fabs(points[j] - (double)j/this->degree) > 1e-15)
{
else
{
- // Check whether the support
- // points come from QGaussLobatto.
+ // Check whether the support points come from QGaussLobatto.
const QGaussLobatto<1> points_gl(n_points);
type = true;
for (unsigned int j=0; j<n_points; j++)
}
-
-template <int dim, int spacedim>
-void
-FE_Q<dim,spacedim>::
-get_interpolation_matrix (const FiniteElement<dim,spacedim> &x_source_fe,
- FullMatrix<double> &interpolation_matrix) const
-{
- // this is only implemented, if the
- // source FE is also a
- // Q element
- typedef FE_Q<dim,spacedim> FEQ;
- typedef FiniteElement<dim,spacedim> FEL;
-
- AssertThrow ((x_source_fe.get_name().find ("FE_Q<") == 0)
- ||
- (dynamic_cast<const FEQ *>(&x_source_fe) != 0),
- typename FEL::
- ExcInterpolationNotImplemented());
-
- 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));
-
- // ok, source is a Q element, so
- // we will be able to do the work
- const FE_Q<dim,spacedim> &source_fe
- = dynamic_cast<const FE_Q<dim,spacedim>&>(x_source_fe);
-
- // compute the interpolation
- // matrices in much the same way as
- // we do for the embedding matrices
- // from mother to child.
- FullMatrix<double> cell_interpolation (this->dofs_per_cell,
- this->dofs_per_cell);
- FullMatrix<double> source_interpolation (this->dofs_per_cell,
- source_fe.dofs_per_cell);
- FullMatrix<double> tmp (this->dofs_per_cell,
- source_fe.dofs_per_cell);
- for (unsigned int j=0; j<this->dofs_per_cell; ++j)
- {
- // read in a point on this
- // cell and evaluate the
- // shape functions there
- const Point<dim> p = this->unit_support_points[j];
- for (unsigned int i=0; i<this->dofs_per_cell; ++i)
- cell_interpolation(j,i) = this->poly_space.compute_value (i, p);
-
- for (unsigned int i=0; i<source_fe.dofs_per_cell; ++i)
- source_interpolation(j,i) = source_fe.poly_space.compute_value (i, p);
- }
-
- // then compute the
- // interpolation matrix
- // for this coordinate
- // direction
- cell_interpolation.gauss_jordan ();
- cell_interpolation.mmult (interpolation_matrix,
- source_interpolation);
-
- const double eps = 2e-13*this->degree*dim;
-
- // cut off very small values
- for (unsigned int i=0; i<this->dofs_per_cell; ++i)
- for (unsigned int j=0; j<source_fe.dofs_per_cell; ++j)
- if (std::fabs(interpolation_matrix(i,j)) < eps)
- interpolation_matrix(i,j) = 0.;
-
- // make sure that the row sum of
- // each of the matrices is 1 at
- // this point. this must be so
- // since the shape functions sum up
- // to 1
- for (unsigned int i=0; i<this->dofs_per_cell; ++i)
- {
- double sum = 0.;
- for (unsigned int j=0; j<source_fe.dofs_per_cell; ++j)
- sum += interpolation_matrix(i,j);
-
- Assert (std::fabs(sum-1) < eps, ExcInternalError());
- }
-}
-
-
-
-template <>
-void
-FE_Q<1>::
-get_face_interpolation_matrix (const FiniteElement<1,1> &/*x_source_fe*/,
- FullMatrix<double> &/*interpolation_matrix*/) const
-{
- Assert (false, ExcImpossibleInDim(1));
-}
-
-
-
-template <>
-void
-FE_Q<1>::
-get_subface_interpolation_matrix (const FiniteElement<1,1> &/*x_source_fe*/,
- const unsigned int /*subface*/,
- FullMatrix<double> &/*interpolation_matrix*/) const
-{
- Assert (false, ExcImpossibleInDim(1));
-}
-
-
-template <>
-void
-FE_Q<1,2>::
-get_face_interpolation_matrix (const FiniteElement<1,2> &/*x_source_fe*/,
- FullMatrix<double> &/*interpolation_matrix*/) const
-{
- typedef FiniteElement<1,2> FEL;
- Assert (false,
- FEL::
- ExcInterpolationNotImplemented ());
-}
-
-
-template <>
-void
-FE_Q<1,2>::
-get_subface_interpolation_matrix (const FiniteElement<1,2> &/*x_source_fe*/,
- const unsigned int /*subface*/,
- FullMatrix<double> &/*interpolation_matrix*/) const
-{
- typedef FiniteElement<1,2> FEL;
- Assert (false,
- FEL::
- ExcInterpolationNotImplemented ());
-}
-
-
-template <>
-void
-FE_Q<1,3>::
-get_face_interpolation_matrix (const FiniteElement<1,3> &/*x_source_fe*/,
- FullMatrix<double> &/*interpolation_matrix*/) const
-{
- typedef FiniteElement<1,3> FEL;
- Assert (false,
- FEL::
- ExcInterpolationNotImplemented ());
-}
-
-
-template <>
-void
-FE_Q<1,3>::
-get_subface_interpolation_matrix (const FiniteElement<1,3> &/*x_source_fe*/,
- const unsigned int /*subface*/,
- FullMatrix<double> &/*interpolation_matrix*/) const
-{
- typedef FiniteElement<1,3> FEL;
- Assert (false,
- FEL::
- ExcInterpolationNotImplemented ());
-}
-
-
-
-template <int dim, int spacedim>
-void
-FE_Q<dim,spacedim>::
-get_face_interpolation_matrix (const FiniteElement<dim,spacedim> &x_source_fe,
- FullMatrix<double> &interpolation_matrix) const
-{
- // this is only implemented, if the
- // source FE is also a
- // Q element
- typedef FE_Q<dim,spacedim> FEQ;
- typedef FiniteElement<dim,spacedim> FEL;
- AssertThrow ((x_source_fe.get_name().find ("FE_Q<") == 0)
- ||
- (dynamic_cast<const FEQ *>(&x_source_fe) != 0),
- typename FEL::
- ExcInterpolationNotImplemented());
-
- Assert (interpolation_matrix.n() == this->dofs_per_face,
- ExcDimensionMismatch (interpolation_matrix.n(),
- this->dofs_per_face));
- Assert (interpolation_matrix.m() == x_source_fe.dofs_per_face,
- ExcDimensionMismatch (interpolation_matrix.m(),
- x_source_fe.dofs_per_face));
-
- // ok, source is a Q element, so
- // we will be able to do the work
- const FE_Q<dim,spacedim> &source_fe
- = dynamic_cast<const FE_Q<dim,spacedim>&>(x_source_fe);
-
- // Make sure, that the element,
- // for which the DoFs should be
- // constrained is the one with
- // the higher polynomial degree.
- // Actually the procedure will work
- // also if this assertion is not
- // satisfied. But the matrices
- // produced in that case might
- // lead to problems in the
- // hp procedures, which use this
- // method.
- Assert (this->dofs_per_face <= source_fe.dofs_per_face,
- typename FEL::
- ExcInterpolationNotImplemented ());
-
- // generate a quadrature
- // with the unit support points.
- // This is later based as a
- // basis for the QProjector,
- // which returns the support
- // points on the face.
- Quadrature<dim-1> quad_face_support (source_fe.get_unit_face_support_points ());
-
- // Rule of thumb for FP accuracy,
- // that can be expected for a
- // given polynomial degree.
- // This value is used to cut
- // off values close to zero.
- const double eps = 2e-13*this->degree*(dim-1);
-
- // compute the interpolation
- // matrix by simply taking the
- // value at the support points.
-//TODO: Verify that all faces are the same with respect to
-// these support points. Furthermore, check if something has to
-// be done for the face orientation flag in 3D.
- const Quadrature<dim> face_quadrature
- = QProjector<dim>::project_to_face (quad_face_support, 0);
- for (unsigned int i=0; i<source_fe.dofs_per_face; ++i)
- {
- const Point<dim> &p = face_quadrature.point (i);
-
- for (unsigned int j=0; j<this->dofs_per_face; ++j)
- {
- double matrix_entry = this->shape_value (this->face_to_cell_index(j, 0), p);
-
- // Correct the interpolated
- // value. I.e. if it is close
- // to 1 or 0, make it exactly
- // 1 or 0. Unfortunately, this
- // is required to avoid problems
- // with higher order elements.
- if (std::fabs (matrix_entry - 1.0) < eps)
- matrix_entry = 1.0;
- if (std::fabs (matrix_entry) < eps)
- matrix_entry = 0.0;
-
- interpolation_matrix(i,j) = matrix_entry;
- }
- }
-
- // make sure that the row sum of
- // each of the matrices is 1 at
- // this point. this must be so
- // since the shape functions sum up
- // to 1
- for (unsigned int j=0; j<source_fe.dofs_per_face; ++j)
- {
- double sum = 0.;
-
- for (unsigned int i=0; i<this->dofs_per_face; ++i)
- sum += interpolation_matrix(j,i);
-
- Assert (std::fabs(sum-1) < 2e-13*this->degree*(dim-1),
- ExcInternalError());
- }
-}
-
-
-
-template <int dim, int spacedim>
-void
-FE_Q<dim,spacedim>::
-get_subface_interpolation_matrix (const FiniteElement<dim,spacedim> &x_source_fe,
- const unsigned int subface,
- FullMatrix<double> &interpolation_matrix) const
-{
- Assert (interpolation_matrix.m() == x_source_fe.dofs_per_face,
- ExcDimensionMismatch (interpolation_matrix.m(),
- x_source_fe.dofs_per_face));
-
- // see if source is a Q element
- if (const FE_Q<dim,spacedim> *source_fe
- = dynamic_cast<const FE_Q<dim,spacedim> *>(&x_source_fe))
- {
- // have this test in here since
- // a table of size 2x0 reports
- // its size as 0x0
- Assert (interpolation_matrix.n() == this->dofs_per_face,
- ExcDimensionMismatch (interpolation_matrix.n(),
- this->dofs_per_face));
-
- // Make sure, that the element,
- // for which the DoFs should be
- // constrained is the one with
- // the higher polynomial degree.
- // Actually the procedure will work
- // also if this assertion is not
- // satisfied. But the matrices
- // produced in that case might
- // lead to problems in the
- // hp procedures, which use this
- // method.
- Assert (this->dofs_per_face <= source_fe->dofs_per_face,
- (typename FiniteElement<dim,spacedim>::
- ExcInterpolationNotImplemented ()));
-
- // generate a point on this
- // cell and evaluate the
- // shape functions there
- const Quadrature<dim-1>
- quad_face_support (source_fe->get_unit_face_support_points ());
-
- // Rule of thumb for FP accuracy,
- // that can be expected for a
- // given polynomial degree.
- // This value is used to cut
- // off values close to zero.
- double eps = 2e-13*this->degree*(dim-1);
-
- // compute the interpolation
- // matrix by simply taking the
- // value at the support points.
-//TODO: Verify that all faces are the same with respect to
-// these support points. Furthermore, check if something has to
-// be done for the face orientation flag in 3D.
- const Quadrature<dim> subface_quadrature
- = QProjector<dim>::project_to_subface (quad_face_support, 0, subface);
- for (unsigned int i=0; i<source_fe->dofs_per_face; ++i)
- {
- const Point<dim> &p = subface_quadrature.point (i);
-
- for (unsigned int j=0; j<this->dofs_per_face; ++j)
- {
- double matrix_entry = this->shape_value (this->face_to_cell_index(j, 0), p);
-
- // Correct the interpolated
- // value. I.e. if it is close
- // to 1 or 0, make it exactly
- // 1 or 0. Unfortunately, this
- // is required to avoid problems
- // with higher order elements.
- if (std::fabs (matrix_entry - 1.0) < eps)
- matrix_entry = 1.0;
- if (std::fabs (matrix_entry) < eps)
- matrix_entry = 0.0;
-
- interpolation_matrix(i,j) = matrix_entry;
- }
- }
-
- // make sure that the row sum of
- // each of the matrices is 1 at
- // this point. this must be so
- // since the shape functions sum up
- // to 1
- for (unsigned int j=0; j<source_fe->dofs_per_face; ++j)
- {
- double sum = 0.;
-
- for (unsigned int i=0; i<this->dofs_per_face; ++i)
- sum += interpolation_matrix(j,i);
-
- Assert (std::fabs(sum-1) < 2e-13*this->degree*dim,
- ExcInternalError());
- }
- }
- else if (dynamic_cast<const FE_Nothing<dim> *>(&x_source_fe) != 0)
- {
- // nothing to do here, the
- // FE_Nothing has no degrees of
- // freedom anyway
- }
- else
- AssertThrow (false,
- (typename FiniteElement<dim,spacedim>::
- ExcInterpolationNotImplemented()));
-}
-
-
-
-template <int dim, int spacedim>
-bool
-FE_Q<dim,spacedim>::hp_constraints_are_implemented () const
-{
- return true;
-}
-
-
-
-
-template <int dim, int spacedim>
-std::vector<std::pair<unsigned int, unsigned int> >
-FE_Q<dim,spacedim>::
-hp_vertex_dof_identities (const FiniteElement<dim,spacedim> &fe_other) const
-{
- // we can presently only compute
- // these identities if both FEs are
- // FE_Qs or if the other one is an
- // FE_Nothing. in the first case,
- // there should be exactly one
- // single DoF of each FE at a
- // vertex, and they should have
- // identical value
- if (dynamic_cast<const FE_Q<dim,spacedim>*>(&fe_other) != 0)
- {
- return
- std::vector<std::pair<unsigned int, unsigned int> >
- (1, std::make_pair (0U, 0U));
- }
- else if (dynamic_cast<const FE_Nothing<dim>*>(&fe_other) != 0)
- {
- // the FE_Nothing has no
- // degrees of freedom, so there
- // are no equivalencies to be
- // recorded
- return std::vector<std::pair<unsigned int, unsigned int> > ();
- }
- else
- {
- Assert (false, ExcNotImplemented());
- return std::vector<std::pair<unsigned int, unsigned int> > ();
- }
-}
-
-
-
-template <int dim, int spacedim>
-std::vector<std::pair<unsigned int, unsigned int> >
-FE_Q<dim,spacedim>::
-hp_line_dof_identities (const FiniteElement<dim,spacedim> &fe_other) const
-{
- // we can presently only compute
- // these identities if both FEs are
- // FE_Qs or if the other one is an
- // FE_Nothing
- if (const FE_Q<dim,spacedim> *fe_q_other = dynamic_cast<const FE_Q<dim,spacedim>*>(&fe_other))
- {
- // dofs are located along lines, so two
- // dofs are identical if they are
- // located at identical positions. if
- // we had only equidistant points, we
- // could simple check for similarity
- // like (i+1)*q == (j+1)*p, but we
- // might have other support points
- // (e.g. Gauss-Lobatto
- // points). Therefore, read the points
- // in unit_support_points for the first
- // coordinate direction. We take the
- // lexicographic ordering of the points
- // in the first direction (i.e.,
- // x-direction), which we access
- // between index 1 and p-1 (index 0 and
- // p are vertex dofs).
- const unsigned int p = this->degree;
- const unsigned int q = fe_q_other->degree;
-
- std::vector<std::pair<unsigned int, unsigned int> > identities;
-
- const std::vector<unsigned int> &index_map_inverse=
- this->poly_space.get_numbering_inverse();
- const std::vector<unsigned int> &index_map_inverse_other=
- fe_q_other->poly_space.get_numbering_inverse();
-
- for (unsigned int i=0; i<p-1; ++i)
- for (unsigned int j=0; j<q-1; ++j)
- if (std::fabs(this->unit_support_points[index_map_inverse[i+1]][0]-
- fe_q_other->unit_support_points[index_map_inverse_other[j+1]][0])
- < 1e-14)
- identities.push_back (std::make_pair(i,j));
-
- return identities;
- }
- else if (dynamic_cast<const FE_Nothing<dim>*>(&fe_other) != 0)
- {
- // the FE_Nothing has no
- // degrees of freedom, so there
- // are no equivalencies to be
- // recorded
- return std::vector<std::pair<unsigned int, unsigned int> > ();
- }
- else
- {
- Assert (false, ExcNotImplemented());
- return std::vector<std::pair<unsigned int, unsigned int> > ();
- }
-}
-
-
-
-template <int dim, int spacedim>
-std::vector<std::pair<unsigned int, unsigned int> >
-FE_Q<dim,spacedim>::
-hp_quad_dof_identities (const FiniteElement<dim,spacedim> &fe_other) const
-{
- // we can presently only compute
- // these identities if both FEs are
- // FE_Qs or if the other one is an
- // FE_Nothing
- if (const FE_Q<dim,spacedim> *fe_q_other = dynamic_cast<const FE_Q<dim,spacedim>*>(&fe_other))
- {
- // this works exactly like the line
- // case above, except that now we have
- // to have two indices i1, i2 and j1,
- // j2 to characterize the dofs on the
- // face of each of the finite
- // elements. since they are ordered
- // lexicographically along the first
- // line and we have a tensor product,
- // the rest is rather straightforward
- const unsigned int p = this->degree;
- const unsigned int q = fe_q_other->degree;
-
- std::vector<std::pair<unsigned int, unsigned int> > identities;
-
- const std::vector<unsigned int> &index_map_inverse=
- this->poly_space.get_numbering_inverse();
- const std::vector<unsigned int> &index_map_inverse_other=
- fe_q_other->poly_space.get_numbering_inverse();
-
- for (unsigned int i1=0; i1<p-1; ++i1)
- for (unsigned int i2=0; i2<p-1; ++i2)
- for (unsigned int j1=0; j1<q-1; ++j1)
- for (unsigned int j2=0; j2<q-1; ++j2)
- if ((std::fabs(this->unit_support_points[index_map_inverse[i1+1]][0]-
- fe_q_other->unit_support_points[index_map_inverse_other[j1+1]][0])
- < 1e-14)
- &&
- (std::fabs(this->unit_support_points[index_map_inverse[i2+1]][0]-
- fe_q_other->unit_support_points[index_map_inverse_other[j2+1]][0])
- < 1e-14))
- identities.push_back (std::make_pair(i1*(p-1)+i2,
- j1*(q-1)+j2));
-
- return identities;
- }
- else if (dynamic_cast<const FE_Nothing<dim>*>(&fe_other) != 0)
- {
- // the FE_Nothing has no
- // degrees of freedom, so there
- // are no equivalencies to be
- // recorded
- return std::vector<std::pair<unsigned int, unsigned int> > ();
- }
- else
- {
- Assert (false, ExcNotImplemented());
- return std::vector<std::pair<unsigned int, unsigned int> > ();
- }
-}
-
-
-
-template <int dim, int spacedim>
-FiniteElementDomination::Domination
-FE_Q<dim,spacedim>::
-compare_for_face_domination (const FiniteElement<dim,spacedim> &fe_other) const
-{
- if (const FE_Q<dim,spacedim> *fe_q_other
- = dynamic_cast<const FE_Q<dim,spacedim>*>(&fe_other))
- {
- if (this->degree < fe_q_other->degree)
- return FiniteElementDomination::this_element_dominates;
- else if (this->degree == fe_q_other->degree)
- return FiniteElementDomination::either_element_can_dominate;
- else
- return FiniteElementDomination::other_element_dominates;
- }
- else if (dynamic_cast<const FE_Nothing<dim>*>(&fe_other) != 0)
- {
- // the FE_Nothing has no
- // degrees of freedom and it is
- // typically used in a context
- // where we don't require any
- // continuity along the
- // interface
- return FiniteElementDomination::no_requirements;
- }
-
- Assert (false, ExcNotImplemented());
- return FiniteElementDomination::neither_element_dominates;
-}
-
-
-//---------------------------------------------------------------------------
-// Auxiliary functions
-//---------------------------------------------------------------------------
-
-
-
-template <int dim, int spacedim>
-void FE_Q<dim,spacedim>::initialize_unit_support_points ()
-{
- // number of points: (degree+1)^dim
- unsigned int n = this->degree+1;
- for (unsigned int i=1; i<dim; ++i)
- n *= this->degree+1;
-
- this->unit_support_points.resize(n);
-
- const std::vector<unsigned int> &index_map_inverse=
- this->poly_space.get_numbering_inverse();
-
- const double step = 1./this->degree;
- Point<dim> p;
-
- unsigned int k=0;
- for (unsigned int iz=0; iz <= ((dim>2) ? this->degree : 0) ; ++iz)
- for (unsigned int iy=0; iy <= ((dim>1) ? this->degree : 0) ; ++iy)
- for (unsigned int ix=0; ix<=this->degree; ++ix)
- {
- p(0) = ix * step;
- if (dim>1)
- p(1) = iy * step;
- if (dim>2)
- p(2) = iz * step;
-
- this->unit_support_points[index_map_inverse[k++]] = p;
- }
-}
-
-
-
-template <int dim, int spacedim>
-void FE_Q<dim,spacedim>::initialize_unit_support_points (const Quadrature<1> &points)
-{
- // number of points: (degree+1)^dim
- unsigned int n = this->degree+1;
- for (unsigned int i=1; i<dim; ++i)
- n *= this->degree+1;
-
- this->unit_support_points.resize(n);
-
- const std::vector<unsigned int> &index_map_inverse=
- this->poly_space.get_numbering_inverse();
-
- Quadrature<dim> support_quadrature(points);
-
- Point<dim> p;
-
- for (unsigned int k=0; k<n ; k++)
- {
- this->unit_support_points[index_map_inverse[k]] = support_quadrature.point(k);
- }
-}
-
-
-
-template <>
-void FE_Q<1>::initialize_unit_face_support_points ()
-{
- // no faces in 1d, so nothing to do
-}
-
-template <>
-void FE_Q<1>::initialize_unit_face_support_points (const Quadrature<1> &/*points*/)
-{
- // no faces in 1d, so nothing to do
-}
-
-template <>
-void FE_Q<1,2>::initialize_unit_face_support_points ()
-{
- // no faces in 1d, so nothing to do
-}
-
-template <>
-void FE_Q<1,2>::initialize_unit_face_support_points (const Quadrature<1> &/*points*/)
-{
- // no faces in 1d, so nothing to do
-}
-
-template <>
-void FE_Q<1,3>::initialize_unit_face_support_points ()
-{
- // no faces in 1d, so nothing to do
-}
-
-template <>
-void FE_Q<1,3>::initialize_unit_face_support_points (const Quadrature<1> &/*points*/)
-{
- // no faces in 1d, so nothing to do
-}
-
-template <int dim, int spacedim>
-void FE_Q<dim,spacedim>::initialize_unit_face_support_points ()
-{
- const unsigned int codim = dim-1;
- this->unit_face_support_points.resize(Utilities::fixed_power<codim>(this->degree+1));
-
- const std::vector<unsigned int> &face_index_map_inverse=
- FE_Q_Helper::invert_numbering(face_index_map);
-
- const double step = 1./this->degree;
- Point<codim> p;
-
- unsigned int k=0;
- for (unsigned int iz=0; iz <= ((codim>2) ? this->degree : 0) ; ++iz)
- for (unsigned int iy=0; iy <= ((codim>1) ? this->degree : 0) ; ++iy)
- for (unsigned int ix=0; ix<=this->degree; ++ix)
- {
- p(0) = ix * step;
- if (codim>1)
- p(1) = iy * step;
- if (codim>2)
- p(2) = iz * step;
-
- this->unit_face_support_points[face_index_map_inverse[k++]] = p;
- }
-}
-
-
-
-template <int dim, int spacedim>
-void FE_Q<dim,spacedim>::initialize_unit_face_support_points (const Quadrature<1> &points)
-{
- const unsigned int codim = dim-1;
- this->unit_face_support_points.resize(Utilities::fixed_power<codim>(this->degree+1));
-
- const std::vector< Point<1> > &edge = points.get_points();
-
- const std::vector<unsigned int> &face_index_map_inverse=
- FE_Q_Helper::invert_numbering(face_index_map);
-
- Point<codim> p;
-
- unsigned int k=0;
- for (unsigned int iz=0; iz <= ((codim>2) ? this->degree : 0) ; ++iz)
- for (unsigned int iy=0; iy <= ((codim>1) ? this->degree : 0) ; ++iy)
- for (unsigned int ix=0; ix<=this->degree; ++ix)
- {
- p(0) = edge[ix](0);
- if (codim>1)
- p(1) = edge[iy](0);
- if (codim>2)
- p(2) = edge[iz](0);
-
- this->unit_face_support_points[face_index_map_inverse[k++]] = p;
- }
-}
-
-
-
-template <int dim, int spacedim>
-void
-FE_Q<dim,spacedim>::initialize_quad_dof_index_permutation ()
-{
- // general template for 1D and 2D, do nothing
-}
-
-
-
-template <>
-void
-FE_Q<3>::initialize_quad_dof_index_permutation ()
-{
- Assert (adjust_quad_dof_index_for_face_orientation_table.n_elements()==8*this->dofs_per_quad,
- ExcInternalError());
-
- const unsigned int n=this->degree-1;
- Assert(n*n==this->dofs_per_quad, ExcInternalError());
-
- // alias for the table to fill
- Table<2,int> &data=this->adjust_quad_dof_index_for_face_orientation_table;
-
- // the dofs on a face are connected to a n x
- // n matrix. for example, for degree==4 we
- // have the following dofs on a quad
-
- // ___________
- // | |
- // | 6 7 8 |
- // | |
- // | 3 4 5 |
- // | |
- // | 0 1 2 |
- // |___________|
- //
- // we have dof_no=i+n*j with index i in
- // x-direction and index j in y-direction
- // running from 0 to n-1. to extract i and j
- // we can use i=dof_no%n and j=dof_no/n. i
- // and j can then be used to construct the
- // rotated and mirrored numbers.
-
-
- for (unsigned int local=0; local<this->dofs_per_quad; ++local)
- // face support points are in lexicographic
- // ordering with x running fastest. invert
- // that (y running fastest)
- {
- unsigned int i=local%n,
- j=local/n;
-
- // face_orientation=false, face_flip=false, face_rotation=false
- data(local,0)=j + i *n - local;
- // face_orientation=false, face_flip=false, face_rotation=true
- data(local,1)=i + (n-1-j)*n - local;
- // face_orientation=false, face_flip=true, face_rotation=false
- data(local,2)=(n-1-j) + (n-1-i)*n - local;
- // face_orientation=false, face_flip=true, face_rotation=true
- data(local,3)=(n-1-i) + j *n - local;
- // face_orientation=true, face_flip=false, face_rotation=false
- data(local,4)=0;
- // face_orientation=true, face_flip=false, face_rotation=true
- data(local,5)=j + (n-1-i)*n - local;
- // face_orientation=true, face_flip=true, face_rotation=false
- data(local,6)=(n-1-i) + (n-1-j)*n - local;
- // face_orientation=true, face_flip=true, face_rotation=true
- data(local,7)=(n-1-j) + i *n - local;
- }
-
- // aditionally initialize reordering of line
- // dofs
- for (unsigned int i=0; i<this->dofs_per_line; ++i)
- this->adjust_line_dof_index_for_line_orientation_table[i]=this->dofs_per_line-1-i - i;
-}
-
-
-
-
-template <int dim, int spacedim>
-std::vector<unsigned int>
-FE_Q<dim,spacedim>::get_dpo_vector(const unsigned int deg)
-{
- std::vector<unsigned int> dpo(dim+1, 1U);
- for (unsigned int i=1; i<dpo.size(); ++i)
- dpo[i]=dpo[i-1]*(deg-1);
- return dpo;
-}
-
-
-template <int dim, int spacedim>
-std::vector<unsigned int>
-FE_Q<dim,spacedim>::face_lexicographic_to_hierarchic_numbering (const unsigned int degree)
-{
- const FiniteElementData<dim-1> face_data(FE_Q<dim-1>::get_dpo_vector(degree),1,degree);
- std::vector<unsigned int> face_renumber (face_data.dofs_per_cell);
- FETools::lexicographic_to_hierarchic_numbering (face_data, face_renumber);
- return face_renumber;
-}
-
-
-
-template <>
-std::vector<unsigned int>
-FE_Q<1>::face_lexicographic_to_hierarchic_numbering (const unsigned int)
-{
- return std::vector<unsigned int>();
-}
-
-template <>
-std::vector<unsigned int>
-FE_Q<1,2>::face_lexicographic_to_hierarchic_numbering (const unsigned int)
-{
- return std::vector<unsigned int>();
-}
-
-
-template <>
-std::vector<unsigned int>
-FE_Q<1,3>::face_lexicographic_to_hierarchic_numbering (const unsigned int)
-{
- return std::vector<unsigned int>();
-}
-
-
-template <int dim, int spacedim>
-void
-FE_Q<dim,spacedim>::initialize_constraints ()
-{
- QTrapez<1> trapez;
- QIterated<1> points (trapez,this->degree);
- Implementation::initialize_constraints (points, *this);
-}
-
-
-
-template <int dim, int spacedim>
-void
-FE_Q<dim,spacedim>::initialize_embedding ()
-{
- // compute the interpolation matrices in
- // much the same way as we do for the
- // constraints. it's actually simpler
- // here, since we don't have this weird
- // renumbering stuff going on. The trick
- // is again that we the interpolation
- // matrix is formed by a permutation of
- // the indices of the cell matrix. The
- // value eps is used a threshold to
- // decide when certain evaluations of the
- // Lagrange polynomials are zero or one.
- const double eps = 1e-15*this->degree*dim;
-
-#ifdef DEBUG
- // in DEBUG mode, check that the evaluation of
- // support points in the current numbering
- // gives the identity operation
- for (unsigned int i=0; i<this->dofs_per_cell; ++i)
- {
- Assert (std::fabs (1.-this->poly_space.compute_value
- (i, this->unit_support_points[i])) < eps,
- ExcInternalError());
- for (unsigned int j=0; j<this->dofs_per_cell; ++j)
- if (j!=i)
- Assert (std::fabs (this->poly_space.compute_value
- (i, this->unit_support_points[j])) < eps,
- ExcInternalError());
- }
-#endif
-
- // to efficiently evaluate the polynomial at
- // the subcell, make use of the tensor product
- // structure of this element and only evaluate
- // 1D information from the polynomial. This
- // makes the cost of this function almost
- // negligible also for high order elements
- const unsigned int dofs1d = this->degree+1;
- std::vector<Table<2,double> >
- subcell_evaluations (dim, Table<2,double>(dofs1d, dofs1d));
- const std::vector<unsigned int> &index_map_inverse =
- this->poly_space.get_numbering_inverse();
-
- // recreate 1D polynomials
- std::vector<Polynomials::Polynomial<double> > poly_space1d =
- FE_Q_Helper::generate_poly_space1d (this->unit_support_points,
- index_map_inverse, dofs1d);
-
- // helper value: step size how to walk through
- // diagonal and how many points we have left
- // apart from the first dimension
- unsigned int step_size_diag = 0;
- {
- unsigned int factor = 1;
- for (unsigned int d=0; d<dim; ++d)
- {
- step_size_diag += factor;
- factor *= dofs1d;
- }
- }
-
- // next evaluate the functions
- // for the different refinement
- // cases.
- for (unsigned int ref=0; ref<RefinementCase<dim>::isotropic_refinement; ++ref)
- for (unsigned int child=0; child<GeometryInfo<dim>::n_children(RefinementCase<dim>(ref+1)); ++child)
- {
- // go through the points in diagonal to
- // capture variation in all directions
- // simultaneously
- for (unsigned int j=0; j<dofs1d; ++j)
- {
- const unsigned int diag_comp = index_map_inverse[j*step_size_diag];
- const Point<dim> p_subcell = this->unit_support_points[diag_comp];
- const Point<dim> p_cell =
- GeometryInfo<dim>::child_to_cell_coordinates (p_subcell, child,
- RefinementCase<dim>(ref+1));
- for (unsigned int i=0; i<dofs1d; ++i)
- for (unsigned int d=0; d<dim; ++d)
- {
- const double cell_value = poly_space1d[i].value (p_cell[d]);
-
- // cut off values that are too
- // small. note that we have here Lagrange
- // interpolation functions, so they
- // should be zero at almost all points,
- // and one at the others, at least on the
- // subcells. so set them to their exact
- // values
- //
- // the actual cut-off value is somewhat
- // fuzzy, but it works for
- // 2e-13*degree*dim (see above), which
- // is kind of reasonable given that we
- // compute the values of the polynomials
- // via an degree-step recursion and then
- // multiply the 1d-values. this gives us
- // a linear growth in degree*dim, times a
- // small constant.
- //
- // the embedding matrix is given by
- // applying the inverse of the subcell
- // matrix on the cell_interpolation
- // matrix. since the subcell matrix is
- // actually only a permutation vector,
- // all we need to do is to switch the
- // rows we write the data into. moreover,
- // cut off very small values here
- if (std::fabs(cell_value) < eps)
- subcell_evaluations[d](j,i) = 0;
- else
- subcell_evaluations[d](j,i) = cell_value;
- }
- }
-
- // now expand from 1D info. block innermost
- // dimension (x_0) in order to avoid difficult
- // checks at innermost loop
- unsigned int j_indices[dim];
- FE_Q_Helper::zero_indices<dim> (j_indices);
- for (unsigned int j=0; j<this->dofs_per_cell; j+=dofs1d)
- {
- unsigned int i_indices[dim];
- FE_Q_Helper::zero_indices<dim> (i_indices);
- for (unsigned int i=0; i<this->dofs_per_cell; i+=dofs1d)
- {
- double val_extra_dim = 1.;
- for (unsigned int d=1; d<dim; ++d)
- val_extra_dim *= subcell_evaluations[d](j_indices[d-1],
- i_indices[d-1]);
-
- // innermost sum where we actually
- // compute. the same as
- // this->prolongation[ref][child](j,i) =
- // this->poly_space.compute_value (i, p_cell);
- for (unsigned int jj=0; jj<dofs1d; ++jj)
- {
- const unsigned int j_ind = index_map_inverse[j+jj];
- for (unsigned int ii=0; ii<dofs1d; ++ii)
- this->prolongation[ref][child](j_ind,index_map_inverse[i+ii])
- = val_extra_dim * subcell_evaluations[0](jj,ii);
- }
-
- // update indices that denote the tensor
- // product position. a bit fuzzy and therefore
- // not done for innermost x_0 direction
- FE_Q_Helper::increment_indices<dim> (i_indices, dofs1d);
- }
- Assert (i_indices[dim-1] == 1, ExcInternalError());
- FE_Q_Helper::increment_indices<dim> (j_indices, dofs1d);
- }
-
- // and make sure that the row sum is
- // 1. this must be so since for this
- // element, the shape functions add up to
- // one
-#ifdef DEBUG
- for (unsigned int row=0; row<this->dofs_per_cell; ++row)
- {
- double sum = 0;
- for (unsigned int col=0; col<this->dofs_per_cell; ++col)
- sum += this->prolongation[ref][child](row,col);
- Assert (std::fabs(sum-1.) < eps, ExcInternalError());
- }
-#endif
- }
-}
-
-
-
-template <int dim, int spacedim>
-void
-FE_Q<dim,spacedim>::initialize_restriction ()
-{
- // for these Lagrange interpolation
- // polynomials, construction of the
- // restriction matrices is relatively
- // simple. the reason is that the
- // interpolation points on the mother cell
- // are (except for the case with arbitrary
- // nonequidistant nodes) always also
- // interpolation points for some shape
- // function on one or the other child,
- // because we have chosen equidistant
- // Lagrange interpolation points for the
- // polynomials
- //
- // so the only thing we have to
- // find out is: for each shape
- // function on the mother cell,
- // which is the child cell
- // (possibly more than one) on
- // which it is located, and which
- // is the corresponding shape
- // function there. rather than
- // doing it for the shape functions
- // on the mother cell, we take the
- // interpolation points there
- //
- // note that the interpolation
- // point of a shape function can be
- // on the boundary between
- // subcells. in that case,
- // restriction from children to
- // mother may produce two or more
- // entries for a dof on the mother
- // cell. however, this doesn't
- // hurt: since the element is
- // continuous, the contribution
- // from each child should yield the
- // same result, and since the
- // element is non-additive we just
- // overwrite one value (compute one
- // one child) by the same value
- // (compute on a later child), so
- // we don't have to care about this
-
- const double eps = 1e-15*this->degree*dim;
- const std::vector<unsigned int> &index_map_inverse =
- this->poly_space.get_numbering_inverse();
-
- // recreate 1D polynomials for faster
- // evaluation of polynomial
- const unsigned int dofs1d = this->degree+1;
- std::vector<Polynomials::Polynomial<double> > poly_space1d =
- FE_Q_Helper::generate_poly_space1d (this->unit_support_points,
- index_map_inverse, dofs1d);
- std::vector<Tensor<1,dim> > evaluations1d (dofs1d);
-
- for (unsigned int i=0; i<this->dofs_per_cell; ++i)
- {
- unsigned int mother_dof = index_map_inverse[i];
- const Point<dim> p_cell = this->unit_support_points[mother_dof];
-
- // then find the children on
- // which the interpolation
- // point is located
- for (unsigned int ref=RefinementCase<dim>::cut_x; ref<=RefinementCase<dim>::isotropic_refinement; ++ref)
- for (unsigned int child=0; child<GeometryInfo<dim>::n_children(RefinementCase<dim>(ref)); ++child)
- {
- // check whether this
- // interpolation point is
- // inside this child cell
- const Point<dim> p_subcell
- = GeometryInfo<dim>::cell_to_child_coordinates (p_cell, child, RefinementCase<dim>(ref));
- if (GeometryInfo<dim>::is_inside_unit_cell (p_subcell))
- {
- // same logic as in initialize_embedding to
- // evaluate the polynomial faster than from
- // the tensor product: since we evaluate all
- // polynomials, it is much faster to just
- // compute the 1D values for all polynomials
- // before and then get the dim-data.
- for (unsigned int j=0; j<dofs1d; ++j)
- for (unsigned int d=0; d<dim; ++d)
- evaluations1d[j][d] = poly_space1d[j].value (p_subcell[d]);
- unsigned int j_indices[dim];
- FE_Q_Helper::zero_indices<dim> (j_indices);
- double sum_check = 0;
- for (unsigned int j = 0; j<this->dofs_per_cell; j += dofs1d)
- {
- double val_extra_dim = 1.;
- for (unsigned int d=1; d<dim; ++d)
- val_extra_dim *= evaluations1d[j_indices[d-1]][d];
- for (unsigned int jj=0; jj<dofs1d; ++jj)
- {
-
- // find the child shape
- // function(s) corresponding
- // to this point. Usually
- // this is just one function;
- // however, when we use FE_Q
- // on arbitrary nodes a
- // parent support point might
- // not be a child support
- // point, and then we will
- // get more than one nonzero
- // value per row. Still, the
- // values should sum up to 1
- const double val
- = val_extra_dim * evaluations1d[jj][0];
- const unsigned int child_dof =
- index_map_inverse[j+jj];
- if (std::fabs (val-1.) < eps)
- this->restriction[ref-1][child](mother_dof,child_dof)=1.;
- else if (std::fabs(val) > eps)
- this->restriction[ref-1][child](mother_dof,child_dof)=val;
- sum_check += val;
- }
- FE_Q_Helper::increment_indices<dim> (j_indices, dofs1d);
- }
- Assert (std::fabs(sum_check-1) < eps,
- ExcInternalError());
- }
- }
- }
-}
-
-
-
-//---------------------------------------------------------------------------
-// Data field initialization
-//---------------------------------------------------------------------------
-
-
-template <>
-bool
-FE_Q<1>::has_support_on_face (const unsigned int shape_index,
- const unsigned int face_index) const
-{
- Assert (shape_index < this->dofs_per_cell,
- ExcIndexRange (shape_index, 0, this->dofs_per_cell));
- Assert (face_index < GeometryInfo<1>::faces_per_cell,
- ExcIndexRange (face_index, 0, GeometryInfo<1>::faces_per_cell));
-
-
- // in 1d, things are simple. since
- // there is only one degree of
- // freedom per vertex in this
- // class, the first is on vertex 0
- // (==face 0 in some sense), the
- // second on face 1:
- return (((shape_index == 0) && (face_index == 0)) ||
- ((shape_index == 1) && (face_index == 1)));
-}
-
-
-template <>
-bool
-FE_Q<1,2>::has_support_on_face (const unsigned int shape_index,
- const unsigned int face_index) const
-{
- Assert (shape_index < this->dofs_per_cell,
- ExcIndexRange (shape_index, 0, this->dofs_per_cell));
- Assert (face_index < GeometryInfo<1>::faces_per_cell,
- ExcIndexRange (face_index, 0, GeometryInfo<1>::faces_per_cell));
-
-
- // in 1d, things are simple. since
- // there is only one degree of
- // freedom per vertex in this
- // class, the first is on vertex 0
- // (==face 0 in some sense), the
- // second on face 1:
- return (((shape_index == 0) && (face_index == 0)) ||
- ((shape_index == 1) && (face_index == 1)));
-}
-
-template <>
-bool
-FE_Q<1,3>::has_support_on_face (const unsigned int shape_index,
- const unsigned int face_index) const
-{
- Assert (shape_index < this->dofs_per_cell,
- ExcIndexRange (shape_index, 0, this->dofs_per_cell));
- Assert (face_index < GeometryInfo<1>::faces_per_cell,
- ExcIndexRange (face_index, 0, GeometryInfo<1>::faces_per_cell));
-
-
- // in 1d, things are simple. since
- // there is only one degree of
- // freedom per vertex in this
- // class, the first is on vertex 0
- // (==face 0 in some sense), the
- // second on face 1:
- return (((shape_index == 0) && (face_index == 0)) ||
- ((shape_index == 1) && (face_index == 1)));
-}
-
-
-template <int dim, int spacedim>
-bool
-FE_Q<dim,spacedim>::has_support_on_face (const unsigned int shape_index,
- const unsigned int face_index) const
-{
- Assert (shape_index < this->dofs_per_cell,
- ExcIndexRange (shape_index, 0, this->dofs_per_cell));
- Assert (face_index < GeometryInfo<dim>::faces_per_cell,
- ExcIndexRange (face_index, 0, GeometryInfo<dim>::faces_per_cell));
-
-
- // first, special-case interior
- // shape functions, since they
- // have no support no-where on
- // the boundary
- if (((dim==2) && (shape_index>=this->first_quad_index))
- ||
- ((dim==3) && (shape_index>=this->first_hex_index)))
- return false;
-
- // let's see whether this is a
- // vertex
- if (shape_index < this->first_line_index)
- {
- // for Q elements, there is
- // one dof per vertex, so
- // shape_index==vertex_number. check
- // whether this vertex is
- // on the given face. thus,
- // for each face, give a
- // list of vertices
- const unsigned int vertex_no = shape_index;
- Assert (vertex_no < GeometryInfo<dim>::vertices_per_cell,
- ExcInternalError());
-
- for (unsigned int v=0; v<GeometryInfo<dim>::vertices_per_face; ++v)
- if (GeometryInfo<dim>::face_to_cell_vertices(face_index, v) == vertex_no)
- return true;
-
- return false;
- }
- else if (shape_index < this->first_quad_index)
- // ok, dof is on a line
- {
- const unsigned int line_index
- = (shape_index - this->first_line_index) / this->dofs_per_line;
- Assert (line_index < GeometryInfo<dim>::lines_per_cell,
- ExcInternalError());
-
- // in 2d, the line is the
- // face, so get the line
- // index
- if (dim == 2)
- return (line_index == face_index);
- else if (dim == 3)
- {
- // see whether the
- // given line is on the
- // given face.
- for (unsigned int l=0; l<GeometryInfo<dim>::lines_per_face; ++l)
- if (GeometryInfo<3>::face_to_cell_lines(face_index, l) == line_index)
- return true;
-
- return false;
- }
- else
- Assert (false, ExcNotImplemented());
- }
- else if (shape_index < this->first_hex_index)
- // dof is on a quad
- {
- const unsigned int quad_index
- = (shape_index - this->first_quad_index) / this->dofs_per_quad;
- Assert (static_cast<signed int>(quad_index) <
- static_cast<signed int>(GeometryInfo<dim>::quads_per_cell),
- ExcInternalError());
-
- // in 2d, cell bubble are
- // zero on all faces. but
- // we have treated this
- // case above already
- Assert (dim != 2, ExcInternalError());
-
- // in 3d,
- // quad_index=face_index
- if (dim == 3)
- return (quad_index == face_index);
- else
- Assert (false, ExcNotImplemented());
- }
- else
- // dof on hex
- {
- // can only happen in 3d,
- // but this case has
- // already been covered
- // above
- Assert (false, ExcNotImplemented());
- return false;
- }
-
- // we should not have gotten here
- Assert (false, ExcInternalError());
- return false;
-}
-
-
-
-template <int dim, int spacedim>
-std::size_t
-FE_Q<dim,spacedim>::memory_consumption () const
-{
- return (FiniteElement<dim,spacedim>::memory_consumption() +
- MemoryConsumption::memory_consumption (face_index_map));
-}
-
-
-
// explicit instantiations
#include "fe_q.inst"
--- /dev/null
+//---------------------------------------------------------------------------
+// $Id$
+// Version: $Name$
+//
+// Copyright (C) 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010, 2011, 2012, 2013 by the deal.II authors
+//
+// This file is subject to QPL and may not be distributed
+// without copyright and license information. Please refer
+// to the file deal.II/doc/license.html for the text and
+// further information on this license.
+//
+//---------------------------------------------------------------------------
+
+#include <deal.II/base/quadrature.h>
+#include <deal.II/base/qprojector.h>
+#include <deal.II/base/template_constraints.h>
+#include <deal.II/base/tensor_product_polynomials.h>
+#include <deal.II/base/tensor_product_polynomials_const.h>
+#include <deal.II/base/polynomials_piecewise.h>
+#include <deal.II/fe/fe_q_base.h>
+#include <deal.II/fe/fe_nothing.h>
+#include <deal.II/fe/fe_tools.h>
+#include <deal.II/base/quadrature_lib.h>
+
+#include <vector>
+#include <sstream>
+
+DEAL_II_NAMESPACE_OPEN
+
+
+namespace FE_Q_Helper
+{
+ namespace
+ {
+ // get the renumbering for faces
+ template <int dim>
+ inline
+ std::vector<unsigned int>
+ face_lexicographic_to_hierarchic_numbering (const unsigned int degree)
+ {
+ std::vector<unsigned int> dpo(dim, 1U);
+ for (unsigned int i=1; i<dpo.size(); ++i)
+ dpo[i]=dpo[i-1]*(degree-1);
+ const dealii::FiniteElementData<dim-1> face_data(dpo,1,degree);
+ std::vector<unsigned int> face_renumber (face_data.dofs_per_cell);
+ FETools::lexicographic_to_hierarchic_numbering (face_data, face_renumber);
+ return face_renumber;
+ }
+
+ // dummy specialization for dim == 1 to avoid linker errors
+ template <>
+ inline
+ std::vector<unsigned int>
+ face_lexicographic_to_hierarchic_numbering<1> (const unsigned int)
+ {
+ return std::vector<unsigned int>();
+ }
+
+
+
+ // in get_restriction_matrix() and get_prolongation_matrix(), want to undo
+ // tensorization on inner loops for performance reasons. this clears a
+ // dim-array
+ template <int dim>
+ inline
+ void
+ zero_indices (unsigned int (&indices)[dim])
+ {
+ for (unsigned int d=0; d<dim; ++d)
+ indices[d] = 0;
+ }
+
+
+
+ // in get_restriction_matrix() and get_prolongation_matrix(), want to undo
+ // tensorization on inner loops for performance reasons. this increments
+ // tensor product indices
+ template <int dim>
+ inline
+ void
+ increment_indices (unsigned int (&indices)[dim],
+ const unsigned int dofs1d)
+ {
+ ++indices[0];
+ for (int d=0; d<dim-1; ++d)
+ if (indices[d]==dofs1d)
+ {
+ indices[d] = 0;
+ indices[d+1]++;
+ }
+ }
+ }
+}
+
+
+
+/**
+ * A class with the same purpose as the similarly named class of the
+ * Triangulation class. See there for more information.
+ */
+template <class POLY, int xdim, int xspacedim>
+struct FE_Q_Base<POLY,xdim,xspacedim>::Implementation
+{
+ /**
+ * Initialize the hanging node constraints matrices. Called from the
+ * constructor in case the finite element is based on quadrature points.
+ */
+ template <int spacedim>
+ static
+ void initialize_constraints (const std::vector<Point<1> > &,
+ FE_Q_Base<POLY,1,spacedim> &)
+ {
+ // no constraints in 1d
+ }
+
+
+ template <int spacedim>
+ static
+ void initialize_constraints (const std::vector<Point<1> > &points,
+ FE_Q_Base<POLY,2,spacedim> &fe)
+ {
+ const unsigned int dim = 2;
+
+ // restricted to each face, the traces of the shape functions is an
+ // element of P_{k} (in 2d), or Q_{k} (in 3d), where k is the degree of
+ // the element. from this, we interpolate between mother and cell face.
+
+ // the interpolation process works as follows: on each subface, we want
+ // that finite element solutions from both sides coincide. i.e. if a and b
+ // are expansion coefficients for the shape functions from both sides, we
+ // seek a relation between a and b such that
+ // sum_j a_j phi^c_j(x) == sum_j b_j phi_j(x)
+ // for all points x on the interface. here, phi^c_j are the shape
+ // functions on the small cell on one side of the face, and phi_j those on
+ // the big cell on the other side. To get this relation, it suffices to
+ // look at a sufficient number of points for which this has to hold. if
+ // there are n functions, then we need n evaluation points, and we choose
+ // them equidistantly.
+ //
+ // we obtain the matrix system
+ // A a == B b
+ // where
+ // A_ij = phi^c_j(x_i)
+ // B_ij = phi_j(x_i)
+ // and the relation we are looking for is
+ // a = A^-1 B b
+ //
+ // for the special case of Lagrange interpolation polynomials, A_ij
+ // reduces to delta_ij, and
+ // a_i = B_ij b_j
+ // Hence, interface_constraints(i,j)=B_ij.
+ //
+ // for the general case, where we don't have Lagrange interpolation
+ // polynomials, this is a little more complicated. Then we would evaluate
+ // at a number of points and invert the interpolation matrix A.
+ //
+ // Note, that we build up these matrices for all subfaces at once, rather
+ // than considering them separately. the reason is that we finally will
+ // want to have them in this order anyway, as this is the format we need
+ // inside deal.II
+
+ // In the following the points x_i are constructed in following order
+ // (n=degree-1)
+ // *----------*---------*
+ // 1..n 0 n+1..2n
+ // i.e. first the midpoint of the line, then the support points on subface
+ // 0 and on subface 1
+ std::vector<Point<dim-1> > constraint_points;
+ // Add midpoint
+ constraint_points.push_back (Point<dim-1> (0.5));
+
+ if (fe.degree>1)
+ {
+ const unsigned int n=fe.degree-1;
+ const double step=1./fe.degree;
+ // subface 0
+ for (unsigned int i=1; i<=n; ++i)
+ constraint_points.push_back (
+ GeometryInfo<dim-1>::child_to_cell_coordinates(Point<dim-1>(i*step),0));
+ // subface 1
+ for (unsigned int i=1; i<=n; ++i)
+ constraint_points.push_back (
+ GeometryInfo<dim-1>::child_to_cell_coordinates(Point<dim-1>(i*step),1));
+ }
+
+ // Now construct relation between destination (child) and source (mother)
+ // dofs.
+
+ fe.interface_constraints
+ .TableBase<2,double>::reinit (fe.interface_constraints_size());
+
+ // use that the element evaluates to 1 at index 0 and along the line at
+ // zero
+ const std::vector<unsigned int> &index_map_inverse =
+ fe.poly_space.get_numbering_inverse();
+ const std::vector<unsigned int> face_index_map =
+ FE_Q_Helper::face_lexicographic_to_hierarchic_numbering<dim>(fe.degree);
+ Assert(std::abs(fe.poly_space.compute_value(index_map_inverse[0],Point<dim>())
+ - 1.) < 1e-14,
+ ExcInternalError());
+
+ for (unsigned int i=0; i<constraint_points.size(); ++i)
+ for (unsigned int j=0; j<fe.degree+1; ++j)
+ {
+ Point<dim> p;
+ p[0] = constraint_points[i](0);
+ fe.interface_constraints(i,face_index_map[j]) =
+ fe.poly_space.compute_value(index_map_inverse[j], p);
+
+ // if the value is small up to round-off, then simply set it to zero
+ // to avoid unwanted fill-in of the constraint matrices (which would
+ // then increase the number of other DoFs a constrained DoF would
+ // couple to)
+ if (std::fabs(fe.interface_constraints(i,j)) < 1e-14)
+ fe.interface_constraints(i,j) = 0;
+ }
+ }
+
+
+ template <int spacedim>
+ static
+ void initialize_constraints (const std::vector<Point<1> > &points,
+ FE_Q_Base<POLY,3,spacedim> &fe)
+ {
+ const unsigned int dim = 3;
+
+ // For a detailed documentation of the interpolation see the
+ // FE_Q_Base<2>::initialize_constraints function.
+
+ // In the following the points x_i are constructed in the order as
+ // described in the documentation of the FiniteElement class (fe_base.h),
+ // i.e.
+ // *--15--4--16--*
+ // | | |
+ // 10 19 6 20 12
+ // | | |
+ // 1--7---0--8---2
+ // | | |
+ // 9 17 5 18 11
+ // | | |
+ // *--13--3--14--*
+ std::vector<Point<dim-1> > constraint_points;
+
+ // Add midpoint
+ constraint_points.push_back (Point<dim-1> (0.5, 0.5));
+
+ // Add midpoints of lines of "mother-face"
+ constraint_points.push_back (Point<dim-1> (0, 0.5));
+ constraint_points.push_back (Point<dim-1> (1, 0.5));
+ constraint_points.push_back (Point<dim-1> (0.5, 0));
+ constraint_points.push_back (Point<dim-1> (0.5, 1));
+
+ if (fe.degree>1)
+ {
+ const unsigned int n=fe.degree-1;
+ const double step=1./fe.degree;
+ std::vector<Point<dim-2> > line_support_points(n);
+ for (unsigned int i=0; i<n; ++i)
+ line_support_points[i](0)=(i+1)*step;
+ Quadrature<dim-2> qline(line_support_points);
+
+ // auxiliary points in 2d
+ std::vector<Point<dim-1> > p_line(n);
+
+ // Add nodes of lines interior in the "mother-face"
+
+ // line 5: use line 9
+ QProjector<dim-1>::project_to_subface(qline, 0, 0, p_line);
+ for (unsigned int i=0; i<n; ++i)
+ constraint_points.push_back (p_line[i] + Point<dim-1> (0.5, 0));
+ // line 6: use line 10
+ QProjector<dim-1>::project_to_subface(qline, 0, 1, p_line);
+ for (unsigned int i=0; i<n; ++i)
+ constraint_points.push_back (p_line[i] + Point<dim-1> (0.5, 0));
+ // line 7: use line 13
+ QProjector<dim-1>::project_to_subface(qline, 2, 0, p_line);
+ for (unsigned int i=0; i<n; ++i)
+ constraint_points.push_back (p_line[i] + Point<dim-1> (0, 0.5));
+ // line 8: use line 14
+ QProjector<dim-1>::project_to_subface(qline, 2, 1, p_line);
+ for (unsigned int i=0; i<n; ++i)
+ constraint_points.push_back (p_line[i] + Point<dim-1> (0, 0.5));
+
+ // DoFs on bordering lines lines 9-16
+ for (unsigned int face=0; face<GeometryInfo<dim-1>::faces_per_cell; ++face)
+ for (unsigned int subface=0;
+ subface<GeometryInfo<dim-1>::max_children_per_face; ++subface)
+ {
+ QProjector<dim-1>::project_to_subface(qline, face, subface, p_line);
+ constraint_points.insert(constraint_points.end(),
+ p_line.begin(), p_line.end());
+ }
+
+ // Create constraints for interior nodes
+ std::vector<Point<dim-1> > inner_points(n*n);
+ for (unsigned int i=0, iy=1; iy<=n; ++iy)
+ for (unsigned int ix=1; ix<=n; ++ix)
+ inner_points[i++] = Point<dim-1> (ix*step, iy*step);
+
+ // at the moment do this for isotropic face refinement only
+ for (unsigned int child=0;
+ child<GeometryInfo<dim-1>::max_children_per_cell; ++child)
+ for (unsigned int i=0; i<inner_points.size(); ++i)
+ constraint_points.push_back (
+ GeometryInfo<dim-1>::child_to_cell_coordinates(inner_points[i], child));
+ }
+
+ // Now construct relation between destination (child) and source (mother)
+ // dofs.
+ const unsigned int pnts=(fe.degree+1)*(fe.degree+1);
+
+ // use that the element evaluates to 1 at index 0 and along the line at
+ // zero
+ const std::vector<unsigned int> &index_map_inverse =
+ fe.poly_space.get_numbering_inverse();
+ const std::vector<unsigned int> face_index_map =
+ FE_Q_Helper::face_lexicographic_to_hierarchic_numbering<dim>(fe.degree);
+ Assert(std::abs(fe.poly_space.compute_value(index_map_inverse[0],Point<dim>())
+ - 1.) < 1e-14,
+ ExcInternalError());
+
+ fe.interface_constraints
+ .TableBase<2,double>::reinit (fe.interface_constraints_size());
+
+ for (unsigned int i=0; i<constraint_points.size(); ++i)
+ {
+ const double interval = (double) (fe.degree * 2);
+ bool mirror[dim - 1];
+ Point<dim> constraint_point;
+
+ // Eliminate FP errors in constraint points. Due to their origin, they
+ // must all be fractions of the unit interval. If we have polynomial
+ // degree 4, the refined element has 8 intervals. Hence the
+ // coordinates must be 0, 0.125, 0.25, 0.375 etc. Now the coordinates
+ // of the constraint points will be multiplied by the inverse of the
+ // interval size (in the example by 8). After that the coordinates
+ // must be integral numbers. Hence a normal truncation is performed
+ // and the coordinates will be scaled back. The equal treatment of all
+ // coordinates should eliminate any FP errors.
+ for (unsigned int k=0; k<dim-1; ++k)
+ {
+ const int coord_int =
+ static_cast<int> (constraint_points[i](k) * interval + 0.25);
+ constraint_point(k) = 1.*coord_int / interval;
+
+ // The following lines of code should eliminate the problems with
+ // the Constraint-Matrix, which appeared for P>=4. The
+ // ConstraintMatrix class complained about different constraints
+ // for the same entry of the Constraint-Matrix. Actually this
+ // difference could be attributed to FP errors, as it was in the
+ // range of 1.0e-16. These errors originate in the loss of
+ // symmetry in the FP approximation of the shape-functions.
+ // Considering a 3rd order shape function in 1D, we have
+ // N0(x)=N3(1-x) and N1(x)=N2(1-x). For higher order polynomials
+ // the FP approximations of the shape functions do not satisfy
+ // these equations any more! Thus in the following code
+ // everything is computed in the interval x \in [0..0.5], which is
+ // sufficient to express all values that could come out from a
+ // computation of any shape function in the full interval
+ // [0..1]. If x > 0.5 the computation is done for 1-x with the
+ // shape function N_{p-n} instead of N_n. Hence symmetry is
+ // preserved and everything works fine...
+ //
+ // For a different explanation of the problem, see the discussion
+ // in the FiniteElement class for constraint matrices in 3d.
+ mirror[k] = (constraint_point(k) > 0.5);
+ if (mirror[k])
+ constraint_point(k) = 1.0 - constraint_point(k);
+ }
+
+ for (unsigned int j=0; j<pnts; ++j)
+ {
+ unsigned int indices[2] = { j % (fe.degree+1), j / (fe.degree+1) };
+
+ for (unsigned int k = 0; k<2; ++k)
+ if (mirror[k])
+ indices[k] = fe.degree - indices[k];
+
+ const unsigned int
+ new_index = indices[1] * (fe.degree + 1) + indices[0];
+
+ fe.interface_constraints(i,face_index_map[j]) =
+ fe.poly_space.compute_value (index_map_inverse[new_index],
+ constraint_point);
+
+ // if the value is small up to round-off, then simply set it to
+ // zero to avoid unwanted fill-in of the constraint matrices
+ // (which would then increase the number of other DoFs a
+ // constrained DoF would couple to)
+ if (std::fabs(fe.interface_constraints(i,j)) < 1e-14)
+ fe.interface_constraints(i,j) = 0;
+ }
+ }
+ }
+};
+
+
+
+template <class POLY, int dim, int spacedim>
+FE_Q_Base<POLY,dim,spacedim>::FE_Q_Base (const POLY &poly_space,
+ const FiniteElementData<dim> &fe_data,
+ const std::vector<bool> &restriction_is_additive_flags)
+ :
+ FE_Poly<POLY,dim,spacedim>(poly_space, fe_data, restriction_is_additive_flags,
+ std::vector<ComponentMask>(1, std::vector<bool>(1,true)))
+{}
+
+
+
+template <class POLY, int dim, int spacedim>
+void
+FE_Q_Base<POLY,dim,spacedim>::initialize (const std::vector<Point<1> > &points)
+{
+ Assert (points[0][0] == 0,
+ ExcMessage ("The first support point has to be zero."));
+ Assert (points.back()[0] == 1,
+ ExcMessage ("The last support point has to be one."));
+
+ // distinguish q/q_dg0 case: need to be flexible enough to allow more
+ // degrees of freedom than there are FE_Q degrees of freedom for derived
+ // class FE_Q_DG0 that otherwise shares 95% of the code.
+ const unsigned int q_dofs_per_cell = Utilities::fixed_power<dim>(this->degree+1);
+ Assert(q_dofs_per_cell == this->dofs_per_cell ||
+ q_dofs_per_cell+1 == this->dofs_per_cell, ExcInternalError());
+
+ {
+ std::vector<unsigned int> renumber(q_dofs_per_cell);
+ const FiniteElementData<dim> fe(get_dpo_vector(this->degree),1,
+ this->degree);
+ FETools::hierarchic_to_lexicographic_numbering (fe, renumber);
+ if (this->dofs_per_cell > q_dofs_per_cell)
+ renumber.push_back(q_dofs_per_cell);
+ this->poly_space.set_numbering(renumber);
+ }
+
+ // finally fill in support points on cell and face
+ initialize_unit_support_points (points);
+ initialize_unit_face_support_points (points);
+
+ // reinit constraints
+ initialize_constraints (points);
+
+ // do not initialize embedding and restriction here. these matrices are
+ // initialized on demand in get_restriction_matrix and
+ // get_prolongation_matrix
+
+ this->initialize_quad_dof_index_permutation();
+}
+
+
+
+template <class POLY, int dim, int spacedim>
+void
+FE_Q_Base<POLY,dim,spacedim>::
+get_interpolation_matrix (const FiniteElement<dim,spacedim> &x_source_fe,
+ FullMatrix<double> &interpolation_matrix) const
+{
+ // this is only implemented, if the source FE is also a Q element
+ AssertThrow ((dynamic_cast<const FE_Q_Base<POLY,dim,spacedim> *>(&x_source_fe) != 0),
+ (typename FiniteElement<dim,spacedim>::ExcInterpolationNotImplemented()));
+
+ 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));
+
+ // ok, source is a Q element, so we will be able to do the work
+ const FE_Q_Base<POLY,dim,spacedim> &source_fe
+ = dynamic_cast<const FE_Q_Base<POLY,dim,spacedim>&>(x_source_fe);
+
+ // only evaluate Q dofs
+ const unsigned int q_dofs_per_cell = Utilities::fixed_power<dim>(this->degree+1);
+ const unsigned int source_q_dofs_per_cell = Utilities::fixed_power<dim>(source_fe.degree+1);
+
+ // evaluation is simply done by evaluating the other FE's basis functions on
+ // the unit support points (FE_Q has the property that the cell
+ // interpolation matrix is a unit matrix, so no need to evaluate it and
+ // invert it)
+ for (unsigned int j=0; j<q_dofs_per_cell; ++j)
+ {
+ // read in a point on this cell and evaluate the shape functions there
+ const Point<dim> p = this->unit_support_points[j];
+
+ // 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());
+
+ for (unsigned int i=0; i<source_q_dofs_per_cell; ++i)
+ interpolation_matrix(j,i) = source_fe.poly_space.compute_value (i, p);
+ }
+
+ // for FE_Q_DG0, add one last row of identity
+ if (q_dofs_per_cell < this->dofs_per_cell)
+ {
+ AssertDimension(source_q_dofs_per_cell+1, source_fe.dofs_per_cell);
+ for (unsigned int i=0; i<source_q_dofs_per_cell; ++i)
+ interpolation_matrix(q_dofs_per_cell, i) = 0.;
+ for (unsigned int j=0; j<q_dofs_per_cell; ++j)
+ interpolation_matrix(j, source_q_dofs_per_cell) = 0.;
+ interpolation_matrix(q_dofs_per_cell, source_q_dofs_per_cell) = 1.;
+ }
+
+ // cut off very small values
+ const double eps = 2e-13*this->degree*dim;
+ for (unsigned int i=0; i<this->dofs_per_cell; ++i)
+ for (unsigned int j=0; j<source_fe.dofs_per_cell; ++j)
+ if (std::fabs(interpolation_matrix(i,j)) < eps)
+ interpolation_matrix(i,j) = 0.;
+
+ // make sure that the row sum of each of the matrices is 1 at this
+ // point. this must be so since the shape functions sum up to 1
+ for (unsigned int i=0; i<this->dofs_per_cell; ++i)
+ {
+ double sum = 0.;
+ for (unsigned int j=0; j<source_fe.dofs_per_cell; ++j)
+ sum += interpolation_matrix(i,j);
+
+ Assert (std::fabs(sum-1) < eps, ExcInternalError());
+ }
+}
+
+
+
+template <class POLY, int dim, int spacedim>
+void
+FE_Q_Base<POLY,dim,spacedim>::
+get_face_interpolation_matrix (const FiniteElement<dim,spacedim> &x_source_fe,
+ FullMatrix<double> &interpolation_matrix) const
+{
+ Assert (dim > 1, ExcImpossibleInDim(1));
+
+ // this is only implemented, if the source FE is also a Q element
+ AssertThrow ((dynamic_cast<const FE_Q_Base<POLY,dim,spacedim> *>(&x_source_fe) != 0),
+ (typename FiniteElement<dim,spacedim>::
+ ExcInterpolationNotImplemented()));
+
+ Assert (interpolation_matrix.n() == this->dofs_per_face,
+ ExcDimensionMismatch (interpolation_matrix.n(),
+ this->dofs_per_face));
+ Assert (interpolation_matrix.m() == x_source_fe.dofs_per_face,
+ ExcDimensionMismatch (interpolation_matrix.m(),
+ x_source_fe.dofs_per_face));
+
+ // ok, source is a Q element, so we will be able to do the work
+ const FE_Q_Base<POLY,dim,spacedim> &source_fe
+ = dynamic_cast<const FE_Q_Base<POLY,dim,spacedim>&>(x_source_fe);
+
+ // Make sure that the element for which the DoFs should be constrained is
+ // the one with the higher polynomial degree. Actually the procedure will
+ // work also if this assertion is not satisfied. But the matrices produced
+ // in that case might lead to problems in the hp procedures, which use this
+ // method.
+ Assert (this->dofs_per_face <= source_fe.dofs_per_face,
+ (typename FiniteElement<dim,spacedim>::
+ ExcInterpolationNotImplemented ()));
+
+ // generate a quadrature with the unit support points. This is later based
+ // as a basis for the QProjector, which returns the support points on the
+ // face.
+ Quadrature<dim-1> quad_face_support (source_fe.get_unit_face_support_points ());
+
+ // Rule of thumb for FP accuracy, that can be expected for a given
+ // polynomial degree. This value is used to cut off values close to zero.
+ const double eps = 2e-13*this->degree*(dim-1);
+
+ // compute the interpolation matrix by simply taking the value at the
+ // support points.
+//TODO: Verify that all faces are the same with respect to
+// these support points. Furthermore, check if something has to
+// be done for the face orientation flag in 3D.
+ const Quadrature<dim> face_quadrature
+ = QProjector<dim>::project_to_face (quad_face_support, 0);
+ for (unsigned int i=0; i<source_fe.dofs_per_face; ++i)
+ {
+ const Point<dim> &p = face_quadrature.point (i);
+
+ for (unsigned int j=0; j<this->dofs_per_face; ++j)
+ {
+ double matrix_entry = this->poly_space.compute_value (this->face_to_cell_index(j, 0), p);
+
+ // Correct the interpolated value. I.e. if it is close to 1 or 0,
+ // make it exactly 1 or 0. Unfortunately, this is required to avoid
+ // problems with higher order elements.
+ if (std::fabs (matrix_entry - 1.0) < eps)
+ matrix_entry = 1.0;
+ if (std::fabs (matrix_entry) < eps)
+ matrix_entry = 0.0;
+
+ interpolation_matrix(i,j) = matrix_entry;
+ }
+ }
+
+ // make sure that the row sum of each of the matrices is 1 at this
+ // point. this must be so since the shape functions sum up to 1
+ for (unsigned int j=0; j<source_fe.dofs_per_face; ++j)
+ {
+ double sum = 0.;
+
+ for (unsigned int i=0; i<this->dofs_per_face; ++i)
+ sum += interpolation_matrix(j,i);
+
+ Assert (std::fabs(sum-1) < 2e-13*this->degree*(dim-1),
+ ExcInternalError());
+ }
+}
+
+
+
+template <class POLY, int dim, int spacedim>
+void
+FE_Q_Base<POLY,dim,spacedim>::
+get_subface_interpolation_matrix (const FiniteElement<dim,spacedim> &x_source_fe,
+ const unsigned int subface,
+ FullMatrix<double> &interpolation_matrix) const
+{
+ Assert (interpolation_matrix.m() == x_source_fe.dofs_per_face,
+ ExcDimensionMismatch (interpolation_matrix.m(),
+ x_source_fe.dofs_per_face));
+
+ // see if source is a Q element
+ if (const FE_Q_Base<POLY,dim,spacedim> *source_fe
+ = dynamic_cast<const FE_Q_Base<POLY,dim,spacedim> *>(&x_source_fe))
+ {
+ // have this test in here since a table of size 2x0 reports its size as
+ // 0x0
+ Assert (interpolation_matrix.n() == this->dofs_per_face,
+ ExcDimensionMismatch (interpolation_matrix.n(),
+ this->dofs_per_face));
+
+ // Make sure that the element for which the DoFs should be constrained
+ // is the one with the higher polynomial degree. Actually the procedure
+ // will work also if this assertion is not satisfied. But the matrices
+ // produced in that case might lead to problems in the hp procedures,
+ // which use this method.
+ Assert (this->dofs_per_face <= source_fe->dofs_per_face,
+ (typename FiniteElement<dim,spacedim>::
+ ExcInterpolationNotImplemented ()));
+
+ // generate a point on this cell and evaluate the shape functions there
+ const Quadrature<dim-1>
+ quad_face_support (source_fe->get_unit_face_support_points ());
+
+ // Rule of thumb for FP accuracy, that can be expected for a given
+ // polynomial degree. This value is used to cut off values close to
+ // zero.
+ double eps = 2e-13*this->degree*(dim-1);
+
+ // compute the interpolation matrix by simply taking the value at the
+ // support points.
+//TODO: Verify that all faces are the same with respect to
+// these support points. Furthermore, check if something has to
+// be done for the face orientation flag in 3D.
+ const Quadrature<dim> subface_quadrature
+ = QProjector<dim>::project_to_subface (quad_face_support, 0, subface);
+ for (unsigned int i=0; i<source_fe->dofs_per_face; ++i)
+ {
+ const Point<dim> &p = subface_quadrature.point (i);
+
+ for (unsigned int j=0; j<this->dofs_per_face; ++j)
+ {
+ double matrix_entry = this->shape_value (this->face_to_cell_index(j, 0), p);
+
+ // Correct the interpolated value. I.e. if it is close to 1 or
+ // 0, make it exactly 1 or 0. Unfortunately, this is required to
+ // avoid problems with higher order elements.
+ if (std::fabs (matrix_entry - 1.0) < eps)
+ matrix_entry = 1.0;
+ if (std::fabs (matrix_entry) < eps)
+ matrix_entry = 0.0;
+
+ interpolation_matrix(i,j) = matrix_entry;
+ }
+ }
+
+ // make sure that the row sum of each of the matrices is 1 at this
+ // point. this must be so since the shape functions sum up to 1
+ for (unsigned int j=0; j<source_fe->dofs_per_face; ++j)
+ {
+ double sum = 0.;
+
+ for (unsigned int i=0; i<this->dofs_per_face; ++i)
+ sum += interpolation_matrix(j,i);
+
+ Assert (std::fabs(sum-1) < 2e-13*this->degree*dim,
+ ExcInternalError());
+ }
+ }
+ else if (dynamic_cast<const FE_Nothing<dim> *>(&x_source_fe) != 0)
+ {
+ // nothing to do here, the FE_Nothing has no degrees of freedom anyway
+ }
+ else
+ AssertThrow (false,(typename FiniteElement<dim,spacedim>::
+ ExcInterpolationNotImplemented()));
+}
+
+
+
+template <class POLY, int dim, int spacedim>
+bool
+FE_Q_Base<POLY,dim,spacedim>::hp_constraints_are_implemented () const
+{
+ return true;
+}
+
+
+
+
+template <class POLY, int dim, int spacedim>
+std::vector<std::pair<unsigned int, unsigned int> >
+FE_Q_Base<POLY,dim,spacedim>::
+hp_vertex_dof_identities (const FiniteElement<dim,spacedim> &fe_other) const
+{
+ // we can presently only compute these identities if both FEs are FE_Qs or
+ // if the other one is an FE_Nothing. in the first case, there should be
+ // exactly one single DoF of each FE at a vertex, and they should have
+ // identical value
+ if (dynamic_cast<const FE_Q_Base<POLY,dim,spacedim>*>(&fe_other) != 0)
+ {
+ return
+ std::vector<std::pair<unsigned int, unsigned int> >
+ (1, std::make_pair (0U, 0U));
+ }
+ else if (dynamic_cast<const FE_Nothing<dim>*>(&fe_other) != 0)
+ {
+ // the FE_Nothing has no degrees of freedom, so there are no
+ // equivalencies to be recorded
+ return std::vector<std::pair<unsigned int, unsigned int> > ();
+ }
+ else
+ {
+ Assert (false, ExcNotImplemented());
+ return std::vector<std::pair<unsigned int, unsigned int> > ();
+ }
+}
+
+
+
+template <class POLY, int dim, int spacedim>
+std::vector<std::pair<unsigned int, unsigned int> >
+FE_Q_Base<POLY,dim,spacedim>::
+hp_line_dof_identities (const FiniteElement<dim,spacedim> &fe_other) const
+{
+ // we can presently only compute these identities if both FEs are FE_Qs or
+ // if the other one is an FE_Nothing
+ if (const FE_Q_Base<POLY,dim,spacedim> *fe_q_other = dynamic_cast<const FE_Q_Base<POLY,dim,spacedim>*>(&fe_other))
+ {
+ // dofs are located along lines, so two dofs are identical if they are
+ // located at identical positions. if we had only equidistant points, we
+ // could simple check for similarity like (i+1)*q == (j+1)*p, but we
+ // might have other support points (e.g. Gauss-Lobatto
+ // points). Therefore, read the points in unit_support_points for the
+ // first coordinate direction. We take the lexicographic ordering of the
+ // points in the first direction (i.e., x-direction), which we access
+ // between index 1 and p-1 (index 0 and p are vertex dofs).
+ const unsigned int p = this->degree;
+ const unsigned int q = fe_q_other->degree;
+
+ std::vector<std::pair<unsigned int, unsigned int> > identities;
+
+ const std::vector<unsigned int> &index_map_inverse=
+ this->poly_space.get_numbering_inverse();
+ const std::vector<unsigned int> &index_map_inverse_other=
+ fe_q_other->poly_space.get_numbering_inverse();
+
+ for (unsigned int i=0; i<p-1; ++i)
+ for (unsigned int j=0; j<q-1; ++j)
+ if (std::fabs(this->unit_support_points[index_map_inverse[i+1]][0]-
+ fe_q_other->unit_support_points[index_map_inverse_other[j+1]][0])
+ < 1e-14)
+ identities.push_back (std::make_pair(i,j));
+
+ return identities;
+ }
+ else if (dynamic_cast<const FE_Nothing<dim>*>(&fe_other) != 0)
+ {
+ // the FE_Nothing has no degrees of freedom, so there are no
+ // equivalencies to be recorded
+ return std::vector<std::pair<unsigned int, unsigned int> > ();
+ }
+ else
+ {
+ Assert (false, ExcNotImplemented());
+ return std::vector<std::pair<unsigned int, unsigned int> > ();
+ }
+}
+
+
+
+template <class POLY, int dim, int spacedim>
+std::vector<std::pair<unsigned int, unsigned int> >
+FE_Q_Base<POLY,dim,spacedim>::
+hp_quad_dof_identities (const FiniteElement<dim,spacedim> &fe_other) const
+{
+ // we can presently only compute these identities if both FEs are FE_Qs or
+ // if the other one is an FE_Nothing
+ if (const FE_Q_Base<POLY,dim,spacedim> *fe_q_other = dynamic_cast<const FE_Q_Base<POLY,dim,spacedim>*>(&fe_other))
+ {
+ // this works exactly like the line case above, except that now we have
+ // to have two indices i1, i2 and j1, j2 to characterize the dofs on the
+ // face of each of the finite elements. since they are ordered
+ // lexicographically along the first line and we have a tensor product,
+ // the rest is rather straightforward
+ const unsigned int p = this->degree;
+ const unsigned int q = fe_q_other->degree;
+
+ std::vector<std::pair<unsigned int, unsigned int> > identities;
+
+ const std::vector<unsigned int> &index_map_inverse=
+ this->poly_space.get_numbering_inverse();
+ const std::vector<unsigned int> &index_map_inverse_other=
+ fe_q_other->poly_space.get_numbering_inverse();
+
+ for (unsigned int i1=0; i1<p-1; ++i1)
+ for (unsigned int i2=0; i2<p-1; ++i2)
+ for (unsigned int j1=0; j1<q-1; ++j1)
+ for (unsigned int j2=0; j2<q-1; ++j2)
+ if ((std::fabs(this->unit_support_points[index_map_inverse[i1+1]][0]-
+ fe_q_other->unit_support_points[index_map_inverse_other[j1+1]][0])
+ < 1e-14)
+ &&
+ (std::fabs(this->unit_support_points[index_map_inverse[i2+1]][0]-
+ fe_q_other->unit_support_points[index_map_inverse_other[j2+1]][0])
+ < 1e-14))
+ identities.push_back (std::make_pair(i1*(p-1)+i2,
+ j1*(q-1)+j2));
+
+ return identities;
+ }
+ else if (dynamic_cast<const FE_Nothing<dim>*>(&fe_other) != 0)
+ {
+ // the FE_Nothing has no degrees of freedom, so there are no
+ // equivalencies to be recorded
+ return std::vector<std::pair<unsigned int, unsigned int> > ();
+ }
+ else
+ {
+ Assert (false, ExcNotImplemented());
+ return std::vector<std::pair<unsigned int, unsigned int> > ();
+ }
+}
+
+
+
+template <class POLY, int dim, int spacedim>
+FiniteElementDomination::Domination
+FE_Q_Base<POLY,dim,spacedim>::
+compare_for_face_domination (const FiniteElement<dim,spacedim> &fe_other) const
+{
+ if (const FE_Q_Base<POLY,dim,spacedim> *fe_q_other
+ = dynamic_cast<const FE_Q_Base<POLY,dim,spacedim>*>(&fe_other))
+ {
+ if (this->degree < fe_q_other->degree)
+ return FiniteElementDomination::this_element_dominates;
+ else if (this->degree == fe_q_other->degree)
+ return FiniteElementDomination::either_element_can_dominate;
+ else
+ return FiniteElementDomination::other_element_dominates;
+ }
+ else if (dynamic_cast<const FE_Nothing<dim>*>(&fe_other) != 0)
+ {
+ // the FE_Nothing has no degrees of freedom and it is typically used in
+ // a context where we don't require any continuity along the interface
+ return FiniteElementDomination::no_requirements;
+ }
+
+ Assert (false, ExcNotImplemented());
+ return FiniteElementDomination::neither_element_dominates;
+}
+
+
+//---------------------------------------------------------------------------
+// Auxiliary functions
+//---------------------------------------------------------------------------
+
+
+
+template <class POLY, int dim, int spacedim>
+void FE_Q_Base<POLY,dim,spacedim>::initialize_unit_support_points (const std::vector<Point<1> > &points)
+{
+ const std::vector<unsigned int> &index_map_inverse=
+ this->poly_space.get_numbering_inverse();
+
+ Quadrature<1> support_1d(points);
+ Quadrature<dim> support_quadrature(support_1d);
+ this->unit_support_points.resize(support_quadrature.size());
+
+ for (unsigned int k=0; k<support_quadrature.size(); k++)
+ this->unit_support_points[index_map_inverse[k]] = support_quadrature.point(k);
+}
+
+
+
+template <class POLY, int dim, int spacedim>
+void FE_Q_Base<POLY,dim,spacedim>::initialize_unit_face_support_points (const std::vector<Point<1> > &points)
+{
+ // no faces in 1d, so nothing to do
+ if (dim == 1)
+ return;
+
+ const unsigned int codim = dim-1;
+ this->unit_face_support_points.resize(Utilities::fixed_power<codim>(this->degree+1));
+
+ // find renumbering of faces and assign from values of quadrature
+ std::vector<unsigned int> face_index_map =
+ FE_Q_Helper::face_lexicographic_to_hierarchic_numbering<dim>(this->degree);
+ Quadrature<1> support_1d(points);
+ Quadrature<codim> support_quadrature(support_1d);
+ this->unit_face_support_points.resize(support_quadrature.size());
+
+ for (unsigned int k=0; k<support_quadrature.size(); k++)
+ this->unit_face_support_points[face_index_map[k]] = support_quadrature.point(k);
+}
+
+
+
+template <class POLY, int dim, int spacedim>
+void
+FE_Q_Base<POLY,dim,spacedim>::initialize_quad_dof_index_permutation ()
+{
+ // for 1D and 2D, do nothing
+ if (dim < 3)
+ return;
+
+ Assert (this->adjust_quad_dof_index_for_face_orientation_table.n_elements()==8*this->dofs_per_quad,
+ ExcInternalError());
+
+ const unsigned int n=this->degree-1;
+ Assert(n*n==this->dofs_per_quad, ExcInternalError());
+
+ // alias for the table to fill
+ Table<2,int> &data=this->adjust_quad_dof_index_for_face_orientation_table;
+
+ // the dofs on a face are connected to a n x n matrix. for example, for
+ // degree==4 we have the following dofs on a quad
+
+ // ___________
+ // | |
+ // | 6 7 8 |
+ // | |
+ // | 3 4 5 |
+ // | |
+ // | 0 1 2 |
+ // |___________|
+ //
+ // we have dof_no=i+n*j with index i in x-direction and index j in
+ // y-direction running from 0 to n-1. to extract i and j we can use
+ // i=dof_no%n and j=dof_no/n. i and j can then be used to construct the
+ // rotated and mirrored numbers.
+
+
+ for (unsigned int local=0; local<this->dofs_per_quad; ++local)
+ // face support points are in lexicographic ordering with x running
+ // fastest. invert that (y running fastest)
+ {
+ unsigned int i=local%n,
+ j=local/n;
+
+ // face_orientation=false, face_flip=false, face_rotation=false
+ data(local,0)=j + i *n - local;
+ // face_orientation=false, face_flip=false, face_rotation=true
+ data(local,1)=i + (n-1-j)*n - local;
+ // face_orientation=false, face_flip=true, face_rotation=false
+ data(local,2)=(n-1-j) + (n-1-i)*n - local;
+ // face_orientation=false, face_flip=true, face_rotation=true
+ data(local,3)=(n-1-i) + j *n - local;
+ // face_orientation=true, face_flip=false, face_rotation=false
+ data(local,4)=0;
+ // face_orientation=true, face_flip=false, face_rotation=true
+ data(local,5)=j + (n-1-i)*n - local;
+ // face_orientation=true, face_flip=true, face_rotation=false
+ data(local,6)=(n-1-i) + (n-1-j)*n - local;
+ // face_orientation=true, face_flip=true, face_rotation=true
+ data(local,7)=(n-1-j) + i *n - local;
+ }
+
+ // aditionally initialize reordering of line dofs
+ for (unsigned int i=0; i<this->dofs_per_line; ++i)
+ this->adjust_line_dof_index_for_line_orientation_table[i]=this->dofs_per_line-1-i - i;
+}
+
+
+
+
+template <class POLY, int dim, int spacedim>
+std::vector<unsigned int>
+FE_Q_Base<POLY,dim,spacedim>::get_dpo_vector(const unsigned int deg)
+{
+ std::vector<unsigned int> dpo(dim+1, 1U);
+ for (unsigned int i=1; i<dpo.size(); ++i)
+ dpo[i]=dpo[i-1]*(deg-1);
+ return dpo;
+}
+
+
+
+template <class POLY, int dim, int spacedim>
+void
+FE_Q_Base<POLY,dim,spacedim>::initialize_constraints (const std::vector<Point<1> > &points)
+{
+ Implementation::initialize_constraints (points, *this);
+}
+
+
+
+template <class POLY, int dim, int spacedim>
+const FullMatrix<double>&
+FE_Q_Base<POLY,dim,spacedim>
+::get_prolongation_matrix (const unsigned int child,
+ const RefinementCase<dim> &refinement_case) const
+{
+ Assert (refinement_case<RefinementCase<dim>::isotropic_refinement+1,
+ ExcIndexRange(refinement_case,0,RefinementCase<dim>::isotropic_refinement+1));
+ Assert (refinement_case!=RefinementCase<dim>::no_refinement,
+ ExcMessage("Prolongation matrices are only available for refined cells!"));
+ Assert (child<GeometryInfo<dim>::n_children(refinement_case),
+ ExcIndexRange(child,0,GeometryInfo<dim>::n_children(refinement_case)));
+
+ // initialization upon first request
+ if (this->prolongation[refinement_case-1][child].n() == 0)
+ {
+ Threads::Mutex::ScopedLock lock(this->mutex);
+
+ // if matrix got updated while waiting for the lock
+ if (this->prolongation[refinement_case-1][child].n() ==
+ this->dofs_per_cell)
+ return this->prolongation[refinement_case-1][child];
+
+ // distinguish q/q_dg0 case: only treat Q dofs first
+ const unsigned int q_dofs_per_cell = Utilities::fixed_power<dim>(this->degree+1);
+
+ // compute the interpolation matrices in much the same way as we do for
+ // the constraints. it's actually simpler here, since we don't have this
+ // weird renumbering stuff going on. The trick is again that we the
+ // interpolation matrix is formed by a permutation of the indices of the
+ // cell matrix. The value eps is used a threshold to decide when certain
+ // evaluations of the Lagrange polynomials are zero or one.
+ const double eps = 1e-15*this->degree*dim;
+
+#ifdef DEBUG
+ // in DEBUG mode, check that the evaluation of support points in the
+ // current numbering gives the identity operation
+ for (unsigned int i=0; i<q_dofs_per_cell; ++i)
+ {
+ Assert (std::fabs (1.-this->poly_space.compute_value
+ (i, this->unit_support_points[i])) < eps,
+ ExcInternalError());
+ for (unsigned int j=0; j<q_dofs_per_cell; ++j)
+ if (j!=i)
+ Assert (std::fabs (this->poly_space.compute_value
+ (i, this->unit_support_points[j])) < eps,
+ ExcInternalError());
+ }
+#endif
+
+ // to efficiently evaluate the polynomial at the subcell, make use of
+ // the tensor product structure of this element and only evaluate 1D
+ // information from the polynomial. This makes the cost of this function
+ // almost negligible also for high order elements
+ const unsigned int dofs1d = this->degree+1;
+ std::vector<Table<2,double> >
+ subcell_evaluations (dim, Table<2,double>(dofs1d, dofs1d));
+ const std::vector<unsigned int> &index_map_inverse =
+ this->poly_space.get_numbering_inverse();
+
+ // helper value: step size how to walk through diagonal and how many
+ // points we have left apart from the first dimension
+ unsigned int step_size_diag = 0;
+ {
+ unsigned int factor = 1;
+ for (unsigned int d=0; d<dim; ++d)
+ {
+ step_size_diag += factor;
+ factor *= dofs1d;
+ }
+ }
+
+ FullMatrix<double> prolongate (this->dofs_per_cell, this->dofs_per_cell);
+
+ // go through the points in diagonal to capture variation in all
+ // directions simultaneously
+ for (unsigned int j=0; j<dofs1d; ++j)
+ {
+ const unsigned int diag_comp = index_map_inverse[j*step_size_diag];
+ const Point<dim> p_subcell = this->unit_support_points[diag_comp];
+ const Point<dim> p_cell =
+ GeometryInfo<dim>::child_to_cell_coordinates (p_subcell, child,
+ refinement_case);
+ for (unsigned int i=0; i<dofs1d; ++i)
+ for (unsigned int d=0; d<dim; ++d)
+ {
+ // evaluate along line where only x is different from zero
+ Point<dim> point;
+ point[0] = p_cell[d];
+ const double cell_value =
+ this->poly_space.compute_value(index_map_inverse[i], point);
+
+ // cut off values that are too small. note that we have here
+ // Lagrange interpolation functions, so they should be zero at
+ // almost all points, and one at the others, at least on the
+ // subcells. so set them to their exact values
+ //
+ // the actual cut-off value is somewhat fuzzy, but it works
+ // for 2e-13*degree*dim (see above), which is kind of
+ // reasonable given that we compute the values of the
+ // polynomials via an degree-step recursion and then multiply
+ // the 1d-values. this gives us a linear growth in degree*dim,
+ // times a small constant.
+ //
+ // the embedding matrix is given by applying the inverse of
+ // the subcell matrix on the cell_interpolation matrix. since
+ // the subcell matrix is actually only a permutation vector,
+ // all we need to do is to switch the rows we write the data
+ // into. moreover, cut off very small values here
+ if (std::fabs(cell_value) < eps)
+ subcell_evaluations[d](j,i) = 0;
+ else
+ subcell_evaluations[d](j,i) = cell_value;
+ }
+ }
+
+ // now expand from 1D info. block innermost dimension (x_0) in order to
+ // avoid difficult checks at innermost loop
+ unsigned int j_indices[dim];
+ FE_Q_Helper::zero_indices<dim> (j_indices);
+ for (unsigned int j=0; j<q_dofs_per_cell; j+=dofs1d)
+ {
+ unsigned int i_indices[dim];
+ FE_Q_Helper::zero_indices<dim> (i_indices);
+ for (unsigned int i=0; i<q_dofs_per_cell; i+=dofs1d)
+ {
+ double val_extra_dim = 1.;
+ for (unsigned int d=1; d<dim; ++d)
+ val_extra_dim *= subcell_evaluations[d](j_indices[d-1],
+ i_indices[d-1]);
+
+ // innermost sum where we actually compute. the same as
+ // prolongate(j,i) = this->poly_space.compute_value (i, p_cell)
+ for (unsigned int jj=0; jj<dofs1d; ++jj)
+ {
+ const unsigned int j_ind = index_map_inverse[j+jj];
+ for (unsigned int ii=0; ii<dofs1d; ++ii)
+ prolongate(j_ind,index_map_inverse[i+ii])
+ = val_extra_dim * subcell_evaluations[0](jj,ii);
+ }
+
+ // update indices that denote the tensor product position. a bit
+ // fuzzy and therefore not done for innermost x_0 direction
+ FE_Q_Helper::increment_indices<dim> (i_indices, dofs1d);
+ }
+ Assert (i_indices[dim-1] == 1, ExcInternalError());
+ FE_Q_Helper::increment_indices<dim> (j_indices, dofs1d);
+ }
+
+ // the discontinuous node is simply mapped on the discontinuous node on
+ // the child element
+ if (q_dofs_per_cell < this->dofs_per_cell)
+ prolongate(q_dofs_per_cell,q_dofs_per_cell) = 1.;
+
+ // and make sure that the row sum is 1. this must be so since for this
+ // element, the shape functions add up to one
+#ifdef DEBUG
+ for (unsigned int row=0; row<this->dofs_per_cell; ++row)
+ {
+ double sum = 0;
+ for (unsigned int col=0; col<this->dofs_per_cell; ++col)
+ sum += prolongate(row,col);
+ Assert (std::fabs(sum-1.) < eps, ExcInternalError());
+ }
+#endif
+
+ // swap matrices
+ std::swap(const_cast<FullMatrix<double> &>
+ (this->prolongation[refinement_case-1][child]), prolongate);
+ }
+
+ // finally return the matrix
+ return this->prolongation[refinement_case-1][child];
+}
+
+
+
+template <class POLY, int dim, int spacedim>
+const FullMatrix<double>&
+FE_Q_Base<POLY,dim,spacedim>
+::get_restriction_matrix (const unsigned int child,
+ const RefinementCase<dim> &refinement_case) const
+{
+ Assert (refinement_case<RefinementCase<dim>::isotropic_refinement+1,
+ ExcIndexRange(refinement_case,0,RefinementCase<dim>::isotropic_refinement+1));
+ Assert (refinement_case!=RefinementCase<dim>::no_refinement,
+ ExcMessage("Restriction matrices are only available for refined cells!"));
+ Assert (child<GeometryInfo<dim>::n_children(refinement_case),
+ ExcIndexRange(child,0,GeometryInfo<dim>::n_children(refinement_case)));
+
+ // initialization upon first request
+ if (this->restriction[refinement_case-1][child].n() == 0)
+ {
+ Threads::Mutex::ScopedLock lock(this->mutex);
+
+ // if matrix got updated while waiting for the lock...
+ if (this->restriction[refinement_case-1][child].n() ==
+ this->dofs_per_cell)
+ return this->restriction[refinement_case-1][child];
+
+ FullMatrix<double> restriction(this->dofs_per_cell, this->dofs_per_cell);
+ // distinguish q/q_dg0 case
+ const unsigned int q_dofs_per_cell = Utilities::fixed_power<dim>(this->degree+1);
+
+ // for these Lagrange interpolation polynomials, construction of the
+ // restriction matrices is relatively simple. the reason is that the
+ // interpolation points on the mother cell are (except for the case with
+ // arbitrary nonequidistant nodes) always also interpolation points for
+ // some shape function on one or the other child, because we have chosen
+ // equidistant Lagrange interpolation points for the polynomials
+ //
+ // so the only thing we have to find out is: for each shape function on
+ // the mother cell, which is the child cell (possibly more than one) on
+ // which it is located, and which is the corresponding shape function
+ // there. rather than doing it for the shape functions on the mother
+ // cell, we take the interpolation points there
+ //
+ // note that the interpolation point of a shape function can be on the
+ // boundary between subcells. in that case, restriction from children to
+ // mother may produce two or more entries for a dof on the mother
+ // cell. however, this doesn't hurt: since the element is continuous,
+ // the contribution from each child should yield the same result, and
+ // since the element is non-additive we just overwrite one value
+ // (compute on one child) by the same value (compute on a later child),
+ // so we don't have to care about this
+
+ const double eps = 1e-15*this->degree*dim;
+ const std::vector<unsigned int> &index_map_inverse =
+ this->poly_space.get_numbering_inverse();
+
+ const unsigned int dofs1d = this->degree+1;
+ std::vector<Tensor<1,dim> > evaluations1d (dofs1d);
+
+ restriction.reinit(this->dofs_per_cell, this->dofs_per_cell);
+
+ for (unsigned int i=0; i<q_dofs_per_cell; ++i)
+ {
+ unsigned int mother_dof = index_map_inverse[i];
+ const Point<dim> p_cell = this->unit_support_points[mother_dof];
+
+ // check whether this interpolation point is inside this child cell
+ const Point<dim> p_subcell
+ = GeometryInfo<dim>::cell_to_child_coordinates (p_cell, child,
+ refinement_case);
+ if (GeometryInfo<dim>::is_inside_unit_cell (p_subcell))
+ {
+ // same logic as in initialize_embedding to evaluate the
+ // polynomial faster than from the tensor product: since we
+ // evaluate all polynomials, it is much faster to just compute
+ // the 1D values for all polynomials before and then get the
+ // dim-data.
+ for (unsigned int j=0; j<dofs1d; ++j)
+ for (unsigned int d=0; d<dim; ++d)
+ {
+ Point<dim> point;
+ point[0] = p_subcell[d];
+ evaluations1d[j][d] =
+ this->poly_space.compute_value(index_map_inverse[j], point);
+ }
+ unsigned int j_indices[dim];
+ FE_Q_Helper::zero_indices<dim> (j_indices);
+ double sum_check = 0;
+ for (unsigned int j = 0; j<q_dofs_per_cell; j += dofs1d)
+ {
+ double val_extra_dim = 1.;
+ for (unsigned int d=1; d<dim; ++d)
+ val_extra_dim *= evaluations1d[j_indices[d-1]][d];
+ for (unsigned int jj=0; jj<dofs1d; ++jj)
+ {
+
+ // find the child shape function(s) corresponding to
+ // this point. Usually this is just one function;
+ // however, when we use FE_Q on arbitrary nodes a parent
+ // support point might not be a child support point, and
+ // then we will get more than one nonzero value per
+ // row. Still, the values should sum up to 1
+ const double val
+ = val_extra_dim * evaluations1d[jj][0];
+ const unsigned int child_dof =
+ index_map_inverse[j+jj];
+ if (std::fabs (val-1.) < eps)
+ restriction(mother_dof,child_dof)=1.;
+ else if (std::fabs(val) > eps)
+ restriction(mother_dof,child_dof)=val;
+ sum_check += val;
+ }
+ FE_Q_Helper::increment_indices<dim> (j_indices, dofs1d);
+ }
+ Assert (std::fabs(sum_check-1) < eps,
+ ExcInternalError());
+ }
+
+ // part for FE_Q_DG0
+ if (q_dofs_per_cell < this->dofs_per_cell)
+ restriction(this->dofs_per_cell-1,this->dofs_per_cell-1) =
+ 1./GeometryInfo<dim>::n_children(RefinementCase<dim>(refinement_case));
+ }
+
+ // swap matrices
+ std::swap(const_cast<FullMatrix<double> &>
+ (this->restriction[refinement_case-1][child]), restriction);
+
+ }
+
+ return this->restriction[refinement_case-1][child];
+}
+
+
+
+//---------------------------------------------------------------------------
+// Data field initialization
+//---------------------------------------------------------------------------
+
+
+template <class POLY, int dim, int spacedim>
+bool
+FE_Q_Base<POLY,dim,spacedim>::has_support_on_face (const unsigned int shape_index,
+ const unsigned int face_index) const
+{
+ Assert (shape_index < this->dofs_per_cell,
+ ExcIndexRange (shape_index, 0, this->dofs_per_cell));
+ Assert (face_index < GeometryInfo<dim>::faces_per_cell,
+ ExcIndexRange (face_index, 0, GeometryInfo<dim>::faces_per_cell));
+
+ // in 1d, things are simple. since there is only one degree of freedom per
+ // vertex in this class, the first is on vertex 0 (==face 0 in some sense),
+ // the second on face 1:
+ if (dim == 1)
+ return (((shape_index == 0) && (face_index == 0)) ||
+ ((shape_index == 1) && (face_index == 1)));
+
+ // first, special-case interior shape functions, since they have no support
+ // no-where on the boundary
+ if (((dim==2) && (shape_index>=this->first_quad_index))
+ ||
+ ((dim==3) && (shape_index>=this->first_hex_index)))
+ return false;
+
+ // let's see whether this is a vertex
+ if (shape_index < this->first_line_index)
+ {
+ // for Q elements, there is one dof per vertex, so
+ // shape_index==vertex_number. check whether this vertex is on the given
+ // face. thus, for each face, give a list of vertices
+ const unsigned int vertex_no = shape_index;
+ Assert (vertex_no < GeometryInfo<dim>::vertices_per_cell,
+ ExcInternalError());
+
+ for (unsigned int v=0; v<GeometryInfo<dim>::vertices_per_face; ++v)
+ if (GeometryInfo<dim>::face_to_cell_vertices(face_index, v) == vertex_no)
+ return true;
+
+ return false;
+ }
+ else if (shape_index < this->first_quad_index)
+ // ok, dof is on a line
+ {
+ const unsigned int line_index
+ = (shape_index - this->first_line_index) / this->dofs_per_line;
+ Assert (line_index < GeometryInfo<dim>::lines_per_cell,
+ ExcInternalError());
+
+ // in 2d, the line is the face, so get the line index
+ if (dim == 2)
+ return (line_index == face_index);
+ else if (dim == 3)
+ {
+ // silence compiler warning
+ const unsigned int lines_per_face =
+ dim == 3 ? GeometryInfo<dim>::lines_per_face : 1;
+ // see whether the given line is on the given face.
+ for (unsigned int l=0; l<lines_per_face; ++l)
+ if (GeometryInfo<3>::face_to_cell_lines(face_index, l) == line_index)
+ return true;
+
+ return false;
+ }
+ else
+ Assert (false, ExcNotImplemented());
+ }
+ else if (shape_index < this->first_hex_index)
+ // dof is on a quad
+ {
+ const unsigned int quad_index
+ = (shape_index - this->first_quad_index) / this->dofs_per_quad;
+ Assert (static_cast<signed int>(quad_index) <
+ static_cast<signed int>(GeometryInfo<dim>::quads_per_cell),
+ ExcInternalError());
+
+ // in 2d, cell bubble are zero on all faces. but we have treated this
+ // case above already
+ Assert (dim != 2, ExcInternalError());
+
+ // in 3d, quad_index=face_index
+ if (dim == 3)
+ return (quad_index == face_index);
+ else
+ Assert (false, ExcNotImplemented());
+ }
+ else
+ // dof on hex
+ {
+ // can only happen in 3d, but this case has already been covered above
+ Assert (false, ExcNotImplemented());
+ return false;
+ }
+
+ // we should not have gotten here
+ Assert (false, ExcInternalError());
+ return false;
+}
+
+
+
+// explicit instantiations
+#include "fe_q_base.inst"
+
+DEAL_II_NAMESPACE_CLOSE
--- /dev/null
+//---------------------------------------------------------------------------
+// $Id$
+// Version: $Name$
+//
+// Copyright (C) 2013 by the deal.II authors
+//
+// This file is subject to QPL and may not be distributed
+// without copyright and license information. Please refer
+// to the file deal.II/doc/license.html for the text and
+// further information on this license.
+//
+//---------------------------------------------------------------------------
+
+
+for (deal_II_dimension : DIMENSIONS; deal_II_space_dimension : SPACE_DIMENSIONS)
+ {
+#if deal_II_dimension <= deal_II_space_dimension
+ template class FE_Q_Base<TensorProductPolynomials<deal_II_dimension>, deal_II_dimension, deal_II_space_dimension>;
+ template class FE_Q_Base<TensorProductPolynomialsConst<deal_II_dimension>, deal_II_dimension, deal_II_space_dimension>;
+ template class FE_Q_Base<TensorProductPolynomials<deal_II_dimension,Polynomials::PiecewisePolynomial<double> >, deal_II_dimension, deal_II_space_dimension>;
+#endif
+ }
+
+
+//---------------------------------------------------------------------------
+// $Id: fe_q.cc 28798 2013-03-07 17:00:02Z maier $
+// Version: $Name$
+//
+// Copyright (C) 2012, 2013 by the deal.II authors
+//
+// This file is subject to QPL and may not be distributed
+// without copyright and license information. Please refer
+// to the file deal.II/doc/license.html for the text and
+// further information on this license.
+//
+//---------------------------------------------------------------------------
+
#include <deal.II/base/quadrature.h>
#include <deal.II/base/qprojector.h>
#include <deal.II/base/template_constraints.h>
#include <deal.II/fe/fe_q_dg0.h>
#include <deal.II/fe/fe_nothing.h>
-#include <deal.II/fe/fe_tools.h>
#include <deal.II/base/quadrature_lib.h>
#include <deal.II/dofs/dof_accessor.h>
DEAL_II_NAMESPACE_OPEN
-// namespace for some functions that are used in this file. they are
-// specific to numbering conventions used for the FE_Q element, and
-// are thus not very interesting to the outside world. we'd like to
-// simply put them into an anonymous namespace, but that triggers an
-// odd error with icc which can't compile this small snippet if the
-// function is static:
-// --------------------
-// template <int> struct int2type {};
-//
-// namespace {
-// static void SYMBOL (const int2type<1> & ) {}
-// }
-//
-// template <int dim, int spacedim> void g() {
-// SYMBOL(int2type<dim>());
-// }
-//
-// template void g<1>();
-// --------------------
-// the function needs to be static because of another icc bug, though.
-// work around this by packing everything into a namespace of its own
-// and have the anonymous namespace inside
-//
-// this is now intel icc issue 216082
-namespace FE_Q_DG0_Helper
-{
- namespace
- {
- // given a permutation array,
- // compute and return the inverse
- // permutation
-#ifdef DEAL_II_ANON_NAMESPACE_BUG
- static
-#endif
- inline
- std::vector<unsigned int>
- invert_numbering (const std::vector<unsigned int> &in)
- {
- std::vector<unsigned int> out (in.size());
- for (unsigned int i=0; i<in.size(); ++i)
- out[in[i]]=i;
- return out;
- }
-
- // in initialize_embedding() and
- // initialize_restriction(), want to undo
- // tensorization on inner loops for
- // performance reasons. this clears a
- // dim-array
- template <int dim>
- inline
- void
- zero_indices (unsigned int indices[dim])
- {
- for (unsigned int d=0; d<dim; ++d)
- indices[d] = 0;
- }
-
- // in initialize_embedding() and
- // initialize_restriction(), want to undo
- // tensorization on inner loops for
- // performance reasons. this increments tensor
- // product indices
- template <int dim>
- inline
- void
- increment_indices (unsigned int indices[dim],
- const unsigned int dofs1d)
- {
- ++indices[0];
- for (int d=0; d<dim-1; ++d)
- if (indices[d]==dofs1d)
- {
- indices[d] = 0;
- indices[d+1]++;
- }
- }
-
- // in initialize_embedding() and
- // initialize_restriction(), want to undo
- // tensorization on inner loops for
- // performance reasons, and we need to again
- // access 1D polynomials. This function
- // creates them from dim-dimensional support
- // points.
- template <int dim>
- inline
- std::vector<Polynomials::Polynomial<double> >
- generate_poly_space1d (const std::vector<Point<dim> > &unit_support_points,
- const std::vector<unsigned int> &index_map_inverse,
- const unsigned int dofs1d)
- {
- AssertDimension (Utilities::fixed_power<dim> (dofs1d)+1,
- unit_support_points.size());
- std::vector<Point<1> > points1d (dofs1d);
- for (unsigned int i=0; i<dofs1d; ++i)
- {
- const unsigned int j = index_map_inverse[i];
- points1d[i] = Point<1>(unit_support_points[j](0));
- for (unsigned int d=1; d<dim; ++d)
- Assert (unit_support_points[j][d] == 0.,
- ExcInternalError());
- }
- return Polynomials::generate_complete_Lagrange_basis (points1d);
- }
- }
-}
-
-
-
-/**
- * A class with the same purpose as the similarly named class of the
- * Triangulation class. See there for more information.
- */
-template <int xdim, int xspacedim>
-struct FE_Q_DG0<xdim,xspacedim>::Implementation
-{
- /**
- * Initialize the hanging node
- * constraints matrices. Called from the
- * constructor in case the finite element
- * is based on quadrature points.
- */
- template <int spacedim>
- static
- void initialize_constraints (const Quadrature<1> &,
- FE_Q_DG0<1,spacedim> &)
- {
- // no constraints in 1d
- }
-
-
- template <int spacedim>
- static
- void initialize_constraints (const Quadrature<1> &points,
- FE_Q_DG0<2,spacedim> &fe)
- {
- const unsigned int dim = 2;
-
- // restricted to each face, the
- // traces of the shape functions is
- // an element of P_{k} (in 2d), or
- // Q_{k} (in 3d), where k is the
- // degree of the element. from
- // this, we interpolate between
- // mother and cell face.
-
- // the interpolation process works
- // as follows: on each subface,
- // we want that finite element
- // solutions from both sides
- // coincide. i.e. if a and b are
- // expansion coefficients for the
- // shape functions from both sides,
- // we seek a relation between a and
- // b such that
- // sum_j a_j phi^c_j(x)
- // == sum_j b_j phi_j(x)
- // for all points x on the
- // interface. here, phi^c_j are the
- // shape functions on the small
- // cell on one side of the face,
- // and phi_j those on the big cell
- // on the other side. To get this
- // relation, it suffices to look at
- // a sufficient number of points
- // for which this has to hold. if
- // there are n functions, then we
- // need n evaluation points, and we
- // choose them equidistantly.
- //
- // we obtain the matrix system
- // A a == B b
- // where
- // A_ij = phi^c_j(x_i)
- // B_ij = phi_j(x_i)
- // and the relation we are looking
- // for is
- // a = A^-1 B b
- //
- // for the special case of Lagrange
- // interpolation polynomials, A_ij
- // reduces to delta_ij, and
- // a_i = B_ij b_j
- // Hence,
- // interface_constraints(i,j)=B_ij.
- //
- // for the general case, where we
- // don't have Lagrange
- // interpolation polynomials, this
- // is a little more
- // complicated. Then we would
- // evaluate at a number of points
- // and invert the interpolation
- // matrix A.
- //
- // Note, that we build up these
- // matrices for all subfaces at
- // once, rather than considering
- // them separately. the reason is
- // that we finally will want to
- // have them in this order anyway,
- // as this is the format we need
- // inside deal.II
-
- // In the following the points x_i
- // are constructed in following
- // order (n=degree-1)
- // *----------*---------*
- // 1..n 0 n+1..2n
- // i.e. first the midpoint of the
- // line, then the support points on
- // subface 0 and on subface 1
- std::vector<Point<dim-1> > constraint_points;
- // Add midpoint
- constraint_points.push_back (Point<dim-1> (0.5));
-
- if (fe.degree>1)
- {
- const unsigned int n=fe.degree-1;
- const double step=1./fe.degree;
- // subface 0
- for (unsigned int i=1; i<=n; ++i)
- constraint_points.push_back (
- GeometryInfo<dim-1>::child_to_cell_coordinates(Point<dim-1>(i*step),0));
- // subface 1
- for (unsigned int i=1; i<=n; ++i)
- constraint_points.push_back (
- GeometryInfo<dim-1>::child_to_cell_coordinates(Point<dim-1>(i*step),1));
- }
-
- // Now construct relation between
- // destination (child) and source (mother)
- // dofs.
- const std::vector<Polynomials::Polynomial<double> > polynomials=
- Polynomials::generate_complete_Lagrange_basis(points.get_points());
-
- fe.interface_constraints
- .TableBase<2,double>::reinit (fe.interface_constraints_size());
-
- for (unsigned int i=0; i<constraint_points.size(); ++i)
- for (unsigned int j=0; j<fe.degree+1; ++j)
- {
- fe.interface_constraints(i,j) =
- polynomials[fe.face_index_map[j]].value (constraint_points[i](0));
-
- // if the value is small up
- // to round-off, then
- // simply set it to zero to
- // avoid unwanted fill-in
- // of the constraint
- // matrices (which would
- // then increase the number
- // of other DoFs a
- // constrained DoF would
- // couple to)
- if (std::fabs(fe.interface_constraints(i,j)) < 1e-14)
- fe.interface_constraints(i,j) = 0;
- }
- }
-
-
- template <int spacedim>
- static
- void initialize_constraints (const Quadrature<1> &points,
- FE_Q_DG0<3,spacedim> &fe)
- {
- const unsigned int dim = 3;
-
- // For a detailed documentation of
- // the interpolation see the
- // FE_Q<2>::initialize_constraints
- // function.
-
- // In the following the points x_i
- // are constructed in the order as
- // described in the documentation
- // of the FiniteElement class
- // (fe_base.h), i.e.
- // *--15--4--16--*
- // | | |
- // 10 19 6 20 12
- // | | |
- // 1--7---0--8---2
- // | | |
- // 9 17 5 18 11
- // | | |
- // *--13--3--14--*
- std::vector<Point<dim-1> > constraint_points;
-
- // Add midpoint
- constraint_points.push_back (Point<dim-1> (0.5, 0.5));
-
- // Add midpoints of lines of
- // "mother-face"
- constraint_points.push_back (Point<dim-1> (0, 0.5));
- constraint_points.push_back (Point<dim-1> (1, 0.5));
- constraint_points.push_back (Point<dim-1> (0.5, 0));
- constraint_points.push_back (Point<dim-1> (0.5, 1));
-
- if (fe.degree>1)
- {
- const unsigned int n=fe.degree-1;
- const double step=1./fe.degree;
- std::vector<Point<dim-2> > line_support_points(n);
- for (unsigned int i=0; i<n; ++i)
- line_support_points[i](0)=(i+1)*step;
- Quadrature<dim-2> qline(line_support_points);
-
- // auxiliary points in 2d
- std::vector<Point<dim-1> > p_line(n);
-
- // Add nodes of lines interior
- // in the "mother-face"
-
- // line 5: use line 9
- QProjector<dim-1>::project_to_subface(qline, 0, 0, p_line);
- for (unsigned int i=0; i<n; ++i)
- constraint_points.push_back (p_line[i] + Point<dim-1> (0.5, 0));
- // line 6: use line 10
- QProjector<dim-1>::project_to_subface(qline, 0, 1, p_line);
- for (unsigned int i=0; i<n; ++i)
- constraint_points.push_back (p_line[i] + Point<dim-1> (0.5, 0));
- // line 7: use line 13
- QProjector<dim-1>::project_to_subface(qline, 2, 0, p_line);
- for (unsigned int i=0; i<n; ++i)
- constraint_points.push_back (p_line[i] + Point<dim-1> (0, 0.5));
- // line 8: use line 14
- QProjector<dim-1>::project_to_subface(qline, 2, 1, p_line);
- for (unsigned int i=0; i<n; ++i)
- constraint_points.push_back (p_line[i] + Point<dim-1> (0, 0.5));
-
- // DoFs on bordering lines
- // lines 9-16
- for (unsigned int face=0; face<GeometryInfo<dim-1>::faces_per_cell; ++face)
- for (unsigned int subface=0;
- subface<GeometryInfo<dim-1>::max_children_per_face; ++subface)
- {
- QProjector<dim-1>::project_to_subface(qline, face, subface, p_line);
- constraint_points.insert(constraint_points.end(),
- p_line.begin(), p_line.end());
- }
-
- // Create constraints for
- // interior nodes
- std::vector<Point<dim-1> > inner_points(n*n);
- for (unsigned int i=0, iy=1; iy<=n; ++iy)
- for (unsigned int ix=1; ix<=n; ++ix)
- inner_points[i++] = Point<dim-1> (ix*step, iy*step);
-
- // at the moment do this for
- // isotropic face refinement only
- for (unsigned int child=0;
- child<GeometryInfo<dim-1>::max_children_per_cell; ++child)
- for (unsigned int i=0; i<inner_points.size(); ++i)
- constraint_points.push_back (
- GeometryInfo<dim-1>::child_to_cell_coordinates(inner_points[i], child));
- }
-
- // Now construct relation between
- // destination (child) and source (mother)
- // dofs.
- const unsigned int pnts=(fe.degree+1)*(fe.degree+1);
- const std::vector<Polynomials::Polynomial<double> > polynomial_basis=
- Polynomials::generate_complete_Lagrange_basis(points.get_points());
-
- const TensorProductPolynomialsConst<dim-1> face_polynomials(polynomial_basis);
-
- fe.interface_constraints
- .TableBase<2,double>::reinit (fe.interface_constraints_size());
-
- for (unsigned int i=0; i<constraint_points.size(); ++i)
- {
- const double interval = (double) (fe.degree * 2);
- bool mirror[dim - 1];
- Point<dim-1> constraint_point;
-
- // Eliminate FP errors in constraint
- // points. Due to their origin, they
- // must all be fractions of the unit
- // interval. If we have polynomial
- // degree 4, the refined element has 8
- // intervals. Hence the coordinates
- // must be 0, 0.125, 0.25, 0.375 etc.
- // Now the coordinates of the
- // constraint points will be multiplied
- // by the inverse of the interval size
- // (in the example by 8). After that
- // the coordinates must be integral
- // numbers. Hence a normal truncation
- // is performed and the coordinates
- // will be scaled back. The equal
- // treatment of all coordinates should
- // eliminate any FP errors.
- for (unsigned int k=0; k<dim-1; ++k)
- {
- const int coord_int =
- static_cast<int> (constraint_points[i](k) * interval + 0.25);
- constraint_point(k) = 1.*coord_int / interval;
-
- // The following lines of code
- // should eliminate the problems
- // with the Constraint-Matrix,
- // which appeared for P>=4. The
- // Constraint-Matrix class
- // complained about different
- // constraints for the same entry
- // of the Constraint-Matrix.
- // Actually this difference could
- // be attributed to FP errors, as
- // it was in the range of
- // 1.0e-16. These errors originate
- // in the loss of symmetry in the
- // FP approximation of the
- // shape-functions. Considering a
- // 3rd order shape function in 1D,
- // we have N0(x)=N3(1-x) and
- // N1(x)=N2(1-x). For higher order
- // polynomials the FP
- // approximations of the shape
- // functions do not satisfy these
- // equations any more! Thus in the
- // following code everything is
- // computed in the interval x \in
- // [0..0.5], which is sufficient to
- // express all values that could
- // come out from a computation of
- // any shape function in the full
- // interval [0..1]. If x > 0.5 the
- // computation is done for 1-x with
- // the shape function N_{p-n}
- // instead of N_n. Hence symmetry
- // is preserved and everything
- // works fine...
- //
- // For a different explanation of
- // the problem, see the discussion
- // in the FiniteElement class
- // for constraint matrices in 3d.
- mirror[k] = (constraint_point(k) > 0.5);
- if (mirror[k])
- constraint_point(k) = 1.0 - constraint_point(k);
- }
-
- for (unsigned int j=0; j<pnts; ++j)
- {
- unsigned int indices[2]
- = { fe.face_index_map[j] % (fe.degree + 1),
- fe.face_index_map[j] / (fe.degree + 1)
- };
-
- for (unsigned int k = 0; k<2; ++k)
- if (mirror[k])
- indices[k] = fe.degree - indices[k];
-
- const unsigned int
- new_index = indices[1] * (fe.degree + 1) + indices[0];
-
- fe.interface_constraints(i,j) =
- face_polynomials.compute_value (new_index, constraint_point);
-
- // if the value is small up
- // to round-off, then
- // simply set it to zero to
- // avoid unwanted fill-in
- // of the constraint
- // matrices (which would
- // then increase the number
- // of other DoFs a
- // constrained DoF would
- // couple to)
- if (std::fabs(fe.interface_constraints(i,j)) < 1e-14)
- fe.interface_constraints(i,j) = 0;
- }
- }
- }
-};
-
-
template <int dim, int spacedim>
FE_Q_DG0<dim,spacedim>::FE_Q_DG0 (const unsigned int degree)
:
- FE_Poly<TensorProductPolynomialsConst<dim>, dim, spacedim> (
+ FE_Q_Base<TensorProductPolynomialsConst<dim>, dim, spacedim> (
TensorProductPolynomialsConst<dim>(Polynomials::LagrangeEquidistant::generate_complete_basis(degree)),
FiniteElementData<dim>(get_dpo_vector(degree),
1, degree,
FiniteElementData<dim>::L2),
- get_riaf_vector(degree),
- std::vector<ComponentMask>(1ll , std::vector<bool>(1,true))),
- face_index_map(FE_Q_DG0_Helper::invert_numbering(
- face_lexicographic_to_hierarchic_numbering (degree)))
+ get_riaf_vector(degree))
{
Assert (degree > 0,
ExcMessage ("This element can only be used for polynomial degrees "
"greater than zero"));
- std::vector<unsigned int> renumber (this->dofs_per_cell-1);
- const FiniteElementData<dim> fe(get_dpo_vector_q(degree),1,degree);
- FETools::hierarchic_to_lexicographic_numbering (fe, renumber);
- renumber.push_back(this->dofs_per_cell-1);
- this->poly_space.set_numbering(renumber);
-
- // finally fill in support points
- // on cell and face
- initialize_unit_support_points ();
- initialize_unit_face_support_points ();
+ std::vector<Point<1> > support_points_1d(degree+1);
+ for (unsigned int i=0; i<=degree; ++i)
+ support_points_1d[i][0] = static_cast<double>(i)/degree;
- // reinit constraints
- initialize_constraints ();
+ this->initialize(support_points_1d);
- // Reinit the vectors of restriction and prolongation matrices to the
- // right sizes and compute the matrices
- this->reinit_restriction_and_prolongation_matrices();
- initialize_embedding();
- initialize_restriction();
-
- initialize_quad_dof_index_permutation();
+ // adjust unit support point for discontinuous node
+ Point<dim> point;
+ for (unsigned int d=0; d<dim; ++d)
+ point[d] = 0.5;
+ this->unit_support_points.push_back(point);
+ AssertDimension(this->dofs_per_cell, this->unit_support_points.size());
}
template <int dim, int spacedim>
FE_Q_DG0<dim,spacedim>::FE_Q_DG0 (const Quadrature<1> &points)
:
- FE_Poly<TensorProductPolynomialsConst<dim>, dim, spacedim> (
+ FE_Q_Base<TensorProductPolynomialsConst<dim>, dim, spacedim> (
TensorProductPolynomialsConst<dim>(Polynomials::generate_complete_Lagrange_basis(points.get_points())),
FiniteElementData<dim>(get_dpo_vector(points.size()-1),
1, points.size()-1,
FiniteElementData<dim>::L2),
- get_riaf_vector(points.size()-1),
- std::vector<ComponentMask>(1, std::vector<bool>(1,true))),
-
- face_index_map(FE_Q_DG0_Helper::invert_numbering(
- face_lexicographic_to_hierarchic_numbering (points.size()-1)))
+ get_riaf_vector(points.size()-1))
{
const int degree = points.size()-1;
Assert (degree > 0,
ExcMessage ("This element can only be used for polynomial degrees "
"at least zero"));
- Assert (points.point(0)(0) == 0,
- ExcMessage ("The first support point has to be zero."));
- Assert (points.point(degree)(0) == 1,
- ExcMessage ("The last support point has to be one."));
-
- std::vector<unsigned int> renumber (this->dofs_per_cell-1);
- const FiniteElementData<dim> fe(get_dpo_vector_q(degree),1,degree);
- FETools::hierarchic_to_lexicographic_numbering (fe, renumber);
- renumber.push_back(this->dofs_per_cell-1);
- this->poly_space.set_numbering(renumber);
-
- // finally fill in support points
- // on cell and face
- initialize_unit_support_points (points);
- initialize_unit_face_support_points (points);
- // reinit constraints
- Implementation::initialize_constraints (points, *this);
+ this->initialize(points.get_points());
- // Reinit the vectors of restriction and prolongation matrices to the
- // right sizes and compute the matrices
- this->reinit_restriction_and_prolongation_matrices();
- initialize_embedding();
- initialize_restriction();
-
- initialize_quad_dof_index_permutation();
+ // adjust unit support point for discontinuous node
+ Point<dim> point;
+ for (unsigned int d=0; d<dim; ++d)
+ point[d] = 0.5;
+ this->unit_support_points.push_back(point);
+ AssertDimension(this->dofs_per_cell, this->unit_support_points.size());
}
std::string
FE_Q_DG0<dim,spacedim>::get_name () const
{
- // note that the
- // FETools::get_fe_from_name
- // function depends on the
- // particular format of the string
- // this function returns, so they
- // have to be kept in synch
+ // note that the FETools::get_fe_from_name function depends on the
+ // particular format of the string this function returns, so they have to be
+ // kept in synch
std::ostringstream namebuf;
bool type = true;
const std::vector<Point<dim> > &unit_support_points = this->unit_support_points;
unsigned int index = 0;
- // Decode the support points
- // in one coordinate direction.
+ // Decode the support points in one coordinate direction.
for (unsigned int j=0; j<dofs_per_cell; j++)
{
if ((dim>1) ? (unit_support_points[j](1)==0 &&
index++;
}
}
- //Do not consider the discontinuous node for dimension 1
+ // Do not consider the discontinuous node for dimension 1
Assert (index == n_points || (dim==1 && index == n_points+1),
ExcMessage ("Could not decode support points in one coordinate direction."));
- // Check whether the support
- // points are equidistant.
+ // Check whether the support points are equidistant.
for (unsigned int j=0; j<n_points; j++)
if (std::fabs(points[j] - (double)j/this->degree) > 1e-15)
{
else
{
- // Check whether the support
- // points come from QGaussLobatto.
+ // Check whether the support points come from QGaussLobatto.
const QGaussLobatto<1> points_gl(n_points);
type = true;
for (unsigned int j=0; j<n_points; j++)
return new FE_Q_DG0<dim,spacedim>(*this);
}
+
+
template <int dim, int spacedim>
void
FE_Q_DG0<dim,spacedim>::interpolate(std::vector<double> &local_dofs,
ExcDimensionMismatch(this->n_components(), 1));
std::copy(values.begin(), values.end(), local_dofs.begin());
- //We don't need the discontinuous function for local interpolation
- local_dofs[local_dofs.size()-1]=0.;
+
+ // We don't need the discontinuous function for local interpolation
+ local_dofs[local_dofs.size()-1] = 0.;
}
+
+
template <int dim, int spacedim>
void
FE_Q_DG0<dim,spacedim>::interpolate(std::vector<double> &local_dofs,
= this->system_to_component_index(i);
local_dofs[i] = values[i](offset+index.first);
}
- //We don't need the discontinuous function for local interpolation
- local_dofs[local_dofs.size()-1]=0.;
-}
+ // We don't need the discontinuous function for local interpolation
+ local_dofs[local_dofs.size()-1] = 0.;
+}
= this->system_to_component_index(i);
local_dofs[i] = values[index.first][i];
}
- //We don't need the discontinuous function for local interpolation
- local_dofs[local_dofs.size()-1]=0.;
+
+ // We don't need the discontinuous function for local interpolation
+ local_dofs[local_dofs.size()-1] = 0.;
}
+
+
template <int dim, int spacedim>
void
FE_Q_DG0<dim,spacedim>::
get_interpolation_matrix (const FiniteElement<dim,spacedim> &x_source_fe,
FullMatrix<double> &interpolation_matrix) const
{
- // this is only implemented, if the
- // source FE is also a
- // Q_DG0 element
+ // this is only implemented, if the source FE is also a Q_DG0 element
typedef FE_Q_DG0<dim,spacedim> FEQDG0;
typedef FiniteElement<dim,spacedim> FEL;
ExcDimensionMismatch (interpolation_matrix.m(),
x_source_fe.dofs_per_cell));
- // ok, source is a Q_DG0 element, so
- // we will be able to do the work
- const FE_Q_DG0<dim,spacedim> &source_fe
- = dynamic_cast<const FE_Q_DG0<dim,spacedim>&>(x_source_fe);
-
- // compute the interpolation
- // matrices in much the same way as
- // we do for the embedding matrices
- // from mother to child.
- FullMatrix<double> cell_interpolation (this->dofs_per_cell,
- this->dofs_per_cell);
- FullMatrix<double> source_interpolation (this->dofs_per_cell,
- source_fe.dofs_per_cell);
- FullMatrix<double> tmp (this->dofs_per_cell,
- source_fe.dofs_per_cell);
- for (unsigned int j=0; j<this->dofs_per_cell-1; ++j)
- {
- // read in a point on this
- // cell and evaluate the
- // shape functions there
- const Point<dim> p = this->unit_support_points[j];
- for (unsigned int i=0; i<this->dofs_per_cell-1; ++i)
- cell_interpolation(j,i) = this->poly_space.compute_value (i, p);
-
- for (unsigned int i=0; i<source_fe.dofs_per_cell-1; ++i)
- source_interpolation(j,i) = source_fe.poly_space.compute_value (i,p);
-
- }
- //the discontinuous node is not transformed
- cell_interpolation(this->dofs_per_cell-1,
- this->dofs_per_cell-1)=1.;
- source_interpolation(this->dofs_per_cell-1,
- source_fe.dofs_per_cell-1)=1.;
-
- // then compute the
- // interpolation matrix
- // for this coordinate
- // direction
- cell_interpolation.gauss_jordan ();
- cell_interpolation.mmult (interpolation_matrix,
- source_interpolation);
-
- const double eps = 2e-13*this->degree*dim;
-
- // cut off very small values
- for (unsigned int i=0; i<this->dofs_per_cell; ++i)
- for (unsigned int j=0; j<source_fe.dofs_per_cell; ++j)
- if (std::fabs(interpolation_matrix(i,j)) < eps)
- interpolation_matrix(i,j) = 0.;
-
- // make sure that the row sum of
- // each of the matrices is 1 at
- // this point. this must be so
- // since the shape functions sum up
- // to 1
- for (unsigned int i=0; i<this->dofs_per_cell; ++i)
- {
- double sum = 0.;
- for (unsigned int j=0; j<source_fe.dofs_per_cell; ++j)
- sum += interpolation_matrix(i,j);
-
- Assert (std::fabs(sum-1) < eps, ExcInternalError());
- }
-}
-
-
-
-template <>
-void
-FE_Q_DG0<1>::
-get_face_interpolation_matrix (const FiniteElement<1,1> &/*x_source_fe*/,
- FullMatrix<double> &/*interpolation_matrix*/) const
-{
- Assert (false, ExcImpossibleInDim(1));
-}
-
-
-
-template <>
-void
-FE_Q_DG0<1>::
-get_subface_interpolation_matrix (const FiniteElement<1,1> &/*x_source_fe*/,
- const unsigned int /*subface*/,
- FullMatrix<double> &/*interpolation_matrix*/) const
-{
- Assert (false, ExcImpossibleInDim(1));
-}
-
-
-template <>
-void
-FE_Q_DG0<1,2>::
-get_face_interpolation_matrix (const FiniteElement<1,2> &/*x_source_fe*/,
- FullMatrix<double> &/*interpolation_matrix*/) const
-{
- typedef FiniteElement<1,2> FEL;
- Assert (false,
- FEL::
- ExcInterpolationNotImplemented ());
-}
-
-
-template <>
-void
-FE_Q_DG0<1,2>::
-get_subface_interpolation_matrix (const FiniteElement<1,2> &/*x_source_fe*/,
- const unsigned int /*subface*/,
- FullMatrix<double> &/*interpolation_matrix*/) const
-{
- typedef FiniteElement<1,2> FEL;
- Assert (false,
- FEL::
- ExcInterpolationNotImplemented ());
-}
-
-
-template <>
-void
-FE_Q_DG0<1,3>::
-get_face_interpolation_matrix (const FiniteElement<1,3> &/*x_source_fe*/,
- FullMatrix<double> &/*interpolation_matrix*/) const
-{
- typedef FiniteElement<1,3> FEL;
- Assert (false,
- FEL::
- ExcInterpolationNotImplemented ());
-}
-
-
-template <>
-void
-FE_Q_DG0<1,3>::
-get_subface_interpolation_matrix (const FiniteElement<1,3> &/*x_source_fe*/,
- const unsigned int /*subface*/,
- FullMatrix<double> &/*interpolation_matrix*/) const
-{
- typedef FiniteElement<1,3> FEL;
- Assert (false,
- FEL::
- ExcInterpolationNotImplemented ());
+ this->FE_Q_Base<TensorProductPolynomialsConst<dim>,dim,spacedim>::
+ get_interpolation_matrix(x_source_fe, interpolation_matrix);
}
template <int dim, int spacedim>
-void
-FE_Q_DG0<dim,spacedim>::
-get_face_interpolation_matrix (const FiniteElement<dim,spacedim> &x_source_fe,
- FullMatrix<double> &interpolation_matrix) const
+std::vector<bool>
+FE_Q_DG0<dim,spacedim>::get_riaf_vector(const unsigned int deg)
{
- // this is only implemented, if the
- // source FE is also a
- // Q_DG0 element
- typedef FE_Q_DG0<dim,spacedim> FEQDG0;
- typedef FiniteElement<dim,spacedim> FEL;
- AssertThrow ((x_source_fe.get_name().find ("FE_Q_DG0<") == 0)
- ||
- (dynamic_cast<const FEQDG0 *>(&x_source_fe) != 0),
- typename FEL::
- ExcInterpolationNotImplemented());
-
- Assert (interpolation_matrix.n() == this->dofs_per_face,
- ExcDimensionMismatch (interpolation_matrix.n(),
- this->dofs_per_face));
- Assert (interpolation_matrix.m() == x_source_fe.dofs_per_face,
- ExcDimensionMismatch (interpolation_matrix.m(),
- x_source_fe.dofs_per_face));
-
- // ok, source is a Q_DG0 element, so
- // we will be able to do the work
- const FE_Q_DG0<dim,spacedim> &source_fe
- = dynamic_cast<const FE_Q_DG0<dim,spacedim>&>(x_source_fe);
-
- // Make sure, that the element,
- // for which the DoFs should be
- // constrained is the one with
- // the higher polynomial degree.
- // Actually the procedure will work
- // also if this assertion is not
- // satisfied. But the matrices
- // produced in that case might
- // lead to problems in the
- // hp procedures, which use this
- // method.
- Assert (this->dofs_per_face <= source_fe.dofs_per_face,
- typename FEL::
- ExcInterpolationNotImplemented ());
-
- // generate a quadrature
- // with the unit support points.
- // This is later based as a
- // basis for the QProjector,
- // which returns the support
- // points on the face.
- Quadrature<dim-1> quad_face_support (source_fe.get_unit_face_support_points ());
-
- // Rule of thumb for FP accuracy,
- // that can be expected for a
- // given polynomial degree.
- // This value is used to cut
- // off values close to zero.
- const double eps = 2e-13*this->degree*(dim-1);
-
- // compute the interpolation
- // matrix by simply taking the
- // value at the support points.
-//TODO: Verify that all faces are the same with respect to
-// these support points. Furthermore, check if something has to
-// be done for the face orientation flag in 3D.
- const Quadrature<dim> face_quadrature
- = QProjector<dim>::project_to_face (quad_face_support, 0);
- for (unsigned int i=0; i<source_fe.dofs_per_face; ++i)
- {
- const Point<dim> &p = face_quadrature.point (i);
-
- for (unsigned int j=0; j<this->dofs_per_face; ++j)
- {
- double matrix_entry = this->shape_value (this->face_to_cell_index(j, 0), p);
-
- // Correct the interpolated
- // value. I.e. if it is close
- // to 1 or 0, make it exactly
- // 1 or 0. Unfortunately, this
- // is required to avoid problems
- // with higher order elements.
- if (std::fabs (matrix_entry - 1.0) < eps)
- matrix_entry = 1.0;
- if (std::fabs (matrix_entry) < eps)
- matrix_entry = 0.0;
-
- interpolation_matrix(i,j) = matrix_entry;
- }
- }
-
- // make sure that the row sum of
- // each of the matrices is 1 at
- // this point. this must be so
- // since the shape functions sum up
- // to 1
- for (unsigned int j=0; j<source_fe.dofs_per_face; ++j)
- {
- double sum = 0.;
-
- for (unsigned int i=0; i<this->dofs_per_face; ++i)
- sum += interpolation_matrix(j,i);
-
- Assert (std::fabs(sum-1) < 2e-13*this->degree*(dim-1),
- ExcInternalError());
- }
+ std::vector<bool> riaf(Utilities::fixed_power<dim>(deg+1)+1,false);
+ riaf[riaf.size()-1]=true;
+ return riaf;
}
template <int dim, int spacedim>
-void
-FE_Q_DG0<dim,spacedim>::
-get_subface_interpolation_matrix (const FiniteElement<dim,spacedim> &x_source_fe,
- const unsigned int subface,
- FullMatrix<double> &interpolation_matrix) const
+std::vector<unsigned int>
+FE_Q_DG0<dim,spacedim>::get_dpo_vector(const unsigned int deg)
{
- Assert (interpolation_matrix.m() == x_source_fe.dofs_per_face,
- ExcDimensionMismatch (interpolation_matrix.m(),
- x_source_fe.dofs_per_face));
-
- // see if source is a Q_DG0 element
- if (const FE_Q_DG0<dim,spacedim> *source_fe
- = dynamic_cast<const FE_Q_DG0<dim,spacedim> *>(&x_source_fe))
- {
- // have this test in here since
- // a table of size 2x0 reports
- // its size as 0x0
- Assert (interpolation_matrix.n() == this->dofs_per_face,
- ExcDimensionMismatch (interpolation_matrix.n(),
- this->dofs_per_face));
-
- // Make sure, that the element,
- // for which the DoFs should be
- // constrained is the one with
- // the higher polynomial degree.
- // Actually the procedure will work
- // also if this assertion is not
- // satisfied. But the matrices
- // produced in that case might
- // lead to problems in the
- // hp procedures, which use this
- // method.
- Assert (this->dofs_per_face <= source_fe->dofs_per_face,
- (typename FiniteElement<dim,spacedim>::
- ExcInterpolationNotImplemented ()));
-
- // generate a point on this
- // cell and evaluate the
- // shape functions there
- const Quadrature<dim-1>
- quad_face_support (source_fe->get_unit_face_support_points ());
-
- // Rule of thumb for FP accuracy,
- // that can be expected for a
- // given polynomial degree.
- // This value is used to cut
- // off values close to zero.
- double eps = 2e-13*this->degree*(dim-1);
-
- // compute the interpolation
- // matrix by simply taking the
- // value at the support points.
-//TODO: Verify that all faces are the same with respect to
-// these support points. Furthermore, check if something has to
-// be done for the face orientation flag in 3D.
- const Quadrature<dim> subface_quadrature
- = QProjector<dim>::project_to_subface (quad_face_support, 0, subface);
- for (unsigned int i=0; i<source_fe->dofs_per_face; ++i)
- {
- const Point<dim> &p = subface_quadrature.point (i);
-
- for (unsigned int j=0; j<this->dofs_per_face; ++j)
- {
- double matrix_entry = this->shape_value (this->face_to_cell_index(j, 0), p);
-
- // Correct the interpolated
- // value. I.e. if it is close
- // to 1 or 0, make it exactly
- // 1 or 0. Unfortunately, this
- // is required to avoid problems
- // with higher order elements.
- if (std::fabs (matrix_entry - 1.0) < eps)
- matrix_entry = 1.0;
- if (std::fabs (matrix_entry) < eps)
- matrix_entry = 0.0;
-
- interpolation_matrix(i,j) = matrix_entry;
- }
- }
-
- // make sure that the row sum of
- // each of the matrices is 1 at
- // this point. this must be so
- // since the shape functions sum up
- // to 1
- for (unsigned int j=0; j<source_fe->dofs_per_face; ++j)
- {
- double sum = 0.;
-
- for (unsigned int i=0; i<this->dofs_per_face; ++i)
- sum += interpolation_matrix(j,i);
+ std::vector<unsigned int> dpo(dim+1, 1U);
+ for (unsigned int i=1; i<dpo.size(); ++i)
+ dpo[i]=dpo[i-1]*(deg-1);
- Assert (std::fabs(sum-1) < 2e-13*this->degree*dim,
- ExcInternalError());
- }
- }
- else if (dynamic_cast<const FE_Nothing<dim> *>(&x_source_fe) != 0)
- {
- // nothing to do here, the
- // FE_Nothing has no degrees of
- // freedom anyway
- }
- else
- AssertThrow (false,
- (typename FiniteElement<dim,spacedim>::
- ExcInterpolationNotImplemented()));
+ dpo[dim]++;//we need an additional DG0-node for a dim-dimensional object
+ return dpo;
}
template <int dim, int spacedim>
bool
-FE_Q_DG0<dim,spacedim>::hp_constraints_are_implemented () const
-{
- return true;
-}
-
-
-
-
-template <int dim, int spacedim>
-std::vector<std::pair<unsigned int, unsigned int> >
-FE_Q_DG0<dim,spacedim>::
-hp_vertex_dof_identities (const FiniteElement<dim,spacedim> &fe_other) const
-{
- // we can presently only compute
- // these identities if both FEs are
- // FE_Q_DG0s or if the other one is an
- // FE_Nothing. in the first case,
- // there should be exactly one
- // single DoF of each FE at a
- // vertex, and they should have
- // identical value
- if (dynamic_cast<const FE_Q_DG0<dim,spacedim>*>(&fe_other) != 0)
- {
- return
- std::vector<std::pair<unsigned int, unsigned int> >
- (1, std::make_pair (0U, 0U));
- }
- else if (dynamic_cast<const FE_Nothing<dim>*>(&fe_other) != 0)
- {
- // the FE_Nothing has no
- // degrees of freedom, so there
- // are no equivalencies to be
- // recorded
- return std::vector<std::pair<unsigned int, unsigned int> > ();
- }
- else
- {
- Assert (false, ExcNotImplemented());
- return std::vector<std::pair<unsigned int, unsigned int> > ();
- }
-}
-
-
-
-template <int dim, int spacedim>
-std::vector<std::pair<unsigned int, unsigned int> >
-FE_Q_DG0<dim,spacedim>::
-hp_line_dof_identities (const FiniteElement<dim,spacedim> &fe_other) const
-{
- // we can presently only compute
- // these identities if both FEs are
- // FE_Q_DG0s or if the other one is an
- // FE_Nothing
- if (const FE_Q_DG0<dim,spacedim> *fe_q_dg0_other = dynamic_cast<const
- FE_Q_DG0<dim,spacedim> *>(&fe_other))
- {
- // dofs are located along lines, so two
- // dofs are identical if they are
- // located at identical positions. if
- // we had only equidistant points, we
- // could simple check for similarity
- // like (i+1)*q == (j+1)*p, but we
- // might have other support points
- // (e.g. Gauss-Lobatto
- // points). Therefore, read the points
- // in unit_support_points for the first
- // coordinate direction. We take the
- // lexicographic ordering of the points
- // in the first direction (i.e.,
- // x-direction), which we access
- // between index 1 and p-1 (index 0 and
- // p are vertex dofs).
- const unsigned int p = this->degree;
- const unsigned int q = fe_q_dg0_other->degree;
-
- std::vector<std::pair<unsigned int, unsigned int> > identities;
-
- const std::vector<unsigned int> &index_map_inverse=
- this->poly_space.get_numbering_inverse();
- const std::vector<unsigned int> &index_map_inverse_other=
- fe_q_dg0_other->poly_space.get_numbering_inverse();
-
- for (unsigned int i=0; i<p-1; ++i)
- for (unsigned int j=0; j<q-1; ++j)
- if (std::fabs(this->unit_support_points[index_map_inverse[i+1]][0]-
-
- fe_q_dg0_other->unit_support_points[index_map_inverse_other[j+1]][0])
- < 1e-14)
- identities.push_back (std::make_pair(i,j));
-
- return identities;
- }
- else if (dynamic_cast<const FE_Nothing<dim>*>(&fe_other) != 0)
- {
- // the FE_Nothing has no
- // degrees of freedom, so there
- // are no equivalencies to be
- // recorded
- return std::vector<std::pair<unsigned int, unsigned int> > ();
- }
- else
- {
- Assert (false, ExcNotImplemented());
- return std::vector<std::pair<unsigned int, unsigned int> > ();
- }
-}
-
-
-
-template <int dim, int spacedim>
-std::vector<std::pair<unsigned int, unsigned int> >
-FE_Q_DG0<dim,spacedim>::
-hp_quad_dof_identities (const FiniteElement<dim,spacedim> &fe_other) const
+FE_Q_DG0<dim,spacedim>::has_support_on_face (const unsigned int shape_index,
+ const unsigned int face_index) const
{
- // we can presently only compute
- // these identities if both FEs are
- // FE_Q_DG0s or if the other one is an
- // FE_Nothing
- if (const FE_Q_DG0<dim,spacedim> *fe_q_dg0_other = dynamic_cast<const
- FE_Q_DG0<dim,spacedim> *>(&fe_other))
- {
- // this works exactly like the line
- // case above, except that now we have
- // to have two indices i1, i2 and j1,
- // j2 to characterize the dofs on the
- // face of each of the finite
- // elements. since they are ordered
- // lexicographically along the first
- // line and we have a tensor product,
- // the rest is rather straightforward
- const unsigned int p = this->degree;
- const unsigned int q = fe_q_dg0_other->degree;
-
- std::vector<std::pair<unsigned int, unsigned int> > identities;
-
- const std::vector<unsigned int> &index_map_inverse=
- this->poly_space.get_numbering_inverse();
- const std::vector<unsigned int> &index_map_inverse_other=
- fe_q_dg0_other->poly_space.get_numbering_inverse();
-
- for (unsigned int i1=0; i1<p-1; ++i1)
- for (unsigned int i2=0; i2<p-1; ++i2)
- for (unsigned int j1=0; j1<q-1; ++j1)
- for (unsigned int j2=0; j2<q-1; ++j2)
- if ((std::fabs(this->unit_support_points[index_map_inverse[i1+1]][0]-
-
- fe_q_dg0_other->unit_support_points[index_map_inverse_other[j1+1]][0])
- < 1e-14)
- &&
- (std::fabs(this->unit_support_points[index_map_inverse[i2+1]][0]-
-
- fe_q_dg0_other->unit_support_points[index_map_inverse_other[j2+1]][0])
- < 1e-14))
- identities.push_back (std::make_pair(i1*(p-1)+i2,
- j1*(q-1)+j2));
-
- return identities;
- }
- else if (dynamic_cast<const FE_Nothing<dim>*>(&fe_other) != 0)
- {
- // the FE_Nothing has no
- // degrees of freedom, so there
- // are no equivalencies to be
- // recorded
- return std::vector<std::pair<unsigned int, unsigned int> > ();
- }
+ // discontinuous function has support on all faces
+ if (shape_index == this->dofs_per_cell-1)
+ return true;
else
- {
- Assert (false, ExcNotImplemented());
- return std::vector<std::pair<unsigned int, unsigned int> > ();
- }
+ return FE_Q_Base<TensorProductPolynomialsConst<dim>,dim,spacedim>::has_support_on_face(shape_index, face_index);
}
-
-template <int dim, int spacedim>
-FiniteElementDomination::Domination
-FE_Q_DG0<dim,spacedim>::
-compare_for_face_domination (const FiniteElement<dim,spacedim> &fe_other) const
-{
- if (const FE_Q_DG0<dim,spacedim> *fe_q_dg0_other
- = dynamic_cast<const FE_Q_DG0<dim,spacedim>*>(&fe_other))
- {
- if (this->degree < fe_q_dg0_other->degree)
- return FiniteElementDomination::this_element_dominates;
- else if (this->degree == fe_q_dg0_other->degree)
- return FiniteElementDomination::either_element_can_dominate;
- else
- return FiniteElementDomination::other_element_dominates;
- }
- else if (dynamic_cast<const FE_Nothing<dim>*>(&fe_other) != 0)
- {
- // the FE_Nothing has no
- // degrees of freedom and it is
- // typically used in a context
- // where we don't require any
- // continuity along the
- // interface
- return FiniteElementDomination::no_requirements;
- }
-
- Assert (false, ExcNotImplemented());
- return FiniteElementDomination::neither_element_dominates;
-}
-
-
-//---------------------------------------------------------------------------
-// Auxiliary functions
-//---------------------------------------------------------------------------
-
-
-
-template <int dim, int spacedim>
-void FE_Q_DG0<dim,spacedim>::initialize_unit_support_points ()
-{
- // number of points: (degree+1)^dim+1
- unsigned int n = this->degree+1;
- for (unsigned int i=1; i<dim; ++i)
- n *= this->degree+1;
- n++;
-
- this->unit_support_points.resize(n);
-
- const std::vector<unsigned int> &index_map_inverse=
- this->poly_space.get_numbering_inverse();
-
- const double step = 1./this->degree;
- Point<dim> p;
-
- unsigned int k=0;
- for (unsigned int iz=0; iz <= ((dim>2) ? this->degree : 0) ; ++iz)
- for (unsigned int iy=0; iy <= ((dim>1) ? this->degree : 0) ; ++iy)
- for (unsigned int ix=0; ix<=this->degree; ++ix)
- {
- p(0) = ix * step;
- if (dim>1)
- p(1) = iy * step;
- if (dim>2)
- p(2) = iz * step;
-
- this->unit_support_points[index_map_inverse[k++]] = p;
- }
- //dg0 support point in the center of the cell
- p(0) = .5;
- if (dim>1)
- {
- p(1) = .5;
- if (dim>2)
- p(2) = .5;
- }
-
- this->unit_support_points[index_map_inverse[k]] = p;
-}
-
-
-
-template <int dim, int spacedim>
-void FE_Q_DG0<dim,spacedim>::initialize_unit_support_points (const Quadrature<1> &points)
-{
- // number of points: (degree+1)^dim+1
- unsigned int n = this->degree+1;
- for (unsigned int i=1; i<dim; ++i)
- n *= this->degree+1;
- n++;
-
- this->unit_support_points.resize(n);
-
- const std::vector<unsigned int> &index_map_inverse=
- this->poly_space.get_numbering_inverse();
-
- Quadrature<dim> support_quadrature(points);
-
- Point<dim> p;
-
- for (unsigned int k=0; k<n ; k++)
- {
- this->unit_support_points[index_map_inverse[k]] = support_quadrature.point(k);
- }
-}
-
-
-
-template <>
-void FE_Q_DG0<1>::initialize_unit_face_support_points ()
-{
- // no faces in 1d, so nothing to do
-}
-
-template <>
-void FE_Q_DG0<1>::initialize_unit_face_support_points (const Quadrature<1> &/*points*/)
-{
- // no faces in 1d, so nothing to do
-}
-
-template <>
-void FE_Q_DG0<1,2>::initialize_unit_face_support_points ()
-{
- // no faces in 1d, so nothing to do
-}
-
-template <>
-void FE_Q_DG0<1,2>::initialize_unit_face_support_points (const Quadrature<1> &/*points*/)
-{
- // no faces in 1d, so nothing to do
-}
-
-template <>
-void FE_Q_DG0<1,3>::initialize_unit_face_support_points ()
-{
- // no faces in 1d, so nothing to do
-}
-
-template <>
-void FE_Q_DG0<1,3>::initialize_unit_face_support_points (const Quadrature<1> &/*points*/)
-{
- // no faces in 1d, so nothing to do
-}
-
-template <int dim, int spacedim>
-void FE_Q_DG0<dim,spacedim>::initialize_unit_face_support_points ()
-{
- const unsigned int codim = dim-1;
-
- // number of points: (degree+1)^codim
- unsigned int n = this->degree+1;
- for (unsigned int i=1; i<codim; ++i)
- n *= this->degree+1;
-
- this->unit_face_support_points.resize(n);
-
- const std::vector<unsigned int> &face_index_map_inverse=
- FE_Q_DG0_Helper::invert_numbering(face_index_map);
-
- const double step = 1./this->degree;
- Point<codim> p;
-
- unsigned int k=0;
- for (unsigned int iz=0; iz <= ((codim>2) ? this->degree : 0) ; ++iz)
- for (unsigned int iy=0; iy <= ((codim>1) ? this->degree : 0) ; ++iy)
- for (unsigned int ix=0; ix<=this->degree; ++ix)
- {
- p(0) = ix * step;
- if (codim>1)
- p(1) = iy * step;
- if (codim>2)
- p(2) = iz * step;
-
- this->unit_face_support_points[face_index_map_inverse[k++]] = p;
- }
-}
-
-
-
-template <int dim, int spacedim>
-void FE_Q_DG0<dim,spacedim>::initialize_unit_face_support_points (const Quadrature<1> &points)
-{
- const unsigned int codim = dim-1;
-
- // number of points: (degree+1)^codim
- unsigned int n = this->degree+1;
- for (unsigned int i=1; i<codim; ++i)
- n *= this->degree+1;
-
- this->unit_face_support_points.resize(n);
-
- const std::vector< Point<1> > edge = points.get_points();
-
- const std::vector<unsigned int> &face_index_map_inverse=
- FE_Q_DG0_Helper::invert_numbering(face_index_map);
-
- Point<codim> p;
-
- unsigned int k=0;
- for (unsigned int iz=0; iz <= ((codim>2) ? this->degree : 0) ; ++iz)
- for (unsigned int iy=0; iy <= ((codim>1) ? this->degree : 0) ; ++iy)
- for (unsigned int ix=0; ix<=this->degree; ++ix)
- {
- p(0) = edge[ix](0);
- if (codim>1)
- p(1) = edge[iy](0);
- if (codim>2)
- p(2) = edge[iz](0);
-
- this->unit_face_support_points[face_index_map_inverse[k++]] = p;
- }
-}
-
-
-
-template <int dim, int spacedim>
-void
-FE_Q_DG0<dim,spacedim>::initialize_quad_dof_index_permutation ()
-{
- // general template for 1D and 2D, do nothing
-}
-
-
-
-template <>
-void
-FE_Q_DG0<3>::initialize_quad_dof_index_permutation ()
-{
- Assert (adjust_quad_dof_index_for_face_orientation_table.n_elements()==8*this->dofs_per_quad,
- ExcInternalError());
-
- const unsigned int n=this->degree-1;
- Assert(n*n==this->dofs_per_quad, ExcInternalError());
-
- // alias for the table to fill
- Table<2,int> &data=this->adjust_quad_dof_index_for_face_orientation_table;
-
- // the dofs on a face are connected to a n x
- // n matrix. for example, for degree==4 we
- // have the following dofs on a quad
-
- // ___________
- // | |
- // | 6 7 8 |
- // | |
- // | 3 4 5 |
- // | |
- // | 0 1 2 |
- // |___________|
- //
- // we have dof_no=i+n*j with index i in
- // x-direction and index j in y-direction
- // running from 0 to n-1. to extract i and j
- // we can use i=dof_no%n and j=dof_no/n. i
- // and j can then be used to construct the
- // rotated and mirrored numbers.
-
-
- for (unsigned int local=0; local<this->dofs_per_quad; ++local)
- // face support points are in lexicographic
- // ordering with x running fastest. invert
- // that (y running fastest)
- {
- unsigned int i=local%n,
- j=local/n;
-
- // face_orientation=false, face_flip=false, face_rotation=false
- data(local,0)=j + i *n - local;
- // face_orientation=false, face_flip=false, face_rotation=true
- data(local,1)=i + (n-1-j)*n - local;
- // face_orientation=false, face_flip=true, face_rotation=false
- data(local,2)=(n-1-j) + (n-1-i)*n - local;
- // face_orientation=false, face_flip=true, face_rotation=true
- data(local,3)=(n-1-i) + j *n - local;
- // face_orientation=true, face_flip=false, face_rotation=false
- data(local,4)=0;
- // face_orientation=true, face_flip=false, face_rotation=true
- data(local,5)=j + (n-1-i)*n - local;
- // face_orientation=true, face_flip=true, face_rotation=false
- data(local,6)=(n-1-i) + (n-1-j)*n - local;
- // face_orientation=true, face_flip=true, face_rotation=true
- data(local,7)=(n-1-j) + i *n - local;
- }
-
- // aditionally initialize reordering of line
- // dofs
- for (unsigned int i=0; i<this->dofs_per_line; ++i)
- this->adjust_line_dof_index_for_line_orientation_table[i]=this->dofs_per_line-1-i - i;
-}
-
-template <int dim, int spacedim>
-std::vector<bool>
-FE_Q_DG0<dim,spacedim>::get_riaf_vector(const unsigned int deg)
-{
- std::vector<bool> riaf
- (FiniteElementData<dim> (get_dpo_vector(deg),1,deg).dofs_per_cell,
- false);
- riaf[riaf.size()-1]=true;
- return riaf;
-}
-
-
-template <int dim, int spacedim>
-std::vector<unsigned int>
-FE_Q_DG0<dim,spacedim>::get_dpo_vector(const unsigned int deg)
-{
- std::vector<unsigned int> dpo(dim+1, 1U);
- for (unsigned int i=1; i<dpo.size(); ++i)
- dpo[i]=dpo[i-1]*(deg-1);
-
- dpo[dim]++;//we need an additional DG0-node for a dim-dimensional object
- return dpo;
-}
-
-template <int dim, int spacedim>
-std::vector<unsigned int>
-FE_Q_DG0<dim,spacedim>::get_dpo_vector_q(const unsigned int deg)
-{
- std::vector<unsigned int> dpo(dim+1, 1U);
- for (unsigned int i=1; i<dpo.size(); ++i)
- dpo[i]=dpo[i-1]*(deg-1);
-
- return dpo;
-}
-
-
-template <int dim, int spacedim>
-std::vector<unsigned int>
-FE_Q_DG0<dim,spacedim>::face_lexicographic_to_hierarchic_numbering (const unsigned int degree)
-{
- const FiniteElementData<dim-1> face_data(FE_Q_DG0<dim-1>::get_dpo_vector_q(degree),1,degree);
- std::vector<unsigned int> face_renumber (face_data.dofs_per_cell);
- FETools::lexicographic_to_hierarchic_numbering (face_data, face_renumber);
- return face_renumber;
-}
-
-
-
-template <>
-std::vector<unsigned int>
-FE_Q_DG0<1>::face_lexicographic_to_hierarchic_numbering (const unsigned int)
-{
- return std::vector<unsigned int>();
-}
-
-template <>
-std::vector<unsigned int>
-FE_Q_DG0<1,2>::face_lexicographic_to_hierarchic_numbering (const unsigned int)
-{
- return std::vector<unsigned int>();
-}
-
-
-template <>
-std::vector<unsigned int>
-FE_Q_DG0<1,3>::face_lexicographic_to_hierarchic_numbering (const unsigned int)
-{
- return std::vector<unsigned int>();
-}
-
-
-template <int dim, int spacedim>
-void
-FE_Q_DG0<dim,spacedim>::initialize_constraints ()
-{
- QTrapez<1> trapez;
- QIterated<1> points (trapez,this->degree);
- Implementation::initialize_constraints (points, *this);
-}
-
-
-template <int dim, int spacedim>
-void
-FE_Q_DG0<dim,spacedim>::initialize_embedding ()
-{
- // compute the interpolation matrices in much the same way as we do for
- // the constraints. it's actually simpler here, since we don't have this
- // weird renumbering stuff going on. The trick is again that the
- // interpolation matrix is formed by a permutation of the indices of the
- // cell matrix. The value eps is used a threshold to decide when certain
- // evaluations of the Lagrange polynomials are zero or one.
- const double eps = 1e-15*this->degree*dim;
-
-#ifdef DEBUG
- // in DEBUG mode, check that the evaluation of support points (except for
- // the discontinuous node) in the current numbering gives the identity
- // operation
- for (unsigned int i=0; i<this->dofs_per_cell-1; ++i)
- {
- Assert (std::fabs (1.-this->poly_space.compute_value
- (i, this->unit_support_points[i])) < eps,
- ExcInternalError());
- for (unsigned int j=0; j<this->dofs_per_cell-1; ++j)
- if (j!=i)
- Assert (std::fabs (this->poly_space.compute_value
- (i, this->unit_support_points[j])) < eps,
- ExcInternalError());
- }
-#endif
-
- // to efficiently evaluate the polynomial at the subcell, make use of the
- // tensor product structure of this element and only evaluate 1D
- // information from the polynomial. This makes the cost of this function
- // almost negligible also for high order elements
- const unsigned int dofs1d = this->degree+1;
- std::vector<Table<2,double> > subcell_evaluations
- (dim, Table<2,double>(dofs1d, dofs1d));
- const std::vector<unsigned int> &index_map_inverse =
- this->poly_space.get_numbering_inverse();
-
- // recreate 1D polynomials, the last entry is not used
- std::vector<Polynomials::Polynomial<double> > poly_space1d =
- FE_Q_DG0_Helper::generate_poly_space1d (this->unit_support_points,
- index_map_inverse, dofs1d);
-
- // helper value: step size how to walk through diagonal and how many
- // points we have left apart from the first dimension
- unsigned int step_size_diag = 0;
- {
- unsigned int factor = 1;
- for (unsigned int d=0; d<dim; ++d)
- {
- step_size_diag += factor;
- factor *= dofs1d;
- }
- }
-
- // next evaluate the functions for the different refinement cases.
- for (unsigned int ref=0; ref<RefinementCase<dim>::isotropic_refinement; ++ref)
- for (unsigned int child=0;
- child<GeometryInfo<dim>::n_children(RefinementCase<dim>(ref+1));
- ++child)
- {
- // go through the points in diagonal to capture variation in all
- // directions simultaneously
- for (unsigned int j=0; j<dofs1d; ++j)
- {
- const unsigned int diag_comp = index_map_inverse[j*step_size_diag];
- const Point<dim> p_subcell = this->unit_support_points[diag_comp];
- const Point<dim> p_cell =
- GeometryInfo<dim>::child_to_cell_coordinates
- (p_subcell, child, RefinementCase<dim>(ref+1));
- for (unsigned int i=0; i<dofs1d; ++i)
- for (unsigned int d=0; d<dim; ++d)
- {
- const double cell_value = poly_space1d[i].value (p_cell[d]);
-
- // cut off values that are too small. note that we have here
- // Lagrange interpolation functions, so they should be zero at
- // almost all points, and one at the others, at least on the
- // subcells. so set them to their exact values.
- //
- // the actual cut-off value is somewhat fuzzy, but it works for
- // 2e-13*degree*dim (see above), which is kind of reasonable
- // given that we compute the values of the polynomials via an
- // degree-step recursion and then multiply the 1d-values. this
- // gives us a linear growth in degree*dim, times a small
- // constant.
- //
- // the embedding matrix is given by applying the inverse of the
- // subcell matrix on the cell_interpolation matrix. since the
- // subcell matrix is actually only a permutation vector, all we
- // need to do is to switch the rows we write the data into.
- // moreover, cut off very small values here
- if (std::fabs(cell_value) < eps)
- subcell_evaluations[d](j,i) = 0;
- else
- subcell_evaluations[d](j,i) = cell_value;
- }
- }
-
- // now expand from 1D info. block innermost dimension (x_0) in order
- // to avoid difficult checks at innermost loop
- unsigned int j_indices[dim];
- FE_Q_DG0_Helper::zero_indices<dim> (j_indices);
- for (unsigned int j=0; j<this->dofs_per_cell-1; j+=dofs1d)
- {
- unsigned int i_indices[dim];
- FE_Q_DG0_Helper::zero_indices<dim> (i_indices);
- for (unsigned int i=0; i<this->dofs_per_cell-1; i+=dofs1d)
- {
- double val_extra_dim = 1.;
- for (unsigned int d=1; d<dim; ++d)
- val_extra_dim *= subcell_evaluations[d](j_indices[d-1],
- i_indices[d-1]);
-
- // innermost sum where we actually compute. the same as
- // this->prolongation[ref][child](j,i) =
- // this->poly_space.compute_value (i, p_cell);
- for (unsigned int jj=0; jj<dofs1d; ++jj)
- {
- const unsigned int j_ind = index_map_inverse[j+jj];
- for (unsigned int ii=0; ii<dofs1d; ++ii)
-
- this->prolongation[ref][child](j_ind,index_map_inverse[i+ii])
- = val_extra_dim * subcell_evaluations[0](jj,ii);
- }
-
- // update indices that denote the tensor product position. a bit
- // fuzzy and therefore not done for innermost x_0 direction
- FE_Q_DG0_Helper::increment_indices<dim> (i_indices, dofs1d);
- }
- Assert (i_indices[dim-1] == 1, ExcInternalError());
- FE_Q_DG0_Helper::increment_indices<dim> (j_indices, dofs1d);
- }
-
- // the discontinuous node is simply mapped on the discontinuous node
- // on the child cell
- for (unsigned int j=0; j<this->dofs_per_cell-1; j++)
- {
- this->prolongation[ref][child](j,this->dofs_per_cell-1) = 0.;
- this->prolongation[ref][child](this->dofs_per_cell-1,j) = 0.;
- }
- this->prolongation[ref][child](this->dofs_per_cell-1,
- this->dofs_per_cell-1) = 1.;
-
- // make sure that the row sum is one. this must be so since for this
- // element, the continuous shape functions add up to one and the
- // discontinuous node is mapped to the discontinuous node on the
- // child cell
-#ifdef DEBUG
- for (unsigned int row=0; row<this->dofs_per_cell; ++row)
- {
- double sum = 0;
- for (unsigned int col=0; col<this->dofs_per_cell; ++col)
- sum += this->prolongation[ref][child](row,col);
- Assert (std::fabs(sum-1.) < eps, ExcInternalError());
- }
-#endif
- }
-}
-
-
-
-template <int dim, int spacedim>
-void
-FE_Q_DG0<dim,spacedim>::initialize_restriction ()
-{
- // for these Lagrange interpolation polynomials, construction of the
- // restriction matrices is relatively simple. the reason is that the
- // interpolation points on the mother cell are (except for the case with
- // arbitrary nonequidistant nodes and for the discontinuous node) always also
- // interpolation points for some shape function on one or the other child,
- // because we have chosen equidistant Lagrange interpolation points for the
- // polynomials
- //
- // so the only thing we have to find out is: for each shape function on
- // the mother cell, which is the child cell (possibly more than one) on
- // which it is located, and which is the corresponding shape function there.
- // rather than doing it for the shape functions on the mother cell, we take
- // the interpolation points there
- //
- // note that the interpolation point of a shape function can be on the
- // boundary between subcells. in that case, restriction from children to
- // mother may produce two or more entries for a dof on the mother cell.
- // however, this doesn't hurt: since the element is continuous (apart from
- // the discontinuous node), the contribution from each child should yield
- // the same result, and since the element (apart from the discontinuous
- // node) is non-additive we just overwrite one value (compute one one child)
- // by the same value (compute on a later child), so we don't have to care
- // about this.
- // for the discontinuous node we just take the mean of all the child cells'
- // contributions.
-
- const double eps = 1e-15*this->degree*dim;
- const std::vector<unsigned int> &index_map_inverse =
- this->poly_space.get_numbering_inverse();
-
- // recreate 1D polynomials for faster evaluation of polynomial, the last
- // entry is not used
- const unsigned int dofs1d = this->degree+1;
- std::vector<Polynomials::Polynomial<double> > poly_space1d =
- FE_Q_DG0_Helper::generate_poly_space1d (this->unit_support_points,
- index_map_inverse, dofs1d);
- std::vector<Tensor<1,dim> > evaluations1d (dofs1d);
-
- for (unsigned int i=0; i<this->dofs_per_cell-1; ++i)
- {
- unsigned int mother_dof = index_map_inverse[i];
- const Point<dim> p_cell = this->unit_support_points[mother_dof];
-
- // then find the children on which the interpolation point is located
- for (unsigned int ref=RefinementCase<dim>::cut_x;
- ref<=RefinementCase<dim>::isotropic_refinement; ++ref)
- for (unsigned int child=0;
- child<GeometryInfo<dim>::n_children(RefinementCase<dim>(ref));
- ++child)
- {
- // check whether this interpolation point is inside this child
- // cell
- const Point<dim> p_subcell =
- GeometryInfo<dim>::cell_to_child_coordinates
- (p_cell, child, RefinementCase<dim>(ref));
- if (GeometryInfo<dim>::is_inside_unit_cell (p_subcell))
- {
- // same logic as in initialize_embedding to evaluate the
- // polynomial faster than from the tensor product: since we
- // evaluate all polynomials, it is much faster to just
- // compute the 1D values for all polynomials before and then
- // get the dim-data.
- for (unsigned int j=0; j<dofs1d; ++j)
- for (unsigned int d=0; d<dim; ++d)
- evaluations1d[j][d] = poly_space1d[j].value(p_subcell[d]);
- unsigned int j_indices[dim];
- FE_Q_DG0_Helper::zero_indices<dim> (j_indices);
- double sum_check = 0;
- for (unsigned int j = 0; j<this->dofs_per_cell-1; j += dofs1d)
- {
- double val_extra_dim = 1.;
- for (unsigned int d=1; d<dim; ++d)
- val_extra_dim *= evaluations1d[j_indices[d-1]][d];
- for (unsigned int jj=0; jj<dofs1d; ++jj)
- {
-
- // find the child shape function(s) corresponding
- // to this point. Usually this is just one function;
- // however, when we use FE_Q_DG0 on arbitrary nodes a
- // parent support point might not be a child support
- // point, and then we will get more than one nonzero
- // value per row. Still, the values should sum up to 1
- const double val = val_extra_dim * evaluations1d[jj][0];
- const unsigned int child_dof = index_map_inverse[j+jj];
- if (std::fabs (val-1.) < eps)
- this->restriction[ref-1][child]
- (mother_dof,child_dof)=1.;
- else if (std::fabs(val) > eps)
- this->restriction[ref-1][child]
- (mother_dof,child_dof)=val;
- sum_check += val;
- }
- FE_Q_DG0_Helper::increment_indices<dim> (j_indices, dofs1d);
- }
- Assert (std::fabs(sum_check-1) < eps,
- ExcInternalError());
- }
- }
- }
- // for the discontinuous node we take the mean of all the child cells'
- // contributions. so there is also a diagonal entry equal to the inverse of
- // n_children.
- for (unsigned int ref=RefinementCase<dim>::cut_x;
- ref<=RefinementCase<dim>::isotropic_refinement; ++ref)
- for (unsigned int child=0;
- child<GeometryInfo<dim>::n_children(RefinementCase<dim>(ref));
- ++child)
- {
- for (unsigned int i=0; i<this->dofs_per_cell-1; ++i)
- {
- this->restriction[ref-1][child](i,this->dofs_per_cell-1)=0.;
- this->restriction[ref-1][child](this->dofs_per_cell-1,i)=0.;
- }
- this->restriction[ref-1][child]
- (this->dofs_per_cell-1,this->dofs_per_cell-1) =
- 1./(double)GeometryInfo<dim>::n_children
- (RefinementCase<dim>(ref));
- }
-
-}
-
-
-
-//---------------------------------------------------------------------------
-// Data field initialization
-//---------------------------------------------------------------------------
-
-
-template <>
-bool
-FE_Q_DG0<1>::has_support_on_face (const unsigned int shape_index,
- const unsigned int face_index) const
-{
- Assert (shape_index < this->dofs_per_cell,
- ExcIndexRange (shape_index, 0, this->dofs_per_cell));
- Assert (face_index < GeometryInfo<1>::faces_per_cell,
- ExcIndexRange (face_index, 0, GeometryInfo<1>::faces_per_cell));
-
-
- // in 1d, things are simple. since
- // there is only one degree of
- // freedom per vertex in this
- // class, the first is on vertex 0
- // (==face 0 in some sense), the
- // second on face 1:
- return (((shape_index == 0) && (face_index == 0)) ||
- ((shape_index == 1) && (face_index == 1)));
-}
-
-
-template <>
-bool
-FE_Q_DG0<1,2>::has_support_on_face (const unsigned int shape_index,
- const unsigned int face_index) const
-{
- Assert (shape_index < this->dofs_per_cell,
- ExcIndexRange (shape_index, 0, this->dofs_per_cell));
- Assert (face_index < GeometryInfo<1>::faces_per_cell,
- ExcIndexRange (face_index, 0, GeometryInfo<1>::faces_per_cell));
-
-
- // in 1d, things are simple. since
- // there is only one degree of
- // freedom per vertex in this
- // class, the first is on vertex 0
- // (==face 0 in some sense), the
- // second on face 1:
- return (((shape_index == 0) && (face_index == 0)) ||
- ((shape_index == 1) && (face_index == 1)));
-}
-
-template <>
-bool
-FE_Q_DG0<1,3>::has_support_on_face (const unsigned int shape_index,
- const unsigned int face_index) const
-{
- Assert (shape_index < this->dofs_per_cell,
- ExcIndexRange (shape_index, 0, this->dofs_per_cell));
- Assert (face_index < GeometryInfo<1>::faces_per_cell,
- ExcIndexRange (face_index, 0, GeometryInfo<1>::faces_per_cell));
-
-
- // in 1d, things are simple. since
- // there is only one degree of
- // freedom per vertex in this
- // class, the first is on vertex 0
- // (==face 0 in some sense), the
- // second on face 1:
- return (((shape_index == 0) && (face_index == 0)) ||
- ((shape_index == 1) && (face_index == 1)));
-}
-
-
-template <int dim, int spacedim>
-bool
-FE_Q_DG0<dim,spacedim>::has_support_on_face (const unsigned int shape_index,
- const unsigned int face_index) const
-{
- Assert (shape_index < this->dofs_per_cell,
- ExcIndexRange (shape_index, 0, this->dofs_per_cell));
- Assert (face_index < GeometryInfo<dim>::faces_per_cell,
- ExcIndexRange (face_index, 0, GeometryInfo<dim>::faces_per_cell));
-
-
- // first, special-case interior
- // shape functions, since they
- // have no support no-where on
- // the boundary
- if (((dim==2) && (shape_index>=this->first_quad_index))
- ||
- ((dim==3) && (shape_index>=this->first_hex_index)))
- return false;
-
- // let's see whether this is a
- // vertex
- if (shape_index < this->first_line_index)
- {
- // for Q_DG0 elements, there is
- // one dof per vertex, so
- // shape_index==vertex_number. check
- // whether this vertex is
- // on the given face. thus,
- // for each face, give a
- // list of vertices
- const unsigned int vertex_no = shape_index;
- Assert (vertex_no < GeometryInfo<dim>::vertices_per_cell,
- ExcInternalError());
-
- for (unsigned int v=0; v<GeometryInfo<dim>::vertices_per_face; ++v)
- if (GeometryInfo<dim>::face_to_cell_vertices(face_index, v) == vertex_no)
- return true;
-
- return false;
- }
- else if (shape_index < this->first_quad_index)
- // ok, dof is on a line
- {
- const unsigned int line_index
- = (shape_index - this->first_line_index) / this->dofs_per_line;
- Assert (line_index < GeometryInfo<dim>::lines_per_cell,
- ExcInternalError());
-
- // in 2d, the line is the
- // face, so get the line
- // index
- if (dim == 2)
- return (line_index == face_index);
- else if (dim == 3)
- {
- // see whether the
- // given line is on the
- // given face.
- for (unsigned int l=0; l<GeometryInfo<dim>::lines_per_face; ++l)
- if (GeometryInfo<3>::face_to_cell_lines(face_index, l) == line_index)
- return true;
-
- return false;
- }
- else
- Assert (false, ExcNotImplemented());
- }
- else if (shape_index < this->first_hex_index)
- // dof is on a quad
- {
- const unsigned int quad_index
- = (shape_index - this->first_quad_index) / this->dofs_per_quad;
- Assert (static_cast<signed int>(quad_index) <
- static_cast<signed int>(GeometryInfo<dim>::quads_per_cell),
- ExcInternalError());
-
- // in 2d, cell bubble are
- // zero on all faces. but
- // we have treated this
- // case above already
- Assert (dim != 2, ExcInternalError());
-
- // in 3d,
- // quad_index=face_index
- if (dim == 3)
- return (quad_index == face_index);
- else
- Assert (false, ExcNotImplemented());
- }
- else
- // dof on hex
- {
- // can only happen in 3d,
- // but this case has
- // already been covered
- // above
- Assert (false, ExcNotImplemented());
- return false;
- }
-
- // we should not have gotten here
- Assert (false, ExcInternalError());
- return false;
-}
-
-
-
-template <int dim, int spacedim>
-std::size_t
-FE_Q_DG0<dim,spacedim>::memory_consumption () const
-{
- return (FiniteElement<dim,spacedim>::memory_consumption() +
- MemoryConsumption::memory_consumption (face_index_map));
-}
-
-
-
// explicit instantiations
#include "fe_q_dg0.inst"
--- /dev/null
+//---------------------------------------------------------------------------
+// $Id$
+// Version: $Name$
+//
+// Copyright (C) 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010, 2011, 2012, 2013 by the deal.II authors
+//
+// This file is subject to QPL and may not be distributed
+// without copyright and license information. Please refer
+// to the file deal.II/doc/license.html for the text and
+// further information on this license.
+//
+//---------------------------------------------------------------------------
+
+#include <deal.II/base/quadrature_lib.h>
+#include <deal.II/fe/fe_q_iso_q1.h>
+#include <deal.II/fe/fe_nothing.h>
+
+#include <vector>
+#include <sstream>
+
+DEAL_II_NAMESPACE_OPEN
+
+
+
+
+
+template <int dim, int spacedim>
+FE_Q_iso_Q1<dim,spacedim>::FE_Q_iso_Q1 (const unsigned int subdivisions)
+ :
+ FE_Q_Base<TensorProductPolynomials<dim,Polynomials::PiecewisePolynomial<double> >, dim, spacedim> (
+ TensorProductPolynomials<dim,Polynomials::PiecewisePolynomial<double> >
+ (Polynomials::generate_complete_Lagrange_basis_on_subdivisions(subdivisions, 1)),
+ FiniteElementData<dim>(this->get_dpo_vector(subdivisions),
+ 1, subdivisions,
+ FiniteElementData<dim>::H1),
+ std::vector<bool> (1, false))
+{
+ Assert (subdivisions > 0,
+ ExcMessage ("This element can only be used with a positive number of "
+ "subelements"));
+
+ QTrapez<1> trapez;
+ QIterated<1> points (trapez, subdivisions);
+
+ this->initialize(points.get_points());
+}
+
+
+
+template <int dim, int spacedim>
+std::string
+FE_Q_iso_Q1<dim,spacedim>::get_name () const
+{
+ // note that the FETools::get_fe_from_name function depends on the
+ // particular format of the string this function returns, so they have to be
+ // kept in synch
+
+ std::ostringstream namebuf;
+ namebuf << "FE_Q_iso_Q1<" << dim << ">(" << this->degree << ")";
+ return namebuf.str();
+}
+
+
+
+template <int dim, int spacedim>
+FiniteElement<dim,spacedim> *
+FE_Q_iso_Q1<dim,spacedim>::clone() const
+{
+ return new FE_Q_iso_Q1<dim,spacedim>(*this);
+}
+
+
+
+template <int dim, int spacedim>
+FiniteElementDomination::Domination
+FE_Q_iso_Q1<dim,spacedim>::
+compare_for_face_domination (const FiniteElement<dim,spacedim> &fe_other) const
+{
+ if (const FE_Q_iso_Q1<dim,spacedim> *fe_q_iso_q1_other
+ = dynamic_cast<const FE_Q_iso_Q1<dim,spacedim>*>(&fe_other))
+ {
+ // different behavior as in FE_Q: as FE_Q_iso_Q1(2) is not a subspace of
+ // FE_Q_iso_Q1(3), need that the element degrees are multiples of each
+ // other
+ if (this->degree < fe_q_iso_q1_other->degree &&
+ fe_q_iso_q1_other->degree % this->degree == 0)
+ return FiniteElementDomination::this_element_dominates;
+ else if (this->degree == fe_q_iso_q1_other->degree)
+ return FiniteElementDomination::either_element_can_dominate;
+ else if (this->degree > fe_q_iso_q1_other->degree &&
+ this->degree % fe_q_iso_q1_other->degree == 0)
+ return FiniteElementDomination::other_element_dominates;
+ else
+ return FiniteElementDomination::neither_element_dominates;
+ }
+ else if (dynamic_cast<const FE_Nothing<dim>*>(&fe_other) != 0)
+ {
+ // the FE_Nothing has no degrees of freedom and it is typically used in
+ // a context where we don't require any continuity along the interface
+ return FiniteElementDomination::no_requirements;
+ }
+
+ Assert (false, ExcNotImplemented());
+ return FiniteElementDomination::neither_element_dominates;
+}
+
+
+// explicit instantiations
+#include "fe_q_iso_q1.inst"
+
+DEAL_II_NAMESPACE_CLOSE
--- /dev/null
+//---------------------------------------------------------------------------
+// $Id$
+// Version: $Name$
+//
+// Copyright (C) 2013 by the deal.II authors
+//
+// This file is subject to QPL and may not be distributed
+// without copyright and license information. Please refer
+// to the file deal.II/doc/license.html for the text and
+// further information on this license.
+//
+//---------------------------------------------------------------------------
+
+
+for (deal_II_dimension : DIMENSIONS; deal_II_space_dimension : SPACE_DIMENSIONS)
+ {
+#if deal_II_dimension <= deal_II_space_dimension
+ template class FE_Q_iso_Q1<deal_II_dimension, deal_II_space_dimension>;
+#endif
+ }
+
+
// $Id$
// Version: $Name$
//
-// Copyright (C) 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010, 2011, 2012 by the deal.II authors
+// Copyright (C) 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010, 2011, 2012, 2013 by the deal.II authors
//
// This file is subject to QPL and may not be distributed
// without copyright and license information. Please refer
template <int dim, int spacedim>
FESystem<dim,spacedim>::InternalData::~InternalData()
{
- // delete pointers and set them to
- // zero to avoid inadvertent use
+ // delete pointers and set them to zero to avoid inadvertent use
for (unsigned int i=0; i<base_fe_datas.size(); ++i)
if (base_fe_datas[i])
{
Assert (component < this->n_components(),
ExcIndexRange (component, 0, this->n_components()));
- // if this value is supposed to be
- // zero, then return right away...
+ // if this value is supposed to be zero, then return right away...
if (this->nonzero_components[i][component] == false)
return Tensor<1,dim>();
- // ...otherwise: first find out to
- // which of the base elements this
- // desired component belongs, and
- // which component within this base
- // element it is
+ // ...otherwise: first find out to which of the base elements this desired
+ // component belongs, and which component within this base element it is
const unsigned int base = this->component_to_base_index(component).first;
const unsigned int component_in_base = this->component_to_base_index(component).second;
- // then get value from base
- // element. note that that will
- // throw an error should the
- // respective shape function not be
- // primitive; thus, there is no
+ // then get value from base element. note that that will throw an error
+ // should the respective shape function not be primitive; thus, there is no
// need to check this here
return (base_element(base).
shape_grad_component(this->system_to_base_table[i].second,
Assert (component < this->n_components(),
ExcIndexRange (component, 0, this->n_components()));
- // if this value is supposed to be
- // zero, then return right away...
+ // if this value is supposed to be zero, then return right away...
if (this->nonzero_components[i][component] == false)
return Tensor<2,dim>();
- // ...otherwise: first find out to
- // which of the base elements this
- // desired component belongs, and
- // which component within this base
- // element it is
+ // ...otherwise: first find out to which of the base elements this desired
+ // component belongs, and which component within this base element it is
const unsigned int base = this->component_to_base_index(component).first;
const unsigned int component_in_base = this->component_to_base_index(component).second;
- // then get value from base
- // element. note that that will
- // throw an error should the
- // respective shape function not be
- // primitive; thus, there is no
+ // then get value from base element. note that that will throw an error
+ // should the respective shape function not be primitive; thus, there is no
// need to check this here
return (base_element(base).
shape_grad_grad_component(this->system_to_base_table[i].second,
ExcDimensionMismatch (interpolation_matrix.m(),
x_source_fe.dofs_per_cell));
- // there are certain conditions
- // that the two elements have to
- // satisfy so that this can work.
+ // there are certain conditions that the two elements have to satisfy so
+ // that this can work.
//
- // condition 1: the other element
- // must also be a system element
+ // condition 1: the other element must also be a system element
typedef FiniteElement<dim,spacedim> FEL;
AssertThrow ((x_source_fe.get_name().find ("FESystem<") == 0)
typename FEL::
ExcInterpolationNotImplemented());
- // ok, source is a system element,
- // so we may be able to do the work
+ // ok, source is a system element, so we may be able to do the work
const FESystem<dim,spacedim> &source_fe
= dynamic_cast<const FESystem<dim,spacedim>&>(x_source_fe);
- // condition 2: same number of
- // basis elements
+ // condition 2: same number of basis elements
AssertThrow (this->n_base_elements() == source_fe.n_base_elements(),
typename FEL::
ExcInterpolationNotImplemented());
- // condition 3: same number of
- // basis elements
+ // condition 3: same number of basis elements
for (unsigned int i=0; i< this->n_base_elements(); ++i)
AssertThrow (this->element_multiplicity(i) ==
source_fe.element_multiplicity(i),
typename FEL::
ExcInterpolationNotImplemented());
- // ok, so let's try whether it
- // works:
-
- // first let's see whether all the
- // basis elements actually generate
- // their interpolation matrices. if
- // we get past the following loop,
- // then apparently none of the
- // called base elements threw an
- // exception, so we're fine
- // continuing and assembling the
- // one big matrix from the small
- // ones of the base elements
+ // ok, so let's try whether it works:
+
+ // first let's see whether all the basis elements actually generate their
+ // interpolation matrices. if we get past the following loop, then
+ // apparently none of the called base elements threw an exception, so we're
+ // fine continuing and assembling the one big matrix from the small ones of
+ // the base elements
std::vector<FullMatrix<double> > base_matrices (this->n_base_elements());
for (unsigned int i=0; i<this->n_base_elements(); ++i)
{
base_matrices[i]);
}
- // first clear big matrix, to make
- // sure that entries that would
- // couple different bases (or
- // multiplicity indices) are really
- // zero. then assign entries
+ // first clear big matrix, to make sure that entries that would couple
+ // different bases (or multiplicity indices) are really zero. then assign
+ // entries
interpolation_matrix = 0;
for (unsigned int i=0; i<this->dofs_per_cell; ++i)
for (unsigned int j=0; j<source_fe.dofs_per_cell; ++j)
+template <int dim, int spacedim>
+const FullMatrix<double>&
+FESystem<dim,spacedim>
+::get_restriction_matrix (const unsigned int child,
+ const RefinementCase<dim> &refinement_case) const
+{
+ Assert (refinement_case<RefinementCase<dim>::isotropic_refinement+1,
+ ExcIndexRange(refinement_case,0,RefinementCase<dim>::isotropic_refinement+1));
+ Assert (refinement_case!=RefinementCase<dim>::no_refinement,
+ ExcMessage("Restriction matrices are only available for refined cells!"));
+ Assert (child<GeometryInfo<dim>::n_children(refinement_case),
+ ExcIndexRange(child,0,GeometryInfo<dim>::n_children(refinement_case)));
+
+ // initialization upon first request
+ if (this->restriction[refinement_case-1][child].n() == 0)
+ {
+ Threads::Mutex::ScopedLock lock(this->mutex);
+
+ // check if updated while waiting for lock
+ if (this->restriction[refinement_case-1][child].n() ==
+ this->dofs_per_cell)
+ return this->restriction[refinement_case-1][child];
+
+ // Check if some of the matrices of the base elements are void.
+ bool do_restriction = true;
+
+ // shortcut for accessing local restrictions further down
+ std::vector<const FullMatrix<double> *>
+ base_matrices(this->n_base_elements());
+
+ for (unsigned int i=0; i<this->n_base_elements(); ++i)
+ {
+ base_matrices[i] =
+ &base_element(i).get_restriction_matrix(child, refinement_case);
+ if (base_matrices[i]->n() != base_element(i).dofs_per_cell)
+ do_restriction = false;
+ }
+ Assert(do_restriction,
+ (typename FiniteElement<dim,spacedim>::ExcProjectionVoid()));
+
+ // if we did not encounter void matrices, initialize the matrix sizes
+ if (do_restriction)
+ {
+ FullMatrix<double> restriction(this->dofs_per_cell,
+ this->dofs_per_cell);
+
+ // distribute the matrices of the base finite elements to the
+ // matrices of this object. for this, loop over all degrees of
+ // freedom and take the respective entry of the underlying base
+ // element.
+ //
+ // note that we by definition of a base element, they are
+ // independent, i.e. do not couple. only DoFs that belong to the
+ // same instance of a base element may couple
+ for (unsigned int i=0; i<this->dofs_per_cell; ++i)
+ for (unsigned int j=0; j<this->dofs_per_cell; ++j)
+ {
+ // first find out to which base element indices i and j
+ // belong, and which instance thereof in case the base element
+ // has a multiplicity greater than one. if they should not
+ // happen to belong to the same instance of a base element,
+ // then they cannot couple, so go on with the next index
+ if (this->system_to_base_table[i].first !=
+ this->system_to_base_table[j].first)
+ continue;
+
+ // so get the common base element and the indices therein:
+ const unsigned int
+ base = this->system_to_base_table[i].first.first;
+
+ const unsigned int
+ base_index_i = this->system_to_base_table[i].second,
+ base_index_j = this->system_to_base_table[j].second;
+
+ // if we are sure that DoFs i and j may couple, then copy
+ // entries of the matrices:
+ restriction(i,j) = (*base_matrices[base])(base_index_i,base_index_j);
+ }
+
+ std::swap(restriction, const_cast<FullMatrix<double> &>
+ (this->restriction[refinement_case-1][child]));
+ }
+ }
+
+ return this->restriction[refinement_case-1][child];
+}
+
+
+
+template <int dim, int spacedim>
+const FullMatrix<double>&
+FESystem<dim,spacedim>
+::get_prolongation_matrix (const unsigned int child,
+ const RefinementCase<dim> &refinement_case) const
+{
+ Assert (refinement_case<RefinementCase<dim>::isotropic_refinement+1,
+ ExcIndexRange(refinement_case,0,RefinementCase<dim>::isotropic_refinement+1));
+ Assert (refinement_case!=RefinementCase<dim>::no_refinement,
+ ExcMessage("Restriction matrices are only available for refined cells!"));
+ Assert (child<GeometryInfo<dim>::n_children(refinement_case),
+ ExcIndexRange(child,0,GeometryInfo<dim>::n_children(refinement_case)));
+
+ // initialization upon first request, construction completely analogous to
+ // restriction matrix
+ if (this->prolongation[refinement_case-1][child].n() == 0)
+ {
+ Threads::Mutex::ScopedLock lock(this->mutex);
+
+ if (this->prolongation[refinement_case-1][child].n() ==
+ this->dofs_per_cell)
+ return this->prolongation[refinement_case-1][child];
+
+ bool do_prolongation = true;
+ std::vector<const FullMatrix<double> *>
+ base_matrices(this->n_base_elements());
+ for (unsigned int i=0; i<this->n_base_elements(); ++i)
+ {
+ base_matrices[i] =
+ &base_element(i).get_prolongation_matrix(child, refinement_case);
+ if (base_matrices[i]->n() != base_element(i).dofs_per_cell)
+ do_prolongation = false;
+ }
+ Assert(do_prolongation,
+ (typename FiniteElement<dim,spacedim>::ExcEmbeddingVoid()));
+
+ if (do_prolongation)
+ {
+ FullMatrix<double> prolongate (this->dofs_per_cell,
+ this->dofs_per_cell);
+
+ for (unsigned int i=0; i<this->dofs_per_cell; ++i)
+ for (unsigned int j=0; j<this->dofs_per_cell; ++j)
+ {
+ if (this->system_to_base_table[i].first !=
+ this->system_to_base_table[j].first)
+ continue;
+ const unsigned int
+ base = this->system_to_base_table[i].first.first;
+
+ const unsigned int
+ base_index_i = this->system_to_base_table[i].second,
+ base_index_j = this->system_to_base_table[j].second;
+ prolongate(i,j) = (*base_matrices[base])(base_index_i,base_index_j);
+ }
+ std::swap(prolongate, const_cast<FullMatrix<double> &>
+ (this->prolongation[refinement_case-1][child]));
+ }
+ }
+
+ return this->prolongation[refinement_case-1][child];
+}
+
+
+
//---------------------------------------------------------------------------
// Data field initialization
//---------------------------------------------------------------------------
{
if (fe_data.is_first_cell())
{
- // Initialize the
- // FEValuesDatas for the
- // base elements.
- // Originally this was the
- // task of
- // FEValues::FEValues() but
- // the latter initializes
- // the FEValuesDatas only
- // of the FESystem, not of
- // the FEValuesDatas needed
- // by the base elements
- // (and: how should it know
- // of their existence,
- // after all).
+ // Initialize the FEValuesDatas for the base elements. Originally
+ // this was the task of FEValues::FEValues() but the latter
+ // initializes the FEValuesDatas only of the FESystem, not of the
+ // FEValuesDatas needed by the base elements (and: how should it
+ // know of their existence, after all).
for (unsigned int base_no=0; base_no<this->n_base_elements(); ++base_no)
{
- // Pointer needed to get
- // the update flags of the
- // base element
+ // Pointer needed to get the update flags of the base element
typename Mapping<dim,spacedim>::InternalDataBase &
base_fe_data = fe_data.get_fe_data(base_no);
const UpdateFlags base_update_flags
= mapping_data.update_flags | base_fe_data.update_flags;
- // Initialize the FEValuesDatas
- // for the base elements.
+ // Initialize the FEValuesDatas for the base elements.
FEValuesData<dim,spacedim> &base_data=fe_data.get_fe_values_data(base_no);
const FiniteElement<dim,spacedim> &base_fe=base_element(base_no);
base_data.initialize (n_q_points, base_fe, base_update_flags);
}
}
- // fill_fe_face_values needs
- // argument Quadrature<dim-1>
- // for both cases
- // dim_1==dim-1 and
- // dim_1=dim. Hence the
- // following workaround
+ // fill_fe_face_values needs argument Quadrature<dim-1> for both cases
+ // dim_1==dim-1 and dim_1=dim. Hence the following workaround
const Quadrature<dim> *cell_quadrature = 0;
const Quadrature<dim-1> *face_quadrature = 0;
- // static cast to the
- // common base class of
- // quadrature being either
- // Quadrature<dim> or
- // Quadrature<dim-1>:
+ // static cast to the common base class of quadrature being either
+ // Quadrature<dim> or Quadrature<dim-1>:
const Subscriptor *quadrature_base_pointer = &quadrature;
if (face_no==invalid_face_number)
= static_cast<const Quadrature<dim-1> *>(quadrature_base_pointer);
}
- // let base elements update the
- // necessary data
+ // let base elements update the necessary data
for (unsigned int base_no=0; base_no<this->n_base_elements(); ++base_no)
{
const FiniteElement<dim,spacedim> &
FEValuesData<dim,spacedim> &
base_data = fe_data.get_fe_values_data(base_no);
- //TODO: Think about a smarter alternative
- // Copy quadrature points. These
- // are required for computing the
- // determinant in the FEPolyTensor
- // class. The determinant is
- // one ingredient of the Piola
- // transformation, which is applied
- // to correctly map the RT space from
- // the reference element to the global
- // coordinate system.
+ //TODO: Think about a smarter alternative Copy quadrature
+ // points. These are required for computing the determinant in the
+ // FEPolyTensor class. The determinant is one ingredient of the
+ // Piola transformation, which is applied to correctly map the RT
+ // space from the reference element to the global coordinate system.
if (cell_similarity != CellSimilarity::translation)
base_data.JxW_values = data.JxW_values;
- // Make sure that in the
- // case of fill_fe_values
- // the data is only copied
- // from base_data to data
- // if base_data is
- // changed. therefore use
- // fe_fe_data.current_update_flags()
+ // Make sure that in the case of fill_fe_values the data is only
+ // copied from base_data to data if base_data is changed. therefore
+ // use fe_fe_data.current_update_flags()
//
- // for the case of
- // fill_fe_(sub)face_values
- // the data needs to be
- // copied from base_data to
- // data on each face,
- // therefore use
+ // for the case of fill_fe_(sub)face_values the data needs to be
+ // copied from base_data to data on each face, therefore use
// base_fe_data.update_flags.
if (face_no==invalid_face_number)
base_fe.fill_fe_values(mapping, cell, *cell_quadrature, mapping_data,
base_fe.fill_fe_subface_values(mapping, cell, face_no, sub_no,
*face_quadrature, mapping_data, base_fe_data, base_data);
- // now data has been
- // generated, so copy
- // it. we used to work by
- // looping over all base
- // elements (i.e. this
- // outer loop), then over
- // multiplicity, then over
- // the shape functions from
- // that base element, but
- // that requires that we
- // can infer the global
- // number of a shape
- // function from its number
- // in the base element. for
- // that we had the
- // component_to_system_table.
+ // now data has been generated, so copy it. we used to work by
+ // looping over all base elements (i.e. this outer loop), then over
+ // multiplicity, then over the shape functions from that base
+ // element, but that requires that we can infer the global number of
+ // a shape function from its number in the base element. for that we
+ // had the component_to_system_table.
//
- // however, this does of
- // course no longer work
- // since we have
- // non-primitive
- // elements. so we go the
- // other way round: loop
- // over all shape functions
- // of the composed element,
- // and here only treat
- // those shape functions
- // that belong to a given
- // base element
+ // however, this does of course no longer work since we have
+ // non-primitive elements. so we go the other way round: loop over
+ // all shape functions of the composed element, and here only treat
+ // those shape functions that belong to a given base element
//TODO: Introduce the needed table and loop only over base element shape functions. This here is not efficient at all AND very bad style
const UpdateFlags base_flags(dim_1==dim ?
base_fe_data.current_update_flags() :
base_fe_data.update_flags);
- // if the current cell is just a
- // translation of the previous
- // one, the underlying data has
- // not changed, and we don't even
- // need to enter this section
+ // if the current cell is just a translation of the previous one,
+ // the underlying data has not changed, and we don't even need to
+ // enter this section
if (cell_similarity != CellSimilarity::translation)
for (unsigned int system_index=0; system_index<this->dofs_per_cell;
++system_index)
base_index = this->system_to_base_table[system_index].second;
Assert (base_index<base_fe.dofs_per_cell, ExcInternalError());
- // now copy. if the
- // shape function is
- // primitive, then
- // there is only one
- // value to be copied,
- // but for
- // non-primitive
- // elements, there
- // might be more values
- // to be copied
+ // now copy. if the shape function is primitive, then there
+ // is only one value to be copied, but for non-primitive
+ // elements, there might be more values to be copied
//
- // so, find out from
- // which index to take
- // this one value, and
- // to which index to
- // put
+ // so, find out from which index to take this one value, and
+ // to which index to put
unsigned int out_index = 0;
for (unsigned int i=0; i<system_index; ++i)
out_index += this->n_nonzero_components(i);
for (unsigned int i=0; i<base_index; ++i)
in_index += base_fe.n_nonzero_components(i);
- // then loop over the
- // number of components
- // to be copied
+ // then loop over the number of components to be copied
Assert (this->n_nonzero_components(system_index) ==
base_fe.n_nonzero_components(base_index),
ExcInternalError());
data.shape_gradients[out_index+s][q]=
base_data.shape_gradients[in_index+s][q];
- // _we_ handle
- // computation of
- // second
- // derivatives,
- // so the base
- // elements
- // should not
- // have computed
- // them!
+ // _we_ handle computation of second derivatives, so the
+ // base elements should not have computed them!
Assert (!(base_flags & update_hessians),
ExcInternalError());
};
void
FESystem<dim,spacedim>::build_cell_tables()
{
- // If the system is not primitive,
- // these have not been initialized
- // by FiniteElement
+ // If the system is not primitive, these have not been initialized by
+ // FiniteElement
this->system_to_component_table.resize(this->dofs_per_cell);
this->face_system_to_component_table.resize(this->dofs_per_face);
Assert (total_index == this->component_to_base_table.size(),
ExcInternalError());
- // Initialize index tables.
- // Multi-component base elements
- // have to be thought of. For
- // non-primitive shape functions,
- // have a special invalid index.
+ // Initialize index tables. Multi-component base elements have to be
+ // thought of. For non-primitive shape functions, have a special invalid
+ // index.
const std::pair<unsigned int, unsigned int>
non_primitive_index (numbers::invalid_unsigned_int,
numbers::invalid_unsigned_int);
- // First enumerate vertex indices,
- // where we first enumerate all
- // indices on the first vertex in
- // the order of the base elements,
- // then of the second vertex, etc
+ // First enumerate vertex indices, where we first enumerate all indices on
+ // the first vertex in the order of the base elements, then of the second
+ // vertex, etc
total_index = 0;
for (unsigned int vertex_number=0;
vertex_number<GeometryInfo<dim>::vertices_per_cell;
void
FESystem<dim,spacedim>::build_face_tables()
{
- // Initialize index tables. do this
- // in the same way as done for the
- // cell tables, except that we now
- // loop over the objects of faces
-
- // For non-primitive shape
- // functions, have a special
- // invalid index
+ // Initialize index tables. do this in the same way as done for the cell
+ // tables, except that we now loop over the objects of faces
+
+ // For non-primitive shape functions, have a special invalid index
const std::pair<unsigned int, unsigned int>
non_primitive_index (numbers::invalid_unsigned_int,
numbers::invalid_unsigned_int);
local_index < base_element(base).dofs_per_vertex;
++local_index, ++total_index)
{
- // get (cell) index of
- // this shape function
- // inside the base
- // element to see
- // whether the shape
- // function is
- // primitive (assume
- // that all shape
- // functions on
- // vertices share the
- // same primitivity
- // property; assume
- // likewise for all
- // shape functions
- // located on lines,
- // quads, etc. this
- // way, we can ask for
- // primitivity of only
- // _one_ shape
- // function, which is
- // taken as
- // representative for
- // all others located
- // on the same type of
+ // get (cell) index of this shape function inside the base
+ // element to see whether the shape function is primitive
+ // (assume that all shape functions on vertices share the same
+ // primitivity property; assume likewise for all shape functions
+ // located on lines, quads, etc. this way, we can ask for
+ // primitivity of only _one_ shape function, which is taken as
+ // representative for all others located on the same type of
// object):
const unsigned int index_in_base
= (base_element(base).dofs_per_vertex*vertex_number +
local_index < base_element(base).dofs_per_line;
++local_index, ++total_index)
{
- // do everything
- // alike for this
- // type of object
+ // do everything alike for this type of object
const unsigned int index_in_base
= (base_element(base).dofs_per_line*line_number +
local_index +
local_index < base_element(base).dofs_per_quad;
++local_index, ++total_index)
{
- // do everything
- // alike for this
- // type of object
+ // do everything alike for this type of object
const unsigned int index_in_base
= (base_element(base).dofs_per_quad*quad_number +
local_index +
template <int dim, int spacedim>
void FESystem<dim,spacedim>::build_interface_constraints ()
{
- // check whether all base elements
- // implement their interface
- // constraint matrices. if this is
- // not the case, then leave the
- // interface costraints of this
- // composed element empty as well;
- // however, the rest of the element
- // is usable
+ // check whether all base elements implement their interface constraint
+ // matrices. if this is not the case, then leave the interface costraints of
+ // this composed element empty as well; however, the rest of the element is
+ // usable
for (unsigned int base=0; base<this->n_base_elements(); ++base)
if (base_element(base).constraints_are_implemented() == false)
return;
this->interface_constraints.
TableBase<2,double>::reinit (this->interface_constraints_size());
- // the layout of the constraints
- // matrix is described in the
- // FiniteElement class. you may
- // want to look there first before
- // trying to understand the
- // following, especially the
- // mapping of the @p{m} index.
+ // the layout of the constraints matrix is described in the FiniteElement
+ // class. you may want to look there first before trying to understand the
+ // following, especially the mapping of the @p{m} index.
//
- // in order to map it to the
- // fe-system class, we have to know
- // which base element a degree of
- // freedom within a vertex, line,
- // etc belongs to. this can be
- // accomplished by the
- // system_to_component_index
- // function in conjunction with the
- // numbers
- // first_{line,quad,...}_index
+ // in order to map it to the fe-system class, we have to know which base
+ // element a degree of freedom within a vertex, line, etc belongs to. this
+ // can be accomplished by the system_to_component_index function in
+ // conjunction with the numbers first_{line,quad,...}_index
for (unsigned int n=0; n<this->interface_constraints.n(); ++n)
for (unsigned int m=0; m<this->interface_constraints.m(); ++m)
{
- // for the pair (n,m) find
- // out which base element
- // they belong to and the
- // number therein
+ // for the pair (n,m) find out which base element they belong to and
+ // the number therein
//
- // first for the n
- // index. this is simple
- // since the n indices are in
- // the same order as they are
- // usually on a face. note
- // that for the data type,
- // first value in pair is
- // (base element,instance of
- // base element), second is
- // index within this instance
+ // first for the n index. this is simple since the n indices are in
+ // the same order as they are usually on a face. note that for the
+ // data type, first value in pair is (base element,instance of base
+ // element), second is index within this instance
const std::pair<std::pair<unsigned int,unsigned int>, unsigned int> n_index
= this->face_system_to_base_table[n];
- // likewise for the m
- // index. this is more
- // complicated due to the
- // strange ordering we have
- // for the dofs on the
- // refined faces.
+ // likewise for the m index. this is more complicated due to the
+ // strange ordering we have for the dofs on the refined faces.
std::pair<std::pair<unsigned int,unsigned int>, unsigned int> m_index;
switch (dim)
{
case 1:
{
- // we should never get here!
- // (in 1d, the constraints matrix
+ // we should never get here! (in 1d, the constraints matrix
// should be of size zero)
Assert (false, ExcInternalError());
break;
case 2:
{
- // the indices m=0..d_v-1 are
- // from the center vertex.
- // their order is the same
- // as for the first vertex
- // of the whole cell, so we
- // can use the
- // system_to_base_table
- // variable (using the
- // face_s_t_base_t function would
- // yield the same)
+ // the indices m=0..d_v-1 are from the center vertex. their order
+ // is the same as for the first vertex of the whole cell, so we
+ // can use the system_to_base_table variable (using the
+ // face_s_t_base_t function would yield the same)
if (m < this->dofs_per_vertex)
m_index = this->system_to_base_table[m];
else
- // then come the two sets of
- // line indices
+ // then come the two sets of line indices
{
const unsigned int index_in_line
= (m-this->dofs_per_vertex) % this->dofs_per_line;
= (m-this->dofs_per_vertex) / this->dofs_per_line;
Assert (sub_line < 2, ExcInternalError());
- // from this
- // information, try
- // to get base
- // element and
- // instance of base
- // element. we do
- // so by
- // constructing the
- // corresponding
- // face index of m
- // in the present
- // element, then
- // use
+ // from this information, try to get base element and instance
+ // of base element. we do so by constructing the corresponding
+ // face index of m in the present element, then use
// face_system_to_base_table
const unsigned int tmp1 = 2*this->dofs_per_vertex+index_in_line;
m_index.first = this->face_system_to_base_table[tmp1].first;
- // what we are
- // still missing is
- // the index of m
- // within the base
- // elements
- // interface_constraints
- // table
+ // what we are still missing is the index of m within the base
+ // elements interface_constraints table
//
- // here, the second
- // value of
- // face_system_to_base_table
- // can help: it
- // denotes the face
- // index of that
- // shape function
- // within the base
- // element. since
- // we know that it
- // is a line dof,
- // we can construct
- // the rest: tmp2
- // will denote the
- // index of this
- // shape function
- // among the line
- // shape functions:
+ // here, the second value of face_system_to_base_table can
+ // help: it denotes the face index of that shape function
+ // within the base element. since we know that it is a line
+ // dof, we can construct the rest: tmp2 will denote the index
+ // of this shape function among the line shape functions:
Assert (this->face_system_to_base_table[tmp1].second >=
2*base_element(m_index.first.first).dofs_per_vertex,
ExcInternalError());
case 3:
{
- // same way as above,
- // although a little
- // more complicated...
-
- // the indices
- // m=0..5*d_v-1 are
- // from the center and
- // the four subline
- // vertices. their
- // order is the same as
- // for the first vertex
- // of the whole cell,
- // so we can use the
- // simple arithmetic
+ // same way as above, although a little more complicated...
+
+ // the indices m=0..5*d_v-1 are from the center and the four
+ // subline vertices. their order is the same as for the first
+ // vertex of the whole cell, so we can use the simple arithmetic
if (m < 5*this->dofs_per_vertex)
m_index = this->system_to_base_table[m];
else
- // then come the 12 sets of
- // line indices
+ // then come the 12 sets of line indices
if (m < 5*this->dofs_per_vertex + 12*this->dofs_per_line)
{
- // for the
- // meaning of all
- // this, see the
- // 2d part
+ // for the meaning of all this, see the 2d part
const unsigned int index_in_line
= (m-5*this->dofs_per_vertex) % this->dofs_per_line;
const unsigned int sub_line
else
// on one of the four sub-quads
{
- // for the
- // meaning of all
- // this, see the
- // 2d part
+ // for the meaning of all this, see the 2d part
const unsigned int index_in_quad
= (m-5*this->dofs_per_vertex-12*this->dofs_per_line) %
this->dofs_per_quad;
Assert (false, ExcNotImplemented());
};
- // now that we gathered all
- // information: use it to
- // build the matrix. note
- // that if n and m belong to
- // different base elements or
- // instances, then there
- // definitely will be no
- // coupling
+ // now that we gathered all information: use it to build the
+ // matrix. note that if n and m belong to different base elements or
+ // instances, then there definitely will be no coupling
if (n_index.first == m_index.first)
this->interface_constraints(m,n)
= (base_element(n_index.first.first).constraints()(m_index.second,
build_cell_tables();
build_face_tables();
- for (unsigned int ref_case=RefinementCase<dim>::cut_x;
- ref_case<RefinementCase<dim>::isotropic_refinement+1;
- ++ref_case)
- {
- // Check if some of the matrices of
- // the base elements are void.
- // repeat this check for each RefineCase
- bool do_restriction = true;
- bool do_prolongation = true;
+ // restriction and prolongation matrices are build on demand
- for (unsigned int i=0; i<this->n_base_elements(); ++i)
- {
- if (base_element(i).restriction[ref_case-1][0].n() != base_element(i).dofs_per_cell)
- do_restriction = false;
- if (base_element(i).prolongation[ref_case-1][0].n() != base_element(i).dofs_per_cell)
- do_prolongation = false;
- }
-
- // if we did not encounter void
- // matrices, initialize the
- // respective matrix sizes
- if (do_restriction)
- for (unsigned int i=0; i<GeometryInfo<dim>::n_children(RefinementCase<dim>(ref_case)); ++i)
- this->restriction[ref_case-1][i].reinit(this->dofs_per_cell,
- this->dofs_per_cell);
- if (do_prolongation)
- for (unsigned int i=0; i<GeometryInfo<dim>::n_children(RefinementCase<dim>(ref_case)); ++i)
- this->prolongation[ref_case-1][i].reinit(this->dofs_per_cell,
- this->dofs_per_cell);
-
- // distribute the matrices of the
- // base finite elements to the
- // matrices of this object. for
- // this, loop over all degrees of
- // freedom and take the respective
- // entry of the underlying base
- // element.
- //
- // note that we by definition of a
- // base element, they are
- // independent, i.e. do not
- // couple. only DoFs that belong to
- // the same instance of a base
- // element may couple
- for (unsigned int i=0; i<this->dofs_per_cell; ++i)
- for (unsigned int j=0; j<this->dofs_per_cell; ++j)
- {
- // first find out to which
- // base element indices i and
- // j belong, and which
- // instance thereof in case
- // the base element has a
- // multiplicity greater than
- // one. if they should not
- // happen to belong to the
- // same instance of a base
- // element, then they cannot
- // couple, so go on with the
- // next index
- if (this->system_to_base_table[i].first !=
- this->system_to_base_table[j].first)
- continue;
-
- // so get the common base
- // element and the indices
- // therein:
- const unsigned int
- base = this->system_to_base_table[i].first.first;
-
- const unsigned int
- base_index_i = this->system_to_base_table[i].second,
- base_index_j = this->system_to_base_table[j].second;
-
- // if we are sure that DoFs i
- // and j may couple, then
- // copy entries of the
- // matrices:
- for (unsigned int child=0; child<GeometryInfo<dim>::n_children(RefinementCase<dim>(ref_case)); ++child)
- {
- if (do_restriction)
- this->restriction[ref_case-1][child] (i,j)
- = (base_element(base)
- .get_restriction_matrix(child, RefinementCase<dim>(ref_case))(
- base_index_i,base_index_j));
-
- if (do_prolongation)
- this->prolongation[ref_case-1][child] (i,j)
- = (base_element(base)
- .get_prolongation_matrix(child, RefinementCase<dim>(ref_case))(
- base_index_i,base_index_j));
- };
- };
- }
- // now set up the interface constraints.
- // this is kind'o hairy, so don't try
+ // now set up the interface constraints. this is kind'o hairy, so don't try
// to do it dimension independent
build_interface_constraints ();
- // finally fill in support points
- // on cell and face
+ // finally fill in support points on cell and face
initialize_unit_support_points ();
initialize_unit_face_support_points ();
FESystem<dim,spacedim>::
initialize_unit_support_points ()
{
- // if one of the base elements
- // has no support points, then
- // it makes no sense to define
- // support points for the
- // composed element, so return
- // an empty array to
- // demonstrate that
- // fact
+ // if one of the base elements has no support points, then it makes no sense
+ // to define support points for the composed element, so return an empty
+ // array to demonstrate that fact
for (unsigned int base_el=0; base_el<this->n_base_elements(); ++base_el)
if (!base_element(base_el).has_support_points())
{
return;
};
- // generate unit support points
- // from unit support points of sub
- // elements
+ // generate unit support points from unit support points of sub elements
this->unit_support_points.resize(this->dofs_per_cell);
for (unsigned int i=0; i<this->dofs_per_cell; ++i)
if (dim == 1)
return;
- // if one of the base elements has no
- // support points, then it makes no sense
- // to define support points for the
- // composed element. In that case, return
- // an empty array to demonstrate that fact
- // (note that we ask whether the base
- // element has no support points at all,
- // not only none on the face!)
+ // if one of the base elements has no support points, then it makes no sense
+ // to define support points for the composed element. In that case, return
+ // an empty array to demonstrate that fact (note that we ask whether the
+ // base element has no support points at all, not only none on the face!)
//
- // on the other hand, if there is an
- // element that simply has no degrees of
- // freedom on the face at all, then we
- // don't care whether it has support points
- // or not. this is, for example, the case
- // for the stable Stokes element Q(p)^dim
- // \times DGP(p-1).
+ // on the other hand, if there is an element that simply has no degrees of
+ // freedom on the face at all, then we don't care whether it has support
+ // points or not. this is, for example, the case for the stable Stokes
+ // element Q(p)^dim \times DGP(p-1).
for (unsigned int base_el=0; base_el<this->n_base_elements(); ++base_el)
if (!base_element(base_el).has_support_points()
&&
}
- // generate unit face support points
- // from unit support points of sub
+ // generate unit face support points from unit support points of sub
// elements
this->unit_face_support_points.resize(this->dofs_per_face);
if (dim < 3)
return;
- // the array into which we want to write
- // should have the correct size already.
+ // the array into which we want to write should have the correct size
+ // already.
Assert (this->adjust_quad_dof_index_for_face_orientation_table.n_elements()==
8*this->dofs_per_quad, ExcInternalError());
- // to obtain the shifts for this composed
- // element, copy the shift information of
- // the base elements
+ // to obtain the shifts for this composed element, copy the shift
+ // information of the base elements
unsigned int index = 0;
for (unsigned int b=0; b<this->n_base_elements(); ++b)
{
Assert (index == this->dofs_per_quad,
ExcInternalError());
- // aditionally compose the permutation
- // information for lines
+ // aditionally compose the permutation information for lines
Assert (this->adjust_line_dof_index_for_line_orientation_table.size()==
this->dofs_per_line, ExcInternalError());
index = 0;
ExcDimensionMismatch (interpolation_matrix.m(),
x_source_fe.dofs_per_face));
- // since dofs for each base are
- // independent, we only have to stack
- // things up from base element to base
- // element
+ // since dofs for each base are independent, we only have to stack things up
+ // from base element to base element
//
- // the problem is that we have to work with
- // two FEs (this and fe_other). only deal
- // with the case that both are FESystems
- // and that they both have the same number
- // of bases (counting multiplicity) each of
- // which match in their number of
- // components. this covers
- // FESystem(FE_Q(p),1,FE_Q(q),2) vs
- // FESystem(FE_Q(r),2,FE_Q(s),1), but not
+ // the problem is that we have to work with two FEs (this and
+ // fe_other). only deal with the case that both are FESystems and that they
+ // both have the same number of bases (counting multiplicity) each of which
+ // match in their number of components. this covers
+ // FESystem(FE_Q(p),1,FE_Q(q),2) vs FESystem(FE_Q(r),2,FE_Q(s),1), but not
// FESystem(FE_Q(p),1,FE_Q(q),2) vs
// FESystem(FESystem(FE_Q(r),2),1,FE_Q(s),1)
const FESystem<dim,spacedim> *fe_other_system
= dynamic_cast<const FESystem<dim,spacedim>*>(&x_source_fe);
- // clear matrix, since we will not get to
- // set all elements
+ // clear matrix, since we will not get to set all elements
interpolation_matrix = 0;
- // loop over all the base elements of
- // this and the other element, counting
+ // loop over all the base elements of this and the other element, counting
// their multiplicities
unsigned int base_index = 0,
base_index_other = 0;
base.get_face_interpolation_matrix (base_other,
base_to_base_interpolation);
- // now translate entries. we'd like to
- // have something like
- // face_base_to_system_index, but that
- // doesn't exist. rather, all we have
- // is the reverse. well, use that then
+ // now translate entries. we'd like to have something like
+ // face_base_to_system_index, but that doesn't exist. rather, all we
+ // have is the reverse. well, use that then
for (unsigned int i=0; i<this->dofs_per_face; ++i)
if (this->face_system_to_base_index(i).first
==
= base_to_base_interpolation(fe_other_system->face_system_to_base_index(j).second,
this->face_system_to_base_index(i).second);
- // advance to the next base element
- // for this and the other
- // fe_system; see if we can simply
- // advance the multiplicity by one,
- // or if have to move on to the
- // next base element
+ // advance to the next base element for this and the other fe_system;
+ // see if we can simply advance the multiplicity by one, or if have to
+ // move on to the next base element
++multiplicity;
if (multiplicity == this->element_multiplicity(base_index))
{
++base_index_other;
}
- // see if we have reached the end
- // of the present element. if so,
- // we should have reached the end
- // of the other one as well
+ // see if we have reached the end of the present element. if so, we
+ // should have reached the end of the other one as well
if (base_index == this->n_base_elements())
{
Assert (base_index_other == fe_other_system->n_base_elements(),
break;
}
- // if we haven't reached the end of
- // this element, we shouldn't have
- // reached the end of the other one
- // either
+ // if we haven't reached the end of this element, we shouldn't have
+ // reached the end of the other one either
Assert (base_index_other != fe_other_system->n_base_elements(),
ExcInternalError());
}
ExcDimensionMismatch (interpolation_matrix.m(),
x_source_fe.dofs_per_face));
- // since dofs for each base are
- // independent, we only have to stack
- // things up from base element to base
- // element
+ // since dofs for each base are independent, we only have to stack things up
+ // from base element to base element
//
- // the problem is that we have to work with
- // two FEs (this and fe_other). only deal
- // with the case that both are FESystems
- // and that they both have the same number
- // of bases (counting multiplicity) each of
- // which match in their number of
- // components. this covers
- // FESystem(FE_Q(p),1,FE_Q(q),2) vs
- // FESystem(FE_Q(r),2,FE_Q(s),1), but not
+ // the problem is that we have to work with two FEs (this and
+ // fe_other). only deal with the case that both are FESystems and that they
+ // both have the same number of bases (counting multiplicity) each of which
+ // match in their number of components. this covers
+ // FESystem(FE_Q(p),1,FE_Q(q),2) vs FESystem(FE_Q(r),2,FE_Q(s),1), but not
// FESystem(FE_Q(p),1,FE_Q(q),2) vs
// FESystem(FESystem(FE_Q(r),2),1,FE_Q(s),1)
const FESystem<dim,spacedim> *fe_other_system
= dynamic_cast<const FESystem<dim,spacedim>*>(&x_source_fe);
- // clear matrix, since we will not get to
- // set all elements
+ // clear matrix, since we will not get to set all elements
interpolation_matrix = 0;
- // loop over all the base elements of
- // this and the other element, counting
+ // loop over all the base elements of this and the other element, counting
// their multiplicities
unsigned int base_index = 0,
base_index_other = 0;
subface,
base_to_base_interpolation);
- // now translate entries. we'd like to
- // have something like
- // face_base_to_system_index, but that
- // doesn't exist. rather, all we have
- // is the reverse. well, use that then
+ // now translate entries. we'd like to have something like
+ // face_base_to_system_index, but that doesn't exist. rather, all we
+ // have is the reverse. well, use that then
for (unsigned int i=0; i<this->dofs_per_face; ++i)
if (this->face_system_to_base_index(i).first
==
= base_to_base_interpolation(fe_other_system->face_system_to_base_index(j).second,
this->face_system_to_base_index(i).second);
- // advance to the next base element
- // for this and the other
- // fe_system; see if we can simply
- // advance the multiplicity by one,
- // or if have to move on to the
- // next base element
+ // advance to the next base element for this and the other fe_system;
+ // see if we can simply advance the multiplicity by one, or if have to
+ // move on to the next base element
++multiplicity;
if (multiplicity == this->element_multiplicity(base_index))
{
++base_index_other;
}
- // see if we have reached the end
- // of the present element. if so,
- // we should have reached the end
- // of the other one as well
+ // see if we have reached the end of the present element. if so, we
+ // should have reached the end of the other one as well
if (base_index == this->n_base_elements())
{
Assert (base_index_other == fe_other_system->n_base_elements(),
break;
}
- // if we haven't reached the end of
- // this element, we shouldn't have
- // reached the end of the other one
- // either
+ // if we haven't reached the end of this element, we shouldn't have
+ // reached the end of the other one either
Assert (base_index_other != fe_other_system->n_base_elements(),
ExcInternalError());
}
std::vector<std::pair<unsigned int, unsigned int> >
FESystem<dim,spacedim>::hp_object_dof_identities (const FiniteElement<dim,spacedim> &fe_other) const
{
- // since dofs on each subobject (vertex,
- // line, ...) are ordered such that first
- // come all from the first base element all
- // multiplicities, then second base element
- // all multiplicities, etc., we simply have
- // to stack all the identities after each
- // other
+ // since dofs on each subobject (vertex, line, ...) are ordered such that
+ // first come all from the first base element all multiplicities, then
+ // second base element all multiplicities, etc., we simply have to stack all
+ // the identities after each other
//
- // the problem is that we have to work with
- // two FEs (this and fe_other). only deal
- // with the case that both are FESystems
- // and that they both have the same number
- // of bases (counting multiplicity) each of
- // which match in their number of
- // components. this covers
- // FESystem(FE_Q(p),1,FE_Q(q),2) vs
- // FESystem(FE_Q(r),2,FE_Q(s),1), but not
+ // the problem is that we have to work with two FEs (this and
+ // fe_other). only deal with the case that both are FESystems and that they
+ // both have the same number of bases (counting multiplicity) each of which
+ // match in their number of components. this covers
+ // FESystem(FE_Q(p),1,FE_Q(q),2) vs FESystem(FE_Q(r),2,FE_Q(s),1), but not
// FESystem(FE_Q(p),1,FE_Q(q),2) vs
// FESystem(FESystem(FE_Q(r),2),1,FE_Q(s),1)
if (const FESystem<dim,spacedim> *fe_other_system
= dynamic_cast<const FESystem<dim,spacedim>*>(&fe_other))
{
- // loop over all the base elements of
- // this and the other element, counting
- // their multiplicities
+ // loop over all the base elements of this and the other element,
+ // counting their multiplicities
unsigned int base_index = 0,
base_index_other = 0;
unsigned int multiplicity = 0,
multiplicity_other = 0;
- // we also need to keep track of the
- // number of dofs already treated for
+ // we also need to keep track of the number of dofs already treated for
// each of the elements
unsigned int dof_offset = 0,
dof_offset_other = 0;
Assert (base.n_components() == base_other.n_components(),
ExcNotImplemented());
- // now translate the identities
- // returned by the base elements to
- // the indices of this system
- // element
+ // now translate the identities returned by the base elements to the
+ // indices of this system element
std::vector<std::pair<unsigned int, unsigned int> > base_identities;
switch (structdim)
{
(std::make_pair (base_identities[i].first + dof_offset,
base_identities[i].second + dof_offset_other));
- // record the dofs treated above as
- // already taken care of
+ // record the dofs treated above as already taken care of
dof_offset += base.template n_dofs_per_object<structdim>();
dof_offset_other += base_other.template n_dofs_per_object<structdim>();
- // advance to the next base element
- // for this and the other
- // fe_system; see if we can simply
- // advance the multiplicity by one,
- // or if have to move on to the
- // next base element
+ // advance to the next base element for this and the other
+ // fe_system; see if we can simply advance the multiplicity by one,
+ // or if have to move on to the next base element
++multiplicity;
if (multiplicity == this->element_multiplicity(base_index))
{
++base_index_other;
}
- // see if we have reached the end
- // of the present element. if so,
- // we should have reached the end
- // of the other one as well
+ // see if we have reached the end of the present element. if so, we
+ // should have reached the end of the other one as well
if (base_index == this->n_base_elements())
{
Assert (base_index_other == fe_other_system->n_base_elements(),
break;
}
- // if we haven't reached the end of
- // this element, we shouldn't have
- // reached the end of the other one
- // either
+ // if we haven't reached the end of this element, we shouldn't have
+ // reached the end of the other one either
Assert (base_index_other != fe_other_system->n_base_elements(),
ExcInternalError());
}
FESystem<dim,spacedim>::
compare_for_face_domination (const FiniteElement<dim,spacedim> &fe_other) const
{
- // at present all we can do is to compare
- // with other FESystems that have the same
- // number of components and bases
+ // at present all we can do is to compare with other FESystems that have the
+ // same number of components and bases
if (const FESystem<dim,spacedim> *fe_sys_other
= dynamic_cast<const FESystem<dim,spacedim>*>(&fe_other))
{
FiniteElementDomination::Domination
domination = FiniteElementDomination::no_requirements;
- // loop over all base elements and do
- // some sanity checks
+ // loop over all base elements and do some sanity checks
for (unsigned int b=0; b<this->n_base_elements(); ++b)
{
Assert (this->base_element(b).n_components() ==
fe_sys_other->element_multiplicity(b),
ExcNotImplemented());
- // for this pair of base elements,
- // check who dominates and combine
+ // for this pair of base elements, check who dominates and combine
// with previous result
const FiniteElementDomination::Domination
base_domination = (this->base_element(b)
domination = domination & base_domination;
}
- // if we've gotten here, then we've
- // either found a winner or either
+ // if we've gotten here, then we've either found a winner or either
// element is fine being dominated
Assert (domination !=
FiniteElementDomination::neither_element_dominates,
summed_multiplicities += multiplicities[i];
}
- unsigned char total_conformity = 0xff;;
-
- for (unsigned int i=0; i<fes.size(); i++)
- if (multiplicities[i]>0)
- total_conformity &= fes[i]->conforming_space;
+ // assume conformity of the first finite element and then take away
+ // bits as indicated by the base elements. if all multiplicities
+ // happen to be zero, then it doesn't matter what we set it to.
+ typename FiniteElementData<dim>::Conformity total_conformity
+ = typename FiniteElementData<dim>::Conformity();
+ {
+ unsigned int index = 0;
+ for (unsigned int index=0; index<fes.size(); ++index)
+ if (multiplicities[index]>0)
+ {
+ total_conformity = fes[index]->conforming_space;
+ break;
+ }
+
+ for (; index<fes.size(); ++index)
+ if (multiplicities[index]>0)
+ total_conformity =
+ typename FiniteElementData<dim>::Conformity(total_conformity
+ &
+ fes[index]->conforming_space);
+ }
std::vector<unsigned int> dpo;
dpo.push_back(multiplied_dofs_per_vertex);
if (dim>1) dpo.push_back(multiplied_dofs_per_quad);
if (dim>2) dpo.push_back(multiplied_dofs_per_hex);
- return FiniteElementData<dim> (
- dpo,
- multiplied_n_components,
- degree,
- typename FiniteElementData<dim>::Conformity(total_conformity),
- summed_multiplicities);
+ return FiniteElementData<dim> (dpo,
+ multiplied_n_components,
+ degree,
+ total_conformity,
+ summed_multiplicities);
}
{
Assert (fes.size() == multiplicities.size(), ExcInternalError());
- // first count the number of dofs
- // and components that will emerge
- // from the given FEs
+ // first count the number of dofs and components that will emerge from the
+ // given FEs
unsigned int n_shape_functions = 0;
for (unsigned int i=0; i<fes.size(); ++i)
if (multiplicities[i]>0) // check needed as fe might be NULL
n_shape_functions += fes[i]->dofs_per_cell * multiplicities[i];
- // generate the array that will
- // hold the output
+ // generate the array that will hold the output
std::vector<bool> retval (n_shape_functions, false);
- // finally go through all the shape
- // functions of the base elements,
- // and copy their flags. this
- // somehow copies the code in
- // build_cell_table, which is not
- // nice as it uses too much
- // implicit knowledge about the
- // layout of the individual bases
- // in the composed FE, but there
- // seems no way around...
+ // finally go through all the shape functions of the base elements, and copy
+ // their flags. this somehow copies the code in build_cell_table, which is
+ // not nice as it uses too much implicit knowledge about the layout of the
+ // individual bases in the composed FE, but there seems no way around...
//
- // for each shape function, copy
- // the flags from the base element
- // to this one, taking into account
- // multiplicities, and other
- // complications
+ // for each shape function, copy the flags from the base element to this
+ // one, taking into account multiplicities, and other complications
unsigned int total_index = 0;
for (unsigned int vertex_number=0;
vertex_number<GeometryInfo<dim>::vertices_per_cell;
{
Assert (fes.size() == multiplicities.size(), ExcInternalError());
- // first count the number of dofs
- // and components that will emerge
- // from the given FEs
+ // first count the number of dofs and components that will emerge from the
+ // given FEs
unsigned int n_shape_functions = 0;
for (unsigned int i=0; i<fes.size(); ++i)
if (multiplicities[i]>0) //needed because fe might be NULL
if (multiplicities[i]>0) //needed because fe might be NULL
n_components += fes[i]->n_components() * multiplicities[i];
- // generate the array that will
- // hold the output
+ // generate the array that will hold the output
std::vector<std::vector<bool> >
retval (n_shape_functions, std::vector<bool> (n_components, false));
- // finally go through all the shape
- // functions of the base elements,
- // and copy their flags. this
- // somehow copies the code in
- // build_cell_table, which is not
- // nice as it uses too much
- // implicit knowledge about the
- // layout of the individual bases
- // in the composed FE, but there
- // seems no way around...
+ // finally go through all the shape functions of the base elements, and copy
+ // their flags. this somehow copies the code in build_cell_table, which is
+ // not nice as it uses too much implicit knowledge about the layout of the
+ // individual bases in the composed FE, but there seems no way around...
//
- // for each shape function, copy
- // the non-zero flags from the base
- // element to this one, taking into
- // account multiplicities, multiple
- // components in base elements, and
- // other complications
+ // for each shape function, copy the non-zero flags from the base element to
+ // this one, taking into account multiplicities, multiple components in base
+ // elements, and other complications
unsigned int total_index = 0;
for (unsigned int vertex_number=0;
vertex_number<GeometryInfo<dim>::vertices_per_cell;
(this->unit_support_points.size() == 0),
typename FEL::ExcFEHasNoSupportPoints ());
- // let's see whether we have the
- // information pre-computed
+ // let's see whether we have the information pre-computed
if (this->unit_support_points.size() != 0)
return this->unit_support_points[index];
else
- // no. ask the base element
- // whether it would like to
- // provide this information
+ // no. ask the base element whether it would like to provide this
+ // information
return (base_element(this->system_to_base_index(index).first.first)
.unit_support_point(this->system_to_base_index(index).second));
}
(this->unit_face_support_points.size() == 0),
typename FEL::ExcFEHasNoSupportPoints ());
- // let's see whether we have the
- // information pre-computed
+ // let's see whether we have the information pre-computed
if (this->unit_face_support_points.size() != 0)
return this->unit_face_support_points[index];
else
- // no. ask the base element
- // whether it would like to
- // provide this information
+ // no. ask the base element whether it would like to provide this
+ // information
return (base_element(this->face_system_to_base_index(index).first.first)
.unit_face_support_point(this->face_system_to_base_index(index).second));
}
std::size_t
FESystem<dim,spacedim>::memory_consumption () const
{
- // neglect size of data stored in
- // @p{base_elements} due to some
- // problems with the
- // compiler. should be neglectable
- // after all, considering the size
+ // neglect size of data stored in @p{base_elements} due to some problems
+ // with the compiler. should be neglectable after all, considering the size
// of the data of the subelements
std::size_t mem = (FiniteElement<dim,spacedim>::memory_consumption () +
sizeof (base_elements));
+ namespace internal
+ {
+ namespace
+ {
+ template <int dim, int spacedim, class InVector>
+ void back_interpolate (const DoFHandler<dim,spacedim> &dof1,
+ const ConstraintMatrix &constraints1,
+ const InVector &u1,
+ const DoFHandler<dim,spacedim> &dof2,
+ const ConstraintMatrix &constraints2,
+ InVector &u1_interpolated)
+ {
+ Vector<typename InVector::value_type> u2(dof2.n_dofs());
+ interpolate(dof1, u1, dof2, constraints2, u2);
+ interpolate(dof2, u2, dof1, constraints1, u1_interpolated);
+ }
+
+ // special version for PETSc
+#ifdef DEAL_II_WITH_PETSC
+ template <int dim, int spacedim>
+ void back_interpolate (const DoFHandler<dim,spacedim> &dof1,
+ const ConstraintMatrix &constraints1,
+ const PETScWrappers::MPI::Vector &u1,
+ const DoFHandler<dim,spacedim> &dof2,
+ const ConstraintMatrix &constraints2,
+ PETScWrappers::MPI::Vector &u1_interpolated)
+ {
+ // if u1 is a parallel distributed PETSc vector, we create a
+ // vector u2 with based on the sets of locally owned and relevant
+ // dofs of dof2
+ IndexSet dof2_locally_owned_dofs = dof2.locally_owned_dofs();
+ IndexSet dof2_locally_relevant_dofs;
+ DoFTools::extract_locally_relevant_dofs (dof2,
+ dof2_locally_relevant_dofs);
+
+ PETScWrappers::MPI::Vector u2_out (u1.get_mpi_communicator(),
+ dof2_locally_owned_dofs);
+ interpolate(dof1, u1, dof2, constraints2, u2_out);
+ PETScWrappers::MPI::Vector u2 (u1.get_mpi_communicator(),
+ dof2_locally_owned_dofs,
+ dof2_locally_relevant_dofs);
+ u2 = u2_out;
+ interpolate(dof2, u2, dof1, constraints1, u1_interpolated);
+ }
+#endif
+
+ // special version for parallel::distributed::Vector
+ template <int dim, int spacedim, typename Number>
+ void back_interpolate (const DoFHandler<dim,spacedim> &dof1,
+ const ConstraintMatrix &constraints1,
+ const parallel::distributed::Vector<Number> &u1,
+ const DoFHandler<dim,spacedim> &dof2,
+ const ConstraintMatrix &constraints2,
+ parallel::distributed::Vector<Number> &u1_interpolated)
+ {
+ IndexSet dof2_locally_owned_dofs = dof2.locally_owned_dofs();
+ IndexSet dof2_locally_relevant_dofs;
+ DoFTools::extract_locally_relevant_dofs (dof2,
+ dof2_locally_relevant_dofs);
+
+ parallel::distributed::Vector<Number>
+ u2 (dof2_locally_owned_dofs,
+ dof2_locally_relevant_dofs,
+ u1.get_mpi_communicator());
+
+ interpolate(dof1, u1, dof2, constraints2, u2);
+ u2.update_ghost_values ();
+ interpolate(dof2, u2, dof1, constraints1, u1_interpolated);
+ }
+ }
+ }
+
+
template <int dim, class InVector, class OutVector, int spacedim>
void back_interpolate(const DoFHandler<dim,spacedim> &dof1,
const ConstraintMatrix &constraints1,
const ConstraintMatrix &constraints2,
OutVector &u1_interpolated)
{
- // For discontinuous elements
- // without constraints take the
- // simpler version of the
- // back_interpolate function.
+ // 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);
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
-#ifdef DEAL_II_WITH_PETSC
- if (dynamic_cast<const PETScWrappers::MPI::Vector *>(&u1) != 0)
- {
- AssertThrow (dynamic_cast<const PETScWrappers::MPI::Vector *>(&u1_interpolated) != 0,
- ExcMessage("Interpolation can only be done between vectors of same type!"));
-
- // 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 (dynamic_cast<const PETScWrappers::MPI::Vector *> (&u1)->get_mpi_communicator(),
- dof2_locally_owned_dofs);
- interpolate(dof1, u1, dof2, constraints2, u2_out);
- PETScWrappers::MPI::Vector u2 (dynamic_cast<const PETScWrappers::MPI::Vector *> (&u1)->get_mpi_communicator(),
- dof2_locally_owned_dofs,
- dof2_locally_relevant_dofs);
- u2 = u2_out;
- interpolate(dof2, u2, dof1, constraints1, u1_interpolated);
- }
- else
-#endif
- {
- Vector<typename OutVector::value_type> u2(dof2.n_dofs());
- interpolate(dof1, u1, dof2, constraints2, u2);
- interpolate(dof2, u2, dof1, constraints1, u1_interpolated);
- }
+ // 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);
}
}
const unsigned int dofs_per_cell = fe.dofs_per_cell;
// polynomial degree
const unsigned int degree = fe.dofs_per_line+1;
- // number of grid points in each
- // direction
+ // number of grid points in each direction
const unsigned int n = degree+1;
- // the following lines of code are
- // somewhat odd, due to the way the
- // hierarchic numbering is
- // organized. if someone would
- // really want to understand these
- // lines, you better draw some
- // pictures where you indicate the
- // indices and orders of vertices,
- // lines, etc, along with the
- // numbers of the degrees of
- // freedom in hierarchical and
- // lexicographical order
+ // the following lines of code are somewhat odd, due to the way the
+ // hierarchic numbering is organized. if someone would really want to
+ // understand these lines, you better draw some pictures where you
+ // indicate the indices and orders of vertices, lines, etc, along with the
+ // numbers of the degrees of freedom in hierarchical and lexicographical
+ // order
switch (dim)
{
case 1:
//---------------------------------------------------------------------------
+for (deal_II_dimension : DIMENSIONS; deal_II_space_dimension : SPACE_DIMENSIONS; Vector : SERIAL_VECTORS)
+ {
+ namespace FETools
+ \{
+#if deal_II_dimension <= deal_II_space_dimension
+ template
+ void interpolate<deal_II_dimension,deal_II_space_dimension>
+ (const DoFHandler<deal_II_dimension,deal_II_space_dimension> &, const Vector &,
+ const DoFHandler<deal_II_dimension,deal_II_space_dimension> &, Vector &);
+
+ template
+ void interpolate<deal_II_dimension,deal_II_space_dimension>
+ (const DoFHandler<deal_II_dimension,deal_II_space_dimension> &, const Vector &,
+ const DoFHandler<deal_II_dimension,deal_II_space_dimension> &, const ConstraintMatrix &,
+ Vector &);
+#endif
+ \}
+ }
+
for (deal_II_dimension : DIMENSIONS; deal_II_space_dimension : SPACE_DIMENSIONS)
{
namespace FETools
template
void compute_embedding_matrices<deal_II_dimension, double, deal_II_space_dimension>
(const FiniteElement<deal_II_dimension,deal_II_space_dimension> &,
- std::vector<std::vector<FullMatrix<double> > >&,bool);
-
- template
- void interpolate<deal_II_dimension,deal_II_space_dimension>
- (const DoFHandler<deal_II_dimension,deal_II_space_dimension> &, const Vector<double> &,
- const DoFHandler<deal_II_dimension,deal_II_space_dimension> &, Vector<double> &);
-
- template
- void interpolate<deal_II_dimension,deal_II_space_dimension>
- (const DoFHandler<deal_II_dimension,deal_II_space_dimension> &, const Vector<double> &,
- const DoFHandler<deal_II_dimension,deal_II_space_dimension> &, const ConstraintMatrix &,
- Vector<double> &);
-
- template
- void interpolate<deal_II_dimension,deal_II_space_dimension>
- (const DoFHandler<deal_II_dimension,deal_II_space_dimension> &, const Vector<float> &,
- const DoFHandler<deal_II_dimension,deal_II_space_dimension> &, Vector<float> &);
- template
-
- void interpolate<deal_II_dimension,deal_II_space_dimension>
- (const DoFHandler<deal_II_dimension,deal_II_space_dimension> &, const Vector<float> &,
- const DoFHandler<deal_II_dimension,deal_II_space_dimension> &, const ConstraintMatrix &,
- Vector<float> &);
-
-
- template
- void interpolate<deal_II_dimension,deal_II_space_dimension>
- (const DoFHandler<deal_II_dimension,deal_II_space_dimension> &, const BlockVector<double> &,
- const DoFHandler<deal_II_dimension,deal_II_space_dimension> &, BlockVector<double> &);
-
- template
- void interpolate<deal_II_dimension,deal_II_space_dimension>
- (const DoFHandler<deal_II_dimension,deal_II_space_dimension> &, const BlockVector<double> &,
- const DoFHandler<deal_II_dimension,deal_II_space_dimension> &, const ConstraintMatrix &,
- BlockVector<double> &);
-
- template
- void interpolate<deal_II_dimension,deal_II_space_dimension>
- (const DoFHandler<deal_II_dimension,deal_II_space_dimension> &, const BlockVector<float> &,
- const DoFHandler<deal_II_dimension,deal_II_space_dimension> &, BlockVector<float> &);
-
- template
- void interpolate<deal_II_dimension,deal_II_space_dimension>
- (const DoFHandler<deal_II_dimension,deal_II_space_dimension> &, const BlockVector<float> &,
- const DoFHandler<deal_II_dimension,deal_II_space_dimension> &, const ConstraintMatrix &,
- BlockVector<float> &);
+ std::vector<std::vector<FullMatrix<double> > >&,bool);
#endif
\}
}
unsigned int n_materials = 0;
unsigned int n_levels = 0;
unsigned int n_subdomains = 0;
- //unsigned int n_level_subdomains = 0; // TODO [CW]: CellAccessor<dim, spacedim> does not seem to possess this attribute ...
-
+ unsigned int n_level_subdomains = 0;
+
unsigned int n = 0;
unsigned int min_level, max_level;
unsigned int cell_label_font_size;
// font size for date, time, legend, and colorbar
- unsigned int font_size = static_cast<unsigned int>(.5 + (height/100.) * 2.);
+ unsigned int font_size = static_cast<unsigned int>(.5 + (height/100.) * 1.75);
// get date and time
// time_t time_stamp;
float x_dimension_perspective, y_dimension_perspective;
- Triangulation<2,2>::active_cell_iterator cell = tria.begin_active(), endc = tria.end();
+ Triangulation<2,2>::cell_iterator cell = tria.begin(), endc = tria.end();
// auxiliary variables for the bounding box and the range of cell levels
double x_min = cell->vertex(0)[0];
for (unsigned int subdomain_index = 0; subdomain_index < 256; subdomain_index++)
subdomains[subdomain_index] = 0;
- // TODO [CW]: not yet implemented ...
- /*
// auxiliary array for the level subdomains being used
int level_subdomains[256];
- for(int level_subdomain_index = 0; level_subdomain_index < 256; level_subdomain_index++) level_subdomains[level_subdomain_index] = 0;
- */
+ for(int level_subdomain_index = 0; level_subdomain_index < 256; level_subdomain_index++)
+ level_subdomains[level_subdomain_index] = 0;
// We use an active cell iterator to determine the
// bounding box of the given triangulation and check
if ((unsigned int)cell->level() < min_level) min_level = cell->level();
if ((unsigned int)cell->level() > max_level) max_level = cell->level();
- if ((unsigned int)cell->material_id()) materials[(unsigned int)cell->material_id()] = 1;
- else if ((unsigned int)cell->material_id() == 0) materials[0] = 1;
-
- if ((int)cell->level()) levels[(unsigned int)cell->level()] = 1;
- else if ((unsigned int)cell->level() == 0) levels[0] = 1;
-
- if ((unsigned int)cell->subdomain_id()) subdomains[(unsigned int)cell->subdomain_id()] = 1;
- else if ((unsigned int)cell->subdomain_id() == 0) subdomains[0] = 1;
-
- // if((unsigned int)(cell->level_subdomain_id())) level_subdomains[(unsigned int)cell->level_subdomain_id()] = 1;
- // else if((unsigned int)(cell->level_subdomain_id()) == 0) level_subdomains[0] = 1;
+ materials[(unsigned int)cell->material_id()] = 1;
+ levels[(unsigned int)cell->level()] = 1;
+ subdomains[cell->subdomain_id()+2] = 1;
+ level_subdomains[cell->level_subdomain_id()+2] = 1;
}
x_dimension = x_max - x_min;
if (subdomains[subdomain_index]) n_subdomains++;
}
- /*
// count the level subdomains being used
for(int level_subdomain_index = 0; level_subdomain_index < 256; level_subdomain_index++)
{
if(level_subdomains[level_subdomain_index]) n_level_subdomains++;
}
- */
switch (svg_flags.coloring)
{
case GridOutFlags::Svg::subdomain_id:
n = n_subdomains;
break;
- // case GridOutFlags::Svg::level_subdomain_id: n = n_level_subdomains;
- // break;
+ case GridOutFlags::Svg::level_subdomain_id: n = n_level_subdomains;
+ break;
default:
break;
}
-
// set the camera position to top view, targeting at the origin
camera_position[0] = 0;
camera_position[1] = 0;
camera_focus = .5 * std::max(x_dimension, y_dimension);
- float *camera_position_temp = new float[3];
- float *camera_direction_temp = new float[3];
- float *camera_horizontal_temp = new float[3];
+ Point<3> camera_position_temp;
+ Point<3> camera_direction_temp;
+ Point<3> camera_horizontal_temp;
const float angle_factor = 3.14159265 / 180.;
camera_horizontal[0] = camera_horizontal_temp[0];
camera_horizontal[1] = camera_horizontal_temp[1];
- delete camera_position_temp;
- delete camera_direction_temp;
- delete camera_horizontal_temp;
-
// translate the camera to the given triangulation
camera_position[0] = x_min + .5 * x_dimension;
camera_position[1] = y_min + .5 * y_dimension;
// determine the bounding box of the given triangulation on the projection plane of the camera viewing system
- cell = tria.begin_active();
+ cell = tria.begin();
endc = tria.end();
point[0] = cell->vertex(0)[0];
x_dimension_perspective = x_max_perspective - x_min_perspective;
y_dimension_perspective = y_max_perspective - y_min_perspective;
- cell_label_font_size = static_cast<unsigned int>(.5 + (height/100.) * 2.25) * 9. * (min_level_min_vertex_distance / std::min(x_dimension, y_dimension));
+ cell_label_font_size = static_cast<unsigned int>(.5 + (height/100.) * 2.75) * 9. * (min_level_min_vertex_distance / std::min(x_dimension, y_dimension));
// create the svg file with an internal style sheet
width = static_cast<unsigned int>(.5 + height * (x_dimension_perspective / y_dimension_perspective));
unsigned int additional_width = 0;
- if (svg_flags.draw_legend && (svg_flags.label_level_number || svg_flags.label_cell_index || svg_flags.label_material_id || svg_flags.label_subdomain_id)) // || svg_flags.label_level_subdomain_id ))
+ if (svg_flags.draw_legend && (svg_flags.label_level_number || svg_flags.label_cell_index || svg_flags.label_material_id || svg_flags.label_subdomain_id || svg_flags.label_level_subdomain_id ))
{
additional_width = static_cast<unsigned int>(.5 + height * .4); // additional width for legend
}
case GridOutFlags::Svg::subdomain_id:
while (!subdomains[labeling_index]) labeling_index++;
break;
- // case GridOutFlags::Svg::level_subdomain_id: while(!level_subdomains[labeling_index]) labeling_index++;
- // break;
+ case GridOutFlags::Svg::level_subdomain_id:
+ while(!level_subdomains[labeling_index]) labeling_index++;
+ break;
default:
break;
}
out << (unsigned int)cell->level();
break;
case GridOutFlags::Svg::subdomain_id:
- out << (unsigned int)cell->subdomain_id();
+ out << cell->subdomain_id() + 2;
break;
- // case GridOutFlags::Svg::level_subdomain_id: out << (unsigned int)cell->level_subdomain_id();
- // break;
+ case GridOutFlags::Svg::level_subdomain_id:
+ out << cell->level_subdomain_id() + 2;
+ break;
default:
break;
}
out << "\"/>" << '\n';
// label the current cell
- if (svg_flags.label_level_number || svg_flags.label_cell_index || svg_flags.label_material_id || svg_flags.label_subdomain_id) // || svg_flags.label_level_subdomain_id)
+ if (svg_flags.label_level_number || svg_flags.label_cell_index || svg_flags.label_material_id || svg_flags.label_subdomain_id || svg_flags.label_level_subdomain_id)
{
point[0] = cell->center()[0];
point[1] = cell->center()[1];
if (svg_flags.label_subdomain_id)
{
if (svg_flags.label_level_number || svg_flags.label_cell_index || svg_flags.label_material_id) out << ',';
- out << cell->subdomain_id();
+ out << static_cast<int>(cell->subdomain_id());
}
- // if(svg_flags.label_level_subdomain_id)
- // {
- // if(svg_flags.label_level_number || svg_flags.label_cell_index || svg_flags.label_material_id || svg_flags.label_subdomain_id) out << ',';
- // out << cell->level_subdomain_id();
- // }
+ if(svg_flags.label_level_subdomain_id)
+ {
+ if(svg_flags.label_level_number
+ || svg_flags.label_cell_index
+ || svg_flags.label_material_id
+ || svg_flags.label_subdomain_id)
+ out << ',';
+ out << static_cast<int>(cell->level_subdomain_id());
+ }
out << "</text>" << '\n';
}
if (!svg_flags.margin) additional_width = static_cast<unsigned int>(.5 + (height/100.) * 2.5);
// explanation of the cell labeling
- if (svg_flags.draw_legend && (svg_flags.label_level_number || svg_flags.label_cell_index || svg_flags.label_material_id || svg_flags.label_subdomain_id)) // || svg_flags.label_level_subdomain_id ))
+ if (svg_flags.draw_legend && (svg_flags.label_level_number || svg_flags.label_cell_index || svg_flags.label_material_id || svg_flags.label_subdomain_id || svg_flags.label_level_subdomain_id ))
{
out << " <rect x=\"" << width + additional_width << "\" y=\"" << static_cast<unsigned int>(.5 + (height/100.) * margin_in_percent)
<< "\" width=\"" << static_cast<unsigned int>(.5 + (height/100.) * (40. - margin_in_percent)) << "\" height=\"" << static_cast<unsigned int>(.5 + height * .165) << "\"/>" << '\n';
<< "\" style=\"text-anchor:start; font-style:oblique; font-size:" << font_size
<< "\">" << "level_number";
- if (svg_flags.label_cell_index || svg_flags.label_material_id || svg_flags.label_subdomain_id) // || svg_flags.label_level_subdomain_id)
+ if (svg_flags.label_cell_index || svg_flags.label_material_id || svg_flags.label_subdomain_id || svg_flags.label_level_subdomain_id)
out << ',';
out << "</text>" << '\n';
<< "\">"
<< "cell_index";
- if (svg_flags.label_material_id || svg_flags.label_subdomain_id) // || svg_flags.label_level_subdomain_id)
+ if (svg_flags.label_material_id || svg_flags.label_subdomain_id || svg_flags.label_level_subdomain_id)
out << ',';
out << "</text>" << '\n';
<< "\">"
<< "material_id";
- if (svg_flags.label_subdomain_id) // || svg_flags.label_level_subdomain_id)
+ if (svg_flags.label_subdomain_id || svg_flags.label_level_subdomain_id)
out << ',';
out << "</text>" << '\n';
<< "\">"
<< "subdomain_id";
- // if(svg_flags.label_level_subdomain_id)
- // out << ',';
+ if(svg_flags.label_level_subdomain_id)
+ out << ',';
out << "</text>" << '\n';
}
- // if(svg_flags.label_level_subdomain_id)
- // {
- // out << " <text x= \"" << width + additional_width + static_cast<unsigned int>(.5 + (height/100.) * 2.)
- // << "\" y=\"" << static_cast<unsigned int>(.5 + (height/100.) * margin_in_percent + (++line_offset) * 1.5 * font_size )
- // << "\" style=\"text-anchor:start; font-style:oblique; font-size:" << font_size
- // << "\">"
- // << "level_subdomain_id"
- // << "</text>" << '\n';
- // }
+ if(svg_flags.label_level_subdomain_id)
+ {
+ out << " <text x= \"" << width + additional_width + static_cast<unsigned int>(.5 + (height/100.) * 2.)
+ << "\" y=\"" << static_cast<unsigned int>(.5 + (height/100.) * margin_in_percent + (++line_offset) * 1.5 * font_size )
+ << "\" style=\"text-anchor:start; font-style:oblique; font-size:" << font_size
+ << "\">"
+ << "level_subdomain_id"
+ << "</text>" << '\n';
+ }
}
// show azimuth angle and polar angle as text below the explanation of the cell labeling
case 3:
out << "subdomain_id";
break;
- // case 4: out << "level_subdomain_id";
- // break;
+ case 4: out << "level_subdomain_id";
+ break;
default:
break;
}
case GridOutFlags::Svg::subdomain_id:
while (!subdomains[labeling_index]) labeling_index++;
break;
- // case GridOutFlags::Svg::level_subdomain_id: while(!level_subdomains[labeling_index]) labeling_index++;
- // break;
+ case GridOutFlags::Svg::level_subdomain_id: while(!level_subdomains[labeling_index]) labeling_index++;
+ break;
default:
break;
}
void GridOut::write_mathgl (const Triangulation<1> &,
std::ostream &) const
{
+ // 1d specialization not done yet
Assert (false, ExcNotImplemented());
}
std::ostream &out) const
{
AssertThrow (out, ExcIO ());
- Assert (dim!=3, ExcNotImplemented ());
// (i) write header
if (true)
// define a helper to keep loops approximately dim-independent
// since MathGL labels axes as x, y, z
- Assert (dim<=3, ExcInternalError ());
const std::string axes = "xyz";
// (ii) write preamble and graphing tweaks
if (mathgl_flags.draw_bounding_box)
out << "\nbox";
- // Default, cf. MathGL / gnuplot.
- out << "\nsetsize 800 800";
-
+ // deal with dimension dependent preamble; eg. default sizes and
+ // views for MathGL (cf. gnuplot).
+ switch (dim)
+ {
+ case 2:
+ out << "\nsetsize 800 800";
+ out << "\nrotate 0 0";
+ break;
+ case 3:
+ out << "\nsetsize 800 800";
+ out << "\nrotate 60 40";
+ break;
+ default:
+ Assert (false, ExcNotImplemented ());
+ };
out << "\n";
// (iii) write vertex ordering
// todo: This denotes the natural ordering of vertices, but it needs
// to check this is really always true for a given grid (it's not
// true in step-1 grid-2 for instance).
- out << "\nlist f 0 1 2 3"
- << "\n";
+ switch (dim)
+ {
+ case 2:
+ out << "\nlist f 0 1 2 3"
+ << "\n";
+ break;
+ case 3:
+ out << "\nlist f 0 2 4 6 | 1 3 5 7 | 0 4 1 5 | 2 6 3 7 | 0 1 2 3 | 4 5 6 7"
+ << "\n";
+ break;
+ default:
+ Assert (false, ExcNotImplemented ());
+ };
// (iv) write a list of vertices of cells
out << "\n#"
}
-Point<2> GridOut::svg_project_point(Point<3> point, Point<3> camera_position, Point<3> camera_direction, Point<3> camera_horizontal, float camera_focus) const
+Point<2> GridOut::svg_project_point(Point<3> point, Point<3> camera_position, Point<3> camera_direction, Point<3> camera_horizontal, float camera_focus)
{
// ...
Point<3> camera_vertical;
// $Id$
// Version: $Name$
//
-// Copyright (C) 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2009, 2010, 2011, 2012 by the deal.II authors
+// Copyright (C) 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2009, 2010, 2011, 2012, 2013 by the deal.II authors
//
// This file is subject to QPL and may not be distributed
// without copyright and license information. Please refer
const SparsityPatternBase &b = block(ib,jb);
for (unsigned int j=0; j<b.n_cols(); ++j)
if (b.exists(i,j))
- out << l+j << " " << -static_cast<signed int>(i+k) << std::endl;;
+ out << l+j << " " << -static_cast<signed int>(i+k) << std::endl;
l += b.n_cols();
}
}
Assert (s.rows == 0, ExcInvalidConstructorCall());
Assert (s.cols == 0, ExcInvalidConstructorCall());
- // perform the checks in the underlying
- // object as well
+ // perform the checks in the underlying object as well
sparsity_pattern = s.sparsity_pattern;
return *this;
{
Assert (chunk_size > 0, ExcInvalidNumber (chunk_size));
- // simply map this function to the
- // other @p{reinit} function
+ // simply map this function to the other @p{reinit} function
const std::vector<unsigned int> row_lengths (m, max_per_row);
reinit (m, n, row_lengths, chunk_size);
}
this->chunk_size = chunk_size;
- // pass down to the necessary information
- // to the underlying object. we need to
- // calculate how many chunks we need: we
- // need to round up (m/chunk_size) and
- // (n/chunk_size). rounding up in integer
- // arithmetic equals
+ // pass down to the necessary information to the underlying object. we need
+ // to calculate how many chunks we need: we need to round up (m/chunk_size)
+ // and (n/chunk_size). rounding up in integer arithmetic equals
// ((m+chunk_size-1)/chunk_size):
const unsigned int m_chunks = (m+chunk_size-1) / chunk_size,
n_chunks = (n+chunk_size-1) / chunk_size;
- // compute the maximum number of chunks in
- // each row. the passed array denotes the
- // number of entries in each row of the big
- // matrix -- in the worst case, these are
- // all in independent chunks, so we have to
- // calculate it as follows (as an example:
- // let chunk_size==2,
- // row_lengths={2,2,...}, and entries in
- // row zero at columns {0,2} and for row
- // one at {4,6} --> we'll need 4 chunks for
- // the first chunk row!) :
+ // compute the maximum number of chunks in each row. the passed array
+ // denotes the number of entries in each row of the big matrix -- in the
+ // worst case, these are all in independent chunks, so we have to calculate
+ // it as follows (as an example: let chunk_size==2, row_lengths={2,2,...},
+ // and entries in row zero at columns {0,2} and for row one at {4,6} -->
+ // we'll need 4 chunks for the first chunk row!) :
std::vector<unsigned int> chunk_row_lengths (m_chunks, 0);
for (unsigned int i=0; i<m; ++i)
chunk_row_lengths[i/chunk_size] += row_lengths[i];
+ // for the case that the reduced sparsity pattern optimizes the diagonal but
+ // the actual sparsity pattern does not, need to take one more entry in the
+ // row to fit the user-required entry
+ if (m != n && m_chunks == n_chunks)
+ for (unsigned int i=0; i<m_chunks; ++i)
+ ++chunk_row_lengths[i];
+
sparsity_pattern.reinit (m_chunks,
n_chunks,
chunk_row_lengths);
{
Assert (chunk_size > 0, ExcInvalidNumber (chunk_size));
- // count number of entries per row, then
- // initialize the underlying sparsity
+ // count number of entries per row, then initialize the underlying sparsity
// pattern
std::vector<unsigned int> entries_per_row (csp.n_rows(), 0);
for (unsigned int row = 0; row<csp.n_rows(); ++row)
+namespace internal
+{
+ namespace
+ {
+ template <typename SP>
+ void copy_sparsity (const SP &src,
+ SparsityPattern &dst)
+ {
+ dst.copy_from(src);
+ }
+
+ void copy_sparsity (const SparsityPattern &src,
+ SparsityPattern &dst)
+ {
+ dst = src;
+ }
+ }
+}
+
+
+
+template <typename Sparsity>
+void
+ChunkSparsityPattern::create_from
+(const unsigned int m,
+ const unsigned int n,
+ const Sparsity &sparsity_pattern_for_chunks,
+ const unsigned int chunk_size_in,
+ const bool)
+{
+ Assert (m > (sparsity_pattern_for_chunks.n_rows()-1) * chunk_size_in &&
+ m <= sparsity_pattern_for_chunks.n_rows() * chunk_size_in,
+ ExcMessage("Number of rows m is not compatible with chunk size "
+ "and number of rows in sparsity pattern for the chunks."));
+ Assert (n > (sparsity_pattern_for_chunks.n_cols()-1) * chunk_size_in &&
+ n <= sparsity_pattern_for_chunks.n_cols() * chunk_size_in,
+ ExcMessage("Number of columns m is not compatible with chunk size "
+ "and number of columns in sparsity pattern for the chunks."));
+
+ internal::copy_sparsity(sparsity_pattern_for_chunks, sparsity_pattern);
+ chunk_size = chunk_size_in;
+ rows = m;
+ cols = n;
+}
+
+
+
bool
ChunkSparsityPattern::empty () const
{
-unsigned int
-ChunkSparsityPattern::row_length (const unsigned int i) const
+void
+ChunkSparsityPattern::symmetrize ()
{
- Assert (i<rows, ExcIndexRange(i,0,rows));
+ // matrix must be square. note that the for some matrix sizes, the current
+ // sparsity pattern may not be square even if the underlying sparsity
+ // pattern is (e.g. a 10x11 matrix with chunk_size 4)
+ Assert (rows==cols, ExcNotQuadratic());
- return sparsity_pattern.row_length (i/chunk_size) * chunk_size;
+ sparsity_pattern.symmetrize ();
}
-void
-ChunkSparsityPattern::symmetrize ()
+unsigned int
+ChunkSparsityPattern::row_length (const unsigned int i) const
{
- // matrix must be square. note that the for
- // some matrix sizes, the current sparsity
- // pattern may not be square even if the
- // underlying sparsity pattern is (e.g. a
- // 10x11 matrix with chunk_size 4)
- Assert (rows==cols, ExcNotQuadratic());
+ Assert (i<rows, ExcIndexRange(i,0,rows));
- sparsity_pattern.symmetrize ();
+ // find out if we did padding and if this row is affected by it
+ if (n_cols() % chunk_size == 0)
+ return sparsity_pattern.row_length (i/chunk_size) * chunk_size;
+ else
+ // if columns don't align, then just iterate over all chunks and see
+ // what this leads to
+ {
+ SparsityPattern::const_iterator p = sparsity_pattern.begin(i/chunk_size),
+ end = sparsity_pattern.end(i/chunk_size);
+ unsigned int n = 0;
+ for ( ; p != end; ++p)
+ if (p->column() != sparsity_pattern.n_cols() - 1)
+ n += chunk_size;
+ else
+ n += (n_cols() % chunk_size);
+ return n;
+ }
}
chunk_size *
chunk_size);
else
- // some of the chunks reach beyond the
- // extent of this matrix. this requires a
- // somewhat more complicated
- // computations, in particular if the
+ // some of the chunks reach beyond the extent of this matrix. this
+ // requires a somewhat more complicated computations, in particular if the
// columns don't align
{
if ((n_rows() % chunk_size != 0)
&&
(n_cols() % chunk_size == 0))
{
- // columns align with chunks, but
- // not rows
+ // columns align with chunks, but not rows
unsigned int n = sparsity_pattern.n_nonzero_elements() *
chunk_size *
chunk_size;
else
{
- // if columns don't align, then
- // just iterate over all chunks and
- // see what this leads to. follow the advice in the documentation of
- // the sparsity pattern iterators to do the loop over individual rows,
+ // if columns don't align, then just iterate over all chunks and see
+ // what this leads to. follow the advice in the documentation of the
+ // sparsity pattern iterators to do the loop over individual rows,
// rather than all elements
unsigned int n = 0;
else if ((row == sparsity_pattern.n_rows() - 1)
&&
(p->column() != sparsity_pattern.n_cols() - 1))
- // last chunk row, but not
- // last chunk column. only a
- // smaller number (n_rows %
- // chunk_size) of rows
- // actually exist
+ // last chunk row, but not last chunk column. only a smaller
+ // number (n_rows % chunk_size) of rows actually exist
n += (n_rows() % chunk_size) * chunk_size;
else if ((row != sparsity_pattern.n_rows() - 1)
&&
(p->column() == sparsity_pattern.n_cols() - 1))
- // last chunk column, but
- // not row
+ // last chunk column, but not row
n += (n_cols() % chunk_size) * chunk_size;
else
// bottom right chunk
AssertThrow (out, ExcIO());
- // for each entry in the underlying
- // sparsity pattern, repeat everything
+ // for each entry in the underlying sparsity pattern, repeat everything
// chunk_size x chunk_size times
for (unsigned int i=0; i<sparsity_pattern.rows; ++i)
for (unsigned int j=sparsity_pattern.rowstart[i];
for (unsigned int e=0;
(e<chunk_size) && (i*chunk_size + e < n_rows());
++e)
- // while matrix entries are
- // usually written (i,j), with i
- // vertical and j horizontal,
- // gnuplot output is x-y, that is
- // we have to exchange the order
- // of output
+ // while matrix entries are usually written (i,j), with i vertical
+ // and j horizontal, gnuplot output is x-y, that is we have to
+ // exchange the order of output
out << sparsity_pattern.colnums[j]*chunk_size+d << " "
<< -static_cast<signed int>(i*chunk_size+e)
<< std::endl;
unsigned int
ChunkSparsityPattern::bandwidth () const
{
- // calculate the bandwidth from that of the
- // underlying sparsity pattern. note that
- // even if the bandwidth of that is zero,
- // then the bandwidth of the chunky pattern
- // is chunk_size-1, if it is 1 then the
- // chunky pattern has
- // chunk_size+(chunk_size-1), etc
+ // calculate the bandwidth from that of the underlying sparsity
+ // pattern. note that even if the bandwidth of that is zero, then the
+ // bandwidth of the chunky pattern is chunk_size-1, if it is 1 then the
+ // chunky pattern has chunk_size+(chunk_size-1), etc
//
// we'll cut it off at max(n(),m())
return std::min (sparsity_pattern.bandwidth()*chunk_size
{
AssertThrow (out, ExcIO());
- // first the simple objects,
- // bracketed in [...]
+ // first the simple objects, bracketed in [...]
out << '['
<< rows << ' '
<< cols << ' '
in >> c;
AssertThrow (c == '[', ExcIO());
- // then read the underlying sparsity
- // pattern
+ // then read the underlying sparsity pattern
sparsity_pattern.block_read (in);
in >> c;
// explicit instantiations
template
+void ChunkSparsityPattern::copy_from<SparsityPattern> (const SparsityPattern &,
+ const unsigned int,
+ const bool);
+template
void ChunkSparsityPattern::copy_from<CompressedSparsityPattern> (const CompressedSparsityPattern &,
const unsigned int,
const bool);
const unsigned int,
const bool);
template
+void ChunkSparsityPattern::create_from<SparsityPattern>
+(const unsigned int,
+ const unsigned int,
+ const SparsityPattern &,
+ const unsigned int,
+ const bool);
+template
+void ChunkSparsityPattern::create_from<CompressedSparsityPattern>
+(const unsigned int,
+ const unsigned int,
+ const CompressedSparsityPattern &,
+ const unsigned int,
+ const bool);
+template
+void ChunkSparsityPattern::create_from<CompressedSetSparsityPattern>
+(const unsigned int,
+ const unsigned int,
+ const CompressedSetSparsityPattern &,
+ const unsigned int,
+ const bool);
+template
+void ChunkSparsityPattern::create_from<CompressedSimpleSparsityPattern>
+(const unsigned int,
+ const unsigned int,
+ const CompressedSimpleSparsityPattern &,
+ const unsigned int,
+ const bool);
+template
void ChunkSparsityPattern::copy_from<float> (const FullMatrix<float> &,
const unsigned int,
const bool);
//---------------------------------------------------------------------------
// $Id$
//
-// Copyright (C) 1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010, 2011, 2012 by the deal.II authors
+// Copyright (C) 1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010, 2011, 2012, 2013 by the deal.II authors
//
// This file is subject to QPL and may not be distributed
// without copyright and license information. Please refer
-#ifdef DEAL_II_WITH_TRILINOS
-
-// this is a specialization for a parallel (non-block) Trilinos vector. The
-// basic idea is to just work on the local range of the vector. But we need
-// access to values that the local nodes are constrained to.
-
-template<>
-void
-ConstraintMatrix::distribute (TrilinosWrappers::MPI::Vector &vec) const
-{
- Assert (sorted==true, ExcMatrixIsClosed());
-
- //TODO: not implemented yet, we need to fix LocalRange() first to only
- //include "owned" indices. For this we need to keep track of the owned
- //indices, because Trilinos doesn't. Use same constructor interface as in
- //PETSc with two IndexSets!
- AssertThrow (vec.vector_partitioner().IsOneToOne(),
- ExcMessage ("Distribute does not work on vectors with overlapping parallel partitioning."));
-
- typedef std::vector<ConstraintLine>::const_iterator constraint_iterator;
- ConstraintLine index_comparison;
- index_comparison.line = vec.local_range().first;
- const constraint_iterator begin_my_constraints =
- Utilities::lower_bound (lines.begin(),lines.end(),index_comparison);
-
- index_comparison.line = vec.local_range().second;
- const constraint_iterator end_my_constraints
- = Utilities::lower_bound(lines.begin(),lines.end(),index_comparison);
-
- // Here we search all the indices that we need to have read-access to -
- // the local nodes and all the nodes that the constraints indicate.
- IndexSet my_indices (vec.size());
- {
- const std::pair<unsigned int, unsigned int>
- local_range = vec.local_range();
-
- my_indices.add_range (local_range.first, local_range.second);
-
- std::set<unsigned int> individual_indices;
- for (constraint_iterator it = begin_my_constraints;
- it != end_my_constraints; ++it)
- for (unsigned int i=0; i<it->entries.size(); ++i)
- if ((it->entries[i].first < local_range.first)
- ||
- (it->entries[i].first >= local_range.second))
- individual_indices.insert (it->entries[i].first);
-
- my_indices.add_indices (individual_indices.begin(),
- individual_indices.end());
- }
-
-#ifdef DEAL_II_WITH_MPI
- const Epetra_MpiComm *mpi_comm
- = dynamic_cast<const Epetra_MpiComm *>(&vec.trilinos_vector().Comm());
-
- Assert (mpi_comm != 0, ExcInternalError());
-
- TrilinosWrappers::MPI::Vector vec_distribute
- (my_indices.make_trilinos_map (mpi_comm->Comm(), true));
-#else
- TrilinosWrappers::MPI::Vector vec_distribute
- (my_indices.make_trilinos_map (MPI_COMM_WORLD, true));
-#endif
-
- // here we import the data
- vec_distribute.reinit(vec,false,true);
-
- for (constraint_iterator it = begin_my_constraints;
- it != end_my_constraints; ++it)
- {
- // fill entry in line next_constraint.line by adding the different
- // contributions
- double new_value = it->inhomogeneity;
- for (unsigned int i=0; i<it->entries.size(); ++i)
- new_value += (vec_distribute(it->entries[i].first) *
- it->entries[i].second);
- vec(it->line) = new_value;
- }
-
- // some processes might not apply constraints, so we need to explicitly
- // state, that the others are doing an insert here:
- vec.compress (::dealii::VectorOperation::insert);
-}
-
-
-
-template<>
-void
-ConstraintMatrix::distribute (TrilinosWrappers::MPI::BlockVector &vec) const
-{
- Assert (sorted==true, ExcMatrixIsClosed());
-
- IndexSet my_indices (vec.size());
- for (unsigned int block=0; block<vec.n_blocks(); ++block)
- {
- typedef std::vector<ConstraintLine>::const_iterator constraint_iterator;
- ConstraintLine index_comparison;
- index_comparison.line = vec.block(block).local_range().first
- +vec.get_block_indices().block_start(block);
- const constraint_iterator begin_my_constraints =
- Utilities::lower_bound (lines.begin(),lines.end(),index_comparison);
-
- index_comparison.line = vec.block(block).local_range().second
- +vec.get_block_indices().block_start(block);
-
- const constraint_iterator end_my_constraints
- = Utilities::lower_bound(lines.begin(),lines.end(),index_comparison);
-
- // Here we search all the indices that we need to have read-access to
- // - the local nodes and all the nodes that the constraints indicate.
- // No caching done yet. would need some more clever data structures
- // for doing that.
- const std::pair<unsigned int, unsigned int>
- local_range = vec.block(block).local_range();
-
- my_indices.add_range (local_range.first, local_range.second);
-
- std::set<unsigned int> individual_indices;
- for (constraint_iterator it = begin_my_constraints;
- it != end_my_constraints; ++it)
- for (unsigned int i=0; i<it->entries.size(); ++i)
- if ((it->entries[i].first < local_range.first)
- ||
- (it->entries[i].first >= local_range.second))
- individual_indices.insert (it->entries[i].first);
-
- my_indices.add_indices (individual_indices.begin(),
- individual_indices.end());
- }
-
-#ifdef DEAL_II_WITH_MPI
- const Epetra_MpiComm *mpi_comm
- = dynamic_cast<const Epetra_MpiComm *>(&vec.block(0).trilinos_vector().Comm());
-
- Assert (mpi_comm != 0, ExcInternalError());
-
- TrilinosWrappers::MPI::Vector vec_distribute
- (my_indices.make_trilinos_map (mpi_comm->Comm(), true));
-#else
- TrilinosWrappers::MPI::Vector vec_distribute
- (my_indices.make_trilinos_map (MPI_COMM_WORLD, true));
-#endif
-
- // here we import the data
- vec_distribute.reinit(vec,true);
-
- for (unsigned int block=0; block<vec.n_blocks(); ++block)
- {
- typedef std::vector<ConstraintLine>::const_iterator constraint_iterator;
- ConstraintLine index_comparison;
- index_comparison.line = vec.block(block).local_range().first
- +vec.get_block_indices().block_start(block);
- const constraint_iterator begin_my_constraints =
- Utilities::lower_bound (lines.begin(),lines.end(),index_comparison);
-
- index_comparison.line = vec.block(block).local_range().second
- +vec.get_block_indices().block_start(block);
-
- const constraint_iterator end_my_constraints
- = Utilities::lower_bound(lines.begin(),lines.end(),index_comparison);
-
- for (constraint_iterator it = begin_my_constraints;
- it != end_my_constraints; ++it)
- {
- // fill entry in line next_constraint.line by adding the
- // different contributions
- double new_value = it->inhomogeneity;
- for (unsigned int i=0; i<it->entries.size(); ++i)
- new_value += (vec_distribute(it->entries[i].first) *
- it->entries[i].second);
- vec(it->line) = new_value;
- }
- vec.block(block).compress(::dealii::VectorOperation::insert);
- }
-}
-
-#endif
-
-#ifdef DEAL_II_WITH_PETSC
-
-// this is a specialization for a parallel (non-block) PETSc vector. The
-// basic idea is to just work on the local range of the vector. But we need
-// access to values that the local nodes are constrained to.
-
-template<>
-void
-ConstraintMatrix::distribute (PETScWrappers::MPI::Vector &vec) const
-{
- Assert (sorted==true, ExcMatrixIsClosed());
-
- typedef std::vector<ConstraintLine>::const_iterator constraint_iterator;
- ConstraintLine index_comparison;
- index_comparison.line = vec.local_range().first;
- const constraint_iterator begin_my_constraints =
- Utilities::lower_bound (lines.begin(),lines.end(),index_comparison);
-
- index_comparison.line = vec.local_range().second;
- const constraint_iterator end_my_constraints
- = Utilities::lower_bound(lines.begin(),lines.end(),index_comparison);
-
- // all indices we need to read from
- IndexSet my_indices (vec.size());
-
- const std::pair<unsigned int, unsigned int>
- local_range = vec.local_range();
-
- my_indices.add_range (local_range.first, local_range.second);
-
- std::set<unsigned int> individual_indices;
- for (constraint_iterator it = begin_my_constraints;
- it != end_my_constraints; ++it)
- for (unsigned int i=0; i<it->entries.size(); ++i)
- if ((it->entries[i].first < local_range.first)
- ||
- (it->entries[i].first >= local_range.second))
- individual_indices.insert (it->entries[i].first);
-
- my_indices.add_indices (individual_indices.begin(),
- individual_indices.end());
-
- IndexSet local_range_is (vec.size());
- local_range_is.add_range(local_range.first, local_range.second);
-
-
- // create a vector and import those indices
- PETScWrappers::MPI::Vector ghost_vec (vec.get_mpi_communicator(),
- local_range_is,
- my_indices);
- ghost_vec = vec;
- ghost_vec.update_ghost_values();
-
- // finally do the distribution on own constraints
- for (constraint_iterator it = begin_my_constraints;
- it != end_my_constraints; ++it)
- {
- // fill entry in line next_constraint.line by adding the different
- // contributions
- PetscScalar new_value = it->inhomogeneity;
- for (unsigned int i=0; i<it->entries.size(); ++i)
- new_value += (PetscScalar(ghost_vec(it->entries[i].first)) *
- it->entries[i].second);
- vec(it->line) = new_value;
- }
-
- vec.compress (VectorOperation::insert);
-}
-
-
-template<>
-void
-ConstraintMatrix::distribute (PETScWrappers::MPI::BlockVector &/*vec*/) const
-{
- Assert (sorted==true, ExcMatrixIsClosed());
- AssertThrow (false, ExcNotImplemented());
-}
-
-#endif
-
-
-
bool ConstraintMatrix::is_identity_constrained (const unsigned int index) const
{
if (is_constrained(index) == false)
VectorType &, \
const FullMatrix<double> &) const; \
template void ConstraintMatrix::distribute<VectorType >(const VectorType &condensed,\
- VectorType &uncondensed) const;\
- template void ConstraintMatrix::distribute<VectorType >(VectorType &vec) const
+ VectorType &uncondensed) const
#define PARALLEL_VECTOR_FUNCTIONS(VectorType) \
template void ConstraintMatrix:: \
const FullMatrix<double> &) const
-// TODO: Can PETSc really do all the operations required by the above
-// condense/distribute function etc also on distributed vectors? Trilinos
-// can't do that - we have to rewrite those functions by hand if we want to
-// use them. The key is to use local ranges etc., which still needs to be
-// implemented.
#ifdef DEAL_II_WITH_PETSC
VECTOR_FUNCTIONS(PETScWrappers::MPI::Vector);
VECTOR_FUNCTIONS(PETScWrappers::MPI::BlockVector);
template void ConstraintMatrix::distribute_local_to_global<T<S> > (
const Vector<double>&, const std::vector<unsigned int> &, T<S> &, const FullMatrix<double>&) const;
template void ConstraintMatrix::distribute<T<S> >(const T<S> &, T<S> &) const;
- template void ConstraintMatrix::distribute<T<S> >(T<S> &) const;
template void ConstraintMatrix::set_zero<T<S> >(T<S> &) const;
}
template void ConstraintMatrix::distribute_local_to_global<parallel::distributed::T<S> > (
const Vector<double>&, const std::vector<unsigned int> &, parallel::distributed::T<S> &, const FullMatrix<double>&) const;
template void ConstraintMatrix::distribute<parallel::distributed::T<S> >(const parallel::distributed::T<S> &, parallel::distributed::T<S> &) const;
- template void ConstraintMatrix::distribute<parallel::distributed::T<S> >(parallel::distributed::T<S> &) const;
template void ConstraintMatrix::set_zero<parallel::distributed::T<S> >(parallel::distributed::T<S> &) const;
}
template void ConstraintMatrix::distribute_local_to_global<V > (
const Vector<double>&, const std::vector<unsigned int> &, V&, const FullMatrix<double>&) const;
template void ConstraintMatrix::distribute<V >(const V&, V&) const;
- template void ConstraintMatrix::distribute<V >(V&) const;
template void ConstraintMatrix::set_zero<V >(V&) const;
}
template void ConstraintMatrix::condense<S1,BlockVector<S2> >(
const SparseMatrix<S1>&, const BlockVector<S2>&, SparseMatrix<S1> &, BlockVector<S2>&) const;
}
+
+
+for (Vec : SERIAL_VECTORS)
+ {
+ template void ConstraintMatrix::distribute<Vec>(Vec &) const;
+ }
}
void
- SolverBase::solve (const unsigned int n_eigenvectors,
+ SolverBase::solve (const unsigned int n_eigenpairs,
unsigned int *n_converged)
{
int ierr;
AssertThrow (ierr == 0, ExcSLEPcError(ierr));
// set number of eigenvectors to compute
- ierr = EPSSetDimensions (solver_data->eps, n_eigenvectors,
+ ierr = EPSSetDimensions (solver_data->eps, n_eigenpairs,
PETSC_DECIDE, PETSC_DECIDE);
AssertThrow (ierr == 0, ExcSLEPcError(ierr));
// get number of converged eigenstates
ierr = EPSGetConverged (solver_data->eps,
- reinterpret_cast<PetscInt *>(n_converged)
- );
+ reinterpret_cast<PetscInt *>(n_converged));
AssertThrow (ierr == 0, ExcSLEPcError(ierr));
int n_iterations = 0;
void
SolverBase::get_eigenpair (const unsigned int index,
-#ifndef PETSC_USE_COMPLEX
- double &kr,
-#else
- std::complex<double> &kr,
-#endif
- PETScWrappers::VectorBase &vr)
+ double &eigenvalues,
+ PETScWrappers::VectorBase &eigenvectors)
{
AssertThrow (solver_data.get() != 0, ExcSLEPcWrappersUsageError());
// get converged eigenpair
int ierr = EPSGetEigenpair (solver_data->eps, index,
- &kr, PETSC_NULL, vr, PETSC_NULL);
+ &eigenvalues, PETSC_NULL,
+ eigenvectors, PETSC_NULL);
+ AssertThrow (ierr == 0, ExcSLEPcError(ierr));
+ }
+
+ void
+ SolverBase::get_eigenpair (const unsigned int index,
+ double &real_eigenvalues,
+ double &imag_eigenvalues,
+ PETScWrappers::VectorBase &real_eigenvectors,
+ PETScWrappers::VectorBase &imag_eigenvectors)
+ {
+ AssertThrow (solver_data.get() != 0, ExcSLEPcWrappersUsageError());
+
+ // get converged eigenpair
+ int ierr = EPSGetEigenpair (solver_data->eps, index,
+ &real_eigenvalues, &imag_eigenvalues,
+ real_eigenvectors, imag_eigenvectors);
AssertThrow (ierr == 0, ExcSLEPcError(ierr));
}
int
SolverBase::convergence_test (EPS /*eps */,
- PetscScalar /*kr */,
- PetscScalar /*ki */,
+ PetscScalar /*real_eigenvalue */,
+ PetscScalar /*imag_eigenvalue */,
PetscReal /*residual_norm */,
PetscReal */*estimated_error */,
void */*solver_control_x*/)
static_cast<int>(additional_data.smoother_overlap));
parameter_list.set("aggregation: threshold",
additional_data.aggregation_threshold);
+ parameter_list.set("coarse: max size", 2000);
if (additional_data.output_details)
parameter_list.set("ML output", 10);
// release memory before reallocation
matrix.reset ();
- temp_vector.clear ();
matrix.reset (new Epetra_FECrsMatrix(*m.matrix));
}
const bool exchange_data)
{
// release memory before reallocation
- temp_vector.clear();
matrix.reset();
// if we want to exchange data, build a usual Trilinos sparsity pattern
void
SparseMatrix::reinit (const SparsityPattern &sparsity_pattern)
{
- temp_vector.clear ();
matrix.reset ();
// reinit with a (parallel) Trilinos
SparseMatrix::reinit (const SparseMatrix &sparse_matrix)
{
column_space_map.reset (new Epetra_Map (sparse_matrix.domain_partitioner()));
- temp_vector.clear ();
matrix.reset ();
matrix.reset (new Epetra_FECrsMatrix
(Copy, sparse_matrix.trilinos_sparsity_pattern(), false));
const Epetra_CrsGraph *graph = &input_matrix.Graph();
- temp_vector.clear ();
matrix.reset ();
matrix.reset (new Epetra_FECrsMatrix(Copy, *graph, false));
// empty matrix.
column_space_map.reset (new Epetra_Map (0, 0,
Utilities::Trilinos::comm_self()));
- temp_vector.clear();
matrix.reset (new Epetra_FECrsMatrix(View, *column_space_map, 0));
matrix->FillComplete();
typename DH::cell_iterator cell = dof.begin(level),
endc = dof.end(level);
for (; cell!=endc; ++cell)
- if (dof.get_tria().locally_owned_subdomain()==numbers::invalid_subdomain_id || cell->level_subdomain_id()==dof.get_tria().locally_owned_subdomain())
+ if (dof.get_tria().locally_owned_subdomain()==numbers::invalid_subdomain_id
+ || cell->level_subdomain_id()==dof.get_tria().locally_owned_subdomain())
{
cell->get_mg_dof_indices (dofs_on_this_cell);
// make sparsity pattern for this cell
endc = dof.end();
for (; cell!=endc; ++cell)
{
+ if (dof.get_tria().locally_owned_subdomain()!=numbers::invalid_subdomain_id
+ && cell->level_subdomain_id()!=dof.get_tria().locally_owned_subdomain())
+ continue;
const FiniteElement<dim> &fe = cell->get_fe();
const unsigned int level = cell->level();
local_dofs.resize(fe.dofs_per_face);
cell = dof.begin(),
endc = dof.end();
for (; cell!=endc; ++cell)
+ if (dof.get_tria().locally_owned_subdomain()==numbers::invalid_subdomain_id
+ || cell->level_subdomain_id()==dof.get_tria().locally_owned_subdomain())
for (unsigned int face_no = 0; face_no < GeometryInfo<dim>::faces_per_cell;
++face_no)
{
for (; cell!=endc; ++cell)
{
+ if (mg_dof_handler.get_tria().locally_owned_subdomain()!=numbers::invalid_subdomain_id
+ && cell->level_subdomain_id()!=mg_dof_handler.get_tria().locally_owned_subdomain())
+ continue;
+
std::fill (cell_dofs.begin(), cell_dofs.end(), false);
for (unsigned int face_nr=0; face_nr<GeometryInfo<dim>::faces_per_cell; ++face_nr)
for (; cell!=endc; ++cell)
{
+ if (mg_dof_handler.get_tria().locally_owned_subdomain()!=numbers::invalid_subdomain_id
+ && cell->level_subdomain_id()!=mg_dof_handler.get_tria().locally_owned_subdomain())
+ continue;
+
std::fill (cell_dofs.begin(), cell_dofs.end(), false);
std::fill (cell_dofs_interface.begin(), cell_dofs_interface.end(), false);
for (; cell!=endc; ++cell)
{
+ if (mg_dof_handler.get_tria().locally_owned_subdomain()!=numbers::invalid_subdomain_id
+ && cell->level_subdomain_id()!=mg_dof_handler.get_tria().locally_owned_subdomain())
+ continue;
+
bool has_coarser_neighbor = false;
std::fill (cell_dofs.begin(), cell_dofs.end(), false);
std::vector<unsigned int> entries (dofs_per_cell);
for (typename DoFHandler<dim,spacedim>::cell_iterator cell=mg_dof.begin(level);
cell != mg_dof.end(level); ++cell)
- if (cell->has_children())
+ if (cell->has_children() &&
+ ( mg_dof.get_tria().locally_owned_subdomain()==numbers::invalid_subdomain_id
+ || cell->level_subdomain_id()==mg_dof.get_tria().locally_owned_subdomain()
+ ))
{
cell->get_mg_dof_indices (dof_indices_parent);
}
}
}
-
- prolongation_sparsities[level]->copy_from (csp);
+
+ internal::MatrixSelector<VECTOR>::reinit(*prolongation_matrices[level],
+ *prolongation_sparsities[level],
+ level,
+ csp,
+ mg_dof);
csp.reinit(0,0);
- prolongation_matrices[level]->reinit (*prolongation_sparsities[level]);
// now actually build the matrices
for (typename DoFHandler<dim,spacedim>::cell_iterator cell=mg_dof.begin(level);
cell != mg_dof.end(level); ++cell)
- if (cell->has_children())
+ if (cell->has_children() &&
+ (mg_dof.get_tria().locally_owned_subdomain()==numbers::invalid_subdomain_id
+ || cell->level_subdomain_id()==mg_dof.get_tria().locally_owned_subdomain())
+ )
{
cell->get_mg_dof_indices (dof_indices_parent);
// by restricting from fine level.
for (; level_cell!=level_end; ++level_cell)
{
+ if (mg_dof.get_tria().locally_owned_subdomain()!=numbers::invalid_subdomain_id
+ && level_cell->level_subdomain_id()!=mg_dof.get_tria().locally_owned_subdomain())
+ continue;
+
// get the dof numbers of
// this cell for the global
// and the level-wise
}
+template <class VECTOR>
+void
+MGTransferPrebuilt<VECTOR>::print_matrices (std::ostream& os) const
+{
+ for (unsigned int level = 0;level<prolongation_matrices.size();++level)
+ {
+ os << "Level " << level << std::endl;
+ prolongation_matrices[level]->print(os);
+ os << std::endl;
+ }
+}
// explicit instantiation
std::vector<unsigned int> dof_indices;
FullMatrix<double> cell_matrix;
dealii::Vector<double> cell_rhs;
+ const ConstraintMatrix *constraints;
};
}
(data.cell_rhs.size() == dofs_per_cell),
ExcInternalError());
- matrix->add(data.dof_indices, data.cell_matrix);
if (right_hand_side != 0)
- for (unsigned int i=0; i<dofs_per_cell; ++i)
- (*right_hand_side)(data.dof_indices[i]) += data.cell_rhs(i);
+ data.constraints->distribute_local_to_global(data.cell_matrix,
+ data.cell_rhs,
+ data.dof_indices,
+ *matrix, *right_hand_side);
+ else
+ data.constraints->distribute_local_to_global(data.cell_matrix,
+ data.dof_indices,
+ *matrix);
}
}
}
const DoFHandler<dim,spacedim> &dof,
const Quadrature<dim> &q,
SparseMatrix<number> &matrix,
- const Function<spacedim> *const coefficient)
+ const Function<spacedim> *const coefficient,
+ const ConstraintMatrix &constraints)
{
Assert (matrix.m() == dof.n_dofs(),
ExcDimensionMismatch (matrix.m(), dof.n_dofs()));
assembler_data.fe_collection.max_dofs_per_cell());
copy_data.cell_rhs.reinit (assembler_data.fe_collection.max_dofs_per_cell());
copy_data.dof_indices.resize (assembler_data.fe_collection.max_dofs_per_cell());
+ copy_data.constraints = &constraints;
WorkStream::run (dof.begin_active(),
static_cast<typename DoFHandler<dim,spacedim>::active_cell_iterator>(dof.end()),
void create_mass_matrix (const DoFHandler<dim,spacedim> &dof,
const Quadrature<dim> &q,
SparseMatrix<number> &matrix,
- const Function<spacedim> *const coefficient)
+ const Function<spacedim> *const coefficient,
+ const ConstraintMatrix &constraints)
{
create_mass_matrix(StaticMappingQ1<dim,spacedim>::mapping, dof,
- q, matrix, coefficient);
+ q, matrix, coefficient, constraints);
}
SparseMatrix<number> &matrix,
const Function<spacedim> &rhs,
Vector<double> &rhs_vector,
- const Function<spacedim> *const coefficient)
+ const Function<spacedim> *const coefficient,
+ const ConstraintMatrix &constraints)
{
Assert (matrix.m() == dof.n_dofs(),
ExcDimensionMismatch (matrix.m(), dof.n_dofs()));
assembler_data.fe_collection.max_dofs_per_cell());
copy_data.cell_rhs.reinit (assembler_data.fe_collection.max_dofs_per_cell());
copy_data.dof_indices.resize (assembler_data.fe_collection.max_dofs_per_cell());
+ copy_data.constraints = &constraints;
WorkStream::run (dof.begin_active(),
static_cast<typename DoFHandler<dim,spacedim>::active_cell_iterator>(dof.end()),
SparseMatrix<number> &matrix,
const Function<spacedim> &rhs,
Vector<double> &rhs_vector,
- const Function<spacedim> *const coefficient)
+ const Function<spacedim> *const coefficient,
+ const ConstraintMatrix &constraints)
{
create_mass_matrix(StaticMappingQ1<dim,spacedim>::mapping,
- dof, q, matrix, rhs, rhs_vector, coefficient);
+ dof, q, matrix, rhs, rhs_vector, coefficient,
+ constraints);
}
const hp::DoFHandler<dim,spacedim> &dof,
const hp::QCollection<dim> &q,
SparseMatrix<number> &matrix,
- const Function<spacedim> *const coefficient)
+ const Function<spacedim> *const coefficient,
+ const ConstraintMatrix &constraints)
{
Assert (matrix.m() == dof.n_dofs(),
ExcDimensionMismatch (matrix.m(), dof.n_dofs()));
assembler_data.fe_collection.max_dofs_per_cell());
copy_data.cell_rhs.reinit (assembler_data.fe_collection.max_dofs_per_cell());
copy_data.dof_indices.resize (assembler_data.fe_collection.max_dofs_per_cell());
+ copy_data.constraints = &constraints;
WorkStream::run (dof.begin_active(),
static_cast<typename hp::DoFHandler<dim,spacedim>::active_cell_iterator>(dof.end()),
template <int dim, typename number, int spacedim>
- void create_mass_matrix (const hp::DoFHandler<dim,spacedim> &dof,
- const hp::QCollection<dim> &q,
+ void create_mass_matrix (const hp::DoFHandler<dim,spacedim> &dof,
+ const hp::QCollection<dim> &q,
SparseMatrix<number> &matrix,
- const Function<spacedim> *const coefficient)
+ const Function<spacedim> *const coefficient,
+ const ConstraintMatrix &constraints)
{
- create_mass_matrix(hp::StaticMappingQ1<dim,spacedim>::mapping_collection, dof, q, matrix, coefficient);
+ create_mass_matrix(hp::StaticMappingQ1<dim,spacedim>::mapping_collection,
+ dof, q, matrix, coefficient, constraints);
}
template <int dim, typename number, int spacedim>
- void create_mass_matrix (const hp::MappingCollection<dim,spacedim> &mapping,
- const hp::DoFHandler<dim,spacedim> &dof,
+ void create_mass_matrix (const hp::MappingCollection<dim,spacedim> &mapping,
+ const hp::DoFHandler<dim,spacedim> &dof,
const hp::QCollection<dim> &q,
SparseMatrix<number> &matrix,
const Function<spacedim> &rhs,
Vector<double> &rhs_vector,
- const Function<spacedim> *const coefficient)
+ const Function<spacedim> *const coefficient,
+ const ConstraintMatrix &constraints)
{
Assert (matrix.m() == dof.n_dofs(),
ExcDimensionMismatch (matrix.m(), dof.n_dofs()));
assembler_data.fe_collection.max_dofs_per_cell());
copy_data.cell_rhs.reinit (assembler_data.fe_collection.max_dofs_per_cell());
copy_data.dof_indices.resize (assembler_data.fe_collection.max_dofs_per_cell());
+ copy_data.constraints = &constraints;
WorkStream::run (dof.begin_active(),
static_cast<typename hp::DoFHandler<dim,spacedim>::active_cell_iterator>(dof.end()),
template <int dim, typename number, int spacedim>
- void create_mass_matrix (const hp::DoFHandler<dim,spacedim> &dof,
- const hp::QCollection<dim> &q,
+ void create_mass_matrix (const hp::DoFHandler<dim,spacedim> &dof,
+ const hp::QCollection<dim> &q,
SparseMatrix<number> &matrix,
- const Function<spacedim> &rhs,
+ const Function<spacedim> &rhs,
Vector<double> &rhs_vector,
- const Function<spacedim> *const coefficient)
+ const Function<spacedim> *const coefficient,
+ const ConstraintMatrix &constraints)
{
create_mass_matrix(hp::StaticMappingQ1<dim,spacedim>::mapping_collection, dof, q,
- matrix, rhs, rhs_vector, coefficient);
+ matrix, rhs, rhs_vector, coefficient, constraints);
}
const DoFHandler<dim,spacedim> &dof,
const Quadrature<dim> &q,
SparseMatrix<double> &matrix,
- const Function<spacedim> *const coefficient)
+ const Function<spacedim> *const coefficient,
+ const ConstraintMatrix &constraints)
{
Assert (matrix.m() == dof.n_dofs(),
ExcDimensionMismatch (matrix.m(), dof.n_dofs()));
assembler_data.fe_collection.max_dofs_per_cell());
copy_data.cell_rhs.reinit (assembler_data.fe_collection.max_dofs_per_cell());
copy_data.dof_indices.resize (assembler_data.fe_collection.max_dofs_per_cell());
+ copy_data.constraints = &constraints;
void (*copy_local_to_global) (const MatrixCreator::internal::AssemblerData::CopyData &,
SparseMatrix<double> *,
void create_laplace_matrix (const DoFHandler<dim,spacedim> &dof,
const Quadrature<dim> &q,
SparseMatrix<double> &matrix,
- const Function<spacedim> *const coefficient)
+ const Function<spacedim> *const coefficient,
+ const ConstraintMatrix &constraints)
{
create_laplace_matrix(StaticMappingQ1<dim,spacedim>::mapping, dof, q, matrix, coefficient);
}
SparseMatrix<double> &matrix,
const Function<spacedim> &rhs,
Vector<double> &rhs_vector,
- const Function<spacedim> *const coefficient)
+ const Function<spacedim> *const coefficient,
+ const ConstraintMatrix &constraints)
{
Assert (matrix.m() == dof.n_dofs(),
ExcDimensionMismatch (matrix.m(), dof.n_dofs()));
assembler_data.fe_collection.max_dofs_per_cell());
copy_data.cell_rhs.reinit (assembler_data.fe_collection.max_dofs_per_cell());
copy_data.dof_indices.resize (assembler_data.fe_collection.max_dofs_per_cell());
+ copy_data.constraints = &constraints;
void (*copy_local_to_global) (const MatrixCreator::internal::AssemblerData::CopyData &,
SparseMatrix<double> *,
SparseMatrix<double> &matrix,
const Function<spacedim> &rhs,
Vector<double> &rhs_vector,
- const Function<spacedim> *const coefficient)
+ const Function<spacedim> *const coefficient,
+ const ConstraintMatrix &constraints)
{
create_laplace_matrix(StaticMappingQ1<dim,spacedim>::mapping, dof, q,
matrix, rhs, rhs_vector, coefficient);
const hp::DoFHandler<dim,spacedim> &dof,
const hp::QCollection<dim> &q,
SparseMatrix<double> &matrix,
- const Function<spacedim> *const coefficient)
+ const Function<spacedim> *const coefficient,
+ const ConstraintMatrix &constraints)
{
Assert (matrix.m() == dof.n_dofs(),
ExcDimensionMismatch (matrix.m(), dof.n_dofs()));
assembler_data.fe_collection.max_dofs_per_cell());
copy_data.cell_rhs.reinit (assembler_data.fe_collection.max_dofs_per_cell());
copy_data.dof_indices.resize (assembler_data.fe_collection.max_dofs_per_cell());
+ copy_data.constraints = &constraints;
void (*copy_local_to_global) (const MatrixCreator::internal::AssemblerData::CopyData &,
SparseMatrix<double> *,
void create_laplace_matrix (const hp::DoFHandler<dim,spacedim> &dof,
const hp::QCollection<dim> &q,
SparseMatrix<double> &matrix,
- const Function<spacedim> *const coefficient)
+ const Function<spacedim> *const coefficient,
+ const ConstraintMatrix &constraints)
{
create_laplace_matrix(hp::StaticMappingQ1<dim,spacedim>::mapping_collection, dof, q, matrix, coefficient);
}
SparseMatrix<double> &matrix,
const Function<spacedim> &rhs,
Vector<double> &rhs_vector,
- const Function<spacedim> *const coefficient)
+ const Function<spacedim> *const coefficient,
+ const ConstraintMatrix &constraints)
{
Assert (matrix.m() == dof.n_dofs(),
ExcDimensionMismatch (matrix.m(), dof.n_dofs()));
assembler_data.fe_collection.max_dofs_per_cell());
copy_data.cell_rhs.reinit (assembler_data.fe_collection.max_dofs_per_cell());
copy_data.dof_indices.resize (assembler_data.fe_collection.max_dofs_per_cell());
+ copy_data.constraints = &constraints;
void (*copy_local_to_global) (const MatrixCreator::internal::AssemblerData::CopyData &,
SparseMatrix<double> *,
SparseMatrix<double> &matrix,
const Function<spacedim> &rhs,
Vector<double> &rhs_vector,
- const Function<spacedim> *const coefficient)
+ const Function<spacedim> *const coefficient,
+ const ConstraintMatrix &constraints)
{
create_laplace_matrix(hp::StaticMappingQ1<dim,spacedim>::mapping_collection, dof, q,
matrix, rhs, rhs_vector, coefficient);
const DoFHandler<deal_II_dimension,deal_II_space_dimension> &dof,
const Quadrature<deal_II_dimension> &q,
SparseMatrix<double> &matrix,
- const Function<deal_II_space_dimension> * const coefficient);
+ const Function<deal_II_space_dimension> * const coefficient,
+ const ConstraintMatrix &constraints);
template
void MatrixCreator::create_mass_matrix<deal_II_dimension,double,deal_II_space_dimension>
(const DoFHandler<deal_II_dimension,deal_II_space_dimension> &dof,
const Quadrature<deal_II_dimension> &q,
SparseMatrix<double> &matrix,
- const Function<deal_II_space_dimension> * const coefficient);
+ const Function<deal_II_space_dimension> * const coefficient,
+ const ConstraintMatrix &constraints);
template
void MatrixCreator::create_mass_matrix<deal_II_dimension,double,deal_II_space_dimension>
(const Mapping<deal_II_dimension,deal_II_space_dimension> &mapping,
SparseMatrix<double> &matrix,
const Function<deal_II_space_dimension> &rhs,
Vector<double> &rhs_vector,
- const Function<deal_II_space_dimension> * const coefficient);
+ const Function<deal_II_space_dimension> * const coefficient,
+ const ConstraintMatrix &constraints);
template
void MatrixCreator::create_mass_matrix<deal_II_dimension,double,deal_II_space_dimension>
(const DoFHandler<deal_II_dimension,deal_II_space_dimension> &dof,
SparseMatrix<double> &matrix,
const Function<deal_II_space_dimension> &rhs,
Vector<double> &rhs_vector,
- const Function<deal_II_space_dimension> * const coefficient);
+ const Function<deal_II_space_dimension> * const coefficient,
+ const ConstraintMatrix &constraints);
template
const DoFHandler<deal_II_dimension,deal_II_space_dimension> &dof,
const Quadrature<deal_II_dimension> &q,
SparseMatrix<float> &matrix,
- const Function<deal_II_space_dimension> * const coefficient);
+ const Function<deal_II_space_dimension> * const coefficient,
+ const ConstraintMatrix &constraints);
template
void MatrixCreator::create_mass_matrix<deal_II_dimension,float,deal_II_space_dimension>
(const DoFHandler<deal_II_dimension,deal_II_space_dimension> &dof,
const Quadrature<deal_II_dimension> &q,
SparseMatrix<float> &matrix,
- const Function<deal_II_space_dimension> * const coefficient);
+ const Function<deal_II_space_dimension> * const coefficient,
+ const ConstraintMatrix &constraints);
template
void MatrixCreator::create_mass_matrix<deal_II_dimension,float,deal_II_space_dimension>
(const Mapping<deal_II_dimension,deal_II_space_dimension> &mapping,
SparseMatrix<float> &matrix,
const Function<deal_II_space_dimension> &rhs,
Vector<double> &rhs_vector,
- const Function<deal_II_space_dimension> * const coefficient);
+ const Function<deal_II_space_dimension> * const coefficient,
+ const ConstraintMatrix &constraints);
template
void MatrixCreator::create_mass_matrix<deal_II_dimension,float,deal_II_space_dimension>
(const DoFHandler<deal_II_dimension,deal_II_space_dimension> &dof,
SparseMatrix<float> &matrix,
const Function<deal_II_space_dimension> &rhs,
Vector<double> &rhs_vector,
- const Function<deal_II_space_dimension> * const coefficient);
+ const Function<deal_II_space_dimension> * const coefficient,
+ const ConstraintMatrix &constraints);
template
void MatrixCreator::create_boundary_mass_matrix<deal_II_dimension,deal_II_space_dimension>
const hp::DoFHandler<deal_II_dimension> &dof,
const hp::QCollection<deal_II_dimension> &q,
SparseMatrix<double> &matrix,
- const Function<deal_II_dimension> * const coefficient);
+ const Function<deal_II_dimension> * const coefficient,
+ const ConstraintMatrix &constraints);
template
void MatrixCreator::create_mass_matrix<deal_II_dimension>
(const hp::DoFHandler<deal_II_dimension> &dof,
const hp::QCollection<deal_II_dimension> &q,
SparseMatrix<double> &matrix,
- const Function<deal_II_dimension> * const coefficient);
+ const Function<deal_II_dimension> * const coefficient,
+ const ConstraintMatrix &constraints);
template
void MatrixCreator::create_mass_matrix<deal_II_dimension>
(const hp::MappingCollection<deal_II_dimension> &mapping,
SparseMatrix<double> &matrix,
const Function<deal_II_dimension> &rhs,
Vector<double> &rhs_vector,
- const Function<deal_II_dimension> * const coefficient);
+ const Function<deal_II_dimension> * const coefficient,
+ const ConstraintMatrix &constraints);
template
void MatrixCreator::create_mass_matrix<deal_II_dimension>
(const hp::DoFHandler<deal_II_dimension> &dof,
SparseMatrix<double> &matrix,
const Function<deal_II_dimension> &rhs,
Vector<double> &rhs_vector,
- const Function<deal_II_dimension> * const coefficient);
+ const Function<deal_II_dimension> * const coefficient,
+ const ConstraintMatrix &constraints);
template
const hp::DoFHandler<deal_II_dimension> &dof,
const hp::QCollection<deal_II_dimension> &q,
SparseMatrix<float> &matrix,
- const Function<deal_II_dimension> * const coefficient);
+ const Function<deal_II_dimension> * const coefficient,
+ const ConstraintMatrix &constraints);
template
void MatrixCreator::create_mass_matrix<deal_II_dimension>
(const hp::DoFHandler<deal_II_dimension> &dof,
const hp::QCollection<deal_II_dimension> &q,
SparseMatrix<float> &matrix,
- const Function<deal_II_dimension> * const coefficient);
+ const Function<deal_II_dimension> * const coefficient,
+ const ConstraintMatrix &constraints);
template
void MatrixCreator::create_mass_matrix<deal_II_dimension>
(const hp::MappingCollection<deal_II_dimension> &mapping,
SparseMatrix<float> &matrix,
const Function<deal_II_dimension> &rhs,
Vector<double> &rhs_vector,
- const Function<deal_II_dimension> * const coefficient);
+ const Function<deal_II_dimension> * const coefficient,
+ const ConstraintMatrix &constraints);
template
void MatrixCreator::create_mass_matrix<deal_II_dimension>
(const hp::DoFHandler<deal_II_dimension> &dof,
SparseMatrix<float> &matrix,
const Function<deal_II_dimension> &rhs,
Vector<double> &rhs_vector,
- const Function<deal_II_dimension> * const coefficient);
+ const Function<deal_II_dimension> * const coefficient,
+ const ConstraintMatrix &constraints);
#if deal_II_dimension != 1
(const DoFHandler<deal_II_dimension> &dof,
const Quadrature<deal_II_dimension> &q,
SparseMatrix<double> &matrix,
- const Function<deal_II_dimension> * const coefficient);
+ const Function<deal_II_dimension> * const coefficient,
+ const ConstraintMatrix &constraints);
template
void MatrixCreator::create_laplace_matrix<deal_II_dimension>
(const Mapping<deal_II_dimension> &mapping,
const DoFHandler<deal_II_dimension> &dof,
const Quadrature<deal_II_dimension> &q,
SparseMatrix<double> &matrix,
- const Function<deal_II_dimension> * const coefficient);
+ const Function<deal_II_dimension> * const coefficient,
+ const ConstraintMatrix &constraints);
template
void MatrixCreator::create_laplace_matrix<deal_II_dimension>
(const Mapping<deal_II_dimension> &mapping,
SparseMatrix<double> &matrix,
const Function<deal_II_dimension> &rhs,
Vector<double> &rhs_vector,
- const Function<deal_II_dimension> * const coefficient);
+ const Function<deal_II_dimension> * const coefficient,
+ const ConstraintMatrix &constraints);
template
void MatrixCreator::create_laplace_matrix<deal_II_dimension>
(const DoFHandler<deal_II_dimension> &dof,
SparseMatrix<double> &matrix,
const Function<deal_II_dimension> &rhs,
Vector<double> &rhs_vector,
- const Function<deal_II_dimension> * const coefficient);
+ const Function<deal_II_dimension> * const coefficient,
+ const ConstraintMatrix &constraints);
// hp versions of create_laplace_matrix
template
(const hp::DoFHandler<deal_II_dimension> &dof,
const hp::QCollection<deal_II_dimension> &q,
SparseMatrix<double> &matrix,
- const Function<deal_II_dimension> * const coefficient);
+ const Function<deal_II_dimension> * const coefficient,
+ const ConstraintMatrix &constraints);
template
void MatrixCreator::create_laplace_matrix<deal_II_dimension>
(const hp::MappingCollection<deal_II_dimension> &mapping,
const hp::DoFHandler<deal_II_dimension> &dof,
const hp::QCollection<deal_II_dimension> &q,
SparseMatrix<double> &matrix,
- const Function<deal_II_dimension> * const coefficient);
+ const Function<deal_II_dimension> * const coefficient,
+ const ConstraintMatrix &constraints);
template
void MatrixCreator::create_laplace_matrix<deal_II_dimension>
(const hp::MappingCollection<deal_II_dimension> &mapping,
SparseMatrix<double> &matrix,
const Function<deal_II_dimension> &rhs,
Vector<double> &rhs_vector,
- const Function<deal_II_dimension> * const coefficient);
+ const Function<deal_II_dimension> * const coefficient,
+ const ConstraintMatrix &constraints);
template
void MatrixCreator::create_laplace_matrix<deal_II_dimension>
(const hp::DoFHandler<deal_II_dimension> &dof,
SparseMatrix<double> &matrix,
const Function<deal_II_dimension> &rhs,
Vector<double> &rhs_vector,
- const Function<deal_II_dimension> * const coefficient);
+ const Function<deal_II_dimension> * const coefficient,
+ const ConstraintMatrix &constraints);