pax_global_header00006660000000000000000000000064131513017430014510gustar00rootroot0000000000000052 comment=6f09eb4435edc1b875f67ada210a759b61993d83 dune-grid-glue-2.5.0/000077500000000000000000000000001315130174300143245ustar00rootroot00000000000000dune-grid-glue-2.5.0/.gitignore000066400000000000000000000000111315130174300163040ustar00rootroot00000000000000build-*/ dune-grid-glue-2.5.0/.gitlab-ci.yml000066400000000000000000000003671315130174300167660ustar00rootroot00000000000000--- dune:2.5--gcc: image: duneci/dune:2.5 script: duneci-standard-test dune:git--gcc: image: duneci/dune:git script: duneci-standard-test dune:git--clang: image: duneci/dune:git script: duneci-standard-test --opts=/duneci/opts.clang dune-grid-glue-2.5.0/CHANGELOG.md000066400000000000000000000034671315130174300161470ustar00rootroot00000000000000Changes 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.5.0/CMakeLists.txt000066400000000000000000000014541315130174300170700ustar00rootroot00000000000000cmake_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.5.0/COPYING000066400000000000000000000035541315130174300153660ustar00rootroot00000000000000Copyright holders: 2014-2017 Ansgar Burchardt 2009 Gerrit Buse 2009-2016 Christian Engwer 2014 Christoph Grüninger 2014-2016 Katja Hanowski 2013 Steffen Müthing 2016 Elias Pipping 2009-2017 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.5.0/README.md000066400000000000000000000034531315130174300156100ustar00rootroot00000000000000The `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 (to be published) 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.5.0/TODO000066400000000000000000000020061315130174300150120ustar00rootroot00000000000000- 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.5.0/config.h.cmake000066400000000000000000000010161315130174300170170ustar00rootroot00000000000000/* 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.5.0/doc/000077500000000000000000000000001315130174300150715ustar00rootroot00000000000000dune-grid-glue-2.5.0/doc/CMakeLists.txt000066400000000000000000000000341315130174300176260ustar00rootroot00000000000000add_subdirectory("doxygen") dune-grid-glue-2.5.0/doc/doxygen/000077500000000000000000000000001315130174300165465ustar00rootroot00000000000000dune-grid-glue-2.5.0/doc/doxygen/CMakeLists.txt000066400000000000000000000001121315130174300213000ustar00rootroot00000000000000# shortcut for creating the Doxyfile.in and Doxyfile add_doxygen_target() dune-grid-glue-2.5.0/doc/doxygen/Doxylocal000066400000000000000000000010701315130174300204250ustar00rootroot00000000000000INPUT += @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.5.0/dune-grid-glue.pc.in000066400000000000000000000005321315130174300200650ustar00rootroot00000000000000prefix=@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.5.0/dune.module000066400000000000000000000004551315130174300164720ustar00rootroot00000000000000#dune module information file# ############################## #Name of the module Module: dune-grid-glue Version: 2.5.0 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.5.0/dune/000077500000000000000000000000001315130174300152575ustar00rootroot00000000000000dune-grid-glue-2.5.0/dune/CMakeLists.txt000066400000000000000000000000341315130174300200140ustar00rootroot00000000000000add_subdirectory(grid-glue) dune-grid-glue-2.5.0/dune/grid-glue/000077500000000000000000000000001315130174300171365ustar00rootroot00000000000000dune-grid-glue-2.5.0/dune/grid-glue/CMakeLists.txt000066400000000000000000000003031315130174300216720ustar00rootroot00000000000000add_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.5.0/dune/grid-glue/adapter/000077500000000000000000000000001315130174300205565ustar00rootroot00000000000000dune-grid-glue-2.5.0/dune/grid-glue/adapter/CMakeLists.txt000066400000000000000000000004151315130174300233160ustar00rootroot00000000000000#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.5.0/dune/grid-glue/adapter/gridglue.cc000066400000000000000000000457161315130174300227040ustar00rootroot00000000000000// -*- tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- // vi: set et ts=4 sw=2 sts=2: /* IMPLEMENTATION OF CLASS G R I D G L U E */ #include "intersection.hh" #include #include #include "../gridglue.hh" #include /** \todo Implement MPI Status check with exception handling */ #define CheckMPIStatus(A,B) {} #if HAVE_MPI namespace { template struct MPITypeInfo {}; template<> struct MPITypeInfo< int > { static const unsigned int size = 1; static inline MPI_Datatype getType() { return MPI_INT; } static const int tag = 1234560; }; template struct MPITypeInfo< Dune::FieldVector > { static const unsigned int size = N; static inline MPI_Datatype getType() { return Dune::MPITraits::getType(); } static const int tag = 1234561; }; template<> struct MPITypeInfo< unsigned int > { static const unsigned int size = 1; static inline MPI_Datatype getType() { return MPI_UNSIGNED; } static const int tag = 1234562; }; template<> struct MPITypeInfo< Dune::GeometryType > { static const unsigned int size = 1; static inline MPI_Datatype getType() { return Dune::MPITraits< Dune::GeometryType >::getType(); } static const int tag = 1234563; }; /** Send std::vector in the ring * data is sent to rankright * from rankleft tmp is received and swapped with data */ template void MPI_SendVectorInRing( std::vector & data, std::vector & tmp, int leftsize, int rightrank, int leftrank, MPI_Comm comm ) { // mpi status stuff int result DUNE_UNUSED; result = 0; MPI_Status status; typedef MPITypeInfo Info; // alloc buffer unsigned int tmpsize = tmp.size(); tmp.resize(leftsize); // send data int rank; MPI_Comm_rank(comm, &rank); // std::cout << rank << " send " << data.size() << " to " << rightrank << std::endl; // std::cout << rank << " recv " << tmp.size() << " from " << leftrank << std::endl; if (leftsize > 0 && data.size() > 0) { // send & receive result = MPI_Sendrecv( &(data[0]), Info::size*data.size(), Info::getType(), rightrank, Info::tag, &(tmp[0]), Info::size*tmp.size(), Info::getType(), leftrank, Info::tag, comm, &status); } if (leftsize == 0 && data.size() > 0) { // send result = MPI_Send( &(data[0]), Info::size*data.size(), Info::getType(), rightrank, Info::tag, comm); } if (leftsize > 0 && data.size() == 0) { // receive result = MPI_Recv( &(tmp[0]), Info::size*tmp.size(), Info::getType(), leftrank, Info::tag, comm, &status); } // check result CheckMPIStatus(result, status); // swap buffers data.swap(tmp); // resize tmp buffer tmp.resize(tmpsize); MPI_Barrier(comm); } /** \brief struct to simplify communication of the patch data sizes */ struct PatchSizes { PatchSizes() : patch0coords(0), patch0entities(0), patch0types(0), patch1coords(0), patch1entities(0), patch1types(0) {} //! initialize patch sizes PatchSizes(unsigned int c0, unsigned int e0, unsigned int t0, unsigned int c1, unsigned int e1, unsigned int t1) : patch0coords(c0), patch0entities(e0), patch0types(t0), patch1coords(c1), patch1entities(e1), patch1types(t1) {} //! initialize patch sizes using the data containers template PatchSizes(const C & c0, const E & e0, const T & t0, const C & c1, const E & e1, const T & t1) : patch0coords(c0.size()), patch0entities(e0.size()), patch0types(t0.size()), patch1coords(c1.size()), patch1entities(e1.size()), patch1types(t1.size()) {} unsigned int patch0coords, patch0entities, patch0types, patch1coords, patch1entities, patch1types; unsigned int maxCoords() const { return std::max(patch0coords, patch1coords); } unsigned int maxEntities() const { return std::max(patch0entities, patch1entities); } unsigned int maxTypes() const { return std::max(patch0types, patch1types); } }; } #endif // HAVE_MPI namespace Dune { namespace GridGlue { template GridGlue::GridGlue(const Grid0Patch& gp0, const Grid1Patch& gp1, Merger* merger) : GridGlue(Dune::stackobject_to_shared_ptr(gp0), Dune::stackobject_to_shared_ptr(gp1), Dune::stackobject_to_shared_ptr(*merger)) { /* Nothing. */ } template GridGlue::GridGlue(const std::shared_ptr gp0, const std::shared_ptr gp1, const std::shared_ptr merger) : patch0_(gp0), patch1_(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(*patch0_, patch0coords, patch0entities, patch0types); extractGrid(*patch1_, 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 #if HAVE_MPI if (commsize > 1) { // setup parallel indexset patch0_is_.beginResize(); patch1_is_.beginResize(); } #endif // HAVE_MPI // merge local patches and add to intersection list if (patch0entities.size() > 0 && patch1entities.size() > 0) mergePatches(patch0coords, patch0entities, patch0types, myrank, patch1coords, patch1entities, patch1types, myrank); else // set size correctly if projection is empty index__sz = 0; #ifdef CALL_MERGER_TWICE if (patch0entities.size() > 0 && patch1entities.size() > 0) mergePatches(patch0coords, patch0entities, patch0types, myrank, patch1coords, patch1entities, patch1types, myrank); #endif #if HAVE_MPI // status variables of communication int mpi_result DUNE_UNUSED; MPI_Status mpi_status; #ifdef DEBUG_GRIDGLUE_PARALLELMERGE std::cout << myrank << " Comm Size" << commsize << std::endl; #endif if (commsize > 1) { // get patch sizes PatchSizes patchSizes (patch0coords, patch0entities, patch0types, patch1coords, patch1entities, patch1types); #ifdef DEBUG_GRIDGLUE_PARALLELMERGE std::cout << myrank << " Start Communication" << std::endl; #endif // communicate max patch size PatchSizes maxPatchSizes; mpi_result = MPI_Allreduce(&patchSizes, &maxPatchSizes, 6, MPI_UNSIGNED, MPI_MAX, MPI_COMM_WORLD); CheckMPIStatus(mpi_result, 0); #ifdef DEBUG_GRIDGLUE_PARALLELMERGE std::cout << myrank << " maxPatchSizes " << "done" << std::endl; #endif /** \todo Use vector for message buffer and MultiVector to copy these */ // allocate remote buffers (maxsize to avoid reallocation) std::vector > remotePatch0coords ( maxPatchSizes.patch0coords ); std::vector remotePatch0entities ( maxPatchSizes.patch0entities ); std::vector remotePatch0types ( maxPatchSizes.patch0types ); std::vector > remotePatch1coords ( maxPatchSizes.patch1coords ); std::vector remotePatch1entities ( maxPatchSizes.patch1entities ); std::vector remotePatch1types ( maxPatchSizes.patch1types ); // copy local patches to remote patch buffers remotePatch0coords.clear(); std::copy(patch0coords.begin(), patch0coords.end(), std::back_inserter(remotePatch0coords)); remotePatch0entities.clear(); std::copy(patch0entities.begin(), patch0entities.end(), std::back_inserter(remotePatch0entities)); remotePatch0types.clear(); std::copy(patch0types.begin(), patch0types.end(), std::back_inserter(remotePatch0types)); remotePatch1coords.clear(); std::copy(patch1coords.begin(), patch1coords.end(), std::back_inserter(remotePatch1coords)); remotePatch1entities.clear(); std::copy(patch1entities.begin(), patch1entities.end(), std::back_inserter(remotePatch1entities)); remotePatch1types.clear(); std::copy(patch1types.begin(), patch1types.end(), std::back_inserter(remotePatch1types)); // allocate tmp buffers (maxsize to avoid reallocation) std::vector > tmpPatchCoords ( maxPatchSizes.maxCoords() ); std::vector tmpPatchEntities ( maxPatchSizes.maxEntities() ); std::vector tmpPatchTypes ( maxPatchSizes.maxTypes() ); // communicate patches in the ring for (int i=1; i::tag, leftrank, MPITypeInfo::tag, mpicomm_, &mpi_status); CheckMPIStatus(mpi_result, mpi_status); } #ifdef DEBUG_GRIDGLUE_PARALLELMERGE std::cout << myrank << " patchSizes " << "done" << std::endl; #endif /* send remote patch to right neighbor and receive from left neighbor */ // patch0coords #ifdef DEBUG_GRIDGLUE_PARALLELMERGE std::cout << myrank << " patch0coords" << std::endl; #endif MPI_SendVectorInRing( remotePatch0coords, tmpPatchCoords, patchSizes.patch0coords, rightrank, leftrank, mpicomm_); // patch0entities #ifdef DEBUG_GRIDGLUE_PARALLELMERGE std::cout << myrank << " patch0entities" << std::endl; #endif MPI_SendVectorInRing( remotePatch0entities, tmpPatchEntities, patchSizes.patch0entities, rightrank, leftrank, mpicomm_); // patch0types #ifdef DEBUG_GRIDGLUE_PARALLELMERGE std::cout << myrank << " patch0types" << std::endl; #endif MPI_SendVectorInRing( remotePatch0types, tmpPatchTypes, patchSizes.patch0types, rightrank, leftrank, mpicomm_); // patch1coords #ifdef DEBUG_GRIDGLUE_PARALLELMERGE std::cout << myrank << " patch1coords" << std::endl; #endif MPI_SendVectorInRing( remotePatch1coords, tmpPatchCoords, patchSizes.patch1coords, rightrank, leftrank, mpicomm_); // patch1entities #ifdef DEBUG_GRIDGLUE_PARALLELMERGE std::cout << myrank << " patch1entities" << std::endl; #endif MPI_SendVectorInRing( remotePatch1entities, tmpPatchEntities, patchSizes.patch1entities, rightrank, leftrank, mpicomm_); // patch1types #ifdef DEBUG_GRIDGLUE_PARALLELMERGE std::cout << myrank << " patch1types" << std::endl; #endif MPI_SendVectorInRing( remotePatch1types, tmpPatchTypes, patchSizes.patch1types, rightrank, leftrank, mpicomm_); /* merging */ // merge local & remote patches // patch0_is_ and patch1_is_ are updated automatically if (remotePatch1entities.size() > 0 && patch0entities.size() > 0) mergePatches(patch0coords, patch0entities, patch0types, myrank, remotePatch1coords, remotePatch1entities, remotePatch1types, remoterank); if (remotePatch0entities.size() > 0 && patch1entities.size() > 0) mergePatches(remotePatch0coords, remotePatch0entities, remotePatch0types, remoterank, patch1coords, patch1entities, patch1types, myrank); std::cout << "Sync processes" << std::endl; MPI_Barrier(mpicomm_); std::cout << "...done" << std::endl; } } 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 } #endif } template void printVector(const std::vector & v, std::string name) { std::cout << 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) { IntersectionData data(*this, i, offset, patch0local, patch1local); intersections_[offset+i] = data; } index__sz = intersections_.size() - 1; std::cout << myrank << " GridGlue::mergePatches : " << "The number of remote intersections is " << intersections_.size()-1 << std::endl; // printVector(patch0coords,"patch0coords"); // printVector(patch0entities,"patch0entities"); // printVector(patch0types,"patch0types"); // printVector(patch1coords,"patch1coords"); // printVector(patch1entities,"patch1entities"); // printVector(patch1types,"patch1types"); #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.grid0local_) { Dune::PartitionType ptype = patch0_->element(it.grid0indices_[0]).partitionType(); patch0_is_.add (gid, LocalIndex(offset+i, ptype) ); } if (it.grid1local_) { Dune::PartitionType ptype = patch1_->element(it.grid1indices_[0]).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 #include using Dune::GridGlue::GridGlue; #endif dune-grid-glue-2.5.0/dune/grid-glue/adapter/gridglueamirawriter.hh000066400000000000000000000104121315130174300251460ustar00rootroot00000000000000/** * @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()); typedef typename std::conditional<(side==0), typename Glue::Grid0View, typename Glue::Grid1View>::type 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.5.0/dune/grid-glue/adapter/gridgluecommunicate.hh000066400000000000000000000237211315130174300251330ustar00rootroot00000000000000// -*- tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- // vi: set et ts=4 sw=2 sts=2: #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.5.0/dune/grid-glue/adapter/gridgluevtkwriter.hh000066400000000000000000000236261315130174300246740ustar00rootroot00000000000000// -*- tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- // vi: set et ts=4 sw=2 sts=2: /* * 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 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()); typedef typename std::conditional<(side==0), typename Glue::Grid0View, typename Glue::Grid1View>::type GridView; typedef typename std::conditional<(side==0), typename Glue::Grid0Patch, typename Glue::Grid1Patch>::type Extractor; 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()); typedef typename std::conditional<(side==0), typename Glue::Grid0View, typename Glue::Grid1View>::type GridView; typedef typename std::conditional<(side==0), typename Glue::Grid0IntersectionIterator, typename Glue::Grid1IntersectionIterator>::type RemoteIntersectionIterator; 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 // ---------------- typedef typename Glue::Grid0Patch Extractor; 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 (RemoteIntersectionIterator isIt = glue.template ibegin(); isIt != glue.template iend(); ++isIt) { for (int i = 0; i < isIt->geometry().corners(); ++i) fmerged << isIt->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.5.0/dune/grid-glue/adapter/intersection.hh000066400000000000000000000561331315130174300236150ustar00rootroot00000000000000// -*- tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- // vi: set et ts=4 sw=2 sts=2: /** @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 #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 */ enum { coorddim = GridGlue::dimworld }; private: // intermediate quantities static const int dim0 = GridGlue::Grid0View::Grid::dimension - GridGlue::Grid0Patch::codim; static const int dim1 = GridGlue::Grid1View::Grid::dimension - GridGlue::Grid1Patch::codim; public: /** \brief Dimension of the intersection */ enum { mydim = (dim0 Grid0LocalGeometry; typedef AffineGeometry Grid0Geometry; typedef AffineGeometry Grid1LocalGeometry; typedef AffineGeometry Grid1Geometry; typedef typename GridGlue::Grid0View::IndexSet::IndexType Grid0IndexType; typedef typename GridGlue::Grid1View::IndexSet::IndexType Grid1IndexType; /** \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() : grid0local_(false), grid1local_(false) {} /* M E M B E R V A R I A B L E S */ /// @brief index of this intersection after GridGlue interface IndexType index_; bool grid0local_; //!< true if the associated grid0 entity is local std::vector grid0indices_; //!< indices of the associated local grid0 entity bool grid1local_; //!< true if the associated grid1 entity is local std::vector grid1indices_; //!< indices of the associated local grid1 entity /** * Embedding of intersection into local grid0 entity coordinates. */ std::vector > grid0localgeom_; /** * Global intersection geometry on grid0 side. * * This is the same as g∘i for the first embedding i into a grid0 * entity as stored in grid0localgeom_ and that entities global * geometry g. */ std::shared_ptr grid0geom_; /** * Embedding of intersection into local grid1 entity coordinates. */ std::vector > grid1localgeom_; /** * Global intersection geometry on grid1 side. * * This is the same as g∘i for the first embedding i into a grid1 * entity as stored in grid1localgeom_ and that entities global * geometry g. */ std::shared_ptr grid1geom_; }; //! \todo move this functionality to GridGlue template IntersectionData::IntersectionData(const GridGlue& glue, unsigned int mergeindex, unsigned int offset, bool grid0local, bool grid1local) : index_(mergeindex+offset), grid0local_(grid0local), grid1local_(grid1local) { unsigned int n_grid0Parents = glue.merger_->template parents<0>(mergeindex); unsigned int n_grid1Parents = glue.merger_->template parents<1>(mergeindex); assert (0 <= n_grid0Parents || 0 <= n_grid1Parents); // init containers grid0indices_.resize(n_grid0Parents); grid0localgeom_.resize(n_grid0Parents); grid1indices_.resize(n_grid1Parents); grid1localgeom_.resize(n_grid1Parents); // default values grid0indices_[0] = 0; grid1indices_[0] = 0; typedef typename GridGlue::ctype ctype; // Number of corners of the intersection const int nSimplexCorners = mydim + 1; // 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); // initialize the local and the global geometries of grid0 { // compute the coordinates of the subface's corners in codim 0 entity local coordinates const int elementdim = GridGlue::Grid0View::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_grid0Parents; ++par) { for (int i = 0; i < nSimplexCorners; ++i) corners_subEntity_local[i] = glue.merger_->template parentLocal<0>(mergeindex, i, par); // Coordinates of the remote intersection corners wrt the element coordinate system std::array, nSimplexCorners> corners_element_local; if (grid0local) { grid0indices_[par] = glue.merger_->template parent<0>(mergeindex,par); typename GridGlue::Grid0Patch::LocalGeometry grid0LocalGeometry = glue.template patch<0>().geometryLocal(grid0indices_[par]); typename GridGlue::Grid0Patch::Geometry grid0WorldGeometry1 = glue.template patch<0>().geometry(grid0indices_[par]); for (std::size_t i=0; i(type, corners_element_local); // Add world geometry only for 0th parent if (par == 0) { typename GridGlue::Grid0Patch::Geometry grid0WorldGeometry = glue.template patch<0>().geometry(grid0indices_[par]); // world coordinates of the remote intersection corners std::array, nSimplexCorners> corners_global; for (std::size_t i=0; i(type, corners_global); } } } } // do the same for the local and the global geometry of grid1 { // compute the coordinates of the subface's corners in codim 0 entity local coordinates const int elementdim = GridGlue::Grid1View::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_grid1Parents; ++par) { for (int i = 0; i < nSimplexCorners; ++i) corners_subEntity_local[i] = glue.merger_->template parentLocal<1>(mergeindex, i, par); // Coordinates of the remote intersection corners wrt the element coordinate system std::array, nSimplexCorners> corners_element_local; if (grid1local) { grid1indices_[par] = glue.merger_->template parent<1>(mergeindex, par); typename GridGlue::Grid1Patch::LocalGeometry grid1LocalGeometry = glue.template patch<1>().geometryLocal(grid1indices_[par]); for (std::size_t i=0; i(type, corners_element_local); // Add world geomety only for 0th parent if (par == 0) { typename GridGlue::Grid1Patch::Geometry grid1WorldGeometry = glue.template patch<1>().geometry(grid1indices_[par]); // world coordinates of the remote intersection corners std::array, nSimplexCorners> corners_global; for (std::size_t i=0; i(type, corners_global); } } } } } /** @brief @todo doc me */ template struct IntersectionDataView; template struct IntersectionDataView { typedef const typename IntersectionData::Grid0LocalGeometry LocalGeometry; typedef const typename IntersectionData::Grid0Geometry Geometry; typedef const typename IntersectionData::Grid0IndexType IndexType; static LocalGeometry& localGeometry(const IntersectionData & i, unsigned int parentId = 0) { return *i.grid0localgeom_[parentId]; } static Geometry& geometry(const IntersectionData & i) { return *i.grid0geom_; } static bool local(const IntersectionData & i) { return i.grid0local_; } static IndexType index(const IntersectionData & i, unsigned int parentId = 0) { return i.grid0indices_[parentId]; } static IndexType parents(const IntersectionData & i) { return i.grid0indices_.size(); } }; template struct IntersectionDataView { typedef const typename IntersectionData::Grid1LocalGeometry LocalGeometry; typedef const typename IntersectionData::Grid1Geometry Geometry; typedef const typename IntersectionData::Grid1IndexType IndexType; static LocalGeometry& localGeometry(const IntersectionData & i, unsigned int parentId = 0) { return *i.grid1localgeom_[parentId]; } static Geometry& geometry(const IntersectionData & i) { return *i.grid1geom_; } static IndexType local(const IntersectionData & i) { return i.grid1local_; } static IndexType index(const IntersectionData & i, unsigned int parentId = 0) { return i.grid1indices_[parentId]; } static IndexType parents(const IntersectionData & i) { return i.grid1indices_.size(); } }; /** @brief @todo doc me */ template struct IntersectionTraits; template struct IntersectionTraits { typedef ::Dune::GridGlue::GridGlue GridGlue; typedef Dune::GridGlue::IntersectionData IntersectionData; typedef typename GridGlue::Grid0View InsideGridView; typedef typename GridGlue::Grid1View OutsideGridView; typedef const typename IntersectionData::Grid0LocalGeometry InsideLocalGeometry; typedef const typename IntersectionData::Grid1LocalGeometry OutsideLocalGeometry; typedef const typename IntersectionData::Grid0Geometry Geometry; typedef const typename IntersectionData::Grid1Geometry OutsideGeometry; enum { coorddim = IntersectionData::coorddim, mydim = IntersectionData::mydim, insidePatch = 0, outsidePatch = 1 }; typedef typename GridGlue::ctype ctype; typedef Dune::FieldVector LocalCoordinate; typedef Dune::FieldVector GlobalCoordinate; }; template struct IntersectionTraits { typedef ::Dune::GridGlue::GridGlue GridGlue; typedef Dune::GridGlue::IntersectionData IntersectionData; typedef typename GridGlue::Grid1View InsideGridView; typedef typename GridGlue::Grid0View OutsideGridView; typedef const typename IntersectionData::Grid1LocalGeometry InsideLocalGeometry; typedef const typename IntersectionData::Grid0LocalGeometry OutsideLocalGeometry; typedef const typename IntersectionData::Grid1Geometry Geometry; typedef const typename IntersectionData::Grid0Geometry OutsideGeometry; typedef const typename IntersectionData::Grid1IndexType InsideIndexType; typedef const typename IntersectionData::Grid0IndexType OutsideIndexType; enum { coorddim = IntersectionData::coorddim, mydim = IntersectionData::mydim, insidePatch = 1, outsidePatch = 0 }; typedef typename GridGlue::ctype ctype; typedef Dune::FieldVector LocalCoordinate; typedef Dune::FieldVector GlobalCoordinate; }; /** @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; enum { /** \brief Dimension of the world space of the intersection */ coorddim = Traits::coorddim, /** \brief Dimension of the intersection */ mydim = Traits::mydim, /** \brief document the inside & outside patch */ //! @{ insidePatch = Traits::insidePatch, outsidePatch = Traits::outsidePatch //! @} }; // typedef unsigned int IndexType; private: /** * \brief codimension of the intersection with respect to the world dimension */ const static 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( IntersectionDataView::index(*i_, parentId)); } /** \brief Return element on the outside of this intersection. */ OutsideEntity outside(unsigned int parentId = 0) const { assert(neighbor()); return glue_->template patch().element( IntersectionDataView::index(*i_, 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 IntersectionDataView::localGeometry(*i_, parentId); } /** \brief Geometric information about this intersection in local coordinates of the outside() element. */ const OutsideLocalGeometry& geometryInOutside(unsigned int parentId = 0) const { return IntersectionDataView::localGeometry(*i_, 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 IntersectionDataView::geometry(*i_); } /** \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 IntersectionDataView::geometry(*i_); } /** \brief Type of reference element for this intersection */ Dune::GeometryType type() const { #ifdef ONLY_SIMPLEX_INTERSECTIONS static const Dune::GeometryType type(Dune::GeometryType::simplex, mydim); return type; #else #error Not Implemented #endif } /** \brief For parallel computations: Return true if inside() entity exists locally */ bool self() const { return IntersectionDataView::local(*i_); } /** \brief Return number of embeddings into local grid0 (grid1) entities. */ size_t neighbor(unsigned int g = 0) const { if (g == 0 && IntersectionDataView::local(*i_)) { return IntersectionDataView::parents(*i_); } else if (g == 1 && IntersectionDataView::local(*i_)) { return IntersectionDataView::parents(*i_); } 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( IntersectionDataView::index(*i_, 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( IntersectionDataView::index(*i_, 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.5.0/dune/grid-glue/adapter/intersectionindexset.hh000066400000000000000000000031241315130174300253510ustar00rootroot00000000000000#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.5.0/dune/grid-glue/adapter/intersectioniterator.hh000066400000000000000000000031701315130174300253600ustar00rootroot00000000000000// -*- tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- // vi: set et ts=4 sw=2 sts=2: /** @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.5.0/dune/grid-glue/adapter/rangegenerators.hh000066400000000000000000000050051315130174300242650ustar00rootroot00000000000000#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::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.5.0/dune/grid-glue/common/000077500000000000000000000000001315130174300204265ustar00rootroot00000000000000dune-grid-glue-2.5.0/dune/grid-glue/common/CMakeLists.txt000066400000000000000000000003311315130174300231630ustar00rootroot00000000000000#install headers install(FILES areawriter.hh areawriter_impl.hh crossproduct.hh projection.hh projection_impl.hh projectionwriter.hh projectionwriter_impl.hh DESTINATION include/dune/grid-glue/common) dune-grid-glue-2.5.0/dune/grid-glue/common/areawriter.hh000066400000000000000000000026061315130174300231200ustar00rootroot00000000000000#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.5.0/dune/grid-glue/common/areawriter_impl.hh000066400000000000000000000077761315130174300241560ustar00rootroot00000000000000#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.5.0/dune/grid-glue/common/crossproduct.hh000066400000000000000000000012751315130174300235060ustar00rootroot00000000000000#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.5.0/dune/grid-glue/common/projection.hh000066400000000000000000000227541315130174300231350ustar00rootroot00000000000000#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.5.0/dune/grid-glue/common/projection_impl.hh000066400000000000000000000357741315130174300241640ustar00rootroot00000000000000#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.5.0/dune/grid-glue/common/projectionwriter.hh000066400000000000000000000036201315130174300243610ustar00rootroot00000000000000#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.5.0/dune/grid-glue/common/projectionwriter_impl.hh000066400000000000000000000131731315130174300254060ustar00rootroot00000000000000#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.5.0/dune/grid-glue/extractors/000077500000000000000000000000001315130174300213345ustar00rootroot00000000000000dune-grid-glue-2.5.0/dune/grid-glue/extractors/CMakeLists.txt000066400000000000000000000002671315130174300241010ustar00rootroot00000000000000#install headers install(FILES codim0extractor.hh codim1extractor.hh extractor.hh extractorpredicate.hh vtksurfacewriter.hh DESTINATION include/dune/grid-glue/extractors) dune-grid-glue-2.5.0/dune/grid-glue/extractors/codim0extractor.hh000066400000000000000000000216041315130174300247670ustar00rootroot00000000000000// -*- tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- // vi: set et ts=4 sw=2 sts=2: /* * Filename: codim0extractor.hh * Version: 1.0 * Created on: Jun 23, 2009 * Author: Oliver Sander, Christian Engwer * --------------------------------- * Project: dune-grid-glue * Description: base class for grid extractors extracting surface grids * */ /** * @file * @brief Mesh grid extractor base class */ #ifndef DUNE_GRIDGLUE_EXTRACTORS_CODIM0EXTRACTOR_HH #define DUNE_GRIDGLUE_EXTRACTORS_CODIM0EXTRACTOR_HH #include #include #include #include #include "extractor.hh" #include "extractorpredicate.hh" namespace Dune { namespace GridGlue { template 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; static const Dune::PartitionIteratorType PType = Dune::Interior_Partition; typedef typename GV::Traits::template Codim<0>::template Partition::Iterator ElementIter; // 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 descr a predicate to mark entities for extraction (unary functor returning bool) */ DUNE_DEPRECATED_MSG("Please use a std::function in favor of the ExtractorPredicate.") Codim0Extractor(const GV& gv, const ExtractorPredicate& descr) : Extractor(gv), positiveNormalDirection_(false) { std::cout << "This is Codim0Extractor on a <" << GV::dimension << "," << GV::dimensionworld << "> grid!" << std::endl; const auto predicate = [&](const Element& element, unsigned int subentity) -> bool { return descr.contains(element, subentity); }; update(predicate); } /** * @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 (ElementIter elit = this->gv_.template begin<0, PType>(); elit != this->gv_.template end<0, PType>(); ++elit) { const auto& elmt = *elit; 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_[eindex] = new 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 = elit->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_[vindex] = new 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()); typename VertexInfoMap::const_iterator it1 = this->vtxInfo_.begin(); for (; it1 != this->vtxInfo_.end(); ++it1) { // get a pointer to the associated info object CoordinateInfo* current = &this->coords_[it1->second->idx]; // store this coordinates index // NEEDED? current->index = it1->second->idx; // store the vertex' index for the index2vertex mapping current->vtxindex = it1->first; // store the vertex' coordinates under the associated index // in the coordinates array const auto vtx = this->grid().entity(it1->second->p); current->coord = vtx.geometry().corner(0); } } } // namespace GridGlue } // namespace Dune #endif // DUNE_GRIDGLUE_EXTRACTORS_CODIM0EXTRACTOR_HH dune-grid-glue-2.5.0/dune/grid-glue/extractors/codim1extractor.hh000066400000000000000000000405251315130174300247730ustar00rootroot00000000000000// -*- tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- // vi: set et ts=4 sw=2 sts=2: /* * 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 "extractorpredicate.hh" #include #include #include #include namespace Dune { namespace GridGlue { 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 enum { 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; static const Dune::PartitionIteratorType PType = Dune::Interior_Partition; typedef typename GV::Traits::template Codim<0>::template Partition::Iterator ElementIter; typedef typename GV::IntersectionIterator IsIter; // 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 descr a predicate to mark entities for extraction (unary functor returning bool) */ DUNE_DEPRECATED_MSG("Please use a std::function in favor of the ExtractorPredicate.") Codim1Extractor(const GV& gv, const ExtractorPredicate& descr) : Extractor(gv) { std::cout << "This is Codim1Extractor on a <" << dim << "," << dimworld << "> grid!" << std::endl; const auto predicate = [&](const Element& element, unsigned int subentity) -> bool { return descr.contains(element, subentity); }; update(predicate); } /** * @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 (ElementIter elit = this->gv_.template begin<0, PType>(); elit != this->gv_.template end<0, PType>(); ++elit) { const auto& elmt = *elit; Dune::GeometryType gt = elmt.type(); // if some face is part of the surface add it! if (elit->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_[eindex] = new 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 (IsIter is = this->gv_.ibegin(elmt); is != this->gv_.iend(elmt); ++is) { // Stop only at selected boundary faces if (!is->boundary() or !predicate(elmt, is->indexInInside())) continue; const Dune::ReferenceElement& refElement = Dune::ReferenceElements::general(gt); // get the corner count of this face const int face_corners = refElement.size(is->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_[eindex]->faces++; // add a new face to the temporary collection temp_faces.push_back(SubEntityInfo(eindex, is->indexInInside(), Dune::GeometryType(Dune::GeometryType::simplex,dim-codim))); 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(is->indexInInside(), 1, i, dim); // get the vertex pointer and the index from the index set const Vertex vertex = elit->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_[vindex] = new 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 = is->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); // we have a quadrilateral here unsigned int vertex_indices[4]; unsigned int vertex_numbers[4]; // register the additional face(s) (2 simplices) this->elmtInfo_[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(is->indexInInside(), 1, i, dim); // get the vertex pointer and the index from the index set const Vertex vertex = elit->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_[vindex] = new 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.push_back(SubEntityInfo(eindex, is->indexInInside(), Dune::GeometryType(Dune::GeometryType::simplex,dim-codim))); 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 = is->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.push_back(SubEntityInfo(eindex, is->indexInInside(), Dune::GeometryType(Dune::GeometryType::simplex,dim-codim))); 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()); typename VertexInfoMap::const_iterator it1 = this->vtxInfo_.begin(); for (; it1 != this->vtxInfo_.end(); ++it1) { // get a pointer to the associated info object CoordinateInfo* current = &this->coords_[it1->second->idx]; // store this coordinates index // NEEDED? current->index = it1->second->idx; // store the vertex' index for the index2vertex mapping current->vtxindex = it1->first; // store the vertex' coordinates under the associated index // in the coordinates array const auto vtx = this->grid().entity(it1->second->p); current->coord = vtx.geometry().corner(0); } } } // namespace GridGlue } // namespace Dune #endif // DUNE_GRIDGLUE_EXTRACTORS_CODIM1EXTRACTOR_HH dune-grid-glue-2.5.0/dune/grid-glue/extractors/extractor.hh000066400000000000000000000316751315130174300237040ustar00rootroot00000000000000// -*- tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- // vi: set et ts=4 sw=2 sts=2: /* * 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: enum {dimworld = GV::dimensionworld}; enum {dim = GV::dimension}; enum {codim = cd}; enum { 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 typename GV::Traits::template Codim<0>::Iterator ElementIter; 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() { geometryType_.makeSimplex(dim-codim); } 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 {} /** \brief Destructor frees allocated memory */ ~Extractor(); /* 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); } // first free all manually allocated vertex/element info items... for (typename VertexInfoMap::iterator it = vtxInfo_.begin(); it != vtxInfo_.end(); ++it) if (it->second != NULL) delete it->second; for (typename ElementInfoMap::iterator it = elmtInfo_.begin(); it != elmtInfo_.end(); ++it) if (it->second != NULL) delete it->second; // ...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_.find(subEntities_[index].parent))->second->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_.find(coords_[index].vtxindex))->second->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; }; template Extractor::~Extractor() { clear(); } /** \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_.find(face.parent)->second->p; const auto elmt = grid().entity(elmtseed); const Dune::GeometryType celltype = elmt.type(); const Dune::ReferenceElement & 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.5.0/dune/grid-glue/extractors/extractorpredicate.hh000066400000000000000000000024111315130174300255470ustar00rootroot00000000000000// -*- tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- // vi: set et ts=4 sw=2 sts=2: /* * Filename: extractorpredicate.hh * Version: 1.0 * Created on: Mar 10, 2009 * Author: Gerrit Buse * --------------------------------- * Project: dune-grid-glue * Description: simple uniform descriptor for surface or mesh parts * */ /** * @file * @brief Base class for predicates selecting the part of a grid to be extracted */ #ifndef DUNE_GRIDGLUE_EXTRACTORS_EXTRACTORPREDICATES_HH #define DUNE_GRIDGLUE_EXTRACTORS_EXTRACTORPREDICATES_HH namespace Dune { namespace GridGlue { /** \brief Base class for subentity-selecting predicates \tparam GV GridView that the subentities are extracted from */ template class ExtractorPredicate { public: typedef typename GV::Traits::template Codim<0>::Entity Element; /** \brief Return true if a subentity should be extracted. \param element An element \param subentity Subentity number */ virtual bool contains(const Element& element, unsigned int subentity) const = 0; /** \brief Dummy virtual destructor */ virtual ~ExtractorPredicate() {} }; } // namespace GridGlue } // namespace Dune #endif // DUNE_GRIDGLUE_EXTRACTORS_EXTRACTORPREDICATES_HH dune-grid-glue-2.5.0/dune/grid-glue/extractors/vtksurfacewriter.hh000066400000000000000000000156261315130174300253010ustar00rootroot00000000000000// -*- tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- // vi: set et ts=4 sw=2 sts=2: /* * 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.5.0/dune/grid-glue/gridglue.hh000066400000000000000000000431071315130174300212660ustar00rootroot00000000000000// -*- tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- // vi: set et ts=4 sw=2 sts=2: /** * @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 "adapter/gridgluecommunicate.hh" #include #include #include #include #include #include #include #include namespace Dune { namespace GridGlue { /** Document the relation between the old grid names and the new numbering */ enum GridOrdering { Domain = 0, Target = 1 }; // forward declarations template class GridGlue; template class IntersectionData; template class Intersection; template class IntersectionIterator; template class IntersectionIndexSet; template struct GridGlueView; template struct GridGlueView { typedef P0 Patch; typedef Dune::GridGlue::IntersectionIterator IntersectionIterator; typedef typename Patch::GridView::template Codim<0>::Entity GridElement; static const P0& patch(const GridGlue& g) { return *g.patch0_; } }; template struct GridGlueView { typedef P1 Patch; typedef Dune::GridGlue::IntersectionIterator IntersectionIterator; typedef typename Patch::GridView::template Codim<0>::Entity GridElement; static const P1& patch(const GridGlue& g) { return *g.patch1_; } }; /** * @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; friend struct GridGlueView; friend struct GridGlueView; /* 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 */ /** \brief GridView of grid 0 (aka domain grid) */ typedef typename P0::GridView Grid0View; /** \brief Grid 0 type */ typedef typename Grid0View::Grid Grid0; /** \brief Coupling patch of grid 0 */ typedef P0 Grid0Patch; /** \brief Dimension of the grid 0 extractor */ enum { /** \brief Dimension of the grid 0 extractor */ grid0dim = Grid0Patch::dim, domdim = Grid0Patch::dim, /** \brief World dimension of the grid 0 extractor */ grid0dimworld = Grid0Patch::dimworld, domdimworld = Grid0Patch::dimworld }; /** \brief GridView of grid 1 (aka target grid) */ typedef typename P1::GridView Grid1View; /** \brief Grid 1 type */ typedef typename Grid1View::Grid Grid1; /** \brief Coupling patch of grid 1 */ typedef P1 Grid1Patch; /** \todo */ typedef unsigned int IndexType; /** \brief Dimension of the grid 1 extractor */ enum { /** \brief Dimension of the grid 1 extractor */ tardim = Grid1Patch::dim, grid1dim = Grid1Patch::dim, /** \brief World dimension of the grid 1 extractor */ tardimworld = Grid1Patch::dimworld, grid1dimworld = Grid1Patch::dimworld }; /** \brief export the world dimension */ enum { /** \brief export the world dimension : maximum of the two extractor world dimensions */ dimworld = ((int)Grid0Patch::dimworld > (int)Grid1Patch::dimworld) ? (int)Grid0Patch::dimworld : (int)Grid1Patch::dimworld }; /** \brief The type used for coordinates */ typedef typename PromotionTraits::PromotedType ctype; /** \brief The type used for coordinate vectors */ typedef Dune::FieldVector Coords; /** \brief The type of the Grid0 elements */ typedef typename Grid0View::Traits::template Codim<0>::Entity Grid0Element; /** \brief The type of the Grid0 vertices */ typedef typename Grid0View::Traits::template Codim::Entity Grid0Vertex; /** \brief The type of the Grid1 elements */ typedef typename Grid1View::Traits::template Codim<0>::Entity Grid1Element; /** \brief The type of the Grid1 vertices */ typedef typename Grid1View::Traits::template Codim::Entity Grid1Vertex; /** \brief Instance of a Merger */ typedef Dune::GridGlue::Merger 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 */ /** \todo Please doc me! */ typedef Dune::GridGlue::IntersectionIterator Grid0IntersectionIterator; /** \todo Please doc me! */ typedef Dune::GridGlue::IntersectionIterator Grid1IntersectionIterator; private: /* M E M B E R V A R I A B L E S */ /// @brief the patch0 description const std::shared_ptr patch0_; /// @brief the patch1 description const std::shared_ptr patch1_; /// @brief the surface merging utility const std::shared_ptr merger_; /// @brief number of intersections IndexType index__sz; #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; * the entities are just written to this array one after another * @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. */ DUNE_DEPRECATED_MSG("Please use a std::shared_ptr for patches and merger") GridGlue(const Grid0Patch& gp0, const Grid1Patch& gp1, Merger* merger); /** * @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 gp0, const std::shared_ptr gp1, const std::shared_ptr merger); /* G E T T E R S */ /** \todo Please doc me! */ template const typename GridGlueView::Patch & patch() const { return GridGlueView::patch(*this); } /** * @brief getter for the GridView of patch P * @return the object */ template const typename GridGlueView::Patch::GridView & gridView() const { return GridGlueView::patch(*this).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 typename GridGlueView::IntersectionIterator ibegin() const { return typename GridGlueView::IntersectionIterator(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 typename GridGlueView::IntersectionIterator iend() const { return typename GridGlueView::IntersectionIterator(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 { 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 DataType* sendbuffer = new DataType[ssz]; DataType* receivebuffer = new DataType[rsz]; // iterators Grid0IntersectionIterator rit = ibegin<0>(); Grid0IntersectionIterator ritend = iend<0>(); // gather Dune::GridGlue::StreamingMessageBuffer gatherbuffer(sendbuffer); for (; rit != ritend; ++rit) { /* we need to have to variants depending on the communication direction. */ if (dir == Dune::ForwardCommunication) { /* dir : Forward (grid0 -> grid1) */ if (rit->self()) { data.gather(gatherbuffer, rit->inside(), *rit); } } else // (dir == Dune::BackwardCommunication) { /* dir : Backward (grid1 -> grid0) */ if (rit->neighbor()) { data.gather(gatherbuffer, rit->outside(), rit->flip()); } } } assert(ssz == rsz); for (int i=0; i scatterbuffer(receivebuffer); for (rit = ibegin<0>(); rit != ritend; ++rit) { /* we need to have to variants depending on the communication direction. */ if (dir == Dune::ForwardCommunication) { /* dir : Forward (grid0 -> grid1) */ if (rit->neighbor()) data.scatter(scatterbuffer, rit->outside(), rit->flip(), data.size(*rit)); } else // (dir == Dune::BackwardCommunication) { /* dir : Backward (grid1 -> grid0) */ if (rit->self()) data.scatter(scatterbuffer, rit->inside(), *rit, data.size(*rit)); } } // cleanup pointers delete[] sendbuffer; delete[] receivebuffer; } } /* * @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/gridglue.cc" #include "adapter/intersection.hh" #include "adapter/intersectioniterator.hh" #include "adapter/intersectionindexset.hh" #include "adapter/rangegenerators.hh" #endif // DUNE_GRIDGLUE_GRIDGLUE_HH dune-grid-glue-2.5.0/dune/grid-glue/merging/000077500000000000000000000000001315130174300205665ustar00rootroot00000000000000dune-grid-glue-2.5.0/dune/grid-glue/merging/CMakeLists.txt000066400000000000000000000005471315130174300233340ustar00rootroot00000000000000#install headers install(FILES computeintersection.hh computeintersection.cc conformingmerge.hh contactmerge.cc contactmerge.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.5.0/dune/grid-glue/merging/computeintersection.cc000066400000000000000000000273531315130174300252120ustar00rootroot00000000000000// -*- tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- // vi: set et ts=4 sw=2 sts=2: 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.5.0/dune/grid-glue/merging/computeintersection.hh000066400000000000000000000206361315130174300252210ustar00rootroot00000000000000#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.5.0/dune/grid-glue/merging/conformingmerge.hh000066400000000000000000000231751315130174300243000ustar00rootroot00000000000000// -*- tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- // vi: set et ts=4 sw=2 sts=2: /* * 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::RemoteSimplicialIntersection RemoteSimplicialIntersection; /** \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: ConformingMerge(T tolerance = 1E-4) : tolerance_(tolerance) {} private: /* M A P P I N G O N I N D E X B A S I S */ /** * @brief get index of grid1 parent simplex for given merged grid simplex * @param idx index of the merged grid simplex * @return index of the grid1 parent simplex */ unsigned int grid1Parent(unsigned int idx, unsigned int parId = 0) const; /** * @brief get index of grid2 parent simplex for given merged grid simplex * @param idx index of the merged grid simplex * @return index of the grid2 parent simplex */ unsigned int grid2Parent(unsigned int idx, unsigned int parId = 0) const; /* G E O M E T R I C A L I N F O R M A T I O N */ /** * @brief get the grid1 parent's simplex local coordinates for a particular merged grid simplex corner * (parent's index can be obtained via "grid1Parent") * @param idx the index of the merged grid simplex * @param corner the index of the simplex' corner * @return local coordinates in parent grid1 simplex */ LocalCoords grid1ParentLocal(unsigned int idx, unsigned int corner, unsigned int parId = 0) const; /** * @brief get the grid2 parent's simplex local coordinates for a particular merged grid simplex corner * (parent's index can be obtained via "grid2Parent") * @param idx the index of the merged grid simplex * @param corner the index of the simplex' corner * @return local coordinates in parent grid2 simplex */ LocalCoords grid2ParentLocal(unsigned int idx, unsigned int corner, unsigned int parId = 0) const; }; 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& refElement = Dune::ReferenceElements::general(grid1ElementType); /** \todo Currently the RemoteIntersections have to be simplices */ if (grid1ElementType.isSimplex()) { intersections.push_back(RemoteSimplicialIntersection(grid1Index, grid2Index)); for (int i=0; i inline unsigned int ConformingMerge::grid1Parent(unsigned int idx, unsigned int parId) const { return this->intersections_[idx].grid1Entities_[parId]; } template inline unsigned int ConformingMerge::grid2Parent(unsigned int idx, unsigned int parId) const { // Warning: Be careful to use the ACTUAL indexing here defined in the array sorted after grid1 parent indices!! return this->intersections_[idx].grid2Entities_[parId]; } template typename ConformingMerge::LocalCoords ConformingMerge::grid1ParentLocal(unsigned int idx, unsigned int corner, unsigned int parId) const { return this->intersections_[idx].grid1Local_[parId][corner]; } template typename ConformingMerge::LocalCoords ConformingMerge::grid2ParentLocal(unsigned int idx, unsigned int corner, unsigned int parId) const { return this->intersections_[idx].grid2Local_[parId][corner]; } } // namespace GridGlue } // namespace Dune #endif // DUNE_GRIDGLUE_MERGING_CONFORMINGMERGE_HH dune-grid-glue-2.5.0/dune/grid-glue/merging/contactmerge.cc000066400000000000000000000321671315130174300235610ustar00rootroot00000000000000// -*- tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- // vi: set et ts=4 sw=2 sts=2: #include #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 #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 { enum {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 defualt 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::RemoteSimplicialIntersection RemoteSimplicialIntersection; 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); /** * @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) { 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 Dune::ReferenceElement& 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.5.0/dune/grid-glue/merging/merger.hh000066400000000000000000000204551315130174300223760ustar00rootroot00000000000000// -*- tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- // vi: set et ts=4 sw=2 sts=2: #ifndef DUNE_GRIDGLUE_MERGING_MERGER_HH #define DUNE_GRIDGLUE_MERGING_MERGER_HH #include #include #include namespace Dune { namespace GridGlue { // forward declaration template class Merger; namespace { // forward calls to the (grid2/grid1)-calls depending on the grid number (0/1) template struct MergerGridPolicy; template struct MergerGridPolicy { typedef Merger Parent; /// @brief the local coordinate type for the grid1 coordinates typedef Dune::FieldVector GridCoords; static unsigned int parents(const Parent & m, unsigned int idx) { return m.grid1Parents(idx); } static unsigned int parent(const Parent & m, unsigned int idx, unsigned int parId = 0) { return m.grid1Parent(idx, parId); } static GridCoords parentLocal(const Parent & m, unsigned int idx, unsigned int corner, unsigned int parId = 0) { return m.grid1ParentLocal(idx, corner, parId); } }; template struct MergerGridPolicy { typedef Merger Parent; /// @brief the local coordinate type for the grid2 coordinates typedef Dune::FieldVector GridCoords; static unsigned int parents(const Parent & m, unsigned int idx) { return m.grid2Parents(idx); } static unsigned int parent(const Parent & m, unsigned int idx, unsigned int parId = 0) { return m.grid2Parent(idx, parId); } static GridCoords parentLocal(const Parent & m, unsigned int idx, unsigned int corner, unsigned int parId = 0) { return m.grid2ParentLocal(idx, corner, parId); } }; } // end empty namespace /** \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 { // the policy class get's access to the Merger friend struct MergerGridPolicy; friend struct MergerGridPolicy; 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; template struct GridTraits { /// @brief the policy class for this grid number typedef MergerGridPolicy Policy; /// @brief the local coordinate type for the grid-n coordinates typedef typename MergerGridPolicy::GridCoords Coords; }; /** * @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 */ virtual unsigned int nSimplices() const = 0; virtual void clear() = 0; /** * doc me */ template unsigned int parents(unsigned int idx) const { return GridTraits::Policy::parents(*this, 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 GridTraits::Policy::parent(*this, idx, parId); } /** * @brief get the merged grid simplices refining a given grid-n simplex * @tparam n specify which grid (grid1/grid2: 0/1) * @param idx index of grid-n simplex * @param indices will be resized first and then filled with the refining simplices * @return TRUE <=> given simplex could be matched and is part of the merged grid */ template bool simplexRefined(unsigned int idx, std::vector& indices) const { return GridTraits::Policy::simplexRefined(*this, idx, indices); } /** * @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 typename GridTraits::Coords parentLocal(unsigned int idx, unsigned int corner, unsigned int parId = 0) const { return GridTraits::Policy::parentLocal(*this, 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; private: virtual unsigned int grid1Parents(unsigned int idx) const = 0; virtual unsigned int grid2Parents(unsigned int idx) const = 0; /** * @brief get index of grid1 parent simplex for given merged grid simplex * @param idx index of the merged grid simplex * @return index of the grid1 parent simplex */ virtual unsigned int grid1Parent(unsigned int idx, unsigned int parId = 0) const = 0; /** * @brief get index of grid2 parent simplex for given merged grid simplex * @param idx index of the merged grid simplex * @return index of the grid2 parent simplex */ virtual unsigned int grid2Parent(unsigned int idx, unsigned int parId = 0) const = 0; /** * @brief get the grid1 parent's simplex local coordinates for a particular merged grid simplex corner * (parent's index can be obtained via "grid1Parent") * @param idx the index of the merged grid simplex * @param corner the index of the simplex' corner * @return local coordinates in parent grid1 */ virtual Grid1Coords grid1ParentLocal(unsigned int idx, unsigned int corner, unsigned int parId = 0) const = 0; /** * @brief get the grid2 parent's simplex local coordinates for a particular merged grid simplex corner * (parent's index can be obtained via "grid2Parent") * @param idx the index of the merged grid simplex * @param corner the index of the simplex' corner * @return local coordinates in parent grid2 */ virtual Grid2Coords grid2ParentLocal(unsigned int idx, unsigned int corner, unsigned int parId = 0) const = 0; }; } /* namespace GridGlue */ } /* namespace Dune */ #endif dune-grid-glue-2.5.0/dune/grid-glue/merging/overlappingmerge.cc000066400000000000000000000171421315130174300244500ustar00rootroot00000000000000// -*- tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- // vi: set et ts=4 sw=2 sts=2: #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 Dune::ReferenceElement& refElement1 = Dune::ReferenceElements::general(grid1ElementType); const Dune::ReferenceElement& 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.push_back(RemoteSimplicialIntersection(grid1Index, grid2Index)); for (i = 0; i < n_intersectionnodes; ++i) { intersections.back().grid1Local_[0][i] = g1local[i]; intersections.back().grid2Local_[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.push_back(RemoteSimplicialIntersection(grid1Index,grid2Index)); for (size_type j = 0; j < n_intersectionnodes; ++j) { intersections.back().grid1Local_[0][j] = g1local[j]; intersections.back().grid2Local_[0][j] = g2local[j]; } } } } } } /* namespace Dune::GridGlue */ } /* namespace Dune */ #endif // DUNE_GRIDGLUE_OVERLAPPINGMERGE_CC dune-grid-glue-2.5.0/dune/grid-glue/merging/overlappingmerge.hh000066400000000000000000000054621315130174300244640ustar00rootroot00000000000000// -*- tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- // vi: set et ts=4 sw=2 sts=2: #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::RemoteSimplicialIntersection RemoteSimplicialIntersection; /** \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.5.0/dune/grid-glue/merging/simplexintersection.cc000066400000000000000000001436001315130174300252110ustar00rootroot00000000000000// -*- tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- // vi: set et ts=4 sw=2 sts=2: 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.5.0/dune/grid-glue/merging/standardmerge.cc000066400000000000000000000021051315130174300237130ustar00rootroot00000000000000// -*- tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- // vi: set et ts=4 sw=2 sts=2: #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.5.0/dune/grid-glue/merging/standardmerge.hh000066400000000000000000001162311315130174300237330ustar00rootroot00000000000000// -*- tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- // vi: set et ts=4 sw=2 sts=2: /** * @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 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 { 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 typedef typename Merger::Grid1Coords Grid1Coords; /// @brief Type used for local coordinates on the grid2 side typedef typename Merger::Grid2Coords Grid2Coords; /// @brief the coordinate type used in this interface typedef Dune::FieldVector WorldCoords; protected: bool valid; StandardMerge() : valid(false) {} struct RemoteSimplicialIntersection { /** \brief Dimension of this intersection */ enum {intersectionDim = (grid1Dim, nVertices> > grid1Local_; // Local coordinates in the grid2 entity std::vector, nVertices> > grid2Local_; // std::vector grid1Entities_; std::vector grid2Entities_; }; /** \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 */ /** \brief The computed intersections */ std::vector intersections_; /** \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 */ 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 ); /* Q U E S T I O N I N G T H E M E R G E D G R I D */ /// @brief get the number of simplices in the merged grid /// The indices are then in 0..nSimplices()-1 unsigned int nSimplices() const; void clear() { // Delete old internal data, from a possible previous run purge(intersections_); purge(grid1ElementCorners_); purge(grid2ElementCorners_); valid = false; } 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; /** clear arbitrary containers */ template static void purge(V & v) { v.clear(); V v2(v); v.swap(v2); } /* M A P P I N G O N I N D E X B A S I S */ /** * @brief get number of grid1 parents to the intersection idx * @param idx index of the merged grid simplex * @return amount of parent simplices */ unsigned int grid1Parents(unsigned int idx) const; /** * @brief get number of grid2 parents to the intersection idx * @param idx index of the merged grid simplex * @return amount of parent simplices */ unsigned int grid2Parents(unsigned int idx) const; /** * @brief get index of grid1 parent simplex for given merged grid simplex * @param idx index of the merged grid simplex * @return index of the grid1 parent simplex */ unsigned int grid1Parent(unsigned int idx, unsigned int parId = 0) const; /** * @brief get index of grid2 parent simplex for given merged grid simplex * @param idx index of the merged grid simplex * @return index of the grid2 parent simplex */ unsigned int grid2Parent(unsigned int idx, unsigned int parId = 0) const; /* G E O M E T R I C A L I N F O R M A T I O N */ /** * @brief get the grid1 parent's simplex local coordinates for a particular merged grid simplex corner * (parent's index can be obtained via "grid1Parent") * @param idx the index of the merged grid simplex * @param corner the index of the simplex' corner * @return local coordinates in parent grid1 simplex */ Grid1Coords grid1ParentLocal(unsigned int idx, unsigned int corner, unsigned int parId = 0) const; /** * @brief get the grid2 parent's simplex local coordinates for a particular merged grid simplex corner * (parent's index can be obtained via "grid2Parent") * @param idx the index of the merged grid simplex * @param corner the index of the simplex' corner * @return local coordinates in parent grid2 simplex */ Grid2Coords grid2ParentLocal(unsigned int idx, unsigned int corner, unsigned int parId = 0) const; /** * 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, RemoteSimplicialIntersection& 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.size() > 0) insertIntersections(candidate0,candidate1,intersections); // Have we found an intersection? return (intersections.size() > 0 || 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& refElement = Dune::ReferenceElements::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 intersections_.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 inline unsigned int StandardMerge::nSimplices() const { assert(valid); return intersections_.size(); } template inline unsigned int StandardMerge::grid1Parents(unsigned int idx) const { assert(valid); return (intersections_[idx].grid1Entities_).size(); } template inline unsigned int StandardMerge::grid2Parents(unsigned int idx) const { assert(valid); return (intersections_[idx].grid2Entities_).size(); } template inline unsigned int StandardMerge::grid1Parent(unsigned int idx, unsigned int parId) const { assert(valid); return intersections_[idx].grid1Entities_[parId]; } template inline unsigned int StandardMerge::grid2Parent(unsigned int idx, unsigned int parId) const { assert(valid); return intersections_[idx].grid2Entities_[parId]; } template typename StandardMerge::Grid1Coords StandardMerge::grid1ParentLocal(unsigned int idx, unsigned int corner, unsigned int parId) const { assert(valid); return intersections_[idx].grid1Local_[parId][corner]; } template typename StandardMerge::Grid2Coords StandardMerge::grid2ParentLocal(unsigned int idx, unsigned int corner, unsigned int parId) const { assert(valid); return intersections_[idx].grid2Local_[parId][corner]; } 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) { // insert each grid1 element and local representation of intersections[i] with parent candidate1 for (size_t j = 0; j < intersections[i].grid1Entities_.size(); ++j) { this->intersections_[index].grid1Entities_.push_back(candidate1); this->intersections_[index].grid1Local_.push_back(intersections[i].grid1Local_[j]); } // insert each grid2 element and local representation of intersections[i] with parent candidate2 for (size_t j = 0; j < intersections[i].grid2Entities_.size(); ++j) { this->intersections_[index].grid2Entities_.push_back(candidate2); this->intersections_[index].grid2Local_.push_back(intersections[i].grid2Local_[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, RemoteSimplicialIntersection& intersection) { // return index in intersections_ if at least one local representation of a Remote Simplicial Intersection (RSI) // 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 RSI for (std::size_t ei = 0; ei < this->intersections_[i].grid1Entities_.size(); ++ei) // merger subelement { if (this->intersections_[i].grid1Entities_[ei] == grid1Index) { for (std::size_t er = 0; er < intersection.grid1Entities_.size(); ++er) // list subelement { bool found_all = true; // compare the local coordinate representations for (std::size_t ci = 0; ci < this->intersections_[i].grid1Local_[ei].size(); ++ci) { Dune::FieldVector ni = this->intersections_[i].grid1Local_[ei][ci]; bool found_ni = false; for (std::size_t cr = 0; cr < intersection.grid1Local_[er].size(); ++cr) { Dune::FieldVector nr = intersection.grid1Local_[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].grid2Entities_[ei] != grid2Index)) return {true, i}; else if (found_all) return {false, 0}; } } } // compare the local representation of the subelements of the RSI for (std::size_t ei = 0; ei < this->intersections_[i].grid2Entities_.size(); ++ei) // merger subelement { if (this->intersections_[i].grid2Entities_[ei] == grid2Index) { for (std::size_t er = 0; er < intersection.grid2Entities_.size(); ++er) // list subelement { bool found_all = true; // compare the local coordinate representations for (std::size_t ci = 0; ci < this->intersections_[i].grid2Local_[ei].size(); ++ci) { Dune::FieldVector ni = this->intersections_[i].grid2Local_[ei][ci]; bool found_ni = false; for (std::size_t cr = 0; cr < intersection.grid2Local_[er].size(); ++cr) { Dune::FieldVector nr = intersection.grid2Local_[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].grid1Entities_[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.5.0/dune/grid-glue/test/000077500000000000000000000000001315130174300201155ustar00rootroot00000000000000dune-grid-glue-2.5.0/dune/grid-glue/test/CMakeLists.txt000066400000000000000000000013631315130174300226600ustar00rootroot00000000000000if(UG_PARALLEL STREQUAL "yes") set(HAVE_UG_PARALLEL 1) else() set(HAVE_UG_PARALLEL 0) endif() dune_add_test(SOURCES callmergertwicetest.cc) dune_add_test(SOURCES computecyclicordertest.cc) dune_add_test(SOURCES disconnectedtest.cc CMAKE_GUARD UG_FOUND "NOT HAVE_UG_PARALLEL") dune_add_test(SOURCES mixeddimcouplingtest.cc) dune_add_test(SOURCES mixeddimoverlappingtest.cc) dune_add_test(SOURCES mixeddimscalingtest.cc) dune_add_test(SOURCES nonoverlappingcouplingtest.cc COMPILE_DEFINITIONS "CALL_MERGER_TWICE") dune_add_test(SOURCES overlappingcouplingtest.cc COMPILE_DEFINITIONS "HAVE_UG_PARALLEL=${HAVE_UG_PARALLEL}" COMPILE_FLAGS "-frounding-math") dune_add_test(SOURCES projectiontest.cc) dune-grid-glue-2.5.0/dune/grid-glue/test/callmergertwicetest.cc000066400000000000000000000142151315130174300245000ustar00rootroot00000000000000// -*- tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- // vi: set et ts=4 sw=2 sts=2: #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> { enum { 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); grid1_element_types.push_back(Dune::GeometryType(Dune::GeometryType::simplex, dim)); grid1_element_types.push_back(Dune::GeometryType(Dune::GeometryType::simplex, dim)); 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); grid2_element_types.push_back(Dune::GeometryType(Dune::GeometryType::simplex, dim)); grid2_element_types.push_back(Dune::GeometryType(Dune::GeometryType::simplex, dim)); } }; template<> struct setupGrid<2> { enum { 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); grid1_element_types.push_back(Dune::GeometryType(Dune::GeometryType::simplex, dim)); grid1_element_types.push_back(Dune::GeometryType(Dune::GeometryType::simplex, dim)); 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); grid2_element_types.push_back(Dune::GeometryType(Dune::GeometryType::simplex, dim)); grid2_element_types.push_back(Dune::GeometryType(Dune::GeometryType::simplex, 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.5.0/dune/grid-glue/test/communicationtest.hh000066400000000000000000000031161315130174300242040ustar00rootroot00000000000000// -*- tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- // vi: set et ts=4 sw=2 sts=2: #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; enum { 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.5.0/dune/grid-glue/test/computecyclicordertest.cc000066400000000000000000000032631315130174300252270ustar00rootroot00000000000000#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.5.0/dune/grid-glue/test/couplingtest.hh000066400000000000000000000170311315130174300231600ustar00rootroot00000000000000// -*- tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- // vi: set et ts=4 sw=2 sts=2: #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) { 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() >= 1e-6 ) { std::cout << __FILE__ << ":" << __LINE__ << ": error: assert( (localGrid0Pos-globalGrid0Pos).two_norm() < 1e-6 ) 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() >= 1e-6 ) { std::cout << __FILE__ << ":" << __LINE__ << ": error: assert( (localGrid1Pos-globalGrid1Pos).two_norm() < 1e-6 ) 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() >= 1e-4 ) { std::cout << __FILE__ << ":" << __LINE__ << ": error: assert( (globalGrid0Pos-globalGrid1Pos).two_norm() < 1e-4 ) 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) { bool success = true; #if DUNE_VERSION_NEWER(DUNE_GRID, 2, 6) using View0Mapper = Dune::MultipleCodimMultipleGeomTypeMapper; using View1Mapper = Dune::MultipleCodimMultipleGeomTypeMapper; View0Mapper view0mapper(glue.template gridView<0>(), Dune::mcmgElementLayout()); View1Mapper view1mapper(glue.template gridView<1>(), Dune::mcmgElementLayout()); #else typedef Dune::MultipleCodimMultipleGeomTypeMapper< typename GlueType::Grid0View, Dune::MCMGElementLayout > View0Mapper; typedef Dune::MultipleCodimMultipleGeomTypeMapper< typename GlueType::Grid1View, Dune::MCMGElementLayout > View1Mapper; 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; typename GlueType::Grid0IntersectionIterator rIIt = glue.template ibegin<0>(); typename GlueType::Grid0IntersectionIterator rIEndIt = glue.template iend<0>(); for (; rIIt!=rIEndIt; ++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 (rIIt = glue.template ibegin<0>(); rIIt!=rIEndIt; ++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 // /////////////////////////////////////// { typename GlueType::Grid0IntersectionIterator rIIt = glue.template ibegin<0>(); typename GlueType::Grid0IntersectionIterator rIEndIt = glue.template iend<0>(); for (; rIIt!=rIEndIt; ++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); } } } // /////////////////////////////////////// // MergedGrid centric Grid1->Grid0 // /////////////////////////////////////// { typename GlueType::Grid1IntersectionIterator rIIt = glue.template ibegin<1>(); typename GlueType::Grid1IntersectionIterator rIEndIt = glue.template iend<1>(); for (; rIIt!=rIEndIt; ++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); } } } if (! success) DUNE_THROW(Dune::Exception, "Test failed, see above for details."); } #endif // DUNE_GRIDGLUE_TEST_COUPLINGTEST_HH dune-grid-glue-2.5.0/dune/grid-glue/test/disconnectedtest.cc000066400000000000000000000101241315130174300237640ustar00rootroot00000000000000#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.5.0/dune/grid-glue/test/mixeddimcouplingtest.cc000066400000000000000000000340701315130174300246710ustar00rootroot00000000000000// -*- tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- // vi: set et ts=4 sw=2 sts=2: #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 Dune::ReferenceElement& 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[]) try { 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 } catch (Exception e) { std::cout << e << std::endl; return 1; } dune-grid-glue-2.5.0/dune/grid-glue/test/mixeddimoverlappingtest.cc000066400000000000000000000066121315130174300254000ustar00rootroot00000000000000// -*- tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- // vi: set et ts=4 sw=2 sts=2: #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.5.0/dune/grid-glue/test/mixeddimscalingtest.cc000066400000000000000000000075511315130174300244750ustar00rootroot00000000000000// -*- tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- // vi: set et ts=4 sw=2 sts=2: #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); 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.5.0/dune/grid-glue/test/nonoverlappingcouplingtest.cc000066400000000000000000000262621315130174300261360ustar00rootroot00000000000000// -*- tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- // vi: set et ts=4 sw=2 sts=2: #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 Dune::ReferenceElement& 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(1); 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(2); FieldVector lower(0); FieldVector upper(1); GridType cubeGrid0(lower, upper, elements); elements.fill(4); 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(2); FieldVector lower(0); FieldVector upper(1); if (tar) { elements.fill(4); 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(), 2); std::bitset periodic(0); FieldVector size(1); int overlap = 1; double shift = 0.0; if (tar) { std::fill(elements.begin(), elements.end(), 4); 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[]) try { 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; } catch (Exception e) { int i = 0; char** c = 0; std::cout << Dune::MPIHelper::instance(i,c).rank() << ": " << e << std::endl; return 1; } dune-grid-glue-2.5.0/dune/grid-glue/test/overlappingcouplingtest.cc000066400000000000000000000235531315130174300254230ustar00rootroot00000000000000// -*- tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- // vi: set et ts=4 sw=2 sts=2: #include #include #include #ifdef HAVE_UG #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_UG 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); 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_UG && 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) try { 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_UG && !HAVE_UG_PARALLEL testSimplexGridsUG<2>(overlappingMerge2d, FieldVector(0.05)); #endif #if HAVE_UG && !HAVE_UG_PARALLEL && 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_UG && !HAVE_UG_PARALLEL testSimplexGridsUG<2>(conformingMerge2d, FieldVector(0)); #endif #if HAVE_UG && !HAVE_UG_PARALLEL && HAVE_HYBRIDTESTGRIDS testHybridGridsUG<2>(conformingMerge2d, FieldVector(0)); #endif } catch (Exception e) { std::cout << e << std::endl; return 1; } dune-grid-glue-2.5.0/dune/grid-glue/test/projectiontest.cc000066400000000000000000000355601315130174300235110ustar00rootroot00000000000000#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.5.0/examples/000077500000000000000000000000001315130174300161425ustar00rootroot00000000000000dune-grid-glue-2.5.0/examples/CMakeLists.txt000066400000000000000000000001361315130174300207020ustar00rootroot00000000000000add_executable(contactmerge contactmerge.cc) target_link_dune_default_libraries(contactmerge) dune-grid-glue-2.5.0/examples/contactmerge.cc000066400000000000000000000025211315130174300211240ustar00rootroot00000000000000#ifdef HAVE_CONFIG_H # include "config.h" #endif #include #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; }