pax_global_header00006660000000000000000000000064143512500230014505gustar00rootroot0000000000000052 comment=3228c649c012f3c6c9a76543671d22b169b07be5 dune-grid-glue-2.9.0/000077500000000000000000000000001435125002300143255ustar00rootroot00000000000000dune-grid-glue-2.9.0/.gitignore000066400000000000000000000003251435125002300163150ustar00rootroot00000000000000# SPDX-FileCopyrightInfo: Copyright © DUNE Project contributors, see file LICENSE.md in module root # SPDX-License-Identifier: LGPL-3.0-or-later OR LicenseRef-GPL-2.0-only-with-dune-grid-glue-exception build-*/ dune-grid-glue-2.9.0/.gitlab-ci.yml000066400000000000000000000020441435125002300167610ustar00rootroot00000000000000# SPDX-FileCopyrightInfo: Copyright © DUNE Project contributors, see file LICENSE.md in module root # SPDX-License-Identifier: LGPL-3.0-or-later OR LicenseRef-GPL-2.0-only-with-dune-grid-glue-exception --- .common: &common script: duneci-standard-test artifacts: expire_in: 2 years reports: junit: junit/*.xml tags: [duneci] dune:2.9 gcc-8 C++17: <<: *common image: registry.dune-project.org/docker/ci/dune:2.9-debian-10-gcc-8-17 dune:2.9 gcc-10 C++20: <<: *common image: registry.dune-project.org/docker/ci/dune:2.9-debian-11-gcc-10-20 dune:2.9 clang-11 C++20: <<: *common image: registry.dune-project.org/docker/ci/dune:2.9-debian-11-clang-11-20 dune:2.8 gcc-9 C++20: <<: *common image: registry.dune-project.org/docker/ci/dune:2.8-debian-11-gcc-9-20 dune:2.7 gcc-8 C++17: <<: *common image: registry.dune-project.org/docker/ci/dune:2.7-debian-10-gcc-8-17 reuse: stage: .pre image: name: docker.io/fsfe/reuse:latest entrypoint: [""] tags: [duneci] before_script: "" script: - reuse lint dune-grid-glue-2.9.0/CHANGELOG.md000066400000000000000000000055521435125002300161450ustar00rootroot00000000000000 Changes in dune-grid-glue v2.9.0 ================================ * The dune-grid-glue source code contains SPDX licensing information now. Changes in dune-grid-glue v2.8.0 ================================ No major changes in dune-grid-glue v2.8.0 Changes in dune-grid-glue v2.7.0 ================================ Major changes in dune-grid-glue v2.7.0 -------------------------------------- * Constants and type aliases including the "side" in their names like `Grid0View` have been deprecated in favor of template constexpr functions or template aliases. Old code like ```c++ using Glue = Dune::GridGlue::GridGlue<...>; ... Glue::grid0dim ... ... Glue::Grid1View ... ``` should be replaced by ```c++ using Glue = Dune::GridGlue::GridGlue<...>; ... Glue::griddim<0>() ... ... Glue::GridView<1> ... ``` Changes in dune-grid-glue v2.5.0 ================================ Incompatible changes in dune-grid-glue v2.5.0 --------------------------------------------- * The autotools-based build system has been removed. * Non-default projection directions in ContactMerge are now set and stored via std::function instead of Dune::VirtualFunction. Changes in dune-grid-glue v2.4.0 ================================ Incompatible changes in dune-grid-glue v2.4.0 --------------------------------------------- * All interfaces have been moved into the `Dune::GridGlue` namespace. * The `contains()` method of the `Codim0Extractor` and `Codim1Extractor` classes now take a codim-0-`Entity` instead of a codim-0-`EntityPointer`. New code can also use a `std::function` instead of the extractor classes. * Methods that returned an `EntityPointer` now return an `Entity` instead when `dune-grid-glue` is built against version 2.4 or later of the DUNE core modules. Major changes in dune-grid-glue v2.4.0 -------------------------------------- * This is the first release that supports version 2.4 of the DUNE core modules. The older 2.3 release is also still supported. * `dune-grid-glue` now requires C++11 support. * Both `ContactMerge` and `OverlappingMerge` had large changes and were partially rewritten. The newer version should both be faster and hopefully have less bugs as well. * Support for the range-based for statement has been added. It is possible to iterate over all intersections of a `GridGlue` object by code like ``` GridGlue<...> glue; for (const auto& in : intersections(glue)) ...; ``` See the documentation for further details. * `PSurfaceMerge` has been replaced by a wrapper around `ContactMerge` and `OverlappingMerge`. It is now also deprecated and will be removed in the next release. dune-grid-glue-2.9.0/CMakeLists.txt000066400000000000000000000017701435125002300170720ustar00rootroot00000000000000# SPDX-FileCopyrightInfo: Copyright © DUNE Project contributors, see file LICENSE.md in module root # SPDX-License-Identifier: LGPL-3.0-or-later OR LicenseRef-GPL-2.0-only-with-dune-grid-glue-exception cmake_minimum_required(VERSION 2.8.6) project(dune-grid-glue CXX) if(NOT (dune-common_DIR OR dune-common_ROOT OR "${CMAKE_PREFIX_PATH}" MATCHES ".*dune-common.*")) string(REPLACE ${CMAKE_PROJECT_NAME} dune-common dune-common_DIR ${PROJECT_BINARY_DIR}) endif() #find dune-common and set the module path find_package(dune-common REQUIRED) list(APPEND CMAKE_MODULE_PATH ${dune-common_MODULE_PATH} "${PROJECT_SOURCE_DIR}/cmake/modules") #include the dune macros include(DuneMacros) # start a dune project with information from dune.module dune_project() dune_register_package_flags(LIBRARIES dunegridglue) add_subdirectory("dune") add_subdirectory("doc") add_subdirectory("examples") # finalize the dune project, e.g. generating config.h etc. finalize_dune_project(GENERATE_CONFIG_H_CMAKE) dune-grid-glue-2.9.0/COPYING000066400000000000000000000036741435125002300153720ustar00rootroot00000000000000Copyright holders: 2014--2020 Ansgar Burchardt 2009 Gerrit Buse 2009--2020 Christian Engwer 2014 Christoph Grüninger 2014--2016 Katja Hanowski 2017 Timo Koch 2020 Tobias Leibner 2013 Steffen Müthing 2016 Elias Pipping 2009--2020 Oliver Sander 2014--2017 Jonathan Youett The dune-grid-glue library, headers and test programs are copyrighted free software. You can use, modify and/or redistribute it under the terms of either one of the two following licenses: * The GNU Lesser General Public License as published by the Free Software Foundation, either Version 3 of the license or (at your option) any later version. You can find a copy of the GNU Lesser General Public License, Version 3, at . * Version 2 of the GNU General Public License as published by the Free Software Foundation, with the following special exception for linking and compiling against the dune-grid-glue library, the so-called "runtime exception": As a special exception, you may use the dune-grid-glue source files as part of a software library or application without restriction. Specifically, if other files instantiate templates or use macros or inline functions from one or more of the dune-grid-glue source files, or you compile one or more of the dune-grid-glue source files and link them with other files to produce an executable, this does not by itself cause the resulting executable to be covered by the GNU General Public License. This exception does not however invalidate any other reasons why the executable file might be covered by the GNU General Public License. This license is intended to be similar to the GNU Lesser General Public License, Version 2, which by itself isn't suitable for a template library. You can find a copy of the GNU General Public License, Version 2, at . dune-grid-glue-2.9.0/LICENSES/000077500000000000000000000000001435125002300155325ustar00rootroot00000000000000dune-grid-glue-2.9.0/LICENSES/LGPL-3.0-or-later.txt000066400000000000000000001221621435125002300210560ustar00rootroot00000000000000GNU LESSER GENERAL PUBLIC LICENSE Version 3, 29 June 2007 Copyright (C) 2007 Free Software Foundation, Inc. Everyone is permitted to copy and distribute verbatim copies of this license document, but changing it is not allowed. This version of the GNU Lesser General Public License incorporates the terms and conditions of version 3 of the GNU General Public License, supplemented by the additional permissions listed below. 0. Additional Definitions. As used herein, "this License" refers to version 3 of the GNU Lesser General Public License, and the "GNU GPL" refers to version 3 of the GNU General Public License. "The Library" refers to a covered work governed by this License, other than an Application or a Combined Work as defined below. An "Application" is any work that makes use of an interface provided by the Library, but which is not otherwise based on the Library. Defining a subclass of a class defined by the Library is deemed a mode of using an interface provided by the Library. A "Combined Work" is a work produced by combining or linking an Application with the Library. The particular version of the Library with which the Combined Work was made is also called the "Linked Version". The "Minimal Corresponding Source" for a Combined Work means the Corresponding Source for the Combined Work, excluding any source code for portions of the Combined Work that, considered in isolation, are based on the Application, and not on the Linked Version. The "Corresponding Application Code" for a Combined Work means the object code and/or source code for the Application, including any data and utility programs needed for reproducing the Combined Work from the Application, but excluding the System Libraries of the Combined Work. 1. Exception to Section 3 of the GNU GPL. You may convey a covered work under sections 3 and 4 of this License without being bound by section 3 of the GNU GPL. 2. Conveying Modified Versions. If you modify a copy of the Library, and, in your modifications, a facility refers to a function or data to be supplied by an Application that uses the facility (other than as an argument passed when the facility is invoked), then you may convey a copy of the modified version: a) under this License, provided that you make a good faith effort to ensure that, in the event an Application does not supply the function or data, the facility still operates, and performs whatever part of its purpose remains meaningful, or b) under the GNU GPL, with none of the additional permissions of this License applicable to that copy. 3. Object Code Incorporating Material from Library Header Files. The object code form of an Application may incorporate material from a header file that is part of the Library. You may convey such object code under terms of your choice, provided that, if the incorporated material is not limited to numerical parameters, data structure layouts and accessors, or small macros, inline functions and templates (ten or fewer lines in length), you do both of the following: a) Give prominent notice with each copy of the object code that the Library is used in it and that the Library and its use are covered by this License. b) Accompany the object code with a copy of the GNU GPL and this license document. 4. Combined Works. You may convey a Combined Work under terms of your choice that, taken together, effectively do not restrict modification of the portions of the Library contained in the Combined Work and reverse engineering for debugging such modifications, if you also do each of the following: a) Give prominent notice with each copy of the Combined Work that the Library is used in it and that the Library and its use are covered by this License. b) Accompany the Combined Work with a copy of the GNU GPL and this license document. c) For a Combined Work that displays copyright notices during execution, include the copyright notice for the Library among these notices, as well as a reference directing the user to the copies of the GNU GPL and this license document. d) Do one of the following: 0) Convey the Minimal Corresponding Source under the terms of this License, and the Corresponding Application Code in a form suitable for, and under terms that permit, the user to recombine or relink the Application with a modified version of the Linked Version to produce a modified Combined Work, in the manner specified by section 6 of the GNU GPL for conveying Corresponding Source. 1) Use a suitable shared library mechanism for linking with the Library. A suitable mechanism is one that (a) uses at run time a copy of the Library already present on the user's computer system, and (b) will operate properly with a modified version of the Library that is interface-compatible with the Linked Version. e) Provide Installation Information, but only if you would otherwise be required to provide such information under section 6 of the GNU GPL, and only to the extent that such information is necessary to install and execute a modified version of the Combined Work produced by recombining or relinking the Application with a modified version of the Linked Version. (If you use option 4d0, the Installation Information must accompany the Minimal Corresponding Source and Corresponding Application Code. If you use option 4d1, you must provide the Installation Information in the manner specified by section 6 of the GNU GPL for conveying Corresponding Source.) 5. Combined Libraries. 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 that are not Applications and are not covered by this License, and convey such a combined library under terms of your choice, if you do both of the following: a) Accompany the combined library with a copy of the same work based on the Library, uncombined with any other library facilities, conveyed under the terms of this License. b) Give prominent notice with the combined library that part of it is a work based on the Library, and explaining where to find the accompanying uncombined form of the same work. 6. Revised Versions of the GNU Lesser General Public License. The Free Software Foundation may publish revised and/or new versions of the GNU 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 as you received it specifies that a certain numbered version of the GNU Lesser General Public License "or any later version" applies to it, you have the option of following the terms and conditions either of that published version or of any later version published by the Free Software Foundation. If the Library as you received it does not specify a version number of the GNU Lesser General Public License, you may choose any version of the GNU Lesser General Public License ever published by the Free Software Foundation. If the Library as you received it specifies that a proxy can decide whether future versions of the GNU Lesser General Public License shall apply, that proxy's public statement of acceptance of any version is permanent authorization for you to choose that version for the Library. GNU GENERAL PUBLIC LICENSE Version 3, 29 June 2007 Copyright © 2007 Free Software Foundation, Inc. Everyone is permitted to copy and distribute verbatim copies of this license document, but changing it is not allowed. Preamble The GNU General Public License is a free, copyleft license for software and other kinds of works. The licenses for most software and other practical works are designed to take away your freedom to share and change the works. By contrast, the GNU General Public License is intended to guarantee your freedom to share and change all versions of a program--to make sure it remains free software for all its users. We, the Free Software Foundation, use the GNU General Public License for most of our software; it applies also to any other work released this way by its authors. You can apply it to your programs, too. When we speak of free software, we are referring to freedom, 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 them if you wish), that you receive source code or can get it if you want it, that you can change the software or use pieces of it in new free programs, and that you know you can do these things. To protect your rights, we need to prevent others from denying you these rights or asking you to surrender the rights. Therefore, you have certain responsibilities if you distribute copies of the software, or if you modify it: responsibilities to respect the freedom of others. For example, if you distribute copies of such a program, whether gratis or for a fee, you must pass on to the recipients the same freedoms that you received. You must make sure that they, too, receive or can get the source code. And you must show them these terms so they know their rights. Developers that use the GNU GPL protect your rights with two steps: (1) assert copyright on the software, and (2) offer you this License giving you legal permission to copy, distribute and/or modify it. For the developers' and authors' protection, the GPL clearly explains that there is no warranty for this free software. For both users' and authors' sake, the GPL requires that modified versions be marked as changed, so that their problems will not be attributed erroneously to authors of previous versions. Some devices are designed to deny users access to install or run modified versions of the software inside them, although the manufacturer can do so. This is fundamentally incompatible with the aim of protecting users' freedom to change the software. The systematic pattern of such abuse occurs in the area of products for individuals to use, which is precisely where it is most unacceptable. Therefore, we have designed this version of the GPL to prohibit the practice for those products. If such problems arise substantially in other domains, we stand ready to extend this provision to those domains in future versions of the GPL, as needed to protect the freedom of users. Finally, every program is threatened constantly by software patents. States should not allow patents to restrict development and use of software on general-purpose computers, but in those that do, we wish to avoid the special danger that patents applied to a free program could make it effectively proprietary. To prevent this, the GPL assures that patents cannot be used to render the program non-free. The precise terms and conditions for copying, distribution and modification follow. TERMS AND CONDITIONS 0. Definitions. “This License” refers to version 3 of the GNU General Public License. “Copyright” also means copyright-like laws that apply to other kinds of works, such as semiconductor masks. “The Program” refers to any copyrightable work licensed under this License. Each licensee is addressed as “you”. “Licensees” and “recipients” may be individuals or organizations. To “modify” a work means to copy from or adapt all or part of the work in a fashion requiring copyright permission, other than the making of an exact copy. The resulting work is called a “modified version” of the earlier work or a work “based on” the earlier work. A “covered work” means either the unmodified Program or a work based on the Program. To “propagate” a work means to do anything with it that, without permission, would make you directly or secondarily liable for infringement under applicable copyright law, except executing it on a computer or modifying a private copy. Propagation includes copying, distribution (with or without modification), making available to the public, and in some countries other activities as well. To “convey” a work means any kind of propagation that enables other parties to make or receive copies. Mere interaction with a user through a computer network, with no transfer of a copy, is not conveying. An interactive user interface displays “Appropriate Legal Notices” to the extent that it includes a convenient and prominently visible feature that (1) displays an appropriate copyright notice, and (2) tells the user that there is no warranty for the work (except to the extent that warranties are provided), that licensees may convey the work under this License, and how to view a copy of this License. If the interface presents a list of user commands or options, such as a menu, a prominent item in the list meets this criterion. 1. Source Code. The “source code” for a work means the preferred form of the work for making modifications to it. “Object code” means any non-source form of a work. A “Standard Interface” means an interface that either is an official standard defined by a recognized standards body, or, in the case of interfaces specified for a particular programming language, one that is widely used among developers working in that language. The “System Libraries” of an executable work include anything, other than the work as a whole, that (a) is included in the normal form of packaging a Major Component, but which is not part of that Major Component, and (b) serves only to enable use of the work with that Major Component, or to implement a Standard Interface for which an implementation is available to the public in source code form. A “Major Component”, in this context, means a major essential component (kernel, window system, and so on) of the specific operating system (if any) on which the executable work runs, or a compiler used to produce the work, or an object code interpreter used to run it. The “Corresponding Source” for a work in object code form means all the source code needed to generate, install, and (for an executable work) run the object code and to modify the work, including scripts to control those activities. However, it does not include the work's System Libraries, or general-purpose tools or generally available free programs which are used unmodified in performing those activities but which are not part of the work. For example, Corresponding Source includes interface definition files associated with source files for the work, and the source code for shared libraries and dynamically linked subprograms that the work is specifically designed to require, such as by intimate data communication or control flow between those subprograms and other parts of the work. The Corresponding Source need not include anything that users can regenerate automatically from other parts of the Corresponding Source. The Corresponding Source for a work in source code form is that same work. 2. Basic Permissions. All rights granted under this License are granted for the term of copyright on the Program, and are irrevocable provided the stated conditions are met. This License explicitly affirms your unlimited permission to run the unmodified Program. The output from running a covered work is covered by this License only if the output, given its content, constitutes a covered work. This License acknowledges your rights of fair use or other equivalent, as provided by copyright law. You may make, run and propagate covered works that you do not convey, without conditions so long as your license otherwise remains in force. You may convey covered works to others for the sole purpose of having them make modifications exclusively for you, or provide you with facilities for running those works, provided that you comply with the terms of this License in conveying all material for which you do not control copyright. Those thus making or running the covered works for you must do so exclusively on your behalf, under your direction and control, on terms that prohibit them from making any copies of your copyrighted material outside their relationship with you. Conveying under any other circumstances is permitted solely under the conditions stated below. Sublicensing is not allowed; section 10 makes it unnecessary. 3. Protecting Users' Legal Rights From Anti-Circumvention Law. No covered work shall be deemed part of an effective technological measure under any applicable law fulfilling obligations under article 11 of the WIPO copyright treaty adopted on 20 December 1996, or similar laws prohibiting or restricting circumvention of such measures. When you convey a covered work, you waive any legal power to forbid circumvention of technological measures to the extent such circumvention is effected by exercising rights under this License with respect to the covered work, and you disclaim any intention to limit operation or modification of the work as a means of enforcing, against the work's users, your or third parties' legal rights to forbid circumvention of technological measures. 4. Conveying Verbatim Copies. You may convey verbatim copies of the Program's source code as you receive it, in any medium, provided that you conspicuously and appropriately publish on each copy an appropriate copyright notice; keep intact all notices stating that this License and any non-permissive terms added in accord with section 7 apply to the code; keep intact all notices of the absence of any warranty; and give all recipients a copy of this License along with the Program. You may charge any price or no price for each copy that you convey, and you may offer support or warranty protection for a fee. 5. Conveying Modified Source Versions. You may convey a work based on the Program, or the modifications to produce it from the Program, in the form of source code under the terms of section 4, provided that you also meet all of these conditions: a) The work must carry prominent notices stating that you modified it, and giving a relevant date. b) The work must carry prominent notices stating that it is released under this License and any conditions added under section 7. This requirement modifies the requirement in section 4 to “keep intact all notices”. c) You must license the entire work, as a whole, under this License to anyone who comes into possession of a copy. This License will therefore apply, along with any applicable section 7 additional terms, to the whole of the work, and all its parts, regardless of how they are packaged. This License gives no permission to license the work in any other way, but it does not invalidate such permission if you have separately received it. d) If the work has interactive user interfaces, each must display Appropriate Legal Notices; however, if the Program has interactive interfaces that do not display Appropriate Legal Notices, your work need not make them do so. A compilation of a covered work with other separate and independent works, which are not by their nature extensions of the covered work, and which are not combined with it such as to form a larger program, in or on a volume of a storage or distribution medium, is called an “aggregate” if the compilation and its resulting copyright are not used to limit the access or legal rights of the compilation's users beyond what the individual works permit. Inclusion of a covered work in an aggregate does not cause this License to apply to the other parts of the aggregate. 6. Conveying Non-Source Forms. You may convey a covered work in object code form under the terms of sections 4 and 5, provided that you also convey the machine-readable Corresponding Source under the terms of this License, in one of these ways: a) Convey the object code in, or embodied in, a physical product (including a physical distribution medium), accompanied by the Corresponding Source fixed on a durable physical medium customarily used for software interchange. b) Convey the object code in, or embodied in, a physical product (including a physical distribution medium), accompanied by a written offer, valid for at least three years and valid for as long as you offer spare parts or customer support for that product model, to give anyone who possesses the object code either (1) a copy of the Corresponding Source for all the software in the product that is covered by this License, on a durable physical medium customarily used for software interchange, for a price no more than your reasonable cost of physically performing this conveying of source, or (2) access to copy the Corresponding Source from a network server at no charge. c) Convey individual copies of the object code with a copy of the written offer to provide the Corresponding Source. This alternative is allowed only occasionally and noncommercially, and only if you received the object code with such an offer, in accord with subsection 6b. d) Convey the object code by offering access from a designated place (gratis or for a charge), and offer equivalent access to the Corresponding Source in the same way through the same place at no further charge. You need not require recipients to copy the Corresponding Source along with the object code. If the place to copy the object code is a network server, the Corresponding Source may be on a different server (operated by you or a third party) that supports equivalent copying facilities, provided you maintain clear directions next to the object code saying where to find the Corresponding Source. Regardless of what server hosts the Corresponding Source, you remain obligated to ensure that it is available for as long as needed to satisfy these requirements. e) Convey the object code using peer-to-peer transmission, provided you inform other peers where the object code and Corresponding Source of the work are being offered to the general public at no charge under subsection 6d. A separable portion of the object code, whose source code is excluded from the Corresponding Source as a System Library, need not be included in conveying the object code work. A “User Product” is either (1) a “consumer product”, which means any tangible personal property which is normally used for personal, family, or household purposes, or (2) anything designed or sold for incorporation into a dwelling. In determining whether a product is a consumer product, doubtful cases shall be resolved in favor of coverage. For a particular product received by a particular user, “normally used” refers to a typical or common use of that class of product, regardless of the status of the particular user or of the way in which the particular user actually uses, or expects or is expected to use, the product. A product is a consumer product regardless of whether the product has substantial commercial, industrial or non-consumer uses, unless such uses represent the only significant mode of use of the product. “Installation Information” for a User Product means any methods, procedures, authorization keys, or other information required to install and execute modified versions of a covered work in that User Product from a modified version of its Corresponding Source. The information must suffice to ensure that the continued functioning of the modified object code is in no case prevented or interfered with solely because modification has been made. If you convey an object code work under this section in, or with, or specifically for use in, a User Product, and the conveying occurs as part of a transaction in which the right of possession and use of the User Product is transferred to the recipient in perpetuity or for a fixed term (regardless of how the transaction is characterized), the Corresponding Source conveyed under this section must be accompanied by the Installation Information. But this requirement does not apply if neither you nor any third party retains the ability to install modified object code on the User Product (for example, the work has been installed in ROM). The requirement to provide Installation Information does not include a requirement to continue to provide support service, warranty, or updates for a work that has been modified or installed by the recipient, or for the User Product in which it has been modified or installed. Access to a network may be denied when the modification itself materially and adversely affects the operation of the network or violates the rules and protocols for communication across the network. Corresponding Source conveyed, and Installation Information provided, in accord with this section must be in a format that is publicly documented (and with an implementation available to the public in source code form), and must require no special password or key for unpacking, reading or copying. 7. Additional Terms. “Additional permissions” are terms that supplement the terms of this License by making exceptions from one or more of its conditions. Additional permissions that are applicable to the entire Program shall be treated as though they were included in this License, to the extent that they are valid under applicable law. If additional permissions apply only to part of the Program, that part may be used separately under those permissions, but the entire Program remains governed by this License without regard to the additional permissions. When you convey a copy of a covered work, you may at your option remove any additional permissions from that copy, or from any part of it. (Additional permissions may be written to require their own removal in certain cases when you modify the work.) You may place additional permissions on material, added by you to a covered work, for which you have or can give appropriate copyright permission. Notwithstanding any other provision of this License, for material you add to a covered work, you may (if authorized by the copyright holders of that material) supplement the terms of this License with terms: a) Disclaiming warranty or limiting liability differently from the terms of sections 15 and 16 of this License; or b) Requiring preservation of specified reasonable legal notices or author attributions in that material or in the Appropriate Legal Notices displayed by works containing it; or c) Prohibiting misrepresentation of the origin of that material, or requiring that modified versions of such material be marked in reasonable ways as different from the original version; or d) Limiting the use for publicity purposes of names of licensors or authors of the material; or e) Declining to grant rights under trademark law for use of some trade names, trademarks, or service marks; or f) Requiring indemnification of licensors and authors of that material by anyone who conveys the material (or modified versions of it) with contractual assumptions of liability to the recipient, for any liability that these contractual assumptions directly impose on those licensors and authors. All other non-permissive additional terms are considered “further restrictions” within the meaning of section 10. If the Program as you received it, or any part of it, contains a notice stating that it is governed by this License along with a term that is a further restriction, you may remove that term. If a license document contains a further restriction but permits relicensing or conveying under this License, you may add to a covered work material governed by the terms of that license document, provided that the further restriction does not survive such relicensing or conveying. If you add terms to a covered work in accord with this section, you must place, in the relevant source files, a statement of the additional terms that apply to those files, or a notice indicating where to find the applicable terms. Additional terms, permissive or non-permissive, may be stated in the form of a separately written license, or stated as exceptions; the above requirements apply either way. 8. Termination. You may not propagate or modify a covered work except as expressly provided under this License. Any attempt otherwise to propagate or modify it is void, and will automatically terminate your rights under this License (including any patent licenses granted under the third paragraph of section 11). However, if you cease all violation of this License, then your license from a particular copyright holder is reinstated (a) provisionally, unless and until the copyright holder explicitly and finally terminates your license, and (b) permanently, if the copyright holder fails to notify you of the violation by some reasonable means prior to 60 days after the cessation. Moreover, your license from a particular copyright holder is reinstated permanently if the copyright holder notifies you of the violation by some reasonable means, this is the first time you have received notice of violation of this License (for any work) from that copyright holder, and you cure the violation prior to 30 days after your receipt of the notice. Termination of your rights under this section does not terminate the licenses of parties who have received copies or rights from you under this License. If your rights have been terminated and not permanently reinstated, you do not qualify to receive new licenses for the same material under section 10. 9. Acceptance Not Required for Having Copies. You are not required to accept this License in order to receive or run a copy of the Program. Ancillary propagation of a covered work occurring solely as a consequence of using peer-to-peer transmission to receive a copy likewise does not require acceptance. However, nothing other than this License grants you permission to propagate or modify any covered work. These actions infringe copyright if you do not accept this License. Therefore, by modifying or propagating a covered work, you indicate your acceptance of this License to do so. 10. Automatic Licensing of Downstream Recipients. Each time you convey a covered work, the recipient automatically receives a license from the original licensors, to run, modify and propagate that work, subject to this License. You are not responsible for enforcing compliance by third parties with this License. An “entity transaction” is a transaction transferring control of an organization, or substantially all assets of one, or subdividing an organization, or merging organizations. If propagation of a covered work results from an entity transaction, each party to that transaction who receives a copy of the work also receives whatever licenses to the work the party's predecessor in interest had or could give under the previous paragraph, plus a right to possession of the Corresponding Source of the work from the predecessor in interest, if the predecessor has it or can get it with reasonable efforts. You may not impose any further restrictions on the exercise of the rights granted or affirmed under this License. For example, you may not impose a license fee, royalty, or other charge for exercise of rights granted under this License, and you may not initiate litigation (including a cross-claim or counterclaim in a lawsuit) alleging that any patent claim is infringed by making, using, selling, offering for sale, or importing the Program or any portion of it. 11. Patents. A “contributor” is a copyright holder who authorizes use under this License of the Program or a work on which the Program is based. The work thus licensed is called the contributor's “contributor version”. A contributor's “essential patent claims” are all patent claims owned or controlled by the contributor, whether already acquired or hereafter acquired, that would be infringed by some manner, permitted by this License, of making, using, or selling its contributor version, but do not include claims that would be infringed only as a consequence of further modification of the contributor version. For purposes of this definition, “control” includes the right to grant patent sublicenses in a manner consistent with the requirements of this License. Each contributor grants you a non-exclusive, worldwide, royalty-free patent license under the contributor's essential patent claims, to make, use, sell, offer for sale, import and otherwise run, modify and propagate the contents of its contributor version. In the following three paragraphs, a “patent license” is any express agreement or commitment, however denominated, not to enforce a patent (such as an express permission to practice a patent or covenant not to sue for patent infringement). To “grant” such a patent license to a party means to make such an agreement or commitment not to enforce a patent against the party. If you convey a covered work, knowingly relying on a patent license, and the Corresponding Source of the work is not available for anyone to copy, free of charge and under the terms of this License, through a publicly available network server or other readily accessible means, then you must either (1) cause the Corresponding Source to be so available, or (2) arrange to deprive yourself of the benefit of the patent license for this particular work, or (3) arrange, in a manner consistent with the requirements of this License, to extend the patent license to downstream recipients. “Knowingly relying” means you have actual knowledge that, but for the patent license, your conveying the covered work in a country, or your recipient's use of the covered work in a country, would infringe one or more identifiable patents in that country that you have reason to believe are valid. If, pursuant to or in connection with a single transaction or arrangement, you convey, or propagate by procuring conveyance of, a covered work, and grant a patent license to some of the parties receiving the covered work authorizing them to use, propagate, modify or convey a specific copy of the covered work, then the patent license you grant is automatically extended to all recipients of the covered work and works based on it. A patent license is “discriminatory” if it does not include within the scope of its coverage, prohibits the exercise of, or is conditioned on the non-exercise of one or more of the rights that are specifically granted under this License. You may not convey a covered work if you are a party to an arrangement with a third party that is in the business of distributing software, under which you make payment to the third party based on the extent of your activity of conveying the work, and under which the third party grants, to any of the parties who would receive the covered work from you, a discriminatory patent license (a) in connection with copies of the covered work conveyed by you (or copies made from those copies), or (b) primarily for and in connection with specific products or compilations that contain the covered work, unless you entered into that arrangement, or that patent license was granted, prior to 28 March 2007. Nothing in this License shall be construed as excluding or limiting any implied license or other defenses to infringement that may otherwise be available to you under applicable patent law. 12. No Surrender of Others' Freedom. If 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 convey a covered work so as to satisfy simultaneously your obligations under this License and any other pertinent obligations, then as a consequence you may not convey it at all. For example, if you agree to terms that obligate you to collect a royalty for further conveying from those to whom you convey the Program, the only way you could satisfy both those terms and this License would be to refrain entirely from conveying the Program. 13. Use with the GNU Affero General Public License. Notwithstanding any other provision of this License, you have permission to link or combine any covered work with a work licensed under version 3 of the GNU Affero General Public License into a single combined work, and to convey the resulting work. The terms of this License will continue to apply to the part which is the covered work, but the special requirements of the GNU Affero General Public License, section 13, concerning interaction through a network will apply to the combination as such. 14. Revised Versions of this License. The Free Software Foundation may publish revised and/or new versions of the GNU 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 Program specifies that a certain numbered version of the GNU General Public License “or any later version” applies to it, you have the option of following the terms and conditions either of that numbered version or of any later version published by the Free Software Foundation. If the Program does not specify a version number of the GNU General Public License, you may choose any version ever published by the Free Software Foundation. If the Program specifies that a proxy can decide which future versions of the GNU General Public License can be used, that proxy's public statement of acceptance of a version permanently authorizes you to choose that version for the Program. Later license versions may give you additional or different permissions. However, no additional obligations are imposed on any author or copyright holder as a result of your choosing to follow a later version. 15. Disclaimer of Warranty. THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM “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 PROGRAM IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION. 16. Limitation of Liability. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS THE PROGRAM 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 PROGRAM (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 PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. 17. Interpretation of Sections 15 and 16. If the disclaimer of warranty and limitation of liability provided above cannot be given local legal effect according to their terms, reviewing courts shall apply local law that most closely approximates an absolute waiver of all civil liability in connection with the Program, unless a warranty or assumption of liability accompanies a copy of the Program in return for a fee. END OF TERMS AND CONDITIONS How to Apply These Terms to Your New Programs If you develop a new program, and you want it to be of the greatest possible use to the public, the best way to achieve this is to make it free software which everyone can redistribute and change under these terms. To do so, attach the following notices to the program. It is safest to attach them to the start of each source file to most effectively state the exclusion of warranty; and each file should have at least the “copyright” line and a pointer to where the full notice is found. Copyright (C) This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . Also add information on how to contact you by electronic and paper mail. If the program does terminal interaction, make it output a short notice like this when it starts in an interactive mode: Copyright (C) This program comes with ABSOLUTELY NO WARRANTY; for details type `show w'. This is free software, and you are welcome to redistribute it under certain conditions; type `show c' for details. The hypothetical commands `show w' and `show c' should show the appropriate parts of the General Public License. Of course, your program's commands might be different; for a GUI interface, you would use an “about box”. You should also get your employer (if you work as a programmer) or school, if any, to sign a “copyright disclaimer” for the program, if necessary. For more information on this, and how to apply and follow the GNU GPL, see . The GNU General Public License does not permit incorporating your program into proprietary programs. If your program is a subroutine library, you may consider it more useful to permit linking proprietary applications with the library. If this is what you want to do, use the GNU Lesser General Public License instead of this License. But first, please read . dune-grid-glue-2.9.0/LICENSES/LicenseRef-GPL-2.0-only-with-dune-grid-glue-exception.txt000066400000000000000000000441101435125002300277610ustar00rootroot00000000000000* Version 2 of the GNU General Public License as published by the Free Software Foundation, with the following special exception for linking and compiling against the dune-grid-glue library, the so-called "runtime exception": As a special exception, you may use the dune-grid-glue source files as part of a software library or application without restriction. Specifically, if other files instantiate templates or use macros or inline functions from one or more of the dune-grid-glue source files, or you compile one or more of the dune-grid-glue source files and link them with other files to produce an executable, this does not by itself cause the resulting executable to be covered by the GNU General Public License. This exception does not however invalidate any other reasons why the executable file might be covered by the GNU General Public License. This license is intended to be similar to the GNU Lesser General Public License, Version 2, which by itself isn't suitable for a template library. You can find a copy of the GNU General Public License, Version 2, at . GNU GENERAL PUBLIC LICENSE Version 2, June 1991 Copyright (C) 1989, 1991 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. Preamble The licenses for most software are designed to take away your freedom to share and change it. By contrast, the GNU General Public License is intended to guarantee your freedom to share and change free software--to make sure the software is free for all its users. This General Public License applies to most of the Free Software Foundation's software and to any other program whose authors commit to using it. (Some other Free Software Foundation software is covered by the GNU Lesser General Public License instead.) You can apply it to your programs, too. When we speak of free software, we are referring to freedom, 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 or use pieces of it in new free programs; and that you know you can do these things. To protect your rights, we need to make restrictions that forbid anyone to deny you these rights or to ask you to surrender the rights. These restrictions translate to certain responsibilities for you if you distribute copies of the software, or if you modify it. For example, if you distribute copies of such a program, whether gratis or for a fee, you must give the recipients all the rights that you have. You must make sure that they, too, receive or can get the source code. And you must show them these terms so they know their rights. We protect your rights with two steps: (1) copyright the software, and (2) offer you this license which gives you legal permission to copy, distribute and/or modify the software. Also, for each author's protection and ours, we want to make certain that everyone understands that there is no warranty for this free software. If the software is modified by someone else and passed on, we want its recipients to know that what they have is not the original, so that any problems introduced by others will not reflect on the original authors' reputations. Finally, any free program is threatened constantly by software patents. We wish to avoid the danger that redistributors of a free program will individually obtain patent licenses, in effect making the program proprietary. To prevent this, we have made it clear that any patent must be licensed for everyone's free use or not licensed at all. The precise terms and conditions for copying, distribution and modification follow. TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION 0. This License applies to any program or other work which contains a notice placed by the copyright holder saying it may be distributed under the terms of this General Public License. The "Program", below, refers to any such program or work, and a "work based on the Program" means either the Program or any derivative work under copyright law: that is to say, a work containing the Program or a portion of it, either verbatim or with modifications and/or translated into another language. (Hereinafter, translation is included without limitation in the term "modification".) Each licensee is addressed as "you". Activities other than copying, distribution and modification are not covered by this License; they are outside its scope. The act of running the Program is not restricted, and the output from the Program is covered only if its contents constitute a work based on the Program (independent of having been made by running the Program). Whether that is true depends on what the Program does. 1. You may copy and distribute verbatim copies of the Program's 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 give any other recipients of the Program a copy of this License along with the Program. 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 Program or any portion of it, thus forming a work based on the Program, 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) You must cause the modified files to carry prominent notices stating that you changed the files and the date of any change. b) You must cause any work that you distribute or publish, that in whole or in part contains or is derived from the Program or any part thereof, to be licensed as a whole at no charge to all third parties under the terms of this License. c) If the modified program normally reads commands interactively when run, you must cause it, when started running for such interactive use in the most ordinary way, to print or display an announcement including an appropriate copyright notice and a notice that there is no warranty (or else, saying that you provide a warranty) and that users may redistribute the program under these conditions, and telling the user how to view a copy of this License. (Exception: if the Program itself is interactive but does not normally print such an announcement, your work based on the Program is not required to print an announcement.) These requirements apply to the modified work as a whole. If identifiable sections of that work are not derived from the Program, 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 Program, 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 Program. In addition, mere aggregation of another work not based on the Program with the Program (or with a work based on the Program) on a volume of a storage or distribution medium does not bring the other work under the scope of this License. 3. You may copy and distribute the Program (or a work based on it, under Section 2) in object code or executable form under the terms of Sections 1 and 2 above provided that you also do one of the following: a) 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; or, b) Accompany it with a written offer, valid for at least three years, to give any third party, for a charge no more than your cost of physically performing source distribution, a complete machine-readable copy of the corresponding source code, to be distributed under the terms of Sections 1 and 2 above on a medium customarily used for software interchange; or, c) Accompany it with the information you received as to the offer to distribute corresponding source code. (This alternative is allowed only for noncommercial distribution and only if you received the program in object code or executable form with such an offer, in accord with Subsection b above.) The source code for a work means the preferred form of the work for making modifications to it. For an executable work, 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 executable. However, as a special exception, the source code 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. If distribution of executable or 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 counts as distribution of the source code, even though third parties are not compelled to copy the source along with the object code. 4. You may not copy, modify, sublicense, or distribute the Program except as expressly provided under this License. Any attempt otherwise to copy, modify, sublicense or distribute the Program 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. 5. 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 Program or its derivative works. These actions are prohibited by law if you do not accept this License. Therefore, by modifying or distributing the Program (or any work based on the Program), you indicate your acceptance of this License to do so, and all its terms and conditions for copying, distributing or modifying the Program or works based on it. 6. Each time you redistribute the Program (or any work based on the Program), the recipient automatically receives a license from the original licensor to copy, distribute or modify the Program 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 to this License. 7. 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 Program at all. For example, if a patent license would not permit royalty-free redistribution of the Program 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 Program. 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. 8. If the distribution and/or use of the Program is restricted in certain countries either by patents or by copyrighted interfaces, the original copyright holder who places the Program 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. 9. The Free Software Foundation may publish revised and/or new versions of the 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 Program 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 Program does not specify a version number of this License, you may choose any version ever published by the Free Software Foundation. 10. If you wish to incorporate parts of the Program into other free programs whose distribution conditions are different, 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 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "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 PROGRAM IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION. 12. 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 PROGRAM 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 PROGRAM (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 PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), 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 Programs If you develop a new program, and you want it to be of the greatest possible use to the public, the best way to achieve this is to make it free software which everyone can redistribute and change under these terms. To do so, attach the following notices to the program. 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 program's name and an idea of what it does. Copyright (C) yyyy name of author This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. Also add information on how to contact you by electronic and paper mail. If the program is interactive, make it output a short notice like this when it starts in an interactive mode: Gnomovision version 69, Copyright (C) year name of author Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'. This is free software, and you are welcome to redistribute it under certain conditions; type `show c' for details. The hypothetical commands `show w' and `show c' should show the appropriate parts of the General Public License. Of course, the commands you use may be called something other than `show w' and `show c'; they could even be mouse-clicks or menu items--whatever suits your program. You should also get your employer (if you work as a programmer) or your school, if any, to sign a "copyright disclaimer" for the program, if necessary. Here is a sample; alter the names: Yoyodyne, Inc., hereby disclaims all copyright interest in the program `Gnomovision' (which makes passes at compilers) written by James Hacker. signature of Ty Coon, 1 April 1989 Ty Coon, President of Vice dune-grid-glue-2.9.0/README.md000066400000000000000000000040351435125002300156060ustar00rootroot00000000000000 The `dune-grid-glue` module =========================== The `dune-grid-glue` module provides infrastructure for the coupling of two unrelated Dune grids. The coupling may be overlapping or nonoverlapping, conforming or nonconforming. The two grids are not requested to be of the same type, and they may even be of different dimensions. Couplings are described as sets of remote intersections. Conceptually, these remote intersections are very close to what the regular intersections in the Dune grid interface are, with the difference that the inside and outside entities are taken from different grids. Installation ------------ `dune-grid-glue` requires the DUNE core modules, version 2.3 or later. Please see the [general instructions for building DUNE modules](https://www.dune-project.org/doc/installation-notes.html) for detailed instructions on how to build the module. Development ----------- The [development version of `dune-grid-glue`](https://gitlab.dune-project.org/extensions/dune-grid-glue) can be obtained from the DUNE project's Gitlab installation. At the same place an [issue tracker](https://gitlab.dune-project.org/extensions/dune-grid-glue/issues) can be found. Publications ------------ * [P. Bastian, G. Buse, O. Sander: Infrastructure for the Coupling of Dune Grids, In 'Proceedings of ENUMATH 2009', Springer, 2010, pp. 107-114](https://dx.doi.org/10.1007/978-3-642-11795-4_10) * [C. Engwer, S. Müthing: Concepts for flexible parallel multi-domain simulations, In 'Domain Decomposition Methods in Science and Engineering XXII', Springer](https://dx.doi.org/10.1007/978-3-319-18827-0_17) License ------- The `dune-grid-glue` module is licensed under the GNU Lesser General Public License, version 3 or later, or the GNU General Public License, version 2, with a special runtime exception. Please see the COPYING file for details. dune-grid-glue-2.9.0/TODO000066400000000000000000000023271435125002300150210ustar00rootroot00000000000000 - Test: does indexInInside for codim0-coupling always return 0? - GridGlueVTKWriter doesn't seem to work - GridGlueVTKWriter crashes when started on an empty GridGlue For the upcoming paper: ./ remove target/domain naming ./ remove extractortraits - rename Extractor to Patch ./ Extractor/Patch should get the predicate ./ remove remoteintersection(iterator)impl CRTP magic (./) implement _new_ parallel merging (see article.tex) ./ move gridglue/adapter/gridglue.hh to gridglue/gridglue.hh - add directed version communicate(data,iftype,dir) ... or similar ./ implement IndexSet Interface changes: - Merger gets (CoordType, dimG1, dimG2, dimworld, mergedDim) template parameters - Merger::build(Range verticesG1, Range entitiesG1, Range verticesG2, Range entitiesG2) - ExtractedEntity (name to be discussed) provides: * list of vertexIds * Dune::GeometryType - Range describes begin and end iterator dune-grid-glue-2.9.0/config.h.cmake000066400000000000000000000013331435125002300170220ustar00rootroot00000000000000// SPDX-FileCopyrightInfo: Copyright © DUNE Project contributors, see file LICENSE.md in module root // SPDX-License-Identifier: LGPL-3.0-or-later OR LicenseRef-GPL-2.0-only-with-dune-grid-glue-exception /* begin dune-grid-glue */ /* Define to the version of dune-grid-glue */ #define DUNE_GRID_GLUE_VERSION "${DUNE_GRID_GLUE_VERSION}" /* Define to the major version of dune-grid-glue */ #define DUNE_GRID_GLUE_VERSION_MAJOR ${DUNE_GRID_GLUE_VERSION_MAJOR} /* Define to the minor version of dune-grid-glue */ #define DUNE_GRID_GLUE_VERSION_MINOR ${DUNE_GRID_GLUE_VERSION_MINOR} /* Define to the revision of dune-grid-glue */ #define DUNE_GRID_GLUE_VERSION_REVISION ${DUNE_GRID_GLUE_VERSION_REVISION} /* end dune-grid-glue */ dune-grid-glue-2.9.0/doc/000077500000000000000000000000001435125002300150725ustar00rootroot00000000000000dune-grid-glue-2.9.0/doc/CMakeLists.txt000066400000000000000000000003501435125002300176300ustar00rootroot00000000000000# SPDX-FileCopyrightInfo: Copyright © DUNE Project contributors, see file LICENSE.md in module root # SPDX-License-Identifier: LGPL-3.0-or-later OR LicenseRef-GPL-2.0-only-with-dune-grid-glue-exception add_subdirectory("doxygen") dune-grid-glue-2.9.0/doc/doxygen/000077500000000000000000000000001435125002300165475ustar00rootroot00000000000000dune-grid-glue-2.9.0/doc/doxygen/CMakeLists.txt000066400000000000000000000004261435125002300213110ustar00rootroot00000000000000# SPDX-FileCopyrightInfo: Copyright © DUNE Project contributors, see file LICENSE.md in module root # SPDX-License-Identifier: LGPL-3.0-or-later OR LicenseRef-GPL-2.0-only-with-dune-grid-glue-exception # shortcut for creating the Doxyfile.in and Doxyfile add_doxygen_target() dune-grid-glue-2.9.0/doc/doxygen/Doxylocal000066400000000000000000000014041435125002300204270ustar00rootroot00000000000000# SPDX-FileCopyrightInfo: Copyright © DUNE Project contributors, see file LICENSE.md in module root # SPDX-License-Identifier: LGPL-3.0-or-later OR LicenseRef-GPL-2.0-only-with-dune-grid-glue-exception INPUT += @top_srcdir@/dune/grid-glue/gridglue.hh \ @top_srcdir@/dune/grid-glue/adapter \ @top_srcdir@/dune/grid-glue/common \ @top_srcdir@/dune/grid-glue/extractors \ @top_srcdir@/dune/grid-glue/merging EXCLUDE += EXAMPLE_PATH += EXAMPLE_PATTERNS += *.dgf IMAGE_PATH += PREDEFINED += DOXYGEN \ HAVE_MPI:=1 \ "DUNE_DEPRECATED:=/** \deprecated */" dune-grid-glue-2.9.0/dune-grid-glue.pc.in000066400000000000000000000010461435125002300200670ustar00rootroot00000000000000# SPDX-FileCopyrightInfo: Copyright © DUNE Project contributors, see file LICENSE.md in module root # SPDX-License-Identifier: LGPL-3.0-or-later OR LicenseRef-GPL-2.0-only-with-dune-grid-glue-exception prefix=@prefix@ exec_prefix=@exec_prefix@ libdir=@libdir@ includedir=@includedir@ CXX=@CXX@ CC=@CC@ DEPENDENCIES=@REQUIRES@ Name: @PACKAGE_NAME@ Version: @VERSION@ Description: dune-grid-glue module URL: http://www.dune-project.org/modules/dune-grid-glue/ Requires: dune-common dune-grid Libs: -L${libdir} -ldunegridglue Cflags: -I${includedir} dune-grid-glue-2.9.0/dune.module000066400000000000000000000007671435125002300165010ustar00rootroot00000000000000# SPDX-FileCopyrightInfo: Copyright © DUNE Project contributors, see file LICENSE.md in module root # SPDX-License-Identifier: LGPL-3.0-or-later OR LicenseRef-GPL-2.0-only-with-dune-grid-glue-exception #dune module information file# ############################## #Name of the module Module: dune-grid-glue Version: 2.9 Maintainer: christian.engwer@uni-muenster.de,oliver.sander@tu-dresden.de #depending on Depends: dune-common (>= 2.4) dune-geometry (>= 2.4) dune-grid (>= 2.4) Whitespace-Hook: Yes dune-grid-glue-2.9.0/dune/000077500000000000000000000000001435125002300152605ustar00rootroot00000000000000dune-grid-glue-2.9.0/dune/CMakeLists.txt000066400000000000000000000003501435125002300200160ustar00rootroot00000000000000# SPDX-FileCopyrightInfo: Copyright © DUNE Project contributors, see file LICENSE.md in module root # SPDX-License-Identifier: LGPL-3.0-or-later OR LicenseRef-GPL-2.0-only-with-dune-grid-glue-exception add_subdirectory(grid-glue) dune-grid-glue-2.9.0/dune/grid-glue/000077500000000000000000000000001435125002300171375ustar00rootroot00000000000000dune-grid-glue-2.9.0/dune/grid-glue/CMakeLists.txt000066400000000000000000000006171435125002300217030ustar00rootroot00000000000000# SPDX-FileCopyrightInfo: Copyright © DUNE Project contributors, see file LICENSE.md in module root # SPDX-License-Identifier: LGPL-3.0-or-later OR LicenseRef-GPL-2.0-only-with-dune-grid-glue-exception add_subdirectory(adapter) add_subdirectory(merging) add_subdirectory(common) add_subdirectory(extractors) add_subdirectory(test) install(FILES gridglue.hh DESTINATION include/dune/grid-glue) dune-grid-glue-2.9.0/dune/grid-glue/adapter/000077500000000000000000000000001435125002300205575ustar00rootroot00000000000000dune-grid-glue-2.9.0/dune/grid-glue/adapter/CMakeLists.txt000066400000000000000000000007311435125002300233200ustar00rootroot00000000000000# SPDX-FileCopyrightInfo: Copyright © DUNE Project contributors, see file LICENSE.md in module root # SPDX-License-Identifier: LGPL-3.0-or-later OR LicenseRef-GPL-2.0-only-with-dune-grid-glue-exception #install headers install(FILES gridglue.cc gridglueamirawriter.hh gridgluecommunicate.hh gridglue.hh gridgluevtkwriter.hh intersection.hh intersectionindexset.hh intersectioniterator.hh rangegenerators.hh DESTINATION include/dune/grid-glue/adapter) dune-grid-glue-2.9.0/dune/grid-glue/adapter/gridglue.cc000066400000000000000000000354521435125002300227010ustar00rootroot00000000000000// -*- tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- // vi: set et ts=4 sw=2 sts=2: // SPDX-FileCopyrightInfo: Copyright © DUNE Project contributors, see file LICENSE.md in module root // SPDX-License-Identifier: LGPL-3.0-or-later OR LicenseRef-GPL-2.0-only-with-dune-grid-glue-exception /* IMPLEMENTATION OF CLASS G R I D G L U E */ #include "intersection.hh" #include #include #include "../gridglue.hh" #if HAVE_MPI #include "../common/ringcomm.hh" #endif #include namespace Dune { namespace GridGlue { template GridGlue::GridGlue(const std::shared_ptr< const GridPatch<0> >& gp0, const std::shared_ptr< const GridPatch<1> >& gp1, const std::shared_ptr& merger) : patches_{gp0, gp1}, merger_(merger) { #if HAVE_MPI // if we have only seq. meshes don't use parallel glueing if (gp0->gridView().comm().size() == 1 && gp1->gridView().comm().size() == 1) mpicomm_ = MPI_COMM_SELF; else mpicomm_ = MPI_COMM_WORLD; #endif // HAVE_MPI std::cout << "GridGlue: Constructor succeeded!" << std::endl; } template void GridGlue::build() { int myrank = 0; #if HAVE_MPI int commsize = 1; MPI_Comm_rank(mpicomm_, &myrank); MPI_Comm_size(mpicomm_, &commsize); #endif // HAVE_MPI // clear the contents from the current intersections array { std::vector dummy(1); // we need size 1, as we always store data for the end-intersection intersections_.swap(dummy); } std::vector > patch0coords; std::vector patch0entities; std::vector patch0types; std::vector > patch1coords; std::vector patch1entities; std::vector patch1types; /* * extract global surface patchs */ // retrieve the coordinate and topology information from the extractors // and apply transformations if necessary extractGrid(patch<0>(), patch0coords, patch0entities, patch0types); extractGrid(patch<1>(), patch1coords, patch1entities, patch1types); std::cout << ">>>> rank " << myrank << " coords: " << patch0coords.size() << " and " << patch1coords.size() << std::endl; std::cout << ">>>> rank " << myrank << " entities: " << patch0entities.size() << " and " << patch1entities.size() << std::endl; std::cout << ">>>> rank " << myrank << " types: " << patch0types.size() << " and " << patch1types.size() << std::endl; #ifdef WRITE_TO_VTK const char prefix[] = "GridGlue::Builder::build() : "; char patch0surf[256]; sprintf(patch0surf, "/tmp/vtk-patch0-test-%i", myrank); char patch1surf[256]; sprintf(patch1surf, "/tmp/vtk-patch1-test-%i", myrank); // std::cout << prefix << "Writing patch0 surface to '" << patch0surf << ".vtk'...\n"; // VtkSurfaceWriter vtksw(patch0surf); // vtksw.writeSurface(patch0coords, patch0entities, grid0dim, dimworld); // std::cout << prefix << "Done writing patch0 surface!\n"; // std::cout << prefix << "Writing patch1 surface to '" << patch1surf << ".vtk'...\n"; // vtksw.setFilename(patch1surf); // vtksw.writeSurface(patch1coords, patch1entities, grid1dim, dimworld); // std::cout << prefix << "Done writing patch1 surface!\n"; #endif // WRITE_TO_VTK // we start with an empty set index__sz = 0; #if HAVE_MPI if (commsize > 1) { // setup parallel indexset patch0_is_.beginResize(); patch1_is_.beginResize(); } auto op = [&]( const int mergingrank, const std::vector >& remotePatch0coords, const std::vector& remotePatch0entities, const std::vector& remotePatch0types, const std::vector >& remotePatch1coords, const std::vector& remotePatch1entities, const std::vector& remotePatch1types ) { if (remotePatch1entities.size() > 0 && patch0entities.size() > 0) mergePatches(patch0coords, patch0entities, patch0types, myrank, remotePatch1coords, remotePatch1entities, remotePatch1types, mergingrank); if (mergingrank != myrank && remotePatch0entities.size() > 0 && patch1entities.size() > 0) mergePatches(remotePatch0coords, remotePatch0entities, remotePatch0types, mergingrank, patch1coords, patch1entities, patch1types, myrank); }; Parallel::MPI_AllApply(mpicomm_, op, patch0coords, patch0entities, patch0types, patch1coords, patch1entities, patch1types ); if (commsize > 1) { // finalize ParallelIndexSet & RemoteIndices patch0_is_.endResize(); patch1_is_.endResize(); // setup remote index information remoteIndices_.setIncludeSelf(true); // #warning add list of neighbors ... remoteIndices_.setIndexSets(patch0_is_, patch1_is_, mpicomm_) ; remoteIndices_.rebuild(); // DEBUG Print all remote indices #ifdef DEBUG_GRIDGLUE_PARALLELMERGE for (auto it = remoteIndices_.begin(); it != remoteIndices_.end(); it++) { std::cout << myrank << "\tri-list\t" << it->first << std::endl; for (auto xit = it->second.first->begin(); xit != it->second.first->end(); ++xit) std::cout << myrank << "\tri-list 1 \t" << it->first << "\t" << *xit << std::endl; for (auto xit = it->second.second->begin(); xit != it->second.second->end(); ++xit) std::cout << myrank << "\tri-list 2 \t" << it->first << "\t" << *xit << std::endl; } #endif } #else // HAVE_MPI if (patch1entities.size() > 0 && patch0entities.size() > 0) { mergePatches(patch0coords, patch0entities, patch0types, myrank, patch1coords, patch1entities, patch1types, myrank); #ifdef CALL_MERGER_TWICE mergePatches(patch0coords, patch0entities, patch0types, myrank, patch1coords, patch1entities, patch1types, myrank); #endif } #endif // HAVE_MPI } template void printVector(const std::vector & v, std::string name, int rank) { std::cout << rank << ": " << name << std::endl; for (size_t i=0; i void GridGlue::mergePatches( const std::vector >& patch0coords, const std::vector& patch0entities, const std::vector& patch0types, const int patch0rank, const std::vector >& patch1coords, const std::vector& patch1entities, const std::vector& patch1types, const int patch1rank) { // howto handle overlap etc? int myrank = 0; #if HAVE_MPI int commsize = 1; MPI_Comm_rank(mpicomm_, &myrank); MPI_Comm_size(mpicomm_, &commsize); #endif // HAVE_MPI // which patches are local? const bool patch0local = (myrank == patch0rank); const bool patch1local = (myrank == patch1rank); // remember the number of previous remote intersections const unsigned int offset = intersections_.size()-1; std::cout << myrank << " GridGlue::mergePatches : rank " << patch0rank << " / " << patch1rank << std::endl; // start the actual build process merger_->build(patch0coords, patch0entities, patch0types, patch1coords, patch1entities, patch1types); // append to intersections list intersections_.resize(merger_->nSimplices() + offset + 1); for (unsigned int i = 0; i < merger_->nSimplices(); ++i) intersections_[offset + i] = IntersectionData(*this, i, offset, patch0local, patch1local); index__sz = intersections_.size() - 1; std::cout << myrank << " GridGlue::mergePatches : " << "The number of remote intersections is " << intersections_.size()-1 << std::endl; #if 0 printVector(patch0coords,"patch0coords",myrank); printVector(patch0entities,"patch0entities",myrank); printVector(patch0types,"patch0types",myrank); printVector(patch1coords,"patch1coords",myrank); printVector(patch1entities,"patch1entities",myrank); printVector(patch1types,"patch1types",myrank); #endif #if HAVE_MPI if (commsize > 1) { // update remote index sets assert(Dune::RESIZE == patch0_is_.state()); assert(Dune::RESIZE == patch1_is_.state()); for (unsigned int i = 0; i < merger_->nSimplices(); i++) { // #warning only handle the newest intersections / merger info const IntersectionData & it = intersections_[i]; GlobalId gid(patch0rank, patch1rank, i); if (it.template local<0>()) { Dune::PartitionType ptype = patch<0>().element(it.template index<0>()).partitionType(); patch0_is_.add (gid, LocalIndex(offset+i, ptype) ); } if (it.template local<1>()) { Dune::PartitionType ptype = patch<1>().element(it.template index<1>()).partitionType(); patch1_is_.add (gid, LocalIndex(offset+i, ptype) ); } } } #endif // HAVE_MPI // cleanup the merger merger_->clear(); } template template void GridGlue::extractGrid (const Extractor & extractor, std::vector > & coords, std::vector & entities, std::vector& geometryTypes) const { std::vector tempcoords; std::vector tempentities; extractor.getCoords(tempcoords); coords.clear(); coords.reserve(tempcoords.size()); for (unsigned int i = 0; i < tempcoords.size(); ++i) { assert(int(dimworld) == int(Extractor::dimworld)); coords.push_back(Dune::FieldVector()); for (size_t j = 0; j template void GridGlue::communicate( Dune::GridGlue::CommDataHandle & data, Dune::InterfaceType iftype, Dune::CommunicationDirection dir) const { typedef Dune::GridGlue::CommDataHandle DataHandle; typedef typename DataHandle::DataType DataType; #if HAVE_MPI if (mpicomm_ != MPI_COMM_SELF) { /* * P A R A L L E L V E R S I O N */ // setup communication interfaces Dune::dinfo << "GridGlue: parallel communication" << std::endl; typedef Dune::EnumItem InteriorFlags; typedef Dune::EnumItem OverlapFlags; typedef Dune::EnumRange AllFlags; Dune::Interface interface; assert(remoteIndices_.isSynced()); switch (iftype) { case Dune::InteriorBorder_InteriorBorder_Interface : interface.build (remoteIndices_, InteriorFlags(), InteriorFlags() ); break; case Dune::InteriorBorder_All_Interface : if (dir == Dune::ForwardCommunication) interface.build (remoteIndices_, InteriorFlags(), AllFlags() ); else interface.build (remoteIndices_, AllFlags(), InteriorFlags() ); break; case Dune::Overlap_OverlapFront_Interface : interface.build (remoteIndices_, OverlapFlags(), OverlapFlags() ); break; case Dune::Overlap_All_Interface : if (dir == Dune::ForwardCommunication) interface.build (remoteIndices_, OverlapFlags(), AllFlags() ); else interface.build (remoteIndices_, AllFlags(), OverlapFlags() ); break; case Dune::All_All_Interface : interface.build (remoteIndices_, AllFlags(), AllFlags() ); break; default : DUNE_THROW(Dune::NotImplemented, "GridGlue::communicate for interface " << iftype << " not implemented"); } // setup communication info (class needed to tunnel all info to the operator) typedef Dune::GridGlue::CommInfo CommInfo; CommInfo commInfo; commInfo.dir = dir; commInfo.gridglue = this; commInfo.data = &data; // create communicator Dune::BufferedCommunicator bComm ; bComm.template build< CommInfo >(commInfo, commInfo, interface); // do communication // choose communication direction. if (dir == Dune::ForwardCommunication) bComm.forward< Dune::GridGlue::ForwardOperator >(commInfo, commInfo); else bComm.backward< Dune::GridGlue::BackwardOperator >(commInfo, commInfo); } else #endif // HAVE_MPI { /* * S E Q U E N T I A L V E R S I O N */ Dune::dinfo << "GridGlue: sequential fallback communication" << std::endl; // get comm buffer size int ssz = size() * 10; // times data per intersection int rsz = size() * 10; // allocate send/receive buffer auto sendbuffer = std::make_unique(ssz); auto receivebuffer = std::make_unique(rsz); // gather Dune::GridGlue::StreamingMessageBuffer gatherbuffer(sendbuffer.get()); for (const auto& in : intersections(*this)) { /* we need to have to variants depending on the communication direction. */ if (dir == Dune::ForwardCommunication) { /* dir : Forward (grid0 -> grid1) */ if (in.self()) { data.gather(gatherbuffer, in.inside(), in); } } else // (dir == Dune::BackwardCommunication) { /* dir : Backward (grid1 -> grid0) */ if (in.neighbor()) { data.gather(gatherbuffer, in.outside(), in.flip()); } } } assert(ssz == rsz); for (int i=0; i scatterbuffer(receivebuffer.get()); for (const auto& in : intersections(*this)) { /* we need to have to variants depending on the communication direction. */ if (dir == Dune::ForwardCommunication) { /* dir : Forward (grid0 -> grid1) */ if (in.neighbor()) data.scatter(scatterbuffer, in.outside(), in.flip(), data.size(in)); } else // (dir == Dune::BackwardCommunication) { /* dir : Backward (grid1 -> grid0) */ if (in.self()) data.scatter(scatterbuffer, in.inside(), in, data.size(in)); } } } } } // end namespace GridGlue } // end namespace Dune dune-grid-glue-2.9.0/dune/grid-glue/adapter/gridglue.hh000066400000000000000000000006671435125002300227130ustar00rootroot00000000000000// SPDX-FileCopyrightInfo: Copyright © DUNE Project contributors, see file LICENSE.md in module root // SPDX-License-Identifier: LGPL-3.0-or-later OR LicenseRef-GPL-2.0-only-with-dune-grid-glue-exception #ifndef DUNE_GRIDGLUE_ADAPTER_GRIDGLUE_HH #define DUNE_GRIDGLUE_ADAPTER_GRIDGLUE_HH #warning This header is deprecated, use #include using Dune::GridGlue::GridGlue; #endif dune-grid-glue-2.9.0/dune/grid-glue/adapter/gridglueamirawriter.hh000066400000000000000000000106371435125002300251600ustar00rootroot00000000000000// SPDX-FileCopyrightInfo: Copyright © DUNE Project contributors, see file LICENSE.md in module root // SPDX-License-Identifier: LGPL-3.0-or-later OR LicenseRef-GPL-2.0-only-with-dune-grid-glue-exception /** * @file * @brief Write all remote intersections to a AmiraMesh file */ #ifndef DUNE_GRIDGLUE_ADAPTER_GRIDGLUEAMIRAWRITER_HH #define DUNE_GRIDGLUE_ADAPTER_GRIDGLUEAMIRAWRITER_HH #include #include #include namespace Dune { namespace GridGlue { /** \brief Write remote intersections to a AmiraMesh file for debugging purposes */ class GridGlueAmiraWriter { /** \brief Write either the grid0 or the grid1-side into streams * \tparam side Write the grid0-side if this is 0, and grid1 if it is 1. */ template static void writeIntersections(const Glue& glue, const std::string& filename) { static_assert((side==0 || side==1), "'side' can only be 0 or 1"); std::ofstream fgrid; fgrid.open(filename.c_str()); using GridView = typename Glue::template GridView; const int dim = GridView::dimension; const int domdimw = GridView::dimensionworld; // coordinates have to be in R^3 in the VTK format std::string coordinatePadding; for (int i=domdimw; i<3; i++) coordinatePadding += " 0"; int overlaps = glue.size(); if (dim==3) { fgrid << "# HyperSurface 0.1 ASCII \n" << std::endl; fgrid<<"\n"; fgrid<<"Parameters {\n"; fgrid<<" Materials {\n"; fgrid<<" outside {\n"; fgrid<<" Id 0\n"; fgrid<<" }\n"; fgrid<<" inside {\n"; fgrid<<" Id 1\n"; fgrid<<" }\n"; fgrid<<" }\n"; fgrid<<"\n"; fgrid<<"}\n"; // //////////////////////////////////////////// // Write vertices // //////////////////////////////////////////// //use dim and not dim+1 fgrid<<"\nVertices "<< overlaps*(dim)<<"\n"; auto isEnd = glue.template iend(); for (auto isIt = glue.template ibegin(); isIt != isEnd; ++isIt) { const auto& geometry = isIt->geometry(); for (int i = 0; i < geometry.corners(); ++i) fgrid << geometry.corner(i) << coordinatePadding << std::endl; } // //////////////////////////////////////////// // Write triangles // //////////////////////////////////////////// fgrid<<"NBranchingPoints 0\n"; fgrid<<"NVerticesOnCurves 0\n"; fgrid<<"BoundaryCurves 0\n"; fgrid<<"Patches 1\n"; fgrid<<"{\n"; fgrid<<"InnerRegion inside\n"; fgrid<<"OuterRegion outside\n"; fgrid<<"BoundaryID 0\n"; fgrid<<"BranchingPoints 0"; fgrid<<"\n"; fgrid<<"Triangles "<(); for (auto isIt = glue.template ibegin(); isIt != isEnd; ++isIt) { const auto& geometry = isIt->geometry(); for (int i = 0; i <2; ++i) fgrid << geometry.corner(i) <<" "<<0<<"\n"; } } fgrid.close(); } public: template static void write(const Glue& glue, const std::string& path, int appendix=1) { std::ostringstream name0; name0 << path; name0 << "/domain.surf" << std::setw(3) << std::setfill('0') << appendix; // Write extracted grid and remote intersection on the grid1-side writeIntersections(glue,name0.str()); std::ostringstream name1; name1 << path; name1 << "/target.surf" << std::setw(3) << std::setfill('0') << appendix; writeIntersections(glue, name1.str()); } }; } // namespace GridGlue } // namespace Dune #endif // DUNE_GRIDGLUE_ADAPTER_GRIDGLUEAMIRAWRITER_HH dune-grid-glue-2.9.0/dune/grid-glue/adapter/gridgluecommunicate.hh000066400000000000000000000242361435125002300251360ustar00rootroot00000000000000// -*- tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- // vi: set et ts=4 sw=2 sts=2: // SPDX-FileCopyrightInfo: Copyright © DUNE Project contributors, see file LICENSE.md in module root // SPDX-License-Identifier: LGPL-3.0-or-later OR LicenseRef-GPL-2.0-only-with-dune-grid-glue-exception #ifndef DUNE_GRIDGLUE_ADAPTER_GRIDGLUECOMMUNICATE_HH #define DUNE_GRIDGLUE_ADAPTER_GRIDGLUECOMMUNICATE_HH /**@file @author Christian Engwer @brief Describes the parallel communication interface class for Dune::GridGlue */ #include #include #include #include #include namespace Dune { namespace GridGlue { typedef std::pair RankPair; struct GlobalId : public std::pair { /** default constructor, required for dune-common RemoteIndices \internal */ GlobalId() { this->first.first = 0; this->first.second = 0; this->second = 0; } /** constructor from int, required for dune-common RemoteIndices \internal */ GlobalId(int i) { this->first.first = i; this->first.second = i; this->second = 0; } /** constructor \param i rank of processor 1 \param j rank of processor 2 \param n local intersection index */ GlobalId(int i, int j, unsigned int n) { this->first.first = std::min(i,j); this->first.second = std::max(i,j); this->second = n; } }; inline std::ostream& operator<<(std::ostream& os, const GlobalId & id) { os << "(" << id.first.first << "," << id.first.second << "," << id.second << ")"; return os; } /** \brief describes the features of a data handle for communication in parallel runs using the GridGlue::communicate methods. Here the Barton-Nackman trick is used to interprete data handle objects as its interface. Therefore usable data handle classes need to be derived from this class. \tparam DataHandleImp implementation of the users data handle \tparam DataTypeImp type of data that are going to be communicated which is exported as \c DataType (for example double) \ingroup GridGlueCommunication */ template class CommDataHandle { public: //! data type of data to communicate typedef DataTypeImp DataType; protected: // one should not create an explicit instance of this inteface object CommDataHandle() {} public: /*! how many objects of type DataType have to be sent for a given intersection Note: Both sender and receiver side need to know this size. */ template size_t size (RISType& i) const { CHECK_INTERFACE_IMPLEMENTATION((asImp().size(i))); return asImp().size(i); } /** @brief pack data from user to message buffer @param buff message buffer provided by the grid @param e entity for which date should be packed to buffer @param i Intersection for which data should be packed to buffer */ template void gather (MessageBufferImp& buff, const EntityType& e, const RISType & i) const { MessageBufferIF buffIF(buff); CHECK_AND_CALL_INTERFACE_IMPLEMENTATION((asImp().gather(buffIF,e,i))); } /*! unpack data from message buffer to user n is the number of objects sent by the sender @param buff message buffer provided by the grid @param e entity for which date should be unpacked from buffer @param i Intersection for which data is received @param n number of data written to buffer for this entity before */ template void scatter (MessageBufferImp& buff, const EntityType& e, const RISType & i, size_t n) { MessageBufferIF buffIF(buff); CHECK_AND_CALL_INTERFACE_IMPLEMENTATION((asImp().scatter(buffIF,e,i,n))); } private: //! Barton-Nackman trick DataHandleImp& asImp () { return static_cast (*this); } //! Barton-Nackman trick const DataHandleImp& asImp () const { return static_cast(*this); } }; // end class CommDataHandleIF /** Streaming MessageBuffer for the GridGlue communication \ingroup GridGlueCommunication */ template class StreamingMessageBuffer { public: typedef DT value_type; // Constructor StreamingMessageBuffer (DT *p) { a=p; i=0; j=0; } // write data to message buffer, acts like a stream ! template void write (const Y& data) { static_assert(std::is_same::value, "DataType mismatch"); a[i++] = data; } // read data from message buffer, acts like a stream ! template void read (Y& data) const { static_assert(std::is_same::value, "DataType mismatch"); data = a[j++]; } size_t counter() const { return i; } void clear() { i = 0; j = 0; } // we need access to these variables in an assertion #ifdef NDEBUG private: #endif DT *a; size_t i; mutable size_t j; }; /** \brief forward gather scatter to user defined CommInfo class - implements the ParallelIndexset gather/scatter interface - redirects all calls to the GridGlueCommDataHandleIF gather/scatter methods */ template class CommunicationOperator { public: template static const typename CommInfo::DataType& gather(const CommInfo& commInfo, size_t i, size_t j = 0) { // get Intersection typedef typename CommInfo::GridGlue::Intersection Intersection; Intersection ris(commInfo.gridglue->getIntersection(i)); // fill buffer if we have a new intersection if (j == 0) { commInfo.mbuffer.clear(); if (dir == Dune::ForwardCommunication) { // read from grid0 if(ris.self()) commInfo.data->gather(commInfo.mbuffer, ris.inside(), ris); } else // (dir == Dune::BackwardCommunication) { // read from grid1 if(ris.neighbor()) commInfo.data->gather(commInfo.mbuffer, ris.outside(), ris.flip()); } } // return the j'th value in the buffer assert(j < commInfo.mbuffer.i); return commInfo.buffer[j]; } template static void scatter(CommInfo& commInfo, const typename CommInfo::DataType& v, std::size_t i, std::size_t j = 0) { // extract GridGlue objects... typedef typename CommInfo::GridGlue::Intersection Intersection; Intersection ris(commInfo.gridglue->getIntersection(i)); // get size if we have a new intersection if (j == 0) { commInfo.mbuffer.clear(); commInfo.currentsize = commInfo.data->size(ris); } // write entry to buffer commInfo.buffer[j] = v; // write back the buffer if we are at the end of this intersection if (j == commInfo.currentsize-1) { if (dir == Dune::ForwardCommunication) { // write to grid1 if(ris.neighbor()) commInfo.data->scatter(commInfo.mbuffer, ris.outside(), ris.flip(), commInfo.currentsize); } else // (dir == Dune::BackwardCommunication) { // write to grid0 if(ris.self()) commInfo.data->scatter(commInfo.mbuffer, ris.inside(), ris, commInfo.currentsize); } assert(commInfo.mbuffer.j <= commInfo.currentsize); } } }; typedef CommunicationOperator ForwardOperator; typedef CommunicationOperator BackwardOperator; /** \brief collects all GridGlue data requried for communication \ingroup GridGlueCommunication */ template struct CommInfo { typedef DataTypeImp value_type; typedef GG GridGlue; typedef DataTypeImp DataType; CommInfo() : buffer(100), mbuffer(&buffer[0]) {} // tunnel information to the policy and the operators const GridGlue * gridglue; ::Dune::GridGlue::CommDataHandle * data; // state variables std::vector buffer; mutable ::Dune::GridGlue::StreamingMessageBuffer mbuffer; size_t currentsize; Dune::CommunicationDirection dir; }; } // end namespace GridGlue #if HAVE_MPI /** * \brief specialization of the CommPolicy struct, required for the ParallelIndexsets * \internal */ template struct CommPolicy< ::Dune::GridGlue::CommInfo > { /** * @brief The type of the GridGlueCommInfo */ typedef ::Dune::GridGlue::CommInfo Type; /** * @brief The datatype that should be communicated. */ typedef DataTypeImp IndexedType; /** * @brief Each intersection can communicate a different number of objects. */ // typedef SizeOne IndexedTypeFlag; typedef VariableSize IndexedTypeFlag; /** * @brief Get the number of objects at an intersection. */ static size_t getSize(const Type& commInfo, size_t i) { // get Intersection typedef typename Type::GridGlue::Intersection Intersection; Intersection ris(commInfo.gridglue->getIntersection(i)); // ask data handle for size return commInfo.data->size(ris); } }; #endif } // end namespace Dune #endif dune-grid-glue-2.9.0/dune/grid-glue/adapter/gridgluevtkwriter.hh000066400000000000000000000234421435125002300246710ustar00rootroot00000000000000// -*- tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- // vi: set et ts=4 sw=2 sts=2: // SPDX-FileCopyrightInfo: Copyright © DUNE Project contributors, see file LICENSE.md in module root // SPDX-License-Identifier: LGPL-3.0-or-later OR LicenseRef-GPL-2.0-only-with-dune-grid-glue-exception /* * Filename: GridGlueVtkWriter.hh * Version: 1.0 * Created on: Mar 5, 2009 * Author: Gerrit Buse * --------------------------------- * Project: dune-grid-glue * Description: Class thought to make graphical debugging of couplings easier. * */ /** * @file * @brief Write all remote intersections to a vtk file for debugging */ #ifndef DUNE_GRIDGLUE_ADAPTER_GRIDGLUEVTKWRITER_HH #define DUNE_GRIDGLUE_ADAPTER_GRIDGLUEVTKWRITER_HH #include #include #include #include #include #include #include #include namespace Dune { namespace GridGlue { /** \brief Write remote intersections to a vtk file for debugging purposes */ class GridGlueVtkWriter { /** \brief Write either the grid0 or the grid1-side into streams * \tparam side Write the grid0-side if this is 0, and grid1 if it is 1. */ template static void writeExtractedPart(const Glue& glue, const std::string& filename) { static_assert((side==0 || side==1), "'side' can only be 0 or 1"); std::ofstream fgrid; fgrid.open(filename.c_str()); using GridView = typename Glue::template GridView; using Extractor = typename Glue::template GridPatch; typedef typename GridView::ctype ctype; const int domdimw = GridView::dimensionworld; const int patchDim = Extractor::dim - Extractor::codim; // coordinates have to be in R^3 in the VTK format std::string coordinatePadding; for (int i=domdimw; i<3; i++) coordinatePadding += " 0"; fgrid << "# vtk DataFile Version 2.0\nFilename: " << filename << "\nASCII" << std::endl; // WRITE POINTS // ---------------- std::vector coords; glue.template patch().getCoords(coords); fgrid << ((patchDim==3) ? "DATASET UNSTRUCTURED_GRID" : "DATASET POLYDATA") << std::endl; fgrid << "POINTS " << coords.size() << " " << Dune::className() << std::endl; for (size_t i=0; i faces; std::vector geometryTypes; glue.template patch().getFaces(faces); glue.template patch().getGeometryTypes(geometryTypes); unsigned int faceCornerCount = 0; for (size_t i=0; i() << " 1" << std::endl; fgrid << "LOOKUP_TABLE default" << std::endl; for (typename GridSubEntityData::const_iterator sEIt = gridSubEntityData.begin(); sEIt != gridSubEntityData.end(); ++sEIt, accum += delta) { // "encode" the parent with one color... fgrid << accum << std::endl; } #endif fgrid.close(); } /** \brief Write either the grid0 or the grid1-side into streams * \tparam side Write the grid0-side if this is 0, and grid1 if it is 1. */ template static void writeIntersections(const Glue& glue, const std::string& filename) { static_assert((side==0 || side==1), "'side' can only be 0 or 1"); std::ofstream fmerged; fmerged.open(filename.c_str()); using GridView = typename Glue::template GridView; typedef typename GridView::ctype ctype; const int domdimw = GridView::dimensionworld; const int intersectionDim = Glue::Intersection::mydim; // coordinates have to be in R^3 in the VTK format std::string coordinatePadding; for (int i=domdimw; i<3; i++) coordinatePadding += " 0"; int overlaps = glue.size(); // WRITE POINTS // ---------------- using Extractor = typename Glue::template GridPatch<0>; std::vector coords; glue.template patch().getCoords(coords); // the merged grid (i.e. the set of remote intersections fmerged << "# vtk DataFile Version 2.0\nFilename: " << filename << "\nASCII" << std::endl; fmerged << ((intersectionDim==3) ? "DATASET UNSTRUCTURED_GRID" : "DATASET POLYDATA") << std::endl; fmerged << "POINTS " << overlaps*(intersectionDim+1) << " " << Dune::className() << std::endl; for (const auto& intersection : intersections(glue, Reverse{})) { const auto& geometry = intersection.geometry(); for (int i = 0; i < geometry.corners(); ++i) fmerged << geometry.corner(i) << coordinatePadding << std::endl; } // WRITE POLYGONS // ---------------- std::vector faces; std::vector geometryTypes; glue.template patch().getFaces(faces); glue.template patch().getGeometryTypes(geometryTypes); unsigned int faceCornerCount = 0; for (size_t i=0; i() << " 1" << std::endl; fmerged << "LOOKUP_TABLE default" << std::endl; for (typename GridSubEntityData::const_iterator sEIt = gridSubEntityData.begin(); sEIt != gridSubEntityData.end(); ++sEIt, accum += delta) { // ...and mark all of its merged grid parts with the same color for (int j = 0; j < sEIt->first.second; ++j) fmerged << accum << std::endl; } #endif fmerged.close(); } public: template static void write(const Glue& glue, const std::string& filenameTrunk) { // Write extracted grid and remote intersection on the grid0-side writeExtractedPart(glue, filenameTrunk + "-grid0.vtk"); writeIntersections(glue, filenameTrunk + "-intersections-grid0.vtk"); // Write extracted grid and remote intersection on the grid1-side writeExtractedPart(glue, filenameTrunk + "-grid1.vtk"); writeIntersections(glue, filenameTrunk + "-intersections-grid1.vtk"); } }; } /* namespace GridGlue */ } /* namespace Dune */ #endif // DUNE_GRIDGLUE_ADAPTER_GRIDGLUEVTKWRITER_HH dune-grid-glue-2.9.0/dune/grid-glue/adapter/intersection.hh000066400000000000000000000447131435125002300236170ustar00rootroot00000000000000// -*- tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- // vi: set et ts=4 sw=2 sts=2: // SPDX-FileCopyrightInfo: Copyright © DUNE Project contributors, see file LICENSE.md in module root // SPDX-License-Identifier: LGPL-3.0-or-later OR LicenseRef-GPL-2.0-only-with-dune-grid-glue-exception /** @file @author Christian Engwer @brief Model of the Intersection concept provided by GridGlue. */ #ifndef DUNE_GRIDGLUE_ADAPTER_INTERSECTION_HH #define DUNE_GRIDGLUE_ADAPTER_INTERSECTION_HH #include #include #include #include #include #include #include #include #define ONLY_SIMPLEX_INTERSECTIONS namespace Dune { namespace GridGlue { // forward declaration template class IntersectionIndexSet; /** @brief storage class for Dune::GridGlue::Intersection related data */ template class IntersectionData { public: typedef ::Dune::GridGlue::GridGlue GridGlue; typedef typename GridGlue::IndexType IndexType; /** \brief Dimension of the world space of the intersection */ static constexpr int coorddim = GridGlue::dimworld; private: // intermediate quantities template static constexpr int dim() { return GridGlue::template GridView::Grid::dimension - GridGlue::template GridPatch::codim; } public: /** \brief Dimension of the intersection */ static constexpr int mydim = dim<0>() < dim<1>() ? dim<0>() : dim<1>(); template using GridLocalGeometry = AffineGeometry< typename GridGlue::template GridView::ctype, mydim, GridGlue::template GridView::dimension>; using Grid0LocalGeometry [[deprecated("please use GridLocalGeometry<0> instead")]] = GridLocalGeometry<0>; using Grid1LocalGeometry [[deprecated("please use GridLocalGeometry<1> instead")]] = GridLocalGeometry<1>; template using GridGeometry = AffineGeometry< typename GridGlue::template GridView::ctype, mydim, GridGlue::template GridView::dimensionworld>; using Grid0Geometry [[deprecated("please use GridGeometry<0> instead")]] = GridGeometry<0>; using Grid1Geometry [[deprecated("please use GridGeometry<1> instead")]] = GridGeometry<1>; template using GridIndexType = typename GridGlue::template GridView::IndexSet::IndexType; using Grid0IndexType [[deprecated("please use GridIndexType<0> instead")]] = GridIndexType<0>; using Grid1IndexType [[deprecated("please use GridIndexType<1> instead")]] = GridIndexType<1>; /** \brief Constructor the n'th IntersectionData of a given GridGlue */ IntersectionData(const GridGlue& glue, unsigned int mergeindex, unsigned int offset, bool grid0local, bool grid1local); /** \brief Default Constructor */ IntersectionData() = default; /* Accessor Functions */ template const GridLocalGeometry& localGeometry(unsigned int parentId = 0) const { return *std::get(sideData_).gridlocalgeom[parentId]; } template const GridGeometry& geometry() const { return *std::get(sideData_).gridgeom; } template bool local() const { return std::get(sideData_).gridlocal; } template IndexType index(unsigned int parentId = 0) const { return std::get(sideData_).gridindices[parentId]; } template IndexType parents() const { return std::get(sideData_).gridindices.size(); } private: template void initializeGeometry(const GridGlue& glue, unsigned mergeindex); /* M E M B E R V A R I A B L E S */ public: /// @brief index of this intersection after GridGlue interface IndexType index_; private: template struct SideData { /** \brief true if the associated grid entity is local */ bool gridlocal = false; /** \brief indices of the associated local grid entity */ std::vector< GridIndexType > gridindices; /** \brief embedding of intersection into local grid entity coordinates */ std::vector< std::optional< GridLocalGeometry > > gridlocalgeom; /** * global intersection geometry on grid `side` side. * * This is the same as g∘i for the first embedding i into a grid * entity as stored in gridlocalgeom and that entities global * geometry g. */ std::optional< GridGeometry > gridgeom; }; std::tuple< SideData<0>, SideData<1> > sideData_; }; template template void IntersectionData::initializeGeometry(const GridGlue& glue, unsigned mergeindex) { auto& data = std::get(sideData_); const unsigned n_parents = glue.merger_->template parents(mergeindex); // init containers data.gridindices.resize(n_parents); data.gridlocalgeom.resize(n_parents); // default values data.gridindices[0] = 0; static constexpr int nSimplexCorners = mydim + 1; using ctype = typename GridGlue::ctype; // initialize the local and the global geometries of grid `side` // compute the coordinates of the subface's corners in codim 0 entity local coordinates static constexpr int elementdim = GridGlue::template GridView::template Codim<0>::Geometry::mydimension; // coordinates within the subentity that contains the remote intersection std::array() >, nSimplexCorners> corners_subEntity_local; for (unsigned int par = 0; par < n_parents; ++par) { for (int i = 0; i < nSimplexCorners; ++i) corners_subEntity_local[i] = glue.merger_->template parentLocal(mergeindex, i, par); // Coordinates of the remote intersection corners wrt the element coordinate system std::array, nSimplexCorners> corners_element_local; if (data.gridlocal) { data.gridindices[par] = glue.merger_->template parent(mergeindex,par); typename GridGlue::template GridPatch::LocalGeometry gridLocalGeometry = glue.template patch().geometryLocal(data.gridindices[par]); for (std::size_t i=0; i::Geometry gridWorldGeometry = glue.template patch().geometry(data.gridindices[par]); // world coordinates of the remote intersection corners std::array::dimensionworld>, nSimplexCorners> corners_global; for (std::size_t i=0; i IntersectionData::IntersectionData(const GridGlue& glue, unsigned int mergeindex, unsigned int offset, bool grid0local, bool grid1local) : index_(mergeindex+offset) { // if an invalid index is given do not proceed! // (happens when the parent GridGlue initializes the "end"-Intersection) assert (0 <= mergeindex || mergeindex < glue.index__sz); std::get<0>(sideData_).gridlocal = grid0local; std::get<1>(sideData_).gridlocal = grid1local; initializeGeometry<0>(glue, mergeindex); initializeGeometry<1>(glue, mergeindex); } /** @brief @todo doc me */ template struct IntersectionTraits { using GridGlue = ::Dune::GridGlue::GridGlue; using IntersectionData = Dune::GridGlue::IntersectionData; using InsideGridView = typename GridGlue::template GridView; using OutsideGridView = typename GridGlue::template GridView; using InsideLocalGeometry = typename IntersectionData::template GridLocalGeometry; using OutsideLocalGeometry = typename IntersectionData::template GridLocalGeometry; using Geometry = typename IntersectionData::template GridGeometry; using OutsideGeometry = typename IntersectionData::template GridGeometry; static constexpr auto coorddim = IntersectionData::coorddim; static constexpr auto mydim = IntersectionData::mydim; static constexpr int insidePatch = inside; static constexpr int outsidePatch = outside; using ctype = typename GridGlue::ctype; using LocalCoordinate = Dune::FieldVector; using GlobalCoordinate = Dune::FieldVector; }; /** @brief The intersection of two entities of the two patches of a GridGlue */ template class Intersection { public: typedef IntersectionTraits Traits; typedef typename Traits::GridGlue GridGlue; typedef typename Traits::IntersectionData IntersectionData; typedef typename Traits::InsideGridView InsideGridView; typedef typename Traits::InsideLocalGeometry InsideLocalGeometry; typedef typename Traits::OutsideGridView OutsideGridView; typedef typename Traits::OutsideLocalGeometry OutsideLocalGeometry; typedef typename Traits::OutsideGeometry OutsideGeometry; typedef typename Traits::Geometry Geometry; typedef typename Traits::ctype ctype; typedef typename InsideGridView::Traits::template Codim<0>::Entity InsideEntity; typedef typename OutsideGridView::Traits::template Codim<0>::Entity OutsideEntity; typedef typename Traits::LocalCoordinate LocalCoordinate; typedef typename Traits::GlobalCoordinate GlobalCoordinate; /** \brief dimension of the world space of the intersection */ static constexpr auto coorddim = Traits::coorddim; /** \brief dimension of the intersection */ static constexpr auto mydim = Traits::mydim; /** \brief inside patch */ static constexpr int insidePatch = Traits::insidePatch; /** \brief outside patch */ static constexpr int outsidePatch = Traits::outsidePatch; // typedef unsigned int IndexType; private: /** * \brief codimension of the intersection with respect to the world dimension */ static constexpr int codimensionWorld = coorddim - mydim; public: /* C O N S T R U C T O R S */ /** \brief Constructor for a given Dataset */ Intersection(const GridGlue* glue, const IntersectionData* i) : glue_(glue), i_(i) {} /* F U N C T I O N A L I T Y */ /** \brief Return element on the inside of this intersection. */ InsideEntity inside(unsigned int parentId = 0) const { assert(self()); return glue_->template patch().element(i_->template index(parentId)); } /** \brief Return element on the outside of this intersection. */ OutsideEntity outside(unsigned int parentId = 0) const { assert(neighbor()); return glue_->template patch().element(i_->template index(parentId)); } /** \brief Return true if intersection is conforming */ bool conforming() const { throw Dune::NotImplemented(); } /** \brief Geometric information about this intersection in local coordinates of the inside() element. */ const InsideLocalGeometry& geometryInInside(unsigned int parentId = 0) const { return i_->template localGeometry(parentId); } /** \brief Geometric information about this intersection in local coordinates of the outside() element. */ const OutsideLocalGeometry& geometryInOutside(unsigned int parentId = 0) const { return i_->template localGeometry(parentId); } /** \brief Geometric information about this intersection as part of the inside grid. * * This is the same geometry as the application of the first * embedding into the "inside" entity and then this entities * global geometry. */ const Geometry& geometry() const { return i_->template geometry(); } /** \brief Geometric information about this intersection as part of the outside grid. * * This is the same geometry as the application of the first * embedding into the "outside" entity and then this entities * global geometry. */ const OutsideGeometry& geometryOutside() const // DUNE_DEPRECATED { return i_->template geometry(); } /** \brief Type of reference element for this intersection */ Dune::GeometryType type() const { #ifdef ONLY_SIMPLEX_INTERSECTIONS # if DUNE_VERSION_NEWER(DUNE_GEOMETRY, 2, 6) return Dune::GeometryTypes::simplex(mydim); # else static const Dune::GeometryType type(Dune::GeometryType::simplex, mydim); return type; # endif #else #error Not Implemented #endif } /** \brief For parallel computations: Return true if inside() entity exists locally */ bool self() const { return i_->template local(); } /** \brief Return number of embeddings into local grid0 (grid1) entities. */ size_t neighbor(unsigned int g = 0) const { if (g == 0 && i_->template local()) { return i_->template parents(); } else if (g == 1 && i_->template local()) { return i_->template parents(); } return 0; } /** \brief Local number of codim 1 entity in the inside() Entity where intersection is contained in. */ int indexInInside(unsigned int parentId = 0) const { assert(self()); return glue_->template patch().indexInInside(i_->template index(parentId)); } /** \brief Local number of codim 1 entity in outside() Entity where intersection is contained in. */ int indexInOutside(unsigned int parentId = 0) const { assert(neighbor()); return glue_->template patch().indexInInside(i_->template index(parentId)); } /** \brief Return an outer normal (length not necessarily 1) * * The outer normal is given with respect to the \ref geometry(). */ GlobalCoordinate outerNormal(const LocalCoordinate &local) const { GlobalCoordinate normal; if (codimensionWorld == 0) DUNE_THROW(Dune::Exception, "There is no normal vector to a full-dimensional intersection"); else if (codimensionWorld == 1) { /* TODO: Implement the general n-ary cross product here */ const auto jacobianTransposed = geometry().jacobianTransposed(local); if (mydim==1) { normal[0] = - jacobianTransposed[0][1]; normal[1] = jacobianTransposed[0][0]; } else if (mydim==2) { normal[0] = (jacobianTransposed[0][1] * jacobianTransposed[1][2] - jacobianTransposed[0][2] * jacobianTransposed[1][1]); normal[1] = - (jacobianTransposed[0][0] * jacobianTransposed[1][2] - jacobianTransposed[0][2] * jacobianTransposed[1][0]); normal[2] = (jacobianTransposed[0][0] * jacobianTransposed[1][1] - jacobianTransposed[0][1] * jacobianTransposed[1][0]); } else DUNE_THROW(Dune::NotImplemented, "Remote intersections don't implement the 'outerNormal' method for " << mydim << "-dimensional intersections yet"); } else DUNE_THROW(Dune::NotImplemented, "Remote intersections don't implement the 'outerNormal' method for intersections with codim >= 2 yet"); return normal; } /** \brief Return a unit outer normal * * The outer normal is given with respect to the \ref geometry(). */ GlobalCoordinate unitOuterNormal(const LocalCoordinate &local) const { GlobalCoordinate normal = outerNormal(local); normal /= normal.two_norm(); return normal; } /** \brief Return an outer normal with the length of the integration element * * The outer normal is given with respect to the \ref geometry(). */ GlobalCoordinate integrationOuterNormal(const LocalCoordinate &local) const { return (unitOuterNormal(local) *= geometry().integrationElement(local)); } /** \brief Unit outer normal at the center of the intersection * * The outer normal is given with respect to the \ref geometry(). */ GlobalCoordinate centerUnitOuterNormal () const { return unitOuterNormal(ReferenceElements::general(type()).position(0,0)); } /** * \brief Return a copy of the intersection with inside and outside switched. */ Intersection flip() const { return Intersection(glue_,i_); } #ifdef QUICKHACK_INDEX typedef typename GridGlue::IndexType IndexType; IndexType index() const { return i_->index_; } #endif private: friend class IntersectionIndexSet; /* M E M B E R V A R I A B L E S */ /// @brief the grid glue entity this is built on const GridGlue* glue_; /// @brief the underlying remote intersection const IntersectionData* i_; }; } // end namespace GridGlue } // end namespace Dune #endif // DUNE_GRIDGLUE_ADAPTER_INTERSECTION_HH dune-grid-glue-2.9.0/dune/grid-glue/adapter/intersectionindexset.hh000066400000000000000000000034411435125002300253540ustar00rootroot00000000000000// SPDX-FileCopyrightInfo: Copyright © DUNE Project contributors, see file LICENSE.md in module root // SPDX-License-Identifier: LGPL-3.0-or-later OR LicenseRef-GPL-2.0-only-with-dune-grid-glue-exception #ifndef DUNE_GRIDGLUE_ADAPTER_INTERSECTIONINDEXSET_HH #define DUNE_GRIDGLUE_ADAPTER_INTERSECTIONINDEXSET_HH #include #include #ifndef ONLY_SIMPLEX_INTERSECTIONS // we currently support only one intersection type. If we want to support more, // we have to think about the semantics of our IndexSet #error Not Implemented #endif namespace Dune { namespace GridGlue { template class IntersectionIndexSet { friend class ::Dune::GridGlue::GridGlue; typedef ::Dune::GridGlue::GridGlue GridGlue; public: /** \brief The type used for the indices */ typedef typename GridGlue::IndexType IndexType; /** \brief The type used for the size */ typedef size_t SizeType; /** @brief Map Dune::GridGlue::Intersection to index. */ template IndexType index (const Intersection & i) const { return i.i_->index_; } /** @brief Return total number of intersections. */ SizeType size () const { return glue_->size(); } private: /** construct from a given GridGlue object */ IntersectionIndexSet(const GridGlue * g) : glue_(g) {} const GridGlue * glue_; }; } // end namespace GridGlue } // end namespace Dune #endif // DUNE_GRIDGLUE_ADAPTER_INTERSECTIONINDEXSET_HH dune-grid-glue-2.9.0/dune/grid-glue/adapter/intersectioniterator.hh000066400000000000000000000035051435125002300253630ustar00rootroot00000000000000// -*- tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- // vi: set et ts=4 sw=2 sts=2: // SPDX-FileCopyrightInfo: Copyright © DUNE Project contributors, see file LICENSE.md in module root // SPDX-License-Identifier: LGPL-3.0-or-later OR LicenseRef-GPL-2.0-only-with-dune-grid-glue-exception /** @file @brief Implement iterators over GridGlue intersections @author Christian Engwer */ #ifndef DUNE_GRIDGLUE_ADAPTER_INTERSECTIONITERATOR_HH #define DUNE_GRIDGLUE_ADAPTER_INTERSECTIONITERATOR_HH #include namespace Dune { namespace GridGlue { /** @todo documentation */ template class IntersectionIterator : public Dune::ForwardIteratorFacade< IntersectionIterator, const Intersection > { public: typedef ::Dune::GridGlue::GridGlue GridGlue; typedef ::Dune::GridGlue::Intersection Intersection; IntersectionIterator(const GridGlue * glue, unsigned int i) : glue_(glue), index_(i), intersection_(glue_, & glue_->intersections_[index_]) {} const Intersection& dereference() const { assert(("never dereference the end iterator" && index_ != glue_->index__sz)); return intersection_; } void increment() { intersection_ = Intersection(glue_, & glue_->intersections_[++index_]); } bool equals(const IntersectionIterator& iter) const { return iter.index_ == index_; } private: const GridGlue* glue_; unsigned int index_; Intersection intersection_; }; } // end namespace GridGlue } // end namespace Dune #endif // DUNE_GRIDGLUE_ADAPTER_INTERSECTIONITERATOR_HH dune-grid-glue-2.9.0/dune/grid-glue/adapter/rangegenerators.hh000066400000000000000000000053311435125002300242700ustar00rootroot00000000000000// SPDX-FileCopyrightInfo: Copyright © DUNE Project contributors, see file LICENSE.md in module root // SPDX-License-Identifier: LGPL-3.0-or-later OR LicenseRef-GPL-2.0-only-with-dune-grid-glue-exception #ifndef DUNE_GRIDGLUE_ADAPTER_RANGEGENERATORS_HH #define DUNE_GRIDGLUE_ADAPTER_RANGEGENERATORS_HH #include namespace Dune { namespace GridGlue { /** * Static tag representing reversal of in- and outside of intersecions. */ template struct Reverse : std::integral_constant { typedef Reverse type; constexpr Reverse operator!() const { return {}; } }; #ifdef DOXYGEN /** * Static tag representing reversal of in- and outside of intersections. * \relates Reverse */ const Reverse reversed; /** * \brief Iterate over all intersections of a GridGlue. * * This function returns an object representing the range of intersections * with respect to the GridGlue glue. Its main purpose is to enable iteration * over these intersections by means of a range-based for loop: * * \code * // Iterate over all intersections of a GridGlue in various ways * using Dune::GridGlue::GridGlue; * using Dune::GridGlue::Reverse; * using Dune::GridGlue::reversed; * * GridGlue<...> glue; * for (const auto& in : intersections(glue)) { ... } * for (const auto& in : intersections(glue, reversed)) { ... } * for (const auto& in : intersections(glue, !reversed)) { ... } * for (const auto& in : intersections(glue, Reversed())) { ... } * \endcode * * The in- and outside of the intersection can be reversed by passing * `reversed` as the second argument. The fourth form can be used in * case a template parameter for reversal is required. * * \since dune-common 2.4 * \relatesalso Dune::GridGlue::GridGlue * \param glue GridGlue to obtain the intersections from * \param reverse Tag to indicate reversal of in- and outside of intersections * \returns an unspecified object that is guaranteed to fulfill the interface * of IteratorRange and that can be iterated over using a range-based * for loop. * \see Dune::GridGlue::Intersection */ template<...> IteratorRange<...> intersections(const GridGlue<...>& glue, const Reverse<...>& reverse = !reversed); #else namespace { const Reverse reversed = {}; } /* namespace */ template IteratorRange< typename GridGlue::template IntersectionIterator > intersections(const GridGlue& glue, const Reverse& = {}) { const static int side = reverse ? 1 : 0; return {glue.template ibegin(), glue.template iend()}; } #endif // DOXYGEN } /* namespace GridGlue */ } /* namespace Dune */ #endif dune-grid-glue-2.9.0/dune/grid-glue/common/000077500000000000000000000000001435125002300204275ustar00rootroot00000000000000dune-grid-glue-2.9.0/dune/grid-glue/common/CMakeLists.txt000066400000000000000000000006631435125002300231740ustar00rootroot00000000000000# SPDX-FileCopyrightInfo: Copyright © DUNE Project contributors, see file LICENSE.md in module root # SPDX-License-Identifier: LGPL-3.0-or-later OR LicenseRef-GPL-2.0-only-with-dune-grid-glue-exception #install headers install(FILES areawriter.hh areawriter_impl.hh crossproduct.hh projection.hh projection_impl.hh projectionwriter.hh projectionwriter_impl.hh ringcomm.hh DESTINATION include/dune/grid-glue/common) dune-grid-glue-2.9.0/dune/grid-glue/common/areawriter.hh000066400000000000000000000031231435125002300231140ustar00rootroot00000000000000// SPDX-FileCopyrightInfo: Copyright © DUNE Project contributors, see file LICENSE.md in module root // SPDX-License-Identifier: LGPL-3.0-or-later OR LicenseRef-GPL-2.0-only-with-dune-grid-glue-exception #ifndef DUNE_GRIDGLUE_COMMON_AREAWRITER_HH #define DUNE_GRIDGLUE_COMMON_AREAWRITER_HH #include #include namespace Dune { namespace GridGlue { template void write_glue_area_vtk(const Glue& glue, std::ostream& out); template void write_glue_area_vtk(const Glue& glue, const std::string& filename); /** * Write area covered by grid glue. * * Write a VTK file for each side that indicate where the grid glue * intersections are defined. A cell data field is provided that gives * the relative area that is covered by glue intersections: if the value * is zero no intersections are defined on the element, if the value is one * the entire element should be covered (provided the glue is injective). * Note that also values greater than one can be reached if the mapping is * not injective. * * This method is intended to be used for debugging purposes only. * * \param glue GridGlue for which the coverage by intersections should * be computed * \param base prefix of filenames to use. The generated files are named * base-inside.vtk and * base-outside.vtk. */ template void write_glue_areas_vtk(const Glue& glue, const std::string& base); } /* namespace GridGlue */ } /* namespace Dune */ #include "areawriter_impl.hh" #endif dune-grid-glue-2.9.0/dune/grid-glue/common/areawriter_impl.hh000066400000000000000000000103131435125002300241340ustar00rootroot00000000000000// SPDX-FileCopyrightInfo: Copyright © DUNE Project contributors, see file LICENSE.md in module root // SPDX-License-Identifier: LGPL-3.0-or-later OR LicenseRef-GPL-2.0-only-with-dune-grid-glue-exception #include #include #include #include #include namespace Dune { namespace GridGlue { namespace AreaWriterImplementation { template struct FacetLayout { bool contains(Dune::GeometryType gt) const { return gt.dim() == dimgrid - 1; } }; template void write_facet_geometry(const GridView& gv, std::ostream& out) { using Coordinate = Dune::FieldVector; std::vector corners; for (const auto& facet : facets(gv)) { const auto geometry = facet.geometry(); for (int i = 0; i < geometry.corners(); ++i) { /* VTK always needs 3-dim coordinates... */ const auto c0 = geometry.corner(i); Coordinate c1; for (int d = 0; d < GridView::dimensionworld; ++d) c1[d] = c0[d]; for (int d = GridView::dimensionworld; d < Coordinate::dimension; ++d) c1[d] = double(0); corners.push_back(c1); } } { out << "DATASET UNSTRUCTURED_GRID\n" << "POINTS " << corners.size() << " double\n"; for (const auto& c : corners) out << c << "\n"; } { out << "CELLS " << gv.size(1) << " " << (gv.size(1) + corners.size()) << "\n"; std::size_t c = 0; for (const auto& facet : facets(gv)) { const auto geometry = facet.geometry(); out << geometry.corners(); for (int i = 0; i < geometry.corners(); ++i, ++c) out << " " << c; out << "\n"; } } { out << "CELL_TYPES " << gv.size(1) << "\n"; for (const auto& facet : facets(gv)) { const auto type = facet.type(); if (type.isVertex()) out << "1\n"; else if (type.isLine()) out << "2\n"; else if (type.isTriangle()) out << "5\n"; else if (type.isQuadrilateral()) out << "9\n"; else if (type.isTetrahedron()) out << "10\n"; else DUNE_THROW(Dune::Exception, "Unhandled geometry type"); } } } } /* namespace AreaWriterImplementation */ template void write_glue_area_vtk(const Glue& glue, std::ostream& out) { using GridView = typename std::decay< decltype(glue.template gridView()) >::type; using Mapper = Dune::MultipleCodimMultipleGeomTypeMapper; using ctype = typename GridView::ctype; const GridView gv = glue.template gridView(); Mapper mapper(gv); std::vector coveredArea(mapper.size(), ctype(0)); std::vector totalArea(mapper.size(), ctype(1)); for (const auto& in : intersections(glue, Reverse())) { const auto element = in.inside(); const auto index = mapper.subIndex(element, in.indexInInside(), 1); coveredArea[index] += in.geometryInInside().volume(); const auto& refElement = Dune::ReferenceElements::general(element.type()); const auto& subGeometry = refElement.template geometry<1>(in.indexInInside()); totalArea[index] = subGeometry.volume(); } for (std::size_t i = 0; i < coveredArea.size(); ++i) coveredArea[i] /= totalArea[i]; out << "# vtk DataFile Version 2.0\n" << "Filename: Glue Area\n" << "ASCII\n"; AreaWriterImplementation::write_facet_geometry(gv, out); out << "CELL_DATA " << coveredArea.size() << "\n" << "SCALARS CoveredArea double 1\n" << "LOOKUP_TABLE default\n"; for (const auto& value : coveredArea) out << value << "\n"; } template void write_glue_area_vtk(const Glue& glue, const std::string& filename) { std::ofstream out(filename.c_str()); write_glue_area_vtk(glue, out); } template void write_glue_areas_vtk(const Glue& glue, const std::string& base) { { std::string filename = base; filename += "-inside.vtk"; write_glue_area_vtk<0>(glue, filename); } { std::string filename = base; filename += "-outside.vtk"; write_glue_area_vtk<1>(glue, filename); } } } /* namespace GridGlue */ } /* namespace Dune */ dune-grid-glue-2.9.0/dune/grid-glue/common/crossproduct.hh000066400000000000000000000016121435125002300235020ustar00rootroot00000000000000// SPDX-FileCopyrightInfo: Copyright © DUNE Project contributors, see file LICENSE.md in module root // SPDX-License-Identifier: LGPL-3.0-or-later OR LicenseRef-GPL-2.0-only-with-dune-grid-glue-exception #ifndef DUNE_GRIDGLUE_COMMON_CROSSPRODUCT_HH #define DUNE_GRIDGLUE_COMMON_CROSSPRODUCT_HH 1 namespace Dune { namespace GridGlue { /** * \brief compute cross product * * \return a × b */ template static Dune::FieldVector crossProduct(const Dune::FieldVector& a, const Dune::FieldVector& b) { if (dim!=3) DUNE_THROW(Dune::NotImplemented, "crossProduct does not work for dimension " << dim); Dune::FieldVector c; c[0] = a[1]*b[2] - a[2]*b[1]; c[1] = a[2]*b[0] - a[0]*b[2]; c[2] = a[0]*b[1] - a[1]*b[0]; return c; } } /* namespace GridGlue */ } /* namespace Dune */ #endif dune-grid-glue-2.9.0/dune/grid-glue/common/projection.hh000066400000000000000000000232711435125002300231310ustar00rootroot00000000000000// SPDX-FileCopyrightInfo: Copyright © DUNE Project contributors, see file LICENSE.md in module root // SPDX-License-Identifier: LGPL-3.0-or-later OR LicenseRef-GPL-2.0-only-with-dune-grid-glue-exception #ifndef DUNE_GRIDGLUE_COMMON_PROJECTIONHELPER2_HH #define DUNE_GRIDGLUE_COMMON_PROJECTIONHELPER2_HH #include #include #include namespace Dune { namespace GridGlue { /** * \brief Projection of a line (triangle) on another line (triangle). * * This class implements methods to project a line (2d) or triangle (3d) on * another line (triangle) along normal field given by values at the corners. */ template class Projection { public: /** * \brief Intersection between two edges of a triangle. * * See also \ref Projection::edgeIntersections() */ struct EdgeIntersection { /** * \brief Edge numbers in image and preimage triangle. */ std::array edge; /** * \brief Local coordinates of intersection and distance along normals. * * Local coordinate of intersection point in barycentric coordinates with * respect to image and preimage triangle. */ std::array local; }; /** * \brief dimension of coordinates */ constexpr static unsigned dim = Coordinate::dimension; /** * \brief maximum number of edge-edge intersections * * See also \seealso edgeIntersections() */ constexpr static unsigned maxEdgeIntersections = dim == 3 ? 9 : 0; static_assert(dim == 2 || dim == 3, "Projection only implemented for dim=2 or dim=3"); /** * \brief Scalar type. */ typedef typename Coordinate::field_type Field; /** * \brief List of corner images. * * This type is used to return the list of images Φ(xᵢ) of the corners xᵢ * in barycentric coordinates with respect to the image simplex. * The last entry is used to return the (signed) distance along the normal. */ typedef std::array Images; /** * List of corner preimages. * * This is used as \ref Images, but for the preimages Φ⁻¹(yᵢ) of the corners * yᵢ of the image simplex. */ typedef Images Preimages; private: /** * \brief Overlap allowed for the projection to be considered valid. */ const Field m_overlap; /** * \brief Maximum value for scalar product ν(x)·ν(Φ(x)) of normals * * The normals at x and Φ(x) are expected * to be opposing to some degree. This value is used to indicate * how much they are allowed to deviate from this by ensuring that * ν(x)·ν(Φ(x)) ≤ m_max_normal_product. */ const Field m_max_normal_product; /** * \brief epsilon used for floating-point comparisons. * * See also \seealso epsilon(Field) */ Field m_epsilon = Field(1e-12); /** \copydoc images() */ std::tuple m_images; /** \copydoc success() */ std::tuple, std::bitset > m_success; /** \copydoc numberOfEdgeIntersections() */ unsigned m_number_of_edge_intersections; /** \copydoc edgeIntersections() */ std::array m_edge_intersections; /** * \brief Forward projection successful for all corners xᵢ * * If true, the forward projection was successful, that is * Φ(xᵢ) could be computed for all xᵢ. * * \warning Note that this only means Φ(xᵢ) lie in the plane spanned by the * image simplex which is required to compute the inverse * projection Φ⁻¹(yᵢ). The bitset \ref m_success should be used to * check whether the projection is feasible. */ bool m_projection_valid; /** * \brief Compute forward projection Φ(xᵢ) for all xᵢ. * * \copydetails project */ template void doProjection(const std::tuple& corners, const std::tuple& normals); /** * \brief Compute inverse projection Φ⁻¹(yᵢ) for all yᵢ. * * \note This requires the forward projection was already computed by * \ref doProjection. * * \copydetails project */ template void doInverseProjection(const std::tuple& corners, const std::tuple& normals); /** * \brief Compute intersections between projected edges and edges of the image simplex. * * \note This requires the forward and inverse projections were already * computed by \ref doProjection and \ref doInverseProjection. * * \copydetails project */ template void doEdgeIntersection(const std::tuple& corners, const std::tuple& normals); /** * \brief Check if projection is feasible. * * Given a point x, its image px in barycentric * coordinates together with the signed distance along the normal at * x in the last entry of px and the corners and * normals of the image simplex given in corners and * normals, this method checks that the projection is feasible. * This means: * *
    *
  • px is inside the image simplex
  • *
  • The signed distance given is not smaller than -\ref m_overlap
  • *
  • The signed distance along the normal at px is not smaller than -\ref m_overlap
  • *
  • The angle between the normals at x and px is at least \ref m_minimum_angle_between_normals *
* * \param x euclidean coordinate of point to project * \param nx outer normal ν(x) at x * \param px barycentric coordinates of projected point; * last entry is distance along normal * \param corners corners of image simplex * \param normals normals of image simplex * \return true if the projection is feasible, false otherwise. */ template inline bool projectionFeasible(const Coordinate& x, const Coordinate& nx, const Coordinate& px, const Corners& corners, const Normals& normals) const; public: /** * \param overlap allowed overlap * \param max_normal_product maximum value for scalar product ν(x)·ν(Φ(x)) */ Projection(const Field overlap = Field(0), const Field max_normal_product = Field(-0.1)); /** * \brief Set epsilon used for floating-point comparisons. * * \param epsilon new epsilon used for floating-point comaprisons */ void epsilon(const Field epsilon); /** * \brief Do the actual projection. * * \param corners euclidean coordinates of corners of preimage and image * \param normals normals at corners of preimage and image * \tparam Corners list of corner coordinates, should be * std::vector or * std::array * \tparam Normals list of corner normals, should be * std::vector or * std::array */ template void project(const std::tuple& corners, const std::tuple& normals); /** * \brief Images and preimages of corners. * * Returns a pair of arrays. The first array contains the images * Φ(xᵢ) of the corners xᵢ. The second * array contains the preimages Φ⁻¹(yⱼ) of the * corners yⱼ. * * The first d-1 values are the barycentric coordinates with respect * to the corners of the (pre)image, the last value is the signed * distance between the projected point and its (pre)image along the * normal at the projected preimage corner or the inverse projected * image corner. * * \note \ref project() must be called before this method can be used. * * \returns pair of arrays giving ((Φ(xᵢ))ᵢ, (Φ⁻¹(yⱼ))ⱼ) in barycentric coordinates * * \ref success() */ const std::tuple& images() const { return m_images; } /** * \brief Indicate whether projection (inverse projection) is valid for each corner or not. * * Returns a pair of bitsets. The first bitset indicates if the projection * Φ(xᵢ) is valid for each corner xᵢ, that is * that Φ(xᵢ) could be computed and lies in the image simplex. * The second bitset indicates the same for the inverse projection * Φ⁻¹(yⱼ) for the corners yⱼ. * * \note \ref project() must be called before this method can be used. * * \returns pair of bitsets indicating success of (inverse) projection at * corners xᵢ (yⱼ) */ const std::tuple, std::bitset >& success() const { return m_success; } /** * \brief Number of edge intersections. * * \note \ref project() must be called before this method can be used. * * \ref edgeIntersections() */ unsigned numberOfEdgeIntersections() const { return m_number_of_edge_intersections; } /** * \brief Edge-edge intersections. * * \note \ref project() must be called before this method can be used. * * \warning Only the first \ref numberOfEdgeIntersections() entries are valid * edge intersections. */ const std::array& edgeIntersections() const { return m_edge_intersections; } }; } /* namespace GridGlue */ } /* namespace Dune */ #include "projection_impl.hh" #endif dune-grid-glue-2.9.0/dune/grid-glue/common/projection_impl.hh000066400000000000000000000363111435125002300241510ustar00rootroot00000000000000// SPDX-FileCopyrightInfo: Copyright © DUNE Project contributors, see file LICENSE.md in module root // SPDX-License-Identifier: LGPL-3.0-or-later OR LicenseRef-GPL-2.0-only-with-dune-grid-glue-exception #include #include namespace Dune { namespace GridGlue { namespace ProjectionImplementation { /** * Return corner coordinates of a simplex. * * Given the number c of a corner, this function returns * the coordinate of the cth corner of the standard * simplex with the same dimension as Coordinate. * * \param c corner number * \returns coordinate of cth corner of the standard simplex */ template inline Coordinate corner(unsigned c) { Coordinate x(Field(0)); if (c == 0) return x; x[c-1] = Field(1); return x; } /** * Translate edge to corner numbers. * * Given the number edge of an edge of a triangle, this * function returns the number of the corners belonging to it. * * \param edge edge number of a triangle * \return numbers of corners of the edge */ inline std::pair edgeToCorners(unsigned edge) { switch(edge) { case 0: return {0, 1}; case 1: return {0, 2}; case 2: return {1, 2}; } DUNE_THROW(Dune::Exception, "Unexpected edge number."); } /** * Convert barycentric coordinates to euclidian coordinates. * * This function converts barycentric coordinates x with respect * to the triangle with corners corners to euclidian coordinates. * For the result y the following equation holds: * yᵢ = (cornersᵢ₊₁ - corners₀) xᵢ * * Note that this can also be for linear interpolation of normals given on the * corners, but this does not preserve the norm (e.g. for unit normals). * * \param x barycentric coordinates * \param corners coordinates or normals at the corners * \return euclidian coordinates or interpolated normal */ template inline typename Corners::value_type interpolate(const Coordinate& x, const Corners& corners) { auto y = corners[0]; for (unsigned i = 0; i < corners.size() - 1; ++i) y.axpy(x[i], corners[i+1] - corners[0]); return y; } /** * Interpolate between unit normals on corners of a simplex. * * This functions interpolates between unit normals given on corners of a * simplex using linear interpolation. * * \param x barycentric coordinates * \param normals unit normals at corners * \return unit normal at x * \seealso interpolate(const Coordinate&, const Corners&) */ template inline typename Normals::value_type interpolate_unit_normals(const Coordinate& x, const Normals& normals) { auto n = interpolate(x, normals); n /= n.two_norm(); return n; } /** * Check if the point x is inside the standard simplex. * * This functions checks if the point x is in the inside * (or on the boundary) of the standard simplex, that is * xᵢ ≥ 0 and ∑ xᵢ ≤ 1. * * \param x coordinates of point to check * \param epsilon tolerance used for floating-point comparisions * \return true if x is inside, false otherwise */ template inline bool inside(const Coordinate& x, const Field& epsilon) { const unsigned dim = Coordinate::dimension; Field sum(0); for (unsigned i = 0; i < dim-1; ++i) { if (x[i] < -epsilon) return false; sum += x[i]; } /* If any xᵢ is NaN, sum will be NaN and this comparison false! */ if (sum <= Field(1) + epsilon) return true; return false; } } /* namespace ProjectionImplementation */ template Projection ::Projection(const Field overlap, const Field max_normal_product) : m_overlap(overlap) , m_max_normal_product(max_normal_product) { /* Nothing. */ } template void Projection ::epsilon(const Field epsilon) { m_epsilon = epsilon; } template template void Projection ::doProjection(const std::tuple& corners, const std::tuple& normals) { /* Try to obtain Φ(xᵢ) for each corner xᵢ of the preimage triangle. * This means solving a linear system of equations * Φ(xᵢ) = (1-α-β) y₀ + α y₁ + β y₂ = xᵢ + δ nᵢ * or α (y₁ - y₀) + β (y₂ - y₀) - δ nᵢ = xᵢ - y₀ * to obtain the barycentric coordinates (α, β) of Φ(xᵢ) in the image * triangle and the distance δ. * * In the matrix m corresponding to the system, only the third column and the * right-hand side depend on i. The first two columns can be assembled before * and reused. */ using namespace ProjectionImplementation; using std::get; typedef Dune::FieldMatrix Matrix; Matrix m; const auto& origin = get<0>(corners); const auto& origin_normals = get<0>(normals); const auto& target = get<1>(corners); const auto& target_normals = get<1>(normals); auto& images = get<0>(m_images); auto& success = get<0>(m_success); /* directionsᵢ = (yᵢ - y₀) / ||yᵢ - y₀|| * These are the first to columns of the system matrix; the rescaling is done * to ensure all columns have a comparable norm (the last has the normal with norm 1. */ std::array directions; std::array scales; /* estimator for the diameter of the target face */ Field scaleSum(0); for (unsigned i = 0; i < dim-1; ++i) { directions[i] = target[i+1] - target[0]; scales[i] = directions[i].infinity_norm(); directions[i] /= scales[i]; scaleSum += scales[i]; } for (unsigned i = 0; i < dim-1; ++i) { for (unsigned j = 0; j < dim; ++j) { m[j][i] = directions[i][j]; } } m_projection_valid = true; success.reset(); /* Now project xᵢ for each i */ for (unsigned i = 0; i < origin.size(); ++i) { for (unsigned j = 0; j < dim; ++j) m[j][dim-1] = origin_normals[i][j]; const Coordinate rhs = origin[i] - target[0]; try { /* y = (α, β, δ) */ auto& y = images[i]; m.solve(y, rhs); for (unsigned j = 0; j < dim-1; ++j) y[j] /= scales[j]; /* Solving gave us -δ as the term is "-δ nᵢ". */ y[dim-1] *= Field(-1); /* If the forward projection is too far in the wrong direction * then this might result in artificial inverse projections or * edge intersections. To prevent these wrong cases but not * dismiss feasible intersections, the projection is dismissed * if the forward projection is further than two times the * approximate diameter of the image triangle. */ if(y[dim-1] < -2*scaleSum) { success.set(i,false); m_projection_valid = false; return; } const bool feasible = projectionFeasible(origin[i], origin_normals[i], y, target, target_normals); success.set(i, feasible); } catch (const Dune::FMatrixError&) { success.set(i, false); m_projection_valid = false; } } } template template void Projection ::doInverseProjection(const std::tuple& corners, const std::tuple& normals) { /* Try to obtain Φ⁻¹(yᵢ) for each corner yᵢ of the image triangle. * Instead of solving the problem directly (which would lead to * non-linear equations), we make use of the forward projection Φ * which projects the preimage triangle on the plane spanned by the * image triangle. The inverse projection is then given by finding * the barycentric coordinates of yᵢ with respect to the triangle * with the corners Φ(xᵢ). This way we only have to solve linear * equations. */ using namespace ProjectionImplementation; using std::get; typedef Dune::FieldMatrix Matrix; typedef Dune::FieldVector Vector; /* The inverse projection can only be computed if the forward projection * managed to project all xᵢ on the plane spanned by the yᵢ */ if (!m_projection_valid) { get<1>(m_success).reset(); return; } const auto& images = get<0>(m_images); const auto& target_corners = get<1>(corners); auto& preimages = get<1>(m_images); auto& success = get<1>(m_success); std::array v; for (unsigned i = 0; i < dim-1; ++i) { v[i] = interpolate(images[i+1], target_corners); v[i] -= interpolate(images[0], target_corners); } Matrix m; for (unsigned i = 0; i < dim-1; ++i) { for (unsigned j = 0; j < dim-1; ++j) { m[i][j] = v[i]*v[j]; } } for (unsigned i = 0; i < dim; ++i) { /* Convert yᵢ to barycentric coordinates with respect to Φ(xⱼ) */ v[dim-1] = target_corners[i]; v[dim-1] -= interpolate(images[0], target_corners); Vector rhs, z; for (unsigned j = 0; j < dim-1; ++j) rhs[j] = v[dim-1]*v[j]; m.solve(z, rhs); for (unsigned j = 0; j < dim-1; ++j) preimages[i][j] = z[j]; /* Calculate distance along normal direction */ const auto x = interpolate(z, get<0>(corners)); preimages[i][dim-1] = (x - target_corners[i]) * get<1>(normals)[i]; /* Check y_i lies inside the Φ(xⱼ) */ const bool feasible = projectionFeasible(target_corners[i], get<1>(normals)[i], preimages[i], get<0>(corners), get<0>(normals)); success.set(i, feasible); } } template template void Projection ::doEdgeIntersection(const std::tuple& corners, const std::tuple& normals) { using namespace ProjectionImplementation; using std::get; m_number_of_edge_intersections = 0; /* There are no edge intersections for 2d, only for 3d */ if (dim != 3) return; /* There are no edge intersections * - when the projection is invalid, * - when the projected triangle lies fully in the target triangle, * - or when the target triangle lies fully in the projected triangle. */ if (!m_projection_valid || get<0>(m_success).all() || get<1>(m_success).all()) { return; } const auto& images = get<0>(m_images); const auto& ys = get<1>(corners); /* Intersect line through Φ(xᵢ), Φ(xⱼ) with line through yₖ, yₗ: We want α, β ∈ ℝ such that Φ(xᵢ) + α (Φ(xⱼ) - Φ(xᵢ)) = yₖ + β (yₗ - yₖ) or α (Φ(xⱼ)-Φ(xᵢ)) + β (yₗ-yₖ) = yₖ-Φ(xᵢ) To get a 2×2 system of equations, multiply with yₘ-y₀ for m ∈ {1,̣̣2} which are linear indep. (and so the system is equivalent to the original 3×2 system) */ for (unsigned edgex = 0; edgex < dim; ++edgex) { unsigned i, j; std::tie(i, j) = edgeToCorners(edgex); /* Both sides of edgex lie in the target triangle means no edge intersection */ if (get<0>(m_success)[i] && get<0>(m_success)[j]) continue; const auto pxi = interpolate(images[i], ys); const auto pxj = interpolate(images[j], ys); const auto pxjpxi = pxj - pxi; typedef Dune::FieldMatrix Matrix; typedef Dune::FieldVector Vector; for (unsigned edgey = 0; edgey < dim; ++edgey) { unsigned k, l; std::tie(k, l) = edgeToCorners(edgey); /* Both sides of edgey lie in the projected triangle means no edge intersection */ if (get<1>(m_success)[k] && get<1>(m_success)[l]) continue; const auto ykyl = ys[k] - ys[l]; const auto ykpxi = ys[k] - pxi; /* If edges are parallel then the intersection is already computed by vertex projections. */ bool parallel = true; for (unsigned h=0; h<3; h++) parallel &= std::abs(ykyl[(h+1)%3]*pxjpxi[(h+2)%3] - ykyl[(h+2)%3]*pxjpxi[(h+1)%3])<1e-14; if (parallel) continue; Matrix mat; Vector rhs, z; for (unsigned m = 0; m < dim-1; ++m) { const auto ym1y0 = ys[m+1] - ys[0]; mat[m][0] = pxjpxi * ym1y0; mat[m][1] = ykyl * ym1y0; rhs[m] = ykpxi * ym1y0; } try { using std::isfinite; mat.solve(z, rhs); /* If solving the system gives a NaN, the edges are probably parallel. */ if (!isfinite(z[0]) || !isfinite(z[1])) continue; /* Filter out corner (pre)images. We only want "real" edge-edge intersections here. */ if (z[0] < m_epsilon || z[0] > Field(1) - m_epsilon || z[1] < m_epsilon || z[1] > Field(1) - m_epsilon) continue; Coordinate local_x = corner(i); local_x.axpy(z[0], corner(j) - corner(i)); Coordinate local_y = corner(k); local_y.axpy(z[1], corner(l) - corner(k)); /* Make sure the intersection is in the triangle. */ if (!inside(local_x, m_epsilon) || !inside(local_y, m_epsilon)) continue; /* Make sure the intersection respects overlap. */ auto xy = interpolate(local_x, get<0>(corners)); xy -= interpolate(local_y, get<1>(corners)); const auto nx = interpolate_unit_normals(local_x, get<0>(normals)); const auto ny = interpolate_unit_normals(local_y, get<1>(normals)); local_x[dim-1] = -(xy*nx); local_y[dim-1] = xy*ny; if (local_x[dim-1] < -m_overlap-m_epsilon || local_y[dim-1] < -m_overlap-m_epsilon) continue; /* Normals should be opposing. */ if (nx*ny > m_max_normal_product + m_epsilon) continue; /* Intersection is feasible. Store it. */ auto& intersection = m_edge_intersections[m_number_of_edge_intersections++]; intersection = { {{edgex, edgey}}, {{local_x, local_y}} }; } catch(const Dune::FMatrixError&) { /* Edges might be parallel, ignore and continue with next edge */ } } } } template template bool Projection ::projectionFeasible(const Coordinate& x, const Coordinate& nx, const Coordinate& px, const Corners& corners, const Normals& normals) const { using namespace ProjectionImplementation; /* Image must be within simplex. */ if (!inside(px, m_epsilon)) return false; /* Distance along normal must not be smaller than -overlap. */ if (px[dim-1] < -m_overlap-m_epsilon) return false; /* Distance along normal at image must not be smaller than -overlap. */ auto xmy = x; xmy -= interpolate(px, corners); const auto n = interpolate_unit_normals(px, normals); const auto d = xmy * n; if (d < -m_overlap-m_epsilon) return false; /* Normals at x and Φ(x) are opposing. */ if (nx * n > m_max_normal_product + m_epsilon) return false; /* Okay, projection is feasible. */ return true; } template template void Projection ::project(const std::tuple& corners, const std::tuple& normals) { doProjection(corners, normals); doInverseProjection(corners, normals); doEdgeIntersection(corners, normals); } } /* namespace GridGlue */ } /* namespace Dune */ dune-grid-glue-2.9.0/dune/grid-glue/common/projectionwriter.hh000066400000000000000000000041351435125002300243640ustar00rootroot00000000000000// SPDX-FileCopyrightInfo: Copyright © DUNE Project contributors, see file LICENSE.md in module root // SPDX-License-Identifier: LGPL-3.0-or-later OR LicenseRef-GPL-2.0-only-with-dune-grid-glue-exception #ifndef DUNE_GRIDGLUE_COMMON_PROJECTIONWRITER_HH #define DUNE_GRIDGLUE_COMMON_PROJECTIONWRITER_HH #include #include #include namespace Dune { namespace GridGlue { /** * \brief write projection in VTK format * * This file writes the projection information in VTK format to the given output * stream. It is intended to be used for debugging so the details of the output * might change at any time. * * \note This currently only works in 3D! * * \param projection projection result * \param corners corners of the projected triangles * \param normals normals of the projected triangles * \param out output stream */ template void write(const Projection& projection, const Corners& corners, const Normals& normals, std::ostream& out); /** * \brief write projection in VTK format * * This function works the same as \ref write(const Projection&, const Corners&, const Normals&, std::ostream&) * but creates a new file with the given name. */ template void write(const Projection& projection, const Corners& corners, const Normals& normals, const std::string& filename); /** * \brief Print information about the projection to std::cout stream * * This method is mainly intended to be used for debugging. * * \param projection projection result * \param corners corners of the projected triangles * \param normals normals of the projected triangles */ template void print(const Projection& projection, const Corners& corners, const Normals& normals); } /* namespace GridGlue */ } /* namespace Dune */ #include "projectionwriter_impl.hh" #endif dune-grid-glue-2.9.0/dune/grid-glue/common/projectionwriter_impl.hh000066400000000000000000000135101435125002300254020ustar00rootroot00000000000000// SPDX-FileCopyrightInfo: Copyright © DUNE Project contributors, see file LICENSE.md in module root // SPDX-License-Identifier: LGPL-3.0-or-later OR LicenseRef-GPL-2.0-only-with-dune-grid-glue-exception #include namespace Dune { namespace GridGlue { namespace ProjectionWriterImplementation { template void write_points(const Projection& projection, const Corners& corners, std::ostream& out) { using namespace ProjectionImplementation; using std::get; const unsigned other_side = 1 - side; for (const auto& c : get(corners)) out << c << "\n"; for (const auto& i : get(projection.images())) { const auto global = interpolate(i, get(corners)); out << global << "\n"; } } template void write_normals(const Projection& projection, const Normals& normals, std::ostream& out) { using namespace ProjectionImplementation; using std::get; const unsigned other_side = 1 - side; for (const auto& n : get(normals)) out << n << "\n"; for (const auto& x : get(projection.images())) { const auto n = interpolate_unit_normals(x, get(normals)); out << n << "\n"; } } template void write_edge_intersection_points(const Projection& projection, const Corners& corners, std::ostream& out) { using namespace ProjectionImplementation; using std::get; for (std::size_t i = 0; i < projection.numberOfEdgeIntersections(); ++i) { const auto& local = projection.edgeIntersections()[i].local; out << interpolate(local[0], get<0>(corners)) << "\n" << interpolate(local[1], get<1>(corners)) << "\n"; } } template void write_edge_intersection_normals(const Projection& projection, const Normals& normals, std::ostream& out) { using namespace ProjectionImplementation; using std::get; for (std::size_t i = 0; i < projection.numberOfEdgeIntersections(); ++i) { const auto& local = projection.edgeIntersections()[i].local; const auto n0 = interpolate_unit_normals(local[0], get<0>(normals)); const auto n1 = interpolate_unit_normals(local[1], get<1>(normals)); out << n0 << "\n" << n1 << "\n"; } } template void write_success(const Projection& projection, std::ostream& out) { using std::get; out << side << "\n"; const auto& success = get(projection.success()); for (std::size_t i = 0; i < success.size(); ++i) out << (success[i] ? "1\n" : "0\n"); } } /* namespace ProjectionWriterImplementation */ template void write(const Projection& projection, const Corners& corners, const Normals& normals, std::ostream& out) { using namespace ProjectionWriterImplementation; const auto numberOfEdgeIntersections = projection.numberOfEdgeIntersections(); const auto nPoints = 12 + 2 * numberOfEdgeIntersections; out << "# vtk DataFile Version2.0\n" << "Filename: projection\n" << "ASCII\n" << "DATASET UNSTRUCTURED_GRID\n" << "POINTS " << nPoints << " double\n"; write_points<0>(projection, corners, out); write_points<1>(projection, corners, out); write_edge_intersection_points(projection, corners, out); out << "CELLS " << (8 + numberOfEdgeIntersections) << " " << (26 + 3 * numberOfEdgeIntersections) << "\n"; out << "3 0 1 2\n" "2 0 3\n" "2 1 4\n" "2 2 5\n" << "3 6 7 8\n" "2 6 9\n" "2 7 10\n" "2 8 11\n"; for (std::size_t i = 0; i < numberOfEdgeIntersections; ++i) out << "2 " << (12 + 2*i) << " " << (12 + 2*i + 1) << "\n"; out << "CELL_TYPES " << (8 + numberOfEdgeIntersections) << "\n" "5\n3\n3\n3\n" "5\n3\n3\n3\n"; for (std::size_t i = 0; i < numberOfEdgeIntersections; ++i) out << "3\n"; out << "CELL_DATA " << (8 + numberOfEdgeIntersections) << "\n"; out << "SCALARS success int 1\n" << "LOOKUP_TABLE success\n"; write_success<0>(projection, out); write_success<1>(projection, out); for (std::size_t i = 0; i < numberOfEdgeIntersections; ++i) out << "2\n"; out << "LOOKUP_TABLE success 2\n" << "1.0 0.0 0.0 1.0\n" << "0.0 1.0 0.0 1.0\n"; out << "POINT_DATA " << nPoints << "\n" << "NORMALS normals double\n"; write_normals<0>(projection, normals, out); write_normals<1>(projection, normals, out); write_edge_intersection_normals(projection, normals, out); } template void write(const Projection& projection, const Corners& corners, const Normals& normals, const std::string& filename) { std::ofstream out(filename.c_str()); write(projection, corners, normals, out); } template void print(const Projection& projection, const Corners& corners, const Normals& normals) { using namespace ProjectionWriterImplementation; std::cout << "Side 0 corners and images:\n"; write_points<0>(projection, corners, std::cout); std::cout << "Side 0 success:\n"; write_success<0>(projection, std::cout); std::cout << "Side 1 corners and images:\n"; write_points<1>(projection, corners, std::cout); std::cout << "Side 1 success:\n"; write_success<1>(projection, std::cout); std::cout << "Side 0 normals and projected normals:\n"; write_normals<0>(projection, normals, std::cout); std::cout << "Side 1 normals and projected normals:\n"; write_normals<1>(projection, normals, std::cout); std::cout << projection.numberOfEdgeIntersections() << " edge intersections:\n"; write_edge_intersection_points(projection, corners, std::cout); } } /* namespace GridGlue */ } /* namespace Dune */ dune-grid-glue-2.9.0/dune/grid-glue/common/ringcomm.hh000066400000000000000000000220071435125002300225640ustar00rootroot00000000000000// -*- tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- // vi: set et ts=4 sw=2 sts=2: // SPDX-FileCopyrightInfo: Copyright © DUNE Project contributors, see file LICENSE.md in module root // SPDX-License-Identifier: LGPL-3.0-or-later OR LicenseRef-GPL-2.0-only-with-dune-grid-glue-exception /* IMPLEMENTATION OF CLASS G R I D G L U E */ /** \todo Implement MPI Status check with exception handling */ #define CheckMPIStatus(A,B) {} #include #include #include #include #include #include namespace Dune { namespace Parallel { namespace Impl { /** \brief traits class to provide some basic information about how to send different C++ types */ template struct MPITypeInfo {}; template<> struct MPITypeInfo< int > { static const unsigned int size = 1; static inline MPI_Datatype getType() { return MPI_INT; } }; template struct MPITypeInfo< Dune::FieldVector > { static const unsigned int size = N; static inline MPI_Datatype getType() { return Dune::MPITraits::getType(); } }; template<> struct MPITypeInfo< unsigned int > { static const unsigned int size = 1; static inline MPI_Datatype getType() { return MPI_UNSIGNED; } }; template<> struct MPITypeInfo< Dune::GeometryType > { static const unsigned int size = 1; static inline MPI_Datatype getType() { return Dune::MPITraits< Dune::GeometryType >::getType(); } }; template void MPI_SetVectorSize( std::vector & data, MPI_Status & status) { typedef MPITypeInfo Info; int sz; MPI_Get_count(&status, Info::getType(), &sz); assert(sz%Info::size == 0); data.resize(sz/Info::size); } /** Send std::vector in the ring \return a pair of MPI_Request, as this operation is asynchroneous * data is sent to rankright * from rankleft next is received * messages are send with tag */ template void MPI_SendVectorInRing( std::vector & data, std::vector & next, int tag, int rightrank, int leftrank, MPI_Comm comm, MPI_Request& r_send, MPI_Request& r_recv ) { // mpi status stuff [[maybe_unused]] int result = 0; typedef MPITypeInfo Info; // resize next buffer to maximum size next.resize(next.capacity()); // send data (explicitly send data.size elements) result = MPI_Isend( &(data[0]), Info::size*data.size(), Info::getType(), rightrank, tag, comm, &r_send); // receive up to maximum size. The acutal size is stored in the status result = MPI_Irecv( &(next[0]), Info::size*next.size(), Info::getType(), leftrank, tag, comm, &r_recv); // // check result // MPI_Status status; // CheckMPIStatus(result, status); } template using ptr_t = T*; /* these helper structs are needed as long as we still support C++11, as we can't use variadic lambdas */ template struct call_MPI_SendVectorInRing { std::tuple & remotedata; std::tuple & nextdata; int & tag; int & rightrank; int & leftrank; MPI_Comm & mpicomm; std::array & requests_send; std::array & requests_recv; template void operator()(I i) { MPI_SendVectorInRing( std::get(remotedata), std::get(nextdata), tag+i, rightrank, leftrank, mpicomm, requests_send[i], requests_recv[i]); } }; template struct call_MPI_SetVectorSize { std::tuple & nextdata; std::array & status_recv; template void operator()(I i) { MPI_SetVectorSize(std::get(nextdata),status_recv[i]); } }; template void MPI_AllApply_impl(MPI_Comm mpicomm, OP && op, std::index_sequence indices, const Args&... data) { constexpr std::size_t N = sizeof...(Args); int myrank = 0; int commsize = 0; #if HAVE_MPI MPI_Comm_rank(mpicomm, &myrank); MPI_Comm_size(mpicomm, &commsize); #endif // HAVE_MPI if (commsize > 1) { #ifdef DEBUG_GRIDGLUE_PARALLELMERGE std::cout << myrank << " Start Communication, size " << commsize << std::endl; #endif // get data sizes std::array size({ ((unsigned int)data.size())... }); // communicate max data size std::array maxSize; MPI_Allreduce(&size, &maxSize, size.size(), MPI_UNSIGNED, MPI_MAX, mpicomm); #ifdef DEBUG_GRIDGLUE_PARALLELMERGE std::cout << myrank << " maxSize " << "done... " << std::endl; #endif // allocate receiving buffers with maxsize to ensure sufficient buffer size for communication std::tuple remotedata { Args(maxSize[Indices])... }; // copy local data to receiving buffer remotedata = std::tie(data...); // allocate second set of receiving buffers necessary for async communication std::tuple nextdata { Args(maxSize[Indices])... }; // communicate data in the ring int rightrank = (myrank + 1 + commsize) % commsize; int leftrank = (myrank - 1 + commsize) % commsize; std::cout << myrank << ": size = " << commsize << std::endl; std::cout << myrank << ": left = " << leftrank << " right = " << rightrank << std::endl; // currently the remote data is our own data int remoterank = myrank; for (int i=1; i class Codim0Extractor : public Extractor { public: /* E X P O R T E D T Y P E S A N D C O N S T A N T S */ using Extractor::codim; typedef typename Extractor::ctype ctype; using Extractor::dim; using Extractor::dimworld; typedef typename Extractor::IndexType IndexType; typedef typename GV::Traits::template Codim::Entity Vertex; typedef typename GV::Traits::template Codim<0>::Entity Element; typedef std::function Predicate; // import typedefs from base class typedef typename Extractor::SubEntityInfo SubEntityInfo; typedef typename Extractor::ElementInfo ElementInfo; typedef typename Extractor::VertexInfo VertexInfo; typedef typename Extractor::CoordinateInfo CoordinateInfo; typedef typename Extractor::VertexInfoMap VertexInfoMap; /** * @brief Constructor * @param gv the grid view object to work with * @param predicate a predicate to mark entities for extraction (unary functor returning bool) */ Codim0Extractor(const GV& gv, const Predicate& predicate) : Extractor(gv), positiveNormalDirection_(false) { std::cout << "This is Codim0Extractor on a <" << GV::dimension << "," << GV::dimensionworld << "> grid!" << std::endl; update(predicate); } bool & positiveNormalDirection() { return positiveNormalDirection_; } const bool & positiveNormalDirection() const { return positiveNormalDirection_; } protected: bool positiveNormalDirection_; private: void update(const Predicate& predicate); }; template void Codim0Extractor::update(const Predicate& predicate) { // In this first pass iterate over all entities of codim 0. // Get its corner vertices, find resp. store them together with their associated index, // and remember the indices of the corners. // free everything there is in this object this->clear(); // several counter for consecutive indexing are needed size_t element_index = 0; size_t vertex_index = 0; // a temporary container where newly acquired face // information can be stored at first std::deque temp_faces; // iterate over all codim 0 elements on the grid for (const auto& elmt : elements(this->gv_, Partitions::interior)) { const auto geometry = elmt.geometry(); IndexType eindex = this->cellMapper_.index(elmt); // only do sth. if this element is "interesting" // implicit cast is done automatically if (predicate(elmt,0)) { // add an entry to the element info map, the index will be set properly later this->elmtInfo_.emplace(eindex, ElementInfo(element_index, elmt, 1)); unsigned int numCorners = elmt.subEntities(dim); unsigned int vertex_indices[numCorners]; // index in global vector unsigned int vertex_numbers[numCorners]; // index in parent entity // try for each of the faces vertices whether it is already inserted or not for (unsigned int i = 0; i < numCorners; ++i) { vertex_numbers[i] = i; // get the vertex pointer and the index from the index set const Vertex vertex = elmt.template subEntity(vertex_numbers[i]); IndexType vindex = this->gv_.indexSet().template index(vertex); // if the vertex is not yet inserted in the vertex info map // it is a new one -> it will be inserted now! typename VertexInfoMap::iterator vimit = this->vtxInfo_.find(vindex); if (vimit == this->vtxInfo_.end()) { // insert into the map this->vtxInfo_.emplace(vindex, VertexInfo(vertex_index, vertex)); // remember this vertex' index vertex_indices[i] = vertex_index; // increase the current index vertex_index++; } else { // only remember the vertex' index vertex_indices[i] = vimit->second.idx; } } // flip cell if necessary { switch (int(dim)) { case 0 : break; case 1 : { // The following test only works if the zero-th coordinate is the // one that defines the orientation. A sufficient condition for // this is dimworld == 1 /* assert(dimworld==1); */ bool elementNormalDirection = (geometry.corner(1)[0] < geometry.corner(0)[0]); if ( positiveNormalDirection_ != elementNormalDirection ) { std::swap(vertex_indices[0], vertex_indices[1]); std::swap(vertex_numbers[0], vertex_numbers[1]); } break; } case 2 : { Dune::FieldVector v0 = geometry.corner(1), v1 = geometry.corner(2); v0 -= geometry.corner(0); v1 -= geometry.corner(0); ctype normal_sign = v0[0]*v1[1] - v0[1]*v1[0]; bool elementNormalDirection = (normal_sign < 0); if ( positiveNormalDirection_ != elementNormalDirection ) { std::cout << "swap\n"; if (elmt.type().isCube()) { for (int i = 0; i < (1<subEntities_.resize(element_index); // ...and fill in the data from the temporary containers copy(temp_faces.begin(), temp_faces.end(), this->subEntities_.begin()); // now first write the array with the coordinates... this->coords_.resize(this->vtxInfo_.size()); for (const auto& vinfo : this->vtxInfo_) { // get a pointer to the associated info object CoordinateInfo* current = &this->coords_[vinfo.second.idx]; // store this coordinates index // NEEDED? current->index = vinfo.second.idx; // store the vertex' index for the index2vertex mapping current->vtxindex = vinfo.first; // store the vertex' coordinates under the associated index // in the coordinates array const auto vtx = this->grid().entity(vinfo.second.p); current->coord = vtx.geometry().corner(0); } } } // namespace GridGlue } // namespace Dune #endif // DUNE_GRIDGLUE_EXTRACTORS_CODIM0EXTRACTOR_HH dune-grid-glue-2.9.0/dune/grid-glue/extractors/codim1extractor.hh000066400000000000000000000377221435125002300250010ustar00rootroot00000000000000// -*- tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- // vi: set et ts=4 sw=2 sts=2: // SPDX-FileCopyrightInfo: Copyright © DUNE Project contributors, see file LICENSE.md in module root // SPDX-License-Identifier: LGPL-3.0-or-later OR LicenseRef-GPL-2.0-only-with-dune-grid-glue-exception /* * Filename: codim1extractor.hh * Version: 1.0 * Created on: Jun 23, 2009 * Author: Oliver Sander, Christian Engwer * --------------------------------- * Project: dune-grid-glue * Description: class for grid extractors extracting surface grids * */ /** * @file * @brief Grid extractor class for codim 1 subgrids */ #ifndef DUNE_GRIDGLUE_EXTRACTORS_CODIM1EXTRACTOR_HH #define DUNE_GRIDGLUE_EXTRACTORS_CODIM1EXTRACTOR_HH #include "extractor.hh" #include #include #include #include #include #include namespace Dune { namespace GridGlue { /** * extractor for codim-1 entities (facets) */ template class Codim1Extractor : public Extractor { public: /* E X P O R T E D T Y P E S A N D C O N S T A N T S */ using Extractor::dimworld; using Extractor::dim; using Extractor::codim; using Extractor::cube_corners; typedef typename Extractor::IndexType IndexType; /// @brief compile time number of corners of surface simplices static constexpr int simplex_corners = dim; typedef GV GridView; typedef typename GV::Grid::ctype ctype; typedef Dune::FieldVector Coords; typedef typename GV::Traits::template Codim::Entity Vertex; typedef typename GV::Traits::template Codim<0>::Entity Element; typedef std::function Predicate; // import typedefs from base class typedef typename Extractor::SubEntityInfo SubEntityInfo; typedef typename Extractor::ElementInfo ElementInfo; typedef typename Extractor::VertexInfo VertexInfo; typedef typename Extractor::CoordinateInfo CoordinateInfo; typedef typename Extractor::VertexInfoMap VertexInfoMap; public: /* C O N S T R U C T O R S A N D D E S T R U C T O R S */ /** * @brief Constructor * @param gv the grid view object to work with * @param predicate a predicate to mark entities for extraction (unary functor returning bool) */ Codim1Extractor(const GV& gv, const Predicate& predicate) : Extractor(gv) { std::cout << "This is Codim1Extractor on a <" << dim << "," << dimworld << "> grid!" << std::endl; update(predicate); } private: /** * Extracts a codimension 1 surface from the grid @c g and builds up two arrays * with the topology of the surface written to them. The description of the * surface part that is to be extracted is given in form of a predicate class. * * Assumed that we are in 2D the coords array will have the structure * x0 y0 x1 y1 ... x(n-1) y(n-1) * Values in the @c _indices array then refer to the indices of the coordinates, e.g. * index 1 is associated with the position x1. If the surface consists of triangles * we have always groups of 3 indices describing one triangle. * * @param predicate a predicate that "selects" the faces to add to the surface */ void update(const Predicate& predicate); }; template void Codim1Extractor::update(const Predicate& predicate) { // free everything there is in this object this->clear(); // In this first pass iterate over all entities of codim 0. // For each codim 1 intersection check if it is part of the boundary and if so, // get its corner vertices, find resp. store them together with their associated index, // and remember the indices of the boundary faces' corners. { // several counter for consecutive indexing are needed int simplex_index = 0; int vertex_index = 0; IndexType eindex = 0; // supress warning // needed later for insertion into a std::set which only // works with const references // a temporary container where newly acquired face // information can be stored at first std::deque temp_faces; // iterate over interior codim 0 elements on the grid for (const auto& elmt : elements(this->gv_, Partitions::interior)) { Dune::GeometryType gt = elmt.type(); // if some face is part of the surface add it! if (elmt.hasBoundaryIntersections()) { // add an entry to the element info map, the index will be set properly later, // whereas the number of faces is already known eindex = this->cellMapper_.index(elmt); this->elmtInfo_.emplace(eindex, ElementInfo(simplex_index, elmt, 0)); // now add the faces in ascending order of their indices // (we are only talking about 1-4 faces here, so O(n^2) is ok!) for (const auto& in : intersections(this->gv_, elmt)) { // Stop only at selected boundary faces if (!in.boundary() or !predicate(elmt, in.indexInInside())) continue; const auto& refElement = Dune::ReferenceElements::general(gt); // get the corner count of this face const int face_corners = refElement.size(in.indexInInside(), 1, dim); // now we only have to care about the 3D case, i.e. a triangle face can be // inserted directly whereas a quadrilateral face has to be divided into two triangles switch (face_corners) { case 2 : case 3: { // we have a simplex here // register the additional face(s) this->elmtInfo_.at(eindex).faces++; // add a new face to the temporary collection temp_faces.emplace_back(eindex, in.indexInInside(), #if DUNE_VERSION_NEWER(DUNE_GEOMETRY, 2, 6) Dune::GeometryTypes::simplex(dim-codim) #else Dune::GeometryType(Dune::GeometryType::simplex,dim-codim) #endif ); std::vector > cornerCoords(face_corners); // try for each of the faces vertices whether it is already inserted or not for (int i = 0; i < face_corners; ++i) { // get the number of the vertex in the parent element int vertex_number = refElement.subEntity(in.indexInInside(), 1, i, dim); // get the vertex pointer and the index from the index set const Vertex vertex = elmt.template subEntity(vertex_number); cornerCoords[i] = vertex.geometry().corner(0); IndexType vindex = this->gv_.indexSet().template index(vertex); // remember the vertex' number in parent element's vertices temp_faces.back().corners[i].num = vertex_number; // if the vertex is not yet inserted in the vertex info map // it is a new one -> it will be inserted now! typename VertexInfoMap::iterator vimit = this->vtxInfo_.find(vindex); if (vimit == this->vtxInfo_.end()) { // insert into the map this->vtxInfo_.emplace(vindex, VertexInfo(vertex_index, vertex)); // remember the vertex as a corner of the current face in temp_faces temp_faces.back().corners[i].idx = vertex_index; // increase the current index vertex_index++; } else { // only insert the index into the simplices array temp_faces.back().corners[i].idx = vimit->second.idx; } } // Now we have the correct vertices in the last entries of temp_faces, but they may // have the wrong orientation. We want them to be oriented such that all boundary edges // point in the counterclockwise direction. Therefore, we check the orientation of the // new face and possibly switch the two vertices. FieldVector realNormal = in.centerUnitOuterNormal(); // Compute segment normal FieldVector reconstructedNormal; if (dim==2) // boundary face is a line segment { reconstructedNormal[0] = cornerCoords[1][1] - cornerCoords[0][1]; reconstructedNormal[1] = cornerCoords[0][0] - cornerCoords[1][0]; } else { // boundary face is a triangle FieldVector segment1 = cornerCoords[1] - cornerCoords[0]; FieldVector segment2 = cornerCoords[2] - cornerCoords[0]; reconstructedNormal = crossProduct(segment1, segment2); } reconstructedNormal /= reconstructedNormal.two_norm(); if (realNormal * reconstructedNormal < 0.0) std::swap(temp_faces.back().corners[0], temp_faces.back().corners[1]); // now increase the current face index simplex_index++; break; } case 4 : { assert(dim == 3 && cube_corners == 4); // we have a quadrilateral here std::array vertex_indices; std::array vertex_numbers; // register the additional face(s) (2 simplices) this->elmtInfo_.at(eindex).faces += 2; std::array, 4> cornerCoords; // get the vertex pointers for the quadrilateral's corner vertices // and try for each of them whether it is already inserted or not for (int i = 0; i < cube_corners; ++i) { // get the number of the vertex in the parent element vertex_numbers[i] = refElement.subEntity(in.indexInInside(), 1, i, dim); // get the vertex pointer and the index from the index set const Vertex vertex = elmt.template subEntity(vertex_numbers[i]); cornerCoords[i] = vertex.geometry().corner(0); IndexType vindex = this->gv_.indexSet().template index(vertex); // if the vertex is not yet inserted in the vertex info map // it is a new one -> it will be inserted now! typename VertexInfoMap::iterator vimit = this->vtxInfo_.find(vindex); if (vimit == this->vtxInfo_.end()) { // insert into the map this->vtxInfo_.emplace(vindex, VertexInfo(vertex_index, vertex)); // remember this vertex' index vertex_indices[i] = vertex_index; // increase the current index vertex_index++; } else { // only remember the vertex' index vertex_indices[i] = vimit->second.idx; } } // now introduce the two triangles subdividing the quadrilateral // ATTENTION: the order of vertices given by "orientedSubface" corresponds to the order // of a Dune quadrilateral, i.e. the triangles are given by 0 1 2 and 3 2 1 // add a new face to the temporary collection for the first tri temp_faces.emplace_back(eindex, in.indexInInside(), #if DUNE_VERSION_NEWER(DUNE_GEOMETRY, 2, 6) Dune::GeometryTypes::simplex(dim-codim) #else Dune::GeometryType(Dune::GeometryType::simplex,dim-codim) #endif ); temp_faces.back().corners[0].idx = vertex_indices[0]; temp_faces.back().corners[1].idx = vertex_indices[1]; temp_faces.back().corners[2].idx = vertex_indices[2]; // remember the vertices' numbers in parent element's vertices temp_faces.back().corners[0].num = vertex_numbers[0]; temp_faces.back().corners[1].num = vertex_numbers[1]; temp_faces.back().corners[2].num = vertex_numbers[2]; // Now we have the correct vertices in the last entries of temp_faces, but they may // have the wrong orientation. We want the triangle vertices on counterclockwise order, // when viewed from the outside of the grid. Therefore, we check the orientation of the // new face and possibly switch two vertices. FieldVector realNormal = in.centerUnitOuterNormal(); // Compute segment normal FieldVector reconstructedNormal = crossProduct(cornerCoords[1] - cornerCoords[0], cornerCoords[2] - cornerCoords[0]); reconstructedNormal /= reconstructedNormal.two_norm(); if (realNormal * reconstructedNormal < 0.0) std::swap(temp_faces.back().corners[0], temp_faces.back().corners[1]); // add a new face to the temporary collection for the second tri temp_faces.emplace_back(eindex, in.indexInInside(), #if DUNE_VERSION_NEWER(DUNE_GEOMETRY, 2, 6) Dune::GeometryTypes::simplex(dim-codim) #else Dune::GeometryType(Dune::GeometryType::simplex,dim-codim) #endif ); temp_faces.back().corners[0].idx = vertex_indices[3]; temp_faces.back().corners[1].idx = vertex_indices[2]; temp_faces.back().corners[2].idx = vertex_indices[1]; // remember the vertices' numbers in parent element's vertices temp_faces.back().corners[0].num = vertex_numbers[3]; temp_faces.back().corners[1].num = vertex_numbers[2]; temp_faces.back().corners[2].num = vertex_numbers[1]; // Now we have the correct vertices in the last entries of temp_faces, but they may // have the wrong orientation. We want the triangle vertices on counterclockwise order, // when viewed from the outside of the grid. Therefore, we check the orientation of the // new face and possibly switch two vertices. // Compute segment normal reconstructedNormal = crossProduct(cornerCoords[2] - cornerCoords[3], cornerCoords[1] - cornerCoords[3]); reconstructedNormal /= reconstructedNormal.two_norm(); if (realNormal * reconstructedNormal < 0.0) std::swap(temp_faces.back().corners[0], temp_faces.back().corners[1]); simplex_index+=2; break; } default : DUNE_THROW(Dune::NotImplemented, "the extractor does only work for triangle and quadrilateral faces (" << face_corners << " corners)"); break; } } // end loop over found surface parts } } // end loop over elements std::cout << "added " << simplex_index << " subfaces\n"; // allocate the array for the face specific information... this->subEntities_.resize(simplex_index); // ...and fill in the data from the temporary containers copy(temp_faces.begin(), temp_faces.end(), this->subEntities_.begin()); } // now first write the array with the coordinates... this->coords_.resize(this->vtxInfo_.size()); for (const auto& vinfo : this->vtxInfo_) { // get a pointer to the associated info object CoordinateInfo* current = &this->coords_[vinfo.second.idx]; // store this coordinates index // NEEDED? current->index = vinfo.second.idx; // store the vertex' index for the index2vertex mapping current->vtxindex = vinfo.first; // store the vertex' coordinates under the associated index // in the coordinates array const auto vtx = this->grid().entity(vinfo.second.p); current->coord = vtx.geometry().corner(0); } } } // namespace GridGlue } // namespace Dune #endif // DUNE_GRIDGLUE_EXTRACTORS_CODIM1EXTRACTOR_HH dune-grid-glue-2.9.0/dune/grid-glue/extractors/extractor.hh000066400000000000000000000314251435125002300236760ustar00rootroot00000000000000// -*- tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- // vi: set et ts=4 sw=2 sts=2: // SPDX-FileCopyrightInfo: Copyright © DUNE Project contributors, see file LICENSE.md in module root // SPDX-License-Identifier: LGPL-3.0-or-later OR LicenseRef-GPL-2.0-only-with-dune-grid-glue-exception /* * Filename: extractor.hh * Version: 1.0 * Created on: Oct 05, 2009 * Author: Christian Engwer * --------------------------------- * Project: dune-grid-glue * Description: base class for all grid extractors * */ /** * @file * @brief extractor base class */ #ifndef DUNE_GRIDGLUE_EXTRACTORS_EXTRACTOR_HH #define DUNE_GRIDGLUE_EXTRACTORS_EXTRACTOR_HH #include #include #include #include #include #include #include #include #include #include namespace Dune { namespace GridGlue { /** * @brief Provides codimension-independent methods for grid extraction * * \tparam GV the grid view type * \tparam cd codimension of the extracted entities */ template class Extractor { public: static constexpr auto dimworld = GV::dimensionworld; static constexpr auto dim = GV::dimension; static constexpr auto codim = cd; static constexpr int cube_corners = 1 << (dim-codim); typedef GV GridView; typedef typename GridView::Grid Grid; typedef typename GV::Grid::ctype ctype; typedef Dune::FieldVector Coords; typedef Dune::FieldVector LocalCoords; typedef typename GV::Traits::template Codim::Entity Vertex; typedef typename Vertex::EntitySeed VertexSeed; typedef typename GV::Traits::template Codim<0>::Entity Element; typedef typename Element::EntitySeed ElementSeed; typedef std::vector VertexVector; #if DUNE_VERSION_NEWER(DUNE_GRID, 2, 6) using CellMapper = MultipleCodimMultipleGeomTypeMapper; #else using CellMapper = MultipleCodimMultipleGeomTypeMapper; #endif // typedef typename CellMapper::IndexType IndexType; typedef int IndexType; public: // transformations typedef Dune::MultiLinearGeometry Geometry; typedef Dune::MultiLinearGeometry LocalGeometry; protected: /************************** PRIVATE SUBCLASSES **********************/ /** * @brief Helpful struct holding one index for the coordinate (vertex) * to which it is associated and the element's corner index; */ struct CornerInfo { unsigned int idx : 28; ///< index of the vertex unsigned int num : 4; ///< element corner }; struct CoordinateInfo { CoordinateInfo() {} CoordinateInfo(unsigned int index_, IndexType vtxindex_) : vtxindex(vtxindex_), index(index_) {} /// @brief the index of the parent element (from index set) IndexType vtxindex; /// @brief the coordinate Coords coord; /// @brief the index of this coordinate (in internal storage scheme) // NEEDED?? unsigned int index; }; /** * @brief simple struct holding a vertex pointer and an index */ struct VertexInfo { VertexInfo(unsigned int idx_, const Vertex& p_) : idx(idx_), p(p_.seed()) {} unsigned int idx; VertexSeed p; }; /** * @brief simple struct holding an element seed and an index */ struct ElementInfo { ElementInfo(unsigned int idx_, const Element& p_, unsigned int f_) : idx(idx_), faces(f_), p(p_.seed()) {} /// @brief the index of this element's first face in the internal list of extracted faces unsigned int idx : 28; /// @brief the number of extracted faces for this element unsigned int faces : 4; /// @brief the entity seed for the element ElementSeed p; }; /** * @brief Holds some information about an element's subentity involved in a coupling */ struct SubEntityInfo { SubEntityInfo() /* * TODO: move default value of `geometryType_` to member declaration * when removing support for older dune-geometry */ #if DUNE_VERSION_NEWER(DUNE_GEOMETRY, 2, 6) : geometryType_(GeometryTypes::simplex(dim-codim)) {} #else { geometryType_.makeSimplex(dim-codim); } #endif SubEntityInfo(IndexType parent_, unsigned int num_in_parent_, const Dune::GeometryType& geometryType) : parent(parent_), num_in_parent(num_in_parent_), geometryType_(geometryType) {} unsigned int nCorners() const { return Dune::ReferenceElements::general(geometryType_).size(dim-codim); } /// @brief the index of the parent element (from index set) IndexType parent; /// @brief the number of the face in the parent element unsigned int num_in_parent : 3; /** \brief The GeometryType of the subentity */ Dune::GeometryType geometryType_; /** @brief the corner indices plus the numbers of the vertices in the parent element This array has the length cube_corners, because currently that is an upper boun d for the number of corners of an element. If more general element types appear we need to change this. */ CornerInfo corners[cube_corners]; // sim = numer of vertices in a simplex }; typedef std::map ElementInfoMap; typedef std::map VertexInfoMap; /************************** MEMBER VARIABLES ************************/ /// @brief the grid object to extract the surface from const GridView gv_; /* Geometrical and Topological Information */ /// @brief all information about the corner vertices of the extracted std::vector coords_; /// @brief all information about the extracted subEntities std::vector subEntities_; /// @brief a map enabling faster access to vertices and coordinates /// /// Maps a vertex' index (from index set) to an object holding the locally /// associated index of the vertex' coordinate in coords_ and an entity /// pointer to the codim entity. VertexInfoMap vtxInfo_; /// @brief a map enabling faster access to elements and faces /// /// Maps an element's index (from index set) to an object holding the locally /// associated index of its first face in _indices (if there are more they are /// positioned consecutively) and an entity pointer to the codim<0> entity. ElementInfoMap elmtInfo_; CellMapper cellMapper_; public: /* C O N S T R U C T O R S A N D D E S T R U C T O R S */ /** * @brief Constructor * @param gv the grid view object to work with */ Extractor(const GV& gv) : gv_(gv) #if DUNE_VERSION_NEWER(DUNE_GRID, 2, 6) , cellMapper_(gv, mcmgElementLayout()) #else , cellMapper_(gv) #endif {} /* F U N C T I O N A L I T Y */ /** * @brief delete everything build up so far and free the memory */ void clear() { // this is an inofficial way on how to free the memory allocated // by a std::vector { std::vector dummy; coords_.swap(dummy); } { std::vector dummy; subEntities_.swap(dummy); } // ...then clear the maps themselves, too vtxInfo_.clear(); elmtInfo_.clear(); } /* G E T T E R S */ /** * @brief getter for the coordinates array * @param coords a vector that will be resized (!) and filled with the coordinates, * note that the single components are written consecutively */ void getCoords(std::vector >& coords) const { coords.resize(coords_.size()); for (unsigned int i = 0; i < coords_.size(); ++i) coords[i] = coords_[i].coord; } /** * @brief getter for the count of coordinates * @return the count */ unsigned int nCoords() const { return coords_.size(); } /** \brief Get the list of geometry types */ void getGeometryTypes(std::vector& geometryTypes) const { geometryTypes.resize(subEntities_.size()); for (size_t i=0; i& faces) const { faces.resize(subEntities_.size()); for (unsigned int i = 0; i < subEntities_.size(); ++i) { faces[i].resize(subEntities_[i].nCorners()); for (unsigned int j = 0; j < subEntities_[i].nCorners(); ++j) faces[i][j] = subEntities_[i].corners[j].idx; } } /** * @brief gets index of first subentity as well as the total number of subentities that * were extracted from this element * @param[in] e the element * @param[out] first will contain the index of the first subentity if it exists, else -1 * @param[out] count will contain the number of subentities extracted from this element * @return true if at least one subentity was extracted from this element */ bool faceIndices(const Element& e, int& first, int& count) const { typename ElementInfoMap::const_iterator it = elmtInfo_.find(cellMapper_.map(e)); if (it == elmtInfo_.end()) { first = -1; count = 0; return false; } // the iterator is valid, fill the out params first = it->second.idx; count = it->second.faces; return true; } /** * @brief gets the number face in the parent element * @param index the index of the face * @return if failed -1, else the index */ int indexInInside(unsigned int index) const { return index < subEntities_.size() ? subEntities_[index].num_in_parent : -1; } // /** // * @brief tests that a given entry in the extraction set does have local couplings // * @todo parallel interface // */ // bool contains (unsigned int global, unsigned int & local) const // { // local = global; // return true; // } /** * @brief give access to the Dune::GridView where this Patch belongs to */ const GridView & gridView() const { return gv_; } const Grid& grid() const { return gv_.grid(); } /** * @brief gets the parent element for a given face index, * throws an exception if index not valid * @param index the index of the face * @return a reference to the element's stored pointer */ Element element(unsigned int index) const { if (index >= subEntities_.size()) DUNE_THROW(Dune::GridError, "invalid face index"); const ElementSeed seed = elmtInfo_.at(subEntities_[index].parent).p; return grid().entity(seed); } #if 1 /** * @brief gets the vertex for a given coordinate index * throws an exception if index not valid * @param index the index of the coordinate * @return a reference to the vertex' stored pointer */ Vertex vertex(unsigned int index) const { if (index >= coords_.size()) DUNE_THROW(Dune::GridError, "invalid coordinate index"); const VertexSeed seed = vtxInfo_.at(coords_[index].vtxindex).p; return grid().entity(seed); } #endif /** \brief Get world geometry of the extracted face */ Geometry geometry(unsigned int index) const; /** \brief Get geometry of the extracted face in element coordinates */ LocalGeometry geometryLocal(unsigned int index) const; }; /** \brief Get World geometry of the extracted face */ template typename Extractor::Geometry Extractor::geometry(unsigned int index) const { std::vector corners(subEntities_[index].nCorners()); for (unsigned int i = 0; i < subEntities_[index].nCorners(); ++i) corners[i] = coords_[subEntities_[index].corners[i].idx].coord; return Geometry(subEntities_[index].geometryType_, corners); } /** \brief Get Geometry of the extracted face in element coordinates */ template typename Extractor::LocalGeometry Extractor::geometryLocal(unsigned int index) const { std::vector corners(subEntities_[index].nCorners()); // get face info const SubEntityInfo & face = subEntities_[index]; Dune::GeometryType facetype = subEntities_[index].geometryType_; // get reference element const auto elmtseed = elmtInfo_.at(face.parent).p; const auto elmt = grid().entity(elmtseed); const Dune::GeometryType celltype = elmt.type(); const auto& re = Dune::ReferenceElements::general(celltype); for (unsigned int i = 0; i < subEntities_[index].nCorners(); ++i) corners[i] = re.position(face.corners[i].num,dim); return LocalGeometry(facetype, corners); } } // namespace GridGlue } // namespace Dune #endif // DUNE_GRIDGLUE_EXTRACTORS_EXTRACTOR_HH dune-grid-glue-2.9.0/dune/grid-glue/extractors/vtksurfacewriter.hh000066400000000000000000000161431435125002300252750ustar00rootroot00000000000000// -*- tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- // vi: set et ts=4 sw=2 sts=2: // SPDX-FileCopyrightInfo: Copyright © DUNE Project contributors, see file LICENSE.md in module root // SPDX-License-Identifier: LGPL-3.0-or-later OR LicenseRef-GPL-2.0-only-with-dune-grid-glue-exception /* * Filename: VtkSurfaceWriter.hh * Version: 1.0 * Created on: Jan 16, 2009 * Author: Gerrit Buse * --------------------------------- * Project: dune-grid-glue * Description: helper class for graphical output of grids in generic representation * */ /** * @file * @brief helper class for graphical output of grids in generic representation */ #ifndef DUNE_GRIDGLUE_EXTRACTORS_VTKSURFACEWRITER_HH #define DUNE_GRIDGLUE_EXTRACTORS_VTKSURFACEWRITER_HH #include #include #include #include #include "../adapter/gridgluevtkwriter.hh" namespace Dune { namespace GridGlue { class VtkSurfaceWriter { public: VtkSurfaceWriter(const char* filename) : filename_(filename) {} ~VtkSurfaceWriter() {} void setFilename(const char* name) { if (std::strlen(name) > 0) this->filename_ = name; } template void writeSurface(const std::vector& coords, const std::vector& indices, int corners, int dim) { std::ofstream fos; char buffer[64]; sprintf(buffer, "%s.vtk", this->filename_); fos.open(buffer); fos << std::setprecision(8) << std::setw(1); // write preamble fos << "# vtk DataFile Version 2.0\nFilename: " << buffer << "\nASCII" << std::endl; this->writePoints(coords, dim, fos); const int polycount = indices.size()/corners; int corner_count[polycount]; for (int i = 0; i < polycount; ++i) corner_count[i] = corners; this->writePolygons(indices, corner_count, polycount, dim, fos); fos.close(); } template void writeSurfaceElementData(const std::vector& coords, const std::vector& indices, int corners, const std::vector& data, const char* dataname, int dim) { std::ofstream fos; char buffer[64]; sprintf(buffer, "%s.vtk", this->filename_); fos.open(buffer); fos << std::setprecision(8) << std::setw(1); // write preamble fos << "# vtk DataFile Version 2.0\nFilename: " << buffer << "\nASCII" << std::endl; this->writePoints(coords, dim, fos); const int polycount = indices.size()/corners; int corner_count[polycount]; for (int i = 0; i < polycount; ++i) corner_count[i] = corners; this->writePolygons(indices, corner_count, polycount, dim, fos); this->writeCellData(data, dataname, dim, fos); fos.close(); } template void writeSurfaceVertexData(const std::vector& coords, const std::vector& indices, int corners, const std::vector& data, const char* dataname, int dim) { std::ofstream fos; char buffer[64]; sprintf(buffer, "%s.vtk", this->filename_); fos.open(buffer); fos << std::setprecision(8) << std::setw(1); // write preamble fos << "# vtk DataFile Version 2.0\nFilename: " << buffer << "\nASCII" << std::endl; this->writePoints(coords, dim, fos); const int polycount = indices.size()/corners; int corner_count[polycount]; for (int i = 0; i < polycount; ++i) corner_count[i] = corners; this->writePolygons(indices, corner_count, polycount, dim, fos); this->writePointData(data, dataname, dim, fos); fos.close(); } protected: template void writePoints(const std::vector& coords, int dim, std::ofstream& fos) { fos << "DATASET POLYDATA\nPOINTS " << coords.size() << " " << TypeNames[Nametraits::nameidx] << std::endl; for (unsigned int i = 0; i < coords.size(); ++i) { fos << coords[i][0]; if (dim == 2) fos << " " << coords[i][1] << " 0 \n" << coords[i][0] << " " << coords[i][1] << " 0.01" << std::endl; else // dim == 3 fos << " " << coords[i][1] << " " << coords[i][2] << std::endl; } } void writePolygons(const std::vector& indices, const int* corners, int ncorners, int dim, std::ofstream& fos) { if (dim == 2) { fos << "POLYGONS " << indices.size()/2 << " " << 5*(indices.size() / 2) << std::endl; for (unsigned int i = 0; i < indices.size(); i += 2) fos << "4 " << 2*indices[i] << " " << 2*indices[i+1] << " " << 2*indices[i+1]+1 << " "<< 2*indices[i]+1 << std::endl; // arbitrary shapes - ignored here! // int sum = ncorners; // for (int i = 0; i < ncorners; ++i) // sum += (corners[i] > 2 ? corners[i] : 3); // // fos << "POLYGONS " << ncorners << " " << sum << std::endl; // int index = 0; // for (int i = 0; i < ncorners; ++i) // { // // write the first index twice if it is an egde // // => triangle instead of edge - paraview can display it then // if (corners[i] > 2) // fos << corners[i]; // else // fos << "3 " << indices[index]; // // for (int j = 0; j < corners[i]; ++j) // fos << " " << indices[index++]; // fos << std::endl; // } } else { int sum = ncorners; for (int i = 0; i < ncorners; ++i) sum += corners[i]; fos << "POLYGONS " << ncorners << " " << sum << std::endl; int index = 0; for (int i = 0; i < ncorners; ++i) { fos << corners[i]; for (int j = 0; j < corners[i]; ++j) fos << " " << indices[index++]; fos << std::endl; } } } template void writeCellData(const std::vector& data, const char* dataname, int dim, std::ofstream& fos) { fos << "CELL_DATA " << data.size()*(dim == 2 ? 2 : 1) << std::endl; fos << "SCALARS " << dataname << " " << TypeNames[Nametraits::nameidx] << " 1" << std::endl; fos << "LOOKUP_TABLE default" << std::endl; for (unsigned int i = 0; i < data.size(); ++i) { fos << data[i] << std::endl; if (dim == 2) fos << data[i] << std::endl; } } template void writePointData(const std::vector& data, const char* dataname, int dim, std::ofstream& fos) { fos << "POINT_DATA " << data.size()*(dim == 2 ? 2 : 1) << std::endl; fos << "SCALARS " << dataname << " " << TypeNames[Nametraits::nameidx] << " 1" << std::endl; fos << "LOOKUP_TABLE default" << std::endl; for (unsigned int i = 0; i < data.size(); ++i) { fos << data[i] << std::endl; if (dim == 2) fos << data[i] << std::endl; } } private: const char* filename_; }; } // namespace GridGlue } // namespace Dune #endif // DUNE_GRIDGLUE_EXTRACTORS_VTKSURFACEWRITER_HH dune-grid-glue-2.9.0/dune/grid-glue/gridglue.hh000066400000000000000000000324041435125002300212650ustar00rootroot00000000000000// -*- tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- // vi: set et ts=4 sw=2 sts=2: // SPDX-FileCopyrightInfo: Copyright © DUNE Project contributors, see file LICENSE.md in module root // SPDX-License-Identifier: LGPL-3.0-or-later OR LicenseRef-GPL-2.0-only-with-dune-grid-glue-exception /** * @file * @brief Central component of the module implementing the coupling of two grids. * @author Gerrit Buse, Christian Engwer */ #ifndef DUNE_GRIDGLUE_GRIDGLUE_HH #define DUNE_GRIDGLUE_GRIDGLUE_HH #include #include #include #include #include #include #include #include #include #include "adapter/gridgluecommunicate.hh" #include #include #include #include #include #include #include #include namespace Dune { namespace GridGlue { // forward declarations template class GridGlue; template class IntersectionData; template class Intersection; template class IntersectionIterator; template class IntersectionIndexSet; /** * @class GridGlue * @brief sequential adapter to couple two grids at specified close together boundaries * * @tparam P0 patch (extractor) to use for grid 0 * @tparam P1 patch (extractor) to use for grid 1 * * \todo adapt member names according to style guide */ template class GridGlue { private: /* F R I E N D S */ friend class IntersectionData; friend class Intersection; friend class Intersection; friend class IntersectionIterator; friend class IntersectionIterator; friend class IntersectionIndexSet; /* P R I V A T E T Y P E S */ /** \brief GlobalId type of an intersection (used for communication) */ typedef ::Dune::GridGlue::GlobalId GlobalId; /** \brief LocalIndex type of an intersection (used for communication) */ typedef Dune::ParallelLocalIndex LocalIndex; /** \brief ParallelIndexSet type (used for communication communication) */ typedef Dune::ParallelIndexSet PIndexSet; public: /* P U B L I C T Y P E S A N D C O N S T A N T S */ /** coupling patch of grid side */ template using GridPatch = std::conditional_t>; /** GridView of grid side */ template using GridView = typename GridPatch::GridView; /** Grid type of grid side */ template using Grid = typename GridView::Grid; /** \brief GridView of grid 0 (aka domain grid) */ using Grid0View [[deprecated("please use GridView<0> instead")]] = GridView<0>; /** \brief Grid 0 type */ using Grid0 [[deprecated("please use Grid<0> instead")]] = Grid<0>; /** \brief Coupling patch of grid 0 */ using Grid0Patch [[deprecated("please use GridPatch<0> instead")]] = GridPatch<0>; template static constexpr auto griddim() { return GridPatch::dim; } template static constexpr auto griddimworld() { return GridPatch::dimworld; } /** \brief dimension of the grid 0 extractor */ [[deprecated("please use griddim<0>() instead")]] static constexpr auto grid0dim = griddim<0>(); [[deprecated("please use griddim<0>() instead")]] static constexpr auto domdim = griddim<0>(); /** \brief world dimension of the grid 0 extractor */ [[deprecated("please use griddimworld<0>() instead")]] static constexpr auto grid0dimworld = griddimworld<0>(); [[deprecated("please use griddimworld<0>() instead")]] static constexpr auto domdimworld = griddimworld<0>(); /** \brief GridView of grid 1 (aka target grid) */ using Grid1View [[deprecated("please use GridView<0> instead")]] = GridView<1>; /** \brief Grid 1 type */ using Grid1 [[deprecated("please use Grid<1> instead")]] = Grid<1>; /** \brief Coupling patch of grid 1 */ using Grid1Patch [[deprecated("please use GridPatch<1> instead")]] = GridPatch<1>; /** \todo */ typedef unsigned int IndexType; /** \brief dimension of the grid 1 extractor */ [[deprecated("please use griddim<1>() instead")]] static constexpr auto grid1dim = griddim<1>(); [[deprecated("please use griddim<1>() instead")]] static constexpr auto tardim = griddim<1>(); /** \brief world dimension of the grid 1 extractor */ [[deprecated("please use griddimworld<1>() instead")]] static constexpr auto grid1dimworld = griddimworld<1>(); [[deprecated("please use griddimworld<1>() instead")]] static constexpr auto tardimworld = griddimworld<1>(); /** \brief export the world dimension * This is the maximum of the extractors' world dimensions. */ static constexpr int dimworld = (int)griddimworld<0>() > (int)griddimworld<1>() ? (int)griddimworld<0>() : (int)griddimworld<1>(); /** \brief The type used for coordinates */ typedef typename PromotionTraits::ctype, typename GridView<1>::ctype>::PromotedType ctype; /** \brief The type used for coordinate vectors */ typedef Dune::FieldVector Coords; /** \brief type of grid elements on side side */ template using GridElement = typename GridView::Traits::template Codim<0>::Entity; /** \brief type of grid vertices on side side */ template using GridVertex = typename GridView::Traits::template Codim::dimension>::Entity; /** \brief The type of the Grid0 elements */ using Grid0Element [[deprecated("please use GridElement<0> instead")]] = GridElement<0>; /** \brief The type of the Grid0 vertices */ using Grid0Vertex [[deprecated("please use GridVertex<0> instead")]] = GridVertex<0>; /** \brief The type of the Grid1 elements */ using Grid1Element [[deprecated("please use GridElement<1> instead")]] = GridElement<1>; /** \brief The type of the Grid1 vertices */ using Grid1Vertex [[deprecated("please use GridVertex<1> instead")]] = GridVertex<1>; /** \brief Instance of a Merger */ typedef Dune::GridGlue::Merger::dimension - GridPatch<0>::codim, Grid<1>::dimension - GridPatch<1>::codim, dimworld> Merger; /** \brief Type of remote intersection objects */ typedef Dune::GridGlue::Intersection Intersection; /** \brief Type of remote intersection indexSet */ typedef Dune::GridGlue::IntersectionIndexSet IndexSet; /** \brief Type of the iterator that iterates over remove intersections */ template using IntersectionIterator = Dune::GridGlue::IntersectionIterator; /** \todo Please doc me! */ using Grid0IntersectionIterator [[deprecated("please use IntersectionIterator<0> instead")]] = IntersectionIterator<0>; /** \todo Please doc me! */ using Grid1IntersectionIterator [[deprecated("please use IntersectionIterator<1> instead")]] = IntersectionIterator<1>; private: /* M E M B E R V A R I A B L E S */ using GridPatches = std::tuple< const std::shared_ptr< const GridPatch<0> >, const std::shared_ptr< const GridPatch<1> > >; const GridPatches patches_; /// @brief the surface merging utility const std::shared_ptr merger_; /// @brief number of intersections IndexType index__sz = 0; #if HAVE_MPI /// @brief MPI_Comm which this GridGlue is working on MPI_Comm mpicomm_; /// @brief parallel indexSet for the intersections with a local grid0 entity PIndexSet patch0_is_; /// @brief parallel indexSet for the intersections with a local grid1 entity PIndexSet patch1_is_; /// @brief keeps information about which process has which intersection Dune::RemoteIndices remoteIndices_; #endif // HAVE_MPI /// \todo typedef Dune::GridGlue::IntersectionData IntersectionData; /// @brief a vector with intersection elements mutable std::vector intersections_; protected: /** * @brief after building the merged grid the intersection can be updated * through this method (for internal use) * * @param patch0coords the patch0 vertices' coordinates ordered like e.g. in 3D x_0 y_0 z_0 x_1 y_1 ... y_(n-1) z_(n-1) * @param patch0entities array with all patch0 entities represented as corner indices into @c patch0coords. Free of (potentially heterogeneous) block structure, the last component of one entity is immediately followed by the first component of the next entity here. * @param patch0types array with all patch0 entities types * @param patch0rank rank of the process where patch0 was extracted * * @param patch1coords the patch2 vertices' coordinates ordered like e.g. in 3D x_0 y_0 z_0 x_1 y_1 ... y_(n-1) z_(n-1) * @param patch1entities just like with the patch0entities and patch0corners * @param patch1types array with all patch1 entities types * @param patch1rank rank of the process where patch1 was extracted * */ void mergePatches(const std::vector >& patch0coords, const std::vector& patch0entities, const std::vector& patch0types, const int patch0rank, const std::vector >& patch1coords, const std::vector& patch1entities, const std::vector& patch1types, const int patch1rank); template void extractGrid (const Extractor & extractor, std::vector > & coords, std::vector & faces, std::vector& geometryTypes) const; public: /* C O N S T R U C T O R S A N D D E S T R U C T O R S */ /** * @brief constructor * * Initializes components but does not "glue" the surfaces. The surfaces * are extracted from the grids here though. * @param gp0 the grid0 patch * @param gp1 the grid1 patch * @param merger The merger object that is used to compute the merged grid. This class has * to be a model of the SurfaceMergeConcept. */ GridGlue(const std::shared_ptr< const GridPatch<0> >& gp0, const std::shared_ptr< const GridPatch<1> >& gp1, const std::shared_ptr& merger); /* G E T T E R S */ /** \todo Please doc me! */ template const GridPatch

& patch() const { return *std::get

(patches_); } /** * @brief getter for the GridView of patch P * @return the object */ template const GridView

& gridView() const { return std::get

(patches_)->gridView(); } /* F U N C T I O N A L I T Y */ void build(); /* I N T E R S E C T I O N S A N D I N T E R S E C T I O N I T E R A T O R S */ /** * @brief gets an iterator over all remote intersections in the merged grid between grid0 and grid1 * @tparam I select inside grid I=0 or I=1 * * @return the iterator */ template IntersectionIterator ibegin() const { return {this, 0}; } /** * @brief gets the (general) end-iterator for grid glue iterations * @tparam I select inside grid I=0 or I=1 * * @return the iterator */ template IntersectionIterator iend() const { return {this, index__sz}; } /*! \brief Communicate information on the MergedGrid of a GridGlue Template parameter is a model of Dune::GridGlue::CommDataHandle \param data GridGlueDataHandle \param iftype Interface for which the Communication should take place \param dir Communication direction (Forward means grid0 to grid1, Backward is the reverse) \todo fix mixed communication: seq->par use commSeq, par->seq use commPar \todo add directed version communicate(data,iftype,dir) */ template void communicate (Dune::GridGlue::CommDataHandle & data, Dune::InterfaceType iftype, Dune::CommunicationDirection dir) const; /* * @brief return an IndexSet mapping from Intersection to IndexType */ IndexSet indexSet() const { return IndexSet(this); } #if QUICKHACK_INDEX // indexset size size_t indexSet_size() const { return index__sz; } #endif Intersection getIntersection(int i) const { return Intersection(this, & intersections_[i]); } size_t size() const { return index__sz; } }; } // end namespace GridGlue } // end namespace Dune #include "adapter/rangegenerators.hh" #include "adapter/gridglue.cc" #include "adapter/intersection.hh" #include "adapter/intersectioniterator.hh" #include "adapter/intersectionindexset.hh" #endif // DUNE_GRIDGLUE_GRIDGLUE_HH dune-grid-glue-2.9.0/dune/grid-glue/merging/000077500000000000000000000000001435125002300205675ustar00rootroot00000000000000dune-grid-glue-2.9.0/dune/grid-glue/merging/CMakeLists.txt000066400000000000000000000011111435125002300233210ustar00rootroot00000000000000# SPDX-FileCopyrightInfo: Copyright © DUNE Project contributors, see file LICENSE.md in module root # SPDX-License-Identifier: LGPL-3.0-or-later OR LicenseRef-GPL-2.0-only-with-dune-grid-glue-exception #install headers install(FILES computeintersection.hh computeintersection.cc conformingmerge.hh contactmerge.cc contactmerge.hh intersectionlist.hh merger.hh overlappingmerge.cc overlappingmerge.hh simplexintersection.cc standardmerge.hh DESTINATION include/dune/grid-glue/merging) dune_add_library(dunegridglue standardmerge.cc ADD_LIBS ${DUNE_LIBS}) dune-grid-glue-2.9.0/dune/grid-glue/merging/computeintersection.cc000066400000000000000000000300441435125002300252020ustar00rootroot00000000000000// -*- tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- // vi: set et ts=4 sw=2 sts=2: // SPDX-FileCopyrightInfo: Copyright © DUNE Project contributors, see file LICENSE.md in module root // SPDX-License-Identifier: LGPL-3.0-or-later OR LicenseRef-GPL-2.0-only-with-dune-grid-glue-exception namespace Dune { namespace GridGlue { //**************************************************************************************** // PUBLIC //**************************************************************************************** template bool IntersectionComputation::computeIntersection(const std::vector& X, const std::vector& Y, std::vector >& SX, std::vector >& SY, std::vector& P) { std::vector > subElementsX, subElementsY; std::vector > faceIdsX, faceIdsY; std::vector subElementX(CM::grid1Dimension+1), subElementY(CM::grid2Dimension+1), sP; std::vector > sSX, sSY; CM::grid1_subdivisions(X,subElementsX,faceIdsX); CM::grid2_subdivisions(Y,subElementsY,faceIdsY); bool intersectionFound = false; for (unsigned int i = 0; i < subElementsX.size(); ++i) { // iterate over all X subelements for (unsigned int ki = 0; ki < subElementsX[i].size(); ++ki) // define the X subelement subElementX[ki] = X[subElementsX[i][ki]]; for (unsigned int j = 0; j < subElementsY.size(); ++j) { // iterate over all Y subelemetns for (unsigned int kj = 0; kj < subElementsY[j].size(); ++kj) // define the Y subleement subElementY[kj] = Y[subElementsY[j][kj]]; sP.clear(); // compute the intersection bool b = CM::computeIntersectionPoints(subElementX,subElementY,sSX,sSY,sP); intersectionFound = intersectionFound || b; // only insert points on outer faces for (unsigned int ki = 0; ki < sSX.size(); ++ki) { // iterate over all faces if (faceIdsX[i][ki] >= 0) { for (unsigned int kii = 0; kii < sSX[ki].size(); ++kii) { int k = insertPoint(sP[sSX[ki][kii]],P); // determine index in P SX[faceIdsX[i][ki]].push_back(k); } } } for (unsigned int kj = 0; kj < sSY.size(); ++kj) { // iterate over all faces if (faceIdsY[j][kj] >= 0) { for (unsigned int kjj = 0; kjj < sSY[kj].size(); ++kjj) { int k = insertPoint(sP[sSY[kj][kjj]],P); // determine index in P SY[faceIdsY[j][kj]].push_back(k); } } } } } return intersectionFound; } //**************************************************************************************** // PRIVATE //**************************************************************************************** template void IntersectionComputation::orderPoints_(std::integral_constant, std::integral_constant, const V& centroid, const std::vector >& SX, const std::vector >& SY, const std::vector& P, std::vector >& H) { int n_facesX = SX.size(); int n_facesY = SY.size(); int m; std::vector no,id,temp ; std::vector p ; std::vector > tempH; std::vector faceOrderingX(n_facesX); std::vector faceOrderingY(n_facesY); if (n_facesX==3) { faceOrderingX[0] = 0; faceOrderingX[1] = 2; faceOrderingX[2] = 1; } else { faceOrderingX[0] = 0; faceOrderingX[1] = 3; faceOrderingX[2] = 2; faceOrderingX[3] = 1; } if (n_facesY==3) { faceOrderingY[0] = 0; faceOrderingY[1] = 2; faceOrderingY[2] = 1; } else { faceOrderingY[0] = 0; faceOrderingY[1] = 3; faceOrderingY[2] = 2; faceOrderingY[3] = 1; } if (P.size() > 3) { for (int i = 0; i < n_facesX; ++i) { // loop on faces of X if (SX[i].size() > 0) { no = SX[faceOrderingX[i]]; removeDuplicates(no); m = no.size() ; if ((m>=3) && newFace3D(no,tempH)) // don't compute degenerate polygons and check if face is new { for ( int l=0; l(), centroid,id,p); // order points counter-clock-wise for ( int l=0; l 0) { no = SY[faceOrderingY[i]]; removeDuplicates(no); m = no.size() ; if ((m>=3) && newFace3D(no,tempH)) // don't compute degenerate polygons and check if face is new { for ( int l=0; l(),centroid,id,p); // order points counter-clock-wise for ( int l=0; l= 3) { for (int j = 1; j <= hs-2;++j) { temp.clear(); temp.push_back(tempH[i][0]); for (int k = 0; k < 2; ++k) temp.push_back(tempH[i][j+k]); H.push_back(temp); } } } } template void IntersectionComputation::orderPoints_(std::integral_constant, std::integral_constant, const V& centroid, const std::vector >& SX, const std::vector >& SY, const std::vector& P, std::vector >& H) { H.clear(); std::vector id, temp(2); orderPointsCC(std::integral_constant(),centroid,id,P); for (std::size_t i = 0; i < id.size();++i) { temp[0] = id[i]; temp[1] = id[(i+1)%(id.size())]; H.push_back(temp); } } template void IntersectionComputation::orderPoints_(std::integral_constant, std::integral_constant, const V& centroid, const std::vector >& SX, const std::vector >& SY, const std::vector& P, std::vector >& H) { H.clear(); std::vector id, temp(2); orderPointsCC(std::integral_constant(),centroid,id,P); for (int i = 0; i < id.size();++i) { temp[0] = id[i]; temp[1] = id[(i+1)%(id.size())]; H.push_back(temp); } } template void IntersectionComputation::removeDuplicates(std::vector & p) { sort(p.begin(),p.end()); std::vector::iterator it = std::unique(p.begin(),p.end()); p.erase(it,p.end()); } template bool IntersectionComputation::newFace3D(const std::vector& id, const std::vector >& H) { // get size_type for all the vectors we are using typedef typename std::vector::size_type size_type; int n = H.size() ; int m = id.size() ; std::vector A ; std::vector B = id ; sort(B.begin(),B.end()) ; int i = 0 ; bool b = true ; double tp ; while ( b && (i=m) { A=H[i] ; sort(A.begin(),A.end()); tp = 0 ; for ( size_type j=0 ; j < m; j++) tp += std::fabs(A[j]-B[j]) ; b = (tp>0) ; } i += 1 ; } return b ; } template void IntersectionComputation::orderPointsCC(std::integral_constant, const V& centroid, std::vector& id, const std::vector& P) { typedef typename std::vector::size_type size_type; id.clear(); // get size_type for all the vectors we are using V c,d1,d2,dr,dn,cross,d ; std::vector ai ; d1 = P[1] - P[0] ; // two reference vectors d2 = P[2] - P[0] ; cross[0] = d1[1]*d2[2] - d1[2]*d2[1] ; // cross product cross[1] = d1[2]*d2[0] - d1[0]*d2[2] ; cross[2] = d1[0]*d2[1] - d1[1]*d2[0] ; if (((centroid - P[0])*cross)<0) // good orientation ? { dr = d1 ; dr /= dr.two_norm() ; // 'x-axis' unit vector dn = dr ; dn *= -(d2*dr) ; dn += d2 ; dn /= dn.two_norm() ; // 'y-axis' unit vector } else { dr = d2 ; dr /= dr.two_norm() ; // 'y-axis' unit vector dn = dr ; dn *= -(d1*dr) ; dn += d1 ; dn /= dn.two_norm() ; // 'x-axis' unit vector } // definition of angles, using projection on the local reference, ie by scalarly multipliying by dr and dn resp. for ( size_type j=1 ; j < P.size() ; j++) { ai.push_back(atan2((P[j]-P[0])*dn,(P[j]-P[0])*dr)) ; id.push_back(j) ; } // sort according to increasing angles for ( size_type j=1; j < ai.size(); j++) { for ( size_type i=0; i < j; i++) { if (ai[j](ai[i],ai[j]) ; std::swap(id[i],id[j]) ; } } } id.insert(id.begin(),0); } template void IntersectionComputation::orderPointsCC(std::integral_constant, const V& centroid, std::vector& id, const std::vector& P) { typedef typename std::vector::size_type size_type; // get size_type for all the vectors we are using typedef typename std::vector::size_type size_type; std::vector ai(P.size()); id.resize(P.size()); // definition of angles for ( size_type i=0; i < P.size(); i++) { ai[i] = atan2(P[i][1]-centroid[1],P[i][0]-centroid[0]); id[i] = i; } // sort according to increasing angles for ( size_type j=1; j < ai.size(); j++) { for ( size_type i=0; i < j; i++) if (ai[j](ai[i],ai[j]); std::swap(id[i],id[j]); } } } } /* namespace Dune::GridGlue */ } /* namespace Dune */ dune-grid-glue-2.9.0/dune/grid-glue/merging/computeintersection.hh000066400000000000000000000212171435125002300252160ustar00rootroot00000000000000// SPDX-FileCopyrightInfo: Copyright © DUNE Project contributors, see file LICENSE.md in module root // SPDX-License-Identifier: LGPL-3.0-or-later OR LicenseRef-GPL-2.0-only-with-dune-grid-glue-exception #ifndef DUNE_GRIDGLUE_MERGING_COMPUTEINTERSECTION_HH #define DUNE_GRIDGLUE_MERGING_COMPUTEINTERSECTION_HH #include #include namespace Dune { namespace GridGlue { template class ComputationMethod { public: typedef FieldVector Vector; static const int grid1Dimension = dim1; static const int grid2Dimension = dim2; static const int intersectionDimension = (dim1 < dim2)?(dim1):(dim2); static bool computeIntersectionPoints(const std::vector X, const std::vector Y, std::vector >& SX, std::vector >& SY, std::vector& P); static void grid1_subdivisions(const std::vector elementCorners, std::vector >& subElements, std::vector >& faceIds); static void grid2_subdivisions(const std::vector elementCorners, std::vector >& subElements, std::vector >& faceIds); }; /** * @brief Intersection computation method for two elements of arbitrary dimension * @tparam dimWorld The world dimension * @tparam T the field type */ template class IntersectionComputation { private: typedef typename CM::Vector V; const int dimWorld = V::dimension; const int dim1 = CM::grid1Dimension; const int dim2 = CM::grid2Dimension; public: /** * @brief Compute the intersection of two elements X and Y * Compute the intersection of two elements X and Y, where X is of dimension dim1 * and Y is of dimension dim2 and return a vector P containing the corner points of * the intersection polyhedron. * * @param X ordered vector of corners defining the element with dimension dim1 * @param Y ordered vector of corners defining the element with dimension dim2 * @param SX indices of points in P on the index i face of X, where i denotes the vector index in SX * @param SY indices of points in P on the index i face of Y, where i denotes the vector index in SY * @param P the intersection points * @return true if enough intersection points were found to define at least one intersection element */ static bool computeIntersection(const std::vector& X, const std::vector& Y, std::vector >& SX, std::vector >& SY, std::vector& P); /** * @brief Order Points in the point list P face-wise such that a subsimplex subdivision can be constructed * @tparam isDim the intersection geometry dimension * @param centroid the center of all points * @param SX indices of points in P on the index i face of X, where i denotes the vector index in SX * @param SY indices of points in P on the index i face of Y, where i denotes the vector index in SY * @param P the point list (remains unchanged) * @param H ordered list of P indices */ template static void orderPoints(const V& centroid, const std::vector >& SX, const std::vector >& SY, const std::vector& P, std::vector >& H) { if (isDim > 1) orderPoints_(std::integral_constant(),std::integral_constant(), centroid, SX, SY, P,H); } private: static void orderPoints_(std::integral_constant, std::integral_constant, const V& centroid, const std::vector >& SX, const std::vector >& SY, const std::vector& P, std::vector >& H) {} static void orderPoints_(std::integral_constant, std::integral_constant, const V& centroid, const std::vector >& SX, const std::vector >& SY, const std::vector& P, std::vector >& H) {} static void orderPoints_(std::integral_constant, std::integral_constant, const V& centroid, const std::vector >& SX, const std::vector >& SY, const std::vector& P, std::vector >& H) {} static void orderPoints_(std::integral_constant, std::integral_constant, const V& centroid, const std::vector >& SX, const std::vector >& SY, const std::vector& P, std::vector >& H); static void orderPoints_(std::integral_constant, std::integral_constant, const V& centroid, const std::vector >& SX, const std::vector >& SY, const std::vector& P, std::vector >& H); static void orderPoints_(std::integral_constant, std::integral_constant, const V& centroid, const std::vector >& SX, const std::vector >& SY, const std::vector& P, std::vector > & H); /** * @brief Order points counterclockwise * @tparam isDim the intersection geometry dimension * @param centroid the center of all points * @param id list of counterclockwise point indices in P * @param P the point list */ static void orderPointsCC(std::integral_constant, const V& centroid, std::vector &id, const std::vector& P); static void orderPointsCC(std::integral_constant, const V& centroid, std::vector &id, const std::vector& P); /** * @brief Removes duplicate entries from the vector p. * @param the list duplicat entries are removed from */ static void removeDuplicates( std::vector & p); /** * @brief Checks if index set is contained already in H * b=NewFace(H,id) checks if a permutation of the vector id is contained in a row of the matrix H * @param id * @param H * @return true if the index set is contained in H */ static bool newFace3D(const std::vector& id, const std::vector >& H); }; template inline int insertPoint(const V p, std::vector& P) { double eps= 1e-8; // tolerance for identical nodes std::size_t k=0 ; if (P.size()>0) { while ((keps*(P[k].infinity_norm()) && (p - P[k]).infinity_norm()>eps*(p.infinity_norm())) && !(p.infinity_norm() < eps && P[k].infinity_norm() =P.size()) P.push_back(p) ; // new node is not contained in P } else P.push_back(p); return k ; } } /* namespace Dune::GridGlue */ } /* namespace Dune */ #include "simplexintersection.cc" #include "computeintersection.cc" #endif dune-grid-glue-2.9.0/dune/grid-glue/merging/conformingmerge.hh000066400000000000000000000164641435125002300243040ustar00rootroot00000000000000// -*- tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- // vi: set et ts=4 sw=2 sts=2: // SPDX-FileCopyrightInfo: Copyright © DUNE Project contributors, see file LICENSE.md in module root // SPDX-License-Identifier: LGPL-3.0-or-later OR LicenseRef-GPL-2.0-only-with-dune-grid-glue-exception /* * Filename: conformingmerge.hh * Version: 1.0 * Created on: Sep 14, 2009 * Author: Oliver Sander * --------------------------------- * Project: dune-grid-glue * Description: implementation of the Merger concept for conforming interfaces * */ /** * @file * @brief * Implementation of the Merger concept for conforming interfaces */ #ifndef DUNE_GRIDGLUE_MERGING_CONFORMINGMERGE_HH #define DUNE_GRIDGLUE_MERGING_CONFORMINGMERGE_HH #include #include #include #include #include #include #include #include namespace Dune { namespace GridGlue { /** \brief Implementation of the Merger concept for conforming interfaces \tparam dim Grid dimension of the coupling grids. Must be the same for both sides \tparam dimworld Dimension of the world coordinates. \tparam T Type used for coordinates */ template class ConformingMerge : public StandardMerge { public: /* E X P O R T E D T Y P E S A N D C O N S T A N T S */ /// @brief the numeric type used in this interface typedef T ctype; /// @brief the coordinate type used in this interface typedef Dune::FieldVector WorldCoords; /// @brief the coordinate type used in this interface typedef Dune::FieldVector LocalCoords; private: /* M E M B E R V A R I A B L E S */ /// @brief maximum distance between two matched points in the mapping T tolerance_; typedef typename StandardMerge::SimplicialIntersection SimplicialIntersection; /** \brief Compute the intersection between two overlapping elements The result is a set of simplices. */ void computeIntersections(const Dune::GeometryType& grid1ElementType, const std::vector >& grid1ElementCorners, std::bitset<(1<& neighborIntersects1, unsigned int grid1Index, const Dune::GeometryType& grid2ElementType, const std::vector >& grid2ElementCorners, std::bitset<(1<& neighborIntersects2, unsigned int grid2Index, std::vector& intersections); public: static constexpr T default_tolerance = 1e-4; ConformingMerge(T tolerance = default_tolerance) : tolerance_(tolerance) {} }; template constexpr T ConformingMerge::default_tolerance; template void ConformingMerge::computeIntersections(const Dune::GeometryType& grid1ElementType, const std::vector >& grid1ElementCorners, std::bitset<(1<& neighborIntersects1, unsigned int grid1Index, const Dune::GeometryType& grid2ElementType, const std::vector >& grid2ElementCorners, std::bitset<(1<& neighborIntersects2, unsigned int grid2Index, std::vector& intersections) { this->counter++; // A few consistency checks assert((unsigned int)(Dune::ReferenceElements::general(grid1ElementType).size(dim)) == grid1ElementCorners.size()); assert((unsigned int)(Dune::ReferenceElements::general(grid2ElementType).size(dim)) == grid2ElementCorners.size()); // any intersection we may find will be the entire elements. neighborIntersects1.reset(); neighborIntersects2.reset(); // the intersection is either conforming or empty, hence the GeometryTypes have to match if (grid1ElementType != grid2ElementType) return; // //////////////////////////////////////////////////////////// // Find correspondences between the different corners // //////////////////////////////////////////////////////////// std::vector other(grid1ElementCorners.size(), -1); for (unsigned int i=0; i::general(grid1ElementType); /** \todo Currently the Intersections have to be simplices */ if (grid1ElementType.isSimplex()) { intersections.emplace_back(grid1Index, grid2Index); for (int i=0; i #include namespace Dune { namespace GridGlue { template void ContactMerge::computeIntersections(const Dune::GeometryType& grid1ElementType, const std::vector >& grid1ElementCorners, std::bitset<(1<& neighborIntersects1, unsigned int grid1Index, const Dune::GeometryType& grid2ElementType, const std::vector >& grid2ElementCorners, std::bitset<(1<& neighborIntersects2, unsigned int grid2Index, std::vector& intersections) { using std::get; std::vector > polytopeCorners; // Initialize neighborIntersects1.reset(); neighborIntersects2.reset(); const int nCorners1 = grid1ElementCorners.size(); const int nCorners2 = grid2ElementCorners.size(); if (nCorners1 != dimworld) DUNE_THROW(Dune::Exception, "element1 must have " << dimworld << " corners, but has " << nCorners1); if (nCorners2 != dimworld) DUNE_THROW(Dune::Exception, "element2 must have " << dimworld << " corners, but has " << nCorners2); // The grid1 projection directions std::vector directions1(nCorners1); for (size_t i=0; igrid1ElementCorners_[grid1Index][i]]; // The grid2 projection directions std::vector directions2(nCorners2); for (size_t i=0; igrid2ElementCorners_[grid2Index][i]]; // The difference between the closest point projection and the normal projection is just the ordering // of the involved surfaces. The closest point projection is done along the outer normal field of grid2 // (due to being a best approximation) and the outer normal projection is using the outer normal field // of grid1 instead. std::array cornersRef ={std::cref(grid1ElementCorners), std::cref(grid2ElementCorners)}; std::array directionsRef ={std::cref(directions1), std::cref(directions2)}; std::array elementTypes = {grid1ElementType, grid2ElementType}; // Determine which is the grid we use for outer normal projection const size_t domGrid = (type_==ProjectionType::OUTER_NORMAL) ? 0 : 1; const size_t tarGrid = (type_==ProjectionType::OUTER_NORMAL) ? 1 : 0; ///////////////////////////////////////////////////// // Compute all corners of the intersection polytope ///////////////////////////////////////////////////// const auto corners = std::tie(cornersRef[domGrid].get(),cornersRef[tarGrid].get()); const auto normals = std::tie(directionsRef[domGrid].get(), directionsRef[tarGrid].get()); Projection p(overlap_, maxNormalProduct_); p.project(corners, normals); /* projection */ { const auto& success = get<0>(p.success()); const auto& images = get<0>(p.images()); for (unsigned i = 0; i < dimworld; ++i) { if (success[i]) { std::array corner; corner[domGrid] = localCornerCoords(i, elementTypes[domGrid]); for (unsigned j = 0; j < dim; ++j) corner[tarGrid][j] = images[i][j]; polytopeCorners.push_back(corner); } } } /* inverse projection */ { const auto& success = get<1>(p.success()); const auto& preimages = get<1>(p.images()); for (unsigned i = 0; i < dimworld; ++i) { if (success[i]) { std::array corner; for (unsigned j = 0; j < dim; ++j) corner[domGrid][j] = preimages[i][j]; corner[tarGrid] = localCornerCoords(i, elementTypes[tarGrid]); polytopeCorners.push_back(corner); } } } /* edge intersections */ { for (unsigned i = 0; i < p.numberOfEdgeIntersections(); ++i) { std::array corner; const auto& local = p.edgeIntersections()[i].local; for (unsigned j = 0; j < dim; ++j) { corner[domGrid][j] = local[0][j]; corner[tarGrid][j] = local[1][j]; } polytopeCorners.push_back(corner); } } // check which neighbors might also intersect std::array neighborIntersectsRef = {std::ref(neighborIntersects1), std::ref(neighborIntersects2)}; const auto& refTar = Dune::ReferenceElements::general(elementTypes[tarGrid]); for (int i=0; i(p.success())[refTar.subEntity(i,1,k,dim)]; if (intersects) neighborIntersectsRef[tarGrid].get()[i] = true; } const auto& refDom = Dune::ReferenceElements::general(elementTypes[domGrid]); for (int i=0; i(p.success())[refDom.subEntity(i,1,k,dim)]; if (intersects) neighborIntersectsRef[domGrid].get()[i] = true; } // Compute the edge intersections for (unsigned i = 0; i < p.numberOfEdgeIntersections(); ++i) { const auto& edge = p.edgeIntersections()[i].edge; neighborIntersects1[edge[domGrid]] = true; neighborIntersects2[edge[tarGrid]] = true; } // remove possible doubles removeDoubles(polytopeCorners); // Compute an interior point of the polytope int nPolyCorners = polytopeCorners.size(); // If the polytope is degenerated then there is no intersection if (nPolyCorners=3 /////////////////////////////////////////////////////////////////////////////// // Compute a point in the middle of the polytope and order all corners cyclic ////////////////////////////////////////////////////////////////////////////// std::array center; center[0] = 0; center[1] = 0; for (int i=0; i ordering; computeCyclicOrder(polytopeCorners,center[0],ordering); ////////////////////////////////////// // Add intersections //////////////////////////////// for (size_t i=1; i void ContactMerge::computeCyclicOrder(const std::vector >& polytopeCorners, const LocalCoords& center, std::vector& ordering) const { ordering.resize(polytopeCorners.size()); for (size_t k=0; k angles(polytopeCorners.size()); for (size_t i=0; i1; i--){ bool swapped = false; for (int j=0; j angles[j+1]){ swapped = true; std::swap(angles[j], angles[j+1]); std::swap(ordering[j], ordering[j+1]); } } if (!swapped) break; } } template void ContactMerge::setupNodalDirections(const std::vector& coords1, const std::vector& elements1, const std::vector& elementTypes1, const std::vector& coords2, const std::vector& elements2, const std::vector& elementTypes2) { if (domainDirections_) { // Sample the provided analytical contact direction field nodalDomainDirections_.resize(coords1.size()); for (size_t i=0; i void ContactMerge::computeOuterNormalField(const std::vector& coords, const std::vector& elements, const std::vector& elementTypes, std::vector& normals) { normals.assign(coords.size(),WorldCoords(0)); int offset = 0; for (size_t i=0; i::general(elementTypes[i]).size(dim); // For segments 1, for triangles or quadrilaterals take the first 2 std::array edges; for (int j=1; j<=dim; j++) edges[j-1] = coords[elements[offset + j]] - coords[elements[offset]]; WorldCoords elementNormal; if (dim==1) { elementNormal[0] = edges[0][1]; elementNormal[1] = -edges[0][0]; } else elementNormal = crossProduct(edges[0], edges[1]); elementNormal /= elementNormal.two_norm(); for (int j=0; j void ContactMerge::removeDoubles(std::vector >& polytopeCorners) { size_t counter(1); for (size_t i=1; i #include #include #include #include #include #include #include #include #include #include #include #include #include #include namespace Dune { namespace GridGlue { /** \brief Merge two codimension-1 surfaces that may be a positive distance apart \tparam dimworld Dimension of the world coordinates. \tparam T Type used for coordinates */ template class ContactMerge : public StandardMerge { static constexpr int dim = dimworld-1; static_assert( dim==1 || dim==2, "ContactMerge yet only handles the cases dim==1 and dim==2!"); typedef StandardMerge Base; public: /* E X P O R T E D T Y P E S A N D C O N S T A N T S */ /// @brief the numeric type used in this interface typedef T ctype; /// @brief the coordinate type used in this interface typedef Dune::FieldVector WorldCoords; /// @brief the coordinate type used in this interface typedef Dune::FieldVector LocalCoords; /// @brief Type of the projection, closest point or outer normal projection enum ProjectionType {OUTER_NORMAL, CLOSEST_POINT}; /** * @brief Construct merger given overlap and possible projection directions. * * @param allowedOverlap Allowed overlap of the surfaces * @param domainDirections Projection direction field for the first surface that differ from the default normal field * @param targetDirections Projection direction field for the second surface that differ from the default normal field */ ContactMerge(const T allowedOverlap=T(0), std::function domainDirections=nullptr, std::function targetDirections=nullptr, ProjectionType type = OUTER_NORMAL) : domainDirections_(domainDirections), targetDirections_(targetDirections), overlap_(allowedOverlap), type_(type) {} /** * @brief Construct merger given overlap and type of the projection * @param allowedOverlap Allowed overlap of the surfacs * @param type Type of the projection */ ContactMerge(const T allowedOverlap, ProjectionType type) : overlap_(allowedOverlap), type_(type) {} /** * @brief Set surface direction functions * * The matching of the geometries offers the possibility to specify a function for * the exact evaluation of domain surface normals. If no such function is specified * (default) normals are interpolated. * @param value the new function (or nullptr to unset the function) */ inline void setSurfaceDirections(std::function domainDirections, std::function targetDirections) { domainDirections_ = domainDirections; targetDirections_ = targetDirections; this->valid = false; } //! Set the allowed overlap of the surfaces. void setOverlap(T overlap) { overlap_ = overlap; } //!Get the allowed overlap of the surfaces. T getOverlap() const { return overlap_; } /** * \brief set minimum angle in radians between normals at x and Φ(x) */ void minNormalAngle(T angle) { using std::cos; maxNormalProduct_ = cos(angle); } /** * \brief get minimum angle in radians between normals at x and Φ(x) */ T minNormalAngle() const { using std::acos; return acos(maxNormalProduct_); } protected: typedef typename StandardMerge::SimplicialIntersection SimplicialIntersection; private: /** \brief Vector field on the domain surface which prescribes the direction in which the domain surface is projected onto the target surface */ std::function domainDirections_; std::vector nodalDomainDirections_; /** \brief Vector field on the target surface which prescribes a 'forward' direction. We use the normals of the target side to increase projection robustness. If these cannot be computed from the surface directly (e.g. because it is not properly oriented), they can be given explicitly through the targetDirections field. */ std::function targetDirections_; std::vector nodalTargetDirections_; //! Allow some overlap, i.e. also look in the negative projection directions T overlap_; //! The type of the projection, i.e. closest point projection or outer normal ProjectionType type_; /** * See Projection::m_max_normal_product */ T maxNormalProduct_ = T(-0.1); /** \brief Compute the intersection between two overlapping elements * * The result is a set of simplices. */ void computeIntersections(const Dune::GeometryType& grid1ElementType, const std::vector >& grid1ElementCorners, std::bitset<(1<& neighborIntersects1, unsigned int grid1Index, const Dune::GeometryType& grid2ElementType, const std::vector >& grid2ElementCorners, std::bitset<(1<& neighborIntersects2, unsigned int grid2Index, std::vector& intersections) override; /** * @copydoc StandardMerge::build */ protected: void build(const std::vector >& grid1Coords, const std::vector& grid1Elements, const std::vector& grid1ElementTypes, const std::vector >& grid2Coords, const std::vector& grid2Elements, const std::vector& grid2ElementTypes) override { std::cout<<"ContactMerge building grid!\n"; // setup the nodal direction vectors setupNodalDirections(grid1Coords, grid1Elements, grid1ElementTypes, grid2Coords, grid2Elements, grid2ElementTypes); Base::build(grid1Coords, grid1Elements, grid1ElementTypes, grid2Coords, grid2Elements, grid2ElementTypes); } private: //! Compute local coordinates of a corner static LocalCoords localCornerCoords(int i, const Dune::GeometryType& gt) { const auto& ref = Dune::ReferenceElements::general(gt); return ref.position(i,dim); } protected: //! Order the corners of the intersection polytope in cyclic order void computeCyclicOrder(const std::vector >& polytopeCorners, const LocalCoords& center, std::vector& ordering) const; //! Setup the direction vectors containing the directions for each vertex void setupNodalDirections(const std::vector& coords1, const std::vector& elements1, const std::vector& elementTypes1, const std::vector& coords2, const std::vector& elements2, const std::vector& elementTypes2); //! If no direction field was specified compute the outer normal field void computeOuterNormalField(const std::vector& coords, const std::vector& elements, const std::vector& elementTypes, std::vector& normals); //! Remove all multiples void removeDoubles(std::vector >& polytopeCorners); }; } /* namespace GridGlue */ } /* namespace Dune */ #include "contactmerge.cc" #endif // DUNE_GRIDGLUE_MERGING_CONTACTMERGE_HH dune-grid-glue-2.9.0/dune/grid-glue/merging/intersectionlist.hh000066400000000000000000000216631435125002300245220ustar00rootroot00000000000000// SPDX-FileCopyrightInfo: Copyright © DUNE Project contributors, see file LICENSE.md in module root // SPDX-License-Identifier: LGPL-3.0-or-later OR LicenseRef-GPL-2.0-only-with-dune-grid-glue-exception #ifndef DUNE_GRIDGLUE_MERGING_INTERSECTIONLIST_HH #define DUNE_GRIDGLUE_MERGING_INTERSECTIONLIST_HH 1 #include #include #include #include #include namespace Dune { namespace GridGlue { /** * \tparam L0 type of local coordinates in the first grid * \tparam L1 type of local coordinates in the second grid */ template class IntersectionListProvider { public: /** * type of local coordinates in the first grid */ using Local0 = L0; /** * type of local coordinates in the second grid */ using Local1 = L1; /** * type used to index intersections */ using Index = unsigned int; /** * number of intersections in the merged grid */ virtual std::size_t size() const = 0; /** * number of embeddings of the `intersection`-th intersection into the first grid * * \param intersection number of the intersection */ virtual std::size_t parents0(Index intersection) const = 0; /** * number of embeddings of the `intersection`-th intersection into the second grid * * \param intersection number of the intersection */ virtual std::size_t parents1(Index intersection) const = 0; /** * parent entity of an embedding of an intersection in the first grid * * \param intersection number of the intersection * \param index number of the embedding of the intersection */ virtual Index parent0(Index intersection, unsigned index) const = 0; /** * parent entity of an embedding of an intersection in the second grid * * \param intersection number of the intersection * \param index number of the embedding of the intersection */ virtual Index parent1(Index intersection, unsigned index) const = 0; /** * corner local coordinates of an embedding of an intersection in the first grid * * \param intersection number of the intersection * \param corner number of the corner * \param index number of the embedding of the intersection */ virtual Local0 corner0(Index intersection, unsigned corner, unsigned index) const = 0; /** * corner local coordinates of an embedding of an intersection in the second grid * * \param intersection number of the intersection * \param corner number of the corner * \param index number of the embedding of the intersection */ virtual Local1 corner1(Index intersection, unsigned corner, unsigned index) const = 0; }; namespace Impl { template struct IntersectionListLocal {}; template struct IntersectionListLocal { static std::size_t parents(const P& p, typename P::Index intersection) { return p.parents0(intersection); } static typename P::Index parent(const P& p, typename P::Index intersection, unsigned index) { return p.parent0(intersection, index); } static typename P::Local0 corner(const P& p, typename P::Index intersection, unsigned corner, unsigned index) { return p.corner0(intersection, corner, index); } }; template struct IntersectionListLocal { static std::size_t parents(const P& p, typename P::Index intersection) { return p.parents1(intersection); } static typename P::Index parent(const P& p, typename P::Index intersection, unsigned index) { return p.parent1(intersection, index); } static typename P::Local1 corner(const P& p, typename P::Index intersection, unsigned corner, unsigned index) { return p.corner1(intersection, corner, index); } }; } /* namespace Impl */ /** * \tparam L0 type of local coordinates in the first grid * \tparam L1 type of local coordinates in the second grid */ template class IntersectionList { public: using Provider = IntersectionListProvider; using Index = typename Provider::Index; IntersectionList(const std::shared_ptr& provider) : impl_(provider) {} /** * number of intersections in the merged grid */ std::size_t size() const { return impl_->size(); } /** * number of embeddings of the `intersection`-th intersection into the `I`-th grid * * \tparam I number of the grid (0 or 1) * \param intersection number of the intersection */ template std::size_t parents(Index intersection) const { static_assert(I == 0 or I == 1, "I must be 0 or 1"); // TODO [C++17]: use `if constexpr` instead of indirection return Impl::IntersectionListLocal::parents(*impl_, intersection); } /** * parent entity of an embedding of an intersection in the `I`-th grid * * \tparam I number of the grid (0 or 1) * \param intersection number of the intersection * \param index number of the embedding of the intersection */ template Index parent(Index intersection, unsigned index = 0) const { static_assert(I == 0 or I == 1, "I must be 0 or 1"); // TODO [C++17]: use `if constexpr` instead of indirection return Impl::IntersectionListLocal::parent(*impl_, intersection, index); } /** * corner local coordinates of an embedding of an intersection in the `I`-th grid * * \tparam I number of the grid (0 or 1) * \param intersection number of the intersection * \param corner number of the corner * \param index number of the embedding of the intersection */ template auto corner(Index intersection, unsigned corner, unsigned index = 0) const { static_assert(I == 0 or I == 1, "I must be 0 or 1"); // TODO [C++17]: use `if constexpr` instead of indirection return Impl::IntersectionListLocal::corner(*impl_, intersection, corner, index); } private: std::shared_ptr impl_; }; /** * intersection list provider storing simplicial intersections * * \tparam dim0 dimension of the first grid * \tparam dim1 dimension of the second grid */ template class SimplicialIntersectionListProvider final : public IntersectionListProvider< FieldVector, FieldVector > { using Base = IntersectionListProvider< FieldVector, FieldVector >; public: using Index = typename Base::Index; using Local0 = FieldVector; using Local1 = FieldVector; template using Local = std::conditional_t< I == 0, Local0, Local1 >; /** * simplical intersection */ struct SimplicialIntersection { private: static constexpr int intersectionDim = dim0 < dim1 ? dim0 : dim1; static constexpr int nVertices = intersectionDim + 1; public: SimplicialIntersection() = default; SimplicialIntersection(Index parent0, Index parent1) : parents0{parent0} , parents1{parent1} {} /** * type of a set of corner local coordinates for an embedding */ template using Corners = std::array, nVertices>; /** * list of sets of corner local coordinates for embeddings into the first grid */ std::vector< Corners<0> > corners0 = std::vector< Corners<0> >(1); /** * list of parent entities for embeddings into the first grid */ std::vector< Index > parents0 = std::vector< Index >(1); /** * list of sets of corner local coordinates for embeddings into the second grid */ std::vector< Corners<1> > corners1 = std::vector< Corners<1> >(1); /** * list of parent entities for embeddings into the second grid */ std::vector< Index > parents1 = std::vector< Index >(1); }; SimplicialIntersectionListProvider() = default; SimplicialIntersectionListProvider(std::vector&& intersections) : intersections_(std::move(intersections)) {} auto& intersections() { return intersections_; } std::size_t size() const override { return intersections_.size(); } std::size_t parents0(Index intersection) const override { return intersections_[intersection].parents0.size(); } std::size_t parents1(Index intersection) const override { return intersections_[intersection].parents1.size(); } Index parent0(Index intersection, unsigned index) const override { return intersections_[intersection].parents0[index]; } Index parent1(Index intersection, unsigned index) const override { return intersections_[intersection].parents1[index]; } Local0 corner0(Index intersection, unsigned corner, unsigned index) const override { return intersections_[intersection].corners0[index][corner]; } Local1 corner1(Index intersection, unsigned corner, unsigned index) const override { return intersections_[intersection].corners1[index][corner]; } void clear() { intersections_.clear(); } private: std::vector intersections_; }; } /* namespace GridGlue */ } /* namespace Dune */ #endif dune-grid-glue-2.9.0/dune/grid-glue/merging/merger.hh000066400000000000000000000105661435125002300224010ustar00rootroot00000000000000// -*- tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- // vi: set et ts=4 sw=2 sts=2: // SPDX-FileCopyrightInfo: Copyright © DUNE Project contributors, see file LICENSE.md in module root // SPDX-License-Identifier: LGPL-3.0-or-later OR LicenseRef-GPL-2.0-only-with-dune-grid-glue-exception #ifndef DUNE_GRIDGLUE_MERGING_MERGER_HH #define DUNE_GRIDGLUE_MERGING_MERGER_HH #include #include #include #include namespace Dune { namespace GridGlue { /** \brief Abstract base for all classes that take extracted grids and build sets of intersections \tparam ctype The type used for coordinates (assumed to be the same for both grids) \tparam grid1Dim Dimension of the grid1 grid \tparam grid2Dim Dimension of the grid2 grid \tparam dimworld Dimension of the world space where the coupling takes place */ template class Merger { public: /// @brief the local coordinate type for the grid1 coordinates typedef Dune::FieldVector Grid1Coords; /// @brief the local coordinate type for the grid2 coordinates typedef Dune::FieldVector Grid2Coords; /// @brief the coordinate type used in this interface typedef Dune::FieldVector WorldCoords; using IntersectionList = Dune::GridGlue::IntersectionList; /** * @brief builds the merged grid * * Note that the indices are used consequently throughout the whole class interface just like they are * introduced here. * * @param grid1_coords the grid1 vertices' coordinates ordered like e.g. in 3D x_0 y_0 z_0 x_1 y_1 ... y_(n-1) z_(n-1) * @param grid1_elements array with all grid1 elements represented as corner indices into @c grid1_coords * @param grid1_element_types array with the GeometryType of the elements listed grid1_elements * @param grid2_coords the grid2 vertices' coordinates ordered like e.g. in 3D x_0 y_0 z_0 x_1 y_1 ... y_(n-1) z_(n-1) * @param grid2_elements just like with the grid1_elements and grid1_coords * @param grid2_element_types array with the GeometryType of the elements listed grid2_elements */ virtual void build(const std::vector >& grid1_coords, const std::vector& grid1_elements, const std::vector& grid1_element_types, const std::vector >& grid2_coords, const std::vector& grid2_elements, const std::vector& grid2_element_types) = 0; /** @brief get the number of simplices in the merged grid The indices are then in 0..nSimplices()-1 */ unsigned int nSimplices() const { return intersectionList()->size(); } virtual void clear() = 0; /** * list of intersections * * \note only valid after `build()` was called */ virtual std::shared_ptr intersectionList() const = 0; /** * doc me */ template unsigned int parents(unsigned int idx) const { return intersectionList()->template parents(idx); } /** * @brief get index of grid-n's parent simplex for given merged grid simplex * @tparam n specify which grid * @param idx index of the merged grid simplex * @return index of the parent simplex */ template unsigned int parent(unsigned int idx, unsigned int parId = 0) const { return intersectionList()->template parent(idx, parId); } /** * @brief get the grid-n parent's simplex local coordinates for a particular merged grid simplex corner * (parent's index can be obtained via "parent") * @tparam n specify which grid * @param idx the index of the merged grid simplex * @param corner the index of the simplex' corner * @return local coordinates in grid-n grid1 */ template auto parentLocal(unsigned int idx, unsigned int corner, unsigned int parId = 0) const { return intersectionList()->template corner(idx, corner, parId); } /** \brief Counts the number of times the computeIntersection method has been called * * Used temporarily to speed up the implementation */ unsigned int counter; }; } /* namespace GridGlue */ } /* namespace Dune */ #endif dune-grid-glue-2.9.0/dune/grid-glue/merging/overlappingmerge.cc000066400000000000000000000172631435125002300244550ustar00rootroot00000000000000// -*- tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- // vi: set et ts=4 sw=2 sts=2: // SPDX-FileCopyrightInfo: Copyright © DUNE Project contributors, see file LICENSE.md in module root // SPDX-License-Identifier: LGPL-3.0-or-later OR LicenseRef-GPL-2.0-only-with-dune-grid-glue-exception #ifndef DUNE_GRIDGLUE_OVERLAPPINGMERGE_CC #define DUNE_GRIDGLUE_OVERLAPPINGMERGE_CC //#include namespace Dune { namespace GridGlue { template bool OverlappingMerge::inPlane(std::vector >& points) { T eps = 1e-8; assert(dim1 == 3 && dim2 == 3 && dimworld == 3); assert(points.size() == 4); FieldVector v1 = points[1]-points[0]; FieldVector v2 = points[2]-points[0]; FieldVector v3 = points[3]-points[0]; FieldVector v1xv2; v1xv2[0] = v1[1]*v2[2] - v1[2]*v2[1]; v1xv2[1] = v1[2]*v2[0] - v1[0]*v2[2]; v1xv2[2] = v1[0]*v2[1] - v1[1]*v2[0]; return (std::abs(v3.dot(v1xv2)) < eps); } template void OverlappingMerge::computeIntersections(const Dune::GeometryType& grid1ElementType, const std::vector >& grid1ElementCorners, std::bitset<(1<& neighborIntersects1, unsigned int grid1Index, const Dune::GeometryType& grid2ElementType, const std::vector >& grid2ElementCorners, std::bitset<(1<& neighborIntersects2, unsigned int grid2Index, std::vector& intersections) { using std::min; this->counter++; intersections.clear(); typedef SimplexMethod CM; #ifndef NDEBUG const auto& refElement1 = Dune::ReferenceElements::general(grid1ElementType); const auto& refElement2 = Dune::ReferenceElements::general(grid2ElementType); // A few consistency checks assert((unsigned int)(refElement1.size(dim1)) == grid1ElementCorners.size()); assert((unsigned int)(refElement2.size(dim2)) == grid2ElementCorners.size()); #endif // Make generic geometries representing the grid1- and grid2 element. // this eases computation of local coordinates. typedef MultiLinearGeometry Geometry1; typedef MultiLinearGeometry Geometry2; Geometry1 grid1Geometry(grid1ElementType, grid1ElementCorners); Geometry2 grid2Geometry(grid2ElementType, grid2ElementCorners); // Dirty workaround for the intersection computation scaling problem (part 1/2) std::vector > scaledGrid1ElementCorners(grid1ElementCorners.size()); std::vector > scaledGrid2ElementCorners(grid2ElementCorners.size()); // the scaling parameter is the length minimum of the lengths of the first edge in the grid1 geometry // and the first edge in the grid2 geometry T scaling = min((grid1ElementCorners[0] - grid1ElementCorners[1]).two_norm(), (grid2ElementCorners[0] - grid2ElementCorners[1]).two_norm()); // scale the coordinates according to scaling parameter for (unsigned int i = 0; i < grid1ElementCorners.size(); ++i) { scaledGrid1ElementCorners[i] = grid1ElementCorners[i]; scaledGrid1ElementCorners[i] *= (1.0/scaling); } for (unsigned int i = 0; i < grid2ElementCorners.size(); ++i) { scaledGrid2ElementCorners[i] = grid2ElementCorners[i]; scaledGrid2ElementCorners[i] *= (1.0/scaling); } // get size_type for all the vectors we are using typedef typename std::vector::size_type size_type; const int dimis = dim1 < dim2 ? dim1 : dim2; const size_type n_intersectionnodes = dimis+1; size_type i; std::vector > scaledP(0), P(0); std::vector > H,SX(1< centroid; // local grid1 coordinates of the intersections std::vector > g1local(n_intersectionnodes); // local grid2 coordinates of the intersections std::vector > g2local(n_intersectionnodes); // compute the intersection nodes IntersectionComputation::computeIntersection(scaledGrid1ElementCorners, scaledGrid2ElementCorners, SX,SY,scaledP); // Dirty workaround - rescale the result (part 2/2) P.resize(scaledP.size()); for (unsigned int i = 0; i < scaledP.size(); ++i) { P[i] = scaledP[i]; P[i] *= scaling; } for (size_type i = 0; i < neighborIntersects1.size(); ++i) { if (i < SX.size()) neighborIntersects1[i] = (SX[i].size() > 0); else neighborIntersects1[i] = false; } for (size_type i = 0; i < neighborIntersects2.size(); ++i) { if (i < SY.size()) neighborIntersects2[i] = (SY[i].size() > 0); else neighborIntersects2[i] = false; } // P is an simplex of dimension dimis if (P.size() == n_intersectionnodes) { for (i = 0; i < n_intersectionnodes; ++i) { g1local[i] = grid1Geometry.local(P[i]); g2local[i] = grid2Geometry.local(P[i]); } intersections.emplace_back(grid1Index, grid2Index); for (i = 0; i < n_intersectionnodes; ++i) { intersections.back().corners0[0][i] = g1local[i]; intersections.back().corners1[0][i] = g2local[i]; } } else if (P.size() > n_intersectionnodes) { // P is a union of simplices of dimension dimis assert(dimis != 1); std::vector > global(n_intersectionnodes); // Compute the centroid centroid=0; for (size_type i=0; i < P.size(); i++) centroid += P[i] ; centroid /= static_cast(P.size()) ; // order the points and get intersection face indices H.clear() ; IntersectionComputation::template orderPoints(centroid,SX,SY,P,H); // Loop over all intersection elements for (size_type i=0; i < H.size(); i++) { int hs = H[i].size(); // number of nodes of the intersection // if the intersection element is not degenerated if (hs==dimis) { // create the intersection geometry for ( size_type j=0 ; j < dimis; ++j) { global[j]= P[H[i][j]]; // get the intersection face } // intersection face + centroid = new element global[dimis]=centroid; // create local representation of the intersection for (size_type j = 0; j < n_intersectionnodes; ++j) { g1local[j] = grid1Geometry.local(global[j]); g2local[j] = grid2Geometry.local(global[j]); } intersections.emplace_back(grid1Index,grid2Index); for (size_type j = 0; j < n_intersectionnodes; ++j) { intersections.back().corners0[0][j] = g1local[j]; intersections.back().corners1[0][j] = g2local[j]; } } } } } } /* namespace Dune::GridGlue */ } /* namespace Dune */ #endif // DUNE_GRIDGLUE_OVERLAPPINGMERGE_CC dune-grid-glue-2.9.0/dune/grid-glue/merging/overlappingmerge.hh000066400000000000000000000057551435125002300244720ustar00rootroot00000000000000// -*- tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- // vi: set et ts=4 sw=2 sts=2: // SPDX-FileCopyrightInfo: Copyright © DUNE Project contributors, see file LICENSE.md in module root // SPDX-License-Identifier: LGPL-3.0-or-later OR LicenseRef-GPL-2.0-only-with-dune-grid-glue-exception #ifndef DUNE_GRIDGLUE_MERGING_OVERLAPPINGMERGE_HH #define DUNE_GRIDGLUE_MERGING_OVERLAPPINGMERGE_HH #include #include #include #include #include #include #include #include #include #include #include namespace Dune { namespace GridGlue { /** \brief Computing overlapping grid intersections for grids of different dimensions \tparam dim1 Grid dimension of grid 1 \tparam dim2 Grid dimension of grid 2 \tparam dimworld World dimension \tparam T Type used for coordinates */ template class OverlappingMerge : public StandardMerge { public: /* E X P O R T E D T Y P E S A N D C O N S T A N T S */ /// @brief the numeric type used in this interface typedef T ctype; /// @brief the coordinate type used in this interface typedef Dune::FieldVector WorldCoords; /// @brief the coordinate type used in this interface //typedef Dune::FieldVector LocalCoords; OverlappingMerge() {} protected: typedef typename StandardMerge::SimplicialIntersection SimplicialIntersection; /** \brief Compute the intersection between two overlapping elements The result is a set of simplices. \param grid1ElementType Type of the first element to be intersected \param grid1ElementCorners World coordinates of the corners of the first element \param grid2ElementType Type of the second element to be intersected \param grid2ElementCorners World coordinates of the corners of the second element */ void computeIntersections(const Dune::GeometryType& grid1ElementType, const std::vector >& grid1ElementCorners, std::bitset<(1<& neighborIntersects1, unsigned int grid1Index, const Dune::GeometryType& grid2ElementType, const std::vector >& grid2ElementCorners, std::bitset<(1<& neighborIntersects2, unsigned int grid2Index, std::vector& intersections); private: bool inPlane(std::vector >& points); }; } /* namespace Dune::GridGlue */ } /* namespace Dune */ #include "overlappingmerge.cc" #endif // DUNE_GRIDGLUE_MERGING_OVERLAPPINGMERGE_HH dune-grid-glue-2.9.0/dune/grid-glue/merging/simplexintersection.cc000066400000000000000000001442011435125002300252100ustar00rootroot00000000000000// -*- tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- // vi: set et ts=4 sw=2 sts=2: // SPDX-FileCopyrightInfo: Copyright © DUNE Project contributors, see file LICENSE.md in module root // SPDX-License-Identifier: LGPL-3.0-or-later OR LicenseRef-GPL-2.0-only-with-dune-grid-glue-exception namespace Dune { namespace GridGlue { template inline void simplexSubdivision(std::integral_constant,const std::vector >& elementCorners, std::vector >& subElements, std::vector >& faceIds); template inline void simplexSubdivision(std::integral_constant,const std::vector >& elementCorners, std::vector >& subElements, std::vector >& faceIds); template inline void simplexSubdivision(std::integral_constant,const std::vector >& elementCorners, std::vector >& subElements, std::vector >& faceIds); template inline void simplexSubdivision(std::integral_constant,const std::vector >& elementCorners, std::vector >& subElements, std::vector >& faceIds); // *****************SIMPLEX INTERSECTION COMPUTATION METHODS *************************** template class SimplexMethod : public ComputationMethod{ static_assert(dim1 > dim2, "Specialization missing"); friend class ComputationMethod; public: typedef FieldVector Vector; static const int grid1Dimension = dim1; static const int grid2Dimension = dim2; static const int intersectionDimension = dim2; static bool computeIntersectionPoints(const std::vector >& X, const std::vector >& Y, std::vector > & SX, std::vector > & SY, std::vector > & P) { return SimplexMethod::computeIntersectionPoints(Y, X, SY, SX, P); } static void grid1_subdivisions(const std::vector& elementCorners, std::vector >& subElements, std::vector >& faceIds) { simplexSubdivision(std::integral_constant(), elementCorners,subElements, faceIds); } static void grid2_subdivisions(const std::vector& elementCorners, std::vector >& subElements, std::vector >& faceIds) { simplexSubdivision(std::integral_constant(), elementCorners, subElements, faceIds); } }; // POINTS ARE EQUAL template class SimplexMethod : public ComputationMethod{ friend class ComputationMethod; public: typedef FieldVector Vector; static const int grid1Dimension = 0; static const int grid2Dimension = 0; static const int intersectionDimension = 0; static bool computeIntersectionPoints( const std::vector >& X, const std::vector >& Y, std::vector > & SX, std::vector > & SY, std::vector > & P) { assert(X.size() == 1 && Y.size() == 1); P.clear(); SX.clear(); SY.clear(); int k; T eps = 1e-8; T a = X[0].infinity_norm(); T b = Y[0].infinity_norm(); T c = (X[0] - Y[0]).infinity_norm(); if (c <= eps*a || c <= eps*b || (a& elementCorners, std::vector >& subElements, std::vector >& faceIds) { simplexSubdivision(std::integral_constant(), elementCorners,subElements, faceIds); } static void grid2_subdivisions(const std::vector& elementCorners, std::vector >& subElements, std::vector >& faceIds) { simplexSubdivision(std::integral_constant(), elementCorners, subElements, faceIds); } }; // POINT ON LINE SEGMENT - :) template class SimplexMethod : public ComputationMethod{ friend class ComputationMethod; public: typedef FieldVector Vector; static const int grid1Dimension = 0; static const int grid2Dimension = 1; static const int intersectionDimension = 0; static bool computeIntersectionPoints(const std::vector >& X, const std::vector >& Y, std::vector > & SX, std::vector > & SY, std::vector > & P) { assert(X.size() == 1 && Y.size() == 2); P.clear(); SX.clear(); SY.clear(); SY.resize(2); if (dimWorld == 1) { T lowerBound = std::max(X[0][0], std::min(Y[0][0],Y[1][0])); T upperBound = std::min(X[0][0], std::max(Y[0][0],Y[1][0])); if (lowerBound <= upperBound) { // Intersection is non-empty insertPoint(X[0],P); return true; } } else { T eps = 1e-8; // check whether the point is on the segment FieldVector v0 = X[0] - Y[0]; FieldVector v1 = X[0] - Y[1]; FieldVector v2 = Y[1] - Y[0]; T s = v0.dot(v1); T t = v0.two_norm()/v2.two_norm(); v2*=t; v2+=Y[0]; v2-=X[0]; if (v2.infinity_norm() < eps && s<=eps && t<=1+eps) { int k = insertPoint(X[0],P); if (s < eps && t < eps) SY[0].push_back(k); else if (s < eps && t>1-eps) SY[1].push_back(k); return true; } } return false; } static void grid1_subdivisions(const std::vector& elementCorners, std::vector >& subElements, std::vector >& faceIds) { simplexSubdivision(std::integral_constant(), elementCorners,subElements, faceIds); } static void grid2_subdivisions(const std::vector& elementCorners, std::vector >& subElements, std::vector >& faceIds) { simplexSubdivision(std::integral_constant(), elementCorners, subElements, faceIds); } }; // POINT IN TRIANGLE - :) template class SimplexMethod : public ComputationMethod{ friend class ComputationMethod; public: typedef FieldVector Vector; static const int grid1Dimension = 0; static const int grid2Dimension = 2; static const int intersectionDimension = 0; static bool computeIntersectionPoints(const std::vector >& X, const std::vector >& Y, std::vector > & SX, std::vector > & SY, std::vector > & P) { assert(X.size() == 1 && Y.size() == 3 && dimWorld > 1); P.clear(); SX.clear(); SY.clear(); SY.resize(3); int k; // If not, check whether it is inside the triangle double eps= 1e-8 ; // tolerance for relative error FieldVector v0,v1,v2,r; v0 = Y[1] - Y[0]; v1 = Y[2] - Y[0]; v2 = X[0] - Y[0]; T s,t,d; d = ((v0.dot(v0))*(v1.dot(v1)) - (v0.dot(v1))*(v0.dot(v1))); s = ((v1.dot(v1))*(v0.dot(v2)) - (v0.dot(v1))*(v1.dot(v2))) / d; t = ((v0.dot(v0))*(v1.dot(v2)) - (v0.dot(v1))*(v0.dot(v2))) / d; v0*=s; v1*=t; r = Y[0] + v0 + v1; if (s > -eps && t > -eps && (s+t)< 1+eps && (r-X[0]).infinity_norm() < eps) { k = insertPoint(X[0],P); if (t < eps) { // t ~ 0, s varies -> edge 0 SY[0].push_back(k); } if (s < eps) { // s ~ 0, t varies -> edge 1 SY[1].push_back(k); } if (s+t > 1-eps) { // s+t ~ 1 -> edge 2 SY[2].push_back(k); } return true; } return false; } static void grid1_subdivisions(const std::vector& elementCorners, std::vector >& subElements, std::vector >& faceIds) { simplexSubdivision(std::integral_constant(), elementCorners,subElements, faceIds); } static void grid2_subdivisions(const std::vector& elementCorners, std::vector >& subElements, std::vector >& faceIds) { simplexSubdivision(std::integral_constant(), elementCorners, subElements, faceIds); } }; // POINT IN TETRAHEDRON - : ) template class SimplexMethod : public ComputationMethod{ friend class ComputationMethod; public: typedef FieldVector Vector; static const int grid1Dimension = 0; static const int grid2Dimension = 3; static const int intersectionDimension = 0; static bool computeIntersectionPoints(const std::vector >& X, const std::vector >& Y, std::vector > & SX, std::vector > & SY, std::vector > & P) { assert(X.size() == 1 && Y.size() == 4 && dimWorld == 3); P.clear(); SX.clear(); SY.clear(); SY.resize(4); T eps = 1e-8; // if not, check whether its inside the tetrahedron FieldMatrix D,DD ; D[0][0] = Y[0][0] ; D[0][1] = Y[1][0] ; D[0][2] = Y[2][0] ; D[0][3] = Y[3][0] ; D[1][0] = Y[0][1] ; D[1][1] = Y[1][1] ; D[1][2] = Y[2][1] ; D[1][3] = Y[3][1] ; D[2][0] = Y[0][2] ; D[2][1] = Y[1][2] ; D[2][2] = Y[2][2] ; D[2][3] = Y[3][2] ; D[3][0] = 1 ; D[3][1] = 1 ; D[3][2] = 1 ; D[3][3] = 1 ; std::array detD; detD[0] = D.determinant(); for(unsigned i = 1; i < detD.size(); ++i) { DD = D; for (unsigned d = 0; d < dimWorld; ++d) DD[d][i-1] = X[0][d]; detD[i] = DD.determinant(); if (std::abs(detD[i]) > eps && std::signbit(detD[0]) != std::signbit(detD[i])) return false; // We are outside. } int k = insertPoint(X[0],P); unsigned int faces[4] = {3,2,1,0}; for (unsigned i = 1; i < detD.size(); ++i) if(std::abs(detD[i]) < eps) SY[faces[i-1]].push_back(k); // on triangle not containing node i-1 return true; } static void grid1_subdivisions(const std::vector& elementCorners, std::vector >& subElements, std::vector >& faceIds) { simplexSubdivision(std::integral_constant(), elementCorners,subElements, faceIds); } static void grid2_subdivisions(const std::vector& elementCorners, std::vector >& subElements, std::vector >& faceIds) { simplexSubdivision(std::integral_constant(), elementCorners, subElements, faceIds); } }; // SEGEMENT-SEGMENT INTERSECTION - :) template class SimplexMethod : public ComputationMethod{ friend class ComputationMethod; public: typedef FieldVector Vector; static const int grid1Dimension = 1; static const int grid2Dimension = 1; static const int intersectionDimension = 1; static bool computeIntersectionPoints(const std::vector >& X, const std::vector >& Y, std::vector > & SX, std::vector > & SY, std::vector > & P) { assert(X.size() == 2 && Y.size() == 2); P.clear(); SX.clear(); SY.clear(); SX.resize(2); SY.resize(2); T eps = 1e-8; int k,idX_min=-1,idX_max=-1,idY_min=-1,idY_max=-1; // compute intersections switch (dimWorld) { case 1: // d { FieldVector lowerbound(std::max(std::min(X[0][0],X[1][0]), std::min(Y[0][0],X[1][0]))); FieldVector upperbound(std::min(std::max(X[0][0],X[1][0]), std::max(Y[0][0],Y[1][0]))); if (lowerbound[0] < upperbound[0]) { // Intersection is non-empty idX_min = (std::min(X[0][0],X[1][0]) < std::min(Y[0][0],Y[1][0]))?(-1):((X[0][0] std::max(Y[0][0],Y[1][0]))?(-1):((X[0][0]>X[1][0])?(0):(1)); if (idX_max < 0) idY_max = ((Y[0][0]>Y[1][0])?(0):(1)); k = insertPoint(lowerbound,P); if (idX_min >= 0) SX[idX_min].push_back(k); else SY[idY_min].push_back(k); k = insertPoint(upperbound,P); if (idX_max >= 0) SX[idX_max].push_back(k); else SY[idY_max].push_back(k); return true; } return false; } case 2: // solve X0 + r_0 * (X1 - X0) = Y0 + r_1 * (Y1 - Y0) { // get size_type for all the vectors we are using FieldMatrix A; A[0][0] = X[1][0] - X[0][0]; A[0][1] = Y[0][0] - Y[1][0]; A[1][0] = X[1][1] - X[0][1]; A[1][1] = Y[0][1] - Y[1][1]; if (std::abs(A.determinant())>eps) { // lines are non parallel and not degenerated FieldVector p,r,b = Y[0] - X[0]; A.solve(r,b) ; if ((r[0]>-eps)&&(r[0]<=1+eps)&&(r[1]>-eps)&&(r[1]<1+eps)) { p = X[1] - X[0]; p *= r[0] ; p += X[0] ; k = insertPoint(p,P); if(r[0] < eps) { // X = X_0 + r_0 (X_1 - X_0) = X_0 SX[0].push_back(k); P[k] = X[0]; } else if(r[0] > 1-eps) { // X = X_0 + r_0 (X_1 - X_0) = X_1 SX[1].push_back(k); P[k] = X[1]; } if(r[1] < eps){ // Y = Y_0 + r_1 (Y_1 - Y_0) = Y_0 SY[0].push_back(k); P[k] = Y[0]; } else if(r[1] > 1-eps) { // Y = Y_0 + r_1 (Y_1 - Y_0) = Y_1 SY[1].push_back(k); P[k] = Y[1]; } return true; } } else if ((X[1]-X[0]).infinity_norm() > eps && (Y[1]-Y[0]).infinity_norm() > eps) { // lines are paralles, but non degenerated bool found = false; // use triangle equality ||a - b||_2 = || a -c ||_2 + || c - b ||_2 for non perpendicular lines for (unsigned i = 0; i < 2; ++i) { if (std::abs((Y[i]-X[0]).two_norm() + std::abs((Y[i]-X[1]).two_norm()) - std::abs((X[1]-X[0]).two_norm())) < eps) { k = insertPoint(Y[i],P); SY[i].push_back(k); found = true; } if (std::abs((X[i]-Y[0]).two_norm() + std::abs((X[i]-Y[1]).two_norm()) - std::abs((Y[1]-Y[0]).two_norm())) < eps) { k = insertPoint(X[i],P); SX[i].push_back(k); found = true; } } return found; } return false; } case 3: // solve X0 + r_0 * (X1 - X0) = Y0 + r_1 * (Y1 - Y0) { FieldVector dX, dY, dZ, cXY, cYZ; dX = X[1]-X[0]; dY = Y[1]-Y[0]; dZ = Y[0]-X[0]; cXY[0] = dX[1]* dY[2] - dX[2]* dY[1]; cXY[1] = dX[2]* dY[0] - dX[0]* dY[2]; cXY[2] = dX[0]* dY[1] - dX[1]* dY[0]; if (fabs(dZ.dot(cXY)) < eps*1e+3 && cXY.infinity_norm()>eps) { // coplanar, but not aligned cYZ[0] = dY[1]* dZ[2] - dY[2]* dZ[1]; cYZ[1] = dY[2]* dZ[0] - dY[0]* dZ[2]; cYZ[2] = dY[0]* dZ[1] - dY[1]* dZ[0]; T s = -cYZ.dot(cXY) / cXY.two_norm2(); if (s > -eps && s < 1+eps) { dX*= s; dX+= X[0]; T o = (dX - Y[0]).two_norm() + (dX- Y[1]).two_norm(); if (std::abs(o-dY.two_norm()) < eps) { k = insertPoint(dX,P); \ if (s 1-eps) { P[k] = X[1]; SX[1].push_back(k); } else if ((dX - Y[0]).two_norm() < eps) { P[k] = Y[0]; SY[0].push_back(k); } else if((dX - Y[1]).two_norm() < eps) { P[k] = Y[1]; SY[1].push_back(k); } return true; } } } else if (cXY.infinity_norm() <= eps) {// lines are parallel bool found = false; // use triangle equality ||a - b||_2 = || a -c ||_2 + || c - b ||_2, // under the assumption (a-c)*(c-b) > 0 or (a-c) = 0 or (c-b) = 0 for (unsigned i = 0; i < 2; ++i) { if ((std::abs((Y[i]-X[0]).two_norm() + std::abs((Y[i]-X[1]).two_norm()) // triangle equality - std::abs((X[1]-X[0]).two_norm())) < eps) && (std::abs((Y[i]-X[0]).dot((Y[i]-X[1]))) > eps // assumption || (Y[i]-X[0]).infinity_norm() < eps || (Y[i]-X[1]).infinity_norm() < eps)) { k = insertPoint(Y[i],P); SY[i].push_back(k); found = true; } if (std::abs((X[i]-Y[0]).two_norm() + std::abs((X[i]-Y[1]).two_norm()) // triangle equality - std::abs((Y[1]-Y[0]).two_norm())) < eps && (std::abs((X[i]-Y[0]).dot((X[i]-Y[1]))) > eps // assumption || (X[i]-Y[0]).infinity_norm() < eps || (X[i]-Y[1]).infinity_norm() < eps)){ k = insertPoint(X[i],P); SX[i].push_back(k); found = true; } } return found; } return false; } } return false; } static void grid1_subdivisions(const std::vector& elementCorners, std::vector >& subElements, std::vector >& faceIds) { simplexSubdivision(std::integral_constant(), elementCorners,subElements, faceIds); } static void grid2_subdivisions(const std::vector& elementCorners, std::vector >& subElements, std::vector >& faceIds) { simplexSubdivision(std::integral_constant(), elementCorners, subElements, faceIds); } }; // SEGEMENT-TRIANGLE INTERSECTION - : ) template class SimplexMethod : public ComputationMethod{ friend class ComputationMethod; public: typedef FieldVector Vector; static const int grid1Dimension = 1; static const int grid2Dimension = 2; static const int intersectionDimension = 1; static bool computeIntersectionPoints(const std::vector >& X, const std::vector >& Y, std::vector > & SX, std::vector > & SY, std::vector > & P) { assert(X.size() == 2 && Y.size() == 3 && dimWorld > 1); P.clear(); SX.clear(); SY.clear(); SX.resize(2); SY.resize(3); int k; std::vector > surfPts, edge(2), pni(1); std::vector > hSX, hSY; // is any segment point inside the triangle? for (unsigned ni = 0; ni < 2; ++ni) { pni[0] = X[ni]; if (SimplexMethod::computeIntersectionPoints(pni,Y,hSX,hSY,surfPts)) { k = insertPoint(X[ni],P); SX[ni].push_back(k); for (unsigned e=0; e < 3; ++e) if (hSY[e].size() > 0) SY[e].push_back(k); } surfPts.clear(); hSX.clear(); hSY.clear(); } if (P.size() >= 2) // we cannot have more than two intersection points return true; unsigned int faces[3] = {0,2,1}; // do triangle faces intersect with the segment? for (unsigned ni = 0; ni < 3; ++ni) { edge[0] = Y[ni]; edge[1] = Y[(ni+1)%3]; if (SimplexMethod::computeIntersectionPoints(X,edge,hSX,hSY,surfPts)) { for (unsigned ne = 0; ne < surfPts.size(); ++ne) { k = insertPoint(surfPts[ne],P); SY[faces[ni]].push_back(k); if (hSX[0].size() > 0) SX[0].push_back(k); if (hSX[1].size() > 0) SX[1].push_back(k); } if (P.size() >= 2) // we cannot have more than two intersection points return true; surfPts.clear(); hSX.clear(); hSY.clear(); } } if (P.size() >= 2) // we cannot have more than two intersection points return true; // if line and triangle are not coplanar in 3d and do not intersect at boundaries if (dimWorld == 3) { T eps = 1e-8; Dune::FieldVector B,r,p ; Dune::FieldMatrix A ; B = Y[0] - X[0] ; for (unsigned i = 0; i < dimWorld; ++i) { A[i][0] = (X[1][i] - X[0][i]); A[i][1] = (Y[0][i] - Y[1][i]); A[i][dimWorld-1] = (Y[0][i] - Y[dimWorld-1][i]); } if (std::abs(A.determinant())>eps) { A.solve(r,B) ; if ((r[0]>=-eps)&&(r[0]<=1+eps) &&(r[1]>=-eps)&&(r[1]<=1+eps) &&(r[2]>=-eps)&&(r[2]<=1+eps) &&(r[1]+r[2]>=-eps) &&(r[1]+r[2]<=1+eps)) { p = X[1] - X[0] ; p *= r[0] ; p += X[0] ; k = insertPoint(p,P); if (std::abs(r[0]) < eps) // we prefer exact locations P[k] = X[0]; else if (std::abs(r[0]) > 1-eps) P[k] = X[1]; else if (std::abs(r[1]) < eps && std::abs(r[2]) < eps) P[k] = Y[0]; else if (std::abs(r[1]) < eps && std::abs(r[2]) > 1-eps) P[k] = Y[2]; else if (std::abs(r[1]) > 1-eps && std::abs(r[2]) < eps) P[k] = Y[1]; if (std::abs(r[1]) < eps) SY[1].push_back(k); if (std::fabs(r[dimWorld-1]) < eps) SY[0].push_back(k); if (std::fabs(r[1]+r[dimWorld-1] - 1) < eps) SY[2].push_back(k); return true ; } } } return false ; } static void grid1_subdivisions(const std::vector& elementCorners, std::vector >& subElements, std::vector >& faceIds) { simplexSubdivision(std::integral_constant(), elementCorners,subElements, faceIds); } static void grid2_subdivisions(const std::vector& elementCorners, std::vector >& subElements, std::vector >& faceIds) { simplexSubdivision(std::integral_constant(), elementCorners, subElements, faceIds); } }; // SEGEMENT-TETRAHEDRON INTERSECTION - : ) template class SimplexMethod : public ComputationMethod{ friend class ComputationMethod; public: typedef FieldVector Vector; static const int grid1Dimension = 1; static const int grid2Dimension = 3; static const int intersectionDimension = 1; static bool computeIntersectionPoints(const std::vector >& X, const std::vector >& Y, std::vector > & SX, std::vector > & SY, std::vector > & P) { assert(X.size() == 2 && Y.size() == 4 && dimWorld > 2); std::vector indices; std::vector > surfPts; std::vector > hSX, hSY; P.clear(); SX.clear(); SY.clear(); SX.resize(2); SY.resize(4); std::vector > pni(1); bool b = false; // check whether the corners of the segment are contained in the tetrahedron for (unsigned int ci = 0; ci < 2; ++ ci) { pni[0] = X[ci]; if(SimplexMethod::computeIntersectionPoints(pni,Y,hSX,hSY,surfPts)) { int k = insertPoint(X[ci],P); SX[ci].push_back(k); b=true; } surfPts.clear(); hSX.clear(); hSY.clear(); } if (P.size() == 2) return true; unsigned int faces[4] = {0,3,2,1}; // check whether tetrahedron faces intersect with segment std::vector > triangle(3); for (unsigned int ci = 0; ci < 4; ++ci) { // iterate over all faces triangle[0] = Y[ci]; triangle[1] = Y[(ci+1)%4]; triangle[2] = Y[(ci+2)%4]; if (SimplexMethod::computeIntersectionPoints(X,triangle,hSX,hSY,surfPts)) { // seg - triangle intersection std::vector indices(surfPts.size()); for (unsigned int np = 0; np < surfPts.size(); ++np) { int k = insertPoint(surfPts[np],P); indices[np]=k; SY[faces[ci]].push_back(k); } // hSX[*] is nonempty if the intersection point is on an edge of the current face of Y for (unsigned int np = 0; np < hSX[0].size(); ++np) SX[0].push_back(indices[hSX[0][np]]); for (unsigned int np = 0; np < hSX[1].size(); ++np) SX[0].push_back(indices[hSX[1][np]]); b = true; } surfPts.clear(); hSX.clear(); hSY.clear(); } return b; } static void grid1_subdivisions(const std::vector& elementCorners, std::vector >& subElements, std::vector >& faceIds) { simplexSubdivision(std::integral_constant(), elementCorners,subElements, faceIds); } static void grid2_subdivisions(const std::vector& elementCorners, std::vector >& subElements, std::vector >& faceIds) { simplexSubdivision(std::integral_constant(), elementCorners, subElements, faceIds); } }; // TRIANGLE -TRIANGLE INTERSECTION template class SimplexMethod : public ComputationMethod{ friend class ComputationMethod; public: typedef FieldVector Vector; static const int grid1Dimension = 2; static const int grid2Dimension = 2; static const int intersectionDimension = 2; static bool computeIntersectionPoints(const std::vector >& X, const std::vector >& Y, std::vector > & SX, std::vector > & SY, std::vector > & P) { assert(X.size() == 3 && Y.size() == 3 && dimWorld > 1); P.clear(); SX.clear(); SY.clear(); SX.resize(3); SY.resize(3); bool b = false; std::vector > edge(2); std::vector > surfPts; std::vector > hSX, hSY; std::vector indices; unsigned int faces[3] = {0,2,1}; for (unsigned int ni = 0; ni < 3; ++ni) { // check whether the faces of triangle Y intersect the triangle X edge[0] = Y[ni]; edge[1] = Y[(ni+1)%3]; if(SimplexMethod::computeIntersectionPoints(X,edge,hSX,hSY,surfPts)) { indices.resize(surfPts.size()); // add intersections of edges of Y with triangle X for (unsigned int np = 0; np < surfPts.size(); ++np) { int k = insertPoint(surfPts[np],P); indices[np] = k; SY[faces[ni]].push_back(k); // add edge data } b=true; } if (P.size() >= 6) return true; surfPts.clear(); hSX.clear(); hSY.clear(); // check whether the faces of triangle X intersect the triangle Y edge[0] = X[ni]; edge[1] = X[(ni+1)%3]; if(SimplexMethod::computeIntersectionPoints(edge,Y,hSX,hSY,surfPts)) { indices.resize(surfPts.size()); // add intersections of edges of X with triangle Y for (unsigned int np = 0; np < surfPts.size(); ++np) { int k = insertPoint(surfPts[np],P); indices[np] = k; SX[faces[ni]].push_back(k); // add edge data } b=true; } if (P.size() >= 6) return true; surfPts.clear(); hSX.clear(); hSY.clear(); } return b; } static void grid1_subdivisions(const std::vector& elementCorners, std::vector >& subElements, std::vector >& faceIds) { simplexSubdivision(std::integral_constant(), elementCorners,subElements, faceIds); } static void grid2_subdivisions(const std::vector& elementCorners, std::vector >& subElements, std::vector >& faceIds) { simplexSubdivision(std::integral_constant(), elementCorners, subElements, faceIds); } }; // TRIANGLE -TETRAHEDRON INTERSECTION -: ) template class SimplexMethod : public ComputationMethod{ friend class ComputationMethod; public: typedef FieldVector Vector; static const int grid1Dimension = 2; static const int grid2Dimension = 3; static const int intersectionDimension = 2; static bool computeIntersectionPoints(const std::vector >& X, const std::vector >& Y, std::vector > & SX, std::vector > & SY, std::vector > & P) { assert(X.size() == 3 && Y.size() == 4 && dimWorld > 2); P.clear(); SX.clear(); SY.clear(); SX.resize(3); SY.resize(4); bool b = false; int k,ni,np, ep; std::vector > surfPts, xni(1); std::vector > hSX, hSY; unsigned int fiX[3][2]; fiX[0][0] = 0; fiX[1][0] = 0; fiX[2][0] = 1; // faces to node fiX[0][1] = 1; fiX[1][1] = 2; fiX[2][1] = 2; // 1st step: check whether the points of the triangle are contained in the tetrahedron for (ni = 0; ni < 3; ++ni) { xni[0] = X[ni]; if (SimplexMethod::computeIntersectionPoints(xni,Y,hSX,hSY,surfPts)) { std::vector indices(surfPts.size()); for (np = 0; np < surfPts.size(); ++np) { k = insertPoint(X[ni],P); indices[np] = k; SX[fiX[ni][0]].push_back(k); // the corresponding edges to the node are ni and (ni+2)%3 SX[fiX[ni][1]].push_back(k); } for (ep = 0; ep < 4; ++ep) { for (np = 0; np < hSY[ep].size();++np) { SY[ep].push_back(indices[hSY[ep][np]]); } } b = true; } hSX.clear(); hSY.clear(); surfPts.clear(); } if (P.size() == 3) // intersection is given by all three corners of the triangle return true; // note: points of Y in X is called indirectly via triangle-triangle intesection // check whether the triangles of the one tetrahedron intersect the triangle unsigned int facesY[4] = {0,3,2,1}; // face ordering std::vector > triangle(3); for (ni = 0; ni < 4; ++ni) { triangle[0] = Y[ni]; triangle[1] = Y[(ni+1)%4]; triangle[2] = Y[(ni+2)%4]; if (SimplexMethod::computeIntersectionPoints(X,triangle,hSX,hSY,surfPts)) { std::vector indices(surfPts.size()); for (np = 0; np < surfPts.size(); ++np) { k = insertPoint(surfPts[np],P); indices[np]=k; SY[facesY[ni]].push_back(k); } // SX[*] is nonempty if the face * of X is intersected for (np = 0; np < 3; ++np) { for (ep = 0; ep < hSX[np].size(); ++ep) { SX[np].push_back(indices[hSX[np][ep]]); } } b = true; } hSX.clear(); hSY.clear(); surfPts.clear(); } return b; } static void grid1_subdivisions(const std::vector& elementCorners, std::vector >& subElements, std::vector >& faceIds) { simplexSubdivision(std::integral_constant(), elementCorners,subElements, faceIds); } static void grid2_subdivisions(const std::vector& elementCorners, std::vector >& subElements, std::vector >& faceIds) { simplexSubdivision(std::integral_constant(), elementCorners, subElements, faceIds); } }; template class SimplexMethod : public ComputationMethod{ friend class ComputationMethod; public: typedef FieldVector Vector; static const int grid1Dimension = 3; static const int grid2Dimension = 3; static const int intersectionDimension = 3; static bool computeIntersectionPoints(const std::vector >& X, const std::vector >& Y, std::vector > & SX, std::vector > & SY, std::vector > & P) { assert(X.size() == 4 && Y.size() == 4 && dimWorld > 2); P.clear(); SX.clear(); SY.clear(); SX.resize(4); SY.resize(4); bool b = false; int ci,np,ne,k,ni[4][3]; ni[0][0]= 0 ; ni[0][1]= 1 ; ni[0][2]= 2 ; // faces touching each node ni[1][0]= 0 ; ni[1][1]= 1 ; ni[1][2]= 3 ; ni[2][0]= 0 ; ni[2][1]= 2 ; ni[2][2]= 3 ; ni[3][0]= 1 ; ni[3][1]= 2 ; ni[3][2]= 3 ; // temporal data container std::vector > surfPts, pci(1); std::vector > hSX, hSY; // check whether the points of the one tetrahedron are contained in the other tetrahedron for (ci = 0; ci < 3; ++ci) { pci[0] = X[ci]; // point of X is inside Y if (SimplexMethod::computeIntersectionPoints(pci,Y,hSX,hSY,surfPts)) { std::vector indices(surfPts.size()); for (np = 0; np < surfPts.size(); ++np) { k = insertPoint(X[ci],P); indices[np]=k; SX[ni[ci][0]].push_back(k); // add face data SX[ni[ci][1]].push_back(k); SX[ni[ci][2]].push_back(k); } // hSY[*] is nonempty if X[ci] is on the face * of Y for (ne = 0; ne < 4; ++ne) { for (np = 0; np < hSY[ne].size(); ++np) { SY[ne].push_back(indices[hSY[ne][np]]); } } b = true; } hSX.clear(); hSY.clear(); surfPts.clear(); // probably one point of Y is inside X surfPts.resize(0); pci[0]=Y[ci]; if (SimplexMethod::computeIntersectionPoints(pci,X,hSY,hSX,surfPts)) { std::vector indices(surfPts.size()); for (np = 0; np < surfPts.size(); ++np) { k = insertPoint(Y[ci],P); indices[np]=k; SY[ni[ci][0]].push_back(k); // add face data SY[ni[ci][1]].push_back(k); SY[ni[ci][2]].push_back(k); } // hSX[*] is nonempty if the point Y[ci] is on the face * of X for (ne = 0; ne < 4; ++ne) { for (np = 0; np < hSX[ne].size(); ++np) { SX[ne].push_back(indices[hSX[ne][np]]); } } b = true; } hSX.clear(); hSY.clear(); surfPts.clear(); } // check whether the triangles of the one tetrahedron intersect the triangles // of the other tetrahedron unsigned int faces[4] = {0,3,2,1}; // face ordering std::vector > triangle(3); for (ci = 0; ci < 4; ++ci) { // iterate over faces of Y triangle[0] = Y[ci]; triangle[1] = Y[(ci+1)%4]; triangle[2] = Y[(ci+2)%4]; if(SimplexMethod::computeIntersectionPoints(X, triangle,hSX,hSY,surfPts)) { // add Triangle of Y intersects tetrahedron Y data for (np = 0; np < surfPts.size(); ++np) { k = insertPoint(surfPts[np],P); SY[faces[ci]].push_back(k); // add face data } b = true; } hSX.clear(); hSY.clear(); surfPts.clear(); triangle[0] = X[ci]; triangle[1] = X[(ci+1)%4]; triangle[2] = X[(ci+2)%4]; if(SimplexMethod::computeIntersectionPoints(Y, triangle,hSY,hSX,surfPts)) { // add Triangle of Y intersects tetrahedron Y data for (np = 0; np < surfPts.size(); ++np) { k = insertPoint(surfPts[np],P); SX[faces[ci]].push_back(k); // add face data } b = true; } hSX.clear(); hSY.clear(); surfPts.clear(); } return b; } static void grid1_subdivisions(const std::vector& elementCorners, std::vector >& subElements, std::vector >& faceIds) { simplexSubdivision(std::integral_constant(), elementCorners,subElements, faceIds); } static void grid2_subdivisions(const std::vector& elementCorners, std::vector >& subElements, std::vector >& faceIds) { simplexSubdivision(std::integral_constant(), elementCorners, subElements, faceIds); } }; template inline void simplexSubdivision(std::integral_constant, const std::vector >& elementCorners, std::vector >& subElements, std::vector >& faceIds) { subElements.resize(1); faceIds.resize(0); subElements[0].push_back(0); } template inline void simplexSubdivision(std::integral_constant, const std::vector >& elementCorners, std::vector >& subElements, std::vector >& faceIds) { subElements.resize(1); faceIds.resize(1); subElements[0].push_back(0); subElements[0].push_back(1); faceIds[0].push_back(0); faceIds[0].push_back(1); } template inline void simplexSubdivision(std::integral_constant, const std::vector >& elementCorners, std::vector >& subElements, std::vector >& faceIds) { subElements.clear(); faceIds.clear(); if (elementCorners.size() == 3) { // triangle subElements.resize(1); faceIds.resize(1); subElements[0].push_back(0); subElements[0].push_back(1); subElements[0].push_back(2); faceIds[0].push_back(0); faceIds[0].push_back(1); faceIds[0].push_back(2); } else if (elementCorners.size() == 4) { // quadrilateral => 2 triangles subElements.resize(2); faceIds.resize(2); subElements[0].push_back(0); subElements[0].push_back(1); subElements[0].push_back(2); subElements[1].push_back(1); subElements[1].push_back(2); subElements[1].push_back(3); faceIds[0].push_back(2); faceIds[0].push_back(0); faceIds[0].push_back(-1); faceIds[1].push_back(-1); faceIds[1].push_back(1); faceIds[1].push_back(3); } } template inline void simplexSubdivision(std::integral_constant, const std::vector >& elementCorners, std::vector >& subElements, std::vector >& faceIds) { subElements.clear(); faceIds.clear(); if (elementCorners.size() == 4) { // tetrahedron subElements.resize(1); faceIds.resize(1); subElements[0].push_back(0); subElements[0].push_back(1); subElements[0].push_back(2); subElements[0].push_back(3); faceIds[0].push_back(0); faceIds[0].push_back(1); faceIds[0].push_back(2); faceIds[0].push_back(3); } else if (elementCorners.size() == 8) { // cube => 5 tetrahedra subElements.resize(5); faceIds.resize(5); subElements[0].push_back(0); subElements[0].push_back(2); subElements[0].push_back(3); subElements[0].push_back(6); subElements[1].push_back(0); subElements[1].push_back(1); subElements[1].push_back(3); subElements[1].push_back(5); subElements[2].push_back(0); subElements[2].push_back(3); subElements[2].push_back(5); subElements[2].push_back(6); subElements[3].push_back(0); subElements[3].push_back(4); subElements[3].push_back(5); subElements[3].push_back(6); subElements[4].push_back(3); subElements[4].push_back(5); subElements[4].push_back(6); subElements[4].push_back(7); faceIds[0].push_back(4); faceIds[0].push_back(0); faceIds[0].push_back(-1); faceIds[0].push_back(3); faceIds[1].push_back(4); faceIds[1].push_back(2); faceIds[1].push_back(-1); faceIds[1].push_back(1); faceIds[2].push_back(-1); faceIds[2].push_back(-1); faceIds[2].push_back(-1); faceIds[2].push_back(-1); faceIds[3].push_back(2); faceIds[3].push_back(0); faceIds[3].push_back(-1); faceIds[3].push_back(5); faceIds[4].push_back(-1); faceIds[4].push_back(1); faceIds[4].push_back(3); faceIds[4].push_back(5); } } } /* namespace Dune::GridGlue */ } /* namespace Dune */ dune-grid-glue-2.9.0/dune/grid-glue/merging/standardmerge.cc000066400000000000000000000024221435125002300237160ustar00rootroot00000000000000// -*- tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- // vi: set et ts=4 sw=2 sts=2: // SPDX-FileCopyrightInfo: Copyright © DUNE Project contributors, see file LICENSE.md in module root // SPDX-License-Identifier: LGPL-3.0-or-later OR LicenseRef-GPL-2.0-only-with-dune-grid-glue-exception #include "config.h" #include "standardmerge.hh" namespace Dune { namespace GridGlue { #define DECL #define STANDARD_MERGE_INSTANTIATE(T,A,B,C) \ DECL template \ void StandardMerge::build(const std::vector >& grid1_coords, \ const std::vector& grid1_elements, \ const std::vector& grid1_element_types, \ const std::vector >& grid2_coords, \ const std::vector& grid2_elements, \ const std::vector& grid2_element_types \ ) STANDARD_MERGE_INSTANTIATE(double,1,1,1); STANDARD_MERGE_INSTANTIATE(double,2,2,2); STANDARD_MERGE_INSTANTIATE(double,3,3,3); #undef STANDARD_MERGE_INSTANTIATE #undef DECL } /* namespace GridGlue */ } /* namespace Dune */ dune-grid-glue-2.9.0/dune/grid-glue/merging/standardmerge.hh000066400000000000000000001056741435125002300237450ustar00rootroot00000000000000// -*- tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- // vi: set et ts=4 sw=2 sts=2: // SPDX-FileCopyrightInfo: Copyright © DUNE Project contributors, see file LICENSE.md in module root // SPDX-License-Identifier: LGPL-3.0-or-later OR LicenseRef-GPL-2.0-only-with-dune-grid-glue-exception /** * @file * \brief Common base class for many merger implementations: produce pairs of entities that _may_ intersect */ #ifndef DUNE_GRIDGLUE_MERGING_STANDARDMERGE_HH #define DUNE_GRIDGLUE_MERGING_STANDARDMERGE_HH #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include namespace Dune { namespace GridGlue { /** \brief Common base class for many merger implementations: produce pairs of entities that _may_ intersect Many merger algorithms consist of two parts: on the one hand there is a mechanism that produces pairs of elements that may intersect. On the other hand there is an algorithm that computes the intersection of two given elements. For the pairs-producing algorithm there appears to be a canonical choice, namely the algorithm by Gander and Japhet described in 'An Algorithm for Non-Matching Grid Projections with Linear Complexity, M.J. Gander and C. Japhet, Domain Decomposition Methods in Science and Engineering XVIII, pp. 185--192, Springer-Verlag, 2009.' This class implements this algorithm, calling a pure virtual function computeIntersection() to compute the intersection between two elements. Actual merger implementations can derive from this class and only implement computeIntersection(). \tparam T The type used for coordinates (assumed to be the same for both grids) \tparam grid1Dim Dimension of the grid1 grid \tparam grid2Dim Dimension of the grid2 grid \tparam dimworld Dimension of the world space where the coupling takes place */ template class StandardMerge : public Merger { using Base = Merger; public: /* E X P O R T E D T Y P E S A N D C O N S T A N T S */ /// @brief the numeric type used in this interface typedef T ctype; /// @brief Type used for local coordinates on the grid1 side using Grid1Coords = typename Base::Grid1Coords; /// @brief Type used for local coordinates on the grid2 side using Grid2Coords = typename Base::Grid2Coords; /// @brief the coordinate type used in this interface using WorldCoords = typename Base::WorldCoords; using IntersectionList = typename Base::IntersectionList; protected: /** \brief The computed intersections */ using IntersectionListProvider = SimplicialIntersectionListProvider; using SimplicialIntersection = typename IntersectionListProvider::SimplicialIntersection; using RemoteSimplicialIntersection = SimplicialIntersection; bool valid = false; StandardMerge() : intersectionListProvider_(std::make_shared()) , intersectionList_(std::make_shared(intersectionListProvider_)) {} virtual ~StandardMerge() = default; /** \brief Compute the intersection between two overlapping elements The result is a set of simplices stored in the vector intersections. */ virtual void computeIntersections(const Dune::GeometryType& grid1ElementType, const std::vector >& grid1ElementCorners, std::bitset<(1<& neighborIntersects1, unsigned int grid1Index, const Dune::GeometryType& grid2ElementType, const std::vector >& grid2ElementCorners, std::bitset<(1<& neighborIntersects2, unsigned int grid2Index, std::vector& intersections) = 0; /** \brief Compute the intersection between two overlapping elements * \return true if at least one intersection point was found */ bool computeIntersection(unsigned int candidate0, unsigned int candidate1, const std::vector >& grid1Coords, const std::vector& grid1_element_types, std::bitset<(1<& neighborIntersects1, const std::vector >& grid2Coords, const std::vector& grid2_element_types, std::bitset<(1<& neighborIntersects2, bool insert = true); /* M E M B E R V A R I A B L E S */ std::shared_ptr intersectionListProvider_; std::shared_ptr intersectionList_; /** \brief Temporary internal data */ std::vector > grid1ElementCorners_; std::vector > grid2ElementCorners_; std::vector > elementNeighbors1_; std::vector > elementNeighbors2_; public: /* C O N C E P T I M P L E M E N T I N G I N T E R F A C E */ /** * @copydoc Merger::build */ void build(const std::vector >& grid1_Coords, const std::vector& grid1_elements, const std::vector& grid1_element_types, const std::vector >& grid2_coords, const std::vector& grid2_elements, const std::vector& grid2_element_types) override; /* P R O B I N G T H E M E R G E D G R I D */ void clear() override { // Delete old internal data, from a possible previous run intersectionListProvider_->clear(); purge(grid1ElementCorners_); purge(grid2ElementCorners_); valid = false; } std::shared_ptr intersectionList() const final { assert(valid); return intersectionList_; } void enableFallback(bool fallback) { m_enableFallback = fallback; } void enableBruteForce(bool bruteForce) { m_enableBruteForce = bruteForce; } private: /** * Enable fallback in case the advancing-front algorithm does not find an intersection. */ bool m_enableFallback = false; /** * Enable brute force implementation instead of advancing-front algorithm. */ bool m_enableBruteForce = false; auto& intersections() { return intersectionListProvider_->intersections(); } /** clear arbitrary containers */ template static void purge(V & v) { v.clear(); V v2(v); v.swap(v2); } /** * Do a brute-force search to find one pair of intersecting elements * to start or continue the advancing-front type algorithm. */ void generateSeed(std::vector& seeds, Dune::BitSetVector<1>& isHandled2, std::stack& candidates2, const std::vector >& grid1Coords, const std::vector& grid1_element_types, const std::vector >& grid2Coords, const std::vector& grid2_element_types); /** * Insert intersections into this->intersection_ and return index */ int insertIntersections(unsigned int candidate1, unsigned int candidate2,std::vector& intersections); /** * Find a grid2 element intersecting the candidate1 grid1 element by brute force search */ int bruteForceSearch(int candidate1, const std::vector >& grid1Coords, const std::vector& grid1_element_types, const std::vector >& grid2Coords, const std::vector& grid2_element_types); /** * Get the index of the intersection in intersections_ (= size if it is a new intersection) */ std::pair intersectionIndex(unsigned int grid1Index, unsigned int grid2Index, SimplicialIntersection& intersection); /** * get the neighbor relations between the given elements */ template void computeNeighborsPerElement(const std::vector& gridElementTypes, const std::vector >& gridElementCorners, std::vector >& elementNeighbors); void buildAdvancingFront( const std::vector >& grid1_Coords, const std::vector& grid1_elements, const std::vector& grid1_element_types, const std::vector >& grid2_coords, const std::vector& grid2_elements, const std::vector& grid2_element_types ); void buildBruteForce( const std::vector >& grid1_Coords, const std::vector& grid1_elements, const std::vector& grid1_element_types, const std::vector >& grid2_coords, const std::vector& grid2_elements, const std::vector& grid2_element_types ); }; /* IMPLEMENTATION */ template bool StandardMerge::computeIntersection(unsigned int candidate0, unsigned int candidate1, const std::vector >& grid1Coords, const std::vector& grid1_element_types, std::bitset<(1<& neighborIntersects1, const std::vector >& grid2Coords, const std::vector& grid2_element_types, std::bitset<(1<& neighborIntersects2, bool insert) { // Select vertices of the grid1 element int grid1NumVertices = grid1ElementCorners_[candidate0].size(); std::vector > grid1ElementCorners(grid1NumVertices); for (int i=0; i > grid2ElementCorners(grid2NumVertices); for (int i=0; i intersections(0); // compute the intersections computeIntersections(grid1_element_types[candidate0], grid1ElementCorners, neighborIntersects1, candidate0, grid2_element_types[candidate1], grid2ElementCorners, neighborIntersects2, candidate1, intersections); // insert intersections if needed if(insert && !intersections.empty()) insertIntersections(candidate0,candidate1,intersections); // Have we found an intersection? return !intersections.empty() || neighborIntersects1.any() || neighborIntersects2.any(); } template int StandardMerge::bruteForceSearch(int candidate1, const std::vector >& grid1Coords, const std::vector& grid1_element_types, const std::vector >& grid2Coords, const std::vector& grid2_element_types) { std::bitset<(1< neighborIntersects1; std::bitset<(1< neighborIntersects2; for (std::size_t i=0; i template void StandardMerge:: computeNeighborsPerElement(const std::vector& gridElementTypes, const std::vector >& gridElementCorners, std::vector >& elementNeighbors) { typedef std::vector FaceType; typedef std::map > FaceSetType; /////////////////////////////////////////////////////////////////////////////////////// // First: grid 1 /////////////////////////////////////////////////////////////////////////////////////// FaceSetType faces; elementNeighbors.resize(gridElementTypes.size()); for (size_t i=0; i::general(gridElementTypes[i]).size(1), -1); for (size_t i=0; i::general(gridElementTypes[i]); for (size_t j=0; j<(size_t)refElement.size(1); j++) { // iterate over all faces of the element FaceType face; // extract element face for (size_t k=0; k<(size_t)refElement.size(j,1,gridDim); k++) face.push_back(gridElementCorners[i][refElement.subEntity(j,1,k,gridDim)]); // sort the face vertices to get rid of twists and other permutations std::sort(face.begin(), face.end()); typename FaceSetType::iterator faceHandle = faces.find(face); if (faceHandle == faces.end()) { // face has not been visited before faces.insert(std::make_pair(face, std::make_pair(i,j))); } else { // face has been visited before: store the mutual neighbor information elementNeighbors[i][j] = faceHandle->second.first; elementNeighbors[faceHandle->second.first][faceHandle->second.second] = i; faces.erase(faceHandle); } } } } // ///////////////////////////////////////////////////////////////////// // Compute the intersection of all pairs of elements // Linear algorithm by Gander and Japhet, Proc. of DD18 // ///////////////////////////////////////////////////////////////////// template void StandardMerge::build(const std::vector >& grid1Coords, const std::vector& grid1_elements, const std::vector& grid1_element_types, const std::vector >& grid2Coords, const std::vector& grid2_elements, const std::vector& grid2_element_types ) { std::cout << "StandardMerge building merged grid..." << std::endl; Dune::Timer watch; clear(); // clear global intersection list intersectionListProvider_->clear(); this->counter = 0; // ///////////////////////////////////////////////////////////////////// // Copy element corners into a data structure with block-structure. // This is not as efficient but a lot easier to use. // We may think about efficiency later. // ///////////////////////////////////////////////////////////////////// // first the grid1 side grid1ElementCorners_.resize(grid1_element_types.size()); unsigned int grid1CornerCounter = 0; for (std::size_t i=0; i::general(grid1_element_types[i]).size(grid1Dim); grid1ElementCorners_[i].resize(numVertices); for (int j=0; j::general(grid2_element_types[i]).size(grid2Dim); grid2ElementCorners_[i].resize(numVertices); for (int j=0; j(grid1_element_types, grid1ElementCorners_, elementNeighbors1_); computeNeighborsPerElement(grid2_element_types, grid2ElementCorners_, elementNeighbors2_); std::cout << "setup took " << watch.elapsed() << " seconds." << std::endl; if (m_enableBruteForce) buildBruteForce(grid1Coords, grid1_elements, grid1_element_types, grid2Coords, grid2_elements, grid2_element_types); else buildAdvancingFront(grid1Coords, grid1_elements, grid1_element_types, grid2Coords, grid2_elements, grid2_element_types); valid = true; std::cout << "intersection construction took " << watch.elapsed() << " seconds." << std::endl; } template void StandardMerge::buildAdvancingFront( const std::vector >& grid1Coords, const std::vector& grid1_elements, const std::vector& grid1_element_types, const std::vector >& grid2Coords, const std::vector& grid2_elements, const std::vector& grid2_element_types ) { //////////////////////////////////////////////////////////////////////// // Data structures for the advancing-front algorithm //////////////////////////////////////////////////////////////////////// std::stack candidates1; std::stack candidates2; std::vector seeds(grid2_element_types.size(), -1); // ///////////////////////////////////////////////////////////////////// // Do a brute-force search to find one pair of intersecting elements // to start the advancing-front type algorithm with. // ///////////////////////////////////////////////////////////////////// // Set flag if element has been handled Dune::BitSetVector<1> isHandled2(grid2_element_types.size()); // Set flag if the element has been entered in the queue Dune::BitSetVector<1> isCandidate2(grid2_element_types.size()); generateSeed(seeds, isHandled2, candidates2, grid1Coords, grid1_element_types, grid2Coords, grid2_element_types); // ///////////////////////////////////////////////////////////////////// // Main loop // ///////////////////////////////////////////////////////////////////// std::set isHandled1; std::set isCandidate1; while (!candidates2.empty()) { // Get the next element on the grid2 side unsigned int currentCandidate2 = candidates2.top(); int seed = seeds[currentCandidate2]; assert(seed >= 0); candidates2.pop(); isHandled2[currentCandidate2] = true; // Start advancing front algorithm on the grid1 side from the 'seed' element that // we stored along with the current grid2 element candidates1.push(seed); isHandled1.clear(); isCandidate1.clear(); while (!candidates1.empty()) { unsigned int currentCandidate1 = candidates1.top(); candidates1.pop(); isHandled1.insert(currentCandidate1); // Test whether there is an intersection between currentCandidate0 and currentCandidate1 std::bitset<(1< neighborIntersects1; std::bitset<(1< neighborIntersects2; bool intersectionFound = computeIntersection(currentCandidate1, currentCandidate2, grid1Coords,grid1_element_types, neighborIntersects1, grid2Coords,grid2_element_types, neighborIntersects2); for (size_t i=0; i-1) { isCandidate2[neighbor][0] = true; candidates2.push(neighbor); seedFound = true; } } if (seedFound || !m_enableFallback) continue; // There is no neighbor with a seed, so we need to be a bit more aggressive... // get all neighbors of currentCandidate2, but not currentCandidate2 itself for (size_t i=0; i::iterator seedIt = isHandled1.begin(); seedIt != isHandled1.end(); ++seedIt) { std::bitset<(1< neighborIntersects1; std::bitset<(1< neighborIntersects2; bool intersectionFound = computeIntersection(*seedIt, neighbor, grid1Coords, grid1_element_types, neighborIntersects1, grid2Coords, grid2_element_types, neighborIntersects2, false); // if the intersection is nonempty, *seedIt is our new seed candidate on the grid1 side if (intersectionFound) { seed = *seedIt; Dune::dwarn << "Algorithm entered first fallback method and found a new seed in the build algorithm." << "Probably, the neighborIntersects bitsets computed in computeIntersection specialization is wrong." << std::endl; break; } } if (seed < 0) { // The fast method didn't find a grid1 element that intersects with // the new grid2 candidate. We have to do a brute-force search. seed = bruteForceSearch(neighbor, grid1Coords,grid1_element_types, grid2Coords,grid2_element_types); Dune::dwarn << "Algorithm entered second fallback method. This probably should not happen." << std::endl; } // We have tried all we could: the candidate is 'handled' now isCandidate2[neighbor] = true; // still no seed? Then the new grid2 candidate isn't overlapped by anything if (seed < 0) continue; // we have a seed now candidates2.push(neighbor); seeds[neighbor] = seed; seedFound = true; } } /* Do a brute-force search if there is still no seed: * There might still be a disconnected region out there. */ if (!seedFound && candidates2.empty()) { generateSeed(seeds, isHandled2, candidates2, grid1Coords, grid1_element_types, grid2Coords, grid2_element_types); } } } template void StandardMerge::buildBruteForce( const std::vector >& grid1Coords, const std::vector& grid1_elements, const std::vector& grid1_element_types, const std::vector >& grid2Coords, const std::vector& grid2_elements, const std::vector& grid2_element_types ) { std::bitset<(1< neighborIntersects1; std::bitset<(1< neighborIntersects2; for (unsigned i = 0; i < grid1_element_types.size(); ++i) { for (unsigned j = 0; j < grid2_element_types.size(); ++j) { (void) computeIntersection(i, j, grid1Coords, grid1_element_types, neighborIntersects1, grid2Coords, grid2_element_types, neighborIntersects2); } } } template void StandardMerge::generateSeed(std::vector& seeds, Dune::BitSetVector<1>& isHandled2, std::stack& candidates2, const std::vector >& grid1Coords, const std::vector& grid1_element_types, const std::vector >& grid2Coords, const std::vector& grid2_element_types) { for (std::size_t j=0; j 0 || isHandled2[j][0]) continue; int seed = bruteForceSearch(j,grid1Coords,grid1_element_types,grid2Coords,grid2_element_types); if (seed >= 0) { candidates2.push(j); // the candidate and a seed for the candidate seeds[j] = seed; break; } else // If the brute force search did not find any intersection we can skip this element isHandled2[j] = true; } } template int StandardMerge::insertIntersections(unsigned int candidate1, unsigned int candidate2, std::vector& intersections) { typedef typename std::vector::size_type size_t; int count = 0; for (size_t i = 0; i < intersections.size(); ++i) { // get the intersection index of the current intersection from intersections in this->intersections bool found; unsigned int index; std::tie(found, index) = intersectionIndex(candidate1,candidate2,intersections[i]); if (found && index >= this->intersections().size()) { //the intersection is not yet contained in this->intersections this->intersections().push_back(intersections[i]); // insert ++count; } else if (found) { auto& intersection = this->intersections()[index]; // insert each grid1 element and local representation of intersections[i] with parent candidate1 for (size_t j = 0; j < intersections[i].parents0.size(); ++j) { intersection.parents0.push_back(candidate1); intersection.corners0.push_back(intersections[i].corners0[j]); } // insert each grid2 element and local representation of intersections[i] with parent candidate2 for (size_t j = 0; j < intersections[i].parents1.size(); ++j) { intersection.parents1.push_back(candidate2); intersection.corners1.push_back(intersections[i].corners1[j]); } ++count; } else { Dune::dwarn << "Computed the same intersection twice!" << std::endl; } } return count; } template std::pair StandardMerge::intersectionIndex(unsigned int grid1Index, unsigned int grid2Index, SimplicialIntersection& intersection) { // return index in intersections_ if at least one local representation of a Simplicial Intersection (SI) // of intersections_ is equal to the local representation of one element in intersections std::size_t n_intersections = this->intersections().size(); if (grid1Dim == grid2Dim) return {true, n_intersections}; T eps = 1e-10; for (std::size_t i = 0; i < n_intersections; ++i) { // compare the local representation of the subelements of the SI for (std::size_t ei = 0; ei < this->intersections()[i].parents0.size(); ++ei) // merger subelement { if (this->intersections()[i].parents0[ei] == grid1Index) { for (std::size_t er = 0; er < intersection.parents0.size(); ++er) // list subelement { bool found_all = true; // compare the local coordinate representations for (std::size_t ci = 0; ci < this->intersections()[i].corners0[ei].size(); ++ci) { Dune::FieldVector ni = this->intersections()[i].corners0[ei][ci]; bool found_ni = false; for (std::size_t cr = 0; cr < intersection.corners0[er].size(); ++cr) { Dune::FieldVector nr = intersection.corners0[er][cr]; found_ni = found_ni || ((ni-nr).infinity_norm() < eps); if (found_ni) break; } found_all = found_all && found_ni; if (!found_ni) break; } if (found_all && (this->intersections()[i].parents1[ei] != grid2Index)) return {true, i}; else if (found_all) return {false, 0}; } } } // compare the local representation of the subelements of the SI for (std::size_t ei = 0; ei < this->intersections()[i].parents1.size(); ++ei) // merger subelement { if (this->intersections()[i].parents1[ei] == grid2Index) { for (std::size_t er = 0; er < intersection.parents1.size(); ++er) // list subelement { bool found_all = true; // compare the local coordinate representations for (std::size_t ci = 0; ci < this->intersections()[i].corners1[ei].size(); ++ci) { Dune::FieldVector ni = this->intersections()[i].corners1[ei][ci]; bool found_ni = false; for (std::size_t cr = 0; cr < intersection.corners1[er].size(); ++cr) { Dune::FieldVector nr = intersection.corners1[er][cr]; found_ni = found_ni || ((ni-nr).infinity_norm() < eps); if (found_ni) break; } found_all = found_all && found_ni; if (!found_ni) break; } if (found_all && (this->intersections()[i].parents0[ei] != grid1Index)) return {true, i}; else if (found_all) return {false, 0}; } } } } return {true, n_intersections}; } #define DECL extern #define STANDARD_MERGE_INSTANTIATE(T,A,B,C) \ DECL template \ void StandardMerge::build(const std::vector >& grid1Coords, \ const std::vector& grid1_elements, \ const std::vector& grid1_element_types, \ const std::vector >& grid2Coords, \ const std::vector& grid2_elements, \ const std::vector& grid2_element_types \ ) STANDARD_MERGE_INSTANTIATE(double,1,1,1); STANDARD_MERGE_INSTANTIATE(double,2,2,2); STANDARD_MERGE_INSTANTIATE(double,3,3,3); #undef STANDARD_MERGE_INSTANTIATE #undef DECL } /* namespace GridGlue */ } /* namespace Dune */ #endif // DUNE_GRIDGLUE_MERGING_STANDARDMERGE_HH dune-grid-glue-2.9.0/dune/grid-glue/test/000077500000000000000000000000001435125002300201165ustar00rootroot00000000000000dune-grid-glue-2.9.0/dune/grid-glue/test/CMakeLists.txt000066400000000000000000000017061435125002300226620ustar00rootroot00000000000000# SPDX-FileCopyrightInfo: Copyright © DUNE Project contributors, see file LICENSE.md in module root # SPDX-License-Identifier: LGPL-3.0-or-later OR LicenseRef-GPL-2.0-only-with-dune-grid-glue-exception dune_add_test(SOURCES callmergertwicetest.cc) dune_add_test(SOURCES ringcommtest.cc MPI_RANKS 1 2 3 4 5 6 7 8 9 10 TIMEOUT 300 CMAKE_GUARD MPI_FOUND) dune_add_test(SOURCES computecyclicordertest.cc) dune_add_test(SOURCES disconnectedtest.cc CMAKE_GUARD UG_FOUND) dune_add_test(SOURCES mixeddimcouplingtest.cc) dune_add_test(SOURCES mixeddimoverlappingtest.cc) dune_add_test(SOURCES mixeddimscalingtest.cc) dune_add_test(SOURCES nonoverlappingcouplingtest.cc MPI_RANKS 1 2 4 TIMEOUT 300 COMPILE_DEFINITIONS "CALL_MERGER_TWICE") dune_add_test(SOURCES overlappingcouplingtest.cc COMPILE_FLAGS "-frounding-math") dune_add_test(SOURCES projectiontest.cc) dune-grid-glue-2.9.0/dune/grid-glue/test/callmergertwicetest.cc000066400000000000000000000161321435125002300245010ustar00rootroot00000000000000// -*- tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- // vi: set et ts=4 sw=2 sts=2: // SPDX-FileCopyrightInfo: Copyright © DUNE Project contributors, see file LICENSE.md in module root // SPDX-License-Identifier: LGPL-3.0-or-later OR LicenseRef-GPL-2.0-only-with-dune-grid-glue-exception #include #include #include #include #include template Dune::FieldVector makeVec(double c) { Dune::FieldVector x; x[0] = c; for (size_t i=1; i Dune::FieldVector makeVec(double c1, double c2) { Dune::FieldVector x; x[0] = c1; x[1] = c2; for (size_t i=2; i struct setupGrid {}; template<> struct setupGrid<1> { static constexpr int dim = 1; template static void fill(std::vector > & grid1_coords, std::vector & grid1_elements, std::vector & grid1_element_types, std::vector > & grid2_coords, std::vector & grid2_elements, std::vector & grid2_element_types) { /* 0 2 5 |--|--------| M |--|--|-----| |-----|-----| 0 3 5 */ grid1_coords.push_back(makeVec(0)); grid1_coords.push_back(makeVec(2)); grid1_coords.push_back(makeVec(5)); grid1_elements.push_back(0); grid1_elements.push_back(1); grid1_elements.push_back(1); grid1_elements.push_back(2); #if DUNE_VERSION_NEWER(DUNE_GEOMETRY, 2, 6) grid1_element_types.emplace_back(Dune::GeometryTypes::simplex(dim)); grid1_element_types.emplace_back(Dune::GeometryTypes::simplex(dim)); #else grid1_element_types.emplace_back(Dune::GeometryType::simplex, dim); grid1_element_types.emplace_back(Dune::GeometryType::simplex, dim); #endif grid2_coords.push_back(makeVec(0)); grid2_coords.push_back(makeVec(3)); grid2_coords.push_back(makeVec(5)); grid2_elements.push_back(0); grid2_elements.push_back(1); grid2_elements.push_back(1); grid2_elements.push_back(2); #if DUNE_VERSION_NEWER(DUNE_GEOMETRY, 2, 6) grid2_element_types.emplace_back(Dune::GeometryTypes::simplex(dim)); grid2_element_types.emplace_back(Dune::GeometryTypes::simplex(dim)); #else grid2_element_types.emplace_back(Dune::GeometryType::simplex, dim); grid2_element_types.emplace_back(Dune::GeometryType::simplex, dim); #endif } }; constexpr int setupGrid<1>::dim; template<> struct setupGrid<2> { static constexpr int dim = 2; template static void fill(std::vector > & grid1_coords, std::vector & grid1_elements, std::vector & grid1_element_types, std::vector > & grid2_coords, std::vector & grid2_elements, std::vector & grid2_element_types) { /* 0,1 1,1 |-----| | \ / | | X | | / \ | |-----| 0,0 1,0 */ grid1_coords.push_back(makeVec(0,0)); grid1_coords.push_back(makeVec(1,0)); grid1_coords.push_back(makeVec(0,1)); grid1_coords.push_back(makeVec(1,1)); grid1_elements.push_back(0); grid1_elements.push_back(1); grid1_elements.push_back(2); grid1_elements.push_back(3); grid1_elements.push_back(2); grid1_elements.push_back(1); #if DUNE_VERSION_NEWER(DUNE_GEOMETRY, 2, 6) grid1_element_types.emplace_back(Dune::GeometryTypes::simplex(dim)); grid1_element_types.emplace_back(Dune::GeometryTypes::simplex(dim)); #else grid1_element_types.emplace_back(Dune::GeometryType::simplex, dim); grid1_element_types.emplace_back(Dune::GeometryType::simplex, dim); #endif grid2_coords.push_back(makeVec(0,0)); grid2_coords.push_back(makeVec(0,1)); grid2_coords.push_back(makeVec(1,0)); grid2_coords.push_back(makeVec(1,1)); grid2_elements.push_back(1); grid2_elements.push_back(3); grid2_elements.push_back(0); grid2_elements.push_back(2); grid2_elements.push_back(0); grid2_elements.push_back(3); #if DUNE_VERSION_NEWER(DUNE_GEOMETRY, 2, 6) grid2_element_types.emplace_back(Dune::GeometryTypes::simplex(dim)); grid2_element_types.emplace_back(Dune::GeometryTypes::simplex(dim)); #else grid2_element_types.emplace_back(Dune::GeometryType::simplex, dim); grid2_element_types.emplace_back(Dune::GeometryType::simplex, dim); #endif } }; constexpr int setupGrid<2>::dim; /* we split the grid0 and grid1 side into different subdomains and call the merger multiple times. This should ensure that the resulting merged grid is the same. This test currently only support coupling of elements of the same dimension */ template void callMergerTwice(Dune::GridGlue::Merger * merger) { std::cout << "============= callMergerTwice === dim " << dim << " === dimworld " << dimworld << " =============" << std::endl; ////////////////////////////////////////////////////////// // setup grid info std::vector > grid1_coords; std::vector grid1_elements; std::vector grid1_element_types; std::vector > grid2_coords; std::vector grid2_elements; std::vector grid2_element_types; setupGrid::fill(grid1_coords, grid1_elements, grid1_element_types, grid2_coords, grid2_elements, grid2_element_types); for (int i=0; i<2; i++) { ////////////////////////////////////////////////////////// // start the actual build process merger->build(grid1_coords, grid1_elements, grid1_element_types, grid2_coords, grid2_elements, grid2_element_types); std::cout << "created intersections: " << merger->nSimplices() << std::endl; ////////////////////////////////////////////////////////// // verify data merger->clear(); } } int main () { { using Merger = Dune::GridGlue::OverlappingMerge<1, 1, 1, double>; Merger merger; callMergerTwice(&merger); } { using Merger = Dune::GridGlue::ContactMerge<2, double>; Merger merger; callMergerTwice(&merger); } { using Merger = Dune::GridGlue::OverlappingMerge<2, 2, 2, double>; Merger merger; callMergerTwice(&merger); } { using Merger = Dune::GridGlue::ContactMerge<3, double>; Merger merger; callMergerTwice(&merger); } } dune-grid-glue-2.9.0/dune/grid-glue/test/communicationtest.hh000066400000000000000000000034471435125002300242140ustar00rootroot00000000000000// -*- tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- // vi: set et ts=4 sw=2 sts=2: // SPDX-FileCopyrightInfo: Copyright © DUNE Project contributors, see file LICENSE.md in module root // SPDX-License-Identifier: LGPL-3.0-or-later OR LicenseRef-GPL-2.0-only-with-dune-grid-glue-exception #ifndef DUNE_GRIDGLUE_TEST_COMMUNICATIONTEST_HH #define DUNE_GRIDGLUE_TEST_COMMUNICATIONTEST_HH template class CheckGlobalCoordDataHandle : public Dune::GridGlue::CommDataHandle< CheckGlobalCoordDataHandle, Dune::FieldVector > { public: template size_t size (RISType& i) const { if (i.self()) return i.geometry().corners(); else return i.geometryOutside().corners(); } template void gather (MessageBuffer& buff, const EntityType& e, const RISType & i) const { assert(i.self()); for (size_t n=0; n void scatter (MessageBuffer& buff, const EntityType& e, const RISType & i, size_t n) { assert(i.self()); assert(n == size(i)); for (size_t n=0; n x; buff.read(x); assert( (x - i.geometry().corner(n)).two_norm() < 1e-6 ); } } }; template void testCommunication (const GlueType& glue) { typedef typename GlueType::ctype ctype; static constexpr int dimw = GlueType::dimworld; CheckGlobalCoordDataHandle dh; glue.communicate(dh, Dune::All_All_Interface, Dune::ForwardCommunication); glue.communicate(dh, Dune::All_All_Interface, Dune::BackwardCommunication); } #endif // DUNE_GRIDGLUE_TEST_COMMUNICATIONTEST_HH dune-grid-glue-2.9.0/dune/grid-glue/test/computecyclicordertest.cc000066400000000000000000000036001435125002300252230ustar00rootroot00000000000000// SPDX-FileCopyrightInfo: Copyright © DUNE Project contributors, see file LICENSE.md in module root // SPDX-License-Identifier: LGPL-3.0-or-later OR LicenseRef-GPL-2.0-only-with-dune-grid-glue-exception #include "config.h" #include #include #include #include const static int dim = 3; typedef double Real; struct MyMerger : public Dune::GridGlue::ContactMerge<3, Real> { typedef Dune::GridGlue::ContactMerge<3, Real> Base; using Base::computeCyclicOrder; }; typedef Dune::FieldVector Local; typedef std::array Corner; typedef std::vector Corners; bool testComputeCyclicOrder() { bool pass = true; Corners corners; for (unsigned i = 0; i < 4; ++i) { Local local; switch (i) { case 0: local[0] = -0.25; local[1] = 1; break; case 1: local[0] = 1; local[1] = 0; break; case 2: local[0] = 0; local[1] = 0; break; case 3: local[0] = 0.75; local[1] = 1; break; } corners.push_back(Corner{{local, local}}); } Local center(0); for (const auto& c : corners) center += c[0]; center /= corners.size(); std::vector ordering; MyMerger merger; merger.computeCyclicOrder(corners, center, ordering); /* expected cycle is 0 -> 3 -> 1 -> 2, but we don't know where it starts */ std::vector next{3, 2, 0, 1}; for (std::size_t i = 0; i < ordering.size(); ++i) { const int current = ordering[i]; const int expected = next[current]; const int got = ordering[(i+1) % ordering.size()]; if (got != expected) { std::cerr << "FAIL: computeCyclicOrder: " << got << " follows " << i << ", but expected " << expected << std::endl; pass = false; } } return pass; } int main() { bool pass = true; pass &= testComputeCyclicOrder(); return pass ? 0 : 1; } dune-grid-glue-2.9.0/dune/grid-glue/test/couplingtest.hh000066400000000000000000000167701435125002300231720ustar00rootroot00000000000000// -*- tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- // vi: set et ts=4 sw=2 sts=2: // SPDX-FileCopyrightInfo: Copyright © DUNE Project contributors, see file LICENSE.md in module root // SPDX-License-Identifier: LGPL-3.0-or-later OR LicenseRef-GPL-2.0-only-with-dune-grid-glue-exception #ifndef DUNE_GRIDGLUE_TEST_COUPLINGTEST_HH #define DUNE_GRIDGLUE_TEST_COUPLINGTEST_HH #include #include #include #include #include #include #include template bool testIntersection(const IntersectionIt & rIIt, double eps) { bool success = true; typedef typename IntersectionIt::value_type Intersection; // Dimension of the intersection const int dim = Intersection::mydim; // Dimension of world coordinates const int coorddim = Intersection::coorddim; // Create a set of test points const Dune::QuadratureRule& quad = Dune::QuadratureRules::rule(rIIt->type(), 3); for (unsigned int l=0; linside(); const auto outside = rIIt->outside(); Dune::FieldVector quadPos = quad[l].position(); Dune::FieldVector localGrid0Pos = inside.geometry().global(rIIt->geometryInInside().global(quadPos)); // currently the intersection maps to the GV::dimworld, this will hopefully change soon Dune::FieldVector globalGrid0Pos = rIIt->geometry().global(quadPos); Dune::FieldVector localGrid1Pos = outside.geometry().global(rIIt->geometryInOutside().global(quadPos)); // currently the intersection maps to the GV::dimworld, this will hopefully change soon Dune::FieldVector globalGrid1Pos = rIIt->geometryOutside().global(quadPos); // Test whether local grid0 position is consistent with global grid0 position if ( (localGrid0Pos-globalGrid0Pos).two_norm() >= eps ) { std::cout << __FILE__ << ":" << __LINE__ << ": error: assert( (localGrid0Pos-globalGrid0Pos).two_norm() < eps ) failed\n"; std::cerr << "localGrid0Pos = " << localGrid0Pos << "\n"; std::cerr << "globalGrid0Pos = " << globalGrid0Pos << "\n"; success = false; } // Test whether local grid1 position is consistent with global grid1 position if ( (localGrid1Pos-globalGrid1Pos).two_norm() >= eps ) { std::cout << __FILE__ << ":" << __LINE__ << ": error: assert( (localGrid1Pos-globalGrid1Pos).two_norm() < eps ) failed\n"; std::cerr << "localGrid1Pos = " << localGrid1Pos << "\n"; std::cerr << "globalGrid1Pos = " << globalGrid1Pos << "\n"; success = false; } // Here we assume that the two interfaces match geometrically: if ( (globalGrid0Pos-globalGrid1Pos).two_norm() >= eps ) { std::cout << __FILE__ << ":" << __LINE__ << ": error: assert( (globalGrid0Pos-globalGrid1Pos).two_norm() < eps ) failed\n"; std::cerr << "localGrid0Pos = " << localGrid0Pos << "\n"; std::cerr << "globalGrid0Pos = " << globalGrid0Pos << "\n"; std::cerr << "localGrid1Pos = " << localGrid1Pos << "\n"; std::cerr << "globalGrid1Pos = " << globalGrid1Pos << "\n"; success = false; } // Test the normal vector methods. At least test whether they don't crash if (coorddim - dim == 1) // only test for codim 1 { rIIt->outerNormal(quadPos); rIIt->unitOuterNormal(quadPos); rIIt->integrationOuterNormal(quadPos); rIIt->centerUnitOuterNormal(); } } return success; } template void testCoupling(const GlueType& glue, double eps = 1e-12) { bool success = true; #if DUNE_VERSION_NEWER(DUNE_GRID, 2, 6) using View0Mapper = Dune::MultipleCodimMultipleGeomTypeMapper< typename GlueType::template GridView<0> >; using View1Mapper = Dune::MultipleCodimMultipleGeomTypeMapper< typename GlueType::template GridView<1> >; View0Mapper view0mapper(glue.template gridView<0>(), Dune::mcmgElementLayout()); View1Mapper view1mapper(glue.template gridView<1>(), Dune::mcmgElementLayout()); #else using View0Mapper = Dune::MultipleCodimMultipleGeomTypeMapper< typename GlueType::template GridView<0>, Dune::MCMGElementLayout >; using View1Mapper = Dune::MultipleCodimMultipleGeomTypeMapper< typename GlueType::template GridView<1>, Dune::MCMGElementLayout >; View0Mapper view0mapper(glue.template gridView<0>()); View1Mapper view1mapper(glue.template gridView<1>()); #endif std::vector countInside0(view0mapper.size()); std::vector countOutside1(view1mapper.size()); std::vector countInside1(view1mapper.size(), 0); std::vector countOutside0(view0mapper.size(), 0); // /////////////////////////////////////// // IndexSet // /////////////////////////////////////// { size_t count = 0; for (auto rIIt = glue.template ibegin<0>(); rIIt != glue.template iend<0>(); ++rIIt) count ++; typename GlueType::IndexSet is = glue.indexSet(); if(is.size() != glue.size()) DUNE_THROW(Dune::Exception, "Inconsistent size information: indexSet.size() " << is.size() << " != GridGlue.size() " << glue.size()); if(is.size() != count) DUNE_THROW(Dune::Exception, "Inconsistent size information: indexSet.size() " << is.size() << " != iterator count " << count); std::vector visited(count, false); for (auto rIIt = glue.template ibegin<0>(); rIIt != glue.template iend<0>(); ++rIIt) { size_t idx = is.index(*rIIt); if(idx >= count) DUNE_THROW(Dune::Exception, "Inconsistent IndexSet: index " << idx << " out of range, size is " << count); if(visited[idx] != false) DUNE_THROW(Dune::Exception, "Inconsistent IndexSet: visited index " << idx << " twice"); visited[idx] = true; } // make sure that we have a consecutive zero starting index set for (size_t i = 0; iGrid1 // /////////////////////////////////////// { for (auto rIIt = glue.template ibegin<0>(); rIIt != glue.template iend<0>(); ++rIIt) { if (rIIt->self() && rIIt->neighbor()) { const auto index0 = view0mapper.index(rIIt->inside()); const auto index1 = view1mapper.index(rIIt->outside()); countInside0[index0]++; countOutside1[index1]++; success = success && testIntersection(rIIt, eps); } } } // /////////////////////////////////////// // MergedGrid centric Grid1->Grid0 // /////////////////////////////////////// { for (auto rIIt = glue.template ibegin<1>(); rIIt != glue.template iend<1>(); ++rIIt) { if (rIIt->self() && rIIt->neighbor()) { const auto index1 = view1mapper.index(rIIt->inside()); const auto index0 = view0mapper.index(rIIt->outside()); countInside1[index1]++; countOutside0[index0]++; success = success && testIntersection(rIIt, eps); } } } if (! success) DUNE_THROW(Dune::Exception, "Test failed, see above for details."); } #endif // DUNE_GRIDGLUE_TEST_COUPLINGTEST_HH dune-grid-glue-2.9.0/dune/grid-glue/test/disconnectedtest.cc000066400000000000000000000104121435125002300237650ustar00rootroot00000000000000// SPDX-FileCopyrightInfo: Copyright © DUNE Project contributors, see file LICENSE.md in module root // SPDX-License-Identifier: LGPL-3.0-or-later OR LicenseRef-GPL-2.0-only-with-dune-grid-glue-exception #include "config.h" /** \file * \brief Tests a disconnected coupling boundary * * StandardMerge contains some extra logic to make sure it finds the complete coupling boundary * if that boundary has more than one connected component. Since StandardMerge is an advancing * front-type algorithm this does not work automatically. This test therefore constructs * a setting where the coupling boundary consists of two connected components, and tests whether * ContactMerge (which is based on StandardMerge) finds both components. */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include const int dim = 3; const int codim = 1; typedef Dune::UGGrid Grid; typedef Grid::LeafGridView GridView; typedef std::shared_ptr GridPtr; typedef Dune::GridFactory GridFactory; typedef Dune::FieldVector Vector; typedef Dune::GridGlue::Merger MyMerger; using Element = Grid::Codim<0>::Entity; std::function make_z_plane_predicate(double z) { return [z](const Element& element, unsigned int subentity) -> bool { using std::abs; const auto geometry = element.template subEntity<1>(subentity).geometry(); const auto global = geometry.center(); const auto epsilon = std::numeric_limits::epsilon(); return abs(global[GridView::dimensionworld-1] - z) < epsilon; }; } void insertCube(GridFactory& factory, unsigned int& vertex, const Vector& offset) { std::vector vertices; for (unsigned i(0); i < 1< merger) { std::cout << "TEST: " << name << std::endl << "===================" << std::endl; bool pass(true); std::array grids; for (unsigned i(0); i < grids.size(); ++i) { unsigned int vertex(0); GridFactory factory; Vector offset(0); offset[dim-1] = i; insertCube(factory, vertex, offset); offset[0] = 2; insertCube(factory, vertex, offset); grids[i] = GridPtr(factory.createGrid()); } typedef Dune::GridGlue::Codim1Extractor Extractor; const Extractor::Predicate predicate = make_z_plane_predicate(1.0); std::array, 2> extractors{{ std::make_shared(grids[0]->leafGridView(), predicate), std::make_shared(grids[1]->leafGridView(), predicate), }}; for (unsigned i(0); i < extractors.size(); ++i) { auto n = extractors[i]->nCoords(); if (n != 8) { std::cerr << "FAIL: Extracted patch on grid " << i << " has " << n << " coordinates (expected 8)" << std::endl; pass = false; } } typedef Dune::GridGlue::GridGlue Glue; Glue glue(extractors[0], extractors[1], merger); glue.build(); if (glue.size() != 4) { std::cerr << "FAIL: " << glue.size() << " remote intersections found (expected 4)." << std::endl; pass = false; } if (!pass) { std::string filename("disconnected-"); filename += name; Dune::GridGlue::GridGlueVtkWriter::write(glue, filename); } return pass; } int main(int argc, char** argv) { Dune::MPIHelper::instance(argc, argv); bool pass(true); { auto merger = std::make_shared< Dune::GridGlue::ContactMerge >(0.0); merger->enableFallback(true); pass &= testDisconnected("ContactMerge", merger); } return pass ? 0 : 1; } dune-grid-glue-2.9.0/dune/grid-glue/test/mixeddimcouplingtest.cc000066400000000000000000000342401435125002300246710ustar00rootroot00000000000000// -*- tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- // vi: set et ts=4 sw=2 sts=2: // SPDX-FileCopyrightInfo: Copyright © DUNE Project contributors, see file LICENSE.md in module root // SPDX-License-Identifier: LGPL-3.0-or-later OR LicenseRef-GPL-2.0-only-with-dune-grid-glue-exception #include "config.h" #include #include #include #include #include #include #include #include #include #include #include using namespace Dune; using namespace Dune::GridGlue; template typename Dune::GridGlue::Codim1Extractor::Predicate makeHorizontalFacePredicate(double sliceCoord) { using Element = typename GridView::Traits::template Codim<0>::Entity; auto predicate = [sliceCoord](const Element& element, unsigned int face) -> bool { const int dim = GridView::dimension; const auto& refElement = Dune::ReferenceElements::general(element.type()); int numVertices = refElement.size(face, 1, dim); for (int i=0; i 1e-6 ) return false; return true; }; return predicate; }; /** \brief Returns always true */ template typename Dune::GridGlue::Codim0Extractor::Predicate makeTruePredicate() { using Element = typename GridView::Traits::template Codim<0>::Entity; auto predicate = [](const Element&, unsigned int) -> bool { return true; }; return predicate; } /** \brief trafo from dim to dim+1 */ template class MixedDimTrafo : public AnalyticalCoordFunction< ctype, dim, dimw, MixedDimTrafo > { static_assert(dim+1==dimw, "MixedDimTrafo assumes dim+1=dimworld"); double yOffset_; public: MixedDimTrafo(double yOffset) : yOffset_(yOffset) {} //! evaluate method for global mapping void evaluate ( const Dune::FieldVector &x, Dune::FieldVector &y ) const { y = yOffset_; y[0] = x[0]; for (int i=2; i struct Embedding : AnalyticalCoordFunction > { static_assert(dimw >= dim, "Embeddings are only possible into a higher-dimensional space"); void evaluate(const Dune::FieldVector& x, Dune::FieldVector& y) const { y = ctype(0); for (unsigned i = 0; i < dim; ++i) y[i] = x[i]; } }; template void test1d2dCouplingMatchingDimworld() { double slice = 0.0; // /////////////////////////////////////// // Make a cube grid and a 1d grid // /////////////////////////////////////// using GridType2d = Dune::YaspGrid; std::array elements; elements.fill(1); FieldVector upper(1); GridType2d cubeGrid0(upper, elements); using GridType1d_ = Dune::YaspGrid; std::array elements1d; elements1d.fill(1); FieldVector upper1d(1); GridType1d_ cubeGrid1_(upper1d, elements1d); using Embedding1 = Embedding; using GridType1d = Dune::GeometryGrid; Embedding1 embedding1; GridType1d cubeGrid1(cubeGrid1_, embedding1); // //////////////////////////////////////// // Set up coupling at their interface // //////////////////////////////////////// typedef typename GridType2d::LevelGridView DomGridView; typedef typename GridType1d::LevelGridView TarGridView; typedef Codim1Extractor DomExtractor; typedef Codim0Extractor TarExtractor; const typename DomExtractor::Predicate domdesc = makeHorizontalFacePredicate(0); const typename TarExtractor::Predicate tardesc = makeTruePredicate(); auto domEx = std::make_shared(cubeGrid0.levelGridView(0), domdesc); auto tarEx = std::make_shared(cubeGrid1.levelGridView(0), tardesc); tarEx->positiveNormalDirection() = (slice == 0.0); typedef Dune::GridGlue::GridGlue GlueType; auto merger = std::make_shared< Dune::GridGlue::ContactMerge >(); merger->minNormalAngle(0.0); GlueType glue(domEx, tarEx, merger); glue.build(); std::cout << "Gluing successful, " << glue.size() << " remote intersections found!" << std::endl; assert(glue.size() > 0); // /////////////////////////////////////////// // Test the coupling // /////////////////////////////////////////// testCoupling(glue); } template void test2d1dCouplingMatchingDimworld() { double slice = 0.0; // /////////////////////////////////////// // Make a cube grid and a 1d grid // /////////////////////////////////////// using GridType1d_ = Dune::YaspGrid; std::array elements1d; elements1d.fill(1); FieldVector upper1d(1); GridType1d_ cubeGrid0_(upper1d, elements1d); using Embedding0 = Embedding; using GridType1d = Dune::GeometryGrid; Embedding0 embedding0; GridType1d cubeGrid0(cubeGrid0_, embedding0); using GridType2d = Dune::YaspGrid; std::array elements; elements.fill(1); FieldVector upper(1); GridType2d cubeGrid1(upper, elements); // //////////////////////////////////////// // Set up coupling at their interface // //////////////////////////////////////// typedef typename GridType1d::LevelGridView DomGridView; typedef typename GridType2d::LevelGridView TarGridView; typedef Codim0Extractor DomExtractor; typedef Codim1Extractor TarExtractor; const typename DomExtractor::Predicate domdesc = makeTruePredicate(); const typename TarExtractor::Predicate tardesc = makeHorizontalFacePredicate(0); auto domEx = std::make_shared(cubeGrid0.levelGridView(0), domdesc); auto tarEx = std::make_shared(cubeGrid1.levelGridView(0), tardesc); domEx->positiveNormalDirection() = (slice == 0.0); typedef Dune::GridGlue::GridGlue GlueType; auto merger = std::make_shared< Dune::GridGlue::ContactMerge >(); merger->minNormalAngle(0.0); GlueType glue(domEx, tarEx, merger); glue.build(); std::cout << "Gluing successful, " << glue.size() << " remote intersections found!" << std::endl; assert(glue.size() > 0); // /////////////////////////////////////////// // Test the coupling // /////////////////////////////////////////// testCoupling(glue); } template void test1d2dCoupling(double slice=0.0) { // /////////////////////////////////////// // Make a cube grid and a 1d grid // /////////////////////////////////////// using GridType2d = Dune::YaspGrid; std::array elements; elements.fill(1); FieldVector upper(1); GridType2d cubeGrid0(upper, elements); using GridType1d = Dune::YaspGrid; std::array elements1d; elements1d.fill(1); FieldVector upper1d(1); typedef GeometryGrid > LiftedGridType; GridType1d cubeGrid1_in(upper1d, elements1d); MixedDimTrafo trafo(slice); // transform dim-1 to dim LiftedGridType cubeGrid1(cubeGrid1_in, trafo); // //////////////////////////////////////// // Set up coupling at their interface // //////////////////////////////////////// typedef typename GridType2d::LevelGridView DomGridView; // typedef typename GridType1d::LevelGridView TarGridView; typedef typename LiftedGridType::LevelGridView TarGridView; typedef Codim1Extractor DomExtractor; typedef Codim0Extractor TarExtractor; const typename DomExtractor::Predicate domdesc = makeHorizontalFacePredicate(slice); const typename TarExtractor::Predicate tardesc = makeTruePredicate(); auto domEx = std::make_shared(cubeGrid0.levelView(0), domdesc); auto tarEx = std::make_shared(cubeGrid1.levelView(0), tardesc); tarEx->positiveNormalDirection() = (slice == 0.0); typedef Dune::GridGlue::GridGlue GlueType; auto merger = std::make_shared< Dune::GridGlue::ContactMerge >(); merger->minNormalAngle(0.0); GlueType glue(domEx, tarEx, merger); glue.build(); std::cout << "Gluing successful, " << glue.size() << " remote intersections found!" << std::endl; assert(glue.size() > 0); // /////////////////////////////////////////// // Test the coupling // /////////////////////////////////////////// testCoupling(glue); } template void test2d1dCoupling(double slice=0.0) { // /////////////////////////////////////// // Make a cube grid and a 1d grid // /////////////////////////////////////// using GridType1d = Dune::YaspGrid; std::array elements1d; elements1d.fill(1); FieldVector upper1d(1); typedef GeometryGrid > LiftedGridType; GridType1d cubeGrid0_in(upper1d, elements1d); MixedDimTrafo trafo(slice); // transform dim-1 to dim LiftedGridType cubeGrid0(cubeGrid0_in, trafo); using GridType2d = Dune::YaspGrid; std::array elements; elements.fill(1); FieldVector upper(1); GridType2d cubeGrid1(upper, elements); // //////////////////////////////////////// // Set up coupling at their interface // //////////////////////////////////////// typedef typename LiftedGridType::LevelGridView DomGridView; typedef typename GridType2d::LevelGridView TarGridView; typedef Codim0Extractor DomExtractor; typedef Codim1Extractor TarExtractor; const typename DomExtractor::Predicate domdesc = makeTruePredicate(); const typename TarExtractor::Predicate tardesc = makeHorizontalFacePredicate(slice); auto domEx = std::make_shared(cubeGrid0.levelGridView(0), domdesc); auto tarEx = std::make_shared(cubeGrid1.levelGridView(0), tardesc); domEx->positiveNormalDirection() = (slice == 0.0); typedef Dune::GridGlue::GridGlue GlueType; auto merger = std::make_shared< Dune::GridGlue::ContactMerge >(); merger->minNormalAngle(0.0); GlueType glue(domEx, tarEx, merger); glue.build(); std::cout << "Gluing successful, " << glue.size() << " remote intersections found!" << std::endl; assert(glue.size() > 0); // /////////////////////////////////////////// // Test the coupling // /////////////////////////////////////////// testCoupling(glue); } int main(int argc, char *argv[]) { Dune::MPIHelper::instance(argc, argv); // ///////////////////////////////////////////////////////////// // First set of tests: the grid have different dimensions, // but the world dimension is the same for both of them. // ///////////////////////////////////////////////////////////// // Test a unit square versus a grid one dimension lower std::cout << "==== 1d 2d == matching =============================\n"; test1d2dCouplingMatchingDimworld<2>(); std::cout << "====================================================\n"; // Test a unit square versus a grid one dimension lower std::cout << "==== 2d 1d == matching =============================\n"; test2d1dCouplingMatchingDimworld<2>(); std::cout << "====================================================\n"; #define _3DTEST 0 #if _3DTEST // Test a unit cube versus a grid one dimension lower std::cout << "==== 3d 2d == matching =============================\n"; test2d1dCouplingMatchingDimworld<3>(); std::cout << "====================================================\n"; #endif // ///////////////////////////////////////////////////////////// // Second set of tests: the grid have different dimensions, // and the world dimension is different as well // -- grids match at y==0.0 // ///////////////////////////////////////////////////////////// // Test a unit square versus a grid one dimension lower std::cout << "==== 1d 2d === nonmatching ==========================\n"; // test1d2dCoupling<2>(); // test1d2dCoupling<2, true>(); std::cout << "=====================================================\n"; // Test a unit square versus a grid one dimension lower std::cout << "==== 2d 1d == nonmatching ==========================\n"; test2d1dCoupling<2>(); test2d1dCoupling<2, true>(); std::cout << "====================================================\n"; #if _3DTEST // Test a unit cube versus a grid one dimension lower std::cout << "==== 3d 2d == nonmatching ==========================\n"; test2d1dCoupling<3>(); test2d1dCoupling<3, true>(); std::cout << "====================================================\n"; #endif // ///////////////////////////////////////////////////////////// // Third set of tests: the grid have different dimensions, // and the world dimension is different as well // -- grids match at y==1.0 // ///////////////////////////////////////////////////////////// // Test a unit square versus a grid one dimension lower std::cout << "==== 1d 2d == nonmatching top ======================\n"; // test1d2dCoupling<2>(1.0); // test1d2dCoupling<2, true>(1.0); std::cout << "====================================================\n"; // Test a unit square versus a grid one dimension lower std::cout << "==== 2d 1d == nonmatching top ======================\n"; test2d1dCoupling<2>(1.0); test2d1dCoupling<2, true>(1.0); std::cout << "====================================================\n"; #if _3DTEST // Test a unit cube versus a grid one dimension lower std::cout << "==== 3d 2d == nonmatching top ======================\n"; test2d1dCoupling<3>(1.0); test2d1dCoupling<3, true>(1.0); std::cout << "====================================================\n"; #endif } dune-grid-glue-2.9.0/dune/grid-glue/test/mixeddimoverlappingtest.cc000066400000000000000000000071271435125002300254030ustar00rootroot00000000000000// -*- tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- // vi: set et ts=4 sw=2 sts=2: // SPDX-FileCopyrightInfo: Copyright © DUNE Project contributors, see file LICENSE.md in module root // SPDX-License-Identifier: LGPL-3.0-or-later OR LicenseRef-GPL-2.0-only-with-dune-grid-glue-exception #include #include #include #include #include #include #include #include using namespace Dune; using namespace Dune::GridGlue; /** \brief Returns always true */ template typename Codim0Extractor::Predicate makeTruePredicate() { using Element = typename GridView::Traits::template Codim<0>::Entity; auto predicate = [](const Element&, unsigned int) -> bool { return true; }; return predicate; } /** \brief trafo from dim to dim+1 */ template class MixedDimTrafo : public AnalyticalCoordFunction< ctype, dim, dimw, MixedDimTrafo > { static_assert(dim+1==dimw, "MixedDimTrafo assumes dim+1=dimworld"); static_assert(dim==1, "MixedDimTrafo currently assumes dim==1"); public: //! evaluate method for global mapping void evaluate ( const Dune::FieldVector &x, Dune::FieldVector &y ) const { y[0] = x[0]+0.2; y[1] = x[0]+0.1; } }; int main(int argc, char** argv) { Dune::MPIHelper::instance(argc, argv); const static int dim0 = 2; const static int dim1 = 1; const static int dimworld = dim0; // ///////////////////////////////////////////////////////// // Make a 2d unit cube grid and a 1d grid embedded in 2d // ///////////////////////////////////////////////////////// using Grid0 = Dune::YaspGrid; std::array elements0; elements0.fill(2); FieldVector upper0(1); Grid0 grid0(upper0, elements0); using Grid1 = Dune::YaspGrid; std::array elements1; elements1.fill(2); FieldVector upper1(1); typedef MixedDimTrafo Transformation; typedef GeometryGrid LiftedGrid; Grid1 cubeGrid1_in(upper1, elements1); Transformation trafo; // transform dim-1 to dim LiftedGrid grid1(cubeGrid1_in, trafo); // //////////////////////////////////////// // Set up an overlapping coupling // //////////////////////////////////////// typedef typename Grid0::LeafGridView DomGridView; typedef typename LiftedGrid::LeafGridView TarGridView; typedef Codim0Extractor DomExtractor; typedef Codim0Extractor TarExtractor; const DomExtractor::Predicate domdesc = makeTruePredicate(); const TarExtractor::Predicate tardesc = makeTruePredicate(); auto domEx = std::make_shared(grid0.leafGridView(), domdesc); auto tarEx = std::make_shared(grid1.leafGridView(), tardesc); typedef Dune::GridGlue::GridGlue GlueType; // The following code is out-commented, because the test functionality // doesn't actually work yet. auto merger = std::make_shared< OverlappingMerge >(); GlueType glue(domEx, tarEx, merger); glue.build(); std::cout << "Gluing successful, " << glue.size() << " remote intersections found!" << std::endl; // /////////////////////////////////////////// // Test the coupling // /////////////////////////////////////////// testCoupling(glue); } dune-grid-glue-2.9.0/dune/grid-glue/test/mixeddimscalingtest.cc000066400000000000000000000101051435125002300244630ustar00rootroot00000000000000// -*- tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- // vi: set et ts=4 sw=2 sts=2: // SPDX-FileCopyrightInfo: Copyright © DUNE Project contributors, see file LICENSE.md in module root // SPDX-License-Identifier: LGPL-3.0-or-later OR LicenseRef-GPL-2.0-only-with-dune-grid-glue-exception #include #include #include #include #include #include #include #include using namespace Dune; using namespace Dune::GridGlue; /** \brief Returns always true */ template typename Codim0Extractor::Predicate makeTruePredicate() { using Element = typename GridView::Traits::template Codim<0>::Entity; auto predicate = [](const Element&, unsigned int) -> bool { return true; }; return predicate; } /** \brief trafo from dim to dim+1 */ template class MixedDimTrafo : public AnalyticalCoordFunction< ctype, dim, dimw, MixedDimTrafo > { static_assert(dim+2==dimw, "MixedDimTrafo assumes dim+2=dimworld"); static_assert(dim==1, "MixedDimTrafo currently assumes dim==1"); const double scale_; public: MixedDimTrafo(double scale) : scale_(scale) {} //! evaluate method for global mapping void evaluate ( const Dune::FieldVector &x, Dune::FieldVector &y ) const { y[0] = 0.5*scale_; y[1] = 0.5*scale_; y[2] = x[0]; } }; bool doTest(double scale) { const static int dim0 = 3; const static int dim1 = 1; const static int dimworld = dim0; // ///////////////////////////////////////////////////////// // Make a 2d unit cube grid and a 1d grid embedded in 2d // ///////////////////////////////////////////////////////// typedef YaspGrid Grid0; std::array elements0 = {{2, 2, 2}}; FieldVector upper0(1.0*scale); Grid0 grid0(upper0, elements0); typedef YaspGrid Grid1; std::array elements1 = {{3}}; FieldVector upper1(1.0*scale); typedef MixedDimTrafo Transformation; typedef GeometryGrid LiftedGrid; Grid1 cubeGrid1_in(upper1, elements1); typedef MixedDimTrafo Transformation; typedef GeometryGrid LiftedGrid; Transformation trafo(scale); // transform dim-1 to dim LiftedGrid grid1(cubeGrid1_in, trafo); // //////////////////////////////////////// // Set up an overlapping coupling // //////////////////////////////////////// typedef typename Grid0::LeafGridView DomGridView; typedef typename LiftedGrid::LeafGridView TarGridView; typedef Codim0Extractor DomExtractor; typedef Codim0Extractor TarExtractor; const DomExtractor::Predicate domdesc = makeTruePredicate(); const TarExtractor::Predicate tardesc = makeTruePredicate(); auto domEx = std::make_shared(grid0.leafGridView(), domdesc); auto tarEx = std::make_shared(grid1.leafGridView(), tardesc); typedef Dune::GridGlue::GridGlue GlueType; // The following code is out-commented, because the test functionality // doesn't actually work yet. auto merger = std::make_shared< OverlappingMerge >(); GlueType glue(domEx, tarEx, merger); glue.build(); // /////////////////////////////////////////// // Test the coupling // /////////////////////////////////////////// testCoupling(glue, scale * 1e-12); bool pass = true; if (glue.size() != 4) { std::cerr << "ERROR: Got " << glue.size() << " intersections, but expected 4" << std::endl; pass = false; } return pass; } int main(int argc, char** argv) { Dune::MPIHelper::instance(argc, argv); bool pass = true; for (const auto scale : {1e10, 1., 1e-3, 1e-8, 1e-10}) { if (!doTest(scale)) pass = false; } return pass ? 0 : 1; } dune-grid-glue-2.9.0/dune/grid-glue/test/nonoverlappingcouplingtest.cc000066400000000000000000000263211435125002300261330ustar00rootroot00000000000000// -*- tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- // vi: set et ts=4 sw=2 sts=2: // SPDX-FileCopyrightInfo: Copyright © DUNE Project contributors, see file LICENSE.md in module root // SPDX-License-Identifier: LGPL-3.0-or-later OR LicenseRef-GPL-2.0-only-with-dune-grid-glue-exception #include "config.h" #include #include #include #include #include #include #include #include #include #include #include #include #include using namespace Dune; using namespace Dune::GridGlue; template typename Dune::GridGlue::Codim1Extractor::Predicate makeVerticalFacePredicate(double sliceCoord) { using Element = typename GridView::Traits::template Codim<0>::Entity; auto predicate = [sliceCoord](const Element& element, unsigned int face) -> bool { const int dim = GridView::dimension; const auto& refElement = Dune::ReferenceElements::general(element.type()); int numVertices = refElement.size(face, 1, dim); for (int i=0; i 1e-6 ) return false; return true; }; return predicate; } /** \brief trafo used for yaspgrids */ template class ShiftTrafo : public AnalyticalCoordFunction< ctype, dim, dim, ShiftTrafo > { double shift; public: ShiftTrafo(double x) : shift(x) {}; //! evaluate method for global mapping void evaluate ( const Dune::FieldVector &x, Dune::FieldVector &y ) const { y = x; y[0] += shift; } }; template void testMatchingCubeGrids() { // /////////////////////////////////////// // Make two cube grids // /////////////////////////////////////// using GridType = Dune::YaspGrid >; std::array elements; elements.fill(8); FieldVector lower(0); FieldVector upper(1); GridType cubeGrid0(lower, upper, elements); lower[0] += 1; upper[0] += 1; GridType cubeGrid1(lower, upper, elements); // //////////////////////////////////////// // Set up coupling at their interface // //////////////////////////////////////// typedef typename GridType::LevelGridView DomGridView; typedef typename GridType::LevelGridView TarGridView; typedef Codim1Extractor DomExtractor; typedef Codim1Extractor TarExtractor; const typename DomExtractor::Predicate domdesc = makeVerticalFacePredicate(1); const typename TarExtractor::Predicate tardesc = makeVerticalFacePredicate(1); auto domEx = std::make_shared(cubeGrid0.levelGridView(0), domdesc); auto tarEx = std::make_shared(cubeGrid1.levelGridView(0), tardesc); typedef Dune::GridGlue::GridGlue GlueType; // Testing with ContactMerge typedef ContactMerge ContactMergeImpl; auto contactMerger = std::make_shared(0.01); GlueType contactGlue(domEx, tarEx, contactMerger); contactGlue.build(); std::cout << "Gluing successful, " << contactGlue.size() << " remote intersections found!" << std::endl; assert(contactGlue.size() > 0); // /////////////////////////////////////////// // Test the coupling // /////////////////////////////////////////// testCoupling(contactGlue); testCommunication(contactGlue); } template void testNonMatchingCubeGrids() { // /////////////////////////////////////// // Make two cube grids // /////////////////////////////////////// using GridType = Dune::YaspGrid >; std::array elements; elements.fill(8); FieldVector lower(0); FieldVector upper(1); GridType cubeGrid0(lower, upper, elements); elements.fill(10); lower[0] += 1; upper[0] += 1; GridType cubeGrid1(lower, upper, elements); // //////////////////////////////////////// // Set up coupling at their interface // //////////////////////////////////////// typedef typename GridType::LevelGridView DomGridView; typedef typename GridType::LevelGridView TarGridView; typedef Codim1Extractor DomExtractor; typedef Codim1Extractor TarExtractor; const typename DomExtractor::Predicate domdesc = makeVerticalFacePredicate(1); const typename TarExtractor::Predicate tardesc = makeVerticalFacePredicate(1); auto domEx = std::make_shared(cubeGrid0.levelGridView(0), domdesc); auto tarEx = std::make_shared(cubeGrid1.levelGridView(0), tardesc); typedef Dune::GridGlue::GridGlue GlueType; // Testing with ContactMerge typedef ContactMerge ContactMergeImpl; auto contactMerger = std::make_shared(0.01); GlueType contactGlue(domEx, tarEx, contactMerger); contactGlue.build(); std::cout << "Gluing successful, " << contactGlue.size() << " remote intersections found!" << std::endl; assert(contactGlue.size() > 0); // /////////////////////////////////////////// // Test the coupling // /////////////////////////////////////////// testCoupling(contactGlue); testCommunication(contactGlue); } template class MeshGenerator { bool tar; public: MeshGenerator(bool b) : tar(b) {}; using GridType = Dune::YaspGrid >; std::shared_ptr generate() { std::array elements; elements.fill(8); FieldVector lower(0); FieldVector upper(1); if (tar) { elements.fill(10); lower[0] += 1; upper[0] += 1; } return std::make_shared(lower, upper, elements); } }; template class MeshGenerator { bool tar; public: MeshGenerator(bool b) : tar(b) {}; typedef YaspGrid HostGridType; typedef GeometryGrid > GridType; std::shared_ptr generate() { std::array elements; std::fill(elements.begin(), elements.end(), 8); std::bitset periodic(0); FieldVector size(1); int overlap = 1; double shift = 0.0; if (tar) { std::fill(elements.begin(), elements.end(), 10); shift = 1.0; } HostGridType * hostgridp = new HostGridType( size, elements, periodic, overlap #if HAVE_MPI , MPI_COMM_WORLD #endif ); ShiftTrafo * trafop = new ShiftTrafo(shift); return std::make_shared(*hostgridp, *trafop); } }; template void testParallelCubeGrids() { // /////////////////////////////////////// // Make two cube grids // /////////////////////////////////////// typedef typename DomGen::GridType GridType0; typedef typename TarGen::GridType GridType1; DomGen domGen(0); TarGen tarGen(1); double slice = 1.0; std::shared_ptr cubeGrid0 = domGen.generate(); std::shared_ptr cubeGrid1 = tarGen.generate(); // //////////////////////////////////////// // Set up Traits // //////////////////////////////////////// typedef typename GridType0::LevelGridView DomGridView; typedef typename GridType1::LevelGridView TarGridView; typedef Codim1Extractor DomExtractor; typedef Codim1Extractor TarExtractor; const typename DomExtractor::Predicate domdesc = makeVerticalFacePredicate(slice); const typename TarExtractor::Predicate tardesc = makeVerticalFacePredicate(slice); auto domEx = std::make_shared(cubeGrid0->levelGridView(0), domdesc); auto tarEx = std::make_shared(cubeGrid1->levelGridView(0), tardesc); // //////////////////////////////////////// // Set up coupling at their interface // //////////////////////////////////////// typedef Dune::GridGlue::GridGlue GlueType; // Testing with ContactMerge typedef ContactMerge ContactMergeImpl; auto contactMerger = std::make_shared(0.01); GlueType contactGlue(domEx, tarEx, contactMerger); contactGlue.build(); std::cout << "Gluing successful, " << contactGlue.size() << " remote intersections found!" << std::endl; assert(contactGlue.size() > 0); // /////////////////////////////////////////// // Test the coupling // /////////////////////////////////////////// testCoupling(contactGlue); testCommunication(contactGlue); } #if HAVE_MPI void eh( MPI_Comm *comm, int *err, ... ) { int len = 1024; char error_txt[len]; MPI_Error_string(*err, error_txt, &len); assert(len <= 1024); DUNE_THROW(Dune::Exception, "MPI ERROR -- " << error_txt); } #endif // HAVE_MPI int main(int argc, char *argv[]) { Dune::MPIHelper::instance(argc, argv); Dune::dinfo.attach(std::cout); #if HAVE_MPI MPI_Errhandler errhandler; MPI_Comm_create_errhandler(eh, &errhandler); MPI_Comm_set_errhandler(MPI_COMM_WORLD, errhandler); #endif // 2d Tests typedef MeshGenerator<2,false> Seq; typedef MeshGenerator<2,true> Par; // Test two unit squares std::cout << "==== 2D hybrid =============================================\n"; testMatchingCubeGrids<2>(); std::cout << "============================================================\n"; testNonMatchingCubeGrids<2>(); std::cout << "============================================================\n"; testParallelCubeGrids<2,Seq,Seq>(); std::cout << "============================================================\n"; testParallelCubeGrids<2,Par,Seq>(); std::cout << "============================================================\n"; testParallelCubeGrids<2,Seq,Par>(); std::cout << "============================================================\n"; testParallelCubeGrids<2,Par,Par>(); std::cout << "============================================================\n"; // 3d Tests #if ! HAVE_MPI typedef MeshGenerator<3,false> Seq3d; typedef MeshGenerator<3,true> Par3d; // Test two unit cubes std::cout << "==== 3D hybrid =============================================\n"; testMatchingCubeGrids<3>(); std::cout << "============================================================\n"; testNonMatchingCubeGrids<3>(); std::cout << "============================================================\n"; testParallelCubeGrids<3,Seq3d,Seq3d>(); std::cout << "============================================================\n"; testParallelCubeGrids<3,Par3d,Seq3d>(); std::cout << "============================================================\n"; testParallelCubeGrids<3,Seq3d,Par3d>(); std::cout << "============================================================\n"; testParallelCubeGrids<3,Par3d,Par3d>(); std::cout << "============================================================\n"; #endif // HAVE_MPI return 0; } dune-grid-glue-2.9.0/dune/grid-glue/test/overlappingcouplingtest.cc000066400000000000000000000237621435125002300254260ustar00rootroot00000000000000// -*- tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- // vi: set et ts=4 sw=2 sts=2: // SPDX-FileCopyrightInfo: Copyright © DUNE Project contributors, see file LICENSE.md in module root // SPDX-License-Identifier: LGPL-3.0-or-later OR LicenseRef-GPL-2.0-only-with-dune-grid-glue-exception #include #include #include #include #ifdef HAVE_DUNE_UGGRID #include #endif #include #include #include #if HAVE_HYBRIDTESTGRIDS # include #endif #include #include #include #include #include using namespace Dune; using namespace Dune::GridGlue; /** \brief Returns always true */ template typename Dune::GridGlue::Codim0Extractor::Predicate makeTruePredicate() { using Element = typename GridView::Traits::template Codim<0>::Entity; auto predicate = [](const Element&, unsigned int) -> bool { return true; }; return predicate; } template void testCubeGrids(std::shared_ptr< Merger > merger, const FieldVector& gridOffset) { // ///////////////////////////////////////////////////////////////// // Make two cube grids that are slightly shifted wrt each other // ///////////////////////////////////////////////////////////////// using GridType = Dune::YaspGrid >; std::array elements; elements.fill(10); FieldVector lower(0); FieldVector upper(1); GridType grid0(lower, upper, elements); lower += gridOffset; upper += gridOffset; GridType grid1(lower, upper, elements); // //////////////////////////////////////// // Set up an overlapping coupling // //////////////////////////////////////// typedef typename GridType::LeafGridView DomGridView; typedef typename GridType::LeafGridView TarGridView; typedef Codim0Extractor DomExtractor; typedef Codim0Extractor TarExtractor; const typename DomExtractor::Predicate domdesc = makeTruePredicate(); const typename TarExtractor::Predicate tardesc = makeTruePredicate(); auto domEx = std::make_shared(grid0.leafGridView(), domdesc); auto tarEx = std::make_shared(grid1.leafGridView(), tardesc); typedef Dune::GridGlue::GridGlue GlueType; GlueType glue(domEx, tarEx, merger); glue.build(); std::cout << "Gluing successful, " << glue.size() << " remote intersections found!" << std::endl; assert(glue.size() > 0); // /////////////////////////////////////////// // Test the coupling // /////////////////////////////////////////// testCoupling(glue); } template void testSimplexGrids(std::shared_ptr< Merger > merger, const FieldVector& gridOffset) { // ///////////////////////////////////////////////////////////////// // Make two cube grids that are slightly shifted wrt each other // ///////////////////////////////////////////////////////////////// using GridType = Dune::YaspGrid >; std::array elements; elements.fill(10); FieldVector lower(0); FieldVector upper(1); GridType grid0(lower, upper, elements); lower += gridOffset; upper += gridOffset; GridType grid1(lower, upper, elements); // //////////////////////////////////////// // Set up an overlapping coupling // //////////////////////////////////////// typedef typename GridType::LeafGridView DomGridView; typedef typename GridType::LeafGridView TarGridView; typedef Codim0Extractor DomExtractor; typedef Codim0Extractor TarExtractor; const typename DomExtractor::Predicate domdesc = makeTruePredicate(); const typename TarExtractor::Predicate tardesc = makeTruePredicate(); auto domEx = std::make_shared(grid0.leafGridView(), domdesc); auto tarEx = std::make_shared(grid1.leafGridView(), tardesc); Dune::GridGlue::GridGlue glue(domEx, tarEx, merger); glue.build(); std::cout << "Gluing successful, " << glue.size() << " remote intersections found!" << std::endl; assert(glue.size() > 0); // /////////////////////////////////////////// // Test the coupling // /////////////////////////////////////////// testCoupling(glue); } #if HAVE_DUNE_UGGRID template void testSimplexGridsUG(std::shared_ptr< Merger > merger, const FieldVector& gridOffset) { // ///////////////////////////////////////////////////////////////// // Make two triangle grids that are slightly shifted wrt each other // ///////////////////////////////////////////////////////////////// typedef UGGrid GridType; FieldVector lowerLeft(0); FieldVector upperRight(1); std::array elements; std::fill(elements.begin(), elements.end(), 10); StructuredGridFactory factory; std::shared_ptr grid0 = factory.createSimplexGrid(lowerLeft, upperRight, elements); lowerLeft += gridOffset; upperRight += gridOffset; std::shared_ptr grid1 = factory.createSimplexGrid(lowerLeft, upperRight, elements); // //////////////////////////////////////// // Set up an overlapping coupling // //////////////////////////////////////// typedef typename GridType::LeafGridView DomGridView; typedef typename GridType::LeafGridView TarGridView; typedef Codim0Extractor DomExtractor; typedef Codim0Extractor TarExtractor; const typename DomExtractor::Predicate domdesc = makeTruePredicate(); const typename TarExtractor::Predicate tardesc = makeTruePredicate(); auto domEx = std::make_shared(grid0->leafGridView(), domdesc); auto tarEx = std::make_shared(grid1->leafGridView(), tardesc); Dune::GridGlue::GridGlue glue(domEx, tarEx, merger); glue.build(); std::cout << "Gluing successful, " << glue.size() << " remote intersections found!" << std::endl; assert(glue.size() > 0); // /////////////////////////////////////////// // Test the coupling // /////////////////////////////////////////// testCoupling(glue); } #endif #if HAVE_DUNE_UGGRID && HAVE_HYBRIDTESTGRIDS template void testHybridGridsUG(std::shared_ptr< Merger > merger, const FieldVector& gridOffset) { // ///////////////////////////////////////////////////////////////////////// // Create the hybrid test grid from dune-grid twice and shift it once // wrt the other grid. // ///////////////////////////////////////////////////////////////////////// typedef UGGrid GridType; std::unique_ptr > grid0(make2DHybridTestGrid >()); std::unique_ptr > grid1(make2DHybridTestGrid >()); // //////////////////////////////////////// // Set up an overlapping coupling // //////////////////////////////////////// typedef typename GridType::LeafGridView DomGridView; typedef typename GridType::LeafGridView TarGridView; typedef Codim0Extractor DomExtractor; typedef Codim0Extractor TarExtractor; const typename DomExtractor::Predicate domdesc = makeTruePredicate(); const typename TarExtractor::Predicate tardesc = makeTruePredicate(); auto domEx = std::make_shared(grid0->leafGridView(), domdesc); auto tarEx = std::make_shared(grid1->leafGridView(), tardesc); Dune::GridGlue::GridGlue glue(domEx, tarEx, merger); glue.build(); std::cout << "Gluing successful, " << glue.size() << " remote intersections found!" << std::endl; assert(glue.size() > 0); // /////////////////////////////////////////// // Test the coupling // /////////////////////////////////////////// testCoupling(glue); } #endif int main(int argc, char** argv) { Dune::MPIHelper::instance(argc, argv); // ////////////////////////////////////////////////////////// // Test with the OverlappingMerge implementation // ////////////////////////////////////////////////////////// auto overlappingMerge1d = std::make_shared< OverlappingMerge<1,1,1,double> >(); auto overlappingMerge2d = std::make_shared< OverlappingMerge<2,2,2,double> >(); testCubeGrids<1>(overlappingMerge1d, FieldVector(0.05)); testCubeGrids<2>(overlappingMerge2d, FieldVector(0.05)); testSimplexGrids<1>(overlappingMerge1d, FieldVector(0.05)); #if HAVE_DUNE_UGGRID testSimplexGridsUG<2>(overlappingMerge2d, FieldVector(0.05)); #endif #if HAVE_DUNE_UGGRID && HAVE_HYBRIDTESTGRIDS testHybridGridsUG<2>(overlappingMerge2d, FieldVector(0.05)); #endif // ////////////////////////////////////////////////////////// // Test with the ConformingMerge implementation // ////////////////////////////////////////////////////////// auto conformingMerge1d = std::make_shared< ConformingMerge<1,1,double> >(); auto conformingMerge2d = std::make_shared< ConformingMerge<2,2,double> >(); auto conformingMerge3d = std::make_shared< ConformingMerge<3,3,double> >(); testCubeGrids<1>(conformingMerge1d, FieldVector(0)); testCubeGrids<2>(conformingMerge2d, FieldVector(0)); testSimplexGrids<1>(conformingMerge1d, FieldVector(0)); #if HAVE_DUNE_UGGRID testSimplexGridsUG<2>(conformingMerge2d, FieldVector(0)); #endif #if HAVE_DUNE_UGGRID && HAVE_HYBRIDTESTGRIDS testHybridGridsUG<2>(conformingMerge2d, FieldVector(0)); #endif } dune-grid-glue-2.9.0/dune/grid-glue/test/projectiontest.cc000066400000000000000000000360751435125002300235140ustar00rootroot00000000000000// SPDX-FileCopyrightInfo: Copyright © DUNE Project contributors, see file LICENSE.md in module root // SPDX-License-Identifier: LGPL-3.0-or-later OR LicenseRef-GPL-2.0-only-with-dune-grid-glue-exception #include "config.h" #include #include #include #include #include #include using Dune::GridGlue::Projection; bool test_project_simple() { using std::get; bool pass = true; typedef Dune::FieldVector V; typedef Projection P; using Corners = std::array; using Normals = Corners; const Corners c0{{{0, 0, 0}, {1, 0, 0}, {0, 1, 0}}}; const Corners c1{{{0, 0, 1}, {1, 0, 1}, {0, 1, 1}}}; const auto& corners = std::tie(c0, c1); const Normals n0{{{0, 0, 1}, {0, 0, 1}, {0, 0, 1}}}; const Normals n1{{{0, 0, -1}, {0, 0, -1}, {0, 0, -1}}}; const auto& normals = std::tie(n0, n1); P p; p.project(corners, normals); /* Check image */ { const auto& success = get<0>(p.success()); if (!success.all()) { std::cout << "ERROR: test_project_simple: not all Phi(x_i) are inside the image triangle" << std::endl; pass = false; } const Corners expected{{{0, 0, 1}, {1, 0, 1}, {0, 1, 1}}}; const auto& images = get<0>(p.images()); for (unsigned i = 0; i < images.size(); ++i) { if (!((images[i] - expected[i]).infinity_norm() < 1e-8)) { std::cout << "ERROR: test_project_simple: corner " << i << " was projected on " << images[i] << "; expected: " << expected[i] << std::endl; pass = false; } } } /* Check preimage */ { const auto& success = get<1>(p.success()); if (!success.all()) { std::cout << "ERROR: test_project_simple: not all Phi^{-1}(y_i) are inside the preimage triangle" << std::endl; pass = false; } const Corners expected{{{0, 0, 1}, {1, 0, 1}, {0, 1, 1}}}; const auto& images = get<1>(p.images()); for (unsigned i = 0; i < images.size(); ++i) { if (!((images[i] - expected[i]).infinity_norm() < 1e-8)) { std::cout << "ERROR: test_project_simple: corner " << i << " was inverse-projected on " << images[i] << "; expected: " << expected[i] << std::endl; pass = false; } } } /* No edge intersections. */ if (p.numberOfEdgeIntersections() != 0) { std::cout << "ERROR: test_project_simple: there were unexpected edge intersections" << std::endl; pass = false; } if (!pass) write(p, corners, normals, "projectiontest_project_simple.vtk"); return pass; } bool test_project_simple2() { using std::get; using std::sqrt; bool pass = true; typedef Dune::FieldVector V; typedef Projection P; using Corners = std::array; using Normals = Corners; const Corners c0{{{0, 0, 0}, {1, 0, 0}, {0, 1, 0}}}; const Corners c1{{{0, 0, 1}, {2, 0, 1}, {0, 2, 1}}}; const auto& corners = std::tie(c0, c1); Normals n0{{{0, 0, 1}, {1, 0, 1}, {0, 1, 1}}}; for (auto& n : n0) n /= n.two_norm(); Normals n1{{{0, 0, -1}, {-1, 0, -1}, {0, -1, -1}}}; for (auto& n : n1) n /= n.two_norm(); const auto& normals = std::tie(n0, n1); P p; p.project(corners, normals); /* Check image */ { const auto& success = get<0>(p.success()); if (!success.all()) { std::cout << "ERROR: test_project_simple2: not all Phi(x_i) are inside the image triangle" << std::endl; pass = false; } const Corners expected{{{0, 0, 1}, {1, 0, sqrt(2.)}, {0, 1, sqrt(2.)}}}; const auto& images = get<0>(p.images()); for (unsigned i = 0; i < images.size(); ++i) { if (!((images[i] - expected[i]).infinity_norm() < 1e-8)) { std::cout << "ERROR: test_project_simple2: corner " << i << " was projected on " << images[i] << "; expected: " << expected[i] << std::endl; pass = false; } } } /* Check preimage */ { const auto& success = get<1>(p.success()); if (!success.all()) { std::cout << "ERROR: test_project_simple: not all Phi^{-1}(y_i) are inside the preimage triangle" << std::endl; pass = false; } const Corners expected{{{0, 0, 1}, {1, 0, sqrt(2.)}, {0, 1, sqrt(2.)}}}; const auto& images = get<1>(p.images()); for (unsigned i = 0; i < images.size(); ++i) { if (!((images[i] - expected[i]).infinity_norm() < 1e-8)) { std::cout << "ERROR: test_project_simple2: corner " << i << " was inverse-projected on " << images[i] << "; expected: " << expected[i] << std::endl; pass = false; } } } /* No edge intersections. */ if (p.numberOfEdgeIntersections() != 0) { std::cout << "ERROR: test_project_simple2: there were unexpected edge intersections" << std::endl; pass = false; } if (!pass) write(p, corners, normals, "projectiontest_project_simple2.vtk"); return pass; } bool test_project3() { /* Test with intersting numbers. * The result was not checked, but is given to prevent accidential changes... Hopefully it is right. */ using std::get; bool pass = true; using V = Dune::FieldVector; using P = Projection; using Corners = std::array; using Normals = Corners; const Corners c0{{{2.85, 4., 3.}, {2.85, 5., 3.}, {1.9, 5., 3.}}}; const Corners c1{{{2., 4.38091, 3.61115}, {-0.6, 4.38091, 3.61115}, {2., 5.08885, 4.31909}}}; const auto& corners = std::tie(c0, c1); const Normals n0{{{0., 0., 1.}, {0., 0., 1.}, {0., 0., 1.}}}; const Normals n1{{{0., 0.587785, -0.809017}, {0., 0.62962, -0.776903}, {0., 0.809017, -0.587785}}}; const auto& normals = std::tie(n0, n1); P p; p.project(corners, normals); /* Check image */ { const auto& success = get<0>(p.success()); if (success[0] || success[1] || !success[2]) { std::cout << "ERROR: test_project3: unexpected Phi(x_i) are in the image triangle" << std::endl; pass = false; } const Corners expected{{ {-0.326923, -0.538054, 0.23024}, {-0.326923, 0.874495, 1.23024}, {0.0384615, 0.874495, 1.23024} }}; const auto& images = get<0>(p.images()); for (unsigned i = 0; i < images.size(); ++i) { if (!((images[i] - expected[i]).infinity_norm() < 1e-5)) { std::cout << "ERROR: test_project3: corner " << i << " was projected on " << images[i] << "; expected: " << expected[i] << std::endl; pass = false; } } } /* Check preimage */ { const auto& success = get<1>(p.success()); if (success.any()) { std::cout << "ERROR: test_project3: not all Phi^{-1}(y_i) are outside the preimage triangle" << std::endl; pass = false; } const Corners expected{{ {-0.513827, 0.894737, 0.494431}, {-3.25067, 3.63158, 0.474804}, {0.194113, 0.894737, 0.775341} }}; const auto& images = get<1>(p.images()); for (unsigned i = 0; i < images.size(); ++i) { if (!((images[i] - expected[i]).infinity_norm() < 1e-5)) { std::cout << "ERROR: test_project3: corner " << i << " was inverse-projected on " << images[i] << "; expected: " << expected[i] << std::endl; pass = false; } } } /* Two edge intersections. */ if (p.numberOfEdgeIntersections() != 2) { std::cout << "ERROR: test_project3: there were unexpected edge intersections" << std::endl; pass = false; } else { { const auto& in = p.edgeIntersections()[0]; if (in.edge[0] != 1 || in.edge[1] != 1) { std::cout << "ERROR: test_project3: edge intersection 0 involves wrong edges " << in.edge[0] << " and " << in.edge[1] << "; expected: 1 and 1" << std::endl; pass = false; } const V expected0{0, 0.894737, 1.12498}; if (!((in.local[0] - expected0).infinity_norm() < 1e-5)) { std::cout << "ERROR: test_project3: edge intersection 0 at local[0] = " << in.local[0] << "; expected: " << expected0 << std::endl; pass = false; } const V expected1{0, 0.725806, 0.736697}; if (!((in.local[1] - expected1).infinity_norm() < 1e-5)) { std::cout << "ERROR: test_project3: edge intersection 0 at local[1] = " << in.local[1] << "; expected: " << expected1 << std::endl; pass = false; } } { const auto& in = p.edgeIntersections()[1]; if (in.edge[0] != 2 || in.edge[1] != 1) { std::cout << "ERROR: test_project3: edge intersection 1 involves wrong edges " << in.edge[0] << " and " << in.edge[1] << "; expected: 2 and 1" << std::endl; pass = false; } const V expected0{0.105263, 0.894737, 1.23024}; if (!((in.local[0] - expected0).infinity_norm() < 1e-5)) { std::cout << "ERROR: test_project3: edge intersection 1 at local[0] = " << in.local[0] << "; expected: " << expected0 << std::endl; pass = false; } const V expected1{0, 0.874495, 0.761376}; if (!((in.local[1] - expected1).infinity_norm() < 1e-5)) { std::cout << "ERROR: test_project3: edge intersection 1 at local[1] = " << in.local[1] << "; expected: " << expected1 << std::endl; pass = false; } } } if (!pass) write(p, corners, normals, "projectiontest_project3.vtk"); return pass; } bool test_project4() { /* Test with intersting numbers. * The result was not checked, but is given to prevent accidential changes... Hopefully it is right. */ using std::get; bool pass = true; using V = Dune::FieldVector; using P = Projection; using Corners = std::array; using Normals = Corners; const Corners c0{{{3.3226, 4.41838, 2.5606}, {3.56991, 4.60089, 2.67132},{3.58641, 4.42509, 2.56724}}}; const Corners c1{{{3.53965, -0.313653, 3.39551},{4.06013, -0.311809, 3.39505},{3.54027, -0.434644, 3.61669}}}; const auto& corners = std::tie(c0, c1); const Normals n0{{{-0.00668383, -0.480515, 0.876961},{-0.00186939, -0.440971, 0.897519},{-0.00727575, -0.477334, 0.878692}}}; const Normals n1{{{0.00296167, -0.872357, -0.48886},{0.0032529,-0.87389, -0.486112},{0.00375284, -0.877906, -0.478818}}}; const auto& normals = std::tie(n0, n1); P p; p.project(corners, normals); /* Check image */ { const auto& success = get<0>(p.success()); if (success.any()) { std::cout << "ERROR: test_project4: unexpected Phi(x_i) are in the image triangle" << std::endl; pass = false; } } /* Check preimage */ { const auto& success = get<1>(p.success()); if (success.any()) { std::cout << "ERROR: test_project4: not all Phi^{-1}(y_i) are outside the preimage triangle" << std::endl; pass = false; } } if (p.numberOfEdgeIntersections() != 0) { std::cout << "ERROR: test_project4: there were unexpected edge intersections" << std::endl; pass = false; } if (!pass) write(p, corners, normals, "projectiontest_project4.vtk"); return pass; } bool test_project5() { using std::get; using std::sqrt; bool pass = true; typedef Dune::FieldVector V; typedef Projection P; using Corners = std::array; using Normals = Corners; const Corners c0{{{1.91, 0.82, 4}, {1.71388, 0.831652, 4.01554}, {1.91, 0.972786, 3.90557}}}; const Corners c1{{{0, 0, 0}, {0, 0, 3}, {0, 1.5, 3}}}; const auto& corners = std::tie(c0, c1); Normals n0{{{0.00368949, -0.588605, -0.808412}, {-0.18944, -0.577784, -0.793901}, {0.00330402, -0.435137, -0.900358}}}; for (auto& n : n0) n /= n.two_norm(); Normals n1{{{-0.57735, -0.57735, -0.57735}, {-0.408248, -0.408248, 0.816497}, {-0.707107, 0, 0.707107}}}; for (auto& n : n1) n /= n.two_norm(); const auto& normals = std::tie(n0, n1); P p(0.2,-0.1); p.project(corners, normals); /* Check image */ { const auto& success0 = get<0>(p.success()); if (success0.any()) { std::cout << "ERROR: test_project5: all Phi(x_i) should be outside of the image triangle" << std::endl; pass = false; } } /* Check preimage */ { const auto& success = get<1>(p.success()); if (success.any()) { std::cout << "ERROR: test_project5: all Phi^{-1}(y_i) should be outside of the preimage triangle" << std::endl; pass = false; } } /* No edge intersections. */ if (p.numberOfEdgeIntersections() != 0) { std::cout << "ERROR: test_project5: there were unexpected edge intersections" << std::endl; pass = false; } if (!pass) write(p, corners, normals, "projectiontest_project_5.vtk"); return pass; } bool test_project_overlap() { using std::get; bool pass = true; typedef Dune::FieldVector V; typedef Projection P; using Corners = std::array; using Normals = Corners; const Corners c0{{{0, 0, 1}, {1, 0, 1}, {0, 4, -1}}}; const Corners c1{{{0, 0, 0}, {1, 0, 0}, {0, 1, 0}}}; const auto& corners = std::tie(c0, c1); const Normals n0{{{0, 0, -1}, {0, 0, -1}, {0, 0, -1}}}; const Normals n1{{{0, 0, 1}, {0, 0, 1}, {0, 0, 1}}}; const auto& normals = std::tie(n0, n1); P p(0.5); p.project(corners, normals); /* Check image */ { const auto& success = get<0>(p.success()); if (success != std::bitset<3>(0b011)) { std::cout << "ERROR: test_project_overlap: forward projection did not succeed/fail as expected" << std::endl; pass = false; } const Corners expected{{{0, 0, 1}, {1, 0, 1}, {0, 4, -1}}}; const auto& images = get<0>(p.images()); for (unsigned i = 0; i < images.size(); ++i) { if (!((images[i] - expected[i]).infinity_norm() < 1e-8)) { std::cout << "ERROR: test_project_overlap: corner " << i << " was projected on " << images[i] << "; expected: " << expected[i] << std::endl; pass = false; } } } /* Check preimage */ { const auto& success = get<1>(p.success()); if (!success.all()) { std::cout << "ERROR: test_project_overlap: not all Phi^{-1}(y_i) are inside the preimage triangle" << std::endl; pass = false; } const Corners expected{{{0, 0, 1}, {1, 0, 1}, {0, 0.25, 0.5}}}; const auto& images = get<1>(p.images()); for (unsigned i = 0; i < images.size(); ++i) { if (!((images[i] - expected[i]).infinity_norm() < 1e-8)) { std::cout << "ERROR: test_project_overlap: corner " << i << " was inverse-projected on " << images[i] << "; expected: " << expected[i] << std::endl; pass = false; } } } /* No edge intersections. */ if (p.numberOfEdgeIntersections() != 0) { std::cout << "ERROR: test_project_overlap: there were unexpected edge intersections" << std::endl; pass = false; } if (!pass) write(p, corners, normals, "projectiontest_project_overlap.vtk"); return pass; } int main() { bool pass = true; pass = pass && test_project_simple(); pass = pass && test_project_simple2(); pass = pass && test_project3(); pass = pass && test_project4(); pass = pass && test_project5(); pass = pass && test_project_overlap(); return pass ? 0 : 1; } dune-grid-glue-2.9.0/dune/grid-glue/test/ringcommtest.cc000066400000000000000000000036711435125002300231470ustar00rootroot00000000000000// -*- tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- // vi: set et ts=4 sw=2 sts=2: // SPDX-FileCopyrightInfo: Copyright © DUNE Project contributors, see file LICENSE.md in module root // SPDX-License-Identifier: LGPL-3.0-or-later OR LicenseRef-GPL-2.0-only-with-dune-grid-glue-exception #include "config.h" #include #include #define DEBUG_GRIDGLUE_PARALLELMERGE 1 #include #include using namespace Dune; // using namespace Dune::GridGlue; #if HAVE_MPI void eh( MPI_Comm *comm, int *err, ... ) { int len = 1024; char error_txt[len]; MPI_Error_string(*err, error_txt, &len); assert(len <= 1024); DUNE_THROW(Dune::Exception, "MPI ERROR -- " << error_txt); } #endif // HAVE_MPI int main(int argc, char *argv[]) { auto & mpihelper = Dune::MPIHelper::instance(argc, argv); Dune::dinfo.attach(std::cout); int rank = 0; #if HAVE_MPI MPI_Errhandler errhandler; MPI_Comm_create_errhandler(eh, &errhandler); MPI_Comm_set_errhandler(MPI_COMM_WORLD, errhandler); rank = mpihelper.rank(); #endif std::vector seen(mpihelper.size(), false); std::vector data1({mpihelper.rank(), 1, 2, 3}); using Vec = Dune::FieldVector; std::vector data2(1000*(mpihelper.rank()+1), Vec(0.0)); auto op = [&](int remote, const std::vector&v1, const std::vector&v2){ std::cout << rank << " received " << v1[0] << "/" << v2.size() << " from " << remote << std::endl; assert(v1[0] == remote); assert(v2.size() == 1000*(remote+1)); seen[remote] = true; }; int sz; MPI_Comm_size(MPI_COMM_WORLD, &sz); std::cout << "SIZE: " << sz << std::endl; std::cout << rank << ": COMM " << MPI_COMM_WORLD << std::endl; Dune::Parallel::MPI_AllApply(MPI_COMM_WORLD, op, data1, data2); for (int i=0; i #include #include #include #include #include const unsigned dim = 3; using Coordinates = Dune::EquidistantOffsetCoordinates; using Grid = Dune::YaspGrid; using Element = Grid::Codim<0>::Entity; using Extractor = Dune::GridGlue::Codim1Extractor; using GridGlue = Dune::GridGlue::GridGlue; using ContactMerge = Dune::GridGlue::ContactMerge; int main(int argc, char** argv) { Dune::MPIHelper::instance(argc, argv); Grid grid0{{0., 0., 0.}, {1., 1., 1.}, {10, 10, 10}}; Grid grid1{{.12, 0.23, 1.05}, {1.12, 1.23, 2.05}, {10, 10, 10}}; auto truePredicate = [](const Element&, unsigned int) { return true; }; auto extractor0 = std::make_shared(grid0.leafGridView(), truePredicate); auto extractor1 = std::make_shared(grid1.leafGridView(), truePredicate); auto merger = std::make_shared(); GridGlue glue(extractor0, extractor1, merger); glue.build(); Dune::GridGlue::GridGlueVtkWriter::write(glue, "contactmerge"); return 0; }