pax_global_header00006660000000000000000000000064151361644300014515gustar00rootroot0000000000000052 comment=f7c187a720483c2050a88d081d70637c37f0ba33 dune-uggrid-2.11.0+dfsg/000077500000000000000000000000001513616443000147275ustar00rootroot00000000000000dune-uggrid-2.11.0+dfsg/.gitignore000066400000000000000000000002341513616443000167160ustar00rootroot00000000000000# SPDX-FileCopyrightText: Copyright © DUNE Project contributors, see file LICENSE.md in module root # SPDX-License-Identifier: LGPL-2.1-or-later /build*/ dune-uggrid-2.11.0+dfsg/.gitlab-ci.yml000066400000000000000000000035411513616443000173660ustar00rootroot00000000000000# SPDX-FileCopyrightText: Copyright © DUNE Project contributors, see file LICENSE.md in module root # SPDX-License-Identifier: LGPL-2.1-or-later --- include: - project: 'core/ci-config' ref: master file: 'config/common/releases/2.11.yml' - project: 'core/ci-config' ref: master file: 'jobs/common/releases/2.11.yml' before_script: - . /duneci/bin/duneci-init-job - duneci-install-module https://gitlab.dune-project.org/core/dune-common.git - duneci-install-module https://gitlab.dune-project.org/core/dune-geometry.git .common: &common script: - duneci-standard-test # test dune-grid as well - export DUNE_CONTROL_PATH=$(pwd):/duneci/modules:$DUNE_CONTROL_PATH - duneci-install-module https://gitlab.dune-project.org/core/dune-grid.git - cd /duneci/modules/dune-grid && duneci-standard-test tags: [duneci] artifacts: expire_in: 2 years reports: junit: junit/*.xml # specific job for testing sequential library version debian:11 gcc-10-20 sequential: <<: *common image: registry.dune-project.org/docker/ci/debian:11 variables: DUNECI_TOOLCHAIN: gcc-10-20 DUNECI_CMAKE_FLAGS: "-DUG_ENABLE_PARALLEL=0" # specific job for testing the debug version debian:10 gcc-10-20 debug: <<: *common image: registry.dune-project.org/docker/ci/debian:11 variables: DUNECI_TOOLCHAIN: gcc-10-20 DUNECI_CMAKE_FLAGS: "-DUG_ENABLE_DEBUGGING:BOOL=1" # Check for spelling mistakes in text code-spelling-check: stage: .pre # Avoid the global 'before_script' before_script: "" image: registry.dune-project.org/docker/ci/debian:11 tags: [duneci] script: - codespell --ignore-words-list alph,ba,broser,createdd,enew,feld,fo,nd,nin,pres,te,theif reuse: stage: .pre image: name: docker.io/fsfe/reuse:latest entrypoint: [""] tags: [duneci] before_script: "" script: - reuse lint dune-uggrid-2.11.0+dfsg/CHANGELOG.md000066400000000000000000000160011513616443000165360ustar00rootroot00000000000000 # Release 2.11 * Cleanup and simplifications # dune-uggrid 2.10 (2024-09-04) * Remove deprecated `AllocEnvMemory` and `FreeEnvMemory`. They were wrappers of standard `malloc` and `free`. * Remove deprecated `Mark` and `Release`. Use `MarkTmpMem` and `ReleaseTmpMem` instead. * Remove deprecated `HeapAllocMode` and its flags `FROM_BOTTOM` and `FROM_TOP`. They lost any influence, as we use the system heap. * Remove deprecated `DDD_InfoProcList`, use `DDD_InfoProcListRange` instead. * Remove deprecated `DDD_IFOneway`, use method overload with context as first argument instead. # dune-uggrid 2.9 (2022-11-25) * The `dune-uggrid` module does not set the preprocessor flag `HAVE_UG` anymore. Use `HAVE_DUNE_UGGRID` instead. * Several unused data members have been removed from the `UGGrid` data structure. The grids will behave as before, but the memory footprint should be a bit smaller. # dune-uggrid 2.8 (2021-09-06) * Added support for All_All communication on facets. * Removes support for `_2` and `_3` macros. * Remove support for XDR. # dune-uggrid 2.7.0 (2019-12-20) * Multiple grids are now also allowed in the parallel implementation [!96]: https://gitlab.dune-project.org/staging/dune-uggrid/merge_requests/96 * The `TET_RULESET` compile-time option has been renamed to `DUNE_UGGRID_TET_RULESET` and is enabled by default. It is no longer necessary to provide the `RefRules.data` file. [!134](https://gitlab.dune-project.org/staging/dune-uggrid/merge_requests/134) * Header files moved below dune/uggrid. Headers are installed in the same sub-directory and no longer into ug/. This breaks compatibility to UG 3.13. [!137](https://gitlab.dune-project.org/staging/dune-uggrid/merge_requests/137) # dune-uggrid 2.6.0 (2018-04-03) * Transfer of element data during load balancing is supported. See [!55][] and [dune-grid!172][] * `dune-uggrid` has gained a new build-time switch `TET_RULESET` (default is off). When set, `UGGrid` will use a better algorithm to compute green closures for red--green grid refinement. This better algorithm, which involves a complete rule set for tetrahedral elements, leads to refined grids with smaller closures. It also fixes at least one [bug](https://gitlab.dune-project.org/core/dune-grid/issues/27). *Beware:* when `TET_RULESET` is set, UG wants to read a table from the file `RefRule.data` (in `uggrid/lib/ugdata`). This file needs to be in the current directory, otherwise `UGGrid` will abort. The long-term plan is to compile the data file into the binary, and make the new closure algorithm the default. * Many now unused parts of UG have been removed from the source. * The memory management of UG got a major overhaul: - As malloc/free memory management was used for a long time, we removed the manual heap management of UG. - `DYNAMIC_MEMORY_ALLOCMODEL` was used by default, now we removed the switch and cleaned up all `#ifdef`s - The `FROM_BOTTOM`/`FROM_TOP` flags during memory allocation didn't have any influence, as we use the system heap. The enums were deprecated and the interface updated. - unified the different memory allocation methods - removed user data from the `MULTIGRID` structure - removed virtual heap management * The `InsertElement` algorithm has been completely rewritten. Up to now the user had to ensure that enough memory was allocated in order to create a lookup for the `InsertElement` neighbor search. This was necessary to ensure an O(n) complexity. Otherwise loading large meshes was prohibitively slow. The new implementation uses modern C++ data structures. To speed up the neighbor search we maintain a hash-map (i.e. `unordered_map`) from a face to an element. The new implementation is as fast as the old one, can dynamically adapt to the mesh size and uses less memory. See the list of all [dune-uggrid 2.6 merge requests][] for minor changes not mentioned here. [!55]: https://gitlab.dune-project.org/staging/dune-uggrid/merge_requests/55 [dune-grid!172]: https://gitlab.dune-project.org/core/dune-grid/merge_requests/172 [dune-uggrid 2.6 merge requests]: https://gitlab.dune-project.org/staging/dune-uggrid/merge_requests?milestone_title=Dune+2.6.0&scope=all&state=all # dune-uggrid 2.5.0 (2017-12-18) * dune-uggrid is now a DUNE module that will only contain UG's grid manager in the future. * Switch to CMake build system. # UG Release 3.13.0 (01-03-2016) * Rename macros `_2` and `_3` to `UG_DIM_2` and `UG_DIM_3` respectively, to avoid clashes with symbols of the same name in libc++. * Add file `.gitlab-ci.yml` to drive the Gitlab continuous integration features * Remove an obsolete XCode project file, and an obsolete mystery file 'conf.h' * Fix an out-of-bounds array access reported by the gcc sanitizer # UG Release 3.12.1 (11-05-2015) * Fix bug in `Makefile.am` which prevented building of tarballs. # UG Release 3.12.0 (11-05-2015) The major change in this release is the official transformation of the entire code base to C++. While pretty much everybody (read: all Dune users) has compiled UG as C++ for many years now, the code itself was still officially C. In the 3.12.0 release all .c files have now been renamed to .cc, and UG will hence build as C++ by default. Thanks to Christoph Grüninger. * Remove code that redefines standard types on specific architectures (Fixes Debian build problems of dune-grid) * Fix various problems when compiling with clang * Fix the return type of a few methods that don't actually return anything. * Removal of dead and redundant code * Minor cleanup and beautifications in ddd # UG Release 3.11.1 (2-12-2014) This is mainly a bugfix release. As the only behavioral change, memory management now defaults to the operating system heap, rather than the built-in heap. This eases debugging and appears to speed up the code. * Make method `CreateLine` return `void` instead of `INT`. This fixes a segfault when compiling with clang. Thanks to Carsten Gräser. * More build system and other cleanup # UG Release 3.11.0 (12-06-2014) This release contains several bugfixes related to dynamic load balancing. It also contains many important cleanup patches (kudos to Ansgar Burchardt). * Properly set `SideVector` `VCOUNT` fields after load balancing (Dune FlySpray 810: https://dune-project.org/flyspray/index.php?do=details&task_id=810 ) * Bugfix: Always identify MIDNODEs to the proclist of the father edge * Bugfix: Initialize EDIDENT for edges for 3d _and 2d_ before refinement * Bugfix: Call the `RestrictPartitioning` method more often before adaptive refinement * Remove the Fortran interface to the DDD library * Remove left-overs from the Chaco load balancer which used to be contained in the UG source tree * Remove lots of code related to obsolete architectures and the old build system * Remove old, non-free version of netgen * Constification in the DDD subsystem * Various build-system improvements dune-uggrid-2.11.0+dfsg/CMakeLists.txt000066400000000000000000000072061513616443000174740ustar00rootroot00000000000000# SPDX-FileCopyrightText: Copyright © DUNE Project contributors, see file LICENSE.md in module root # SPDX-License-Identifier: LGPL-2.1-or-later cmake_minimum_required(VERSION 3.16) # set up project project("dune-uggrid" C CXX) #circumvent not building docs set(BUILD_DOCS 1) # Guess the dune-common build directory if it is not yet set 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} "${CMAKE_SOURCE_DIR}/cmake/modules")# make sure our own modules are found #include the dune macros include(DuneMacros) # deactivate global include-directories dune_policy(SET DP_DEFAULT_INCLUDE_DIRS NEW) # deactivate global calls to add_dune_all_flags in tests dune_policy(SET DP_TEST_ADD_ALL_FLAGS NEW) # do not make suggested dependencies required automatically dune_policy(SET DP_SUGGESTED_MODULE_DEPENDENCIES_REQUIRED_DOWNSTREAM NEW) # start a dune project with information from dune.module dune_project() find_package(MPI) # set defines that are only used internally. # The rest is in cmake/modules/DuneUggrid.cmake if(MPI_C_FOUND) set(UG_ENABLE_PARALLEL True CACHE BOOL "Enable a parallel UG (default is True if MPI is there False otherwise)") else() set(UG_ENABLE_PARALLEL False CACHE BOOL "Enable a parallel UG (default is True if MPI is there False otherwise)") endif() set(UG_ENABLE_DEBUGGING False CACHE BOOL "Enable UG debugging (default is Off)") set(UG_ENABLE_SYSTEM_HEAP ON CACHE BOOL "If ON/True then we are using the operating system heap instead of the one internal to UG (Default: ON)") set(UG_DDD_MAX_MACROBITS "24" CACHE STRING "Set number of bits of an unsigned int used to store the process number, the remaining bits are used to store the local entity id") set(DUNE_UGGRID_TET_RULESET True CACHE BOOL "Use complete rule set for refinement of tetrahedral elements") if(TET_RULESET) set(DUNE_UGGRID_TET_RULESET True) message(DEPRECATION "The TET_RULESET option has been renamed to DUNE_UGGRID_TET_RULESET") endif() if(UG_ENABLE_DEBUGGING) list(APPEND UG_COMPILE_DEFINITIONS "Debug") set(UG_EXTRAFLAGS "${UG_EXTRAFLAGS} -DDebug") endif() #Always build parallel libs if MPI is found if(UG_ENABLE_PARALLEL) if(NOT MPI_C_FOUND) message(SEND_ERROR "A parallel UG was requested but MPI was not found. Either change variable UG_ENABLE_PARALLEL or install MPI." ) endif() list(APPEND UG_COMPILE_DEFINITIONS "ModelP") set(UG_EXTRAFLAGS "${UG_EXTRAFLAGS} -DModelP") endif() # define target for duneuggrid dune_add_library(duneuggrid EXPORT_NAME UGGrid) target_compile_definitions(duneuggrid PUBLIC ${UG_COMPILE_DEFINITIONS}) target_link_libraries(duneuggrid PUBLIC Dune::Common) add_dune_mpi_flags(duneuggrid) # set include directories for duneuggrid library dune_default_include_directories(duneuggrid PUBLIC) check_include_file(sys/time.h HAVE_SYS_TIME_H) check_include_file(time.h HAVE_TIME_H) if(HAVE_TIME_H AND HAVE_SYS_TIME_H) set(TIME_WITH_SYS_TIME True) endif() add_subdirectory(dune) add_subdirectory(cmake/modules) # set variable names for config.h set(DDD_MAX_PROCBITS_IN_GID ${UG_DDD_MACROBITS}) # finalize the dune project, e.g., generate config.h etc. # Use package init to set additional information set(dune-uggrid_INIT "set(UG_PARALLEL ${UG_ENABLE_PARALLEL})") # make sure downstream projects must find MPI too if (UG_ENABLE_PARALLEL) string(JOIN "\n" DUNE_CUSTOM_PKG_CONFIG_SECTION "find_dependency(MPI)" ) endif() finalize_dune_project() dune-uggrid-2.11.0+dfsg/COPYING000066400000000000000000000051361513616443000157670ustar00rootroot00000000000000UG -- a software framework for finite element methods COPYRIGHT --------- Copyright (C) 1994-1998 Universität Stuttgart 1992-1994, 1998-2014 Universität Heidelberg AUTHORS ------- Authors of the UG software are: (name in parentheses is is the login name visible in the vcs logs) Bernhard Huurdemann (bernhard) Klaus Birken (birken) Carsten Schwarz (carsten) Christian Wagner (chris) (christia) (christian) Christian Engwer (christi) Christoph Reisinger (christop) Christoph Reisinger (creising) (df) Dirk Feuchter (dirk) Dmitriy Logachenko (dmitriy) Peter Frolkovic (frolko) Gabi Beddies (gabi) George Mazukiewicz (george) Achim Gordner (gordner) Christoph Grüninger (gruenich) Andreas Hauser (hauser) Henrik Rentz-Reichert (henrik) Ingo Heppner (ingo) Jorrit Fahlke (joe) Jürgen Bey (juergen) (kathrin) Klaus Johannsen (klaus) Michael Lampe (lampe) Stefan Lang (langsn) Markus Blatt (mblatt) Niko Neuss (niko) Oliver Sterz (os) Sebastien Paxion (paxion) Peter Bastian (peter) Philip Broser(?) (philip) Volker Reichenberger (reichenb) (root) Oliver Sander (sander) Sandra Nägele (sandra) Stefan Lang (stefan) Thimo Neubauer (thimo) (UG-GRAPE) (ugtest) (ug) Christian Wieners (wieners) Ansgar Burchardt Bernd Flemisch Carsten Gräser Felix Gruber René Heß Roland Kaufmann Liam Keegan Timo Koch Steffen Müthing Martin Nolte Santiago Ospina Elias Pipping Simon Praetorius Lukas Riedel Eugen Salzmann Henrik Stolzmann LICENSE ------- This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this library; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA dune-uggrid-2.11.0+dfsg/COPYING.LGPL-2.1000066400000000000000000000636311513616443000170260ustar00rootroot00000000000000 GNU LESSER GENERAL PUBLIC LICENSE Version 2.1, February 1999 Copyright (C) 1991, 1999 Free Software Foundation, Inc. 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA Everyone is permitted to copy and distribute verbatim copies of this license document, but changing it is not allowed. [This is the first released version of the Lesser GPL. It also counts as the successor of the GNU Library Public License, version 2, hence the version number 2.1.] Preamble The licenses for most software are designed to take away your freedom to share and change it. By contrast, the GNU General Public Licenses are intended to guarantee your freedom to share and change free software--to make sure the software is free for all its users. This license, the Lesser General Public License, applies to some specially designated software packages--typically libraries--of the Free Software Foundation and other authors who decide to use it. You can use it too, but we suggest you first think carefully about whether this license or the ordinary General Public License is the better strategy to use in any particular case, based on the explanations below. When we speak of free software, we are referring to freedom of use, not price. Our General Public Licenses are designed to make sure that you have the freedom to distribute copies of free software (and charge for this service if you wish); that you receive source code or can get it if you want it; that you can change the software and use pieces of it in new free programs; and that you are informed that you can do these things. To protect your rights, we need to make restrictions that forbid distributors to deny you these rights or to ask you to surrender these rights. These restrictions translate to certain responsibilities for you if you distribute copies of the library or if you modify it. For example, if you distribute copies of the library, whether gratis or for a fee, you must give the recipients all the rights that we gave you. You must make sure that they, too, receive or can get the source code. If you link other code with the library, you must provide complete object files to the recipients, so that they can relink them with the library after making changes to the library and recompiling it. And you must show them these terms so they know their rights. We protect your rights with a two-step method: (1) we copyright the library, and (2) we offer you this license, which gives you legal permission to copy, distribute and/or modify the library. To protect each distributor, we want to make it very clear that there is no warranty for the free library. Also, if the library is modified by someone else and passed on, the recipients should know that what they have is not the original version, so that the original author's reputation will not be affected by problems that might be introduced by others. Finally, software patents pose a constant threat to the existence of any free program. We wish to make sure that a company cannot effectively restrict the users of a free program by obtaining a restrictive license from a patent holder. Therefore, we insist that any patent license obtained for a version of the library must be consistent with the full freedom of use specified in this license. Most GNU software, including some libraries, is covered by the ordinary GNU General Public License. This license, the GNU Lesser General Public License, applies to certain designated libraries, and is quite different from the ordinary General Public License. We use this license for certain libraries in order to permit linking those libraries into non-free programs. When a program is linked with a library, whether statically or using a shared library, the combination of the two is legally speaking a combined work, a derivative of the original library. The ordinary General Public License therefore permits such linking only if the entire combination fits its criteria of freedom. The Lesser General Public License permits more lax criteria for linking other code with the library. We call this license the "Lesser" General Public License because it does Less to protect the user's freedom than the ordinary General Public License. It also provides other free software developers Less of an advantage over competing non-free programs. These disadvantages are the reason we use the ordinary General Public License for many libraries. However, the Lesser license provides advantages in certain special circumstances. For example, on rare occasions, there may be a special need to encourage the widest possible use of a certain library, so that it becomes a de-facto standard. To achieve this, non-free programs must be allowed to use the library. A more frequent case is that a free library does the same job as widely used non-free libraries. In this case, there is little to gain by limiting the free library to free software only, so we use the Lesser General Public License. In other cases, permission to use a particular library in non-free programs enables a greater number of people to use a large body of free software. For example, permission to use the GNU C Library in non-free programs enables many more people to use the whole GNU operating system, as well as its variant, the GNU/Linux operating system. Although the Lesser General Public License is Less protective of the users' freedom, it does ensure that the user of a program that is linked with the Library has the freedom and the wherewithal to run that program using a modified version of the Library. The precise terms and conditions for copying, distribution and modification follow. Pay close attention to the difference between a "work based on the library" and a "work that uses the library". The former contains code derived from the library, whereas the latter must be combined with the library in order to run. GNU LESSER GENERAL PUBLIC LICENSE TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION 0. This License Agreement applies to any software library or other program which contains a notice placed by the copyright holder or other authorized party saying it may be distributed under the terms of this Lesser General Public License (also called "this License"). Each licensee is addressed as "you". A "library" means a collection of software functions and/or data prepared so as to be conveniently linked with application programs (which use some of those functions and data) to form executables. The "Library", below, refers to any such software library or work which has been distributed under these terms. A "work based on the Library" means either the Library or any derivative work under copyright law: that is to say, a work containing the Library or a portion of it, either verbatim or with modifications and/or translated straightforwardly into another language. (Hereinafter, translation is included without limitation in the term "modification".) "Source code" for a work means the preferred form of the work for making modifications to it. For a library, complete source code means all the source code for all modules it contains, plus any associated interface definition files, plus the scripts used to control compilation and installation of the library. Activities other than copying, distribution and modification are not covered by this License; they are outside its scope. The act of running a program using the Library is not restricted, and output from such a program is covered only if its contents constitute a work based on the Library (independent of the use of the Library in a tool for writing it). Whether that is true depends on what the Library does and what the program that uses the Library does. 1. You may copy and distribute verbatim copies of the Library's complete source code as you receive it, in any medium, provided that you conspicuously and appropriately publish on each copy an appropriate copyright notice and disclaimer of warranty; keep intact all the notices that refer to this License and to the absence of any warranty; and distribute a copy of this License along with the Library. You may charge a fee for the physical act of transferring a copy, and you may at your option offer warranty protection in exchange for a fee. 2. You may modify your copy or copies of the Library or any portion of it, thus forming a work based on the Library, and copy and distribute such modifications or work under the terms of Section 1 above, provided that you also meet all of these conditions: a) The modified work must itself be a software library. b) You must cause the files modified to carry prominent notices stating that you changed the files and the date of any change. c) You must cause the whole of the work to be licensed at no charge to all third parties under the terms of this License. d) If a facility in the modified Library refers to a function or a table of data to be supplied by an application program that uses the facility, other than as an argument passed when the facility is invoked, then you must make a good faith effort to ensure that, in the event an application does not supply such function or table, the facility still operates, and performs whatever part of its purpose remains meaningful. (For example, a function in a library to compute square roots has a purpose that is entirely well-defined independent of the application. Therefore, Subsection 2d requires that any application-supplied function or table used by this function must be optional: if the application does not supply it, the square root function must still compute square roots.) These requirements apply to the modified work as a whole. If identifiable sections of that work are not derived from the Library, and can be reasonably considered independent and separate works in themselves, then this License, and its terms, do not apply to those sections when you distribute them as separate works. But when you distribute the same sections as part of a whole which is a work based on the Library, the distribution of the whole must be on the terms of this License, whose permissions for other licensees extend to the entire whole, and thus to each and every part regardless of who wrote it. Thus, it is not the intent of this section to claim rights or contest your rights to work written entirely by you; rather, the intent is to exercise the right to control the distribution of derivative or collective works based on the Library. In addition, mere aggregation of another work not based on the Library with the Library (or with a work based on the Library) on a volume of a storage or distribution medium does not bring the other work under the scope of this License. 3. You may opt to apply the terms of the ordinary GNU General Public License instead of this License to a given copy of the Library. To do this, you must alter all the notices that refer to this License, so that they refer to the ordinary GNU General Public License, version 2, instead of to this License. (If a newer version than version 2 of the ordinary GNU General Public License has appeared, then you can specify that version instead if you wish.) Do not make any other change in these notices. Once this change is made in a given copy, it is irreversible for that copy, so the ordinary GNU General Public License applies to all subsequent copies and derivative works made from that copy. This option is useful when you wish to copy part of the code of the Library into a program that is not a library. 4. You may copy and distribute the Library (or a portion or derivative of it, under Section 2) in object code or executable form under the terms of Sections 1 and 2 above provided that you accompany it with the complete corresponding machine-readable source code, which must be distributed under the terms of Sections 1 and 2 above on a medium customarily used for software interchange. If distribution of object code is made by offering access to copy from a designated place, then offering equivalent access to copy the source code from the same place satisfies the requirement to distribute the source code, even though third parties are not compelled to copy the source along with the object code. 5. A program that contains no derivative of any portion of the Library, but is designed to work with the Library by being compiled or linked with it, is called a "work that uses the Library". Such a work, in isolation, is not a derivative work of the Library, and therefore falls outside the scope of this License. However, linking a "work that uses the Library" with the Library creates an executable that is a derivative of the Library (because it contains portions of the Library), rather than a "work that uses the library". The executable is therefore covered by this License. Section 6 states terms for distribution of such executables. When a "work that uses the Library" uses material from a header file that is part of the Library, the object code for the work may be a derivative work of the Library even though the source code is not. Whether this is true is especially significant if the work can be linked without the Library, or if the work is itself a library. The threshold for this to be true is not precisely defined by law. If such an object file uses only numerical parameters, data structure layouts and accessors, and small macros and small inline functions (ten lines or less in length), then the use of the object file is unrestricted, regardless of whether it is legally a derivative work. (Executables containing this object code plus portions of the Library will still fall under Section 6.) Otherwise, if the work is a derivative of the Library, you may distribute the object code for the work under the terms of Section 6. Any executables containing that work also fall under Section 6, whether or not they are linked directly with the Library itself. 6. As an exception to the Sections above, you may also combine or link a "work that uses the Library" with the Library to produce a work containing portions of the Library, and distribute that work under terms of your choice, provided that the terms permit modification of the work for the customer's own use and reverse engineering for debugging such modifications. You must give prominent notice with each copy of the work that the Library is used in it and that the Library and its use are covered by this License. You must supply a copy of this License. If the work during execution displays copyright notices, you must include the copyright notice for the Library among them, as well as a reference directing the user to the copy of this License. Also, you must do one of these things: a) Accompany the work with the complete corresponding machine-readable source code for the Library including whatever changes were used in the work (which must be distributed under Sections 1 and 2 above); and, if the work is an executable linked with the Library, with the complete machine-readable "work that uses the Library", as object code and/or source code, so that the user can modify the Library and then relink to produce a modified executable containing the modified Library. (It is understood that the user who changes the contents of definitions files in the Library will not necessarily be able to recompile the application to use the modified definitions.) b) Use a suitable shared library mechanism for linking with the Library. A suitable mechanism is one that (1) uses at run time a copy of the library already present on the user's computer system, rather than copying library functions into the executable, and (2) will operate properly with a modified version of the library, if the user installs one, as long as the modified version is interface-compatible with the version that the work was made with. c) Accompany the work with a written offer, valid for at least three years, to give the same user the materials specified in Subsection 6a, above, for a charge no more than the cost of performing this distribution. d) If distribution of the work is made by offering access to copy from a designated place, offer equivalent access to copy the above specified materials from the same place. e) Verify that the user has already received a copy of these materials or that you have already sent this user a copy. For an executable, the required form of the "work that uses the Library" must include any data and utility programs needed for reproducing the executable from it. However, as a special exception, the materials to be distributed need not include anything that is normally distributed (in either source or binary form) with the major components (compiler, kernel, and so on) of the operating system on which the executable runs, unless that component itself accompanies the executable. It may happen that this requirement contradicts the license restrictions of other proprietary libraries that do not normally accompany the operating system. Such a contradiction means you cannot use both them and the Library together in an executable that you distribute. 7. You may place library facilities that are a work based on the Library side-by-side in a single library together with other library facilities not covered by this License, and distribute such a combined library, provided that the separate distribution of the work based on the Library and of the other library facilities is otherwise permitted, and provided that you do these two things: a) Accompany the combined library with a copy of the same work based on the Library, uncombined with any other library facilities. This must be distributed under the terms of the Sections above. b) Give prominent notice with the combined library of the fact that part of it is a work based on the Library, and explaining where to find the accompanying uncombined form of the same work. 8. You may not copy, modify, sublicense, link with, or distribute the Library except as expressly provided under this License. Any attempt otherwise to copy, modify, sublicense, link with, or distribute the Library is void, and will automatically terminate your rights under this License. However, parties who have received copies, or rights, from you under this License will not have their licenses terminated so long as such parties remain in full compliance. 9. You are not required to accept this License, since you have not signed it. However, nothing else grants you permission to modify or distribute the Library or its derivative works. These actions are prohibited by law if you do not accept this License. Therefore, by modifying or distributing the Library (or any work based on the Library), you indicate your acceptance of this License to do so, and all its terms and conditions for copying, distributing or modifying the Library or works based on it. 10. Each time you redistribute the Library (or any work based on the Library), the recipient automatically receives a license from the original licensor to copy, distribute, link with or modify the Library subject to these terms and conditions. You may not impose any further restrictions on the recipients' exercise of the rights granted herein. You are not responsible for enforcing compliance by third parties with this License. 11. If, as a consequence of a court judgment or allegation of patent infringement or for any other reason (not limited to patent issues), conditions are imposed on you (whether by court order, agreement or otherwise) that contradict the conditions of this License, they do not excuse you from the conditions of this License. If you cannot distribute so as to satisfy simultaneously your obligations under this License and any other pertinent obligations, then as a consequence you may not distribute the Library at all. For example, if a patent license would not permit royalty-free redistribution of the Library by all those who receive copies directly or indirectly through you, then the only way you could satisfy both it and this License would be to refrain entirely from distribution of the Library. If any portion of this section is held invalid or unenforceable under any particular circumstance, the balance of the section is intended to apply, and the section as a whole is intended to apply in other circumstances. It is not the purpose of this section to induce you to infringe any patents or other property right claims or to contest validity of any such claims; this section has the sole purpose of protecting the integrity of the free software distribution system which is implemented by public license practices. Many people have made generous contributions to the wide range of software distributed through that system in reliance on consistent application of that system; it is up to the author/donor to decide if he or she is willing to distribute software through any other system and a licensee cannot impose that choice. This section is intended to make thoroughly clear what is believed to be a consequence of the rest of this License. 12. If the distribution and/or use of the Library is restricted in certain countries either by patents or by copyrighted interfaces, the original copyright holder who places the Library under this License may add an explicit geographical distribution limitation excluding those countries, so that distribution is permitted only in or among countries not thus excluded. In such case, this License incorporates the limitation as if written in the body of this License. 13. The Free Software Foundation may publish revised and/or new versions of the Lesser General Public License from time to time. Such new versions will be similar in spirit to the present version, but may differ in detail to address new problems or concerns. Each version is given a distinguishing version number. If the Library specifies a version number of this License which applies to it and "any later version", you have the option of following the terms and conditions either of that version or of any later version published by the Free Software Foundation. If the Library does not specify a license version number, you may choose any version ever published by the Free Software Foundation. 14. If you wish to incorporate parts of the Library into other free programs whose distribution conditions are incompatible with these, write to the author to ask for permission. For software which is copyrighted by the Free Software Foundation, write to the Free Software Foundation; we sometimes make exceptions for this. Our decision will be guided by the two goals of preserving the free status of all derivatives of our free software and of promoting the sharing and reuse of software generally. NO WARRANTY 15. BECAUSE THE LIBRARY IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY FOR THE LIBRARY, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES PROVIDE THE LIBRARY "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE LIBRARY IS WITH YOU. SHOULD THE LIBRARY PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION. 16. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR REDISTRIBUTE THE LIBRARY AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE LIBRARY (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A FAILURE OF THE LIBRARY TO OPERATE WITH ANY OTHER SOFTWARE), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. END OF TERMS AND CONDITIONS How to Apply These Terms to Your New Libraries If you develop a new library, and you want it to be of the greatest possible use to the public, we recommend making it free software that everyone can redistribute and change. You can do so by permitting redistribution under these terms (or, alternatively, under the terms of the ordinary General Public License). To apply these terms, attach the following notices to the library. It is safest to attach them to the start of each source file to most effectively convey the exclusion of warranty; and each file should have at least the "copyright" line and a pointer to where the full notice is found. Copyright (C) This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this library; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA Also add information on how to contact you by electronic and paper mail. You should also get your employer (if you work as a programmer) or your school, if any, to sign a "copyright disclaimer" for the library, if necessary. Here is a sample; alter the names: Yoyodyne, Inc., hereby disclaims all copyright interest in the library `Frob' (a library for tweaking knobs) written by James Random Hacker. , 1 April 1990 Ty Coon, President of Vice That's all there is to it! dune-uggrid-2.11.0+dfsg/LICENSES/000077500000000000000000000000001513616443000161345ustar00rootroot00000000000000dune-uggrid-2.11.0+dfsg/LICENSES/LGPL-2.1-or-later.txt000066400000000000000000000625571513616443000214730ustar00rootroot00000000000000GNU LESSER GENERAL PUBLIC LICENSE Version 2.1, February 1999 Copyright (C) 1991, 1999 Free Software Foundation, Inc. 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA Everyone is permitted to copy and distribute verbatim copies of this license document, but changing it is not allowed. [This is the first released version of the Lesser GPL. It also counts as the successor of the GNU Library Public License, version 2, hence the version number 2.1.] Preamble The licenses for most software are designed to take away your freedom to share and change it. By contrast, the GNU General Public Licenses are intended to guarantee your freedom to share and change free software--to make sure the software is free for all its users. This license, the Lesser General Public License, applies to some specially designated software packages--typically libraries--of the Free Software Foundation and other authors who decide to use it. You can use it too, but we suggest you first think carefully about whether this license or the ordinary General Public License is the better strategy to use in any particular case, based on the explanations below. When we speak of free software, we are referring to freedom of use, not price. Our General Public Licenses are designed to make sure that you have the freedom to distribute copies of free software (and charge for this service if you wish); that you receive source code or can get it if you want it; that you can change the software and use pieces of it in new free programs; and that you are informed that you can do these things. To protect your rights, we need to make restrictions that forbid distributors to deny you these rights or to ask you to surrender these rights. These restrictions translate to certain responsibilities for you if you distribute copies of the library or if you modify it. For example, if you distribute copies of the library, whether gratis or for a fee, you must give the recipients all the rights that we gave you. You must make sure that they, too, receive or can get the source code. If you link other code with the library, you must provide complete object files to the recipients, so that they can relink them with the library after making changes to the library and recompiling it. And you must show them these terms so they know their rights. We protect your rights with a two-step method: (1) we copyright the library, and (2) we offer you this license, which gives you legal permission to copy, distribute and/or modify the library. To protect each distributor, we want to make it very clear that there is no warranty for the free library. Also, if the library is modified by someone else and passed on, the recipients should know that what they have is not the original version, so that the original author's reputation will not be affected by problems that might be introduced by others. Finally, software patents pose a constant threat to the existence of any free program. We wish to make sure that a company cannot effectively restrict the users of a free program by obtaining a restrictive license from a patent holder. Therefore, we insist that any patent license obtained for a version of the library must be consistent with the full freedom of use specified in this license. Most GNU software, including some libraries, is covered by the ordinary GNU General Public License. This license, the GNU Lesser General Public License, applies to certain designated libraries, and is quite different from the ordinary General Public License. We use this license for certain libraries in order to permit linking those libraries into non-free programs. When a program is linked with a library, whether statically or using a shared library, the combination of the two is legally speaking a combined work, a derivative of the original library. The ordinary General Public License therefore permits such linking only if the entire combination fits its criteria of freedom. The Lesser General Public License permits more lax criteria for linking other code with the library. We call this license the "Lesser" General Public License because it does Less to protect the user's freedom than the ordinary General Public License. It also provides other free software developers Less of an advantage over competing non-free programs. These disadvantages are the reason we use the ordinary General Public License for many libraries. However, the Lesser license provides advantages in certain special circumstances. For example, on rare occasions, there may be a special need to encourage the widest possible use of a certain library, so that it becomes a de-facto standard. To achieve this, non-free programs must be allowed to use the library. A more frequent case is that a free library does the same job as widely used non-free libraries. In this case, there is little to gain by limiting the free library to free software only, so we use the Lesser General Public License. In other cases, permission to use a particular library in non-free programs enables a greater number of people to use a large body of free software. For example, permission to use the GNU C Library in non-free programs enables many more people to use the whole GNU operating system, as well as its variant, the GNU/Linux operating system. Although the Lesser General Public License is Less protective of the users' freedom, it does ensure that the user of a program that is linked with the Library has the freedom and the wherewithal to run that program using a modified version of the Library. The precise terms and conditions for copying, distribution and modification follow. Pay close attention to the difference between a "work based on the library" and a "work that uses the library". The former contains code derived from the library, whereas the latter must be combined with the library in order to run. TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION 0. This License Agreement applies to any software library or other program which contains a notice placed by the copyright holder or other authorized party saying it may be distributed under the terms of this Lesser General Public License (also called "this License"). Each licensee is addressed as "you". A "library" means a collection of software functions and/or data prepared so as to be conveniently linked with application programs (which use some of those functions and data) to form executables. The "Library", below, refers to any such software library or work which has been distributed under these terms. A "work based on the Library" means either the Library or any derivative work under copyright law: that is to say, a work containing the Library or a portion of it, either verbatim or with modifications and/or translated straightforwardly into another language. (Hereinafter, translation is included without limitation in the term "modification".) "Source code" for a work means the preferred form of the work for making modifications to it. For a library, complete source code means all the source code for all modules it contains, plus any associated interface definition files, plus the scripts used to control compilation and installation of the library. Activities other than copying, distribution and modification are not covered by this License; they are outside its scope. The act of running a program using the Library is not restricted, and output from such a program is covered only if its contents constitute a work based on the Library (independent of the use of the Library in a tool for writing it). Whether that is true depends on what the Library does and what the program that uses the Library does. 1. You may copy and distribute verbatim copies of the Library's complete source code as you receive it, in any medium, provided that you conspicuously and appropriately publish on each copy an appropriate copyright notice and disclaimer of warranty; keep intact all the notices that refer to this License and to the absence of any warranty; and distribute a copy of this License along with the Library. You may charge a fee for the physical act of transferring a copy, and you may at your option offer warranty protection in exchange for a fee. 2. You may modify your copy or copies of the Library or any portion of it, thus forming a work based on the Library, and copy and distribute such modifications or work under the terms of Section 1 above, provided that you also meet all of these conditions: a) The modified work must itself be a software library. b) You must cause the files modified to carry prominent notices stating that you changed the files and the date of any change. c) You must cause the whole of the work to be licensed at no charge to all third parties under the terms of this License. d) If a facility in the modified Library refers to a function or a table of data to be supplied by an application program that uses the facility, other than as an argument passed when the facility is invoked, then you must make a good faith effort to ensure that, in the event an application does not supply such function or table, the facility still operates, and performs whatever part of its purpose remains meaningful. (For example, a function in a library to compute square roots has a purpose that is entirely well-defined independent of the application. Therefore, Subsection 2d requires that any application-supplied function or table used by this function must be optional: if the application does not supply it, the square root function must still compute square roots.) These requirements apply to the modified work as a whole. If identifiable sections of that work are not derived from the Library, and can be reasonably considered independent and separate works in themselves, then this License, and its terms, do not apply to those sections when you distribute them as separate works. But when you distribute the same sections as part of a whole which is a work based on the Library, the distribution of the whole must be on the terms of this License, whose permissions for other licensees extend to the entire whole, and thus to each and every part regardless of who wrote it. Thus, it is not the intent of this section to claim rights or contest your rights to work written entirely by you; rather, the intent is to exercise the right to control the distribution of derivative or collective works based on the Library. In addition, mere aggregation of another work not based on the Library with the Library (or with a work based on the Library) on a volume of a storage or distribution medium does not bring the other work under the scope of this License. 3. You may opt to apply the terms of the ordinary GNU General Public License instead of this License to a given copy of the Library. To do this, you must alter all the notices that refer to this License, so that they refer to the ordinary GNU General Public License, version 2, instead of to this License. (If a newer version than version 2 of the ordinary GNU General Public License has appeared, then you can specify that version instead if you wish.) Do not make any other change in these notices. Once this change is made in a given copy, it is irreversible for that copy, so the ordinary GNU General Public License applies to all subsequent copies and derivative works made from that copy. This option is useful when you wish to copy part of the code of the Library into a program that is not a library. 4. You may copy and distribute the Library (or a portion or derivative of it, under Section 2) in object code or executable form under the terms of Sections 1 and 2 above provided that you accompany it with the complete corresponding machine-readable source code, which must be distributed under the terms of Sections 1 and 2 above on a medium customarily used for software interchange. If distribution of object code is made by offering access to copy from a designated place, then offering equivalent access to copy the source code from the same place satisfies the requirement to distribute the source code, even though third parties are not compelled to copy the source along with the object code. 5. A program that contains no derivative of any portion of the Library, but is designed to work with the Library by being compiled or linked with it, is called a "work that uses the Library". Such a work, in isolation, is not a derivative work of the Library, and therefore falls outside the scope of this License. However, linking a "work that uses the Library" with the Library creates an executable that is a derivative of the Library (because it contains portions of the Library), rather than a "work that uses the library". The executable is therefore covered by this License. Section 6 states terms for distribution of such executables. When a "work that uses the Library" uses material from a header file that is part of the Library, the object code for the work may be a derivative work of the Library even though the source code is not. Whether this is true is especially significant if the work can be linked without the Library, or if the work is itself a library. The threshold for this to be true is not precisely defined by law. If such an object file uses only numerical parameters, data structure layouts and accessors, and small macros and small inline functions (ten lines or less in length), then the use of the object file is unrestricted, regardless of whether it is legally a derivative work. (Executables containing this object code plus portions of the Library will still fall under Section 6.) Otherwise, if the work is a derivative of the Library, you may distribute the object code for the work under the terms of Section 6. Any executables containing that work also fall under Section 6, whether or not they are linked directly with the Library itself. 6. As an exception to the Sections above, you may also combine or link a "work that uses the Library" with the Library to produce a work containing portions of the Library, and distribute that work under terms of your choice, provided that the terms permit modification of the work for the customer's own use and reverse engineering for debugging such modifications. You must give prominent notice with each copy of the work that the Library is used in it and that the Library and its use are covered by this License. You must supply a copy of this License. If the work during execution displays copyright notices, you must include the copyright notice for the Library among them, as well as a reference directing the user to the copy of this License. Also, you must do one of these things: a) Accompany the work with the complete corresponding machine-readable source code for the Library including whatever changes were used in the work (which must be distributed under Sections 1 and 2 above); and, if the work is an executable linked with the Library, with the complete machine-readable "work that uses the Library", as object code and/or source code, so that the user can modify the Library and then relink to produce a modified executable containing the modified Library. (It is understood that the user who changes the contents of definitions files in the Library will not necessarily be able to recompile the application to use the modified definitions.) b) Use a suitable shared library mechanism for linking with the Library. A suitable mechanism is one that (1) uses at run time a copy of the library already present on the user's computer system, rather than copying library functions into the executable, and (2) will operate properly with a modified version of the library, if the user installs one, as long as the modified version is interface-compatible with the version that the work was made with. c) Accompany the work with a written offer, valid for at least three years, to give the same user the materials specified in Subsection 6a, above, for a charge no more than the cost of performing this distribution. d) If distribution of the work is made by offering access to copy from a designated place, offer equivalent access to copy the above specified materials from the same place. e) Verify that the user has already received a copy of these materials or that you have already sent this user a copy. For an executable, the required form of the "work that uses the Library" must include any data and utility programs needed for reproducing the executable from it. However, as a special exception, the materials to be distributed need not include anything that is normally distributed (in either source or binary form) with the major components (compiler, kernel, and so on) of the operating system on which the executable runs, unless that component itself accompanies the executable. It may happen that this requirement contradicts the license restrictions of other proprietary libraries that do not normally accompany the operating system. Such a contradiction means you cannot use both them and the Library together in an executable that you distribute. 7. You may place library facilities that are a work based on the Library side-by-side in a single library together with other library facilities not covered by this License, and distribute such a combined library, provided that the separate distribution of the work based on the Library and of the other library facilities is otherwise permitted, and provided that you do these two things: a) Accompany the combined library with a copy of the same work based on the Library, uncombined with any other library facilities. This must be distributed under the terms of the Sections above. b) Give prominent notice with the combined library of the fact that part of it is a work based on the Library, and explaining where to find the accompanying uncombined form of the same work. 8. You may not copy, modify, sublicense, link with, or distribute the Library except as expressly provided under this License. Any attempt otherwise to copy, modify, sublicense, link with, or distribute the Library is void, and will automatically terminate your rights under this License. However, parties who have received copies, or rights, from you under this License will not have their licenses terminated so long as such parties remain in full compliance. 9. You are not required to accept this License, since you have not signed it. However, nothing else grants you permission to modify or distribute the Library or its derivative works. These actions are prohibited by law if you do not accept this License. Therefore, by modifying or distributing the Library (or any work based on the Library), you indicate your acceptance of this License to do so, and all its terms and conditions for copying, distributing or modifying the Library or works based on it. 10. Each time you redistribute the Library (or any work based on the Library), the recipient automatically receives a license from the original licensor to copy, distribute, link with or modify the Library subject to these terms and conditions. You may not impose any further restrictions on the recipients' exercise of the rights granted herein. You are not responsible for enforcing compliance by third parties with this License. 11. If, as a consequence of a court judgment or allegation of patent infringement or for any other reason (not limited to patent issues), conditions are imposed on you (whether by court order, agreement or otherwise) that contradict the conditions of this License, they do not excuse you from the conditions of this License. If you cannot distribute so as to satisfy simultaneously your obligations under this License and any other pertinent obligations, then as a consequence you may not distribute the Library at all. For example, if a patent license would not permit royalty-free redistribution of the Library by all those who receive copies directly or indirectly through you, then the only way you could satisfy both it and this License would be to refrain entirely from distribution of the Library. If any portion of this section is held invalid or unenforceable under any particular circumstance, the balance of the section is intended to apply, and the section as a whole is intended to apply in other circumstances. It is not the purpose of this section to induce you to infringe any patents or other property right claims or to contest validity of any such claims; this section has the sole purpose of protecting the integrity of the free software distribution system which is implemented by public license practices. Many people have made generous contributions to the wide range of software distributed through that system in reliance on consistent application of that system; it is up to the author/donor to decide if he or she is willing to distribute software through any other system and a licensee cannot impose that choice. This section is intended to make thoroughly clear what is believed to be a consequence of the rest of this License. 12. If the distribution and/or use of the Library is restricted in certain countries either by patents or by copyrighted interfaces, the original copyright holder who places the Library under this License may add an explicit geographical distribution limitation excluding those countries, so that distribution is permitted only in or among countries not thus excluded. In such case, this License incorporates the limitation as if written in the body of this License. 13. The Free Software Foundation may publish revised and/or new versions of the Lesser General Public License from time to time. Such new versions will be similar in spirit to the present version, but may differ in detail to address new problems or concerns. Each version is given a distinguishing version number. If the Library specifies a version number of this License which applies to it and "any later version", you have the option of following the terms and conditions either of that version or of any later version published by the Free Software Foundation. If the Library does not specify a license version number, you may choose any version ever published by the Free Software Foundation. 14. If you wish to incorporate parts of the Library into other free programs whose distribution conditions are incompatible with these, write to the author to ask for permission. For software which is copyrighted by the Free Software Foundation, write to the Free Software Foundation; we sometimes make exceptions for this. Our decision will be guided by the two goals of preserving the free status of all derivatives of our free software and of promoting the sharing and reuse of software generally. NO WARRANTY 15. BECAUSE THE LIBRARY IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY FOR THE LIBRARY, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES PROVIDE THE LIBRARY "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE LIBRARY IS WITH YOU. SHOULD THE LIBRARY PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION. 16. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR REDISTRIBUTE THE LIBRARY AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE LIBRARY (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A FAILURE OF THE LIBRARY TO OPERATE WITH ANY OTHER SOFTWARE), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. END OF TERMS AND CONDITIONS How to Apply These Terms to Your New Libraries If you develop a new library, and you want it to be of the greatest possible use to the public, we recommend making it free software that everyone can redistribute and change. You can do so by permitting redistribution under these terms (or, alternatively, under the terms of the ordinary General Public License). To apply these terms, attach the following notices to the library. It is safest to attach them to the start of each source file to most effectively convey the exclusion of warranty; and each file should have at least the "copyright" line and a pointer to where the full notice is found. one line to give the library's name and an idea of what it does. Copyright (C) year name of author This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this library; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA Also add information on how to contact you by electronic and paper mail. You should also get your employer (if you work as a programmer) or your school, if any, to sign a "copyright disclaimer" for the library, if necessary. Here is a sample; alter the names: Yoyodyne, Inc., hereby disclaims all copyright interest in the library `Frob' (a library for tweaking knobs) written by James Random Hacker. signature of Ty Coon, 1 April 1990 Ty Coon, President of Vice That's all there is to it! dune-uggrid-2.11.0+dfsg/README.md000066400000000000000000000055011513616443000162070ustar00rootroot00000000000000 # dune-uggrid This is a fork of the old [UG](https://doi.org/10.1007/s007910050003) finite element software, wrapped as a Dune module, and stripped of everything but the grid data structure. You need this module if you want to use the `UGGrid` grid implementation from the `dune-grid` module. To use this module, simply have it available when building `dune-grid`. The Dune build system will then pick it up when building `dune-grid`, and the `UGGrid` grid implementation becomes available. ## Features The `UGGrid` grid data structure is very powerful and flexible. Its main features are: * Unstructured two- and three-dimensional grids * Grids with more than one element type: triangles and quadrilaterals in 2d, tetrahedra, hexahedra, prisms and pyramids in 3d * Adaptive red-green refinement, and nonconforming refinement * Anisotropic refinement * Distributed grids on large numbers of processes, connected by MPI * Free-form domain boundaries: Individual grids always have polyhedral boundaries, but refining the grids will approximate the actual (free-form) boundary better and better. The features of `UGGrid` are described in more detail in the [Dune book](https://link.springer.com/book/10.1007/978-3-030-59702-3). ## Planned features The following features are natural next steps in the development of `dune-uggrid`. * Checkpointing: Save the entire grid hierarchy to a file, and read it back in again. * Direct construction of distributed grids (instead of constructing the grid on rank 0 and then distributing) * Two-dimensional grids in a three-dimensional world ## Releases Although technically not a "Dune core module", `dune-uggrid` is released together with the Dune core modules. Starting with version 2.10 you can find `dune-uggrid` release tarballs at the [same site](https://dune-project.org/releases/) as the Dune core module releases. Older release tarballs can be found at the following links:
version source signature
2.9.1 dune-uggrid-2.9.1.tar.gz dune-uggrid-2.9.1.tar.gz.asc
2.8.0 dune-uggrid-2.8.0.tar.gz dune-uggrid-2.8.0.tar.gz.asc
## Maintainer The `dune-uggrid` module is currently maintained by [Oliver Sander](https://tu-dresden.de/mn/math/numerik/sander). dune-uggrid-2.11.0+dfsg/cmake/000077500000000000000000000000001513616443000160075ustar00rootroot00000000000000dune-uggrid-2.11.0+dfsg/cmake/modules/000077500000000000000000000000001513616443000174575ustar00rootroot00000000000000dune-uggrid-2.11.0+dfsg/cmake/modules/CMakeLists.txt000066400000000000000000000003371513616443000222220ustar00rootroot00000000000000# SPDX-FileCopyrightText: Copyright © DUNE Project contributors, see file LICENSE.md in module root # SPDX-License-Identifier: LGPL-2.1-or-later install(FILES DuneUggridMacros.cmake DESTINATION ${DUNE_INSTALL_MODULEDIR}) dune-uggrid-2.11.0+dfsg/cmake/modules/DuneUggridMacros.cmake000066400000000000000000000005221513616443000236620ustar00rootroot00000000000000# SPDX-FileCopyrightText: Copyright © DUNE Project contributors, see file LICENSE.md in module root # SPDX-License-Identifier: LGPL-2.1-or-later # # Compatibility against previous UG versions. set(UG_FOUND True) set(UG_VERSION "${DUNE_UGGRID_VERSION}") set(UG_DEFINITIONS) if(UG_PARALLEL) list(APPEND UG_DEFINITIONS "ModelP") endif() dune-uggrid-2.11.0+dfsg/config.h.cmake000066400000000000000000000020031513616443000174170ustar00rootroot00000000000000// SPDX-FileCopyrightText: Copyright © DUNE Project contributors, see file LICENSE.md in module root // SPDX-License-Identifier: LGPL-2.1-or-later /* begin dune-uggrid */ /* Define to the version of dune-common */ #define DUNE_UGGRID_VERSION "${DUNE_UGGRID_VERSION}" /* Define to the major version of dune-common */ #define DUNE_UGGRID_VERSION_MAJOR ${DUNE_UGGRID_VERSION_MAJOR} /* Define to the minor version of dune-common */ #define DUNE_UGGRID_VERSION_MINOR ${DUNE_UGGRID_VERSION_MINOR} /* Define to the revision of dune-common */ #define DUNE_UGGRID_VERSION_REVISION ${DUNE_UGGRID_VERSION_REVISION} /* begin private section */ /* see parallel/ddd/dddi.h */ #cmakedefine DDD_MAX_PROCBITS_IN_GID ${UG_DDD_MAX_MACROBITS} /* Define to 1 if you can safely include both and . */ #cmakedefine TIME_WITH_SYS_TIME 1 /* Define to 1 if UGGrid should use the complete set of green refinement rules for tetrahedra */ #cmakedefine DUNE_UGGRID_TET_RULESET 1 /* end private section */ /* end dune-uggrid */ dune-uggrid-2.11.0+dfsg/dune-uggrid.pc.in000066400000000000000000000006721513616443000200770ustar00rootroot00000000000000# SPDX-FileCopyrightText: Copyright © DUNE Project contributors, see file LICENSE.md in module root # SPDX-License-Identifier: LGPL-2.1-or-later prefix=@prefix@ exec_prefix=@exec_prefix@ libdir=@libdir@ includedir=@includedir@ parallel=@parallel@ fordune=yes Name: libug Version: @VERSION@ Description: library for the discretization of PDEs on unstructured grids Requires: Libs: -L${libdir} -ldevS Cflags: -I${includedir} @UG_EXTRAFLAGS@ dune-uggrid-2.11.0+dfsg/dune.module000066400000000000000000000004271513616443000170740ustar00rootroot00000000000000# SPDX-FileCopyrightText: Copyright © DUNE Project contributors, see file LICENSE.md in module root # SPDX-License-Identifier: LGPL-2.1-or-later Module: dune-uggrid Version: 2.11 Depends: dune-common (>= 2.11) Maintainer: dune-devel@lists.dune-project.org Whitespace-Hook: Yes dune-uggrid-2.11.0+dfsg/dune/000077500000000000000000000000001513616443000156625ustar00rootroot00000000000000dune-uggrid-2.11.0+dfsg/dune/CMakeLists.txt000066400000000000000000000002541513616443000204230ustar00rootroot00000000000000# SPDX-FileCopyrightText: Copyright © DUNE Project contributors, see file LICENSE.md in module root # SPDX-License-Identifier: LGPL-2.1-or-later add_subdirectory(uggrid) dune-uggrid-2.11.0+dfsg/dune/uggrid/000077500000000000000000000000001513616443000171435ustar00rootroot00000000000000dune-uggrid-2.11.0+dfsg/dune/uggrid/CMakeLists.txt000066400000000000000000000025001513616443000217000ustar00rootroot00000000000000# SPDX-FileCopyrightText: Copyright © DUNE Project contributors, see file LICENSE.md in module root # SPDX-License-Identifier: LGPL-2.1-or-later set(UG_ENABLED_DIMENSIONS 2 3) # define dimension specific object libraries foreach(dim ${UG_ENABLED_DIMENSIONS}) add_library(duneuggrid${dim}d OBJECT) target_link_libraries(duneuggrid${dim}d PRIVATE ${DUNE_LIBS}) dune_default_include_directories(duneuggrid${dim}d PRIVATE) target_compile_definitions(duneuggrid${dim}d PRIVATE "UG_DIM_${dim}") target_compile_definitions(duneuggrid${dim}d PRIVATE ${UG_COMPILE_DEFINITIONS}) add_dune_mpi_flags(duneuggrid${dim}d OBJECT) # register dimension-dependent objects in duneuggrid library target_sources(duneuggrid PRIVATE $) endforeach() # macro that adds sources to all dimension-targets `${target}${dim}d`, # see UG_ENABLED_DIMENSIONS macro(target_sources_dims target) foreach(dim ${UG_ENABLED_DIMENSIONS}) target_sources(${target}${dim}d ${ARGN}) endforeach(dim) endmacro() target_sources(duneuggrid PRIVATE ugdevices.cc) target_sources_dims(duneuggrid PRIVATE initug.cc) install( FILES ugdevices.h initug.h DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}/dune/uggrid) add_subdirectory(domain) add_subdirectory(gm) add_subdirectory(lib) add_subdirectory(low) add_subdirectory(parallel) dune-uggrid-2.11.0+dfsg/dune/uggrid/domain/000077500000000000000000000000001513616443000204125ustar00rootroot00000000000000dune-uggrid-2.11.0+dfsg/dune/uggrid/domain/CMakeLists.txt000066400000000000000000000004711513616443000231540ustar00rootroot00000000000000# SPDX-FileCopyrightText: Copyright © DUNE Project contributors, see file LICENSE.md in module root # SPDX-License-Identifier: LGPL-2.1-or-later target_sources_dims(duneuggrid PRIVATE std_domain.cc std_parallel.cc) install(FILES std_domain.h DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}/dune/uggrid/domain) dune-uggrid-2.11.0+dfsg/dune/uggrid/domain/std_domain.cc000066400000000000000000001270511513616443000230500ustar00rootroot00000000000000// SPDX-FileCopyrightText: Copyright © DUNE Project contributors, see file LICENSE.md in module root // SPDX-License-Identifier: LGPL-2.1-or-later // -*- tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- // vi: set et ts=4 sw=2 sts=2: /*! \file std_domain.c * \ingroup std */ /** \addtogroup std * * @{ */ /****************************************************************************/ /* */ /* File: std_domain.c */ /* */ /* Purpose: standard ug domain description */ /* */ /* Author: Klaus Johannsen / Christian Wieners */ /* Institut fuer Computeranwendungen III */ /* Universitaet Stuttgart */ /* Pfaffenwaldring 27 */ /* 70550 Stuttgart */ /* email: ug@ica3.uni-stuttgart.de */ /* */ /* History: Feb 18 1996 begin, ug version 3.1 */ /* Sep 12 1996 ug version 3.4 */ /* Apr 9 1998 first step to Marc */ /* */ /* Remarks: */ /* */ /****************************************************************************/ /****************************************************************************/ /* */ /* include files */ /* system include files */ /* application include files */ /* */ /****************************************************************************/ #include /* standard C library */ #include #include #include #include #include #include /* standard C++ library */ /* set needed in BVP_Init */ #include #include /* low modules */ #include #include #include #include #include #include #include #include #include #include /* dev modules */ #include /* domain module */ #include USING_UGDIM_NAMESPACE USING_UG_NAMESPACE #ifdef ModelP using namespace PPIF; #endif /****************************************************************************/ /* */ /* defines in the following order */ /* */ /* compile time constants defining static data size (i.e. arrays) */ /* other constants */ /* macros */ /* */ /****************************************************************************/ #define SMALL_DIFF SMALL_C*100 /****************************************************************************/ /* */ /* data structures used in this source file (exported data structures are */ /* in the corresponding include file!) */ /* */ /****************************************************************************/ /****************************************************************************/ /* */ /* definition of exported global variables */ /* */ /****************************************************************************/ /****************************************************************************/ /* */ /* definition of variables global to this source file only (static!) */ /* */ /****************************************************************************/ static STD_BVP *currBVP; /****************************************************************************/ /* Methods for the class 'boundary_segment' */ /****************************************************************************/ boundary_segment::boundary_segment(INT idA, const INT* pointsA, BndSegFuncPtr bndSegFuncA, void *dataA) : id(idA), BndSegFunc(bndSegFuncA), data(dataA) { for (INT i = 0; i < CORNERS_OF_BND_SEG; i++) points[i] = pointsA[i]; } /****************************************************************************/ /* Methods for the class 'linear_segment' */ /****************************************************************************/ linear_segment::linear_segment(INT idA, INT nA, const INT * point, const std::array, CORNERS_OF_BND_SEG>& xA) : id(idA), n(nA), x(xA) { if (n > CORNERS_OF_BND_SEG) std::terminate(); for (int i = 0; i < n; i++) points[i] = point[i]; } UINT NS_DIM_PREFIX GetBoundarySegmentId(BNDS* boundarySegment) { const BND_PS *ps = (BND_PS*)boundarySegment; const PATCH *patch = currBVP->patches[ps->patch_id]; if (patch == nullptr) { PrintErrorMessageF ('E', "GetBoundarySegmentId", "invalid argument"); return 0; } /* The ids in the patch data structure are consecutive but they start at currBVP->sideoffset instead of zero. */ return PATCH_ID(patch) - currBVP->sideoffset; } static INT GetNumberOfPatches (const PATCH * p) { switch (PATCH_TYPE (p)) { case PARAMETRIC_PATCH_TYPE : case LINEAR_PATCH_TYPE : return (1); case POINT_PATCH_TYPE : return (POINT_PATCH_N (p)); #ifdef UG_DIM_3 case LINE_PATCH_TYPE : return (LINE_PATCH_N (p)); #endif } return (-1); } static INT GetPatchId (const PATCH * p, INT i) { switch (PATCH_TYPE (p)) { case LINEAR_PATCH_TYPE : case PARAMETRIC_PATCH_TYPE : return (PATCH_ID (p)); case POINT_PATCH_TYPE : return (POINT_PATCH_PID (p, i)); #ifdef UG_DIM_3 case LINE_PATCH_TYPE : return (LINE_PATCH_PID (p, i)); #endif } assert(0); return (-1); } static BNDP * CreateBndPOnPoint (HEAP * Heap, PATCH * p) { BND_PS *ps; PATCH *pp; INT j, l, m; if (PATCH_TYPE (p) != POINT_PATCH_TYPE) return (NULL); PRINTDEBUG (dom, 1, (" p %d\n", PATCH_ID (p))); for (l = 0; l < GetNumberOfPatches (p); l++) PRINTDEBUG (dom, 1, (" bp pid %d\n", GetPatchId (p, l))); m = POINT_PATCH_N (p); ps = (BND_PS *) GetFreelistMemory (Heap, sizeof (BND_PS) + (m - 1) * sizeof (COORD_BND_VECTOR)); if (ps == NULL) REP_ERR_RETURN (NULL); ps->n = m; ps->patch_id = PATCH_ID (p); for (j = 0; j < m; j++) { pp = currBVP->patches[POINT_PATCH_PID (p, j)]; if (PATCH_TYPE (pp) == PARAMETRIC_PATCH_TYPE) { PRINTDEBUG (dom, 1, ("cp r %f %f %f %f\n", PARAM_PATCH_RANGE (pp)[0][0], PARAM_PATCH_RANGE (pp)[0][1], PARAM_PATCH_RANGE (pp)[1][0], PARAM_PATCH_RANGE (pp)[1][1])); switch (POINT_PATCH_CID (p, j)) { #ifdef UG_DIM_2 case 0 : ps->local[j][0] = PARAM_PATCH_RANGE (pp)[0][0]; break; case 1 : ps->local[j][0] = PARAM_PATCH_RANGE (pp)[1][0]; break; #endif #ifdef UG_DIM_3 case 0 : ps->local[j][0] = PARAM_PATCH_RANGE (pp)[0][0]; ps->local[j][1] = PARAM_PATCH_RANGE (pp)[0][1]; break; case 1 : ps->local[j][0] = PARAM_PATCH_RANGE (pp)[1][0]; ps->local[j][1] = PARAM_PATCH_RANGE (pp)[0][1]; break; case 2 : ps->local[j][0] = PARAM_PATCH_RANGE (pp)[1][0]; ps->local[j][1] = PARAM_PATCH_RANGE (pp)[1][1]; break; case 3 : ps->local[j][0] = PARAM_PATCH_RANGE (pp)[0][0]; ps->local[j][1] = PARAM_PATCH_RANGE (pp)[1][1]; break; #endif } PRINTDEBUG (dom, 1, ("mesh loc j %d pid %d cid %d loc %f %f\n", j, POINT_PATCH_PID (p, j), POINT_PATCH_CID (p, j), ps->local[j][0], ps->local[j][1])); } else if (PATCH_TYPE (pp) == LINEAR_PATCH_TYPE) { switch (POINT_PATCH_CID (p, j)) { #ifdef UG_DIM_2 case 0 : ps->local[j][0] = 0.0; break; case 1 : ps->local[j][0] = 1.0; break; #endif #ifdef UG_DIM_3 case 0 : ps->local[j][0] = 0.0; ps->local[j][1] = 0.0; break; case 1 : ps->local[j][0] = 1.0; ps->local[j][1] = 0.0; break; case 2 : /* This coordinate depends on whether we're looking at a triangle or a quadrilateral */ ps->local[j][0] = (LINEAR_PATCH_N(pp)==3) ? 0.0 : 1.0; ps->local[j][1] = 1.0; break; case 3 : ps->local[j][0] = 0.0; ps->local[j][1] = 1.0; break; #endif } } } return ((BNDP *) ps); } static INT CreateCornerPoints (HEAP * Heap, STD_BVP * theBVP, BNDP ** bndp) { int i; for (i = 0; i < theBVP->ncorners; i++) { bndp[i] = CreateBndPOnPoint (Heap, theBVP->patches[i]); if (bndp[i] == NULL) REP_ERR_RETURN (1); } for (i = 0; i < theBVP->ncorners; i++) PRINTDEBUG (dom, 1, (" id %d\n", PATCH_ID (theBVP->patches[i]))); return (0); } #ifdef UG_DIM_3 /** \brief Add a line between two vertices to the boundary data structure \param i, j The line goes from vertex i to vertex j \param corners Array with pointers to all vertices */ static void CreateLine(INT i, INT j, HEAP *Heap, PATCH **corners, PATCH **lines, PATCH **sides, INT *nlines, INT *err) { INT k, n, m; k = 0; for (n = 0; n < POINT_PATCH_N (corners[i]); n++) for (m = 0; m < POINT_PATCH_N (corners[j]); m++) if (POINT_PATCH_PID (corners[i], n) == POINT_PATCH_PID (corners[j], m)) k++; /* points share one patch only and lie on opposite corners of this patch */ if (k < 2) return; PATCH* thePatch = (PATCH *) GetFreelistMemory (Heap, sizeof (LINE_PATCH) + (k - 1) * sizeof (struct line_on_patch)); if (thePatch == NULL) return; PATCH_TYPE (thePatch) = LINE_PATCH_TYPE; PATCH_ID (thePatch) = *nlines; LINE_PATCH_C0 (thePatch) = i; LINE_PATCH_C1 (thePatch) = j; k = 0; for (n = 0; n < POINT_PATCH_N (corners[i]); n++) for (m = 0; m < POINT_PATCH_N (corners[j]); m++) if (POINT_PATCH_PID (corners[i], n) == POINT_PATCH_PID (corners[j], m)) { LINE_PATCH_PID (thePatch, k) = POINT_PATCH_PID (corners[i], n); LINE_PATCH_CID0 (thePatch, k) = POINT_PATCH_CID (corners[i], n); LINE_PATCH_CID1 (thePatch, k) = POINT_PATCH_CID (corners[j], m); k++; } LINE_PATCH_N (thePatch) = k; for (n = 0; n < LINE_PATCH_N (thePatch); n++) PRINTDEBUG (dom, 1, (" pid %d cid %d %d", LINE_PATCH_PID (thePatch, n), LINE_PATCH_CID0 (thePatch, n), LINE_PATCH_CID1 (thePatch, n))); PRINTDEBUG (dom, 1, ("\n")); IFDEBUG (dom, 10) if (k == 2) { INT o0, o1, s0, s1; s0 = LINE_PATCH_PID (thePatch, 0); s1 = LINE_PATCH_PID (thePatch, 1); o0 = (LINE_PATCH_CID0 (thePatch, 0) == ((LINE_PATCH_CID1 (thePatch, 0) + 1) % (2 * DIM_OF_BND))); o1 = (LINE_PATCH_CID0 (thePatch, 1) == ((LINE_PATCH_CID1 (thePatch, 1) + 1) % (2 * DIM_OF_BND))); if (o0 != o1) { if ((PARAM_PATCH_LEFT (sides[s0]) != PARAM_PATCH_LEFT (sides[s1])) || ((PARAM_PATCH_RIGHT (sides[s0]) != PARAM_PATCH_RIGHT (sides[s1])))) { PRINTDEBUG (dom, 0, ("patch %d and patch %d:" "orientations do not match\n", s0, s1)); (*err)++; } } else { if ((PARAM_PATCH_LEFT (sides[s0]) != PARAM_PATCH_RIGHT (sides[s1])) || ((PARAM_PATCH_RIGHT (sides[s0]) != PARAM_PATCH_LEFT (sides[s1])))) { PRINTDEBUG (dom, 0, ("patch %d and patch %d:" "orientations do not match\n", s0, s1)); (*err)++; } } } ENDDEBUG lines[(*nlines)++] = thePatch; PRINTDEBUG (dom, 1, ("lines id %d type %d n %d\n", PATCH_ID (thePatch), PATCH_TYPE (thePatch), LINE_PATCH_N (thePatch))); } #endif void NS_DIM_PREFIX BVP_Init (STD_BVP* theBVP, HEAP * Heap, MESH * Mesh, INT MarkKey) { PATCH **corners, **sides; unsigned short* segmentsPerPoint, *cornerCounters; INT i, j, n, m, ncorners, nlines, nsides; # ifdef UG_DIM_3 PATCH **lines; INT err; INT nn; # endif assert(theBVP); currBVP = theBVP; auto& theDomain = theBVP->Domain; assert(theDomain); /* fill in data of domain */ ncorners = theDomain->numOfCorners; nsides = theDomain->numOfSegments; /* create parameter patches */ sides = (PATCH **) GetTmpMem (Heap, nsides * sizeof (PATCH *), MarkKey); assert (sides); for (i = 0; i < nsides; i++) sides[i] = NULL; theBVP->nsides = nsides; for (const boundary_segment& theSegment : theDomain->boundarySegments) { assert((theSegment.id >= 0) && (theSegment.id < nsides)); PATCH* thePatch = (PATCH *) GetFreelistMemory (Heap, sizeof (PARAMETER_PATCH)); assert (thePatch); PATCH_TYPE (thePatch) = PARAMETRIC_PATCH_TYPE; PATCH_ID (thePatch) = theSegment.id; for (i = 0; i < 2 * DIM_OF_BND; i++) PARAM_PATCH_POINTS (thePatch, i) = theSegment.points[i]; // TODO: Remove PARAM_PATCH_RANGE, because it is always (0,1)^d for (i = 0; i < DIM_OF_BND; i++) { PARAM_PATCH_RANGE (thePatch)[0][i] = 0; PARAM_PATCH_RANGE (thePatch)[1][i] = 1; } PARAM_PATCH_BS (thePatch) = theSegment.BndSegFunc; PARAM_PATCH_BSD (thePatch) = theSegment.data; sides[theSegment.id] = thePatch; PRINTDEBUG (dom, 1, ("sides id %d type %d left %d right %d\n", PATCH_ID (thePatch), PATCH_TYPE (thePatch), PARAM_PATCH_LEFT (thePatch), PARAM_PATCH_RIGHT (thePatch))); for (i = 0; i < 2 * DIM_OF_BND; i++) PRINTDEBUG (dom, 1, (" corners %d", PARAM_PATCH_POINTS (thePatch, i))); PRINTDEBUG (dom, 1, ("\n")); } for (const linear_segment& theLinSegment : theDomain->linearSegments) { assert((theLinSegment.id >= 0) && (theLinSegment.id < nsides)); PATCH* thePatch = (PATCH *) GetFreelistMemory (Heap, sizeof (LINEAR_PATCH)); assert(thePatch); PATCH_TYPE (thePatch) = LINEAR_PATCH_TYPE; PATCH_ID (thePatch) = theLinSegment.id; LINEAR_PATCH_N (thePatch) = theLinSegment.n; for (j = 0; j < theLinSegment.n; j++) { LINEAR_PATCH_POINTS (thePatch, j) = theLinSegment.points[j]; for (i = 0; i < DIM; i++) LINEAR_PATCH_POS (thePatch, j)[i] = theLinSegment.x[j][i]; } sides[theLinSegment.id] = thePatch; PRINTDEBUG (dom, 1, ("sides id %d type %d left %d right %d\n", PATCH_ID (thePatch), PATCH_TYPE (thePatch), LINEAR_PATCH_LEFT (thePatch), LINEAR_PATCH_RIGHT (thePatch))); } for (i = 0; i < nsides; i++) assert(sides[i]); /* create point patches */ corners = (PATCH **) GetTmpMem (Heap, ncorners * sizeof (PATCH *), MarkKey); assert(corners); theBVP->ncorners = ncorners; /* precompute the number of segments at each point patch */ segmentsPerPoint = (unsigned short*)calloc(ncorners,sizeof(unsigned short)); for (j = 0; j < nsides; j++) { if (PATCH_TYPE (sides[j]) == LINEAR_PATCH_TYPE) { for (n = 0; n < LINEAR_PATCH_N (sides[j]); n++) segmentsPerPoint[LINEAR_PATCH_POINTS (sides[j], n)]++; } else if (PATCH_TYPE (sides[j]) == PARAMETRIC_PATCH_TYPE) { for (n = 0; n < 2 * DIM_OF_BND; n++) if (PARAM_PATCH_POINTS (sides[j], n) >= 0) /* Entry may be -1 for triangular faces */ segmentsPerPoint[PARAM_PATCH_POINTS (sides[j], n)]++; } } /* Allocate point patches */ for (i = 0; i < ncorners; i++) { m = segmentsPerPoint[i]; PATCH* thePatch = (PATCH *) GetFreelistMemory (Heap, sizeof (POINT_PATCH) + (m-1) * sizeof (struct point_on_patch)); assert(thePatch); PATCH_TYPE (thePatch) = POINT_PATCH_TYPE; PATCH_ID (thePatch) = i; POINT_PATCH_N (thePatch) = m; corners[i] = thePatch; } cornerCounters = (unsigned short*)calloc(ncorners,sizeof(unsigned short)); for (j = 0; j < nsides; j++) { if (PATCH_TYPE (sides[j]) == LINEAR_PATCH_TYPE) { for (n = 0; n < LINEAR_PATCH_N (sides[j]); n++) { i = LINEAR_PATCH_POINTS (sides[j], n); POINT_PATCH_PID (corners[i], cornerCounters[i]) = j; POINT_PATCH_CID (corners[i], cornerCounters[i]++) = n; } } else if (PATCH_TYPE (sides[j]) == PARAMETRIC_PATCH_TYPE) { for (n = 0; n < 2 * DIM_OF_BND; n++) { i = PARAM_PATCH_POINTS (sides[j], n); if (i>=0 && i > set; set bnd_edges; for (int s=0; s z(min,max); if ( bnd_edges.insert(z).second ) /* true if bnd_edges didn't contain z yet */ { /* Insert the line into the boundary data structure */ CreateLine(min, max, Heap, corners, lines, sides, &nlines, &err); } else bnd_edges.erase(z); } } else if (PATCH_TYPE (sides[s]) == PARAMETRIC_PATCH_TYPE) { /* Handle edges of parametric patches */ /* Determine whether the boundary segment is a triangle or a quadrilateral. We assume that it is a triangle if the fourth vertex is invalid, and a quadrilateral otherwise. This is the best we can do. */ int cornersOfParametricPatch = (PARAM_PATCH_POINTS (sides[s], 3) < 0 || PARAM_PATCH_POINTS (sides[s], 3) > ncorners) ? 3 : 4; for (nn = 0; nn < cornersOfParametricPatch; nn++) { i = PARAM_PATCH_POINTS (sides[s], nn); j = PARAM_PATCH_POINTS (sides[s], (nn+1)%cornersOfParametricPatch); long max = std::max(i,j); long min = i + j - max; std::pair z(min,max); if ( bnd_edges.insert(z).second ) /* true if bnd_edges didn't contain z yet */ { /* Insert the line into the boundary data structure */ CreateLine(min, max, Heap, corners, lines, sides, &nlines, &err); } else bnd_edges.erase(z); } } else UserWrite("Error: unknown PATCH_TYPE found for a boundary side!\n"); } ASSERT (err == 0); #endif m = ncorners + nlines; theBVP->sideoffset = m; theBVP->patches.resize(m+nsides); n = 0; for (i = 0; i < ncorners; i++) { PATCH* thePatch = corners[i]; for (j = 0; j < POINT_PATCH_N (thePatch); j++) POINT_PATCH_PID (thePatch, j) += m; theBVP->patches[n++] = thePatch; } #ifdef UG_DIM_3 for (i = 0; i < nlines; i++) { PATCH* thePatch = lines[i]; PATCH_ID (thePatch) = n; for (j = 0; j < LINE_PATCH_N (thePatch); j++) LINE_PATCH_PID (thePatch, j) += m; theBVP->patches[n++] = thePatch; } #endif for (i = 0; i < nsides; i++) { PATCH* thePatch = sides[i]; PATCH_ID (thePatch) = n; theBVP->patches[n++] = thePatch; } PRINTDEBUG (dom, 1, ("ncorners %d\n", theBVP->ncorners)); for (i = 0; i < theBVP->ncorners; i++) PRINTDEBUG (dom, 1, (" id %d\n", PATCH_ID (theBVP->patches[i]))); if (Mesh != NULL) { Mesh->mesh_status = MESHSTAT_CNODES; Mesh->nBndP = theBVP->ncorners; Mesh->nInnP = 0; Mesh->nElements = NULL; Mesh->VertexLevel = NULL; Mesh->VertexPrio = NULL; Mesh->ElementLevel = NULL; Mesh->ElementPrio = NULL; Mesh->ElemSideOnBnd = NULL; Mesh->theBndPs = (BNDP **) GetTmpMem (Heap, n * sizeof (BNDP *), MarkKey); assert(Mesh->theBndPs); CreateCornerPoints (Heap, theBVP, Mesh->theBndPs); PRINTDEBUG (dom, 1, ("mesh n %d\n", Mesh->nBndP)); for (i = 0; i < theBVP->ncorners; i++) PRINTDEBUG (dom, 1, (" id %d\n", BND_PATCH_ID ((BND_PS *) (Mesh->theBndPs[i])))); } } /* domain interface function: for description see domain.h */ NS_DIM_PREFIX std_BoundaryValueProblem::~std_BoundaryValueProblem() { for (auto&& p : patches) free (p); } void NS_DIM_PREFIX Set_Current_BVP(STD_BVP *theBVP) { currBVP = theBVP; } static INT GetNumberOfCommonPatches (const PATCH * p0, const PATCH * p1, INT * Pid) { INT i, j, cnt, np0, np1, pid; cnt = 0; np0 = GetNumberOfPatches (p0); np1 = GetNumberOfPatches (p1); for (i = 0; i < np0; i++) { pid = GetPatchId (p0, i); for (j = 0; j < np1; j++) if (pid == GetPatchId (p1, j)) { if (!cnt) *Pid = pid; cnt++; } } return (cnt); } #ifdef UG_DIM_3 static INT GetCommonPatchId (const PATCH * p0, const PATCH * p1, INT k) { INT i, j, cnt; cnt = 0; for (i = 0; i < GetNumberOfPatches (p0); i++) for (j = 0; j < GetNumberOfPatches (p1); j++) if (GetPatchId (p0, i) == GetPatchId (p1, j)) if (k == cnt++) return (GetPatchId (p1, j)); return (-1); } static INT GetCommonLinePatchId (PATCH * p0, PATCH * p1) { INT i, k, l, cnt, cnt1; if (PATCH_TYPE (p0) == LINE_PATCH_TYPE) return (PATCH_ID (p0)); else if (PATCH_TYPE (p1) == LINE_PATCH_TYPE) return (PATCH_ID (p1)); cnt = GetNumberOfCommonPatches (p0, p1, &i); if (cnt < 1) return (-1); for (k = currBVP->ncorners; k < currBVP->sideoffset; k++) { PATCH *p = currBVP->patches[k]; if (LINE_PATCH_N (p) != cnt) continue; cnt1 = 0; for (i = 0; i < cnt; i++) for (l = 0; l < LINE_PATCH_N (p); l++) if (GetCommonPatchId (p0, p1, i) == LINE_PATCH_PID (p, l)) cnt1++; if (cnt == cnt1) return (k); } return (-1); } #endif /****************************************************************************/ /****************************************************************************/ /* */ /* functions for BNDS */ /* */ /****************************************************************************/ /****************************************************************************/ static INT PatchGlobal (const PATCH * p, DOUBLE * lambda, Dune::FieldVector& global) { if (PATCH_TYPE (p) == PARAMETRIC_PATCH_TYPE) return ((*PARAM_PATCH_BS (p))(PARAM_PATCH_BSD (p), lambda, global)); else if (PATCH_TYPE (p) == LINEAR_PATCH_TYPE) { #ifdef UG_DIM_2 global[0] = (1 - lambda[0]) * LINEAR_PATCH_POS (p, 0)[0] + lambda[0] * LINEAR_PATCH_POS (p, 1)[0]; global[1] = (1 - lambda[0]) * LINEAR_PATCH_POS (p, 0)[1] + lambda[0] * LINEAR_PATCH_POS (p, 1)[1]; #endif #ifdef UG_DIM_3 if (LINEAR_PATCH_N(p) ==3) { /* Linear interpolation for a triangle boundary segment */ int i; for (i=0; i<3; i++) global[i] = (1 - lambda[0] - lambda[1]) * LINEAR_PATCH_POS (p, 0)[i] + lambda[0] * LINEAR_PATCH_POS (p, 1)[i] + lambda[1] * LINEAR_PATCH_POS (p, 2)[i]; } else { /* Bilinear interpolation for a quadrilateral boundary segment */ int i; for (i=0; i<3; i++) global[i] = LINEAR_PATCH_POS (p, 0)[i] + lambda[0]*(LINEAR_PATCH_POS (p, 1)[i] - LINEAR_PATCH_POS (p, 0)[i]) + lambda[1]*(LINEAR_PATCH_POS (p, 3)[i] - LINEAR_PATCH_POS (p, 0)[i]) + lambda[0]*lambda[1]*(LINEAR_PATCH_POS (p, 0)[i]+LINEAR_PATCH_POS (p, 2)[i]-LINEAR_PATCH_POS (p, 1)[i]-LINEAR_PATCH_POS (p, 3)[i]); } #endif return (0); } return (1); } static INT local2lambda (BND_PS * ps, const Dune::FieldVector& local, DOUBLE lambda[]) { const PATCH *p = currBVP->patches[ps->patch_id]; if ((PATCH_TYPE (p) == PARAMETRIC_PATCH_TYPE) || (PATCH_TYPE (p) == LINEAR_PATCH_TYPE)) #ifdef UG_DIM_2 lambda[0] = (1.0 - local[0]) * ps->local[0][0] + local[0] * ps->local[1][0]; #endif #ifdef UG_DIM_3 switch (ps->n) { case 3 : lambda[0] = (1.0 - local[0] - local[1]) * ps->local[0][0] + local[0] * ps->local[1][0] + local[1] * ps->local[2][0]; lambda[1] = (1.0 - local[0] - local[1]) * ps->local[0][1] + local[0] * ps->local[1][1] + local[1] * ps->local[2][1]; break; case 4 : lambda[0] = (1.0 - local[0]) * (1.0 - local[1]) * ps->local[0][0] + local[0] * (1.0 - local[1]) * ps->local[1][0] + local[0] * local[1] * ps->local[2][0] + (1.0 - local[0]) * local[1] * ps->local[3][0]; lambda[1] = (1.0 - local[0]) * (1.0 - local[1]) * ps->local[0][1] + local[0] * (1.0 - local[1]) * ps->local[1][1] + local[0] * local[1] * ps->local[2][1] + (1.0 - local[0]) * local[1] * ps->local[3][1]; break; } #endif else return (1); return (0); } static bool SideIsCooriented (BND_PS * ps) { # ifdef UG_DIM_2 if (BND_LOCAL (ps, 1)[0] > BND_LOCAL (ps, 0)[0]) return true; else return false; # endif # ifdef UG_DIM_3 DOUBLE vp, x0[2], x1[2]; ASSERT (BND_N (ps) >= 3); /* check whether an (arbitrary) angle of the side is > 180 degree */ V2_SUBTRACT (BND_LOCAL (ps, 1), BND_LOCAL (ps, 0), x0); V2_SUBTRACT (BND_LOCAL (ps, 2), BND_LOCAL (ps, 0), x1); V2_VECTOR_PRODUCT (x1, x0, vp); ASSERT (fabs (vp) > SMALL_C); if (vp > SMALL_C) return true; else return false; # endif } /* domain interface function: for description see domain.h */ INT NS_DIM_PREFIX BNDS_BndSDesc (BNDS * theBndS, INT * id, INT * nbid) { BND_PS *ps; PATCH *p; INT left, right; ps = (BND_PS *) theBndS; p = currBVP->patches[ps->patch_id]; if (PATCH_TYPE (p) == PARAMETRIC_PATCH_TYPE) { left = PARAM_PATCH_LEFT (p); right = PARAM_PATCH_RIGHT (p); } else if (PATCH_TYPE (p) == LINEAR_PATCH_TYPE) { left = LINEAR_PATCH_LEFT (p); right = LINEAR_PATCH_RIGHT (p); } else return (1); /* check orientation */ if (SideIsCooriented (ps)) { /* patch and side are co-oriented */ *id = left; *nbid = right; } else { /* patch and side are anti-oriented */ *id = right; *nbid = left; } return (0); } /* domain interface function: for description see domain.h */ BNDP *NS_DIM_PREFIX BNDS_CreateBndP (HEAP * Heap, BNDS * aBndS, const FieldVector& local) { BND_PS *ps, *pp; if (aBndS == NULL) return (NULL); ps = (BND_PS *) aBndS; pp = (BND_PS *) GetFreelistMemory (Heap, sizeof (BND_PS)); if (pp == NULL) return (NULL); pp->patch_id = ps->patch_id; pp->n = 1; if (local2lambda (ps, local, pp->local[0])) return (NULL); PRINTDEBUG (dom, 1, (" BNDP s %d\n", pp->patch_id)); return ((BNDP *) pp); } /****************************************************************************/ /****************************************************************************/ /* */ /* functions for BNDP */ /* */ /****************************************************************************/ /****************************************************************************/ /* domain interface function: for description see domain.h */ INT NS_DIM_PREFIX BNDP_Global (const BNDP * aBndP, FieldVector& global) { using std::abs; BND_PS *ps; PATCH *p, *s; INT j, k; FieldVector pglobal; ps = (BND_PS *) aBndP; p = currBVP->patches[ps->patch_id]; PRINTDEBUG (dom, 1, (" bndp pid %d %d %d\n", ps->patch_id, PATCH_ID (p), PATCH_TYPE (p))); switch (PATCH_TYPE (p)) { case PARAMETRIC_PATCH_TYPE : case LINEAR_PATCH_TYPE : return (PatchGlobal (p, ps->local[0], global)); case POINT_PATCH_TYPE : s = currBVP->patches[POINT_PATCH_PID (p, 0)]; PRINTDEBUG (dom, 1, (" bndp n %d %d loc %f %f gl \n", POINT_PATCH_N (p), POINT_PATCH_PID (p, 0), ps->local[0][0], ps->local[0][1])); PatchGlobal(s, ps->local[0], global); for (j = 1; j < POINT_PATCH_N (p); j++) { s = currBVP->patches[POINT_PATCH_PID (p, j)]; if (PatchGlobal(s, ps->local[j], pglobal)) REP_ERR_RETURN (1); PRINTDEBUG (dom,1, (" bndp j %d %d loc %f %f gl %f %f %f\n", j, POINT_PATCH_PID (p, j), ps->local[j][0], ps->local[j][1], pglobal[0], pglobal[1], pglobal[2])); for (k = 0; k < DIM; k++) if (abs(pglobal[k] - global[k]) > SMALL_DIFF) REP_ERR_RETURN (1); } return (0); #ifdef UG_DIM_3 case LINE_PATCH_TYPE : s = currBVP->patches[LINE_PATCH_PID (p, 0)]; if (PatchGlobal(s, ps->local[0], global)) REP_ERR_RETURN (1); PRINTDEBUG (dom, 1, (" bndp n %d %d loc %f %f gl %f %f %f\n", POINT_PATCH_N (p), LINE_PATCH_PID (p, 0), ps->local[0][0], ps->local[0][1], global[0], global[1], global[2])); for (j = 1; j < LINE_PATCH_N (p); j++) { s = currBVP->patches[LINE_PATCH_PID (p, j)]; if (PatchGlobal(s, ps->local[j], pglobal)) REP_ERR_RETURN (1); PRINTDEBUG (dom, 1, (" bndp j %d %d loc %f %f gl %f %f %f\n", j, LINE_PATCH_PID (p, j), ps->local[j][0], ps->local[j][1], pglobal[0], pglobal[1], pglobal[2])); for (k = 0; k < DIM; k++) if (abs(pglobal[k] - global[k]) > SMALL_DIFF) REP_ERR_RETURN (1); } return (0); #endif } REP_ERR_RETURN (1); } /* domain interface function: for description see domain.h */ INT NS_DIM_PREFIX BNDP_BndPDesc (BNDP * theBndP, INT * move) { BND_PS *ps; PATCH *p; ps = (BND_PS *) theBndP; p = STD_BVP_PATCH (currBVP, ps->patch_id); switch (PATCH_TYPE (p)) { case PARAMETRIC_PATCH_TYPE : case LINEAR_PATCH_TYPE : *move = DIM_OF_BND; return (0); case POINT_PATCH_TYPE : *move = 0; return (0); # ifdef UG_DIM_3 case LINE_PATCH_TYPE : *move = 1; return (0); # endif } return (1); } /* domain interface function: for description see domain.h */ INT NS_DIM_PREFIX BNDP_BndEDesc (BNDP * aBndP0, BNDP * aBndP1) { const BND_PS *bp0 = (BND_PS*)aBndP0; const BND_PS *bp1 = (BND_PS*)aBndP1; if ((bp0 == nullptr) || (bp1 == nullptr)) REP_ERR_RETURN (1); return (0); } /* domain interface function: for description see domain.h */ BNDS *NS_DIM_PREFIX BNDP_CreateBndS (HEAP * Heap, BNDP ** aBndP, INT n) { BND_PS *bp[4], *bs; PATCH *p[4]; DOUBLE *lambda[4]; INT i, j, l, pid; # ifdef UG_DIM_3 INT k; # endif PRINTDEBUG (dom, 1, ("Create BNDS:\n")); for (i = 0; i < n; i++) { bp[i] = (BND_PS *) aBndP[i]; p[i] = currBVP->patches[bp[i]->patch_id]; PRINTDEBUG (dom, 1, (" bp %d p %d n %d\n", bp[i]->patch_id, PATCH_ID (p[i]), n)); for (l = 0; l < GetNumberOfPatches (p[i]); l++) PRINTDEBUG (dom, 1, (" bp pid %d\n", GetPatchId (p[i], l))); } pid = -1; #ifdef UG_DIM_2 if (n != 2) return (NULL); /* find common patch of boundary points */ for (i = 0; i < GetNumberOfPatches (p[0]); i++) for (j = 0; j < GetNumberOfPatches (p[1]); j++) { PRINTDEBUG (dom, 1, (" pid i, j %d %d %d %d\n", i, j, GetPatchId (p[0], i), GetPatchId (p[1], j))); if (GetPatchId (p[0], i) == GetPatchId (p[1], j)) { pid = GetPatchId (p[0], i); lambda[0] = bp[0]->local[i]; lambda[1] = bp[1]->local[j]; break; PRINTDEBUG (dom, 1, (" pid %d \n", pid)); } } #endif #ifdef UG_DIM_3 switch (n) { case 3 : for (i = 0; i < GetNumberOfPatches (p[0]); i++) for (j = 0; j < GetNumberOfPatches (p[1]); j++) if (GetPatchId (p[0], i) == GetPatchId (p[1], j)) for (k = 0; k < GetNumberOfPatches (p[2]); k++) if (GetPatchId (p[0], i) == GetPatchId (p[2], k)) { pid = GetPatchId (p[0], i); lambda[0] = bp[0]->local[i]; lambda[1] = bp[1]->local[j]; lambda[2] = bp[2]->local[k]; break; } break; case 4 : for (i = 0; i < GetNumberOfPatches (p[0]); i++) for (j = 0; j < GetNumberOfPatches (p[1]); j++) if (GetPatchId (p[0], i) == GetPatchId (p[1], j)) for (k = 0; k < GetNumberOfPatches (p[2]); k++) if (GetPatchId (p[0], i) == GetPatchId (p[2], k)) for (l = 0; l < GetNumberOfPatches (p[3]); l++) if (GetPatchId (p[0], i) == GetPatchId (p[3], l)) { pid = GetPatchId (p[0], i); lambda[0] = bp[0]->local[i]; lambda[1] = bp[1]->local[j]; lambda[2] = bp[2]->local[k]; lambda[3] = bp[3]->local[l]; break; } break; } #endif if (pid == -1) return (NULL); bs = (BND_PS *) GetFreelistMemory (Heap, (n - 1) * sizeof (COORD_BND_VECTOR) + sizeof (BND_PS)); if (bs == NULL) return (NULL); bs->n = n; bs->patch_id = pid; for (i = 0; i < n; i++) for (j = 0; j < DIM_OF_BND; j++) bs->local[i][j] = lambda[i][j]; for (i = 0; i < n; i++) for (j = 0; j < DIM_OF_BND; j++) PRINTDEBUG (dom, 1, (" bnds i, j %d %d %f\n", i, j, lambda[i][j])); PRINTDEBUG (dom, 1, (" Create BNDS %x %d\n", bs, pid)); return ((BNDS *) bs); } /* domain interface function: for description see domain.h */ BNDP *NS_DIM_PREFIX BNDP_CreateBndP (HEAP * Heap, BNDP * aBndP0, BNDP * aBndP1, DOUBLE lcoord) { BND_PS *bp0, *bp1, *bp; PATCH *p0, *p1; INT i, j, k, l, cnt; bp0 = (BND_PS *) aBndP0; bp1 = (BND_PS *) aBndP1; if ((bp0 == NULL) || (bp1 == NULL)) return (NULL); p0 = currBVP->patches[bp0->patch_id]; p1 = currBVP->patches[bp1->patch_id]; PRINTDEBUG (dom, 1, (" bp0 %d pid %d\n", bp0->patch_id, PATCH_ID (p0))); for (l = 0; l < GetNumberOfPatches (p0); l++) PRINTDEBUG (dom, 1, (" bp pid %d\n", GetPatchId (p0, l))); PRINTDEBUG (dom, 1, (" bp1 %d pid %d\n", bp1->patch_id, PATCH_ID (p1))); for (l = 0; l < GetNumberOfPatches (p1); l++) PRINTDEBUG (dom, 1, (" bp pid %d\n", GetPatchId (p1, l))); cnt = GetNumberOfCommonPatches (p0, p1, &i); if (cnt == 0) return (NULL); bp = (BND_PS *) GetFreelistMemory (Heap, (cnt - 1) * sizeof (COORD_BND_VECTOR) + sizeof (BND_PS)); if (bp == NULL) return (NULL); bp->n = cnt; #ifdef UG_DIM_3 if (cnt > 1) { PATCH *p; k = GetCommonLinePatchId (p0, p1); if ((k < currBVP->ncorners) || (k >= currBVP->sideoffset)) return (NULL); p = currBVP->patches[k]; bp->patch_id = k; PRINTDEBUG (dom, 1, (" Create BNDP line %d cnt %d\n", k, cnt)); PRINTDEBUG (dom, 1, (" bp0 %d pid %d\n", bp0->patch_id, PATCH_ID (p0))); for (l = 0; l < GetNumberOfPatches (p0); l++) PRINTDEBUG (dom, 1, (" bp pid %d\n", GetPatchId (p0, l))); PRINTDEBUG (dom, 1, (" bp1 %d pid %d\n", bp1->patch_id, PATCH_ID (p1))); for (l = 0; l < GetNumberOfPatches (p1); l++) PRINTDEBUG (dom, 1, (" bp pid %d\n", GetPatchId (p1, l))); for (l = 0; l < LINE_PATCH_N (p); l++) { for (i = 0; i < GetNumberOfPatches (p0); i++) if (GetPatchId (p0, i) == LINE_PATCH_PID (p, l)) for (j = 0; j < GetNumberOfPatches (p1); j++) if (GetPatchId (p1, j) == LINE_PATCH_PID (p, l)) for (k = 0; k < DIM_OF_BND; k++) bp->local[l][k] = (1.0 - lcoord) * bp0->local[i][k] + lcoord * bp1->local[j][k]; } for (l = 0; l < LINE_PATCH_N (p); l++) PRINTDEBUG (dom, 1, (" Create BNDP line %d l %d %f %f\n", LINE_PATCH_PID (p, l), l, bp->local[l][0], bp->local[l][1])); return ((BNDP *) bp); } #endif for (i = 0; i < GetNumberOfPatches (p0); i++) for (j = 0; j < GetNumberOfPatches (p1); j++) if (GetPatchId (p0, i) == GetPatchId (p1, j)) { bp->patch_id = GetPatchId (p0, i); for (k = 0; k < DIM_OF_BND; k++) bp->local[0][k] = (1.0 - lcoord) * bp0->local[i][k] + lcoord * bp1->local[j][k]; PRINTDEBUG (dom, 1, (" Create BNDP param %d \n", GetPatchId (p0, i))); break; } return ((BNDP *) bp); } /* domain interface function: for description see domain.h */ INT NS_DIM_PREFIX BNDP_SaveInsertedBndP (BNDP * theBndP, char *data, INT max_data_size) { BND_PS *bp; PATCH *p; INT pid; bp = (BND_PS *) theBndP; if (bp == NULL) return (1); pid = bp->patch_id; p = currBVP->patches[pid]; switch (PATCH_TYPE (p)) { case PARAMETRIC_PATCH_TYPE : case LINEAR_PATCH_TYPE : pid -= currBVP->sideoffset; break; case POINT_PATCH_TYPE : pid = POINT_PATCH_PID (p, 0) - currBVP->sideoffset; break; #ifdef UG_DIM_3 case LINE_PATCH_TYPE : pid = LINE_PATCH_PID (p, 0) - currBVP->sideoffset; break; #endif } PRINTDEBUG (dom, 1, (" Insert pid %d %d\n", bp->patch_id, pid)); #ifdef UG_DIM_2 if (snprintf (data, max_data_size, "bn %d %f", pid, (float) bp->local[0][0]) > max_data_size) return (1); #endif #ifdef UG_DIM_3 if (snprintf (data, max_data_size, "bn %d %f %f", (int) pid, (float) bp->local[0][0], (float) bp->local[0][1]) > max_data_size) return (1); #endif return (0); } /* domain interface function: for description see domain.h */ INT NS_DIM_PREFIX BNDP_SurfaceId (BNDP * aBndP, INT * n, INT i) { BND_PS *ps; if (i < 0) return (1); ps = (BND_PS *) aBndP; if (ps == NULL) return (-1); return ps->patch_id; } /* domain interface function: for description see domain.h */ INT NS_DIM_PREFIX BNDP_Dispose (HEAP * Heap, BNDP * theBndP) { BND_PS *ps; if (theBndP == NULL) return (0); ps = (BND_PS *) theBndP; DisposeMem(Heap, ps); return 0; } /* domain interface function: for description see domain.h */ INT NS_DIM_PREFIX BNDS_Dispose (HEAP * Heap, BNDS * theBndS) { BND_PS *ps; if (theBndS == NULL) return (0); ps = (BND_PS *) theBndS; DisposeMem(Heap, ps); return 0; } /* domain interface function: for description see domain.h */ INT NS_DIM_PREFIX BNDP_SaveBndP (BNDP * BndP) { BND_PS *bp; INT i, j; int iList[2]; double dList[DIM]; iList[0] = BND_PATCH_ID (BndP); iList[1] = BND_N (BndP); if (Bio_Write_mint (2, iList)) return (1); bp = (BND_PS *) BndP; for (i = 0; i < BND_N (BndP); i++) { for (j = 0; j < DIM - 1; j++) dList[j] = bp->local[i][j]; if (Bio_Write_mdouble (DIM - 1, dList)) return (1); } return (0); } INT NS_DIM_PREFIX BNDP_SaveBndP_Ext (BNDP * BndP) { BND_PS *bp; INT i, j; int iList[2]; double dList[DIM]; /* TODO: save free boundary points */ iList[0] = BND_PATCH_ID (BndP); iList[1] = BND_N (BndP); if (Bio_Write_mint (2, iList)) return (1); bp = (BND_PS *) BndP; for (i = 0; i < BND_N (BndP); i++) { for (j = 0; j < DIM - 1; j++) dList[j] = bp->local[i][j]; if (Bio_Write_mdouble (DIM - 1, dList)) return (1); } return (0); } /* domain interface function: for description see domain.h */ BNDP *NS_DIM_PREFIX BNDP_LoadBndP (STD_BVP *theBVP, HEAP * Heap) { BND_PS *bp; int i, j, pid, n; int iList[2]; double dList[DIM]; if (Bio_Read_mint (2, iList)) return (NULL); pid = iList[0]; n = iList[1]; bp = (BND_PS *) GetFreelistMemory (Heap, (n - 1) * sizeof (COORD_BND_VECTOR) + sizeof (BND_PS)); bp->n = n; bp->patch_id = pid; for (i = 0; i < n; i++) { if (Bio_Read_mdouble (DIM - 1, dList)) return (NULL); for (j = 0; j < DIM - 1; j++) bp->local[i][j] = dList[j]; } return ((BNDP *) bp); } BNDP *NS_DIM_PREFIX BNDP_LoadBndP_Ext (void) { BND_PS *bp; int i, j, pid, n; int iList[2]; double dList[DIM - 1]; if (Bio_Read_mint (2, iList)) return (NULL); pid = iList[0]; n = iList[1]; bp = (BND_PS *) malloc ((n - 1) * sizeof (COORD_BND_VECTOR) + sizeof (BND_PS)); bp->n = n; bp->patch_id = pid; for (i = 0; i < n; i++) { if (Bio_Read_mdouble (DIM - 1, dList)) return (NULL); for (j = 0; j < DIM - 1; j++) bp->local[i][j] = dList[j]; } return ((BNDP *) bp); } /** @} */ dune-uggrid-2.11.0+dfsg/dune/uggrid/domain/std_domain.h000066400000000000000000000576651513616443000227270ustar00rootroot00000000000000// -*- tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- // vi: set et ts=4 sw=2 sts=2: // SPDX-FileCopyrightInfo: Copyright © DUNE Project contributors, see file LICENSE.md in module root // SPDX-License-Identifier: LGPL-2.1-or-later /** \defgroup std The Standard Domain * \ingroup dom */ /*! \file std_domain.h * \ingroup std */ /** \addtogroup std * * @{ */ /****************************************************************************/ /* */ /* File: std_domain.h */ /* */ /* Purpose: standard domain declaration */ /* */ /* Author: Peter Bastian/Klaus Johannsen */ /* Institut fuer Computeranwendungen III */ /* Universitaet Stuttgart */ /* Pfaffenwaldring 27 */ /* 70550 Stuttgart */ /* email: ug@ica3.uni-stuttgart.de */ /* */ /* History: 29.01.92 begin, ug version 2.0 */ /* */ /* Remarks: */ /* */ /****************************************************************************/ /****************************************************************************/ /* */ /* auto include mechanism and other include files */ /* */ /****************************************************************************/ #ifndef __STD_DOMAIN__ #define __STD_DOMAIN__ #include #include #include #include #ifdef ModelP # include #endif #include #include #include #include #include #include START_UGDIM_NAMESPACE /** \brief Status for mesh */ enum MeshStatus {MESHSTAT_NOTINIT, MESHSTAT_EMPTY, MESHSTAT_CNODES, MESHSTAT_SURFMESH, MESHSTAT_MESH}; typedef void *BNDS; /*!< Structure handled by domain module */ typedef void *BNDP; /*!< Structure handled by domain module */ #undef CORNERS_OF_BND_SEG #define CORNERS_OF_BND_SEG 2*DIM_OF_BND /** \brief Data type of the functions mapping parameter space to world space * * The first argument of type void * is the user data pointer from * the corresponding BOUNDARY_SEGMENT. The second parameter of type DOUBLE * * provides an array containing the parameters where the boundary segment * function should be evaluated (one number in 2D, two numbers in 3D). The * third parameter of type DOUBLE * provides an array where the result can be placed * (x,y values in 2D, x,y,z values in 3D). */ typedef INT (*BndSegFuncPtr)(void *,DOUBLE *, FieldVector&); /** \brief Data structure defining part of the boundary of a domain A domain for UG is described as a set of boundary segments defined by the \ref boundary_segment structure. Each boundary segment is a mapping from `d`-1 dimensional parameter space to `d` dimensional Euclidean space. The parameter space is an interval [0,1] in two dimensions or a square [0,1]x[0,1] in three-dimensional applications. For all boundary segments the points in `d` dimensional space corresponding to the parameters 0 and 1 in two dimensions ((0,0),(0,1),(1,0),(1,1) in three dimensions) are called `corners` of the domain. Locally for each boundary segment the corners are numbered like shown in the figures above. The corners are numbered `globally` in a consecutive way beginning with 0. \warning boundary segments must be defined in such a way that no two corners are identical! */ struct boundary_segment { /** \brief Create a new BOUNDARY_SEGMENT * * @param id - id of this boundary segment * @param point - the endpoints of the boundary segment * @param BndSegFunc - function mapping parameters * @param data - user defined space */ boundary_segment(INT id, const INT* point, BndSegFuncPtr BndSegFunc, void *data); /** \brief Number of the boundary segment beginning with zero */ INT id; /** \brief Numbers of the vertices (ID) * * Mapping of local numbers of corners to global numbers. Remember, all * global numbers of corners must be different. */ INT points[CORNERS_OF_BND_SEG]; /** \brief Pointer to a function describing the mapping from parameter space to world space */ BndSegFuncPtr BndSegFunc; /** \brief User defined pointer * * This pointer is passed as the first argument to the BndSegFunc of the segment. * This pointer can be used to construct an interface to geometry data files, * e.g. from a CAD system. */ void *data; }; /** \brief Boundary segment with a (multi-)linear geometry */ struct linear_segment { /** \brief Constructor * * @param idA id of this boundary segment * @param nA Number of corners * @param point The ids of the vertices that make up the boundary segment * @param xA Coordinates of the vertices */ linear_segment(INT idA, INT nA, const INT * point, const std::array, CORNERS_OF_BND_SEG>& xA); /** \brief Unique id of that segment */ INT id; /** \brief Number of corners */ INT n; /** \brief Numbers of the vertices (ID) */ INT points[CORNERS_OF_BND_SEG]; /** \brief Coordinates */ std::array, CORNERS_OF_BND_SEG> x; }; /** \brief Data type describing a domain The \ref domain structure describes a two- or three-dimensional domain (boundary). This geometry information is used by UG when it refines a grid, i.e., complex geometries are approximated better when the grid is refined. A domain is made up of one or several `boundary segments` which are defined by the \ref boundary_segment structure. The points where boundary segments join are called corners of the domain. For each corner a \ref node is automatically created. */ struct domain { /** \brief Number of boundary segments */ INT numOfSegments; /** \brief The boundary segments with a parametrization */ std::vector boundarySegments; /** \brief The boundary segments without a parametrization */ std::vector linearSegments; /** \brief Number of corner points */ INT numOfCorners; }; /*********************************************/ /* Code that was formerly in std_internal.hh */ /*********************************************/ typedef DOUBLE COORD_BND_VECTOR[DIM_OF_BND]; enum PatchType {POINT_PATCH_TYPE, #ifdef UG_DIM_3 LINE_PATCH_TYPE, #endif LINEAR_PATCH_TYPE, PARAMETRIC_PATCH_TYPE}; /** @name Macros for DOMAIN */ /*@{*/ #define DOMAIN_NSEGMENT(p) ((p)->numOfSegments) #define DOMAIN_NCORNER(p) ((p)->numOfCorners) /*@}*/ /** @name Macros for STD_BVP */ /*@{*/ #define STD_BVP_DOMAIN(p) ((p)->Domain) #define STD_BVP_NSIDES(p) ((p)->nsides) #define STD_BVP_SIDEOFFSET(p) ((p)->sideoffset) #define STD_BVP_PATCH(p,i) ((p)->patches[i]) #define GetSTD_BVP(p) ((STD_BVP *)(p)) /*@}*/ /****************************************************************************/ /* */ /* macros for patches */ /* */ /****************************************************************************/ /** @name Macros for patches */ /*@{*/ #define PATCH_TYPE(p) (p)->ge.type #define PATCH_ID(p) (p)->ge.id #define POINT_PATCH_N(p) (p)->po.npatches #define POINT_PATCH_PID(p,i) (p)->po.pop[i].patch_id #define POINT_PATCH_CID(p,i) (p)->po.pop[i].corner_id #define LINE_PATCH_C0(p) ((p)->li.c0) #define LINE_PATCH_C1(p) ((p)->li.c1) #define LINE_PATCH_N(p) (p)->li.npatches #define LINE_PATCH_PID(p,i) (p)->li.lop[i].patch_id #define LINE_PATCH_CID0(p,i) (p)->li.lop[i].corner_id[0] #define LINE_PATCH_CID1(p,i) (p)->li.lop[i].corner_id[1] #define PARAM_PATCH_LEFT(p) (p)->pa.left #define PARAM_PATCH_RIGHT(p) (p)->pa.right #define PARAM_PATCH_POINTS(p,i) (p)->pa.points[i] #define PARAM_PATCH_RANGE(p) (p)->pa.range #define PARAM_PATCH_BS(p) (p)->pa.BndSegFunc #define PARAM_PATCH_BSD(p) (p)->pa.bs_data #define LINEAR_PATCH_LEFT(p) (p)->lp.left #define LINEAR_PATCH_RIGHT(p) (p)->lp.right #define LINEAR_PATCH_N(p) (p)->lp.corners #define LINEAR_PATCH_POINTS(p,i) (p)->lp.points[i] #define LINEAR_PATCH_POS(p,i) (p)->lp.pos[i] #define BND_PATCH_ID(p) (((BND_PS *)p)->patch_id) #define BND_DATA(p) (((BND_PS *)p)->data) #define BND_N(p) (((BND_PS *)p)->n) #define BND_LOCAL(p,i) (((BND_PS *)p)->local[i]) #define BND_SIZE(p) ((((BND_PS *)p)->n-1)*sizeof(COORD_BND_VECTOR)+sizeof(BND_PS)) #define M_BNDS_NSIZE(n) (((n)-1)*sizeof(M_BNDP)+sizeof(M_BNDS)) #define M_BNDS_SIZE(p) M_BNDS_NSIZE(((M_BNDS *)(p))->n) /*@}*/ /****************************************************************************/ /* */ /* BoundaryValueProblem data structure */ /* */ /****************************************************************************/ /** \brief ??? * * \todo Please doc me! */ struct std_BoundaryValueProblem { ~std_BoundaryValueProblem(); /** \brief Domain pointer */ std::unique_ptr Domain; /** \brief File name for boundary infos */ char bnd_file[NS_PREFIX NAMESIZE]; /** \brief File name for meshinfos */ char mesh_file[NS_PREFIX NAMESIZE]; /** @name Boundary description */ /*@{*/ INT ncorners; INT nsides; INT sideoffset; /** \brief list of patches */ std::vector patches; /*@}*/ }; /****************************************************************************/ /* */ /* Patch data structure */ /* */ /****************************************************************************/ /** \brief ??? * * \todo Please doc me! */ struct generic_patch { /** \brief Patch type */ enum PatchType type; /** \brief Unique id used for load/store */ INT id; }; /** \brief ??? * * \todo Please doc me! */ struct point_on_patch { INT patch_id; INT corner_id; }; /** \brief ??? * * \todo Please doc me! */ struct point_patch { /** \brief Patch type */ enum PatchType type; /** \brief Unique id used for load/store */ INT id; /** \brief Number of patches */ INT npatches; /** \brief Reference to surface */ struct point_on_patch pop[1]; }; #ifdef UG_DIM_3 /** \brief ??? * * \todo Please doc me! */ struct line_on_patch { INT patch_id; INT corner_id[2]; }; /** \brief ??? * * \todo Please doc me! */ struct line_patch { /** \brief Patch type */ enum PatchType type; /** \brief Unique id used for load/store */ INT id; /** \brief Number of patches */ INT npatches; /** \brief Corner 0 of line */ INT c0; /** \brief Corner 1 of line */ INT c1; /** \brief Reference to surface */ struct line_on_patch lop[1]; }; #endif /** \brief ??? * * \todo Please doc me! */ struct linear_patch { /** \brief Patch type */ enum PatchType type; /** \brief Unique id used for load/store */ INT id; /** \brief Id of left and right subdomain */ INT left,right; /** \brief Number of corners */ INT corners; /** \brief Ids of points */ INT points[CORNERS_OF_BND_SEG]; /** \brief Position */ DOUBLE pos[CORNERS_OF_BND_SEG][DIM]; }; /** \brief ??? * * \todo Please doc me! */ struct parameter_patch { /** \brief Patch type */ enum PatchType type; /** \brief Unique id used for load/store */ INT id; /** \brief Id of left and right subdomain */ INT left,right; /** \brief Ids of points */ INT points[CORNERS_OF_BND_SEG]; /** \brief Parameter range * * The range is an axis-aligned rectangle, described by two points * in DIM_OF_BND-dimensional space. */ DOUBLE range[2][DIM_OF_BND]; /** \brief Pointer to definition function */ BndSegFuncPtr BndSegFunc; /** \brief Can be used by applic to find data */ void *bs_data; /*@}*/ }; /** \brief ??? * * \todo Please doc me! */ union patch { struct generic_patch ge; struct point_patch po; struct linear_patch lp; struct parameter_patch pa; #ifdef UG_DIM_3 struct line_patch li; #endif } ; /** \brief ??? * * \todo Please doc me! */ struct bnd_ps { /** \brief Associated patch */ INT patch_id; /** \brief E.g. global coordinates, pointers... */ void *data; /** \brief Number of arguments */ INT n; /** \brief Parameter range */ COORD_BND_VECTOR local[1]; }; /*----------- typedef for structs ------------------------------------------*/ /* typedefs */ #undef DOMAIN typedef struct domain DOMAIN; typedef struct linear_segment LINEAR_SEGMENT; typedef struct boundary_segment BOUNDARY_SEGMENT; typedef struct std_BoundaryValueProblem STD_BVP; typedef union patch PATCH; typedef struct point_patch POINT_PATCH; typedef struct line_patch LINE_PATCH; typedef struct linear_patch LINEAR_PATCH; typedef struct parameter_patch PARAMETER_PATCH; typedef struct bnd_ps BND_PS; /* --- public functions --- */ /** \brief Access the id of the segment (used by DUNE) */ UINT GetBoundarySegmentId(BNDS* boundarySegment); /** \todo Please doc me! */ struct mesh { /** \brief Status */ enum MeshStatus mesh_status; /** \brief Number of boundary points */ INT nBndP; /** \brief List of boundary points */ BNDP **theBndPs; /** \brief Number of inner nodes */ INT nInnP; /** \brief Positions of inner nodes */ DOUBLE **Position; /** \brief Number of boundary sides per subdomain */ INT *nSides; /** \brief Number of side corners */ INT **Side_corners; /** \brief Triangle_id for prism */ INT **xy_Side; /** \brief Corner ids */ INT ***Side_corner_ids; /** \brief Number of elements per subdomain */ INT *nElements; /** \brief Number of element corners */ INT **Element_corners; /** \brief Number of side corners */ INT ***Element_corner_ids; /** \brief Number of side corners */ INT ***nbElements; /** \brief Used bitwise: sides on bnd for elem */ INT **ElemSideOnBnd; /** @name Parallel part */ /*@}*/ /** \brief Level of vertex NULL if all vertex on level 0 */ unsigned char *VertexLevel; /** \brief Priority of vertex NULL if all vertex are master */ char *VertexPrio; /** \brief Level of element in subdomain NULL if all elements on level 0 */ char **ElementLevel; /** \brief Priority of element in subdomain NULL if all elements are master */ char **ElementPrio; /*@}*/ }; typedef struct mesh MESH; void Set_Current_BVP(STD_BVP *theBVP); /****************************************************************************/ /** \brief Initialize a BVP and return a mesh * * @param theHeap - heap * @param MarkKey - use key for temporary memory allocation (do not Mark/Release) Function initialize a BVP and returns a mesh. */ /****************************************************************************/ void BVP_Init (STD_BVP *theBVP, NS_PREFIX HEAP *theHeap, MESH *Mesh, INT MarkKey); /****************************************************************************/ /** \brief Write command to insert this BNDP * * @param theBndP - BNDP structure * @param data - string to store command * @param max_data_size - maximal datasize to use This function writes a command to string which inserts the BNDP. * @return
    *
  • 0 if ok *
  • 1 if error. *
*/ /****************************************************************************/ INT BNDP_SaveInsertedBndP (BNDP *theBndP, char *data, INT max_data_size); /****************************************************************************/ /** \brief Return global coordinates of BNDP * * @param theBndP - BNDP structure * @param global - global coordinates This function returns global coordinates of BNDP * @return
    *
  • 0 if ok
  • *
  • 1 if error.
  • *
*/ /****************************************************************************/ INT BNDP_Global (const BNDP *theBndP, Dune::FieldVector& global); /****************************************************************************/ /** \brief Sets descriptor for BNDP * * @param theBndP - BNDP structure * @param move - movable flag (0: no, 1:yes) This function sets the descriptor for a BNDP. * @return
    *
  • 0 if ok
  • *
  • 1 if error.
  • *
*/ /****************************************************************************/ INT BNDP_BndPDesc (BNDP *theBndP, INT *move); /****************************************************************************/ /** \brief Sets descriptor for BNDE (boundary edge) * * @param theBndP0 - first BNDP * @param theBndP1 - second BNDP This function sets the descriptor for a BNDE. * @return
    *
  • 0 if ok *
  • 1 if error. *
*/ /****************************************************************************/ INT BNDP_BndEDesc (BNDP *theBndP0, BNDP *theBndP1); /****************************************************************************/ /** \brief Creates a BNDS from a nb of BNDPs * * @param Heap - heap to allocate from * @param theBndP - Pointer to list of BNDP structures * @param n - Number of BNDPs This function creates a BNDS from n BNDPs * @return
    *
  • pointer
  • *
  • NULL if the points describe an inner side
  • *
*/ /****************************************************************************/ BNDS* BNDP_CreateBndS (NS_PREFIX HEAP *Heap, BNDP **theBndP, INT n); /****************************************************************************/ /** \brief Sets BNDP from a two of BNDPs * * @param theBndP0 - first BNDP * @param theBndP1 - second BNDP * @param lcoord - local coordinate between P0 and P1 where the BNDP will be created This function sets a BNDP from two BNDPs * @return
    *
  • pointer
  • *
  • NULL if the points describe an inner point
  • *
*/ /****************************************************************************/ BNDP* BNDP_CreateBndP (NS_PREFIX HEAP *Heap, BNDP *theBndP0, BNDP *theBndP1, DOUBLE lcoord); /****************************************************************************/ /** \brief Dispose a BNDP * * @param Heap - heap * @param theBndP - BNDP This function disposes a BNDP * @return
    *
  • 0 if ok
  • *
  • 1 if error.
  • *
*/ /****************************************************************************/ INT BNDP_Dispose (NS_PREFIX HEAP *Heap, BNDP *theBndP); /****************************************************************************/ /** \brief Save a BNDP * * @param theBndP - BNDP * @param stream - file This function saves a BNDP on a file. * @return
    *
  • 0 if ok
  • *
  • 1 if error.
  • *
*/ /****************************************************************************/ INT BNDP_SaveBndP (BNDP *theBndP); INT BNDP_SaveBndP_Ext (BNDP *theBndP); /****************************************************************************/ /** \brief Load a BNDP * * @param theBVP - BVP structure * @param Heap - heap to allocate from * @param stream - file This function loads a BNDP with the format given by BVP_SaveBndP and allocates it from the given heap. * @return
    *
  • 0 if ok
  • *
  • 1 if error.
  • *
*/ /****************************************************************************/ BNDP *BNDP_LoadBndP (STD_BVP *theBVP, NS_PREFIX HEAP *Heap); BNDP *BNDP_LoadBndP_Ext (void); /****************************************************************************/ /** \brief Sets descriptor for BNDS * * @param theBndS - BNDS structure * @param id - subdomain ID of the element with aBndS * @param nbid - subdomain ID of the neighbour element (across the boundary) This function sets the descriptor for a BNDS. * @return
    *
  • 0 if ok
  • *
  • 1 if error.
  • *
*/ /****************************************************************************/ INT BNDS_BndSDesc (BNDS *theBndS, INT *id, INT *nbid); /****************************************************************************/ /** \brief Create BNDP on BNDS * * @param Heap - heap to allocate from * @param theBndS - BNDS structure * @param local - local coordinate on BNDS This function creates a boundary point (BNDP) on a BNDS * @return
    *
  • 0 if ok
  • *
  • 1 if error.
  • *
*/ /****************************************************************************/ BNDP* BNDS_CreateBndP (NS_PREFIX HEAP *Heap, BNDS *theBndS, const FieldVector& local); /****************************************************************************/ /** \brief Dispose BNDS * * @param Heap - heap * @param theBndS - BNDS struct This function disposes a BNDS * @return
    *
  • 0 if ok
  • *
  • 1 if error.
  • *
*/ /****************************************************************************/ INT BNDS_Dispose (NS_PREFIX HEAP *Heap, BNDS *theBndS); /****************************************************************************/ /** \brief Gets surface ids for a BNDP * * @param aBndP - BNDP structure * @param i - evaluate on patch i * @param n - number of BNDS This function returns surface ids of the n surfaces on which the BNDP resides * @return surface id */ /****************************************************************************/ INT BNDP_SurfaceId (BNDP *aBndP, INT *n, INT i); #ifdef ModelP void DomInitParallel (INT TypeBndP, INT TypeBndS); void DomHandlerInit (INT handlerSet); void BElementXferBndS (DDD::DDDContext& context, BNDS **bnds, int n, int proc, int prio); void BElementGatherBndS (BNDS **bnds, int n, int cnt, char *data); void BElementScatterBndS (const DDD::DDDContext& context, BNDS **bnds, int n, int cnt, char *data); void BVertexXferBndP (DDD::DDDContext& context, BNDP *bndp, int proc, int prio); void BVertexGatherBndP (BNDP *bndp, int cnt, char *data); void BVertexScatterBndP (const DDD::DDDContext& context, BNDP **bndp, int cnt, char *data); #endif END_UGDIM_NAMESPACE /** @} */ #endif dune-uggrid-2.11.0+dfsg/dune/uggrid/domain/std_parallel.cc000066400000000000000000000154401513616443000233730ustar00rootroot00000000000000// SPDX-FileCopyrightText: Copyright © DUNE Project contributors, see file LICENSE.md in module root // SPDX-License-Identifier: LGPL-2.1-or-later // -*- tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- // vi: set et ts=4 sw=2 sts=2: /****************************************************************************/ /* */ /* File: std_parallel.c */ /* */ /* Purpose: parallel part of standard ug domain description */ /* */ /* Author: Klaus Birken / Christian Wieners */ /* Institut fuer Computeranwendungen III */ /* Universitaet Stuttgart */ /* Pfaffenwaldring 27 */ /* 70550 Stuttgart */ /* email: ug@ica3.uni-stuttgart.de */ /* */ /* History: Sep 12 1996 ug version 3.4 */ /* */ /* Remarks: */ /* */ /****************************************************************************/ #ifdef ModelP /****************************************************************************/ /* */ /* include files */ /* system include files */ /* application include files */ /* */ /****************************************************************************/ /* standard C library */ #include #include #include #include #include #include /* low modules */ #include #include #include #include #include /* parallel modules */ #include #include /* domain module */ #include "std_domain.h" USING_UGDIM_NAMESPACE USING_UG_NAMESPACE #ifdef ModelP using namespace PPIF; #endif /****************************************************************************/ /* */ /* defines in the following order */ /* */ /* compile time constants defining static data size (i.e. arrays) */ /* other constants */ /* macros */ /* */ /****************************************************************************/ #define CEIL(n) ((n)+((ALIGNMENT-((n)&(ALIGNMENT-1)))&(ALIGNMENT-1))) /****************************************************************************/ /* */ /* data structures used in this source file (exported data structures are */ /* in the corresponding include file!) */ /* */ /****************************************************************************/ /****************************************************************************/ /* */ /* definition of exported global variables */ /* */ /****************************************************************************/ /****************************************************************************/ /* */ /* definition of variables global to this source file only (static!) */ /* */ /****************************************************************************/ /****************************************************************************/ /* */ /* forward declarations of functions used before they are defined */ /* */ /****************************************************************************/ void NS_DIM_PREFIX DomInitParallel (INT TypeBndP, INT TypeBndS) {} void NS_DIM_PREFIX DomHandlerInit (INT handlerSet) {} void NS_DIM_PREFIX BElementXferBndS(DDD::DDDContext& context, BNDS **bnds, int n, int proc, int prio) { INT size,i,size0; size = CEIL(sizeof(INT)); for (i=0; i #include #include #include #include #include "GenerateRules.h" #include "gm.h" #include "simplex.h" #include "ugrefine3d.h" #include /* only compile for 3D version */ #ifdef UG_DIM_3 /****************************************************************************/ /* */ /* defines and macros */ /* */ /****************************************************************************/ #define PATTERNFILTER 0x3F /* mask for the first 6 digits of pattern: 00111111 */ #define NOFATHERSIDE 5 /* has to be just greater than MAX_SIDES_OF_ELEM */ #define NRULES 242 #define MAXCORNERS 11 /* max no. of new corners (incl. center) */ #define NOTDONE -1 /* SHORT has to be signed! */ #define DONE 0 #define TOUCHED 1 /* has been visited by FindPathForNeighbours*/ /****************************************************************************/ /* */ /* data structures used in this source file (exported data structures are */ /* in the corresponding include file!) */ /* */ /****************************************************************************/ /****************************************************************************/ /* */ /* global variables */ /* */ /****************************************************************************/ static EDGEDATA EdgeData[MAXCORNERS][MAXCORNERS] = { {{0,0,0,0},{0,0,1,0},{0,0,2,0},{0,0,3,0},{0,0,4,0},{2,0,5,0},{0,0,6,0},{0,0,7,0},{2,0,8,3},{2,0,9,2},{1,0,10,0}}, {{0,0,1,0},{0,1,1,0},{0,1,2,0},{0,1,3,0},{0,1,4,0},{0,1,5,0},{2,1,6,0},{2,1,7,3},{0,1,8,0},{2,1,9,1},{1,1,10,0}}, {{0,0,2,0},{0,1,2,0},{0,2,2,0},{0,2,3,0},{2,2,4,0},{0,2,5,0},{0,2,6,0},{2,2,7,2},{2,2,8,1},{0,2,9,0},{1,2,10,0}}, {{0,0,3,0},{0,1,3,0},{0,2,3,0},{0,3,3,0},{2,3,4,3},{2,3,5,1},{2,3,6,2},{0,3,7,0},{0,3,8,0},{0,3,9,0},{1,3,10,0}}, {{0,0,4,0},{0,1,4,0},{2,2,4,0},{2,3,4,3},{0,4,4,0},{2,4,5,0},{2,4,6,0},{2,4,7,3},{2,4,8,3},{1,4,9,0},{1,4,10,0}}, {{2,0,5,0},{0,1,5,0},{0,2,5,0},{2,3,5,1},{2,4,5,0},{0,5,5,0},{2,5,6,0},{1,5,7,0},{2,5,8,1},{2,5,9,1},{1,5,10,0}}, {{0,0,6,0},{2,1,6,0},{0,2,6,0},{2,3,6,2},{2,4,6,0},{2,5,6,0},{0,6,6,0},{2,6,7,2},{1,6,8,0},{2,6,9,2},{1,6,10,0}}, {{0,0,7,0},{2,1,7,3},{2,2,7,2},{0,3,7,0},{2,4,7,3},{1,5,7,0},{2,6,7,2},{0,7,7,0},{2,7,8,3},{2,7,9,2},{1,7,10,0}}, {{2,0,8,3},{0,1,8,0},{2,2,8,1},{0,3,8,0},{2,4,8,3},{2,5,8,1},{1,6,8,0},{2,7,8,3},{0,8,8,0},{2,8,9,1},{1,8,10,0}}, {{2,0,9,2},{2,1,9,1},{0,2,9,0},{0,3,9,0},{1,4,9,0},{2,5,9,1},{2,6,9,2},{2,7,9,2},{2,8,9,1},{0,9,9,0},{1,9,10,0}}, {{1,0,10,0},{1,1,10,0},{1,2,10,0},{1,3,10,0},{1,4,10,0},{1,5,10,0},{1,6,10,0},{1,7,10,0},{1,8,10,0},{1,9,10,0},{0,10,10,0}} }; static SHORT CornerOfSonSide[MAX_SIDES_OF_ELEM][3] = {{0,1,2},{1,2,3},{0,2,3},{0,1,3}}; static SHORT IsOnSide[MAX_SIDES_OF_ELEM][MAXCORNERS] = {{1,1,1,0,1,1,1,0,0,0,0}, {0,1,1,1,0,1,0,0,1,1,0}, {1,0,1,1,0,0,1,1,0,1,0}, {1,1,0,1,1,0,0,1,1,0,0}}; static int nRulesTh; /* total number of theoretical refinement rules */ static int nRules; /* total number of generated refinement rules */ static int FirstRuleWithEdgePattern; /* Rule no. of first of several SidePatterns */ static REFRULE *RuleList; /* list is allocated in main program */ static SHORT *PatternToRefrule; /* vector is allocated in main program */ static bool Output; /* if true output of generated rules */ /* prototype for new rules without any data */ static REFRULE EmptyRule = {0,{0,0,0,0,0,0},0,{{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0}}, {{0,0,0,0},{0,0,0,0},{0,0,0,0},{0,0,0,0}, {0,0,0,0},{0,0,0,0},{0,0,0,0},{0,0,0,0}, {0,0,0,0},{0,0,0,0},{0,0,0,0},{0,0,0,0}, {0,0,0,0},{0,0,0,0},{0,0,0,0},{0,0,0,0}}, {{{0,0,0,0},{NOTDONE,NOTDONE,NOTDONE,NOTDONE},0}, {{0,0,0,0},{NOTDONE,NOTDONE,NOTDONE,NOTDONE},0}, {{0,0,0,0},{NOTDONE,NOTDONE,NOTDONE,NOTDONE},0}, {{0,0,0,0},{NOTDONE,NOTDONE,NOTDONE,NOTDONE},0}, {{0,0,0,0},{NOTDONE,NOTDONE,NOTDONE,NOTDONE},0}, {{0,0,0,0},{NOTDONE,NOTDONE,NOTDONE,NOTDONE},0}, {{0,0,0,0},{NOTDONE,NOTDONE,NOTDONE,NOTDONE},0}, {{0,0,0,0},{NOTDONE,NOTDONE,NOTDONE,NOTDONE},0}, {{0,0,0,0},{NOTDONE,NOTDONE,NOTDONE,NOTDONE},0}, {{0,0,0,0},{NOTDONE,NOTDONE,NOTDONE,NOTDONE},0}, {{0,0,0,0},{NOTDONE,NOTDONE,NOTDONE,NOTDONE},0}, {{0,0,0,0},{NOTDONE,NOTDONE,NOTDONE,NOTDONE},0}}}; /****************************************************************************/ /* */ /* functions */ /* */ /****************************************************************************/ static SHORT SideWithCorners (SHORT C0,SHORT C1,SHORT C2) { SHORT Side; for (Side=0; Sidensons; i++) for (theSon = theRule->sons+i, j=0; jcorners[j] = ReplaceBy[theSon->corners[j]]; return (0); } static int PrintRule (REFRULE *theRule, SHORT nEdges) { SHORT i,j; printf("nsons %d; pattern %d%d%d%d%d%d; ",(int)theRule->nsons, (int)theRule->pattern[5], (int)theRule->pattern[4], (int)theRule->pattern[3], (int)theRule->pattern[2], (int)theRule->pattern[1], (int)theRule->pattern[0]); printf("pat %#04x; (nedges %d)\n",(int)theRule->pat,(int)nEdges); printf("edges: "); for (i=0; i<8; i++) printf("{%d,%d,%d,%d}",(int)theRule->edges[i].type,(int)theRule->edges[i].from, (int)theRule->edges[i].to,(int)theRule->edges[i].side); printf("\n\t"); for (; iedges[i].type,(int)theRule->edges[i].from, (int)theRule->edges[i].to,(int)theRule->edges[i].side); printf("\nsons: "); for (i=0; i<6; i++) printf("{{%d,%d,%d,%d}{%d,%d,%d,%d}}",(int)theRule->sons[i].corners[0],(int)theRule->sons[i].corners[1], (int)theRule->sons[i].corners[2],(int)theRule->sons[i].corners[3], (int)theRule->sons[i].nb[0],(int)theRule->sons[i].nb[1], (int)theRule->sons[i].nb[2],(int)theRule->sons[i].nb[3]); printf("\n\t"); for (; isons[i].corners[0],(int)theRule->sons[i].corners[1], (int)theRule->sons[i].corners[2],(int)theRule->sons[i].corners[3], (int)theRule->sons[i].nb[0],(int)theRule->sons[i].nb[1], (int)theRule->sons[i].nb[2],(int)theRule->sons[i].nb[3]); for (i=1; insons; i++) { printf("\npath to %d: son0",i); for (j=0; jsons[i].path); j++) printf("-->nb%d",(int) NEXTSIDE(theRule->sons[i].path,j)); printf(" (%d steps)",(int) PATHDEPTH(theRule->sons[i].path)); } printf("\nsonandnode:"); for (i=0; i(%d,%d)",(int)(i+CORNERS_OF_ELEM),(int)theRule->sonandnode[i][0],(int)theRule->sonandnode[i][1]); printf("\n"); return (0); } static int CopySonsIntoRule (REFRULE *theRule,SONDATA sons[SONS]) { SHORT i; for (i=0; isons[i] = sons[i]; return (0); } static int CompareEdgesForSides (const void *Edge1, const void *Edge2) { EDGEDATA *theEdge1,*theEdge2; theEdge1 = (EDGEDATA *) Edge1; theEdge2 = (EDGEDATA *) Edge2; /* leave type==0 at end of the list */ if ((theEdge1->type)==0) return (1); if ((theEdge2->type)==0) return (-1); if ((theEdge1->side)==(theEdge2->side)) return (0); else if ((theEdge1->side)>(theEdge2->side)) return (1); else return (-1); } static int CompareEdges (const void *theEdge1, const void *theEdge2) { if (((EDGEDATA *)theEdge1)->from==((EDGEDATA *)theEdge2)->from) { if (((EDGEDATA *)theEdge1)->to>((EDGEDATA *)theEdge2)->to) return (1); else if (((EDGEDATA *)theEdge1)->to<((EDGEDATA *)theEdge2)->to) return (-1); else return (0); } else if (((EDGEDATA *)theEdge1)->from>((EDGEDATA *)theEdge2)->from) return (1); else return (-1); } static int CompareCorners (const void *theCorner1, const void *theCorner2) { SHORT C1,C2; C1 = * ((SHORT *) theCorner1); C2 = * ((SHORT *) theCorner2); assert(C1!=C2); if (C1>C2) return (1); else return (-1); } static int NewEdgesAreEqual (EDGEDATA *NewEdges0, EDGEDATA *NewEdges1) { SHORT i; for (i=0; isons[myID].nb[i])sons[nbID].path); /* copy myPath to nbPath */ *nbPath = theRule->sons[myID].path; /* complete nbPath */ nbPATHDEPTH = PATHDEPTH(*nbPath); SETNEXTSIDE(*nbPath,nbPATHDEPTH,i); SETPATHDEPTH(*nbPath,++nbPATHDEPTH); Status[nbID] = TOUCHED; } /* recursive call for TOUCHED sons */ for (nbID=1; nbIDnsons; nbID++) if (Status[nbID]==TOUCHED) { Status[nbID] = DONE; FindPathForNeighbours (theRule,nbID,Status); } return (0); } /****************************************************************************/ /* */ /* AddRuleIfNew */ /* called by most of the main functions */ /* */ /* the additional data fields of the refrule are filled and the */ /* rule is stored if not already there */ /* */ /****************************************************************************/ static int AddRuleIfNew (REFRULE *theRule) { EDGEDATA theEdgeData,*InnerEdge[2]; SONDATA *SONi,*SONj,*theSon; SHORT i,j,nEdges,theEdge,FatherSide,newcorner,corner,son,edge,found,SidePattern; SHORT SIDEi,SIDEj,side,SideBit,Status[SONS]; assert(nRules 3) and fill edges field */ nEdges = 0; for (son=0; sonnsons; son++) for (i=0; isons[son].corners[i]] [theRule->sons[son].corners[j]]).type) { /* (From,To) is a new edge: already stored? */ for (theEdge=0; theEdgeedges[theEdge].from==theEdgeData.from)&&(theRule->edges[theEdge].to==theEdgeData.to)) break; if (theEdge>=nEdges) theRule->edges[nEdges++] = theEdgeData; } /* sort edges for corner IDs (necessary for fast comparison of SidePatterns) */ qsort((void *)theRule->edges,nEdges,sizeof(EDGEDATA),CompareEdges); /* if this SidePattern is not already in RuleList: store it */ for (i=FirstRuleWithEdgePattern; iedges,RuleList[i].edges)) break; if (insons; i++) qsort((void *)theRule->sons[i].corners,4,sizeof(SHORT),CompareCorners); /* fill entries of nb field in the SONDATA */ for (i=0; insons; i++) for (SONi=theRule->sons+i, SIDEi=0; SIDEinb[SIDEi] == NOTDONE) { /* outer face? */ if ((FatherSide=SideWithCorners(SONi->corners[CornerOfSonSide[SIDEi][0]], SONi->corners[CornerOfSonSide[SIDEi][1]], SONi->corners[CornerOfSonSide[SIDEi][2]]))!=NOFATHERSIDE) { SONi->nb[SIDEi] = FatherSide; continue; } for (j=i+1; jnsons; j++) for (SONj=theRule->sons+j, SIDEj=0; SIDEjcorners[CornerOfSonSide[SIDEi][0]]==SONj->corners[CornerOfSonSide[SIDEj][0]]) && (SONi->corners[CornerOfSonSide[SIDEi][1]]==SONj->corners[CornerOfSonSide[SIDEj][1]]) && (SONi->corners[CornerOfSonSide[SIDEi][2]]==SONj->corners[CornerOfSonSide[SIDEj][2]])) { /* neighbour found */ SONi->nb[SIDEi] = j; SONj->nb[SIDEj] = i; j=SONS; break; } } /* clear the remaining NOTDONEs */ for (i=theRule->nsons; isons+i, SIDEi=0; SIDEinb[SIDEi] = 0; /* fill the sonandnode field */ for (newcorner=0; newcornersonandnode[newcorner][0] = NOTUSED; for (newcorner=CORNERS_OF_ELEM; newcorner<(NEWCORNERS+CORNERS_OF_ELEM); newcorner++) for (son=0; sonsons+son, corner=0; cornercorners[corner]==newcorner) { theRule->sonandnode[newcorner-CORNERS_OF_ELEM][0] = son; theRule->sonandnode[newcorner-CORNERS_OF_ELEM][1] = corner; son = SONS; break; } /* make a consistence check: newcorners in sondata indicate the refined edges */ for (newcorner=0; newcornersonandnode[newcorner][0]==NOTUSED) { assert(theRule->pattern[newcorner]==0); assert((theRule->pat & (1<pattern[newcorner]==1); assert((theRule->pat & (1<0); } /* find the SidePattern of theRule */ SidePattern = 0; for (side=0; sidepat & CondensedEdgeOfSide[side]][0] >= 0) { /* here we have a side with a trisection edge */ for (found=0, edge=0; edgeedges[edge].type==2) && (theRule->edges[edge].side==side)) { /* we have an inner edge of side (which has a trisection node) */ InnerEdge[found++] = theRule->edges+edge; } assert(found==2); if (InnerEdge[0]->from==InnerEdge[1]->from) theEdge = InnerEdge[0]->from - CORNERS_OF_ELEM; else if (InnerEdge[0]->from==InnerEdge[1]->to) theEdge = InnerEdge[0]->from - CORNERS_OF_ELEM; else if (InnerEdge[0]->to==InnerEdge[1]->from) theEdge = InnerEdge[0]->to - CORNERS_OF_ELEM; else if (InnerEdge[0]->to==InnerEdge[1]->to) theEdge = InnerEdge[0]->to - CORNERS_OF_ELEM; else assert(0); if (TriSectionEdge[theRule->pat & CondensedEdgeOfSide[side]][0] == theEdge) SideBit = 0; else if (TriSectionEdge[theRule->pat & CondensedEdgeOfSide[side]][1] == theEdge) SideBit = 1; else assert(0); if (SideBit) SidePattern |= (1<nsons; i++) Status[i] = NOTDONE; FindPathForNeighbours (theRule,0,Status); /* put the new rule into the RuleList */ PatternToRefrule[theRule->pat | (SidePattern<=0; found--) BisectSon(SonID[found],CornerID0[found],CornerID1[found],theEdge,theNewRule.sons,theNewRule.nsons++); /* recursively refine the remaining edges: */ EdgePattern[theEdge] = 0; BisectEdge(EdgePattern,theNewRule); EdgePattern[theEdge] = 1; } if (nEdges==0) AddRuleIfNew(&theRule); return (0); } /****************************************************************************/ /****************************************************************************/ /* */ /* main functions: */ /* MakeRule... */ /* */ /* the Rules refining n edges are generated */ /* */ /****************************************************************************/ /****************************************************************************/ /****************************************************************************/ /* */ /* MakeRuleByBisection */ /* generates rules by recursive bisection of the father */ /* */ /****************************************************************************/ static int MakeRuleByBisection (SHORT pattern) { REFRULE NewRule; SONDATA father = {{0,1,2,3},{NOTDONE,NOTDONE,NOTDONE,NOTDONE}}; SHORT EdgePattern[EDGES],RefEdgesPerSide[MAX_SIDES_OF_ELEM]; SHORT i,nTrapezoid; NewRule = EmptyRule; NewRule.nsons = 1; NewRule.sons[0] = father; NewRule.pat = pattern; /* make extended pattern */ for (i=0; i0); /* find the number of trapezoids for check purposes */ for (i=0; i %d SidePatterns\n",(int)nTrapezoid,(int)(1<0); if (AddRuleIfNew(&theRule)==1) printf("MakeRule3: already there\n"); } return (1); } else { printf(" rule 3: 3 on one side: 1 Rule\n"); nRulesTh += 1; theRule = EmptyRule; theRule.nsons = 4; CopySonsIntoRule(&theRule,SidePrototype); if (Rot!=IDENTITY) RotateCorners(&theRule,Rot); theRule.pat = pattern; /* fill extended pattern */ for (j=0; j0); if (AddRuleIfNew(&theRule)==1) printf("MakeRule3: already there\n"); return (0); } } #define RULE4CORNER 1 #define RULE4CORNER_PROTO 4 #define RULE4PLANE 2 #define RULE4PLANE_PROTO 2 static int MakeRule4 (SHORT pattern) { SONDATA CornerPrototype[RULE4CORNER_PROTO][SONS] = { {{{0,4,6,7},{NOTDONE,NOTDONE,NOTDONE,NOTDONE},0}, {{5,4,6,7},{NOTDONE,NOTDONE,NOTDONE,NOTDONE},0}, {{3,4,7,5},{NOTDONE,NOTDONE,NOTDONE,NOTDONE},0}, {{3,4,1,5},{NOTDONE,NOTDONE,NOTDONE,NOTDONE},0}, {{6,3,7,5},{NOTDONE,NOTDONE,NOTDONE,NOTDONE},0}, {{6,3,2,5},{NOTDONE,NOTDONE,NOTDONE,NOTDONE},0}, {{0,0,0,0},{NOTDONE,NOTDONE,NOTDONE,NOTDONE},0}, {{0,0,0,0},{NOTDONE,NOTDONE,NOTDONE,NOTDONE},0}, {{0,0,0,0},{NOTDONE,NOTDONE,NOTDONE,NOTDONE},0}, {{0,0,0,0},{NOTDONE,NOTDONE,NOTDONE,NOTDONE},0}, {{0,0,0,0},{NOTDONE,NOTDONE,NOTDONE,NOTDONE},0}, {{0,0,0,0},{NOTDONE,NOTDONE,NOTDONE,NOTDONE},0}}, {{{0,4,6,7},{NOTDONE,NOTDONE,NOTDONE,NOTDONE},0}, {{5,4,6,7},{NOTDONE,NOTDONE,NOTDONE,NOTDONE},0}, {{3,4,7,5},{NOTDONE,NOTDONE,NOTDONE,NOTDONE},0}, {{3,4,1,5},{NOTDONE,NOTDONE,NOTDONE,NOTDONE},0}, {{2,7,3,5},{NOTDONE,NOTDONE,NOTDONE,NOTDONE},0}, {{2,7,6,5},{NOTDONE,NOTDONE,NOTDONE,NOTDONE},0}, {{0,0,0,0},{NOTDONE,NOTDONE,NOTDONE,NOTDONE},0}, {{0,0,0,0},{NOTDONE,NOTDONE,NOTDONE,NOTDONE},0}, {{0,0,0,0},{NOTDONE,NOTDONE,NOTDONE,NOTDONE},0}, {{0,0,0,0},{NOTDONE,NOTDONE,NOTDONE,NOTDONE},0}, {{0,0,0,0},{NOTDONE,NOTDONE,NOTDONE,NOTDONE},0}, {{0,0,0,0},{NOTDONE,NOTDONE,NOTDONE,NOTDONE},0}}, {{{0,4,6,7},{NOTDONE,NOTDONE,NOTDONE,NOTDONE},0}, {{5,4,6,7},{NOTDONE,NOTDONE,NOTDONE,NOTDONE},0}, {{1,7,4,5},{NOTDONE,NOTDONE,NOTDONE,NOTDONE},0}, {{1,7,3,5},{NOTDONE,NOTDONE,NOTDONE,NOTDONE},0}, {{2,7,3,5},{NOTDONE,NOTDONE,NOTDONE,NOTDONE},0}, {{2,7,6,5},{NOTDONE,NOTDONE,NOTDONE,NOTDONE},0}, {{0,0,0,0},{NOTDONE,NOTDONE,NOTDONE,NOTDONE},0}, {{0,0,0,0},{NOTDONE,NOTDONE,NOTDONE,NOTDONE},0}, {{0,0,0,0},{NOTDONE,NOTDONE,NOTDONE,NOTDONE},0}, {{0,0,0,0},{NOTDONE,NOTDONE,NOTDONE,NOTDONE},0}, {{0,0,0,0},{NOTDONE,NOTDONE,NOTDONE,NOTDONE},0}, {{0,0,0,0},{NOTDONE,NOTDONE,NOTDONE,NOTDONE},0}}, {{{0,4,6,7},{NOTDONE,NOTDONE,NOTDONE,NOTDONE},0}, {{5,4,6,7},{NOTDONE,NOTDONE,NOTDONE,NOTDONE},0}, {{1,7,4,5},{NOTDONE,NOTDONE,NOTDONE,NOTDONE},0}, {{1,7,3,5},{NOTDONE,NOTDONE,NOTDONE,NOTDONE},0}, {{6,3,7,5},{NOTDONE,NOTDONE,NOTDONE,NOTDONE},0}, {{6,3,2,5},{NOTDONE,NOTDONE,NOTDONE,NOTDONE},0}, {{0,0,0,0},{NOTDONE,NOTDONE,NOTDONE,NOTDONE},0}, {{0,0,0,0},{NOTDONE,NOTDONE,NOTDONE,NOTDONE},0}, {{0,0,0,0},{NOTDONE,NOTDONE,NOTDONE,NOTDONE},0}, {{0,0,0,0},{NOTDONE,NOTDONE,NOTDONE,NOTDONE},0}, {{0,0,0,0},{NOTDONE,NOTDONE,NOTDONE,NOTDONE},0}, {{0,0,0,0},{NOTDONE,NOTDONE,NOTDONE,NOTDONE},0}} }; SONDATA PlanePrototype[RULE4PLANE_PROTO][SONS] = { {{{1,8,5,10},{NOTDONE,NOTDONE,NOTDONE,NOTDONE},0}, {{1,8,7,10},{NOTDONE,NOTDONE,NOTDONE,NOTDONE},0}, {{0,6,5,10},{NOTDONE,NOTDONE,NOTDONE,NOTDONE},0}, {{0,6,7,10},{NOTDONE,NOTDONE,NOTDONE,NOTDONE},0}, {{0,1,5,10},{NOTDONE,NOTDONE,NOTDONE,NOTDONE},0}, {{0,1,7,10},{NOTDONE,NOTDONE,NOTDONE,NOTDONE},0}, {{2,5,6,10},{NOTDONE,NOTDONE,NOTDONE,NOTDONE},0}, {{2,5,8,10},{NOTDONE,NOTDONE,NOTDONE,NOTDONE},0}, {{3,7,6,10},{NOTDONE,NOTDONE,NOTDONE,NOTDONE},0}, {{3,7,8,10},{NOTDONE,NOTDONE,NOTDONE,NOTDONE},0}, {{3,2,8,10},{NOTDONE,NOTDONE,NOTDONE,NOTDONE},0}, {{3,2,6,10},{NOTDONE,NOTDONE,NOTDONE,NOTDONE},0}}, {{{1,5,6,10},{NOTDONE,NOTDONE,NOTDONE,NOTDONE},0}, {{1,5,8,10},{NOTDONE,NOTDONE,NOTDONE,NOTDONE},0}, {{0,7,6,10},{NOTDONE,NOTDONE,NOTDONE,NOTDONE},0}, {{0,7,8,10},{NOTDONE,NOTDONE,NOTDONE,NOTDONE},0}, {{0,1,6,10},{NOTDONE,NOTDONE,NOTDONE,NOTDONE},0}, {{0,1,8,10},{NOTDONE,NOTDONE,NOTDONE,NOTDONE},0}, {{2,6,5,10},{NOTDONE,NOTDONE,NOTDONE,NOTDONE},0}, {{2,6,7,10},{NOTDONE,NOTDONE,NOTDONE,NOTDONE},0}, {{3,8,5,10},{NOTDONE,NOTDONE,NOTDONE,NOTDONE},0}, {{3,8,7,10},{NOTDONE,NOTDONE,NOTDONE,NOTDONE},0}, {{2,3,5,10},{NOTDONE,NOTDONE,NOTDONE,NOTDONE},0}, {{2,3,7,10},{NOTDONE,NOTDONE,NOTDONE,NOTDONE},0}} }; SHORT *Rot0,*Rot1; REFRULE theRule; SHORT i,j,theRule4; if ((pattern&0x0D)==0x0D) switch (pattern&~0x0D) /* corner 0 */ { case (1<<1) : Rot0 = IDENTITY; Rot1 = IDENTITY; theRule4 = RULE4CORNER; break; case (1<<4) : Rot0 = IDENTITY; Rot1 = Ax0Left; theRule4 = RULE4CORNER; break; case (1<<5) : Rot0 = IDENTITY; Rot1 = Ax0Right; theRule4 = RULE4CORNER; break; } else if ((pattern&0x13)==0x13) switch (pattern&~0x13) /* corner 1 */ { case (1<<2) : Rot0 = Ax3Left; Rot1 = IDENTITY; theRule4 = RULE4CORNER; break; case (1<<3) : Rot0 = Ax3Left; Rot1 = Ax1Right; theRule4 = RULE4CORNER; break; case (1<<5) : Rot0 = Ax3Left; Rot1 = Ax1Left; theRule4 = RULE4CORNER; break; } else if ((pattern&0x26)==0x26) switch (pattern&~0x26) /* corner 2 */ { case (1<<0) : Rot0 = Ax3Right; Rot1 = IDENTITY; theRule4 = RULE4CORNER; break; case (1<<3) : Rot0 = Ax3Right; Rot1 = Ax2Left; theRule4 = RULE4CORNER; break; case (1<<4) : Rot0 = Ax3Right; Rot1 = Ax2Right; theRule4 = RULE4CORNER; break; } else if ((pattern&0x38)==0x38) switch (pattern&~0x38) /* corner 3 */ { case (1<<0) : Rot0 = Ax1Right; Rot1 = IDENTITY; theRule4 = RULE4CORNER; break; case (1<<1) : Rot0 = Ax1Right; Rot1 = Ax3Left; theRule4 = RULE4CORNER; break; case (1<<2) : Rot0 = Ax1Right; Rot1 = Ax3Right; theRule4 = RULE4CORNER; break; } else if (pattern==0x1E) /* plane 5,6,7,8 (011110) */ { Rot0 = IDENTITY; theRule4 = RULE4PLANE; } else if (pattern==0x35) /* plane 4,6,8,9 (110101) */ { Rot0 = Ax3Left; theRule4 = RULE4PLANE; } else if (pattern==0x2B) /* plane 4,5,7,9 (101011) */ { Rot0 = Ax3Right; theRule4 = RULE4PLANE; } else assert(0); /* should not happen */ /* rotate the Prototype son patterns into the pattern position and copy them into the rule */ if (theRule4==RULE4CORNER) { printf(" rule 4: 3 next to one node: 4 Rules\n"); nRulesTh += 4; for (i=0; i0); if (AddRuleIfNew(&theRule)==1) printf("MakeRule4: already there\n"); } return (0); } else { printf(" rule 4: 4 on a plane: 2 Rules\n"); /* nRulesTh += 2; will be counted by MakeRuleByBisection */ for (i=0; i0); if (AddRuleIfNew(&theRule)==1) printf("MakeRule4: already there\n"); } return (1); } } #define RULE5_PROTO 4 static int MakeRule5 (SHORT pattern) { SONDATA CornerPrototype[RULE5_PROTO][SONS] = { {{{3,7,8,9},{NOTDONE,NOTDONE,NOTDONE,NOTDONE},0}, {{2,9,6,5},{NOTDONE,NOTDONE,NOTDONE,NOTDONE},0}, {{6,7,8,9},{NOTDONE,NOTDONE,NOTDONE,NOTDONE},0}, {{5,6,8,9},{NOTDONE,NOTDONE,NOTDONE,NOTDONE},0}, {{0,6,7,8},{NOTDONE,NOTDONE,NOTDONE,NOTDONE},0}, {{0,6,5,8},{NOTDONE,NOTDONE,NOTDONE,NOTDONE},0}, {{0,1,5,8},{NOTDONE,NOTDONE,NOTDONE,NOTDONE},0}, {{0,0,0,0},{NOTDONE,NOTDONE,NOTDONE,NOTDONE},0}, {{0,0,0,0},{NOTDONE,NOTDONE,NOTDONE,NOTDONE},0}, {{0,0,0,0},{NOTDONE,NOTDONE,NOTDONE,NOTDONE},0}, {{0,0,0,0},{NOTDONE,NOTDONE,NOTDONE,NOTDONE},0}, {{0,0,0,0},{NOTDONE,NOTDONE,NOTDONE,NOTDONE},0}}, {{{3,7,8,9},{NOTDONE,NOTDONE,NOTDONE,NOTDONE},0}, {{2,9,6,5},{NOTDONE,NOTDONE,NOTDONE,NOTDONE},0}, {{6,7,8,9},{NOTDONE,NOTDONE,NOTDONE,NOTDONE},0}, {{5,6,8,9},{NOTDONE,NOTDONE,NOTDONE,NOTDONE},0}, {{1,6,8,5},{NOTDONE,NOTDONE,NOTDONE,NOTDONE},0}, {{1,6,8,7},{NOTDONE,NOTDONE,NOTDONE,NOTDONE},0}, {{0,1,6,7},{NOTDONE,NOTDONE,NOTDONE,NOTDONE},0}, {{0,0,0,0},{NOTDONE,NOTDONE,NOTDONE,NOTDONE},0}, {{0,0,0,0},{NOTDONE,NOTDONE,NOTDONE,NOTDONE},0}, {{0,0,0,0},{NOTDONE,NOTDONE,NOTDONE,NOTDONE},0}, {{0,0,0,0},{NOTDONE,NOTDONE,NOTDONE,NOTDONE},0}, {{0,0,0,0},{NOTDONE,NOTDONE,NOTDONE,NOTDONE},0}}, {{{3,7,8,9},{NOTDONE,NOTDONE,NOTDONE,NOTDONE},0}, {{2,9,6,5},{NOTDONE,NOTDONE,NOTDONE,NOTDONE},0}, {{6,7,8,9},{NOTDONE,NOTDONE,NOTDONE,NOTDONE},0}, {{5,6,8,9},{NOTDONE,NOTDONE,NOTDONE,NOTDONE},0}, {{1,6,8,5},{NOTDONE,NOTDONE,NOTDONE,NOTDONE},0}, {{0,1,6,8},{NOTDONE,NOTDONE,NOTDONE,NOTDONE},0}, {{0,7,6,8},{NOTDONE,NOTDONE,NOTDONE,NOTDONE},0}, {{0,0,0,0},{NOTDONE,NOTDONE,NOTDONE,NOTDONE},0}, {{0,0,0,0},{NOTDONE,NOTDONE,NOTDONE,NOTDONE},0}, {{0,0,0,0},{NOTDONE,NOTDONE,NOTDONE,NOTDONE},0}, {{0,0,0,0},{NOTDONE,NOTDONE,NOTDONE,NOTDONE},0}, {{0,0,0,0},{NOTDONE,NOTDONE,NOTDONE,NOTDONE},0}}, {{{3,7,8,9},{NOTDONE,NOTDONE,NOTDONE,NOTDONE},0}, {{2,9,6,5},{NOTDONE,NOTDONE,NOTDONE,NOTDONE},0}, {{9,7,5,8},{NOTDONE,NOTDONE,NOTDONE,NOTDONE},0}, {{9,7,5,6},{NOTDONE,NOTDONE,NOTDONE,NOTDONE},0}, {{0,7,6,5},{NOTDONE,NOTDONE,NOTDONE,NOTDONE},0}, {{0,1,7,5},{NOTDONE,NOTDONE,NOTDONE,NOTDONE},0}, {{1,7,5,8},{NOTDONE,NOTDONE,NOTDONE,NOTDONE},0}, {{0,0,0,0},{NOTDONE,NOTDONE,NOTDONE,NOTDONE},0}, {{0,0,0,0},{NOTDONE,NOTDONE,NOTDONE,NOTDONE},0}, {{0,0,0,0},{NOTDONE,NOTDONE,NOTDONE,NOTDONE},0}, {{0,0,0,0},{NOTDONE,NOTDONE,NOTDONE,NOTDONE},0}, {{0,0,0,0},{NOTDONE,NOTDONE,NOTDONE,NOTDONE},0}} }; SHORT *Rot0,*Rot1; REFRULE theRule; SHORT i,j; printf(" rule 5: 4 Rules\n"); nRulesTh += 4; switch (~pattern&PATTERNFILTER) { case (1<<0) : Rot0 = IDENTITY; Rot1 = IDENTITY; break; /* all but edge 0 (111110) */ case (1<<1) : Rot0 = Ax3Left; Rot1 = IDENTITY; break; /* all but edge 1 (111101) */ case (1<<2) : Rot0 = Ax3Right; Rot1 = IDENTITY; break; /* all but edge 2 (111011) */ case (1<<3) : Rot0 = Ax2Left; Rot1 = IDENTITY; break; /* all but edge 3 (110111) */ case (1<<4) : Rot0 = Ax2Right; Rot1 = IDENTITY; break; /* all but edge 4 (101111) */ case (1<<5) : Rot0 = Ax2Left; Rot1 = Ax1Right; break; /* all but edge 5 (011111) */ default : assert (0); /* should not happen */ } /* rotate the Prototype son patterns into the pattern position and copy them into the rule */ for (i=0; i0); if (AddRuleIfNew(&theRule)==1) printf("MakeRule5: already there\n"); } return (0); } static int MakeRule6 (SHORT pattern) { SONDATA FullRefPrototype[SONS] = {{{0,4,6,7},{NOTDONE,NOTDONE,NOTDONE,NOTDONE},0}, {{4,1,5,8},{NOTDONE,NOTDONE,NOTDONE,NOTDONE},0}, {{6,5,2,9},{NOTDONE,NOTDONE,NOTDONE,NOTDONE},0}, {{7,8,9,3},{NOTDONE,NOTDONE,NOTDONE,NOTDONE},0}, {{4,6,7,8},{NOTDONE,NOTDONE,NOTDONE,NOTDONE},0}, {{4,6,5,8},{NOTDONE,NOTDONE,NOTDONE,NOTDONE},0}, {{6,5,8,9},{NOTDONE,NOTDONE,NOTDONE,NOTDONE},0}, {{6,7,8,9},{NOTDONE,NOTDONE,NOTDONE,NOTDONE},0}, {{0,0,0,0},{0,0,0,0},0}, {{0,0,0,0},{0,0,0,0},0}, {{0,0,0,0},{0,0,0,0},0}, {{0,0,0,0},{0,0,0,0},0}}; REFRULE theRule; SHORT j; printf(" rule 6: 3 Rules\n"); nRulesTh += 3; /* inner edge 6-8 */ theRule = EmptyRule; theRule.nsons = 8; theRule.pat = pattern; for (j=0; j0); CopySonsIntoRule(&theRule,FullRefPrototype); AddRuleIfNew(&theRule); /* inner edge 4-9 */ theRule = EmptyRule; theRule.nsons = 8; theRule.pat = pattern; for (j=0; j0); CopySonsIntoRule(&theRule,FullRefPrototype); RotateCorners(&theRule,Ax1Left); FirstRuleWithEdgePattern = nRules; AddRuleIfNew(&theRule); /* inner edge 5-7 */ theRule = EmptyRule; theRule.nsons = 8; theRule.pat = pattern; for (j=0; j0); CopySonsIntoRule(&theRule,FullRefPrototype); RotateCorners(&theRule,Ax1Right); FirstRuleWithEdgePattern = nRules; AddRuleIfNew(&theRule); /* reset PatternToRefrule[111111] to the first of the FullRefRules */ PatternToRefrule[pattern] = nRules-3; return (0); } int main ([[maybe_unused]] int argc, [[maybe_unused]] char **argv) { FILE *stream; SHORT pattern,nRefEdge,nRE,i; int MINnRefEdge,MAXnRefEdge,j,err,SaveList; MINnRefEdge = 0; MAXnRefEdge = EDGES; Output = false; SaveList = 1; #ifdef TEST_GR if (argc<3) { printf("usage: GenerateRules [-o] [-s]\n"); return (1); } /* scan args for options */ if (sscanf(argv[1],"%d",&MINnRefEdge)!=1) return (1); if (sscanf(argv[2],"%d",&MAXnRefEdge)!=1) return (1); for (i=3; iEDGES)) { printf("ERROR: min # of refined edges out of range\n"); return (1); } if ((MAXnRefEdge<0) || (MAXnRefEdge>EDGES)) { printf("ERROR: min # of refined edges out of range\n"); return (1); } if (MAXnRefEdge max\n"); return (1); } /* get storage for RuleList */ RuleList = (REFRULE *) malloc(NRULES*sizeof(REFRULE)); if (RuleList==NULL) { printf("ERROR: no storage for RuleList\n"); return (1); } /* get storage for PatternToRefrule */ PatternToRefrule = (SHORT *) malloc((1<<(EDGES+MAX_SIDES_OF_ELEM))*sizeof(SHORT)); if (PatternToRefrule==NULL) { printf("ERROR: no storage for PatternToRefrule\n"); return (1); } for (j=0; j<(1<<(EDGES+MAX_SIDES_OF_ELEM)); j++) PatternToRefrule[j] = NOTUSED; nRules = nRulesTh = 0; for (nRefEdge=MINnRefEdge; nRefEdge<=MAXnRefEdge; nRefEdge++) { printf("\n### %d refined edges ###\n",(int)nRefEdge); for (pattern=0; pattern < (1<0; /* take only pattern with nRE==nRefEdge */ if (nRE!=nRefEdge) continue; /* set begin of possibly identical SidePatterns for AddRuleIfNew () */ FirstRuleWithEdgePattern = nRules; for (i=0; i0)); switch (nRefEdge) { case 0 : MakeRule0(pattern); break; case 1 : MakeRuleByBisection(pattern); break; case 2 : MakeRuleByBisection(pattern); break; case 3 : if (MakeRule3(pattern)) MakeRuleByBisection(pattern); break; case 4 : if (MakeRule4(pattern)) MakeRuleByBisection(pattern); break; case 5 : MakeRule5(pattern); break; case 6 : MakeRule6(pattern); break; } } } /* sort edges for sides (necessary for ugrefine) */ for (i=2; i RefRules */ if (err!=1) goto exit; fclose(stream); printf("\nRuleList saved to 'RefRules.data'\n"); } printf("\n######## DONE #########\n"); return (0); exit: fclose(stream); return (1); } #endif dune-uggrid-2.11.0+dfsg/dune/uggrid/gm/GenerateRules.h000066400000000000000000000143441513616443000224720ustar00rootroot00000000000000// -*- tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- // vi: set et ts=4 sw=2 sts=2: // SPDX-FileCopyrightInfo: Copyright © DUNE Project contributors, see file LICENSE.md in module root // SPDX-License-Identifier: LGPL-2.1-or-later /*! \file GenerateRules.h * \ingroup gm */ /****************************************************************************/ /* */ /* File: GenerateRules.h */ /* */ /* Purpose: header file for GenerateRules.c */ /* */ /* Author: Henrik Reichert */ /* Institut fuer Angewandte Mathematik */ /* Universitaet Heidelberg */ /* Im Neuenheimer Feld 294 */ /* 6900 Heidelberg */ /* */ /* History: 10.9.1993 begin */ /* */ /****************************************************************************/ /****************************************************************************/ /* */ /* auto include mechanism and other include files */ /* */ /****************************************************************************/ #ifndef __RULEGEN__ #define __RULEGEN__ #include /****************************************************************************/ /* */ /* defines in the following order */ /* */ /* compile time constants defining static data size (i.e. arrays) */ /* other constants */ /* macros */ /* */ /****************************************************************************/ /* macros for referencing of sons */ /* 4 high bits for no of neighbours to be passed */ #define PATHDEPTHMASK 0xF0000000 #define PATHDEPTHSHIFT 28 #define PATHDEPTH(i) (((i) & PATHDEPTHMASK)>>PATHDEPTHSHIFT) #define SETPATHDEPTH(i,val) (i) = ((i)&(~PATHDEPTHMASK))|(((val)<>(2*(n))) #define SETNEXTSIDE(i,n,val) (i) = ((i)&(~(NEXTSIDEMASK<<(2*(n)))))|(((val)&NEXTSIDEMASK)<<(2*(n))) /****************************************************************************/ /* */ /* data structures exported by the corresponding source file */ /* */ /****************************************************************************/ /****************************************************************************/ /* */ /* definition of exported global variables */ /* */ /****************************************************************************/ /****************************************************************************/ /* */ /* function declarations */ /* */ /****************************************************************************/ #endif dune-uggrid-2.11.0+dfsg/dune/uggrid/gm/RefRules.cc000066400000000000000000011717431513616443000216220ustar00rootroot00000000000000// SPDX-FileCopyrightText: Copyright © DUNE Project contributors, see file LICENSE.md in module root // SPDX-License-Identifier: LGPL-2.1-or-later // This file was generated by "gm/rm3-writeRefRules2file" static const std::size_t nTetrahedronRefinementRules = 242; static REFRULE tetrahedronRefinementRules[] = { // Rule 0 {TETRAHEDRON,0,RED_CLASS,0, // tag, mark, rclass, nsons {0,0,0,0,0,0,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,}, // pattern 0, // pat {{-1,0},{-1,0},{-1,0},{-1,0},{-1,0},{-1,0},{-1,-1}, // sonandnode {-1,-1},{-1,-1},{-1,-1},{-1,0},{-1,-1},{-1,-1}, {-1,-1},{-1,-1},{-1,-1},{-1,-1},{-1,-1},{-1,-1}, }, {{TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, // sons {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, }}, // Rule 1 {TETRAHEDRON,1,RED_CLASS,1, // tag, mark, rclass, nsons {0,0,0,0,0,0,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,}, // pattern 0, // pat {{-1,0},{-1,0},{-1,0},{-1,0},{-1,0},{-1,0},{-1,-1}, // sonandnode {-1,-1},{-1,-1},{-1,-1},{-1,0},{-1,-1},{-1,-1}, {-1,-1},{-1,-1},{-1,-1},{-1,-1},{-1,-1},{-1,-1}, }, {{TETRAHEDRON,{0,1,2,3,-1,-1,-1,-1,},{100,101,102,103,-1,-1,},0}, // sons {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, }}, // Rule 2 {TETRAHEDRON,2,RED_CLASS,2, // tag, mark, rclass, nsons {1,0,0,0,0,0,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,}, // pattern 1, // pat {{0,2},{-1,0},{-1,0},{-1,0},{-1,0},{-1,0},{-1,-1}, // sonandnode {-1,-1},{-1,-1},{-1,-1},{-1,0},{-1,-1},{-1,-1}, {-1,-1},{-1,-1},{-1,-1},{-1,-1},{-1,-1},{-1,-1}, }, {{TETRAHEDRON,{2,3,4,1,-1,-1,-1,-1,},{1,103,100,101,-1,-1,},0}, // sons {TETRAHEDRON,{0,2,3,4,-1,-1,-1,-1,},{102,0,103,100,-1,-1,},268435456}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, }}, // Rule 3 {TETRAHEDRON,3,RED_CLASS,2, // tag, mark, rclass, nsons {0,1,0,0,0,0,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,}, // pattern 2, // pat {{-1,0},{0,3},{-1,0},{-1,0},{-1,0},{-1,0},{-1,-1}, // sonandnode {-1,-1},{-1,-1},{-1,-1},{-1,0},{-1,-1},{-1,-1}, {-1,-1},{-1,-1},{-1,-1},{-1,-1},{-1,-1},{-1,-1}, }, {{TETRAHEDRON,{0,2,3,5,-1,-1,-1,-1,},{102,101,1,100,-1,-1,},0}, // sons {TETRAHEDRON,{1,3,5,0,-1,-1,-1,-1,},{101,0,100,103,-1,-1,},268435458}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, }}, // Rule 4 {TETRAHEDRON,4,RED_CLASS,2, // tag, mark, rclass, nsons {0,0,1,0,0,0,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,}, // pattern 4, // pat {{-1,0},{-1,0},{0,2},{-1,0},{-1,0},{-1,0},{-1,-1}, // sonandnode {-1,-1},{-1,-1},{-1,-1},{-1,0},{-1,-1},{-1,-1}, {-1,-1},{-1,-1},{-1,-1},{-1,-1},{-1,-1},{-1,-1}, }, {{TETRAHEDRON,{2,3,6,1,-1,-1,-1,-1,},{102,1,100,101,-1,-1,},0}, // sons {TETRAHEDRON,{1,3,6,0,-1,-1,-1,-1,},{0,102,100,103,-1,-1,},268435457}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, }}, // Rule 5 {TETRAHEDRON,5,RED_CLASS,2, // tag, mark, rclass, nsons {0,0,0,1,0,0,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,}, // pattern 8, // pat {{-1,0},{-1,0},{-1,0},{0,2},{-1,0},{-1,0},{-1,-1}, // sonandnode {-1,-1},{-1,-1},{-1,-1},{-1,0},{-1,-1},{-1,-1}, {-1,-1},{-1,-1},{-1,-1},{-1,-1},{-1,-1},{-1,-1}, }, {{TETRAHEDRON,{2,3,7,1,-1,-1,-1,-1,},{102,103,1,101,-1,-1,},0}, // sons {TETRAHEDRON,{0,1,2,7,-1,-1,-1,-1,},{100,0,102,103,-1,-1,},268435458}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, }}, // Rule 6 {TETRAHEDRON,6,RED_CLASS,2, // tag, mark, rclass, nsons {0,0,0,0,1,0,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,}, // pattern 16, // pat {{-1,0},{-1,0},{-1,0},{-1,0},{0,3},{-1,0},{-1,-1}, // sonandnode {-1,-1},{-1,-1},{-1,-1},{-1,0},{-1,-1},{-1,-1}, {-1,-1},{-1,-1},{-1,-1},{-1,-1},{-1,-1},{-1,-1}, }, {{TETRAHEDRON,{0,2,3,8,-1,-1,-1,-1,},{102,101,103,1,-1,-1,},0}, // sons {TETRAHEDRON,{0,1,2,8,-1,-1,-1,-1,},{100,101,0,103,-1,-1,},268435459}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, }}, // Rule 7 {TETRAHEDRON,7,RED_CLASS,2, // tag, mark, rclass, nsons {0,0,0,0,0,1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,}, // pattern 32, // pat {{-1,0},{-1,0},{-1,0},{-1,0},{-1,0},{0,2},{-1,-1}, // sonandnode {-1,-1},{-1,-1},{-1,-1},{-1,0},{-1,-1},{-1,-1}, {-1,-1},{-1,-1},{-1,-1},{-1,-1},{-1,-1},{-1,-1}, }, {{TETRAHEDRON,{1,3,9,0,-1,-1,-1,-1,},{101,102,1,103,-1,-1,},0}, // sons {TETRAHEDRON,{0,1,2,9,-1,-1,-1,-1,},{100,101,102,0,-1,-1,},268435458}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, }}, // Rule 8 {TETRAHEDRON,8,RED_CLASS,3, // tag, mark, rclass, nsons {1,1,0,0,0,0,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,}, // pattern 3, // pat {{0,2},{0,3},{-1,0},{-1,0},{-1,0},{-1,0},{-1,-1}, // sonandnode {-1,-1},{-1,-1},{-1,-1},{-1,0},{-1,-1},{-1,-1}, {-1,-1},{-1,-1},{-1,-1},{-1,-1},{-1,-1},{-1,-1}, }, {{TETRAHEDRON,{2,3,4,5,-1,-1,-1,-1,},{1,2,100,101,-1,-1,},0}, // sons {TETRAHEDRON,{0,2,3,4,-1,-1,-1,-1,},{102,0,103,100,-1,-1,},268435456}, {TETRAHEDRON,{3,4,5,1,-1,-1,-1,-1,},{0,100,101,103,-1,-1,},268435457}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, }}, // Rule 9 {TETRAHEDRON,9,RED_CLASS,3, // tag, mark, rclass, nsons {1,1,0,0,0,0,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,}, // pattern 3, // pat {{1,1},{0,3},{-1,0},{-1,0},{-1,0},{-1,0},{-1,-1}, // sonandnode {-1,-1},{-1,-1},{-1,-1},{-1,0},{-1,-1},{-1,-1}, {-1,-1},{-1,-1},{-1,-1},{-1,-1},{-1,-1},{-1,-1}, }, {{TETRAHEDRON,{0,2,3,5,-1,-1,-1,-1,},{102,101,2,100,-1,-1,},0}, // sons {TETRAHEDRON,{3,4,5,1,-1,-1,-1,-1,},{2,100,101,103,-1,-1,},536870918}, {TETRAHEDRON,{0,3,4,5,-1,-1,-1,-1,},{103,1,100,0,-1,-1,},268435458}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, }}, // Rule 10 {TETRAHEDRON,10,RED_CLASS,3, // tag, mark, rclass, nsons {1,0,1,0,0,0,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,}, // pattern 5, // pat {{0,2},{-1,0},{1,2},{-1,0},{-1,0},{-1,0},{-1,-1}, // sonandnode {-1,-1},{-1,-1},{-1,-1},{-1,0},{-1,-1},{-1,-1}, {-1,-1},{-1,-1},{-1,-1},{-1,-1},{-1,-1},{-1,-1}, }, {{TETRAHEDRON,{2,3,4,1,-1,-1,-1,-1,},{1,103,100,101,-1,-1,},0}, // sons {TETRAHEDRON,{3,4,6,2,-1,-1,-1,-1,},{2,100,102,0,-1,-1,},268435456}, {TETRAHEDRON,{0,3,4,6,-1,-1,-1,-1,},{103,1,100,102,-1,-1,},536870912}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, }}, // Rule 11 {TETRAHEDRON,11,RED_CLASS,3, // tag, mark, rclass, nsons {1,0,1,0,0,0,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,}, // pattern 5, // pat {{1,1},{-1,0},{0,2},{-1,0},{-1,0},{-1,0},{-1,-1}, // sonandnode {-1,-1},{-1,-1},{-1,-1},{-1,0},{-1,-1},{-1,-1}, {-1,-1},{-1,-1},{-1,-1},{-1,-1},{-1,-1},{-1,-1}, }, {{TETRAHEDRON,{2,3,6,1,-1,-1,-1,-1,},{102,1,100,101,-1,-1,},0}, // sons {TETRAHEDRON,{3,4,6,1,-1,-1,-1,-1,},{2,100,0,103,-1,-1,},268435457}, {TETRAHEDRON,{0,3,4,6,-1,-1,-1,-1,},{103,1,100,102,-1,-1,},536870913}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, }}, // Rule 12 {TETRAHEDRON,12,RED_CLASS,3, // tag, mark, rclass, nsons {0,1,1,0,0,0,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,}, // pattern 6, // pat {{-1,0},{0,1},{0,2},{-1,0},{-1,0},{-1,0},{-1,-1}, // sonandnode {-1,-1},{-1,-1},{-1,-1},{-1,0},{-1,-1},{-1,-1}, {-1,-1},{-1,-1},{-1,-1},{-1,-1},{-1,-1},{-1,-1}, }, {{TETRAHEDRON,{3,5,6,2,-1,-1,-1,-1,},{2,100,102,101,-1,-1,},0}, // sons {TETRAHEDRON,{1,3,5,0,-1,-1,-1,-1,},{101,2,100,103,-1,-1,},536870912}, {TETRAHEDRON,{0,3,5,6,-1,-1,-1,-1,},{1,0,100,102,-1,-1,},268435456}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, }}, // Rule 13 {TETRAHEDRON,13,RED_CLASS,3, // tag, mark, rclass, nsons {0,1,1,0,0,0,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,}, // pattern 6, // pat {{-1,0},{0,1},{0,2},{-1,0},{-1,0},{-1,0},{-1,-1}, // sonandnode {-1,-1},{-1,-1},{-1,-1},{-1,0},{-1,-1},{-1,-1}, {-1,-1},{-1,-1},{-1,-1},{-1,-1},{-1,-1},{-1,-1}, }, {{TETRAHEDRON,{3,5,6,2,-1,-1,-1,-1,},{2,100,102,101,-1,-1,},0}, // sons {TETRAHEDRON,{1,3,6,0,-1,-1,-1,-1,},{2,102,100,103,-1,-1,},536870924}, {TETRAHEDRON,{1,3,5,6,-1,-1,-1,-1,},{101,0,100,1,-1,-1,},268435456}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, }}, // Rule 14 {TETRAHEDRON,14,RED_CLASS,3, // tag, mark, rclass, nsons {1,0,0,1,0,0,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,}, // pattern 9, // pat {{0,2},{-1,0},{-1,0},{1,2},{-1,0},{-1,0},{-1,-1}, // sonandnode {-1,-1},{-1,-1},{-1,-1},{-1,0},{-1,-1},{-1,-1}, {-1,-1},{-1,-1},{-1,-1},{-1,-1},{-1,-1},{-1,-1}, }, {{TETRAHEDRON,{2,3,4,1,-1,-1,-1,-1,},{1,103,100,101,-1,-1,},0}, // sons {TETRAHEDRON,{3,4,7,2,-1,-1,-1,-1,},{103,2,102,0,-1,-1,},268435456}, {TETRAHEDRON,{2,4,7,0,-1,-1,-1,-1,},{1,103,102,100,-1,-1,},536870916}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, }}, // Rule 15 {TETRAHEDRON,15,RED_CLASS,3, // tag, mark, rclass, nsons {1,0,0,1,0,0,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,}, // pattern 9, // pat {{1,2},{-1,0},{-1,0},{0,2},{-1,0},{-1,0},{-1,-1}, // sonandnode {-1,-1},{-1,-1},{-1,-1},{-1,0},{-1,-1},{-1,-1}, {-1,-1},{-1,-1},{-1,-1},{-1,-1},{-1,-1},{-1,-1}, }, {{TETRAHEDRON,{2,3,7,1,-1,-1,-1,-1,},{102,103,1,101,-1,-1,},0}, // sons {TETRAHEDRON,{1,2,4,7,-1,-1,-1,-1,},{100,2,103,0,-1,-1,},268435458}, {TETRAHEDRON,{2,4,7,0,-1,-1,-1,-1,},{1,103,102,100,-1,-1,},536870918}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, }}, // Rule 16 {TETRAHEDRON,16,RED_CLASS,4, // tag, mark, rclass, nsons {0,1,0,1,0,0,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,}, // pattern 10, // pat {{-1,0},{0,1},{-1,0},{0,2},{-1,0},{-1,0},{-1,-1}, // sonandnode {-1,-1},{-1,-1},{-1,-1},{-1,0},{-1,-1},{-1,-1}, {-1,-1},{-1,-1},{-1,-1},{-1,-1},{-1,-1},{-1,-1}, }, {{TETRAHEDRON,{3,5,7,2,-1,-1,-1,-1,},{1,3,102,101,-1,-1,},0}, // sons {TETRAHEDRON,{1,3,5,7,-1,-1,-1,-1,},{101,0,2,103,-1,-1,},268435456}, {TETRAHEDRON,{0,1,5,7,-1,-1,-1,-1,},{100,1,3,103,-1,-1,},536870920}, {TETRAHEDRON,{2,5,7,0,-1,-1,-1,-1,},{0,2,102,100,-1,-1,},268435457}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, }}, // Rule 17 {TETRAHEDRON,17,RED_CLASS,3, // tag, mark, rclass, nsons {0,0,1,1,0,0,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,}, // pattern 12, // pat {{-1,0},{-1,0},{0,2},{1,3},{-1,0},{-1,0},{-1,-1}, // sonandnode {-1,-1},{-1,-1},{-1,-1},{-1,0},{-1,-1},{-1,-1}, {-1,-1},{-1,-1},{-1,-1},{-1,-1},{-1,-1},{-1,-1}, }, {{TETRAHEDRON,{2,3,6,1,-1,-1,-1,-1,},{102,1,100,101,-1,-1,},0}, // sons {TETRAHEDRON,{1,3,6,7,-1,-1,-1,-1,},{0,102,2,103,-1,-1,},268435457}, {TETRAHEDRON,{0,1,6,7,-1,-1,-1,-1,},{100,1,102,103,-1,-1,},536870921}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, }}, // Rule 18 {TETRAHEDRON,18,RED_CLASS,3, // tag, mark, rclass, nsons {0,0,1,1,0,0,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,}, // pattern 12, // pat {{-1,0},{-1,0},{1,2},{0,2},{-1,0},{-1,0},{-1,-1}, // sonandnode {-1,-1},{-1,-1},{-1,-1},{-1,0},{-1,-1},{-1,-1}, {-1,-1},{-1,-1},{-1,-1},{-1,-1},{-1,-1},{-1,-1}, }, {{TETRAHEDRON,{2,3,7,1,-1,-1,-1,-1,},{102,103,1,101,-1,-1,},0}, // sons {TETRAHEDRON,{1,2,6,7,-1,-1,-1,-1,},{100,102,2,0,-1,-1,},268435458}, {TETRAHEDRON,{0,1,6,7,-1,-1,-1,-1,},{100,1,102,103,-1,-1,},536870922}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, }}, // Rule 19 {TETRAHEDRON,19,RED_CLASS,3, // tag, mark, rclass, nsons {1,0,0,0,1,0,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,}, // pattern 17, // pat {{0,2},{-1,0},{-1,0},{-1,0},{0,3},{-1,0},{-1,-1}, // sonandnode {-1,-1},{-1,-1},{-1,-1},{-1,0},{-1,-1},{-1,-1}, {-1,-1},{-1,-1},{-1,-1},{-1,-1},{-1,-1},{-1,-1}, }, {{TETRAHEDRON,{2,3,4,8,-1,-1,-1,-1,},{1,103,2,101,-1,-1,},0}, // sons {TETRAHEDRON,{0,2,3,4,-1,-1,-1,-1,},{102,0,103,100,-1,-1,},268435456}, {TETRAHEDRON,{1,2,4,8,-1,-1,-1,-1,},{100,0,103,101,-1,-1,},268435458}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, }}, // Rule 20 {TETRAHEDRON,20,RED_CLASS,3, // tag, mark, rclass, nsons {1,0,0,0,1,0,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,}, // pattern 17, // pat {{1,2},{-1,0},{-1,0},{-1,0},{0,3},{-1,0},{-1,-1}, // sonandnode {-1,-1},{-1,-1},{-1,-1},{-1,0},{-1,-1},{-1,-1}, {-1,-1},{-1,-1},{-1,-1},{-1,-1},{-1,-1},{-1,-1}, }, {{TETRAHEDRON,{0,2,3,8,-1,-1,-1,-1,},{102,101,103,2,-1,-1,},0}, // sons {TETRAHEDRON,{1,2,4,8,-1,-1,-1,-1,},{100,2,103,101,-1,-1,},536870915}, {TETRAHEDRON,{2,4,8,0,-1,-1,-1,-1,},{1,103,0,100,-1,-1,},268435459}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, }}, // Rule 21 {TETRAHEDRON,21,RED_CLASS,3, // tag, mark, rclass, nsons {0,1,0,0,1,0,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,}, // pattern 18, // pat {{-1,0},{0,3},{-1,0},{-1,0},{1,2},{-1,0},{-1,-1}, // sonandnode {-1,-1},{-1,-1},{-1,-1},{-1,0},{-1,-1},{-1,-1}, {-1,-1},{-1,-1},{-1,-1},{-1,-1},{-1,-1},{-1,-1}, }, {{TETRAHEDRON,{0,2,3,5,-1,-1,-1,-1,},{102,101,1,100,-1,-1,},0}, // sons {TETRAHEDRON,{3,5,8,0,-1,-1,-1,-1,},{101,2,103,0,-1,-1,},268435458}, {TETRAHEDRON,{0,1,5,8,-1,-1,-1,-1,},{100,101,1,103,-1,-1,},536870918}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, }}, // Rule 22 {TETRAHEDRON,22,RED_CLASS,3, // tag, mark, rclass, nsons {0,1,0,0,1,0,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,}, // pattern 18, // pat {{-1,0},{1,1},{-1,0},{-1,0},{0,3},{-1,0},{-1,-1}, // sonandnode {-1,-1},{-1,-1},{-1,-1},{-1,0},{-1,-1},{-1,-1}, {-1,-1},{-1,-1},{-1,-1},{-1,-1},{-1,-1},{-1,-1}, }, {{TETRAHEDRON,{0,2,3,8,-1,-1,-1,-1,},{102,101,103,1,-1,-1,},0}, // sons {TETRAHEDRON,{2,5,8,0,-1,-1,-1,-1,},{101,2,0,100,-1,-1,},268435459}, {TETRAHEDRON,{0,1,5,8,-1,-1,-1,-1,},{100,101,1,103,-1,-1,},536870919}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, }}, // Rule 23 {TETRAHEDRON,23,RED_CLASS,4, // tag, mark, rclass, nsons {0,0,1,0,1,0,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,}, // pattern 20, // pat {{-1,0},{-1,0},{0,2},{-1,0},{0,3},{-1,0},{-1,-1}, // sonandnode {-1,-1},{-1,-1},{-1,-1},{-1,0},{-1,-1},{-1,-1}, {-1,-1},{-1,-1},{-1,-1},{-1,-1},{-1,-1},{-1,-1}, }, {{TETRAHEDRON,{2,3,6,8,-1,-1,-1,-1,},{102,1,3,101,-1,-1,},0}, // sons {TETRAHEDRON,{3,6,8,0,-1,-1,-1,-1,},{0,2,103,102,-1,-1,},268435457}, {TETRAHEDRON,{0,1,6,8,-1,-1,-1,-1,},{100,3,1,103,-1,-1,},536870917}, {TETRAHEDRON,{1,2,6,8,-1,-1,-1,-1,},{100,0,2,101,-1,-1,},268435458}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, }}, // Rule 24 {TETRAHEDRON,24,RED_CLASS,3, // tag, mark, rclass, nsons {0,0,0,1,1,0,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,}, // pattern 24, // pat {{-1,0},{-1,0},{-1,0},{0,2},{0,3},{-1,0},{-1,-1}, // sonandnode {-1,-1},{-1,-1},{-1,-1},{-1,0},{-1,-1},{-1,-1}, {-1,-1},{-1,-1},{-1,-1},{-1,-1},{-1,-1},{-1,-1}, }, {{TETRAHEDRON,{2,3,7,8,-1,-1,-1,-1,},{102,103,2,101,-1,-1,},0}, // sons {TETRAHEDRON,{0,1,2,7,-1,-1,-1,-1,},{100,2,102,103,-1,-1,},536870914}, {TETRAHEDRON,{1,2,7,8,-1,-1,-1,-1,},{1,0,103,101,-1,-1,},268435458}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, }}, // Rule 25 {TETRAHEDRON,25,RED_CLASS,3, // tag, mark, rclass, nsons {0,0,0,1,1,0,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,}, // pattern 24, // pat {{-1,0},{-1,0},{-1,0},{0,2},{0,3},{-1,0},{-1,-1}, // sonandnode {-1,-1},{-1,-1},{-1,-1},{-1,0},{-1,-1},{-1,-1}, {-1,-1},{-1,-1},{-1,-1},{-1,-1},{-1,-1},{-1,-1}, }, {{TETRAHEDRON,{2,3,7,8,-1,-1,-1,-1,},{102,103,2,101,-1,-1,},0}, // sons {TETRAHEDRON,{0,1,2,8,-1,-1,-1,-1,},{100,101,2,103,-1,-1,},536870926}, {TETRAHEDRON,{0,2,7,8,-1,-1,-1,-1,},{102,0,103,1,-1,-1,},268435458}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, }}, // Rule 26 {TETRAHEDRON,26,RED_CLASS,4, // tag, mark, rclass, nsons {1,0,0,0,0,1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,}, // pattern 33, // pat {{0,1},{-1,0},{-1,0},{-1,0},{-1,0},{0,2},{-1,-1}, // sonandnode {-1,-1},{-1,-1},{-1,-1},{-1,0},{-1,-1},{-1,-1}, {-1,-1},{-1,-1},{-1,-1},{-1,-1},{-1,-1},{-1,-1}, }, {{TETRAHEDRON,{3,4,9,1,-1,-1,-1,-1,},{1,3,101,103,-1,-1,},0}, // sons {TETRAHEDRON,{0,3,4,9,-1,-1,-1,-1,},{103,0,2,102,-1,-1,},268435456}, {TETRAHEDRON,{2,4,9,0,-1,-1,-1,-1,},{3,1,102,100,-1,-1,},536870920}, {TETRAHEDRON,{1,2,4,9,-1,-1,-1,-1,},{100,2,0,101,-1,-1,},268435457}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, }}, // Rule 27 {TETRAHEDRON,27,RED_CLASS,3, // tag, mark, rclass, nsons {0,1,0,0,0,1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,}, // pattern 34, // pat {{-1,0},{0,2},{-1,0},{-1,0},{-1,0},{0,3},{-1,-1}, // sonandnode {-1,-1},{-1,-1},{-1,-1},{-1,0},{-1,-1},{-1,-1}, {-1,-1},{-1,-1},{-1,-1},{-1,-1},{-1,-1},{-1,-1}, }, {{TETRAHEDRON,{0,3,5,9,-1,-1,-1,-1,},{1,101,2,102,-1,-1,},0}, // sons {TETRAHEDRON,{1,3,5,0,-1,-1,-1,-1,},{101,0,100,103,-1,-1,},268435456}, {TETRAHEDRON,{2,5,9,0,-1,-1,-1,-1,},{101,0,102,100,-1,-1,},268435458}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, }}, // Rule 28 {TETRAHEDRON,28,RED_CLASS,3, // tag, mark, rclass, nsons {0,1,0,0,0,1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,}, // pattern 34, // pat {{-1,0},{1,1},{-1,0},{-1,0},{-1,0},{0,2},{-1,-1}, // sonandnode {-1,-1},{-1,-1},{-1,-1},{-1,0},{-1,-1},{-1,-1}, {-1,-1},{-1,-1},{-1,-1},{-1,-1},{-1,-1},{-1,-1}, }, {{TETRAHEDRON,{1,3,9,0,-1,-1,-1,-1,},{101,102,2,103,-1,-1,},0}, // sons {TETRAHEDRON,{2,5,9,0,-1,-1,-1,-1,},{101,2,102,100,-1,-1,},536870922}, {TETRAHEDRON,{0,1,5,9,-1,-1,-1,-1,},{100,101,1,0,-1,-1,},268435458}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, }}, // Rule 29 {TETRAHEDRON,29,RED_CLASS,3, // tag, mark, rclass, nsons {0,0,1,0,0,1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,}, // pattern 36, // pat {{-1,0},{-1,0},{0,1},{-1,0},{-1,0},{0,2},{-1,-1}, // sonandnode {-1,-1},{-1,-1},{-1,-1},{-1,0},{-1,-1},{-1,-1}, {-1,-1},{-1,-1},{-1,-1},{-1,-1},{-1,-1},{-1,-1}, }, {{TETRAHEDRON,{3,6,9,1,-1,-1,-1,-1,},{102,2,101,1,-1,-1,},0}, // sons {TETRAHEDRON,{1,3,6,0,-1,-1,-1,-1,},{0,102,100,103,-1,-1,},268435459}, {TETRAHEDRON,{1,2,6,9,-1,-1,-1,-1,},{100,102,0,101,-1,-1,},268435457}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, }}, // Rule 30 {TETRAHEDRON,30,RED_CLASS,3, // tag, mark, rclass, nsons {0,0,1,0,0,1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,}, // pattern 36, // pat {{-1,0},{-1,0},{1,2},{-1,0},{-1,0},{0,2},{-1,-1}, // sonandnode {-1,-1},{-1,-1},{-1,-1},{-1,0},{-1,-1},{-1,-1}, {-1,-1},{-1,-1},{-1,-1},{-1,-1},{-1,-1},{-1,-1}, }, {{TETRAHEDRON,{1,3,9,0,-1,-1,-1,-1,},{101,102,2,103,-1,-1,},0}, // sons {TETRAHEDRON,{1,2,6,9,-1,-1,-1,-1,},{100,102,2,101,-1,-1,},536870918}, {TETRAHEDRON,{0,1,6,9,-1,-1,-1,-1,},{100,1,102,0,-1,-1,},268435458}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, }}, // Rule 31 {TETRAHEDRON,31,RED_CLASS,3, // tag, mark, rclass, nsons {0,0,0,1,0,1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,}, // pattern 40, // pat {{-1,0},{-1,0},{-1,0},{0,1},{-1,0},{0,2},{-1,-1}, // sonandnode {-1,-1},{-1,-1},{-1,-1},{-1,0},{-1,-1},{-1,-1}, {-1,-1},{-1,-1},{-1,-1},{-1,-1},{-1,-1},{-1,-1}, }, {{TETRAHEDRON,{3,7,9,1,-1,-1,-1,-1,},{102,2,101,103,-1,-1,},0}, // sons {TETRAHEDRON,{0,1,2,7,-1,-1,-1,-1,},{100,2,102,103,-1,-1,},536870913}, {TETRAHEDRON,{1,2,7,9,-1,-1,-1,-1,},{1,102,0,101,-1,-1,},268435457}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, }}, // Rule 32 {TETRAHEDRON,32,RED_CLASS,3, // tag, mark, rclass, nsons {0,0,0,1,0,1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,}, // pattern 40, // pat {{-1,0},{-1,0},{-1,0},{0,1},{-1,0},{0,2},{-1,-1}, // sonandnode {-1,-1},{-1,-1},{-1,-1},{-1,0},{-1,-1},{-1,-1}, {-1,-1},{-1,-1},{-1,-1},{-1,-1},{-1,-1},{-1,-1}, }, {{TETRAHEDRON,{3,7,9,1,-1,-1,-1,-1,},{102,2,101,103,-1,-1,},0}, // sons {TETRAHEDRON,{0,1,2,9,-1,-1,-1,-1,},{100,101,102,2,-1,-1,},536870921}, {TETRAHEDRON,{1,7,9,0,-1,-1,-1,-1,},{0,102,1,103,-1,-1,},268435457}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, }}, // Rule 33 {TETRAHEDRON,33,RED_CLASS,3, // tag, mark, rclass, nsons {0,0,0,0,1,1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,}, // pattern 48, // pat {{-1,0},{-1,0},{-1,0},{-1,0},{0,2},{0,3},{-1,-1}, // sonandnode {-1,-1},{-1,-1},{-1,-1},{-1,0},{-1,-1},{-1,-1}, {-1,-1},{-1,-1},{-1,-1},{-1,-1},{-1,-1},{-1,-1}, }, {{TETRAHEDRON,{0,3,8,9,-1,-1,-1,-1,},{103,101,2,102,-1,-1,},0}, // sons {TETRAHEDRON,{0,1,2,8,-1,-1,-1,-1,},{100,101,2,103,-1,-1,},536870926}, {TETRAHEDRON,{2,8,9,0,-1,-1,-1,-1,},{101,0,102,1,-1,-1,},268435458}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, }}, // Rule 34 {TETRAHEDRON,34,RED_CLASS,3, // tag, mark, rclass, nsons {0,0,0,0,1,1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,}, // pattern 48, // pat {{-1,0},{-1,0},{-1,0},{-1,0},{0,2},{0,3},{-1,-1}, // sonandnode {-1,-1},{-1,-1},{-1,-1},{-1,0},{-1,-1},{-1,-1}, {-1,-1},{-1,-1},{-1,-1},{-1,-1},{-1,-1},{-1,-1}, }, {{TETRAHEDRON,{0,3,8,9,-1,-1,-1,-1,},{103,101,2,102,-1,-1,},0}, // sons {TETRAHEDRON,{0,1,2,9,-1,-1,-1,-1,},{100,101,102,2,-1,-1,},536870922}, {TETRAHEDRON,{1,8,9,0,-1,-1,-1,-1,},{101,0,1,103,-1,-1,},268435458}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, }}, // Rule 35 {TETRAHEDRON,35,RED_CLASS,4, // tag, mark, rclass, nsons {1,1,1,0,0,0,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,}, // pattern 7, // pat {{1,1},{0,1},{0,2},{-1,0},{-1,0},{-1,0},{-1,-1}, // sonandnode {-1,-1},{-1,-1},{-1,-1},{-1,0},{-1,-1},{-1,-1}, {-1,-1},{-1,-1},{-1,-1},{-1,-1},{-1,-1},{-1,-1}, }, {{TETRAHEDRON,{3,5,6,2,-1,-1,-1,-1,},{2,100,102,101,-1,-1,},0}, // sons {TETRAHEDRON,{3,4,5,1,-1,-1,-1,-1,},{2,100,101,103,-1,-1,},536870924}, {TETRAHEDRON,{4,5,6,3,-1,-1,-1,-1,},{100,0,3,1,-1,-1,},268435456}, {TETRAHEDRON,{0,3,4,6,-1,-1,-1,-1,},{103,2,100,102,-1,-1,},536870920}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, }}, // Rule 36 {TETRAHEDRON,36,RED_CLASS,4, // tag, mark, rclass, nsons {1,1,0,1,0,0,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,}, // pattern 11, // pat {{0,2},{0,3},{-1,0},{1,2},{-1,0},{-1,0},{-1,-1}, // sonandnode {-1,-1},{-1,-1},{-1,-1},{-1,0},{-1,-1},{-1,-1}, {-1,-1},{-1,-1},{-1,-1},{-1,-1},{-1,-1},{-1,-1}, }, {{TETRAHEDRON,{2,3,4,5,-1,-1,-1,-1,},{1,2,100,101,-1,-1,},0}, // sons {TETRAHEDRON,{3,4,7,2,-1,-1,-1,-1,},{103,3,102,0,-1,-1,},268435456}, {TETRAHEDRON,{3,4,5,1,-1,-1,-1,-1,},{0,100,101,103,-1,-1,},268435457}, {TETRAHEDRON,{2,4,7,0,-1,-1,-1,-1,},{1,103,102,100,-1,-1,},536870916}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, }}, // Rule 37 {TETRAHEDRON,37,RED_CLASS,5, // tag, mark, rclass, nsons {1,1,0,1,0,0,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,}, // pattern 11, // pat {{1,1},{0,1},{-1,0},{0,2},{-1,0},{-1,0},{-1,-1}, // sonandnode {-1,-1},{-1,-1},{-1,-1},{-1,0},{-1,-1},{-1,-1}, {-1,-1},{-1,-1},{-1,-1},{-1,-1},{-1,-1},{-1,-1}, }, {{TETRAHEDRON,{3,5,7,2,-1,-1,-1,-1,},{2,4,102,101,-1,-1,},0}, // sons {TETRAHEDRON,{3,4,5,1,-1,-1,-1,-1,},{2,100,101,103,-1,-1,},536870924}, {TETRAHEDRON,{4,5,7,3,-1,-1,-1,-1,},{3,0,103,1,-1,-1,},268435456}, {TETRAHEDRON,{0,4,5,7,-1,-1,-1,-1,},{100,2,4,103,-1,-1,},536870912}, {TETRAHEDRON,{2,5,7,0,-1,-1,-1,-1,},{0,3,102,100,-1,-1,},268435457}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, }}, // Rule 38 {TETRAHEDRON,38,RED_CLASS,5, // tag, mark, rclass, nsons {1,1,0,1,0,0,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,}, // pattern 11, // pat {{2,0},{0,1},{-1,0},{0,2},{-1,0},{-1,0},{-1,-1}, // sonandnode {-1,-1},{-1,-1},{-1,-1},{-1,0},{-1,-1},{-1,-1}, {-1,-1},{-1,-1},{-1,-1},{-1,-1},{-1,-1},{-1,-1}, }, {{TETRAHEDRON,{3,5,7,2,-1,-1,-1,-1,},{1,3,102,101,-1,-1,},0}, // sons {TETRAHEDRON,{1,3,5,7,-1,-1,-1,-1,},{101,0,2,103,-1,-1,},268435456}, {TETRAHEDRON,{4,5,7,1,-1,-1,-1,-1,},{4,1,103,100,-1,-1,},536870920}, {TETRAHEDRON,{2,5,7,0,-1,-1,-1,-1,},{0,4,102,100,-1,-1,},268435457}, {TETRAHEDRON,{0,4,5,7,-1,-1,-1,-1,},{100,2,3,103,-1,-1,},805306376}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, }}, // Rule 39 {TETRAHEDRON,39,RED_CLASS,5, // tag, mark, rclass, nsons {1,1,0,1,0,0,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,}, // pattern 11, // pat {{1,1},{0,1},{-1,0},{0,2},{-1,0},{-1,0},{-1,-1}, // sonandnode {-1,-1},{-1,-1},{-1,-1},{-1,0},{-1,-1},{-1,-1}, {-1,-1},{-1,-1},{-1,-1},{-1,-1},{-1,-1},{-1,-1}, }, {{TETRAHEDRON,{3,5,7,2,-1,-1,-1,-1,},{4,1,102,101,-1,-1,},0}, // sons {TETRAHEDRON,{2,4,5,7,-1,-1,-1,-1,},{100,3,0,2,-1,-1,},268435457}, {TETRAHEDRON,{2,4,7,0,-1,-1,-1,-1,},{1,103,102,100,-1,-1,},536870925}, {TETRAHEDRON,{4,5,7,1,-1,-1,-1,-1,},{1,4,103,100,-1,-1,},536870917}, {TETRAHEDRON,{1,3,5,7,-1,-1,-1,-1,},{101,0,3,103,-1,-1,},268435456}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, }}, // Rule 40 {TETRAHEDRON,40,RED_CLASS,9, // tag, mark, rclass, nsons {1,0,1,1,0,0,-1,-1,-1,-1,1,-1,-1,-1,-1,-1,-1,-1,-1,}, // pattern 1037, // pat {{0,1},{-1,0},{0,2},{0,3},{-1,0},{-1,0},{-1,-1}, // sonandnode {-1,-1},{-1,-1},{-1,-1},{1,2},{-1,-1},{-1,-1}, {-1,-1},{-1,-1},{-1,-1},{-1,-1},{-1,-1},{-1,-1}, }, {{TETRAHEDRON,{0,4,6,7,-1,-1,-1,-1,},{100,1,102,103,-1,-1,},0}, // sons {TETRAHEDRON,{7,6,14,4,-1,-1,-1,-1,},{7,6,4,0,-1,-1,},268435457}, {TETRAHEDRON,{2,3,14,1,-1,-1,-1,-1,},{8,3,5,101,-1,-1,},1073741989}, {TETRAHEDRON,{3,4,14,1,-1,-1,-1,-1,},{4,6,2,103,-1,-1,},805306405}, {TETRAHEDRON,{7,4,14,3,-1,-1,-1,-1,},{1,3,8,103,-1,-1,},536870917}, {TETRAHEDRON,{1,2,6,14,-1,-1,-1,-1,},{100,7,6,2,-1,-1,},1342177957}, {TETRAHEDRON,{4,6,14,1,-1,-1,-1,-1,},{1,5,3,100,-1,-1,},536870921}, {TETRAHEDRON,{6,7,14,2,-1,-1,-1,-1,},{1,8,5,102,-1,-1,},536870913}, {TETRAHEDRON,{7,3,14,2,-1,-1,-1,-1,},{4,2,7,102,-1,-1,},805306389}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, }}, // Rule 41 {TETRAHEDRON,41,RED_CLASS,9, // tag, mark, rclass, nsons {1,0,1,1,0,0,-1,-1,-1,-1,1,-1,-1,-1,-1,-1,-1,-1,-1,}, // pattern 1037, // pat {{0,1},{-1,0},{0,2},{0,3},{-1,0},{-1,0},{-1,-1}, // sonandnode {-1,-1},{-1,-1},{-1,-1},{1,2},{-1,-1},{-1,-1}, {-1,-1},{-1,-1},{-1,-1},{-1,-1},{-1,-1},{-1,-1}, }, {{TETRAHEDRON,{0,4,6,7,-1,-1,-1,-1,},{100,1,102,103,-1,-1,},0}, // sons {TETRAHEDRON,{7,6,14,4,-1,-1,-1,-1,},{8,6,4,0,-1,-1,},268435457}, {TETRAHEDRON,{2,3,14,1,-1,-1,-1,-1,},{7,3,5,101,-1,-1,},1073741973}, {TETRAHEDRON,{3,7,14,1,-1,-1,-1,-1,},{8,4,2,103,-1,-1,},805306389}, {TETRAHEDRON,{7,4,14,1,-1,-1,-1,-1,},{1,5,3,103,-1,-1,},536870917}, {TETRAHEDRON,{1,2,4,14,-1,-1,-1,-1,},{100,6,4,2,-1,-1,},805306405}, {TETRAHEDRON,{4,6,14,2,-1,-1,-1,-1,},{1,7,5,100,-1,-1,},536870921}, {TETRAHEDRON,{6,3,14,2,-1,-1,-1,-1,},{8,2,6,102,-1,-1,},1342177429}, {TETRAHEDRON,{6,7,14,3,-1,-1,-1,-1,},{1,3,7,102,-1,-1,},536870913}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, }}, // Rule 42 {TETRAHEDRON,42,RED_CLASS,4, // tag, mark, rclass, nsons {1,0,1,1,0,0,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,}, // pattern 13, // pat {{0,2},{-1,0},{1,2},{2,2},{-1,0},{-1,0},{-1,-1}, // sonandnode {-1,-1},{-1,-1},{-1,-1},{-1,0},{-1,-1},{-1,-1}, {-1,-1},{-1,-1},{-1,-1},{-1,-1},{-1,-1},{-1,-1}, }, {{TETRAHEDRON,{2,3,4,1,-1,-1,-1,-1,},{1,103,100,101,-1,-1,},0}, // sons {TETRAHEDRON,{3,4,6,2,-1,-1,-1,-1,},{2,100,102,0,-1,-1,},268435456}, {TETRAHEDRON,{4,6,7,3,-1,-1,-1,-1,},{3,102,103,1,-1,-1,},536870912}, {TETRAHEDRON,{0,4,6,7,-1,-1,-1,-1,},{100,2,102,103,-1,-1,},805306368}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, }}, // Rule 43 {TETRAHEDRON,43,RED_CLASS,4, // tag, mark, rclass, nsons {1,0,1,1,0,0,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,}, // pattern 13, // pat {{0,2},{-1,0},{2,1},{1,2},{-1,0},{-1,0},{-1,-1}, // sonandnode {-1,-1},{-1,-1},{-1,-1},{-1,0},{-1,-1},{-1,-1}, {-1,-1},{-1,-1},{-1,-1},{-1,-1},{-1,-1},{-1,-1}, }, {{TETRAHEDRON,{2,3,4,1,-1,-1,-1,-1,},{1,103,100,101,-1,-1,},0}, // sons {TETRAHEDRON,{3,4,7,2,-1,-1,-1,-1,},{103,2,102,0,-1,-1,},268435456}, {TETRAHEDRON,{4,6,7,2,-1,-1,-1,-1,},{3,102,1,100,-1,-1,},536870916}, {TETRAHEDRON,{0,4,6,7,-1,-1,-1,-1,},{100,2,102,103,-1,-1,},805306372}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, }}, // Rule 44 {TETRAHEDRON,44,RED_CLASS,4, // tag, mark, rclass, nsons {1,0,1,1,0,0,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,}, // pattern 13, // pat {{1,1},{-1,0},{0,2},{2,2},{-1,0},{-1,0},{-1,-1}, // sonandnode {-1,-1},{-1,-1},{-1,-1},{-1,0},{-1,-1},{-1,-1}, {-1,-1},{-1,-1},{-1,-1},{-1,-1},{-1,-1},{-1,-1}, }, {{TETRAHEDRON,{2,3,6,1,-1,-1,-1,-1,},{102,1,100,101,-1,-1,},0}, // sons {TETRAHEDRON,{3,4,6,1,-1,-1,-1,-1,},{2,100,0,103,-1,-1,},268435457}, {TETRAHEDRON,{4,6,7,3,-1,-1,-1,-1,},{3,102,103,1,-1,-1,},536870913}, {TETRAHEDRON,{0,4,6,7,-1,-1,-1,-1,},{100,2,102,103,-1,-1,},805306369}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, }}, // Rule 45 {TETRAHEDRON,45,RED_CLASS,4, // tag, mark, rclass, nsons {1,0,1,1,0,0,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,}, // pattern 13, // pat {{2,0},{-1,0},{0,2},{1,3},{-1,0},{-1,0},{-1,-1}, // sonandnode {-1,-1},{-1,-1},{-1,-1},{-1,0},{-1,-1},{-1,-1}, {-1,-1},{-1,-1},{-1,-1},{-1,-1},{-1,-1},{-1,-1}, }, {{TETRAHEDRON,{2,3,6,1,-1,-1,-1,-1,},{102,1,100,101,-1,-1,},0}, // sons {TETRAHEDRON,{1,3,6,7,-1,-1,-1,-1,},{0,102,2,103,-1,-1,},268435457}, {TETRAHEDRON,{4,6,7,1,-1,-1,-1,-1,},{3,1,103,100,-1,-1,},536870921}, {TETRAHEDRON,{0,4,6,7,-1,-1,-1,-1,},{100,2,102,103,-1,-1,},805306377}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, }}, // Rule 46 {TETRAHEDRON,46,RED_CLASS,4, // tag, mark, rclass, nsons {1,0,1,1,0,0,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,}, // pattern 13, // pat {{1,2},{-1,0},{2,1},{0,2},{-1,0},{-1,0},{-1,-1}, // sonandnode {-1,-1},{-1,-1},{-1,-1},{-1,0},{-1,-1},{-1,-1}, {-1,-1},{-1,-1},{-1,-1},{-1,-1},{-1,-1},{-1,-1}, }, {{TETRAHEDRON,{2,3,7,1,-1,-1,-1,-1,},{102,103,1,101,-1,-1,},0}, // sons {TETRAHEDRON,{1,2,4,7,-1,-1,-1,-1,},{100,2,103,0,-1,-1,},268435458}, {TETRAHEDRON,{4,6,7,2,-1,-1,-1,-1,},{3,102,1,100,-1,-1,},536870918}, {TETRAHEDRON,{0,4,6,7,-1,-1,-1,-1,},{100,2,102,103,-1,-1,},805306374}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, }}, // Rule 47 {TETRAHEDRON,47,RED_CLASS,4, // tag, mark, rclass, nsons {1,0,1,1,0,0,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,}, // pattern 13, // pat {{2,0},{-1,0},{1,2},{0,2},{-1,0},{-1,0},{-1,-1}, // sonandnode {-1,-1},{-1,-1},{-1,-1},{-1,0},{-1,-1},{-1,-1}, {-1,-1},{-1,-1},{-1,-1},{-1,-1},{-1,-1},{-1,-1}, }, {{TETRAHEDRON,{2,3,7,1,-1,-1,-1,-1,},{102,103,1,101,-1,-1,},0}, // sons {TETRAHEDRON,{1,2,6,7,-1,-1,-1,-1,},{100,102,2,0,-1,-1,},268435458}, {TETRAHEDRON,{4,6,7,1,-1,-1,-1,-1,},{3,1,103,100,-1,-1,},536870922}, {TETRAHEDRON,{0,4,6,7,-1,-1,-1,-1,},{100,2,102,103,-1,-1,},805306378}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, }}, // Rule 48 {TETRAHEDRON,48,RED_CLASS,5, // tag, mark, rclass, nsons {0,1,1,1,0,0,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,}, // pattern 14, // pat {{-1,0},{0,1},{0,2},{1,3},{-1,0},{-1,0},{-1,-1}, // sonandnode {-1,-1},{-1,-1},{-1,-1},{-1,0},{-1,-1},{-1,-1}, {-1,-1},{-1,-1},{-1,-1},{-1,-1},{-1,-1},{-1,-1}, }, {{TETRAHEDRON,{3,5,6,2,-1,-1,-1,-1,},{2,100,102,101,-1,-1,},0}, // sons {TETRAHEDRON,{1,3,5,7,-1,-1,-1,-1,},{101,2,4,103,-1,-1,},536870920}, {TETRAHEDRON,{5,6,7,3,-1,-1,-1,-1,},{3,102,1,0,-1,-1,},268435456}, {TETRAHEDRON,{0,5,6,7,-1,-1,-1,-1,},{100,2,102,4,-1,-1,},536870912}, {TETRAHEDRON,{0,1,5,7,-1,-1,-1,-1,},{100,1,3,103,-1,-1,},805306408}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, }}, // Rule 49 {TETRAHEDRON,49,RED_CLASS,5, // tag, mark, rclass, nsons {0,1,1,1,0,0,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,}, // pattern 14, // pat {{-1,0},{0,1},{3,1},{0,2},{-1,0},{-1,0},{-1,-1}, // sonandnode {-1,-1},{-1,-1},{-1,-1},{-1,0},{-1,-1},{-1,-1}, {-1,-1},{-1,-1},{-1,-1},{-1,-1},{-1,-1},{-1,-1}, }, {{TETRAHEDRON,{3,5,7,2,-1,-1,-1,-1,},{1,3,102,101,-1,-1,},0}, // sons {TETRAHEDRON,{1,3,5,7,-1,-1,-1,-1,},{101,0,2,103,-1,-1,},268435456}, {TETRAHEDRON,{0,1,5,7,-1,-1,-1,-1,},{100,1,4,103,-1,-1,},536870920}, {TETRAHEDRON,{5,6,7,2,-1,-1,-1,-1,},{4,102,0,100,-1,-1,},268435457}, {TETRAHEDRON,{0,5,6,7,-1,-1,-1,-1,},{100,3,102,2,-1,-1,},805306408}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, }}, // Rule 50 {TETRAHEDRON,50,RED_CLASS,4, // tag, mark, rclass, nsons {0,1,1,1,0,0,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,}, // pattern 14, // pat {{-1,0},{0,1},{0,2},{1,3},{-1,0},{-1,0},{-1,-1}, // sonandnode {-1,-1},{-1,-1},{-1,-1},{-1,0},{-1,-1},{-1,-1}, {-1,-1},{-1,-1},{-1,-1},{-1,-1},{-1,-1},{-1,-1}, }, {{TETRAHEDRON,{3,5,6,2,-1,-1,-1,-1,},{2,100,102,101,-1,-1,},0}, // sons {TETRAHEDRON,{1,3,6,7,-1,-1,-1,-1,},{2,102,3,103,-1,-1,},536870924}, {TETRAHEDRON,{1,3,5,6,-1,-1,-1,-1,},{101,0,100,1,-1,-1,},268435456}, {TETRAHEDRON,{0,1,6,7,-1,-1,-1,-1,},{100,1,102,103,-1,-1,},805306412}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, }}, // Rule 51 {TETRAHEDRON,51,RED_CLASS,5, // tag, mark, rclass, nsons {0,1,1,1,0,0,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,}, // pattern 14, // pat {{-1,0},{0,1},{1,1},{0,2},{-1,0},{-1,0},{-1,-1}, // sonandnode {-1,-1},{-1,-1},{-1,-1},{-1,0},{-1,-1},{-1,-1}, {-1,-1},{-1,-1},{-1,-1},{-1,-1},{-1,-1},{-1,-1}, }, {{TETRAHEDRON,{3,5,7,2,-1,-1,-1,-1,},{4,1,102,101,-1,-1,},0}, // sons {TETRAHEDRON,{5,6,7,2,-1,-1,-1,-1,},{3,102,0,100,-1,-1,},268435457}, {TETRAHEDRON,{0,1,6,7,-1,-1,-1,-1,},{100,3,102,103,-1,-1,},805306401}, {TETRAHEDRON,{1,5,6,7,-1,-1,-1,-1,},{100,1,2,4,-1,-1,},536870913}, {TETRAHEDRON,{1,3,5,7,-1,-1,-1,-1,},{101,0,3,103,-1,-1,},268435456}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, }}, // Rule 52 {TETRAHEDRON,52,RED_CLASS,9, // tag, mark, rclass, nsons {1,1,0,0,1,0,-1,-1,-1,-1,1,-1,-1,-1,-1,-1,-1,-1,-1,}, // pattern 1043, // pat {{0,0},{0,1},{-1,0},{-1,0},{0,2},{-1,0},{-1,-1}, // sonandnode {-1,-1},{-1,-1},{-1,-1},{1,2},{-1,-1},{-1,-1}, {-1,-1},{-1,-1},{-1,-1},{-1,-1},{-1,-1},{-1,-1}, }, {{TETRAHEDRON,{4,5,8,1,-1,-1,-1,-1,},{1,101,103,100,-1,-1,},0}, // sons {TETRAHEDRON,{5,8,14,4,-1,-1,-1,-1,},{4,7,6,0,-1,-1,},268435456}, {TETRAHEDRON,{3,2,14,0,-1,-1,-1,-1,},{3,5,8,102,-1,-1,},1073742000}, {TETRAHEDRON,{3,5,14,2,-1,-1,-1,-1,},{4,6,2,101,-1,-1,},805306416}, {TETRAHEDRON,{3,5,8,14,-1,-1,-1,-1,},{101,1,8,3,-1,-1,},536870912}, {TETRAHEDRON,{2,4,14,0,-1,-1,-1,-1,},{6,7,2,100,-1,-1,},1342177968}, {TETRAHEDRON,{2,4,5,14,-1,-1,-1,-1,},{100,1,3,5,-1,-1,},536870920}, {TETRAHEDRON,{4,8,14,0,-1,-1,-1,-1,},{1,8,5,103,-1,-1,},536870916}, {TETRAHEDRON,{8,3,14,0,-1,-1,-1,-1,},{4,2,7,103,-1,-1,},805306400}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, }}, // Rule 53 {TETRAHEDRON,53,RED_CLASS,9, // tag, mark, rclass, nsons {1,1,0,0,1,0,-1,-1,-1,-1,1,-1,-1,-1,-1,-1,-1,-1,-1,}, // pattern 1043, // pat {{0,0},{0,1},{-1,0},{-1,0},{0,2},{-1,0},{-1,-1}, // sonandnode {-1,-1},{-1,-1},{-1,-1},{1,2},{-1,-1},{-1,-1}, {-1,-1},{-1,-1},{-1,-1},{-1,-1},{-1,-1},{-1,-1}, }, {{TETRAHEDRON,{4,5,8,1,-1,-1,-1,-1,},{1,101,103,100,-1,-1,},0}, // sons {TETRAHEDRON,{5,8,14,4,-1,-1,-1,-1,},{4,8,6,0,-1,-1,},268435456}, {TETRAHEDRON,{3,2,14,0,-1,-1,-1,-1,},{3,5,7,102,-1,-1,},1073741984}, {TETRAHEDRON,{3,8,14,2,-1,-1,-1,-1,},{8,4,2,101,-1,-1,},805306400}, {TETRAHEDRON,{2,5,8,14,-1,-1,-1,-1,},{101,1,3,5,-1,-1,},536870912}, {TETRAHEDRON,{2,5,14,0,-1,-1,-1,-1,},{4,6,2,100,-1,-1,},805306416}, {TETRAHEDRON,{0,4,5,14,-1,-1,-1,-1,},{100,1,5,7,-1,-1,},536870920}, {TETRAHEDRON,{4,3,14,0,-1,-1,-1,-1,},{8,2,6,103,-1,-1,},1342177696}, {TETRAHEDRON,{4,8,14,3,-1,-1,-1,-1,},{1,3,7,103,-1,-1,},536870916}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, }}, // Rule 54 {TETRAHEDRON,54,RED_CLASS,4, // tag, mark, rclass, nsons {1,1,0,0,1,0,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,}, // pattern 19, // pat {{0,2},{0,3},{-1,0},{-1,0},{2,3},{-1,0},{-1,-1}, // sonandnode {-1,-1},{-1,-1},{-1,-1},{-1,0},{-1,-1},{-1,-1}, {-1,-1},{-1,-1},{-1,-1},{-1,-1},{-1,-1},{-1,-1}, }, {{TETRAHEDRON,{2,3,4,5,-1,-1,-1,-1,},{1,2,100,101,-1,-1,},0}, // sons {TETRAHEDRON,{0,2,3,4,-1,-1,-1,-1,},{102,0,103,100,-1,-1,},268435456}, {TETRAHEDRON,{3,4,5,8,-1,-1,-1,-1,},{0,3,101,103,-1,-1,},268435457}, {TETRAHEDRON,{4,5,8,1,-1,-1,-1,-1,},{2,101,103,100,-1,-1,},536870917}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, }}, // Rule 55 {TETRAHEDRON,55,RED_CLASS,4, // tag, mark, rclass, nsons {1,1,0,0,1,0,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,}, // pattern 19, // pat {{0,2},{2,2},{-1,0},{-1,0},{0,3},{-1,0},{-1,-1}, // sonandnode {-1,-1},{-1,-1},{-1,-1},{-1,0},{-1,-1},{-1,-1}, {-1,-1},{-1,-1},{-1,-1},{-1,-1},{-1,-1},{-1,-1}, }, {{TETRAHEDRON,{2,3,4,8,-1,-1,-1,-1,},{1,103,2,101,-1,-1,},0}, // sons {TETRAHEDRON,{0,2,3,4,-1,-1,-1,-1,},{102,0,103,100,-1,-1,},268435456}, {TETRAHEDRON,{2,4,5,8,-1,-1,-1,-1,},{100,3,101,0,-1,-1,},268435458}, {TETRAHEDRON,{4,5,8,1,-1,-1,-1,-1,},{2,101,103,100,-1,-1,},536870918}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, }}, // Rule 56 {TETRAHEDRON,56,RED_CLASS,4, // tag, mark, rclass, nsons {1,1,0,0,1,0,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,}, // pattern 19, // pat {{1,1},{0,3},{-1,0},{-1,0},{1,3},{-1,0},{-1,-1}, // sonandnode {-1,-1},{-1,-1},{-1,-1},{-1,0},{-1,-1},{-1,-1}, {-1,-1},{-1,-1},{-1,-1},{-1,-1},{-1,-1},{-1,-1}, }, {{TETRAHEDRON,{0,2,3,5,-1,-1,-1,-1,},{102,101,2,100,-1,-1,},0}, // sons {TETRAHEDRON,{3,4,5,8,-1,-1,-1,-1,},{2,3,101,103,-1,-1,},536870918}, {TETRAHEDRON,{0,3,4,5,-1,-1,-1,-1,},{103,1,100,0,-1,-1,},268435458}, {TETRAHEDRON,{4,5,8,1,-1,-1,-1,-1,},{1,101,103,100,-1,-1,},805306390}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, }}, // Rule 57 {TETRAHEDRON,57,RED_CLASS,4, // tag, mark, rclass, nsons {1,1,0,0,1,0,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,}, // pattern 19, // pat {{2,0},{0,3},{-1,0},{-1,0},{1,2},{-1,0},{-1,-1}, // sonandnode {-1,-1},{-1,-1},{-1,-1},{-1,0},{-1,-1},{-1,-1}, {-1,-1},{-1,-1},{-1,-1},{-1,-1},{-1,-1},{-1,-1}, }, {{TETRAHEDRON,{0,2,3,5,-1,-1,-1,-1,},{102,101,1,100,-1,-1,},0}, // sons {TETRAHEDRON,{3,5,8,0,-1,-1,-1,-1,},{101,3,103,0,-1,-1,},268435458}, {TETRAHEDRON,{4,5,8,1,-1,-1,-1,-1,},{3,101,103,100,-1,-1,},805306390}, {TETRAHEDRON,{0,4,5,8,-1,-1,-1,-1,},{100,2,1,103,-1,-1,},536870918}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, }}, // Rule 58 {TETRAHEDRON,58,RED_CLASS,4, // tag, mark, rclass, nsons {1,1,0,0,1,0,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,}, // pattern 19, // pat {{1,1},{1,2},{-1,0},{-1,0},{0,3},{-1,0},{-1,-1}, // sonandnode {-1,-1},{-1,-1},{-1,-1},{-1,0},{-1,-1},{-1,-1}, {-1,-1},{-1,-1},{-1,-1},{-1,-1},{-1,-1},{-1,-1}, }, {{TETRAHEDRON,{0,2,3,8,-1,-1,-1,-1,},{102,101,103,2,-1,-1,},0}, // sons {TETRAHEDRON,{2,4,5,8,-1,-1,-1,-1,},{100,3,101,2,-1,-1,},536870915}, {TETRAHEDRON,{2,4,8,0,-1,-1,-1,-1,},{1,103,0,100,-1,-1,},268435459}, {TETRAHEDRON,{4,5,8,1,-1,-1,-1,-1,},{1,101,103,100,-1,-1,},805306387}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, }}, // Rule 59 {TETRAHEDRON,59,RED_CLASS,4, // tag, mark, rclass, nsons {1,1,0,0,1,0,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,}, // pattern 19, // pat {{2,0},{1,1},{-1,0},{-1,0},{0,3},{-1,0},{-1,-1}, // sonandnode {-1,-1},{-1,-1},{-1,-1},{-1,0},{-1,-1},{-1,-1}, {-1,-1},{-1,-1},{-1,-1},{-1,-1},{-1,-1},{-1,-1}, }, {{TETRAHEDRON,{0,2,3,8,-1,-1,-1,-1,},{102,101,103,1,-1,-1,},0}, // sons {TETRAHEDRON,{2,5,8,0,-1,-1,-1,-1,},{101,3,0,100,-1,-1,},268435459}, {TETRAHEDRON,{4,5,8,1,-1,-1,-1,-1,},{3,101,103,100,-1,-1,},805306391}, {TETRAHEDRON,{0,4,5,8,-1,-1,-1,-1,},{100,2,1,103,-1,-1,},536870919}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, }}, // Rule 60 {TETRAHEDRON,60,RED_CLASS,4, // tag, mark, rclass, nsons {1,0,1,0,1,0,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,}, // pattern 21, // pat {{0,2},{-1,0},{1,2},{-1,0},{0,3},{-1,0},{-1,-1}, // sonandnode {-1,-1},{-1,-1},{-1,-1},{-1,0},{-1,-1},{-1,-1}, {-1,-1},{-1,-1},{-1,-1},{-1,-1},{-1,-1},{-1,-1}, }, {{TETRAHEDRON,{2,3,4,8,-1,-1,-1,-1,},{1,103,3,101,-1,-1,},0}, // sons {TETRAHEDRON,{3,4,6,2,-1,-1,-1,-1,},{2,100,102,0,-1,-1,},268435456}, {TETRAHEDRON,{0,3,4,6,-1,-1,-1,-1,},{103,1,100,102,-1,-1,},536870912}, {TETRAHEDRON,{1,2,4,8,-1,-1,-1,-1,},{100,0,103,101,-1,-1,},268435458}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, }}, // Rule 61 {TETRAHEDRON,61,RED_CLASS,5, // tag, mark, rclass, nsons {1,0,1,0,1,0,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,}, // pattern 21, // pat {{1,1},{-1,0},{0,2},{-1,0},{0,3},{-1,0},{-1,-1}, // sonandnode {-1,-1},{-1,-1},{-1,-1},{-1,0},{-1,-1},{-1,-1}, {-1,-1},{-1,-1},{-1,-1},{-1,-1},{-1,-1},{-1,-1}, }, {{TETRAHEDRON,{2,3,6,8,-1,-1,-1,-1,},{102,1,4,101,-1,-1,},0}, // sons {TETRAHEDRON,{3,4,6,8,-1,-1,-1,-1,},{2,3,0,103,-1,-1,},268435457}, {TETRAHEDRON,{0,3,4,6,-1,-1,-1,-1,},{103,1,100,102,-1,-1,},536870913}, {TETRAHEDRON,{4,6,8,1,-1,-1,-1,-1,},{1,4,103,100,-1,-1,},536870917}, {TETRAHEDRON,{1,2,6,8,-1,-1,-1,-1,},{100,0,3,101,-1,-1,},268435458}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, }}, // Rule 62 {TETRAHEDRON,62,RED_CLASS,5, // tag, mark, rclass, nsons {1,0,1,0,1,0,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,}, // pattern 21, // pat {{2,0},{-1,0},{0,2},{-1,0},{0,3},{-1,0},{-1,-1}, // sonandnode {-1,-1},{-1,-1},{-1,-1},{-1,0},{-1,-1},{-1,-1}, {-1,-1},{-1,-1},{-1,-1},{-1,-1},{-1,-1},{-1,-1}, }, {{TETRAHEDRON,{2,3,6,8,-1,-1,-1,-1,},{102,1,3,101,-1,-1,},0}, // sons {TETRAHEDRON,{3,6,8,0,-1,-1,-1,-1,},{0,4,103,102,-1,-1,},268435457}, {TETRAHEDRON,{4,6,8,1,-1,-1,-1,-1,},{4,3,103,100,-1,-1,},536870922}, {TETRAHEDRON,{1,2,6,8,-1,-1,-1,-1,},{100,0,2,101,-1,-1,},268435458}, {TETRAHEDRON,{0,4,6,8,-1,-1,-1,-1,},{100,2,1,103,-1,-1,},536870917}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, }}, // Rule 63 {TETRAHEDRON,63,RED_CLASS,5, // tag, mark, rclass, nsons {1,0,1,0,1,0,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,}, // pattern 21, // pat {{1,2},{-1,0},{0,2},{-1,0},{0,3},{-1,0},{-1,-1}, // sonandnode {-1,-1},{-1,-1},{-1,-1},{-1,0},{-1,-1},{-1,-1}, {-1,-1},{-1,-1},{-1,-1},{-1,-1},{-1,-1},{-1,-1}, }, {{TETRAHEDRON,{2,3,6,8,-1,-1,-1,-1,},{102,4,2,101,-1,-1,},0}, // sons {TETRAHEDRON,{1,2,4,8,-1,-1,-1,-1,},{100,2,103,101,-1,-1,},536870922}, {TETRAHEDRON,{4,6,8,2,-1,-1,-1,-1,},{3,0,1,100,-1,-1,},268435458}, {TETRAHEDRON,{0,4,6,8,-1,-1,-1,-1,},{100,2,4,103,-1,-1,},536870914}, {TETRAHEDRON,{3,6,8,0,-1,-1,-1,-1,},{0,3,103,102,-1,-1,},268435457}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, }}, // Rule 64 {TETRAHEDRON,64,RED_CLASS,4, // tag, mark, rclass, nsons {0,1,1,0,1,0,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,}, // pattern 22, // pat {{-1,0},{0,1},{0,2},{-1,0},{1,2},{-1,0},{-1,-1}, // sonandnode {-1,-1},{-1,-1},{-1,-1},{-1,0},{-1,-1},{-1,-1}, {-1,-1},{-1,-1},{-1,-1},{-1,-1},{-1,-1},{-1,-1}, }, {{TETRAHEDRON,{3,5,6,2,-1,-1,-1,-1,},{2,100,102,101,-1,-1,},0}, // sons {TETRAHEDRON,{3,5,8,0,-1,-1,-1,-1,},{101,3,103,2,-1,-1,},536870912}, {TETRAHEDRON,{0,3,5,6,-1,-1,-1,-1,},{1,0,100,102,-1,-1,},268435456}, {TETRAHEDRON,{0,1,5,8,-1,-1,-1,-1,},{100,101,1,103,-1,-1,},805306384}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, }}, // Rule 65 {TETRAHEDRON,65,RED_CLASS,5, // tag, mark, rclass, nsons {0,1,1,0,1,0,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,}, // pattern 22, // pat {{-1,0},{0,1},{0,2},{-1,0},{1,2},{-1,0},{-1,-1}, // sonandnode {-1,-1},{-1,-1},{-1,-1},{-1,0},{-1,-1},{-1,-1}, {-1,-1},{-1,-1},{-1,-1},{-1,-1},{-1,-1},{-1,-1}, }, {{TETRAHEDRON,{3,5,6,2,-1,-1,-1,-1,},{2,100,102,101,-1,-1,},0}, // sons {TETRAHEDRON,{3,6,8,0,-1,-1,-1,-1,},{2,4,103,102,-1,-1,},536870916}, {TETRAHEDRON,{5,6,8,3,-1,-1,-1,-1,},{3,1,101,0,-1,-1,},268435456}, {TETRAHEDRON,{1,5,6,8,-1,-1,-1,-1,},{100,2,4,101,-1,-1,},536870912}, {TETRAHEDRON,{0,1,6,8,-1,-1,-1,-1,},{100,3,1,103,-1,-1,},805306388}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, }}, // Rule 66 {TETRAHEDRON,66,RED_CLASS,5, // tag, mark, rclass, nsons {0,1,1,0,1,0,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,}, // pattern 22, // pat {{-1,0},{3,0},{0,2},{-1,0},{0,3},{-1,0},{-1,-1}, // sonandnode {-1,-1},{-1,-1},{-1,-1},{-1,0},{-1,-1},{-1,-1}, {-1,-1},{-1,-1},{-1,-1},{-1,-1},{-1,-1},{-1,-1}, }, {{TETRAHEDRON,{2,3,6,8,-1,-1,-1,-1,},{102,1,3,101,-1,-1,},0}, // sons {TETRAHEDRON,{3,6,8,0,-1,-1,-1,-1,},{0,2,103,102,-1,-1,},268435457}, {TETRAHEDRON,{0,1,6,8,-1,-1,-1,-1,},{100,4,1,103,-1,-1,},536870917}, {TETRAHEDRON,{5,6,8,2,-1,-1,-1,-1,},{4,0,101,100,-1,-1,},268435458}, {TETRAHEDRON,{1,5,6,8,-1,-1,-1,-1,},{100,3,2,101,-1,-1,},805306389}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, }}, // Rule 67 {TETRAHEDRON,67,RED_CLASS,5, // tag, mark, rclass, nsons {0,1,1,0,1,0,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,}, // pattern 22, // pat {{-1,0},{1,0},{0,2},{-1,0},{0,3},{-1,0},{-1,-1}, // sonandnode {-1,-1},{-1,-1},{-1,-1},{-1,0},{-1,-1},{-1,-1}, {-1,-1},{-1,-1},{-1,-1},{-1,-1},{-1,-1},{-1,-1}, }, {{TETRAHEDRON,{2,3,6,8,-1,-1,-1,-1,},{102,4,1,101,-1,-1,},0}, // sons {TETRAHEDRON,{5,6,8,2,-1,-1,-1,-1,},{3,0,101,100,-1,-1,},268435458}, {TETRAHEDRON,{0,1,5,8,-1,-1,-1,-1,},{100,101,3,103,-1,-1,},805306418}, {TETRAHEDRON,{0,5,6,8,-1,-1,-1,-1,},{100,1,4,2,-1,-1,},536870914}, {TETRAHEDRON,{3,6,8,0,-1,-1,-1,-1,},{0,3,103,102,-1,-1,},268435457}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, }}, // Rule 68 {TETRAHEDRON,68,RED_CLASS,4, // tag, mark, rclass, nsons {1,0,0,1,1,0,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,}, // pattern 25, // pat {{0,1},{-1,0},{-1,0},{0,2},{1,3},{-1,0},{-1,-1}, // sonandnode {-1,-1},{-1,-1},{-1,-1},{-1,0},{-1,-1},{-1,-1}, {-1,-1},{-1,-1},{-1,-1},{-1,-1},{-1,-1},{-1,-1}, }, {{TETRAHEDRON,{2,4,7,0,-1,-1,-1,-1,},{2,103,102,100,-1,-1,},0}, // sons {TETRAHEDRON,{1,2,4,8,-1,-1,-1,-1,},{100,2,103,101,-1,-1,},536870920}, {TETRAHEDRON,{4,7,8,2,-1,-1,-1,-1,},{103,3,1,0,-1,-1,},268435456}, {TETRAHEDRON,{2,3,7,8,-1,-1,-1,-1,},{102,103,2,101,-1,-1,},536870916}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, }}, // Rule 69 {TETRAHEDRON,69,RED_CLASS,5, // tag, mark, rclass, nsons {0,1,0,1,1,0,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,}, // pattern 26, // pat {{-1,0},{0,1},{-1,0},{0,2},{1,2},{-1,0},{-1,-1}, // sonandnode {-1,-1},{-1,-1},{-1,-1},{-1,0},{-1,-1},{-1,-1}, {-1,-1},{-1,-1},{-1,-1},{-1,-1},{-1,-1},{-1,-1}, }, {{TETRAHEDRON,{3,5,7,2,-1,-1,-1,-1,},{1,3,102,101,-1,-1,},0}, // sons {TETRAHEDRON,{5,7,8,3,-1,-1,-1,-1,},{4,103,101,0,-1,-1,},268435456}, {TETRAHEDRON,{0,1,5,7,-1,-1,-1,-1,},{100,4,3,103,-1,-1,},536870917}, {TETRAHEDRON,{2,5,7,0,-1,-1,-1,-1,},{0,2,102,100,-1,-1,},268435457}, {TETRAHEDRON,{1,5,7,8,-1,-1,-1,-1,},{2,1,103,101,-1,-1,},536870912}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, }}, // Rule 70 {TETRAHEDRON,70,RED_CLASS,5, // tag, mark, rclass, nsons {0,1,0,1,1,0,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,}, // pattern 26, // pat {{-1,0},{0,1},{-1,0},{0,2},{1,2},{-1,0},{-1,-1}, // sonandnode {-1,-1},{-1,-1},{-1,-1},{-1,0},{-1,-1},{-1,-1}, {-1,-1},{-1,-1},{-1,-1},{-1,-1},{-1,-1},{-1,-1}, }, {{TETRAHEDRON,{3,5,7,2,-1,-1,-1,-1,},{1,4,102,101,-1,-1,},0}, // sons {TETRAHEDRON,{5,7,8,3,-1,-1,-1,-1,},{3,103,101,0,-1,-1,},268435456}, {TETRAHEDRON,{0,1,5,8,-1,-1,-1,-1,},{100,101,3,103,-1,-1,},805306416}, {TETRAHEDRON,{0,5,7,8,-1,-1,-1,-1,},{4,1,103,2,-1,-1,},536870912}, {TETRAHEDRON,{2,5,7,0,-1,-1,-1,-1,},{0,3,102,100,-1,-1,},268435457}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, }}, // Rule 71 {TETRAHEDRON,71,RED_CLASS,5, // tag, mark, rclass, nsons {0,1,0,1,1,0,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,}, // pattern 26, // pat {{-1,0},{1,1},{-1,0},{0,2},{0,3},{-1,0},{-1,-1}, // sonandnode {-1,-1},{-1,-1},{-1,-1},{-1,0},{-1,-1},{-1,-1}, {-1,-1},{-1,-1},{-1,-1},{-1,-1},{-1,-1},{-1,-1}, }, {{TETRAHEDRON,{2,3,7,8,-1,-1,-1,-1,},{102,103,2,101,-1,-1,},0}, // sons {TETRAHEDRON,{2,5,7,0,-1,-1,-1,-1,},{2,4,102,100,-1,-1,},536870926}, {TETRAHEDRON,{5,7,8,2,-1,-1,-1,-1,},{3,0,101,1,-1,-1,},268435458}, {TETRAHEDRON,{1,5,7,8,-1,-1,-1,-1,},{4,2,103,101,-1,-1,},536870914}, {TETRAHEDRON,{0,1,5,7,-1,-1,-1,-1,},{100,3,1,103,-1,-1,},805306398}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, }}, // Rule 72 {TETRAHEDRON,72,RED_CLASS,4, // tag, mark, rclass, nsons {0,1,0,1,1,0,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,}, // pattern 26, // pat {{-1,0},{1,1},{-1,0},{0,2},{0,3},{-1,0},{-1,-1}, // sonandnode {-1,-1},{-1,-1},{-1,-1},{-1,0},{-1,-1},{-1,-1}, {-1,-1},{-1,-1},{-1,-1},{-1,-1},{-1,-1},{-1,-1}, }, {{TETRAHEDRON,{2,3,7,8,-1,-1,-1,-1,},{102,103,3,101,-1,-1,},0}, // sons {TETRAHEDRON,{2,5,8,0,-1,-1,-1,-1,},{101,2,3,100,-1,-1,},536870926}, {TETRAHEDRON,{0,1,5,8,-1,-1,-1,-1,},{100,101,1,103,-1,-1,},805306398}, {TETRAHEDRON,{0,2,7,8,-1,-1,-1,-1,},{102,0,103,1,-1,-1,},268435458}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, }}, // Rule 73 {TETRAHEDRON,73,RED_CLASS,5, // tag, mark, rclass, nsons {0,0,1,1,1,0,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,}, // pattern 28, // pat {{-1,0},{-1,0},{0,2},{1,1},{0,3},{-1,0},{-1,-1}, // sonandnode {-1,-1},{-1,-1},{-1,-1},{-1,0},{-1,-1},{-1,-1}, {-1,-1},{-1,-1},{-1,-1},{-1,-1},{-1,-1},{-1,-1}, }, {{TETRAHEDRON,{2,3,6,8,-1,-1,-1,-1,},{102,1,4,101,-1,-1,},0}, // sons {TETRAHEDRON,{6,7,8,3,-1,-1,-1,-1,},{3,103,0,102,-1,-1,},268435457}, {TETRAHEDRON,{0,1,6,7,-1,-1,-1,-1,},{100,3,102,103,-1,-1,},805306369}, {TETRAHEDRON,{1,6,7,8,-1,-1,-1,-1,},{2,1,103,4,-1,-1,},536870913}, {TETRAHEDRON,{1,2,6,8,-1,-1,-1,-1,},{100,0,3,101,-1,-1,},268435458}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, }}, // Rule 74 {TETRAHEDRON,74,RED_CLASS,5, // tag, mark, rclass, nsons {0,0,1,1,1,0,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,}, // pattern 28, // pat {{-1,0},{-1,0},{0,2},{1,1},{0,3},{-1,0},{-1,-1}, // sonandnode {-1,-1},{-1,-1},{-1,-1},{-1,0},{-1,-1},{-1,-1}, {-1,-1},{-1,-1},{-1,-1},{-1,-1},{-1,-1},{-1,-1}, }, {{TETRAHEDRON,{2,3,6,8,-1,-1,-1,-1,},{102,1,3,101,-1,-1,},0}, // sons {TETRAHEDRON,{6,7,8,3,-1,-1,-1,-1,},{4,103,0,102,-1,-1,},268435457}, {TETRAHEDRON,{0,1,6,8,-1,-1,-1,-1,},{100,3,4,103,-1,-1,},536870922}, {TETRAHEDRON,{1,2,6,8,-1,-1,-1,-1,},{100,0,2,101,-1,-1,},268435458}, {TETRAHEDRON,{0,6,7,8,-1,-1,-1,-1,},{102,1,103,2,-1,-1,},536870913}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, }}, // Rule 75 {TETRAHEDRON,75,RED_CLASS,4, // tag, mark, rclass, nsons {0,0,1,1,1,0,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,}, // pattern 28, // pat {{-1,0},{-1,0},{1,2},{0,2},{0,3},{-1,0},{-1,-1}, // sonandnode {-1,-1},{-1,-1},{-1,-1},{-1,0},{-1,-1},{-1,-1}, {-1,-1},{-1,-1},{-1,-1},{-1,-1},{-1,-1},{-1,-1}, }, {{TETRAHEDRON,{2,3,7,8,-1,-1,-1,-1,},{102,103,3,101,-1,-1,},0}, // sons {TETRAHEDRON,{1,2,6,7,-1,-1,-1,-1,},{100,102,2,3,-1,-1,},536870914}, {TETRAHEDRON,{0,1,6,7,-1,-1,-1,-1,},{100,1,102,103,-1,-1,},805306402}, {TETRAHEDRON,{1,2,7,8,-1,-1,-1,-1,},{1,0,103,101,-1,-1,},268435458}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, }}, // Rule 76 {TETRAHEDRON,76,RED_CLASS,5, // tag, mark, rclass, nsons {0,0,1,1,1,0,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,}, // pattern 28, // pat {{-1,0},{-1,0},{1,2},{0,2},{0,3},{-1,0},{-1,-1}, // sonandnode {-1,-1},{-1,-1},{-1,-1},{-1,0},{-1,-1},{-1,-1}, {-1,-1},{-1,-1},{-1,-1},{-1,-1},{-1,-1},{-1,-1}, }, {{TETRAHEDRON,{2,3,7,8,-1,-1,-1,-1,},{102,103,2,101,-1,-1,},0}, // sons {TETRAHEDRON,{1,2,6,8,-1,-1,-1,-1,},{100,2,4,101,-1,-1,},536870922}, {TETRAHEDRON,{6,7,8,2,-1,-1,-1,-1,},{3,0,1,102,-1,-1,},268435458}, {TETRAHEDRON,{0,6,7,8,-1,-1,-1,-1,},{102,2,103,4,-1,-1,},536870914}, {TETRAHEDRON,{0,1,6,8,-1,-1,-1,-1,},{100,1,3,103,-1,-1,},805306410}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, }}, // Rule 77 {TETRAHEDRON,77,RED_CLASS,5, // tag, mark, rclass, nsons {1,1,0,0,0,1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,}, // pattern 35, // pat {{0,0},{0,1},{-1,0},{-1,0},{-1,0},{0,2},{-1,-1}, // sonandnode {-1,-1},{-1,-1},{-1,-1},{-1,0},{-1,-1},{-1,-1}, {-1,-1},{-1,-1},{-1,-1},{-1,-1},{-1,-1},{-1,-1}, }, {{TETRAHEDRON,{4,5,9,3,-1,-1,-1,-1,},{4,101,1,2,-1,-1,},0}, // sons {TETRAHEDRON,{0,3,4,9,-1,-1,-1,-1,},{103,0,3,102,-1,-1,},268435458}, {TETRAHEDRON,{3,4,5,1,-1,-1,-1,-1,},{0,100,101,103,-1,-1,},268435459}, {TETRAHEDRON,{2,4,9,0,-1,-1,-1,-1,},{4,1,102,100,-1,-1,},536870922}, {TETRAHEDRON,{2,4,5,9,-1,-1,-1,-1,},{100,0,101,3,-1,-1,},268435456}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, }}, // Rule 78 {TETRAHEDRON,78,RED_CLASS,5, // tag, mark, rclass, nsons {1,1,0,0,0,1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,}, // pattern 35, // pat {{0,1},{3,2},{-1,0},{-1,0},{-1,0},{0,2},{-1,-1}, // sonandnode {-1,-1},{-1,-1},{-1,-1},{-1,0},{-1,-1},{-1,-1}, {-1,-1},{-1,-1},{-1,-1},{-1,-1},{-1,-1},{-1,-1}, }, {{TETRAHEDRON,{3,4,9,1,-1,-1,-1,-1,},{1,4,101,103,-1,-1,},0}, // sons {TETRAHEDRON,{0,3,4,9,-1,-1,-1,-1,},{103,0,2,102,-1,-1,},268435456}, {TETRAHEDRON,{2,4,9,0,-1,-1,-1,-1,},{3,1,102,100,-1,-1,},536870920}, {TETRAHEDRON,{2,4,5,9,-1,-1,-1,-1,},{100,4,101,2,-1,-1,},805306376}, {TETRAHEDRON,{4,5,9,1,-1,-1,-1,-1,},{3,101,0,100,-1,-1,},268435457}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, }}, // Rule 79 {TETRAHEDRON,79,RED_CLASS,4, // tag, mark, rclass, nsons {1,1,0,0,0,1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,}, // pattern 35, // pat {{1,1},{0,2},{-1,0},{-1,0},{-1,0},{0,3},{-1,-1}, // sonandnode {-1,-1},{-1,-1},{-1,-1},{-1,0},{-1,-1},{-1,-1}, {-1,-1},{-1,-1},{-1,-1},{-1,-1},{-1,-1},{-1,-1}, }, {{TETRAHEDRON,{0,3,5,9,-1,-1,-1,-1,},{2,101,3,102,-1,-1,},0}, // sons {TETRAHEDRON,{3,4,5,1,-1,-1,-1,-1,},{2,100,101,103,-1,-1,},536870916}, {TETRAHEDRON,{0,3,4,5,-1,-1,-1,-1,},{103,1,100,0,-1,-1,},268435456}, {TETRAHEDRON,{2,5,9,0,-1,-1,-1,-1,},{101,0,102,100,-1,-1,},268435458}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, }}, // Rule 80 {TETRAHEDRON,80,RED_CLASS,5, // tag, mark, rclass, nsons {1,1,0,0,0,1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,}, // pattern 35, // pat {{0,1},{1,1},{-1,0},{-1,0},{-1,0},{0,2},{-1,-1}, // sonandnode {-1,-1},{-1,-1},{-1,-1},{-1,0},{-1,-1},{-1,-1}, {-1,-1},{-1,-1},{-1,-1},{-1,-1},{-1,-1},{-1,-1}, }, {{TETRAHEDRON,{3,4,9,1,-1,-1,-1,-1,},{4,2,101,103,-1,-1,},0}, // sons {TETRAHEDRON,{2,5,9,0,-1,-1,-1,-1,},{101,3,102,100,-1,-1,},805306401}, {TETRAHEDRON,{4,5,9,1,-1,-1,-1,-1,},{3,101,0,100,-1,-1,},268435457}, {TETRAHEDRON,{0,4,5,9,-1,-1,-1,-1,},{100,2,1,4,-1,-1,},536870913}, {TETRAHEDRON,{0,3,4,9,-1,-1,-1,-1,},{103,0,3,102,-1,-1,},268435456}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, }}, // Rule 81 {TETRAHEDRON,81,RED_CLASS,5, // tag, mark, rclass, nsons {1,0,1,0,0,1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,}, // pattern 37, // pat {{0,1},{-1,0},{1,2},{-1,0},{-1,0},{0,2},{-1,-1}, // sonandnode {-1,-1},{-1,-1},{-1,-1},{-1,0},{-1,-1},{-1,-1}, {-1,-1},{-1,-1},{-1,-1},{-1,-1},{-1,-1},{-1,-1}, }, {{TETRAHEDRON,{3,4,9,1,-1,-1,-1,-1,},{1,4,101,103,-1,-1,},0}, // sons {TETRAHEDRON,{3,4,6,9,-1,-1,-1,-1,},{2,3,102,0,-1,-1,},268435456}, {TETRAHEDRON,{0,3,4,6,-1,-1,-1,-1,},{103,1,100,102,-1,-1,},536870912}, {TETRAHEDRON,{4,6,9,2,-1,-1,-1,-1,},{1,102,4,100,-1,-1,},536870916}, {TETRAHEDRON,{1,2,4,9,-1,-1,-1,-1,},{100,3,0,101,-1,-1,},268435457}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, }}, // Rule 82 {TETRAHEDRON,82,RED_CLASS,5, // tag, mark, rclass, nsons {1,0,1,0,0,1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,}, // pattern 37, // pat {{0,1},{-1,0},{2,1},{-1,0},{-1,0},{0,2},{-1,-1}, // sonandnode {-1,-1},{-1,-1},{-1,-1},{-1,0},{-1,-1},{-1,-1}, {-1,-1},{-1,-1},{-1,-1},{-1,-1},{-1,-1},{-1,-1}, }, {{TETRAHEDRON,{3,4,9,1,-1,-1,-1,-1,},{1,3,101,103,-1,-1,},0}, // sons {TETRAHEDRON,{0,3,4,9,-1,-1,-1,-1,},{103,0,4,102,-1,-1,},268435456}, {TETRAHEDRON,{4,6,9,2,-1,-1,-1,-1,},{4,102,3,100,-1,-1,},536870917}, {TETRAHEDRON,{1,2,4,9,-1,-1,-1,-1,},{100,2,0,101,-1,-1,},268435457}, {TETRAHEDRON,{0,4,6,9,-1,-1,-1,-1,},{100,2,102,1,-1,-1,},536870920}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, }}, // Rule 83 {TETRAHEDRON,83,RED_CLASS,4, // tag, mark, rclass, nsons {1,0,1,0,0,1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,}, // pattern 37, // pat {{1,1},{-1,0},{0,1},{-1,0},{-1,0},{0,2},{-1,-1}, // sonandnode {-1,-1},{-1,-1},{-1,-1},{-1,0},{-1,-1},{-1,-1}, {-1,-1},{-1,-1},{-1,-1},{-1,-1},{-1,-1},{-1,-1}, }, {{TETRAHEDRON,{3,6,9,1,-1,-1,-1,-1,},{102,3,101,1,-1,-1,},0}, // sons {TETRAHEDRON,{3,4,6,1,-1,-1,-1,-1,},{2,100,0,103,-1,-1,},268435459}, {TETRAHEDRON,{0,3,4,6,-1,-1,-1,-1,},{103,1,100,102,-1,-1,},536870915}, {TETRAHEDRON,{1,2,6,9,-1,-1,-1,-1,},{100,102,0,101,-1,-1,},268435457}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, }}, // Rule 84 {TETRAHEDRON,84,RED_CLASS,5, // tag, mark, rclass, nsons {1,0,1,0,0,1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,}, // pattern 37, // pat {{0,1},{-1,0},{1,2},{-1,0},{-1,0},{0,2},{-1,-1}, // sonandnode {-1,-1},{-1,-1},{-1,-1},{-1,0},{-1,-1},{-1,-1}, {-1,-1},{-1,-1},{-1,-1},{-1,-1},{-1,-1},{-1,-1}, }, {{TETRAHEDRON,{3,4,9,1,-1,-1,-1,-1,},{4,2,101,103,-1,-1,},0}, // sons {TETRAHEDRON,{1,2,6,9,-1,-1,-1,-1,},{100,102,2,101,-1,-1,},536870917}, {TETRAHEDRON,{4,6,9,1,-1,-1,-1,-1,},{3,1,0,100,-1,-1,},268435457}, {TETRAHEDRON,{0,4,6,9,-1,-1,-1,-1,},{100,2,102,4,-1,-1,},536870913}, {TETRAHEDRON,{0,3,4,9,-1,-1,-1,-1,},{103,0,3,102,-1,-1,},268435456}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, }}, // Rule 85 {TETRAHEDRON,85,RED_CLASS,9, // tag, mark, rclass, nsons {0,1,1,0,0,1,-1,-1,-1,-1,1,-1,-1,-1,-1,-1,-1,-1,-1,}, // pattern 1062, // pat {{-1,0},{0,0},{0,1},{-1,0},{-1,0},{0,2},{-1,-1}, // sonandnode {-1,-1},{-1,-1},{-1,-1},{1,2},{-1,-1},{-1,-1}, {-1,-1},{-1,-1},{-1,-1},{-1,-1},{-1,-1},{-1,-1}, }, {{TETRAHEDRON,{5,6,9,2,-1,-1,-1,-1,},{1,102,101,100,-1,-1,},0}, // sons {TETRAHEDRON,{6,9,14,5,-1,-1,-1,-1,},{4,7,6,0,-1,-1,},268435456}, {TETRAHEDRON,{1,3,14,0,-1,-1,-1,-1,},{8,3,5,103,-1,-1,},1073741984}, {TETRAHEDRON,{3,6,14,0,-1,-1,-1,-1,},{4,6,2,102,-1,-1,},805306400}, {TETRAHEDRON,{9,6,14,3,-1,-1,-1,-1,},{1,3,8,102,-1,-1,},536870912}, {TETRAHEDRON,{0,1,5,14,-1,-1,-1,-1,},{100,7,6,2,-1,-1,},1342177952}, {TETRAHEDRON,{0,5,6,14,-1,-1,-1,-1,},{100,1,3,5,-1,-1,},536870920}, {TETRAHEDRON,{5,9,14,1,-1,-1,-1,-1,},{1,8,5,101,-1,-1,},536870916}, {TETRAHEDRON,{1,3,9,14,-1,-1,-1,-1,},{101,4,7,2,-1,-1,},805306384}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, }}, // Rule 86 {TETRAHEDRON,86,RED_CLASS,9, // tag, mark, rclass, nsons {0,1,1,0,0,1,-1,-1,-1,-1,1,-1,-1,-1,-1,-1,-1,-1,-1,}, // pattern 1062, // pat {{-1,0},{0,0},{0,1},{-1,0},{-1,0},{0,2},{-1,-1}, // sonandnode {-1,-1},{-1,-1},{-1,-1},{1,2},{-1,-1},{-1,-1}, {-1,-1},{-1,-1},{-1,-1},{-1,-1},{-1,-1},{-1,-1}, }, {{TETRAHEDRON,{5,6,9,2,-1,-1,-1,-1,},{1,102,101,100,-1,-1,},0}, // sons {TETRAHEDRON,{6,9,14,5,-1,-1,-1,-1,},{4,8,6,0,-1,-1,},268435456}, {TETRAHEDRON,{1,3,14,0,-1,-1,-1,-1,},{7,3,5,103,-1,-1,},1073741968}, {TETRAHEDRON,{3,9,14,0,-1,-1,-1,-1,},{8,4,2,102,-1,-1,},805306384}, {TETRAHEDRON,{9,6,14,0,-1,-1,-1,-1,},{1,5,3,102,-1,-1,},536870912}, {TETRAHEDRON,{0,1,6,14,-1,-1,-1,-1,},{100,6,4,2,-1,-1,},805306400}, {TETRAHEDRON,{1,5,6,14,-1,-1,-1,-1,},{100,1,5,7,-1,-1,},536870920}, {TETRAHEDRON,{1,3,5,14,-1,-1,-1,-1,},{101,8,6,2,-1,-1,},1342177424}, {TETRAHEDRON,{5,9,14,3,-1,-1,-1,-1,},{1,3,7,101,-1,-1,},536870916}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, }}, // Rule 87 {TETRAHEDRON,87,RED_CLASS,4, // tag, mark, rclass, nsons {0,1,1,0,0,1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,}, // pattern 38, // pat {{-1,0},{0,1},{0,2},{-1,0},{-1,0},{0,3},{-1,-1}, // sonandnode {-1,-1},{-1,-1},{-1,-1},{-1,0},{-1,-1},{-1,-1}, {-1,-1},{-1,-1},{-1,-1},{-1,-1},{-1,-1},{-1,-1}, }, {{TETRAHEDRON,{3,5,6,9,-1,-1,-1,-1,},{2,3,102,101,-1,-1,},0}, // sons {TETRAHEDRON,{1,3,5,0,-1,-1,-1,-1,},{101,2,100,103,-1,-1,},536870912}, {TETRAHEDRON,{0,3,5,6,-1,-1,-1,-1,},{1,0,100,102,-1,-1,},268435456}, {TETRAHEDRON,{5,6,9,2,-1,-1,-1,-1,},{0,102,101,100,-1,-1,},268435457}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, }}, // Rule 88 {TETRAHEDRON,88,RED_CLASS,4, // tag, mark, rclass, nsons {0,1,1,0,0,1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,}, // pattern 38, // pat {{-1,0},{0,2},{2,1},{-1,0},{-1,0},{0,3},{-1,-1}, // sonandnode {-1,-1},{-1,-1},{-1,-1},{-1,0},{-1,-1},{-1,-1}, {-1,-1},{-1,-1},{-1,-1},{-1,-1},{-1,-1},{-1,-1}, }, {{TETRAHEDRON,{0,3,5,9,-1,-1,-1,-1,},{1,101,3,102,-1,-1,},0}, // sons {TETRAHEDRON,{1,3,5,0,-1,-1,-1,-1,},{101,0,100,103,-1,-1,},268435456}, {TETRAHEDRON,{5,6,9,2,-1,-1,-1,-1,},{3,102,101,100,-1,-1,},536870918}, {TETRAHEDRON,{0,5,6,9,-1,-1,-1,-1,},{100,2,102,0,-1,-1,},268435458}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, }}, // Rule 89 {TETRAHEDRON,89,RED_CLASS,4, // tag, mark, rclass, nsons {0,1,1,0,0,1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,}, // pattern 38, // pat {{-1,0},{0,1},{0,2},{-1,0},{-1,0},{0,3},{-1,-1}, // sonandnode {-1,-1},{-1,-1},{-1,-1},{-1,0},{-1,-1},{-1,-1}, {-1,-1},{-1,-1},{-1,-1},{-1,-1},{-1,-1},{-1,-1}, }, {{TETRAHEDRON,{3,5,6,9,-1,-1,-1,-1,},{2,3,102,101,-1,-1,},0}, // sons {TETRAHEDRON,{1,3,6,0,-1,-1,-1,-1,},{2,102,100,103,-1,-1,},536870924}, {TETRAHEDRON,{1,3,5,6,-1,-1,-1,-1,},{101,0,100,1,-1,-1,},268435456}, {TETRAHEDRON,{5,6,9,2,-1,-1,-1,-1,},{0,102,101,100,-1,-1,},268435457}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, }}, // Rule 90 {TETRAHEDRON,90,RED_CLASS,4, // tag, mark, rclass, nsons {0,1,1,0,0,1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,}, // pattern 38, // pat {{-1,0},{2,0},{0,1},{-1,0},{-1,0},{0,2},{-1,-1}, // sonandnode {-1,-1},{-1,-1},{-1,-1},{-1,0},{-1,-1},{-1,-1}, {-1,-1},{-1,-1},{-1,-1},{-1,-1},{-1,-1},{-1,-1}, }, {{TETRAHEDRON,{3,6,9,1,-1,-1,-1,-1,},{102,3,101,1,-1,-1,},0}, // sons {TETRAHEDRON,{1,3,6,0,-1,-1,-1,-1,},{0,102,100,103,-1,-1,},268435459}, {TETRAHEDRON,{5,6,9,2,-1,-1,-1,-1,},{3,102,101,100,-1,-1,},536870917}, {TETRAHEDRON,{1,5,6,9,-1,-1,-1,-1,},{100,2,0,101,-1,-1,},268435457}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, }}, // Rule 91 {TETRAHEDRON,91,RED_CLASS,4, // tag, mark, rclass, nsons {0,1,1,0,0,1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,}, // pattern 38, // pat {{-1,0},{1,0},{1,1},{-1,0},{-1,0},{0,2},{-1,-1}, // sonandnode {-1,-1},{-1,-1},{-1,-1},{-1,0},{-1,-1},{-1,-1}, {-1,-1},{-1,-1},{-1,-1},{-1,-1},{-1,-1},{-1,-1}, }, {{TETRAHEDRON,{1,3,9,0,-1,-1,-1,-1,},{101,102,2,103,-1,-1,},0}, // sons {TETRAHEDRON,{5,6,9,2,-1,-1,-1,-1,},{3,102,101,100,-1,-1,},805306394}, {TETRAHEDRON,{0,1,5,9,-1,-1,-1,-1,},{100,101,3,0,-1,-1,},268435458}, {TETRAHEDRON,{0,5,6,9,-1,-1,-1,-1,},{100,1,102,2,-1,-1,},536870922}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, }}, // Rule 92 {TETRAHEDRON,92,RED_CLASS,4, // tag, mark, rclass, nsons {0,1,1,0,0,1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,}, // pattern 38, // pat {{-1,0},{1,0},{1,1},{-1,0},{-1,0},{0,2},{-1,-1}, // sonandnode {-1,-1},{-1,-1},{-1,-1},{-1,0},{-1,-1},{-1,-1}, {-1,-1},{-1,-1},{-1,-1},{-1,-1},{-1,-1},{-1,-1}, }, {{TETRAHEDRON,{1,3,9,0,-1,-1,-1,-1,},{101,102,2,103,-1,-1,},0}, // sons {TETRAHEDRON,{5,6,9,2,-1,-1,-1,-1,},{3,102,101,100,-1,-1,},805306390}, {TETRAHEDRON,{0,1,6,9,-1,-1,-1,-1,},{100,3,102,0,-1,-1,},268435458}, {TETRAHEDRON,{1,5,6,9,-1,-1,-1,-1,},{100,1,2,101,-1,-1,},536870918}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, }}, // Rule 93 {TETRAHEDRON,93,RED_CLASS,5, // tag, mark, rclass, nsons {1,0,0,1,0,1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,}, // pattern 41, // pat {{0,1},{-1,0},{-1,0},{1,2},{-1,0},{0,2},{-1,-1}, // sonandnode {-1,-1},{-1,-1},{-1,-1},{-1,0},{-1,-1},{-1,-1}, {-1,-1},{-1,-1},{-1,-1},{-1,-1},{-1,-1},{-1,-1}, }, {{TETRAHEDRON,{3,4,9,1,-1,-1,-1,-1,},{1,4,101,103,-1,-1,},0}, // sons {TETRAHEDRON,{3,4,7,9,-1,-1,-1,-1,},{103,3,102,0,-1,-1,},268435456}, {TETRAHEDRON,{2,4,7,0,-1,-1,-1,-1,},{3,103,102,100,-1,-1,},805306420}, {TETRAHEDRON,{4,7,9,2,-1,-1,-1,-1,},{1,102,4,2,-1,-1,},536870916}, {TETRAHEDRON,{1,2,4,9,-1,-1,-1,-1,},{100,3,0,101,-1,-1,},268435457}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, }}, // Rule 94 {TETRAHEDRON,94,RED_CLASS,5, // tag, mark, rclass, nsons {1,0,0,1,0,1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,}, // pattern 41, // pat {{0,1},{-1,0},{-1,0},{1,2},{-1,0},{0,2},{-1,-1}, // sonandnode {-1,-1},{-1,-1},{-1,-1},{-1,0},{-1,-1},{-1,-1}, {-1,-1},{-1,-1},{-1,-1},{-1,-1},{-1,-1},{-1,-1}, }, {{TETRAHEDRON,{3,4,9,1,-1,-1,-1,-1,},{1,3,101,103,-1,-1,},0}, // sons {TETRAHEDRON,{3,4,7,9,-1,-1,-1,-1,},{103,4,102,0,-1,-1,},268435456}, {TETRAHEDRON,{2,4,9,0,-1,-1,-1,-1,},{3,4,102,100,-1,-1,},536870917}, {TETRAHEDRON,{1,2,4,9,-1,-1,-1,-1,},{100,2,0,101,-1,-1,},268435457}, {TETRAHEDRON,{4,7,9,0,-1,-1,-1,-1,},{1,102,2,103,-1,-1,},536870916}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, }}, // Rule 95 {TETRAHEDRON,95,RED_CLASS,4, // tag, mark, rclass, nsons {1,0,0,1,0,1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,}, // pattern 41, // pat {{1,2},{-1,0},{-1,0},{0,1},{-1,0},{0,2},{-1,-1}, // sonandnode {-1,-1},{-1,-1},{-1,-1},{-1,0},{-1,-1},{-1,-1}, {-1,-1},{-1,-1},{-1,-1},{-1,-1},{-1,-1},{-1,-1}, }, {{TETRAHEDRON,{3,7,9,1,-1,-1,-1,-1,},{102,3,101,103,-1,-1,},0}, // sons {TETRAHEDRON,{1,2,4,7,-1,-1,-1,-1,},{100,2,103,3,-1,-1,},536870913}, {TETRAHEDRON,{2,4,7,0,-1,-1,-1,-1,},{1,103,102,100,-1,-1,},805306385}, {TETRAHEDRON,{1,2,7,9,-1,-1,-1,-1,},{1,102,0,101,-1,-1,},268435457}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, }}, // Rule 96 {TETRAHEDRON,96,RED_CLASS,5, // tag, mark, rclass, nsons {1,0,0,1,0,1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,}, // pattern 41, // pat {{1,2},{-1,0},{-1,0},{0,1},{-1,0},{0,2},{-1,-1}, // sonandnode {-1,-1},{-1,-1},{-1,-1},{-1,0},{-1,-1},{-1,-1}, {-1,-1},{-1,-1},{-1,-1},{-1,-1},{-1,-1},{-1,-1}, }, {{TETRAHEDRON,{3,7,9,1,-1,-1,-1,-1,},{102,2,101,103,-1,-1,},0}, // sons {TETRAHEDRON,{1,2,4,9,-1,-1,-1,-1,},{100,4,2,101,-1,-1,},536870925}, {TETRAHEDRON,{1,4,7,9,-1,-1,-1,-1,},{103,3,0,1,-1,-1,},268435457}, {TETRAHEDRON,{4,7,9,0,-1,-1,-1,-1,},{2,102,4,103,-1,-1,},536870917}, {TETRAHEDRON,{2,4,9,0,-1,-1,-1,-1,},{1,3,102,100,-1,-1,},805306397}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, }}, // Rule 97 {TETRAHEDRON,97,RED_CLASS,5, // tag, mark, rclass, nsons {0,1,0,1,0,1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,}, // pattern 42, // pat {{-1,0},{0,1},{-1,0},{0,2},{-1,0},{0,3},{-1,-1}, // sonandnode {-1,-1},{-1,-1},{-1,-1},{-1,0},{-1,-1},{-1,-1}, {-1,-1},{-1,-1},{-1,-1},{-1,-1},{-1,-1},{-1,-1}, }, {{TETRAHEDRON,{3,5,7,9,-1,-1,-1,-1,},{1,4,102,101,-1,-1,},0}, // sons {TETRAHEDRON,{1,3,5,7,-1,-1,-1,-1,},{101,0,2,103,-1,-1,},268435456}, {TETRAHEDRON,{0,1,5,7,-1,-1,-1,-1,},{100,1,3,103,-1,-1,},536870920}, {TETRAHEDRON,{2,5,7,0,-1,-1,-1,-1,},{4,2,102,100,-1,-1,},805306408}, {TETRAHEDRON,{5,7,9,2,-1,-1,-1,-1,},{0,102,101,3,-1,-1,},268435457}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, }}, // Rule 98 {TETRAHEDRON,98,RED_CLASS,5, // tag, mark, rclass, nsons {0,1,0,1,0,1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,}, // pattern 42, // pat {{-1,0},{0,1},{-1,0},{0,2},{-1,0},{0,3},{-1,-1}, // sonandnode {-1,-1},{-1,-1},{-1,-1},{-1,0},{-1,-1},{-1,-1}, {-1,-1},{-1,-1},{-1,-1},{-1,-1},{-1,-1},{-1,-1}, }, {{TETRAHEDRON,{3,5,7,9,-1,-1,-1,-1,},{1,4,102,101,-1,-1,},0}, // sons {TETRAHEDRON,{1,3,5,7,-1,-1,-1,-1,},{101,0,3,103,-1,-1,},268435456}, {TETRAHEDRON,{2,5,9,0,-1,-1,-1,-1,},{101,4,102,100,-1,-1,},536870921}, {TETRAHEDRON,{0,1,5,7,-1,-1,-1,-1,},{100,1,4,103,-1,-1,},536870920}, {TETRAHEDRON,{5,7,9,0,-1,-1,-1,-1,},{0,102,2,3,-1,-1,},268435457}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, }}, // Rule 99 {TETRAHEDRON,99,RED_CLASS,5, // tag, mark, rclass, nsons {0,1,0,1,0,1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,}, // pattern 42, // pat {{-1,0},{1,1},{-1,0},{0,1},{-1,0},{0,2},{-1,-1}, // sonandnode {-1,-1},{-1,-1},{-1,-1},{-1,0},{-1,-1},{-1,-1}, {-1,-1},{-1,-1},{-1,-1},{-1,-1},{-1,-1},{-1,-1}, }, {{TETRAHEDRON,{3,7,9,1,-1,-1,-1,-1,},{102,3,101,103,-1,-1,},0}, // sons {TETRAHEDRON,{2,5,7,0,-1,-1,-1,-1,},{2,4,102,100,-1,-1,},805306421}, {TETRAHEDRON,{5,7,9,2,-1,-1,-1,-1,},{3,102,101,1,-1,-1,},536870917}, {TETRAHEDRON,{1,5,7,9,-1,-1,-1,-1,},{4,2,0,101,-1,-1,},268435457}, {TETRAHEDRON,{0,1,5,7,-1,-1,-1,-1,},{100,3,1,103,-1,-1,},536870913}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, }}, // Rule 100 {TETRAHEDRON,100,RED_CLASS,4, // tag, mark, rclass, nsons {0,1,0,1,0,1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,}, // pattern 42, // pat {{-1,0},{1,1},{-1,0},{0,1},{-1,0},{0,2},{-1,-1}, // sonandnode {-1,-1},{-1,-1},{-1,-1},{-1,0},{-1,-1},{-1,-1}, {-1,-1},{-1,-1},{-1,-1},{-1,-1},{-1,-1},{-1,-1}, }, {{TETRAHEDRON,{3,7,9,1,-1,-1,-1,-1,},{102,3,101,103,-1,-1,},0}, // sons {TETRAHEDRON,{2,5,9,0,-1,-1,-1,-1,},{101,2,102,100,-1,-1,},805306409}, {TETRAHEDRON,{0,1,5,9,-1,-1,-1,-1,},{100,101,1,3,-1,-1,},536870921}, {TETRAHEDRON,{1,7,9,0,-1,-1,-1,-1,},{0,102,2,103,-1,-1,},268435457}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, }}, // Rule 101 {TETRAHEDRON,101,RED_CLASS,4, // tag, mark, rclass, nsons {0,0,1,1,0,1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,}, // pattern 44, // pat {{-1,0},{-1,0},{0,2},{1,3},{-1,0},{0,3},{-1,-1}, // sonandnode {-1,-1},{-1,-1},{-1,-1},{-1,0},{-1,-1},{-1,-1}, {-1,-1},{-1,-1},{-1,-1},{-1,-1},{-1,-1},{-1,-1}, }, {{TETRAHEDRON,{1,2,6,9,-1,-1,-1,-1,},{100,102,2,101,-1,-1,},0}, // sons {TETRAHEDRON,{0,1,6,7,-1,-1,-1,-1,},{100,2,102,103,-1,-1,},536870914}, {TETRAHEDRON,{1,6,7,9,-1,-1,-1,-1,},{1,102,3,0,-1,-1,},268435458}, {TETRAHEDRON,{3,7,9,1,-1,-1,-1,-1,},{102,2,101,103,-1,-1,},536870922}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, }}, // Rule 102 {TETRAHEDRON,102,RED_CLASS,5, // tag, mark, rclass, nsons {1,0,0,0,1,1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,}, // pattern 49, // pat {{0,0},{-1,0},{-1,0},{-1,0},{0,1},{0,2},{-1,-1}, // sonandnode {-1,-1},{-1,-1},{-1,-1},{-1,0},{-1,-1},{-1,-1}, {-1,-1},{-1,-1},{-1,-1},{-1,-1},{-1,-1},{-1,-1}, }, {{TETRAHEDRON,{4,8,9,3,-1,-1,-1,-1,},{4,101,1,103,-1,-1,},0}, // sons {TETRAHEDRON,{0,3,4,9,-1,-1,-1,-1,},{103,0,3,102,-1,-1,},268435458}, {TETRAHEDRON,{1,2,4,8,-1,-1,-1,-1,},{100,4,103,101,-1,-1,},536870912}, {TETRAHEDRON,{2,4,9,0,-1,-1,-1,-1,},{4,1,102,100,-1,-1,},536870922}, {TETRAHEDRON,{2,4,8,9,-1,-1,-1,-1,},{2,0,101,3,-1,-1,},268435456}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, }}, // Rule 103 {TETRAHEDRON,103,RED_CLASS,5, // tag, mark, rclass, nsons {1,0,0,0,1,1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,}, // pattern 49, // pat {{0,0},{-1,0},{-1,0},{-1,0},{0,1},{0,2},{-1,-1}, // sonandnode {-1,-1},{-1,-1},{-1,-1},{-1,0},{-1,-1},{-1,-1}, {-1,-1},{-1,-1},{-1,-1},{-1,-1},{-1,-1},{-1,-1}, }, {{TETRAHEDRON,{4,8,9,3,-1,-1,-1,-1,},{4,101,1,103,-1,-1,},0}, // sons {TETRAHEDRON,{0,3,4,9,-1,-1,-1,-1,},{103,0,2,102,-1,-1,},268435458}, {TETRAHEDRON,{2,4,9,0,-1,-1,-1,-1,},{3,1,102,100,-1,-1,},536870922}, {TETRAHEDRON,{1,2,4,9,-1,-1,-1,-1,},{100,2,4,101,-1,-1,},805306378}, {TETRAHEDRON,{1,4,8,9,-1,-1,-1,-1,},{103,0,101,3,-1,-1,},268435456}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, }}, // Rule 104 {TETRAHEDRON,104,RED_CLASS,4, // tag, mark, rclass, nsons {1,0,0,0,1,1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,}, // pattern 49, // pat {{1,2},{-1,0},{-1,0},{-1,0},{0,2},{0,3},{-1,-1}, // sonandnode {-1,-1},{-1,-1},{-1,-1},{-1,0},{-1,-1},{-1,-1}, {-1,-1},{-1,-1},{-1,-1},{-1,-1},{-1,-1},{-1,-1}, }, {{TETRAHEDRON,{0,3,8,9,-1,-1,-1,-1,},{103,101,3,102,-1,-1,},0}, // sons {TETRAHEDRON,{1,2,4,8,-1,-1,-1,-1,},{100,2,103,101,-1,-1,},805306382}, {TETRAHEDRON,{2,4,8,0,-1,-1,-1,-1,},{1,103,3,100,-1,-1,},536870926}, {TETRAHEDRON,{2,8,9,0,-1,-1,-1,-1,},{101,0,102,2,-1,-1,},268435458}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, }}, // Rule 105 {TETRAHEDRON,105,RED_CLASS,5, // tag, mark, rclass, nsons {1,0,0,0,1,1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,}, // pattern 49, // pat {{1,2},{-1,0},{-1,0},{-1,0},{0,2},{0,3},{-1,-1}, // sonandnode {-1,-1},{-1,-1},{-1,-1},{-1,0},{-1,-1},{-1,-1}, {-1,-1},{-1,-1},{-1,-1},{-1,-1},{-1,-1},{-1,-1}, }, {{TETRAHEDRON,{0,3,8,9,-1,-1,-1,-1,},{103,101,3,102,-1,-1,},0}, // sons {TETRAHEDRON,{1,2,4,9,-1,-1,-1,-1,},{100,4,2,101,-1,-1,},805306418}, {TETRAHEDRON,{1,4,8,9,-1,-1,-1,-1,},{103,3,101,1,-1,-1,},536870914}, {TETRAHEDRON,{4,8,9,0,-1,-1,-1,-1,},{2,0,4,103,-1,-1,},268435458}, {TETRAHEDRON,{2,4,9,0,-1,-1,-1,-1,},{1,3,102,100,-1,-1,},536870922}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, }}, // Rule 106 {TETRAHEDRON,106,RED_CLASS,4, // tag, mark, rclass, nsons {0,1,0,0,1,1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,}, // pattern 50, // pat {{-1,0},{0,2},{-1,0},{-1,0},{0,3},{1,2},{-1,-1}, // sonandnode {-1,-1},{-1,-1},{-1,-1},{-1,0},{-1,-1},{-1,-1}, {-1,-1},{-1,-1},{-1,-1},{-1,-1},{-1,-1},{-1,-1}, }, {{TETRAHEDRON,{0,1,5,8,-1,-1,-1,-1,},{100,101,2,103,-1,-1,},0}, // sons {TETRAHEDRON,{2,5,9,0,-1,-1,-1,-1,},{101,2,102,100,-1,-1,},536870922}, {TETRAHEDRON,{5,8,9,0,-1,-1,-1,-1,},{101,3,1,0,-1,-1,},268435458}, {TETRAHEDRON,{0,3,8,9,-1,-1,-1,-1,},{103,101,2,102,-1,-1,},536870918}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, }}, // Rule 107 {TETRAHEDRON,107,RED_CLASS,5, // tag, mark, rclass, nsons {0,0,1,0,1,1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,}, // pattern 52, // pat {{-1,0},{-1,0},{0,0},{-1,0},{0,1},{0,2},{-1,-1}, // sonandnode {-1,-1},{-1,-1},{-1,-1},{-1,0},{-1,-1},{-1,-1}, {-1,-1},{-1,-1},{-1,-1},{-1,-1},{-1,-1},{-1,-1}, }, {{TETRAHEDRON,{6,8,9,3,-1,-1,-1,-1,},{4,101,102,1,-1,-1,},0}, // sons {TETRAHEDRON,{3,6,8,0,-1,-1,-1,-1,},{0,2,103,102,-1,-1,},268435459}, {TETRAHEDRON,{0,1,6,8,-1,-1,-1,-1,},{100,3,1,103,-1,-1,},536870919}, {TETRAHEDRON,{1,2,6,8,-1,-1,-1,-1,},{100,4,2,101,-1,-1,},805306391}, {TETRAHEDRON,{2,6,8,9,-1,-1,-1,-1,},{3,0,101,102,-1,-1,},268435456}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, }}, // Rule 108 {TETRAHEDRON,108,RED_CLASS,5, // tag, mark, rclass, nsons {0,0,1,0,1,1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,}, // pattern 52, // pat {{-1,0},{-1,0},{0,0},{-1,0},{0,1},{0,2},{-1,-1}, // sonandnode {-1,-1},{-1,-1},{-1,-1},{-1,0},{-1,-1},{-1,-1}, {-1,-1},{-1,-1},{-1,-1},{-1,-1},{-1,-1},{-1,-1}, }, {{TETRAHEDRON,{6,8,9,3,-1,-1,-1,-1,},{4,101,102,1,-1,-1,},0}, // sons {TETRAHEDRON,{3,6,8,0,-1,-1,-1,-1,},{0,3,103,102,-1,-1,},268435459}, {TETRAHEDRON,{1,2,6,9,-1,-1,-1,-1,},{100,102,4,101,-1,-1,},536870924}, {TETRAHEDRON,{0,1,6,8,-1,-1,-1,-1,},{100,4,1,103,-1,-1,},536870919}, {TETRAHEDRON,{1,6,8,9,-1,-1,-1,-1,},{3,0,101,2,-1,-1,},268435456}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, }}, // Rule 109 {TETRAHEDRON,109,RED_CLASS,5, // tag, mark, rclass, nsons {0,0,1,0,1,1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,}, // pattern 52, // pat {{-1,0},{-1,0},{1,2},{-1,0},{0,2},{0,3},{-1,-1}, // sonandnode {-1,-1},{-1,-1},{-1,-1},{-1,0},{-1,-1},{-1,-1}, {-1,-1},{-1,-1},{-1,-1},{-1,-1},{-1,-1},{-1,-1}, }, {{TETRAHEDRON,{0,3,8,9,-1,-1,-1,-1,},{103,101,3,102,-1,-1,},0}, // sons {TETRAHEDRON,{1,2,6,8,-1,-1,-1,-1,},{100,2,4,101,-1,-1,},805306370}, {TETRAHEDRON,{2,6,8,9,-1,-1,-1,-1,},{1,3,101,102,-1,-1,},536870914}, {TETRAHEDRON,{6,8,9,0,-1,-1,-1,-1,},{2,0,102,4,-1,-1,},268435458}, {TETRAHEDRON,{0,1,6,8,-1,-1,-1,-1,},{100,1,3,103,-1,-1,},536870926}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, }}, // Rule 110 {TETRAHEDRON,110,RED_CLASS,4, // tag, mark, rclass, nsons {0,0,1,0,1,1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,}, // pattern 52, // pat {{-1,0},{-1,0},{1,2},{-1,0},{0,2},{0,3},{-1,-1}, // sonandnode {-1,-1},{-1,-1},{-1,-1},{-1,0},{-1,-1},{-1,-1}, {-1,-1},{-1,-1},{-1,-1},{-1,-1},{-1,-1},{-1,-1}, }, {{TETRAHEDRON,{0,3,8,9,-1,-1,-1,-1,},{103,101,3,102,-1,-1,},0}, // sons {TETRAHEDRON,{1,2,6,9,-1,-1,-1,-1,},{100,102,2,101,-1,-1,},805306394}, {TETRAHEDRON,{0,1,6,9,-1,-1,-1,-1,},{100,1,102,3,-1,-1,},536870922}, {TETRAHEDRON,{1,8,9,0,-1,-1,-1,-1,},{101,0,2,103,-1,-1,},268435458}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, }}, // Rule 111 {TETRAHEDRON,111,RED_CLASS,9, // tag, mark, rclass, nsons {0,0,0,1,1,1,-1,-1,-1,-1,1,-1,-1,-1,-1,-1,-1,-1,-1,}, // pattern 1080, // pat {{-1,0},{-1,0},{-1,0},{0,0},{0,1},{0,2},{-1,-1}, // sonandnode {-1,-1},{-1,-1},{-1,-1},{1,2},{-1,-1},{-1,-1}, {-1,-1},{-1,-1},{-1,-1},{-1,-1},{-1,-1},{-1,-1}, }, {{TETRAHEDRON,{7,8,9,3,-1,-1,-1,-1,},{1,101,102,103,-1,-1,},0}, // sons {TETRAHEDRON,{8,9,14,7,-1,-1,-1,-1,},{4,7,6,0,-1,-1,},268435456}, {TETRAHEDRON,{0,1,2,14,-1,-1,-1,-1,},{100,3,8,5,-1,-1,},1073742000}, {TETRAHEDRON,{2,8,14,1,-1,-1,-1,-1,},{4,6,2,101,-1,-1,},805306416}, {TETRAHEDRON,{2,8,9,14,-1,-1,-1,-1,},{101,1,8,3,-1,-1,},536870912}, {TETRAHEDRON,{1,7,14,0,-1,-1,-1,-1,},{6,7,2,103,-1,-1,},1342178224}, {TETRAHEDRON,{8,7,14,1,-1,-1,-1,-1,},{1,5,3,103,-1,-1,},536870920}, {TETRAHEDRON,{7,9,14,0,-1,-1,-1,-1,},{1,8,5,102,-1,-1,},536870916}, {TETRAHEDRON,{9,2,14,0,-1,-1,-1,-1,},{4,2,7,102,-1,-1,},805306400}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, }}, // Rule 112 {TETRAHEDRON,112,RED_CLASS,9, // tag, mark, rclass, nsons {0,0,0,1,1,1,-1,-1,-1,-1,1,-1,-1,-1,-1,-1,-1,-1,-1,}, // pattern 1080, // pat {{-1,0},{-1,0},{-1,0},{0,0},{0,1},{0,2},{-1,-1}, // sonandnode {-1,-1},{-1,-1},{-1,-1},{1,2},{-1,-1},{-1,-1}, {-1,-1},{-1,-1},{-1,-1},{-1,-1},{-1,-1},{-1,-1}, }, {{TETRAHEDRON,{7,8,9,3,-1,-1,-1,-1,},{1,101,102,103,-1,-1,},0}, // sons {TETRAHEDRON,{8,9,14,7,-1,-1,-1,-1,},{4,8,6,0,-1,-1,},268435456}, {TETRAHEDRON,{0,1,2,14,-1,-1,-1,-1,},{100,3,7,5,-1,-1,},1073741984}, {TETRAHEDRON,{2,9,14,1,-1,-1,-1,-1,},{8,4,2,101,-1,-1,},805306400}, {TETRAHEDRON,{1,8,9,14,-1,-1,-1,-1,},{101,1,3,5,-1,-1,},536870912}, {TETRAHEDRON,{1,8,14,0,-1,-1,-1,-1,},{4,6,2,103,-1,-1,},805306416}, {TETRAHEDRON,{8,7,14,0,-1,-1,-1,-1,},{1,7,5,103,-1,-1,},536870920}, {TETRAHEDRON,{7,2,14,0,-1,-1,-1,-1,},{8,2,6,102,-1,-1,},1342177952}, {TETRAHEDRON,{7,9,14,2,-1,-1,-1,-1,},{1,3,7,102,-1,-1,},536870916}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, }}, // Rule 113 {TETRAHEDRON,113,RED_CLASS,4, // tag, mark, rclass, nsons {0,0,0,1,1,1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,}, // pattern 56, // pat {{-1,0},{-1,0},{-1,0},{0,0},{0,1},{0,2},{-1,-1}, // sonandnode {-1,-1},{-1,-1},{-1,-1},{-1,0},{-1,-1},{-1,-1}, {-1,-1},{-1,-1},{-1,-1},{-1,-1},{-1,-1},{-1,-1}, }, {{TETRAHEDRON,{7,8,9,3,-1,-1,-1,-1,},{3,101,102,103,-1,-1,},0}, // sons {TETRAHEDRON,{0,1,2,7,-1,-1,-1,-1,},{100,2,102,103,-1,-1,},805306368}, {TETRAHEDRON,{1,2,7,8,-1,-1,-1,-1,},{1,3,103,101,-1,-1,},536870912}, {TETRAHEDRON,{2,7,8,9,-1,-1,-1,-1,},{2,0,101,102,-1,-1,},268435456}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, }}, // Rule 114 {TETRAHEDRON,114,RED_CLASS,4, // tag, mark, rclass, nsons {0,0,0,1,1,1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,}, // pattern 56, // pat {{-1,0},{-1,0},{-1,0},{0,0},{0,1},{0,2},{-1,-1}, // sonandnode {-1,-1},{-1,-1},{-1,-1},{-1,0},{-1,-1},{-1,-1}, {-1,-1},{-1,-1},{-1,-1},{-1,-1},{-1,-1},{-1,-1}, }, {{TETRAHEDRON,{7,8,9,3,-1,-1,-1,-1,},{3,101,102,103,-1,-1,},0}, // sons {TETRAHEDRON,{0,1,2,7,-1,-1,-1,-1,},{100,2,102,103,-1,-1,},805306380}, {TETRAHEDRON,{1,2,7,9,-1,-1,-1,-1,},{1,102,3,101,-1,-1,},536870924}, {TETRAHEDRON,{1,7,8,9,-1,-1,-1,-1,},{103,0,101,2,-1,-1,},268435456}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, }}, // Rule 115 {TETRAHEDRON,115,RED_CLASS,4, // tag, mark, rclass, nsons {0,0,0,1,1,1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,}, // pattern 56, // pat {{-1,0},{-1,0},{-1,0},{0,0},{0,1},{0,2},{-1,-1}, // sonandnode {-1,-1},{-1,-1},{-1,-1},{-1,0},{-1,-1},{-1,-1}, {-1,-1},{-1,-1},{-1,-1},{-1,-1},{-1,-1},{-1,-1}, }, {{TETRAHEDRON,{7,8,9,3,-1,-1,-1,-1,},{3,101,102,103,-1,-1,},0}, // sons {TETRAHEDRON,{0,1,2,8,-1,-1,-1,-1,},{100,101,2,103,-1,-1,},805306416}, {TETRAHEDRON,{0,2,7,8,-1,-1,-1,-1,},{102,3,103,1,-1,-1,},536870912}, {TETRAHEDRON,{2,7,8,9,-1,-1,-1,-1,},{2,0,101,102,-1,-1,},268435456}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, }}, // Rule 116 {TETRAHEDRON,116,RED_CLASS,4, // tag, mark, rclass, nsons {0,0,0,1,1,1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,}, // pattern 56, // pat {{-1,0},{-1,0},{-1,0},{0,0},{0,1},{0,2},{-1,-1}, // sonandnode {-1,-1},{-1,-1},{-1,-1},{-1,0},{-1,-1},{-1,-1}, {-1,-1},{-1,-1},{-1,-1},{-1,-1},{-1,-1},{-1,-1}, }, {{TETRAHEDRON,{7,8,9,3,-1,-1,-1,-1,},{3,101,102,103,-1,-1,},0}, // sons {TETRAHEDRON,{0,1,2,8,-1,-1,-1,-1,},{100,101,2,103,-1,-1,},805306424}, {TETRAHEDRON,{2,8,9,0,-1,-1,-1,-1,},{101,3,102,1,-1,-1,},536870920}, {TETRAHEDRON,{0,7,8,9,-1,-1,-1,-1,},{103,0,2,102,-1,-1,},268435456}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, }}, // Rule 117 {TETRAHEDRON,117,RED_CLASS,4, // tag, mark, rclass, nsons {0,0,0,1,1,1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,}, // pattern 56, // pat {{-1,0},{-1,0},{-1,0},{0,0},{0,1},{0,2},{-1,-1}, // sonandnode {-1,-1},{-1,-1},{-1,-1},{-1,0},{-1,-1},{-1,-1}, {-1,-1},{-1,-1},{-1,-1},{-1,-1},{-1,-1},{-1,-1}, }, {{TETRAHEDRON,{7,8,9,3,-1,-1,-1,-1,},{3,101,102,103,-1,-1,},0}, // sons {TETRAHEDRON,{0,1,2,9,-1,-1,-1,-1,},{100,101,102,2,-1,-1,},805306412}, {TETRAHEDRON,{1,7,9,0,-1,-1,-1,-1,},{3,102,1,103,-1,-1,},536870924}, {TETRAHEDRON,{1,7,8,9,-1,-1,-1,-1,},{103,0,101,2,-1,-1,},268435456}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, }}, // Rule 118 {TETRAHEDRON,118,RED_CLASS,4, // tag, mark, rclass, nsons {0,0,0,1,1,1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,}, // pattern 56, // pat {{-1,0},{-1,0},{-1,0},{0,0},{0,1},{0,2},{-1,-1}, // sonandnode {-1,-1},{-1,-1},{-1,-1},{-1,0},{-1,-1},{-1,-1}, {-1,-1},{-1,-1},{-1,-1},{-1,-1},{-1,-1},{-1,-1}, }, {{TETRAHEDRON,{7,8,9,3,-1,-1,-1,-1,},{3,101,102,103,-1,-1,},0}, // sons {TETRAHEDRON,{0,1,2,9,-1,-1,-1,-1,},{100,101,102,2,-1,-1,},805306408}, {TETRAHEDRON,{1,8,9,0,-1,-1,-1,-1,},{101,3,1,103,-1,-1,},536870920}, {TETRAHEDRON,{0,7,8,9,-1,-1,-1,-1,},{103,0,2,102,-1,-1,},268435456}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, }}, // Rule 119 {TETRAHEDRON,119,RED_CLASS,6, // tag, mark, rclass, nsons {1,1,1,1,0,0,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,}, // pattern 15, // pat {{0,1},{1,1},{0,2},{0,3},{-1,0},{-1,0},{-1,-1}, // sonandnode {-1,-1},{-1,-1},{-1,-1},{-1,0},{-1,-1},{-1,-1}, {-1,-1},{-1,-1},{-1,-1},{-1,-1},{-1,-1},{-1,-1}, }, {{TETRAHEDRON,{0,4,6,7,-1,-1,-1,-1,},{100,1,102,103,-1,-1,},0}, // sons {TETRAHEDRON,{4,5,6,7,-1,-1,-1,-1,},{100,4,0,2,-1,-1,},268435457}, {TETRAHEDRON,{4,5,7,3,-1,-1,-1,-1,},{1,4,103,3,-1,-1,},536870925}, {TETRAHEDRON,{3,4,5,1,-1,-1,-1,-1,},{2,100,101,103,-1,-1,},805306429}, {TETRAHEDRON,{5,6,7,3,-1,-1,-1,-1,},{1,102,2,5,-1,-1,},536870917}, {TETRAHEDRON,{3,5,6,2,-1,-1,-1,-1,},{4,100,102,101,-1,-1,},805306421}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, }}, // Rule 120 {TETRAHEDRON,120,RED_CLASS,6, // tag, mark, rclass, nsons {1,1,1,1,0,0,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,}, // pattern 15, // pat {{0,1},{1,1},{0,2},{0,3},{-1,0},{-1,0},{-1,-1}, // sonandnode {-1,-1},{-1,-1},{-1,-1},{-1,0},{-1,-1},{-1,-1}, {-1,-1},{-1,-1},{-1,-1},{-1,-1},{-1,-1},{-1,-1}, }, {{TETRAHEDRON,{0,4,6,7,-1,-1,-1,-1,},{100,1,102,103,-1,-1,},0}, // sons {TETRAHEDRON,{4,5,6,7,-1,-1,-1,-1,},{100,5,0,2,-1,-1,},268435457}, {TETRAHEDRON,{4,5,7,3,-1,-1,-1,-1,},{1,4,103,3,-1,-1,},536870925}, {TETRAHEDRON,{3,4,5,1,-1,-1,-1,-1,},{2,100,101,103,-1,-1,},805306429}, {TETRAHEDRON,{3,5,7,2,-1,-1,-1,-1,},{2,5,102,101,-1,-1,},805306397}, {TETRAHEDRON,{5,6,7,2,-1,-1,-1,-1,},{1,102,4,100,-1,-1,},536870917}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, }}, // Rule 121 {TETRAHEDRON,121,RED_CLASS,6, // tag, mark, rclass, nsons {1,1,1,1,0,0,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,}, // pattern 15, // pat {{0,1},{1,1},{0,2},{0,3},{-1,0},{-1,0},{-1,-1}, // sonandnode {-1,-1},{-1,-1},{-1,-1},{-1,0},{-1,-1},{-1,-1}, {-1,-1},{-1,-1},{-1,-1},{-1,-1},{-1,-1},{-1,-1}, }, {{TETRAHEDRON,{0,4,6,7,-1,-1,-1,-1,},{100,1,102,103,-1,-1,},0}, // sons {TETRAHEDRON,{4,5,6,7,-1,-1,-1,-1,},{100,5,0,2,-1,-1,},268435457}, {TETRAHEDRON,{4,5,7,1,-1,-1,-1,-1,},{1,3,103,100,-1,-1,},536870925}, {TETRAHEDRON,{1,3,5,7,-1,-1,-1,-1,},{101,4,2,103,-1,-1,},805306397}, {TETRAHEDRON,{3,5,7,2,-1,-1,-1,-1,},{3,5,102,101,-1,-1,},1073741917}, {TETRAHEDRON,{5,6,7,2,-1,-1,-1,-1,},{1,102,4,100,-1,-1,},536870917}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, }}, // Rule 122 {TETRAHEDRON,122,RED_CLASS,6, // tag, mark, rclass, nsons {1,1,1,1,0,0,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,}, // pattern 15, // pat {{0,1},{1,1},{0,2},{0,3},{-1,0},{-1,0},{-1,-1}, // sonandnode {-1,-1},{-1,-1},{-1,-1},{-1,0},{-1,-1},{-1,-1}, {-1,-1},{-1,-1},{-1,-1},{-1,-1},{-1,-1},{-1,-1}, }, {{TETRAHEDRON,{0,4,6,7,-1,-1,-1,-1,},{100,1,102,103,-1,-1,},0}, // sons {TETRAHEDRON,{4,5,6,7,-1,-1,-1,-1,},{100,4,0,2,-1,-1,},268435457}, {TETRAHEDRON,{4,5,7,1,-1,-1,-1,-1,},{1,3,103,100,-1,-1,},536870925}, {TETRAHEDRON,{1,3,5,7,-1,-1,-1,-1,},{101,4,2,103,-1,-1,},805306397}, {TETRAHEDRON,{5,6,7,3,-1,-1,-1,-1,},{1,102,3,5,-1,-1,},536870917}, {TETRAHEDRON,{3,5,6,2,-1,-1,-1,-1,},{4,100,102,101,-1,-1,},805306421}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, }}, // Rule 123 {TETRAHEDRON,123,RED_CLASS,6, // tag, mark, rclass, nsons {1,1,1,0,1,0,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,}, // pattern 23, // pat {{0,0},{0,1},{1,2},{-1,0},{0,2},{-1,0},{-1,-1}, // sonandnode {-1,-1},{-1,-1},{-1,-1},{-1,0},{-1,-1},{-1,-1}, {-1,-1},{-1,-1},{-1,-1},{-1,-1},{-1,-1},{-1,-1}, }, {{TETRAHEDRON,{4,5,8,1,-1,-1,-1,-1,},{1,101,103,100,-1,-1,},0}, // sons {TETRAHEDRON,{4,5,6,8,-1,-1,-1,-1,},{100,2,4,0,-1,-1,},268435456}, {TETRAHEDRON,{5,6,8,3,-1,-1,-1,-1,},{1,4,101,3,-1,-1,},536870916}, {TETRAHEDRON,{3,5,6,2,-1,-1,-1,-1,},{2,100,102,101,-1,-1,},805306420}, {TETRAHEDRON,{3,4,6,8,-1,-1,-1,-1,},{5,1,2,103,-1,-1,},536870920}, {TETRAHEDRON,{0,3,4,6,-1,-1,-1,-1,},{103,4,100,102,-1,-1,},805306376}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, }}, // Rule 124 {TETRAHEDRON,124,RED_CLASS,6, // tag, mark, rclass, nsons {1,1,1,0,1,0,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,}, // pattern 23, // pat {{0,0},{0,1},{1,2},{-1,0},{0,2},{-1,0},{-1,-1}, // sonandnode {-1,-1},{-1,-1},{-1,-1},{-1,0},{-1,-1},{-1,-1}, {-1,-1},{-1,-1},{-1,-1},{-1,-1},{-1,-1},{-1,-1}, }, {{TETRAHEDRON,{4,5,8,1,-1,-1,-1,-1,},{1,101,103,100,-1,-1,},0}, // sons {TETRAHEDRON,{4,5,6,8,-1,-1,-1,-1,},{100,2,5,0,-1,-1,},268435456}, {TETRAHEDRON,{5,6,8,3,-1,-1,-1,-1,},{1,4,101,3,-1,-1,},536870916}, {TETRAHEDRON,{3,5,6,2,-1,-1,-1,-1,},{2,100,102,101,-1,-1,},805306420}, {TETRAHEDRON,{3,6,8,0,-1,-1,-1,-1,},{2,5,103,102,-1,-1,},805306388}, {TETRAHEDRON,{0,4,6,8,-1,-1,-1,-1,},{100,1,4,103,-1,-1,},536870920}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, }}, // Rule 125 {TETRAHEDRON,125,RED_CLASS,6, // tag, mark, rclass, nsons {1,1,1,0,1,0,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,}, // pattern 23, // pat {{0,0},{0,1},{1,2},{-1,0},{0,2},{-1,0},{-1,-1}, // sonandnode {-1,-1},{-1,-1},{-1,-1},{-1,0},{-1,-1},{-1,-1}, {-1,-1},{-1,-1},{-1,-1},{-1,-1},{-1,-1},{-1,-1}, }, {{TETRAHEDRON,{4,5,8,1,-1,-1,-1,-1,},{1,101,103,100,-1,-1,},0}, // sons {TETRAHEDRON,{4,5,6,8,-1,-1,-1,-1,},{100,2,5,0,-1,-1,},268435456}, {TETRAHEDRON,{5,6,8,2,-1,-1,-1,-1,},{1,3,101,100,-1,-1,},536870916}, {TETRAHEDRON,{2,3,6,8,-1,-1,-1,-1,},{102,4,2,101,-1,-1,},805306388}, {TETRAHEDRON,{3,6,8,0,-1,-1,-1,-1,},{3,5,103,102,-1,-1,},1073741908}, {TETRAHEDRON,{0,4,6,8,-1,-1,-1,-1,},{100,1,4,103,-1,-1,},536870920}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, }}, // Rule 126 {TETRAHEDRON,126,RED_CLASS,6, // tag, mark, rclass, nsons {1,1,1,0,1,0,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,}, // pattern 23, // pat {{0,0},{0,1},{1,2},{-1,0},{0,2},{-1,0},{-1,-1}, // sonandnode {-1,-1},{-1,-1},{-1,-1},{-1,0},{-1,-1},{-1,-1}, {-1,-1},{-1,-1},{-1,-1},{-1,-1},{-1,-1},{-1,-1}, }, {{TETRAHEDRON,{4,5,8,1,-1,-1,-1,-1,},{1,101,103,100,-1,-1,},0}, // sons {TETRAHEDRON,{4,5,6,8,-1,-1,-1,-1,},{100,2,4,0,-1,-1,},268435456}, {TETRAHEDRON,{5,6,8,2,-1,-1,-1,-1,},{1,3,101,100,-1,-1,},536870916}, {TETRAHEDRON,{2,3,6,8,-1,-1,-1,-1,},{102,4,2,101,-1,-1,},805306388}, {TETRAHEDRON,{3,4,6,8,-1,-1,-1,-1,},{5,1,3,103,-1,-1,},536870920}, {TETRAHEDRON,{0,3,4,6,-1,-1,-1,-1,},{103,4,100,102,-1,-1,},805306376}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, }}, // Rule 127 {TETRAHEDRON,127,RED_CLASS,6, // tag, mark, rclass, nsons {1,1,0,1,1,0,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,}, // pattern 27, // pat {{0,0},{0,1},{-1,0},{1,2},{0,2},{-1,0},{-1,-1}, // sonandnode {-1,-1},{-1,-1},{-1,-1},{-1,0},{-1,-1},{-1,-1}, {-1,-1},{-1,-1},{-1,-1},{-1,-1},{-1,-1},{-1,-1}, }, {{TETRAHEDRON,{4,5,8,1,-1,-1,-1,-1,},{1,101,103,100,-1,-1,},0}, // sons {TETRAHEDRON,{4,5,7,8,-1,-1,-1,-1,},{2,4,103,0,-1,-1,},268435456}, {TETRAHEDRON,{2,4,5,7,-1,-1,-1,-1,},{100,1,4,3,-1,-1,},536870912}, {TETRAHEDRON,{2,4,7,0,-1,-1,-1,-1,},{2,103,102,100,-1,-1,},805306416}, {TETRAHEDRON,{5,7,8,2,-1,-1,-1,-1,},{1,5,101,2,-1,-1,},536870916}, {TETRAHEDRON,{2,3,7,8,-1,-1,-1,-1,},{102,103,4,101,-1,-1,},805306388}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, }}, // Rule 128 {TETRAHEDRON,128,RED_CLASS,6, // tag, mark, rclass, nsons {1,1,0,1,1,0,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,}, // pattern 27, // pat {{0,0},{0,1},{-1,0},{1,2},{0,2},{-1,0},{-1,-1}, // sonandnode {-1,-1},{-1,-1},{-1,-1},{-1,0},{-1,-1},{-1,-1}, {-1,-1},{-1,-1},{-1,-1},{-1,-1},{-1,-1},{-1,-1}, }, {{TETRAHEDRON,{4,5,8,1,-1,-1,-1,-1,},{1,101,103,100,-1,-1,},0}, // sons {TETRAHEDRON,{4,5,7,8,-1,-1,-1,-1,},{2,5,103,0,-1,-1,},268435456}, {TETRAHEDRON,{2,4,5,7,-1,-1,-1,-1,},{100,1,4,3,-1,-1,},536870912}, {TETRAHEDRON,{2,4,7,0,-1,-1,-1,-1,},{2,103,102,100,-1,-1,},805306416}, {TETRAHEDRON,{3,5,7,2,-1,-1,-1,-1,},{5,2,102,101,-1,-1,},805306400}, {TETRAHEDRON,{5,7,8,3,-1,-1,-1,-1,},{1,103,101,4,-1,-1,},536870916}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, }}, // Rule 129 {TETRAHEDRON,129,RED_CLASS,6, // tag, mark, rclass, nsons {1,1,0,1,1,0,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,}, // pattern 27, // pat {{0,0},{0,1},{-1,0},{1,2},{0,2},{-1,0},{-1,-1}, // sonandnode {-1,-1},{-1,-1},{-1,-1},{-1,0},{-1,-1},{-1,-1}, {-1,-1},{-1,-1},{-1,-1},{-1,-1},{-1,-1},{-1,-1}, }, {{TETRAHEDRON,{4,5,8,1,-1,-1,-1,-1,},{1,101,103,100,-1,-1,},0}, // sons {TETRAHEDRON,{4,5,7,8,-1,-1,-1,-1,},{2,5,103,0,-1,-1,},268435456}, {TETRAHEDRON,{0,4,5,7,-1,-1,-1,-1,},{100,1,3,103,-1,-1,},536870912}, {TETRAHEDRON,{2,5,7,0,-1,-1,-1,-1,},{4,2,102,100,-1,-1,},805306400}, {TETRAHEDRON,{3,5,7,2,-1,-1,-1,-1,},{5,3,102,101,-1,-1,},1073741856}, {TETRAHEDRON,{5,7,8,3,-1,-1,-1,-1,},{1,103,101,4,-1,-1,},536870916}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, }}, // Rule 130 {TETRAHEDRON,130,RED_CLASS,6, // tag, mark, rclass, nsons {1,1,0,1,1,0,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,}, // pattern 27, // pat {{0,0},{0,1},{-1,0},{1,2},{0,2},{-1,0},{-1,-1}, // sonandnode {-1,-1},{-1,-1},{-1,-1},{-1,0},{-1,-1},{-1,-1}, {-1,-1},{-1,-1},{-1,-1},{-1,-1},{-1,-1},{-1,-1}, }, {{TETRAHEDRON,{4,5,8,1,-1,-1,-1,-1,},{1,101,103,100,-1,-1,},0}, // sons {TETRAHEDRON,{4,5,7,8,-1,-1,-1,-1,},{2,4,103,0,-1,-1,},268435456}, {TETRAHEDRON,{0,4,5,7,-1,-1,-1,-1,},{100,1,3,103,-1,-1,},536870912}, {TETRAHEDRON,{2,5,7,0,-1,-1,-1,-1,},{4,2,102,100,-1,-1,},805306400}, {TETRAHEDRON,{5,7,8,2,-1,-1,-1,-1,},{1,5,101,3,-1,-1,},536870916}, {TETRAHEDRON,{2,3,7,8,-1,-1,-1,-1,},{102,103,4,101,-1,-1,},805306388}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, }}, // Rule 131 {TETRAHEDRON,131,RED_CLASS,6, // tag, mark, rclass, nsons {1,0,1,1,1,0,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,}, // pattern 29, // pat {{0,1},{-1,0},{0,2},{0,3},{1,3},{-1,0},{-1,-1}, // sonandnode {-1,-1},{-1,-1},{-1,-1},{-1,0},{-1,-1},{-1,-1}, {-1,-1},{-1,-1},{-1,-1},{-1,-1},{-1,-1},{-1,-1}, }, {{TETRAHEDRON,{0,4,6,7,-1,-1,-1,-1,},{100,1,102,103,-1,-1,},0}, // sons {TETRAHEDRON,{4,6,7,8,-1,-1,-1,-1,},{0,2,103,4,-1,-1,},268435457}, {TETRAHEDRON,{6,7,8,2,-1,-1,-1,-1,},{1,3,4,102,-1,-1,},536870917}, {TETRAHEDRON,{2,3,7,8,-1,-1,-1,-1,},{102,103,2,101,-1,-1,},805306389}, {TETRAHEDRON,{4,6,8,2,-1,-1,-1,-1,},{1,2,5,100,-1,-1,},536870925}, {TETRAHEDRON,{1,2,4,8,-1,-1,-1,-1,},{100,4,103,101,-1,-1,},805306413}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, }}, // Rule 132 {TETRAHEDRON,132,RED_CLASS,6, // tag, mark, rclass, nsons {1,0,1,1,1,0,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,}, // pattern 29, // pat {{0,1},{-1,0},{0,2},{0,3},{1,3},{-1,0},{-1,-1}, // sonandnode {-1,-1},{-1,-1},{-1,-1},{-1,0},{-1,-1},{-1,-1}, {-1,-1},{-1,-1},{-1,-1},{-1,-1},{-1,-1},{-1,-1}, }, {{TETRAHEDRON,{0,4,6,7,-1,-1,-1,-1,},{100,1,102,103,-1,-1,},0}, // sons {TETRAHEDRON,{4,6,7,8,-1,-1,-1,-1,},{0,2,103,5,-1,-1,},268435457}, {TETRAHEDRON,{6,7,8,2,-1,-1,-1,-1,},{1,3,4,102,-1,-1,},536870917}, {TETRAHEDRON,{2,3,7,8,-1,-1,-1,-1,},{102,103,2,101,-1,-1,},805306389}, {TETRAHEDRON,{1,2,6,8,-1,-1,-1,-1,},{100,2,5,101,-1,-1,},805306405}, {TETRAHEDRON,{4,6,8,1,-1,-1,-1,-1,},{1,4,103,100,-1,-1,},536870925}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, }}, // Rule 133 {TETRAHEDRON,133,RED_CLASS,6, // tag, mark, rclass, nsons {1,0,1,1,1,0,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,}, // pattern 29, // pat {{0,1},{-1,0},{0,2},{0,3},{1,3},{-1,0},{-1,-1}, // sonandnode {-1,-1},{-1,-1},{-1,-1},{-1,0},{-1,-1},{-1,-1}, {-1,-1},{-1,-1},{-1,-1},{-1,-1},{-1,-1},{-1,-1}, }, {{TETRAHEDRON,{0,4,6,7,-1,-1,-1,-1,},{100,1,102,103,-1,-1,},0}, // sons {TETRAHEDRON,{4,6,7,8,-1,-1,-1,-1,},{0,2,103,5,-1,-1,},268435457}, {TETRAHEDRON,{6,7,8,3,-1,-1,-1,-1,},{1,103,3,102,-1,-1,},536870917}, {TETRAHEDRON,{2,3,6,8,-1,-1,-1,-1,},{102,2,4,101,-1,-1,},805306405}, {TETRAHEDRON,{1,2,6,8,-1,-1,-1,-1,},{100,3,5,101,-1,-1,},1073741989}, {TETRAHEDRON,{4,6,8,1,-1,-1,-1,-1,},{1,4,103,100,-1,-1,},536870925}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, }}, // Rule 134 {TETRAHEDRON,134,RED_CLASS,6, // tag, mark, rclass, nsons {1,0,1,1,1,0,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,}, // pattern 29, // pat {{0,1},{-1,0},{0,2},{0,3},{1,3},{-1,0},{-1,-1}, // sonandnode {-1,-1},{-1,-1},{-1,-1},{-1,0},{-1,-1},{-1,-1}, {-1,-1},{-1,-1},{-1,-1},{-1,-1},{-1,-1},{-1,-1}, }, {{TETRAHEDRON,{0,4,6,7,-1,-1,-1,-1,},{100,1,102,103,-1,-1,},0}, // sons {TETRAHEDRON,{4,6,7,8,-1,-1,-1,-1,},{0,2,103,4,-1,-1,},268435457}, {TETRAHEDRON,{6,7,8,3,-1,-1,-1,-1,},{1,103,3,102,-1,-1,},536870917}, {TETRAHEDRON,{2,3,6,8,-1,-1,-1,-1,},{102,2,4,101,-1,-1,},805306405}, {TETRAHEDRON,{4,6,8,2,-1,-1,-1,-1,},{1,3,5,100,-1,-1,},536870925}, {TETRAHEDRON,{1,2,4,8,-1,-1,-1,-1,},{100,4,103,101,-1,-1,},805306413}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, }}, // Rule 135 {TETRAHEDRON,135,RED_CLASS,12, // tag, mark, rclass, nsons {0,1,1,1,1,0,-1,-1,-1,-1,1,-1,-1,-1,-1,-1,-1,-1,-1,}, // pattern 1054, // pat {{-1,0},{0,0},{2,2},{1,0},{0,1},{-1,0},{-1,-1}, // sonandnode {-1,-1},{-1,-1},{-1,-1},{0,2},{-1,-1},{-1,-1}, {-1,-1},{-1,-1},{-1,-1},{-1,-1},{-1,-1},{-1,-1}, }, {{TETRAHEDRON,{5,8,14,1,-1,-1,-1,-1,},{7,1,4,101,-1,-1,},0}, // sons {TETRAHEDRON,{8,7,14,1,-1,-1,-1,-1,},{9,5,0,103,-1,-1,},268435457}, {TETRAHEDRON,{0,5,6,14,-1,-1,-1,-1,},{100,6,3,4,-1,-1,},536870922}, {TETRAHEDRON,{7,6,14,0,-1,-1,-1,-1,},{8,2,5,102,-1,-1,},805306410}, {TETRAHEDRON,{0,1,5,14,-1,-1,-1,-1,},{100,0,2,5,-1,-1,},268435458}, {TETRAHEDRON,{1,7,14,0,-1,-1,-1,-1,},{1,3,4,103,-1,-1,},536870921}, {TETRAHEDRON,{5,6,14,2,-1,-1,-1,-1,},{2,11,7,100,-1,-1,},805306394}, {TETRAHEDRON,{2,5,8,14,-1,-1,-1,-1,},{101,0,10,6,-1,-1,},268435456}, {TETRAHEDRON,{6,7,14,3,-1,-1,-1,-1,},{3,9,11,102,-1,-1,},1073741866}, {TETRAHEDRON,{7,8,14,3,-1,-1,-1,-1,},{1,10,8,103,-1,-1,},536870913}, {TETRAHEDRON,{3,8,14,2,-1,-1,-1,-1,},{9,7,11,101,-1,-1,},536870920}, {TETRAHEDRON,{6,3,14,2,-1,-1,-1,-1,},{8,10,6,102,-1,-1,},1073741914}, }}, // Rule 136 {TETRAHEDRON,136,RED_CLASS,12, // tag, mark, rclass, nsons {0,1,1,1,1,0,-1,-1,-1,-1,1,-1,-1,-1,-1,-1,-1,-1,-1,}, // pattern 1054, // pat {{-1,0},{0,1},{0,2},{2,1},{1,1},{-1,0},{-1,-1}, // sonandnode {-1,-1},{-1,-1},{-1,-1},{0,3},{-1,-1},{-1,-1}, {-1,-1},{-1,-1},{-1,-1},{-1,-1},{-1,-1},{-1,-1}, }, {{TETRAHEDRON,{1,5,6,14,-1,-1,-1,-1,},{100,6,4,1,-1,-1,},0}, // sons {TETRAHEDRON,{5,8,14,1,-1,-1,-1,-1,},{8,5,0,101,-1,-1,},268435459}, {TETRAHEDRON,{7,6,14,0,-1,-1,-1,-1,},{7,4,3,102,-1,-1,},536870922}, {TETRAHEDRON,{8,7,14,0,-1,-1,-1,-1,},{9,2,5,103,-1,-1,},805306394}, {TETRAHEDRON,{0,1,6,14,-1,-1,-1,-1,},{100,0,2,5,-1,-1,},268435458}, {TETRAHEDRON,{1,8,14,0,-1,-1,-1,-1,},{1,3,4,103,-1,-1,},536870919}, {TETRAHEDRON,{5,6,14,2,-1,-1,-1,-1,},{0,7,10,100,-1,-1,},268435457}, {TETRAHEDRON,{6,7,14,2,-1,-1,-1,-1,},{2,11,6,102,-1,-1,},805306378}, {TETRAHEDRON,{3,5,8,14,-1,-1,-1,-1,},{101,1,9,10,-1,-1,},536870915}, {TETRAHEDRON,{7,8,14,3,-1,-1,-1,-1,},{3,8,11,103,-1,-1,},1073741850}, {TETRAHEDRON,{3,5,14,2,-1,-1,-1,-1,},{8,6,11,101,-1,-1,},536870921}, {TETRAHEDRON,{7,3,14,2,-1,-1,-1,-1,},{9,10,7,102,-1,-1,},1073741898}, }}, // Rule 137 {TETRAHEDRON,137,RED_CLASS,6, // tag, mark, rclass, nsons {0,1,1,1,1,0,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,}, // pattern 30, // pat {{-1,0},{0,1},{0,2},{1,1},{1,2},{-1,0},{-1,-1}, // sonandnode {-1,-1},{-1,-1},{-1,-1},{-1,0},{-1,-1},{-1,-1}, {-1,-1},{-1,-1},{-1,-1},{-1,-1},{-1,-1},{-1,-1}, }, {{TETRAHEDRON,{3,5,6,2,-1,-1,-1,-1,},{2,100,102,101,-1,-1,},0}, // sons {TETRAHEDRON,{5,7,8,3,-1,-1,-1,-1,},{5,103,101,2,-1,-1,},536870920}, {TETRAHEDRON,{5,6,7,3,-1,-1,-1,-1,},{3,102,1,0,-1,-1,},268435456}, {TETRAHEDRON,{0,5,6,7,-1,-1,-1,-1,},{100,2,102,4,-1,-1,},536870912}, {TETRAHEDRON,{0,1,5,7,-1,-1,-1,-1,},{100,5,3,103,-1,-1,},805306416}, {TETRAHEDRON,{1,5,7,8,-1,-1,-1,-1,},{4,1,103,101,-1,-1,},805306376}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, }}, // Rule 138 {TETRAHEDRON,138,RED_CLASS,6, // tag, mark, rclass, nsons {0,1,1,1,1,0,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,}, // pattern 30, // pat {{-1,0},{0,1},{0,2},{1,1},{1,2},{-1,0},{-1,-1}, // sonandnode {-1,-1},{-1,-1},{-1,-1},{-1,0},{-1,-1},{-1,-1}, {-1,-1},{-1,-1},{-1,-1},{-1,-1},{-1,-1},{-1,-1}, }, {{TETRAHEDRON,{3,5,6,2,-1,-1,-1,-1,},{2,100,102,101,-1,-1,},0}, // sons {TETRAHEDRON,{5,7,8,3,-1,-1,-1,-1,},{5,103,101,2,-1,-1,},536870920}, {TETRAHEDRON,{5,6,7,3,-1,-1,-1,-1,},{4,102,1,0,-1,-1,},268435456}, {TETRAHEDRON,{0,1,5,8,-1,-1,-1,-1,},{100,101,5,103,-1,-1,},1073742024}, {TETRAHEDRON,{0,5,6,7,-1,-1,-1,-1,},{100,2,102,5,-1,-1,},536870912}, {TETRAHEDRON,{0,5,7,8,-1,-1,-1,-1,},{4,1,103,3,-1,-1,},805306376}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, }}, // Rule 139 {TETRAHEDRON,139,RED_CLASS,6, // tag, mark, rclass, nsons {0,1,1,1,1,0,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,}, // pattern 30, // pat {{-1,0},{0,1},{3,1},{0,2},{1,2},{-1,0},{-1,-1}, // sonandnode {-1,-1},{-1,-1},{-1,-1},{-1,0},{-1,-1},{-1,-1}, {-1,-1},{-1,-1},{-1,-1},{-1,-1},{-1,-1},{-1,-1}, }, {{TETRAHEDRON,{3,5,7,2,-1,-1,-1,-1,},{1,3,102,101,-1,-1,},0}, // sons {TETRAHEDRON,{5,7,8,3,-1,-1,-1,-1,},{5,103,101,0,-1,-1,},268435456}, {TETRAHEDRON,{0,1,5,7,-1,-1,-1,-1,},{100,5,4,103,-1,-1,},805306417}, {TETRAHEDRON,{5,6,7,2,-1,-1,-1,-1,},{4,102,0,100,-1,-1,},268435457}, {TETRAHEDRON,{0,5,6,7,-1,-1,-1,-1,},{100,3,102,2,-1,-1,},536870913}, {TETRAHEDRON,{1,5,7,8,-1,-1,-1,-1,},{2,1,103,101,-1,-1,},536870912}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, }}, // Rule 140 {TETRAHEDRON,140,RED_CLASS,6, // tag, mark, rclass, nsons {0,1,1,1,1,0,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,}, // pattern 30, // pat {{-1,0},{0,1},{4,1},{0,2},{1,2},{-1,0},{-1,-1}, // sonandnode {-1,-1},{-1,-1},{-1,-1},{-1,0},{-1,-1},{-1,-1}, {-1,-1},{-1,-1},{-1,-1},{-1,-1},{-1,-1},{-1,-1}, }, {{TETRAHEDRON,{3,5,7,2,-1,-1,-1,-1,},{1,4,102,101,-1,-1,},0}, // sons {TETRAHEDRON,{5,7,8,3,-1,-1,-1,-1,},{3,103,101,0,-1,-1,},268435456}, {TETRAHEDRON,{0,1,5,8,-1,-1,-1,-1,},{100,101,3,103,-1,-1,},805306416}, {TETRAHEDRON,{0,5,7,8,-1,-1,-1,-1,},{5,1,103,2,-1,-1,},536870912}, {TETRAHEDRON,{5,6,7,2,-1,-1,-1,-1,},{5,102,0,100,-1,-1,},268435457}, {TETRAHEDRON,{0,5,6,7,-1,-1,-1,-1,},{100,4,102,3,-1,-1,},805306368}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, }}, // Rule 141 {TETRAHEDRON,141,RED_CLASS,6, // tag, mark, rclass, nsons {0,1,1,1,1,0,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,}, // pattern 30, // pat {{-1,0},{0,1},{0,2},{1,1},{1,2},{-1,0},{-1,-1}, // sonandnode {-1,-1},{-1,-1},{-1,-1},{-1,0},{-1,-1},{-1,-1}, {-1,-1},{-1,-1},{-1,-1},{-1,-1},{-1,-1},{-1,-1}, }, {{TETRAHEDRON,{3,5,6,2,-1,-1,-1,-1,},{2,100,102,101,-1,-1,},0}, // sons {TETRAHEDRON,{6,7,8,3,-1,-1,-1,-1,},{5,103,2,102,-1,-1,},536870916}, {TETRAHEDRON,{5,6,8,3,-1,-1,-1,-1,},{4,1,101,0,-1,-1,},268435456}, {TETRAHEDRON,{0,1,6,7,-1,-1,-1,-1,},{100,5,102,103,-1,-1,},1073741828}, {TETRAHEDRON,{1,5,6,8,-1,-1,-1,-1,},{100,2,5,101,-1,-1,},536870912}, {TETRAHEDRON,{1,6,7,8,-1,-1,-1,-1,},{3,1,103,4,-1,-1,},805306372}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, }}, // Rule 142 {TETRAHEDRON,142,RED_CLASS,6, // tag, mark, rclass, nsons {0,1,1,1,1,0,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,}, // pattern 30, // pat {{-1,0},{0,1},{0,2},{1,1},{1,2},{-1,0},{-1,-1}, // sonandnode {-1,-1},{-1,-1},{-1,-1},{-1,0},{-1,-1},{-1,-1}, {-1,-1},{-1,-1},{-1,-1},{-1,-1},{-1,-1},{-1,-1}, }, {{TETRAHEDRON,{3,5,6,2,-1,-1,-1,-1,},{2,100,102,101,-1,-1,},0}, // sons {TETRAHEDRON,{6,7,8,3,-1,-1,-1,-1,},{5,103,2,102,-1,-1,},536870916}, {TETRAHEDRON,{5,6,8,3,-1,-1,-1,-1,},{3,1,101,0,-1,-1,},268435456}, {TETRAHEDRON,{1,5,6,8,-1,-1,-1,-1,},{100,2,4,101,-1,-1,},536870912}, {TETRAHEDRON,{0,1,6,8,-1,-1,-1,-1,},{100,3,5,103,-1,-1,},805306400}, {TETRAHEDRON,{0,6,7,8,-1,-1,-1,-1,},{102,1,103,4,-1,-1,},805306372}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, }}, // Rule 143 {TETRAHEDRON,143,RED_CLASS,6, // tag, mark, rclass, nsons {0,1,1,1,1,0,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,}, // pattern 30, // pat {{-1,0},{4,0},{0,2},{1,1},{0,3},{-1,0},{-1,-1}, // sonandnode {-1,-1},{-1,-1},{-1,-1},{-1,0},{-1,-1},{-1,-1}, {-1,-1},{-1,-1},{-1,-1},{-1,-1},{-1,-1},{-1,-1}, }, {{TETRAHEDRON,{2,3,6,8,-1,-1,-1,-1,},{102,1,4,101,-1,-1,},0}, // sons {TETRAHEDRON,{6,7,8,3,-1,-1,-1,-1,},{3,103,0,102,-1,-1,},268435457}, {TETRAHEDRON,{0,1,6,7,-1,-1,-1,-1,},{100,3,102,103,-1,-1,},805306369}, {TETRAHEDRON,{1,6,7,8,-1,-1,-1,-1,},{2,1,103,5,-1,-1,},536870913}, {TETRAHEDRON,{5,6,8,2,-1,-1,-1,-1,},{5,0,101,100,-1,-1,},268435458}, {TETRAHEDRON,{1,5,6,8,-1,-1,-1,-1,},{100,4,3,101,-1,-1,},805306417}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, }}, // Rule 144 {TETRAHEDRON,144,RED_CLASS,6, // tag, mark, rclass, nsons {0,1,1,1,1,0,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,}, // pattern 30, // pat {{-1,0},{3,0},{0,2},{1,1},{0,3},{-1,0},{-1,-1}, // sonandnode {-1,-1},{-1,-1},{-1,-1},{-1,0},{-1,-1},{-1,-1}, {-1,-1},{-1,-1},{-1,-1},{-1,-1},{-1,-1},{-1,-1}, }, {{TETRAHEDRON,{2,3,6,8,-1,-1,-1,-1,},{102,1,3,101,-1,-1,},0}, // sons {TETRAHEDRON,{6,7,8,3,-1,-1,-1,-1,},{5,103,0,102,-1,-1,},268435457}, {TETRAHEDRON,{0,1,6,8,-1,-1,-1,-1,},{100,4,5,103,-1,-1,},805306402}, {TETRAHEDRON,{5,6,8,2,-1,-1,-1,-1,},{4,0,101,100,-1,-1,},268435458}, {TETRAHEDRON,{1,5,6,8,-1,-1,-1,-1,},{100,3,2,101,-1,-1,},536870914}, {TETRAHEDRON,{0,6,7,8,-1,-1,-1,-1,},{102,1,103,2,-1,-1,},536870913}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, }}, // Rule 145 {TETRAHEDRON,145,RED_CLASS,6, // tag, mark, rclass, nsons {0,1,1,1,1,0,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,}, // pattern 30, // pat {{-1,0},{0,1},{1,1},{0,2},{4,2},{-1,0},{-1,-1}, // sonandnode {-1,-1},{-1,-1},{-1,-1},{-1,0},{-1,-1},{-1,-1}, {-1,-1},{-1,-1},{-1,-1},{-1,-1},{-1,-1},{-1,-1}, }, {{TETRAHEDRON,{3,5,7,2,-1,-1,-1,-1,},{4,1,102,101,-1,-1,},0}, // sons {TETRAHEDRON,{5,6,7,2,-1,-1,-1,-1,},{3,102,0,100,-1,-1,},268435457}, {TETRAHEDRON,{0,1,6,7,-1,-1,-1,-1,},{100,3,102,103,-1,-1,},805306401}, {TETRAHEDRON,{1,5,6,7,-1,-1,-1,-1,},{100,1,2,5,-1,-1,},536870913}, {TETRAHEDRON,{5,7,8,3,-1,-1,-1,-1,},{5,103,101,0,-1,-1,},268435456}, {TETRAHEDRON,{1,5,7,8,-1,-1,-1,-1,},{3,4,103,101,-1,-1,},805306417}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, }}, // Rule 146 {TETRAHEDRON,146,RED_CLASS,6, // tag, mark, rclass, nsons {0,1,1,1,1,0,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,}, // pattern 30, // pat {{-1,0},{1,0},{1,1},{0,2},{0,3},{-1,0},{-1,-1}, // sonandnode {-1,-1},{-1,-1},{-1,-1},{-1,0},{-1,-1},{-1,-1}, {-1,-1},{-1,-1},{-1,-1},{-1,-1},{-1,-1},{-1,-1}, }, {{TETRAHEDRON,{2,3,7,8,-1,-1,-1,-1,},{102,103,3,101,-1,-1,},0}, // sons {TETRAHEDRON,{5,6,7,2,-1,-1,-1,-1,},{5,102,3,100,-1,-1,},536870926}, {TETRAHEDRON,{0,1,6,7,-1,-1,-1,-1,},{100,5,102,103,-1,-1,},1073741966}, {TETRAHEDRON,{5,7,8,2,-1,-1,-1,-1,},{4,0,101,1,-1,-1,},268435458}, {TETRAHEDRON,{1,5,7,8,-1,-1,-1,-1,},{5,3,103,101,-1,-1,},536870914}, {TETRAHEDRON,{1,5,6,7,-1,-1,-1,-1,},{100,1,2,4,-1,-1,},805306382}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, }}, // Rule 147 {TETRAHEDRON,147,RED_CLASS,6, // tag, mark, rclass, nsons {0,1,1,1,1,0,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,}, // pattern 30, // pat {{-1,0},{1,0},{1,1},{0,2},{0,3},{-1,0},{-1,-1}, // sonandnode {-1,-1},{-1,-1},{-1,-1},{-1,0},{-1,-1},{-1,-1}, {-1,-1},{-1,-1},{-1,-1},{-1,-1},{-1,-1},{-1,-1}, }, {{TETRAHEDRON,{2,3,7,8,-1,-1,-1,-1,},{102,103,2,101,-1,-1,},0}, // sons {TETRAHEDRON,{5,6,7,2,-1,-1,-1,-1,},{5,102,2,100,-1,-1,},536870926}, {TETRAHEDRON,{5,7,8,2,-1,-1,-1,-1,},{3,0,101,1,-1,-1,},268435458}, {TETRAHEDRON,{1,5,7,8,-1,-1,-1,-1,},{4,2,103,101,-1,-1,},536870914}, {TETRAHEDRON,{0,1,5,7,-1,-1,-1,-1,},{100,3,5,103,-1,-1,},805306370}, {TETRAHEDRON,{0,5,6,7,-1,-1,-1,-1,},{100,1,102,4,-1,-1,},805306382}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, }}, // Rule 148 {TETRAHEDRON,148,RED_CLASS,6, // tag, mark, rclass, nsons {0,1,1,1,1,0,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,}, // pattern 30, // pat {{-1,0},{1,0},{0,2},{4,1},{0,3},{-1,0},{-1,-1}, // sonandnode {-1,-1},{-1,-1},{-1,-1},{-1,0},{-1,-1},{-1,-1}, {-1,-1},{-1,-1},{-1,-1},{-1,-1},{-1,-1},{-1,-1}, }, {{TETRAHEDRON,{2,3,6,8,-1,-1,-1,-1,},{102,4,1,101,-1,-1,},0}, // sons {TETRAHEDRON,{5,6,8,2,-1,-1,-1,-1,},{3,0,101,100,-1,-1,},268435458}, {TETRAHEDRON,{0,1,5,8,-1,-1,-1,-1,},{100,101,3,103,-1,-1,},805306418}, {TETRAHEDRON,{0,5,6,8,-1,-1,-1,-1,},{100,1,5,2,-1,-1,},536870914}, {TETRAHEDRON,{6,7,8,3,-1,-1,-1,-1,},{5,103,0,102,-1,-1,},268435457}, {TETRAHEDRON,{0,6,7,8,-1,-1,-1,-1,},{102,4,103,3,-1,-1,},805306402}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, }}, // Rule 149 {TETRAHEDRON,149,RED_CLASS,6, // tag, mark, rclass, nsons {0,1,1,1,1,0,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,}, // pattern 30, // pat {{-1,0},{1,0},{1,1},{0,2},{0,3},{-1,0},{-1,-1}, // sonandnode {-1,-1},{-1,-1},{-1,-1},{-1,0},{-1,-1},{-1,-1}, {-1,-1},{-1,-1},{-1,-1},{-1,-1},{-1,-1},{-1,-1}, }, {{TETRAHEDRON,{2,3,7,8,-1,-1,-1,-1,},{102,103,3,101,-1,-1,},0}, // sons {TETRAHEDRON,{5,6,8,2,-1,-1,-1,-1,},{5,3,101,100,-1,-1,},536870922}, {TETRAHEDRON,{0,1,5,8,-1,-1,-1,-1,},{100,101,5,103,-1,-1,},1073742026}, {TETRAHEDRON,{6,7,8,2,-1,-1,-1,-1,},{4,0,1,102,-1,-1,},268435458}, {TETRAHEDRON,{0,6,7,8,-1,-1,-1,-1,},{102,3,103,5,-1,-1,},536870914}, {TETRAHEDRON,{0,5,6,8,-1,-1,-1,-1,},{100,1,4,2,-1,-1,},805306378}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, }}, // Rule 150 {TETRAHEDRON,150,RED_CLASS,6, // tag, mark, rclass, nsons {0,1,1,1,1,0,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,}, // pattern 30, // pat {{-1,0},{1,0},{1,1},{0,2},{0,3},{-1,0},{-1,-1}, // sonandnode {-1,-1},{-1,-1},{-1,-1},{-1,0},{-1,-1},{-1,-1}, {-1,-1},{-1,-1},{-1,-1},{-1,-1},{-1,-1},{-1,-1}, }, {{TETRAHEDRON,{2,3,7,8,-1,-1,-1,-1,},{102,103,2,101,-1,-1,},0}, // sons {TETRAHEDRON,{5,6,8,2,-1,-1,-1,-1,},{5,2,101,100,-1,-1,},536870922}, {TETRAHEDRON,{6,7,8,2,-1,-1,-1,-1,},{3,0,1,102,-1,-1,},268435458}, {TETRAHEDRON,{0,6,7,8,-1,-1,-1,-1,},{102,2,103,4,-1,-1,},536870914}, {TETRAHEDRON,{0,1,6,8,-1,-1,-1,-1,},{100,5,3,103,-1,-1,},805306418}, {TETRAHEDRON,{1,5,6,8,-1,-1,-1,-1,},{100,1,4,101,-1,-1,},805306378}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, }}, // Rule 151 {TETRAHEDRON,151,RED_CLASS,6, // tag, mark, rclass, nsons {1,1,1,0,0,1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,}, // pattern 39, // pat {{1,0},{0,0},{0,1},{-1,0},{-1,0},{0,2},{-1,-1}, // sonandnode {-1,-1},{-1,-1},{-1,-1},{-1,0},{-1,-1},{-1,-1}, {-1,-1},{-1,-1},{-1,-1},{-1,-1},{-1,-1},{-1,-1}, }, {{TETRAHEDRON,{5,6,9,2,-1,-1,-1,-1,},{1,102,101,100,-1,-1,},0}, // sons {TETRAHEDRON,{4,5,6,9,-1,-1,-1,-1,},{100,0,2,4,-1,-1,},268435456}, {TETRAHEDRON,{3,4,6,9,-1,-1,-1,-1,},{3,1,102,4,-1,-1,},536870920}, {TETRAHEDRON,{0,3,4,6,-1,-1,-1,-1,},{103,2,100,102,-1,-1,},805306376}, {TETRAHEDRON,{4,5,9,3,-1,-1,-1,-1,},{1,101,2,5,-1,-1,},536870924}, {TETRAHEDRON,{3,4,5,1,-1,-1,-1,-1,},{4,100,101,103,-1,-1,},805306428}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, }}, // Rule 152 {TETRAHEDRON,152,RED_CLASS,6, // tag, mark, rclass, nsons {1,1,1,0,0,1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,}, // pattern 39, // pat {{1,0},{0,0},{0,1},{-1,0},{-1,0},{0,2},{-1,-1}, // sonandnode {-1,-1},{-1,-1},{-1,-1},{-1,0},{-1,-1},{-1,-1}, {-1,-1},{-1,-1},{-1,-1},{-1,-1},{-1,-1},{-1,-1}, }, {{TETRAHEDRON,{5,6,9,2,-1,-1,-1,-1,},{1,102,101,100,-1,-1,},0}, // sons {TETRAHEDRON,{4,5,6,9,-1,-1,-1,-1,},{100,0,2,5,-1,-1,},268435456}, {TETRAHEDRON,{3,4,6,9,-1,-1,-1,-1,},{3,1,102,4,-1,-1,},536870920}, {TETRAHEDRON,{0,3,4,6,-1,-1,-1,-1,},{103,2,100,102,-1,-1,},805306376}, {TETRAHEDRON,{3,4,9,1,-1,-1,-1,-1,},{2,5,101,103,-1,-1,},805306424}, {TETRAHEDRON,{4,5,9,1,-1,-1,-1,-1,},{1,101,4,100,-1,-1,},536870924}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, }}, // Rule 153 {TETRAHEDRON,153,RED_CLASS,6, // tag, mark, rclass, nsons {1,1,1,0,0,1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,}, // pattern 39, // pat {{1,0},{0,0},{0,1},{-1,0},{-1,0},{0,2},{-1,-1}, // sonandnode {-1,-1},{-1,-1},{-1,-1},{-1,0},{-1,-1},{-1,-1}, {-1,-1},{-1,-1},{-1,-1},{-1,-1},{-1,-1},{-1,-1}, }, {{TETRAHEDRON,{5,6,9,2,-1,-1,-1,-1,},{1,102,101,100,-1,-1,},0}, // sons {TETRAHEDRON,{4,5,6,9,-1,-1,-1,-1,},{100,0,2,5,-1,-1,},268435456}, {TETRAHEDRON,{0,4,6,9,-1,-1,-1,-1,},{100,1,102,3,-1,-1,},536870920}, {TETRAHEDRON,{0,3,4,9,-1,-1,-1,-1,},{103,4,2,102,-1,-1,},805306424}, {TETRAHEDRON,{3,4,9,1,-1,-1,-1,-1,},{3,5,101,103,-1,-1,},1073741944}, {TETRAHEDRON,{4,5,9,1,-1,-1,-1,-1,},{1,101,4,100,-1,-1,},536870924}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, }}, // Rule 154 {TETRAHEDRON,154,RED_CLASS,6, // tag, mark, rclass, nsons {1,1,1,0,0,1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,}, // pattern 39, // pat {{1,0},{0,0},{0,1},{-1,0},{-1,0},{0,2},{-1,-1}, // sonandnode {-1,-1},{-1,-1},{-1,-1},{-1,0},{-1,-1},{-1,-1}, {-1,-1},{-1,-1},{-1,-1},{-1,-1},{-1,-1},{-1,-1}, }, {{TETRAHEDRON,{5,6,9,2,-1,-1,-1,-1,},{1,102,101,100,-1,-1,},0}, // sons {TETRAHEDRON,{4,5,6,9,-1,-1,-1,-1,},{100,0,2,4,-1,-1,},268435456}, {TETRAHEDRON,{0,4,6,9,-1,-1,-1,-1,},{100,1,102,3,-1,-1,},536870920}, {TETRAHEDRON,{0,3,4,9,-1,-1,-1,-1,},{103,4,2,102,-1,-1,},805306424}, {TETRAHEDRON,{4,5,9,3,-1,-1,-1,-1,},{1,101,3,5,-1,-1,},536870924}, {TETRAHEDRON,{3,4,5,1,-1,-1,-1,-1,},{4,100,101,103,-1,-1,},805306428}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, }}, // Rule 155 {TETRAHEDRON,155,RED_CLASS,12, // tag, mark, rclass, nsons {1,1,0,1,0,1,-1,-1,-1,-1,1,-1,-1,-1,-1,-1,-1,-1,-1,}, // pattern 1067, // pat {{0,0},{2,2},{-1,0},{0,1},{-1,0},{1,1},{-1,-1}, // sonandnode {-1,-1},{-1,-1},{-1,-1},{0,2},{-1,-1},{-1,-1}, {-1,-1},{-1,-1},{-1,-1},{-1,-1},{-1,-1},{-1,-1}, }, {{TETRAHEDRON,{4,7,14,0,-1,-1,-1,-1,},{7,1,4,103,-1,-1,},0}, // sons {TETRAHEDRON,{7,9,14,0,-1,-1,-1,-1,},{9,5,0,102,-1,-1,},268435457}, {TETRAHEDRON,{2,4,5,14,-1,-1,-1,-1,},{100,6,3,4,-1,-1,},536870914}, {TETRAHEDRON,{2,5,9,14,-1,-1,-1,-1,},{101,8,5,2,-1,-1,},805306402}, {TETRAHEDRON,{2,4,14,0,-1,-1,-1,-1,},{2,0,5,100,-1,-1,},268435458}, {TETRAHEDRON,{9,2,14,0,-1,-1,-1,-1,},{3,4,1,102,-1,-1,},536870917}, {TETRAHEDRON,{4,5,14,1,-1,-1,-1,-1,},{2,11,7,100,-1,-1,},805306386}, {TETRAHEDRON,{7,4,14,1,-1,-1,-1,-1,},{0,6,10,103,-1,-1,},268435456}, {TETRAHEDRON,{5,9,14,3,-1,-1,-1,-1,},{3,9,11,101,-1,-1,},1073741922}, {TETRAHEDRON,{9,7,14,3,-1,-1,-1,-1,},{1,10,8,102,-1,-1,},536870913}, {TETRAHEDRON,{3,7,14,1,-1,-1,-1,-1,},{9,7,11,103,-1,-1,},536870916}, {TETRAHEDRON,{1,3,5,14,-1,-1,-1,-1,},{101,8,6,10,-1,-1,},1073741906}, }}, // Rule 156 {TETRAHEDRON,156,RED_CLASS,12, // tag, mark, rclass, nsons {1,1,0,1,0,1,-1,-1,-1,-1,1,-1,-1,-1,-1,-1,-1,-1,-1,}, // pattern 1067, // pat {{0,1},{0,2},{-1,0},{1,1},{-1,0},{2,2},{-1,-1}, // sonandnode {-1,-1},{-1,-1},{-1,-1},{0,3},{-1,-1},{-1,-1}, {-1,-1},{-1,-1},{-1,-1},{-1,-1},{-1,-1},{-1,-1}, }, {{TETRAHEDRON,{0,4,5,14,-1,-1,-1,-1,},{100,6,4,1,-1,-1,},0}, // sons {TETRAHEDRON,{4,7,14,0,-1,-1,-1,-1,},{8,5,0,103,-1,-1,},268435459}, {TETRAHEDRON,{2,5,9,14,-1,-1,-1,-1,},{101,7,3,4,-1,-1,},536870914}, {TETRAHEDRON,{7,9,14,2,-1,-1,-1,-1,},{9,2,5,102,-1,-1,},805306402}, {TETRAHEDRON,{2,5,14,0,-1,-1,-1,-1,},{2,0,5,100,-1,-1,},268435458}, {TETRAHEDRON,{7,2,14,0,-1,-1,-1,-1,},{3,4,1,102,-1,-1,},536870919}, {TETRAHEDRON,{4,5,14,1,-1,-1,-1,-1,},{0,7,10,100,-1,-1,},268435457}, {TETRAHEDRON,{5,9,14,1,-1,-1,-1,-1,},{2,11,6,101,-1,-1,},805306386}, {TETRAHEDRON,{7,4,14,3,-1,-1,-1,-1,},{1,10,9,103,-1,-1,},536870915}, {TETRAHEDRON,{9,7,14,3,-1,-1,-1,-1,},{3,8,11,102,-1,-1,},1073741858}, {TETRAHEDRON,{3,4,14,1,-1,-1,-1,-1,},{8,6,11,103,-1,-1,},536870921}, {TETRAHEDRON,{1,3,9,14,-1,-1,-1,-1,},{101,9,7,10,-1,-1,},1073741906}, }}, // Rule 157 {TETRAHEDRON,157,RED_CLASS,6, // tag, mark, rclass, nsons {1,1,0,1,0,1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,}, // pattern 43, // pat {{0,0},{0,1},{-1,0},{1,2},{-1,0},{0,2},{-1,-1}, // sonandnode {-1,-1},{-1,-1},{-1,-1},{-1,0},{-1,-1},{-1,-1}, {-1,-1},{-1,-1},{-1,-1},{-1,-1},{-1,-1},{-1,-1}, }, {{TETRAHEDRON,{4,5,9,3,-1,-1,-1,-1,},{5,101,1,2,-1,-1,},0}, // sons {TETRAHEDRON,{3,4,7,9,-1,-1,-1,-1,},{103,4,102,0,-1,-1,},268435458}, {TETRAHEDRON,{3,4,5,1,-1,-1,-1,-1,},{0,100,101,103,-1,-1,},268435459}, {TETRAHEDRON,{2,4,7,0,-1,-1,-1,-1,},{4,103,102,100,-1,-1,},805306422}, {TETRAHEDRON,{4,7,9,2,-1,-1,-1,-1,},{1,102,5,3,-1,-1,},536870918}, {TETRAHEDRON,{2,4,5,9,-1,-1,-1,-1,},{100,0,101,4,-1,-1,},268435456}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, }}, // Rule 158 {TETRAHEDRON,158,RED_CLASS,6, // tag, mark, rclass, nsons {1,1,0,1,0,1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,}, // pattern 43, // pat {{0,0},{0,1},{-1,0},{1,2},{-1,0},{0,2},{-1,-1}, // sonandnode {-1,-1},{-1,-1},{-1,-1},{-1,0},{-1,-1},{-1,-1}, {-1,-1},{-1,-1},{-1,-1},{-1,-1},{-1,-1},{-1,-1}, }, {{TETRAHEDRON,{4,5,9,3,-1,-1,-1,-1,},{4,101,1,2,-1,-1,},0}, // sons {TETRAHEDRON,{3,4,7,9,-1,-1,-1,-1,},{103,5,102,0,-1,-1,},268435458}, {TETRAHEDRON,{3,4,5,1,-1,-1,-1,-1,},{0,100,101,103,-1,-1,},268435459}, {TETRAHEDRON,{2,4,9,0,-1,-1,-1,-1,},{4,5,102,100,-1,-1,},536870924}, {TETRAHEDRON,{2,4,5,9,-1,-1,-1,-1,},{100,0,101,3,-1,-1,},268435456}, {TETRAHEDRON,{4,7,9,0,-1,-1,-1,-1,},{1,102,3,103,-1,-1,},536870918}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, }}, // Rule 159 {TETRAHEDRON,159,RED_CLASS,6, // tag, mark, rclass, nsons {1,1,0,1,0,1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,}, // pattern 43, // pat {{0,1},{4,2},{-1,0},{1,2},{-1,0},{0,2},{-1,-1}, // sonandnode {-1,-1},{-1,-1},{-1,-1},{-1,0},{-1,-1},{-1,-1}, {-1,-1},{-1,-1},{-1,-1},{-1,-1},{-1,-1},{-1,-1}, }, {{TETRAHEDRON,{3,4,9,1,-1,-1,-1,-1,},{1,5,101,103,-1,-1,},0}, // sons {TETRAHEDRON,{3,4,7,9,-1,-1,-1,-1,},{103,3,102,0,-1,-1,},268435456}, {TETRAHEDRON,{2,4,7,0,-1,-1,-1,-1,},{3,103,102,100,-1,-1,},805306420}, {TETRAHEDRON,{4,7,9,2,-1,-1,-1,-1,},{1,102,4,2,-1,-1,},536870916}, {TETRAHEDRON,{2,4,5,9,-1,-1,-1,-1,},{100,5,101,3,-1,-1,},805306404}, {TETRAHEDRON,{4,5,9,1,-1,-1,-1,-1,},{4,101,0,100,-1,-1,},268435457}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, }}, // Rule 160 {TETRAHEDRON,160,RED_CLASS,6, // tag, mark, rclass, nsons {1,1,0,1,0,1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,}, // pattern 43, // pat {{0,1},{3,2},{-1,0},{1,2},{-1,0},{0,2},{-1,-1}, // sonandnode {-1,-1},{-1,-1},{-1,-1},{-1,0},{-1,-1},{-1,-1}, {-1,-1},{-1,-1},{-1,-1},{-1,-1},{-1,-1},{-1,-1}, }, {{TETRAHEDRON,{3,4,9,1,-1,-1,-1,-1,},{1,4,101,103,-1,-1,},0}, // sons {TETRAHEDRON,{3,4,7,9,-1,-1,-1,-1,},{103,5,102,0,-1,-1,},268435456}, {TETRAHEDRON,{2,4,9,0,-1,-1,-1,-1,},{3,5,102,100,-1,-1,},805306417}, {TETRAHEDRON,{2,4,5,9,-1,-1,-1,-1,},{100,4,101,2,-1,-1,},536870913}, {TETRAHEDRON,{4,5,9,1,-1,-1,-1,-1,},{3,101,0,100,-1,-1,},268435457}, {TETRAHEDRON,{4,7,9,0,-1,-1,-1,-1,},{1,102,2,103,-1,-1,},536870916}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, }}, // Rule 161 {TETRAHEDRON,161,RED_CLASS,6, // tag, mark, rclass, nsons {1,1,0,1,0,1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,}, // pattern 43, // pat {{1,1},{0,1},{-1,0},{0,2},{-1,0},{0,3},{-1,-1}, // sonandnode {-1,-1},{-1,-1},{-1,-1},{-1,0},{-1,-1},{-1,-1}, {-1,-1},{-1,-1},{-1,-1},{-1,-1},{-1,-1},{-1,-1}, }, {{TETRAHEDRON,{3,5,7,9,-1,-1,-1,-1,},{2,5,102,101,-1,-1,},0}, // sons {TETRAHEDRON,{3,4,5,1,-1,-1,-1,-1,},{2,100,101,103,-1,-1,},536870924}, {TETRAHEDRON,{4,5,7,3,-1,-1,-1,-1,},{3,0,103,1,-1,-1,},268435456}, {TETRAHEDRON,{0,4,5,7,-1,-1,-1,-1,},{100,2,4,103,-1,-1,},536870912}, {TETRAHEDRON,{2,5,7,0,-1,-1,-1,-1,},{5,3,102,100,-1,-1,},805306400}, {TETRAHEDRON,{5,7,9,2,-1,-1,-1,-1,},{0,102,101,4,-1,-1,},268435457}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, }}, // Rule 162 {TETRAHEDRON,162,RED_CLASS,6, // tag, mark, rclass, nsons {1,1,0,1,0,1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,}, // pattern 43, // pat {{1,1},{0,1},{-1,0},{0,2},{-1,0},{0,3},{-1,-1}, // sonandnode {-1,-1},{-1,-1},{-1,-1},{-1,0},{-1,-1},{-1,-1}, {-1,-1},{-1,-1},{-1,-1},{-1,-1},{-1,-1},{-1,-1}, }, {{TETRAHEDRON,{3,5,7,9,-1,-1,-1,-1,},{2,5,102,101,-1,-1,},0}, // sons {TETRAHEDRON,{3,4,5,1,-1,-1,-1,-1,},{2,100,101,103,-1,-1,},536870924}, {TETRAHEDRON,{4,5,7,3,-1,-1,-1,-1,},{4,0,103,1,-1,-1,},268435456}, {TETRAHEDRON,{2,5,9,0,-1,-1,-1,-1,},{101,5,102,100,-1,-1,},536870921}, {TETRAHEDRON,{0,4,5,7,-1,-1,-1,-1,},{100,2,5,103,-1,-1,},536870912}, {TETRAHEDRON,{5,7,9,0,-1,-1,-1,-1,},{0,102,3,4,-1,-1,},268435457}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, }}, // Rule 163 {TETRAHEDRON,163,RED_CLASS,6, // tag, mark, rclass, nsons {1,1,0,1,0,1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,}, // pattern 43, // pat {{2,0},{0,1},{-1,0},{0,2},{-1,0},{0,3},{-1,-1}, // sonandnode {-1,-1},{-1,-1},{-1,-1},{-1,0},{-1,-1},{-1,-1}, {-1,-1},{-1,-1},{-1,-1},{-1,-1},{-1,-1},{-1,-1}, }, {{TETRAHEDRON,{3,5,7,9,-1,-1,-1,-1,},{1,5,102,101,-1,-1,},0}, // sons {TETRAHEDRON,{1,3,5,7,-1,-1,-1,-1,},{101,0,2,103,-1,-1,},268435456}, {TETRAHEDRON,{4,5,7,1,-1,-1,-1,-1,},{4,1,103,100,-1,-1,},536870920}, {TETRAHEDRON,{2,5,7,0,-1,-1,-1,-1,},{5,4,102,100,-1,-1,},1073741960}, {TETRAHEDRON,{0,4,5,7,-1,-1,-1,-1,},{100,2,3,103,-1,-1,},805306376}, {TETRAHEDRON,{5,7,9,2,-1,-1,-1,-1,},{0,102,101,3,-1,-1,},268435457}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, }}, // Rule 164 {TETRAHEDRON,164,RED_CLASS,6, // tag, mark, rclass, nsons {1,1,0,1,0,1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,}, // pattern 43, // pat {{3,0},{0,1},{-1,0},{0,2},{-1,0},{0,3},{-1,-1}, // sonandnode {-1,-1},{-1,-1},{-1,-1},{-1,0},{-1,-1},{-1,-1}, {-1,-1},{-1,-1},{-1,-1},{-1,-1},{-1,-1},{-1,-1}, }, {{TETRAHEDRON,{3,5,7,9,-1,-1,-1,-1,},{1,4,102,101,-1,-1,},0}, // sons {TETRAHEDRON,{1,3,5,7,-1,-1,-1,-1,},{101,0,3,103,-1,-1,},268435456}, {TETRAHEDRON,{2,5,9,0,-1,-1,-1,-1,},{101,4,102,100,-1,-1,},536870921}, {TETRAHEDRON,{4,5,7,1,-1,-1,-1,-1,},{5,1,103,100,-1,-1,},536870920}, {TETRAHEDRON,{5,7,9,0,-1,-1,-1,-1,},{0,102,2,5,-1,-1,},268435457}, {TETRAHEDRON,{0,4,5,7,-1,-1,-1,-1,},{100,3,4,103,-1,-1,},805306376}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, }}, // Rule 165 {TETRAHEDRON,165,RED_CLASS,6, // tag, mark, rclass, nsons {1,1,0,1,0,1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,}, // pattern 43, // pat {{1,1},{0,1},{-1,0},{0,2},{-1,0},{0,3},{-1,-1}, // sonandnode {-1,-1},{-1,-1},{-1,-1},{-1,0},{-1,-1},{-1,-1}, {-1,-1},{-1,-1},{-1,-1},{-1,-1},{-1,-1},{-1,-1}, }, {{TETRAHEDRON,{3,5,7,9,-1,-1,-1,-1,},{4,5,102,101,-1,-1,},0}, // sons {TETRAHEDRON,{2,4,5,7,-1,-1,-1,-1,},{100,3,5,2,-1,-1,},805306376}, {TETRAHEDRON,{2,4,7,0,-1,-1,-1,-1,},{1,103,102,100,-1,-1,},1073742024}, {TETRAHEDRON,{4,5,7,1,-1,-1,-1,-1,},{1,4,103,100,-1,-1,},536870920}, {TETRAHEDRON,{1,3,5,7,-1,-1,-1,-1,},{101,0,3,103,-1,-1,},268435456}, {TETRAHEDRON,{5,7,9,2,-1,-1,-1,-1,},{0,102,101,1,-1,-1,},268435457}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, }}, // Rule 166 {TETRAHEDRON,166,RED_CLASS,6, // tag, mark, rclass, nsons {1,1,0,1,0,1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,}, // pattern 43, // pat {{1,1},{1,2},{-1,0},{0,1},{-1,0},{0,2},{-1,-1}, // sonandnode {-1,-1},{-1,-1},{-1,-1},{-1,0},{-1,-1},{-1,-1}, {-1,-1},{-1,-1},{-1,-1},{-1,-1},{-1,-1},{-1,-1}, }, {{TETRAHEDRON,{3,7,9,1,-1,-1,-1,-1,},{102,4,101,103,-1,-1,},0}, // sons {TETRAHEDRON,{2,4,5,7,-1,-1,-1,-1,},{100,5,3,2,-1,-1,},805306421}, {TETRAHEDRON,{2,4,7,0,-1,-1,-1,-1,},{1,103,102,100,-1,-1,},1073742069}, {TETRAHEDRON,{5,7,9,2,-1,-1,-1,-1,},{4,102,101,1,-1,-1,},536870917}, {TETRAHEDRON,{1,5,7,9,-1,-1,-1,-1,},{5,3,0,101,-1,-1,},268435457}, {TETRAHEDRON,{4,5,7,1,-1,-1,-1,-1,},{1,4,103,100,-1,-1,},536870913}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, }}, // Rule 167 {TETRAHEDRON,167,RED_CLASS,6, // tag, mark, rclass, nsons {1,1,0,1,0,1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,}, // pattern 43, // pat {{4,0},{1,1},{-1,0},{0,1},{-1,0},{0,2},{-1,-1}, // sonandnode {-1,-1},{-1,-1},{-1,-1},{-1,0},{-1,-1},{-1,-1}, {-1,-1},{-1,-1},{-1,-1},{-1,-1},{-1,-1},{-1,-1}, }, {{TETRAHEDRON,{3,7,9,1,-1,-1,-1,-1,},{102,3,101,103,-1,-1,},0}, // sons {TETRAHEDRON,{2,5,7,0,-1,-1,-1,-1,},{2,5,102,100,-1,-1,},805306421}, {TETRAHEDRON,{5,7,9,2,-1,-1,-1,-1,},{3,102,101,1,-1,-1,},536870917}, {TETRAHEDRON,{1,5,7,9,-1,-1,-1,-1,},{4,2,0,101,-1,-1,},268435457}, {TETRAHEDRON,{4,5,7,1,-1,-1,-1,-1,},{5,3,103,100,-1,-1,},536870913}, {TETRAHEDRON,{0,4,5,7,-1,-1,-1,-1,},{100,4,1,103,-1,-1,},1073741941}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, }}, // Rule 168 {TETRAHEDRON,168,RED_CLASS,6, // tag, mark, rclass, nsons {1,1,0,1,0,1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,}, // pattern 43, // pat {{0,1},{1,1},{-1,0},{4,2},{-1,0},{0,2},{-1,-1}, // sonandnode {-1,-1},{-1,-1},{-1,-1},{-1,0},{-1,-1},{-1,-1}, {-1,-1},{-1,-1},{-1,-1},{-1,-1},{-1,-1},{-1,-1}, }, {{TETRAHEDRON,{3,4,9,1,-1,-1,-1,-1,},{4,2,101,103,-1,-1,},0}, // sons {TETRAHEDRON,{2,5,9,0,-1,-1,-1,-1,},{101,3,102,100,-1,-1,},805306401}, {TETRAHEDRON,{4,5,9,1,-1,-1,-1,-1,},{3,101,0,100,-1,-1,},268435457}, {TETRAHEDRON,{0,4,5,9,-1,-1,-1,-1,},{100,2,1,5,-1,-1,},536870913}, {TETRAHEDRON,{3,4,7,9,-1,-1,-1,-1,},{103,5,102,0,-1,-1,},268435456}, {TETRAHEDRON,{4,7,9,0,-1,-1,-1,-1,},{4,102,3,103,-1,-1,},805306417}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, }}, // Rule 169 {TETRAHEDRON,169,RED_CLASS,6, // tag, mark, rclass, nsons {1,1,0,1,0,1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,}, // pattern 43, // pat {{2,0},{1,1},{-1,0},{0,1},{-1,0},{0,2},{-1,-1}, // sonandnode {-1,-1},{-1,-1},{-1,-1},{-1,0},{-1,-1},{-1,-1}, {-1,-1},{-1,-1},{-1,-1},{-1,-1},{-1,-1},{-1,-1}, }, {{TETRAHEDRON,{3,7,9,1,-1,-1,-1,-1,},{102,3,101,103,-1,-1,},0}, // sons {TETRAHEDRON,{2,5,9,0,-1,-1,-1,-1,},{101,5,102,100,-1,-1,},1073741965}, {TETRAHEDRON,{4,5,9,1,-1,-1,-1,-1,},{5,101,3,100,-1,-1,},536870925}, {TETRAHEDRON,{1,4,7,9,-1,-1,-1,-1,},{103,4,0,2,-1,-1,},268435457}, {TETRAHEDRON,{4,7,9,0,-1,-1,-1,-1,},{3,102,5,103,-1,-1,},536870917}, {TETRAHEDRON,{0,4,5,9,-1,-1,-1,-1,},{100,2,1,4,-1,-1,},805306381}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, }}, // Rule 170 {TETRAHEDRON,170,RED_CLASS,6, // tag, mark, rclass, nsons {1,1,0,1,0,1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,}, // pattern 43, // pat {{1,1},{1,2},{-1,0},{0,1},{-1,0},{0,2},{-1,-1}, // sonandnode {-1,-1},{-1,-1},{-1,-1},{-1,0},{-1,-1},{-1,-1}, {-1,-1},{-1,-1},{-1,-1},{-1,-1},{-1,-1},{-1,-1}, }, {{TETRAHEDRON,{3,7,9,1,-1,-1,-1,-1,},{102,2,101,103,-1,-1,},0}, // sons {TETRAHEDRON,{2,4,5,9,-1,-1,-1,-1,},{100,5,101,4,-1,-1,},1073741861}, {TETRAHEDRON,{1,4,7,9,-1,-1,-1,-1,},{103,3,0,5,-1,-1,},268435457}, {TETRAHEDRON,{4,7,9,0,-1,-1,-1,-1,},{2,102,4,103,-1,-1,},536870917}, {TETRAHEDRON,{2,4,9,0,-1,-1,-1,-1,},{1,3,102,100,-1,-1,},805306405}, {TETRAHEDRON,{4,5,9,1,-1,-1,-1,-1,},{1,101,2,100,-1,-1,},536870925}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, }}, // Rule 171 {TETRAHEDRON,171,RED_CLASS,6, // tag, mark, rclass, nsons {1,0,1,1,0,1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,}, // pattern 45, // pat {{0,1},{-1,0},{0,2},{0,3},{-1,0},{1,3},{-1,-1}, // sonandnode {-1,-1},{-1,-1},{-1,-1},{-1,0},{-1,-1},{-1,-1}, {-1,-1},{-1,-1},{-1,-1},{-1,-1},{-1,-1},{-1,-1}, }, {{TETRAHEDRON,{0,4,6,7,-1,-1,-1,-1,},{100,1,102,103,-1,-1,},0}, // sons {TETRAHEDRON,{4,6,7,9,-1,-1,-1,-1,},{0,102,4,2,-1,-1,},268435457}, {TETRAHEDRON,{4,6,9,1,-1,-1,-1,-1,},{1,3,4,100,-1,-1,},536870925}, {TETRAHEDRON,{1,2,6,9,-1,-1,-1,-1,},{100,102,2,101,-1,-1,},805306397}, {TETRAHEDRON,{1,4,7,9,-1,-1,-1,-1,},{103,1,5,2,-1,-1,},536870921}, {TETRAHEDRON,{3,7,9,1,-1,-1,-1,-1,},{102,4,101,103,-1,-1,},805306409}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, }}, // Rule 172 {TETRAHEDRON,172,RED_CLASS,6, // tag, mark, rclass, nsons {1,0,1,1,0,1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,}, // pattern 45, // pat {{0,1},{-1,0},{0,2},{0,3},{-1,0},{1,3},{-1,-1}, // sonandnode {-1,-1},{-1,-1},{-1,-1},{-1,0},{-1,-1},{-1,-1}, {-1,-1},{-1,-1},{-1,-1},{-1,-1},{-1,-1},{-1,-1}, }, {{TETRAHEDRON,{0,4,6,7,-1,-1,-1,-1,},{100,1,102,103,-1,-1,},0}, // sons {TETRAHEDRON,{4,6,7,9,-1,-1,-1,-1,},{0,102,5,2,-1,-1,},268435457}, {TETRAHEDRON,{4,6,9,1,-1,-1,-1,-1,},{1,3,4,100,-1,-1,},536870925}, {TETRAHEDRON,{1,2,6,9,-1,-1,-1,-1,},{100,102,2,101,-1,-1,},805306397}, {TETRAHEDRON,{3,4,9,1,-1,-1,-1,-1,},{5,2,101,103,-1,-1,},805306413}, {TETRAHEDRON,{3,4,7,9,-1,-1,-1,-1,},{103,1,102,4,-1,-1,},536870921}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, }}, // Rule 173 {TETRAHEDRON,173,RED_CLASS,6, // tag, mark, rclass, nsons {1,0,1,1,0,1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,}, // pattern 45, // pat {{0,1},{-1,0},{0,2},{0,3},{-1,0},{1,3},{-1,-1}, // sonandnode {-1,-1},{-1,-1},{-1,-1},{-1,0},{-1,-1},{-1,-1}, {-1,-1},{-1,-1},{-1,-1},{-1,-1},{-1,-1},{-1,-1}, }, {{TETRAHEDRON,{0,4,6,7,-1,-1,-1,-1,},{100,1,102,103,-1,-1,},0}, // sons {TETRAHEDRON,{4,6,7,9,-1,-1,-1,-1,},{0,102,5,2,-1,-1,},268435457}, {TETRAHEDRON,{4,6,9,2,-1,-1,-1,-1,},{1,102,3,100,-1,-1,},536870925}, {TETRAHEDRON,{1,2,4,9,-1,-1,-1,-1,},{100,2,4,101,-1,-1,},805306413}, {TETRAHEDRON,{3,4,9,1,-1,-1,-1,-1,},{5,3,101,103,-1,-1,},1073741997}, {TETRAHEDRON,{3,4,7,9,-1,-1,-1,-1,},{103,1,102,4,-1,-1,},536870921}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, }}, // Rule 174 {TETRAHEDRON,174,RED_CLASS,6, // tag, mark, rclass, nsons {1,0,1,1,0,1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,}, // pattern 45, // pat {{0,1},{-1,0},{0,2},{0,3},{-1,0},{1,3},{-1,-1}, // sonandnode {-1,-1},{-1,-1},{-1,-1},{-1,0},{-1,-1},{-1,-1}, {-1,-1},{-1,-1},{-1,-1},{-1,-1},{-1,-1},{-1,-1}, }, {{TETRAHEDRON,{0,4,6,7,-1,-1,-1,-1,},{100,1,102,103,-1,-1,},0}, // sons {TETRAHEDRON,{4,6,7,9,-1,-1,-1,-1,},{0,102,4,2,-1,-1,},268435457}, {TETRAHEDRON,{4,6,9,2,-1,-1,-1,-1,},{1,102,3,100,-1,-1,},536870925}, {TETRAHEDRON,{1,2,4,9,-1,-1,-1,-1,},{100,2,4,101,-1,-1,},805306413}, {TETRAHEDRON,{1,4,7,9,-1,-1,-1,-1,},{103,1,5,3,-1,-1,},536870921}, {TETRAHEDRON,{3,7,9,1,-1,-1,-1,-1,},{102,4,101,103,-1,-1,},805306409}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, }}, // Rule 175 {TETRAHEDRON,175,RED_CLASS,6, // tag, mark, rclass, nsons {0,1,1,1,0,1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,}, // pattern 46, // pat {{-1,0},{0,0},{0,1},{1,2},{-1,0},{0,2},{-1,-1}, // sonandnode {-1,-1},{-1,-1},{-1,-1},{-1,0},{-1,-1},{-1,-1}, {-1,-1},{-1,-1},{-1,-1},{-1,-1},{-1,-1},{-1,-1}, }, {{TETRAHEDRON,{5,6,9,2,-1,-1,-1,-1,},{1,102,101,100,-1,-1,},0}, // sons {TETRAHEDRON,{5,6,7,9,-1,-1,-1,-1,},{4,102,2,0,-1,-1,},268435456}, {TETRAHEDRON,{1,5,7,9,-1,-1,-1,-1,},{4,1,3,101,-1,-1,},536870920}, {TETRAHEDRON,{3,7,9,1,-1,-1,-1,-1,},{102,2,101,103,-1,-1,},805306408}, {TETRAHEDRON,{1,5,6,7,-1,-1,-1,-1,},{100,1,5,2,-1,-1,},536870912}, {TETRAHEDRON,{0,1,6,7,-1,-1,-1,-1,},{100,4,102,103,-1,-1,},805306400}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, }}, // Rule 176 {TETRAHEDRON,176,RED_CLASS,6, // tag, mark, rclass, nsons {0,1,1,1,0,1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,}, // pattern 46, // pat {{-1,0},{0,0},{0,1},{1,2},{-1,0},{0,2},{-1,-1}, // sonandnode {-1,-1},{-1,-1},{-1,-1},{-1,0},{-1,-1},{-1,-1}, {-1,-1},{-1,-1},{-1,-1},{-1,-1},{-1,-1},{-1,-1}, }, {{TETRAHEDRON,{5,6,9,2,-1,-1,-1,-1,},{1,102,101,100,-1,-1,},0}, // sons {TETRAHEDRON,{5,6,7,9,-1,-1,-1,-1,},{5,102,2,0,-1,-1,},268435456}, {TETRAHEDRON,{1,5,7,9,-1,-1,-1,-1,},{4,1,3,101,-1,-1,},536870920}, {TETRAHEDRON,{3,7,9,1,-1,-1,-1,-1,},{102,2,101,103,-1,-1,},805306408}, {TETRAHEDRON,{0,1,5,7,-1,-1,-1,-1,},{100,2,5,103,-1,-1,},805306376}, {TETRAHEDRON,{0,5,6,7,-1,-1,-1,-1,},{100,1,102,4,-1,-1,},536870912}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, }}, // Rule 177 {TETRAHEDRON,177,RED_CLASS,6, // tag, mark, rclass, nsons {0,1,1,1,0,1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,}, // pattern 46, // pat {{-1,0},{0,0},{0,1},{1,2},{-1,0},{0,2},{-1,-1}, // sonandnode {-1,-1},{-1,-1},{-1,-1},{-1,0},{-1,-1},{-1,-1}, {-1,-1},{-1,-1},{-1,-1},{-1,-1},{-1,-1},{-1,-1}, }, {{TETRAHEDRON,{5,6,9,2,-1,-1,-1,-1,},{1,102,101,100,-1,-1,},0}, // sons {TETRAHEDRON,{5,6,7,9,-1,-1,-1,-1,},{5,102,2,0,-1,-1,},268435456}, {TETRAHEDRON,{3,5,7,9,-1,-1,-1,-1,},{3,1,102,101,-1,-1,},536870920}, {TETRAHEDRON,{1,3,5,7,-1,-1,-1,-1,},{101,2,4,103,-1,-1,},805306376}, {TETRAHEDRON,{0,1,5,7,-1,-1,-1,-1,},{100,3,5,103,-1,-1,},1073741960}, {TETRAHEDRON,{0,5,6,7,-1,-1,-1,-1,},{100,1,102,4,-1,-1,},536870912}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, }}, // Rule 178 {TETRAHEDRON,178,RED_CLASS,6, // tag, mark, rclass, nsons {0,1,1,1,0,1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,}, // pattern 46, // pat {{-1,0},{0,0},{0,1},{1,2},{-1,0},{0,2},{-1,-1}, // sonandnode {-1,-1},{-1,-1},{-1,-1},{-1,0},{-1,-1},{-1,-1}, {-1,-1},{-1,-1},{-1,-1},{-1,-1},{-1,-1},{-1,-1}, }, {{TETRAHEDRON,{5,6,9,2,-1,-1,-1,-1,},{1,102,101,100,-1,-1,},0}, // sons {TETRAHEDRON,{5,6,7,9,-1,-1,-1,-1,},{4,102,2,0,-1,-1,},268435456}, {TETRAHEDRON,{3,5,7,9,-1,-1,-1,-1,},{3,1,102,101,-1,-1,},536870920}, {TETRAHEDRON,{1,3,5,7,-1,-1,-1,-1,},{101,2,4,103,-1,-1,},805306376}, {TETRAHEDRON,{1,5,6,7,-1,-1,-1,-1,},{100,1,5,3,-1,-1,},536870912}, {TETRAHEDRON,{0,1,6,7,-1,-1,-1,-1,},{100,4,102,103,-1,-1,},805306400}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, }}, // Rule 179 {TETRAHEDRON,179,RED_CLASS,6, // tag, mark, rclass, nsons {1,1,0,0,1,1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,}, // pattern 51, // pat {{0,0},{0,1},{-1,0},{-1,0},{0,2},{1,2},{-1,-1}, // sonandnode {-1,-1},{-1,-1},{-1,-1},{-1,0},{-1,-1},{-1,-1}, {-1,-1},{-1,-1},{-1,-1},{-1,-1},{-1,-1},{-1,-1}, }, {{TETRAHEDRON,{4,5,8,1,-1,-1,-1,-1,},{1,101,103,100,-1,-1,},0}, // sons {TETRAHEDRON,{5,8,9,4,-1,-1,-1,-1,},{101,2,4,0,-1,-1,},268435456}, {TETRAHEDRON,{4,8,9,0,-1,-1,-1,-1,},{1,3,4,103,-1,-1,},536870916}, {TETRAHEDRON,{0,3,8,9,-1,-1,-1,-1,},{103,101,2,102,-1,-1,},805306388}, {TETRAHEDRON,{0,4,5,9,-1,-1,-1,-1,},{100,1,5,2,-1,-1,},536870920}, {TETRAHEDRON,{2,5,9,0,-1,-1,-1,-1,},{101,4,102,100,-1,-1,},805306408}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, }}, // Rule 180 {TETRAHEDRON,180,RED_CLASS,6, // tag, mark, rclass, nsons {1,1,0,0,1,1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,}, // pattern 51, // pat {{0,0},{0,1},{-1,0},{-1,0},{0,2},{1,2},{-1,-1}, // sonandnode {-1,-1},{-1,-1},{-1,-1},{-1,0},{-1,-1},{-1,-1}, {-1,-1},{-1,-1},{-1,-1},{-1,-1},{-1,-1},{-1,-1}, }, {{TETRAHEDRON,{4,5,8,1,-1,-1,-1,-1,},{1,101,103,100,-1,-1,},0}, // sons {TETRAHEDRON,{5,8,9,4,-1,-1,-1,-1,},{101,2,5,0,-1,-1,},268435456}, {TETRAHEDRON,{4,8,9,0,-1,-1,-1,-1,},{1,3,4,103,-1,-1,},536870916}, {TETRAHEDRON,{0,3,8,9,-1,-1,-1,-1,},{103,101,2,102,-1,-1,},805306388}, {TETRAHEDRON,{2,4,9,0,-1,-1,-1,-1,},{5,2,102,100,-1,-1,},805306404}, {TETRAHEDRON,{2,4,5,9,-1,-1,-1,-1,},{100,1,101,4,-1,-1,},536870920}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, }}, // Rule 181 {TETRAHEDRON,181,RED_CLASS,6, // tag, mark, rclass, nsons {1,1,0,0,1,1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,}, // pattern 51, // pat {{0,0},{0,1},{-1,0},{-1,0},{0,2},{1,2},{-1,-1}, // sonandnode {-1,-1},{-1,-1},{-1,-1},{-1,0},{-1,-1},{-1,-1}, {-1,-1},{-1,-1},{-1,-1},{-1,-1},{-1,-1},{-1,-1}, }, {{TETRAHEDRON,{4,5,8,1,-1,-1,-1,-1,},{1,101,103,100,-1,-1,},0}, // sons {TETRAHEDRON,{5,8,9,4,-1,-1,-1,-1,},{101,2,5,0,-1,-1,},268435456}, {TETRAHEDRON,{4,8,9,3,-1,-1,-1,-1,},{1,101,3,103,-1,-1,},536870916}, {TETRAHEDRON,{0,3,4,9,-1,-1,-1,-1,},{103,2,4,102,-1,-1,},805306404}, {TETRAHEDRON,{2,4,9,0,-1,-1,-1,-1,},{5,3,102,100,-1,-1,},1073741988}, {TETRAHEDRON,{2,4,5,9,-1,-1,-1,-1,},{100,1,101,4,-1,-1,},536870920}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, }}, // Rule 182 {TETRAHEDRON,182,RED_CLASS,6, // tag, mark, rclass, nsons {1,1,0,0,1,1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,}, // pattern 51, // pat {{0,0},{0,1},{-1,0},{-1,0},{0,2},{1,2},{-1,-1}, // sonandnode {-1,-1},{-1,-1},{-1,-1},{-1,0},{-1,-1},{-1,-1}, {-1,-1},{-1,-1},{-1,-1},{-1,-1},{-1,-1},{-1,-1}, }, {{TETRAHEDRON,{4,5,8,1,-1,-1,-1,-1,},{1,101,103,100,-1,-1,},0}, // sons {TETRAHEDRON,{5,8,9,4,-1,-1,-1,-1,},{101,2,4,0,-1,-1,},268435456}, {TETRAHEDRON,{4,8,9,3,-1,-1,-1,-1,},{1,101,3,103,-1,-1,},536870916}, {TETRAHEDRON,{0,3,4,9,-1,-1,-1,-1,},{103,2,4,102,-1,-1,},805306404}, {TETRAHEDRON,{0,4,5,9,-1,-1,-1,-1,},{100,1,5,3,-1,-1,},536870920}, {TETRAHEDRON,{2,5,9,0,-1,-1,-1,-1,},{101,4,102,100,-1,-1,},805306408}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, }}, // Rule 183 {TETRAHEDRON,183,RED_CLASS,12, // tag, mark, rclass, nsons {1,0,1,0,1,1,-1,-1,-1,-1,1,-1,-1,-1,-1,-1,-1,-1,-1,}, // pattern 1077, // pat {{2,0},{-1,0},{0,0},{-1,0},{1,1},{0,1},{-1,-1}, // sonandnode {-1,-1},{-1,-1},{-1,-1},{0,2},{-1,-1},{-1,-1}, {-1,-1},{-1,-1},{-1,-1},{-1,-1},{-1,-1},{-1,-1}, }, {{TETRAHEDRON,{6,9,14,2,-1,-1,-1,-1,},{7,1,4,102,-1,-1,},0}, // sons {TETRAHEDRON,{2,8,9,14,-1,-1,-1,-1,},{101,9,0,5,-1,-1,},268435457}, {TETRAHEDRON,{4,6,14,1,-1,-1,-1,-1,},{6,4,3,100,-1,-1,},536870922}, {TETRAHEDRON,{8,4,14,1,-1,-1,-1,-1,},{8,2,5,103,-1,-1,},805306410}, {TETRAHEDRON,{1,2,6,14,-1,-1,-1,-1,},{100,0,2,5,-1,-1,},268435458}, {TETRAHEDRON,{2,8,14,1,-1,-1,-1,-1,},{1,3,4,101,-1,-1,},536870925}, {TETRAHEDRON,{0,4,6,14,-1,-1,-1,-1,},{100,2,7,11,-1,-1,},805306378}, {TETRAHEDRON,{9,6,14,0,-1,-1,-1,-1,},{0,6,10,102,-1,-1,},268435456}, {TETRAHEDRON,{4,8,14,3,-1,-1,-1,-1,},{3,9,11,103,-1,-1,},1073741866}, {TETRAHEDRON,{8,9,14,3,-1,-1,-1,-1,},{1,10,8,101,-1,-1,},536870917}, {TETRAHEDRON,{3,9,14,0,-1,-1,-1,-1,},{9,7,11,102,-1,-1,},536870916}, {TETRAHEDRON,{4,3,14,0,-1,-1,-1,-1,},{8,10,6,103,-1,-1,},1073742026}, }}, // Rule 184 {TETRAHEDRON,184,RED_CLASS,12, // tag, mark, rclass, nsons {1,0,1,0,1,1,-1,-1,-1,-1,1,-1,-1,-1,-1,-1,-1,-1,-1,}, // pattern 1077, // pat {{0,0},{-1,0},{0,1},{-1,0},{2,1},{1,1},{-1,-1}, // sonandnode {-1,-1},{-1,-1},{-1,-1},{0,2},{-1,-1},{-1,-1}, {-1,-1},{-1,-1},{-1,-1},{-1,-1},{-1,-1},{-1,-1}, }, {{TETRAHEDRON,{4,6,14,2,-1,-1,-1,-1,},{6,1,4,100,-1,-1,},0}, // sons {TETRAHEDRON,{6,9,14,2,-1,-1,-1,-1,},{8,5,0,102,-1,-1,},268435457}, {TETRAHEDRON,{8,4,14,1,-1,-1,-1,-1,},{7,4,3,103,-1,-1,},536870922}, {TETRAHEDRON,{1,8,9,14,-1,-1,-1,-1,},{101,9,5,2,-1,-1,},805306394}, {TETRAHEDRON,{1,2,4,14,-1,-1,-1,-1,},{100,0,2,5,-1,-1,},268435458}, {TETRAHEDRON,{2,9,14,1,-1,-1,-1,-1,},{1,3,4,101,-1,-1,},536870917}, {TETRAHEDRON,{0,4,6,14,-1,-1,-1,-1,},{100,0,10,7,-1,-1,},268435456}, {TETRAHEDRON,{4,8,14,0,-1,-1,-1,-1,},{2,11,6,103,-1,-1,},805306378}, {TETRAHEDRON,{9,6,14,3,-1,-1,-1,-1,},{1,10,9,102,-1,-1,},536870913}, {TETRAHEDRON,{8,9,14,3,-1,-1,-1,-1,},{3,8,11,101,-1,-1,},1073741914}, {TETRAHEDRON,{3,6,14,0,-1,-1,-1,-1,},{8,6,11,102,-1,-1,},536870920}, {TETRAHEDRON,{8,3,14,0,-1,-1,-1,-1,},{9,10,7,103,-1,-1,},1073741898}, }}, // Rule 185 {TETRAHEDRON,185,RED_CLASS,6, // tag, mark, rclass, nsons {1,0,1,0,1,1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,}, // pattern 53, // pat {{0,0},{-1,0},{1,2},{-1,0},{0,1},{0,2},{-1,-1}, // sonandnode {-1,-1},{-1,-1},{-1,-1},{-1,0},{-1,-1},{-1,-1}, {-1,-1},{-1,-1},{-1,-1},{-1,-1},{-1,-1},{-1,-1}, }, {{TETRAHEDRON,{4,8,9,3,-1,-1,-1,-1,},{5,101,1,103,-1,-1,},0}, // sons {TETRAHEDRON,{3,4,6,9,-1,-1,-1,-1,},{2,4,102,0,-1,-1,},268435458}, {TETRAHEDRON,{0,3,4,6,-1,-1,-1,-1,},{103,1,100,102,-1,-1,},536870914}, {TETRAHEDRON,{1,2,4,8,-1,-1,-1,-1,},{100,5,103,101,-1,-1,},536870912}, {TETRAHEDRON,{4,6,9,2,-1,-1,-1,-1,},{1,102,5,100,-1,-1,},536870918}, {TETRAHEDRON,{2,4,8,9,-1,-1,-1,-1,},{3,0,101,4,-1,-1,},268435456}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, }}, // Rule 186 {TETRAHEDRON,186,RED_CLASS,6, // tag, mark, rclass, nsons {1,0,1,0,1,1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,}, // pattern 53, // pat {{0,0},{-1,0},{1,2},{-1,0},{0,1},{0,2},{-1,-1}, // sonandnode {-1,-1},{-1,-1},{-1,-1},{-1,0},{-1,-1},{-1,-1}, {-1,-1},{-1,-1},{-1,-1},{-1,-1},{-1,-1},{-1,-1}, }, {{TETRAHEDRON,{4,8,9,3,-1,-1,-1,-1,},{5,101,1,103,-1,-1,},0}, // sons {TETRAHEDRON,{3,4,6,9,-1,-1,-1,-1,},{2,3,102,0,-1,-1,},268435458}, {TETRAHEDRON,{0,3,4,6,-1,-1,-1,-1,},{103,1,100,102,-1,-1,},536870914}, {TETRAHEDRON,{4,6,9,2,-1,-1,-1,-1,},{1,102,4,100,-1,-1,},536870918}, {TETRAHEDRON,{1,2,4,9,-1,-1,-1,-1,},{100,3,5,101,-1,-1,},805306406}, {TETRAHEDRON,{1,4,8,9,-1,-1,-1,-1,},{103,0,101,4,-1,-1,},268435456}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, }}, // Rule 187 {TETRAHEDRON,187,RED_CLASS,6, // tag, mark, rclass, nsons {1,0,1,0,1,1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,}, // pattern 53, // pat {{0,0},{-1,0},{3,1},{-1,0},{0,1},{0,2},{-1,-1}, // sonandnode {-1,-1},{-1,-1},{-1,-1},{-1,0},{-1,-1},{-1,-1}, {-1,-1},{-1,-1},{-1,-1},{-1,-1},{-1,-1},{-1,-1}, }, {{TETRAHEDRON,{4,8,9,3,-1,-1,-1,-1,},{4,101,1,103,-1,-1,},0}, // sons {TETRAHEDRON,{0,3,4,9,-1,-1,-1,-1,},{103,0,5,102,-1,-1,},268435458}, {TETRAHEDRON,{1,2,4,8,-1,-1,-1,-1,},{100,4,103,101,-1,-1,},536870912}, {TETRAHEDRON,{4,6,9,2,-1,-1,-1,-1,},{5,102,4,100,-1,-1,},536870924}, {TETRAHEDRON,{2,4,8,9,-1,-1,-1,-1,},{2,0,101,3,-1,-1,},268435456}, {TETRAHEDRON,{0,4,6,9,-1,-1,-1,-1,},{100,3,102,1,-1,-1,},536870922}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, }}, // Rule 188 {TETRAHEDRON,188,RED_CLASS,6, // tag, mark, rclass, nsons {1,0,1,0,1,1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,}, // pattern 53, // pat {{0,0},{-1,0},{2,1},{-1,0},{0,1},{0,2},{-1,-1}, // sonandnode {-1,-1},{-1,-1},{-1,-1},{-1,0},{-1,-1},{-1,-1}, {-1,-1},{-1,-1},{-1,-1},{-1,-1},{-1,-1},{-1,-1}, }, {{TETRAHEDRON,{4,8,9,3,-1,-1,-1,-1,},{5,101,1,103,-1,-1,},0}, // sons {TETRAHEDRON,{0,3,4,9,-1,-1,-1,-1,},{103,0,4,102,-1,-1,},268435458}, {TETRAHEDRON,{4,6,9,2,-1,-1,-1,-1,},{4,102,3,100,-1,-1,},805306394}, {TETRAHEDRON,{1,2,4,9,-1,-1,-1,-1,},{100,2,5,101,-1,-1,},1073741978}, {TETRAHEDRON,{0,4,6,9,-1,-1,-1,-1,},{100,2,102,1,-1,-1,},536870922}, {TETRAHEDRON,{1,4,8,9,-1,-1,-1,-1,},{103,0,101,3,-1,-1,},268435456}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, }}, // Rule 189 {TETRAHEDRON,189,RED_CLASS,6, // tag, mark, rclass, nsons {1,0,1,0,1,1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,}, // pattern 53, // pat {{1,1},{-1,0},{0,0},{-1,0},{0,1},{0,2},{-1,-1}, // sonandnode {-1,-1},{-1,-1},{-1,-1},{-1,0},{-1,-1},{-1,-1}, {-1,-1},{-1,-1},{-1,-1},{-1,-1},{-1,-1},{-1,-1}, }, {{TETRAHEDRON,{6,8,9,3,-1,-1,-1,-1,},{5,101,102,1,-1,-1,},0}, // sons {TETRAHEDRON,{3,4,6,8,-1,-1,-1,-1,},{2,3,0,103,-1,-1,},268435459}, {TETRAHEDRON,{0,3,4,6,-1,-1,-1,-1,},{103,1,100,102,-1,-1,},536870915}, {TETRAHEDRON,{4,6,8,1,-1,-1,-1,-1,},{1,4,103,100,-1,-1,},536870919}, {TETRAHEDRON,{1,2,6,8,-1,-1,-1,-1,},{100,5,3,101,-1,-1,},805306391}, {TETRAHEDRON,{2,6,8,9,-1,-1,-1,-1,},{4,0,101,102,-1,-1,},268435456}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, }}, // Rule 190 {TETRAHEDRON,190,RED_CLASS,6, // tag, mark, rclass, nsons {1,0,1,0,1,1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,}, // pattern 53, // pat {{1,1},{-1,0},{0,0},{-1,0},{0,1},{0,2},{-1,-1}, // sonandnode {-1,-1},{-1,-1},{-1,-1},{-1,0},{-1,-1},{-1,-1}, {-1,-1},{-1,-1},{-1,-1},{-1,-1},{-1,-1},{-1,-1}, }, {{TETRAHEDRON,{6,8,9,3,-1,-1,-1,-1,},{5,101,102,1,-1,-1,},0}, // sons {TETRAHEDRON,{3,4,6,8,-1,-1,-1,-1,},{2,4,0,103,-1,-1,},268435459}, {TETRAHEDRON,{0,3,4,6,-1,-1,-1,-1,},{103,1,100,102,-1,-1,},536870915}, {TETRAHEDRON,{1,2,6,9,-1,-1,-1,-1,},{100,102,5,101,-1,-1,},536870924}, {TETRAHEDRON,{4,6,8,1,-1,-1,-1,-1,},{1,5,103,100,-1,-1,},536870919}, {TETRAHEDRON,{1,6,8,9,-1,-1,-1,-1,},{4,0,101,3,-1,-1,},268435456}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, }}, // Rule 191 {TETRAHEDRON,191,RED_CLASS,6, // tag, mark, rclass, nsons {1,0,1,0,1,1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,}, // pattern 53, // pat {{2,0},{-1,0},{0,0},{-1,0},{0,1},{0,2},{-1,-1}, // sonandnode {-1,-1},{-1,-1},{-1,-1},{-1,0},{-1,-1},{-1,-1}, {-1,-1},{-1,-1},{-1,-1},{-1,-1},{-1,-1},{-1,-1}, }, {{TETRAHEDRON,{6,8,9,3,-1,-1,-1,-1,},{5,101,102,1,-1,-1,},0}, // sons {TETRAHEDRON,{3,6,8,0,-1,-1,-1,-1,},{0,4,103,102,-1,-1,},268435459}, {TETRAHEDRON,{4,6,8,1,-1,-1,-1,-1,},{4,3,103,100,-1,-1,},805306391}, {TETRAHEDRON,{1,2,6,8,-1,-1,-1,-1,},{100,5,2,101,-1,-1,},1073741911}, {TETRAHEDRON,{0,4,6,8,-1,-1,-1,-1,},{100,2,1,103,-1,-1,},536870919}, {TETRAHEDRON,{2,6,8,9,-1,-1,-1,-1,},{3,0,101,102,-1,-1,},268435456}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, }}, // Rule 192 {TETRAHEDRON,192,RED_CLASS,6, // tag, mark, rclass, nsons {1,0,1,0,1,1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,}, // pattern 53, // pat {{3,0},{-1,0},{0,0},{-1,0},{0,1},{0,2},{-1,-1}, // sonandnode {-1,-1},{-1,-1},{-1,-1},{-1,0},{-1,-1},{-1,-1}, {-1,-1},{-1,-1},{-1,-1},{-1,-1},{-1,-1},{-1,-1}, }, {{TETRAHEDRON,{6,8,9,3,-1,-1,-1,-1,},{4,101,102,1,-1,-1,},0}, // sons {TETRAHEDRON,{3,6,8,0,-1,-1,-1,-1,},{0,5,103,102,-1,-1,},268435459}, {TETRAHEDRON,{1,2,6,9,-1,-1,-1,-1,},{100,102,4,101,-1,-1,},536870924}, {TETRAHEDRON,{4,6,8,1,-1,-1,-1,-1,},{5,4,103,100,-1,-1,},536870912}, {TETRAHEDRON,{1,6,8,9,-1,-1,-1,-1,},{3,0,101,2,-1,-1,},268435456}, {TETRAHEDRON,{0,4,6,8,-1,-1,-1,-1,},{100,3,1,103,-1,-1,},536870919}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, }}, // Rule 193 {TETRAHEDRON,193,RED_CLASS,6, // tag, mark, rclass, nsons {1,0,1,0,1,1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,}, // pattern 53, // pat {{1,2},{-1,0},{0,0},{-1,0},{0,1},{0,2},{-1,-1}, // sonandnode {-1,-1},{-1,-1},{-1,-1},{-1,0},{-1,-1},{-1,-1}, {-1,-1},{-1,-1},{-1,-1},{-1,-1},{-1,-1},{-1,-1}, }, {{TETRAHEDRON,{6,8,9,3,-1,-1,-1,-1,},{5,101,102,4,-1,-1,},0}, // sons {TETRAHEDRON,{1,2,4,8,-1,-1,-1,-1,},{100,2,103,101,-1,-1,},1073741975}, {TETRAHEDRON,{4,6,8,2,-1,-1,-1,-1,},{3,5,1,100,-1,-1,},805306391}, {TETRAHEDRON,{0,4,6,8,-1,-1,-1,-1,},{100,2,4,103,-1,-1,},536870919}, {TETRAHEDRON,{3,6,8,0,-1,-1,-1,-1,},{0,3,103,102,-1,-1,},268435459}, {TETRAHEDRON,{2,6,8,9,-1,-1,-1,-1,},{2,0,101,102,-1,-1,},268435456}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, }}, // Rule 194 {TETRAHEDRON,194,RED_CLASS,6, // tag, mark, rclass, nsons {1,0,1,0,1,1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,}, // pattern 53, // pat {{1,2},{-1,0},{2,1},{-1,0},{0,2},{0,3},{-1,-1}, // sonandnode {-1,-1},{-1,-1},{-1,-1},{-1,0},{-1,-1},{-1,-1}, {-1,-1},{-1,-1},{-1,-1},{-1,-1},{-1,-1},{-1,-1}, }, {{TETRAHEDRON,{0,3,8,9,-1,-1,-1,-1,},{103,101,4,102,-1,-1,},0}, // sons {TETRAHEDRON,{1,2,4,8,-1,-1,-1,-1,},{100,2,103,101,-1,-1,},1073741954}, {TETRAHEDRON,{4,6,8,2,-1,-1,-1,-1,},{5,3,1,100,-1,-1,},805306370}, {TETRAHEDRON,{2,6,8,9,-1,-1,-1,-1,},{2,4,101,102,-1,-1,},536870914}, {TETRAHEDRON,{6,8,9,0,-1,-1,-1,-1,},{3,0,102,5,-1,-1,},268435458}, {TETRAHEDRON,{0,4,6,8,-1,-1,-1,-1,},{100,2,4,103,-1,-1,},536870926}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, }}, // Rule 195 {TETRAHEDRON,195,RED_CLASS,6, // tag, mark, rclass, nsons {1,0,1,0,1,1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,}, // pattern 53, // pat {{4,0},{-1,0},{1,2},{-1,0},{0,2},{0,3},{-1,-1}, // sonandnode {-1,-1},{-1,-1},{-1,-1},{-1,0},{-1,-1},{-1,-1}, {-1,-1},{-1,-1},{-1,-1},{-1,-1},{-1,-1},{-1,-1}, }, {{TETRAHEDRON,{0,3,8,9,-1,-1,-1,-1,},{103,101,3,102,-1,-1,},0}, // sons {TETRAHEDRON,{1,2,6,8,-1,-1,-1,-1,},{100,2,4,101,-1,-1,},805306370}, {TETRAHEDRON,{2,6,8,9,-1,-1,-1,-1,},{1,3,101,102,-1,-1,},536870914}, {TETRAHEDRON,{6,8,9,0,-1,-1,-1,-1,},{2,0,102,5,-1,-1,},268435458}, {TETRAHEDRON,{4,6,8,1,-1,-1,-1,-1,},{5,1,103,100,-1,-1,},1073741954}, {TETRAHEDRON,{0,4,6,8,-1,-1,-1,-1,},{100,4,3,103,-1,-1,},536870926}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, }}, // Rule 196 {TETRAHEDRON,196,RED_CLASS,6, // tag, mark, rclass, nsons {1,0,1,0,1,1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,}, // pattern 53, // pat {{0,0},{-1,0},{1,2},{-1,0},{0,1},{0,2},{-1,-1}, // sonandnode {-1,-1},{-1,-1},{-1,-1},{-1,0},{-1,-1},{-1,-1}, {-1,-1},{-1,-1},{-1,-1},{-1,-1},{-1,-1},{-1,-1}, }, {{TETRAHEDRON,{4,8,9,3,-1,-1,-1,-1,},{5,101,4,103,-1,-1,},0}, // sons {TETRAHEDRON,{1,2,6,9,-1,-1,-1,-1,},{100,102,2,101,-1,-1,},1073741914}, {TETRAHEDRON,{4,6,9,1,-1,-1,-1,-1,},{3,1,5,100,-1,-1,},805306394}, {TETRAHEDRON,{0,4,6,9,-1,-1,-1,-1,},{100,2,102,4,-1,-1,},536870922}, {TETRAHEDRON,{0,3,4,9,-1,-1,-1,-1,},{103,0,3,102,-1,-1,},268435458}, {TETRAHEDRON,{1,4,8,9,-1,-1,-1,-1,},{103,0,101,2,-1,-1,},268435456}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, }}, // Rule 197 {TETRAHEDRON,197,RED_CLASS,6, // tag, mark, rclass, nsons {1,0,1,0,1,1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,}, // pattern 53, // pat {{2,0},{-1,0},{1,2},{-1,0},{0,2},{0,3},{-1,-1}, // sonandnode {-1,-1},{-1,-1},{-1,-1},{-1,0},{-1,-1},{-1,-1}, {-1,-1},{-1,-1},{-1,-1},{-1,-1},{-1,-1},{-1,-1}, }, {{TETRAHEDRON,{0,3,8,9,-1,-1,-1,-1,},{103,101,4,102,-1,-1,},0}, // sons {TETRAHEDRON,{1,2,6,9,-1,-1,-1,-1,},{100,102,2,101,-1,-1,},1073741938}, {TETRAHEDRON,{4,6,9,1,-1,-1,-1,-1,},{5,1,3,100,-1,-1,},805306418}, {TETRAHEDRON,{1,4,8,9,-1,-1,-1,-1,},{103,4,101,2,-1,-1,},536870914}, {TETRAHEDRON,{4,8,9,0,-1,-1,-1,-1,},{3,0,5,103,-1,-1,},268435458}, {TETRAHEDRON,{0,4,6,9,-1,-1,-1,-1,},{100,2,102,4,-1,-1,},536870922}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, }}, // Rule 198 {TETRAHEDRON,198,RED_CLASS,6, // tag, mark, rclass, nsons {1,0,1,0,1,1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,}, // pattern 53, // pat {{1,2},{-1,0},{4,1},{-1,0},{0,2},{0,3},{-1,-1}, // sonandnode {-1,-1},{-1,-1},{-1,-1},{-1,0},{-1,-1},{-1,-1}, {-1,-1},{-1,-1},{-1,-1},{-1,-1},{-1,-1},{-1,-1}, }, {{TETRAHEDRON,{0,3,8,9,-1,-1,-1,-1,},{103,101,3,102,-1,-1,},0}, // sons {TETRAHEDRON,{1,2,4,9,-1,-1,-1,-1,},{100,4,2,101,-1,-1,},805306418}, {TETRAHEDRON,{1,4,8,9,-1,-1,-1,-1,},{103,3,101,1,-1,-1,},536870914}, {TETRAHEDRON,{4,8,9,0,-1,-1,-1,-1,},{2,0,5,103,-1,-1,},268435458}, {TETRAHEDRON,{4,6,9,2,-1,-1,-1,-1,},{5,102,1,100,-1,-1,},1073741938}, {TETRAHEDRON,{0,4,6,9,-1,-1,-1,-1,},{100,4,102,3,-1,-1,},536870922}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, }}, // Rule 199 {TETRAHEDRON,199,RED_CLASS,6, // tag, mark, rclass, nsons {0,1,1,0,1,1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,}, // pattern 54, // pat {{-1,0},{0,0},{0,1},{-1,0},{1,2},{0,2},{-1,-1}, // sonandnode {-1,-1},{-1,-1},{-1,-1},{-1,0},{-1,-1},{-1,-1}, {-1,-1},{-1,-1},{-1,-1},{-1,-1},{-1,-1},{-1,-1}, }, {{TETRAHEDRON,{5,6,9,2,-1,-1,-1,-1,},{1,102,101,100,-1,-1,},0}, // sons {TETRAHEDRON,{5,6,8,9,-1,-1,-1,-1,},{2,4,101,0,-1,-1,},268435456}, {TETRAHEDRON,{0,5,6,8,-1,-1,-1,-1,},{100,1,4,3,-1,-1,},536870912}, {TETRAHEDRON,{0,1,5,8,-1,-1,-1,-1,},{100,101,2,103,-1,-1,},805306416}, {TETRAHEDRON,{6,8,9,0,-1,-1,-1,-1,},{1,5,102,2,-1,-1,},536870916}, {TETRAHEDRON,{0,3,8,9,-1,-1,-1,-1,},{103,101,4,102,-1,-1,},805306388}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, }}, // Rule 200 {TETRAHEDRON,200,RED_CLASS,6, // tag, mark, rclass, nsons {0,1,1,0,1,1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,}, // pattern 54, // pat {{-1,0},{0,0},{0,1},{-1,0},{1,2},{0,2},{-1,-1}, // sonandnode {-1,-1},{-1,-1},{-1,-1},{-1,0},{-1,-1},{-1,-1}, {-1,-1},{-1,-1},{-1,-1},{-1,-1},{-1,-1},{-1,-1}, }, {{TETRAHEDRON,{5,6,9,2,-1,-1,-1,-1,},{1,102,101,100,-1,-1,},0}, // sons {TETRAHEDRON,{5,6,8,9,-1,-1,-1,-1,},{2,5,101,0,-1,-1,},268435456}, {TETRAHEDRON,{0,5,6,8,-1,-1,-1,-1,},{100,1,4,3,-1,-1,},536870912}, {TETRAHEDRON,{0,1,5,8,-1,-1,-1,-1,},{100,101,2,103,-1,-1,},805306416}, {TETRAHEDRON,{3,6,8,0,-1,-1,-1,-1,},{5,2,103,102,-1,-1,},805306400}, {TETRAHEDRON,{6,8,9,3,-1,-1,-1,-1,},{1,101,102,4,-1,-1,},536870916}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, }}, // Rule 201 {TETRAHEDRON,201,RED_CLASS,6, // tag, mark, rclass, nsons {0,1,1,0,1,1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,}, // pattern 54, // pat {{-1,0},{0,0},{0,1},{-1,0},{1,2},{0,2},{-1,-1}, // sonandnode {-1,-1},{-1,-1},{-1,-1},{-1,0},{-1,-1},{-1,-1}, {-1,-1},{-1,-1},{-1,-1},{-1,-1},{-1,-1},{-1,-1}, }, {{TETRAHEDRON,{5,6,9,2,-1,-1,-1,-1,},{1,102,101,100,-1,-1,},0}, // sons {TETRAHEDRON,{5,6,8,9,-1,-1,-1,-1,},{2,5,101,0,-1,-1,},268435456}, {TETRAHEDRON,{1,5,6,8,-1,-1,-1,-1,},{100,1,3,101,-1,-1,},536870912}, {TETRAHEDRON,{0,1,6,8,-1,-1,-1,-1,},{100,2,4,103,-1,-1,},805306400}, {TETRAHEDRON,{3,6,8,0,-1,-1,-1,-1,},{5,3,103,102,-1,-1,},1073741984}, {TETRAHEDRON,{6,8,9,3,-1,-1,-1,-1,},{1,101,102,4,-1,-1,},536870916}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, }}, // Rule 202 {TETRAHEDRON,202,RED_CLASS,6, // tag, mark, rclass, nsons {0,1,1,0,1,1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,}, // pattern 54, // pat {{-1,0},{0,0},{0,1},{-1,0},{1,2},{0,2},{-1,-1}, // sonandnode {-1,-1},{-1,-1},{-1,-1},{-1,0},{-1,-1},{-1,-1}, {-1,-1},{-1,-1},{-1,-1},{-1,-1},{-1,-1},{-1,-1}, }, {{TETRAHEDRON,{5,6,9,2,-1,-1,-1,-1,},{1,102,101,100,-1,-1,},0}, // sons {TETRAHEDRON,{5,6,8,9,-1,-1,-1,-1,},{2,4,101,0,-1,-1,},268435456}, {TETRAHEDRON,{1,5,6,8,-1,-1,-1,-1,},{100,1,3,101,-1,-1,},536870912}, {TETRAHEDRON,{0,1,6,8,-1,-1,-1,-1,},{100,2,4,103,-1,-1,},805306400}, {TETRAHEDRON,{6,8,9,0,-1,-1,-1,-1,},{1,5,102,3,-1,-1,},536870916}, {TETRAHEDRON,{0,3,8,9,-1,-1,-1,-1,},{103,101,4,102,-1,-1,},805306388}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, }}, // Rule 203 {TETRAHEDRON,203,RED_CLASS,6, // tag, mark, rclass, nsons {1,0,0,1,1,1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,}, // pattern 57, // pat {{1,0},{-1,0},{-1,0},{0,0},{0,1},{0,2},{-1,-1}, // sonandnode {-1,-1},{-1,-1},{-1,-1},{-1,0},{-1,-1},{-1,-1}, {-1,-1},{-1,-1},{-1,-1},{-1,-1},{-1,-1},{-1,-1}, }, {{TETRAHEDRON,{7,8,9,3,-1,-1,-1,-1,},{1,101,102,103,-1,-1,},0}, // sons {TETRAHEDRON,{4,7,8,9,-1,-1,-1,-1,},{103,0,2,4,-1,-1,},268435456}, {TETRAHEDRON,{2,4,8,9,-1,-1,-1,-1,},{3,1,101,4,-1,-1,},536870920}, {TETRAHEDRON,{1,2,4,8,-1,-1,-1,-1,},{100,2,103,101,-1,-1,},805306376}, {TETRAHEDRON,{4,7,9,2,-1,-1,-1,-1,},{1,102,2,5,-1,-1,},536870924}, {TETRAHEDRON,{2,4,7,0,-1,-1,-1,-1,},{4,103,102,100,-1,-1,},805306428}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, }}, // Rule 204 {TETRAHEDRON,204,RED_CLASS,6, // tag, mark, rclass, nsons {1,0,0,1,1,1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,}, // pattern 57, // pat {{1,0},{-1,0},{-1,0},{0,0},{0,1},{0,2},{-1,-1}, // sonandnode {-1,-1},{-1,-1},{-1,-1},{-1,0},{-1,-1},{-1,-1}, {-1,-1},{-1,-1},{-1,-1},{-1,-1},{-1,-1},{-1,-1}, }, {{TETRAHEDRON,{7,8,9,3,-1,-1,-1,-1,},{1,101,102,103,-1,-1,},0}, // sons {TETRAHEDRON,{4,7,8,9,-1,-1,-1,-1,},{103,0,2,5,-1,-1,},268435456}, {TETRAHEDRON,{2,4,8,9,-1,-1,-1,-1,},{3,1,101,4,-1,-1,},536870920}, {TETRAHEDRON,{1,2,4,8,-1,-1,-1,-1,},{100,2,103,101,-1,-1,},805306376}, {TETRAHEDRON,{2,4,9,0,-1,-1,-1,-1,},{2,5,102,100,-1,-1,},805306424}, {TETRAHEDRON,{4,7,9,0,-1,-1,-1,-1,},{1,102,4,103,-1,-1,},536870924}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, }}, // Rule 205 {TETRAHEDRON,205,RED_CLASS,6, // tag, mark, rclass, nsons {1,0,0,1,1,1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,}, // pattern 57, // pat {{1,0},{-1,0},{-1,0},{0,0},{0,1},{0,2},{-1,-1}, // sonandnode {-1,-1},{-1,-1},{-1,-1},{-1,0},{-1,-1},{-1,-1}, {-1,-1},{-1,-1},{-1,-1},{-1,-1},{-1,-1},{-1,-1}, }, {{TETRAHEDRON,{7,8,9,3,-1,-1,-1,-1,},{1,101,102,103,-1,-1,},0}, // sons {TETRAHEDRON,{4,7,8,9,-1,-1,-1,-1,},{103,0,2,5,-1,-1,},268435456}, {TETRAHEDRON,{1,4,8,9,-1,-1,-1,-1,},{103,1,101,3,-1,-1,},536870920}, {TETRAHEDRON,{1,2,4,9,-1,-1,-1,-1,},{100,4,2,101,-1,-1,},805306424}, {TETRAHEDRON,{2,4,9,0,-1,-1,-1,-1,},{3,5,102,100,-1,-1,},1073741944}, {TETRAHEDRON,{4,7,9,0,-1,-1,-1,-1,},{1,102,4,103,-1,-1,},536870924}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, }}, // Rule 206 {TETRAHEDRON,206,RED_CLASS,6, // tag, mark, rclass, nsons {1,0,0,1,1,1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,}, // pattern 57, // pat {{1,0},{-1,0},{-1,0},{0,0},{0,1},{0,2},{-1,-1}, // sonandnode {-1,-1},{-1,-1},{-1,-1},{-1,0},{-1,-1},{-1,-1}, {-1,-1},{-1,-1},{-1,-1},{-1,-1},{-1,-1},{-1,-1}, }, {{TETRAHEDRON,{7,8,9,3,-1,-1,-1,-1,},{1,101,102,103,-1,-1,},0}, // sons {TETRAHEDRON,{4,7,8,9,-1,-1,-1,-1,},{103,0,2,4,-1,-1,},268435456}, {TETRAHEDRON,{1,4,8,9,-1,-1,-1,-1,},{103,1,101,3,-1,-1,},536870920}, {TETRAHEDRON,{1,2,4,9,-1,-1,-1,-1,},{100,4,2,101,-1,-1,},805306424}, {TETRAHEDRON,{4,7,9,2,-1,-1,-1,-1,},{1,102,3,5,-1,-1,},536870924}, {TETRAHEDRON,{2,4,7,0,-1,-1,-1,-1,},{4,103,102,100,-1,-1,},805306428}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, }}, // Rule 207 {TETRAHEDRON,207,RED_CLASS,6, // tag, mark, rclass, nsons {0,1,0,1,1,1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,}, // pattern 58, // pat {{-1,0},{1,0},{-1,0},{0,0},{0,1},{0,2},{-1,-1}, // sonandnode {-1,-1},{-1,-1},{-1,-1},{-1,0},{-1,-1},{-1,-1}, {-1,-1},{-1,-1},{-1,-1},{-1,-1},{-1,-1},{-1,-1}, }, {{TETRAHEDRON,{7,8,9,3,-1,-1,-1,-1,},{1,101,102,103,-1,-1,},0}, // sons {TETRAHEDRON,{5,7,8,9,-1,-1,-1,-1,},{4,0,101,2,-1,-1,},268435456}, {TETRAHEDRON,{5,7,9,0,-1,-1,-1,-1,},{1,102,3,4,-1,-1,},536870924}, {TETRAHEDRON,{2,5,9,0,-1,-1,-1,-1,},{101,2,102,100,-1,-1,},805306412}, {TETRAHEDRON,{0,5,7,8,-1,-1,-1,-1,},{2,1,103,5,-1,-1,},536870912}, {TETRAHEDRON,{0,1,5,8,-1,-1,-1,-1,},{100,101,4,103,-1,-1,},805306416}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, }}, // Rule 208 {TETRAHEDRON,208,RED_CLASS,6, // tag, mark, rclass, nsons {0,1,0,1,1,1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,}, // pattern 58, // pat {{-1,0},{1,0},{-1,0},{0,0},{0,1},{0,2},{-1,-1}, // sonandnode {-1,-1},{-1,-1},{-1,-1},{-1,0},{-1,-1},{-1,-1}, {-1,-1},{-1,-1},{-1,-1},{-1,-1},{-1,-1},{-1,-1}, }, {{TETRAHEDRON,{7,8,9,3,-1,-1,-1,-1,},{1,101,102,103,-1,-1,},0}, // sons {TETRAHEDRON,{5,7,8,9,-1,-1,-1,-1,},{5,0,101,2,-1,-1,},268435456}, {TETRAHEDRON,{5,7,9,0,-1,-1,-1,-1,},{1,102,3,4,-1,-1,},536870924}, {TETRAHEDRON,{2,5,9,0,-1,-1,-1,-1,},{101,2,102,100,-1,-1,},805306412}, {TETRAHEDRON,{0,1,5,7,-1,-1,-1,-1,},{100,5,2,103,-1,-1,},805306428}, {TETRAHEDRON,{1,5,7,8,-1,-1,-1,-1,},{4,1,103,101,-1,-1,},536870912}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, }}, // Rule 209 {TETRAHEDRON,209,RED_CLASS,6, // tag, mark, rclass, nsons {0,1,0,1,1,1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,}, // pattern 58, // pat {{-1,0},{1,0},{-1,0},{0,0},{0,1},{0,2},{-1,-1}, // sonandnode {-1,-1},{-1,-1},{-1,-1},{-1,0},{-1,-1},{-1,-1}, {-1,-1},{-1,-1},{-1,-1},{-1,-1},{-1,-1},{-1,-1}, }, {{TETRAHEDRON,{7,8,9,3,-1,-1,-1,-1,},{1,101,102,103,-1,-1,},0}, // sons {TETRAHEDRON,{5,7,8,9,-1,-1,-1,-1,},{5,0,101,2,-1,-1,},268435456}, {TETRAHEDRON,{5,7,9,2,-1,-1,-1,-1,},{1,102,101,3,-1,-1,},536870924}, {TETRAHEDRON,{2,5,7,0,-1,-1,-1,-1,},{2,4,102,100,-1,-1,},805306428}, {TETRAHEDRON,{0,1,5,7,-1,-1,-1,-1,},{100,5,3,103,-1,-1,},1073741948}, {TETRAHEDRON,{1,5,7,8,-1,-1,-1,-1,},{4,1,103,101,-1,-1,},536870912}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, }}, // Rule 210 {TETRAHEDRON,210,RED_CLASS,6, // tag, mark, rclass, nsons {0,1,0,1,1,1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,}, // pattern 58, // pat {{-1,0},{1,0},{-1,0},{0,0},{0,1},{0,2},{-1,-1}, // sonandnode {-1,-1},{-1,-1},{-1,-1},{-1,0},{-1,-1},{-1,-1}, {-1,-1},{-1,-1},{-1,-1},{-1,-1},{-1,-1},{-1,-1}, }, {{TETRAHEDRON,{7,8,9,3,-1,-1,-1,-1,},{1,101,102,103,-1,-1,},0}, // sons {TETRAHEDRON,{5,7,8,9,-1,-1,-1,-1,},{4,0,101,2,-1,-1,},268435456}, {TETRAHEDRON,{5,7,9,2,-1,-1,-1,-1,},{1,102,101,3,-1,-1,},536870924}, {TETRAHEDRON,{2,5,7,0,-1,-1,-1,-1,},{2,4,102,100,-1,-1,},805306428}, {TETRAHEDRON,{0,5,7,8,-1,-1,-1,-1,},{3,1,103,5,-1,-1,},536870912}, {TETRAHEDRON,{0,1,5,8,-1,-1,-1,-1,},{100,101,4,103,-1,-1,},805306416}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, }}, // Rule 211 {TETRAHEDRON,211,RED_CLASS,6, // tag, mark, rclass, nsons {0,0,1,1,1,1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,}, // pattern 60, // pat {{-1,0},{-1,0},{1,0},{0,0},{0,1},{0,2},{-1,-1}, // sonandnode {-1,-1},{-1,-1},{-1,-1},{-1,0},{-1,-1},{-1,-1}, {-1,-1},{-1,-1},{-1,-1},{-1,-1},{-1,-1},{-1,-1}, }, {{TETRAHEDRON,{7,8,9,3,-1,-1,-1,-1,},{1,101,102,103,-1,-1,},0}, // sons {TETRAHEDRON,{6,7,8,9,-1,-1,-1,-1,},{2,0,4,102,-1,-1,},268435456}, {TETRAHEDRON,{1,6,7,8,-1,-1,-1,-1,},{3,1,103,4,-1,-1,},536870912}, {TETRAHEDRON,{0,1,6,7,-1,-1,-1,-1,},{100,2,102,103,-1,-1,},805306368}, {TETRAHEDRON,{1,6,8,9,-1,-1,-1,-1,},{2,1,101,5,-1,-1,},536870920}, {TETRAHEDRON,{1,2,6,9,-1,-1,-1,-1,},{100,102,4,101,-1,-1,},805306424}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, }}, // Rule 212 {TETRAHEDRON,212,RED_CLASS,6, // tag, mark, rclass, nsons {0,0,1,1,1,1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,}, // pattern 60, // pat {{-1,0},{-1,0},{1,0},{0,0},{0,1},{0,2},{-1,-1}, // sonandnode {-1,-1},{-1,-1},{-1,-1},{-1,0},{-1,-1},{-1,-1}, {-1,-1},{-1,-1},{-1,-1},{-1,-1},{-1,-1},{-1,-1}, }, {{TETRAHEDRON,{7,8,9,3,-1,-1,-1,-1,},{1,101,102,103,-1,-1,},0}, // sons {TETRAHEDRON,{6,7,8,9,-1,-1,-1,-1,},{2,0,5,102,-1,-1,},268435456}, {TETRAHEDRON,{1,6,7,8,-1,-1,-1,-1,},{3,1,103,4,-1,-1,},536870912}, {TETRAHEDRON,{0,1,6,7,-1,-1,-1,-1,},{100,2,102,103,-1,-1,},805306368}, {TETRAHEDRON,{1,2,6,8,-1,-1,-1,-1,},{100,5,2,101,-1,-1,},805306416}, {TETRAHEDRON,{2,6,8,9,-1,-1,-1,-1,},{4,1,101,102,-1,-1,},536870920}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, }}, // Rule 213 {TETRAHEDRON,213,RED_CLASS,6, // tag, mark, rclass, nsons {0,0,1,1,1,1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,}, // pattern 60, // pat {{-1,0},{-1,0},{1,0},{0,0},{0,1},{0,2},{-1,-1}, // sonandnode {-1,-1},{-1,-1},{-1,-1},{-1,0},{-1,-1},{-1,-1}, {-1,-1},{-1,-1},{-1,-1},{-1,-1},{-1,-1},{-1,-1}, }, {{TETRAHEDRON,{7,8,9,3,-1,-1,-1,-1,},{1,101,102,103,-1,-1,},0}, // sons {TETRAHEDRON,{6,7,8,9,-1,-1,-1,-1,},{2,0,5,102,-1,-1,},268435456}, {TETRAHEDRON,{0,6,7,8,-1,-1,-1,-1,},{102,1,103,3,-1,-1,},536870912}, {TETRAHEDRON,{0,1,6,8,-1,-1,-1,-1,},{100,4,2,103,-1,-1,},805306416}, {TETRAHEDRON,{1,2,6,8,-1,-1,-1,-1,},{100,5,3,101,-1,-1,},1073741936}, {TETRAHEDRON,{2,6,8,9,-1,-1,-1,-1,},{4,1,101,102,-1,-1,},536870920}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, }}, // Rule 214 {TETRAHEDRON,214,RED_CLASS,6, // tag, mark, rclass, nsons {0,0,1,1,1,1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,}, // pattern 60, // pat {{-1,0},{-1,0},{1,0},{0,0},{0,1},{0,2},{-1,-1}, // sonandnode {-1,-1},{-1,-1},{-1,-1},{-1,0},{-1,-1},{-1,-1}, {-1,-1},{-1,-1},{-1,-1},{-1,-1},{-1,-1},{-1,-1}, }, {{TETRAHEDRON,{7,8,9,3,-1,-1,-1,-1,},{1,101,102,103,-1,-1,},0}, // sons {TETRAHEDRON,{6,7,8,9,-1,-1,-1,-1,},{2,0,4,102,-1,-1,},268435456}, {TETRAHEDRON,{0,6,7,8,-1,-1,-1,-1,},{102,1,103,3,-1,-1,},536870912}, {TETRAHEDRON,{0,1,6,8,-1,-1,-1,-1,},{100,4,2,103,-1,-1,},805306416}, {TETRAHEDRON,{1,6,8,9,-1,-1,-1,-1,},{3,1,101,5,-1,-1,},536870920}, {TETRAHEDRON,{1,2,6,9,-1,-1,-1,-1,},{100,102,4,101,-1,-1,},805306424}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, }}, // Rule 215 {TETRAHEDRON,215,RED_CLASS,7, // tag, mark, rclass, nsons {1,1,1,1,1,0,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,}, // pattern 31, // pat {{0,0},{0,1},{1,2},{1,3},{0,2},{-1,0},{-1,-1}, // sonandnode {-1,-1},{-1,-1},{-1,-1},{-1,0},{-1,-1},{-1,-1}, {-1,-1},{-1,-1},{-1,-1},{-1,-1},{-1,-1},{-1,-1}, }, {{TETRAHEDRON,{4,5,8,1,-1,-1,-1,-1,},{2,101,103,100,-1,-1,},0}, // sons {TETRAHEDRON,{0,4,6,7,-1,-1,-1,-1,},{100,3,102,103,-1,-1,},805306376}, {TETRAHEDRON,{4,5,6,8,-1,-1,-1,-1,},{100,4,3,0,-1,-1,},268435456}, {TETRAHEDRON,{4,6,7,8,-1,-1,-1,-1,},{1,5,103,2,-1,-1,},536870920}, {TETRAHEDRON,{5,6,8,2,-1,-1,-1,-1,},{2,5,101,100,-1,-1,},536870916}, {TETRAHEDRON,{6,7,8,2,-1,-1,-1,-1,},{3,6,4,102,-1,-1,},805306392}, {TETRAHEDRON,{2,3,7,8,-1,-1,-1,-1,},{102,103,5,101,-1,-1,},1073741912}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, }}, // Rule 216 {TETRAHEDRON,216,RED_CLASS,7, // tag, mark, rclass, nsons {1,1,1,1,1,0,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,}, // pattern 31, // pat {{0,0},{0,1},{1,2},{1,3},{0,2},{-1,0},{-1,-1}, // sonandnode {-1,-1},{-1,-1},{-1,-1},{-1,0},{-1,-1},{-1,-1}, {-1,-1},{-1,-1},{-1,-1},{-1,-1},{-1,-1},{-1,-1}, }, {{TETRAHEDRON,{4,5,8,1,-1,-1,-1,-1,},{2,101,103,100,-1,-1,},0}, // sons {TETRAHEDRON,{0,4,6,7,-1,-1,-1,-1,},{100,3,102,103,-1,-1,},805306376}, {TETRAHEDRON,{4,5,6,8,-1,-1,-1,-1,},{100,5,3,0,-1,-1,},268435456}, {TETRAHEDRON,{4,6,7,8,-1,-1,-1,-1,},{1,4,103,2,-1,-1,},536870920}, {TETRAHEDRON,{6,7,8,3,-1,-1,-1,-1,},{3,103,5,102,-1,-1,},805306392}, {TETRAHEDRON,{5,6,8,3,-1,-1,-1,-1,},{2,4,101,6,-1,-1,},536870916}, {TETRAHEDRON,{3,5,6,2,-1,-1,-1,-1,},{5,100,102,101,-1,-1,},805306420}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, }}, // Rule 217 {TETRAHEDRON,217,RED_CLASS,7, // tag, mark, rclass, nsons {1,1,1,1,1,0,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,}, // pattern 31, // pat {{0,0},{0,1},{1,2},{1,3},{0,2},{-1,0},{-1,-1}, // sonandnode {-1,-1},{-1,-1},{-1,-1},{-1,0},{-1,-1},{-1,-1}, {-1,-1},{-1,-1},{-1,-1},{-1,-1},{-1,-1},{-1,-1}, }, {{TETRAHEDRON,{4,5,8,1,-1,-1,-1,-1,},{2,101,103,100,-1,-1,},0}, // sons {TETRAHEDRON,{0,4,6,7,-1,-1,-1,-1,},{100,3,102,103,-1,-1,},805306376}, {TETRAHEDRON,{4,5,6,8,-1,-1,-1,-1,},{100,6,3,0,-1,-1,},268435456}, {TETRAHEDRON,{4,6,7,8,-1,-1,-1,-1,},{1,4,103,2,-1,-1,},536870920}, {TETRAHEDRON,{6,7,8,3,-1,-1,-1,-1,},{3,103,5,102,-1,-1,},805306392}, {TETRAHEDRON,{2,3,6,8,-1,-1,-1,-1,},{102,4,6,101,-1,-1,},1073741976}, {TETRAHEDRON,{5,6,8,2,-1,-1,-1,-1,},{2,5,101,100,-1,-1,},536870916}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, }}, // Rule 218 {TETRAHEDRON,218,RED_CLASS,7, // tag, mark, rclass, nsons {1,1,1,1,1,0,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,}, // pattern 31, // pat {{0,0},{0,1},{1,2},{1,3},{0,2},{-1,0},{-1,-1}, // sonandnode {-1,-1},{-1,-1},{-1,-1},{-1,0},{-1,-1},{-1,-1}, {-1,-1},{-1,-1},{-1,-1},{-1,-1},{-1,-1},{-1,-1}, }, {{TETRAHEDRON,{4,5,8,1,-1,-1,-1,-1,},{2,101,103,100,-1,-1,},0}, // sons {TETRAHEDRON,{0,4,6,7,-1,-1,-1,-1,},{100,3,102,103,-1,-1,},805306400}, {TETRAHEDRON,{4,5,7,8,-1,-1,-1,-1,},{3,6,103,0,-1,-1,},268435456}, {TETRAHEDRON,{4,5,6,7,-1,-1,-1,-1,},{100,4,1,2,-1,-1,},536870912}, {TETRAHEDRON,{5,6,7,2,-1,-1,-1,-1,},{3,102,5,100,-1,-1,},805306384}, {TETRAHEDRON,{3,5,7,2,-1,-1,-1,-1,},{6,4,102,101,-1,-1,},1073741968}, {TETRAHEDRON,{5,7,8,3,-1,-1,-1,-1,},{2,103,101,5,-1,-1,},536870916}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, }}, // Rule 219 {TETRAHEDRON,219,RED_CLASS,7, // tag, mark, rclass, nsons {1,1,1,1,0,1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,}, // pattern 47, // pat {{0,1},{1,0},{0,2},{0,3},{-1,0},{1,2},{-1,-1}, // sonandnode {-1,-1},{-1,-1},{-1,-1},{-1,0},{-1,-1},{-1,-1}, {-1,-1},{-1,-1},{-1,-1},{-1,-1},{-1,-1},{-1,-1}, }, {{TETRAHEDRON,{0,4,6,7,-1,-1,-1,-1,},{100,2,102,103,-1,-1,},0}, // sons {TETRAHEDRON,{5,6,9,2,-1,-1,-1,-1,},{3,102,101,100,-1,-1,},805306421}, {TETRAHEDRON,{4,5,6,7,-1,-1,-1,-1,},{100,3,0,4,-1,-1,},268435457}, {TETRAHEDRON,{5,6,7,9,-1,-1,-1,-1,},{2,102,5,1,-1,-1,},536870917}, {TETRAHEDRON,{4,5,7,1,-1,-1,-1,-1,},{2,5,103,100,-1,-1,},536870925}, {TETRAHEDRON,{1,5,7,9,-1,-1,-1,-1,},{4,3,6,101,-1,-1,},805306405}, {TETRAHEDRON,{3,7,9,1,-1,-1,-1,-1,},{102,5,101,103,-1,-1,},1073741989}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, }}, // Rule 220 {TETRAHEDRON,220,RED_CLASS,7, // tag, mark, rclass, nsons {1,1,1,1,0,1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,}, // pattern 47, // pat {{0,1},{1,0},{0,2},{0,3},{-1,0},{1,2},{-1,-1}, // sonandnode {-1,-1},{-1,-1},{-1,-1},{-1,0},{-1,-1},{-1,-1}, {-1,-1},{-1,-1},{-1,-1},{-1,-1},{-1,-1},{-1,-1}, }, {{TETRAHEDRON,{0,4,6,7,-1,-1,-1,-1,},{100,2,102,103,-1,-1,},0}, // sons {TETRAHEDRON,{5,6,9,2,-1,-1,-1,-1,},{3,102,101,100,-1,-1,},805306421}, {TETRAHEDRON,{4,5,6,7,-1,-1,-1,-1,},{100,3,0,5,-1,-1,},268435457}, {TETRAHEDRON,{5,6,7,9,-1,-1,-1,-1,},{2,102,4,1,-1,-1,},536870917}, {TETRAHEDRON,{3,5,7,9,-1,-1,-1,-1,},{5,3,102,101,-1,-1,},805306405}, {TETRAHEDRON,{4,5,7,3,-1,-1,-1,-1,},{2,4,103,6,-1,-1,},536870925}, {TETRAHEDRON,{3,4,5,1,-1,-1,-1,-1,},{5,100,101,103,-1,-1,},805306429}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, }}, // Rule 221 {TETRAHEDRON,221,RED_CLASS,7, // tag, mark, rclass, nsons {1,1,1,1,0,1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,}, // pattern 47, // pat {{0,1},{1,0},{0,2},{0,3},{-1,0},{1,2},{-1,-1}, // sonandnode {-1,-1},{-1,-1},{-1,-1},{-1,0},{-1,-1},{-1,-1}, {-1,-1},{-1,-1},{-1,-1},{-1,-1},{-1,-1},{-1,-1}, }, {{TETRAHEDRON,{0,4,6,7,-1,-1,-1,-1,},{100,2,102,103,-1,-1,},0}, // sons {TETRAHEDRON,{5,6,9,2,-1,-1,-1,-1,},{3,102,101,100,-1,-1,},805306421}, {TETRAHEDRON,{4,5,6,7,-1,-1,-1,-1,},{100,3,0,6,-1,-1,},268435457}, {TETRAHEDRON,{5,6,7,9,-1,-1,-1,-1,},{2,102,4,1,-1,-1,},536870917}, {TETRAHEDRON,{3,5,7,9,-1,-1,-1,-1,},{5,3,102,101,-1,-1,},805306405}, {TETRAHEDRON,{1,3,5,7,-1,-1,-1,-1,},{101,4,6,103,-1,-1,},1073741861}, {TETRAHEDRON,{4,5,7,1,-1,-1,-1,-1,},{2,5,103,100,-1,-1,},536870925}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, }}, // Rule 222 {TETRAHEDRON,222,RED_CLASS,7, // tag, mark, rclass, nsons {1,1,1,1,0,1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,}, // pattern 47, // pat {{0,1},{1,0},{0,2},{0,3},{-1,0},{1,2},{-1,-1}, // sonandnode {-1,-1},{-1,-1},{-1,-1},{-1,0},{-1,-1},{-1,-1}, {-1,-1},{-1,-1},{-1,-1},{-1,-1},{-1,-1},{-1,-1}, }, {{TETRAHEDRON,{0,4,6,7,-1,-1,-1,-1,},{100,2,102,103,-1,-1,},0}, // sons {TETRAHEDRON,{5,6,9,2,-1,-1,-1,-1,},{3,102,101,100,-1,-1,},805306397}, {TETRAHEDRON,{4,6,7,9,-1,-1,-1,-1,},{0,102,6,3,-1,-1,},268435457}, {TETRAHEDRON,{4,5,6,9,-1,-1,-1,-1,},{100,1,2,4,-1,-1,},536870925}, {TETRAHEDRON,{4,5,9,1,-1,-1,-1,-1,},{3,101,5,100,-1,-1,},805306429}, {TETRAHEDRON,{3,4,9,1,-1,-1,-1,-1,},{6,4,101,103,-1,-1,},1073742013}, {TETRAHEDRON,{3,4,7,9,-1,-1,-1,-1,},{103,2,102,5,-1,-1,},536870921}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, }}, // Rule 223 {TETRAHEDRON,223,RED_CLASS,7, // tag, mark, rclass, nsons {1,1,1,0,1,1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,}, // pattern 55, // pat {{0,0},{0,1},{1,1},{-1,0},{0,2},{1,2},{-1,-1}, // sonandnode {-1,-1},{-1,-1},{-1,-1},{-1,0},{-1,-1},{-1,-1}, {-1,-1},{-1,-1},{-1,-1},{-1,-1},{-1,-1},{-1,-1}, }, {{TETRAHEDRON,{4,5,8,1,-1,-1,-1,-1,},{2,101,103,100,-1,-1,},0}, // sons {TETRAHEDRON,{5,6,9,2,-1,-1,-1,-1,},{3,102,101,100,-1,-1,},805306392}, {TETRAHEDRON,{5,8,9,4,-1,-1,-1,-1,},{101,4,3,0,-1,-1,},268435456}, {TETRAHEDRON,{4,5,6,9,-1,-1,-1,-1,},{100,1,5,2,-1,-1,},536870920}, {TETRAHEDRON,{4,8,9,3,-1,-1,-1,-1,},{2,101,5,103,-1,-1,},536870916}, {TETRAHEDRON,{3,4,6,9,-1,-1,-1,-1,},{6,3,102,4,-1,-1,},805306408}, {TETRAHEDRON,{0,3,4,6,-1,-1,-1,-1,},{103,5,100,102,-1,-1,},1073741864}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, }}, // Rule 224 {TETRAHEDRON,224,RED_CLASS,7, // tag, mark, rclass, nsons {1,1,1,0,1,1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,}, // pattern 55, // pat {{0,0},{0,1},{1,1},{-1,0},{0,2},{1,2},{-1,-1}, // sonandnode {-1,-1},{-1,-1},{-1,-1},{-1,0},{-1,-1},{-1,-1}, {-1,-1},{-1,-1},{-1,-1},{-1,-1},{-1,-1},{-1,-1}, }, {{TETRAHEDRON,{4,5,8,1,-1,-1,-1,-1,},{2,101,103,100,-1,-1,},0}, // sons {TETRAHEDRON,{5,6,9,2,-1,-1,-1,-1,},{3,102,101,100,-1,-1,},805306392}, {TETRAHEDRON,{5,8,9,4,-1,-1,-1,-1,},{101,5,3,0,-1,-1,},268435456}, {TETRAHEDRON,{4,5,6,9,-1,-1,-1,-1,},{100,1,4,2,-1,-1,},536870920}, {TETRAHEDRON,{0,4,6,9,-1,-1,-1,-1,},{100,3,102,5,-1,-1,},805306408}, {TETRAHEDRON,{4,8,9,0,-1,-1,-1,-1,},{2,6,4,103,-1,-1,},536870916}, {TETRAHEDRON,{0,3,8,9,-1,-1,-1,-1,},{103,101,5,102,-1,-1,},805306388}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, }}, // Rule 225 {TETRAHEDRON,225,RED_CLASS,7, // tag, mark, rclass, nsons {1,1,1,0,1,1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,}, // pattern 55, // pat {{0,0},{0,1},{1,1},{-1,0},{0,2},{1,2},{-1,-1}, // sonandnode {-1,-1},{-1,-1},{-1,-1},{-1,0},{-1,-1},{-1,-1}, {-1,-1},{-1,-1},{-1,-1},{-1,-1},{-1,-1},{-1,-1}, }, {{TETRAHEDRON,{4,5,8,1,-1,-1,-1,-1,},{2,101,103,100,-1,-1,},0}, // sons {TETRAHEDRON,{5,6,9,2,-1,-1,-1,-1,},{3,102,101,100,-1,-1,},805306392}, {TETRAHEDRON,{5,8,9,4,-1,-1,-1,-1,},{101,6,3,0,-1,-1,},268435456}, {TETRAHEDRON,{4,5,6,9,-1,-1,-1,-1,},{100,1,4,2,-1,-1,},536870920}, {TETRAHEDRON,{0,4,6,9,-1,-1,-1,-1,},{100,3,102,5,-1,-1,},805306408}, {TETRAHEDRON,{0,3,4,9,-1,-1,-1,-1,},{103,6,4,102,-1,-1,},1073742056}, {TETRAHEDRON,{4,8,9,3,-1,-1,-1,-1,},{2,101,5,103,-1,-1,},536870916}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, }}, // Rule 226 {TETRAHEDRON,226,RED_CLASS,7, // tag, mark, rclass, nsons {1,1,1,0,1,1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,}, // pattern 55, // pat {{0,0},{0,1},{1,1},{-1,0},{0,2},{1,2},{-1,-1}, // sonandnode {-1,-1},{-1,-1},{-1,-1},{-1,0},{-1,-1},{-1,-1}, {-1,-1},{-1,-1},{-1,-1},{-1,-1},{-1,-1},{-1,-1}, }, {{TETRAHEDRON,{4,5,8,1,-1,-1,-1,-1,},{2,101,103,100,-1,-1,},0}, // sons {TETRAHEDRON,{5,6,9,2,-1,-1,-1,-1,},{3,102,101,100,-1,-1,},805306420}, {TETRAHEDRON,{4,5,6,8,-1,-1,-1,-1,},{100,3,6,0,-1,-1,},268435456}, {TETRAHEDRON,{5,6,8,9,-1,-1,-1,-1,},{2,4,101,1,-1,-1,},536870916}, {TETRAHEDRON,{6,8,9,3,-1,-1,-1,-1,},{3,101,102,5,-1,-1,},805306388}, {TETRAHEDRON,{3,6,8,0,-1,-1,-1,-1,},{4,6,103,102,-1,-1,},1073742036}, {TETRAHEDRON,{0,4,6,8,-1,-1,-1,-1,},{100,2,5,103,-1,-1,},536870920}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, }}, // Rule 227 {TETRAHEDRON,227,RED_CLASS,7, // tag, mark, rclass, nsons {1,1,0,1,1,1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,}, // pattern 59, // pat {{1,0},{1,1},{-1,0},{0,0},{0,1},{0,2},{-1,-1}, // sonandnode {-1,-1},{-1,-1},{-1,-1},{-1,0},{-1,-1},{-1,-1}, {-1,-1},{-1,-1},{-1,-1},{-1,-1},{-1,-1},{-1,-1}, }, {{TETRAHEDRON,{7,8,9,3,-1,-1,-1,-1,},{2,101,102,103,-1,-1,},0}, // sons {TETRAHEDRON,{4,5,8,1,-1,-1,-1,-1,},{3,101,103,100,-1,-1,},805306416}, {TETRAHEDRON,{5,7,8,9,-1,-1,-1,-1,},{3,0,101,4,-1,-1,},268435456}, {TETRAHEDRON,{4,5,7,8,-1,-1,-1,-1,},{5,2,103,1,-1,-1,},536870912}, {TETRAHEDRON,{5,7,9,2,-1,-1,-1,-1,},{2,102,101,5,-1,-1,},536870924}, {TETRAHEDRON,{2,4,5,7,-1,-1,-1,-1,},{100,3,4,6,-1,-1,},805306368}, {TETRAHEDRON,{2,4,7,0,-1,-1,-1,-1,},{5,103,102,100,-1,-1,},1073742016}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, }}, // Rule 228 {TETRAHEDRON,228,RED_CLASS,7, // tag, mark, rclass, nsons {1,1,0,1,1,1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,}, // pattern 59, // pat {{1,0},{1,1},{-1,0},{0,0},{0,1},{0,2},{-1,-1}, // sonandnode {-1,-1},{-1,-1},{-1,-1},{-1,0},{-1,-1},{-1,-1}, {-1,-1},{-1,-1},{-1,-1},{-1,-1},{-1,-1},{-1,-1}, }, {{TETRAHEDRON,{7,8,9,3,-1,-1,-1,-1,},{2,101,102,103,-1,-1,},0}, // sons {TETRAHEDRON,{4,5,8,1,-1,-1,-1,-1,},{3,101,103,100,-1,-1,},805306416}, {TETRAHEDRON,{5,7,8,9,-1,-1,-1,-1,},{3,0,101,5,-1,-1,},268435456}, {TETRAHEDRON,{4,5,7,8,-1,-1,-1,-1,},{4,2,103,1,-1,-1,},536870912}, {TETRAHEDRON,{0,4,5,7,-1,-1,-1,-1,},{100,3,5,103,-1,-1,},805306368}, {TETRAHEDRON,{5,7,9,0,-1,-1,-1,-1,},{2,102,6,4,-1,-1,},536870924}, {TETRAHEDRON,{2,5,9,0,-1,-1,-1,-1,},{101,5,102,100,-1,-1,},805306412}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, }}, // Rule 229 {TETRAHEDRON,229,RED_CLASS,7, // tag, mark, rclass, nsons {1,1,0,1,1,1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,}, // pattern 59, // pat {{1,0},{1,1},{-1,0},{0,0},{0,1},{0,2},{-1,-1}, // sonandnode {-1,-1},{-1,-1},{-1,-1},{-1,0},{-1,-1},{-1,-1}, {-1,-1},{-1,-1},{-1,-1},{-1,-1},{-1,-1},{-1,-1}, }, {{TETRAHEDRON,{7,8,9,3,-1,-1,-1,-1,},{2,101,102,103,-1,-1,},0}, // sons {TETRAHEDRON,{4,5,8,1,-1,-1,-1,-1,},{3,101,103,100,-1,-1,},805306416}, {TETRAHEDRON,{5,7,8,9,-1,-1,-1,-1,},{3,0,101,6,-1,-1,},268435456}, {TETRAHEDRON,{4,5,7,8,-1,-1,-1,-1,},{4,2,103,1,-1,-1,},536870912}, {TETRAHEDRON,{0,4,5,7,-1,-1,-1,-1,},{100,3,5,103,-1,-1,},805306368}, {TETRAHEDRON,{2,5,7,0,-1,-1,-1,-1,},{6,4,102,100,-1,-1,},1073741952}, {TETRAHEDRON,{5,7,9,2,-1,-1,-1,-1,},{2,102,101,5,-1,-1,},536870924}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, }}, // Rule 230 {TETRAHEDRON,230,RED_CLASS,7, // tag, mark, rclass, nsons {1,1,0,1,1,1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,}, // pattern 59, // pat {{1,0},{1,1},{-1,0},{0,0},{0,1},{0,2},{-1,-1}, // sonandnode {-1,-1},{-1,-1},{-1,-1},{-1,0},{-1,-1},{-1,-1}, {-1,-1},{-1,-1},{-1,-1},{-1,-1},{-1,-1},{-1,-1}, }, {{TETRAHEDRON,{7,8,9,3,-1,-1,-1,-1,},{2,101,102,103,-1,-1,},0}, // sons {TETRAHEDRON,{4,5,8,1,-1,-1,-1,-1,},{3,101,103,100,-1,-1,},805306424}, {TETRAHEDRON,{4,7,8,9,-1,-1,-1,-1,},{103,0,3,6,-1,-1,},268435456}, {TETRAHEDRON,{5,8,9,4,-1,-1,-1,-1,},{101,2,4,1,-1,-1,},536870920}, {TETRAHEDRON,{2,4,5,9,-1,-1,-1,-1,},{100,3,101,5,-1,-1,},805306408}, {TETRAHEDRON,{2,4,9,0,-1,-1,-1,-1,},{4,6,102,100,-1,-1,},1073742056}, {TETRAHEDRON,{4,7,9,0,-1,-1,-1,-1,},{2,102,5,103,-1,-1,},536870924}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, }}, // Rule 231 {TETRAHEDRON,231,RED_CLASS,7, // tag, mark, rclass, nsons {1,0,1,1,1,1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,}, // pattern 61, // pat {{1,1},{-1,0},{1,2},{0,0},{0,1},{0,2},{-1,-1}, // sonandnode {-1,-1},{-1,-1},{-1,-1},{-1,0},{-1,-1},{-1,-1}, {-1,-1},{-1,-1},{-1,-1},{-1,-1},{-1,-1},{-1,-1}, }, {{TETRAHEDRON,{7,8,9,3,-1,-1,-1,-1,},{2,101,102,103,-1,-1,},0}, // sons {TETRAHEDRON,{0,4,6,7,-1,-1,-1,-1,},{100,3,102,103,-1,-1,},805306380}, {TETRAHEDRON,{4,7,8,9,-1,-1,-1,-1,},{103,0,4,3,-1,-1,},268435456}, {TETRAHEDRON,{4,6,7,9,-1,-1,-1,-1,},{1,102,2,5,-1,-1,},536870924}, {TETRAHEDRON,{1,4,8,9,-1,-1,-1,-1,},{103,2,101,5,-1,-1,},536870920}, {TETRAHEDRON,{4,6,9,1,-1,-1,-1,-1,},{3,6,4,100,-1,-1,},805306428}, {TETRAHEDRON,{1,2,6,9,-1,-1,-1,-1,},{100,102,5,101,-1,-1,},1073741948}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, }}, // Rule 232 {TETRAHEDRON,232,RED_CLASS,7, // tag, mark, rclass, nsons {1,0,1,1,1,1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,}, // pattern 61, // pat {{1,1},{-1,0},{1,2},{0,0},{0,1},{0,2},{-1,-1}, // sonandnode {-1,-1},{-1,-1},{-1,-1},{-1,0},{-1,-1},{-1,-1}, {-1,-1},{-1,-1},{-1,-1},{-1,-1},{-1,-1},{-1,-1}, }, {{TETRAHEDRON,{7,8,9,3,-1,-1,-1,-1,},{2,101,102,103,-1,-1,},0}, // sons {TETRAHEDRON,{0,4,6,7,-1,-1,-1,-1,},{100,3,102,103,-1,-1,},805306380}, {TETRAHEDRON,{4,7,8,9,-1,-1,-1,-1,},{103,0,5,3,-1,-1,},268435456}, {TETRAHEDRON,{4,6,7,9,-1,-1,-1,-1,},{1,102,2,4,-1,-1,},536870924}, {TETRAHEDRON,{4,6,9,2,-1,-1,-1,-1,},{3,102,5,100,-1,-1,},805306428}, {TETRAHEDRON,{2,4,8,9,-1,-1,-1,-1,},{6,2,101,4,-1,-1,},536870920}, {TETRAHEDRON,{1,2,4,8,-1,-1,-1,-1,},{100,5,103,101,-1,-1,},805306376}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, }}, // Rule 233 {TETRAHEDRON,233,RED_CLASS,7, // tag, mark, rclass, nsons {1,0,1,1,1,1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,}, // pattern 61, // pat {{1,1},{-1,0},{1,2},{0,0},{0,1},{0,2},{-1,-1}, // sonandnode {-1,-1},{-1,-1},{-1,-1},{-1,0},{-1,-1},{-1,-1}, {-1,-1},{-1,-1},{-1,-1},{-1,-1},{-1,-1},{-1,-1}, }, {{TETRAHEDRON,{7,8,9,3,-1,-1,-1,-1,},{2,101,102,103,-1,-1,},0}, // sons {TETRAHEDRON,{0,4,6,7,-1,-1,-1,-1,},{100,3,102,103,-1,-1,},805306380}, {TETRAHEDRON,{4,7,8,9,-1,-1,-1,-1,},{103,0,6,3,-1,-1,},268435456}, {TETRAHEDRON,{4,6,7,9,-1,-1,-1,-1,},{1,102,2,4,-1,-1,},536870924}, {TETRAHEDRON,{4,6,9,2,-1,-1,-1,-1,},{3,102,5,100,-1,-1,},805306428}, {TETRAHEDRON,{1,2,4,9,-1,-1,-1,-1,},{100,4,6,101,-1,-1,},1073742012}, {TETRAHEDRON,{1,4,8,9,-1,-1,-1,-1,},{103,2,101,5,-1,-1,},536870920}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, }}, // Rule 234 {TETRAHEDRON,234,RED_CLASS,7, // tag, mark, rclass, nsons {1,0,1,1,1,1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,}, // pattern 61, // pat {{1,1},{-1,0},{1,2},{0,0},{0,1},{0,2},{-1,-1}, // sonandnode {-1,-1},{-1,-1},{-1,-1},{-1,0},{-1,-1},{-1,-1}, {-1,-1},{-1,-1},{-1,-1},{-1,-1},{-1,-1},{-1,-1}, }, {{TETRAHEDRON,{7,8,9,3,-1,-1,-1,-1,},{2,101,102,103,-1,-1,},0}, // sons {TETRAHEDRON,{0,4,6,7,-1,-1,-1,-1,},{100,3,102,103,-1,-1,},805306368}, {TETRAHEDRON,{6,7,8,9,-1,-1,-1,-1,},{3,0,6,102,-1,-1,},268435456}, {TETRAHEDRON,{4,6,7,8,-1,-1,-1,-1,},{1,2,103,4,-1,-1,},536870912}, {TETRAHEDRON,{4,6,8,1,-1,-1,-1,-1,},{3,5,103,100,-1,-1,},805306416}, {TETRAHEDRON,{1,2,6,8,-1,-1,-1,-1,},{100,6,4,101,-1,-1,},1073741936}, {TETRAHEDRON,{2,6,8,9,-1,-1,-1,-1,},{5,2,101,102,-1,-1,},536870920}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, }}, // Rule 235 {TETRAHEDRON,235,RED_CLASS,7, // tag, mark, rclass, nsons {0,1,1,1,1,1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,}, // pattern 62, // pat {{-1,0},{1,0},{1,1},{0,0},{0,1},{0,2},{-1,-1}, // sonandnode {-1,-1},{-1,-1},{-1,-1},{-1,0},{-1,-1},{-1,-1}, {-1,-1},{-1,-1},{-1,-1},{-1,-1},{-1,-1},{-1,-1}, }, {{TETRAHEDRON,{7,8,9,3,-1,-1,-1,-1,},{2,101,102,103,-1,-1,},0}, // sons {TETRAHEDRON,{5,6,9,2,-1,-1,-1,-1,},{3,102,101,100,-1,-1,},805306424}, {TETRAHEDRON,{6,7,8,9,-1,-1,-1,-1,},{4,0,3,102,-1,-1,},268435456}, {TETRAHEDRON,{5,6,8,9,-1,-1,-1,-1,},{5,2,101,1,-1,-1,},536870920}, {TETRAHEDRON,{0,6,7,8,-1,-1,-1,-1,},{102,2,103,5,-1,-1,},536870912}, {TETRAHEDRON,{0,5,6,8,-1,-1,-1,-1,},{100,3,4,6,-1,-1,},805306376}, {TETRAHEDRON,{0,1,5,8,-1,-1,-1,-1,},{100,101,5,103,-1,-1,},1073742024}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, }}, // Rule 236 {TETRAHEDRON,236,RED_CLASS,7, // tag, mark, rclass, nsons {0,1,1,1,1,1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,}, // pattern 62, // pat {{-1,0},{1,0},{1,1},{0,0},{0,1},{0,2},{-1,-1}, // sonandnode {-1,-1},{-1,-1},{-1,-1},{-1,0},{-1,-1},{-1,-1}, {-1,-1},{-1,-1},{-1,-1},{-1,-1},{-1,-1},{-1,-1}, }, {{TETRAHEDRON,{7,8,9,3,-1,-1,-1,-1,},{2,101,102,103,-1,-1,},0}, // sons {TETRAHEDRON,{5,6,9,2,-1,-1,-1,-1,},{3,102,101,100,-1,-1,},805306424}, {TETRAHEDRON,{6,7,8,9,-1,-1,-1,-1,},{5,0,3,102,-1,-1,},268435456}, {TETRAHEDRON,{5,6,8,9,-1,-1,-1,-1,},{4,2,101,1,-1,-1,},536870920}, {TETRAHEDRON,{1,5,6,8,-1,-1,-1,-1,},{100,3,5,101,-1,-1,},805306376}, {TETRAHEDRON,{1,6,7,8,-1,-1,-1,-1,},{6,2,103,4,-1,-1,},536870912}, {TETRAHEDRON,{0,1,6,7,-1,-1,-1,-1,},{100,5,102,103,-1,-1,},805306368}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, }}, // Rule 237 {TETRAHEDRON,237,RED_CLASS,7, // tag, mark, rclass, nsons {0,1,1,1,1,1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,}, // pattern 62, // pat {{-1,0},{1,0},{1,1},{0,0},{0,1},{0,2},{-1,-1}, // sonandnode {-1,-1},{-1,-1},{-1,-1},{-1,0},{-1,-1},{-1,-1}, {-1,-1},{-1,-1},{-1,-1},{-1,-1},{-1,-1},{-1,-1}, }, {{TETRAHEDRON,{7,8,9,3,-1,-1,-1,-1,},{2,101,102,103,-1,-1,},0}, // sons {TETRAHEDRON,{5,6,9,2,-1,-1,-1,-1,},{3,102,101,100,-1,-1,},805306424}, {TETRAHEDRON,{6,7,8,9,-1,-1,-1,-1,},{6,0,3,102,-1,-1,},268435456}, {TETRAHEDRON,{5,6,8,9,-1,-1,-1,-1,},{4,2,101,1,-1,-1,},536870920}, {TETRAHEDRON,{1,5,6,8,-1,-1,-1,-1,},{100,3,5,101,-1,-1,},805306376}, {TETRAHEDRON,{0,1,6,8,-1,-1,-1,-1,},{100,4,6,103,-1,-1,},1073741960}, {TETRAHEDRON,{0,6,7,8,-1,-1,-1,-1,},{102,2,103,5,-1,-1,},536870912}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, }}, // Rule 238 {TETRAHEDRON,238,RED_CLASS,7, // tag, mark, rclass, nsons {0,1,1,1,1,1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,}, // pattern 62, // pat {{-1,0},{1,0},{1,1},{0,0},{0,1},{0,2},{-1,-1}, // sonandnode {-1,-1},{-1,-1},{-1,-1},{-1,0},{-1,-1},{-1,-1}, {-1,-1},{-1,-1},{-1,-1},{-1,-1},{-1,-1},{-1,-1}, }, {{TETRAHEDRON,{7,8,9,3,-1,-1,-1,-1,},{2,101,102,103,-1,-1,},0}, // sons {TETRAHEDRON,{5,6,9,2,-1,-1,-1,-1,},{3,102,101,100,-1,-1,},805306428}, {TETRAHEDRON,{5,7,8,9,-1,-1,-1,-1,},{6,0,101,3,-1,-1,},268435456}, {TETRAHEDRON,{5,6,7,9,-1,-1,-1,-1,},{4,102,2,1,-1,-1,},536870924}, {TETRAHEDRON,{0,5,6,7,-1,-1,-1,-1,},{100,3,102,5,-1,-1,},805306380}, {TETRAHEDRON,{0,1,5,7,-1,-1,-1,-1,},{100,6,4,103,-1,-1,},1073742028}, {TETRAHEDRON,{1,5,7,8,-1,-1,-1,-1,},{5,2,103,101,-1,-1,},536870912}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, }}, // Rule 239 {TETRAHEDRON,239,RED_CLASS,8, // tag, mark, rclass, nsons {1,1,1,1,1,1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,}, // pattern 63, // pat {{0,1},{1,1},{0,2},{0,3},{1,2},{2,2},{-1,-1}, // sonandnode {-1,-1},{-1,-1},{-1,-1},{-1,0},{-1,-1},{-1,-1}, {-1,-1},{-1,-1},{-1,-1},{-1,-1},{-1,-1},{-1,-1}, }, {{TETRAHEDRON,{0,4,6,7,-1,-1,-1,-1,},{100,4,102,103,-1,-1,},0}, // sons {TETRAHEDRON,{4,5,8,1,-1,-1,-1,-1,},{5,101,103,100,-1,-1,},805306429}, {TETRAHEDRON,{5,6,9,2,-1,-1,-1,-1,},{6,102,101,100,-1,-1,},1073742045}, {TETRAHEDRON,{7,8,9,3,-1,-1,-1,-1,},{7,101,102,103,-1,-1,},805306389}, {TETRAHEDRON,{4,6,7,8,-1,-1,-1,-1,},{0,7,103,5,-1,-1,},268435457}, {TETRAHEDRON,{4,5,6,8,-1,-1,-1,-1,},{100,6,4,1,-1,-1,},536870925}, {TETRAHEDRON,{5,6,8,9,-1,-1,-1,-1,},{5,7,101,2,-1,-1,},805306397}, {TETRAHEDRON,{6,7,8,9,-1,-1,-1,-1,},{4,3,6,102,-1,-1,},536870917}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, }}, // Rule 240 {TETRAHEDRON,240,RED_CLASS,8, // tag, mark, rclass, nsons {1,1,1,1,1,1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,}, // pattern 63, // pat {{1,0},{0,0},{0,1},{2,0},{1,2},{0,2},{-1,-1}, // sonandnode {-1,-1},{-1,-1},{-1,-1},{-1,0},{-1,-1},{-1,-1}, {-1,-1},{-1,-1},{-1,-1},{-1,-1},{-1,-1},{-1,-1}, }, {{TETRAHEDRON,{5,6,9,2,-1,-1,-1,-1,},{4,102,101,100,-1,-1,},0}, // sons {TETRAHEDRON,{4,5,8,1,-1,-1,-1,-1,},{5,101,103,100,-1,-1,},805306428}, {TETRAHEDRON,{7,8,9,3,-1,-1,-1,-1,},{6,101,102,103,-1,-1,},1073741916}, {TETRAHEDRON,{0,4,6,7,-1,-1,-1,-1,},{100,7,102,103,-1,-1,},805306376}, {TETRAHEDRON,{4,5,6,9,-1,-1,-1,-1,},{100,0,7,5,-1,-1,},268435456}, {TETRAHEDRON,{5,8,9,4,-1,-1,-1,-1,},{101,6,4,1,-1,-1,},536870924}, {TETRAHEDRON,{4,7,8,9,-1,-1,-1,-1,},{103,2,5,7,-1,-1,},805306396}, {TETRAHEDRON,{4,6,7,9,-1,-1,-1,-1,},{3,102,6,4,-1,-1,},536870920}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, }}, // Rule 241 {TETRAHEDRON,241,RED_CLASS,8, // tag, mark, rclass, nsons {1,1,1,1,1,1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,}, // pattern 63, // pat {{1,0},{1,1},{2,2},{0,0},{0,1},{0,2},{-1,-1}, // sonandnode {-1,-1},{-1,-1},{-1,-1},{-1,0},{-1,-1},{-1,-1}, {-1,-1},{-1,-1},{-1,-1},{-1,-1},{-1,-1},{-1,-1}, }, {{TETRAHEDRON,{7,8,9,3,-1,-1,-1,-1,},{4,101,102,103,-1,-1,},0}, // sons {TETRAHEDRON,{4,5,8,1,-1,-1,-1,-1,},{5,101,103,100,-1,-1,},805306416}, {TETRAHEDRON,{0,4,6,7,-1,-1,-1,-1,},{100,6,102,103,-1,-1,},1073741952}, {TETRAHEDRON,{5,6,9,2,-1,-1,-1,-1,},{7,102,101,100,-1,-1,},805306428}, {TETRAHEDRON,{5,7,8,9,-1,-1,-1,-1,},{5,0,101,7,-1,-1,},268435456}, {TETRAHEDRON,{4,5,7,8,-1,-1,-1,-1,},{6,4,103,1,-1,-1,},536870912}, {TETRAHEDRON,{4,5,6,7,-1,-1,-1,-1,},{100,7,2,5,-1,-1,},805306368}, {TETRAHEDRON,{5,6,7,9,-1,-1,-1,-1,},{6,102,4,3,-1,-1,},536870924}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, {TETRAHEDRON,{0,0,0,0,-1,-1,-1,-1,},{0,0,0,0,-1,-1,},0}, }}, }; static const NS_PREFIX SHORT pattern2RuleTetrahedron[1024] = {0,2,3,9,4,10,13,35,5,15,16,38,17,41,50,122,6,19,22,53,23,60,66,126,25,68,72,130,74,134,144,217,7,26,27,79,30,82,86,154,31,95,97,163,101,174,178,221,34,103,106,182,110,188,202,225,112,206,210,229,214,233,237,239,-1,-1,-1,8,-1,11,12,-1,-1,-1,-1,39,-1,45,48,-1,-1,-1,-1,55,-1,61,67,-1,-1,-1,-1,127,-1,133,148,-1,-1,-1,-1,77,-1,84,88,-1,-1,-1,-1,165,-1,171,177,-1,-1,-1,-1,181,-1,196,199,-1,-1,-1,-1,227,-1,231,235,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,21,56,-1,-1,65,123,-1,-1,70,129,-1,-1,142,216,-1,-1,28,80,-1,-1,92,153,-1,-1,99,167,-1,-1,175,219,33,102,-1,-1,109,187,-1,-1,115,203,-1,-1,213,232,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,54,-1,-1,64,-1,-1,-1,-1,128,-1,-1,138,-1,-1,-1,-1,78,-1,-1,91,-1,-1,-1,-1,166,-1,-1,176,-1,-1,-1,-1,-1,-1,183,-1,-1,-1,-1,-1,-1,-1,234,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,18,46,51,121,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,76,131,150,215,-1,-1,-1,-1,29,81,89,151,32,96,98,164,-1,-1,-1,-1,-1,-1,-1,-1,108,186,201,223,118,205,207,228,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,47,49,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,132,149,-1,-1,-1,-1,-1,-1,83,87,-1,-1,-1,-1,155,-1,-1,-1,-1,-1,-1,-1,-1,-1,190,200,-1,-1,-1,-1,230,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,136,218,-1,-1,-1,-1,-1,-1,90,152,-1,-1,100,169,-1,-1,-1,-1,-1,-1,-1,-1,107,185,-1,-1,116,204,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,140,-1,-1,-1,-1,-1,-1,-1,85,-1,-1,-1,-1,170,-1,-1,-1,-1,-1,-1,-1,-1,-1,189,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,14,-1,37,-1,42,-1,119,-1,20,-1,59,-1,63,-1,125,24,-1,71,-1,73,-1,143,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,93,-1,161,-1,173,-1,220,-1,105,-1,179,-1,198,-1,224,114,-1,209,-1,211,-1,236,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,36,-1,44,-1,-1,-1,-1,-1,58,-1,62,-1,-1,-1,-1,-1,-1,-1,-1,135,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,157,-1,172,-1,-1,-1,-1,-1,180,-1,197,-1,-1,-1,-1,-1,-1,-1,-1,238,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,57,-1,-1,-1,124,-1,-1,69,-1,-1,-1,141,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,156,-1,-1,-1,222,-1,104,-1,-1,-1,194,-1,-1,113,-1,-1,-1,212,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,52,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,137,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,159,-1,-1,-1,-1,-1,-1,-1,-1,-1,195,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,43,-1,120,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,75,-1,146,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,94,-1,162,-1,-1,-1,-1,-1,-1,-1,-1,-1,184,-1,226,117,-1,208,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,40,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,147,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,158,-1,-1,-1,-1,-1,-1,-1,-1,-1,192,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,145,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,168,-1,-1,-1,-1,-1,-1,-1,-1,-1,193,-1,-1,111,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,139,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,160,-1,-1,-1,-1,-1,-1,-1,-1,-1,191,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,}; dune-uggrid-2.11.0+dfsg/dune/uggrid/gm/algebra.cc000066400000000000000000001016411513616443000214550ustar00rootroot00000000000000// SPDX-FileCopyrightText: Copyright © DUNE Project contributors, see file LICENSE.md in module root // SPDX-License-Identifier: LGPL-2.1-or-later // -*- tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- // vi: set et ts=4 sw=2 sts=2: /*! \file algebra.c * \ingroup gm */ /** \addtogroup gm * * @{ */ /****************************************************************************/ /* */ /* File: algebra.c */ /* */ /* Purpose: management for algebraic structures */ /* */ /* Author: Klaus Johannsen */ /* Interdisziplinaeres Zentrum fuer Wissenschaftliches Rechnen */ /* Universitaet Heidelberg */ /* Im Neuenheimer Feld 294 */ /* 6900 Heidelberg */ /* email: ug@ica3.uni-stuttgart.de */ /* */ /* blockvector data structure: */ /* Christian Wrobel */ /* Institut fuer Computeranwendungen III */ /* Universitaet Stuttgart */ /* Pfaffenwaldring 27 */ /* 70569 Stuttgart */ /* email: ug@ica3.uni-stuttgart.de */ /* */ /* History: 1.12.93 begin, ug 3d */ /* 26.10.94 begin combination 2D/3D version */ /* 28.09.95 blockvector implemented (Christian Wrobel) */ /* */ /* Remarks: */ /* */ /****************************************************************************/ /****************************************************************************/ /* */ /* defines to exclude functions */ /* */ /****************************************************************************/ /****************************************************************************/ /* */ /* include files */ /* system include files */ /* application include files */ /* */ /****************************************************************************/ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "algebra.h" #include "cw.h" #include "dlmgr.h" #include "gm.h" #include "elements.h" #include "refine.h" #include "ugm.h" #include "evm.h" #include "dlmgr.h" #ifdef ModelP #include #endif USING_UG_NAMESPACE USING_UGDIM_NAMESPACE using namespace PPIF; /****************************************************************************/ /** \brief Return pointer to a new vector structure * * @param theGrid - grid where vector should be inserted * @param side - one of the types defined in gm * @param object - associate vector with this object * @param vHandle - handle of new vector, i.e. a pointer to a pointer where a pointer to the new vector is placed. This function returns a pointer to a new side vector structure. First the free list is checked for a free entry, if none is available, a new structure is allocated from the heap. * @return
    *
  • 0 if ok
  • *
  • 1 if error occurred.
*/ /****************************************************************************/ INT NS_DIM_PREFIX CreateSideVector (GRID *theGrid, INT side, GEOM_OBJECT *object, VECTOR **vHandle) { *vHandle = nullptr; #ifdef UG_DIM_2 return 0; #endif MULTIGRID *theMG = MYMG(theGrid); VECTOR *pv = (VECTOR *)GetMemoryForObject(theMG,sizeof(VECTOR),VEOBJ); if (pv==NULL) REP_ERR_RETURN(1); /* initialize data */ SETOBJT(pv,VEOBJ); SETVDATATYPE(pv,BITWISE_TYPE(SIDEVEC)); SETVOTYPE(pv,SIDEVEC); SETVCLASS(pv,3); SETVNCLASS(pv,0); SETVNEW(pv,1); /* SETPRIO(dddContext, pv,PrioMaster); */ #ifndef ModelP // Dune uses the id field for face indices in sequential grids pv->id = (theGrid->mg->vectorIdCounter)++; #endif #ifdef ModelP DDD_AttrSet(PARHDR(pv),GRID_ATTR(theGrid)); #endif VOBJECT(pv) = object; VINDEX(pv) = (long)NVEC(theGrid); SUCCVC(pv) = FIRSTVECTOR(theGrid); GRID_LINK_VECTOR(theGrid,pv,PrioMaster); *vHandle = pv; SETVECTORSIDE(*vHandle,side); SETVCOUNT(*vHandle,1); return (0); } /****************************************************************************/ /** \brief Remove vector from the data structure * * @param theGrid - grid level where theVector is in. * @param theVector - VECTOR to be disposed. This function removes vector from the data structure and places it in the free list. * @return
    *
  • 0 if ok
  • *
  • 1 if error occurred.
*/ /****************************************************************************/ INT NS_DIM_PREFIX DisposeVector (GRID *theGrid, VECTOR *theVector) { INT Size; if (theVector == NULL) return(0); /* now remove vector from vector list */ GRID_UNLINK_VECTOR(theGrid,theVector); /* reset count flags */ SETVCOUNT(theVector,0); /* delete the vector itself */ Size = sizeof(VECTOR); if (PutFreeObject(theGrid->mg,theVector,Size,VEOBJ)) RETURN(1); return(0); } /****************************************************************************/ /** \brief Dispose one of two vectors associated to a face * * @param theGrid - pointer to grid * @param Elem0,side0 - first element and side * @param Elem1,side1 - second element and side After grid refinement it may happen that two side vector are associated to a face in the grid. The elements on both sides of the face each have their own side vector. This is an inconsistent state -- there should be only one vector per face. This routine deletes one of the two side vectors and makes the data structure consistent again. This is easier than only creating one unique side vector to begin with. * @return
    *
  • 0 if ok
  • *
  • 1 if error occurred.
*/ /****************************************************************************/ #ifdef UG_DIM_3 INT NS_DIM_PREFIX DisposeDoubledSideVector (GRID *theGrid, ELEMENT *Elem0, INT Side0, ELEMENT *Elem1, INT Side1) { if (VEC_DEF_IN_OBJ_OF_GRID(theGrid,SIDEVEC)) { assert(NBELEM(Elem0,Side0)==Elem1 && NBELEM(Elem1,Side1)==Elem0); VECTOR *Vector0 = SVECTOR(Elem0,Side0); VECTOR *Vector1 = SVECTOR(Elem1,Side1); if (Vector0 == Vector1) return (0); if ((Vector0==NULL) || (Vector1==NULL)) /* this is the case at boundaries between different parts the part not using vectors in SIDEs will not need a pointer to the side vector */ return (0); assert(VCOUNT(Vector0)==1 && VCOUNT(Vector1)==1); SET_SVECTOR(Elem1,Side1,Vector0); SETVCOUNT(Vector0,2); if (DisposeVector (theGrid,Vector1)) RETURN (1); return (0); } RETURN (1); } #endif /****************************************************************************/ /** \brief Get a pointer list to all side data * @param theElement - that element * @param cnt - how many vectors * @param vList - array to store vector list This function gets a pointer array to all VECTORs in sides of the given element. * @return
    *
  • GM_OK if ok
  • *
  • GM_ERROR if error occurred.
*/ /****************************************************************************/ #ifdef UG_DIM_3 INT NS_DIM_PREFIX GetVectorsOfSides (const ELEMENT *theElement, INT *cnt, VECTOR **vList) { INT i; *cnt = 0; for (i=0; i *
  • 0 if ok *
  • 1 if error occurred. */ /****************************************************************************/ #ifdef UG_DIM_3 INT NS_DIM_PREFIX GetElementInfoFromSideVector (const VECTOR *theVector, ELEMENT **Elements, INT *Sides) { INT i; ELEMENT *theNeighbor; if (VOTYPE(theVector) != SIDEVEC) RETURN (1); Elements[0] = (ELEMENT *)VOBJECT(theVector); Sides[0] = VECTORSIDE(theVector); /* find neighbor */ Elements[1] = theNeighbor = NBELEM(Elements[0],Sides[0]); if (theNeighbor == NULL) return (0); /* search the side */ for (i=0; i 0) { theGrid = GRID_ON_LEVEL(theMG,TOPLEVEL(theMG)); ClearVectorClasses(theGrid); for (theElement=PFIRSTELEMENT(theGrid); theElement!=NULL; theElement=SUCCE(theElement)) { if (MinNodeClass(theElement)==3) SeedVectorClasses(theGrid,theElement); } PropagateVectorClasses(theGrid); theGrid = GRID_ON_LEVEL(theMG,0); ClearNextVectorClasses(theGrid); for (theElement=PFIRSTELEMENT(theGrid); theElement!=NULL; theElement=SUCCE(theElement)) { if (MinNextNodeClass(theElement)==3) SeedNextVectorClasses(theGrid,theElement); } PropagateNextVectorClasses(theGrid); } for (level--; level>0; level--) { theGrid = GRID_ON_LEVEL(theMG,level); ClearVectorClasses(theGrid); ClearNextVectorClasses(theGrid); for (theElement=PFIRSTELEMENT(theGrid); theElement!=NULL; theElement=SUCCE(theElement)) { if (MinNodeClass(theElement)==3) SeedVectorClasses(theGrid,theElement); if (MinNextNodeClass(theElement)==3) SeedNextVectorClasses(theGrid,theElement); } PropagateVectorClasses(theGrid); PropagateNextVectorClasses(theGrid); } fullrefine = TOPLEVEL(theMG); for (level=TOPLEVEL(theMG); level>=0; level--) { theGrid = GRID_ON_LEVEL(theMG,level); for (v=PFIRSTVECTOR(theGrid); v!= NULL; v=SUCCVC(v)) { SETFINE_GRID_DOF(v,((VCLASS(v)>=2)&&(VNCLASS(v)<=1))); if (FINE_GRID_DOF(v)) fullrefine = level; } } #ifdef ModelP fullrefine = UG_GlobalMinINT(theMG->ppifContext(), fullrefine); #endif FULLREFINELEVEL(theMG) = fullrefine; return(0); } /****************************************************************************/ /** \brief Creates the algebra for a grid * @param theGrid - pointer to grid This function allocates VECTORs in all geometrical objects of the grid. * @return
      *
    • GM_OK if ok
    */ /****************************************************************************/ INT NS_DIM_PREFIX CreateAlgebra (MULTIGRID *theMG) { GRID *g = nullptr; #ifdef UG_DIM_3 VECTOR *nbvec; ELEMENT *nbelem; INT j; #endif ELEMENT *elem; INT i; if (MG_COARSE_FIXED(theMG) == false) { for (i=0; i<=TOPLEVEL(theMG); i++) { g = GRID_ON_LEVEL(theMG,i); if (NVEC(g)>0) continue; /* skip this level */ /* loop elements and element sides */ for (elem=PFIRSTELEMENT(g); elem!=NULL; elem=SUCCE(elem)) { /* side vectors */ #ifdef UG_DIM_3 for (INT side=0; sidefacemap.clear(); #ifdef ModelP /* update VNEW-flags */ auto& context = theMG->dddContext(); const auto& dddctrl = ddd_ctrl(context); DDD_IFExchange(context, dddctrl.BorderVectorSymmIF,sizeof(INT), Gather_VectorVNew,Scatter_VectorVNew); DDD_IFOneway(context, dddctrl.VectorIF,IF_FORWARD,sizeof(INT), Gather_VectorVNew,Scatter_GhostVectorVNew); #endif SetSurfaceClasses(theMG); return(GM_OK); } INT NS_DIM_PREFIX PrepareAlgebraModification (MULTIGRID *theMG) { int j,k; ELEMENT *theElement; VECTOR *theVector; j = theMG->topLevel; for (k=0; k<=j; k++) { for (theElement=PFIRSTELEMENT(GRID_ON_LEVEL(theMG,k)); theElement!=NULL; theElement=SUCCE(theElement)) { SETUSED(theElement,0); } for (theVector=PFIRSTVECTOR(GRID_ON_LEVEL(theMG,k)); theVector!= NULL; theVector=SUCCVC(theVector)) { SETVNEW(theVector,0); } } return (0); } /****************************************************************************/ /** \brief Checks validity of geom_object and its vector * @param fmt - FORMAT of associated multigrid * @param theObject - the object which points to theVector * @param ObjectString - for error message * @param theVector - the vector of theObject * @param VectorObjType - NODEVEC,... * @param side - element side for SIDEVEC This function checks the consistency between an geom_object and its vector. * @return
      *
    • GM_OK if ok *
    • GM_ERROR if error occurred.
    */ /****************************************************************************/ #ifdef UG_DIM_3 static INT CheckVector (GEOM_OBJECT *theObject, const char *ObjectString, VECTOR *theVector, INT VectorObjType, INT side) { GEOM_OBJECT *VecObject; INT errors = 0; if (theVector == NULL) { errors++; UserWriteF("%s ID=%ld has NO VECTOR", ObjectString, ID(theObject)); UserWrite("\n"); } else { VecObject = VOBJECT(theVector); if (VecObject == NULL) { errors++; UserWriteF("vector=" VINDEX_FMTX " %s GID=" GID_FMT " has NO BACKPTR\n", VINDEX_PRTX(theVector), ObjectString, (OBJT(theObject)==BEOBJ || OBJT(theObject)==IEOBJ) ? EGID(&(theObject->el)) : (OBJT(theObject)==NDOBJ) ? GID(&(theObject->nd)) : GID(&(theObject->ed)) ); } else { if (VecObject != theObject) { if (OBJT(VecObject) != OBJT(theObject)) { int error = 1; /* both objects may be elements */ if ((OBJT(VecObject)==BEOBJ || OBJT(VecObject)==IEOBJ) && (OBJT(theObject)==BEOBJ || OBJT(theObject)==IEOBJ) ) { ELEMENT *theElement = (ELEMENT *)theObject; ELEMENT *vecElement = (ELEMENT *)VecObject; int i; #ifdef ModelP if (EMASTER(theElement) || EMASTER(vecElement) ) { #endif for (i=0; i ok */ error = 0; break; } #ifdef ModelP } #endif if (error) { UserWriteF("vector=" VINDEX_FMTX " has type %s, but points " "to wrong vecobj=" EID_FMTX " NO NB of obj=" EID_FMTX "\n", VINDEX_PRTX(theVector),ObjectString, EID_PRTX(vecElement),EID_PRTX(theElement)); } } else { errors++; UserWriteF("vector=" VINDEX_FMTX " has type %s, but points " "to wrong obj=%d type OBJT=%d\n", VINDEX_PRTX(theVector),ObjectString,ID(VecObject), OBJT(VecObject)); } } else { #ifdef UG_DIM_3 if (VectorObjType == SIDEVEC) { /* TODO: check side vector */ } else #endif { errors++; UserWriteF("%s vector=" VINDEX_FMTX " is referenced by " "obj0=%x, but points to wrong obj1=%x\n", ObjectString, VINDEX_PRTX(theVector), theObject, VecObject); #ifdef ModelP if (strcmp(ObjectString,"EDGE")==0) UserWriteF("obj0: n0=%d n1=%d obj1: " "n0=%d n1=%d\n", GID(NBNODE(LINK0(&(theObject->ed)))), GID(NBNODE(LINK1(&(theObject->ed)))), GID(NBNODE(LINK0(&(VecObject->ed)))), GID(NBNODE(LINK1(&(VecObject->ed)))) ); #endif } } } } } return(errors); } #endif /****************************************************************************/ /** \brief Check the algebraic part of the data structure * @param theGrid - grid level to check This function checks the consistency of the algebraic data structures including the interconnections between the geometric part. This function assumes a correct geometric data structure. * @return
      *
    • GM_OK if ok
    • *
    • GM_ERROR if error occurred.
    */ /****************************************************************************/ INT NS_DIM_PREFIX CheckAlgebra (GRID *theGrid) { INT errors = 0; if ((GLEVEL(theGrid)==0) && !MG_COARSE_FIXED(MYMG(theGrid))) { if (NVEC(theGrid)>0) { errors++; UserWriteF("coarse grid not fixed but vectors allocated\n"); } return(errors); } /* check pointers to element, side, edge vector */ for (ELEMENT *theElement = PFIRSTELEMENT(theGrid); theElement != nullptr; theElement=SUCCE(theElement)) { #ifdef UG_DIM_3 /* check side vectors */ if (VEC_DEF_IN_OBJ_OF_GRID(theGrid,SIDEVEC)) { for (INT i=0; i *
  • 0 if ok
  • *
  • 1 if error occurred.
  • */ /****************************************************************************/ INT NS_DIM_PREFIX VectorPosition (const VECTOR *theVector, FieldVector& position) { #ifdef UG_DIM_3 ELEMENT *theElement; INT theSide,j; #endif ASSERT(theVector != NULL); switch (VOTYPE(theVector)) { #ifdef UG_DIM_3 case SIDEVEC : theElement = (ELEMENT *)VOBJECT(theVector); theSide = VECTORSIDE(theVector); for (INT i=0; i *
  • 0 if ok
  • *
  • 1 if error occurred.
  • */ /****************************************************************************/ INT NS_DIM_PREFIX SeedVectorClasses (GRID *theGrid, ELEMENT *theElement) { #ifdef UG_DIM_3 INT cnt; VECTOR *vList[20]; if (VEC_DEF_IN_OBJ_OF_GRID(theGrid,SIDEVEC)) { GetVectorsOfSides(theElement,&cnt,vList); for (INT i=0; i *
  • 0 if ok
  • *
  • 1 if error occurred.
  • */ /****************************************************************************/ INT NS_DIM_PREFIX ClearVectorClasses (GRID *theGrid) { VECTOR *theVector; /* reset class of each vector to 0 */ for (theVector=PFIRSTVECTOR(theGrid); theVector!=NULL; theVector=SUCCVC(theVector)) SETVCLASS(theVector,0); return(0); } #ifdef ModelP static int Gather_VectorVClass (DDD::DDDContext&, DDD_OBJ obj, void *data) { VECTOR *theVector = (VECTOR *)obj; PRINTDEBUG(gm,1,("Gather_VectorVClass(): v=" VINDEX_FMTX " vclass=%d\n", VINDEX_PRTX(theVector),VCLASS(theVector))) ((INT *)data)[0] = VCLASS(theVector); return(0); } static int Scatter_VectorVClass (DDD::DDDContext&, DDD_OBJ obj, void *data) { VECTOR *theVector = (VECTOR *)obj; SETVCLASS(theVector,std::max((INT)VCLASS(theVector),((INT *)data)[0])); PRINTDEBUG(gm,2,("Scatter_VectorVClass(): v=" VINDEX_FMTX " vclass=%d\n", VINDEX_PRTX(theVector),VCLASS(theVector))) return(0); } static int Scatter_GhostVectorVClass (DDD::DDDContext&, DDD_OBJ obj, void *data) { VECTOR *theVector = (VECTOR *)obj; SETVCLASS(theVector,((INT *)data)[0]); PRINTDEBUG(gm,1,("Scatter_GhostVectorVClass(): v=" VINDEX_FMTX " vclass=%d\n", VINDEX_PRTX(theVector),VCLASS(theVector))) return(0); } #endif /****************************************************************************/ /** \brief Compute vector classes after initialization * @param theGrid - pointer to grid After vector classes have been reset and initialized, this function now computes the class 2 and class 1 vectors. * @return
      *
    • 0 if ok
    • *
    • 1 if error occurred
    */ /****************************************************************************/ INT NS_DIM_PREFIX PropagateVectorClasses (GRID *theGrid) { #ifdef ModelP auto& context = theGrid->dddContext(); const auto& dddctrl = ddd_ctrl(context); PRINTDEBUG(gm,1,("\nPropagateVectorClasses():" " 1. communication on level %d\n",GLEVEL(theGrid))) /* exchange VCLASS of vectors */ DDD_IFAExchange(context, dddctrl.BorderVectorSymmIF,GRID_ATTR(theGrid),sizeof(INT), Gather_VectorVClass, Scatter_VectorVClass); #endif #ifdef ModelP PRINTDEBUG(gm,1,("\nPropagateVectorClasses(): 2. communication\n")) /* exchange VCLASS of vectors */ DDD_IFAExchange(context, dddctrl.BorderVectorSymmIF,GRID_ATTR(theGrid),sizeof(INT), Gather_VectorVClass, Scatter_VectorVClass); #endif #ifdef ModelP PRINTDEBUG(gm,1,("\nPropagateVectorClasses(): 3. communication\n")) /* exchange VCLASS of vectors */ DDD_IFAExchange(context, dddctrl.BorderVectorSymmIF,GRID_ATTR(theGrid),sizeof(INT), Gather_VectorVClass, Scatter_VectorVClass); #endif #ifdef ModelP /* send VCLASS to ghosts */ DDD_IFAOneway(context, dddctrl.VectorIF,GRID_ATTR(theGrid),IF_FORWARD,sizeof(INT), Gather_VectorVClass, Scatter_GhostVectorVClass); #endif return(0); } /****************************************************************************/ /** \brief Reset class of the vectors on the next level * @param theGrid - pointer to grid This function clears VNCLASS flag in all vectors. This is the first step to compute the class of the dofs on the *NEXT* level, which is also the basis for determining copies. * @return
      *
    • 0 if ok
    • *
    • 1 if error occurred.
    */ /****************************************************************************/ INT NS_DIM_PREFIX ClearNextVectorClasses (GRID *theGrid) { VECTOR *theVector; /* reset class of each vector to 0 */ for (theVector=PFIRSTVECTOR(theGrid); theVector!=NULL; theVector=SUCCVC(theVector)) SETVNCLASS(theVector,0); /* now the refinement algorithm will initialize the class 3 vectors */ /* on the *NEXT* level. */ return(0); } /****************************************************************************/ /** \brief Set VNCLASS in all vectors associated with element * @param theGrid - given grid * @param theElement - pointer to element Set VNCLASS in all vectors associated with the element to 3. * @return
      *
    • 0 if ok
    • *
    • 1 if error occurred.
    */ /****************************************************************************/ INT NS_DIM_PREFIX SeedNextVectorClasses (GRID *theGrid, ELEMENT *theElement) { #ifdef UG_DIM_3 if (VEC_DEF_IN_OBJ_OF_GRID(theGrid,SIDEVEC)) { VECTOR *vList[20]; INT cnt; GetVectorsOfSides(theElement,&cnt,vList); for (INT i=0; i *
  • 0 if ok
  • *
  • 1 if error occurred
  • */ /****************************************************************************/ INT NS_DIM_PREFIX PropagateNextVectorClasses (GRID *theGrid) { #ifdef ModelP auto& context = theGrid->dddContext(); const auto& dddctrl = ddd_ctrl(context); PRINTDEBUG(gm,1,("\nPropagateNextVectorClasses(): 1. communication\n")) /* exchange VNCLASS of vectors */ DDD_IFAExchange(context, dddctrl.BorderVectorSymmIF,GRID_ATTR(theGrid),sizeof(INT), Gather_VectorVNClass, Scatter_VectorVNClass); #endif #ifdef ModelP PRINTDEBUG(gm,1,("\nPropagateNextVectorClasses(): 2. communication\n")) /* exchange VNCLASS of vectors */ DDD_IFAExchange(context, dddctrl.BorderVectorSymmIF,GRID_ATTR(theGrid),sizeof(INT), Gather_VectorVNClass, Scatter_VectorVNClass); #endif #ifdef ModelP PRINTDEBUG(gm,1,("\nPropagateNextVectorClasses(): 3. communication\n")) /* exchange VNCLASS of vectors */ DDD_IFAExchange(context, dddctrl.BorderVectorSymmIF,GRID_ATTR(theGrid),sizeof(INT), Gather_VectorVNClass, Scatter_VectorVNClass); /* send VCLASS to ghosts */ DDD_IFAOneway(context, dddctrl.VectorIF,GRID_ATTR(theGrid),IF_FORWARD,sizeof(INT), Gather_VectorVNClass, Scatter_GhostVectorVNClass); #endif return(0); } /*@}*/ dune-uggrid-2.11.0+dfsg/dune/uggrid/gm/algebra.h000066400000000000000000000122051513616443000213140ustar00rootroot00000000000000// -*- tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- // vi: set et ts=4 sw=2 sts=2: // SPDX-FileCopyrightInfo: Copyright © DUNE Project contributors, see file LICENSE.md in module root // SPDX-License-Identifier: LGPL-2.1-or-later /*! \file algebra.h * \ingroup gm */ /** \addtogroup gm * * @{ */ /****************************************************************************/ /* */ /* File: algebra.h */ /* */ /* Purpose: header for algebraic structures */ /* internal interface for grid manager module */ /* */ /* Author: Klaus Johannsen */ /* Interdisziplinaeres Zentrum fuer Wissenschaftliches Rechnen */ /* Universitaet Heidelberg */ /* Im Neuenheimer Feld 294 */ /* 6900 Heidelberg */ /* internet: ug@ica3.uni-stuttgart.de */ /* */ /* blockvector data structure: */ /* Christian Wrobel */ /* Institut fuer Computeranwendungen III */ /* Universitaet Stuttgart */ /* Pfaffenwaldring 27 */ /* 70569 Stuttgart */ /* email: ug@ica3.uni-stuttgart.de */ /* */ /* History: 1.12.93 begin, ug 3d */ /* 27.09.95 blockvector implemented (Christian Wrobel) */ /* */ /* Remarks: */ /* */ /****************************************************************************/ /****************************************************************************/ /* */ /* auto include mechanism and other include files */ /* */ /****************************************************************************/ #ifndef __ALGEBRA__ #define __ALGEBRA__ #include #include #include "gm.h" START_UGDIM_NAMESPACE /****************************************************************************/ /* */ /* function declarations */ /* */ /****************************************************************************/ /** @name basic create and dispose functions */ /*@{*/ INT CreateSideVector (GRID *theGrid, INT side, GEOM_OBJECT *object, VECTOR **vHandle); INT DisposeVector (GRID *theGrid, VECTOR *theVector); /*@}*/ /** @name More create and dispose */ /*@{*/ #ifdef UG_DIM_3 INT DisposeDoubledSideVector (GRID *theGrid, ELEMENT *Elem0, INT Side0, ELEMENT *Elem1, INT Side1); #endif /*@}*/ /** @name Query functions */ /*@{*/ INT GetVectorsOfSides (const ELEMENT *theElement, INT *cnt, VECTOR **vList); INT GetElementInfoFromSideVector (const VECTOR *theVector, ELEMENT **Elements, INT *Sides); /*@}*/ /** @name Gridwise functions */ /*@{*/ INT SetSurfaceClasses (MULTIGRID *theMG); INT CreateAlgebra (MULTIGRID *theMG); /*@}*/ /** @name Check algebra */ /*@{*/ INT CheckAlgebra (GRID *theGrid); /*@}*/ /** @name Determination of vector classes */ /*@{*/ INT ClearVectorClasses (GRID *theGrid); INT SeedVectorClasses (GRID *theGrid, ELEMENT *theElement); INT PropagateVectorClasses (GRID *theGrid); INT ClearNextVectorClasses (GRID *theGrid); INT SeedNextVectorClasses (GRID *theGrid, ELEMENT *theElement); INT PropagateNextVectorClasses (GRID *theGrid); /*@}*/ /** @name Miscellaneous routines */ /*@{*/ INT PrepareAlgebraModification (MULTIGRID *theMG); /*@}*/ END_UGDIM_NAMESPACE #endif /** @} */ dune-uggrid-2.11.0+dfsg/dune/uggrid/gm/cw.cc000066400000000000000000000543661513616443000205040ustar00rootroot00000000000000// SPDX-FileCopyrightText: Copyright © DUNE Project contributors, see file LICENSE.md in module root // SPDX-License-Identifier: LGPL-2.1-or-later // -*- tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- // vi: set et ts=4 sw=2 sts=2: /****************************************************************************/ /* */ /* File: cw.c */ /* */ /* Purpose: define global array with predefined control word entries */ /* */ /* Author: Peter Bastian */ /* Interdisziplinaeres Zentrum fuer Wissenschaftliches Rechnen */ /* Universitaet Heidelberg */ /* Im Neuenheimer Feld 368 */ /* 6900 Heidelberg */ /* Internet: bastian@iwr1.iwr.uni-heidelberg.de */ /* */ /* History: 11.01.95 begin, ug version 3.0 */ /* */ /* Remarks: */ /* */ /****************************************************************************/ #include #include #include /* define this to exclude extern definition of global arrays */ #define __COMPILE_CW__ #include #include #include #include #include "algebra.h" #include "refine.h" #include "cw.h" USING_UG_NAMESPACE USING_UGDIM_NAMESPACE using namespace PPIF; /****************************************************************************/ /* */ /* defines in the following order */ /* */ /* compile time constants defining static data size (i.e. arrays) */ /* other constants */ /* macros */ /* */ /****************************************************************************/ #define CW_EDOBJ (BITWISE_TYPE(EDOBJ) | BITWISE_TYPE(LIOBJ)) /* take both edges and links in one */ #define CW_GROBJ BITWISE_TYPE(GROBJ) #define CW_MGOBJ BITWISE_TYPE(MGOBJ) #define CW_NDOBJ BITWISE_TYPE(NDOBJ) #define CW_VEOBJ BITWISE_TYPE(VEOBJ) #define CW_VXOBJS (BITWISE_TYPE(IVOBJ) | BITWISE_TYPE(BVOBJ)) #define CW_ELOBJS (BITWISE_TYPE(IEOBJ) | BITWISE_TYPE(BEOBJ)) #define CW_GEOMOBJS (CW_VXOBJS | CW_ELOBJS | CW_NDOBJ | CW_EDOBJ | CW_GROBJ) /* NOTE: CW_GEOMOBJS and GEOM_OBJECTS differ*/ /** @name Status of control entry */ /*@{*/ #define CE_USED 1 #define CE_LOCKED 1 /*@}*/ /** @name Initializer macros for control entry and word predefines */ /*@{*/ #define CE_INIT(mode,cw,ce,objs) {mode, STR(ce), cw ## CW, ce ## CE, ce ## SHIFT, ce ## LEN, objs} /*@}*/ /****************************************************************************/ /* */ /* data structures used in this source file (exported data structures are */ /* in the corresponding include file!) */ /* */ /****************************************************************************/ /** \brief Description of a control word */ typedef struct { /** \brief where in object is it ? */ UINT offset_in_object; /** \brief bitwise object ID */ INT objt_used; /** \brief used bits */ UINT used_mask; } CONTROL_WORD; /** \brief Description of a control word predefines */ typedef struct { INT control_word_id; /**< Index in control_words */ UINT offset_in_object ; /**< Where in object is it ? */ INT objt_used; /**< Bitwise object ID */ } CONTROL_WORD_PREDEF; /** \brief Description of a control entry predefines */ typedef struct { INT used; /**< Used this entry */ const char *name; /**< Name string */ INT control_word; /**< Index of corresp. controlword */ INT control_entry_id; /**< Index in control_entries */ INT offset_in_word; /**< Shift in control word */ INT length; /**< Number of bits used */ INT objt_used; /**< Bitwise object ID */ } CONTROL_ENTRY_PREDEF; /****************************************************************************/ /* */ /* definition of exported global variables */ /* */ /****************************************************************************/ CONTROL_ENTRY NS_DIM_PREFIX control_entries[MAX_CONTROL_ENTRIES]; /****************************************************************************/ /* */ /* definition of variables global to this source file only (static!) */ /* */ /****************************************************************************/ // The order of the entries here has to match the GM_CW enumeration in gm.h constexpr INT MAX_CONTROL_WORDS = GM_N_CW; static CONTROL_WORD control_words[MAX_CONTROL_WORDS] = { {VECTOR_OFFSET, CW_VEOBJ, 0b0}, {VERTEX_OFFSET, CW_VXOBJS, 0b0}, {NODE_OFFSET, CW_NDOBJ, 0b0}, {LINK_OFFSET, CW_EDOBJ, 0b0}, {EDGE_OFFSET, CW_EDOBJ, 0b0}, {ELEMENT_OFFSET, CW_ELOBJS, 0b0}, {FLAG_OFFSET, CW_ELOBJS, 0b0}, {PROPERTY_OFFSET, CW_ELOBJS, 0b0}, {GRID_OFFSET, CW_GROBJ, 0b0}, {GRID_STATUS_OFFSET, CW_GROBJ, 0b0}, {MULTIGRID_STATUS_OFFSET, CW_MGOBJ, 0b0} }; static CONTROL_ENTRY_PREDEF ce_predefines[MAX_CONTROL_ENTRIES] = { CE_INIT(CE_LOCKED, VECTOR_, VOTYPE_, CW_VEOBJ), CE_INIT(CE_LOCKED, VECTOR_, VCOUNT_, CW_VEOBJ), CE_INIT(CE_LOCKED, VECTOR_, VECTORSIDE_, CW_VEOBJ), CE_INIT(CE_LOCKED, VECTOR_, VCLASS_, CW_VEOBJ), CE_INIT(CE_LOCKED, VECTOR_, VDATATYPE_, CW_VEOBJ), CE_INIT(CE_LOCKED, VECTOR_, VNCLASS_, CW_VEOBJ), CE_INIT(CE_LOCKED, VECTOR_, VNEW_, CW_VEOBJ), CE_INIT(CE_LOCKED, VECTOR_, VCCUT_, CW_VEOBJ), CE_INIT(CE_LOCKED, VECTOR_, FINE_GRID_DOF_, CW_VEOBJ), CE_INIT(CE_LOCKED, GENERAL_, OBJ_, (CW_GEOMOBJS | CW_VEOBJ)), CE_INIT(CE_LOCKED, GENERAL_, USED_, (CW_GEOMOBJS | CW_VEOBJ)), CE_INIT(CE_LOCKED, GENERAL_, THEFLAG_, (CW_GEOMOBJS | CW_VEOBJ)), CE_INIT(CE_LOCKED, GENERAL_, LEVEL_, CW_GEOMOBJS), CE_INIT(CE_LOCKED, VERTEX_, MOVE_, CW_VXOBJS), CE_INIT(CE_LOCKED, VERTEX_, MOVED_, CW_VXOBJS), CE_INIT(CE_LOCKED, VERTEX_, ONEDGE_, CW_VXOBJS), CE_INIT(CE_LOCKED, VERTEX_, ONSIDE_, CW_VXOBJS), CE_INIT(CE_LOCKED, VERTEX_, ONNBSIDE_, CW_VXOBJS), CE_INIT(CE_LOCKED, VERTEX_, NOOFNODE_, CW_VXOBJS), CE_INIT(CE_LOCKED, NODE_, NSUBDOM_, CW_NDOBJ), CE_INIT(CE_LOCKED, NODE_, NPROP_, CW_NDOBJ), CE_INIT(CE_LOCKED, NODE_, NCLASS_, CW_NDOBJ), CE_INIT(CE_LOCKED, NODE_, NNCLASS_, CW_NDOBJ), CE_INIT(CE_LOCKED, NODE_, MODIFIED_, (CW_NDOBJ | CW_GROBJ)), CE_INIT(CE_LOCKED, NODE_, NTYPE_, CW_NDOBJ), CE_INIT(CE_USED, LINK_, LOFFSET_, CW_EDOBJ), CE_INIT(CE_USED, EDGE_, AUXEDGE_, CW_EDOBJ), CE_INIT(CE_USED, EDGE_, PATTERN_, CW_EDOBJ), CE_INIT(CE_USED, EDGE_, ADDPATTERN_, CW_EDOBJ), CE_INIT(CE_USED, EDGE_, EDGENEW_, CW_EDOBJ), CE_INIT(CE_USED, EDGE_, EDSUBDOM_, CW_EDOBJ), CE_INIT(CE_USED, EDGE_, NO_OF_ELEM_, CW_EDOBJ), CE_INIT(CE_USED, ELEMENT_, REFINE_, CW_ELOBJS), CE_INIT(CE_USED, ELEMENT_, ECLASS_, CW_ELOBJS), CE_INIT(CE_USED, ELEMENT_, NSONS_, CW_ELOBJS), CE_INIT(CE_USED, ELEMENT_, REFINECLASS_, CW_ELOBJS), CE_INIT(CE_USED, ELEMENT_, NEWEL_, CW_ELOBJS), CE_INIT(CE_USED, ELEMENT_, TAG_, CW_ELOBJS), CE_INIT(CE_USED, FLAG_, MARK_, CW_ELOBJS), CE_INIT(CE_USED, FLAG_, COARSEN_, CW_ELOBJS), CE_INIT(CE_USED, FLAG_, DECOUPLED_, CW_ELOBJS), CE_INIT(CE_USED, FLAG_, UPDATE_GREEN_, CW_ELOBJS), CE_INIT(CE_USED, FLAG_, SIDEPATTERN_, CW_ELOBJS), CE_INIT(CE_USED, FLAG_, MARKCLASS_, CW_ELOBJS), CE_INIT(CE_USED, PROPERTY_, SUBDOMAIN_, CW_ELOBJS), CE_INIT(CE_USED, PROPERTY_, NODEORD_, CW_ELOBJS), CE_INIT(CE_USED, PROPERTY_, PROP_, CW_ELOBJS), #ifdef ModelP CE_INIT(CE_USED, VECTOR_, XFERVECTOR_, CW_VEOBJ), #endif /* ModelP */ }; /****************************************************************************/ /** \brief Initialize control word entries This function initializes the predefined control word entries. Predefined entries are not checked for overlap. * @return
      *
    • GM_OK if ok
    • *
    • GM_ERROR if error occurred
    • *
    */ /****************************************************************************/ static INT InitPredefinedControlEntries (void) { CONTROL_ENTRY *ce,*test_ce; CONTROL_WORD *cw; CONTROL_ENTRY_PREDEF *pce,*test_pce; INT i,j,k,mask,error,nused; /* clear everything */ memset(control_entries,0,MAX_CONTROL_ENTRIES*sizeof(CONTROL_ENTRY)); error = 0; nused = 0; for (i=0; icontrol_entry_idcontrol_entry_id; if (ce->used) { printf("redefinition of control entry '%s'\n",pce->name); return(__LINE__); } cw = control_words+pce->control_word; ce->used = pce->used; ce->name = pce->name; ce->control_word = pce->control_word; ce->offset_in_word = pce->offset_in_word; ce->length = pce->length; ce->objt_used = pce->objt_used; ce->offset_in_object = cw->offset_in_object; ce->mask = (POW2(ce->length)-1)<offset_in_word; ce->xor_mask = ~ce->mask; PRINTDEBUG(gm,1,("ceID %d used %d name %s cw %d\n", i,ce->used,ce->name,ce->control_word)); ASSERT(ce->objt_used & cw->objt_used); /* ce and cw have! common objects */ /* set mask in all cws that use some of the ces objects and have the same offset than cw */ const UINT offset = ce->offset_in_object; mask = ce->mask; for (k=0; kobjt_used & cw->objt_used)) continue; if (cw->offset_in_object!=offset) continue; /* do other control entries overlap? */ if (cw->used_mask & mask) { IFDEBUG(gm,1) printf("predef ctrl entry '%s' has overlapping bits with previous ctrl entries:\n",pce->name); for (j=0; jcontrol_entry_id; if (test_ce->objt_used & ce->objt_used) if (test_ce->offset_in_object==offset) if (test_ce->mask & mask) printf(" '%s'",test_pce->name); } printf("\n"); ENDDEBUG error++; } cw->used_mask |= mask; } } /* TODO: enable next lines for error control */ IFDEBUG(gm,1) if (error) return (__LINE__); ENDDEBUG if (nused!=REFINE_N_CE) { printf("InitPredefinedControlEntries: nused=%d != REFINE_N_CE=%d\n",nused,REFINE_N_CE); assert(false); } return (GM_OK); } /****************************************************************************/ /** \brief Function to replace CW_READ macro and does extended error checks * @param obj - object pointer * @param ceID - control entry ID This function is to replace the CW_READ and CW_READ_STATIC macros of gm.h and does extended error checks:~
    • obj != NULL
    • HEAPFAULT
    • ceID in valid range
    • control entry used
    • the object type is checked (with the natural exception of the first SETOBJ access)
    Additionally the read accesses to a control entry are counted. CAUTION: set #define _DEBUG_CW_ to replace CW_READ by ReadCW but be aware of the slowing down of the program in this case (no large problems!). @return Number read from the control entry of the object */ /****************************************************************************/ UINT NS_DIM_PREFIX ReadCW (const void *obj, INT ceID) { UINT off_in_obj,mask,i,off_in_wrd,cw,cw_objt; ASSERT(obj!=NULL); if ((ceID<0) || (ceID>=MAX_CONTROL_ENTRIES)) { printf("ReadCW: ceID=%d out of range\n",ceID); assert(false); } const CONTROL_ENTRY *ce = control_entries + ceID; if (!ce->used) { printf("ReadCW: ceID=%d unused\n",ceID); assert(false); } cw_objt = BITWISE_TYPE(OBJT(obj)); if (!(cw_objt & ce->objt_used)) { if (ce->name!=NULL) printf("ReadCW: invalid objt %d for ce %s\n",OBJT(obj),ce->name); else printf("ReadCW: invalid objt %d for ce %d\n",OBJT(obj),ceID); assert(false); } off_in_wrd = ce->offset_in_word; off_in_obj = ce->offset_in_object; mask = ce->mask; cw = ((UINT *)(obj))[off_in_obj]; i = cw & mask; i = i>>off_in_wrd; return (i); } /****************************************************************************/ /** \brief Function to replace CW_WRITE macro and does extended error checks * @param obj - object pointer * @param ceID - control entry ID * @param n - number to write to the objects control entry This function is to replace the CW_WRITE and CW_WRITE_STATIC macros of gm.h and does extended error checks:~
    • obj != NULL
    • HEAPFAULT
    • ceID in valid range
    • control entry used
    • the object type is checked
    • n small enough for length of control entry
    Additionally the write accesses to a control entry are counted. CAUTION: set #define _DEBUG_CW_ to replace CW_WRITE by WriteCW but be aware of the slowing down of the program in this case (no large problems!). @return Number read from the control entry of the object */ /****************************************************************************/ void NS_DIM_PREFIX WriteCW (void *obj, INT ceID, INT n) { UINT off_in_obj,mask,i,j,off_in_wrd,xmsk; UINT *pcw; ASSERT(obj!=NULL); if ((ceID<0) || (ceID>=MAX_CONTROL_ENTRIES)) { printf("WriteCW: ceID=%d out of range\n",ceID); assert(false); } const CONTROL_ENTRY *ce = control_entries + ceID; if (!ce->used) { printf("WriteCW: ceID=%d unused\n",ceID); assert(false); } const UINT cw_objt = BITWISE_TYPE(OBJT(obj)); /* special: SETOBJT cannot be checked since at this point the OBJT is unknown of course */ if (cw_objt==BITWISE_TYPE(0)) { if (ceID!=OBJ_CE) if (cw_objt != ce->objt_used) { if (ce->name!=NULL) printf("WriteCW: objt 0 but %s rather than expected SETOBJT access\n",ce->name); else printf("WriteCW: objt 0 but %d rather than expected SETOBJT access\n",ceID); assert(false); } } else if (!(cw_objt & ce->objt_used)) { if (ce->name!=NULL) printf("WriteCW: invalid objt %d for ce %s\n",OBJT(obj),ce->name); else printf("WriteCW: invalid objt %d for ce %d\n",OBJT(obj),ceID); assert(false); } off_in_wrd = ce->offset_in_word; off_in_obj = ce->offset_in_object; mask = ce->mask; xmsk = ce->xor_mask; pcw = ((UINT *)(obj)) + off_in_obj; i = (*pcw) & xmsk; j = n<mask) { if (ce->name!=NULL) printf("WriteCW: value=%d exceeds max=%d for %s\n", n,POW2(ce->length)-1,ce->name); else printf("WriteCW: value=%d exceeds max=%d for %d\n", n,POW2(ce->length)-1,ceID); assert(false); } j = j & mask; *pcw = i | j; } /****************************************************************************/ /** \brief Allocates space in object control words * @param cw_id - id of a control word * @param length - number of bits to allocate * @param ce_id - returns identifier of control entry descriptor This function allocates 'length' consecutive bits in the control word of an object identified through the `control word id` 'cw_id'. It returns '0' and a valid id in 'ce_id' if space was available. The 'ce_id' can be used to read and write the requested bits with the 'CW_READ' and 'CW_WRITE' macros as in the following example. The control word ids of all UG objects are defined in 'gm.h' and usually have the name ``'_CW', except e.g. the 'ELEMENT' which has three words that are used bitwise. EXAMPLE: The following code fragment allocates 'NORDER_LEN' bits in the 'flag' word of the 'ELEMENT' structure. \verbatim INT ce_NORDER; if (AllocateControlEntry(FLAG_CW,NORDER_LEN,&ce_NORDER) != GM_OK) return (1); \endverbatim The following macros then read and write the requested bits \verbatim *#define NORDER(p) CW_READ(p,ce_NORDER) *#define SETNORDER(p,n) CW_WRITE(p,ce_NORDER,n) \endverbatim @return
  • GM_OK if ok
  • GM_ERROR if error occurred.
  • */ /****************************************************************************/ INT NS_DIM_PREFIX AllocateControlEntry (INT cw_id, INT length, INT *ce_id) { INT free, i, offset; CONTROL_ENTRY *ce; CONTROL_WORD *cw; UINT mask; /* check input */ if ((length<0)||(length>=32)) return(GM_ERROR); if ((cw_id<0)||(cw_id>=MAX_CONTROL_WORDS)) return(GM_ERROR); /* it is sufficient to check only the control entries control word multiple object types are only allowed for predefines */ cw = control_words+cw_id; /* find unused entry */ for (i=0; iused_mask)==0) break; mask <<= 1; } if (i>32-length) return(GM_ERROR); offset = i; /* fill new entry */ *ce_id = free; ce->used = 1; ce->control_word = cw_id; ce->offset_in_object = cw->offset_in_object; ce->offset_in_word = offset; ce->length = length; ce->mask = mask; ce->xor_mask = ~mask; ce->name = NULL; ce->objt_used = cw->objt_used; /* remember used bits */ cw->used_mask |= mask; /* ok, exit */ return(GM_OK); } /****************************************************************************/ /** \brief Frees space in object control words * @param ce_id - control entry descriptor to free This function frees space in object control words that has been allocated with 'AllocateControlEntry'. @return
    • GM_OK if ok
    • GM_ERROR if error occurred.
    */ /****************************************************************************/ INT NS_DIM_PREFIX FreeControlEntry (INT ce_id) { CONTROL_ENTRY *ce; CONTROL_WORD *cw; /* check parameter */ if ((ce_id<0)||(ce_id>=MAX_CONTROL_ENTRIES)) return(GM_ERROR); ce = control_entries+ce_id; cw = control_words+ce->control_word; /* check if locked */ if (ce->used == 2) return(GM_ERROR); /* free used bits */ cw->used_mask &= ce->xor_mask; /* free control entry */ ce->used = 0; /* ok, exit */ return(GM_OK); } /****************************************************************************/ /** \brief Init cw.c file This function initializes the control word manager. @return
    • GM_OK if ok
    • > 0 line in which error occurred.
    */ /****************************************************************************/ INT NS_DIM_PREFIX InitCW (void) { if (InitPredefinedControlEntries()) return (__LINE__); return (GM_OK); } dune-uggrid-2.11.0+dfsg/dune/uggrid/gm/cw.h000066400000000000000000000067371513616443000203450ustar00rootroot00000000000000// -*- tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- // vi: set et ts=4 sw=2 sts=2: // SPDX-FileCopyrightInfo: Copyright © DUNE Project contributors, see file LICENSE.md in module root // SPDX-License-Identifier: LGPL-2.1-or-later /****************************************************************************/ /* */ /* File: cw.h */ /* */ /* Purpose: control word definitions header file */ /* */ /* Author: Peter Bastian */ /* Institut fuer Computeranwendungen III */ /* Universitaet Stuttgart */ /* Pfaffenwaldring 27 */ /* 70569 Stuttgart */ /* email: ug@ica3.uni-stuttgart.de */ /* */ /* History: 11.01.95 begin, ug version 3.0 */ /* */ /* Remarks: */ /* */ /****************************************************************************/ /****************************************************************************/ /* */ /* auto include mechanism and other include files */ /* */ /****************************************************************************/ #ifndef __CW__ #define __CW__ #include START_UGDIM_NAMESPACE /** @name Macros for the control word management */ /*@{*/ /** \brief max number of entries */ #define MAX_CONTROL_ENTRIES 100 /*@}*/ /** \brief Manage part of a control word */ typedef struct { /** \brief this struct is used */ INT used; /** \brief name string */ const char *name; /** \brief pointer to corresponding control word */ INT control_word; /** \brief shift in control word */ INT offset_in_word; /** \brief number of bits used */ INT length; /** \brief bitwise object ID */ INT objt_used; /** \brief copy from control word (faster) */ UINT offset_in_object; /** \brief 1 where bits are used */ UINT mask; /** \brief 0 where bits are used */ UINT xor_mask; } CONTROL_ENTRY; /** \brief Predefined control words */ extern CONTROL_ENTRY control_entries[MAX_CONTROL_ENTRIES]; /****************************************************************************/ /* */ /* function definitions */ /* */ /****************************************************************************/ INT InitCW (void); END_UGDIM_NAMESPACE #endif dune-uggrid-2.11.0+dfsg/dune/uggrid/gm/dlmgr.cc000066400000000000000000000067601513616443000211730ustar00rootroot00000000000000// SPDX-FileCopyrightText: Copyright © DUNE Project contributors, see file LICENSE.md in module root // SPDX-License-Identifier: LGPL-2.1-or-later // -*- tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- // vi: set et ts=4 sw=2 sts=2: /****************************************************************************/ /* */ /* File: dlmgr.c */ /* */ /* Purpose: functions for dynamic linked list management */ /* */ /* Author: Stefan Lang */ /* Institut fuer Computeranwendungen III */ /* Universitaet Stuttgart */ /* Pfaffenwaldring 27 */ /* 70550 Stuttgart */ /* email: stefan@ica3.uni-stuttgart.de */ /* phone: 0049-(0)711-685-7003 */ /* fax : 0049-(0)711-685-7000 */ /* */ /* History: 961216 sl start of dynamic list management */ /* */ /* Remarks: */ /* Management of dynamic linked lists, which consist of */ /* several parts. An object can be mapped to a part of the list */ /* by its priority using PRIO2LISTPART(). */ /* The formulation on object basis allows for management of */ /* elements, nodes, vectors and vertices. */ /* A list has the form: */ /* p0first-p0last->p1first-p1last->...->pnfirst..pnlast */ /* where each part p0,p1,..,pn is limited by two pointers, */ /* pxfirst and pxlast, x=0..n. The part numbers are ordered */ /* increasingly and connected in a manner that one can run */ /* through the whole list in increasing order (SUCC) but only */ /* through one listpart in decreasing order (PRED). */ /* Linking/Unlinking of objects in a list part is done in a */ /* way that preserves these conventions. */ /* */ /****************************************************************************/ #include #include #include "dlmgr.h" #include "gm.h" #include "refine.h" #ifdef ModelP #include #endif USING_UG_NAMESPACES using namespace PPIF; /* element */ #define OTYPE ELEMENT #define PRED PREDE #define SUCC SUCCE #include "dlmgr.t" /* node */ #define OTYPE NODE #define PRED PREDN #define SUCC SUCCN #include "dlmgr.t" /* vertex */ #define OTYPE VERTEX #define PRED PREDV #define SUCC SUCCV #include "dlmgr.t" /* vector */ #define OTYPE VECTOR #define PRED PREDVC #define SUCC SUCCVC #include "dlmgr.t" #undef OTYPE #undef PRED #undef SUCC dune-uggrid-2.11.0+dfsg/dune/uggrid/gm/dlmgr.h000066400000000000000000000115321513616443000210260ustar00rootroot00000000000000// -*- tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- // vi: set et ts=4 sw=2 sts=2: // SPDX-FileCopyrightInfo: Copyright © DUNE Project contributors, see file LICENSE.md in module root // SPDX-License-Identifier: LGPL-2.1-or-later /*! \file dlmgr.h * \ingroup gm */ /****************************************************************************/ /* */ /* File: dlmgr.h */ /* */ /* Purpose: defines for dynamic linked list management */ /* */ /* Author: Stefan Lang */ /* Institut fuer Computeranwendungen III */ /* Universitaet Stuttgart */ /* Pfaffenwaldring 27 */ /* 70550 Stuttgart */ /* email: ug@ica3.uni-stuttgart.de */ /* */ /* History: 960915 sl start of dynamic list management */ /* */ /* Remarks: */ /* Management of dynamic linked lists, which consist of */ /* several parts. An object can be mapped to a part of the list */ /* by its priority using PRIO2LISTPART(). */ /* The formulation on object basis allows for management of */ /* elements, nodes, vectors and vertices. */ /* A list has the form: */ /* p0first-p0last->p1first-p1last->...->pnfirst..pnlast */ /* where each part p0,p1,..,pn is limited by two pointers, */ /* pxfirst and pxlast, x=0..n. The part numbers are ordered */ /* increasingly and connected in a manner that one can run */ /* through the whole list in increasing order (SUCC) but only */ /* through one listpart in decreasing order (PRED). */ /* Linking/Unlinking of objects in a list part is done in a */ /* way that preserves these conventions. */ /* */ /****************************************************************************/ #ifndef __DLMGR_H__ #include "gm.h" #include #include #include #ifdef ModelP #include #endif START_UGDIM_NAMESPACE #ifdef ModelP #define FIRSTPART_OF_LIST 0 #define LASTPART_OF_LIST(OTYPE) ((CAT(OTYPE,_LISTPARTS)) -1) /* define DDD_HDR macros */ #define HDRELEMENT PARHDRE #define HDRNODE PARHDR #define HDRVERTEX PARHDRV #define HDRVECTOR PARHDR #define HDR(OTYPE) CAT(HDR,OTYPE) /* define macros for formatted output */ #define ELEMENTFMT EID_ #define NODEFMT ID_ #define VERTEXFMT VID_ #define VECTORFMT VINDEX_ #define FORMAT(t) CAT(t,FMT) #endif /* define Object COUNTER macros */ #define COUNTELEMENT NT #define COUNTNODE NN #define COUNTVERTEX NV #define COUNTVECTOR NVEC /* define Object COUNTER macros for priorities */ #define PRIOCOUNTELEMENT NT_PRIO #define PRIOCOUNTNODE NN_PRIO #define PRIOCOUNTVERTEX NV_PRIO #define PRIOCOUNTVECTOR NVEC_PRIO /* define header prototypes */ #define UNLINK(OTYPE) void CAT(GRID_UNLINK_, OTYPE ) (GRID *Grid, OTYPE *Object) #define LINK(OTYPE) void CAT(GRID_LINK_,OTYPE) (GRID *Grid, OTYPE *Object, INT Prio) #define LINKX(OTYPE) void CAT(GRID_LINKX_,OTYPE) (GRID *Grid, OTYPE *Object, INT Prio, OTYPE *After) #define INIT(OTYPE) void CAT3(GRID_INIT_,OTYPE,_LIST(GRID *Grid)) #define CHECK(OTYPE) void CAT3(GRID_CHECK_,OTYPE,_LIST(GRID *Grid)) #ifdef ModelP #define PRINT_LIST(OTYPE) void CAT(PRINT_LIST_STARTS_,OTYPE) (GRID *Grid, INT prios) #endif LINK(ELEMENT); LINKX(ELEMENT); UNLINK(ELEMENT); INIT(ELEMENT); CHECK(ELEMENT); LINK(NODE); LINKX(NODE); UNLINK(NODE); INIT(NODE); CHECK(NODE); LINK(VERTEX); LINKX(VERTEX); UNLINK(VERTEX); INIT(VERTEX); CHECK(VERTEX); LINK(VECTOR); LINKX(VECTOR); UNLINK(VECTOR); INIT(VECTOR); CHECK(VECTOR); #ifdef ModelP PRINT_LIST(ELEMENT); PRINT_LIST(NODE); PRINT_LIST(VERTEX); PRINT_LIST(VECTOR); #endif END_UGDIM_NAMESPACE #endif /* __DLMGR_H__ */ dune-uggrid-2.11.0+dfsg/dune/uggrid/gm/dlmgr.t000066400000000000000000000427141513616443000210500ustar00rootroot00000000000000// SPDX-FileCopyrightText: Copyright © DUNE Project contributors, see file LICENSE.md in module root // SPDX-License-Identifier: LGPL-2.1-or-later /****************************************************************************/ /* */ /* File: dlmgr.t */ /* */ /* Purpose: templates for dynamic linked list management */ /* */ /* Author: Stefan Lang */ /* Institut fuer Computeranwendungen III */ /* Universitaet Stuttgart */ /* Pfaffenwaldring 27 */ /* 70550 Stuttgart */ /* email: stefan@ica3.uni-stuttgart.de */ /* phone: 0049-(0)711-685-7003 */ /* fax : 0049-(0)711-685-7000 */ /* */ /* History: 960915 sl start of dynamic list management */ /* */ /* Remarks: */ /* Management of dynamic linked lists, which consist of */ /* several parts. An object can be mapped to a part of the list */ /* by its priority using PRIO2LISTPART(). */ /* The formulation on object basis allows for management of */ /* elements, nodes, vectors and vertices. */ /* A list has the form: */ /* p0first-p0last->p1first-p1last->...->pnfirst..pnlast */ /* where each part p0,p1,..,pn is limited by two pointers, */ /* pxfirst and pxlast, x=0..n. The part numbers are ordered */ /* increasingly and connected in a manner that one can run */ /* through the whole list in increasing order (SUCC) but only */ /* through one listpart in decreasing order (PRED). */ /* Linking/Unlinking of objects in a list part is done in a */ /* way that preserves these conventions. */ /* */ /****************************************************************************/ START_UGDIM_NAMESPACE #ifdef ModelP UNLINK(OTYPE) { INT Prio = DDD_InfoPriority( HDR(OTYPE)((Object)) ); INT listpart = PRIO2LISTPART( CAT(OTYPE,_LIST) ,Prio); INT listpart1 = listpart; OTYPE *Object1 = NULL; IFDEBUG(gm,2) printf("GRID_UNLINK_" STR(OTYPE) "():" STR(OTYPE) " has listpart=%d for prio=%d\n",listpart,Prio); fflush(stdout); ENDDEBUG if (listpart<0 || listpart>LASTPART_OF_LIST(OTYPE)) { printf(" GRID_UNLINK_" STR(OTYPE) "(): ERROR " STR(OTYPE) " has no valid listpart=%d for prio=%d\n",listpart,Prio); fflush(stdout); ASSERT(0); } IFDEBUG(gm,4) { INT n = 0; printf(" GRID_UNLINK_" STR(OTYPE) "_LIST before is:\n"); for (Object1 = CAT(PFIRST,OTYPE(Grid)); Object1 != NULL; Object1 = SUCC(Object1)) { n++; printf(" nob=%d o=" CAT(FORMAT(OTYPE),FMTX) "\n", n,CAT(FORMAT(OTYPE),PRTX(Object1))); } CAT(PRINT_LIST_STARTS_,OTYPE)(Grid,CAT(OTYPE,_LISTPARTS)); } ENDDEBUG switch (listpart) { case FIRSTPART_OF_LIST: if (PRED(Object)!=NULL) SUCC(PRED(Object)) = SUCC(Object); if (CAT(LISTPART_LAST,OTYPE(Grid,listpart)) != Object) { if (CAT(LISTPART_FIRST,OTYPE(Grid,listpart)) == Object) CAT(LISTPART_FIRST,OTYPE(Grid,listpart)) = SUCC(Object); if (SUCC(Object)!=NULL) PRED(SUCC(Object)) = PRED(Object); } else { if (CAT(LISTPART_FIRST,OTYPE(Grid,listpart)) == Object) CAT(LISTPART_FIRST,OTYPE(Grid,listpart)) = NULL; CAT(LISTPART_LAST,OTYPE(Grid,listpart)) = PRED(Object); } break; case LASTPART_OF_LIST(OTYPE): if (PRED(Object)!=NULL) SUCC(PRED(Object)) = SUCC(Object); else { CAT(LISTPART_FIRST,OTYPE(Grid,LASTPART_OF_LIST(OTYPE))) = SUCC(Object); do { listpart1--; Object1 = CAT(LISTPART_LAST,OTYPE(Grid,listpart1)); } while (listpart1>FIRSTPART_OF_LIST && Object1==NULL); if (Object1!=NULL) SUCC(Object1) = SUCC(Object); } if (SUCC(Object)!=NULL) PRED(SUCC(Object)) = PRED(Object); else { CAT(LISTPART_LAST,OTYPE(Grid,LASTPART_OF_LIST(OTYPE))) = PRED(Object); if (PRED(Object) != NULL) SUCC(PRED(Object)) = NULL; } break; default: /* unlink in middle of list */ if (PRED(Object)!=NULL) SUCC(PRED(Object)) = SUCC(Object); else { if (SUCC(Object)!=NULL) PRED(SUCC(Object)) = NULL; do { listpart1--; Object1 = CAT(LISTPART_LAST,OTYPE(Grid,listpart1)); } while (listpart1>FIRSTPART_OF_LIST && Object1==NULL); if (Object1!=NULL) SUCC(Object1) = SUCC(Object); } if (CAT(LISTPART_LAST,OTYPE(Grid,listpart)) != Object) { if (CAT(LISTPART_FIRST,OTYPE(Grid,listpart)) == Object) CAT(LISTPART_FIRST,OTYPE(Grid,listpart)) = SUCC(Object); if (SUCC(Object)!=NULL) PRED(SUCC(Object)) = PRED(Object); } else { if (CAT(LISTPART_FIRST,OTYPE(Grid,listpart)) == Object) CAT(LISTPART_FIRST,OTYPE(Grid,listpart)) = NULL; CAT(LISTPART_LAST,OTYPE(Grid,listpart)) = PRED(Object); } break; } SUCC(Object) = PRED(Object) = NULL; /* decrement counter */ CAT(COUNT,OTYPE(Grid))--; ASSERT(CAT(COUNT,OTYPE(Grid))>=0); /* decrement counter for priority */ CAT(PRIOCOUNT,OTYPE(Grid,Prio))--; ASSERT(CAT(PRIOCOUNT,OTYPE(Grid,Prio))>=0); ASSERT(Prio>0); IFDEBUG(gm,4) /* debug loop in list */ { INT n = 0; printf(" GRID_UNLINK_" STR(OTYPE) "_LIST after is:\n"); for (Object1 = CAT(PFIRST,OTYPE(Grid)); Object1 != NULL; Object1 = SUCC(Object1)) { n++; printf(" nob=%d o=" CAT(FORMAT(OTYPE),FMTX) "\n", n,CAT(FORMAT(OTYPE),PRTX(Object1))); if (n>10000) { printf("GRID_UNLINK_" STR(OTYPE) "(): LOOPERROR " STR(OTYPE) " has listpart=%d for prio=%d\n",listpart,Prio); fflush(stdout); assert(0); } } CAT(PRINT_LIST_STARTS_,OTYPE)(Grid,CAT(OTYPE,_LISTPARTS)); /* object number error detection */ if (n != CAT(COUNT,OTYPE(Grid))) { printf(" Object=" CAT(FORMAT(OTYPE),FMTX) "\n", CAT(FORMAT(OTYPE),PRTX(Object))); printf("GRID_UNLINK_" STR(OTYPE) "(): COUNTERERROR " STR(OTYPE) " has listpart=%d for prio=%d n=%d count=%d\n", listpart,Prio,n,CAT(COUNT,OTYPE(Grid))); fflush(stdout); assert(0); } } ENDDEBUG } #else UNLINK(OTYPE) { if (PRED(Object)!=NULL) SUCC(PRED(Object)) = SUCC(Object); else { CAT(FIRST,OTYPE(Grid)) = SUCC(Object); if (SUCC(Object)!=NULL) PRED(SUCC(Object)) = NULL; } if (SUCC(Object)!=NULL) PRED(SUCC(Object)) = PRED(Object); else { CAT(LAST,OTYPE(Grid)) = PRED(Object); if (PRED(Object)!=NULL) SUCC(PRED(Object)) = NULL; } /* decrement counter */ CAT(COUNT,OTYPE(Grid))--; } #endif #ifdef ModelP LINK(OTYPE) { INT listpart = PRIO2LISTPART(CAT(OTYPE,_LIST),Prio); INT listpartprev = listpart; INT listpartnext = listpart; OTYPE *Object1 = NULL; ASSERT(Grid != NULL); ASSERT(Object != NULL); ASSERT(Prio >= 0); IFDEBUG(gm,2) printf("GRID_LINK_" STR(OTYPE) "():" STR(OTYPE) " has listpart=%d for prio=%d obj=%p\n", listpart, Prio, (void*) Object); fflush(stdout); ENDDEBUG if (listpart<0 || listpart>LASTPART_OF_LIST(OTYPE)) { printf("GRID_LINK_" STR(OTYPE) "(): ERROR " STR(OTYPE) " has no valid listpart=%d for prio=%d\n",listpart,Prio); fflush(stdout); ASSERT(0); } PRED(Object) = SUCC(Object) = NULL; switch (listpart) { case FIRSTPART_OF_LIST: Object1 = CAT(LISTPART_FIRST,OTYPE(Grid,FIRSTPART_OF_LIST)); PRED(Object) = NULL; CAT(LISTPART_FIRST,OTYPE(Grid,FIRSTPART_OF_LIST)) = Object; if (Object1==NULL) { CAT(LISTPART_LAST,OTYPE(Grid,FIRSTPART_OF_LIST)) = Object; do { listpartnext++; CAT(Object1=LISTPART_FIRST,OTYPE(Grid,listpartnext)); } while (listpartnextFIRSTPART_OF_LIST && Object1==NULL); if (Object1!=NULL) SUCC(Object1) = Object; } else { PRED(Object) = Object1; SUCC(Object1) = Object; } break; default: /* link in middle of list */ Object1 = CAT(LISTPART_FIRST,OTYPE(Grid,listpart)); CAT(LISTPART_FIRST,OTYPE(Grid,listpart)) = Object; SUCC(Object) = Object1; PRED(Object) = NULL; /* empty list? */ if (Object1 == NULL) { CAT(LISTPART_LAST,OTYPE(Grid,listpart)) = Object; do { listpartnext++; Object1=CAT(LISTPART_FIRST,OTYPE(Grid,listpartnext)); } while (listpartnextFIRSTPART_OF_LIST && Object1==NULL); if (Object1 != NULL) SUCC(Object1) = Object; break; } /* increment counter */ CAT(COUNT,OTYPE(Grid))++; /* increment counter for priority */ CAT(PRIOCOUNT,OTYPE(Grid,Prio))++; ASSERT(Prio>0); IFDEBUG(gm,4) /* debug loop in list */ { INT n = 0; for (Object1 = CAT(PFIRST,OTYPE(Grid)); Object1 != NULL; Object1 = SUCC(Object1)) { n++; if (n>10000) { printf("GRID_LINK_" STR(OTYPE) "(): LOOPERROR " STR(OTYPE) " has listpart=%d for prio=%d\n",listpart,Prio); fflush(stdout); assert(0); } } /* object number error detection */ if (n != CAT(COUNT,OTYPE(Grid))) { printf("GRID_LINK_" STR(OTYPE) "(): COUNTERERROR " STR(OTYPE) " has listpart=%d for prio=%d n=%d count=%d\n", listpart,Prio,n,CAT(COUNT,OTYPE(Grid))); fflush(stdout); assert(0); } } ENDDEBUG } #else LINK(OTYPE) { OTYPE *after; after = CAT(LAST,OTYPE(Grid)); SUCC(Object) = NULL; if (after==NULL) { PRED(Object) = NULL; CAT(LAST,OTYPE(Grid)) = Object; CAT(FIRST,OTYPE(Grid)) = Object; } else { PRED(Object) = after; CAT(LAST,OTYPE(Grid)) = Object; SUCC(after) = Object; } /* increment counter */ CAT(COUNT,OTYPE(Grid))++; } #endif #ifdef ModelP LINKX(OTYPE) { INT listpart = PRIO2LISTPART(CAT(OTYPE,_LIST),Prio); OTYPE *Object1 = NULL; ASSERT(Grid != NULL); ASSERT(Object != NULL); ASSERT(Prio >= 0); if (After == NULL) { IFDEBUG(gm,2) printf(" GRID_LINKX_" STR(OTYPE) "():" STR(OTYPE) " calling GRID_LINK_" STR(OTYPE) "(): Object=%p After=%p \n", (void*) Object, (void*) After); ENDDEBUG CAT(GRID_LINK_,OTYPE) (Grid,Object,Prio); return; } #ifdef Debug /* this conistency is not true since elements have already their new priorities, but the handlers for them must not have been called at this point */ if (0) { INT listpartafter; /* After object must be in same list as Object */ listpartafter = PRIO2LISTPART(CAT(OTYPE,_LIST),DDD_InfoPriority(HDR(OTYPE)(After))); ASSERT(listpart == listpartafter); } #endif IFDEBUG(gm,2) printf("GRID_LINKX_" STR(OTYPE) "():" STR(OTYPE) " has listpart=%d for prio=%d obj=%p\n", listpart, Prio, (void*) Object); fflush(stdout); ENDDEBUG #ifdef Debug if (listpart<0 || listpart>LASTPART_OF_LIST(OTYPE)) { printf("GRID_LINKX_" STR(OTYPE) "(): ERROR " STR(OTYPE) " has no valid listpart=%d for prio=%d\n",listpart,Prio); fflush(stdout); ASSERT(0); } #endif SUCC(Object) = SUCC(After); if (SUCC(Object) != NULL) { if (PRED(SUCC(Object)) == After) PRED(SUCC(Object)) = Object; } SUCC(After) = Object; PRED(Object) = After; if (After == CAT(LISTPART_LAST,OTYPE(Grid,listpart))) { CAT(LISTPART_LAST,OTYPE(Grid,listpart)) = Object; } /* increment counter */ CAT(COUNT,OTYPE(Grid))++; /* increment counter for priority */ CAT(PRIOCOUNT,OTYPE(Grid,Prio))++; ASSERT(Prio>0); IFDEBUG(gm,4) /* debug loop in list */ { INT n = 0; for (Object1 = CAT(PFIRST,OTYPE(Grid)); Object1 != NULL; Object1 = SUCC(Object1)) { n++; if (n>10000) { printf("GRID_LINKX_" STR(OTYPE) "(): LOOPERROR " STR(OTYPE) " has listpart=%d for prio=%d\n",listpart,Prio); fflush(stdout); assert(0); } } /* object number error detection */ if (n != CAT(COUNT,OTYPE(Grid))) { printf("GRID_LINKX_" STR(OTYPE) "(): COUNTERERROR " STR(OTYPE) " has listpart=%d for prio=%d n=%d count=%d\n", listpart,Prio,n,CAT(COUNT,OTYPE(Grid))); fflush(stdout); assert(0); } } ENDDEBUG } #else LINKX(OTYPE) { INT listpart = PRIO2LISTPART(CAT(OTYPE,_LIST),Prio); ASSERT(Grid != NULL); ASSERT(Object != NULL); ASSERT(Prio >= 0); if (After == NULL) { IFDEBUG(gm,2) printf(" GRID_LINKX_" STR(OTYPE) "():" STR(OTYPE) " calling GRID_LINK_" STR(OTYPE) "(): Object=%p After=%p \n", (void*) Object, (void*) After); ENDDEBUG CAT(GRID_LINK_,OTYPE) (Grid,Object,Prio); return; } IFDEBUG(gm,2) printf("GRID_LINKX_" STR(OTYPE) "():" STR(OTYPE) " has listpart=%d for prio=%d obj=%p\n", listpart, Prio, (void*) Object); fflush(stdout); ENDDEBUG SUCC(Object) = SUCC(After); if (SUCC(Object) != NULL) { if (PRED(SUCC(Object)) == After) PRED(SUCC(Object)) = Object; } SUCC(After) = Object; PRED(Object) = After; if (After == CAT(LAST,OTYPE(Grid))) { CAT(LAST,OTYPE(Grid)) = Object; } /* increment counter */ CAT(COUNT,OTYPE(Grid))++; } #endif #ifdef ModelP INIT(OTYPE) { INT i; for (i=0; i<=LASTPART_OF_LIST(OTYPE); i++) { CAT(LISTPART_FIRST,OTYPE(Grid,i)) = NULL; CAT(LISTPART_LAST,OTYPE(Grid,i)) = NULL; } CAT(COUNT,OTYPE(Grid)) = 0; } #else INIT(OTYPE) { CAT(FIRST,OTYPE(Grid)) = CAT(LAST,OTYPE(Grid)) = NULL; CAT(COUNT,OTYPE(Grid)) = 0; } #endif #ifdef ModelP PRINT_LIST(OTYPE) { if (prios==2) { printf (" fg=%p fg=%p fm=%p lm=%p\n", (void*) CAT(LISTPART_FIRST,OTYPE(Grid,0)), (void*) CAT(LISTPART_LAST,OTYPE(Grid,0)), (void*) CAT(LISTPART_FIRST,OTYPE(Grid,1)), (void*) CAT(LISTPART_LAST,OTYPE(Grid,1))); } else { printf (" fg=%p fg=%p fb=%p lb=%p fm=%p lm=%p\n", (void*) CAT(LISTPART_FIRST,OTYPE(Grid,0)), (void*) CAT(LISTPART_LAST,OTYPE(Grid,0)), (void*) CAT(LISTPART_FIRST,OTYPE(Grid,1)), (void*) CAT(LISTPART_LAST,OTYPE(Grid,1)), (void*) CAT(LISTPART_FIRST,OTYPE(Grid,2)), (void*) CAT(LISTPART_LAST,OTYPE(Grid,2))); } } CHECK(OTYPE) { INT i,objs = 0; OTYPE *Object; PRINTDEBUG(gm,2,(" GRID_CHECK_" STR(OTYPE) "_LIST:\n")); IFDEBUG(gm,2) CAT(PRINT_LIST_STARTS_,OTYPE)(Grid,CAT(OTYPE,_LISTPARTS)); ENDDEBUG for (Object = CAT(PFIRST,OTYPE(Grid)); Object != NULL; Object = SUCC(Object)) { objs++; } if (objs != CAT(COUNT,OTYPE(Grid))) { printf(" ERROR: %d objs in list, but counter=%d\n", objs,CAT(COUNT,OTYPE(Grid))); } for (i=FIRSTPART_OF_LIST; i<=LASTPART_OF_LIST(OTYPE); i++) { INT prios[MAX_LISTPARTS],j,prio_error; LISTPART2PRIO(CAT(OTYPE,_LIST),i,prios); objs = 0; for (Object = CAT(LISTPART_LAST,OTYPE(Grid,i)); Object != NULL; Object = PRED(Object)) { INT prio = DDD_InfoPriority(HDR(OTYPE)(Object)); assert(prio != -1); objs++; prio_error = 1; for (j=0; jFIRSTPART_OF_LIST) { INT listpartprev = i; OTYPE *Object1; do { listpartprev--; Object1=CAT(LISTPART_LAST,OTYPE(Grid,listpartprev)); } while (listpartprev>FIRSTPART_OF_LIST && Object1==NULL); if (Object1 != NULL) if (CAT(LISTPART_FIRST,OTYPE(Grid,i))!= SUCC(Object1)) { printf(" ERROR: first pointer of listpart=%d" " dead\n",i); } } PRINTDEBUG(gm,2,(" listpart=%d prio=%d has nobjs=%d\n", i,prio,objs)); } } } } #else CHECK(OTYPE) { } #endif /* undefine used macros to allow redefinition */ #undef OTYPE #undef PRED #undef SUCC END_UGDIM_NAMESPACE dune-uggrid-2.11.0+dfsg/dune/uggrid/gm/elements.cc000066400000000000000000000433301513616443000216740ustar00rootroot00000000000000// SPDX-FileCopyrightText: Copyright © DUNE Project contributors, see file LICENSE.md in module root // SPDX-License-Identifier: LGPL-2.1-or-later // -*- tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- // vi: set et ts=4 sw=2 sts=2: /****************************************************************************/ /* */ /* File: elements.c */ /* */ /* Purpose: implements a general element concept */ /* */ /* Author: Peter Bastian, Stefan Lang */ /* Institut fuer Computeranwendungen III */ /* Universitaet Stuttgart */ /* Pfaffenwaldring 27 */ /* 70569 Stuttgart */ /* email: ug@ica3.uni-stuttgart.de */ /* */ /* History: 24.03.95 begin, ug version 3.0 */ /* 18.03.96 ug3.1 */ /* */ /* Remarks: */ /* */ /****************************************************************************/ #include #include #include #include "gm.h" #include "ugm.h" #ifdef ModelP #include #endif #include "elements.h" USING_UG_NAMESPACE USING_UGDIM_NAMESPACE /****************************************************************************/ /* */ /* defines in the following order */ /* */ /* compile time constants defining static data size (i.e. arrays) */ /* other constants */ /* macros */ /* */ /****************************************************************************/ /****************************************************************************/ /* */ /* data structures used in this source file (exported data structures are */ /* in the corresponding include file!) */ /* */ /****************************************************************************/ /****************************************************************************/ /* */ /* definition of exported global variables */ /* */ /****************************************************************************/ GENERAL_ELEMENT * NS_DIM_PREFIX element_descriptors[TAGS]; /****************************************************************************/ /* */ /* definition of local variables */ /* */ /****************************************************************************/ #ifdef UG_DIM_2 static GENERAL_ELEMENT def_triangle = { .tag = TRIANGLE, .sides_of_elem = 3, .corners_of_elem = 3, .local_corner = {{0.0,0.0},{1.0,0.0},{0.0,1.0}}, .edges_of_elem = 3, .edges_of_side = {1,1,1,-1}, .corners_of_side = {2,2,2,-1}, .edge_of_side = {{0},{1},{2},{-1}}, .corner_of_side = {{0,1},{1,2},{2,0},{-1,-1}}, .corner_of_edge = {{0,1},{1,2},{2,0},{-1,-1}}, .inner_size = offsetof(triangle,bnds), .bnd_size = sizeof(triangle) } ; static GENERAL_ELEMENT def_quadrilateral = { .tag = QUADRILATERAL, .sides_of_elem = 4, .corners_of_elem = 4, .local_corner = {{0.0,0.0},{1.0,0.0},{1.0,1.0},{0.0,1.0}}, .edges_of_elem = 4, .edges_of_side = {1,1,1,1}, .corners_of_side = {2,2,2,2}, .edge_of_side = {{0},{1},{2},{3}}, .corner_of_side = {{0,1},{1,2},{2,3},{3,0}}, .corner_of_edge = {{0,1},{1,2},{2,3},{3,0}}, .inner_size = offsetof(quadrilateral,bnds), .bnd_size = sizeof(quadrilateral) } ; #endif #ifdef UG_DIM_3 static GENERAL_ELEMENT def_tetrahedron = { .tag = TETRAHEDRON, .sides_of_elem = 4, .corners_of_elem = 4, .local_corner = {{0.0,0.0,0.0},{1.0,0.0,0.0},{0.0,1.0,0.0},{0.0,0.0,1.0}}, .edges_of_elem = 6, .edges_of_side = {3,3,3,3,-1,-1}, .corners_of_side = {3,3,3,3,-1,-1}, .edge_of_side = {{2,1,0,-1},{1,5,4,-1},{3,5,2,-1},{0,4,3,-1}}, .corner_of_side = {{0,2,1,-1},{1,2,3,-1},{0,3,2,-1},{0,1,3,-1}}, .corner_of_edge = {{0,1},{1,2},{0,2},{0,3},{1,3},{2,3}}, .inner_size = offsetof(tetrahedron,bnds), .bnd_size = sizeof(tetrahedron) } ; static GENERAL_ELEMENT def_pyramid = { .tag = PYRAMID, .sides_of_elem = 5, .corners_of_elem = 5, .local_corner = {{0.0,0.0,0.0},{1.0,0.0,0.0},{1.0,1.0,0.0},{0.0,1.0,0.0},{0.0,0.0,1.0}}, .edges_of_elem = 8, .edges_of_side = {4,3,3,3,3,-1}, .corners_of_side = {4,3,3,3,3,-1}, .edge_of_side = {{3,2,1,0},{0,5,4,-1},{1,6,5,-1},{2,7,6,-1},{3,4,7,-1}}, .corner_of_side = {{0,3,2,1},{0,1,4,-1},{1,2,4,-1},{2,3,4,-1},{3,0,4,-1}}, .corner_of_edge = {{0,1},{1,2},{2,3},{3,0},{0,4},{1,4},{2,4},{3,4}}, .inner_size = offsetof(pyramid,bnds), .bnd_size = sizeof(pyramid) } ; static GENERAL_ELEMENT def_prism = { .tag = PRISM, .sides_of_elem = 5, .corners_of_elem = 6, .local_corner = {{0.0,0.0,0.0},{1.0,0.0,0.0},{0.0,1.0,0.0}, {0.0,0.0,1.0},{1.0,0.0,1.0},{0.0,1.0,1.0}}, .edges_of_elem = 9, .edges_of_side = {3,4,4,4,3,-1}, .corners_of_side = {3,4,4,4,3,-1}, .edge_of_side = {{2,1,0,-1},{0,4,6,3},{1,5,7,4},{2,3,8,5},{6,7,8,-1}}, .corner_of_side = {{0,2,1,-1},{0,1,4,3},{1,2,5,4},{2,0,3,5},{3,4,5,-1}}, .corner_of_edge = {{0,1},{1,2},{2,0},{0,3},{1,4},{2,5},{3,4},{4,5},{5,3}}, .inner_size = offsetof(prism,bnds), .bnd_size = sizeof(prism) } ; static GENERAL_ELEMENT def_hexahedron = { .tag = HEXAHEDRON, .sides_of_elem = 6, .corners_of_elem = 8, .local_corner = {{0.0,0.0,0.0},{1.0,0.0,0.0}, {1.0,1.0,0.0},{0.0,1.0,0.0}, {0.0,0.0,1.0},{1.0,0.0,1.0}, {1.0,1.0,1.0},{0.0,1.0,1.0}}, .edges_of_elem = 12, .edges_of_side = {4,4,4,4,4,4}, .corners_of_side = {4,4,4,4,4,4}, .edge_of_side = {{3,2,1,0},{0,5,8,4},{1,6,9,5},{2,7,10,6},{3,4,11,7},{8,9,10,11}}, .corner_of_side = {{0,3,2,1},{0,1,5,4},{1,2,6,5},{2,3,7,6},{3,0,4,7},{4,5,6,7}}, .corner_of_edge = {{0,1},{1,2},{2,3},{3,0},{0,4},{1,5},{2,6},{3,7},{4,5},{5,6},{6,7},{7,4}}, .inner_size = offsetof(hexahedron,bnds), .bnd_size = sizeof(hexahedron) } ; #endif /****************************************************************************/ /** \brief Compute index fields for a given element type \param el pointer to an element description This function processes a topology description of an element type and computes index mappings. Currently descriptions for triangles, quadrilaterals and tetrahedra are included. Hexahedral elements have been implemented in a prototype version. CAUTION: The above data structure is filled UP TO appropriate sizes for memory allocation as well as offsets in the 'refs' array of the 'generic_element'! For complete filling you will have to call 'ProcessElementDescription' Only the following components of the GENERAL_ELEMENT structure must be provided. All other components are derived from the given information. . tag - New tag for the element which will be delivered by the 'TAG' macro. . sides_of_elem - Number of sides for that element type. . corners_of_elem - Number of corners for that element type. . edges_of_elem - Number of edges for that element type. . edges_of_side - Number of edges for each side. . corners_of_side - Number of corners of each side. . edge_of_side[s][e] - The edges are numbered in the element and in each side of the element. This array provides a mapping that tells you the number of edge 'e' of side 's' with respect to the numbering in the element. . corner_of_side[s][c] - The corners edges are numbered in the element and in each side of the element. This array provides a mapping that tells you the number of corner 'c' of side 's' with respect to the numbering in the element. . corner_of_edge[e][c] - Tells you the number of corner 'c' in edge 'e' with respect to the numbering in the element. */ /****************************************************************************/ static INT ProcessElementDescription (GENERAL_ELEMENT *el) { INT i,j,k; INT tag = el->tag; /* derive additional index fields */ /* edge_with_corners(i,j) : number of edge between corners i and j, -1 if no such edge ex. */ for (i=0; iedge_with_corners[i][j] = -1; for (i=0; iedges_of_elem; i++) { el->edge_with_corners[el->corner_of_edge[i][0]][el->corner_of_edge[i][1]] = i; el->edge_with_corners[el->corner_of_edge[i][1]][el->corner_of_edge[i][0]] = i; } /* side_with_edge(i,j) : edge i is an edge of side side_with_edge(i,j) */ for (i=0; iside_with_edge[i][j] = -1; for (k=0; kedges_of_elem; k++) { const INT from = el->corner_of_edge[k][0]; const INT to = el->corner_of_edge[k][1]; for (i=0; isides_of_elem; i++) { INT n = el->corners_of_side[i]; for (j=0; jcorner_of_side[i][j]==from)&&(el->corner_of_side[i][(j+1)%n]==to)) el->side_with_edge[k][1] = i; if ((el->corner_of_side[i][j]==to)&&(el->corner_of_side[i][(j+1)%n]==from)) el->side_with_edge[k][0] = i; } } } /* corner_of_side_inv(i,j) : j is number of a corner in the element. Then this array returns the local number of this corner within side i or -1 if side i does not contain this corner. */ for (i=0; icorner_of_side_inv[i][j] = -1; for (i=0; isides_of_elem; i++) for (j=0; jcorners_of_side[i]; j++) { const INT n = el->corner_of_side[i][j]; el->corner_of_side_inv[i][n] = j; } /* edges_of_corner(i,j) : i is a number of a corner within the element, then edges_of_corner(i,j) gives the number of an edge adjacent to corner i or -1 */ for (i=0; iedges_of_corner[i][j] = -1; for (i=0; iedges_of_elem; i++) for (j=0; jcorner_of_edge[i][j]; for (k=0; kedges_of_corner[n][k]<0) { el->edges_of_corner[n][k] = i; break; } } /* fields not valid for all elements */ /* corner_opp_to_side(i) */ for (i=0; icorner_opp_to_side[i] = -1; /* opposite_edge(i) */ for (i=0; iopposite_edge[i] = -1; /* side_opp_to_corner(i) */ for (i=0; iside_opp_to_corner[i] = -1; /* edge_of_corner(i,j) */ for (i=0; iedge_of_corner[i][j] = -1; /* edge_of_corner(i,j) */ for (i=0; iedges_of_elem; i++) { for (j=0; jcorner_of_edge[i][j] >=0) { for (k=0; kedges_of_elem; k++) if (el->edge_of_corner[el->corner_of_edge[i][j]][k] < 0) break; assert(kedges_of_elem); el->edge_of_corner[el->corner_of_edge[i][j]][k] = i; } } } #ifdef UG_DIM_2 switch (tag) { case TRIANGLE : /* corner_opp_to_side(i) */ /* is not defined! */ /* opposite_edge(i) */ /* is not defined! */ /* side_opp_to_corner(i) */ /* is not defined! */ break; case QUADRILATERAL : /* corner_opp_to_side(i) */ /* is not defined! */ /* opposite_edge(i) */ for (i=0; iedges_of_elem; i++) { INT n = 0; for (j=0; jedges_of_elem; k++) { if (el->edges_of_corner[el->corner_of_edge[i][j]][k] >= 0) n |= (0x1<<(el->edges_of_corner[el->corner_of_edge[i][j]][k])); } } for (j=0; jedges_of_elem; j++) if (((n>>j) & 0x1) == 0) break; assert(jedges_of_elem); el->opposite_edge[i] = j; } /* side_opp_to_corner(i) */ /* is not defined! */ break; } #endif #ifdef UG_DIM_3 /* edge_of_two_sides(i,j) */ for (i=0; iedge_of_two_sides[i][j] = -1; switch (tag) { case TETRAHEDRON : /* corner_opp_to_side(i) */ for (i=0; isides_of_elem; i++) { INT n = 0; for (j=0; jcorners_of_side[i]; j++) { n |= (0x1<<(el->corner_of_side[i][j])); } for (j=0; jcorners_of_elem; j++) { if (((n>>j) & 0x1) == 0) break; } assert(jcorners_of_elem); el->corner_opp_to_side[i] = j; } /* opposite_edge(i) */ for (i=0; iedges_of_elem; i++) { INT n = 0; for (j=0; jedges_of_elem; k++) { if (el->edges_of_corner[el->corner_of_edge[i][j]][k] >= 0) n |= (0x1<<(el->edges_of_corner[el->corner_of_edge[i][j]][k])); } } for (j=0; jedges_of_elem; j++) if (((n>>j) & 0x1) == 0) break; assert(jedges_of_elem); el->opposite_edge[i] = j; } /* side_opp_to_corner(i) */ for (i=0; icorners_of_elem; i++) { for (j=0; jsides_of_elem; j++) { INT n = 0; for (k=0; kcorners_of_side[j]; k++) n |= (0x1<<(el->corner_of_side[j][k])); if (((n>>i) & 0x1) == 0) { el->side_opp_to_corner[i] = j; break; } } assert(jsides_of_elem); } break; case PYRAMID : /* corner_opp_to_side(i) */ for (i=0; isides_of_elem; i++) { if (el->corners_of_side[i] == 4) { INT n = 0; for (j=0; jcorners_of_side[i]; j++) { n |= (0x1<<(el->corner_of_side[i][j])); } for (j=0; jcorners_of_elem; j++) { if (((n>>j) & 0x1) == 0) break; } assert(jcorners_of_elem); el->corner_opp_to_side[i] = j; } } /* opposite_edge(i) */ /* is not defined! */ /* side_opp_to_corner(i) */ for (i=0; icorners_of_elem; i++) { for (j=0; jsides_of_elem; j++) { INT n = 0; for (k=0; kcorners_of_side[j]; k++) n |= (0x1<<(el->corner_of_side[j][k])); if (((n>>i) & 0x1) == 0) { el->side_opp_to_corner[i] = j; break; } } assert(jsides_of_elem); } break; case PRISM : /* corner_opp_to_side(i) */ /* is not defined! */ /* opposite_edge(i) */ /* is not defined! */ /* side_opp_to_corner(i) */ /* is not defined! */ break; case HEXAHEDRON : /* corner_opp_to_side(i) */ /* is not defined! */ /* opposite_edge(i) */ for (i=0; iedges_of_elem; i++) { INT n = 0; for (j=0; jcorner_of_edge[i][j]; for (k=0; kedges_of_elem; k++) { if (el->edges_of_corner[n1][k] >= 0) { n |= (0x1<<(el->edges_of_corner[n1][k])); for (INT l=0; lcorner_of_edge[el->edges_of_corner[n1][k]][l]; if (n2 != n1) { for (INT m=0; medges_of_elem; m++) { if (el->edges_of_corner[n2][m] >= 0) n |= (0x1<<(el->edges_of_corner[n2][m])); } } } } } } for (k=0; kedges_of_elem; k++) if (((n>>k) & 0x1) == 0) break; assert(kedges_of_elem); el->opposite_edge[i] = k; } /* side_opp_to_corner(i) */ /* is not defined! */ break; } for (i=0; isides_of_elem; i++) for (j=0; jsides_of_elem; j++) for (k=0; kedges_of_side[i]; k++) for (INT l=0; ledges_of_side[j]; l++) if (el->edge_of_side[i][k] == el->edge_of_side[j][l]) { assert( (i==j) || (el->edge_of_two_sides[i][j]==-1) || (el->edge_of_two_sides[i][j]==el->edge_of_side[i][k]) ); el->edge_of_two_sides[i][j] = el->edge_of_side[i][k]; } #endif /* make description globally available */ element_descriptors[tag] = el; /* get a free object id for free list */ if (el->mapped_inner_objt < 0) el->mapped_inner_objt = GetFreeOBJT(); if (el->mapped_inner_objt < 0) return(GM_ERROR); if (el->mapped_bnd_objt < 0) el->mapped_bnd_objt = GetFreeOBJT(); if (el->mapped_bnd_objt < 0) return(GM_ERROR); return(GM_OK); } /****************************************************************************/ /** \brief Initialize topological information for element types This function initializes topological information for element types and is called once during startup. Add your initialization of a new element type here. \return
    • GM_OK if ok
    • GM_ERROR if error occurred
    */ /****************************************************************************/ INT NS_DIM_PREFIX InitElementTypes() { INT err; #ifdef UG_DIM_2 err = ProcessElementDescription(&def_triangle); if (err!=GM_OK) return err; err = ProcessElementDescription(&def_quadrilateral); if (err!=GM_OK) return err; #endif #ifdef UG_DIM_3 err = ProcessElementDescription(&def_tetrahedron); if (err!=GM_OK) return err; err = ProcessElementDescription(&def_pyramid); if (err!=GM_OK) return err; err = ProcessElementDescription(&def_prism); if (err!=GM_OK) return err; err = ProcessElementDescription(&def_hexahedron); if (err!=GM_OK) return err; #endif return (0); } dune-uggrid-2.11.0+dfsg/dune/uggrid/gm/elements.h000066400000000000000000000174331513616443000215430ustar00rootroot00000000000000// -*- tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- // vi: set et ts=4 sw=2 sts=2: // SPDX-FileCopyrightInfo: Copyright © DUNE Project contributors, see file LICENSE.md in module root // SPDX-License-Identifier: LGPL-2.1-or-later /*! \file elements.h * \ingroup gm */ /****************************************************************************/ /* */ /* File: elements.h */ /* */ /* Purpose: general element concept (header file) */ /* */ /* Author: Peter Bastian */ /* Institut fuer Computeranwendungen III */ /* Universitaet Stuttgart */ /* Pfaffenwaldring 27 */ /* 70569 Stuttgart */ /* email: ug@ica3.uni-stuttgart.de */ /* */ /* History: 24.03.95 begin, ug version 3.0 */ /* */ /* Remarks: */ /* */ /****************************************************************************/ /****************************************************************************/ /* */ /* auto include mechanism and other include files */ /* */ /****************************************************************************/ #ifndef __ELEMENTS__ #define __ELEMENTS__ #include #include "gm.h" START_UGDIM_NAMESPACE /** \brief Number of different element types */ #define TAGS 8 #ifdef UG_DIM_2 // The indexing of these arrays must match the definitions of the enum values // TRIANGLE, QUADRILATERAL, etc in gm.h constexpr INT n_offset[TAGS] = {-1,-1, -1, (offsetof(triangle,n) - offsetof(generic_element,refs))/sizeof(void*), (offsetof(quadrilateral,n) - offsetof(generic_element,refs))/sizeof(void*)}; constexpr INT father_offset[TAGS] = {-1, -1, -1, (offsetof(triangle,father) - offsetof(generic_element,refs))/sizeof(void*), (offsetof(quadrilateral,father) - offsetof(generic_element,refs))/sizeof(void*)}; constexpr INT sons_offset[TAGS] = {-1, -1, -1, (offsetof(triangle,sons) - offsetof(generic_element,refs))/sizeof(void*), (offsetof(quadrilateral,sons) - offsetof(generic_element,refs))/sizeof(void*)}; constexpr INT nb_offset[TAGS] = {-1, -1, -1, (offsetof(triangle,nb) - offsetof(generic_element,refs))/sizeof(void*), (offsetof(quadrilateral,nb) - offsetof(generic_element,refs))/sizeof(void*)}; constexpr INT side_offset[TAGS] = {-1, -1, -1, (offsetof(triangle,bnds) - offsetof(generic_element,refs))/sizeof(void*), (offsetof(quadrilateral,bnds) - offsetof(generic_element,refs))/sizeof(void*)}; #endif #ifdef UG_DIM_3 // The indexing of these arrays must match the definitions of the enum values // TETRAHEDRON, PYRAMID, etc in gm.h constexpr INT n_offset[TAGS] = {-1, -1, -1, -1, (offsetof(tetrahedron,n) - offsetof(generic_element,refs))/sizeof(void*), (offsetof(pyramid,n) - offsetof(generic_element,refs))/sizeof(void*), (offsetof(prism,n) - offsetof(generic_element,refs))/sizeof(void*), (offsetof(hexahedron,n) - offsetof(generic_element,refs))/sizeof(void*)}; constexpr INT father_offset[TAGS] = {-1, -1, -1, -1, (offsetof(tetrahedron,father) - offsetof(generic_element,refs))/sizeof(void*), (offsetof(pyramid,father) - offsetof(generic_element,refs))/sizeof(void*), (offsetof(prism,father) - offsetof(generic_element,refs))/sizeof(void*), (offsetof(hexahedron,father) - offsetof(generic_element,refs))/sizeof(void*)}; constexpr INT sons_offset[TAGS] = {-1, -1, -1, -1, (offsetof(tetrahedron,sons) - offsetof(generic_element,refs))/sizeof(void*), (offsetof(pyramid,sons) - offsetof(generic_element,refs))/sizeof(void*), (offsetof(prism,sons) - offsetof(generic_element,refs))/sizeof(void*), (offsetof(hexahedron,sons) - offsetof(generic_element,refs))/sizeof(void*)}; constexpr INT nb_offset[TAGS] = {-1, -1, -1, -1, (offsetof(tetrahedron,nb) - offsetof(generic_element,refs))/sizeof(void*), (offsetof(pyramid,nb) - offsetof(generic_element,refs))/sizeof(void*), (offsetof(prism,nb) - offsetof(generic_element,refs))/sizeof(void*), (offsetof(hexahedron,nb) - offsetof(generic_element,refs))/sizeof(void*)}; constexpr INT svector_offset[TAGS] = {-1, -1, -1, -1, (offsetof(tetrahedron,sidevector) - offsetof(generic_element,refs))/sizeof(void*), (offsetof(pyramid,sidevector) - offsetof(generic_element,refs))/sizeof(void*), (offsetof(prism,sidevector) - offsetof(generic_element,refs))/sizeof(void*), (offsetof(hexahedron,sidevector) - offsetof(generic_element,refs))/sizeof(void*)}; constexpr INT side_offset[TAGS] = {-1, -1, -1, -1, (offsetof(tetrahedron,bnds) - offsetof(generic_element,refs))/sizeof(void*), (offsetof(pyramid,bnds) - offsetof(generic_element,refs))/sizeof(void*), (offsetof(prism,bnds) - offsetof(generic_element,refs))/sizeof(void*), (offsetof(hexahedron,bnds) - offsetof(generic_element,refs))/sizeof(void*)}; #endif /* the element descriptions are also globally available, these are pointers ! */ extern GENERAL_ELEMENT *element_descriptors[TAGS]; // The element tags, indexed by the number of element vertices #ifdef UG_DIM_2 constexpr INT reference2tag[MAX_CORNERS_OF_ELEM+1] = {-1, -1, -1, TRIANGLE, QUADRILATERAL}; #else constexpr INT reference2tag[MAX_CORNERS_OF_ELEM+1] = {-1, -1, -1, -1, TETRAHEDRON, PYRAMID, PRISM, HEXAHEDRON}; #endif /****************************************************************************/ /* */ /* function definitions */ /* */ /****************************************************************************/ INT InitElementTypes(); END_UGDIM_NAMESPACE #endif dune-uggrid-2.11.0+dfsg/dune/uggrid/gm/er.cc000066400000000000000000001737501513616443000205000ustar00rootroot00000000000000// SPDX-FileCopyrightText: Copyright © DUNE Project contributors, see file LICENSE.md in module root // SPDX-License-Identifier: LGPL-2.1-or-later // -*- tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- // vi: set et ts=4 sw=2 sts=2: /****************************************************************************/ /* */ /* File: er.c */ /* */ /* Purpose: extract rules realized in a multigrid */ /* */ /* Author: Henrik Rentz-Reichert */ /* Institut fuer Computeranwendungen III */ /* Universitaet Stuttgart */ /* Pfaffenwaldring 27 */ /* 70550 Stuttgart */ /* email: ug@ica3.uni-stuttgart.de */ /* */ /* History: 06.12.97 begin, ug version 3.7 */ /* */ /* Remarks: */ /* */ /****************************************************************************/ #undef __DEBUG_ER__ #undef __PATCH_UG_RULES__ /****************************************************************************/ /* storage allocation stages: Notation: M - Mark(Tmp)Mem G - Get(Tmp)Mem R - Release(Tmp)Mem ------------------------+-+-+-+-+---+-+-+-+-+ |BOTTOM | | TOP | ------------------------+-+-+-+-+---+-+-+-+-+ stack level |0|1|2|3| |0|1|2|3| ------------------------+-+-+-+-+---+-+-+-+-+ (1) for hrules |M| | | | | | | | | (2) hash table | | | | | | |M| | | | | | | | | |G| | | (3) interface rules | | | | | | | |M| | | | | | | | | |G| | (4) hrules |G| | | | | | | | | (5) free (3) | | | | | | | |R| | (6) further hrules |G| | | | | | | | | (6) hrule table |G| | | | | | | | | (7) free (2) | | | | | | |R| | | (7) mrule table (rm+er) | | | | | |G| | | | (9) free hrules |R| | | | | | | | | ------------------------+-+-+-+-+---+-+-+-+-+ */ /****************************************************************************/ /****************************************************************************/ /* */ /* include files */ /* system include files */ /* application include files */ /* */ /****************************************************************************/ #include #include #include #include /* gm */ #include "rm.h" #include "mgio.h" #include "ugm.h" #include "cw.h" #include "elements.h" /* own header */ #include "er.h" USING_UG_NAMESPACES /****************************************************************************/ /* */ /* defines in the following order */ /* */ /* compile time constants defining static data size (i.e. arrays) */ /* other constants */ /* macros */ /* */ /****************************************************************************/ /* TODO (HRR 971207): increase REFINE_LEN by shifting REFINE-ce to flag cw */ #define MAX_HRID (1<0) ? 1 : 0) /* include NO_REFINEMENT from ug */ #define HAS_NO_RULE(e) (REFINE(e)>=UGMAXRULE(TAG(e))) #else #define UGMAXRULE(tag) (MaxRules[tag]) #define HAS_NO_RULE(e) (REFINE(e)==COPY && REFINECLASS(e)==GREEN_CLASS) #endif #define BEYOND_UG_RULES(e) (REFINE(e)>=UGMAXRULE(TAG(e))) #define NOTDONE -1 /* for computing son paths */ enum NB_STATUS { NB_DONE, NB_NOTDONE, NB_TOUCHED }; /* debug levels of extract rule module */ enum ER_DBG { ER_DBG_GENERAL = 1, ER_DBG_RULES = 2, ER_DBG_RULE_VERBOSE = 3, ER_DBG_ELEM = 3 }; #define HASH_SIZE 1000 #define HASH_FACTOR .61803398874989 /* golden section: 0.5*(sqrt(5)-1) */ #define HASH_ADDRESS(k) floor(HASH_SIZE*(k*HASH_FACTOR-floor(k*HASH_FACTOR))) #define ER_NSONS(p) ((p)->nsons) #define ER_NCO(p,i) ((p)->nco[i]) #define ER_DCO(p,i) ((p)->dco[i]) #define HR_ID(p) ((p)->id) #define HR_KEY(p) ((p)->key) #define HR_TAG(p) ((p)->tag) #define HR_NEXT(p) ((p)->next) #define HR_ERULE(p) (&((p)->erule)) #define HR_NSONS(p) ((p)->erule.nsons) #define HR_NCO(p,i) ((p)->erule.nco[i]) #define HR_DCO(p,i) ((p)->erule.dco[i]) #define HR_OCOPTR(p) ((p)->erule.dco+HR_NSONS(p)) #define HR_OCO(p,i) ((p)->erule.dco[HR_NSONS(p)+i]) /* debug macros */ #define ELEM_INFO(f,c,e,ns) f ": %sconsiderd elem%ld tag%d refine%ld nsons%d (actually %d)\n", \ (c) ? "not " : "", \ (long)ID(e), \ (int)TAG(e), \ (long)REFINE(e), \ (int)NSONS(e), \ (int)ns #ifdef Debug #define PD_ERR(l,x,e) {PRINTDEBUG(gm,l,x); e++; /* ASSERT(false);*/} #define PD(x) {PrintDebug x;} #else #define PD_ERR(l,x,e) /* no debug */ #define PD(x) /* no debug */ #ifdef PrintDebug #undef PrintDebug #define PrintDebug printf #endif #endif /****************************************************************************/ /* */ /* data structures used in this source file (exported data structures are */ /* in the corresponding include file!) */ /* */ /****************************************************************************/ typedef struct { SHORT nsons; /* number of son elements */ SHORT nco[MAX_SONS]; /* number of son corners */ DOUBLE dco[MAX_SONS]; /* corners coded as digits to base */ /* MAX_REFINED_CORNERS_DIM */ } ERULE; typedef INT HRID; struct hashed_rule { HRID id; /* rule id will continue tag-wise rm-rules */ DOUBLE key; /* hash key */ SHORT tag; /* tag of element */ struct hashed_rule *next; /* list of rules per hash entry */ ERULE erule; /* refinement rule */ /* will be allocated with additional doubles for ordered sons */ /* CAUTION: storage occupied may be < sizeof(HRULE) */ }; /* HRULE example for 3 sons: id key tag next nsons // begin of ERULE nco[MAX_SONS] dco[3] oco[3] // corners in ascending order */ typedef struct hashed_rule HRULE; typedef REFRULE URULE; /****************************************************************************/ /* */ /* definition of exported global variables */ /* */ /****************************************************************************/ /****************************************************************************/ /* */ /* definition of variables global to this source file only (static!) */ /* */ /****************************************************************************/ static struct { HEAP *heap; /* multigrid heap */ HRULE **hash_table; /* hash table */ std::array hrule; /* tables with hrules sorted by id */ std::array maxrule; /* max rule id per tag (rm+er) */ long maxrules; /* max rule id (rm+er) */ std::array nelem_inspected; /* elements getting er-rules per tag */ long nelems_inspected; /* elements getting er-rules */ std::array nelem_not_inspected; /* elements having rm-rules per tag */ long nelems_not_inspected; /* elements having rm-rules */ #ifdef ModelP long if_elems; /* number of elements getting er-rules */ ERULE *interface_rules; /* table of interface rules */ #endif } global; /* static globals of this module */ /****************************************************************************/ /* */ /* forward declarations of functions used before they are defined */ /* */ /****************************************************************************/ /****************************************************************************/ /*doctext_disabled Corner2DCorners - map corner array to DOUBLE SYNOPSIS: static DOUBLE Corner2DCorners (INT n, SHORT corners[]) PARAMETERS: . n - number of corners . corners - array of corner IDs DESCRIPTION: Convert list of corner IDs into one DOUBLE value. Corner IDs are digits in a MAX_REFINED_CORNERS_DIM base. RETURN VALUE: DOUBLE .n coded corners doctext_disabled*/ /****************************************************************************/ static DOUBLE Corner2DCorners (INT n, const SHORT corners[]) { DOUBLE dco = corners[0]; for (int i = 1; i < n; i++) { dco *= MAX_REFINED_CORNERS_DIM; dco += corners[i]; } return (dco); } /****************************************************************************/ /*doctext_disabled DCorners2Corners - convert DOUBLE into array of corner IDs SYNOPSIS: static void DCorners2Corners (INT n, DOUBLE dco, SHORT corners[]) PAAMETERS: . n - number of corners . dco - corners coded on DOUBLE . corners - array of corner IDs DESCRIPTION: Convert DOUBLE into array of corner IDs. For encoding see 'Corner2DCorners'. RETURN VALUE: void .n none SEE_ASLO: Corner2DCorners doctext_disabled*/ /****************************************************************************/ static void DCorners2Corners (INT n, DOUBLE dco, SHORT corners[]) { for (int i = n-1; i >= 0; i--) { DOUBLE x = floor(dco/((DOUBLE)MAX_REFINED_CORNERS_DIM)); corners[i] = (SHORT)(dco-x*MAX_REFINED_CORNERS_DIM); dco = x; } } /****************************************************************************/ /*doctext_disabled FillOrderedSons - fill array with ordered sons SYNOPSIS: static void FillOrderedSons (const ERULE *er, DOUBLE oco[]) PAAMETERS: . er - rule . oco - array of ordered sons DESCRIPTION: Fill array with sons in ascending order whose ordered corners are coded as DOUBLEs. RETURN VALUE: void .n none doctext_disabled*/ /****************************************************************************/ static void FillOrderedSons (const ERULE *er, DOUBLE oco[]) { SHORT corners[MAX_CORNERS_OF_ELEM_DIM]; /* sort corners of each son */ for (int s = 0; s < ER_NSONS(er); s++) { DCorners2Corners(ER_NCO(er,s),ER_DCO(er,s),corners); std::sort(corners, corners + ER_NCO(er,s)); oco[s] = Corner2DCorners(ER_NCO(er,s),corners); } /* sort sons in ascending order coded on a DOUBLE (cf. `Corner2DCorners`) */ std::sort(oco, oco + ER_NSONS(er)); } /****************************************************************************/ /*doctext_disabled Hash_Init - allocate and initialize hash table SYNOPSIS: static INT Hash_Init (int MarkKey) PAAMETERS: . MarkKey - mark key for memory allocation DESCRIPTION: Allocate and initialize hash table RETURN VALUE: INT .n 0: ok .n 1: no memory doctext_disabled*/ /****************************************************************************/ #if (defined UG_DIM_3) || (defined __DEBUG_ER__) static INT Hash_Init (int MarkKey) { global.hash_table = (HRULE**) GetTmpMem(global.heap,HASH_SIZE*sizeof(HRULE*),MarkKey); if (global.hash_table==NULL) REP_ERR_RETURN(1); for (int i = 0; i < HASH_SIZE; i++) global.hash_table[i] = NULL; return (0); } #endif /****************************************************************************/ /*doctext_disabled Hash_InsertRule - insert a rule into the hash table SYNOPSIS: static HRID Hash_InsertRule (INT etag, INT key, const ERULE *er, const DOUBLE oco[], HRULE **next_handle) PAAMETERS: . etag - element tag . key - hash key . er - rule . oco - ordered corners . next_handle - insert here into linked list of rules in hash table DESCRIPTION: Make an HRULE from an ERULE and insert it into the hash table. RETURN VALUE: HRID .n >=0: ok .n -1: no memory for HRULE doctext_disabled*/ /****************************************************************************/ static HRID Hash_InsertRule (INT etag, INT key, const ERULE *er, const DOUBLE oco[], HRULE **next_handle) { size_t size = sizeof(HRULE) /* full HRULE */ +sizeof(DOUBLE)* (2*ER_NSONS(er) /* #DOUBLEs needed */ -MAX_SONS); /* #DOUBLEs at end of HRULE */ // I think that nullptr can replace the call to GetCurrentMultigrid, because that method // has been returning nullptr for a long time. // In other words: it seems the method we are in is never called. HRULE *hr = (HRULE*) GetMemoryForObject(nullptr/*GetCurrentMultigrid()*/,size,NOOBJ); HRID id = global.maxrule[etag]++; if (hr==NULL) REP_ERR_RETURN (-1); /* insert in list */ HR_NEXT(hr) = *next_handle; *next_handle = hr; /* init */ HR_ID(hr) = id; HR_KEY(hr) = key; HR_TAG(hr) = etag; memcpy(HR_ERULE(hr), er, sizeof(ERULE)+sizeof(DOUBLE)*(ER_NSONS(er)-MAX_SONS)); memcpy(HR_OCOPTR(hr), oco, sizeof(DOUBLE)*ER_NSONS(er)); return (id); } /****************************************************************************/ /*doctext_disabled SonsAreEqual - compare sons of rule with array of ordered sons SYNOPSIS: static INT SonsAreEqual (INT nsons, const DOUBLE oco[], const HRULE *hr) PAAMETERS: . nsons - number of sons . oco - array of ordered sons . hr - rule DESCRIPTION: Compare sons of rule with array of ordered sons RETURN VALUE: INT .n YES: sons are equal .n NO: sons are not equal doctext_disabled*/ /****************************************************************************/ static bool SonsAreEqual (INT nsons, const DOUBLE oco[], const HRULE *hr) { if (nsons!=HR_NSONS(hr)) return false; for (int s = 0; s < nsons; s++) { if (oco[s] != HR_OCO(hr, s)) return false; } return true; } /****************************************************************************/ /*doctext_disabled GetRuleID - insert in hash table if not found there and return rule id for element SYNOPSIS: static HRID GetRuleID (ELEMENT *elem, INT etag, const ERULE *er) PAAMETERS: . elem - element (only in debug mode) . etag - element tag . er - rule DESCRIPTION: Insert in hash table if not found there and return rule id for element. RETURN VALUE: HRID .n rule id (starting after rm IDs per tag) doctext_disabled*/ /****************************************************************************/ #if (defined UG_DIM_3) || (defined __DEBUG_ER__) static HRID GetRuleID ( #ifdef Debug ELEMENT *elem, #endif INT etag, const ERULE *er ) { DOUBLE key = 0; DOUBLE oco[MAX_SONS]; global.nelem_inspected[etag]++; global.nelems_inspected++; PRINTDEBUG(gm,ER_DBG_ELEM,(ELEM_INFO("GetRuleID",true,elem,ER_NSONS(er)))); FillOrderedSons(er,oco); for (int s = 0; s < ER_NSONS(er); s++) key += oco[s]; /** \todo (HRR 971211): use tag also for key? */ int h = HASH_ADDRESS(key); HRULE *hr = global.hash_table[h]; if (hr==NULL) return (Hash_InsertRule(etag,key,er,oco,&(global.hash_table[h]))); for (; hr!=NULL; hr=HR_NEXT(hr)) if (key==HR_KEY(hr) && etag==HR_TAG(hr) && SonsAreEqual(ER_NSONS(er),oco,hr)) return (HR_ID(hr)); else if ((HR_NEXT(hr)==NULL) || (key=nco1) { corners_match = false; break; } } if (corners_match) break; } } if (s1>=ns1) { PrintDebug("CompareRules: rules not equal: elem%d (son=%d of urule not in erule)\n",id,s0); return (NO); } } return (YES); } #endif /****************************************************************************/ /*doctext_disabled ExtractERule - extract rule from element SYNOPSIS: static INT ExtractERule (ELEMENT *elem, ERULE *er) PAAMETERS: . elem - element . er - extracted rule DESCRIPTION: Extract rule from element (rule may be incomplete in parallel) RETURN VALUE: INT .n 0: ok .n >0: error doctext_disabled*/ /****************************************************************************/ static INT ExtractERule (ELEMENT *elem, ERULE *er) { int nsons = NSONS(elem); ELEMENT *sons[MAX_SONS]; NODE *nodes[MAX_REFINED_CORNERS_DIM]; if (GetNodeContext(elem,nodes)) REP_ERR_RETURN(1); /* get sons with master priority */ if (GetAllSons(elem,sons)) REP_ERR_RETURN(1); ER_NSONS(er) = 0; for (int s = 0; s < nsons; s++) { ELEMENT *son = sons[s]; int coe = CORNERS_OF_ELEM(son); SHORT corners[MAX_CORNERS_OF_ELEM_DIM]; if (EGHOST(son)) continue; ER_NSONS(er)++; /* corners and dcorners */ ER_NCO(er,s) = coe; for (int j = 0; j < coe; j++) { const NODE *node = CORNER(son,j); int k; for (k = 0; k < MAX_REFINED_CORNERS_DIM; k++) if (node==nodes[k]) break; ASSERT(k1)) { URULE *ur = MARK2RULEADR(elem,REFINE(elem)); RuleCompare(ID(elem),ur,er); } #endif return (0); } /****************************************************************************/ /* functions for parallel mode only */ /****************************************************************************/ #ifdef ModelP /****************************************************************************/ /*doctext_disabled CountIFElements - count interface elements having no rm-rule SYNOPSIS: static int CountIFElements (DDD_OBJ obj) PAAMETERS: . obj - element DESCRIPTION: Count interface elements having no rm-rule (masters and VH-hgosts). Those elements are flagged true. RETURN VALUE: int .n 0: ok SEE ALSO: ExtractInterfaceRules doctext_disabled*/ /****************************************************************************/ #if (defined UG_DIM_3) || (defined __DEBUG_ER__) static int CountIFElements (DDD::DDDContext&, DDD_OBJ obj) { ELEMENT *elem = (ELEMENT*) obj; if (HAS_NO_RULE(elem)) { SETTHEFLAG(elem,true); ASSERT(global.if_elems0: error SEE ALSO: ExtractInterfaceRules doctext_disabled*/ /****************************************************************************/ static int InitMasterRules (DDD::DDDContext&, DDD_OBJ obj) { ELEMENT *elem = (ELEMENT*) obj; if (THEFLAG(elem)) { ERULE *er = global.interface_rules+REFINE(elem); return (ExtractERule((ELEMENT*)obj,er)); } else return (0); } /****************************************************************************/ /*doctext_disabled Gather_ERULE - extract rules from interface elements SYNOPSIS: static int Gather_ERULE (DDD_OBJ obj, void *data) PAAMETERS: . obj - element . data - rule DESCRIPTION: Extract rules from interface elements (masters and VH-ghosts) RETURN VALUE: int .n 0: ok .n >0: error SEE ALSO: ExtractInterfaceRules doctext_disabled*/ /****************************************************************************/ static int Gather_ERULE (DDD::DDDContext&, DDD_OBJ obj, void *data) { ELEMENT *elem = (ELEMENT*) obj; if (THEFLAG(elem)) return (ExtractERule(elem,(ERULE*)data)); else return (0); } /****************************************************************************/ /*doctext_disabled Scatter_ERULE - write completed rule for VH-ghosts SYNOPSIS: static int Scatter_ERULE (DDD_OBJ obj, void *data) PAAMETERS: . obj - element . data - rule previously completed by master DESCRIPTION: Write completed rule for VH-ghosts. RETURN VALUE: int .n 0: ok SEE ALSO: ExtractInterfaceRules doctext_disabled*/ /****************************************************************************/ static int Scatter_ERULE (DDD::DDDContext&, DDD_OBJ obj, void *data) { ELEMENT *elem = (ELEMENT*)obj; if (THEFLAG(elem)) { ERULE *er = global.interface_rules+REFINE(elem); memcpy(er,data,sizeof(ERULE)); } return (0); } /****************************************************************************/ /*doctext_disabled Scatter_partial_ERULE - add son-info from VH-ghosts to master rule SYNOPSIS: static int Scatter_partial_ERULE (DDD_OBJ obj, void *data) PAAMETERS: . obj - element . data - rule DESCRIPTION: Add son-info from VH-ghosts to master rule. RETURN VALUE: int .n 0: ok SEE ALSO: ExtractInterfaceRules doctext_disabled*/ /****************************************************************************/ static int Scatter_partial_ERULE (DDD::DDDContext&, DDD_OBJ obj, void *data) { ELEMENT *elem = (ELEMENT*)obj; if (THEFLAG(elem)) { ERULE *er_ma = global.interface_rules+REFINE(elem); ERULE *er_gh = (ERULE*)data; int s_ma = ER_NSONS(er_ma); int s_gh; /* put sons at and of rule */ for (s_gh=0; s_gh0: error in storage allocation doctext_disabled*/ /****************************************************************************/ static INT ExtractInterfaceRules (MULTIGRID *mg) { auto& context = mg->dddContext(); const auto& dddctrl = ddd_ctrl(context); /* TODO (HRR 971211): don't include TOPLEVEL (no elem refined there) */ for (int lev = 0; lev <= TOPLEVEL(mg); lev++) { GRID *grid = GRID_ON_LEVEL(mg,lev); /* count interface master and vhghost elements */ global.if_elems = 1; DDD_IFAExecLocal(context, dddctrl.ElementVHIF, GRID_ATTR(grid), CountIFElements); if (global.if_elems>1) { INT MarkKey; PRINTDEBUG(gm,ER_DBG_GENERAL,("ExtractInterfaceRules: interface elements to consider on level %d: %ld\n",lev,global.if_elems)); if (MarkTmpMem(global.heap,&MarkKey)) REP_ERR_RETURN(1); /* REMARK (HRR 971207): storage could be Marked and Released in pieces if necessary to allow BOTTOM-storage to grow */ global.interface_rules = (ERULE*)GetTmpMem(global.heap,(global.if_elems+1)*sizeof(ERULE),MarkKey); if (global.interface_rules==NULL) REP_ERR_RETURN(1); /* init rules of masters */ DDD_IFAExecLocal(context, dddctrl.ElementIF, GRID_ATTR(grid), InitMasterRules); /* communicate VHghosts --> master */ DDD_IFAOneway(context, dddctrl.ElementVHIF, GRID_ATTR(grid), IF_BACKWARD, sizeof(ERULE), Gather_ERULE, Scatter_partial_ERULE); /* communicate master --> VHghosts */ DDD_IFAOneway(context, dddctrl.ElementVHIF, GRID_ATTR(grid), IF_FORWARD, sizeof(ERULE), Gather_ERULE, Scatter_ERULE); /* extract rules from interface elements */ DDD_IFAExecLocal(context, dddctrl.ElementVHIF, GRID_ATTR(grid), ExtractInterfaceERule); IFDEBUG(gm,ER_DBG_GENERAL) long N_er = 0; PrintDebug("ExtractInterfaceRules: number of refrules extracted from interface on level %d:\n",lev); for (int tag = 0; tag < TAGS; tag++) { long n_er = global.maxrule[tag] - UGMAXRULE(tag); N_er += n_er; PrintDebug("tag %d: %ld extracted rules\n",tag,n_er); } PrintDebug("total: %ld extracted rules\n",N_er); ENDDEBUG if (ReleaseTmpMem(global.heap,MarkKey)) REP_ERR_RETURN(1); } } return (0); } #endif #endif /* ModelP */ /****************************************************************************/ /*doctext_disabled ExtractRules - extract all realized rules that have no rm-rule SYNOPSIS: static INT ExtractRules (MULTIGRID *mg) PAAMETERS: . mg - multigrid DESCRIPTION: Extract all realized rules of the mg that have no rm-rule. RETURN VALUE: INT .n 0: ok .n >0: error doctext_disabled*/ /****************************************************************************/ #if (defined UG_DIM_3) || (defined __DEBUG_ER__) static INT ExtractRules (MULTIGRID *mg) { ERULE er; INT MarkKey; int maxrules; /* for hash table */ if (MarkTmpMem(global.heap,&MarkKey)) REP_ERR_RETURN(1); if (Hash_Init(MarkKey)) REP_ERR_RETURN(1); global.nelems_inspected = global.nelems_not_inspected = 0; for (int tag = 0; tag < TAGS; tag++) global.nelem_inspected[tag] = global.nelem_not_inspected[tag] = 0; /* loop elements and extract rules */ #ifdef ModelP /* TODO (HRR 971211): don't include TOPLEVEL (no elem refined there) */ for (int l = 0; l <= TOPLEVEL(mg); l++) for (ELEMENT *elem = FIRSTELEMENT(GRID_ON_LEVEL(mg, l)); elem != NULL; elem = SUCCE(elem)) SETUSED(elem,false); if (ExtractInterfaceRules(mg)) REP_ERR_RETURN(1); #endif /* TODO (HRR 971211): don't include TOPLEVEL (no elem refined there) */ for (int l = 0; l <= TOPLEVEL(mg); l++) for (ELEMENT *elem = FIRSTELEMENT(GRID_ON_LEVEL(mg, l)); elem != NULL; elem = SUCCE(elem)) #ifdef ModelP if (!USED(elem)) { #endif if (HAS_NO_RULE(elem)) { if (ExtractERule(elem,&er)) REP_ERR_RETURN(1); HRID id = GetRuleID( #ifdef Debug elem, #endif TAG(elem),&er); ASSERT(id0) { #ifdef Debug int n = 0; #endif int max_list_len = 0; /* make tables of subsequent IDs */ // I think that nullptr can replace the call to GetCurrentMultigrid, because that method // has been returning nullptr for a long time. // In other words: it seems the method we are in is never called. global.hrule[0] = (HRULE**) GetMemoryForObject(nullptr/*GetCurrentMultigrid()*/, global.maxrules*sizeof(HRULE*),NOOBJ); if (global.hrule[0]==NULL) REP_ERR_RETURN(1); for (int tag = 1; tag < TAGS; tag++) global.hrule[tag] = global.hrule[tag-1]+global.maxrule[tag-1]; for (int h = 0; h < HASH_SIZE; h++) { int list_len = 0; HRULE *hr; for (hr=global.hash_table[h]; hr!=NULL; hr=HR_NEXT(hr)) { global.hrule[HR_TAG(hr)][HR_ID(hr)] = hr; list_len++; #ifdef Debug n++; #endif } max_list_len = std::max(max_list_len,list_len); } ASSERT(maxrules==n); PRINTDEBUG(gm,ER_DBG_GENERAL,("ExtractRules: max members of hash table entries is %d\n",max_list_len)); } else PRINTDEBUG(gm,ER_DBG_GENERAL,("ExtractRules: realized rules were completely covered by rm rules\n")); if (ReleaseTmpMem(global.heap,MarkKey)) REP_ERR_RETURN(1); return (0); } #endif /****************************************************************************/ /*doctext_disabled FindPathForNeighbours - recursive function computing path infos SYNOPSIS: static void FindPathForNeighbours (MGIO_RR_RULE *rule, SHORT myID, SHORT Status[MAX_SONS]) PAAMETERS: . rule - mrule . myID - son ID . Status - status (see 'enum NB_STATUS' in er.c) DESCRIPTION: Recursive function computing path infos for sons. RETURN VALUE: void .n none doctext_disabled*/ /****************************************************************************/ static void FindPathForNeighbours (MGIO_RR_RULE *rule, SHORT myID, SHORT Status[MAX_SONS]) { for (SHORT i = 0; i < MAX_SIDES_OF_ELEM; i++) { SHORT nbID = rule->sons[myID].nb[i]; if ((nbID < FATHER_SIDE_OFFSET) && (Status[nbID] == NB_NOTDONE)) { /* copy myPath to nbPath */ INT nbPath = rule->sons[myID].path; /* complete nbPath */ SHORT nbPathDepth = PATHDEPTH(nbPath); SETNEXTSIDE(nbPath,nbPathDepth,i); SETPATHDEPTH(nbPath,++nbPathDepth); Status[nbID] = NB_TOUCHED; } } /* recursive call for NB_TOUCHED sons */ for (SHORT nbID = 1; nbID < rule->nsons; nbID++) if (Status[nbID]==NB_TOUCHED) { Status[nbID] = NB_DONE; FindPathForNeighbours(rule,nbID,Status); } } /****************************************************************************/ /*doctext_disabled FillSonPaths - fill son path components in mrule SYNOPSIS: static void FillSonPaths (MGIO_RR_RULE *rule) PAAMETERS: . rule - mrule DESCRIPTION: Fill son path components in mrule by recursion (using 'FindPathForNeighbours'). RETURN VALUE: void .n none doctext_disabled*/ /****************************************************************************/ #ifdef UG_DIM_3 static void FillSonPaths (MGIO_RR_RULE *rule) { SHORT Status[MAX_SONS]; /* TODO (HRR 971211): debug recursive path construction (taken from GenerateRules but not used by ugio) */ /* son 0 has trivial path */ Status[0] = NB_DONE; rule->sons[0].path = 0; for (int i = 1; i < rule->nsons; i++) Status[i] = NB_NOTDONE; /* start recursion with son 0 */ FindPathForNeighbours(rule,0,Status); } #endif /****************************************************************************/ /*doctext_disabled GetFSidesOfCorners - fill array for father side the given side corners belong to SYNOPSIS: static INT GetFSidesOfCorners (int tag, int n, SHORT corners[MAX_CORNERS_OF_SIDE], SHORT corner_on_side[MAX_CORNERS_OF_SIDE][MAX_SIDES_OF_ELEM]) PAAMETERS: . tag - father tag . n - number of side nodes . corners - side node local IDs . corner_on_side - YES/NO indicating corner lying on father side DESCRIPTION: Fill array for father side the given side corners belong to. RETURN VALUE: INT .n true: ok, maybe there is a common father side .n false: sorry, center node definitely not on a father side doctext_disabled*/ /****************************************************************************/ static bool GetFSidesOfCorners (int tag, int n, const SHORT corners[MAX_CORNERS_OF_SIDE], SHORT corner_on_side[MAX_CORNERS_OF_SIDE][MAX_SIDES_OF_ELEM]) { int coe = CORNERS_OF_TAG(tag); int eoe = EDGES_OF_TAG(tag); int soe = SIDES_OF_TAG(tag); for (int co = 0; co < n; co++) for (int side = 0; side < soe; side++) corner_on_side[co][side] = false; for (int co = 0; co < n; co++) if (corners[co]==coe+CENTER_NODE_INDEX_TAG(tag)) { /* center node: can not be part of a father side */ return false; } else if (corners[co]=0) corner_on_side[co][side] = true; } else if (corners[co]<(coe+eoe)) { /* edge mid node */ int ed = corners[co]-coe; #ifdef UG_DIM_2 corner_on_side[co][ed] = true; #else for (int i = 0; i < MAX_SIDES_OF_EDGE; i++) { int sd = SIDE_WITH_EDGE_TAG(tag,ed,i); if (sd>=0) corner_on_side[co][sd] = true; } #endif } #ifdef UG_DIM_3 else if (corners[co]<(coe+eoe+soe)) { /* side mid */ int sd = corners[co]-(coe+eoe); corner_on_side[co][sd] = true; } #endif else ASSERT(false); /* Huh??? */ return true; } /****************************************************************************/ /*doctext_disabled GetCommonFSide - return common father element side iff SYNOPSIS: static INT GetCommonFSide (int nco, int nsi, SHORT corner_on_side[MAX_CORNERS_OF_SIDE][MAX_SIDES_OF_ELEM]) PAAMETERS: . nco - number of corners on side . nsi - number of sides . corner_on_side - array filled by 'GetFSidesOfCorners' DESCRIPTION: Return common father element side iff. RETURN VALUE: INT .n father side if common for all side corners .n nsi else doctext_disabled*/ /****************************************************************************/ static INT GetCommonFSide (int nco, int nsi, SHORT corner_on_side[MAX_CORNERS_OF_SIDE][MAX_SIDES_OF_ELEM]) { for (int side = 0; side < nsi; side++) { int i; for (i = 0; i < nco; i++) if (!corner_on_side[i][side]) break; if (i>=nco) return (side); } return (nsi); } /****************************************************************************/ /*doctext_disabled IsOnFatherSide - determine whether son side lies on father side SYNOPSIS: static INT IsOnFatherSide (int tag, int nsco, SHORT sco[], SHORT *nb) PAAMETERS: . tag - father tag . nsco - number of side corners . sco - side corner array . nb - fill nb component with FATHER_SIDE_OFFSET+fside iff common father side DESCRIPTION: Determine whether son side lies on father side. RETURN VALUE: INT .n true: there is a common father side .n false: there is no common father side doctext_disabled*/ /****************************************************************************/ static bool IsOnFatherSide (int tag, int nsco, SHORT sco[], SHORT *nb) { SHORT sco_on_side[MAX_CORNERS_OF_SIDE][MAX_SIDES_OF_ELEM]; if (GetFSidesOfCorners(tag,nsco,sco,sco_on_side)) { int fside = GetCommonFSide(nsco,SIDES_OF_TAG(tag),sco_on_side); if (fsiderclass = GREEN_CLASS; mr->nsons = HR_NSONS(hr); for (int i = 0; i < MGIO_MAX_NEW_CORNERS; i++) mr->pattern[i] = 0; /* son tags, corners, sonandnode, pattern */ for (int s = 0; s < mr->nsons; s++) { struct mgio_sondata *sonData = &(mr->sons[s]); int nco = HR_NCO(hr,s); int j; int sd0; for (sd0=0; sd0nb[sd0] = NOTDONE; sonData->tag = REF2TAG(nco); DCorners2Corners(nco,HR_DCO(hr,s),sonData->corners); for (j=0; jcorners[j]-coe; if (newco<0) continue; /* TODO (HRR 971208): what about center node pattern for tets? */ mr->pattern[newco] = 1; mr->sonandnode[newco][0] = s; mr->sonandnode[newco][1] = j; } } /* son nb */ for (int s0 = 0; s0 < mr->nsons; s0++) { struct mgio_sondata *sonData0 = mr->sons+s0; for (int sd0 = 0; sd0 < MAX_SIDES_OF_ELEM; sd0++) if (sonData0->nb[sd0] == NOTDONE) { int stag0 = sonData0->tag; int nsco0 = CORNERS_OF_SIDE_TAG(stag0,sd0); SHORT sco0[MAX_CORNERS_OF_SIDE]; for (int j = 0; j < nsco0; j++) sco0[j] = sonData0->corners[CORNER_OF_SIDE_TAG(stag0,sd0,j)]; if (!IsOnFatherSide(HR_TAG(hr),nsco0,sco0,&(sonData0->nb[sd0]))) { bool found = false; /* find matching side of other son */ for (int s1 = s0+1; s1 < mr->nsons; s1++) { struct mgio_sondata *sonData1 = mr->sons+s1; for (int sd1 = 0; sd1 < MAX_SIDES_OF_ELEM; sd1++) { int stag1 = sonData1->tag; int nsco1 = CORNERS_OF_SIDE_TAG(stag1,sd1); if (nsco0==nsco1) { SHORT sco1[MAX_CORNERS_OF_SIDE]; {int j; for (j=0; jcorners[CORNER_OF_SIDE_TAG(stag1,sd1,j)];} if (SidesMatch(nsco0,sco0,sco1)) { /* neighbour found */ sonData0->nb[sd0] = s1; sonData1->nb[sd1] = s0; found = true; break; } } } if (found) break; } ASSERT(found); } } } #ifdef UG_DIM_3 /* 2D: not even in rm */ /* son path */ FillSonPaths(mr); #endif } /****************************************************************************/ /*doctext_disabled URule2Mrule - convert rule manager rule to MGIO_RR_RULE SYNOPSIS: static void URule2Mrule (const URULE *ur, MGIO_RR_RULE *mr) PAAMETERS: . ur - rule manager rule . mr - mgio rule DESCRIPTION: Convert rule manager rule to mgio rule. RETURN VALUE: void .n doctext_disabled*/ /****************************************************************************/ static void URule2Mrule (const URULE *ur, MGIO_RR_RULE *mr) { mr->rclass = ur->rclass; mr->nsons = ur->nsons; for (int j = 0; j < MGIO_MAX_NEW_CORNERS; j++) mr->pattern[j] = ur->pattern[j]; for (int j = 0; j < MGIO_MAX_NEW_CORNERS; j++) { mr->sonandnode[j][0] = ur->sonandnode[j][0]; mr->sonandnode[j][1] = ur->sonandnode[j][1]; } for (int j = 0; j < mr->nsons; j++) { struct mgio_sondata *sonData = &(mr->sons[j]); sonData->tag = ur->sons[j].tag; for (int k = 0; k < MGIO_MAX_CORNERS_OF_ELEM; k++) sonData->corners[k] = ur->sons[j].corners[k]; for (int k = 0; k < MGIO_MAX_SIDES_OF_ELEM; k++) sonData->nb[k] = ur->sons[j].nb[k]; sonData->path = ur->sons[j].path; } } static void WriteDebugInfo (void) { long N_rm=0,N_er=0; long Nelem_inspected = 0; long Nelem_not_inspected = 0; /* number of rules (rm+er) */ PrintDebug("------------- Write_RefRules statistics --------------\n"); PrintDebug("number of refrules:\n"); for (int tag = 0; tag < TAGS; tag++) { long n_rm = UGMAXRULE(tag); long n_er = global.maxrule[tag]-UGMAXRULE(tag); N_rm += n_rm; N_er += n_er; Nelem_inspected = global.nelem_inspected[tag]; Nelem_not_inspected += global.nelem_not_inspected[tag]; PrintDebug("tag %d: %3ld rm rules, %4ld extracted rules (elems inspected: %6ld yes %6ld no)\n", tag, n_rm, n_er, global.nelem_inspected[tag], global.nelem_not_inspected[tag]); } PrintDebug("total: %3ld rm rules, %4ld extracted rules (elems inspected: %6ld yes %6ld no)\n", N_rm, N_er, Nelem_inspected, Nelem_not_inspected); PrintDebug("------------------------------------------------------\n"); } INT NS_DIM_PREFIX GetOrderedSons (ELEMENT *theElement, MGIO_RR_RULE *theRule, NODE **NodeContext, ELEMENT **SonList, INT *nmax) { ELEMENT *NonorderedSonList[MAX_SONS]; *nmax = 0; if (GetAllSons(theElement,NonorderedSonList)) REP_ERR_RETURN(1); for (INT i = 0; i < theRule->nsons; i++) { INT found = 1; for (INT j = 0; j < CORNERS_OF_TAG(theRule->sons[i].tag); j++) if (NodeContext[theRule->sons[i].corners[j]] == NULL) { found=0; break; } if (!found) { SonList[i] = NULL; continue; } /* identify (hopefully) an element of SonList */ for (INT j = 0; NonorderedSonList[j] != NULL; j++) { found=0; for (INT l = 0; l < CORNERS_OF_TAG(theRule->sons[i].tag); l++) { const NODE *theNode = NodeContext[theRule->sons[i].corners[l]]; for (INT k = 0; k < CORNERS_OF_ELEM(NonorderedSonList[j]); k++) if (theNode==CORNER(NonorderedSonList[j],k)) { found++; break; } } if (found==CORNERS_OF_TAG(theRule->sons[i].tag)) { SonList[i] = NonorderedSonList[j]; *nmax = i+1; break; } else SonList[i] = NULL; } } return (0); } static int CheckNBrelations (MGIO_RR_RULE *mr, int rule, int tag) { int n = mr->nsons; int err=0; for (int s = 0; s < n; s++) { struct mgio_sondata *son = &(mr->sons[s]); int ns = SIDES_OF_TAG(son->tag); for (int i = 0; i < ns; i++) { int nb = son->nb[i]; if (nbsons[nb]); int nnbs = SIDES_OF_TAG(nbson->tag); int j; for (j=0; jnb[j]==s) break; if (j>=nnbs) { PrintDebug("ERROR: rule %d of %d, asym in son %d, nb %d\n",rule,tag,s,i); err++; } } } } return (err); } static void CheckMRules (MULTIGRID *mg, INT RefRuleOffset[], MGIO_RR_RULE *mrules) { int max_path_depth = 0; int use_bug_in_rule = true; short *bug_in_rule[TAGS]; INT MarkKey; if (MarkTmpMem(global.heap,&MarkKey)) use_bug_in_rule = false; else { bug_in_rule[0] = (short*) GetTmpMem(global.heap,global.maxrules*sizeof(short),MarkKey); if (bug_in_rule[0]==NULL) use_bug_in_rule = false; else { for (int t = 0; t < TAGS; t++) { bug_in_rule[t] = bug_in_rule[0] + RefRuleOffset[t]; for (int i = 0; i < global.maxrule[t]; i++) bug_in_rule[t][i] = false; } } } /* check symmetry of nb relations */ for (int tg = 0; tg < TAGS; tg++) { for (int i = 0; i < global.maxrule[tg]; i++) if (CheckNBrelations(mrules+RefRuleOffset[tg]+i,i,tg)) if (use_bug_in_rule) bug_in_rule[tg][i] = true; } for (int l = 0; l < TOPLEVEL(mg); l++) for (ELEMENT *elem = PFIRSTELEMENT(GRID_ON_LEVEL(mg,l )); elem != NULL; elem = SUCCE(elem)) if (NSONS(elem)>0) { int refi = REFINE(elem); int tag = TAG(elem); MGIO_RR_RULE *mr = mrules + RefRuleOffset[tag] + refi; long id = ID(elem); int nsons = mr->nsons; int coe = CORNERS_OF_TAG(tag); int soe = SIDES_OF_TAG(tag); NODE *nodes[MAX_REFINED_CORNERS_DIM]; NODE **newnodes = nodes+coe; INT maxsonex = 0; ELEMENT *sons[MAX_SONS]; int error = 0; /* check nsons */ if (NSONS(elem)!=nsons) PD_ERR(ER_DBG_RULE_VERBOSE,("ERROR in CheckMRules, elem %ld: NSONS(elem)!=mr->nsons\n",id),error); if (GetNodeContext(elem,nodes)) ASSERT(false); /* check pattern */ for (int i = 0; i < MAX_NEW_CORNERS_DIM; i++) if (mr->pattern[i]) { #ifndef ModelP if (newnodes[i]==NULL) PD_ERR(ER_DBG_RULE_VERBOSE,("ERROR in CheckMRules, elem %ld: pattern %d inconsistent (says ex but doesn't)\n",id,i),error); #endif } else { if (newnodes[i]!=NULL) PD_ERR(ER_DBG_RULE_VERBOSE,("ERROR in CheckMRules, elem %ld: pattern %d inconsistent (says nonex but does)\n",id,i),error); } /* check sons */ if (GetOrderedSons(elem,mr,nodes,sons,&maxsonex)) ASSERT(false); #ifndef ModelP if (maxsonex!=nsons) PD_ERR(ER_DBG_RULE_VERBOSE,("ERROR in CheckMRules, elem %ld: wrong number of sons (%d vs %d)\n",id,maxsonex,nsons),error); #endif for (int s = 0; s < maxsonex; s++) { ELEMENT *son = sons[s]; if (son!=NULL) { struct mgio_sondata *rson = &(mr->sons[s]); int nco = CORNERS_OF_ELEM(son); int nsi = SIDES_OF_ELEM(son); if (rson->tag!=TAG(son)) PD_ERR(ER_DBG_RULE_VERBOSE,("ERROR in CheckMRules, elem %ld: wrong tag of son %d (%d vs %d)\n",id,s,rson->tag,TAG(son)),error); /* check corners */ for (int co = 0; co < nco; co++) if (CORNER(son,co)!=nodes[rson->corners[co]]) PD_ERR(ER_DBG_RULE_VERBOSE,("ERROR in CheckMRules, elem %ld: corner %d of son %d inconsistent\n",id,co,s),error); /* check neighbours */ for (int si = 0; si < nsi; si++) { const ELEMENT *nb = NBELEM(son,si); if (nb!=NULL) { const ELEMENT *nbf = EFATHER(nb); if (nbf==elem) { /* check inner side */ #ifdef ModelP if (sons[rson->nb[si]]!=NULL) #endif if (nb!=sons[rson->nb[si]]) PD_ERR(ER_DBG_RULE_VERBOSE,("ERROR in CheckMRules, elem %ld: inner nb %d of son %d inconsistent\n",id,si,s),error); } else if (nbf!=NULL) { int j; /* check father side */ for (j=0; jnb[si]-FATHER_SIDE_OFFSET)) PD_ERR(ER_DBG_RULE_VERBOSE,("ERROR in CheckMRules, elem %ld: outer nb %d of son %d inconsistent\n",id,si,s),error); } } else { #ifndef ModelP if (rson->nb[si]0) { ELEMENT *nson = sons[0]; int path = rson->path; int pd = PATHDEPTH(path); int son_path_ok = false; int j; max_path_depth = MAX(max_path_depth,pd); for (j=0; j=SIDES_OF_ELEM(nson)) { PD_ERR(ER_DBG_RULE_VERBOSE,("ERROR in CheckMRules, elem %ld: path of son %d at %d has invalid side %s\n",id,s,j,ns),error); break; } nson = NBELEM(nson,ns); } if (nson!=son) PD_ERR(ER_DBG_RULE_VERBOSE,("ERROR in CheckMRules, elem %ld: wrong path of son %d\n",id,s),error) else son_path_ok = true; if (!son_path_ok) some_path_wrong = true; }*/ #endif #endif } } /*if (!some_path_wrong) PD_ERR(ER_DBG_RULE_VERBOSE,("FINE in CheckMRules (%c-rule), elem %ld: all paths ok\n",(refisonandnode[i][0]]!=NULL) if (CORNER(sons[mr->sonandnode[i][0]],mr->sonandnode[i][1]) != newnodes[i]) PD_ERR(ER_DBG_RULE_VERBOSE,("ERROR in CheckMRules, elem %ld: sonandnode %d inconsistent\n",id,i),error);*/ /* summary */ if (error) { PD(("in total %3d ERRORS in CheckMRules (%c-rule %3d of %d), elem %ld\n",error,(refi0: error D*/ /****************************************************************************/ INT NS_DIM_PREFIX NEW_Write_RefRules (MULTIGRID *mg, INT RefRuleOffset[], INT MarkKey, MGIO_RR_RULE **mrule_handle) { MGIO_RR_GENERAL rr_general; MGIO_RR_RULE *mrule; INT BotMarkKey; if (mg==NULL) REP_ERR_RETURN(1); global.heap = MGHEAP(mg); if (MarkTmpMem(global.heap,&BotMarkKey)) REP_ERR_RETURN(1); /* init rule counters (continue with last rule IDs of rm) */ /* TODO (HRR 971207): this is important for matching existing rules after loading a grid (coarsening) but CAUTION: refine should never address a rule beyond rm rules! */ for (int tag = 0; tag < TAGS; tag++) global.maxrule[tag] = UGMAXRULE(tag); #if (defined UG_DIM_3) || (defined __DEBUG_ER__) /* incomplete refrule set: extract non-existing rules that are realized in mg */ if (ExtractRules(mg)) REP_ERR_RETURN(1); #endif global.maxrules = 0; for (int tag = 0; tag < TAGS; tag++) global.maxrules += global.maxrule[tag]; /* write refrules general */ RefRuleOffset[0] = 0; for (int tag = 0; tag < TAGS; tag++) { if (tag>0) RefRuleOffset[tag] = RefRuleOffset[tag-1] + global.maxrule[tag-1]; rr_general.RefRuleOffset[tag] = RefRuleOffset[tag]; } rr_general.nRules = global.maxrules; if (Write_RR_General(&rr_general)) REP_ERR_RETURN(1); /* allocate MGIO_RR_RULE table (will stay in scope beyond this module) */ *mrule_handle = (MGIO_RR_RULE*) GetTmpMem(global.heap,global.maxrules*sizeof(MGIO_RR_RULE),MarkKey); if (*mrule_handle==NULL) REP_ERR_RETURN(1); /* write refrules */ mrule = *mrule_handle; for (int tag = 0; tag < TAGS; tag++) { int i; /* rm rules */ for (i=0; i START_UGDIM_NAMESPACE /****************************************************************************/ /* */ /* defines in the following order */ /* */ /* compile time constants defining static data size (i.e. arrays) */ /* other constants */ /* macros */ /* */ /****************************************************************************/ /****************************************************************************/ /* */ /* data structures exported by the corresponding source file */ /* */ /****************************************************************************/ /****************************************************************************/ /* */ /* definition of exported global variables */ /* */ /****************************************************************************/ /****************************************************************************/ /* */ /* function declarations */ /* */ /****************************************************************************/ INT GetOrderedSons (ELEMENT *theElement, MGIO_RR_RULE *theRule, NODE **NodeContext, ELEMENT **SonList, INT *nmax); INT NEW_Write_RefRules (MULTIGRID *mg, INT RefRuleOffset[], INT MarkKey, MGIO_RR_RULE **mrule_handle); INT ResetRefineTagsBeyondRuleManager (MULTIGRID *mg); END_UGDIM_NAMESPACE #endif dune-uggrid-2.11.0+dfsg/dune/uggrid/gm/evm.cc000066400000000000000000000322411513616443000206460ustar00rootroot00000000000000// SPDX-FileCopyrightText: Copyright © DUNE Project contributors, see file LICENSE.md in module root // SPDX-License-Identifier: LGPL-2.1-or-later // -*- tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- // vi: set et ts=4 sw=2 sts=2: /****************************************************************************/ /* */ /* File: evm.c */ /* */ /* Purpose: elementary vector manipulations */ /* */ /* Author: Klaus Johannsen */ /* Institut fuer Computeranwendungen */ /* Universitaet Stuttgart */ /* Pfaffenwaldring 27 */ /* 70569 Stuttgart */ /* internet: ug@ica3.uni-stuttgart.de */ /* */ /* History: 8.12.94 begin, ug3-version */ /* */ /* Remarks: */ /* */ /****************************************************************************/ /****************************************************************************/ /* */ /* include files */ /* system include files */ /* application include files */ /* */ /****************************************************************************/ #include #include #include #include #include #include #include #include #include #include "elements.h" #include "evm.h" USING_UG_NAMESPACE USING_UGDIM_NAMESPACE /****************************************************************************/ /* */ /* defines in the following order */ /* */ /* compile time constants defining static data size (i.e. arrays) */ /* other constants */ /* macros */ /* */ /****************************************************************************/ #define OneSixth 0.166666666666666667 /****************************************************************************/ /* */ /* data structures used in this source file (exported data structures are */ /* in the corresponding include file!) */ /* */ /****************************************************************************/ /****************************************************************************/ /* */ /* forward declarations of macros */ /* */ /****************************************************************************/ #define MIN_DETERMINANT 0.0001*SMALL_C /****************************************************************************/ /****************************************************************************/ /****************************************************************************/ /**** ****/ /**** 2D routines ****/ /**** ****/ /****************************************************************************/ /****************************************************************************/ /****************************************************************************/ /****************************************************************************/ /*D M3_Invert - Calculate inverse of a 3x3 DOUBLE matrix SYNOPSIS: INT M3_Invert (DOUBLE *Inverse, const DOUBLE *Matrix); PARAMETERS: . Inverse - inverse of matrix . Matrix - matrix DESCRIPTION: This function calculates inverse of a 3x3 DOUBLE matrix. The entries of the matrices are given in a linear array with the following order - .vb | Matrix[0] Matrix[1] Matrix[2]| | Matrix[3] Matrix[4] Matrix[5]| | Matrix[6] Matrix[7] Matrix[8]| .ve RETURN VALUE: INT .n 0 when ok .n 1 when matrix is nearly singular. D*/ /****************************************************************************/ INT NS_DIM_PREFIX M3_Invert (DOUBLE *Inverse, const DOUBLE *Matrix) { DOUBLE determinant,invdet; INT i,i1,i2, j,j1,j2; for (i=0; i<3; i++) { i1 = (i+1)%3; i2 = (i+2)%3; for ( j=0; j<3; j++) { j1 = (j+1)%3; j2 = (j+2)%3; Inverse[j+3*i] = Matrix[i1+3*j1]*Matrix[i2+3*j2] - Matrix[i1+3*j2]*Matrix[i2+3*j1]; } } determinant = Inverse[0+3*0]*Matrix[0+3*0] + Inverse[0+3*1]*Matrix[1+3*0] + Inverse[0+3*2]*Matrix[2+3*0]; /* check the determinant */ if (fabs(determinant) > MIN_DETERMINANT) { invdet = 1.0/determinant; for (i=0; i<3; i++) for (j=0; j<3; j++) Inverse[i+3*j] *= invdet; return(0); } return(1); } /****************************************************************************/ /*D vp - Return positive number if vector 2 is "left" of vector 1 SYNOPSIS: DOUBLE vp (const DOUBLE x1, const DOUBLE y1, const DOUBLE x2, const DOUBLE y2); PARAMETERS: . x1,y1 - coordinates of a 2D vector . x2,y2 - coordinates of a 2D vector DESCRIPTION: This function returns positive number if vector 2 is "left" of vector 1, i.e. the third component of the vector product of (x1,y1,0) and (x2,y2,0). RETURN VALUE: DOUBLE D*/ /****************************************************************************/ DOUBLE NS_DIM_PREFIX vp (const DOUBLE x1, const DOUBLE y1, const DOUBLE x2, const DOUBLE y2) { DOUBLE l1,l2; l1 = sqrt(x1*x1+y1*y1); l2 = sqrt(x2*x2+y2*y2); if ((l1& a) { DOUBLE norm; V3_EUKLIDNORM(a,norm); if (norm < SMALL_C) return(2); V3_SCALE(1.0/norm,a); return(0); } /* Volume computations, orientation is same as in general element definition ! Idea of the computations: All the shapes are subdivided into pyramids whose bases are either triangles or quadrilaterals. The volume of any pyramid is V = S h / 3 where S is area of the base and h is height of the pyramid. The areas of the triangles and the quadrilaterals are computed by means of vector products. The height of the pyramid is then taken into account using scalar products. */ /* 1. Volume of a tetrahedron. A tetrahedron is a prism with a triangular base. */ DOUBLE NS_DIM_PREFIX V_te (const DOUBLE *x0, const DOUBLE *x1, const DOUBLE *x2, const DOUBLE *x3) { FieldVector a, b, h, n; V3_SUBTRACT(x1,x0,a); V3_SUBTRACT(x2,x0,b); V3_SUBTRACT(x3,x0,h); V3_VECTOR_PRODUCT(a,b,n); return(OneSixth*V3_SCAL_PROD(n,h)); } /* 2. Volume of an UG pyramid. An UG pyramid is a pyramid with a quadrilateral as the base. */ DOUBLE NS_DIM_PREFIX V_py (const DOUBLE *x0, const DOUBLE *x1, const DOUBLE *x2, const DOUBLE *x3, const DOUBLE *x4) { FieldVector a,b,h,n; V3_SUBTRACT(x2,x0,a); V3_SUBTRACT(x3,x1,b); V3_SUBTRACT(x4,x0,h); V3_VECTOR_PRODUCT(a,b,n); return(OneSixth*V3_SCAL_PROD(n,h)); } /* 3. Volume of an UG prism. An UG prism is a shape with two (in general non-parallel) bases that are triangles and four sides that are quadrilaterals. This 'prism' is subdivided into two pyramids: a) {x0, x_1, x_4, x_3; x_5} b) {x_0, x_1, x_2; x_5} (a tetrahedron) */ DOUBLE NS_DIM_PREFIX V_pr (const DOUBLE *x0, const DOUBLE *x1, const DOUBLE *x2, const DOUBLE *x3, const DOUBLE *x4, const DOUBLE *x5) { FieldVector a,b,c,d,e,m,n; V3_SUBTRACT(x4,x0,a); V3_SUBTRACT(x1,x3,b); V3_SUBTRACT(x1,x0,c); V3_SUBTRACT(x2,x0,d); V3_SUBTRACT(x5,x0,e); V3_VECTOR_PRODUCT(a,b,m); V3_VECTOR_PRODUCT(c,d,n); V3_ADD(n,m,n); return(OneSixth*V3_SCAL_PROD(n,e)); } /* 4. Volume of an UG hexahedron. An UG hexahedron is subdivided into two UG prisms. */ DOUBLE NS_DIM_PREFIX V_he (const DOUBLE *x0, const DOUBLE *x1, const DOUBLE *x2, const DOUBLE *x3, const DOUBLE *x4, const DOUBLE *x5, const DOUBLE *x6, const DOUBLE *x7) { return(V_pr(x0,x1,x2,x4,x5,x6)+V_pr(x0,x2,x3,x4,x6,x7)); } DOUBLE NS_DIM_PREFIX GeneralElementVolume (INT tag, DOUBLE *x_co[]) { switch (tag) { # ifdef UG_DIM_2 case TRIANGLE : return(c_tarea (x_co[0],x_co[1],x_co[2])); case QUADRILATERAL : return(c_qarea (x_co[0],x_co[1],x_co[2],x_co[3])); # endif # ifdef UG_DIM_3 case TETRAHEDRON : return(V_te(x_co[0],x_co[1],x_co[2],x_co[3])); case PYRAMID : return (V_py(x_co[0],x_co[1],x_co[2],x_co[3],x_co[4])); case PRISM : return (V_pr(x_co[0],x_co[1],x_co[2],x_co[3],x_co[4],x_co[5])); case HEXAHEDRON : return(V_he(x_co[0],x_co[1],x_co[2],x_co[3],x_co[4],x_co[5],x_co[6],x_co[7])); # endif default : PrintErrorMessage('E',"GeneralElementVolume","unknown element"); return(0.0); } } DOUBLE NS_DIM_PREFIX ElementVolume (const ELEMENT *elem) { DOUBLE *x_co[MAX_CORNERS_OF_ELEM]; INT i; for (i=0; i #include #include #include #include #include "gm.h" START_UGDIM_NAMESPACE /****************************************************************************/ /* */ /* defines in the following order */ /* */ /* compile time constants defining static data size (i.e. arrays) */ /* other constants */ /* macros */ /* */ /****************************************************************************/ /****************************************************************************/ /* */ /* macros */ /* */ /****************************************************************************/ /* macros for 2D vector operations */ #define V2_LINCOMB(a,A,b,B,C) {(C)[0] = (a)*(A)[0] + (b)*(B)[0];\ (C)[1] = (a)*(A)[1] + (b)*(B)[1];} #define V2_COPY(A,C) {(C)[0] = (A)[0];\ (C)[1] = (A)[1];} #define V2_SUBTRACT(A,B,C) {(C)[0] = (A)[0] - (B)[0];\ (C)[1] = (A)[1] - (B)[1];} #define V2_ADD(A,B,C) {(C)[0] = (A)[0] + (B)[0];\ (C)[1] = (A)[1] + (B)[1];} #define V2_SCALE(c,C) {(C)[0] = (c)*(C)[0];\ (C)[1] = (c)*(C)[1];} #define V2_VECTOR_PRODUCT(A,B,c) (c) = (A)[0]*(B)[1] - (A)[1]*(B)[0]; #define V2_ISEQUAL(A,B) ((std::abs((A)[0]-(B)[0])& a); /* volume calculations*/ DOUBLE GeneralElementVolume (INT tag, DOUBLE *x_co[]); DOUBLE ElementVolume (const ELEMENT *elem); END_UGDIM_NAMESPACE #endif dune-uggrid-2.11.0+dfsg/dune/uggrid/gm/gm.h000066400000000000000000003617431513616443000203400ustar00rootroot00000000000000// -*- tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- // vi: set et ts=4 sw=2 sts=2: // SPDX-FileCopyrightInfo: Copyright © DUNE Project contributors, see file LICENSE.md in module root // SPDX-License-Identifier: LGPL-2.1-or-later /*! \file gm.h * \ingroup gm */ /******************************************************************************/ /* */ /* File: gm.h */ /* */ /* Purpose: grid manager header file (the heart of ug) */ /* */ /* Author: Peter Bastian, Klaus Johannsen */ /* */ /* Institut fuer Computeranwendungen III */ /* Universitaet Stuttgart */ /* Pfaffenwaldring 27 */ /* 70569 Stuttgart */ /* email: ug@ica3.uni-stuttgart.de */ /* */ /* blockvector data structure: */ /* Christian Wrobel */ /* Institut fuer Computeranwendungen III */ /* Universitaet Stuttgart */ /* Pfaffenwaldring 27 */ /* 70569 Stuttgart */ /* email: ug@ica3.uni-stuttgart.de */ /* */ /* History: 09.03.92 begin, ug version 2.0 (as ugtypes2.h) */ /* 13.12.94 begin, ug version 3.0 */ /* 27.09.95 blockvector implemented (Christian Wrobel) */ /* */ /* Remarks: */ /* */ /* */ /******************************************************************************/ /****************************************************************************/ /* */ /* auto include mechanism and other include files */ /* */ /****************************************************************************/ #ifndef __GM__ #define __GM__ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "pargm.h" #include "cw.h" #include #ifdef ModelP # include #endif /****************************************************************************/ /* */ /* derive additional switches from commandline specified basic switches */ /* */ /****************************************************************************/ #ifdef Debug #define DEBUG_MODE "ON" #else #define DEBUG_MODE "OFF" #endif START_UGDIM_NAMESPACE /****************************************************************************/ /* */ /* "hard" switches for interpolation matrix and block-vectors */ /* */ /****************************************************************************/ /** \brief Define to have matrices > 4KB (control word too small, adds integer to matrix struct) */ #define __XXL_MSIZE__ /** \brief If pointer between element/centernode is stored */ #undef __CENTERNODE__ /****************************************************************************/ /* */ /* defines in the following order */ /* */ /* compile time constants defining static data size (i.e. arrays) */ /* other constants */ /* macros */ /* */ /****************************************************************************/ /* Necessary for most C runtime libraries */ #undef DOMAIN /** @name Some size parameters */ /*@{*/ /** \brief maximum depth of triangulation */ #define MAXLEVEL 32 /** \brief use 5 bits for object identification */ #define MAXOBJECTS 32 /*@}*/ /** @name Some size macros for allocation purposes */ /*@{*/ #ifdef UG_DIM_2 /** \brief max number of sides of an element */ #define MAX_SIDES_OF_ELEM 4 /** \brief max number of edges of an element */ #define MAX_EDGES_OF_ELEM 4 /** \brief max number of corners of an element */ #define MAX_CORNERS_OF_ELEM 4 /** \brief max number of edges of a side */ #define MAX_EDGES_OF_SIDE 1 /** \brief max number of edges meeting in a corner */ #define MAX_EDGES_OF_CORNER 2 /** \brief max number of corners of a side */ #define MAX_CORNERS_OF_SIDE 2 /** \brief two sides have one edge in common */ #define MAX_SIDES_OF_EDGE 2 /** \brief max number of sons of an element */ enum {MAX_SONS = 4}; /** \brief max number of nodes on elem side */ #define MAX_SIDE_NODES 3 #else // UG_DIM_3 /** \brief max number of sides of an element */ #define MAX_SIDES_OF_ELEM 6 /** \brief max number of edges of an element */ #define MAX_EDGES_OF_ELEM 12 /** \brief max number of corners of an element */ #define MAX_CORNERS_OF_ELEM 8 /** \brief max number of edges of a side */ #define MAX_EDGES_OF_SIDE 4 /** \brief max number of edges meeting in a corner */ #define MAX_EDGES_OF_CORNER 4 /** \brief max number of corners of a side */ #define MAX_CORNERS_OF_SIDE 4 /** \brief two sides have one edge in common */ #define MAX_SIDES_OF_EDGE 2 /** \brief max number of sons of an element */ enum {MAX_SONS = 30}; /** \brief max number of nodes on elem side */ #define MAX_SIDE_NODES 9 #endif /** \brief an edge has always two corners.. */ #define CORNERS_OF_EDGE 2 /** \brief max number of son edges of edge */ #define MAX_SON_EDGES 2 /** \brief max number of doubles in a vector or matrix mod 32 */ #define MAX_NDOF_MOD_32 256 /** \brief max number of doubles in a vector or matrix */ #define MAX_NDOF 32*MAX_NDOF_MOD_32 /*@}*/ /****************************************************************************/ /* */ /* defines for algebra */ /* */ /****************************************************************************/ /** \brief Number of different data types */ #define MAXVOBJECTS 1 /** \brief max number of abstract vector types */ #define MAXVECTORS 1 #if (MAXVECTORSiv.topnode) */ /****************************************************************************/ /* */ /* format definition data structure */ /* */ /****************************************************************************/ /*----------- general typedefs ---------------------------------------------*/ /** @name General typedefs */ /*@{*/ using DOUBLE_VECTOR = FieldVector; /*@}*/ /*----------- definition of structs ----------------------------------------*/ /****************************************************************************/ /* */ /* matrix/vector/blockvector data structure */ /* */ /****************************************************************************/ /** \brief Data type for unknowns in sparse matrix structure The VECTOR data type is part of the sparse matrix vector data structure. A VECTOR stores a user definable number of DOUBLE values and is associated with a geometric object of the mesh (nodes, edges, sides and elements). The size of the VECTOR can be specified differently for each type of geometric object, but not (yet) for each individual VECTOR object. Since there are four different geometric objects that can have degrees of freedom, there are four different `vector types`. The vector type is stored in the control word (see VTYPE macro) but currently it can only have the value SIDEVECTOR. The VECTOR provides access to the rows of the sparse matrix belonging to all degrees of freedom stored in the vector. MACROS: `General macros in control word` \verbatim Macro name Pos Len Purpose ----------------------------------------------------------------------------- INT OBJT (VECTOR *p); 27 5 Object type VEOBJ void SETOBJT (VECTOR *p, INT n); INT USED (VECTOR *p); 23 1 used only temporarily void SETUSED (VECTOR *p, INT n); INT TAG (VECTOR *p); 24 3 not used void SETTAG (VECTOR *p, INT n); INT THEFLAG (VECTOR *p); 16 1 used only temporarily void SETTHEFLAG (VECTOR *p, INT n); ----------------------------------------------------------------------------- \endverbatim `Macros for the VECTOR structure in control` \verbatim Macro name Pos Len Purpose ----------------------------------------------------------------------------- VTYPE (VECTOR *v); 0 2 Type of geometric object the SETVTYPE (VECTOR *v, INT n); vector belongs to. Values: NODEVECTOR, EDGEVECTOR, SIDEVECTOR or ELEMVECTOR. VCOUNT (VECTOR *v); 5 2 internal use SETVCOUNT (VECTOR *v, INT n); VECTORSIDE (VECTOR *v); 7 2 Side in VOBJECT where VECTOR SETVECTORSIDE (VECTOR *v, INT n); belongs to (SIDEVECTOR only) VCLASS (VECTOR *v); 11 2 Vector class for local multigrid SETVCLASS (VECTOR *v, INT n); between 0 and 3. VDATATYPE (VECTOR *v); 13 4 This is 2^VTYPE(v) SETVDATATYPE (VECTOR *v, INT n); VNCLASS (VECTOR *v); 17 2 Vector class of vector at same SETVNCLASS (VECTOR *v, INT n); position on finer level VNEW (VECTOR *v); 19 1 True if VECTOR has been created SETVNEW (VECTOR *v, INT n); in last refinement step. VCNEW (VECTOR *v); 20 1 True if VECTOR got a new SETVCNEW (VECTOR *v, INT n); connection in refinement ----------------------------------------------------------------------------- \endverbatim \sa NODE, EDGE, ELEMENT. */ struct vector { /** \brief object identification, various flags */ UINT control; /** \brief associated geometric object */ union geom_object *object; #ifdef ModelP /** \todo Please doc me! */ DDD_HEADER ddd; #endif /** \brief double linked list of vectors */ struct vector *pred,*succ; /** \brief ordering of unknowns */ UINT index; /** \brief Index if the vector is part of the leaf grid */ UINT leafIndex; #ifndef ModelP // Dune uses ddd.gid for ids in parallel /** \brief A unique and persistent, but not necessarily consecutive index Used to implement face ids for Dune. */ INT id; #endif /** \brief User data * * Array of double values. This array is allocated dynamically with the * size specified in the FORMAT structure. */ DOUBLE value[1]; }; typedef struct vector VECTOR; /****************************************************************************/ /* */ /* unstructured grid data structures */ /* */ /****************************************************************************/ /*----------- typedef for functions ----------------------------------------*/ /*----------- definition of structs ----------------------------------------*/ /** \brief Inner vertex data structure Data type storing level-independent node information The VERTEX structure stores the level independent information of a NODE. If several NODEs on different levels of the MULTIGRID structure are at the same position then they share a common VERTEX object. The VERTEX is a union of inner vertex ivertex and boundary vertex bvertex. The bvertex has all of the ivertex plus some extra information where the vertex is on the boundary of the domain. In the code one always works with pointers of type VERTEX * and accesses the components through the macros described below. CONTROL WORDS: The first word of many UG data structure is used bitwise for various purposes. `General macros available for all objects` \verbatim Macro name Pos Len Purpose ----------------------------------------------------------------------------- INT OBJT (VERTEX *p); 27 5 Object type IVOBJ for inner void SETOBJT (VERTEX *p, INT n); and BVOBJ for boundary vertex INT USED (VERTEX *p); 23 1 used only temporarily void SETUSED (VERTEX *p, INT n); INT TAG (VERTEX *p); 24 3 available for user void SETTAG (VERTEX *p, INT n); INT LEVEL (VERTEX *p); 17 5 level on which vertex is void SETLEVEL (VERTEX *p, INT n); defined INT THEFLAG (VERTEX *p); 16 1 used only temporarily void SETTHEFLAG (VERTEX *p, INT n); ----------------------------------------------------------------------------- \endverbatim `Macros specific to the VERTEX structure` \verbatim Macro name Pos Len Purpose ----------------------------------------------------------------------------- INT MOVE (VERTEX *p); 4 2 Number of dimensions in which void SETMOVE (VERTEX *p, INT n); a vertex can be moved: 0: vertices at corners 1: boundary vertex in 2D 2: inner in 2D, boundary in 3D 3: inner in 3D INT MOVED (VERTEX *p); 0 1 TRUE if vertex has been moved void SETMOVED (VERTEX *p, INT n); away from initial position. INT ONEDGE (VERTEX *p); 1 3 Edge in father element of vertex void SETONEDGE (VERTEX *p, INT n); on which this vertex resides. 2D: only valid for boundary vertex! ----------------------------------------------------------------------------- \endverbatim D*/ struct ivertex { /** \brief Object identification, various flags */ UINT control; /** \brief Unique id used for load/store */ INT id; /** \brief Vertex position */ FieldVector x; /** \brief Local coordinates in father element * * This is used to represent the multigrid hierarchy. The father component points * to an ELEMENT of the next coarser grid level and xi gives the position of the VERTEX * within this element in the local coordinate system of the ELEMENT. In this way * also loosely coupled grids can be represented although the grid refinement algorithm * is currently not able to produce such grids. The solvers however would work * also on much more general multigrid hierarchies. */ FieldVector xi; /* When UG is used as part of the DUNE numerics system we need a few more indices per node */ /** \brief An index hat is unique and consecutive per level. Controlled by DUNE */ int leafIndex; #ifdef ModelP /** \todo Please doc me! */ DDD_HEADER ddd; #endif /** \brief Doubly linked list of vertices * * Pointers realizing a double linked list of VERTEX objects per level. * The beginning of this list is in the GRID structure. */ union vertex *pred,*succ; /** \brief Associated user data structure */ void *data; /** \brief Father element */ union element *father; #ifdef TOPNODE /** \brief Highest node where defect is valid \todo REMARK: TOPNODE no more available since 970411 because of problems in parallelisation to use it in serial version uncomment define TOPNODE If several NODES share this VERTEX then this pointer refers to the NODE on the highest level. This pointer will probably `not` be supported in the next version, its use is not recommended! */ struct node *topnode; #endif }; /** \brief Boundary vertex data structure Data type storing level-independent node information The VERTEX structure stores the level independent information of a NODE. If several NODEs on different levels of the MULTIGRID structure are at the same position then they share a common VERTEX object. The VERTEX is a union of inner vertex ivertex and boundary vertex bvertex. The bvertex has all of the ivertex plus some extra information where the vertex is on the boundary of the domain. In the code one always works with pointers of type VERTEX * and accesses the components through the macros described below. CONTROL WORDS: The first word of many UG data structure is used bitwise for various purposes. `General macros available for all objects` \verbatim Macro name Pos Len Purpose ----------------------------------------------------------------------------- INT OBJT (VERTEX *p); 27 5 Object type IVOBJ for inner void SETOBJT (VERTEX *p, INT n); and BVOBJ for boundary vertex INT USED (VERTEX *p); 23 1 used only temporarily void SETUSED (VERTEX *p, INT n); INT TAG (VERTEX *p); 24 3 available for user void SETTAG (VERTEX *p, INT n); INT LEVEL (VERTEX *p); 17 5 level on which vertex is void SETLEVEL (VERTEX *p, INT n); defined INT THEFLAG (VERTEX *p); 16 1 used only temporarily void SETTHEFLAG (VERTEX *p, INT n); ----------------------------------------------------------------------------- \endverbatim `Macros specific to the VERTEX structure` \verbatim Macro name Pos Len Purpose ----------------------------------------------------------------------------- INT MOVE (VERTEX *p); 4 2 Number of dimensions in which void SETMOVE (VERTEX *p, INT n); a vertex can be moved: 0: vertices at corners 1: boundary vertex in 2D 2: inner in 2D, boundary in 3D 3: inner in 3D INT MOVED (VERTEX *p); 0 1 TRUE if vertex has been moved void SETMOVED (VERTEX *p, INT n); away from initial position. INT ONEDGE (VERTEX *p); 1 3 Edge in father element of vertex void SETONEDGE (VERTEX *p, INT n); on which this vertex resides. 2D: only valid for boundary vertex! ----------------------------------------------------------------------------- \endverbatim D*/ struct bvertex { /* variables */ /** \brief Object identification, various flags */ UINT control; /** \brief Unique id used for load/store */ INT id; /** \brief Vertex position */ FieldVector x; /** \brief Local coordinates in father element * * This is used to represent the multigrid hierarchy. The father component points * to an ELEMENT of the next coarser grid level and xi gives the position of the VERTEX * within this element in the local coordinate system of the ELEMENT. In this way * also loosely coupled grids can be represented although the grid refinement algorithm * is currently not able to produce such grids. The solvers however would work * also on much more general multigrid hierarchies. */ FieldVector xi; /* When UG is used as part of the DUNE numerics system we need a few more indices per node */ /** \brief An index hat is unique and consecutive per level. Controlled by DUNE */ int leafIndex; #ifdef ModelP /** \brief Information about the parallelization of this object */ DDD_HEADER ddd; #endif /* pointers */ /** \brief Doubly linked list of vertices */ union vertex *pred,*succ; /** \brief Associated user data structure */ void *data; /** \brief Father element */ union element *father; #ifdef TOPNODE /** \brief Highest node where defect is valid \todo REMARK: TOPNODE no more available since 970411 because of problems in parallelisation to use it in serial version uncomment define TOPNODE */ struct node *topnode; #endif /** \brief Pointer to boundary point descriptor */ BNDP *bndp; }; /** \brief Only used to define pointer to vertex */ union vertex { struct ivertex iv; struct bvertex bv; }; /** \brief Level-dependent part of a vertex Each node of the mesh is represented by a NODE structure. When a mesh is refined then new NODE objects are allocated on the new grid level even at those positions where nodes were already in the coarse mesh. However, NODEs at the same position share a common VERTEX structure. A node provides access to all neighboring nodes via the LINK structure. There is `no` access from a node to all the elements having the node as a corner! CONTROL WORDS: `General macros available for all objects` \verbatim Macro name Pos Len Purpose ----------------------------------------------------------------------------- INT OBJT (NODE *p); 27 5 Object type NDOBJ for a node. void SETOBJT (NODE *p, INT n); INT USED (NODE *p); 23 1 used only temporarily void SETUSED (NODE *p, INT n); INT TAG (NODE *p); 24 3 available for user void SETTAG (NODE *p, INT n); INT LEVEL (NODE *p); 17 5 level on which node is void SETLEVEL (NODE *p, INT n); allocated INT THEFLAG (NODE *p); 16 1 used only temporarily void SETTHEFLAG (NODE *p, INT n); ----------------------------------------------------------------------------- \endverbatim `Macros for the NODE structure` \verbatim Macro name Pos Len Purpose ----------------------------------------------------------------------------- INT CLASS (NODE *p); 0 3 node class for local multigrid void SETCLASS (NODE *p, INT n); only for backward compatibility INT NCLASS (NODE *p); 3 3 node class for node on next level void SETNCLASS (NODE *p, INT n); only for backward compatibility INT MODIFIED (NODE *p); 6 1 is true when node has been created void SETMODIFIED (NODE *p, INT n); or modified during last refinement step. This in 2D only ! INT NPROP (NODE *p); 7 8 node property derived from void SETNPROP (NODE *p, INT n); element property. ----------------------------------------------------------------------------- \endverbatim \sa VERTEX, LINK, GRID. D*/ struct node { /** \brief Object identification, various flags */ UINT control; /** \brief Unique id used for load/store */ INT id; /* When UG is used as part of the DUNE numerics system we need a few more indices per node */ /** \brief An index hat is unique and consecutive per level. Controlled by DUNE */ int levelIndex; /** \brief Information if this node is on the leaf. */ bool isLeaf; #ifdef ModelP /** \brief Per-node message buffer used by Dune for dynamic load-balancing */ char* message_buffer_; /** \brief Size of the `message_buffer` */ std::size_t message_buffer_size_; #endif #ifdef ModelP /** \brief Information about the parallelization of this object */ DDD_HEADER ddd; #endif /* pointers */ /** \brief Doubly linked list of nodes per level*/ struct node *pred,*succ; /** \brief List of links * * Points to the first element of the LINK list. The LINK list * provides access to all neighbors of the node. */ struct link *start; /** \brief Node or edge on coarser level (NULL if none) */ union geom_object *father; /** \brief Node on finer level (NULL if none) */ struct node *son; /** \brief Corresponding vertex structure */ union vertex *myvertex; #ifdef ModelP const char* message_buffer() const { return message_buffer_; } std::size_t message_buffer_size() const { return message_buffer_size_; } void message_buffer(char* p, std::size_t size) { message_buffer_ = p; message_buffer_size_ = size; } void message_buffer_free() { std::free(message_buffer_); message_buffer(nullptr, 0); } #endif }; /** \brief Data type realizing a list of neighbors of a node The \ref link structures form a single linked list starting in each NODE. Two nodes are said to be neighbors if they are connected by an edge `in the mesh`. Note that this is only the geometric neighborship, which can be different from the algebraic neighborship derived from the non-zero structure of the global stiffness matrix. Each LINK provides a pointer to one neighbor of the NODE where the list starts. The neighbor relationship is symmetric, therefore if node `a` is a neighbor of node `b` then `a` occurs in the list of `b` and vice versa. These two link structures are then combined in an EDGE structure. MACROS: #NBNODE(LINK *p) #NEXT(LINK *p) #MYEDGE(LINK *p) #REVERSE (LINK *p) CONTROL WORDS: `General macros available for all objects` \verbatim Macro name Pos Len Purpose ----------------------------------------------------------------------------- INT OBJT (LINK *p); 27 5 Object type EDOBJ for first void SETOBJT (LINK *p, INT n); LINK of an EDGE INT USED (LINK *p); 23 1 used only temporarily void SETUSED (LINK *p, INT n); INT THEFLAG (LINK *p); 16 1 used only temporarily void SETTHEFLAG (LINK *p, INT n); ----------------------------------------------------------------------------- \endverbatim `Macros for the LINK structure` \verbatim Macro name Pos Len Purpose ----------------------------------------------------------------------------- INT LOFFSET (LINK *p); 0 1 0 if first LINK of EDGE void SETLOFFSET (LINK *p, INT n); 1 if second LINK of EDGE ----------------------------------------------------------------------------- \endverbatim \sa edge, node */ struct link { /** \brief object identification, various flags */ UINT control; /** \brief ptr to next link */ struct link *next; /** \brief ptr to neighbor node */ struct node *nbnode; /** \brief ptr to neighboring elem */ #if defined(UG_DIM_2) union element *elem; #endif }; /** \brief Undirected edge of the grid graph The EDGE data type combines LINK structures to form an `undirected` connection of two NODEs. An EDGE represents an edge of the mesh. CONTROL WORDS: `General macros available for all objects` \verbatim Macro name Pos Len Purpose ----------------------------------------------------------------------------- INT OBJT (EDGE *p); 27 5 Object type EDOBJ for an edge void SETOBJT (EDGE *p, INT n); INT USED (EDGE *p); 23 1 used only temporarily void SETUSED (EDGE *p, INT n); INT LEVEL (EDGE *p); 17 5 level on which edge is void SETLEVEL (EDGE *p, INT n); allocated INT THEFLAG (EDGE *p); 16 1 used only temporarily void SETTHEFLAG (EDGE *p, INT n); ----------------------------------------------------------------------------- \endverbatim `Macros for the EDGE structure` \verbatim Macro name Pos Len Purpose ----------------------------------------------------------------------------- INT EOFFSET (EDGE *p); 0 1 Overlay with bit from LINK void SETEOFFSET (EDGE *p, INT n); INT EXTRA (EDGE *p); 1 1 True if additional edge is void SETEXTRA (EDGE *p, INT n); diagonal of quadrilateral. This is provided for backward compatibility INT NO_OF_ELEM (EDGE *p); 2 7 Number of elements sharing the void SET_NO_OF_ELEM (EDGE *p, INT n); given edge. This is provided void INC_NO_OF_ELEM (EDGE *p); only in 3D version void DEC_NO_OF_ELEM (EDGE *p); INT EDGENEW (EDGE *p); 16 1 True if edge has been created in void SETEDGENEW (EDGE *p, INT n); last refinement step. 3D only! ----------------------------------------------------------------------------- \endverbatim \sa LINK */ struct edge { /** \brief The two links that make up this edge * * LINKs are always allocated pairwise and in consecutive memory locations. * This allows to switch easily from a given LINK to the LINK in reverse direction or to the EDGE. */ struct link links[2]; /* When UG is used as part of the DUNE numerics system we need place to store codim dim-1 indices */ /** \brief An index hat is unique and consecutive per level. Controlled by DUNE */ int levelIndex; /** \brief An index hat is unique and consecutive on the grid surface. Controlled by DUNE */ int leafIndex; /** \brief A unique and persistent, but not necessarily consecutive index */ INT id; #ifdef ModelP /** Bookkeeping information for DDD */ DDD_HEADER ddd; #endif /** \brief Pointer to mid node on next finer grid * * In 3D a pointer to the node created on the midpoint of an edge is * needed during refinement (This is because many elements share an edge in 3D). */ struct node *midnode; /** \brief associated vector * * WARNING: the allocation of the vector pointer depends on the format */ VECTOR *vector; }; /** \brief A generic grid element No difference between inner and boundary elements */ struct generic_element { /** \brief object identification, various flags */ UINT control; /** \brief unique id used for load/store */ INT id; /** \brief additional flags for elements * A lot of information requiring only a small number of bits must be stored * for each element. Therefore a second control word, the flag, has been introduced. * The flag is also used bitwise. */ UINT flag; /** \brief to store NodeOrder for hexahedrons * * Since control and flag were full, a third word had to be introduced that * can be used bitwise. A part of this word stores the element property, which is simple * a number per element. This number can be used to distinguish different materials * for example. */ INT property; /* When UG is used as part of the DUNE numerics system we need a few more indices per element */ /** \brief An index hat is unique and consecutive per level. Controlled by DUNE */ int levelIndex; /** \brief An index hat is unique and consecutive on the grid surface. Controlled by DUNE */ int leafIndex; #ifdef ModelP /** \brief Per-node message buffer used by Dune for dynamic load-balancing */ char* message_buffer; /** \brief Size of the `message_buffer` */ std::size_t message_buffer_size; #endif #ifdef ModelP /** \brief Information about the parallelization of this object */ DDD_HEADER ddd; /** \brief Stores partition information */ INT lb1; #endif /** \brief double linked list of elements */ union element *pred, *succ; #ifdef __CENTERNODE__ /** \brief Pointer to center node */ struct node *centernode; #endif /** \brief Element specific part of variable length array managed by ug */ void *refs[1]; }; /** \brief A triangle element in a 2d grid \implements generic_element */ struct triangle { /** \brief Object identification, various flags */ UINT control; /** \brief Unique id used for load/store */ INT id; /** \brief Additional flags for elements */ UINT flag; /** \brief Even more property bits */ INT property; /* When UG is used as part of the DUNE numerics system we need a few more indices per element */ /** \brief An index hat is unique and consecutive per level. Controlled by DUNE */ int levelIndex; /** \brief An index hat is unique and consecutive on the grid surface. Controlled by DUNE */ int leafIndex; #ifdef ModelP /** \brief Per-node message buffer used by Dune for dynamic load-balancing */ char* message_buffer; /** \brief Size of the `message_buffer` */ std::size_t message_buffer_size; #endif #ifdef ModelP /** \brief Information about the parallelization of this object */ DDD_HEADER ddd; /** \brief stores partition information */ INT lb1; #endif /** \brief Realize a doubly linked list of elements */ union element *pred, *succ; #ifdef __CENTERNODE__ /** \brief Pointer to the center node */ struct node *centernode; #endif /** \brief Corners of this element */ struct node *n[3]; /** \brief Father element on next-coarser grid */ union element *father; #ifdef ModelP /** \brief Element tree */ union element *sons[2]; #else /** \brief Element tree */ union element *sons[1]; #endif /** \brief The neighboring elements */ union element *nb[3]; /** \brief Only on the boundary, NULL if interior side */ BNDS *bnds[3]; }; /** \brief A quadrilateral element in a 2d grid \implements generic_element */ struct quadrilateral { /** \brief object identification, various flags */ UINT control; /** \brief unique id used for load/store */ INT id; /** \brief additional flags for elements */ UINT flag; /** \brief Even more flags */ INT property; /* When UG is used as part of the DUNE numerics system we need a few more indices per element */ /** \brief An index hat is unique and consecutive per level. Controlled by DUNE */ int levelIndex; /** \brief An index hat is unique and consecutive on the grid surface. Controlled by DUNE */ int leafIndex; #ifdef ModelP /** \brief Per-node message buffer used by Dune for dynamic load-balancing */ char* message_buffer; /** \brief Size of the `message_buffer` */ std::size_t message_buffer_size; #endif #ifdef ModelP /** \brief Information about the parallelization of this object */ DDD_HEADER ddd; /** \brief stores partition information */ INT lb1; #endif /** \brief doubly linked list of elements */ union element *pred, *succ; #ifdef __CENTERNODE__ /** \brief pointer to center node */ struct node *centernode; #endif /** \brief corners of that element */ struct node *n[4]; /** \brief father element on coarser grid */ union element *father; #ifdef ModelP /** \brief Element tree */ union element *sons[2]; #else /** \brief Element tree */ union element *sons[1]; #endif /** \brief The neighbor elements */ union element *nb[4]; /** \brief only on bnd, NULL if interior side */ BNDS *bnds[4]; }; /** \brief A tetrahedral element in a 3d grid \implements generic_element */ struct tetrahedron { /** \brief object identification, various flags */ UINT control; /** \brief Unique id used for load/store */ INT id; /** \brief Additional flags */ UINT flag; /** \brief Even more flags */ INT property; /* When UG is used as part of the DUNE numerics system we need a few more indices per element */ /** \brief An index hat is unique and consecutive per level. Controlled by DUNE */ int levelIndex; /** \brief An index hat is unique and consecutive on the grid surface. Controlled by DUNE */ int leafIndex; #ifdef ModelP /** \brief Per-node message buffer used by Dune for dynamic load-balancing */ char* message_buffer; /** \brief Size of the `message_buffer` */ std::size_t message_buffer_size; #endif #ifdef ModelP /** \brief Information about the parallelization of this element */ DDD_HEADER ddd; /** \brief Stores partition information */ INT lb1; #endif /* pointers */ /** \brief Realize a double linked list of elements */ union element *pred, *succ; #ifdef __CENTERNODE__ /** \brief Pointer to the center node */ struct node *centernode; #endif /** \brief Corners of this element */ struct node *n[4]; /** \brief Father element on coarser grid */ union element *father; #ifdef ModelP /** \brief Element tree */ union element *sons[2]; /* element tree */ #else /** \brief Element tree */ union element *sons[1]; #endif /** \brief The neighboring elements */ union element *nb[4]; /** \brief Associated vector for sides */ VECTOR *sidevector[4]; /** \brief The boundary segments, NULL if interior side */ BNDS *bnds[4]; }; /** \brief A pyramid element in a 3d grid \implements generic_element */ struct pyramid { /** \brief object identification, various flags */ UINT control; /** \brief Unique id used for load/store */ INT id; /** \brief Additional flags for elements */ UINT flag; /** \brief Even more flags */ INT property; /* When UG is used as part of the DUNE numerics system we need a few more indices per element */ /** \brief An index hat is unique and consecutive per level. Controlled by DUNE */ int levelIndex; /** \brief An index hat is unique and consecutive on the grid surface. Controlled by DUNE */ int leafIndex; #ifdef ModelP /** \brief Per-node message buffer used by Dune for dynamic load-balancing */ char* message_buffer; /** \brief Size of the `message_buffer` */ std::size_t message_buffer_size; #endif #ifdef ModelP /** \brief Information about the parallelization of this element */ DDD_HEADER ddd; /** \brief Stores partition information */ INT lb1; #endif /* pointers */ /** \brief Realize a doubly linked list of elements */ union element *pred, *succ; #ifdef __CENTERNODE__ /** \brief Pointer to center node */ struct node *centernode; #endif /** \brief Corners of this element */ struct node *n[5]; /** \brief Father element on coarser grid */ union element *father; #ifdef ModelP /** \brief Element tree */ union element *sons[2]; #else /** \brief Element tree */ union element *sons[1]; #endif /** \brief The neighbor elements */ union element *nb[5]; /** \brief Associated vector for sides */ VECTOR *sidevector[5]; /** \brief The boundary segments, NULL if interior side */ BNDS *bnds[5]; }; /** \brief A prism element in a 3d grid \implements generic_element */ struct prism { /** \brief object identification, various flags */ UINT control; /** \brief Unique id used for load/store */ INT id; /** \brief Additional flags for this element */ UINT flag; /** \brief Even more flags */ INT property; /* When UG is used as part of the DUNE numerics system we need a few more indices per element */ /** \brief An index hat is unique and consecutive per level. Controlled by DUNE */ int levelIndex; /** \brief An index hat is unique and consecutive on the grid surface. Controlled by DUNE */ int leafIndex; #ifdef ModelP /** \brief Per-node message buffer used by Dune for dynamic load-balancing */ char* message_buffer; /** \brief Size of the `message_buffer` */ std::size_t message_buffer_size; #endif #ifdef ModelP /** \brief Information about the parallelization of this element */ DDD_HEADER ddd; /** \brief Stores partition information */ INT lb1; #endif /* pointers */ /** \brief Realize doubly linked list */ union element *pred, *succ; #ifdef __CENTERNODE__ /** \brief Pointer to center node */ struct node *centernode; #endif /** \brief Corners of this element */ struct node *n[6]; /** \brief Father element on next coarser grid */ union element *father; #ifdef ModelP /** \brief Element tree */ union element *sons[2]; #else /** \brief Element tree */ union element *sons[1]; #endif /** \brief Neighbor elements */ union element *nb[5]; /** \brief Associated vectors for sides */ VECTOR *sidevector[5]; /** \brief Boundary segments, NULL if interior side */ BNDS *bnds[5]; }; /** \brief A hexahedral element in a 3d grid \implements generic_element */ struct hexahedron { /** \brief object identification, various flags */ UINT control; /** \brief Unique id used for load/store */ INT id; /** \brief Additional flags for this element */ UINT flag; /** \brief Even more flags */ INT property; /* When UG is used as part of the DUNE numerics system we need a few more indices per element */ /** \brief An index hat is unique and consecutive per level. Controlled by DUNE */ int levelIndex; /** \brief An index hat is unique and consecutive on the grid surface. Controlled by DUNE */ int leafIndex; #ifdef ModelP /** \brief Per-node message buffer used by Dune for dynamic load-balancing */ char* message_buffer; /** \brief Size of the `message_buffer` */ std::size_t message_buffer_size; #endif #ifdef ModelP /** \brief Information about the parallelization of this element */ DDD_HEADER ddd; /** \brief Stores partition information */ INT lb1; #endif /** \brief Realize doubly linked list of elements on one grid level */ union element *pred, *succ; #ifdef __CENTERNODE__ /** \brief Pointer to center node */ struct node *centernode; #endif /** \brief Corners of this element */ struct node *n[8]; /** \brief Father element on coarser grid */ union element *father; #ifdef ModelP /** \brief Element tree */ union element *sons[2]; #else /** \brief Element tree */ union element *sons[1]; #endif /** \brief The neighboring elements */ union element *nb[6]; /** \brief Associated vectors for sides */ VECTOR *sidevector[6]; /** \brief Boundary segments, NULL if interior side */ BNDS *bnds[6]; } ; /** \brief Objects that can hold an element */ /** \brief Data type representing an element in the mesh UG provides a flexible element concept, i.e. there may be different types of elements in a mesh (currently limited to 8). All element types are derived from the generic_element where the refs array is allocated to the appropriate length. Data types for the currently implemented three different elements triangle, quadrilateral and tetrahedron are provided only for illustration and debugging purposes. Internally only the generic_element is used. The TAG field in the control word is used to identify the element type at run-time, therefore the limitation to eight element types. Memory requirements are also higher for elements having at least one side on the boundary because additional pointers to boundary information is stored. In 3D, degrees of freedom can be associated also with the sides of an element. Since there is no data type to represent sides, the degrees of freedom associated with a side of an element are accessed via the element (a side is shared by exactly two elements, UG ensures the consistency of the pointers). as the element has sides. MACROS: #SIDES_OF_ELEM (ELEMENT *p) #EDGES_OF_ELEM (ELEMENT *p) #CORNERS_OF_ELEM (ELEMENT *p) #SONS_OF_ELEM (ELEMENT *p) #EDGES_OF_SIDE (ELEMENT *p,INT i) #CORNERS_OF_SIDE (ELEMENT *p,INT i) #EDGE_OF_SIDE (ELEMENT *p,INT s,INT e) #CORNER_OF_SIDE (ELEMENT *p,INT s,INT c) #CORNER_OF_EDGE (ELEMENT *p,INT e,INT c) #EDGE_WITH_CORNERS (ELEMENT *p,INT c0,INT c1) #SIDE_WITH_EDGE (ELEMENT *p,INT e,INT k) #CORNER_OF_SIDE_INV (ELEMENT *p,INT s,INT c) #EDGES_OF_CORNER (ELEMENT *p,INT c,INT k) #SUCCE (ELEMENT *p) #PREDE (ELEMENT *p) #CORNER (ELEMENT *p,INT i) #EFATHER (ELEMENT *p) #SON (ELEMENT *p,INT i) #NBELEM (ELEMENT *p,INT i) #SVECTOR (ELEMENT *p,INT i) CONTROL WORDS: `General macros available for all objects` \verbatim Macro name Pos Len Purpose ----------------------------------------------------------------------------- INT OBJT (ELEMENT *p); 27 5 Object type BEOBJ for an element void SETOBJT (ELEMENT *p, INT n); with at least one side on a boundary and IEOBJ else INT USED (ELEMENT *p); 23 1 used only temporarily void SETUSED (ELEMENT *p, INT n); INT TAG (ELEMENT *p); 24 3 identifies element type. E.g. void SETTAG (ELEMENT *p, INT n); 3=triangle, 4=quadrilateral. should not be used anymore! INT LEVEL (ELEMENT *p); 17 5 level on which element is void SETLEVEL (ELEMENT *p, INT n); allocated INT THEFLAG (ELEMENT *p); 16 1 True if elements refinement rule void SETTHEFLAG (ELEMENT *p, INT n); changed during last refinement step. 3D only ! ----------------------------------------------------------------------------- \endverbatim `Macros for the ELEMENT structure in control` \verbatim Macro name Pos Len Purpose ----------------------------------------------------------------------------- INT ECLASS (ELEMENT *p); 8 2 stores element class which is void SETECLASS (ELEMENT *p,INT n); out of COPY_CLASS, IRREGULAR_CLASS or REGULAR_CLASS INT NSONS (ELEMENT *p); 10 4 number of sons of an element. void SETNSONS (ELEMENT *p,INT n); INT NEWEL (ELEMENT *p); 14 1 Set at creation time but never void SETNEWEL (ELEMENT *p,INT n); reset. Do not use it! ----------------------------------------------------------------------------- \endverbatim `Macros for the ELEMENT structure in flag are all for internal use only` `Macros for the ELEMENT structure in property` \verbatim Macro name Pos Len Purpose ----------------------------------------------------------------------------- INT PROP (ELEMENT *p); 0 32 Stores element property number. void SETPROP (ELEMENT *p,INT n); ----------------------------------------------------------------------------- \endverbatim */ union element { struct generic_element ge; #ifdef UG_DIM_2 struct triangle tr; struct quadrilateral qu; #endif #ifdef UG_DIM_3 struct tetrahedron te; struct pyramid py; struct prism pr; struct hexahedron he; #endif #ifdef ModelP const char* message_buffer() const { return ge.message_buffer; } std::size_t message_buffer_size() const { return ge.message_buffer_size; } void message_buffer(char* p, std::size_t size) { ge.message_buffer = p; ge.message_buffer_size = size; } void message_buffer_free() { std::free(ge.message_buffer); message_buffer(nullptr, 0); } #endif }; /** \brief Union of all geometric objects This data type unifies all data types that can have references to a VECTOR structure. This type is never used for allocation. */ union geom_object { struct node nd; struct edge ed; union element el; }; /** \brief Objects that can have a key */ union object_with_key { struct node nd; union element el; struct vector ve; union vertex vertex; struct edge edge; }; typedef struct { UINT VecReserv[MAXVECTORS][MAX_NDOF_MOD_32]; UINT MatReserv[MAXCONNECTIONS][MAX_NDOF_MOD_32]; /** \todo Is this used anywhere? */ UINT VecConsistentStatus[MAXMATRICES][MAX_NDOF_MOD_32]; /** \todo Is this used anywhere? */ UINT VecCollectStatus[MAXMATRICES][MAX_NDOF_MOD_32]; } DATA_STATUS; /** \brief Data type giving access to all objects on a grid level The \ref grid data type provides access to all objects defined on a grid level. All the pointers to the first list elements are there. CONTROL WORDS: No entries of the control word are currently used. */ struct grid { /** \brief Object identification, various flags */ UINT control; /** \brief A word storing status information. This can be used also by the problem class, e.g. to store whether the grid level is assembled or not. */ INT status; /** \brief Level within the multigrid structure */ UINT level; /** \brief Number of vertices */ INT nVert[NS_DIM_PREFIX MAX_PRIOS]; /** \brief Number of nodes on this grid level */ INT nNode[NS_DIM_PREFIX MAX_PRIOS]; /** \brief Number of elements on this grid level */ INT nElem[NS_DIM_PREFIX MAX_PRIOS]; /** \brief Number of edges on this grid level */ INT nEdge; /** \brief Number of vectors on this grid level */ INT nVector[NS_DIM_PREFIX MAX_PRIOS]; DATA_STATUS data_status; /* memory management for vectors|matrix */ /* status for consistent and collect */ /* pointers */ union element *elements[NS_DIM_PREFIX ELEMENT_LISTPARTS]; /* pointer to first element*/ union element *lastelement[NS_DIM_PREFIX ELEMENT_LISTPARTS]; /*pointer to last element*/ union vertex *vertices[NS_DIM_PREFIX VERTEX_LISTPARTS]; /* pointer to first vertex */ union vertex *lastvertex[NS_DIM_PREFIX VERTEX_LISTPARTS]; /* pointer to last vertex */ struct node *firstNode[NS_DIM_PREFIX NODE_LISTPARTS]; /* pointer to first node */ struct node *lastNode[NS_DIM_PREFIX NODE_LISTPARTS]; /* pointer to last node */ VECTOR *firstVector[NS_DIM_PREFIX VECTOR_LISTPARTS]; /* pointer to first vector */ VECTOR *lastVector[NS_DIM_PREFIX VECTOR_LISTPARTS]; /* pointer to last vector */ struct grid *coarser, *finer; /* coarser and finer grids */ struct multigrid *mg; /* corresponding multigrid structure */ const PPIF::PPIFContext& ppifContext() const; #ifdef ModelP const DDD::DDDContext& dddContext() const; DDD::DDDContext& dddContext(); #endif }; /** \brief Data type representing a complete multigrid structure Data type providing access to all information about the complete multigrid hierarchy, problem description and memory management information. This is the root of all. MACROS: */ struct multigrid { /** \brief The MULTIGRID is an environment item, i.e. it resides in the environment tree. * * v stores also the name of the MULTIGRID as it is declared in the new * and open commands. */ NS_PREFIX ENVDIR v; /** \brief Multigrid status word */ INT status; /** \brief used for identification */ INT magic_cookie; /** \brief count objects in that multigrid */ INT vertIdCounter; /** \brief count objects in that multigrid */ INT nodeIdCounter; /** \brief count objects in that multigrid */ INT elemIdCounter; /** \brief count objects in that multigrid */ INT edgeIdCounter; #ifndef ModelP /** \brief Count vector objects in that multigrid */ INT vectorIdCounter; #endif /** \brief Finest grid level currently allocated in the MULTIGRID */ INT topLevel; /** \brief last level with complete surface */ INT fullrefineLevel; /** \brief pointer to BndValProblem */ STD_BVP *theBVP; /** \brief description of BVP-properties */ std::string BVP_Name; /** \brief associated heap structure */ NS_PREFIX HEAP *theHeap; /** \brief max nb of properties used in elements*/ INT nProperty; /** \brief memory management for vectors|matrix * status for consistent and collect */ DATA_STATUS data_status; /* pointers */ /** \brief pointers to the grids */ struct grid *grids[MAXLEVEL]; /** @{ Helper structures to for an O(n) InsertElement */ /** \brief List of pointers to face nodes, used as an Id of a face */ struct FaceNodes : public std::array { using array::array; }; /** \brief Hasher for FaceNodes */ struct FaceHasher { std::hash hasher; std::size_t operator() (const FaceNodes& key) const { return std::accumulate(key.begin(), key.end(), 144451, [&](auto a, auto b){ return hasher(a+b); }); } }; /** \brief hash-map used for an O(1) search of the neighboring element during InsertElement */ std::unordered_map, FaceHasher> facemap; /** @} */ /* i/o handling */ /** \brief 1 if multigrid saved */ INT saved; /** \brief filename if saved */ char filename[NS_PREFIX NAMESIZE]; /** \brief coarse grid complete */ INT CoarseGridFixed; /** \brief coarse grid MarkKey for SIMPLE_HEAP Mark/Release */ INT MarkKey; const PPIF::PPIFContext& ppifContext() const { return *ppifContext_; } std::shared_ptr ppifContext_; #ifdef ModelP const DDD::DDDContext& dddContext() const { return *dddContext_; } DDD::DDDContext& dddContext() { return *dddContext_; } std::shared_ptr dddContext_; #endif }; /****************************************************************************/ /* */ /* typedef for structs */ /* */ /****************************************************************************/ /* geometrical part */ typedef union vertex VERTEX; typedef struct node NODE; typedef union element ELEMENT; typedef struct link LINK; typedef struct edge EDGE; typedef union geom_object GEOM_OBJECT; typedef struct grid GRID; typedef struct multigrid MULTIGRID; typedef union object_with_key KEY_OBJECT; /****************************************************************************/ /* */ /* dynamic management of control words */ /* */ /****************************************************************************/ #define ControlWord(p,ce) (((UINT *)(p))[control_entries[ce].offset_in_object]) #define CW_READ(p,ce) ((ControlWord(p,ce) & control_entries[ce].mask)>>control_entries[ce].offset_in_word) #define CW_WRITE(p,ce,n) ControlWord(p,ce) = (ControlWord(p,ce)&control_entries[ce].xor_mask)|(((n)<> s ## SHIFT) #define CW_WRITE_STATIC(p,s,t,n) \ StaticControlWord(p,t) = \ (StaticControlWord(p,t) & (~StaticControlWordMask(s))) | \ (((n) << s ## SHIFT) & StaticControlWordMask(s)) /** \brief Enumeration list of all control words of gm.h */ enum GM_CW { VECTOR_CW, VERTEX_CW, NODE_CW, LINK_CW, EDGE_CW, ELEMENT_CW, FLAG_CW, PROPERTY_CW, GRID_CW, GRID_STATUS_CW, MULTIGRID_STATUS_CW, GM_N_CW }; /** \brief Enumeration list of all control entry of gm.h */ enum GM_CE { VOTYPE_CE, VCOUNT_CE, VECTORSIDE_CE, VCLASS_CE, VDATATYPE_CE, VNCLASS_CE, VNEW_CE, VCCUT_CE, FINE_GRID_DOF_CE, OBJ_CE, USED_CE, TAG_CE, LEVEL_CE, THEFLAG_CE, MOVE_CE, MOVED_CE, ONEDGE_CE, ONSIDE_CE, ONNBSIDE_CE, NOOFNODE_CE, NSUBDOM_CE, NTYPE_CE, NPROP_CE, MODIFIED_CE, NCLASS_CE, NNCLASS_CE, LOFFSET_CE, NO_OF_ELEM_CE, AUXEDGE_CE, EDGENEW_CE, EDSUBDOM_CE, ECLASS_CE, NSONS_CE, NEWEL_CE, SUBDOMAIN_CE, NODEORD_CE, PROP_CE, #ifdef ModelP XFERVECTOR_CE, #endif GM_N_CE }; enum LV_MODIFIERS { LV_VO_INFO = (1<<1), /* vector object related info */ LV_POS = (1<<2) /* position vector */ }; /****************************************************************************/ /* */ /* Macro definitions for algebra structures */ /* */ /* */ /* Use of the control word: */ /* */ /* macro name|bits |V|M|use */ /* */ /* all objects: */ /* */ /* vectors: */ /* VOTYPE |0 - 1 |*| | node-,edge-,side- or elemvector */ /* VCUSED |4 |*| | flag for general use */ /* VCOUNT |5-6 |*| | The number of elements that reference */ /* the vector (if it is a side vector) */ /* VECTORSIDE|7 - 9 |*| | nb of side the side vect corr. to (in object elem)*/ /* VCLASS |11-12 |*| | class of v. (3: if corr. to red/green elem) */ /* (2: if corr. to first algebraic nb.) */ /* (1: if corr. to second algebraic nb.) */ /* VDATATYPE |13-16 |*| | data type used bitwise */ /* VNCLASS |17-18 |*| | type of elem on finer grid the v. lies geom. in: */ /* 0: no elem on finer grid */ /* 1: elem of 'second alg. nbhood' only */ /* 2: elem of 'first alg. nbhood' only */ /* 3: red or green elem */ /* VNEW |19 |*| | 1 if vector is new */ /* VCNEW |20 |*| | 1 if vector has a new connection */ /* VCCUT |26 |*| | */ /* */ /****************************************************************************/ /****************************************************************************/ /* */ /* general macros */ /* */ /****************************************************************************/ /* macros to calculate from a coordinate (2D/3D) a hopefully unique ID */ #define SIGNIFICANT_DIGITS(d,exp_ptr) (ceil(frexp((d),(exp_ptr))*1e5)) /* the idea to calculate from a 2d/3D position a (hopefully) unique key: add the weighted significant digits of the coordinates; the weights may not have a common divisor to ensure uniqueness of the result; take from this again the sigificant digits */ #ifdef UG_DIM_2 #define COORDINATE_TO_KEY(coord,dummy_int_ptr) ((INT)(SIGNIFICANT_DIGITS((SIGNIFICANT_DIGITS((coord)[0],(dummy_int_ptr))*1.246509423749342 + \ SIGNIFICANT_DIGITS((coord)[1],(dummy_int_ptr))*Dune::StandardMathematicalConstants::pi())\ , (dummy_int_ptr)))) #endif #ifdef UG_DIM_3 #define COORDINATE_TO_KEY(coord,dummy_int_ptr) ((INT)(SIGNIFICANT_DIGITS((SIGNIFICANT_DIGITS((coord)[0],(dummy_int_ptr))*1.246509423749342 + \ SIGNIFICANT_DIGITS((coord)[1],(dummy_int_ptr))*Dune::StandardMathematicalConstants::pi() + \ SIGNIFICANT_DIGITS((coord)[2],(dummy_int_ptr))*0.76453456834568356936598)\ , (dummy_int_ptr)))) #endif /****************************************************************************/ /* */ /* macros for VECTORs */ /* */ /****************************************************************************/ /* control word offset */ #define VECTOR_OFFSET offsetof(struct NS_DIM_PREFIX vector, control)/sizeof(UINT) /* predefined control word entries */ #define VOTYPE_SHIFT 0 #define VOTYPE_LEN 2 #define VOTYPE(p) CW_READ_STATIC(p,VOTYPE_,VECTOR_) #define SETVOTYPE(p,n) CW_WRITE_STATIC(p,VOTYPE_,VECTOR_,n) #if (MAXVOBJECTS > POW2(VOTYPE_LEN)) #error *** VOTYPE_LEN too small *** #endif #define VDATATYPE_SHIFT 4 #define VDATATYPE_LEN 4 #define VDATATYPE(p) CW_READ_STATIC(p,VDATATYPE_,VECTOR_) #define SETVDATATYPE(p,n) CW_WRITE_STATIC(p,VDATATYPE_,VECTOR_,n) #if (MAXVTYPES > VDATATYPE_LEN) #error *** VDATATYPE_LEN too small *** #endif #define VCLASS_SHIFT 8 #define VCLASS_LEN 2 #define VCLASS(p) CW_READ_STATIC(p,VCLASS_,VECTOR_) #define SETVCLASS(p,n) CW_WRITE_STATIC(p,VCLASS_,VECTOR_,n) #define VNCLASS_SHIFT 10 #define VNCLASS_LEN 2 #define VNCLASS(p) CW_READ_STATIC(p,VNCLASS_,VECTOR_) #define SETVNCLASS(p,n) CW_WRITE_STATIC(p,VNCLASS_,VECTOR_,n) #define VNEW_SHIFT 12 #define VNEW_LEN 1 #define VNEW(p) CW_READ_STATIC(p,VNEW_,VECTOR_) #define SETVNEW(p,n) CW_WRITE_STATIC(p,VNEW_,VECTOR_,n) #define VCCUT_SHIFT 13 #define VCCUT_LEN 1 #define VCCUT(p) CW_READ_STATIC(p,VCCUT_,VECTOR_) #define SETVCCUT(p,n) CW_WRITE_STATIC(p,VCCUT_,VECTOR_,n) #define VCOUNT_SHIFT 14 #define VCOUNT_LEN 2 #define VCOUNT(p) CW_READ_STATIC(p,VCOUNT_,VECTOR_) #define SETVCOUNT(p,n) CW_WRITE_STATIC(p,VCOUNT_,VECTOR_,n) #define VECTORSIDE_SHIFT 16 #define VECTORSIDE_LEN 3 #define VECTORSIDE(p) CW_READ_STATIC(p,VECTORSIDE_,VECTOR_) #define SETVECTORSIDE(p,n) CW_WRITE_STATIC(p,VECTORSIDE_,VECTOR_,n) #define FINE_GRID_DOF_SHIFT 20 #define FINE_GRID_DOF_LEN 1 #define FINE_GRID_DOF(p) CW_READ_STATIC(p,FINE_GRID_DOF_,VECTOR_) #define SETFINE_GRID_DOF(p,n) CW_WRITE_STATIC(p,FINE_GRID_DOF_,VECTOR_,n) #ifdef ModelP #define XFERVECTOR_SHIFT 20 #define XFERVECTOR_LEN 2 #define XFERVECTOR(p) CW_READ(p,XFERVECTOR_CE) #define SETXFERVECTOR(p,n) CW_WRITE(p,XFERVECTOR_CE,n) #endif /* ModelP */ #define VOBJECT(v) ((v)->object) #ifdef ModelP #define PPREDVC(p,v) (((v)==PRIO_FIRSTVECTOR(p,PrioMaster)) ? \ PRIO_LASTVECTOR(p,PrioBorder) : (v)->pred) #else #define PPREDVC(p,v) ((v)->pred) #endif #define PREDVC(v) ((v)->pred) #define SUCCVC(v) ((v)->succ) #define VINDEX(v) ((v)->index) /****************************************************************************/ /* */ /* Macro definitions for geometric objects */ /* */ /* */ /* Use of the control word: */ /* */ /* macro name|bits |V|N|L|E|V|M| use */ /* C */ /* all objects: */ /* TAG |18-20 | | | |*| | |general purpose tag field */ /* LEVEL |21-25 |*|*| |*| | |level of a node/element (imp. for copies) */ /* THEFLAG |26 |*|*|*|*| | |general purp., leave them as you found 'em*/ /* USED |27 |*|*|*|*| | |object visited, leave them as you found 'em*/ /* OBJT |28-31 |*|*|*|*| | |object type identification */ /* */ /* vertices: */ /* MOVED |0 |*| | | | | |boundary vertex not lying on edge midpoint */ /* MOVE |1-2 |*| | | | | |vertex can be moved on a 0(1,2,3) dim subsp*/ /* ONEDGE |3 - 6 |*| | | | | |no. of edge in father element */ /* ONSIDE |3 - 5 |*| | | | | |no. of side in father element */ /* ONNBSIDE |6 - 8 |*| | | | | |no. of side in the neighbor of the father */ /* NOOFNODE |9 -13 |*| | | | | |??? */ /* */ /* nodes: */ /* NSUBDOM |0-3 | |*| | | | |subdomain id */ /* MODIFIED |6 | |*| | | | |1 if node must be assembled */ /* N_OUTFLOW |0-7 | */ /* N_INFLOW |8-15 | */ /* */ /* links and edges: */ /* LOFFSET |0 | | |*| | | |position of link in links array */ /* EDGENEW |1 | | |*| | | |status of edge */ /* NOOFELEM |2-8 | | |*| | | |nb. of elem. the edge is part of */ /* AUXEDGE |9 | */ /* EDSUBDOM |12-17 | | | |*| | |subdomain of edge if inner edge, 0 else */ /* */ /* elements: */ /* ECLASS |8-9 | | | |*| | |element class from enumeration type */ /* NSONS |10-13 | | | |*| | |number of sons */ /* NEWEL |14 | | | |*| | |element just created */ /* VSIDES |11-14 | | | |*| | |viewable sides */ /* NORDER |15-19 | | | |*| | |view position order of the nodes */ /* CUTMODE |26-27 | | | |*| | |elem intersects cutplane or... */ /* */ /****************************************************************************/ /* object identification */ enum GM_OBJECTS { MGOBJ, /*!< Multigrid object */ IVOBJ, /*!< Inner vertex */ BVOBJ, /*!< Boundary vertex */ IEOBJ, /*!< Inner element */ BEOBJ, /*!< Boundary element */ EDOBJ, /*!< Edge object */ NDOBJ, /*!< Node object */ GROBJ, /*!< Grid object */ /* object numbers for algebra */ VEOBJ, /*!< Vector object */ NPREDEFOBJ, /*!< Number of predefined objects */ NOOBJ = -1 /*!< No object */ }; #define LIOBJ EDOBJ /* link and edge are identified */ /****************************************************************************/ /* */ /* general macros */ /* */ /****************************************************************************/ /* control word offset */ #define GENERAL_CW NODE_CW /* any of the geom objects */ #define GENERAL_OFFSET 0 #define OBJ_SHIFT 28 #define OBJ_LEN 4 #define OBJT(p) (enum GM_OBJECTS)CW_READ_STATIC(p,OBJ_,GENERAL_) #define SETOBJT(p,n) CW_WRITE_STATIC(p,OBJ_,GENERAL_,n) #define OBJT_MAX (POW2(OBJ_LEN)-1) #define USED_SHIFT 27 #define USED_LEN 1 #define USED(p) CW_READ_STATIC(p,USED_,GENERAL_) #define SETUSED(p,n) CW_WRITE_STATIC(p,USED_,GENERAL_,n) #define THEFLAG_SHIFT 26 #define THEFLAG_LEN 1 #define THEFLAG(p) CW_READ_STATIC(p,THEFLAG_,GENERAL_) #define SETTHEFLAG(p,n) CW_WRITE_STATIC(p,THEFLAG_,GENERAL_,n) #define LEVEL_SHIFT 21 #define LEVEL_LEN 5 #define LEVEL(p) CW_READ_STATIC(p,LEVEL_,GENERAL_) #define SETLEVEL(p,n) CW_WRITE_STATIC(p,LEVEL_,GENERAL_,n) #define TAG_SHIFT 18 #define TAG_LEN 3 #define TAG(p) CW_READ_STATIC(p,TAG_,GENERAL_) #define SETTAG(p,n) CW_WRITE_STATIC(p,TAG_,GENERAL_,n) #define REF2TAG(n) (reference2tag[n]) #define CTRL(p) (*((UINT *)(p))) #define ID(p) (((INT *)(p))[1]) /****************************************************************************/ /* */ /* macros for vertices */ /* */ /****************************************************************************/ /* control word offset */ #define VERTEX_OFFSET offsetof(struct ivertex,control)/sizeof(UINT) #define MOVE_SHIFT 1 #define MOVE_LEN 2 #define MOVE(p) CW_READ_STATIC(p,MOVE_,VERTEX_) #define SETMOVE(p,n) CW_WRITE_STATIC(p,MOVE_,VERTEX_,n) #define MOVED_SHIFT 0 #define MOVED_LEN 1 #define MOVED(p) CW_READ_STATIC(p,MOVED_,VERTEX_) #define SETMOVED(p,n) CW_WRITE_STATIC(p,MOVED_,VERTEX_,n) #define ONEDGE_SHIFT 3 #define ONEDGE_LEN 4 #define ONEDGE(p) CW_READ_STATIC(p,ONEDGE_,VERTEX_) #define SETONEDGE(p,n) CW_WRITE_STATIC(p,ONEDGE_,VERTEX_,n) /* the following two overlap with ONEDGE */ #define ONSIDE_SHIFT 3 #define ONSIDE_LEN 3 #define ONSIDE(p) CW_READ_STATIC(p,ONSIDE_,VERTEX_) #define SETONSIDE(p,n) CW_WRITE_STATIC(p,ONSIDE_,VERTEX_,n) #define ONNBSIDE_SHIFT 6 #define ONNBSIDE_LEN 3 #define ONNBSIDE(p) CW_READ_STATIC(p,ONNBSIDE_,VERTEX_) #define SETONNBSIDE(p,n) CW_WRITE_STATIC(p,ONNBSIDE_,VERTEX_,n) #define NOOFNODE_SHIFT 9 #define NOOFNODE_LEN 5 #define NOOFNODEMAX POW2(NOOFNODE_LEN) #if (MAXLEVEL > NOOFNODEMAX) #error **** set NOOFNODEMAX/_LEN appropriate to MAXLEVEL: 2^NOOFNODE_LEN = NOOFNODEMAX >= MAXLEVEL **** #endif #define NOOFNODE(p) CW_READ_STATIC(p,NOOFNODE_,VERTEX_) #define SETNOOFNODE(p,n) CW_WRITE_STATIC(p,NOOFNODE_,VERTEX_,n) #define INCNOOFNODE(p) SETNOOFNODE(p,NOOFNODE(p)+1) #define DECNOOFNODE(p) SETNOOFNODE(p,NOOFNODE(p)-1) #define PREDV(p) ((p)->iv.pred) #define SUCCV(p) ((p)->iv.succ) #define CVECT(p) ((p)->iv.x) #define LCVECT(p) ((p)->iv.xi) #define VDATA(p) ((p)->iv.data) #define VFATHER(p) ((p)->iv.father) /* for boundary vertices */ #define V_BNDP(p) ((p)->bv.bndp) /* parallel macros */ #ifdef ModelP #define PARHDRV(p) (&((p)->iv.ddd)) #endif /* ModelP */ /****************************************************************************/ /* */ /* macros for nodes */ /* */ /****************************************************************************/ /* control word offset */ #define NODE_OFFSET offsetof(struct node, control)/sizeof(UINT) #define NTYPE_SHIFT 0 #define NTYPE_LEN 3 #define NTYPE(p) CW_READ_STATIC(p,NTYPE_,NODE_) #define SETNTYPE(p,n) CW_WRITE_STATIC(p,NTYPE_,NODE_,n) #define NSUBDOM_SHIFT 3 #define NSUBDOM_LEN 6 #define NSUBDOM(p) CW_READ_STATIC(p,NSUBDOM_,NODE_) #define SETNSUBDOM(p,n) CW_WRITE_STATIC(p,NSUBDOM_,NODE_,n) #define NPROP_SHIFT 11 #define NPROP_LEN 4 #define NPROP(p) CW_READ_STATIC(p,NPROP_,NODE_) #define SETNPROP(p,n) CW_WRITE_STATIC(p,NPROP_,NODE_,n) #define MODIFIED_SHIFT 15 #define MODIFIED_LEN 1 #define MODIFIED(p) CW_READ_STATIC(p,MODIFIED_,NODE_) #define SETMODIFIED(p,n) CW_WRITE_STATIC(p,MODIFIED_,NODE_,n) #define NCLASS_SHIFT 16 #define NCLASS_LEN 2 #define NCLASS(p) CW_READ_STATIC(p,NCLASS_,NODE_) #define SETNCLASS(p,n) CW_WRITE_STATIC(p,NCLASS_,NODE_,n) #define NNCLASS_SHIFT 18 #define NNCLASS_LEN 2 #define NNCLASS(p) CW_READ_STATIC(p,NNCLASS_,NODE_) #define SETNNCLASS(p,n) CW_WRITE_STATIC(p,NNCLASS_,NODE_,n) #define PREDN(p) ((p)->pred) #define SUCCN(p) ((p)->succ) #define START(p) ((p)->start) #define NFATHER(p) ((NODE*)(p)->father) #define SETNFATHER(p,n) ((p)->father = n) #define NFATHEREDGE(p) ((EDGE*)(p)->father) /* #define NFATHER(p) ((NTYPE(p) == CORNER_NODE) ? (p)->father : NULL) #define NFATHEREDGE(p) ((NTYPE(p) == MID_NODE) ? (EDGE *)(p)->father : NULL) #define SETNFATHEREDGE(p,e) ((p)->father = (NODE *) (e)) */ #define CORNERTYPE(p) (NTYPE(p) == CORNER_NODE) #define MIDTYPE(p) (NTYPE(p) == MID_NODE) #define SIDETYPE(p) (NTYPE(p) == SIDE_NODE) #define CENTERTYPE(p) (NTYPE(p) == CENTER_NODE) #define SONNODE(p) ((p)->son) #define MYVERTEX(p) ((p)->myvertex) #define ELEMENT_PTR(p) ((p)->el) /****************************************************************************/ /* */ /* macros for links */ /* */ /****************************************************************************/ /* CAUTION: the controlword of LINK0 and its edge are identical (AVOID overlapping of flags) */ /* control word offset */ #define LINK_OFFSET offsetof(struct link, control)/sizeof(UINT) #define LOFFSET_SHIFT 0 #define LOFFSET_LEN 1 #define LOFFSET(p) CW_READ(p,LOFFSET_CE) #define SETLOFFSET(p,n) CW_WRITE(p,LOFFSET_CE,n) /** \brief Get the neighboring node of a link */ #define NBNODE(p) ((p)->nbnode) #define NEXT(p) ((p)->next) #define LDATA(p) ((p)->matelem) #define MATELEM(p) ((p)->matelem) /* can be used for node and link */ #define MYEDGE(p) ((EDGE *)((p)-LOFFSET(p))) /** Macro that provides fast access to the LINK in the reverse direction. If the given LINK connects node `a` with node `b`, then REVERSE provides the LINK in the list of node `b` pointing to `a`. */ #define REVERSE(p) ((p)+(1-LOFFSET(p)*2)) #if defined(UG_DIM_2) #define LELEM(p) ((p)->elem) #define SET_LELEM(p,e) ((p)->elem = (e)) #endif /****************************************************************************/ /* */ /* macros for edges */ /* */ /****************************************************************************/ /* control word offset: Use the control word of the link object contained in the edge object */ #define EDGE_OFFSET offsetof(struct edge, links[0].control)/sizeof(UINT) #define NO_OF_ELEM_SHIFT 2 #define NO_OF_ELEM_LEN 7 #define NO_OF_ELEM_MAX 128 #define NO_OF_ELEM(p) CW_READ(p,NO_OF_ELEM_CE) #define SET_NO_OF_ELEM(p,n) CW_WRITE(p,NO_OF_ELEM_CE,n) #define INC_NO_OF_ELEM(p) SET_NO_OF_ELEM(p,NO_OF_ELEM(p)+1) #define DEC_NO_OF_ELEM(p) SET_NO_OF_ELEM(p,NO_OF_ELEM(p)-1) #define AUXEDGE_SHIFT 9 #define AUXEDGE_LEN 1 #define AUXEDGE(p) CW_READ(p,AUXEDGE_CE) #define SETAUXEDGE(p,n) CW_WRITE(p,AUXEDGE_CE,n) #define EDGENEW_SHIFT 1 #define EDGENEW_LEN 1 #define EDGENEW(p) CW_READ(p,EDGENEW_CE) #define SETEDGENEW(p,n) CW_WRITE(p,EDGENEW_CE,n) /* boundary edges will be indicated by a subdomain id of 0 */ #define EDSUBDOM_SHIFT 12 #define EDSUBDOM_LEN 6 #define EDSUBDOM(p) CW_READ(p,EDSUBDOM_CE) #define SETEDSUBDOM(p,n) CW_WRITE(p,EDSUBDOM_CE,n) #define LINK0(p) (&((p)->links[0])) #define LINK1(p) (&((p)->links[1])) #define MIDNODE(p) ((p)->midnode) #define EDDATA(p) ((p)->data) #define EDVECTOR(p) ((p)->vector) /****************************************************************************/ /* */ /* macros for elements */ /* */ /****************************************************************************/ enum {TRIANGLE = 3, QUADRILATERAL = 4}; enum {TETRAHEDRON = 4, PYRAMID = 5, PRISM = 6, HEXAHEDRON = 7}; /* control word offsets */ #define ELEMENT_OFFSET offsetof(struct generic_element, control)/sizeof(UINT) #define FLAG_OFFSET offsetof(struct generic_element, flag)/sizeof(UINT) #define PROPERTY_OFFSET offsetof(struct generic_element, property)/sizeof(UINT) /* macros for control word */ #define ECLASS_SHIFT 8 #define ECLASS_LEN 2 #define ECLASS(p) CW_READ(p,ECLASS_CE) #define SETECLASS(p,n) CW_WRITE(p,ECLASS_CE,n) #define NSONS_SHIFT 10 #define NSONS_LEN 5 #define NSONS(p) CW_READ(p,NSONS_CE) #define SETNSONS(p,n) CW_WRITE(p,NSONS_CE,n) #define NEWEL_SHIFT 17 #define NEWEL_LEN 1 #define NEWEL(p) CW_READ(p,NEWEL_CE) #define SETNEWEL(p,n) CW_WRITE(p,NEWEL_CE,n) /* macros for flag word */ /* are obviously all for internal use */ /* the property field */ #define SUBDOMAIN_SHIFT 24 #define SUBDOMAIN_LEN 6 #define SUBDOMAIN(p) CW_READ(p,SUBDOMAIN_CE) #define SETSUBDOMAIN(p,n) CW_WRITE(p,SUBDOMAIN_CE,n) #define NODEORD_SHIFT 0 #define NODEORD_LEN 24 #define NODEORD(p) CW_READ(p,NODEORD_CE) #define SETNODEORD(p,n) CW_WRITE(p,NODEORD_CE,n) #define PROP_SHIFT 30 #define PROP_LEN 2 #define PROP(p) CW_READ(p,PROP_CE) #define SETPROP(p,n) CW_WRITE(p,PROP_CE,n) /* parallel macros */ #ifdef ModelP #define PARTITION(p) ((p)->ge.lb1) #define PARHDRE(p) (&((p)->ge.ddd)) #endif /*******************************/ /* the general element concept */ /*******************************/ /** \brief This structure contains all topological properties of an element and more .. */ struct GENERAL_ELEMENT { INT tag; /**< Element type to be defined */ /* the following parameters determine size of refs array in element */ INT sides_of_elem; /**< How many sides ? */ INT corners_of_elem; /**< How many corners ? */ /* local geometric description of the element */ DOUBLE_VECTOR local_corner[MAX_CORNERS_OF_ELEM]; /**< Local coordinates of the corners of the element */ /* more size parameters */ INT edges_of_elem; /**< How many edges ? */ INT edges_of_side[MAX_SIDES_OF_ELEM]; /**< Number of edges for each side */ INT corners_of_side[MAX_SIDES_OF_ELEM]; /**< Number of corners for each side */ /* index computations */ /* Within each element sides, edges, corners are numbered in some way. */ /* Within each side the edges and corners are numbered, within the edge the */ /* corners are numbered. The following arrays map the local numbers within */ /* the side or edge to the numbering within the element. */ INT edge_of_side[MAX_SIDES_OF_ELEM][MAX_EDGES_OF_SIDE]; INT corner_of_side[MAX_SIDES_OF_ELEM][MAX_CORNERS_OF_SIDE]; INT corner_of_edge[MAX_EDGES_OF_ELEM][CORNERS_OF_EDGE]; /* the following parameters are derived from data above */ GM_OBJECTS mapped_inner_objt = NOOBJ; /* tag to objt mapping for free list*/ GM_OBJECTS mapped_bnd_objt = NOOBJ; /* tag to objt mapping for free list*/ INT inner_size, bnd_size; /* size in bytes used for alloc */ INT edge_with_corners[MAX_CORNERS_OF_ELEM][MAX_CORNERS_OF_ELEM]; INT side_with_edge[MAX_EDGES_OF_ELEM][MAX_SIDES_OF_EDGE]; INT corner_of_side_inv[MAX_SIDES_OF_ELEM][MAX_CORNERS_OF_ELEM]; INT edges_of_corner[MAX_CORNERS_OF_ELEM][MAX_EDGES_OF_ELEM]; INT corner_opp_to_side[MAX_SIDES_OF_ELEM]; INT opposite_edge[MAX_EDGES_OF_ELEM]; INT side_opp_to_corner[MAX_CORNERS_OF_ELEM]; INT edge_of_corner[MAX_CORNERS_OF_ELEM][MAX_EDGES_OF_ELEM]; INT edge_of_two_sides[MAX_SIDES_OF_ELEM][MAX_SIDES_OF_ELEM]; /* ... the refinement rules should be placed here later */ }; END_UGDIM_NAMESPACE /** \todo move this to include section, when other general element stuff is separated */ #include "elements.h" START_UGDIM_NAMESPACE /****************************************************************************/ /* */ /* macros for element descriptors */ /* */ /****************************************************************************/ /** @name Macros to access element descriptors by element pointers */ /*@{*/ /** Returns the number of sides of a given element. In 2D the number of sides and number of edges of an element coincide. The nb, sidevector and side arrays are of this size. */ #define SIDES_OF_ELEM(p) (element_descriptors[TAG(p)]->sides_of_elem) /** Returns the number of edges of a given element. In 2D the number of sides and number of edges of an element coincide. */ #define EDGES_OF_ELEM(p) (element_descriptors[TAG(p)]->edges_of_elem) /** Returns the number of corners of a given element. This is also the size of the n array. */ #define CORNERS_OF_ELEM(p) (element_descriptors[TAG(p)]->corners_of_elem) #define LOCAL_COORD_OF_ELEM(p,c) (element_descriptors[TAG(p)]->local_corner[(c)]) /** \brief Returns the number of edges of side i of the given element. * * In 2D a side has always one edge since edges and sides coincide. */ #define EDGES_OF_SIDE(p,i) (element_descriptors[TAG(p)]->edges_of_side[(i)]) /** \brief Returns the number of corners of side i of the given element. */ #define CORNERS_OF_SIDE(p,i) (element_descriptors[TAG(p)]->corners_of_side[(i)]) /** \brief Returns the number of edge e of side s within the element p. */ #define EDGE_OF_SIDE(p,s,e) (element_descriptors[TAG(p)]->edge_of_side[(s)][(e)]) #define EDGE_OF_TWO_SIDES(p,s,t) (element_descriptors[TAG(p)]->edge_of_two_sides[(s)][(t)]) /** \brief Returns the number of corner c of side s within the element p. */ #define CORNER_OF_SIDE(p,s,c) (element_descriptors[TAG(p)]->corner_of_side[(s)][(c)]) /** \brief Returns the number of corner c of edge e within the element p. */ #define CORNER_OF_EDGE(p,e,c) (element_descriptors[TAG(p)]->corner_of_edge[(e)][(c)]) /** \brief Returns the number of the edge (with respect to numbering in the element p) * that connects corners with numbers c0 and c1 (with respect to numbering in * element p). */ #define EDGE_WITH_CORNERS(p,c0,c1) (element_descriptors[TAG(p)]->edge_with_corners[(c0)][(c1)]) /** SIDE_WITH_EDGE(p,e,0) and SIDE_WITH_EDGE(p,e,1) deliver the numbers * of the two sides (with respect to numbering in p) that share edge number e * (also with respect to the element). */ #define SIDE_WITH_EDGE(p,e,k) (element_descriptors[TAG(p)]->side_with_edge[(e)][(k)]) /** When c is the number of a corner and s is the number of a side * (both with respect to numbering in the element) then * CORNER_OF_SIDE_INV returns the number of corner c with respect * to the numbering in side s or -1 if s does not contain corner c. */ #define CORNER_OF_SIDE_INV(p,s,c) (element_descriptors[TAG(p)]->corner_of_side_inv[(s)][(c)]) /** If c is the number of a corner with respect to numbering within * the element then EDGES_OF_CORNER(p,c,k) returns all numbers * of edges (with respect to p) that are connected to corner c. * Since this number is variable a value of -1 identifies an invalid entry. * The edges are numbered consecutively, i.e. if a -1 is encountered * larger values of k (less than EDGES_OF_ELEM(p)) will lead also to -1). */ #define EDGES_OF_CORNER(p,c,k) (element_descriptors[TAG(p)]->edges_of_corner[(c)][(k)]) #define CORNER_OPP_TO_SIDE(p,s) (element_descriptors[TAG(p)]->corner_opp_to_side[(s)]) #define OPPOSITE_EDGE(p,e) (element_descriptors[TAG(p)]->opposite_edge[(e)]) #define SIDE_OPP_TO_CORNER(p,c) (element_descriptors[TAG(p)]->side_opp_to_corner[(c)]) #define EDGE_OF_CORNER(p,c,e) (element_descriptors[TAG(p)]->edge_of_corner[(c)][(e)]) #define FLAG(p) ((p)->ge.flag) #define SUCCE(p) ((p)->ge.succ) #define PREDE(p) ((p)->ge.pred) #ifdef __CENTERNODE__ #define CENTERNODE(p) ((p)->ge.centernode) #endif /** \brief Returns a pointer to corner i of element p. * * i should be less than CORNERS_OF_ELEM(p). */ #define CORNER(p,i) ((NODE *) (p)->ge.refs[n_offset[TAG(p)]+(i)]) /** \brief Returns a pointer to the father element. */ #define EFATHER(p) ((ELEMENT *) (p)->ge.refs[father_offset[TAG(p)]]) /** \brief Returns a pointer to son i of p in the element hierarchy. * * In 3D only i=0 is allowed and the function GetSons should be used instead. * i should be smaller than NSONS(p). */ #define SON(p,i) ((ELEMENT *) (p)->ge.refs[sons_offset[TAG(p)]+(i)]) /** \todo NbElem is declared in ugm.h, but never defined. We need a clean solution. */ /* #if defined(UG_DIM_2) #define NBELEM(p,i) NbElem((p),(i)) #else */ /** \brief Returns a pointer to neighboring element over side i. * * i should be less than SIDES_OF_ELEM(p). */ #define NBELEM(p,i) ((ELEMENT *) (p)->ge.refs[nb_offset[TAG(p)]+(i)]) /* #endif */ #define ELEM_BNDS(p,i) ((BNDS *) (p)->ge.refs[side_offset[TAG(p)]+(i)]) #define EVECTOR(p) ((VECTOR *) (p)->ge.refs[0]) /** \brief Returns a pointer to the VECTOR associated with the side i of element p. * * i must be less than SIDES_OF_ELEM(p). */ #define SVECTOR(p,i) ((VECTOR *) (p)->ge.refs[svector_offset[TAG(p)]+(i)]) #define SIDE_ON_BND(p,i) (ELEM_BNDS(p,i) != NULL) #define INNER_SIDE(p,i) (ELEM_BNDS(p,i) == NULL) #define INNER_BOUNDARY(p,i) (InnerBoundary(p,i)) /* TODO: replace by function call */ #ifdef UG_DIM_2 #define EDGE_ON_BND(p,i) (ELEM_BNDS(p,i) != NULL) #endif #ifdef UG_DIM_3 #define EDGE_ON_BND(p,i) (SIDE_ON_BND(p,SIDE_WITH_EDGE(p,i,0)) || \ SIDE_ON_BND(p,SIDE_WITH_EDGE(p,i,1))) #endif /*@}*/ /* use the following macros to assign values, since definition */ /* above is no proper lvalue. */ #ifdef __CENTERNODE__ #define SET_CENTERNODE(p,q) ((p)->ge.centernode = q) #endif #define SET_CORNER(p,i,q) ((p)->ge.refs[n_offset[TAG(p)]+(i)] = q) #define SET_EFATHER(p,q) ((p)->ge.refs[father_offset[TAG(p)]] = q) #define SET_SON(p,i,q) ((p)->ge.refs[sons_offset[TAG(p)]+(i)] = q) /** \todo Set_NbElem is declared in ugm.h, but never defined. We need a clean solution. */ /* #if defined(UG_DIM_2) #define SET_NBELEM(p,i,q) Set_NbElem((p),(i),(q)) #else */ #define SET_NBELEM(p,i,q) ((p)->ge.refs[nb_offset[TAG(p)]+(i)] = q) /* #endif */ #if defined(UG_DIM_2) #define VOID_NBELEM(p,i) NBELEM(p,i) #else #define VOID_NBELEM(p,i) ((p)->ge.refs[nb_offset[TAG(p)]+(i)]) #endif #define SET_BNDS(p,i,q) ((p)->ge.refs[side_offset[TAG(p)]+(i)] = q) #define SET_EVECTOR(p,q) ((p)->ge.refs[evector_offset[TAG(p)]] = q) #if defined(UG_DIM_3) #define SET_SVECTOR(p,i,q) ((p)->ge.refs[svector_offset[TAG(p)]+(i)] = q) #endif /** @name Macros to access corner pointers directly */ /*@{*/ #define CORNER_OF_EDGE_PTR(e,i,j) (CORNER(e,CORNER_OF_EDGE(e,i,j))) #define CORNER_OF_SIDE_PTR(e,i,j) (CORNER(e,CORNER_OF_SIDE(e,i,j))) /*@}*/ /** @name Macros to access element descriptors by element tags */ /*@{*/ #define INNER_SIZE_TAG(t) (element_descriptors[t]->inner_size) #define BND_SIZE_TAG(t) (element_descriptors[t]->bnd_size) #define MAPPED_INNER_OBJT_TAG(t) (element_descriptors[t]->mapped_inner_objt) #define MAPPED_BND_OBJT_TAG(t) (element_descriptors[t]->mapped_bnd_objt) #define SIDES_OF_TAG(t) (element_descriptors[t]->sides_of_elem) #define EDGES_OF_TAG(t) (element_descriptors[t]->edges_of_elem) #define CORNERS_OF_TAG(t) (element_descriptors[t]->corners_of_elem) #define LOCAL_COORD_OF_TAG(t,c) (element_descriptors[t]->local_corner[(c)]) #define EDGES_OF_SIDE_TAG(t,i) (element_descriptors[t]->edges_of_side[(i)]) #define CORNERS_OF_SIDE_TAG(t,i) (element_descriptors[t]->corners_of_side[(i)]) #define EDGE_OF_SIDE_TAG(t,s,e) (element_descriptors[t]->edge_of_side[(s)][(e)]) #define EDGE_OF_TWO_SIDES_TAG(t,s,u) (element_descriptors[t]->edge_of_two_sides[(s)][(u)]) #define CORNER_OF_SIDE_TAG(t,s,c) (element_descriptors[t]->corner_of_side[(s)][(c)]) #define CORNER_OF_EDGE_TAG(t,e,c) (element_descriptors[t]->corner_of_edge[(e)][(c)]) #define EDGE_WITH_CORNERS_TAG(t,c0,c1) (element_descriptors[t]->edge_with_corners[(c0)][(c1)]) #define SIDE_WITH_EDGE_TAG(t,e,k) (element_descriptors[t]->side_with_edge[(e)][(k)]) #define CORNER_OF_SIDE_INV_TAG(t,s,c) (element_descriptors[t]->corner_of_side_inv[(s)][(c)]) #define EDGES_OF_CORNER_TAG(t,c,k) (element_descriptors[t]->edges_of_corner[(c)][(k)]) #define CORNER_OPP_TO_SIDE_TAG(t,s) (element_descriptors[t]->corner_opp_to_side[(s)]) #define OPPOSITE_EDGE_TAG(t,e) (element_descriptors[t]->opposite_edge[(e)]) #define SIDE_OPP_TO_CORNER_TAG(t,c) (element_descriptors[t]->side_opp_to_corner[(c)]) #define EDGE_OF_CORNER_TAG(t,c,e) (element_descriptors[t]->edge_of_corner[(c)][(e)]) /*@}*/ /****************************************************************************/ /* */ /* macros for grids */ /* */ /****************************************************************************/ /* control word offset */ #define GRID_OFFSET offsetof(grid,control)/sizeof(UINT) #define GRID_STATUS_OFFSET offsetof(grid,status)/sizeof(UINT) #define GLEVEL(p) ((p)->level) #define GFORMAT(p) MGFORMAT(MYMG(p)) #define SETGLOBALGSTATUS(p) ((p)->status=~0) #define GSTATUS(p,n) ((p)->status&(n)) /** \brief Set or reset all bits that are 1 in the mask n. */ #define RESETGSTATUS(p,n) ((p)->status&=~(n)) #ifdef ModelP #define PFIRSTELEMENT(p) ((LISTPART_FIRSTELEMENT(p,0)!=NULL) ?\ (LISTPART_FIRSTELEMENT(p,0)) : (FIRSTELEMENT(p))) #define PRIO_FIRSTELEMENT(p,prio) ((p)->elements[PRIO2LISTPART(ELEMENT_LIST,prio)]) #define LISTPART_FIRSTELEMENT(p,part) ((p)->elements[part]) #define FIRSTELEMENT(p) ((p)->elements[PRIO2LISTPART(ELEMENT_LIST,PrioMaster)]) #define PLASTELEMENT(p) LASTELEMENT(p) #define PRIO_LASTELEMENT(p,prio) ((p)->lastelement[PRIO2LISTPART(ELEMENT_LIST,prio)]) #define LISTPART_LASTELEMENT(p,part) ((p)->lastelement[part]) #define LASTELEMENT(p) ((p)->lastelement[PRIO2LISTPART(ELEMENT_LIST,PrioMaster)]) #else #define FIRSTELEMENT(p) ((p)->elements[0]) #define PFIRSTELEMENT(p) FIRSTELEMENT(p) #define LASTELEMENT(p) ((p)->lastelement[0]) #define PLASTELEMENT(p) LASTELEMENT(p) #endif #ifdef ModelP #define PFIRSTVERTEX(p) ((LISTPART_FIRSTVERTEX(p,0)!=NULL) ?\ (LISTPART_FIRSTVERTEX(p,0)) :\ ((LISTPART_FIRSTVERTEX(p,1)!=NULL) ?\ (LISTPART_FIRSTVERTEX(p,1)) : (FIRSTVERTEX(p)))) #define PRIO_FIRSTVERTEX(p,prio) ((p)->vertices[PRIO2LISTPART(VERTEX_LIST,prio)]) #define LISTPART_FIRSTVERTEX(p,part) ((p)->vertices[part]) #define FIRSTVERTEX(p) (((p)->vertices[PRIO2LISTPART(VERTEX_LIST,\ PrioBorder)]!=NULL) ?\ (p)->vertices[PRIO2LISTPART(VERTEX_LIST,PrioBorder)] :\ (p)->vertices[PRIO2LISTPART(VERTEX_LIST,PrioMaster)]) #define SFIRSTVERTEX(p) (p)->vertices[PRIO2LISTPART(VERTEX_LIST,PrioMaster)] #define PLASTVERTEX(p) LASTVERTEX(p) #define PRIO_LASTVERTEX(p,prio) ((p)->lastvertex[PRIO2LISTPART(VERTEX_LIST,prio)]) #define LISTPART_LASTVERTEX(p,part) ((p)->lastvertex[part]) #define LASTVERTEX(p) ((p)->lastvertex[PRIO2LISTPART(VERTEX_LIST,PrioMaster)]) #else #define FIRSTVERTEX(p) ((p)->vertices[0]) #define PFIRSTVERTEX(p) FIRSTVERTEX(p) #define SFIRSTVERTEX(p) FIRSTVERTEX(p) #define LASTVERTEX(p) ((p)->lastvertex[0]) #define PLASTVERTEX(p) LASTVERTEX(p) #endif #define FIRSTELEMSIDE(p) ((p)->sides) #ifdef ModelP #define PFIRSTNODE(p) ((LISTPART_FIRSTNODE(p,0)!=NULL) ?\ (LISTPART_FIRSTNODE(p,0)) :\ ((LISTPART_FIRSTNODE(p,1)!=NULL) ?\ (LISTPART_FIRSTNODE(p,1)) : (FIRSTNODE(p)))) #define PRIO_FIRSTNODE(p,prio) ((p)->firstNode[PRIO2LISTPART(NODE_LIST,prio)]) #define LISTPART_FIRSTNODE(p,part) ((p)->firstNode[part]) #define FIRSTNODE(p) (((p)->firstNode[PRIO2LISTPART(NODE_LIST,\ PrioBorder)]!=NULL) ?\ (p)->firstNode[PRIO2LISTPART(NODE_LIST,PrioBorder)] :\ (p)->firstNode[PRIO2LISTPART(NODE_LIST,PrioMaster)]) #define SFIRSTNODE(p) (p)->firstNode[PRIO2LISTPART(NODE_LIST,PrioMaster)] #define PLASTNODE(p) LASTNODE(p) #define PRIO_LASTNODE(p,prio) ((p)->lastNode[PRIO2LISTPART(NODE_LIST,prio)]) #define LISTPART_LASTNODE(p,part) ((p)->lastNode[part]) #define LASTNODE(p) ((p)->lastNode[PRIO2LISTPART(NODE_LIST,PrioMaster)]) #else #define FIRSTNODE(p) ((p)->firstNode[0]) #define PFIRSTNODE(p) FIRSTNODE(p) #define SFIRSTNODE(p) FIRSTNODE(p) #define LASTNODE(p) ((p)->lastNode[0]) #define PLASTNODE(p) LASTNODE(p) #endif #ifdef ModelP #define PFIRSTVECTOR(p) ((LISTPART_FIRSTVECTOR(p,0)!=NULL) ?\ (LISTPART_FIRSTVECTOR(p,0)) :\ ((LISTPART_FIRSTVECTOR(p,1)!=NULL) ?\ (LISTPART_FIRSTVECTOR(p,1)) : (FIRSTVECTOR(p)))) #define PRIO_FIRSTVECTOR(p,prio) ((p)->firstVector[PRIO2LISTPART(VECTOR_LIST,prio)]) #define LISTPART_FIRSTVECTOR(p,part) ((p)->firstVector[part]) #define FIRSTVECTOR(p) (((p)->firstVector[PRIO2LISTPART(VECTOR_LIST,\ PrioBorder)]!=NULL) ?\ (p)->firstVector[PRIO2LISTPART(VECTOR_LIST,PrioBorder)] :\ (p)->firstVector[PRIO2LISTPART(VECTOR_LIST,PrioMaster)]) #define SFIRSTVECTOR(p) (p)->firstVector[PRIO2LISTPART(VECTOR_LIST,PrioMaster)] #define PLASTVECTOR(p) LASTVECTOR(p) #define PRIO_LASTVECTOR(p,prio) ((p)->lastVector[PRIO2LISTPART(VECTOR_LIST,prio)]) #define LISTPART_LASTVECTOR(p,part) ((p)->lastVector[part]) #define LASTVECTOR(p) ((p)->lastVector[PRIO2LISTPART(VECTOR_LIST,PrioMaster)]) #else #define FIRSTVECTOR(p) ((p)->firstVector[0]) #define PFIRSTVECTOR(p) FIRSTVECTOR(p) #define SFIRSTVECTOR(p) FIRSTVECTOR(p) #define LASTVECTOR(p) ((p)->lastVector[0]) #define PLASTVECTOR(p) LASTVECTOR(p) #endif #define UPGRID(p) ((p)->finer) #define DOWNGRID(p) ((p)->coarser) #define MYMG(p) ((p)->mg) #define NV(p) ((p)->nVert[0]) #define NN(p) ((p)->nNode[0]) #define NT(p) ((p)->nElem[0]) #define NVEC(p) ((p)->nVector[0]) #ifdef ModelP #define NV_PRIO(p,prio) ((p)->nVert[prio]) #define NN_PRIO(p,prio) ((p)->nNode[prio]) #define NT_PRIO(p,prio) ((p)->nElem[prio]) #define NVEC_PRIO(p,prio) ((p)->nVector[prio]) #endif #define NE(p) ((p)->nEdge) #define NS(p) ((p)->nSide) #ifdef UG_DIM_3 #define VEC_DEF_IN_OBJ_OF_GRID(p,tp) (true) // 3d grids have side vectors #else #define VEC_DEF_IN_OBJ_OF_GRID(p,tp) (false) // 2d grids have no vectors at all #endif #define NIMAT(p) ((p)->nIMat) #define GRID_ATTR(g) ((unsigned char) (GLEVEL(g)+32)) #define ATTR_TO_GLEVEL(i) (i-32) inline const PPIF::PPIFContext& grid::ppifContext() const { return mg->ppifContext(); } #ifdef ModelP inline const DDD::DDDContext& grid::dddContext() const { return mg->dddContext(); } inline DDD::DDDContext& grid::dddContext() { return mg->dddContext(); } #endif /****************************************************************************/ /* */ /* macros for multigrids */ /* */ /****************************************************************************/ /* control word offset */ #define MULTIGRID_STATUS_OFFSET offsetof(struct multigrid, status)/sizeof(UINT) #define MGSTATUS(p) ((p)->status) #define RESETMGSTATUS(p) {(p)->status=0; (p)->magic_cookie = (int)time(NULL); (p)->saved=0;} #define MG_MAGIC_COOKIE(p) ((p)->magic_cookie) #define VIDCNT(p) ((p)->vertIdCounter) #define NIDCNT(p) ((p)->nodeIdCounter) #define EIDCNT(p) ((p)->elemIdCounter) #define TOPLEVEL(p) ((p)->topLevel) #define FULLREFINELEVEL(p) ((p)->fullrefineLevel) #define MG_BVP(p) ((p)->theBVP) #define MG_BVPD(p) (&((p)->theBVPD)) #define MGHEAP(p) ((p)->theHeap) #define MG_NPROPERTY(p) ((p)->nProperty) #define GRID_ON_LEVEL(p,i) ((p)->grids[i]) #define MGNAME(p) ((p)->v.name) #ifdef UG_DIM_3 #define VEC_DEF_IN_OBJ_OF_MG(p,tp) (true) // 3d grids have side vectors #else #define VEC_DEF_IN_OBJ_OF_MG(p,tp) (false) // 2d grids have no vectors at all #endif #define MG_SAVED(p) ((p)->saved) /****************************************************************************/ /* */ #define MG_FILENAME(p) ((p)->filename) #define MG_COARSE_FIXED(p) ((p)->CoarseGridFixed) #define MG_MARK_KEY(p) ((p)->MarkKey) /* macros for formats */ /* */ /****************************************************************************/ /** \brief Constants for USED flags of objects */ enum {MG_ELEMUSED = 1, MG_NODEUSED = 2, MG_EDGEUSED = 4, MG_VERTEXUSED = 8, MG_VECTORUSED = 16, MG_MATRIXUSED = 32}; /****************************************************************************/ /* */ /* interface functions for module grid manager */ /* */ /****************************************************************************/ /** \brief Return values for functions returning an INT. The usual rule is: 0 ok, >0 error */ enum {GM_OK = 0, GM_ERROR = 1, GM_FILEOPEN_ERROR = 2, GM_RULE_WITH_ORIENTATION = 3, GM_RULE_WITHOUT_ORIENTATION = 4, GM_OUT_OF_MEM = 5, GM_OUT_OF_RANGE = 6, GM_NOT_FOUND = 7, GM_INCONSISTENCY = 8, GM_COARSE_NOT_FIXED = 9, GM_FATAL = 999}; /** @name Some constants passed as parameters */ /*@{*/ enum {GM_KEEP_BOUNDARY_NODES, GM_MOVE_BOUNDARY_NODES, GM_REFINE_TRULY_LOCAL, GM_COPY_ALL, GM_REFINE_NOT_CLOSED}; enum {GM_REFINE_PARALLEL, GM_REFINE_SEQUENTIAL}; enum {GM_REFINE_NOHEAPTEST, GM_REFINE_HEAPTEST}; /*@}*/ /* get/set current multigrid, loop through multigrids */ MULTIGRID *MakeMGItem (const char *name, std::shared_ptr context); MULTIGRID *GetMultigrid (const char *name); MULTIGRID *GetFirstMultigrid (void); MULTIGRID *GetNextMultigrid (const MULTIGRID *theMG); /* create, saving and disposing a multigrid structure */ MULTIGRID *CreateMultiGrid (char *MultigridName, STD_BVP *theBVP, const char *format, INT optimizedIE, INT insertMesh, std::shared_ptr ppifContext = nullptr); MULTIGRID *OpenMGFromDataFile(MULTIGRID *theMG, INT number, char *type, char *DataFileName, NS_PREFIX MEM heapSize); INT DisposeGrid (GRID *theGrid); INT DisposeMultiGrid (MULTIGRID *theMG); INT Collapse (MULTIGRID *theMG); /* coarse grid manipulations */ NODE *InsertInnerNode (GRID *theGrid, const DOUBLE *pos); NODE *InsertBoundaryNode (GRID *theGrid, BNDP *bndp); INT DeleteNode (GRID *theGrid, NODE *theNode); ELEMENT *InsertElement (GRID *theGrid, INT n, NODE **NodeList, ELEMENT **ElemList, INT *NbgSdList, INT *bnds_flag); INT InsertMesh (MULTIGRID *theMG, MESH *theMesh); INT DeleteElement (MULTIGRID *theMG, ELEMENT *theElement); /* refinement */ /** \todo !!! should be moved to rm.h [Thimo] */ INT EstimateHere (const ELEMENT *theElement); INT MarkForRefinement (ELEMENT *theElement, enum RefinementRule rule, INT data); INT GetRefinementMark (ELEMENT *theElement, INT *rule, void *data); INT GetRefinementMarkType (ELEMENT *theElement); INT AdaptMultiGrid (MULTIGRID *theMG, INT flag, INT seq, INT mgtest); INT SetRefineInfo (MULTIGRID *theMG); /* moving nodes */ #ifdef UG_DIM_3 INT GetSideIDFromScratch (ELEMENT *theElement, NODE *theNode); #endif /* algebraic connections */ INT DisposeConnectionsInGrid (GRID *theGrid); /* searching */ INT InnerBoundary (ELEMENT *t, INT side); /* list */ void ListMultiGridHeader (const INT longformat); void ListMultiGrid (const MULTIGRID *theMG, const INT isCurrent, const INT longformat); INT MultiGridStatus (const MULTIGRID *theMG, INT gridflag, INT greenflag, INT lbflag, INT verbose); void ListGrids (const MULTIGRID *theMG); void ListNode (const MULTIGRID *theMG, const NODE *theNode, INT dataopt, INT bopt, INT nbopt, INT vopt); void ListElement (const MULTIGRID *theMG, const ELEMENT *theElement, INT dataopt, INT bopt, INT nbopt, INT vopt); void ListVector (const MULTIGRID *theMG, const VECTOR *theVector, INT dataopt, INT modifiers); /* query */ LINK *GetLink (const NODE *from, const NODE *to); EDGE *GetSonEdge (const EDGE *theEdge); INT GetSonEdges (const EDGE *theEdge, EDGE *SonEdges[MAX_SON_EDGES]); EDGE *GetFatherEdge (const EDGE *theEdge); #ifdef UG_DIM_3 EDGE *FatherEdge (NODE **SideNodes, INT ncorners, NODE **Nodes, EDGE *theEdge); #endif EDGE *GetEdge (const NODE *from, const NODE *to); INT GetSons (const ELEMENT *theElement, ELEMENT *SonList[MAX_SONS]); #ifdef ModelP INT GetAllSons (const ELEMENT *theElement, ELEMENT *SonList[MAX_SONS]); #endif INT VectorPosition (const VECTOR *theVector, FieldVector& position); /* check */ #ifndef ModelP INT CheckGrid (GRID *theGrid, INT checkgeom, INT checkalgebra, INT checklists); #else INT CheckGrid (GRID *theGrid, INT checkgeom, INT checkalgebra, INT checklists, INT checkif); #endif INT CheckLists (GRID *theGrid); INT CheckSubdomains (MULTIGRID *theMG); /* multigrid user data space management (using the heaps.c block heap management) */ INT AllocateControlEntry (INT cw_id, INT length, INT *ce_id); INT FreeControlEntry (INT ce_id); UINT ReadCW (const void *obj, INT ce); void WriteCW (void *obj, INT ce, INT n); /* miscellaneous */ INT MGSetVectorClasses (MULTIGRID *theMG); INT SetEdgeSubdomainFromElements (GRID *theGrid); INT SetSubdomainIDfromBndInfo (MULTIGRID *theMG); INT FixCoarseGrid (MULTIGRID *theMG); INT ClearMultiGridUsedFlags (MULTIGRID *theMG, INT FromLevel, INT ToLevel, INT mask); void CalculateCenterOfMass (ELEMENT *theElement, DOUBLE_VECTOR center_of_mass); INT KeyForObject (KEY_OBJECT *obj); /** \todo remove the following functions after the code will never need any debugging */ char *PrintElementInfo (ELEMENT *theElement,INT full); END_UGDIM_NAMESPACE #endif dune-uggrid-2.11.0+dfsg/dune/uggrid/gm/gmcheck.cc000066400000000000000000001633351513616443000214710ustar00rootroot00000000000000// SPDX-FileCopyrightText: Copyright © DUNE Project contributors, see file LICENSE.md in module root // SPDX-License-Identifier: LGPL-2.1-or-later /****************************************************************************/ /* */ /* File: gmcheck.c */ /* */ /* Purpose: checks of the data structure */ /* */ /* Author: Stefan Lang */ /* Institut fuer Computeranwendungen III */ /* Universitaet Stuttgart */ /* Pfaffenwaldring 27 */ /* 70569 Stuttgart */ /* email: ug@ica3.uni-stuttgart.de */ /* */ /* History: Juli 1, 1997 moved from ugm.c */ /* */ /* Remarks: */ /* */ /****************************************************************************/ /****************************************************************************/ /* */ /* defines to exclude functions */ /* */ /****************************************************************************/ /****************************************************************************/ /* */ /* include files */ /* system include files */ /* application include files */ /* */ /****************************************************************************/ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "evm.h" #include "gm.h" #include "rm.h" #include "dlmgr.h" #include "algebra.h" #include "ugm.h" #include "elements.h" #include "shapes.h" #include "refine.h" #include #ifdef ModelP #include #endif #include "cw.h" USING_UG_NAMESPACES using namespace PPIF; /****************************************************************************/ /* */ /* data structures used in this source file (exported data structures are */ /* in the corresponding include file!) */ /* */ /****************************************************************************/ /****************************************************************************/ /* */ /* definition of exported global variables */ /* */ /****************************************************************************/ /****************************************************************************/ /* */ /* definition of variables global to this source file only (static!) */ /* */ /****************************************************************************/ #ifdef ModelP #if defined(UG_DIM_2) static DOUBLE hghost_overlap = 1.0; #endif #endif /****************************************************************************/ /* */ /* forward declarations of functions used before they are defined */ /* */ /****************************************************************************/ static INT CheckVertex (ELEMENT *theElement, NODE* theNode, VERTEX *theVertex) { ELEMENT *theFather = VFATHER(theVertex); EDGE *theEdge; INT i,nerrors,n; DOUBLE diff; DOUBLE_VECTOR global1; DOUBLE *x[MAX_CORNERS_OF_ELEM]; nerrors = 0; if (SONNODE(theNode) == NULL) { INT cnt = NOOFNODE(theVertex); NODE *Node = theNode; while (Node!=NULL && CORNERTYPE(Node)) { cnt--; Node = (NODE*) NFATHER(Node); } if (cnt != 1) { UserWriteF("elem=" EID_FMTX " node=" ID_FMTX " vertex=" VID_FMTX " NOOFNODE %d wrong\n", EID_PRTX(theElement),ID_PRTX(theNode), VID_PRTX(theVertex), NOOFNODE(theVertex)); nerrors = 1; } } if (theFather==NULL && MASTER(theNode) && LEVEL(theVertex)>0) { #ifdef ModelP if (!CORNERTYPE(theNode)) { nerrors = 0; IFDEBUG(gm,1) nerrors = 1; ENDDEBUG } if (nerrors == 0) return(nerrors); #endif UserWriteF("elem=" EID_FMTX " node=" ID_FMTX " vertex=" VID_FMTX " VFATHER=NULL vertex needs VFATHER\n",EID_PRTX(theElement),ID_PRTX(theNode), VID_PRTX(theVertex)); return(nerrors++); } if (theFather!=NULL && MASTER(theNode) && EPRIO(theFather)==PrioHGhost) { #ifdef ModelP if (!CORNERTYPE(theNode)) { nerrors = 0; IFDEBUG(gm,1) nerrors = 1; ENDDEBUG } #endif if (nerrors == 0) return(nerrors); UserWriteF("elem=" EID_FMTX " node=" ID_FMTX " vertex=" VID_FMTX " VFATHER=" EID_FMTX " vertex needs VFATHER with prio master or vghost\n", EID_PRTX(theElement),ID_PRTX(theNode),VID_PRTX(theVertex),EID_PRTX(theFather)); return(nerrors++); } if (theFather != NULL) { CORNER_COORDINATES(theFather,n,x); const Dune::FieldVector& global = CVECT(theVertex); const Dune::FieldVector& local = LCVECT(theVertex); LOCAL_TO_GLOBAL(n,x,local,global1); V_DIM_EUKLIDNORM_OF_DIFF(global1,global,diff); if (diff > MAX_PAR_DIST) { nerrors++; #ifdef ModelP if (CORNERTYPE(theNode) || GHOST(theNode)) { nerrors = 0; IFDEBUG(gm,1) nerrors = 1; ENDDEBUG } #endif if (nerrors >= 1) { UserWriteF("elem=" EID_FMTX " node=" ID_FMTX "/%d vertex=" VID_FMTX " WARNING VFATHER=%x WARNING diff %f local and global coordinates don't match\n", EID_PRTX(theElement),ID_PRTX(theNode), NTYPE(theNode),VID_PRTX(theVertex),theFather,diff); } } } switch (NTYPE(theNode)) { case (CORNER_NODE) : if (LEVEL(theVertex)==0 && theFather != NULL) { UserWriteF("EID=" EID_FMTX " NID=" ID_FMTX " VID=" VID_FMTX " CORNER_NODE has VFATHER\n", EID_PRTX(theElement),ID_PRTX(theNode),VID_PRTX(theVertex)); } #ifdef ModelP IFDEBUG(gm,0) /* break for ghost nodes if debugging off */ if (GHOST(theNode)) break; ENDDEBUG #endif if (LEVEL(theVertex)>0 && theFather == NULL) { UserWriteF("EID=" EID_FMTX " NID=" ID_FMTX " VID=" VID_FMTX " CORNER_NODE has no VFATHER\n", EID_PRTX(theElement),ID_PRTX(theNode),VID_PRTX(theVertex)); } break; case (MID_NODE) : /* check ONEDGE and VFATHER */ if (theFather == NULL) { #ifdef ModelP IFDEBUG(gm,0) /* break for ghost nodes if debugging off */ if (GHOST(theNode)) break; ENDDEBUG #endif UserWriteF("EID=" EID_FMTX " NID=" ID_FMTX " VID=" VID_FMTX " MID_NODE VFATHER=NULL\n", EID_PRTX(theElement),ID_PRTX(theNode),VID_PRTX(theVertex)); nerrors++; break; } i = ONEDGE(theVertex); theEdge = GetEdge(CORNER(theFather,CORNER_OF_EDGE(theFather,i,0)), CORNER(theFather,CORNER_OF_EDGE(theFather,i,1))); if (theEdge==NULL || theNode!=MIDNODE(theEdge)) { nerrors++; #ifdef ModelP if (EGHOST(theElement)) { nerrors = 0; IFDEBUG(gm,1) nerrors = 1; ENDDEBUG } #endif if (nerrors == 0) break; UserWriteF("EID=" EID_FMTX " NID=" ID_FMTX " VID=" VID_FMTX " ONEDGE and VFATHER incompatible edgeptr=%08x\n", EID_PRTX(theElement),ID_PRTX(theNode), VID_PRTX(theVertex),theEdge); } break; #ifdef UG_DIM_3 case (SIDE_NODE) : if (theFather == NULL) { nerrors++; #ifdef ModelP if (EPRIO(theElement)==PrioHGhost) { nerrors = 0; IFDEBUG(gm,1) nerrors = 1; ENDDEBUG } #endif if (nerrors == 0) break; UserWriteF("EID=" EID_FMTX " NID=" ID_FMTX " VID=" VID_FMTX " SIDE_NODE VFATHER=NULL\n", EID_PRTX(theElement),ID_PRTX(theNode),VID_PRTX(theVertex)); break; } else { if (GetSideNode(theFather,ONSIDE(theVertex)) != theNode) { nerrors = 1; UserWriteF("EID=" EID_FMTX " NID=" ID_FMTX " VID=" VID_FMTX " inconsistent ONSIDE entry\n", EID_PRTX(theElement),ID_PRTX(theNode), VID_PRTX(theVertex)); } } break; #endif case (CENTER_NODE) : if (theFather == NULL) { nerrors++; #ifdef ModelP if (EGHOST(theElement)) { nerrors = 0; IFDEBUG(gm,1) nerrors = 1; ENDDEBUG } #endif if (nerrors == 0) break; UserWriteF("EID=" EID_FMTX " NID=" ID_FMTX " VID=" VID_FMTX " CENTER_NODE VFATHER=NULL\n", EID_PRTX(theElement),ID_PRTX(theNode),VID_PRTX(theVertex)); break; } break; } return(nerrors); } static INT CheckNode (ELEMENT *theElement, NODE* theNode, INT i) { VERTEX *theVertex = MYVERTEX(theNode); NODE *FatherNode; EDGE *FatherEdge; INT nerrors = 0; SETUSED(theNode,1); if (OBJT(theNode) != NDOBJ) { UserWriteF(" node=" ID_FMTX " has wrong OBJ=%d\n", ID_PRTX(theNode),OBJT(theNode)); return(nerrors++); } switch (NTYPE(theNode)) { case (LEVEL_0_NODE) : if (LEVEL(theNode) > 0) { UserWriteF(" node=" ID_FMTX " has NTYPE=LEVEL_0_NODE" " but is on level=%d\n", ID_PRTX(theNode),LEVEL(theNode)); return(nerrors++); } break; case (CORNER_NODE) : { FatherNode = (NODE *)NFATHER(theNode); if (0) /* this code is for special debugging (980204 s.l.) */ if (GID(theNode)==0x11011 && FatherNode!=NULL) { UserWriteF(" cornernode=" ID_FMTX " has father=" ID_FMTX "\n", ID_PRTX(theNode),ID_PRTX(FatherNode)); } if (FatherNode == NULL) { #ifdef ModelP if (MASTER(theNode)) { #endif UserWriteF(" ERROR cornernode=" ID_FMTX " has no father level=%d\n", ID_PRTX(theNode),LEVEL(theNode)); UserWriteF(" elem=" EID_FMTX, EID_PRTX(theElement)); if (EFATHER(theElement) != NULL) { ELEMENT *theFather = EFATHER(theElement); UserWriteF(" father=" EID_FMTX "\n",EID_PRTX(theFather)); for (int j=0; j < CORNERS_OF_ELEM(theFather); j++) { UserWriteF("son[%d]=" ID_FMTX "\n",j,ID_PRTX(CORNER(theFather,j))); } } else UserWriteF(" father=NULL\n"); nerrors++; #ifdef ModelP } else { INT print = 0; IFDEBUG(gm,1) print = 1; ENDDEBUG if (print) UserWriteF(" WARN cornernode=" ID_FMTX " has no father level=%d\n", ID_PRTX(theNode),LEVEL(theNode)); } #endif } if (FatherNode != NULL) { if (OBJT(FatherNode) != NDOBJ) { UserWriteF(" cornernode=" ID_FMTX " has father of wrong type=%d\n", ID_PRTX(theNode),OBJT(FatherNode)); nerrors++; } else { if (SONNODE(FatherNode) != theNode) { UserWriteF(" cornernode=" ID_FMTX " has node father=" ID_FMTX " with wrong backptr=%x\n", ID_PRTX(theNode),ID_PRTX(FatherNode),SONNODE(FatherNode)); /* TODO: this should be deleted */ if (0) SONNODE(FatherNode) = theNode; else nerrors++; } } } } break; case (MID_NODE) : if (LEVEL(theNode)>0) { FatherEdge = (EDGE *)NFATHER(theNode); if (FatherEdge == NULL) { #ifdef ModelP if (MASTER(theNode)) { #endif UserWriteF(" ERROR midnode=" ID_FMTX " has no father level=%d\n", ID_PRTX(theNode),LEVEL(theNode)); UserWriteF(" elem=" EID_FMTX, EID_PRTX(theElement)); if (EFATHER(theElement) != NULL) UserWriteF(" father=" EID_FMTX "\n",EID_PRTX(EFATHER(theElement))); else UserWriteF(" father=NULL\n"); nerrors++; #ifdef ModelP } else { IFDEBUG(gm,1) UserWriteF(" WARN midnode=" ID_FMTX " has no father level=%d\n", ID_PRTX(theNode),LEVEL(theNode)); ENDDEBUG } #endif } if (FatherEdge != NULL) { if (OBJT(FatherEdge) != EDOBJ) { UserWriteF(" midnode=" ID_FMTX " has father of wrong type=%d obj=\n", ID_PRTX(theNode),OBJT(FatherEdge)); nerrors++; } else { if (MIDNODE(FatherEdge) != theNode) { UserWriteF(" midnode=" ID_FMTX " has edge father=" ID_FMTX " with wrong backptr=%x\n", ID_PRTX(theNode),ID_PRTX(FatherEdge),MIDNODE(FatherEdge)); /* TODO: this should be deleted */ if (0) MIDNODE(FatherEdge) = theNode; else nerrors++; /*nerrors++; temp. auskommentiert, um Reperaturwirkung wirklich nutzen zu koennen */ } } } } else { UserWriteF(" node=" ID_FMTX " is midnode BUT on level=%d\n", ID_PRTX(theNode),LEVEL(theNode)); nerrors++; } break; case (SIDE_NODE) : break; case (CENTER_NODE) : break; default : UserWriteF(" node=" ID_FMTX " has unrecognized NTYPE=%d\n", ID_PRTX(theNode),NTYPE(theNode)); break; } if (theVertex != NULL) { CheckVertex(theElement,theNode,theVertex); } else { UserWriteF("elem=" EID_FMTX " node[%d]=" ID_FMTX " vertex=NULL\n", EID_PRTX(theElement),i,ID_PRTX(theNode)); nerrors++; } return(nerrors); } static INT CheckEdge (ELEMENT *theElement, EDGE* theEdge, UINT i) { INT nerrors = 0; NODE *theNode; VERTEX *theVertex; SETUSED(theEdge,1); /** \todo Commented out because it uses GetElemLink, which does not exist */ #if 0 # if defined(UG_DIM_2) { int elemlink,no_of_elem,No_Of_Elem; NODE *n0,*n1; LINK *l0,*l1; ELEMENT *e0,*e1; n0 = CORNER_OF_EDGE_PTR(theElement,i,0); n1 = CORNER_OF_EDGE_PTR(theElement,i,1); elemlink = GetElemLink(n0,n1,theElement); l0 = LINK0(theEdge); l1 = LINK1(theEdge); e0 = LELEM(l0); e1 = LELEM(l1); /* check number of edge neighbor elements */ no_of_elem = 0; if (e0 != NULL) { no_of_elem++; HEAPFAULT(e0); } if (e1 != NULL) { no_of_elem++; HEAPFAULT(e1); } No_Of_Elem = NO_OF_ELEM(theEdge); if (no_of_elem==0 || No_Of_Elem!=no_of_elem) { UserWriteF("elem=" EID_FMTX " edge%d=" EDID_FMTX " NO_OF_ELEM wrong" "NO_OF_ELEM=%d no_of_elem=%d\n", EID_PRTX(theElement),i,EDID_PRTX(theEdge),No_Of_Elem,no_of_elem); } if (elemlink == 0) { if (e0 != theElement) { UserWriteF("elem=" EID_FMTX " edge%d=" EDID_FMTX " LELEM0 wrong" "elemlink=%d LELEM0=%08x\n", EID_PRTX(theElement),i,EDID_PRTX(theEdge),elemlink, (e0!=NULL) ? EGID(e0) : 0); nerrors++; } } else { if (e1 != theElement) { UserWriteF("elem=" EID_FMTX " edge%d=" EDID_FMTX " LELEM0 wrong" "elemlink=%d LELEM0=%08x\n", EID_PRTX(theElement),i,EDID_PRTX(theEdge),elemlink, (e1!=NULL) ? EGID(e1) : 0); nerrors++; } } } # endif #endif theNode = MIDNODE(theEdge); if (theNode == NULL) { #ifdef DUNE_UGGRID_TET_RULESET if (((REFINE(theElement) == RED) && (TAG(theElement) != TETRAHEDRON)) || ((TAG(theElement) == TETRAHEDRON) && (NSONS(theElement) == 8))) #else if (REFINE(theElement) == RED) #endif { #ifdef ModelP IFDEBUG(gm,1) #endif UserWriteF("elem=" EID_FMTX " edge%d=" EDID_FMTX " midnode NID=NULL" " BUT REFINE(elem)=RED\n",EID_PRTX(theElement),i,EDID_PRTX(theEdge)); nerrors++; #ifdef ModelP ENDDEBUG #endif return(nerrors); } else return(nerrors); } theVertex = MYVERTEX(theNode); if (theVertex == NULL) { UserWriteF("elem=" EID_FMTX " edge=%d/%x midnode NID=" ID_FMTX " vertex=NULL\n", EID_PRTX(theElement),i,theEdge,ID_PRTX(theNode)); return(nerrors++); } if (VFATHER(theVertex) != theElement) return(nerrors); if (i != ONEDGE(theVertex)) { if (EGHOST(theElement)) { IFDEBUG(gm,1) UserWriteF("EID=" EID_FMTX " VID=" VID_FMTX " WARNING edgenumber of vertex wrong\n", EID_PRTX(theElement),VID_PRTX(theVertex)); ENDDEBUG } else { UserWriteF("EID=" EID_FMTX " VID=" VID_FMTX " ERROR edgenumber of vertex wrong\n", EID_PRTX(theElement),VID_PRTX(theVertex)); /*nerrors++; !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!*/ } return(nerrors); } return(nerrors); } #ifdef ModelP int EdgeHasTMasterCopy (DDD::DDDContext& context, ELEMENT *e, int i) { EDGE* edge = GetEdge(CORNER_OF_EDGE_PTR(e,i,0),CORNER_OF_EDGE_PTR(e,i,1)); assert(edge != NULL); const auto& proclist = DDD_InfoProcListRange(context, PARHDR(edge)); const int nmaster = CheckProcListCons(proclist, PrioMaster); const int nborder = CheckProcListCons(proclist, PrioBorder); const int nall = nmaster + nborder; if (0) assert(nall==1 || nall==2); if (nall > 2) { UserWriteF("EID=" EID_FMTX " EDID=" EDID_FMTX " ERROR edge%d has mastertype prios=%d\n", EID_PRTX(e),EDID_PRTX(edge),i,nall); } return(nall-1); } #endif static INT CheckElement (GRID *theGrid, ELEMENT *theElement, INT *SideError, INT *EdgeError, INT *NodeError, INT *ESonError, INT *NSonError, INT *errors) { INT j,k,l,n,nsons,bserror,nerrors; NODE *theNode,*theNode1; EDGE *theEdge; ELEMENT *NbElement,*theFather; ELEMENT *SonList[MAX_SONS]; VERTEX *theVertex,*Vertices[MAX_CORNERS_OF_ELEM]; #if defined(ModelP) && defined(UG_DIM_2) auto& dddContext = theGrid->dddContext(); #endif *SideError = 0; *NodeError = 0; *EdgeError = 0; *ESonError = 0; *NSonError = 0; nerrors = 0; bserror = 0; /* check level */ if (GLEVEL(theGrid) != LEVEL(theElement)) { UserWriteF("elem=" EID_FMTX " ERROR level=%2d but gridlevel=%2d\n", EID_PRTX(theElement),LEVEL(theElement),GLEVEL(theGrid)); nerrors++; } /* check side information */ for (INT i=0; i=1 #endif ) for (l=1; l= EDGES_OF_ELEM(theFather)) { #ifdef ModelP if (EMASTER(theFather)) { IFDEBUG(gm,1) UserWriteF("ELEM(" EID_FMTX ") WARNING MIDNODE=NULL" " for mid node[%d]" ID_FMTX "\n", EID_PRTX(theFather),i,ID_PRTX(theNode)); ENDDEBUG } #else UserWriteF("ELEM(" EID_FMTX ") ERROR MIDNODE=NULL" " for mid node[%d]=" ID_FMTX "\n", EID_PRTX(theFather),i,ID_PRTX(theNode)); nerrors++; #endif } } } /* check son information of father */ if (GetAllSons(theFather,SonList)) { UserWrite("cannot get sons\n"); return (1); } UINT i; for (i=0; i 0) { if (EMASTER(theElement)) { UserWriteF("ELEM(" EID_FMTX ") ERROR father=NULL\n", EID_PRTX(theElement)); nerrors++; } } } #endif /* check son information */ if (NSONS(theElement)!=0) { nsons = NSONS(theElement); if (GetAllSons(theElement,SonList)) { UserWrite("cannot get sons\n"); return (1); } for (INT i=0; (SonList[i]!=NULL || i= nsons) { UserWriteF("ELEM(" EID_FMTX "): element has nsons=%d but " " son[%d]=" EID_FMTX " exists\n", EID_PRTX(theElement), NSONS(theElement),i,EID_PRTX(SonList[i])); /* TODO: activate if NSONS is consistent */ if (0) nerrors++; } if (SonList[i] == NULL) { UserWriteF("ELEM(" EID_FMTX "): element has nsons=%d but " " son[%d]=NULL\n", EID_PRTX(theElement),nsons,i); *ESonError |= (1< 0) { UserWriteF("ELEM(" EID_FMTX "): element has %d errors\n", EID_PRTX(theElement),nerrors); *errors = nerrors; } if (*SideError || *EdgeError || *NodeError || *ESonError || *NSonError) return (1); return (0); } #if defined(UG_DIM_2) || defined(ModelP) INT CheckSubdomains (const MULTIGRID *theMG) { return (0); } #else static INT CheckElementSubdomains (GRID *theGrid, ELEMENT *theElement, INT *NodeError, INT *EdgeError, INT *NbError, INT *FatherError, INT *errors) { INT side,found,i,j,k,nerrors,sdid,sc; NODE *theNode,*n1,*n2,*nbn1,*nbn2,*nbn3,*nbn4; EDGE *theEdge,*father_edge; ELEMENT *theFather; VERTEX *theVertex; *NodeError = 0; *EdgeError = 0; *NbError = 0; *FatherError = 0; nerrors = 0; /* check side information */ for (i=0; iNTYPE(n2)) {theNode=n1; n1=n2; n2=theNode;} switch (NTYPE(n1)|(NTYPE(n2)<<4)) { case (CORNER_NODE | (CORNER_NODE<<4)) : father_edge = GetEdge(NFATHER(n1),NFATHER(n2)); if (father_edge!=NULL) sdid=EDSUBDOM(father_edge); else { /* do fathers of n1, n2 lies on a side (of the father) which has BNDS? */ for (j=0; j=0 && (OBJT(theFather)==BEOBJ) && SIDE_ON_BND(theFather,side)) sdid=0; } break; case (MID_NODE | (MID_NODE<<4)) : father_edge = NFATHEREDGE(n1); assert(father_edge!=NULL); nbn1 = NBNODE(LINK0(father_edge)); nbn2 = NBNODE(LINK1(father_edge)); father_edge = NFATHEREDGE(n2); assert(father_edge!=NULL); nbn3 = NBNODE(LINK0(father_edge)); nbn4 = NBNODE(LINK1(father_edge)); /* do all nodes nbn1, nbn2, nbn3, nbn4 ly on the same side of father? */ side=-1; for (j=0; j=0 && (OBJT(theFather)==BEOBJ) && SIDE_ON_BND(theFather,side)) sdid=0; break; case (CORNER_NODE | (SIDE_NODE<<4)) : theVertex = MYVERTEX(n2); if (VFATHER(theVertex)==theFather) side = ONSIDE(theVertex); else side = ONNBSIDE(theVertex); if ((OBJT(theFather)==BEOBJ) && SIDE_ON_BND(theFather,side)) for (k=0; k0) { UserWriteF("ELEM(" EID_FMTX "): element has %d errors\n",EID_PRTX(theElement),nerrors); *errors = nerrors; } if (*NodeError || *EdgeError || *NbError || *FatherError) return (1); return (0); } INT CheckSubdomains (MULTIGRID *theMG) { GRID *theGrid; NODE *theNode; EDGE *theEdge; LINK *theLink; ELEMENT *theElement; INT i,j,k,nerror,NodeError,EdgeError,NbError,FatherError,sd_errors; /* init */ nerror=0; /* first level 0 */ theGrid = GRID_ON_LEVEL(theMG,0); for (theNode=PFIRSTNODE(theGrid); theNode!=NULL; theNode=SUCCN(theNode)) for (theLink=START(theNode); theLink!=NULL; theLink=NEXT(theLink)) SETUSED(MYEDGE(theLink),1); for (theElement=PFIRSTELEMENT(theGrid); theElement!=NULL; theElement=SUCCE(theElement)) if (OBJT(theElement)==BEOBJ) for (i=0; ippifContext(), errors); #endif if (errors != GM_OK) { totalerrors += errors; error++; UserWriteF(" geometry BAD: %d errors",errors); } else UserWrite(" ok"); } /* check algebraic data structures */ if (checkalgebra) { UserWrite(", algebra:"); errors = CheckAlgebra(theGrid); #ifdef ModelP errors = UG_GlobalSumINT(theGrid->ppifContext(), errors); #endif if (errors != GM_OK) { totalerrors += errors; error++; UserWriteF(" algebra BAD: %d errors",errors); } else UserWrite(" ok"); } /* check lists and counters */ if (checklists) { UserWrite(", lists:"); errors = CheckLists(theGrid); #ifdef ModelP errors = UG_GlobalSumINT(theGrid->ppifContext(), errors); #endif if (errors != GM_OK) { totalerrors += errors; error++; UserWriteF(" lists BAD: %d errors",errors); } else UserWrite(" ok"); } #ifdef ModelP /* check interfaces to other procs */ if (checkif) { UserWrite(", interface:"); errors = CheckInterfaces(theGrid); #ifdef ModelP errors = UG_GlobalSumINT(theGrid->ppifContext(), errors); #endif if (errors != GM_OK) { totalerrors += errors; error++; UserWriteF(" interfaces BAD: %d errors",errors); } else UserWrite(" ok"); } #endif if (totalerrors) UserWriteF(", grid BAD: %d check(s) with %d totalerror(s)", error,totalerrors); else UserWrite(", grid ok"); return(error); } dune-uggrid-2.11.0+dfsg/dune/uggrid/gm/initgm.cc000066400000000000000000000066221513616443000213520ustar00rootroot00000000000000// SPDX-FileCopyrightText: Copyright © DUNE Project contributors, see file LICENSE.md in module root // SPDX-License-Identifier: LGPL-2.1-or-later // -*- tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- // vi: set et ts=4 sw=2 sts=2: /****************************************************************************/ /* */ /* File: initgm.c */ /* */ /* Purpose: call the init routines of the grid manager module */ /* */ /* Author: Henrik Rentz-Reichert */ /* Institut fuer Computeranwendungen III */ /* Universitaet Stuttgart */ /* Pfaffenwaldring 27 */ /* 70569 Stuttgart */ /* email: ug@ica3.uni-stuttgart.de */ /* */ /* History: 27.02.95 begin, ug version 3.0 */ /* */ /* Remarks: */ /* */ /****************************************************************************/ /****************************************************************************/ /* */ /* include files */ /* system include files */ /* application include files */ /* */ /****************************************************************************/ /* ANSI-C includes */ #include #include /* low module */ #include #include /* gm module */ #include "gm.h" #include "algebra.h" #include "cw.h" #include "ugm.h" #include "elements.h" #include "refine.h" #include "rm.h" /* own header */ #include "initgm.h" USING_UG_NAMESPACE USING_UGDIM_NAMESPACE /****************************************************************************/ /* */ /* definition of variables global to this source file only (static!) */ /* */ /****************************************************************************/ /****************************************************************************/ /* InitGm - Call the inits for the grid manager module SYNOPSIS: INT InitGm (); PARAMETERS: . void DESCRIPTION: This function calls the inits for the grid manager module. RETURN VALUE: INT .n 0 if ok .n 1 if some error occurred. */ /****************************************************************************/ INT NS_DIM_PREFIX InitGm () { INT err; /* cw.c */ if ((err=InitCW())!=0) { SetHiWrd(err,__LINE__); return (err); } /* elements.c */ if ((err=InitElementTypes())!=0) { SetHiWrd(err,__LINE__); return (err); } /* ugm.c */ if ((err=InitUGManager())!=0) { SetHiWrd(err,__LINE__); return (err); } /* rm.c */ if ((err=InitRuleManager())!=0) { SetHiWrd(err,__LINE__); return (err); } return (0); } INT NS_DIM_PREFIX ExitGm() { INT err; /* ugm.c */ if ((err=ExitUGManager())!=0) { SetHiWrd(err,__LINE__); return (err); } return 0; } dune-uggrid-2.11.0+dfsg/dune/uggrid/gm/initgm.h000066400000000000000000000066021513616443000212120ustar00rootroot00000000000000// -*- tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- // vi: set et ts=4 sw=2 sts=2: // SPDX-FileCopyrightInfo: Copyright © DUNE Project contributors, see file LICENSE.md in module root // SPDX-License-Identifier: LGPL-2.1-or-later /** \defgroup gm The Grid Manager * \ingroup ug */ /*! \file initgm.h * \ingroup gm */ /****************************************************************************/ /* */ /* File: initgm.h */ /* */ /* Purpose: call the init routines of the grid manager module */ /* (header file) */ /* */ /* Author: Henrik Rentz-Reichert */ /* Institut fuer Computeranwendungen III */ /* Universitaet Stuttgart */ /* Pfaffenwaldring 27 */ /* 70569 Stuttgart */ /* email: ug@ica3.uni-stuttgart.de */ /* */ /* History: 27.02.95 begin, ug version 3.0 */ /* */ /* Remarks: */ /* */ /****************************************************************************/ #ifndef __INITGM__ #define __INITGM__ #include #include START_UGDIM_NAMESPACE /****************************************************************************/ /* */ /* function declarations */ /* */ /****************************************************************************/ /* initialisation of the gm module */ INT InitGm (); /* Clean up of the gm module */ INT ExitGm (); END_UGDIM_NAMESPACE #endif dune-uggrid-2.11.0+dfsg/dune/uggrid/gm/mgio.cc000066400000000000000000001316341513616443000210200ustar00rootroot00000000000000// SPDX-FileCopyrightText: Copyright © DUNE Project contributors, see file LICENSE.md in module root // SPDX-License-Identifier: LGPL-2.1-or-later // -*- tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- // vi: set et ts=4 sw=2 sts=2: /****************************************************************************/ /* */ /* File: mgio.c */ /* */ /* Purpose: input/output of loc ref mg */ /* */ /* Author: Klaus Johannsen */ /* Institut fuer Computeranwendungen III */ /* Universitaet Stuttgart */ /* Pfaffenwaldring 27 */ /* 70550 Stuttgart */ /* email: ug@ica3.uni-stuttgart.de */ /* */ /* History: 18.11.96 begin, */ /* */ /* Remarks: */ /* */ /****************************************************************************/ /****************************************************************************/ /* */ /* include files */ /* system include files */ /* application include files */ /* */ /****************************************************************************/ #include #include #include #include #include #include #include #include "mgio.h" #ifdef __MGIO_USE_IN_UG__ #include #include #endif USING_UG_NAMESPACE USING_UGDIM_NAMESPACE /****************************************************************************/ /* */ /* defines in the following order */ /* */ /* compile time constants defining static data size (i.e. arrays) */ /* other constants */ /* macros */ /* */ /****************************************************************************/ #define MGIO_TITLE_LINE "####.sparse.mg.storage.format.####" #define MGIO_INTSIZE 1000 /* minimal 497 !!! */ #define MGIO_DOUBLESIZE 200 #define MGIO_BUFFERSIZE 1024 #define MGIO_CHECK_INTSIZE(n) if ((n)>MGIO_INTSIZE) assert(0) /*return (1)*/ #define MGIO_CHECK_DOUBLESIZE(n) if ((n)>MGIO_DOUBLESIZE) return (1) #define MGIO_CHECK_BUFFERIZE(s) if (strlen(s)>MGIO_BUFFERSIZE) return (1) #define MGIO_ECTRL_NF_LEN 5 #define MGIO_ECTRL_NM_LEN 5 #define MGIO_ECTRL_RF_LEN 18 #define MGIO_ECTRL_RC_LEN 3 #define MGIO_ECTRL_ON_LEN 1 #define MGIO_ECTRL_NF_SHIFT 0 #define MGIO_ECTRL_NM_SHIFT (MGIO_ECTRL_NF_SHIFT + MGIO_ECTRL_NF_LEN) #define MGIO_ECTRL_RF_SHIFT (MGIO_ECTRL_NM_SHIFT + MGIO_ECTRL_NM_LEN) #define MGIO_ECTRL_RC_SHIFT (MGIO_ECTRL_RF_SHIFT + MGIO_ECTRL_RF_LEN) #define MGIO_ECTRL_ON_SHIFT (MGIO_ECTRL_RC_SHIFT + MGIO_ECTRL_RC_LEN) #define MGIO_ECTRL(rf,nf,nm,rc,on) ((((nf)&((1<>MGIO_ECTRL_NF_SHIFT)&((1<>MGIO_ECTRL_NM_SHIFT)&((1<>MGIO_ECTRL_RF_SHIFT)&((1<>MGIO_ECTRL_RC_SHIFT)&((1<>MGIO_ECTRL_ON_SHIFT)&((1< lge; /****************************************************************************/ /* */ /* forward declarations of functions used before they are defined */ /* */ /****************************************************************************/ /****************************************************************************/ /*D MGIO_dircreate - create a directory for multigrid files SYNOPSIS: int MGIO_dircreate (char *filename, int rename); PARAMETERS: . filename - name of directory . rename - renaming option DESCRIPTION: Create a directory with specified name incl. renaming option. The considered path entry is "mgpaths". RETURN VALUE: int .n 0 if ok .n 1 when error occurred. SEE ALSO: D*/ /****************************************************************************/ #ifdef __MGIO_USE_IN_UG__ int NS_DIM_PREFIX MGIO_dircreate (char *filename, int rename) { if (mgpathes_set) return(DirCreateUsingSearchPaths_r(filename,"mgpaths",rename)); else return(DirCreateUsingSearchPaths_r(filename,NULL,rename)); } #endif /****************************************************************************/ /*D MGIO_filetype - test for type of multigrid file SYNOPSIS: INT MGIO_filetype (char *filename); PARAMETERS: . filename - name of file DESCRIPTION: Test for type of multigrid file with name filename in searching paths if exist. The considered path entry is "mgpaths". RETURN VALUE: int .n FT_FILE if regular file .n FT_DIR if directory .n FT_LINK if link and #define S_IFLNK .n FT_UNKNOWN else SEE ALSO: D*/ /****************************************************************************/ #ifdef __MGIO_USE_IN_UG__ int NS_DIM_PREFIX MGIO_filetype (char *filename) { if (mgpathes_set) return(FileTypeUsingSearchPaths(filename,"mgpaths")); else return(filetype(filename)); } #endif /****************************************************************************/ /*D Read_OpenMGFile - opens multigrid file for reading SYNOPSIS: int Read_OpenMGFile (char *filename); PARAMETERS: . filename - name of file DESCRIPTION: Opens a multigrid file with specified name for reading. The considered path entry is "mgpaths". RETURN VALUE: int .n 0 if ok .n 1 when error occurred. SEE ALSO: D*/ /****************************************************************************/ int NS_DIM_PREFIX Read_OpenMGFile (char *filename) { #ifdef __MGIO_USE_IN_UG__ if (mgpathes_set) stream = FileOpenUsingSearchPaths(filename,"r","mgpaths"); else stream = fileopen(filename,"r"); #else stream = fopen(filename,"r"); #endif if (stream==NULL) return (1); return (0); } /****************************************************************************/ /*D Write_OpenMGFile - opens multigrid file for writing SYNOPSIS: int Write_OpenMGFile (char *filename, int rename); PARAMETERS: . filename - name of file . rename - renaming option DESCRIPTION: Opens a multigrid file with specified name for writing incl. renaming option. The considered path entry is "mgpaths". RETURN VALUE: int .n 0 if ok .n 1 when error occurred. SEE ALSO: D*/ /****************************************************************************/ int NS_DIM_PREFIX Write_OpenMGFile (char *filename, int rename) { #ifdef __MGIO_USE_IN_UG__ if (mgpathes_set) stream = FileOpenUsingSearchPaths_r(filename,"w","mgpaths",rename); else stream = fileopen_r(filename,"w",rename); #else stream = fopen(filename,"w"); #endif if (stream==NULL) return (1); return (0); } /****************************************************************************/ /* Read_MG_General - reads general information about mg SYNOPSIS: int Read_MG_General (MGIO_MG_GENERAL *mg_general); PARAMETERS: . mg_general - general information about mg DESCRIPTION: function reads general information about the mg RETURN VALUE: INT .n 0 if ok .n 1 if read error. SEE ALSO: */ /****************************************************************************/ int NS_DIM_PREFIX Read_MG_General (MGIO_MG_GENERAL *mg_general) { /* initialize basic i/o */ if (Bio_Initialize(stream,BIO_ASCII,'r')) return (1); /* head always in ACSII */ if (Bio_Read_string(buffer)) return (1); if (strcmp(buffer,MGIO_TITLE_LINE)!=0) return (1); if (Bio_Read_mint(1,intList)) return (1); mg_general->mode = intList[0]; /* re-initialize basic i/o */ if (Bio_Initialize(stream,mg_general->mode,'r')) return (1); /* now special mode */ if (Bio_Read_string(mg_general->version)) return (1); if (strcmp(mg_general->version,"UG_IO_2.2")==0) { strcpy(mg_general->version,"UG_IO_2.3"); } if (Bio_Read_string(mg_general->ident)) return (1); if (Bio_Read_string(mg_general->DomainName)) return (1); if (Bio_Read_string(mg_general->MultiGridName)) return (1); if (Bio_Read_string(mg_general->Formatname)) return (1); if (Bio_Read_mint(11,intList)) return (1); mg_general->dim = intList[0]; mg_general->magic_cookie= intList[1]; mg_general->heapsize = intList[2]; mg_general->nLevel = intList[3]; mg_general->nNode = intList[4]; mg_general->nPoint = intList[5]; mg_general->nElement = intList[6]; mg_general->VectorTypes = intList[7]; mg_general->me = intList[8]; mg_general->nparfiles = intList[9]; if (intList[10]!=MGIO_DEBUG) RETURN (1); /* check debug-level of file: 0: no debug information */ /* init global parameters */ nparfiles = mg_general->nparfiles; return (0); } /****************************************************************************/ /* Write_MG_General - writes general information about mg SYNOPSIS: int Write_MG_General (MGIO_MG_GENERAL *mg_general); PARAMETERS: . mg_general - general information about mg DESCRIPTION: function writes general information about the mg RETURN VALUE: INT .n 0 if ok .n 1 if read error. SEE ALSO: */ /****************************************************************************/ int NS_DIM_PREFIX Write_MG_General (MGIO_MG_GENERAL *mg_general) { /* initialize basic i/o */ if (Bio_Initialize(stream,BIO_ASCII,'w')) return (1); /* head always in ACSII */ if (Bio_Write_string(MGIO_TITLE_LINE)) return (1); intList[0] = mg_general->mode; if (Bio_Write_mint(1,intList)) return (1); /* initialize basic i/o */ if (Bio_Initialize(stream,mg_general->mode,'w')) return (1); /* now special mode */ if (Bio_Write_string(mg_general->version)) return (1); if (Bio_Write_string(mg_general->ident)) return (1); if (Bio_Write_string(mg_general->DomainName)) return (1); if (Bio_Write_string(mg_general->MultiGridName)) return (1); if (Bio_Write_string(mg_general->Formatname)) return (1); intList[0] = mg_general->dim; intList[1] = mg_general->magic_cookie; intList[2] = mg_general->heapsize; intList[3] = mg_general->nLevel; intList[4] = mg_general->nNode; intList[5] = mg_general->nPoint; intList[6] = mg_general->nElement; intList[7] = mg_general->VectorTypes; intList[8] = mg_general->me; intList[9] = mg_general->nparfiles; intList[10]= MGIO_DEBUG; if (Bio_Write_mint(11,intList)) return (1); /* init global parameters */ nparfiles = mg_general->nparfiles; return (0); } /****************************************************************************/ /* Read_GE_General - reads general information about general elements SYNOPSIS: int Read_GE_General (MGIO_GE_GENERAL *ge_general); PARAMETERS: . ge_general - general information about general elements DESCRIPTION: function reads general information about general elements RETURN VALUE: INT .n 0 if ok .n 1 if read error. SEE ALSO: */ /****************************************************************************/ int NS_DIM_PREFIX Read_GE_General (MGIO_GE_GENERAL *ge_general) { if (Bio_Read_mint(1,intList)) return (1); ge_general->nGenElement = intList[0]; return (0); } /****************************************************************************/ /* Write_GE_General - writes general information about general elements SYNOPSIS: int Write_GE_General (MGIO_GE_GENERAL *ge_general); PARAMETERS: . ge_general - general information about general elements DESCRIPTION: function writes general information about general elements RETURN VALUE: INT .n 0 if ok .n 1 if read error. SEE ALSO: */ /****************************************************************************/ int NS_DIM_PREFIX Write_GE_General (MGIO_GE_GENERAL *ge_general) { intList[0] = ge_general->nGenElement; if (Bio_Write_mint(1,intList)) return (1); return (0); } /****************************************************************************/ /* Read_GE_Elements - reads general elements SYNOPSIS: int Read_GE_Elements (int n, MGIO_GE_ELEMENT *ge_element); PARAMETERS: . n - nb of general elements to read . ge_element - first general elements DESCRIPTION: function reads general elements RETURN VALUE: INT .n 0 if ok .n 1 if read error. SEE ALSO: */ /****************************************************************************/ int NS_DIM_PREFIX Read_GE_Elements (int n, MGIO_GE_ELEMENT *ge_element) { MGIO_GE_ELEMENT *pge; pge = ge_element; for (int i = 0; i < n; i++) { if (Bio_Read_mint(4,intList)) return 1; int s = 0; pge->tag = lge[i].tag = intList[s++]; pge->nCorner = lge[i].nCorner = intList[s++]; pge->nEdge = lge[i].nEdge = intList[s++]; pge->nSide = lge[i].nSide = intList[s++]; if (pge->nEdge>0 || pge->nSide>0) { if (Bio_Read_mint(2*pge->nEdge+4*pge->nSide,intList)) return 1; s=0; for (int j = 0; j < pge->nEdge; j++) { pge->CornerOfEdge[j][0] = lge[i].CornerOfEdge[j][0] = intList[s++]; pge->CornerOfEdge[j][1] = lge[i].CornerOfEdge[j][1] = intList[s++]; } for (int j = 0; j < pge->nSide; j++) { pge->CornerOfSide[j][0] = lge[i].CornerOfSide[j][0] = intList[s++]; pge->CornerOfSide[j][1] = lge[i].CornerOfSide[j][1] = intList[s++]; pge->CornerOfSide[j][2] = lge[i].CornerOfSide[j][2] = intList[s++]; pge->CornerOfSide[j][3] = lge[i].CornerOfSide[j][3] = intList[s++]; } } pge++; } return 0; } /****************************************************************************/ /* Write_GE_Elements - writes general elements SYNOPSIS: int Write_GE_Elements (int n, MGIO_GE_ELEMENT *ge_element); PARAMETERS: . n - nb of general elements to write . ge_element - first general elements DESCRIPTION: function writes general elements RETURN VALUE: INT .n 0 if ok .n 1 if read error. SEE ALSO: */ /****************************************************************************/ int NS_DIM_PREFIX Write_GE_Elements (int n, MGIO_GE_ELEMENT *ge_element) { MGIO_GE_ELEMENT *pge = ge_element; for (int i = 0; i < n; i++) { int s = 0; intList[s++] = lge[i].tag = pge->tag; intList[s++] = lge[i].nCorner = pge->nCorner; intList[s++] = lge[i].nEdge = pge->nEdge; intList[s++] = lge[i].nSide = pge->nSide; for (int j = 0; j < pge->nEdge; j++) { intList[s++] = lge[i].CornerOfEdge[j][0] = pge->CornerOfEdge[j][0]; intList[s++] = lge[i].CornerOfEdge[j][1] = pge->CornerOfEdge[j][1]; } for (int j = 0; j < pge->nSide; j++) { intList[s++] = lge[i].CornerOfSide[j][0] = pge->CornerOfSide[j][0]; intList[s++] = lge[i].CornerOfSide[j][1] = pge->CornerOfSide[j][1]; intList[s++] = lge[i].CornerOfSide[j][2] = pge->CornerOfSide[j][2]; intList[s++] = lge[i].CornerOfSide[j][3] = pge->CornerOfSide[j][3]; } MGIO_CHECK_INTSIZE(s); if (Bio_Write_mint(s,intList)) return (1); pge++; } return (0); } /****************************************************************************/ /* Read_RR_General - reads general information about refinement rules SYNOPSIS: int Read_RR_General (MGIO_RR_GENERAL *mgio_rr_general); PARAMETERS: . mgio_rr_general - general information about refinement rules DESCRIPTION: function reads general information about refinement rules RETURN VALUE: INT .n 0 if ok .n 1 if read error. SEE ALSO: */ /****************************************************************************/ int NS_DIM_PREFIX Read_RR_General (MGIO_RR_GENERAL *mgio_rr_general) { if (Bio_Read_mint(1+MGIO_TAGS,intList)) return 1; int s = 0; mgio_rr_general->nRules = intList[s++]; for (int i = 0; i < MGIO_TAGS; i++) mgio_rr_general->RefRuleOffset[i] = intList[s++]; return (0); } /****************************************************************************/ /* Write_GE_General - writes general information about refinement rules SYNOPSIS: int Write_RR_General (MGIO_RR_GENERAL *mgio_rr_general); PARAMETERS: . mgio_rr_general - general information about refinement rules DESCRIPTION: function writes general information about refinement rules RETURN VALUE: INT .n 0 if ok .n 1 if read error. SEE ALSO: */ /****************************************************************************/ int NS_DIM_PREFIX Write_RR_General (MGIO_RR_GENERAL *mgio_rr_general) { int s = 0; intList[s++] = mgio_rr_general->nRules; for (int i = 0; i < MGIO_TAGS; i++) intList[s++] = mgio_rr_general->RefRuleOffset[i]; if (Bio_Write_mint(s,intList)) return (1); return (0); } /****************************************************************************/ /* Read_RR_Rules - reads refinement rules SYNOPSIS: int Read_RR_Rules (int n, MGIO_RR_RULE *rr_rules); PARAMETERS: . n - nb of refinement rules to read . rr_rules - first refinement rule DESCRIPTION: function reads refinement rules RETURN VALUE: INT .n 0 if ok .n 1 if read error. SEE ALSO: */ /****************************************************************************/ int NS_DIM_PREFIX Read_RR_Rules (int n, MGIO_RR_RULE *rr_rules) { MGIO_RR_RULE *prr; prr = rr_rules; for (int i = 0; i < n; i++) { if (Bio_Read_mint(2,intList)) return (1); prr->rclass = intList[0]; prr->nsons = intList[1]; int m = MGIO_MAX_NEW_CORNERS+2*MGIO_MAX_NEW_CORNERS+prr->nsons*(1+MGIO_MAX_CORNERS_OF_ELEM+MGIO_MAX_SIDES_OF_ELEM+1); if (Bio_Read_mint(m,intList)) return (1); int s = 0; for (int j = 0; j < MGIO_MAX_NEW_CORNERS; j++) prr->pattern[j] = intList[s++]; for (int j = 0; j < MGIO_MAX_NEW_CORNERS; j++) { prr->sonandnode[j][0] = intList[s++]; prr->sonandnode[j][1] = intList[s++]; } for (int j = 0; j < prr->nsons; j++) { prr->sons[j].tag = intList[s++]; for (int k = 0; k < MGIO_MAX_CORNERS_OF_ELEM; k++) prr->sons[j].corners[k] = intList[s++]; for (int k = 0; k < MGIO_MAX_SIDES_OF_ELEM; k++) prr->sons[j].nb[k] = intList[s++]; prr->sons[j].path = intList[s++]; } prr++; } return (0); } /****************************************************************************/ /* Write_RR_Rules - writes refinement rules SYNOPSIS: int Write_RR_Rules (int n, MGIO_RR_RULE *rr_rules); PARAMETERS: . n - nb of refinement rules to write . rr_rules - first refinement rule DESCRIPTION: function writes refinement rules RETURN VALUE: INT .n 0 if ok .n 1 if read error. SEE ALSO: */ /****************************************************************************/ int NS_DIM_PREFIX Write_RR_Rules (int n, MGIO_RR_RULE *rr_rules) { MGIO_RR_RULE *prr; prr = rr_rules; for (int i = 0; i < n; i++) { int s = 0; intList[s++] = prr->rclass; intList[s++] = prr->nsons; for (int j = 0; j < MGIO_MAX_NEW_CORNERS; j++) intList[s++] = prr->pattern[j]; for (int j = 0; j < MGIO_MAX_NEW_CORNERS; j++) { intList[s++] = prr->sonandnode[j][0]; intList[s++] = prr->sonandnode[j][1]; } for (int j = 0; j < prr->nsons; j++) { intList[s++] = prr->sons[j].tag; for (int k = 0; k < MGIO_MAX_CORNERS_OF_ELEM; k++) intList[s++] = prr->sons[j].corners[k]; for (int k = 0; k < MGIO_MAX_SIDES_OF_ELEM; k++) intList[s++] = prr->sons[j].nb[k]; intList[s++] = prr->sons[j].path; } MGIO_CHECK_INTSIZE(s); if (Bio_Write_mint(s,intList)) return (1); prr++; } return (0); } /****************************************************************************/ /* Read_CG_General - reads general information about coarse grid SYNOPSIS: int Read_CG_General (MGIO_CG_GENERAL *cg_general); PARAMETERS: . cg_general - general information about coarse grid DESCRIPTION: function reads general information about coarse grid RETURN VALUE: INT .n 0 if ok .n 1 if read error. SEE ALSO: */ /****************************************************************************/ int NS_DIM_PREFIX Read_CG_General (MGIO_CG_GENERAL *cg_general) { if (Bio_Read_mint(6,intList)) return (1); cg_general->nPoint = intList[0]; cg_general->nBndPoint = intList[1]; cg_general->nInnerPoint = intList[2]; cg_general->nElement = intList[3]; cg_general->nBndElement = intList[4]; cg_general->nInnerElement = intList[5]; return (0); } /****************************************************************************/ /* Write_CG_General - writes general information about coarse grid SYNOPSIS: int Write_CG_General (MGIO_CG_GENERAL *cg_general); PARAMETERS: . cg_general - general information about coarse grid DESCRIPTION: function writes general information about coarse grid RETURN VALUE: INT .n 0 if ok .n 1 if read error. SEE ALSO: */ /****************************************************************************/ int NS_DIM_PREFIX Write_CG_General (MGIO_CG_GENERAL *cg_general) { intList[0] = cg_general->nPoint; intList[1] = cg_general->nBndPoint; intList[2] = cg_general->nInnerPoint; intList[3] = cg_general->nElement; intList[4] = cg_general->nBndElement; intList[5] = cg_general->nInnerElement; if (Bio_Write_mint(6,intList)) return (1); return (0); } /****************************************************************************/ /* Read_CG_Points - reads coarse grid points SYNOPSIS: int Read_CG_Points (MGIO_CG_POINT *cg_point); PARAMETERS: . n - nb of coarse grid points to read . cg_point - first coarse grid point DESCRIPTION: function reads coarse grid points RETURN VALUE: INT .n 0 if ok .n 1 if read error. SEE ALSO: */ /****************************************************************************/ int NS_DIM_PREFIX Read_CG_Points (int n, MGIO_CG_POINT *cg_point) { for (int i = 0; i < n; i++) { if (Bio_Read_mdouble(MGIO_DIM,doubleList)) return (1); MGIO_CG_POINT *cgp = MGIO_CG_POINT_PS(cg_point,i); for (int j = 0; j < MGIO_DIM; j++) cgp->position[j] = doubleList[j]; if (MGIO_PARFILE) { if (Bio_Read_mint(2,intList)) return (1); cgp->level = intList[0]; cgp->prio = intList[1]; } } return (0); } /****************************************************************************/ /* Write_CG_Points - writes coarse grid points SYNOPSIS: int Write_CG_Points (MGIO_CG_POINT *cg_point); PARAMETERS: . n - nb of coarse grid points to write . cg_point - first coarse grid point DESCRIPTION: function writes coarse grid points RETURN VALUE: INT .n 0 if ok .n 1 if read error. SEE ALSO: */ /****************************************************************************/ int NS_DIM_PREFIX Write_CG_Points (int n, MGIO_CG_POINT *cg_point) { for (int i = 0; i < n; i++) { MGIO_CG_POINT *cgp = MGIO_CG_POINT_PS(cg_point,i); for (int j = 0; j < MGIO_DIM; j++) doubleList[j] = cgp->position[j]; if (Bio_Write_mdouble(MGIO_DIM,doubleList)) return (1); if (MGIO_PARFILE) { intList[0] = cgp->level; intList[1] = cgp->prio; if (Bio_Write_mint(2,intList)) return (1); } } return (0); } /****************************************************************************/ /* Read_pinfo - reads parallel-info for an element SYNOPSIS: static int Read_pinfo (MGIO_CG_ELEMENT *pe); */ /****************************************************************************/ int NS_DIM_PREFIX Read_pinfo (int ge, MGIO_PARINFO *pinfo) { #if (MGIO_DEBUG>0) char buffer[28]; static int nb=0; if (Bio_Read_string(buffer)) return (1); if(strcmp(buffer,"PINFO_BEGIN")!=0) { printf("proc=%d, nb=%d\n",me,nb); fflush(stdout); assert(0); } nb++; #endif int s = 0; int m = 3 + 6 * lge[ge].nCorner; if (Bio_Read_mint(m,intList)) return (1); pinfo->prio_elem = intList[s++]; assert(pinfo->prio_elem<32); pinfo->ncopies_elem = intList[s++]; int np = pinfo->ncopies_elem; pinfo->e_ident = intList[s++]; for (int i = 0; i < lge[ge].nCorner; i++) { pinfo->prio_node[i] = intList[s++]; assert(pinfo->prio_node[i]<32); pinfo->ncopies_node[i] = intList[s++]; np+= pinfo->ncopies_node[i]; pinfo->n_ident[i] = intList[s++]; } for (int i = 0; i < lge[ge].nCorner; i++) { pinfo->prio_vertex[i] = intList[s++]; assert(pinfo->prio_vertex[i]<32); pinfo->ncopies_vertex[i] = intList[s++]; np+= pinfo->ncopies_vertex[i]; pinfo->v_ident[i] = intList[s++]; } s=0; m = 3*lge[ge].nEdge; if (Bio_Read_mint(m,intList)) return (1); for (int i = 0; i < lge[ge].nEdge; i++) { pinfo->prio_edge[i] = intList[s++]; assert(pinfo->prio_edge[i]<32); pinfo->ncopies_edge[i] = intList[s++]; np+= pinfo->ncopies_edge[i]; pinfo->ed_ident[i] = intList[s++]; } if ((np > 0) && Bio_Read_mint(np,intList)) return 1; for (int i = 0; i < np; i++) { pinfo->proclist[i] = intList[i]; ASSERT(pinfo->proclist[i]0) if (Bio_Write_string("PINFO_BEGIN")) return (1); #endif int s = 0; intList[s++] = pinfo->prio_elem; intList[s++] = np = pinfo->ncopies_elem; intList[s++] = pinfo->e_ident; for (int i = 0; i < lge[ge].nCorner; i++) { intList[s++] = pinfo->prio_node[i]; intList[s++] = pinfo->ncopies_node[i]; np+= pinfo->ncopies_node[i]; intList[s++] = pinfo->n_ident[i]; } for (int i = 0; i < lge[ge].nCorner; i++) { intList[s++] = pinfo->prio_vertex[i]; intList[s++] = pinfo->ncopies_vertex[i]; np+= pinfo->ncopies_vertex[i]; intList[s++] = pinfo->v_ident[i]; } if (Bio_Write_mint(s,intList)) RETURN (1); s=0; for (int i = 0; iprio_edge[i]; intList[s++] = pinfo->ncopies_edge[i]; np+= pinfo->ncopies_edge[i]; intList[s++] = pinfo->ed_ident[i]; } if (Bio_Write_mint(s,intList)) RETURN (1); for (int i = 0; i < np; i++) { intList[i] = pinfo->proclist[i]; ASSERT(intList[i] 0) && Bio_Write_mint(np,intList)) return 1; return (0); } /****************************************************************************/ /* Read_CG_Elements - reads coarse grid elements SYNOPSIS: int Read_CG_Elements (int n, MGIO_CG_ELEMENT *cg_element); PARAMETERS: . n - nb of coarse grid elements to read . cg_element - first coarse grid element DESCRIPTION: function reads coarse grid elements RETURN VALUE: INT .n 0 if ok .n 1 if read error. SEE ALSO: */ /****************************************************************************/ int NS_DIM_PREFIX Read_CG_Elements (int n, MGIO_CG_ELEMENT *cg_element) { int i,j,m,s; MGIO_CG_ELEMENT *pe; for (i=0; ige)) return (1); m=lge[pe->ge].nCorner+lge[pe->ge].nSide+3; if (Bio_Read_mint(m,intList)) return (1); s=0; pe->nref = intList[s++]; for (j=0; jge].nCorner; j++) pe->cornerid[j] = intList[s++]; for (j=0; jge].nSide; j++) pe->nbid[j] = intList[s++]; pe->se_on_bnd = intList[s++]; pe->subdomain = intList[s++]; if (MGIO_PARFILE) { if (Bio_Read_mint(1,intList)) return (1); s=0; pe->level = intList[s++]; } #if (MGIO_DEBUG>0) /* read debug extension */ m = 1 + lge[pe->ge].nCorner + lge[pe->ge].nSide; if (Bio_Read_mint(m,intList)) return (1); s=0; pe->mykey = intList[s++]; for (j=0; jge].nCorner; j++) pe->nodekey[j] = intList[s++]; for (j=0; jge].nSide; j++) pe->neighborkey[j] = intList[s++]; #endif } return (0); } /****************************************************************************/ /* Write_CG_Elements - writes coarse grid elements SYNOPSIS: int Write_CG_Elements (int n, MGIO_CG_ELEMENT *cg_element); PARAMETERS: . n - nb of coarse grid elements to write . rr_rules - first coarse grid element DESCRIPTION: function writes coarse grid elements RETURN VALUE: INT .n 0 if ok .n 1 if read error. SEE ALSO: */ /****************************************************************************/ int NS_DIM_PREFIX Write_CG_Elements (int n, MGIO_CG_ELEMENT *cg_element) { for (int i = 0; i < n; i++) { const MGIO_CG_ELEMENT *pe = MGIO_CG_ELEMENT_PS(cg_element, i); /* coarse grid part */ int s = 0; intList[s++] = pe->ge; intList[s++] = pe->nref; for (int j = 0; j < lge[pe->ge].nCorner; j++) intList[s++] = pe->cornerid[j]; for (int j = 0; j < lge[pe->ge].nSide; j++) intList[s++] = pe->nbid[j]; intList[s++] = pe->se_on_bnd; intList[s++] = pe->subdomain; MGIO_CHECK_INTSIZE(s); if (Bio_Write_mint(s,intList)) return (1); if (MGIO_PARFILE) { s=0; intList[s++] = pe->level; if (Bio_Write_mint(s,intList)) return (1); } #if (MGIO_DEBUG>0) /* write debug extension */ s=0; intList[s++] = pe->mykey; for (int j = 0; j < lge[pe->ge].nCorner; j++) intList[s++] = pe->nodekey[j]; for (int j = 0; j < lge[pe->ge].nSide; j++) intList[s++] = pe->neighborkey[j]; if (Bio_Write_mint(s,intList)) return (1); #endif } return (0); } /****************************************************************************/ /* Read_HE_Refinement - reads hierarchical elements SYNOPSIS: int Read_HE_Refinement (MGIO_HE_ELEMENT *he_element); PARAMETERS: . n - nb of hierarchical elements to read . he_element - hierarchical element DESCRIPTION: function reads hierarchical elements RETURN VALUE: INT .n 0 if ok .n 1 if read error. SEE ALSO: */ /****************************************************************************/ int NS_DIM_PREFIX Read_Refinement (MGIO_REFINEMENT *pr, MGIO_RR_RULE *rr_rules) { #if (MGIO_DEBUG>0) char buffer[128]; if (Bio_Read_string(buffer)) assert(0); /*return (1);*/ if(strcmp(buffer,"REFINEMENT_BEGIN")!=0) assert(0); /*return (1);*/ if (Bio_Read_mint(1,intList)) assert(0); /*return (1);*/ #endif if (Bio_Read_mint(2,intList)) assert(0); /*return (1);*/ unsigned int ctrl = intList[0]; pr->sonref = intList[1]; pr->refrule = MGIO_ECTRL_RF(ctrl)-1; if (pr->refrule>-1) { pr->nnewcorners = MGIO_ECTRL_NF(ctrl); pr->nmoved = MGIO_ECTRL_NM(ctrl); pr->refclass = MGIO_ECTRL_RC(ctrl); if (pr->nnewcorners+pr->nmoved>0) if (Bio_Read_mint(pr->nnewcorners+pr->nmoved,intList)) assert(0); /*return (1);*/ int s = 0; for (int j = 0; j < pr->nnewcorners; j++) pr->newcornerid[j] = intList[s++]; for (int j = 0; j < pr->nmoved; j++) pr->mvcorner[j].id = intList[s++]; if (pr->nmoved>0) { if (Bio_Read_mdouble(MGIO_DIM*pr->nmoved,doubleList)) assert(0); /*return (1);*/ s=0; for (int j = 0; j < pr->nmoved; j++) for (int k = 0; k < MGIO_DIM; k++) pr->mvcorner[j].position[k] = doubleList[s++]; } } if (MGIO_PARFILE) { pr->orphanid_ex = MGIO_ECTRL_ON(ctrl); int s = 2; if (pr->orphanid_ex) s += pr->nnewcorners; if (Bio_Read_mint(s,intList)) assert(0); /*return (1);*/ s=0; pr->sonex = intList[s++]; pr->nbid_ex = intList[s++]; if (pr->orphanid_ex) for (int j = 0; j < pr->nnewcorners; j++) pr->orphanid[j] = intList[s++]; for (int k = 0; k < MGIO_MAX_SONS_OF_ELEM; k++) if ((pr->sonex>>k)&1) { int tag = rr_rules[pr->refrule].sons[k].tag; if (Read_pinfo(tag,&pr->pinfo[k])) assert(0); /*return (1);*/ if ((pr->nbid_ex>>k)&1) { if (Bio_Read_mint(lge[tag].nSide,intList)) assert(0); /*return (1);*/ for (int j = 0; j < lge[tag].nSide; j++) pr->nbid[k][j] = intList[j]; } } } #if (MGIO_DEBUG>0) /* read debug extension */ /* read mykey */ if (Bio_Read_mint(1,&(pr->mykey))) assert(0); /*return (1);*/ /* read myfatherkey */ if (Bio_Read_mint(1,&(pr->myfatherkey))) assert(0); /*return (1);*/ /* read nbkey[] */ if (Bio_Read_mint(MGIO_MAX_SIDES_OF_ELEM,pr->nbkey)) assert(0); /*return (1);*/ /* read mycorners */ if (Bio_Read_mint(1,&(pr->mycorners))) assert(0); /*return (1);*/ assert(pr->mycorners>0); if (Bio_Read_mint(3*pr->mycorners,intList)) assert(0); /*return (1);*/ int s = 0; for (int j = 0; j < pr->mycorners; j++) { pr->mycornerkey[j] = intList[s++]; pr->mycornerfatherkey[j] = intList[s++]; pr->mycornersonkey[j] = intList[s++]; } if (pr->refrule>-1) { if (MGIO_PARFILE) { /* read sonskey[], sonsnbkey[][] and nbkey[][] */ for (int k = 0; k < MGIO_MAX_SONS_OF_ELEM; k++) if ((pr->sonex>>k)&1) { tag = rr_rules[pr->refrule].sons[k].tag; s = 1+lge[tag].nSide; if (Bio_Read_mint(s,intList)) assert(0); /*return (1);*/ s=0; pr->sonskey[k] = intList[s++]; for (int j = 0; j < lge[tag].nSide; j++) pr->sonsnbkey[k][j] = intList[s++]; } else pr->sonskey[k] = -1 ; } } #endif return (0); } /****************************************************************************/ /* Write_HE_Refinement - writes hierarchical elements SYNOPSIS: int Write_HE_Refinement (int n, MGIO_HE_ELEMENT *he_element); PARAMETERS: . n - nb of hierarchical elements to write . he_element - hierarchical element DESCRIPTION: function writes hierarchical elements RETURN VALUE: INT .n 0 if ok .n 1 if read error. SEE ALSO: */ /****************************************************************************/ int NS_DIM_PREFIX Write_Refinement (MGIO_REFINEMENT *pr, MGIO_RR_RULE *rr_rules) { int j,k,s,t,tag; #if (MGIO_DEBUG>0) static int g_count; if (Bio_Write_string("REFINEMENT_BEGIN")) return (1); if (Bio_Write_mint(1,&g_count)) return (1); g_count++; #endif s=t=0; if (MGIO_PARFILE) { intList[s++] = MGIO_ECTRL(pr->refrule+1,pr->nnewcorners,pr->nmoved,pr->refclass,pr->orphanid_ex); } else { intList[s++] = MGIO_ECTRL(pr->refrule+1,pr->nnewcorners,pr->nmoved,pr->refclass,0); } intList[s++] = pr->sonref; if (pr->refrule>-1) { for (j=0; jnnewcorners; j++) intList[s++] = pr->newcornerid[j]; for (j=0; jnmoved; j++) intList[s++] = pr->mvcorner[j].id; for (j=0; jnmoved; j++) for (k=0; kmvcorner[j].position[k]; } MGIO_CHECK_INTSIZE(s); if (Bio_Write_mint(s,intList)) return (1); MGIO_CHECK_DOUBLESIZE(t); if (t>0) if (Bio_Write_mdouble(t,doubleList)) return (1); if (MGIO_PARFILE) { s=0; intList[s++] = pr->sonex; intList[s++] = pr->nbid_ex; if (pr->orphanid_ex) for (j=0; jnnewcorners; j++) intList[s++] = pr->orphanid[j]; if (Bio_Write_mint(s,intList)) return (1); for (k=0; ksonex>>k)&1) { tag = rr_rules[pr->refrule].sons[k].tag; if (Write_pinfo(tag,&pr->pinfo[k])) return (1); if ((pr->nbid_ex>>k)&1) { for (j=0; jnbid[k][j]; if (Bio_Write_mint(lge[tag].nSide,intList)) return (1); } } } #if (MGIO_DEBUG>0) /* write debug extension */ /* write mykey */ if (Bio_Write_mint(1,&(pr->mykey))) assert(0); /*return (1);*/ /* write myfatherkey */ if (Bio_Write_mint(1,&(pr->myfatherkey))) assert(0); /*return (1);*/ /* write nbkey[] */ MGIO_CHECK_INTSIZE(MGIO_MAX_SIDES_OF_ELEM); if (Bio_Write_mint(MGIO_MAX_SIDES_OF_ELEM,pr->nbkey)) assert(0); /*return (1);*/ /* write mycorners */ if (Bio_Write_mint(1,&(pr->mycorners))) assert(0); /*return (1);*/ assert(pr->mycorners > 0); s=0; for (j=0; jmycorners; j++) { intList[s++] = pr->mycornerkey[j]; intList[s++] = pr->mycornerfatherkey[j]; intList[s++] = pr->mycornersonkey[j]; } MGIO_CHECK_INTSIZE(s); if (Bio_Write_mint(s,intList)) assert(0); /*return (1);*/ if (pr->refrule>-1) { if (MGIO_PARFILE) { /* write sonskey[], sonsnbkey[][] and nbkey[][] */ for (k=0; ksonex>>k)&1) { s=0; tag = rr_rules[pr->refrule].sons[k].tag; intList[s++] = pr->sonskey[k]; for (j=0; jsonsnbkey[k][j]; MGIO_CHECK_INTSIZE(s); if (Bio_Write_mint(s,intList)) assert(0); /*return (1);*/ } } } #endif return (0); } /****************************************************************************/ /* Read_BD_General - reads general information about boundary description SYNOPSIS: int Read_BD_General (MGIO_BD_GENERAL *bd_general); PARAMETERS: . bd_general - information about boundary description DESCRIPTION: function reads general information about boundary description RETURN VALUE: INT .n 0 if ok .n 1 if read error. SEE ALSO: */ /****************************************************************************/ int NS_DIM_PREFIX Read_BD_General (MGIO_BD_GENERAL *bd_general) { if (Bio_Read_mint(1,intList)) return (1); bd_general->nBndP = intList[0]; return (0); } /****************************************************************************/ /* Write_BD_General - writes general information about boundary description SYNOPSIS: int Write_BD_General (MGIO_BD_GENERAL *bd_general); PARAMETERS: . bd_general - information about boundary description DESCRIPTION: function writes general information about boundary description RETURN VALUE: INT .n 0 if ok .n 1 if read error. SEE ALSO: */ /****************************************************************************/ int NS_DIM_PREFIX Write_BD_General (MGIO_BD_GENERAL *bd_general) { intList[0] = bd_general->nBndP; if (Bio_Write_mint(1,intList)) return (1); return (0); } /****************************************************************************/ /* Read_PBndDesc - reads BNDPs SYNOPSIS: int Read_PBndDesc (MGIO_HEAP *theHeap, int n, BNDP **BndPList); PARAMETERS: . theHeap - heap . n - nb of BndP to read . BndPList - list of ptrs to BndP DESCRIPTION: function reads BNDPs RETURN VALUE: INT .n 0 if ok .n 1 if read error. SEE ALSO: */ /****************************************************************************/ #ifdef __MGIO_USE_IN_UG__ int NS_DIM_PREFIX Read_PBndDesc (STD_BVP *theBVP, HEAP *theHeap, int n, BNDP **BndPList) { if (theBVP!=NULL && theHeap==NULL) return (1); if (theBVP!=NULL) { for (int i = 0; i 0) { for (int i = 0; i < n; i++) if (BNDP_SaveBndP (BndPList[i])) return (1); } else { n=-n; for (int i = 0; i < n; i++) if (BNDP_SaveBndP_Ext (BndPList[i])) return (1); } return (0); } #endif /****************************************************************************/ /* CloseMGFile - close the file SYNOPSIS: int CloseMGFile (); PARAMETERS: DESCRIPTION: close the file RETURN VALUE: INT .n 0 if ok .n 1 if read error. SEE ALSO: */ /****************************************************************************/ int NS_DIM_PREFIX CloseMGFile (void) { if (fclose(stream)!=0) return (1); return (0); } /****************************************************************************/ /* MGIO_Init - init input/output for mg SYNOPSIS: int MGIO_Init (void); PARAMETERS: DESCRIPTION: init the i/o of mg RETURN VALUE: INT .n 0 if ok .n 1 if read error. SEE ALSO: */ /****************************************************************************/ int NS_DIM_PREFIX MGIO_Init () { #ifdef __MGIO_USE_IN_UG__ /* check consistency with output macros */ MGIO_CHECKEXTMACROS; /* path to grid-dirs */ mgpathes_set = 0; if (ReadSearchingPaths("defaults","mgpaths")==0) mgpathes_set = 1; #endif return (0); } dune-uggrid-2.11.0+dfsg/dune/uggrid/gm/mgio.h000066400000000000000000000716031513616443000206610ustar00rootroot00000000000000// -*- tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- // vi: set et ts=4 sw=2 sts=2: // SPDX-FileCopyrightInfo: Copyright © DUNE Project contributors, see file LICENSE.md in module root // SPDX-License-Identifier: LGPL-2.1-or-later /*! \file mgio.h * \ingroup gm */ /****************************************************************************/ /* */ /* File: mgio.h */ /* */ /* Purpose: header file for mgio.c */ /* */ /* Author: Klaus Johannsen */ /* Institut fuer Computeranwendungen III */ /* Universitaet Stuttgart */ /* Pfaffenwaldring 27 */ /* 70550 Stuttgart */ /* email: ug@ica3.uni-stuttgart.de */ /* */ /* History: 13.11.96 begin */ /* */ /* Remarks: */ /* */ /****************************************************************************/ /* switch */ #define __MGIO_USE_IN_UG__ /****************************************************************************/ /* */ /* auto include mechanism and other include files */ /* */ /****************************************************************************/ #ifndef __MGIO__ #define __MGIO__ #include #include #ifdef __MGIO_USE_IN_UG__ #include #include "gm.h" #include "rm.h" #endif #include START_UGDIM_NAMESPACE /****************************************************************************/ /* */ /* configuration of interface */ /* */ /****************************************************************************/ #define MGIO_VERSION "UG_IO_2.5" #define __MGIO_USE_IN_UG__ #define MGIO_DIM 3 /****************************************************************************/ /* */ /* defines in the following order */ /* */ /* compile time constants defining static data size (i.e. arrays) */ /* other constants */ /* macros */ /* */ /****************************************************************************/ #ifdef __MGIO_USE_IN_UG__ #define MGIO_PARFILE (nparfiles>1) #define MGIO_DEBUG 0 #define MGIO_BNDP BNDP #define MGIO_BNDS BNDS #undef MGIO_DIM #define MGIO_DIM DIM #define MGIO_MAX_SONS_OF_ELEM MAX_SONS #define MGIO_MAX_EDGES_OF_ELEM MAX_EDGES_OF_ELEM #define MGIO_MAX_CORNERS_OF_ELEM MAX_CORNERS_OF_ELEM #define MGIO_MAX_SIDES_OF_ELEM MAX_SIDES_OF_ELEM #define MGIO_MAX_NEW_CORNERS MAX_NEW_CORNERS_DIM #define MGIO_MAX_CORNERS_OF_SIDE MAX_CORNERS_OF_SIDE #define MGIO_FATHER_SIDE_OFFSET FATHER_SIDE_OFFSET #define MGIO_MAXLEVEL MAXLEVEL #define MGIO_TAGS TAGS #define MGIO_REFINEMENT_SIZE (MGIO_PARFILE ? sizeof(MGIO_REFINEMENT) : sizeof(struct mgio_refinement_seq)) #define MGIO_CG_POINT_SIZE (MGIO_PARFILE ? (sizeof(MGIO_CG_POINT)) : (sizeof(struct mgio_cg_point_seq))) #define MGIO_CG_ELEMENT_SIZE (MGIO_PARFILE ? (sizeof(MGIO_CG_ELEMENT)) : (sizeof(struct mgio_cg_element_seq))) #define MGIO_REFINEMENT_PS(r,n) (MGIO_PARFILE ? ((r)+(n)) : ((MGIO_REFINEMENT*)(((struct mgio_refinement_seq*)(r))+(n)))) #define MGIO_CG_POINT_PS(p,n) (MGIO_PARFILE ? ((p)+(n)) : ((MGIO_CG_POINT*)(((struct mgio_cg_point_seq*)(p))+(n)))) #define MGIO_CG_ELEMENT_PS(e,n) (MGIO_PARFILE ? ((e)+(n)) : ((MGIO_CG_ELEMENT*)(((struct mgio_cg_element_seq*)(e))+(n)))) #if (MGIO_DIM==2) #define MGIO_CHECKEXTMACROS {assert(MGIO_MAXLEVEL==32); \ assert(MGIO_TAGS==8); \ assert(MGIO_MAX_SONS_OF_ELEM==4); \ assert(MGIO_MAX_EDGES_OF_ELEM==4); \ assert(MGIO_MAX_CORNERS_OF_ELEM==4); \ assert(MGIO_MAX_SIDES_OF_ELEM==4); \ assert(MGIO_MAX_NEW_CORNERS==5); \ assert(MGIO_MAX_CORNERS_OF_SIDE==2);} #endif #if (MGIO_DIM==3) #define MGIO_CHECKEXTMACROS {assert(MGIO_MAXLEVEL==32); \ assert(MGIO_TAGS==8); \ assert(MGIO_MAX_SONS_OF_ELEM==30); \ assert(MGIO_MAX_EDGES_OF_ELEM==12); \ assert(MGIO_MAX_CORNERS_OF_ELEM==8); \ assert(MGIO_MAX_SIDES_OF_ELEM==6); \ assert(MGIO_MAX_NEW_CORNERS==19); \ assert(MGIO_MAX_CORNERS_OF_SIDE==4);} #endif #else #define MGIO_DEBUG 0 /* DO NOT TOUCH !!!!! */ #define MGIO_PAR 0 #define MGIO_MAXLEVEL 32 #define MGIO_TAGS 8 #if (MGIO_DIM==2) #define MGIO_MAX_SONS_OF_ELEM 30 #define MGIO_MAX_EDGES_OF_ELEM 12 #define MGIO_MAX_CORNERS_OF_ELEM 8 #define MGIO_MAX_SIDES_OF_ELEM 6 #define MGIO_MAX_NEW_CORNERS 5 #define MGIO_MAX_CORNERS_OF_SIDE 4 #endif #if (MGIO_DIM==3) #define MGIO_MAX_SONS_OF_ELEM 30 #define MGIO_MAX_EDGES_OF_ELEM 12 #define MGIO_MAX_CORNERS_OF_ELEM 8 #define MGIO_MAX_SIDES_OF_ELEM 6 #define MGIO_MAX_NEW_CORNERS 19 #define MGIO_MAX_CORNERS_OF_SIDE 4 #endif #endif /* defines for MGIO_MG_GENERAL */ #define MGIO_NAMELEN 128 #define MGIO_IDENTLEN 4096 #define MGIO_NODEVECTOR 1 #define MGIO_EDGEVECTOR 2 #define MGIO_SIDEVECTOR 4 #define MGIO_ELEMVECTOR 8 /* macros for MGIO_MG_GENERAL */ #define MGIO_SET_VECTYPE(p,i) (p)->VectorTypes=(i) #define MGIO_ADD_VECTYPE(p,i) (p)->VectorTypes|=(i) #define MGIO_IS_VECTYPE(p,i) (p)->VectorTypes==(i) #define MGIO_CONT_VECTYPE(p,i) (p)->VectorTypes&(i) /****************************************************************************/ /* */ /* data structures exported by the corresponding source file */ /* */ /****************************************************************************/ struct mgio_mg_general { /* information about the file */ int mode; /* macros see above */ char version[MGIO_NAMELEN]; /* version of i/o */ int magic_cookie; /* identification number */ char ident[MGIO_IDENTLEN]; /* identification string from input file */ /* parallel part */ int nparfiles; /* number of processors */ int me; /* id of my processor */ /* number of objects */ int nLevel; /* nb of levels of the mg */ int nNode; /* nb of nodes, i.e. corners of elements */ int nPoint; /* nb of points, i.e. diff node locations in mg */ int nElement; /* nb of elements in mg */ /* information on geometry */ int dim; /* dimension */ char DomainName[MGIO_NAMELEN]; /* name of domain in ug */ char MultiGridName[MGIO_NAMELEN]; /* name of multigrid */ /* information on algebraic structure */ char Formatname[MGIO_NAMELEN]; /* name of format used in ug */ int heapsize; /* heapsize in kbyte, used in ug */ int VectorTypes; /* macros see above */ }; struct mgio_ge_general { int nGenElement; /* nb of general elements used */ }; struct mgio_ge_element { int tag; /* identification of general element in ug */ int nCorner; /* nb of corners */ int nEdge; /* nb of edges */ int nSide; /* nb of sides */ int CornerOfEdge[MGIO_MAX_EDGES_OF_ELEM][2]; /* corners of edge */ int CornerOfSide[MGIO_MAX_SIDES_OF_ELEM][4]; /* corners of side */ }; struct mgio_rr_general { int nRules; /* nb of rules used */ int RefRuleOffset[MGIO_TAGS]; /* offsets used in ug */ }; struct mgio_sondata { SHORT tag; /* which element type is the son */ SHORT corners[MGIO_MAX_CORNERS_OF_ELEM]; /* corners of the son */ SHORT nb[MGIO_MAX_SIDES_OF_ELEM]; /* neighbors of this son */ /* < 20 if neighbor has same father */ /* >= 20 if neighbor has other father */ INT path; /* path used in GetSons() for ug */ }; struct mgio_rr_rule { int rclass; /* class of rule:3bits for COPY, IREG, REG */ int nsons; /* number of sons rule creates */ int pattern[MGIO_MAX_NEW_CORNERS]; /* stores which edges are refined */ int sonandnode[MGIO_MAX_NEW_CORNERS][2]; /* for each new node the number of the son */ /* and the local node number of the node */ struct mgio_sondata sons[MGIO_MAX_SONS_OF_ELEM]; /* for all new sons */ }; struct mgio_cg_general { int nPoint; /* nb of points on coarse grid, sum of next two */ int nBndPoint; /* nb of bnd points on coarse grid */ int nInnerPoint; /* nb of inner points on coarse grid */ int nElement; /* nb of elements on coarse grid, sum of next two */ int nBndElement; /* nb of bnd elements on coarse grid */ int nInnerElement; /* nb of inner elements on coarse grid */ }; struct mgio_cg_point_seq { double position[MGIO_DIM]; /* position of the point */ }; struct mgio_cg_point { double position[MGIO_DIM]; /* position of the point */ int level; /* level of creation */ int prio; /* priority */ }; struct mgio_movedcorner { int id; /* local id of moved node */ double position[MGIO_DIM]; /* position of the point */ }; struct mgio_parinfo { unsigned short *proclist; /* NULL for elements without copies */ unsigned short prio_elem; unsigned short ncopies_elem; int e_ident; /* identification of element */ unsigned short prio_node[MGIO_MAX_CORNERS_OF_ELEM]; unsigned short ncopies_node[MGIO_MAX_CORNERS_OF_ELEM]; int n_ident[MGIO_MAX_CORNERS_OF_ELEM]; /* identification of nodes of elem */ unsigned short prio_vertex[MGIO_MAX_CORNERS_OF_ELEM]; unsigned short ncopies_vertex[MGIO_MAX_CORNERS_OF_ELEM]; int v_ident[MGIO_MAX_CORNERS_OF_ELEM]; /* identification of vertices of elem */ unsigned short prio_edge[MGIO_MAX_EDGES_OF_ELEM]; unsigned short ncopies_edge[MGIO_MAX_EDGES_OF_ELEM]; int ed_ident[MGIO_MAX_EDGES_OF_ELEM]; /* identification of edges of element */ }; struct mgio_cg_element_seq { int ge; /* id of general element */ int cornerid[MGIO_MAX_CORNERS_OF_ELEM]; /* ids of nodes (data reference) */ int nbid[MGIO_MAX_SIDES_OF_ELEM]; /* ids of neighbor elements */ int se_on_bnd; /* side/edge lies on bnd (used bitwise) */ int nref; /* nb of refinements for this element */ /* if 0 element not refined */ int subdomain; /* id of subdomain */ #if (MGIO_DEBUG>0) /* debug extension */ int mykey; /* keys of mine */ int nodekey[MGIO_MAX_CORNERS_OF_ELEM]; /* keys of nodes */ int neighborkey[MGIO_MAX_SIDES_OF_ELEM]; /* keys of neighbors */ #endif }; struct mgio_cg_element { int ge; /* id of general element */ int cornerid[MGIO_MAX_CORNERS_OF_ELEM]; /* ids of nodes (data reference) */ int nbid[MGIO_MAX_SIDES_OF_ELEM]; /* ids of neighbor elements */ int se_on_bnd; /* side/edge lies on bnd (used bitwise) */ int nref; /* nb of refinements for this element */ /* if 0 element not refined */ int subdomain; /* id of subdomain */ #if (MGIO_DEBUG>0) /* debug extension */ int mykey; /* keys of mine */ int nodekey[MGIO_MAX_CORNERS_OF_ELEM]; /* keys of nodes */ int neighborkey[MGIO_MAX_SIDES_OF_ELEM]; /* keys of neighbors */ #endif /* (procs>1)-extension */ int level; }; struct mgio_refinement_seq { /* used only for sizeof */ int refrule; /* id of refinement rule */ int sonref; /* 1 if sons are refined, bitwise */ int refclass; /* refinement class */ int nnewcorners; /* nb of new corners on next level */ int newcornerid[MGIO_MAX_CORNERS_OF_ELEM+MGIO_MAX_NEW_CORNERS]; /* ids of new vert.or -1 */ int nmoved; /* nmoved new vertices moved */ struct mgio_movedcorner mvcorner[MGIO_MAX_NEW_CORNERS]; /* array of moved node */ }; struct mgio_refinement { int refrule; /* id of refinement rule */ int sonref; /* 1 if sons are refined, bitwise */ int refclass; /* refinement class */ int nnewcorners; /* nb of new corners on next level */ int newcornerid[MGIO_MAX_CORNERS_OF_ELEM+MGIO_MAX_NEW_CORNERS]; /* ids of new vert.or -1 */ int nmoved; /* nmoved new vertices moved */ struct mgio_movedcorner mvcorner[MGIO_MAX_NEW_CORNERS]; /* array of moved node */ /* (procs>1)-extension */ int sonex; /* used bitwise */ int orphanid_ex; /* 1 if exists */ int orphanid[MGIO_MAX_CORNERS_OF_ELEM+MGIO_MAX_NEW_CORNERS]; /* ids of orphan node or -1 */ int nbid_ex; /* used bitwise: nbid exists for son ... */ int nbid[MGIO_MAX_SONS_OF_ELEM][MGIO_MAX_SIDES_OF_ELEM]; /* nb-elem-ids of non-orphan */ /* elems referring to orphan elems if nec. */ struct mgio_parinfo pinfo[MGIO_MAX_SONS_OF_ELEM]; #if (MGIO_DEBUG>0) /* debug extension */ int mykey; /* key of the element itself */ int myfatherkey; /* keys of my father */ int mycorners; /* number of element corners */ int mycornerkey[MGIO_MAX_CORNERS_OF_ELEM]; /* keys of the element's corners */ int mycornerfatherkey[MGIO_MAX_CORNERS_OF_ELEM]; /* keys of the element's corners fathers*/ int mycornersonkey[MGIO_MAX_CORNERS_OF_ELEM]; /* keys of the element's corners sons*/ int nbkey[MGIO_MAX_SIDES_OF_ELEM]; /* nb-elem-keys element */ /* (procs>1)-extension */ int sonskey[MGIO_MAX_SONS_OF_ELEM]; /* keys of sons of element */ int sonsnbkey[MGIO_MAX_SONS_OF_ELEM][MGIO_MAX_SIDES_OF_ELEM]; /* keys of neighbors of sons of element */ #endif }; struct mgio_bd_general { int nBndP; /* n BNDP in mg, only ug */ }; typedef struct mgio_mg_general MGIO_MG_GENERAL; typedef struct mgio_ge_general MGIO_GE_GENERAL; typedef struct mgio_ge_element MGIO_GE_ELEMENT; typedef struct mgio_rr_general MGIO_RR_GENERAL; typedef struct mgio_rr_rule MGIO_RR_RULE; typedef struct mgio_cg_general MGIO_CG_GENERAL; typedef struct mgio_cg_point MGIO_CG_POINT; typedef struct mgio_cg_element MGIO_CG_ELEMENT; typedef struct mgio_refinement MGIO_REFINEMENT; typedef struct mgio_bd_general MGIO_BD_GENERAL; typedef struct mgio_parinfo MGIO_PARINFO; /****************************************************************************/ /* */ /* definition of exported global variables */ /* */ /****************************************************************************/ extern int mgpathes_set; /****************************************************************************/ /* */ /* function declarations */ /* */ /****************************************************************************/ /* read functions */ int Read_OpenMGFile (char *filename); int Read_MG_General (MGIO_MG_GENERAL *mg_general); int Read_GE_General (MGIO_GE_GENERAL *ge_general); int Read_GE_Elements (int n, MGIO_GE_ELEMENT *ge_element); int Read_RR_General (MGIO_RR_GENERAL *rr_general); int Read_RR_Rules (int n, MGIO_RR_RULE *rr_rules); int Read_CG_General (MGIO_CG_GENERAL *cg_general); int Read_CG_Points (int n, MGIO_CG_POINT *cg_point); int Read_CG_Elements (int n, MGIO_CG_ELEMENT *cg_element); int Read_Refinement (MGIO_REFINEMENT *refinement, MGIO_RR_RULE *rr_rules); int Read_BD_General (MGIO_BD_GENERAL *bd_general); /* write functions */ int Write_OpenMGFile (char *filename, int rename); int Write_MG_General (MGIO_MG_GENERAL *mg_general); int Write_GE_General (MGIO_GE_GENERAL *ge_general); int Write_GE_Elements (int n, MGIO_GE_ELEMENT *ge_element); int Write_RR_General (MGIO_RR_GENERAL *rr_general); int Write_RR_Rules (int n, MGIO_RR_RULE *rr_rules); int Write_CG_General (MGIO_CG_GENERAL *cg_general); int Write_CG_Points (int n, MGIO_CG_POINT *cg_point); int Write_CG_Elements (int n, MGIO_CG_ELEMENT *cg_element); int Write_Refinement (MGIO_REFINEMENT *refinement, MGIO_RR_RULE *rr_rules); int Write_BD_General (MGIO_BD_GENERAL *bd_general); #ifdef __MGIO_USE_IN_UG__ int Read_pinfo (int ge, MGIO_PARINFO *pinfo); int Write_pinfo (int ge, MGIO_PARINFO *pinfo); int MGIO_filetype (char *filename); int Read_PBndDesc (STD_BVP *theBVP, NS_PREFIX HEAP *theHeap, int n, BNDP **BndPList); int Write_PBndDesc (int n, BNDP **BndPList); #endif /* general functions */ int CloseMGFile (void); int MGIO_Init (void); int MGIO_dircreate (char *filename, int rename); END_UGDIM_NAMESPACE #endif dune-uggrid-2.11.0+dfsg/dune/uggrid/gm/pargm.h000066400000000000000000000427261513616443000210400ustar00rootroot00000000000000// -*- tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- // vi: set et ts=4 sw=2 sts=2: // SPDX-FileCopyrightInfo: Copyright © DUNE Project contributors, see file LICENSE.md in module root // SPDX-License-Identifier: LGPL-2.1-or-later /*! \file pargm.h * \ingroup gm */ /****************************************************************************/ /* */ /* File: pargm.h */ /* */ /* Purpose: defines for parallel grid manager */ /* */ /* Author: Stefan Lang, Klaus Birken */ /* Institut fuer Computeranwendungen III */ /* Universitaet Stuttgart */ /* Pfaffenwaldring 27 */ /* 70550 Stuttgart */ /* email: stefan@ica3.uni-stuttgart.de */ /* phone: 0049-(0)711-685-7003 */ /* fax : 0049-(0)711-685-7000 */ /* */ /* History: 960410 kb created from parallel.h */ /* */ /* Remarks: */ /* */ /****************************************************************************/ /****************************************************************************/ /* */ /* auto include mechanism and other include files */ /* */ /****************************************************************************/ #ifndef __PARGM_H__ #define __PARGM_H__ #include #include #ifdef ModelP #include #include #endif START_UGDIM_NAMESPACE /****************************************************************************/ /* */ /* defines in the following order */ /* */ /* compile time constants defining static data size (i.e. arrays) */ /* other constants */ /* macros */ /* */ /****************************************************************************/ /* object priorities */ enum Priorities { PrioNone = 0, PrioHGhost = 1, PrioVGhost = 2, PrioVHGhost = 3, PrioBorder = 4, PrioMaster = 5 }; /* define dynamic lists ids */ enum DynamicListId {ELEMENT_LIST, NODE_LIST, VECTOR_LIST, VERTEX_LIST}; #ifdef ModelP /* define number of priorities for objects */ enum {MAX_PRIOS = 6}; enum {ELEMENT_PRIOS = 4}; enum {NODE_PRIOS = 5}; enum {VECTOR_PRIOS = 5}; enum {VERTEX_PRIOS = 5}; /* define number of listparts for objects */ enum {MAX_LISTPARTS = 8}; enum {ELEMENT_LISTPARTS = 2}; enum {NODE_LISTPARTS = 3}; enum {VECTOR_LISTPARTS = 3}; enum {VERTEX_LISTPARTS = 3}; /* define mapping from object priority to position in linked list */ #define PRIO2LISTPART(listtype,prio) \ ((listtype == ELEMENT_LIST) ? ((prio == PrioHGhost) ? 0 : \ (prio == PrioVGhost) ? 0 : (prio == PrioVHGhost) ? 0 : \ (prio == PrioMaster) ? 1 : -1) : \ ((prio == PrioHGhost) ? 0 : (prio ==PrioVGhost) ? 0 : \ (prio == PrioVHGhost) ? 0 : \ (prio == PrioBorder) ? 2 : (prio == PrioMaster) ? 2 : -1)) /* define mapping from position in linked list to object priority */ #define LISTPART2PRIO(listtype,listpart,prios) \ { \ INT Entry; \ for (Entry=0; Entryddd)) #define GETGID(x) (( OBJT(x)==IEOBJ || OBJT(x)==BEOBJ) ? EGID((ELEMENT*)(x)) : \ ((OBJT(x)==IVOBJ || OBJT(x)==BVOBJ) ? VXGID((VERTEX *)(x)) :\ ((OBJT(x)==NDOBJ || OBJT(x)==VEOBJ || OBJT(x)==EDOBJ) ? \ GID((NODE *)(x)) : -1))) #else /* not ModelP */ /* define number of priorities for objects */ enum {MAX_PRIOS = 1}; enum {ELEMENT_PRIOS = 1}; enum {NODE_PRIOS = 1}; enum {VECTOR_PRIOS = 1}; enum {VERTEX_PRIOS = 1}; /* define number of listparts for objects */ enum {MAX_LISTPARTS = 1}; enum {ELEMENT_LISTPARTS = 1}; enum {NODE_LISTPARTS = 1}; enum {VECTOR_LISTPARTS = 1}; enum {VERTEX_LISTPARTS = 1}; /** \brief define mapping from object priority to position in linked list */ #define PRIO2LISTPART(listtype,prio) 0 /* define mapping from position in linked list to object priority */ #define LISTPART2PRIO(listtype,listpart,prios) 0 /* define mapping from position in linked list to object priority */ #define PRIO2INDEX(prio) 0 #endif /* printing of IDs via printf() use ID_FMT as format string, and ID_PRT as macro for printing. example of usage: printf("NodeId " ID_FMT "\n", ID_PRT(theNode)); ID_FFMT (fixed format) is a version of ID_FMT with fixed width. ID_FFMTE (extended) is a version of ID_FFMT with additional information. in ModelP, additionally the DDD_GlobalID is printed for each object. NOTE: for vertices and elements, one must use the VID_ and EID_ macros, respectively. this is due to differences in data structures (unions -> PARHDRV/PARHDRE ->VID_/EID_) */ #ifdef ModelP #define ID_FMT "%ld/" GID_FMT #define ID_FFMT "%9ld/" GID_FMT #define ID_PRT(x) ((long)ID(x)),GID(x) #define ID_FMTE "%ld/" GID_FMT "/%d" #define ID_FFMTE "%9ld/" GID_FMT "/%02d" #define ID_PRTE(x) ((long)ID(x)),GID(x),PRIO(x) #define ID_FMTX "%d/%ld/" GID_FMT "/%d" #define ID_FFMTX "%x/%9ld/" GID_FMT "/%02d" #define ID_PRTX(x) KeyForObject((KEY_OBJECT *)x),((long)ID(x)),GID(x),PRIO(x) #define VID_FMT ID_FMT #define VID_FFMT ID_FFMT #define VID_PRT(x) ((long)ID(x)),VXGID(x) #define VID_FMTE ID_FMTE #define VID_FFMTE ID_FFMTE #define VID_PRTE(x) ((long)ID(x)),VXGID(x),VXPRIO(x) #define VID_FMTX ID_FMTX "/%d" #define VID_FFMTX ID_FFMTX "/%d" #define VID_PRTX(x) KeyForObject((KEY_OBJECT *)x),((long)ID(x)),VXGID(x),VXPRIO(x),LEVEL(x) #define EID_FMT ID_FMT #define EID_FFMT ID_FFMT #define EID_PRT(x) ((long)ID(x)),EGID(x) #define EID_FMTE ID_FMTE #define EID_FFMTE ID_FFMTE #define EID_PRTE(x) ((long)ID(x)),EGID(x),EPRIO(x) #define EID_FMTX ID_FMTX "/%d/%d/%d/%d" #define EID_FFMTX ID_FFMTX "/%d" #define EID_PRTX(x) KeyForObject((KEY_OBJECT *)x),((long)ID(x)),EGID(x),EPRIO(x),TAG(x),\ LEVEL(x),ECLASS(x),REFINECLASS(x) #define VINDEX_FMT ID_FMT #define VINDEX_FFMT ID_FFMT #define VINDEX_PRT(x) ((long)VINDEX(x)),GID(x) #define VINDEX_FMTE ID_FMTE #define VINDEX_FFMTE ID_FFMTE #define VINDEX_PRTE(x) ((long)VINDEX(x)),GID(x),PRIO(x) #define VINDEX_FMTX ID_FMTX #define VINDEX_FFMTX ID_FFMTX #define VINDEX_PRTX(x) KeyForObject((KEY_OBJECT *)x),((long)VINDEX(x)),GID(x),PRIO(x) #define EDID_FMT GID_FMT #define EDID_FFMT EDID_FMT #define EDID_PRT(x) GID(x) #define EDID_FMTE GID_FMT "/%d" #define EDID_FFMTE EDID_FMTE #define EDID_PRTE(x) GID(x),PRIO(x) #define EDID_FMTX "%x/" GID_FMT "/%d" #define EDID_FFMTX EDID_FMTX #define EDID_PRTX(x) x,GID(x),PRIO(x) #define PFMT "%3d:" /* PAR/ENDPAR parallel preprocessor statements */ /* to select code only valid for ModelP */ #define PAR(x) x #define ENDPAR #else #define ID_FMT "%ld" #define ID_FFMT "%9ld" #define ID_PRT(x) ((long)ID(x)) #define ID_FMTE "%ld" #define ID_FFMTE "%9ld" #define ID_PRTE(x) ID_PRT(x) #define ID_FMTX "%ld" #define ID_FFMTX "%9ld" #define ID_PRTX(x) ID_PRT(x) #define VID_FMT ID_FMT #define VID_FFMT ID_FFMT #define VID_PRT(x) ID_PRT(x) #define VID_FMTE ID_FMTE #define VID_FFMTE ID_FFMTE #define VID_PRTE(x) VID_PRT(x) #define VID_FMTX ID_FMTX #define VID_FFMTX ID_FFMTX #define VID_PRTX(x) VID_PRT(x) #define EID_FMT ID_FMT #define EID_FFMT ID_FFMT #define EID_PRT(x) ID_PRT(x) #define EID_FMTE ID_FMTE #define EID_FFMTE ID_FFMTE #define EID_PRTE(x) EID_PRT(x) #define EID_FMTX ID_FMTX #define EID_FFMTX ID_FFMTX #define EID_PRTX(x) EID_PRT(x) #define VINDEX_FMT ID_FMT #define VINDEX_FFMT ID_FFMT #define VINDEX_PRT(x) ((long)VINDEX(x)) #define VINDEX_FMTE ID_FMTE #define VINDEX_FFMTE ID_FFMTE #define VINDEX_PRTE(x) VINDEX_PRT(x) #define VINDEX_FMTX ID_FMTX #define VINDEX_FFMTX ID_FFMTX #define VINDEX_PRTX(x) VINDEX_PRT(x) #define EDID_FMT "%08x" #define EDID_FFMT EDID_FMT #define EDID_PRT(x) (x) #define EDID_FMTE "%08x" #define EDID_FFMTE EDID_FMTE #define EDID_PRTE(x) (x) #define EDID_FMTX "%08x" #define EDID_FFMTX EDID_FMTX #define EDID_PRTX(x) (x) #define PFMT "%1d:" #define GID_FMT "%1d" /* dummies for global id */ #define EGID(e) ID(e) #define GID(e) ((OBJT(e)==VEOBJ) ? VINDEX((VECTOR *)e) : ID(e)) #define VGID(e) ID(e) /* PAR/ENDPAR parallel preprocessor statements */ /* for serial case expanded to code x is ignored */ #define PAR(x) #define ENDPAR #define GetAllSons(e,s) GetSons(e,s) /* dummy defines for serial case according to parallel defines in parallel.h */ /* dummies for elements */ #define EMASTER(p) 1 #define EGHOST(p) 0 #define EHGHOST(p) 0 #define EVGHOST(p) 0 #define EPRIO(p) 0 #define SETEPRIO(context, p,i) ; #define EMASTERPRIO(p) 1 #define EPROCLIST(context, p) (&_proclist_) #define ENCOPIES(context, p) 1 #define PARTITION(p) _partition_ /* dummies for nodes, vectors, edges */ #define MASTER(p) 1 #define GHOST(p) 0 #define HGHOST(p) 0 #define VGHOST(p) 0 #define PRIO(p) 0 #define EPRIO(p) 0 #define VXPRIO(p) 0 #define SETPRIO(context, p,i) ; #define PROCLIST(context, p) (&_proclist_) #define NCOPIES(context, p) 1 /* dummies for vertices */ #define SETVXPRIO(context, e,p) ; /* ddd dummies */ #define DDD_OBJ void * #define DDD_IdentifyBegin(context) #define DDD_IdentifyEnd(context) #define DDD_IdentifyNumber(context, o,p,n) #define DDD_IFAOneway(context, p1,p2,p3,p4,p5,p6) /* ppif dummies */ #define Broadcast(context, p,n) ((int)0) /* dummys for reduction functions implemented in dune/uggrid/parallel/dddif/support.c */ #define UG_GlobalSumINT(context, x) x #define UG_GlobalMaxINT(context, x) x #define UG_GlobalMinINT(context, x) x #define UG_GlobalSumNINT(context, x,y) #define UG_GlobalMaxNINT(context, x,y) #define UG_GlobalMinNINT(context, x,y) #define UG_GlobalSumDOUBLE(context, x) x #define UG_GlobalMaxDOUBLE(context, x) x #define UG_GlobalMinDOUBLE(context, x) x #define UG_GlobalSumNDOUBLE(context, x,y) #define UG_GlobalMaxNDOUBLE(context, x,y) #define UG_GlobalMinNDOUBLE(context, x,y) #endif /****************************************************************************/ /* */ /* exported global variables */ /* */ /****************************************************************************/ /****************************************************************************/ /* */ /* function declarations */ /* */ /****************************************************************************/ /* functions implemented in dune/uggrid/parallel/dddif/support.c */ #ifdef ModelP INT UG_GlobalSumINT (const PPIF::PPIFContext& context, INT x); INT UG_GlobalMaxINT (const PPIF::PPIFContext& context, INT x); INT UG_GlobalMinINT (const PPIF::PPIFContext& context, INT x); void UG_GlobalSumNINT (const PPIF::PPIFContext& context, INT n, INT *x); void UG_GlobalMaxNINT (const PPIF::PPIFContext& context, INT n, INT *x); void UG_GlobalMinNINT (const PPIF::PPIFContext& context, INT n, INT *x); DOUBLE UG_GlobalSumDOUBLE (const PPIF::PPIFContext& context, DOUBLE i); DOUBLE UG_GlobalMaxDOUBLE (const PPIF::PPIFContext& context, DOUBLE i); DOUBLE UG_GlobalMinDOUBLE (const PPIF::PPIFContext& context, DOUBLE i); void UG_GlobalSumNDOUBLE (const PPIF::PPIFContext& context, INT n, DOUBLE *x); void UG_GlobalMaxNDOUBLE (const PPIF::PPIFContext& context, INT n, DOUBLE *x); void UG_GlobalMinNDOUBLE (const PPIF::PPIFContext& context, INT n, DOUBLE *x); #endif END_UGDIM_NAMESPACE #endif /* __PARGM_H__ */ dune-uggrid-2.11.0+dfsg/dune/uggrid/gm/refine.cc000066400000000000000000005575051513616443000213460ustar00rootroot00000000000000// SPDX-FileCopyrightText: Copyright © DUNE Project contributors, see file LICENSE.md in module root // SPDX-License-Identifier: LGPL-2.1-or-later /****************************************************************************/ /* */ /* File: refine.c */ /* */ /* Purpose: unstructured grid adaption using a general element concept */ /* (dimension independent for 2/3D) */ /* */ /* Author: Stefan Lang */ /* Institut fuer Computeranwendungen III */ /* Universitaet Stuttgart */ /* Pfaffenwaldring 27 */ /* 70569 Stuttgart */ /* email: ug@ica3.uni-stuttgart.de */ /* */ /* History: 08.08.95 begin serial algorithm, ug version 3.0 */ /* */ /* Remarks: - level 0 grid consists of red elements only */ /* - the only restriction in the element hierarchy is that */ /* green or yellow elements might not have sons of class */ /* green or red */ /* - the rule set for refinement consists of regular (red) */ /* and irregular rules; regular rules create red elements */ /* while irregular rules result in green elements */ /* (green elements are needed for the closure of the grid, */ /* yellow elements, which are from copy rules, save */ /* the numerical properties of the solver and are handsome for */ /* the discretisation */ /* - if the rule set for the red rules is not complete for build-*/ /* up a consistent red refined region the FIFO might be used */ /* for some (hopefully not too much) iterations to find a */ /* consistent one */ /* - in 2D: exists a complete rule set for grids of triangles */ /* and quadrilaterals exclusively */ /* - in 3D: exists a complete rule set for tetrahedrons */ /* and we assume after some analysation a complete set */ /* of rules described by an algorithm for hexahedrons */ /* - for mixed element types in arbitrary dimension no */ /* rule set for the closure exists */ /* - BEFORE refinement we assume a situation where the error */ /* estimator has detected and marked the leaf elements for */ /* further refinement */ /* - AFTER refinement all elements are refined by a rule in way */ /* that no hanging nodes remain (this is the default mode) */ /* or with hanging nodes (in the hanging node mode) */ /* if you use inconsistent red refinement, you need to tell */ /* the algorithm explicitly to use the FIFO */ /* */ /****************************************************************************/ /****************************************************************************/ /* */ /* include files */ /* system include files */ /* application include files */ /* */ /****************************************************************************/ /* standard C library */ #include #include #include #include #include #include #include #include #include /* low module */ #include #include #include #include /* dev module */ #include /* gm module */ #include "algebra.h" #include "evm.h" #include "gm.h" #include "cw.h" #include "refine.h" #include "elements.h" #include "rm.h" #include "ugm.h" /* parallel modules */ #ifdef ModelP #include #include #include #include #include #include "pargm.h" #endif #ifdef Debug #include #endif #include USING_UG_NAMESPACES using namespace PPIF; /****************************************************************************/ /* */ /* defines in the following order */ /* */ /* compile time constants defining static data size (i.e. arrays) */ /* other constants */ /* macros */ /* */ /****************************************************************************/ /* undefine if overlap should be only updated where needed */ /* This does not work since the connection of the overlap needs the fatherelements on both sides (ghost and master sons) and this is not ensured. #define UPDATE_FULLOVERLAP */ /* define for use of DDD_ConsCheck() */ /* #define DDD_CONSCHECK(context) if (DDD_ConsCheck(context)) assert(0); */ #define DDD_CONSCHECK(context) #define MINVNCLASS 2 /* determines copies, dep. on discr. ! */ /* defines for side matching of elements 8 bits: */ /* _ _ _ _ (4 bits for corner of one element) _ _ _ _ (4 bits for the other)*/ #define LINEPOINTS 51 /* 0011 0011 */ #define TRIPOINTS 119 /* 0111 0111 */ #define QUADPOINTS 255 /* 1111 1111 */ #define MAX_GREEN_SONS 32 /* max num of sons for green refinement */ /* define to control element which is responsible */ /* equal side refinement of neighboring elements */ #ifdef ModelP #define _EID_ EGID #define _ID_ GID #else #define _EID_ ID #define _ID_ ID #endif #define EDGE_IN_PATTERN(p,i) (((p)[(i)]) & 0x1) #define SIDE_IN_PATTERN(e,p,i) (((p)[EDGES_OF_ELEM(e)+(i)]) & 0x1) #define EDGE_IN_PAT(p,i) (((p)>>(i)) & 0x1) #define SIDE_IN_PAT(p,i) (((p)>>(i)) & 0x1) #define MARK_BISECT_EDGE(r,i) ((r)->pattern[(i)]==1) #define REF_TYPE_CHANGES(e) ((REFINE(e)!=MARK(e)) || \ (REFINECLASS(e)!=MARKCLASS(e))) #define MARKED(e) (MARK(e)!=NO_REFINEMENT) /* green marked elements were NEWGREEN is true are refined without rule */ #ifdef DUNE_UGGRID_TET_RULESET #define NEWGREEN(e) (TAG(e)==HEXAHEDRON || TAG(e)== PRISM || \ TAG(e)==PYRAMID) #else #define NEWGREEN(e) (TAG(e)==HEXAHEDRON || TAG(e)== PRISM || \ TAG(e)==PYRAMID || TAG(e)== TETRAHEDRON) #endif /* marked elem with new green refinement (without rule, only 3D) */ #ifdef __ANISOTROPIC__ #define MARKED_NEW_GREEN(elem) \ (DIM==3 && ((NEWGREEN(elem) && MARKCLASS(elem)==GREEN_CLASS) || \ ((TAG(elem)==PRISM && MARKCLASS(elem)==RED_CLASS && USED(elem)==1)))) #else #define MARKED_NEW_GREEN(elem) \ (DIM==3 && NEWGREEN(elem) && MARKCLASS(elem)==GREEN_CLASS) #endif /** \brief Refined elem with new green refinement (without rule, only 3D) */ #define REFINED_NEW_GREEN(elem) \ (DIM==3 && NEWGREEN(elem) && REFINECLASS(elem)==GREEN_CLASS) /** \brief Macro to test whether element changes refinement */ #define REFINEMENT_CHANGES(elem) \ (REF_TYPE_CHANGES(elem) || \ (MARKED_NEW_GREEN(elem) && \ (REFINECLASS(elem)!=GREEN_CLASS || (REFINECLASS(elem)==GREEN_CLASS \ && USED(elem)==1)))) /** @name Macros for storing sparse data needed in ExchangeClosureInfo() */ /*@{*/ #define MARKCLASSDATA_SHIFT 20 #define GETMARKCLASSDATA(elem,dataadr) \ (*(dataadr)) = (*(dataadr)) | ((MARKCLASS(elem))<>MARKCLASSDATA_SHIFT)&((1<>MARKDATA_SHIFT)&((1<>COARSENDATA_SHIFT)&((1<=0; i--) \ { \ theEdge=GetEdge(CORNER_OF_EDGE_PTR((elem),i,0), \ CORNER_OF_EDGE_PTR((elem),i,1)); \ ASSERT(theEdge!=NULL); \ \ pattern = (pattern<<1) | macro(theEdge); \ } \ \ (*(patadr)) |= pattern; \ } #define SetEdgeInfo(elem,pat,macro,OP) \ { \ INT i,pattern; \ EDGE *theEdge; \ \ pattern = (pat); \ for (i=0; i>= 1; \ } \ } /*@}*/ #define REFINE_CONTEXT_LIST(d,context) \ IFDEBUG(gm,2) \ { \ INT i; \ \ UserWrite(" UpdateContext is :\n"); \ for(i=0; i
  • GM_OK if ok
  • GM_ERROR if an error occurs
  • */ /****************************************************************************/ INT NS_DIM_PREFIX SetRefineInfo (MULTIGRID *theMG) { if (MultiGridStatus(theMG,1,0,0,0) != GM_OK) return(GM_ERROR); return(GM_OK); } /****************************************************************************/ /** \brief Drop marks from leafelements to first regular This function drops marks from leafelements to first regular, and resets marks on all elements above (important for restrict marks) \return
      .n GM_OK if ok .n GM_ERROR if an error occurs */ /****************************************************************************/ static INT DropMarks (MULTIGRID *theMG) { return(GM_OK); for (INT k = TOPLEVEL(theMG); k > 0; k--) { const GRID *theGrid = GRID_ON_LEVEL(theMG,k); for (ELEMENT *theElement = FIRSTELEMENT(theGrid); theElement != NULL; theElement=SUCCE(theElement)) if ((MARKCLASS(theElement) == RED_CLASS) && (ECLASS(theElement) != RED_CLASS)) { INT Mark = MARK(theElement); /** \todo marks must be changed if element type changes */ if (TAG(theElement)!=HEXAHEDRON && TAG(EFATHER(theElement))==HEXAHEDRON) Mark = HEXA_RED; if (TAG(theElement)!=PYRAMID && TAG(EFATHER(theElement))==PYRAMID) Mark = PYR_RED; ELEMENT *FatherElement = theElement; SETMARK(FatherElement,NO_REFINEMENT); SETMARKCLASS(FatherElement,NO_CLASS); FatherElement = EFATHER(FatherElement); SETMARK(FatherElement,Mark); SETMARKCLASS(FatherElement,RED_CLASS); } } return(GM_OK); } /* Functions for realizing the (parallel) closure FIFO */ /****************************************************************************/ /** \brief Function for realizing the (parallel) closure FIFO */ /****************************************************************************/ static INT InitClosureFIFO (void) { fifo_first=fifo_last=fifo_insertfirst=fifo_insertlast=NULL; first = 1; fifoloop = 0; if (0) UserWriteF("Using FIFO: loop %d\n",fifoloop); return (GM_OK); } /****************************************************************************/ /** \brief Function for realizing the (parallel) closure FIFO \param theGrid - pointer to grid structure . theElement . thePattern . NewPattern DESCRIPTION: */ /****************************************************************************/ static INT UpdateFIFOLists (GRID *theGrid, ELEMENT *theElement, INT thePattern, INT NewPattern) { if (MARKCLASS(theElement)==RED_CLASS && thePattern!=NewPattern) { #ifdef UG_DIM_2 for (INT j = 0; j < EDGES_OF_ELEM(theElement); j++) { if (EDGE_IN_PAT(thePattern,j)==0 && EDGE_IN_PAT(NewPattern,j)) { EDGE *theEdge = GetEdge(CORNER_OF_EDGE_PTR(theElement, j, 0), CORNER_OF_EDGE_PTR(theElement, j, 1)); ASSERT(theEdge != NULL); SETPATTERN(theEdge,1); /* boundary case */ if (SIDE_ON_BND(theElement,j)) continue; /* add the element sharing this edge to fifo_queue */ ELEMENT *NbElement = NBELEM(theElement, j); if (NbElement==NULL) continue; PRINTDEBUG(gm,1,(" ADDING to FIFO: NBID=%d\n", ID(NbElement))) /* unlink element from element list */ if (PREDE(NbElement) != NULL) SUCCE(PREDE(NbElement)) = SUCCE(NbElement); if (SUCCE(NbElement) != NULL) PREDE(SUCCE(NbElement)) = PREDE(NbElement); if (FIRSTELEMENT(theGrid) == NbElement) FIRSTELEMENT(theGrid) = SUCCE(NbElement); SUCCE(NbElement) = PREDE(NbElement) = NULL; /* insert into fifo */ if (fifo_insertfirst == NULL) { fifo_insertfirst = fifo_insertlast = NbElement; } else { SUCCE(fifo_insertlast) = NbElement; PREDE(NbElement) = fifo_insertlast; fifo_insertlast = NbElement; } } if (EDGE_IN_PAT(thePattern,j) && EDGE_IN_PAT(NewPattern,j)==0) { UserWriteF("UpdateFIFOLists(): ERROR EID=%d in fifo " "thePattern=%d has edge=%d refined but " "NewPattern=%d NOT!\n", ID(theElement),thePattern,j,NewPattern); RETURN(-1); } } #endif #ifdef UG_DIM_3 UserWriteF("UpdateFIFOLists(): ERROR fifo for 3D NOT implemented!\n"); ASSERT(0); #endif } return(GM_OK); } /****************************************************************************/ /** \brief Function for realizing the (parallel) closure FIFO \param theGrid - pointer to grid structure */ /****************************************************************************/ static INT UpdateClosureFIFO (GRID *theGrid) { /* insert fifo work list into elementlist */ for (ELEMENT *theElement = fifo_last; theElement != nullptr; theElement=PREDE(theElement)) { SUCCE(theElement) = FIRSTELEMENT(theGrid); PREDE(FIRSTELEMENT(theGrid)) = theElement; FIRSTELEMENT(theGrid) = theElement; } PREDE(FIRSTELEMENT(theGrid)) = NULL; if (fifo_insertfirst != NULL) { /* append fifo insert list to fifo work list */ firstElement = fifo_first = fifo_insertfirst; fifo_last = fifo_insertlast; IFDEBUG(gm,2) UserWriteF(" FIFO Queue:"); for (ELEMENT *theElement = fifo_first; theElement != nullptr; theElement=SUCCE(theElement)) UserWriteF(" %d\n", ID(theElement)); ENDDEBUG fifo_insertfirst = fifo_insertlast = NULL; first = 0; fifoloop++; UserWriteF(" loop %d",fifoloop); return(1); } return(0); } /****************************************************************************/ /* ManageParallelFIFO - function for realizing the (parallel) closure FIFO SYNOPSIS: static INT ManageParallelFIFO (ELEMENT *firstElement); PARAMETERS: \param firstElement DESCRIPTION: \return
        INT */ /****************************************************************************/ static INT ManageParallelFIFO (const PPIF::PPIFContext& context, const ELEMENT *firstElement) { #if defined(FIFO) && defined(ModelP) if (context.procs() == 1) return(0); do { /* exchange FIFO flag and PATTERN from slaves to master */ IF_FIF0AndPat_S2M(GLEVEL(grid)); /* add all master elements of horizontal interface to FIFO */ for (ELEMENT *theElement = firstElement; theElement != nullptr; theElement=SUCCE(theElement)) { if (IS_HOR_MASTER(theElement) && FIFO(theElement)) { AddToFIFIO(theElement); SETFIFO(theElement,0); } } /* check condition for termination of pattern adaptation */ AllFIFOsEmpty = CheckGlobalFIFOStatus(fifo); } while (fifo==NULL && AllFIFOsEmpty==1); #else return (0); #endif } /****************************************************************************/ /** \brief Changes refinement of element \param theElement - pointer to element This function returns a boolean value to indicate, whether an element changes its refinement (1) or not (0). \return
          .n 0 if element will not change refinement .n 1 if it will */ /****************************************************************************/ INT NS_DIM_PREFIX Refinement_Changes (ELEMENT *theElement) { return(REFINEMENT_CHANGES(theElement)); } /****************************************************************************/ /* GridClosure - compute closure for next level SYNOPSIS: static INT PrepareGridClosure (GRID *theGrid); PARAMETERS: \param theGrid - pointer to grid structure DESCRIPTION: This function computes the closure for next level. A closure can only be determined if the rule set for the used elements is complete. This means that for all side and edge patterns possible for an element type exists a rule which closes the element. In this case a FIFO for computing the closure is not needed any more and the closure can be computed in one step. \return
            INT .n >0 if elements will be refined .n 0 if no elements will be refined .n -1 if an error occurred */ /****************************************************************************/ static INT PrepareGridClosure (const GRID *theGrid) { /* reset USED flag of elements and PATTERN and */ /* ADDPATTERN flag on the edges */ for (ELEMENT *theElement = PFIRSTELEMENT(theGrid); theElement != nullptr; theElement=SUCCE(theElement)) { SETUSED(theElement,0); if (EGHOST(theElement)) { SETCOARSEN(theElement,0); SETMARK(theElement,NO_REFINEMENT); SETMARKCLASS(theElement,0); } for (INT j = 0; j < EDGES_OF_ELEM(theElement); j++) { EDGE *theEdge = GetEdge(CORNER_OF_EDGE_PTR(theElement, j, 0), CORNER_OF_EDGE_PTR(theElement, j, 1)); ASSERT(theEdge != NULL); SETPATTERN(theEdge,0); SETADDPATTERN(theEdge,1); /* needed in RestrictMarks() */ } } return(GM_OK); } #ifdef ModelP /****************************************************************************/ /* Gather_ElementClosureInfo - SYNOPSIS: static int Gather_ElementClosureInfo (DDD_OBJ obj, void *data); PARAMETERS: . obj . data DESCRIPTION: \return
              int */ /****************************************************************************/ static int Gather_ElementClosureInfo (DDD::DDDContext&, DDD_OBJ obj, void *data, DDD_PROC proc, DDD_PRIO prio) { ELEMENT *theElement = (ELEMENT *)obj; PRINTDEBUG(gm,1,("Gather_ElementClosureInfo(): e=" EID_FMTX "\n", EID_PRTX(theElement))) INT refinedata = 0; #ifdef UG_DIM_2 GetEdgeInfo(theElement,&refinedata,PATTERN); #endif /* mark and sidepattern have same control word positions */ /* if this changes sidepattern must be sent separately */ GETMARKDATA(theElement,&refinedata); GETMARKCLASSDATA(theElement,&refinedata); GETCOARSENDATA(theElement,&refinedata); ((INT *)data)[0] = refinedata; PRINTDEBUG(gm,1,("Gather_ElementClosureInfo(): refinedata=%08x " "sidepattern=%d markclass=%d mark=%d coarse=%d\n",refinedata, SIDEPATTERN(theElement),MARKCLASS(theElement),MARK(theElement),COARSEN(theElement))) return(GM_OK); } /****************************************************************************/ /* Scatter_ElementClosureInfo - SYNOPSIS: static int Scatter_ElementClosureInfo (DDD_OBJ obj, void *data); PARAMETERS: . obj . data DESCRIPTION: \return
                int */ /****************************************************************************/ static int Scatter_ElementClosureInfo (DDD::DDDContext&, DDD_OBJ obj, void *data, DDD_PROC proc, DDD_PRIO prio) { ELEMENT *theElement = (ELEMENT *)obj; PRINTDEBUG(gm,1,("Scatter_ElementClosureInfo(): e=" EID_FMTX "\n", EID_PRTX(theElement))) INT refinedata = ((INT *)data)[0]; #ifdef UG_DIM_2 SetEdgeInfo(theElement,refinedata,PATTERN,|); #endif /* mark and sidepattern have same control word positions */ /* if this changes sidepattern must be sent separately */ SETMARKDATA(theElement,refinedata); if (EMASTER(theElement)) return(GM_OK); if (EGHOST(theElement) && EGHOSTPRIO(prio)) return(GM_OK); SETMARKCLASSDATA(theElement,refinedata); SETCOARSENDATA(theElement,refinedata); PRINTDEBUG(gm,1,("Scatter_ElementClosureInfo(): refinedata=%08x " "sidepattern=%d markclass=%d mark=%d coarse=%d\n",refinedata, SIDEPATTERN(theElement),MARKCLASS(theElement),MARK(theElement),COARSEN(theElement))) return(GM_OK); } static INT ExchangeElementClosureInfo (GRID *theGrid) { auto& context = theGrid->dddContext(); const auto& dddctrl = ddd_ctrl(context); /* exchange information of elements to compute closure */ DDD_IFAOnewayX(context, dddctrl.ElementSymmVHIF,GRID_ATTR(theGrid),IF_FORWARD,sizeof(INT), Gather_ElementClosureInfo, Scatter_ElementClosureInfo); return(GM_OK); } static int Gather_ElementRefine (DDD::DDDContext&, DDD_OBJ obj, void *data, DDD_PROC proc, DDD_PRIO prio) { ELEMENT *theElement = (ELEMENT *)obj; PRINTDEBUG(gm,1,("Gather_ElementRefine(): e=" EID_FMTX "\n", EID_PRTX(theElement))) ((INT *)data)[0] = MARKCLASS(theElement); ((INT *)data)[1] = MARK(theElement); return(GM_OK); } static int Scatter_ElementRefine (DDD::DDDContext&, DDD_OBJ obj, void *data, DDD_PROC proc, DDD_PRIO prio) { ELEMENT *theElement = (ELEMENT *)obj; PRINTDEBUG(gm,1,("Scatter_ElementClosureInfo(): e=" EID_FMTX "\n", EID_PRTX(theElement))) if (EMASTER(theElement)) return(GM_OK); if (EGHOST(theElement) && EGHOSTPRIO(prio)) return(GM_OK); SETMARKCLASS(theElement,((INT *)data)[0]); SETMARK(theElement,((INT *)data)[1]); return(GM_OK); } static INT ExchangeElementRefine (GRID *theGrid) { auto& context = theGrid->dddContext(); const auto& dddctrl = ddd_ctrl(context); /* exchange information of elements to compute closure */ DDD_IFAOnewayX(context, dddctrl.ElementSymmVHIF,GRID_ATTR(theGrid),IF_FORWARD,2*sizeof(INT), Gather_ElementRefine, Scatter_ElementRefine); return(GM_OK); } #ifdef UG_DIM_3 /****************************************************************************/ /* Gather_EdgeClosureInfo - SYNOPSIS: static int Gather_EdgeClosureInfo (DDD_OBJ obj, void *data); PARAMETERS: . obj . data DESCRIPTION: \return
                  int */ /****************************************************************************/ static int Gather_EdgeClosureInfo (DDD::DDDContext&, DDD_OBJ obj, void *data) { EDGE *theEdge = (EDGE *)obj; PRINTDEBUG(gm,1,("Gather_EdgeClosureInfo(): e=" ID_FMTX "pattern=%d \n", ID_PRTX(theEdge),PATTERN(theEdge))) INT pattern = PATTERN(theEdge); ((INT *)data)[0] = pattern; return(GM_OK); } /****************************************************************************/ /* Scatter_EdgeClosureInfo - SYNOPSIS: static int Scatter_EdgeClosureInfo (DDD_OBJ obj, void *data); PARAMETERS: . obj . data DESCRIPTION: \return
                    int */ /****************************************************************************/ static int Scatter_EdgeClosureInfo (DDD::DDDContext&, DDD_OBJ obj, void *data) { EDGE *theEdge = (EDGE *)obj; INT pattern = std::max((INT)PATTERN(theEdge),((INT *)data)[0]); PRINTDEBUG(gm,1,("Gather_EdgeClosureInfo(): e=" ID_FMTX "pattern=%d \n", ID_PRTX(theEdge),pattern)) SETPATTERN(theEdge,pattern); return(GM_OK); } INT ExchangeEdgeClosureInfo (GRID *theGrid) { auto& context = theGrid->dddContext(); const auto& dddctrl = ddd_ctrl(context); /* exchange information of edges to compute closure */ DDD_IFAOneway(context, dddctrl.EdgeVHIF,GRID_ATTR(theGrid),IF_FORWARD,sizeof(INT), Gather_EdgeClosureInfo, Scatter_EdgeClosureInfo); return(GM_OK); } #endif /****************************************************************************/ /* ExchangeClosureInfo - SYNOPSIS: static INT ExchangeClosureInfo (GRID *theGrid); PARAMETERS: . theGrid DESCRIPTION: \return
                      INT */ /****************************************************************************/ static INT ExchangeClosureInfo (GRID *theGrid) { /* exchange information of elements to compute closure */ if (ExchangeElementClosureInfo(theGrid) != GM_OK) RETURN(GM_ERROR); #ifdef UG_DIM_3 /* exchange information of edges to compute closure */ if (ExchangeEdgeClosureInfo(theGrid) != GM_OK) RETURN(GM_ERROR); #endif return(GM_OK); } #endif /****************************************************************************/ /* ComputePatterns - SYNOPSIS: static INT ComputePatterns (GRID *theGrid); PARAMETERS: . theGrid - pointer to grid structure DESCRIPTION: \return
                        INT */ /****************************************************************************/ static INT ComputePatterns (const GRID *theGrid) { /* ComputePatterns works only on master elements */ /* since ghost elements have no information from */ /* RestrictMarks() up to this time and this may */ /* leed to inconsistency while coarsening */ /* reset EDGE/SIDEPATTERN in elements */ /* set SIDEPATTERN in elements */ /* set PATTERN on the edges */ for (ELEMENT *theElement = PFIRSTELEMENT(theGrid); theElement != nullptr; theElement=SUCCE(theElement)) { #ifdef ModelP if (EGHOST(theElement)) { #ifdef UG_DIM_3 SETSIDEPATTERN(theElement,0); #endif continue; } #endif if (MARKCLASS(theElement)==RED_CLASS) { INT Mark = MARK(theElement); SHORT *thePattern = MARK2PATTERN(theElement,Mark); for (INT i = 0; i < EDGES_OF_ELEM(theElement); i++) if (EDGE_IN_PATTERN(thePattern,i)) { EDGE *theEdge = GetEdge(CORNER_OF_EDGE_PTR(theElement, i, 0), CORNER_OF_EDGE_PTR(theElement, i, 1)); ASSERT(theEdge != NULL); SETPATTERN(theEdge,1); } #ifdef UG_DIM_3 /* SIDEPATTERN must be reset here for master elements, */ /* because it overlaps with MARK (980217 s.l.) */ SETSIDEPATTERN(theElement,0); for (INT i = 0; i < SIDES_OF_ELEM(theElement); i++) { #ifdef DUNE_UGGRID_TET_RULESET if (CORNERS_OF_SIDE(theElement,i)==4) { #endif /* set SIDEPATTERN if side has node */ if(SIDE_IN_PATTERN(theElement,thePattern,i)) SETSIDEPATTERN(theElement, SIDEPATTERN(theElement) | 1< INT */ /****************************************************************************/ static INT CorrectTetrahedronSidePattern (ELEMENT *theElement, INT i, ELEMENT *theNeighbor, INT j) { INT theEdgeNum,theEdgePattern=0; INT NbEdgeNum,NbEdgePattern,NbSidePattern,NbSideMask; if (TAG(theElement)==PYRAMID || TAG(theElement)==PRISM) return(GM_OK); for (INT k = EDGES_OF_ELEM(theElement) - 1; k >= 0; k--) { EDGE *theEdge = GetEdge(CORNER_OF_EDGE_PTR(theElement, k, 0), CORNER_OF_EDGE_PTR(theElement, k, 1)); ASSERT(theEdge!=NULL); theEdgePattern = (theEdgePattern<<1) | PATTERN(theEdge); } /* because SIDEPATTERN is set to zero, */ /* I choose TriSectionEdge[0] */ theEdgeNum = TriSectionEdge[theEdgePattern &CondensedEdgeOfSide[i]][0]; if (theEdgeNum == -2) RETURN(-1); if (theEdgeNum == -1) return(GM_OK); switch (TAG(theNeighbor)) { case TETRAHEDRON : NbEdgePattern = 0; for (INT k = 0; k < EDGES_OF_ELEM(theNeighbor); k++) { EDGE *NbEdge = GetEdge(CORNER_OF_EDGE_PTR(theNeighbor, k, 0), CORNER_OF_EDGE_PTR(theNeighbor, k, 1)); ASSERT(NbEdge!=NULL); NbEdgePattern = NbEdgePattern | (PATTERN(NbEdge)<trisectionedge)) trisectionedge = edge; } assert(trisectionedge != -1); if (theEdgeNum != trisectionedge) SETSIDEPATTERN(theNeighbor, SIDEPATTERN(theNeighbor)|(1< INT */ /****************************************************************************/ static INT CorrectElementSidePattern (ELEMENT *theElement, ELEMENT *theNeighbor, INT i) { INT j; #ifdef ModelP /* this case should not occur */ if (theNeighbor == NULL) { ASSERT(EGHOST(theElement)); UserWriteF("CorrectElementSidePattern(): error elem=" EID_FMTX " nb[%d]=" EID_FMTX " nb=" EID_FMTX "\n", EID_PRTX(theElement),i,EID_PRTX(NBELEM(theElement,i)), EID_PRTX(theNeighbor)); return(GM_OK); } #endif /* search neighbors side */ for (j=0; j= SIDES_OF_ELEM(theNeighbor)) { if (!(EGHOST(theElement) && EGHOST(theNeighbor))) { UserWriteF("CorrectElementSidePattern(): ERROR nbelem not found elem=%08x/" EID_FMTX " nb=%08x/" EID_FMTX "\n", theElement,EID_PRTX(theElement),theNeighbor,EID_PRTX(theNeighbor)); } ASSERT(EGHOST(theElement) && EGHOST(theNeighbor)); return(GM_OK); } #else ASSERT(j INT */ /****************************************************************************/ static INT SetElementSidePatterns (GRID *theGrid, ELEMENT *firstElement) { INT i; ELEMENT *theElement,*theNeighbor; /* set pattern (edge and side) on the elements */ for (theElement=firstElement; theElement!=NULL; theElement=SUCCE(theElement)) { /* make edgepattern consistent with pattern of edges */ SETUSED(theElement,1); #ifndef __ANISOTROPIC__ /** \todo change this for red refinement of pyramids */ if (DIM==3 && TAG(theElement)==PYRAMID) continue; #endif /* make sidepattern consistent with neighbors */ for (i=0; i INT */ /****************************************************************************/ static INT SetElementRules (GRID *theGrid, ELEMENT *firstElement, INT *cnt) { INT Mark,NewPattern; INT thePattern,theEdgePattern,theSidePattern=0; ELEMENT *theElement; [[maybe_unused]] const int me = theGrid->ppifContext().me(); /* set refinement rules from edge- and sidepattern */ (*cnt) = 0; for (theElement=firstElement; theElement!=NULL; theElement=SUCCE(theElement)) { theEdgePattern = 0; /* compute element pattern */ GetEdgeInfo(theElement,&theEdgePattern,PATTERN); #ifdef UG_DIM_2 thePattern = theEdgePattern; PRINTDEBUG(gm,2,(PFMT "SetElementRules(): e=" EID_FMTX " edgepattern=%d\n", me,EID_PRTX(theElement),theEdgePattern)); #endif #ifdef UG_DIM_3 theSidePattern = SIDEPATTERN(theElement); thePattern = theSidePattern< int */ /****************************************************************************/ static int Gather_AddEdgePattern (DDD::DDDContext&, DDD_OBJ obj, void *data) { #ifdef UG_DIM_2 INT pat; ELEMENT *theElement = (ELEMENT *)obj; pat = 0; GetEdgeInfo(theElement,&pat,ADDPATTERN); ((INT *)data)[0] = pat; PRINTDEBUG(gm,4,("Gather_AddEdgePattern(): elem=" EID_FMTX "pat=%08x\n", EID_PRTX(theElement),pat)); return(GM_OK); #endif #ifdef UG_DIM_3 INT addpattern; EDGE *theEdge = (EDGE *)obj; addpattern = ADDPATTERN(theEdge); ((INT *)data)[0] = addpattern; PRINTDEBUG(gm,4,("Gather_AddEdgePattern(): edge=" ID_FMTX "pat=%08x\n", ID_PRTX(theEdge),addpattern)); return(GM_OK); #endif } /****************************************************************************/ /* Scatter_AddEdgePattern - SYNOPSIS: static int Scatter_AddEdgePattern (DDD_OBJ obj, void *data); PARAMETERS: . obj . data DESCRIPTION: \return
                          int */ /****************************************************************************/ static int Scatter_AddEdgePattern (DDD::DDDContext&, DDD_OBJ obj, void *data) { #ifdef UG_DIM_2 INT pat; ELEMENT *theElement = (ELEMENT *)obj; /** \todo (HRR 971207): output after SetEdgeInfo (pat not init)? */ PRINTDEBUG(gm,4,("Scatter_AddEdgePattern(): elem=" EID_FMTX "pat=%08x\n", EID_PRTX(theElement),pat)); pat = ((INT *)data)[0]; SetEdgeInfo(theElement,pat,ADDPATTERN,&); return(GM_OK); #endif #ifdef UG_DIM_3 INT addpattern; EDGE *theEdge = (EDGE *)obj; addpattern = std::min((INT)ADDPATTERN(theEdge),((INT *)data)[0]); PRINTDEBUG(gm,4,("Gather_AddEdgePattern(): edge=" ID_FMTX "pat=%08x\n", ID_PRTX(theEdge),addpattern)); SETADDPATTERN(theEdge,addpattern); return(GM_OK); #endif } /****************************************************************************/ /* ExchangeAddPatterns - SYNOPSIS: static INT ExchangeAddPatterns (GRID *theGrid); PARAMETERS: . theGrid - pointer to grid structure DESCRIPTION: \return
                            INT */ /****************************************************************************/ static INT ExchangeAddPatterns (GRID *theGrid) { auto& context = theGrid->dddContext(); const auto& dddctrl = ddd_ctrl(context); /* exchange addpatterns of edges */ #ifdef UG_DIM_2 DDD_IFAOneway(context, dddctrl.ElementVHIF,GRID_ATTR(theGrid),IF_FORWARD,sizeof(INT), Gather_AddEdgePattern, Scatter_AddEdgePattern); #endif #ifdef UG_DIM_3 DDD_IFAOneway(context, dddctrl.EdgeVHIF,GRID_ATTR(theGrid),IF_FORWARD,sizeof(INT), Gather_AddEdgePattern, Scatter_AddEdgePattern); #endif return(GM_OK); } #endif /****************************************************************************/ /* SetAddPatterns - SYNOPSIS: static INT SetAddPatterns (GRID *theGrid); PARAMETERS: . theGrid - pointer to grid structure DESCRIPTION: \return
                              INT */ /****************************************************************************/ static INT SetAddPatterns (GRID *theGrid) { INT j; ELEMENT *theElement; EDGE *theEdge; /* set additional pattern on the edges */ for (theElement=PFIRSTELEMENT(theGrid); theElement!=NULL; theElement=SUCCE(theElement)) { if (MARKCLASS(theElement)!=RED_CLASS) continue; REFINE_ELEMENT_LIST(1,theElement,"SetAddPatterns(): addpattern=0"); for (j=0; j INT */ /****************************************************************************/ static INT BuildGreenClosure (const GRID *theGrid) { INT i; ELEMENT *theElement; EDGE *theEdge; #ifdef UG_DIM_3 INT j; #endif /* build a green covering around the red elements */ for (theElement=PFIRSTELEMENT(theGrid); theElement!=NULL; theElement=SUCCE(theElement)) { #ifdef __ANISOTROPIC__ if (MARKCLASS(theElement)==RED_CLASS && !(TAG(theElement)==PRISM && MARK(theElement)==PRI_QUADSECT)) continue; ASSERT(MARKCLASS(theElement)!=RED_CLASS || (MARKCLASS(theElement)==RED_CLASS && TAG(theElement)==PRISM && MARK(theElement)==PRI_QUADSECT)); #else if (MARKCLASS(theElement)==RED_CLASS) continue; #endif SETUPDATE_GREEN(theElement,0); /* if edge node exists element needs to be green */ for (i=0; i= SIDES_OF_ELEM(theNeighbor)) { ASSERT(EGHOST(theElement) && EGHOST(theNeighbor)); continue; } #else ASSERT(j reset USED flag */ /* in parallel case: one communication to determine the minimum */ /* over all copies of an green element would be needed */ if (REFINECLASS(theElement)==GREEN_CLASS && MARKCLASS(theElement)==GREEN_CLASS && UPDATE_GREEN(theElement)==0) { /* do not renew green refinement */ SETUSED(theElement,0); } #ifdef __ANISOTROPIC__ if (MARKCLASS(theElement)==RED_CLASS && UPDATE_GREEN(theElement)==0) { ASSERT(TAG(theElement)==PRISM && MARK(theElement)==PRI_QUADSECT); SETUSED(theElement,0); } #endif #endif } return(GM_OK); } #if defined(ModelP) && defined(Debug) #define CEIL(n) ((n)+((ALIGNMENT-((n)&(ALIGNMENT-1)))&(ALIGNMENT-1))) /****************************************************************************/ /* Gather_ElementInfo - SYNOPSIS: static int Gather_ElementInfo (DDD_OBJ obj, void *Data); PARAMETERS: . obj . Data DESCRIPTION: \return
                                int */ /****************************************************************************/ static int Gather_ElementInfo (DDD::DDDContext&, DDD_OBJ obj, void *Data) { INT epat,eaddpat; ELEMENT *theElement = (ELEMENT *)obj; char *data = (char *)Data; PRINTDEBUG(gm,4,("Gather_ElementInfo(): elem=" EID_FMTX "\n", EID_PRTX(theElement))); memcpy(data,theElement,sizeof(struct generic_element)); data += CEIL(sizeof(struct generic_element)); epat = 0; GetEdgeInfo(theElement,&epat,PATTERN); ((int *)data)[0] = epat; data += sizeof(INT); eaddpat = 0; GetEdgeInfo(theElement,&eaddpat,ADDPATTERN); ((int *)data)[0] = eaddpat; return(GM_OK); } /* this macro compares control word macros of two elements */ #define COMPARE_MACRO(elem0,elem1,macro,print) \ if (macro(elem0) != macro(elem1)) \ { \ print("e=" EID_FMTX " macro=%s differs value0=%d value1=%d \n", \ EID_PRTX(elem0),# macro,macro(elem0),macro(elem1)); \ assert(0); \ } #ifdef DUNE_UGGRID_TET_RULESET #define COMPARE_MACROX(elem0,elem1,macro,print) \ { \ INT _mark0,_mark1,_pat0,_pat1; \ \ _mark0 = macro(elem0); _mark1 = macro(elem1); \ _pat0 = MARK2PAT((elem0),_mark0); _pat1 = MARK2PAT((elem1),_mark1); \ if ((_pat0 & ((1<<10)-1)) != (_pat1 & ((1<<10)-1))) \ COMPARE_MACRO(elem0,elem1,macro,print) \ } #else #define COMPARE_MACROX(elem0,elem1,macro,print) \ COMPARE_MACRO(elem0,elem1,macro,print) #endif /* this macro compares two values */ #define COMPARE_VALUE(elem0,val0,val1,string,print) \ if ((val0) != (val1)) \ { \ (print)("e=" EID_FMTX " %s differs value0=%d value1=%d \n", \ EID_PRTX(elem0),(string),(val0),(val1)); \ assert(0); \ } /****************************************************************************/ /* Scatter_ElementInfo - SYNOPSIS: static int Scatter_ElementInfo (DDD_OBJ obj, void *Data); PARAMETERS: . obj . Data DESCRIPTION: \return
                                  int */ /****************************************************************************/ static int Scatter_ElementInfo (DDD::DDDContext&, DDD_OBJ obj, void *Data) { INT epat,mpat,eaddpat,maddpat; ELEMENT *theElement = (ELEMENT *)obj; struct generic_element ge; ELEMENT *theMaster = (ELEMENT *)≥ char *data = (char *)Data; memcpy(theMaster,data,sizeof(struct generic_element)); data += CEIL(sizeof(struct generic_element)); PRINTDEBUG(gm,4,("Scatter_ElementInfo(): Comparing elem=" EID_FMTX " master=" EID_FMTX "\n",EID_PRTX(theElement), EID_PRTX(theMaster))); /* now compare the control entries of master with it local copy */ COMPARE_MACRO(theElement,theMaster,REFINECLASS,PrintDebug) COMPARE_MACRO(theElement,theMaster,MARKCLASS,PrintDebug) COMPARE_MACROX(theElement,theMaster,REFINE,PrintDebug) COMPARE_MACROX(theElement,theMaster,MARK,PrintDebug) COMPARE_MACRO(theElement,theMaster,COARSEN,PrintDebug) COMPARE_MACRO(theElement,theMaster,USED,PrintDebug) /* #ifndef DUNE_UGGRID_TET_RULESET */ #ifdef UG_DIM_3 COMPARE_MACRO(theElement,theMaster,SIDEPATTERN,PrintDebug) #endif /* #endif */ epat = 0; GetEdgeInfo(theElement,&epat,PATTERN); mpat = ((INT *)data)[0]; data += sizeof(INT); COMPARE_VALUE(theElement,epat,mpat,"EdgePattern",PrintDebug) eaddpat = 0; GetEdgeInfo(theElement,&eaddpat,ADDPATTERN); maddpat = ((INT *)data)[0]; COMPARE_VALUE(theElement,eaddpat,maddpat,"EdgeAddPattern",PrintDebug) return(GM_OK); } static INT CheckElementInfo (GRID *theGrid) { auto& context = theGrid->dddContext(); const auto& dddctrl = ddd_ctrl(context); /* exchange element info */ DDD_IFAOneway(context, dddctrl.ElementVHIF,GRID_ATTR(theGrid),IF_FORWARD, CEIL(sizeof(struct generic_element))+2*sizeof(INT), Gather_ElementInfo, Scatter_ElementInfo); return(GM_OK); } #endif /****************************************************************************/ /* */ /* Function: GridClosure */ /* */ /* Purpose: compute closure for next level. A closure can only be */ /* determined if the rule set for the used elements is complete. */ /* This means that for all side and edge patterns possible for */ /* an element type exists a rule which closes the element. */ /* In this case a FIFO for computing the closure is not needed */ /* any more and the closure can be computed in one step. */ /* */ /* Param: GRID *theGrid: pointer to grid structure */ /* */ /* return: INT >0: elements will be refined */ /* INT 0: no elements will be refined */ /* INT -1: an error occurred */ /* */ /****************************************************************************/ /****************************************************************************/ /** \brief Compute closure for next level \param theGrid - pointer to grid structure This function computes closure for next level. A closure can only be determined if the rule set for the used elements is complete. This means that for all side and edge patterns possible for an element type exists a rule which closes the element. In this case a FIFO for computing the closure is not needed any more and the closure can be computed in one step. \return
                                    .n >0 elements will be refined .n =0 no elements will be refined .n =-1 an error occurred */ /****************************************************************************/ static int GridClosure (GRID *theGrid) { INT cnt; /* initialize used control word entries */ if (PrepareGridClosure(theGrid) != GM_OK) RETURN(GM_ERROR); /* compute pattern on edges and elements */ if (ComputePatterns(theGrid) != GM_OK) RETURN(GM_ERROR); firstElement = PFIRSTELEMENT(theGrid); if (fifoFlag) if (InitClosureFIFO() != GM_OK) return(GM_OK); /* fifo loop */ do { #ifdef UG_DIM_3 #if defined(ModelP) && defined(DUNE_UGGRID_TET_RULESET) /* edge pattern is needed consistently in CorrectTetrahedronSidePattern() */ if (!refine_seq) { if (ExchangeEdgeClosureInfo(theGrid) != GM_OK) return(GM_ERROR); } #endif /* set side patterns on the elements */ if (SetElementSidePatterns(theGrid,firstElement) != GM_OK) RETURN(GM_ERROR); #endif #ifdef ModelP if (ExchangeClosureInfo(theGrid) != GM_OK) RETURN(GM_ERROR); #endif /* set rules on the elements */ if (SetElementRules(theGrid,firstElement,&cnt) != GM_OK) RETURN(GM_ERROR); } /* exit only if fifo not active or fifo queue */ /* empty or all processor have finished closure */ while (fifoFlag && UpdateClosureFIFO(theGrid) && ManageParallelFIFO(theGrid->ppifContext(), firstElement)); /* set patterns on all edges of red elements */ if (SetAddPatterns(theGrid) != GM_OK) RETURN(GM_ERROR); /* build the closure around the red elements */ if (BuildGreenClosure(theGrid) != GM_OK) RETURN(GM_ERROR); #if defined(Debug) && defined(ModelP) if (CheckElementInfo(theGrid)) RETURN(GM_ERROR); #endif return(cnt); } /****************************************************************************/ /* GetNeighborSons - fill SonList for theElement SYNOPSIS: static INT GetNeighborSons (ELEMENT *theElement, ELEMENT *theSon, ELEMENT *SonList[MAX_SONS], int count, int nsons); PARAMETERS: . theElement - father element . theSon - currently visited son . SonList[MAX_SONS] - the list of sons . count - son count . sons - number of sons DESCRIPTION: This function fills SonList for theElement with a breadth first search \return
                                      INT .n new son count */ /****************************************************************************/ static INT GetNeighborSons (ELEMENT *theElement, ELEMENT *theSon, ELEMENT *SonList[MAX_SONS], int count, int nsons) { ELEMENT *NbElement; int i,j, startson, stopson; startson = count; for (i=0; i INT .n 0 if ok .n 1 if an error occurs */ /****************************************************************************/ INT NS_DIM_PREFIX GetAllSons (const ELEMENT *theElement, ELEMENT *SonList[MAX_SONS]) { ELEMENT *son; int SonID,i; ASSERT(theElement != NULL); for (SonID=0; SonID INT */ /****************************************************************************/ INT NS_DIM_PREFIX GetSons (const ELEMENT *theElement, ELEMENT *SonList[MAX_SONS]) { int SonID; ELEMENT *son; if (theElement==NULL) RETURN(GM_ERROR); for (SonID=0; SonID0 error */ /* */ /****************************************************************************/ /****************************************************************************/ /* RestrictElementMark - restrict refinement marks SYNOPSIS: static INT RestrictElementMark(ELEMENT *theElement); PARAMETERS: . theElement - pointer to the element DESCRIPTION: This function restricts refinement marks of an element whose sons are further marked for refinement \return
                                        INT .n =0 - ok .n >0 - error */ /****************************************************************************/ static INT RestrictElementMark(ELEMENT *theElement) { #ifdef UG_DIM_3 #ifdef DUNE_UGGRID_TET_RULESET EDGE *theEdge; int j,Rule,Pattern; #endif #endif if (MARKCLASS(theElement)==RED_CLASS) { /** \todo this mark is from DropMarks()! */ /* theElement is marked from outside */ /** \todo edit this for new element type or */ /* for different restrictions */ switch (TAG(theElement)) { #ifdef UG_DIM_2 case TRIANGLE : SETMARK(theElement,T_RED); break; case QUADRILATERAL : SETMARK(theElement,Q_RED); break; #endif #ifdef UG_DIM_3 case TETRAHEDRON : #ifdef DUNE_UGGRID_TET_RULESET if (MARK(theElement)!=RED) /** \todo Is REFINE always as red rule available? */ SETMARK(theElement,REFINE(theElement)); #else SETMARK(theElement,TET_RED); #endif break; case PYRAMID : SETMARK(theElement,PYR_RED); break; case PRISM : SETMARK(theElement,PRI_RED); break; case HEXAHEDRON : SETMARK(theElement,HEXA_RED); break; #endif default : ASSERT(0); } } else { /** \todo edit this for new element type or for different restrictions */ switch (TAG(theElement)) { #ifdef UG_DIM_2 case TRIANGLE : SETMARK(theElement,T_RED); break; case QUADRILATERAL : SETMARK(theElement,Q_RED); break; #endif #ifdef UG_DIM_3 case TETRAHEDRON : #ifdef DUNE_UGGRID_TET_RULESET /* theElement is not marked from outside, */ /* so find a reg. rule being consistent */ /* with those neighbors of all sons of */ /* theElement which are marked for refine.*/ /* this choice will make sure these marks */ /* will not be distroyed. */ Pattern = RULE2PAT(theElement, REFINE(theElement)); for (j=0; j INT .n 0 if ok .n >0 if an error occurs */ /****************************************************************************/ static INT RestrictMarks (const GRID *theGrid) { ELEMENT *theElement,*SonList[MAX_SONS]; INT flag; for (theElement=FIRSTELEMENT(theGrid); theElement!=NULL; theElement=SUCCE(theElement)) { if (GetSons(theElement,SonList)!=GM_OK) RETURN(GM_ERROR); if (hFlag) { if ( /* if element is not refined anyway, */ /* then there are no restrictions to apply */ REFINE(theElement) == NO_REFINEMENT || /* irregular elements are marked by estimator, */ /* because they are leaf elements */ ECLASS(theElement) == YELLOW_CLASS || ECLASS(theElement) == GREEN_CLASS || /* regular elements with YELLOW_CLASS copies are */ /* marked by estimator, because the marks are dropped */ REFINECLASS(theElement) == YELLOW_CLASS ) { continue; } /* regular elements with GREEN_CLASS refinement */ /* go to no refinement or red refinement */ if (REFINECLASS(theElement)==GREEN_CLASS) { for (UINT i=0; iNO_REFINEMENT) { if (RestrictElementMark(theElement)) RETURN(GM_ERROR); /* this must be done only once for each element */ break; } } continue; } /* regular elements with regular refinement are */ /* the only ones to coarsen */ if (REFINECLASS(theElement) == RED_CLASS) { #ifndef __ANISOTROPIC__ SETMARK(theElement,REFINE(theElement)); SETMARKCLASS(theElement,REFINECLASS(theElement)); #else ASSERT(MARK(theElement)>=1); #endif } } #ifdef ModelP /* if no (or not all) sons are found by GetSons() on */ /* this proc then coarsening is not allowed */ if (REFINECLASS(theElement)==RED_CLASS && SonList[0]==NULL) continue; #endif flag = 0; for (UINT i=0; i < MAX_SONS && SonList[i]!=NULL; i++) { /* if not all sons are marked no unrefinement is possible */ if (!COARSEN(SonList[i]) || REFINECLASS(SonList[i])==RED_CLASS) { flag = 1; break; } } if (flag) continue; /* preserve regular refinement marks */ if (hFlag==0 && SonList[0]==NULL) continue; /* remove refinement */ SETMARK(theElement,NO_REFINEMENT); SETMARKCLASS(theElement,NO_CLASS); SETCOARSEN(theElement,1); } return(GM_OK); } /****************************************************************************/ /* ComputeCopies - determine copy elements from node classes SYNOPSIS: static int ComputeCopies (GRID *theGrid); PARAMETERS: . theGrid - pointer to grid structure DESCRIPTION: This function determines copy elements from node classes \return
                                          int .n GM_OK if ok */ /****************************************************************************/ static int ComputeCopies (GRID *theGrid) { ELEMENT *theElement; int flag; int cnt = 0; PRINTDEBUG(gm,1,("ComputeCopies on level %d\n",GLEVEL(theGrid))); [[maybe_unused]] const int me = theGrid->ppifContext().me(); /* set class of all dofs on next level to 0 */ ClearNextNodeClasses(theGrid); /* seed dofs of regularly and irregularly refined elements to 3 */ flag = 0; for (theElement=PFIRSTELEMENT(theGrid); theElement!=NULL; theElement=SUCCE(theElement)) { if (MARK(theElement)!=NO_REFINEMENT && (MARKCLASS(theElement)==RED_CLASS || MARKCLASS(theElement)==GREEN_CLASS)) { SeedNextNodeClasses(theElement); flag=1; /* there is at least one element to be refined */ } } /* copy all option or neighborhood */ if (rFlag==GM_COPY_ALL) { #ifdef ModelP flag = UG_GlobalMaxINT(theGrid->ppifContext(), flag); #endif if (flag) for (theElement=FIRSTELEMENT(theGrid); theElement!=NULL; theElement=SUCCE(theElement)) { SeedNextNodeClasses(theElement); } } else { PropagateNextNodeClasses(theGrid); } /* an element is copied if it has a dof of class 2 and higher */ for (theElement=PFIRSTELEMENT(theGrid); theElement!=NULL; theElement=SUCCE(theElement)) { INT maxclass = 0; if ((MARK(theElement)==NO_REFINEMENT)&& ((maxclass=MaxNextNodeClass(theElement))>=MINVNCLASS)) { PRINTDEBUG(gm,1,(PFMT "ComputeCopies(): level=%d e=" EID_FMTX "yellow marked\n", me,LEVEL(theElement),EID_PRTX(theElement))); SETMARK(theElement,COPY); SETMARKCLASS(theElement,YELLOW_CLASS); cnt++; } else { PRINTDEBUG(gm,1,(PFMT "ComputeCopies(): level=%d e=" EID_FMTX "not yellow marked" " mark=%d maxclass=%d\n", me,LEVEL(theElement),EID_PRTX(theElement),MARK(theElement),maxclass)); } } return(cnt); } /****************************************************************************/ /* CheckElementContextConsistency - check NTYPE flags of nodes SYNOPSIS: static void CheckElementContextConsistency(ELEMENT *theElement); PARAMETERS: . theElement - element to check DESCRIPTION: This function checks NTYPE flags of nodes in elementcontextt with the sons \return
                                            void */ /****************************************************************************/ #ifdef Debug static void CheckElementContextConsistency(ELEMENT *theElement, ELEMENTCONTEXT theElementContext) { int i; [[maybe_unused]] int errorflag = 0; int errortype[MAX_CORNERS_OF_ELEM+MAX_NEW_CORNERS_DIM]; int correcttype[MAX_CORNERS_OF_ELEM+MAX_NEW_CORNERS_DIM]; for (i=0; i int .n 0 - ok .n 1 - fatal memory error */ /****************************************************************************/ static int UpdateContext (GRID *theGrid, ELEMENT *theElement, NODE **theElementContext) { /* reset context to NULL */ for(INT i=0; i INT */ /****************************************************************************/ static INT UnrefineElement (GRID *theGrid, ELEMENT *theElement) { int s; ELEMENT *theSon,*SonList[MAX_SONS]; /* something to do ? */ if ((REFINE(theElement)==NO_REFINEMENT)||(theGrid==NULL)) return(GM_OK); if (GetAllSons(theElement,SonList)!=GM_OK) RETURN(GM_FATAL); for (s=0; sppifContext().me(); for (s=0; s bool */ /****************************************************************************/ static bool compare_node(const NODE* a, const NODE* b) { return a > b; } /****************************************************************************/ /** \brief Get the sons of an element side \param[in] theElement Input element \param[in] side Input element side number \param[out] Sons_of_Side Number of topological sons of the element side \param[in,out] SonList[MAX_SONS] Output elements \param[out] SonSides Output element side numbers \param[in] NeedSons If this is false, the correct list of sons is expected to be provided in SonList. If not it is recomputed. \param[in] ioflag An obsolete debugging flag \param[in] useRefineClass For a given side of an element, this routine computes all element sides on the next finer grid level which are topological sons of the input element side. */ /****************************************************************************/ INT NS_DIM_PREFIX Get_Sons_of_ElementSide (const ELEMENT *theElement, INT side, INT *Sons_of_Side, ELEMENT *SonList[MAX_SONS], INT *SonSides, INT NeedSons, INT ioflag, INT useRefineClass) { enum MarkClass markclass; /* reset soncount */ *Sons_of_Side = 0; /* get sons of element */ if (NeedSons) if (GetAllSons(theElement,SonList) != GM_OK) RETURN(GM_FATAL); IFDEBUG(gm,2) UserWriteF(" Get_Sons_of_ElementSide():" " id=%d tag=%d, refineclass=%d markclass=%d refine=%d mark=%d coarse=%d" " used=%d nsons=%d side=%d needsons=%d\n", ID(theElement),TAG(theElement),REFINECLASS(theElement),MARKCLASS(theElement), REFINE(theElement),MARK(theElement),COARSEN(theElement), USED(theElement),NSONS(theElement),side,NeedSons); for (INT i = 0; i < MAX_SONS && SonList[i] != NULL; i++) UserWriteF(" son[%d]=" EID_FMTX "\n",i,EID_PRTX(SonList[i])); ENDDEBUG #ifdef UG_DIM_2 markclass = RED_CLASS; #endif #ifdef UG_DIM_3 /* The following line used to read: markclass = (enum MarkClass) MARKCLASS(theElement); This works well within the UG grid refinement context. However, now I want to use this method within the DUNE UGGridLeafIntersectionIterator. The problem is that the user may have randomly marked elements before calling the iterator. In that case the mark classes may not be set the way this method expects it. Hence we allow the option to use REFINECLASS instead. To be absolutely certain we don't break existing code we keep the old behaviour as the default.*/ markclass = (enum MarkClass) ((useRefineClass) ? REFINECLASS(theElement) : MARKCLASS(theElement)); #endif /** \todo quick fix */ #ifdef ModelP if (EHGHOST(theElement)) markclass = GREEN_CLASS; #endif /* select sons to connect */ switch (markclass) { case YELLOW_CLASS : { *Sons_of_Side = 1; SonSides[0] = side; break; } case GREEN_CLASS : case RED_CLASS : { /* determine sonnodes of side */ NODE *SideNodes[MAX_SIDE_NODES]; INT nodes; INT nsons = 0; /* determine nodes of sons on side of element */ GetSonSideNodes(theElement,side,&nodes,SideNodes,ioflag); /* sort side nodes in descending address order */ std::sort(SideNodes, SideNodes + MAX_SIDE_NODES, compare_node); IFDEBUG(gm,3) UserWriteF("After qsort:\n"); for (INT i = 0; i < MAX_SIDE_NODES; i++) UserWriteF(" %8d",i); UserWriteF("\n"); for (INT i = 0; i < MAX_SIDE_NODES; i++) if (SideNodes[i]!=NULL) UserWriteF(" %x",SideNodes[i]); else UserWriteF(" %8d",0); UserWriteF("\n"); ENDDEBUG /* determine sonnode on side */ /* for (i=0; i corner; std::fill(corner.begin(), corner.end(), -1); IFDEBUG(gm,4) UserWriteF("son=%d\n",i); ENDDEBUG /* soncorners on side */ for (INT j = 0; j < CORNERS_OF_ELEM(SonList[i]); j++) { const NODE *nd = CORNER(SonList[i], j); if (std::binary_search(SideNodes, SideNodes + nodes, nd, compare_node)) { corner[n] = j; n++; } } assert(n<5); IFDEBUG(gm,4) UserWriteF("\n nodes on side n=%d:",n); for (INT j = 0; j < MAX_CORNERS_OF_SIDE; j++) UserWriteF(" %d",corner[j]); ENDDEBUG IFDEBUG(gm,0) if (n==3) assert(TAG(SonList[i])!=HEXAHEDRON); if (n==4) assert(TAG(SonList[i])!=TETRAHEDRON); ENDDEBUG /* sonside on side */ #ifdef UG_DIM_2 assert(n<=2); if (n==2) { if (corner[0]+1 == corner[1]) SonSides[nsons] = corner[0]; else { /** \todo find proper assert assert(corner[1] == CORNERS_OF_ELEM(theElement)-1); */ SonSides[nsons] = corner[1]; } SonList[nsons] = SonList[i]; nsons++; } #endif #ifdef UG_DIM_3 if (n==3 || n==4) { /* determine side number */ INT edge0 = EDGE_WITH_CORNERS(SonList[i],corner[0],corner[1]); INT edge1 = EDGE_WITH_CORNERS(SonList[i],corner[1],corner[2]); /* corners are not stored in local side numbering, */ /* therefore corner[x]-corner[y] might be the diagonal */ if (n==4 && edge0==-1) edge0 = EDGE_WITH_CORNERS(SonList[i],corner[0], corner[3]); if (n==4 && edge1==-1) edge1 = EDGE_WITH_CORNERS(SonList[i],corner[1], corner[3]); assert(edge0!=-1 && edge1!=-1); INT sonside = -1; for (INT side0 = 0; side0 < MAX_SIDES_OF_EDGE; side0++) { for (INT side1 = 0; side1 < MAX_SIDES_OF_EDGE; side1++) { IFDEBUG(gm,5) UserWriteF("edge0=%d side0=%d SIDE_WITH_EDGE=%d\n", edge0, side0, SIDE_WITH_EDGE(SonList[i],edge0,side0)); UserWriteF("edge1=%d side1=%d SIDE_WITH_EDGE=%d\n", edge1, side1, SIDE_WITH_EDGE(SonList[i],edge1,side1)); ENDDEBUG if (SIDE_WITH_EDGE(SonList[i],edge0,side0) == SIDE_WITH_EDGE(SonList[i],edge1,side1)) { sonside = SIDE_WITH_EDGE(SonList[i],edge0,side0); break; } } if (sonside != -1) break; } assert(sonside != -1); IFDEBUG(gm,4) UserWriteF(" son[%d]=%x with sonside=%d on eside=%d\n", i,SonList[i],sonside,side); ENDDEBUG IFDEBUG(gm,3) for (INT k = 0; k < SIDES_OF_ELEM(SonList[i]); k++) { const ELEMENT *Nb = NBELEM(SonList[i],k); if (Nb!=NULL) { INT j; for (j=0; j0 && nsons<6); #endif IFDEBUG(gm,3) UserWriteF(" nsons on side=%d\n",nsons); ENDDEBUG *Sons_of_Side = nsons; break; } /* old style This case would work for the sequential case if SonList is ordered according to rule (e.g. introduce GetOrderedSonList()). The upper case, used now in each situation, is a factor of 2 slower for uniform refinement!! (s.l. 981016) #ifndef ModelP case RED_CLASS: #endif */ { INT nsons = 0; for (INT i = 0; i < MAX_SONS && SonList[i] != NULL; i++) { const SONDATA *sondata = SON_OF_RULE(MARK2RULEADR(theElement, MARK(theElement)), i); for (INT j = 0; j < SIDES_OF_ELEM(SonList[i]); j++) if (SON_NB(sondata,j) == FATHER_SIDE_OFFSET+side) { SonSides[nsons] = j; SonList[nsons] = SonList[i]; nsons ++; } } *Sons_of_Side = nsons; break; } default : RETURN(GM_FATAL); } #ifdef ModelP IFDEBUG(gm,4) UserWriteF("Sons_of_Side=%d\n",*Sons_of_Side); for (INT i = 0; i < *Sons_of_Side; i++) UserWriteF("son[%d]=" EID_FMTX " sonside[%d]=%d\n",i, EID_PRTX(SonList[i]),i,SonSides[i]); ENDDEBUG #endif for (INT i = *Sons_of_Side; i < MAX_SONS; i++) SonList[i] = NULL; return(GM_OK); } /****************************************************************************/ /* Sort_Node_Ptr - SYNOPSIS: static INT Sort_Node_Ptr (INT n,NODE **nodes); PARAMETERS: . n . nodes DESCRIPTION: \return
                                              INT */ /****************************************************************************/ static INT Sort_Node_Ptr (INT n,NODE **nodes) { NODE* nd; INT i,j,max; max = 0; switch (n) { #ifdef UG_DIM_2 case 2 : #endif #ifdef UG_DIM_3 case 3 : case 4 : #endif for (i=0; i INT */ /****************************************************************************/ static INT Fill_Comp_Table (COMPARE_RECORD **SortTable, COMPARE_RECORD *Table, INT nelems, ELEMENT **Elements, const INT *Sides) { for (INT i = 0; i < nelems; i++) { SortTable[i] = Table+i; COMPARE_RECORD *Entry = Table+i; Entry->elem = Elements[i]; Entry->side = Sides[i]; Entry->nodes = CORNERS_OF_SIDE(Entry->elem,Entry->side); for (INT j = 0; j < CORNERS_OF_SIDE(Entry->elem, Entry->side); j++) Entry->nodeptr[j] = CORNER_OF_SIDE_PTR(Entry->elem,Entry->side,j); if (Sort_Node_Ptr(Entry->nodes,Entry->nodeptr)!=GM_OK) RETURN(GM_FATAL); } return(GM_OK); } /****************************************************************************/ /* compare_nodes - SYNOPSIS: static bool compare_nodes(const COMPARE_RECORD* a, const COMPARE_RECORD* b) PARAMETERS: . a . b DESCRIPTION: \return
                                                bool */ /****************************************************************************/ static bool compare_nodes(const COMPARE_RECORD* a, const COMPARE_RECORD* b) { const int n = (a->nodes == 4 && b->nodes == 4) ? 4 : 3; for (int i = 0; i < n; ++i) { if (a->nodeptr[i] > b->nodeptr[i]) return true; else if (a->nodeptr[i] < b->nodeptr[i]) return false; } return false; } /****************************************************************************/ /* Connect_Sons_of_ElementSide - SYNOPSIS: INT Connect_Sons_of_ElementSide (GRID *theGrid, ELEMENT *theElement, INT side, INT Sons_of_Side, ELEMENT **Sons_of_Side_List, INT *SonSides, INT ioflag); PARAMETERS: . theGrid . theElement . side . Sons_of_Side . Sons_of_Side_List . SonSides . ioflag DESCRIPTION: \return
                                                  INT */ /****************************************************************************/ INT NS_DIM_PREFIX Connect_Sons_of_ElementSide (GRID *theGrid, ELEMENT *theElement, INT side, INT Sons_of_Side, ELEMENT **Sons_of_Side_List, INT *SonSides, INT ioflag) { COMPARE_RECORD ElemSonTable[MAX_SONS]; COMPARE_RECORD NbSonTable[MAX_SONS]; COMPARE_RECORD *ElemSortTable[MAX_SONS]; COMPARE_RECORD *NbSortTable[MAX_SONS]; ELEMENT *theNeighbor; ELEMENT *Sons_of_NbSide_List[MAX_SONS]; INT nbside,Sons_of_NbSide,NbSonSides[MAX_SONS]; INT k; IFDEBUG(gm,2) UserWriteF("Connect_Sons_of_ElementSide: ID(elem)=%d side=%d " "Sons_of_Side=%d\n",ID(theElement),side,Sons_of_Side); REFINE_ELEMENT_LIST(0,theElement,"theElement:"); ENDDEBUG if (Sons_of_Side <= 0) return(GM_OK); /* connect to boundary */ if (OBJT(theElement)==BEOBJ && SIDE_ON_BND(theElement,side)) { /** \todo connect change test */ for (int i = 0; i < Sons_of_Side; i++) { assert(OBJT(Sons_of_Side_List[i])==BEOBJ); if (CreateSonElementSide(theGrid,theElement,side, Sons_of_Side_List[i],SonSides[i]) != GM_OK) { return(GM_FATAL); } } /* internal boundaries not connected */ /* return(GM_OK); */ } /* connect to neighbor element */ theNeighbor = NBELEM(theElement,side); if (theNeighbor==NULL) return(GM_OK); /* master elements only connect to master elements */ /* ghost elements connect to ghost and master elements */ #ifdef ModelP if (!ioflag && EMASTER(theElement) && EHGHOST(theNeighbor)) return(GM_OK); #endif /* only yellow elements may have no neighbors */ if (MARKCLASS(theNeighbor)==NO_CLASS) { if (hFlag) assert(MARKCLASS(theElement)==YELLOW_CLASS); return(GM_OK); } if (REFINEMENT_CHANGES(theNeighbor)) return(GM_OK); /* determine corresponding side of neighbor */ for (nbside=0; nbside0 && Sons_of_NbSide<6); else if (!(Sons_of_Side == Sons_of_NbSide && Sons_of_NbSide>0 && Sons_of_NbSide<6)) { ELEMENT *elem=NULL; ELEMENT *SonList[MAX_SONS]; REFINE_ELEMENT_LIST(0,theElement,"theElement:"); REFINE_ELEMENT_LIST(0,theNeighbor,"theNeighbor:"); UserWriteF("elem=" EID_FMTX " nb=" EID_FMTX "Sons_of_Side=%d Sons_of_NbSide=%d\n",EID_PRTX(theElement), EID_PRTX(theNeighbor),Sons_of_Side,Sons_of_NbSide); fflush(stdout); GetAllSons(theElement,SonList); for (int i = 0; i < MAX_SONS && SonList[i] != NULL; i++) { REFINE_ELEMENT_LIST(0,SonList[i],"son:"); } GetAllSons(theNeighbor,SonList); for (int i = 0; i < MAX_SONS && SonList[i] != NULL; i++) { REFINE_ELEMENT_LIST(0,SonList[i],"nbson:"); } /* sig bus error to see stack in totalview */ SET_NBELEM(elem,0,NULL); assert(0); } #ifdef ModelP } #endif IFDEBUG(gm,2) UserWriteF("Connect_Sons_of_ElementSide: NBID(elem)=%d side=%d " "Sons_of_Side=%d\n",ID(theNeighbor),nbside,Sons_of_NbSide); REFINE_ELEMENT_LIST(0,theNeighbor,"theNeighbor:"); ENDDEBUG /* fill sort and comparison tables */ Fill_Comp_Table(ElemSortTable,ElemSonTable,Sons_of_Side,Sons_of_Side_List, SonSides); Fill_Comp_Table(NbSortTable,NbSonTable,Sons_of_NbSide,Sons_of_NbSide_List, NbSonSides); IFDEBUG(gm,5) if (!ioflag) { UserWriteF("BEFORE qsort\n"); /* test whether all entries are corresponding */ for (int i = 0; i < Sons_of_Side; i++) { COMPARE_RECORD *Entry, *NbEntry; Entry = ElemSortTable[i]; NbEntry = NbSortTable[i]; if (Entry->nodes != NbEntry->nodes) UserWriteF("Connect_Sons_of_ElementSide(): LIST Sorttables[%d]" " eNodes=%d nbNodes=%d\n", i,Entry->nodes,NbEntry->nodes); for (int j = 0; j < Entry->nodes; j++) UserWriteF("Connect_Sons_of_ElementSide(): LIST Sorttables[%d][%d]" " eNodePtr=%d/%8x/%d nbNodePtr=%d/%8x/%d\n", i,j, ID(Entry->nodeptr[j]),Entry->nodeptr[j],NTYPE(Entry->nodeptr[j]), ID(NbEntry->nodeptr[j]),NbEntry->nodeptr[j],NTYPE(NbEntry->nodeptr[j])); UserWriteF("\n"); } UserWriteF("\n\n"); } ENDDEBUG /* qsort the tables using nodeptrs */ std::sort(ElemSortTable, ElemSortTable + Sons_of_Side, compare_nodes); std::sort(NbSortTable, NbSortTable + Sons_of_NbSide, compare_nodes); #ifdef ModelP if (!ioflag && Sons_of_NbSide!=Sons_of_Side) ASSERT(0); #endif #ifdef Debug if (!ioflag) /* check whether both sort table match exactly */ for (int i = 0; i < Sons_of_Side; i++) { COMPARE_RECORD *Entry, *NbEntry; Entry = ElemSortTable[i]; NbEntry = NbSortTable[i]; if (Entry->nodes != NbEntry->nodes) { printf("Connect_Sons_of_ElementSide(): ERROR Sorttables[%d]"\ " eNodes=%d nbNodes=%d\n",i,Entry->nodes,NbEntry->nodes); assert(0); } for (int j = 0; j < Entry->nodes; j++) if (Entry->nodeptr[j] != NbEntry->nodeptr[j]) { printf("Connect_Sons_of_ElementSide(): " "ERROR Sorttables[%d][%d]"\ " eNodePtr=%p nbNodePtr=%p\n", i,j,Entry->nodeptr[j],NbEntry->nodeptr[j]); /* assert(0);*/ } } #endif IFDEBUG(gm,4) if (!ioflag) { UserWriteF("After qsort\n"); /* test whether all entries are corresponding */ UserWriteF("SORTTABLELIST:\n"); for (int i = 0; i < Sons_of_Side; i++) { COMPARE_RECORD *Entry, *NbEntry; Entry = ElemSortTable[i]; NbEntry = NbSortTable[i]; UserWriteF("EAdr=%x side=%d realNbAdr=%x NbAdr=%x nbside=%x " "realNbAdr=%x\n", Entry->elem, Entry->side, NBELEM(Entry->elem,Entry->side), NbEntry->elem, NbEntry->side,NBELEM(NbEntry->elem,NbEntry->side)); } for (int i = 0; i < Sons_of_Side; i++) { COMPARE_RECORD *Entry, *NbEntry; Entry = ElemSortTable[i]; NbEntry = NbSortTable[i]; if (NBELEM(Entry->elem,Entry->side)!=NbEntry->elem) { UserWriteF("NOTEQUAL for i=%d elem=%x: elemrealnb=%x " "elemsortnb=%x\n", i,Entry->elem,NBELEM(Entry->elem,Entry->side),NbEntry->elem); REFINE_ELEMENT_LIST(0,theElement,"theElement:"); REFINE_ELEMENT_LIST(0,theNeighbor,"theNeighbor:"); } if (NBELEM(NbEntry->elem,NbEntry->side)!=Entry->elem) { UserWriteF("NOTEQUAL for i=%d nb=%x: nbrealnb=%x nbsortnb=%x\n", i,NbEntry->elem,NBELEM(NbEntry->elem,NbEntry->side), Entry->elem); REFINE_ELEMENT_LIST(0,theElement,"theE:"); REFINE_ELEMENT_LIST(0,theNeighbor,"theN:"); } } UserWriteF("\n\n"); } ENDDEBUG /* set neighborship relations */ if (ioflag) { for (int i = 0; i < Sons_of_Side; i++) { const COMPARE_RECORD *Entry = ElemSortTable[i]; for (k=0; knodes != NbEntry->nodes) continue; int idx; for (idx = 0; idx < Entry->nodes; idx++) if (Entry->nodeptr[idx] != NbEntry->nodeptr[idx]) break; if (idx == Entry->nodes) { SET_NBELEM(ElemSortTable[i]->elem,ElemSortTable[i]->side, NbSortTable[k]->elem); SET_NBELEM(NbSortTable[k]->elem,NbSortTable[k]->side, ElemSortTable[i]->elem); } } } } else /* all entries need to match exactly */ for (int i = 0; i < Sons_of_Side; i++) { SET_NBELEM(ElemSortTable[i]->elem,ElemSortTable[i]->side, NbSortTable[i]->elem); SET_NBELEM(NbSortTable[i]->elem,NbSortTable[i]->side, ElemSortTable[i]->elem); #ifdef UG_DIM_3 if (VEC_DEF_IN_OBJ_OF_GRID(theGrid,SIDEVEC)) if (DisposeDoubledSideVector(theGrid,ElemSortTable[i]->elem, ElemSortTable[i]->side, NbSortTable[i]->elem, NbSortTable[i]->side)) RETURN(GM_FATAL); #endif } return(GM_OK); } /****************************************************************************/ /** \brief Copy an element \param theGrid - grid level of sons of theElement \param theElement - element to refine \param theContext - nodes needed for new elements This function copies an element, (i) corner nodes are already allocated, (iv) create son and set references to sons \return
                                                  • 0 - ok
                                                  • 1 - fatal memory error
                                                  */ /****************************************************************************/ static INT RefineElementYellow (GRID *theGrid, ELEMENT *theElement, NODE **theContext) { INT i; bool boundaryelement = false; const int me = theGrid->ppifContext().me(); /* check for boundary */ if (OBJT(theElement) == BEOBJ) for (i=0; i INT .n 0 - ok .n 1 - fatal memory error */ /****************************************************************************/ static int RefineElementGreen (GRID *theGrid, ELEMENT *theElement, NODE **theContext) { struct greensondata { /** \brief Element type */ short tag; /** \brief Boundary element: yes (=1) or no (=0) */ short bdy; std::array corners; int nb[MAX_SIDES_OF_ELEM]; ELEMENT *theSon; }; typedef struct greensondata GREENSONDATA; std::array sons; int j, k, l; int node0; bool bdy; IFDEBUG(gm,1) UserWriteF("RefineElementGreen(): ELEMENT ID=%d\n",ID(theElement)); ENDDEBUG /* init son data array */ for (int i = 0; i < MAX_GREEN_SONS; i++) { sons[i].tag = -1; sons[i].bdy = -1; for (j=0; j sides; std::array theSideNodes; for (int i = 0; i < SIDES_OF_ELEM(theElement); i++) { NODE *theNode = theContext[CORNERS_OF_ELEM(theElement)+ EDGES_OF_ELEM(theElement)+i]; const int nedges = EDGES_OF_SIDE(theElement,i); bdy = (OBJT(theElement) == BEOBJ && SIDE_ON_BND(theElement,i)); int nelem = 5*i; /* A face in 3d gets subdivided into at most 5 (yes, 5) parts */ for (j=nelem; j<(nelem+5); j++) sons[j].bdy = bdy; k = 0; for (j=0; jmaxedge) maxedge = 2*k+1; */ /* neighboring elements need to refine in the same way */ /* in parallel case all copies of the elements also */ if (theSideNodes[2*k+1]!=NULL && _ID_(theSideNodes[2*k+1])>maxid) maxid = _ID_(theSideNodes[2*k+1]); } #if !defined ModelP // For an unknown reason the maxid variable is unsigned when ModelP is set, and signed otherwise. assert(maxid != -1); #endif assert(node0 != -1); /* if (node0 == maxedge && ((SIDEPATTERN(theElement)&(1< elementsSide0; l = 0; for (j=side0*5; j<(side0*5+5); j++) { for (k=0; k elementsSide1; l = 0; for (j=side1*5; j<(side1*5+5); j++) { for (int m = 0; m < MAX_SIDES_OF_ELEM; m++) if ((sons[j].nb[m]-MAX_GREEN_SONS)==side0) elementsSide1[l++] = j; } ASSERT(l==2); /* determine neighboring elements */ for (j=0; j= 0) { IFDEBUG(gm,2) if (i%5 == 0) UserWriteF(" SIDE %d:\n",i/5); ENDDEBUG NODE *ElementNodes[MAX_CORNERS_OF_ELEM]; l = 0; for (j=0; j= 0) /* valid son entry */ { l = 0; IFDEBUG(gm,0) for (j=0; j0 && Sons_of_Side<6); if (Connect_Sons_of_ElementSide(theGrid,theElement,i,Sons_of_Side, Sons_of_Side_List,SonSides,0)!=GM_OK) RETURN(GM_FATAL); #ifdef ModelP if (Identify_Objects_of_ElementSide(theGrid,theElement,i)) RETURN(GM_FATAL); #endif } return(GM_OK); } /****************************************************************************/ /* RefineElementRed - refine an element in the given context SYNOPSIS: static int RefineElementRed (GRID *theGrid, ELEMENT *theElement, NODE **theElementContext); PARAMETERS: \param theGrid - grid level of sons of theElement \param theElement - element to refine \param theContext - current context of element DESCRIPTION: This function refines an element in the given context, (i) corner and midnodes are already allocated, (ii) edges between corner and midnodes are ok, (iii) create interior nodes and edges, (iv) create sons and set references to sons. \return
                                                    INT .n GM_OK - ok .n GM_FATAL - fatal memory error */ /****************************************************************************/ static int RefineElementRed (GRID *theGrid, ELEMENT *theElement, NODE **theElementContext) { const int me = theGrid->ppifContext().me(); /* is something to do ? */ if (!MARKED(theElement)) return(GM_OK); std::array SonList = {}; REFRULE const* rule = MARK2RULEADR(theElement,MARK(theElement)); /* create elements */ for (INT s=0; s= FATHER_SIDE_OFFSET) { /* at the boundary */ if (SIDE_ON_BND(theElement,side-FATHER_SIDE_OFFSET)) { boundaryelement = true; break; } } } } NODE* ElementNodes[MAX_CORNERS_OF_ELEM]; for (INT i=0; i INT .n GM_OK - ok .n GM_FATAL - fatal memory error */ /****************************************************************************/ static INT RefineElement (GRID *UpGrid, ELEMENT *theElement,NODE** theNodeContext) { switch (MARKCLASS(theElement)) { case (YELLOW_CLASS) : if (RefineElementYellow(UpGrid,theElement,theNodeContext)!=GM_OK) RETURN(GM_FATAL); break; case (GREEN_CLASS) : #ifdef __ANISOTROPIC__ case (RED_CLASS) : #endif if (MARKED_NEW_GREEN(theElement)) { /* elements with incomplete rules set */ if (RefineElementGreen(UpGrid,theElement,theNodeContext) != GM_OK) RETURN(GM_FATAL); } else { /* elements with complete rules set */ if (RefineElementRed(UpGrid,theElement,theNodeContext)!=GM_OK) RETURN(GM_FATAL); } break; #ifndef __ANISOTROPIC__ case (RED_CLASS) : if (RefineElementRed(UpGrid,theElement,theNodeContext)!=GM_OK) RETURN(GM_FATAL); break; #endif default : RETURN(GM_FATAL); } return(GM_OK); } /****************************************************************************/ /* AdaptGrid - adapt one level of the multigrid SYNOPSIS: static int AdaptGrid (GRID *theGrid, INT *nadapted) PARAMETERS: \param theGrid - grid level to refine \param nadapted - number elements have been changed DESCRIPTION: This function refines one level of the grid \return
                                                      INT .n GM_OK - ok .n GM_FATAL - fatal memory error */ /****************************************************************************/ #ifdef ModelP static int AdaptLocalGrid (GRID *theGrid, INT *nadapted) #else static int AdaptGrid (GRID *theGrid, INT *nadapted) #endif { INT modified = 0; ELEMENT *NextElement; #ifdef ModelP const int me = theGrid->ppifContext().me(); auto& dddContext = theGrid->dddContext(); #endif GRID *UpGrid = UPGRID(theGrid); if (UpGrid == nullptr) RETURN(GM_FATAL); REFINE_GRID_LIST(1,MYMG(theGrid),GLEVEL(theGrid),("AdaptGrid(%d):\n",GLEVEL(theGrid)),""); #ifdef IDENT_ONLY_NEW /* reset ident flags for old objects */ for (NODE *theNode = PFIRSTNODE(UpGrid); theNode != nullptr; theNode = SUCCN(theNode)) SETNEW_NIDENT(theNode, 0); for (ELEMENT* theElement = PFIRSTELEMENT(UpGrid); theElement != nullptr; theElement = SUCCE(theElement)) { for (INT i = 0; i < EDGES_OF_ELEM(theElement); i++) { EDGE *theEdge = GetEdge(CORNER_OF_EDGE_PTR(theElement, i, 0), CORNER_OF_EDGE_PTR(theElement, i, 1)); SETNEW_EDIDENT(theEdge, 0); } } #endif /* refine elements */ /* ModelP: first loop over master elems, then loop over ghost elems */ /* this assures that no unnecessary disposures of objects are done */ /* which may cause trouble during identification (s.l. 9803020 */ for (ELEMENT *theElement = FIRSTELEMENT(theGrid); theElement != nullptr; theElement=NextElement) { NextElement = SUCCE(theElement); #ifdef ModelP /* loop over master elems first, then over ghost elems */ if (NextElement == NULL) NextElement=PFIRSTELEMENT(theGrid); if (NextElement == FIRSTELEMENT(theGrid)) NextElement = NULL; #endif #ifdef ModelP /* reset update overlap flag */ SETTHEFLAG(theElement,0); #endif /* do not change PrioVGhost elements */ if (EVGHOST(theElement)) continue; if (REFINEMENT_CHANGES(theElement)) { #ifdef ModelP { /* check for valid load balancing */ const auto& proclist = DDD_InfoProcListRange(dddContext, PARHDRE(theElement), false); for (auto&& [proc, prio] : proclist) { if (prio != PrioMaster && prio != PrioHGhost) { UserWriteF(PFMT "ERROR invalid load balancing: element=" EID_FMTX " has copies of type=%d on proc=%d\n", me, EID_PRTX(theElement), prio, proc); REFINE_ELEMENT_LIST(0,theElement,"ERROR element: "); assert(0); } } } #endif if (hFlag==0 && MARKCLASS(theElement)!=RED_CLASS) { /* remove copy marks */ SETMARK(theElement,NO_REFINEMENT); SETMARKCLASS(theElement,NO_CLASS); /* continue; */ } REFINE_ELEMENT_LIST(1,theElement,"REFINING element: "); if (UnrefineElement(UpGrid,theElement)) RETURN(GM_FATAL); #ifdef ModelP /* dispose hghost elements with EFATHER==NULL */ /** \todo how handle this situation? */ /* situation possibly some elements to be coarsened are */ /* disconnected from their fathers (970109 s.l.) */ if (0) if (EHGHOST(theElement) && COARSEN(theElement)) { if (LEVEL(theElement)>0 && EFATHER(theElement)==NULL) { DisposeElement(theGrid,theElement); continue; } } #endif if (EMASTER(theElement)) { ELEMENTCONTEXT theContext; if (UpdateContext(UpGrid,theElement,theContext)!=0) RETURN(GM_FATAL); REFINE_CONTEXT_LIST(2,theContext); #ifdef Debug CheckElementContextConsistency(theElement,theContext); #endif /* is something to do ? */ if (MARKED(theElement)) if (RefineElement(UpGrid,theElement,theContext)) RETURN(GM_FATAL); } /* refine and refineclass flag */ SETREFINE(theElement,MARK(theElement)); SETREFINECLASS(theElement,MARKCLASS(theElement)); SETUSED(theElement,0); #ifdef ModelP /* set update overlap flag */ SETTHEFLAG(theElement,1); #endif /* this grid is modified */ modified++; } else { #ifdef ModelP /* dispose hghost elements with EFATHER==NULL */ /** \todo how handle this situation? */ /* situation possibly some elements to be coarsened are */ /* disconnected from their fathers (970109 s.l.) */ if (0) if (EHGHOST(theElement) && COARSEN(theElement)) { if (LEVEL(theElement)>0 && EFATHER(theElement)==NULL) { DisposeElement(theGrid,theElement); continue; } } #endif #ifdef __ANISOTROPIC__ if (USED(theElement)==0 && MARKCLASS(theElement)==GREEN_CLASS) #else if (USED(theElement)==0) #endif { /* count not updated green refinements */ No_Green_Update++; } } /* count green marks */ if (MARKCLASS(theElement) == GREEN_CLASS) Green_Marks++; /* reset coarse flag */ SETCOARSEN(theElement,0); } if (UG_GlobalMaxINT(theGrid->ppifContext(), modified)) { /* reset (multi)grid status */ SETGLOBALGSTATUS(UpGrid); RESETMGSTATUS(MYMG(UpGrid)); } REFINE_GRID_LIST(1,MYMG(theGrid),GLEVEL(theGrid), ("END AdaptGrid(%d):\n",GLEVEL(theGrid)),""); *nadapted = modified; return(GM_OK); } #ifdef ModelP static int AdaptGrid (GRID *theGrid, INT toplevel, INT level, INT newlevel, INT *nadapted) { GRID *FinerGrid = UPGRID(theGrid); START_TIMER(gridadapti_timer) #ifdef UPDATE_FULLOVERLAP DDD_XferBegin(theGrid->dddContext()); { for (ELEMENT *theElement = PFIRSTELEMENT(FinerGrid); theElement != nullptr; theElement=SUCCE(theElement)) { if (EPRIO(theElement) == PrioHGhost) DisposeElement(FinerGrid,theElement,true); } } DDD_XferEnd(theGrid->dddContext()); #endif DDD_IdentifyBegin(theGrid->dddContext()); SET_IDENT_MODE(IDENT_ON); DDD_XferBegin(theGrid->dddContext()); DDD_CONSCHECK(theGrid->dddContext()); /* now really manipulate the next finer level */ START_TIMER(gridadaptl_timer) #ifdef DDDOBJMGR DDD_ObjMgrBegin(); #endif if (leveldddContext()); SUM_TIMER(gridadaptl_timer) DDD_CONSCHECK(theGrid->dddContext()); { int check=1; int debugstart=3; #ifdef Debug int gmlevel=Debuggm; #else int gmlevel=0; #endif if (IDENT_IN_STEPS) { DDD_IdentifyEnd(theGrid->dddContext()); } /* if no grid adaption has occurred adapt next level */ *nadapted = UG_GlobalSumINT(theGrid->ppifContext(), *nadapted); if (*nadapted == 0) { if (!IDENT_IN_STEPS) { SET_IDENT_MODE(IDENT_OFF); DDD_IdentifyEnd(theGrid->dddContext()); } SUM_TIMER(gridadapti_timer) return(GM_OK); } /* DDD_JoinBegin(); */ if (IDENT_IN_STEPS) DDD_IdentifyBegin(theGrid->dddContext()); DDD_CONSCHECK(theGrid->dddContext()); START_TIMER(ident_timer) if (Identify_SonObjects(theGrid)) RETURN(GM_FATAL); SET_IDENT_MODE(IDENT_OFF); DDD_IdentifyEnd(theGrid->dddContext()); SUM_TIMER(ident_timer) /* DDD_JoinEnd(); */ DDD_CONSCHECK(theGrid->dddContext()); if (leveldddContext()); if (0) /* delete sine this is already done in */ /* ConstructConsistentGrid() (s.l. 980522) */ if (SetGridBorderPriorities(theGrid)) RETURN(GM_FATAL); if (UpdateGridOverlap(theGrid)) RETURN(GM_FATAL); DDD_XferEnd(theGrid->dddContext()); DDD_CONSCHECK(theGrid->dddContext()); DDD_XferBegin(theGrid->dddContext()); if (ConnectGridOverlap(theGrid)) RETURN(GM_FATAL); DDD_XferEnd(theGrid->dddContext()); DDD_CONSCHECK(theGrid->dddContext()); /* this is needed due to special cases while coarsening */ /* sample scene: a ghost element is needed as overlap */ /* for two master elements, one of the master elements */ /* is coarsened, then the prio of nodes of the ghost */ /* element must eventually be downgraded from master */ /* to ghost prio (s.l. 971020) */ /* this is done as postprocessing step, since this needs */ /* 2 XferBegin/Ends here per modified gridlevel (s.l. 980522) */ /* #ifndef NEW_GRIDCONS_STYLE ConstructConsistentGrid(FinerGrid); #endif */ SUM_TIMER(overlap_timer) } DDD_CONSCHECK(theGrid->dddContext()); CheckConsistency(MYMG(theGrid),(INT)level,(INT)debugstart,(INT)gmlevel,&check); } if (0) CheckGrid(FinerGrid,1,0,1,1); SUM_TIMER(gridadapti_timer) return(GM_OK); } #endif #ifdef ModelP /* parameters for CheckGrid() */ #define GHOSTS 1 #define GEOM 1 #define ALG 0 #define LIST 1 #define IF 1 /****************************************************************************/ /* CheckConsistency - SYNOPSIS: void CheckConsistency (MULTIGRID *theMG, INT level ,INT debugstart, INT gmlevel, INT *check); PARAMETERS: . theMG . level . debugstart . gmlevel . check */ /****************************************************************************/ static void CheckConsistency (MULTIGRID *theMG, INT level ,INT debugstart, INT gmlevel, int *check) { GRID *theGrid = GRID_ON_LEVEL(theMG,level); IFDEBUG(gm,debugstart) printf(PFMT "AdaptMultiGrid(): %d. ConsCheck() on level=%d\n",theMG->ppifContext().me(),(*check)++,level); #ifdef Debug Debuggm = GHOSTS; #endif CheckGrid(theGrid,GEOM,ALG,LIST,IF); #ifdef Debug Debuggm=gmlevel; #endif if (DDD_ConsCheck(theMG->dddContext()) > 0) buggy(theMG); ENDDEBUG } #endif #ifdef STAT_OUT void NS_DIM_PREFIX Manage_Adapt_Timer (int alloc) { if (alloc) { NEW_TIMER(adapt_timer) NEW_TIMER(closure_timer) NEW_TIMER(gridadapt_timer) NEW_TIMER(gridadapti_timer) NEW_TIMER(gridadaptl_timer) NEW_TIMER(ident_timer) NEW_TIMER(overlap_timer) NEW_TIMER(gridcons_timer) NEW_TIMER(algebra_timer) } else { DEL_TIMER(adapt_timer) DEL_TIMER(closure_timer) DEL_TIMER(gridadapt_timer) DEL_TIMER(gridadapti_timer) DEL_TIMER(gridadaptl_timer) DEL_TIMER(ident_timer) DEL_TIMER(overlap_timer) DEL_TIMER(gridcons_timer) DEL_TIMER(algebra_timer) } } void NS_DIM_PREFIX Print_Adapt_Timer (const MULTIGRID* theMG, int total_adapted) { UserWriteF("ADAPT: total_adapted=%d t_adapt=%.2f: t_closure=%.2f t_gridadapt=%.2f t_gridadapti=%.2f " "t_gridadaptl=%.2f t_overlap=%.2f t_ident=%.2f t_gridcons=%.2f t_algebra=%.2f\n", total_adapted,EVAL_TIMER(adapt_timer),EVAL_TIMER(closure_timer),EVAL_TIMER(gridadapt_timer), EVAL_TIMER(gridadapti_timer),EVAL_TIMER(gridadaptl_timer),EVAL_TIMER(overlap_timer), EVAL_TIMER(ident_timer),EVAL_TIMER(gridcons_timer),EVAL_TIMER(algebra_timer)); UserWriteF("ADAPTMAX: total_adapted=%d t_adapt=%.2f: t_closure=%.2f t_gridadapt=%.2f " "t_gridadapti=%.2f " "t_gridadaptl=%.2f t_overlap=%.2f t_ident=%.2f t_gridcons=%.2f t_algebra=%.2f\n", total_adapted,UG_GlobalMaxDOUBLE(theMG->ppifContext(), EVAL_TIMER(adapt_timer)), UG_GlobalMaxDOUBLE(theMG->ppifContext(), EVAL_TIMER(closure_timer)), UG_GlobalMaxDOUBLE(theMG->ppifContext(), EVAL_TIMER(gridadapt_timer)),UG_GlobalMaxDOUBLE(theMG->ppifContext(), EVAL_TIMER(gridadapti_timer)), UG_GlobalMaxDOUBLE(theMG->ppifContext(), EVAL_TIMER(gridadaptl_timer)), UG_GlobalMaxDOUBLE(theMG->ppifContext(), EVAL_TIMER(overlap_timer)), UG_GlobalMaxDOUBLE(theMG->ppifContext(), EVAL_TIMER(ident_timer)),UG_GlobalMaxDOUBLE(theMG->ppifContext(), EVAL_TIMER(gridcons_timer)), UG_GlobalMaxDOUBLE(theMG->ppifContext(), EVAL_TIMER(algebra_timer))); } #endif static INT PreProcessAdaptMultiGrid(MULTIGRID *theMG) { /* The matrices for the calculation are removed, to remember the recalculating the MGSTATUS is set to 1 */ MGSTATUS(theMG) = 1 ; return(0); } static INT PostProcessAdaptMultiGrid(MULTIGRID *theMG) { START_TIMER(algebra_timer) if (CreateAlgebra(theMG)) REP_ERR_RETURN(1); SUM_TIMER(algebra_timer) REFINE_MULTIGRID_LIST(1,theMG,"END AdaptMultiGrid():\n","",""); /* if (hFlag) UserWriteF(" Number of green refinements not updated: " "%d (%d green marks)\n",No_Green_Update,Green_Marks); */ /* increment step count */ SETREFINESTEP(REFINEINFO(theMG),REFINESTEP(REFINEINFO(theMG))+1); SUM_TIMER(adapt_timer) /* CheckMultiGrid(theMG); */ #ifdef STAT_OUT Print_Adapt_Timer(theMG, total_adapted); Manage_Adapt_Timer(0); #endif return(0); } /****************************************************************************/ /** \brief Adapt whole multigrid structure \param theMG - multigrid to refine \param flag - flag for switching between different yellow closures This function refines whole multigrid structure \return
                                                      • 0 - ok
                                                      • 1 - out of memory, but data structure as before
                                                      • 2 - fatal memory error, data structure corrupted
                                                      */ /****************************************************************************/ INT NS_DIM_PREFIX AdaptMultiGrid (MULTIGRID *theMG, INT flag, INT seq, INT mgtest) { INT nrefined,nadapted; /* check necessary condition */ if (!MG_COARSE_FIXED(theMG)) return (GM_COARSE_NOT_FIXED); if (PreProcessAdaptMultiGrid(theMG)) REP_ERR_RETURN(1); #ifdef ModelP { /* check and restrict partitioning of elements */ if (CheckPartitioning(theMG)) { /* Each call to RestrictPartitioning fixes the partitionings of children with * respect to their fathers. To fix also fix the partitionings of the grandchildren, * the method has to be called again. To be on the save side we call it once for * every level. * If I omit the loop (the way it was until 11.4.2014 I get assertion failures here * when mixing load balancing and adaptive refinement. I am not really sure whether * the loop is the correct fix, or whether it just papers over the problem. * Anyway, no crashes for now. */ for (int level = 0; level < TOPLEVEL(theMG); level++) if (RestrictPartitioning(theMG)) RETURN(GM_FATAL); if (CheckPartitioning(theMG)) assert(0); } } #endif #ifdef STAT_OUT Manage_Adapt_Timer(1); #endif START_TIMER(adapt_timer) /* set up information in refine_info */ #ifndef ModelP if (TOPLEVEL(theMG) == 0) #else if (UG_GlobalMaxINT(theMG->ppifContext(), TOPLEVEL(theMG)) == 0) #endif { SETREFINESTEP(REFINEINFO(theMG),0); } /* set info for refinement prediction */ SetRefineInfo(theMG); /* evaluate prediction */ if (mgtest) { UserWriteF("refinetest: predicted_new0=%9.0f predicted_new1=%9.0f\n", PREDNEW0(REFINEINFO(theMG)), PREDNEW1(REFINEINFO(theMG))); } /* set flags for different modes */ rFlag=flag & 0x03; /* copy local or all */ hFlag=!((flag>>2)&0x1); /* use hanging nodes */ fifoFlag=(flag>>3)&0x1; /* use fifo */ refine_seq = seq; No_Green_Update=0; Green_Marks=0; /* drop marks to regular elements */ if (hFlag) if (DropMarks(theMG)) RETURN(GM_ERROR); /* prepare algebra (set internal flags correctly) */ START_TIMER(algebra_timer) PrepareAlgebraModification(theMG); SUM_TIMER(algebra_timer) const INT toplevel = TOPLEVEL(theMG); REFINE_MULTIGRID_LIST(1,theMG,"AdaptMultiGrid()","","") /* compute modification of coarser levels from above */ START_TIMER(closure_timer) for (INT level = toplevel; level > 0; level--) { GRID *theGrid = GRID_ON_LEVEL(theMG,level); if (hFlag) { PRINTDEBUG(gm,1,("Begin GridClosure(%d,down):\n",level)) if ((nrefined = GridClosure(GRID_ON_LEVEL(theMG,level)))<0) { PrintErrorMessage('E',"AdaptMultiGrid","error in GridClosure"); RETURN(GM_ERROR); } REFINE_GRID_LIST(1,theMG,level,("End GridClosure(%d,down):\n",level),""); } #ifdef ModelP else { ExchangeElementRefine(theGrid); } #endif /* restrict marks on next lower grid level */ if (RestrictMarks(GRID_ON_LEVEL(theMG,level-1))!=GM_OK) RETURN(GM_ERROR); REFINE_GRID_LIST(1,theMG,level-1,("End RestrictMarks(%d,down):\n",level),""); } SUM_TIMER(closure_timer) #ifdef ModelP IdentifyInit(theMG); #endif INT newlevel = 0; for (INT level = 0; level <= toplevel; level++) { GRID *theGrid = GRID_ON_LEVEL(theMG,level); GRID *FinerGrid = nullptr; if (level < toplevel) FinerGrid = GRID_ON_LEVEL(theMG,level+1); START_TIMER(closure_timer) /* reset MODIFIED flags for grid and nodes */ SETMODIFIED(theGrid,0); for (NODE *theNode = FIRSTNODE(theGrid); theNode != nullptr; theNode = SUCCN(theNode)) { SETMODIFIED(theNode,0); } if (hFlag) { /* leave only regular marks */ for (ELEMENT *theElement = PFIRSTELEMENT(theGrid); theElement != nullptr; theElement = SUCCE(theElement)) { if ((ECLASS(theElement)==RED_CLASS) && MARKCLASS(theElement)==RED_CLASS) continue; SETMARK(theElement,NO_REFINEMENT); } PRINTDEBUG(gm,1,("Begin GridClosure(%d,up):\n",level)); /* determine regular and irregular elements on next level */ if ((nrefined = GridClosure(theGrid))<0) { PrintErrorMessage('E',"AdaptMultiGrid","error in 2. GridClosure"); RETURN(GM_ERROR); } REFINE_GRID_LIST(1,theMG,level,("End GridClosure(%d,up):\n",level),""); } #ifdef ModelP else { ExchangeElementRefine(theGrid); } #endif nrefined += ComputeCopies(theGrid); /** \todo bug fix to force new level creation */ if (!hFlag) { /* set this variable>0 */ nrefined = 1; } /* create a new grid level, if at least one element is refined on finest level */ if (nrefined>0 && level==toplevel) newlevel = 1; #ifdef ModelP newlevel = UG_GlobalMaxINT(theMG->ppifContext(), newlevel); #endif if (newlevel) { if (CreateNewLevel(theMG)==NULL) RETURN(GM_FATAL); FinerGrid = GRID_ON_LEVEL(theMG,toplevel+1); } PRINTDEBUG(gm,1,(PFMT "AdaptMultiGrid(): toplevel=%d nrefined=%d newlevel=%d\n", me,toplevel,nrefined,newlevel)); SUM_TIMER(closure_timer) /* now really manipulate the next finer level */ START_TIMER(gridadapt_timer) nadapted = 0; if (level=GREEN_CLASS || (rFlag==GM_COPY_ALL)) { SeedNodeClasses(theElement); } PropagateNodeClasses(FinerGrid); SUM_TIMER(algebra_timer) } } #ifdef ModelP IdentifyExit(); /* now repair inconsistencies */ /* former done on each grid level (s.l. 980522) */ START_TIMER(gridcons_timer); ConstructConsistentMultiGrid(theMG); SUM_TIMER(gridcons_timer) #endif DisposeTopLevel(theMG); if (TOPLEVEL(theMG) > 0) DisposeTopLevel(theMG); if (PostProcessAdaptMultiGrid(theMG)) REP_ERR_RETURN(1); return(GM_OK); } dune-uggrid-2.11.0+dfsg/dune/uggrid/gm/refine.h000066400000000000000000000370641513616443000212010ustar00rootroot00000000000000// -*- tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- // vi: set et ts=4 sw=2 sts=2: // SPDX-FileCopyrightInfo: Copyright © DUNE Project contributors, see file LICENSE.md in module root // SPDX-License-Identifier: LGPL-2.1-or-later /*! \file refine.h * \ingroup gm */ /****************************************************************************/ /* */ /* File: refine.h */ /* */ /* Purpose: definitions for two AND three dimensional refinement */ /* */ /* Author: Peter Bastian */ /* Interdisziplinaeres Zentrum fuer Wissenschaftliches Rechnen */ /* Universitaet Heidelberg */ /* Im Neuenheimer Feld 368 */ /* 6900 Heidelberg */ /* internet: bastian@iwr1.iwr.uni-heidelberg.de */ /* */ /* History: 09.03.92 begin, ug version 2.0 */ /* */ /* Remarks: */ /* */ /****************************************************************************/ /****************************************************************************/ /* */ /* auto include mechanism and other include files */ /* */ /****************************************************************************/ #ifndef __REFINE__ #define __REFINE__ #include #include #include "gm.h" #include "algebra.h" /* just for ALGEBRA_N_CE */ START_UGDIM_NAMESPACE /****************************************************************************/ /* */ /* defines in the following order */ /* */ /* compile time constants defining static data size (i.e. arrays) */ /* other constants */ /* macros */ /* */ /****************************************************************************/ #define NOTUSED -1 /* SHORT has to be signed! */ #define NO_CENTER_NODE NOTUSED #ifdef ModelP /* undefine if all son objects shall be identified */ #define IDENT_ONLY_NEW #endif /* define this if you want to apply anistropic rules */ /* #define __ANISOTROPIC__ */ /****************************************************************************/ /* */ /* control word definitions */ /* */ /****************************************************************************/ enum REFINE_CE { PATTERN_CE = GM_N_CE, /* continue after gm.h entries */ ADDPATTERN_CE, REFINE_CE, MARK_CE, COARSEN_CE, DECOUPLED_CE, REFINECLASS_CE, UPDATE_GREEN_CE, SIDEPATTERN_CE, MARKCLASS_CE, REFINE_N_CE }; /* edges */ #define PATTERN_SHIFT 10 #define PATTERN_LEN 1 #define PATTERN(p) CW_READ(p,PATTERN_CE) #define SETPATTERN(p,n) CW_WRITE(p,PATTERN_CE,n) #define ADDPATTERN_SHIFT 11 #define ADDPATTERN_LEN 1 #define ADDPATTERN(p) CW_READ(p,ADDPATTERN_CE) #define SETADDPATTERN(p,n) CW_WRITE(p,ADDPATTERN_CE,n) /* element */ #define REFINE_SHIFT 0 #define REFINE_LEN 8 #define REFINE(p) CW_READ(p,REFINE_CE) #define SETREFINE(p,n) CW_WRITE(p,REFINE_CE,n) #define MARK_SHIFT 0 #define MARK_LEN 8 #define MARK(p) CW_READ(p,MARK_CE) #define SETMARK(p,n) CW_WRITE(p,MARK_CE,n) #define COARSEN_SHIFT 10 #define COARSEN_LEN 1 #define COARSEN(p) CW_READ(p,COARSEN_CE) #define SETCOARSEN(p,n) CW_WRITE(p,COARSEN_CE,n) #define DECOUPLED_SHIFT 12 #define DECOUPLED_LEN 1 #define DECOUPLED(p) CW_READ(p,DECOUPLED_CE) #define SETDECOUPLED(p,n) CW_WRITE(p,DECOUPLED_SHIFT,n) #define REFINECLASS_SHIFT 15 #define REFINECLASS_LEN 2 #define REFINECLASS(p) CW_READ(p,REFINECLASS_CE) #define SETREFINECLASS(p,n) CW_WRITE(p,REFINECLASS_CE,n) #define UPDATE_GREEN_SHIFT 8 #define UPDATE_GREEN_LEN 1 #define UPDATE_GREEN(p) CW_READ(p,UPDATE_GREEN_CE) #define SETUPDATE_GREEN(p,n) CW_WRITE(p,UPDATE_GREEN_CE,n) #define SIDEPATTERN_SHIFT 0 #define SIDEPATTERN_LEN 6 #define SIDEPATTERN(p) CW_READ(p,SIDEPATTERN_CE) #define SETSIDEPATTERN(p,n) CW_WRITE(p,SIDEPATTERN_CE,n) #define MARKCLASS_SHIFT 13 #define MARKCLASS_LEN 2 #define MARKCLASS(p) CW_READ(p,MARKCLASS_CE) #define SETMARKCLASS(p,n) CW_WRITE(p,MARKCLASS_CE,n) #ifdef ModelP #define NEW_NIDENT_LEN 2 #define NEW_NIDENT(p) CW_READ(p,ce_NEW_NIDENT) #define SETNEW_NIDENT(p,n) CW_WRITE(p,ce_NEW_NIDENT,n) #define NEW_EDIDENT_LEN 2 #define NEW_EDIDENT(p) CW_READ(p,ce_NEW_EDIDENT) #define SETNEW_EDIDENT(p,n) CW_WRITE(p,ce_NEW_EDIDENT,n) #endif /* macros for refineinfo */ #define RINFO_MAX 100 #define REFINEINFO(mg) refine_info #define REFINESTEP(r) (r).step #define SETREFINESTEP(r,s) (r).step = ((s)%RINFO_MAX) #define MARKCOUNT(r) (r).markcount[(r).step] #define SETMARKCOUNT(r,n) (r).markcount[(r).step] = (n) #define PREDNEW0(r) (r).predicted_new[(r).step][0] #define SETPREDNEW0(r,n) (r).predicted_new[(r).step][0] = (n) #define PREDNEW1(r) (r).predicted_new[(r).step][1] #define SETPREDNEW1(r,n) (r).predicted_new[(r).step][1] = (n) #define PREDNEW2(r) (r).predicted_new[(r).step][2] #define SETPREDNEW2(r,n) (r).predicted_new[(r).step][2] = (n) #define REAL(r) (r).real[(r).step] #define SETREAL(r,n) (r).real[(r).step] = (n) /* macros for listing */ #define REFINE_ELEMENT_LIST(d,e,s) \ IFDEBUG(gm,d) \ if (e!=NULL) \ UserWriteF( s " ID=%d/%08x PRIO=%d TAG=%d BE=%d ECLASS=%d LEVEL=%d" \ " REFINECLASS=%d MARKCLASS=%d REFINE=%d MARK=%d COARSE=%d" \ " USED=%d NSONS=%d EFATHERID=%d SIDEPATTERN=%d\n", \ ID(e),EGID(e),EPRIO(e),TAG(e),(OBJT(e)==BEOBJ),ECLASS(e),LEVEL(e), \ REFINECLASS(e),MARKCLASS(e),REFINE(e),MARK(e),COARSEN(e), \ USED(e),NSONS(e),(EFATHER(e)!=NULL) ? ID(EFATHER(e)) : 0,SIDEPATTERN(e));\ ENDDEBUG #define REFINE_GRID_LIST(d,mg,k,s1,s2) \ IFDEBUG(gm,d) \ { \ GRID *grid = GRID_ON_LEVEL(mg,k); \ ELEMENT *theElement; \ \ UserWriteF s1 ; \ for (theElement=PFIRSTELEMENT(grid); \ theElement!=NULL; \ theElement=SUCCE(theElement)) \ { \ REFINE_ELEMENT_LIST(d,theElement,s2) \ } \ } \ ENDDEBUG #define REFINE_MULTIGRID_LIST(d,mg,s1,s2,s3) \ IFDEBUG(gm,d) \ { \ INT k; \ \ UserWriteF( s1 ); \ for (k=0; k<=TOPLEVEL(mg); k++) \ { \ GRID *grid = GRID_ON_LEVEL(mg,k); \ ELEMENT *theElement; \ \ UserWriteF( s2 ); \ for (theElement=PFIRSTELEMENT(grid); \ theElement!=NULL; \ theElement=SUCCE(theElement)) \ { \ REFINE_ELEMENT_LIST(d,theElement,s3) \ } \ } \ } \ ENDDEBUG /****************************************************************************/ /* */ /* typedefs */ /* */ /****************************************************************************/ typedef struct refineinfo { INT step; /* count of calls to AdaptMultiGrid */ float markcount[RINFO_MAX]; /* count of currently marked elements */ float predicted_new[RINFO_MAX][3]; /* count of elements, would be created */ float real[RINFO_MAX]; /* count of elements before refinement */ } REFINEINFO; typedef INT (*Get_Sons_of_ElementSideProcPtr)(ELEMENT *theElement, INT side, INT *Sons_of_Side,ELEMENT *SonList[MAX_SONS], INT *SonSides, INT NeedSons); /****************************************************************************/ /* */ /* definition of exported global variables */ /* */ /****************************************************************************/ extern REFINEINFO refine_info; #ifdef ModelP extern INT ce_NEW_NIDENT; extern INT ce_NEW_EDIDENT; #endif /****************************************************************************/ /* */ /* functions exported */ /* */ /****************************************************************************/ INT GetSonSideNodes (const ELEMENT *theElement, INT side, INT *nodes, NODE *SideNodes[MAX_SIDE_NODES], INT ioflag); INT Get_Sons_of_ElementSide(const ELEMENT *theElement, INT side, INT *Sons_of_Side, ELEMENT *SonList[MAX_SONS], INT *SonSides, INT NeedSons, INT ioflag, INT useRefineClass=0); INT Connect_Sons_of_ElementSide (GRID *theGrid, ELEMENT *theElement, INT side, INT Sons_of_Side, ELEMENT **Sons_of_Side_List, INT *SonSides, INT ioflag); INT Refinement_Changes (ELEMENT *theElement); END_UGDIM_NAMESPACE #endif dune-uggrid-2.11.0+dfsg/dune/uggrid/gm/rm-show.cc000066400000000000000000000026341513616443000214560ustar00rootroot00000000000000// SPDX-FileCopyrightText: Copyright © DUNE Project contributors, see file LICENSE.md in module root // SPDX-License-Identifier: LGPL-2.1-or-later #include "config.h" #include #include #include #include #include #include #include #include #include int main(int argc, char** argv) { NS_PREFIX InitLow(); NS_PREFIX InitDevices(); NS_DIM_PREFIX InitGm(); std::vector rules; std::vector patterns; // use an arbitrary additional argument to use the rules from "lib/ugdata/RefRules.data" if( argc > 1 ) { // read the file "lib/ugdata/RefRules.data" and use those rules std::FILE* stream = std::fopen(argv[1], "r"); if (!stream) DUNE_THROW(Dune::Exception, "Could not open file " << argv[1] << ": " << std::strerror(errno)); NS_DIM_PREFIX readTetrahedronRules(stream, rules, patterns); std::fclose(stream); NS_DIM_PREFIX RefRules[NS_DIM_PREFIX TETRAHEDRON] = rules.data(); NS_DIM_PREFIX MaxRules[NS_DIM_PREFIX TETRAHEDRON] = rules.size(); } // write rules for(int i=0; i #include #include #include #include "evm.h" #include "gm.h" #include "rm.h" USING_UGDIM_NAMESPACE USING_UG_NAMESPACE static bool CheckVolumes(REFRULE const *Rule) { bool pass = true; DOUBLE_VECTOR coords [MAX_CORNERS_OF_ELEM+MAX_NEW_CORNERS_DIM]; DOUBLE_VECTOR coord; DOUBLE_VECTOR p[MAX_CORNERS_OF_ELEM]; /* this function work only for TETRAHEDRA!!! */ int tag = TETRAHEDRON; /* reset coords */ for (int i=0; imark != 0) { printf("Rule %d :sum over sons = %f != 1\n",Rule->mark,sum); pass = false; } return pass; } int main(int argc, char** argv) { Dune::MPIHelper::instance(argc, argv); InitUg(&argc, &argv); bool pass = true; std::printf("Testing %d refinement rules for the tetrahedron...\n", MaxRules[TETRAHEDRON]); REFRULE* rules = RefRules[TETRAHEDRON]; for (int i = 0; i < MaxRules[TETRAHEDRON]; ++i) pass = pass && CheckVolumes(rules + i); ExitUg(); return pass ? 0 : 1; } dune-uggrid-2.11.0+dfsg/dune/uggrid/gm/rm-write2file.cc000066400000000000000000000266601513616443000225570ustar00rootroot00000000000000// SPDX-FileCopyrightText: Copyright © DUNE Project contributors, see file LICENSE.md in module root // SPDX-License-Identifier: LGPL-2.1-or-later #include "config.h" #include #include "rm-write2file.h" #ifdef UG_DIM_3 static NS_DIM_PREFIX REFRULE Empty_Rule = {-1,-1,NS_DIM_PREFIX NO_CLASS,-1, {-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1}, -1, {{-1,-1},{-1,-1},{-1,-1},{-1,-1},{-1,-1},{-1,-1}, {-1,-1},{-1,-1},{-1,-1},{-1,-1},{-1,-1},{-1,-1}, {-1,-1},{-1,-1},{-1,-1},{-1,-1},{-1,-1},{-1,-1}, {-1,-1}}, {{-1,{-1,-1,-1,-1,-1,-1,-1,-1},{-1,-1,-1,-1,-1,-1},-1}, {-1,{-1,-1,-1,-1,-1,-1,-1,-1},{-1,-1,-1,-1,-1,-1},-1}, {-1,{-1,-1,-1,-1,-1,-1,-1,-1},{-1,-1,-1,-1,-1,-1},-1}, {-1,{-1,-1,-1,-1,-1,-1,-1,-1},{-1,-1,-1,-1,-1,-1},-1}, {-1,{-1,-1,-1,-1,-1,-1,-1,-1},{-1,-1,-1,-1,-1,-1},-1}, {-1,{-1,-1,-1,-1,-1,-1,-1,-1},{-1,-1,-1,-1,-1,-1},-1}, {-1,{-1,-1,-1,-1,-1,-1,-1,-1},{-1,-1,-1,-1,-1,-1},-1}, {-1,{-1,-1,-1,-1,-1,-1,-1,-1},{-1,-1,-1,-1,-1,-1},-1}, {-1,{-1,-1,-1,-1,-1,-1,-1,-1},{-1,-1,-1,-1,-1,-1},-1}, {-1,{-1,-1,-1,-1,-1,-1,-1,-1},{-1,-1,-1,-1,-1,-1},-1}, {-1,{-1,-1,-1,-1,-1,-1,-1,-1},{-1,-1,-1,-1,-1,-1},-1}, {-1,{-1,-1,-1,-1,-1,-1,-1,-1},{-1,-1,-1,-1,-1,-1},-1}}}; template int writeArray(FILE* stream, const T* array, int const n) { int num_chars = 0; for(int i=0; i < n;i++) { num_chars += std::fprintf(stream,"%d,", static_cast(array[i])); } return num_chars; } const char* tag2string(int const tag) { switch(tag) { case NS_DIM_PREFIX TETRAHEDRON: return "TETRAHEDRON"; case NS_DIM_PREFIX PYRAMID: return "PYRAMID"; case NS_DIM_PREFIX PRISM: return "PRISM"; case NS_DIM_PREFIX HEXAHEDRON: return "HEXAHEDRON"; default: DUNE_THROW(Dune::Exception, "tag2string: unknown tag " << tag); } } const char* class2string(int const rclass) { switch(rclass) { case NS_DIM_PREFIX NO_CLASS: return "NO_CLASS"; case NS_DIM_PREFIX YELLOW_CLASS: return "YELLOW_CLASS"; case NS_DIM_PREFIX GREEN_CLASS: return "GREEN_CLASS"; case NS_DIM_PREFIX RED_CLASS: return "RED_CLASS"; case NS_DIM_PREFIX SWITCH_CLASS: return "SWITCH_CLASS"; default: DUNE_THROW(Dune::Exception, "class2string: unknown class " << rclass); } } int WriteSonData(std::FILE* const stream, NS_DIM_PREFIX sondata const& son) { using std::fprintf; int num_chars = 0; // tag int tag = son.tag; const char* tag_s = tag2string(tag); num_chars += fprintf( stream,"{%s,{",tag_s); // corners num_chars += writeArray(stream, son.corners, MAX_CORNERS_OF_ELEM_DIM); num_chars += fprintf( stream,"},{"); // nb num_chars += writeArray(stream, son.nb, MAX_SIDES_OF_ELEM_DIM); num_chars += fprintf(stream ,"},%d}",son.path); return num_chars; } void WriteRule2File(std::FILE* const stream, NS_DIM_PREFIX REFRULE const& theRule) { using std::fprintf; // only used for alignment of comments int comment_row = 80; // tag, mark, rclass, nsons const char* tag_s = tag2string(theRule.tag); const char* rclass_s = class2string(theRule.rclass); int char0 = fprintf( stream," {%s,%d,%s,%d,",tag_s ,theRule.mark,rclass_s,theRule.nsons); fprintf( stream,"%*s// tag, mark, rclass, nsons\n", comment_row - char0," "); // pattern char0 = fprintf( stream," {"); char0 += writeArray(stream, theRule.pattern, MAX_NEW_CORNERS_DIM); fprintf( stream,"},%*s// pattern\n", comment_row - char0 -2, " "); // pat char0 = std::fprintf( stream," %d,",theRule.pat); fprintf( stream,"%*s// pat\n", comment_row - char0, " "); // sonandnode bool alreadyCommented = false; char0 = fprintf( stream," {"); for(int i=0; i < MAX_NEW_CORNERS_DIM; i++) { char0 += fprintf( stream,"{%d,%d},",theRule.sonandnode[i][0],theRule.sonandnode[i][1]); // new line after 6 sons if( (i%6) ==0 && i !=0) { // comment if (!alreadyCommented) { fprintf( stream,"%*s// sonandnode", comment_row - char0, " "); alreadyCommented = !alreadyCommented; } fprintf( stream,"\n "); } } fprintf( stream,"},\n"); // sons alreadyCommented = false; char0 = fprintf( stream," {"); for(int i=0; i const& rules, std::vector const& patterns) { std::fprintf( stream, "// This file was generated by \"gm/rm3-writeRefRules2file\"\n\n"); std::fprintf( stream, "static const std::size_t nTetrahedronRefinementRules = %zd;\n", rules.size() ); std::fprintf( stream, "static REFRULE tetrahedronRefinementRules[] =\n{\n"); for (std::size_t i=0; i < rules.size(); i++) { std::fprintf( stream, " // Rule %lu\n",i); WriteRule2File(stream, rules[i]); std::fprintf( stream,",\n\n"); } std::fprintf( stream, "};\n"); std::fprintf( stream, "static const NS_PREFIX SHORT pattern2RuleTetrahedron[%zd] = {", patterns.size()); writeArray(stream, patterns.data(), patterns.size()); std::fprintf( stream,"};\n"); } START_UGDIM_NAMESPACE static void CorrectRule40 (refrule *theRule) { for (int i : {1,4,8}) { auto&& son = theRule->sons[i]; std::swap(son.corners[0],son.corners[1]); std::swap(son.nb[1],son.nb[2]); } } static void CorrectRule41 (refrule *theRule) { for (int i : {1,4,7}) { auto&& son = theRule->sons[i]; std::swap(son.corners[0],son.corners[1]); std::swap(son.nb[1],son.nb[2]); } } static void CorrectRule52 (refrule *theRule) { for (int i : {2,8}) { auto&& son = theRule->sons[i]; std::swap(son.corners[0],son.corners[1]); std::swap(son.nb[1],son.nb[2]); } } static void CorrectRule53 (refrule *theRule) { for (int i : {2,7}) { auto&& son = theRule->sons[i]; std::swap(son.corners[0],son.corners[1]); std::swap(son.nb[1],son.nb[2]); } } static void CorrectRule85 (refrule *theRule) { // i == 4 auto&& son = theRule->sons[4]; std::swap(son.corners[0],son.corners[1]); std::swap(son.nb[1],son.nb[2]); } static void CorrectRule86 (refrule *theRule) { // i == 4 auto&& son = theRule->sons[4]; std::swap(son.corners[0],son.corners[1]); std::swap(son.nb[1],son.nb[2]); } static void CorrectRule111 (refrule *theRule) { for (int i : {6,8}) { auto&& son = theRule->sons[i]; std::swap(son.corners[0],son.corners[1]); std::swap(son.nb[1],son.nb[2]); } } static void CorrectRule112 (refrule *theRule) { for (int i : {6,7}) { auto&& son = theRule->sons[i]; std::swap(son.corners[0],son.corners[1]); std::swap(son.nb[1],son.nb[2]); } } static void CorrectRule135 (refrule *theRule) { for (int i : {1,3,11}) { auto&& son = theRule->sons[i]; std::swap(son.corners[0],son.corners[1]); std::swap(son.nb[1],son.nb[2]); } } static void CorrectRule136 (refrule *theRule) { for (int i : {2,3,11}) { auto&& son = theRule->sons[i]; std::swap(son.corners[0],son.corners[1]); std::swap(son.nb[1],son.nb[2]); } } static void CorrectRule155 (refrule *theRule) { for (int i : {5,7,9}) { auto&& son = theRule->sons[i]; std::swap(son.corners[0],son.corners[1]); std::swap(son.nb[1],son.nb[2]); } } static void CorrectRule156 (refrule *theRule) { for (int i : {5,8,9}) { auto&& son = theRule->sons[i]; std::swap(son.corners[0],son.corners[1]); std::swap(son.nb[1],son.nb[2]); } } static void CorrectRule183 (refrule *theRule) { for (int i : {3,7,11}) { auto&& son = theRule->sons[i]; std::swap(son.corners[0],son.corners[1]); std::swap(son.nb[1],son.nb[2]); } } static void CorrectRule184 (refrule *theRule) { for (int i : {2,8,11}) { auto&& son = theRule->sons[i]; std::swap(son.corners[0],son.corners[1]); std::swap(son.nb[1],son.nb[2]); } } static int FReadRule (FILE *stream, REFRULE *theRule) { int ns,p0,p1,p2,p3,p4,p5,pat; // init tag theRule->tag = TETRAHEDRON; if (fscanf(stream,"%d %d %d %d %d %d %d %d",&ns,&p0,&p1,&p2,&p3,&p4,&p5,&pat)!=8) return (1); theRule->nsons = ns; theRule->pattern[0] = p0; theRule->pattern[1] = p1; theRule->pattern[2] = p2; theRule->pattern[3] = p3; theRule->pattern[4] = p4; theRule->pattern[5] = p5; theRule->pat = pat; // MAXEDGES = 16 for tetrahedra int type,from,to,side; for (int i=0; i<16; i++) { if (fscanf(stream," %d %d %d %d",&type,&from,&to,&side)!=4) return (1); } // MAX_SONS = 12 for tetrahedra for (int i=0; i<12; i++) { int c0,c1,c2,c3,n0,n1,n2,n3,pa; if (fscanf(stream," %d %d %d %d %d %d %d %d %d",&c0,&c1,&c2,&c3,&n0,&n1,&n2,&n3,&pa)!=9) return (1); theRule->sons[i].tag = TETRAHEDRON; if (c0 == 10) c0 = 14; theRule->sons[i].corners[0] = c0; if (c1 == 10) c1 = 14; theRule->sons[i].corners[1] = c1; if (c2 == 10) c2 = 14; theRule->sons[i].corners[2] = c2; if (c3 == 10) c3 = 14; theRule->sons[i].corners[3] = c3; theRule->sons[i].nb[0] = n0; theRule->sons[i].nb[1] = n1; theRule->sons[i].nb[2] = n2; theRule->sons[i].nb[3] = n3; theRule->sons[i].path = pa; static const int nSidesOfTetrahedron = 4; /* == SIDES_OF_TAG(TETRAHEDRON) */ for (int j=0; j < nSidesOfTetrahedron; j++) if (theRule->sons[i].nb[j]>=TET_RULE_FATHER_SIDE_OFFSET) theRule->sons[i].nb[j] += FATHER_SIDE_OFFSET-TET_RULE_FATHER_SIDE_OFFSET; } // NEWCORNERS = 7 for tetrahedra // read edge node information int sn0,sn1; for (int i=0; i<6; i++) { if (fscanf(stream," %d %d",&sn0,&sn1)!=2) return (1); theRule->sonandnode[i][0] = sn0; theRule->sonandnode[i][1] = sn1; } // read center node information if (fscanf(stream," %d %d",&sn0,&sn1)!=2) return (1); theRule->sonandnode[10][0] = sn0; theRule->sonandnode[10][1] = sn1; // init Pattern and pat for center node if (theRule->sonandnode[10][0] != NO_CENTER_NODE) { theRule->pattern[10] = 1; theRule->pat |= (1<<10); } return (0); } void readTetrahedronRules(FILE* stream, std::vector& rules, std::vector& patterns) { USING_UGDIM_NAMESPACE USING_UG_NAMESPACE { int nRules; int nPatterns; // read Rules and nPatterns from file if (std::fscanf(stream,"%d %d\n",&nRules,&nPatterns)!=2) DUNE_THROW(Dune::Exception, "failed to read nRules and nPatterns from file"); rules.assign(nRules, Empty_Rule); patterns.assign(nPatterns, -1); } // read Rules { int i = 0; for (auto& rule : rules) { rule.mark = i++; rule.rclass = RED_CLASS|GREEN_CLASS; if (FReadRule(stream, &rule)) DUNE_THROW(Dune::Exception, "failed to read rule"); } } for (auto& pattern : patterns) { if (std::fscanf(stream,"%hd",&pattern)!=1) DUNE_THROW(Dune::Exception, "failed to read pattern from file"); } // bug fix CorrectRule40(&rules[40]); CorrectRule41(&rules[41]); CorrectRule52(&rules[52]); CorrectRule53(&rules[53]); CorrectRule85(&rules[85]); CorrectRule86(&rules[86]); CorrectRule111(&rules[111]); CorrectRule112(&rules[112]); CorrectRule135(&rules[135]); CorrectRule136(&rules[136]); CorrectRule155(&rules[155]); CorrectRule156(&rules[156]); CorrectRule183(&rules[183]); CorrectRule184(&rules[184]); } END_UGDIM_NAMESPACE #endif //__THREEDIM dune-uggrid-2.11.0+dfsg/dune/uggrid/gm/rm-write2file.h000066400000000000000000000017761513616443000224220ustar00rootroot00000000000000// SPDX-FileCopyrightInfo: Copyright © DUNE Project contributors, see file LICENSE.md in module root // SPDX-License-Identifier: LGPL-2.1-or-later #ifndef RM_WRITE2FILE_H #define RM_WRITE2FILE_H // standard C library #include #include #include #include // std library #include #include #include #include #include #include #include #include #include "gm.h" #include "rm.h" #include "evm.h" #define TET_RULE_FATHER_SIDE_OFFSET 20 int WriteSonData(std::FILE* stream, NS_DIM_PREFIX sondata const& son); void WriteRule2File(std::FILE* stream, NS_DIM_PREFIX REFRULE const& rules); void Write2File(std::FILE* stream, std::vector const& rules, std::vector const& patterns); START_UGDIM_NAMESPACE void readTetrahedronRules(FILE* stream, std::vector& rules, std::vector& patterns); END_UGDIM_NAMESPACE #endif dune-uggrid-2.11.0+dfsg/dune/uggrid/gm/rm-writeRefRules2file.cc000066400000000000000000000025421513616443000242200ustar00rootroot00000000000000// SPDX-FileCopyrightText: Copyright © DUNE Project contributors, see file LICENSE.md in module root // SPDX-License-Identifier: LGPL-2.1-or-later #include "config.h" #include #include #include #include #include #include #include #include #include int main(int argc, char** argv) { if (argc != 3) { std::cerr << "usage: " << argv[0] << " \n"; return 1; } std::vector rules; std::vector patterns; // Read rules { const char* filename = argv[1]; std::FILE* stream = std::fopen(filename, "r"); if (!stream) DUNE_THROW(Dune::Exception, "Could not open " << filename << " for reading: " << std::strerror(errno)); readTetrahedronRules(stream, rules, patterns); std::fclose(stream); } // Write rules { const char* filename = argv[2]; std::FILE* stream = std::fopen(filename, "w"); if (!stream) DUNE_THROW(Dune::Exception, "Could not open " << filename << " for writing: " << std::strerror(errno)); Write2File(stream, rules, patterns); if (std::fclose(stream)) DUNE_THROW(Dune::Exception, "E: Closing " << filename << " failed: " << std::strerror(errno)); } return 0; } dune-uggrid-2.11.0+dfsg/dune/uggrid/gm/rm.cc000066400000000000000000003610311513616443000204770ustar00rootroot00000000000000// SPDX-FileCopyrightText: Copyright © DUNE Project contributors, see file LICENSE.md in module root // SPDX-License-Identifier: LGPL-2.1-or-later // -*- tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- // vi: set et ts=4 sw=2 sts=2: /****************************************************************************/ /* */ /* File: rm.c */ /* */ /* Purpose: rule manager for 2D and 3D refinement rules */ /* */ /* Author: Stefan Lang */ /* Institut fuer Computeranwendungen III */ /* Universitaet Stuttgart */ /* Pfaffenwaldring 27 */ /* 70550 Stuttgart */ /* */ /* History: 21.11.95 begin, ugp version 3.0 */ /* */ /* Remarks: */ /* */ /****************************************************************************/ /****************************************************************************/ /* */ /* include files */ /* system include files */ /* application include files */ /* */ /****************************************************************************/ #include /* standard C library */ #include #include #include #include /* low module */ #include #include #include #include /* dev module */ #include /* gm module */ #include "evm.h" #include "gm.h" #include "refine.h" #include "shapes.h" #include "rm.h" #include "cw.h" #include "elements.h" #ifdef ModelP #include using namespace PPIF; #endif USING_UG_NAMESPACES /****************************************************************************/ /* */ /* defines in the following order */ /* */ /* compile time constants defining static data size (i.e. arrays) */ /* other constants */ /* macros */ /* */ /****************************************************************************/ /* macros defining best refrule, specify exactly one of them !! */ /*#define __SHORTEST_INTERIOR_EDGE__*/ /*#define __MIDDLE_INTERIOR_EDGE__*/ #define __LONGEST_INTERIOR_EDGE__ #define NOINDEX -1 /* rule count for element types */ #ifdef UG_DIM_2 #define MAX_TRI_RULES 18 #define MAX_QUA_RULES 17 #else #ifndef DUNE_UGGRID_TET_RULESET #define MAX_TET_RULES 6 #endif #define MAX_PYR_RULES 5 #define MAX_PRI_RULES 15 #define MAX_HEX_RULES 13 #endif /* shorthand notation */ #define FO FATHER_SIDE_OFFSET /****************************************************************************/ /* */ /* data structures used in this source file (exported data structures are */ /* in the corresponding include file!) */ /* */ /****************************************************************************/ /****************************************************************************/ /* */ /* definition of exported global variables */ /* */ /****************************************************************************/ INT NS_DIM_PREFIX MaxRules[TAGS] = {0,0,0,0,0,0,0,0}; INT NS_DIM_PREFIX MaxNewCorners[TAGS] = {0,0,0,0,0,0,0,0}; INT NS_DIM_PREFIX MaxNewEdges[TAGS] = {0,0,0,0,0,0,0,0}; INT NS_DIM_PREFIX CenterNodeIndex[TAGS] = {0,0,0,0,0,0,0,0}; REFRULE * NS_DIM_PREFIX RefRules[TAGS] = {NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL}; SHORT const* NS_DIM_PREFIX Pattern2Rule[TAGS]; #ifdef UG_DIM_3 /* define the standard regular rules for tetrahedrons */ FULLREFRULEPTR NS_DIM_PREFIX theFullRefRule; #endif /****************************************************************************/ /* */ /* definition of variables global to this source file only (static!) */ /* */ /****************************************************************************/ #ifdef UG_DIM_2 [[maybe_unused]] static REFRULE Empty_Rule = {-1,-1,NO_CLASS,-1,{-1,-1,-1,-1},-1, {{-1,-1},{-1,-1},{-1,-1},{-1,-1},{-1,-1}}, {{-1,{-1,-1,-1,-1},{-1,-1,-1,-1},-1}, {-1,{-1,-1,-1,-1},{-1,-1,-1,-1},-1}, {-1,{-1,-1,-1,-1},{-1,-1,-1,-1},-1}, {-1,{-1,-1,-1,-1},{-1,-1,-1,-1},-1}}}; /* define Rules for Triangles */ static REFRULE TriangleRules[MAX_TRI_RULES] = { /* T_NOREF */ {TRIANGLE,T_NOREF,NO_CLASS,0, {0,0,0,0},0, {{-1,-1},{-1,-1},{-1,-1},{-1,-1},{-1,-1}}, {{-1,{-1,-1,-1,-1},{-1,-1,-1,-1},-1}, {-1,{-1,-1,-1,-1},{-1,-1,-1,-1},-1}, {-1,{-1,-1,-1,-1},{-1,-1,-1,-1},-1}, {-1,{-1,-1,-1,-1},{-1,-1,-1,-1},-1}}}, /* T_COPY */ {TRIANGLE,T_COPY,RED_CLASS|GREEN_CLASS,1, {0,0,0,0},0, {{-1,-1},{-1,-1},{-1,-1},{-1,-1},{-1,-1}}, {{TRIANGLE,{0,1,2,-1},{FO+0,FO+1,FO+2,-1},0}, {-1,{-1,-1,-1,-1},{-1,-1,-1,-1},-1}, {-1,{-1,-1,-1,-1},{-1,-1,-1,-1},-1}, {-1,{-1,-1,-1,-1},{-1,-1,-1,-1},-1}}}, /* T_RED */ {TRIANGLE,T_RED,RED_CLASS|GREEN_CLASS|SWITCH_CLASS,4, {1,1,1,0},(1<<3)-1, {{0,1},{1,2},{0,2},{-1,-1},{-1,-1}}, {{TRIANGLE,{0,3,5,-1},{FO+0, 3,FO+2,-1},0}, {TRIANGLE,{3,1,4,-1},{FO+0,FO+1, 3,-1},0}, {TRIANGLE,{4,2,5,-1},{ FO+1,FO+2,3,-1},0}, {TRIANGLE,{3,4,5,-1},{ 1, 2, 0,-1},0}}}, /* T_BISECT_1 edge 0 bisected */ {TRIANGLE,T_BISECT_1_0,RED_CLASS|GREEN_CLASS,2, {1,0,0,0},1, {{0,1},{-1,-1},{-1,-1},{-1,-1},{-1,-1}}, {{TRIANGLE,{0,3,2,-1},{FO+0, 1,FO+2,-1},0}, {TRIANGLE,{3,1,2,-1},{FO+0,FO+1, 0,-1},0}, {-1,{-1,-1,-1,-1},{-1,-1,-1,-1},-1}, {-1,{-1,-1,-1,-1},{-1,-1,-1,-1},-1}}}, /* T_BISECT_1 edge 1 bisected */ {TRIANGLE,T_BISECT_1_1,RED_CLASS|GREEN_CLASS,2, {0,1,0,0},1<<1, {{-1,-1},{0,2},{-1,-1},{-1,-1},{-1,-1}}, {{TRIANGLE,{0,1,4,-1},{FO+0,FO+1, 1,-1},0}, {TRIANGLE,{0,4,2,-1},{ 0,FO+1,FO+2,-1},0}, {-1,{-1,-1,-1,-1},{-1,-1,-1,-1},-1}, {-1,{-1,-1,-1,-1},{-1,-1,-1,-1},-1}}}, /* T_BISECT_1 edge 2 bisected */ {TRIANGLE,T_BISECT_1_2,RED_CLASS|GREEN_CLASS,2, {0,0,1,0},1<<2, {{-1,-1},{-1,-1},{0,2},{-1,-1},{-1,-1}}, {{TRIANGLE,{0,1,5,-1},{FO+0, 1,FO+2,-1},0}, {TRIANGLE,{5,1,2,-1},{ 0,FO+1,FO+2,-1},0}, {-1,{-1,-1,-1,-1},{-1,-1,-1,-1},-1}, {-1,{-1,-1,-1,-1},{-1,-1,-1,-1},-1}}}, /* T_BISECT_2_T1 edge 2 not bisected */ {TRIANGLE,T_BISECT_2_T1_2,RED_CLASS|GREEN_CLASS,3, {1,1,0,0},(1<<2)-1, {{0,1},{1,2},{-1,-1},{-1,-1},{-1,-1}}, {{TRIANGLE,{0,3,2,-1},{FO+0, 2,FO+2,-1},0}, {TRIANGLE,{3,1,4,-1},{FO+0,FO+1, 2,-1},0}, {TRIANGLE,{3,4,2,-1},{ 1,FO+1, 0,-1},0}, {-1,{-1,-1,-1,-1},{-1,-1,-1,-1},-1}}}, /* T_BISECT_2_T1 edge 0 not bisected */ {TRIANGLE,T_BISECT_2_T1_0,RED_CLASS|GREEN_CLASS,3, {0,1,1,0},6, {{-1,-1},{0,2},{1,2},{-1,-1},{-1,-1}}, {{TRIANGLE,{0,1,4,-1},{FO+0,FO+1, 1,-1},0}, {TRIANGLE,{0,4,5,-1},{ 0, 2,FO+2,-1},0}, {TRIANGLE,{5,4,2,-1},{ 1,FO+1,FO+2,-1},0}, {-1,{-1,-1,-1,-1},{-1,-1,-1,-1},-1}}}, /* T_BISECT_2_T1 edge 1 not bisected */ {TRIANGLE,T_BISECT_2_T1_1,RED_CLASS|GREEN_CLASS,3, {1,0,1,0},5, {{0,1},{-1,-1},{1,2},{-1,-1},{-1,-1}}, {{TRIANGLE,{0,3,5,-1},{FO+0, 1,FO+2,-1},0}, {TRIANGLE,{3,1,5,-1},{FO+0, 2, 0,-1},0}, {TRIANGLE,{5,1,2,-1},{ 1,FO+1,FO+2,-1},0}, {-1,{-1,-1,-1,-1},{-1,-1,-1,-1},-1}}}, /* T_BISECT_2_T2 edge 1 not bisected */ {TRIANGLE,T_BISECT_2_T2_1,RED_CLASS|GREEN_CLASS,3, {1,0,1,0},5, {{0,1},{-1,-1},{0,2},{-1,-1},{-1,-1}}, {{TRIANGLE,{0,3,5,-1},{FO+0, 1,FO+2,-1},0}, {TRIANGLE,{5,3,2,-1},{ 0, 2,FO+2,-1},0}, {TRIANGLE,{3,1,2,-1},{FO+0,FO+1, 1,-1},0}, {-1,{-1,-1,-1,-1},{-1,-1,-1,-1},-1}}}, /* T_BISECT_2_T2 edge 2 not bisected */ {TRIANGLE,T_BISECT_2_T2_2,RED_CLASS|GREEN_CLASS,3, {1,1,0,0},3, {{0,1},{0,2},{-1,-1},{-1,-1},{-1,-1}}, {{TRIANGLE,{0,3,4,-1},{FO+0, 1, 2,-1},0}, {TRIANGLE,{3,1,4,-1},{FO+0,FO+1, 0,-1},0}, {TRIANGLE,{0,4,2,-1},{ 0,FO+1,FO+2,-1},0}, {-1,{-1,-1,-1,-1},{-1,-1,-1,-1},-1}}}, /* T_BISECT_2_T2 edge 0 not bisected */ {TRIANGLE,T_BISECT_2_T2_0,RED_CLASS|GREEN_CLASS,3, {0,1,1,0},6, {{-1,-1},{1,2},{0,2},{-1,-1},{-1,-1}}, {{TRIANGLE,{0,1,5,-1},{FO+0, 1,FO+2,-1},0}, {TRIANGLE,{5,1,4,-1},{ 0,FO+1, 2,-1},0}, {TRIANGLE,{5,4,2,-1},{ 1,FO+1,FO+2,-1},0}, {-1,{-1,-1,-1,-1},{-1,-1,-1,-1},-1}}}, /* T_BISECT_2_Q edge 0 not bisected */ {TRIANGLE,T_BISECT_2_Q_0,RED_CLASS|GREEN_CLASS,2, {0,1,1,0},6, {{-1,-1},{0,2},{0,3},{-1,-1},{-1,-1}}, {{QUADRILATERAL,{0,1,4,5},{FO+0,FO+1, 1,FO+2},0}, {TRIANGLE,{5,4,2,-1},{ 0,FO+1,FO+2,-1},0}, {-1,{-1,-1,-1,-1},{-1,-1,-1,-1},-1}, {-1,{-1,-1,-1,-1},{-1,-1,-1,-1},-1}}}, /* T_BISECT_2_Q edge 1 not bisected */ {TRIANGLE,T_BISECT_2_Q_1,RED_CLASS|GREEN_CLASS,2, {1,0,1,0},5, {{0,1},{-1,-1},{0,2},{-1,-1},{-1,-1}}, {{TRIANGLE,{0,3,5,-1},{FO+0, 1,FO+2,-1},0}, {QUADRILATERAL,{3,1,2,5},{FO+0,FO+1,FO+2, 0},0}, {-1,{-1,-1,-1,-1},{-1,-1,-1,-1},-1}, {-1,{-1,-1,-1,-1},{-1,-1,-1,-1},-1}}}, /* T_BISECT_2_Q edge 2 not bisected */ {TRIANGLE,T_BISECT_2_Q_2,RED_CLASS|GREEN_CLASS,2, {1,1,0,0},3, {{0,1},{0,2},{-1,-1},{-1,-1},{-1,-1}}, {{QUADRILATERAL,{0,3,4,2},{FO+0, 1,FO+1,FO+2},0}, {TRIANGLE,{3,1,4,-1},{FO+0,FO+1, 0,-1},0}, {-1,{-1,-1,-1,-1},{-1,-1,-1,-1},-1}, {-1,{-1,-1,-1,-1},{-1,-1,-1,-1},-1}}}, /* T_BISECT_3 edge 0 */ {TRIANGLE,T_BISECT_3_0,RED_CLASS|GREEN_CLASS,4, {1,1,1,0},7, {{0,1},{3,2},{0,2},{-1,-1},{-1,-1}}, {{TRIANGLE,{0,3,5,-1},{FO+0, 1,FO+2,-1},0}, {TRIANGLE,{5,3,2,-1},{ 0, 2,FO+2,-1},0}, {TRIANGLE,{3,4,2,-1},{ 3,FO+1, 1,-1},0}, {TRIANGLE,{3,1,4,-1},{FO+0,FO+1, 2,-1},0}}}, /* T_BISECT_3 edge 1 */ {TRIANGLE,T_BISECT_3_1,RED_CLASS|GREEN_CLASS,4, {1,1,1,0},7, {{0,1},{0,2},{1,2},{-1,-1},{-1,-1}}, {{TRIANGLE,{0,3,4,-1},{FO+0, 3, 1,-1},0}, {TRIANGLE,{0,4,5,-1},{ 0, 2,FO+2,-1},0}, {TRIANGLE,{5,4,2,-1},{ 1,FO+1,FO+2,-1},0}, {TRIANGLE,{3,1,4,-1},{FO+0,FO+1, 0,-1},0}}}, /* T_BISECT_3 edge 2 */ {TRIANGLE,T_BISECT_3_2,RED_CLASS|GREEN_CLASS,4, {1,1,1,0},7, {{0,1},{2,2},{1,2},{-1,-1},{-1,-1}}, {{TRIANGLE,{0,3,5,-1},{FO+0, 1,FO+2,-1},0}, {TRIANGLE,{3,1,5,-1},{FO+0, 2, 0,-1},0}, {TRIANGLE,{5,1,4,-1},{ 1,FO+1, 3,-1},0}, {TRIANGLE,{5,4,2,-1},{ 2,FO+1,FO+2,-1},0}}}, }; /* define Rules for Quadrilaterals */ static REFRULE QuadrilateralRules[MAX_QUA_RULES] = { /* Q_NOREF */ {QUADRILATERAL,Q_NOREF,NO_CLASS,0, {0,0,0,0},0, {{-1,-1},{-1,-1},{-1,-1},{-1,-1},{-1,-1}}, {{-1,{-1,-1,-1,-1},{-1,-1,-1,-1},-1}, {-1,{-1,-1,-1,-1},{-1,-1,-1,-1},-1}, {-1,{-1,-1,-1,-1},{-1,-1,-1,-1},-1}, {-1,{-1,-1,-1,-1},{-1,-1,-1,-1},-1}}}, /* Q_COPY */ {QUADRILATERAL,Q_COPY,RED_CLASS|GREEN_CLASS,1, {0,0,0,0},0, {{-1,-1},{-1,-1},{-1,-1},{-1,-1},{-1,-1}}, {{QUADRILATERAL,{0,1,2,3},{FO+0,FO+1,FO+2,FO+3},-1}, {-1,{-1,-1,-1,-1},{-1,-1,-1,-1},-1}, {-1,{-1,-1,-1,-1},{-1,-1,-1,-1},-1}, {-1,{-1,-1,-1,-1},{-1,-1,-1,-1},-1}}}, /* Q_RED */ {QUADRILATERAL,Q_RED,RED_CLASS|GREEN_CLASS|SWITCH_CLASS,4, {1,1,1,1,1},(1<<5)-1, {{0,1},{1,2},{2,3},{3,0},{0,2}}, {{QUADRILATERAL,{0,4,8,7},{FO+0, 1, 3,FO+3},-1}, {QUADRILATERAL,{4,1,5,8},{FO+0,FO+1, 2, 0},-1}, {QUADRILATERAL,{8,5,2,6},{ 1,FO+1,FO+2, 3},-1}, {QUADRILATERAL,{7,8,6,3},{ 0, 2,FO+2,FO+3},-1}}}, /* Q_CLOSE_1 edge 0 and 1 bisected */ {QUADRILATERAL,Q_CLOSE_1_0,RED_CLASS|GREEN_CLASS,3, {1,1,0,0,1},3+16, {{0,1},{1,2},{-1,-1},{-1,-1},{0,2}}, {{QUADRILATERAL,{0,4,8,3},{FO+0, 1, 2,FO+3},-1}, {QUADRILATERAL,{4,1,5,8},{FO+0,FO+1, 2, 0},-1}, {QUADRILATERAL,{8,5,2,3},{ 1,FO+1,FO+2, 0},-1}, {-1,{-1,-1,-1,-1},{-1,-1,-1,-1},-1}}}, /* Q_CLOSE_1 edge 1 and 2 bisected */ {QUADRILATERAL,Q_CLOSE_1_1,RED_CLASS|GREEN_CLASS,3, {0,1,1,0,1},6+16, {{-1,-1},{0,2},{1,3},{-1,-1},{0,3}}, {{QUADRILATERAL,{0,1,5,8},{FO+0,FO+1, 1, 2},-1}, {QUADRILATERAL,{8,5,2,6},{ 0,FO+1,FO+2, 2},-1}, {QUADRILATERAL,{0,8,6,3},{ 0, 1,FO+2,FO+3},-1}, {-1,{-1,-1,-1,-1},{-1,-1,-1,-1},-1}}}, /* Q_CLOSE_1 edge 2 and 3 bisected */ {QUADRILATERAL,Q_CLOSE_1_2,RED_CLASS|GREEN_CLASS,3, {0,0,1,1,1},12+16, {{-1,-1},{-1,-1},{1,3},{0,3},{0,2}}, {{QUADRILATERAL,{0,1,8,7},{FO+0, 1, 2,FO+3},-1}, {QUADRILATERAL,{8,1,2,6},{ 0,FO+1,FO+2, 2},-1}, {QUADRILATERAL,{7,8,6,3},{ 0, 1,FO+2,FO+3},-1}, {-1,{-1,-1,-1,-1},{-1,-1,-1,-1},-1}}}, /* Q_CLOSE_1 edge 0 and 3 bisected */ {QUADRILATERAL,Q_CLOSE_1_3,RED_CLASS|GREEN_CLASS,3, {1,0,0,1,1},9+16, {{0,1},{-1,-1},{-1,-1},{0,3},{0,2}}, {{QUADRILATERAL,{0,4,8,7},{FO+0, 1, 2,FO+3},-1}, {QUADRILATERAL,{4,1,2,8},{FO+0,FO+1, 2, 0},-1}, {QUADRILATERAL,{7,8,2,3},{ 0, 1,FO+2,FO+3},-1}, {-1,{-1,-1,-1,-1},{-1,-1,-1,-1},-1}}}, /* Q_BLUE edge 0 and 2 bisected */ {QUADRILATERAL,Q_BLUE_0,RED_CLASS|GREEN_CLASS,2, {1,0,1,0,0},5, {{0,1},{-1,-1},{0,2},{-1,-1},{-1,-1}}, {{QUADRILATERAL,{0,4,6,3},{FO+0, 1,FO+2,FO+3},-1}, {QUADRILATERAL,{4,1,2,6},{FO+0,FO+1,FO+2, 0},-1}, {-1,{-1,-1,-1,-1},{-1,-1,-1,-1},-1}, {-1,{-1,-1,-1,-1},{-1,-1,-1,-1},-1}}}, /* Q_BLUE edge 1 and 3 bisected */ {QUADRILATERAL,Q_BLUE_1,RED_CLASS|GREEN_CLASS,2, {0,1,0,1,0},10, {{-1,-1},{0,2},{-1,-1},{0,3},{-1,-1}}, {{QUADRILATERAL,{0,1,5,7},{FO+0,FO+1, 1,FO+3},-1}, {QUADRILATERAL,{7,5,2,3},{ 0,FO+1,FO+2,FO+3},-1}, {-1,{-1,-1,-1,-1},{-1,-1,-1,-1},-1}, {-1,{-1,-1,-1,-1},{-1,-1,-1,-1},-1}}}, /* Q_CLOSE_2 edge 0 bisected */ {QUADRILATERAL,Q_CLOSE_2_0,RED_CLASS|GREEN_CLASS,3, {1,0,0,0,1},1+16, {{0,1},{-1,-1},{-1,-1},{-1,-1},{0,2}}, {{QUADRILATERAL,{0,4,8,3},{FO+0, 1, 2,FO+3},-1}, {QUADRILATERAL,{4,1,2,8},{FO+0,FO+1, 2, 0},-1}, {TRIANGLE,{8,2,3,-1},{ 1,FO+2, 0,-1},-1}, {-1,{-1,-1,-1,-1},{-1,-1,-1,-1},-1}}}, /* Q_CLOSE_2 edge 1 bisected */ {QUADRILATERAL,Q_CLOSE_2_1,RED_CLASS|GREEN_CLASS,3, {0,1,0,0,1},2+16, {{-1,-1},{0,2},{-1,-1},{-1,-1},{0,3}}, {{QUADRILATERAL,{0,1,5,8},{FO+0,FO+1, 1, 2},-1}, {QUADRILATERAL,{8,5,2,3},{ 0,FO+1,FO+2, 2},-1}, {TRIANGLE,{0,8,3,-1},{ 0, 1,FO+3,-1},-1}, {-1,{-1,-1,-1,-1},{-1,-1,-1,-1},-1}}}, /* Q_CLOSE_2 edge 2 bisected */ {QUADRILATERAL,Q_CLOSE_2_2,RED_CLASS|GREEN_CLASS,3, {0,0,1,0,1},4+16, {{-1,-1},{-1,-1},{1,3},{-1,-1},{0,2}}, {{TRIANGLE,{0,1,8,-1},{FO+0, 1, 2,-1},-1}, {QUADRILATERAL,{8,1,2,6},{ 0,FO+1,FO+2, 2},-1}, {QUADRILATERAL,{0,8,6,3},{ 0, 1,FO+2,FO+3},-1}, {-1,{-1,-1,-1,-1},{-1,-1,-1,-1},-1}}}, /* Q_CLOSE_2 edge 3 bisected */ {QUADRILATERAL,Q_CLOSE_2_3,RED_CLASS|GREEN_CLASS,3, {0,0,0,1,1},8+16, {{-1,-1},{-1,-1},{-1,-1},{0,3},{0,2}}, {{QUADRILATERAL,{0,1,8,7},{FO+0, 1, 2,FO+3},-1}, {TRIANGLE,{1,2,8,-1},{FO+1, 2, 0,-1},-1}, {QUADRILATERAL,{7,8,2,3},{ 0, 1,FO+2,FO+3},-1}, {-1,{-1,-1,-1,-1},{-1,-1,-1,-1},-1}}}, /* Q_CLOSE_3 edge 0 not bisected */ {QUADRILATERAL,Q_CLOSE_3_0,RED_CLASS|GREEN_CLASS,4, {0,1,1,1,0},14, {{-1,-1},{0,2},{1,2},{0,3},{-1,-1}}, {{QUADRILATERAL,{0,1,5,7},{FO+0,FO+1, 1,FO+3},-1}, {TRIANGLE,{7,5,6,-1},{ 0, 2, 3,-1},-1}, {TRIANGLE,{5,2,6,-1},{FO+1,FO+2, 1,-1},-1}, {TRIANGLE,{7,6,3,-1},{ 1,FO+2,FO+3,-1},-1}}}, /* Q_CLOSE_3 edge 1 not bisected */ {QUADRILATERAL,Q_CLOSE_3_1,RED_CLASS|GREEN_CLASS,4, {1,0,1,1,0},13, {{0,1},{-1,-1},{1,2},{0,2},{-1,-1}}, {{TRIANGLE,{0,4,7,-1},{FO+0, 1,FO+3,-1},-1}, {TRIANGLE,{7,4,6,-1},{ 0, 3, 2,-1},-1}, {TRIANGLE,{7,6,3,-1},{ 1,FO+2,FO+3,-1},-1}, {QUADRILATERAL,{4,1,2,6},{FO+0,FO+1,FO+2, 1},-1}}}, /* Q_CLOSE_3 edge 2 not bisected */ {QUADRILATERAL,Q_CLOSE_3_2,RED_CLASS|GREEN_CLASS,4, {1,1,0,1,0},11, {{0,1},{2,2},{-1,-1},{0,2},{-1,-1}}, {{TRIANGLE,{0,4,7,-1},{FO+0, 1,FO+3,-1},-1}, {TRIANGLE,{4,5,7,-1},{ 2, 3, 0,-1},-1}, {TRIANGLE,{4,1,5,-1},{FO+0,FO+1, 1,-1},-1}, {QUADRILATERAL,{7,5,2,3},{ 1,FO+1,FO+2,FO+3},-1}}}, /* Q_CLOSE_3 edge 3 not bisected */ {QUADRILATERAL,Q_CLOSE_3_3,RED_CLASS|GREEN_CLASS,4, {1,1,1,0,0},7, {{0,1},{2,2},{0,2},{-1,-1},{-1,-1}}, {{QUADRILATERAL,{0,4,6,3},{FO+0, 1,FO+2,FO+3},-1}, {TRIANGLE,{4,5,6,-1},{ 2, 3, 0,-1},-1}, {TRIANGLE,{4,1,5,-1},{FO+0,FO+1, 1,-1},-1}, {TRIANGLE,{5,2,6,-1},{FO+1,FO+2, 1,-1},-1}}} }; #endif #ifdef UG_DIM_3 static INT theBFRRDirID; /* env type for BestFullRefRule */ static INT theBFRRVarID; #ifndef DUNE_UGGRID_TET_RULESET /* define the regular rules for tetrahedron */ [[maybe_unused]] static REFRULE TetrahedronRules[MAX_TET_RULES] = { /* TET_NO_REF */ {TETRAHEDRON,0,NO_CLASS,0, {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0},0, {{-1,-1},{-1,-1},{-1,-1},{-1,-1},{-1,-1},{-1,-1}, {-1,-1},{-1,-1},{-1,-1},{-1,-1},{-1,-1},{-1,-1}, {-1,-1},{-1,-1},{-1,-1},{-1,-1},{-1,-1},{-1,-1}, {-1,-1}}, {{-1,{-1,-1,-1,-1,-1,-1,-1,-1},{-1,-1,-1,-1,-1,-1},-1}, {-1,{-1,-1,-1,-1,-1,-1,-1,-1},{-1,-1,-1,-1,-1,-1},-1}, {-1,{-1,-1,-1,-1,-1,-1,-1,-1},{-1,-1,-1,-1,-1,-1},-1}, {-1,{-1,-1,-1,-1,-1,-1,-1,-1},{-1,-1,-1,-1,-1,-1},-1}, {-1,{-1,-1,-1,-1,-1,-1,-1,-1},{-1,-1,-1,-1,-1,-1},-1}, {-1,{-1,-1,-1,-1,-1,-1,-1,-1},{-1,-1,-1,-1,-1,-1},-1}, {-1,{-1,-1,-1,-1,-1,-1,-1,-1},{-1,-1,-1,-1,-1,-1},-1}, {-1,{-1,-1,-1,-1,-1,-1,-1,-1},{-1,-1,-1,-1,-1,-1},-1}, {-1,{-1,-1,-1,-1,-1,-1,-1,-1},{-1,-1,-1,-1,-1,-1},-1}, {-1,{-1,-1,-1,-1,-1,-1,-1,-1},{-1,-1,-1,-1,-1,-1},-1}, {-1,{-1,-1,-1,-1,-1,-1,-1,-1},{-1,-1,-1,-1,-1,-1},-1}}}, /* TET_COPY */ {TETRAHEDRON,1,YELLOW_CLASS,1, {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0},0, {{-1,-1},{-1,-1},{-1,-1},{-1,-1},{-1,-1},{-1,-1}, {-1,-1},{-1,-1},{-1,-1},{-1,-1},{-1,-1},{-1,-1}, {-1,-1},{-1,-1},{-1,-1},{-1,-1},{-1,-1},{-1,-1}, {-1,-1}}, {{TETRAHEDRON,{ 0, 1, 2, 3,-1,-1,-1,-1},{FO+0,FO+1,FO+2,FO+3,-1,-1},-1}, {-1,{-1,-1,-1,-1,-1,-1,-1,-1},{-1,-1,-1,-1,-1,-1},-1}, {-1,{-1,-1,-1,-1,-1,-1,-1,-1},{-1,-1,-1,-1,-1,-1},-1}, {-1,{-1,-1,-1,-1,-1,-1,-1,-1},{-1,-1,-1,-1,-1,-1},-1}, {-1,{-1,-1,-1,-1,-1,-1,-1,-1},{-1,-1,-1,-1,-1,-1},-1}, {-1,{-1,-1,-1,-1,-1,-1,-1,-1},{-1,-1,-1,-1,-1,-1},-1}, {-1,{-1,-1,-1,-1,-1,-1,-1,-1},{-1,-1,-1,-1,-1,-1},-1}, {-1,{-1,-1,-1,-1,-1,-1,-1,-1},{-1,-1,-1,-1,-1,-1},-1}, {-1,{-1,-1,-1,-1,-1,-1,-1,-1},{-1,-1,-1,-1,-1,-1},-1}, {-1,{-1,-1,-1,-1,-1,-1,-1,-1},{-1,-1,-1,-1,-1,-1},-1}, {-1,{-1,-1,-1,-1,-1,-1,-1,-1},{-1,-1,-1,-1,-1,-1},-1}, {-1,{-1,-1,-1,-1,-1,-1,-1,-1},{-1,-1,-1,-1,-1,-1},-1}}}, /* TET_RED equals TET_RED_2_4 */ {TETRAHEDRON,2,RED_CLASS|SWITCH_CLASS,8, {1,1,1,1,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0},(1<<6)-1, /* sonandnode */ {{0,1},{1,1},{0,2},{0,3},{1,2},{2,2}, {-1,-1},{-1,-1},{-1,-1},{-1,-1},{-1,-1},{-1,-1}, {-1,-1},{-1,-1},{-1,-1},{-1,-1},{-1,-1},{-1,-1}, {-1,-1}}, /* sons */ {{TETRAHEDRON,{0,4,6,7,-1,-1,-1,-1},{FO+0,4,FO+2,FO+3,-1,-1},0x0}, {TETRAHEDRON,{4,5,8,1,-1,-1,-1,-1},{5,FO+1,FO+3,FO+0,-1,-1}, 0x3<PI/2.0) { help = std::abs(Length[l]*(DOUBLE)(cos((double)Angle[l])/sin((double)Angle[l]))); Max = MAX(Max,help); } } for (k=0; k<2; k++) { for (l=0; l<2; l++) Corners[l] = MidPoints[SideEdgesOfEdge[j][k][l]]; if (TetAngleAndLength(theElement,Corners,Angle,Length)) return (FULL_REFRULE_0_5); for (i=0; iPI/2.0) { help = std::abs(Length[l]*(DOUBLE)(cos((double)Angle[l])/sin((double)Angle[l]))); Max = MAX(Max,help); } } if (MaxPI/2.0) sum += std::abs(Length[l]*(DOUBLE)cos((double)Angle[l])/(DOUBLE)sin((double)Angle[l])); } for (k=0; k<2; k++) { for (l=0; l<2; l++) Corners[l] = MidPoints[SideEdgesOfEdge[j][k][l]]; if (TetAngleAndLength(theElement,Corners,Angle,Length)) return (FULL_REFRULE_0_5); for (i=0; iPI/2.0) sum += std::abs(Length[l]*(DOUBLE)cos((double)Angle[l])/(DOUBLE)sin((double)Angle[l])); } if (sumMax) { Max = sprd; imin = i; } } INT refrule; switch (imin) { case -1 : refrule = ShortestInteriorEdge (theElement); UserWrite ("#"); break; case 0 : refrule = FULL_REFRULE_0_5; break; case 1 : refrule = FULL_REFRULE_1_3; break; case 2 : refrule = FULL_REFRULE_2_4; break; } return (refrule); } /****************************************************************************/ /** \brief MaxRightAngle - compute best full refined refrule for the element SYNOPSIS: static INT MaxRightAngle (ELEMENT *theElement); PARAMETERS: \param theElement - for that element DESCRIPTION: This function computes the best full refined refrule for the element: optimal laplace-disc w.r.t. M-Matrix eigenschaft \return INT .n Mark: number of refrule */ /****************************************************************************/ static INT MaxRightAngle (ELEMENT *theElement) { DOUBLE *Corners[MAX_CORNERS_OF_ELEM]; /* get physical position of the corners */ for (INT i=0; iMax) { Max = norm; imin = i; } } INT refrule; switch (imin) { case -1 : refrule = ShortestInteriorEdge (theElement); UserWrite ("#"); break; case 0 : refrule = FULL_REFRULE_0_5; break; case 1 : refrule = FULL_REFRULE_1_3; break; case 2 : refrule = FULL_REFRULE_2_4; break; } return (refrule); } #endif /* UG_DIM_3 */ /****************************************************************************/ /** \brief Mark an element for refinement \param theElement - Element to be refined \param rule - type of refinement mark This function marks an element for refinement \return
                                                      • 1 if element has been marked
                                                      • 0 if element cannot be marked
                                                      */ /****************************************************************************/ INT NS_DIM_PREFIX MarkForRefinement (ELEMENT *theElement, enum RefinementRule rule, INT side) { if (theElement == NULL) return(0); #ifdef ModelP if (EGHOST(theElement)) return(0); #endif SETCOARSEN(theElement,0); if (rule != COARSE) theElement = ELEMENT_TO_MARK(theElement); ASSERT(theElement!=NULL); PRINTDEBUG(gm,4,("MarkForRefinement() e=" EID_FMTX "rule=%d\n", EID_PRTX(theElement),rule)) /* choose dimension */ switch (DIM) { #ifdef UG_DIM_2 /* 2D case */ case (2) : switch (TAG(theElement)) { case (TRIANGLE) : switch (rule) { case COARSE : SETCOARSEN(theElement,1); SETMARK(theElement,NO_REFINEMENT); SETMARKCLASS(theElement,0); break; case NO_REFINEMENT : SETMARK(theElement,NO_REFINEMENT); SETMARKCLASS(theElement,0); break; case COPY : SETMARK(theElement,T_COPY); SETMARKCLASS(theElement,RED_CLASS); break; case RED : SETMARK(theElement,T_RED); SETMARKCLASS(theElement,RED_CLASS); break; /* TODO: these marks must be introduced first case BISECTION_3: if (side<0) return (GM_ERROR); SETMARK(theElement,TRI_BISECT_3+side%3); SETMARKCLASS(theElement,RED_CLASS); break; case BISECTION_1: if (side<0) return (GM_ERROR); SETMARK(theElement,TRI_BISECT_1+side%3); SETMARKCLASS(theElement,RED_CLASS); break; case BISECTION_2_Q: if (side<0) return (GM_ERROR); SETMARK(theElement,TRI_BISECT_2_Q+side%3); SETMARKCLASS(theElement,RED_CLASS); break; case BISECTION_2_T1: if (side<0) return (GM_ERROR); SETMARK(theElement,TRI_BISECT_2_T1+side%3); SETMARKCLASS(theElement,RED_CLASS); break; case BISECTION_2_T2: if (side<0) return (GM_ERROR); SETMARK(theElement,TRI_BISECT_2_T2+side%3); SETMARKCLASS(theElement,RED_CLASS); break; */ default : return(GM_ERROR); } break; case (QUADRILATERAL) : switch (rule) { case COARSE : SETCOARSEN(theElement,1); SETMARKCLASS(theElement,0); SETMARK(theElement,NO_REFINEMENT); break; case NO_REFINEMENT : SETMARK(theElement,NO_REFINEMENT); SETMARKCLASS(theElement,0); break; case COPY : SETMARK(theElement,Q_COPY); SETMARKCLASS(theElement,RED_CLASS); break; case RED : SETMARK(theElement,Q_RED); SETMARKCLASS(theElement,RED_CLASS); break; /* TODO: these mark must be introduced first */ case BLUE : if (side<0) return (GM_ERROR); if (side%2 == 0) SETMARK(theElement,Q_BLUE_0); else SETMARK(theElement,Q_BLUE_1); SETMARKCLASS(theElement,RED_CLASS); break; default : return(GM_ERROR); } break; default : return(GM_ERROR); } break; #endif /* UG_DIM_2 */ #ifdef UG_DIM_3 /* 3D case */ case (3) : switch (TAG(theElement)) { case (TETRAHEDRON) : switch(rule) { case (COARSE) : SETMARK(theElement,NO_REFINEMENT); SETMARKCLASS(theElement,0); SETCOARSEN(theElement,1); break; case (NO_REFINEMENT) : SETMARK(theElement,NO_REFINEMENT); SETMARKCLASS(theElement,0); break; case (COPY) : SETMARK(theElement,TET_COPY); SETMARKCLASS(theElement,RED_CLASS); break; case (RED) : SETMARK(theElement,(*theFullRefRule)(theElement)); SETMARKCLASS(theElement,RED_CLASS); break; #ifndef DUNE_UGGRID_TET_RULESET case (TETRA_RED_HEX) : SETMARK(theElement,TET_RED_HEX); SETMARKCLASS(theElement,RED_CLASS); break; #endif default : return(GM_ERROR); } break; case (PYRAMID) : switch(rule) { case (COARSE) : SETMARK(theElement,NO_REFINEMENT); SETMARKCLASS(theElement,0); SETCOARSEN(theElement,1); break; case (NO_REFINEMENT) : SETMARK(theElement,NO_REFINEMENT); SETMARKCLASS(theElement,0); break; case (COPY) : SETMARK(theElement,PYR_COPY); SETMARKCLASS(theElement,RED_CLASS); break; case (RED) : SETMARK(theElement,PYR_RED); SETMARKCLASS(theElement,RED_CLASS); break; default : return(GM_ERROR); } break; case (PRISM) : switch(rule) { case (COARSE) : SETMARK(theElement,NO_REFINEMENT); SETMARKCLASS(theElement,0); SETCOARSEN(theElement,1); break; case (NO_REFINEMENT) : SETMARK(theElement,NO_REFINEMENT); SETMARKCLASS(theElement,0); break; case (COPY) : SETMARK(theElement,PRI_COPY); SETMARKCLASS(theElement,RED_CLASS); break; case (RED) : SETMARKCLASS(theElement,RED_CLASS); #ifdef __ANISOTROPIC__ { INT newrule; if (GetRule_AnisotropicRed(theElement,&newrule)) { SETMARK(theElement,newrule); break; } } #endif SETMARK(theElement,PRI_RED); break; case (PRISM_BISECT_1_2) : SETMARK(theElement,PRI_BISECT_1_2); SETMARKCLASS(theElement,RED_CLASS); break; case (PRISM_QUADSECT) : SETMARK(theElement,PRI_QUADSECT); SETMARKCLASS(theElement,RED_CLASS); break; case (PRISM_BISECT_HEX0) : SETMARK(theElement,PRI_BISECT_HEX0); SETMARKCLASS(theElement,RED_CLASS); break; case (PRISM_BISECT_HEX1) : SETMARK(theElement,PRI_BISECT_HEX1); SETMARKCLASS(theElement,RED_CLASS); break; case (PRISM_BISECT_HEX2) : SETMARK(theElement,PRI_BISECT_HEX2); SETMARKCLASS(theElement,RED_CLASS); break; case (PRISM_ROTATE_LEFT) : SETMARK(theElement,PRI_ROT_L); SETMARKCLASS(theElement,RED_CLASS); break; case (PRISM_ROTATE_RGHT) : SETMARK(theElement,PRI_ROT_R); SETMARKCLASS(theElement,RED_CLASS); break; case (PRISM_QUADSECT_HEXPRI0) : SETMARK(theElement,PRI_QUADSECT_HEXPRI0); SETMARKCLASS(theElement,RED_CLASS); break; case (PRISM_BISECT_0_1) : SETMARK(theElement,PRI_BISECT_0_1); SETMARKCLASS(theElement,RED_CLASS); break; case (PRISM_BISECT_0_2) : SETMARK(theElement,PRI_BISECT_0_2); SETMARKCLASS(theElement,RED_CLASS); break; case (PRISM_BISECT_0_3) : SETMARK(theElement,PRI_BISECT_0_3); SETMARKCLASS(theElement,RED_CLASS); break; default : return(GM_ERROR); } break; case (HEXAHEDRON) : switch(rule) { case (COARSE) : SETMARK(theElement,NO_REFINEMENT); SETMARKCLASS(theElement,0); SETCOARSEN(theElement,1); break; case (NO_REFINEMENT) : SETMARK(theElement,NO_REFINEMENT); SETMARKCLASS(theElement,0); break; case (COPY) : SETMARK(theElement,HEXA_COPY); SETMARKCLASS(theElement,RED_CLASS); break; case (RED) : SETMARK(theElement,HEXA_RED); SETMARKCLASS(theElement,RED_CLASS); break; case (HEX_BISECT_0_1) : SETMARK(theElement,HEXA_BISECT_0_1); SETMARKCLASS(theElement,RED_CLASS); break; case (HEX_BISECT_0_2) : SETMARK(theElement,HEXA_BISECT_0_2); SETMARKCLASS(theElement,RED_CLASS); break; case (HEX_BISECT_0_3) : SETMARK(theElement,HEXA_BISECT_0_3); SETMARKCLASS(theElement,RED_CLASS); break; case (HEX_TRISECT_0) : SETMARK(theElement,HEXA_TRISECT_0); SETMARKCLASS(theElement,RED_CLASS); break; case (HEX_TRISECT_5) : SETMARK(theElement,HEXA_TRISECT_5); SETMARKCLASS(theElement,RED_CLASS); break; case (HEX_QUADSECT_0) : SETMARK(theElement,HEXA_QUADSECT_0); SETMARKCLASS(theElement,RED_CLASS); break; case (HEX_QUADSECT_1) : SETMARK(theElement,HEXA_QUADSECT_1); SETMARKCLASS(theElement,RED_CLASS); break; case (HEX_QUADSECT_2) : SETMARK(theElement,HEXA_QUADSECT_2); SETMARKCLASS(theElement,RED_CLASS); break; case (HEX_BISECT_HEXPRI0) : SETMARK(theElement,HEXA_BISECT_HEXPRI0); SETMARKCLASS(theElement,RED_CLASS); break; case (HEX_BISECT_HEXPRI1) : SETMARK(theElement,HEXA_BISECT_HEXPRI1); SETMARKCLASS(theElement,RED_CLASS); break; default : return(GM_ERROR); } break; default : return(GM_ERROR); } break; #endif /* UG_DIM_3 */ default : return(GM_ERROR); } return(GM_OK); } /****************************************************************************/ /** \brief Return true when element can be tagged for refinement \param theElement - element to refine This function returns true (1) when element can be tagged for refinement \return
                                                      • false - do not tag element
                                                      • true - element can be tagged for refinement
                                                      */ /****************************************************************************/ INT NS_DIM_PREFIX EstimateHere (const ELEMENT *theElement) { #ifdef ModelP if (EGHOST(theElement)) return(0); #endif return(LEAFELEM(theElement)); } /****************************************************************************/ /** \brief Return mark of rule for a specific pattern \param theElement - element rule is searched for \param pattern: pattern a rule is searched for This function returns mark of rule for a specific pattern \return Mark rule; values of the unnamed enums in the file rm.h mark of rule */ /****************************************************************************/ INT NS_DIM_PREFIX Patterns2Rules(ELEMENT *theElement, INT pattern) { #ifdef UG_DIM_2 switch (TAG(theElement)) { case (TRIANGLE) : switch (pattern) { /** \todo 0 can mean T_COPY OR T_NOREF */ case (0) : return(T_NOREF); case (1) : return(T_BISECT_1_0); case (2) : return(T_BISECT_1_1); case (3) : return(T_BISECT_2_T1_2); case (4) : return(T_BISECT_1_2); case (5) : return(T_BISECT_2_T1_1); case (6) : return(T_BISECT_2_T1_0); case (7) : return(T_RED); default : assert(0); PrintErrorMessage('E',"Patterns2Rules","no mapping for TRIANGLE and this pattern!"); return(-1); } break; case (QUADRILATERAL) : switch (pattern) { /** \todo 0 can mean Q_COPY OR Q_NOREF */ case (0) : return(Q_NOREF); case (5) : return(Q_BLUE_0); case (7) : return(Q_CLOSE_3_3); case (10) : return(Q_BLUE_1); case (11) : return(Q_CLOSE_3_2); case (13) : return(Q_CLOSE_3_1); case (14) : return(Q_CLOSE_3_0); case (1) : /* mapping for green closure */ case (17) : return(Q_CLOSE_2_0); case (2) : /* mapping for green closure */ case (18) : return(Q_CLOSE_2_1); case (3) : /* mapping for green closure */ case (19) : return(Q_CLOSE_1_0); case (4) : /* mapping for green closure */ case (20) : return(Q_CLOSE_2_2); case (6) : /* mapping for green closure */ case (22) : return(Q_CLOSE_1_1); case (8) : /* mapping for green closure */ case (24) : return(Q_CLOSE_2_3); case (9) : /* mapping for green closure */ case (25) : return(Q_CLOSE_1_3); case (12) : /* mapping for green closure */ case (28) : return(Q_CLOSE_1_2); case (15) : /* mapping for green closure */ case (31) : return(Q_RED); default : assert(0); PrintErrorMessage('E',"Patterns2Rules","no mapping for QUADRILATERAL and this pattern!"); return(-1); } break; default : PrintErrorMessage('E',"Patterns2Rules","Elementtype not found!"); assert(0); return(-1); } #endif #ifdef UG_DIM_3 switch (TAG(theElement)) { case (TETRAHEDRON) : #ifdef DUNE_UGGRID_TET_RULESET /* convert pattern to old style */ pattern &= (~(1<<10)); IFDEBUG(gm,0) int tetrarule; if (pattern<0 || pattern>1023) PRINTDEBUG(gm,0,("Pattern2Rule(): ERROR elem=" EID_FMTX " pattern=%d\n",EID_PRTX(theElement),pattern)) assert(pattern>=0 && pattern<=1023); tetrarule = Pattern2Rule[TAG(theElement)][pattern]; if (tetrarule<0 || tetrarule>MaxRules[TETRAHEDRON]) PRINTDEBUG(gm,0,("Pattern2Rule(): ERROR elem=" EID_FMTX " pattern=%d rule=%d\n",EID_PRTX(theElement),pattern,tetrarule)) assert(tetrarule>=0 && tetrarule<=MaxRules[TETRAHEDRON]); ENDDEBUG return(Pattern2Rule[TAG(theElement)][pattern]); #else if (MARKCLASS(theElement) != RED_CLASS) return(0); switch (pattern) { /* copy rule */ case (0) : return(0); case (63) : return(TET_RED); case (1023) : return(TET_RED_HEX); default : PrintErrorMessage('E',"Patterns2Rules","no mapping for TETRAHEDRON and this pattern!"); assert(0); return(-1); } break; #endif case (PYRAMID) : if (MARKCLASS(theElement) != RED_CLASS) return(0); switch (pattern) { /* copy rule */ case (0) : return(0); case (511) : return(PYR_RED); default : PrintErrorMessage('E',"Patterns2Rules","no mapping for PYRAMID and this pattern!"); assert(0); return(-1); } break; case (PRISM) : if (MARKCLASS(theElement) != RED_CLASS) return(0); switch (pattern) { /* copy rule */ case (0) : return(0); case (7679) : return(PRI_RED); case (455) : return(PRI_QUADSECT); case 56 : return PRI_BISECT_1_2; case 65 : return PRI_BISECT_0_1; case 130 : return PRI_BISECT_0_2; case 260 : return PRI_BISECT_0_3; case 325 : return PRI_BISECT_HEX0; case 195 : return PRI_BISECT_HEX1; case 390 : return PRI_BISECT_HEX2; default : PrintErrorMessageF('E',"Patterns2Rules","no mapping for PRISM and pattern %d!", pattern); #ifndef __ANISOTROPIC__ assert(0); #endif return(-1); } break; case (HEXAHEDRON) : if (MARKCLASS(theElement) != RED_CLASS) return(0); switch (pattern) { /* copy rule */ case (0) : return(0); /* full red rule */ case (262143) : return(HEXA_RED); case (1285) : return HEXA_BISECT_0_1; case (2570) : return HEXA_BISECT_0_2; case (240) : return HEXA_BISECT_0_3; case (139023) : return HEXA_QUADSECT_0; case (42485) : return HEXA_QUADSECT_1; case (84730) : return HEXA_QUADSECT_2; case (5) : return HEXA_TRISECT_0; case (1280) : return HEXA_TRISECT_5; case (2056) : return HEXA_BISECT_HEXPRI0; case (257) : return HEXA_BISECT_HEXPRI1; default : PrintErrorMessage('E',"Patterns2Rules","no mapping for HEXAHEDRON and this pattern!"); UserWriteF("pattern=%d\n",pattern); assert(0); return(-1); } break; default : PrintErrorMessage('E',"Patterns2Rules","Elementtype not found!"); assert(0); return(-1); } #endif PrintErrorMessage('E',"Patterns2Rules","Elementtype not found!"); assert(0); return(-1); } /****************************************************************************/ /** \brief Gets the element which has to be marked \param MarkElement - element to be estimated This function gets the element which has to be marked \return
                                                      • first element downward with class RED_CLASS
                                                      • NULL if MarkElement was no surface element
                                                      */ /****************************************************************************/ ELEMENT * NS_DIM_PREFIX ELEMENT_TO_MARK (ELEMENT *theElement) { if (IS_REFINED(theElement)) return(NULL); PRINTDEBUG(gm,4,("ELEMENT_TO_MARK() called for e=" EID_FMTX "\n", EID_PRTX(theElement))) while (ECLASS(theElement) != RED_CLASS) { theElement = EFATHER(theElement); ASSERT(theElement != NULL); } return(theElement); } /****************************************************************************/ /** \brief Gets rule of refinement \param theElement - element to refine \param rule - filled with current refinement rule \param data - filled with side, if rule is oriented This function gets rule of refinement \return .n 0: side information valid .n 1: rule without orientation */ /****************************************************************************/ INT NS_DIM_PREFIX GetRefinementMark (ELEMENT *theElement, INT *rule, void *data) { INT *side = (INT*)data; INT mark; if (LEAFELEM(theElement) && ECLASS(theElement) != RED_CLASS) theElement = ELEMENT_TO_MARK(theElement); ASSERT(theElement != NULL); if (!((ECLASS(theElement) == RED_CLASS) && (REFINECLASS(theElement) != RED_CLASS))) { printf("GetRefinementMark: eclass=%d refineclass=%d\n", ECLASS(theElement),REFINECLASS(theElement)); return(-1); } mark = MARK(theElement); #if defined(UG_DIM_3) /* tetrahedra have three red rules */ if (TAG(theElement)==TETRAHEDRON && (mark==TET_RED_2_4 || mark==TET_RED_0_5 || mark==TET_RED_1_3)) { *rule=RED; return(GM_RULE_WITHOUT_ORIENTATION); } #endif switch (mark) { case RED : *rule=RED; break; #ifdef UG_DIM_2 case Q_BLUE_0 : *rule = BLUE; break; case Q_BLUE_1 : *rule = BLUE; break; #endif case NO_REFINEMENT : *rule=NO_REFINEMENT; if (COARSEN(theElement)) *rule = COARSE; break; case COPY : *rule=COPY; break; default : *rule=NO_REFINEMENT; break; } *side=0; return(GM_RULE_WITHOUT_ORIENTATION); } /****************************************************************************/ /** \brief GetRefinementMarkType - gets type of mark for an element SYNOPSIS: INT GetRefinementMarkType (ELEMENT *theElement); PARAMETERS: \param theElement - element to refine DESCRIPTION: This function gets the type of mark for an element \return INT .n 0 if element is not marked .n 1 if element is marked for refinement .n -1 if element is marked for coarsening */ /****************************************************************************/ INT NS_DIM_PREFIX GetRefinementMarkType (ELEMENT *theElement) { INT rule; INT side; if (GetRefinementMark(theElement,&rule,&side) == -1) RETURN(GM_ERROR); switch (rule) { case RED : #ifdef UG_DIM_2 case BLUE : #endif return(1); case COPY : case NO_REFINEMENT : return(0); case COARSE : return(-1); default : assert(0); } return(0); } /****************************************************************************/ /* PrintSonData - SYNOPSIS: static INT PrintSonData(struct sondata theSonData); PARAMETERS: \param theSonData DESCRIPTION: \return INT */ /****************************************************************************/ static INT PrintSonData (struct sondata theSonData, PrintfProcPtr Printf) { char buffer[128]; int i,j; int path = theSonData.path; int pd = PATHDEPTH(path); Printf("tag=%d ",(int)theSonData.tag); j = 0; j = snprintf(buffer,128," corners="); for (i=0; icorners_of_elem; i++) { j += snprintf(buffer+j,128-j,"%2d ",(int)theSonData.corners[i]); } Printf(buffer); j = 0; j += snprintf(buffer,128," nb="); for (i=0; isides_of_elem; i++) { j += snprintf(buffer+j,128-j,"%2d ",(int)theSonData.nb[i]); } Printf(buffer); Printf(" path of depth %d=",pd); /*for (i=8*sizeof(INT)-1; i>=0; i--) { snprintf(buffer,128,"%d",(int)((theSonData.path>>i) & 0x1)); if (i%2 == 0 && theSonData.tag == TETRAHEDRON) sprintf(buffer+1," "); if (i%3 == 0 && theSonData.tag == HEXAHEDRON) sprintf(buffer+1," "); Printf(buffer); }*/ if (pd>=MAX_PATH_DEPTH) Printf(" ERROR: path depth > MAX_PATH_DEPTH"); else for (j=0; jtag,(int)theRule->mark,(int)theRule->rclass,(int)theRule->nsons); /* pattern */ Printf(" pattern= "); for (i=0; i<(element_descriptors[tag]->edges_of_elem+element_descriptors[tag]->sides_of_elem+1); i++) Printf("%2d ",(int)theRule->pattern[i]); Printf("\n"); /* pat */ Printf(" pat = "); for (i=0; i<(element_descriptors[tag]->edges_of_elem+element_descriptors[tag]->sides_of_elem+1); i++) Printf("%2d ",(int)((theRule->pat>>i) & 0x1)); Printf("\n"); /* sonandnode */ for (i=0; isonandnode[i][0]); Printf(" [%2d][1]=%2d\n",i,(int)theRule->sonandnode[i][1]); } Printf("\n"); /* print edge data Printf(" Edge data\n"); for (i=0; iedges[i]); if (i%2 == 1) Printf("\n"); } Printf("\n");*/ /* print sondata data */ Printf(" Son data\n"); for (i=0; i<(int)theRule->nsons; i++) { Printf(" son %2d: ",i); PrintSonData(theRule->sons[i],Printf); Printf("\n"); } return (0); } INT NS_DIM_PREFIX ShowRefRule (INT tag, INT nb) { return (ShowRefRuleX(tag,nb,UserWriteF)); } #ifdef UG_DIM_3 /****************************************************************************/ /** \brief InitRuleManager3D - Read the rule data set and initialize the rules This function reads the rule data set and initializes the rules data structure for tetrahedrons. Initializes the regular refinement rules (red rules) for hexahedrons. Irregular refinement of green closure is done algorithmically. \return .n 0 if ok .n >0 if an error occurs */ /****************************************************************************/ #ifdef DUNE_UGGRID_TET_RULESET # include "RefRules.cc" #endif static INT InitRuleManager3D (void) { FULLREFRULE *newFRR; int nRules; /* now make rules for tetrahedrons globally available */ MaxNewCorners[TETRAHEDRON] = 11; MaxNewEdges[TETRAHEDRON] = 16; CenterNodeIndex[TETRAHEDRON] = 10; #ifdef DUNE_UGGRID_TET_RULESET RefRules[TETRAHEDRON] = tetrahedronRefinementRules; MaxRules[TETRAHEDRON] = nTetrahedronRefinementRules; Pattern2Rule[TETRAHEDRON] = pattern2RuleTetrahedron; #else RefRules[TETRAHEDRON] = TetrahedronRules; MaxRules[TETRAHEDRON] = MAX_TET_RULES; #endif /************************************************************************/ /* */ /* init refinement rules from for pyramids */ /* */ /************************************************************************/ nRules = MAX_PYR_RULES; /* make rules for pyramids globally available */ MaxRules[PYRAMID] = nRules; MaxNewCorners[PYRAMID] = 19; MaxNewEdges[PYRAMID] = 54; CenterNodeIndex[PYRAMID] = 18; RefRules[PYRAMID] = PyramidRules; /************************************************************************/ /* */ /* init refinement rules for prisms */ /* */ /************************************************************************/ nRules = MAX_PRI_RULES; /* make rules for prisms globally available */ MaxRules[PRISM] = nRules; MaxNewCorners[PRISM] = 19; MaxNewEdges[PRISM] = 54; CenterNodeIndex[PRISM] = 18; RefRules[PRISM] = PrismRules; /************************************************************************/ /* */ /* init refinement rules from for hexahedrons */ /* */ /************************************************************************/ nRules = MAX_HEX_RULES; /* make rules for tetrahedrons globally available */ MaxRules[HEXAHEDRON] = nRules; MaxNewCorners[HEXAHEDRON] = 19; MaxNewEdges[HEXAHEDRON] = 54; CenterNodeIndex[HEXAHEDRON] = 18; RefRules[HEXAHEDRON] = HexahedronRules; /************************************************************************/ /* */ /* install best full refrules for tetrahedrons */ /* */ /************************************************************************/ /* install the /Menu directory */ if (ChangeEnvDir("/")==NULL) { PrintErrorMessage('F',"InitRuleManager3D","could not changedir to root"); return(__LINE__); } theBFRRDirID = GetNewEnvDirID(); if (MakeEnvItem("best full refrule",theBFRRDirID,sizeof(ENVDIR))==NULL) { PrintErrorMessage('F',"InitRuleManager3D","could not install '/best full refrule' dir"); return(__LINE__); } if (ChangeEnvDir("/best full refrule")==NULL) return(__LINE__); theBFRRVarID = GetNewEnvVarID(); newFRR = (FULLREFRULE *) MakeEnvItem("shortestie",theBFRRVarID,sizeof(FULLREFRULE)); if (newFRR==NULL) return(__LINE__); newFRR->theFullRefRule = ShortestInteriorEdge; newFRR = (FULLREFRULE *) MakeEnvItem("maxper",theBFRRVarID,sizeof(FULLREFRULE)); if (newFRR==NULL) return(__LINE__); newFRR->theFullRefRule = MaxPerpendicular; newFRR = (FULLREFRULE *) MakeEnvItem("mra",theBFRRVarID,sizeof(FULLREFRULE)); if (newFRR==NULL) return(__LINE__); newFRR->theFullRefRule = MaxRightAngle; newFRR = (FULLREFRULE *) MakeEnvItem("maxarea",theBFRRVarID,sizeof(FULLREFRULE)); if (newFRR==NULL) return(__LINE__); newFRR->theFullRefRule = MaxArea; #ifdef __ALLRULES__ newFRR = (FULLREFRULE *) MakeEnvItem("minangle",theBFRRVarID,sizeof(FULLREFRULE)); if (newFRR==NULL) return(__LINE__); newFRR->theFullRefRule = MinimalSideAngle; newFRR = (FULLREFRULE *) MakeEnvItem("bestm",theBFRRVarID,sizeof(FULLREFRULE)); if (newFRR==NULL) return(__LINE__); newFRR->theFullRefRule = BestLaplaceMMatrix; newFRR = (FULLREFRULE *) MakeEnvItem("minentry",theBFRRVarID,sizeof(FULLREFRULE)); if (newFRR==NULL) return(__LINE__); newFRR->theFullRefRule = MinimalSideEntry; #endif /* default full refrule */ theFullRefRule = ShortestInteriorEdge; UserWrite("3D RefRules installed\n"); return (GM_OK); } #endif /* UG_DIM_3 */ #ifdef UG_DIM_2 /****************************************************************************/ /** \brief InitRuleManager2D - Initializes rules for triangles and quadrilaterals SYNOPSIS: static INT InitRuleManager2D (void); PARAMETERS: . void DESCRIPTION: This function initializes rules for triangles and quadrilaterals \return INT .n 0 - ok .n >0 - error */ /****************************************************************************/ static INT InitRuleManager2D (void) { /************************************************************************/ /* */ /* init refinement rules for triangles */ /* */ /************************************************************************/ /* there are 8 = 2^3 different patterns */ /* but why is there a 17 here? probably could be 8... */ static const SHORT pattern2RuleTriangle[17] = { /* 0: */ T_COPY, /* 0 0 0 */ /* 1: */ T_BISECT_1_0, /* 0 0 1 */ /* 2: */ T_BISECT_1_1, /* 0 1 0 */ /* 3: */ T_BISECT_2_T1_0, /* 0 1 1 */ /* 4: */ T_BISECT_1_2, /* 1 0 0 */ /* 5: */ NOINDEX, /* 1 0 1 */ /* 6: */ NOINDEX, /* 1 1 0 */ /* 7: */ T_RED, /* 1 1 1 */ }; Pattern2Rule[TRIANGLE] = pattern2RuleTriangle; /* Pattern2Rule gives the starting index for rules with same pattern */ /* now make rules for triangles globally available */ MaxRules[TRIANGLE] = MAX_TRI_RULES; MaxNewCorners[TRIANGLE] = 3; MaxNewEdges[TRIANGLE] = 9; CenterNodeIndex[TRIANGLE] = 4; RefRules[TRIANGLE] = TriangleRules; /************************************************************************/ /* */ /* init refinement rules for quadrilaterals */ /* */ /************************************************************************/ /* there are 32 = 2^5 different patterns */ static const SHORT pattern2RuleQuadrilateral[32] = { /* Pattern2Rule gives the starting index for rules with same pattern */ /* 0: */ NOINDEX, /* 0 0 0 0 0 */ /* 1: */ NOINDEX, /* 0 0 0 0 1 */ /* 2: */ NOINDEX, /* 0 0 0 1 0 */ /* 3: */ NOINDEX, /* 0 0 0 1 1 */ /* 4: */ NOINDEX, /* 0 0 1 0 0 */ /* 5: */ NOINDEX, /* 0 0 1 0 1 */ /* 6: */ NOINDEX, /* 0 0 1 1 0 */ /* 7: */ NOINDEX, /* 0 0 1 1 1 */ /* 8: */ NOINDEX, /* 0 1 0 0 0 */ /* 9: */ NOINDEX, /* 0 1 0 0 1 */ /* 10: */ NOINDEX, /* 0 1 0 1 0 */ /* 11: */ NOINDEX, /* 0 1 0 1 1 */ /* 12: */ NOINDEX, /* 0 1 1 0 0 */ /* 13: */ NOINDEX, /* 0 1 1 0 1 */ /* 14: */ NOINDEX, /* 0 1 1 1 0 */ /* 15: */ NOINDEX, /* 0 1 1 1 1 */ /* 16: */ NOINDEX, /* 1 0 0 0 0 */ /* 17: */ NOINDEX, /* 1 0 0 0 1 */ /* 18: */ NOINDEX, /* 1 0 0 1 0 */ /* 19: */ NOINDEX, /* 1 0 0 1 1 */ /* 20: */ NOINDEX, /* 1 0 1 0 0 */ /* 21: */ NOINDEX, /* 1 0 1 0 1 */ /* 22: */ NOINDEX, /* 1 0 1 1 0 */ /* 23: */ NOINDEX, /* 1 0 1 1 1 */ /* 24: */ NOINDEX, /* 1 1 0 0 0 */ /* 25: */ NOINDEX, /* 1 1 0 0 1 */ /* 26: */ NOINDEX, /* 1 1 0 1 0 */ /* 27: */ NOINDEX, /* 1 1 0 1 1 */ /* 28: */ NOINDEX, /* 1 1 1 0 0 */ /* 29: */ NOINDEX, /* 1 1 1 0 1 */ /* 30: */ NOINDEX, /* 1 1 1 1 0 */ /* 31: */ Q_RED, /* 1 1 1 1 1 */ }; Pattern2Rule[QUADRILATERAL] = pattern2RuleQuadrilateral; /* now make rules for quadrilaterals globally available */ MaxRules[QUADRILATERAL] = MAX_QUA_RULES; MaxNewCorners[QUADRILATERAL] = 4; MaxNewEdges[QUADRILATERAL] = 12; CenterNodeIndex[QUADRILATERAL] = 4; RefRules[QUADRILATERAL] = QuadrilateralRules; return (GM_OK); } #endif /* UG_DIM_2 */ /****************************************************************************/ /** \brief InitRuleManager Initialize the 2- or 3D rule set This function initialize the 2- or 3D rule set */ /****************************************************************************/ INT NS_DIM_PREFIX InitRuleManager (void) { INT err; /* init 2- or 3D rulemanager */ if ((err=CONCAT(InitRuleManager,DIM,D) ()) != GM_OK) { SetHiWrd(err,__LINE__); return(err); } return (0); } dune-uggrid-2.11.0+dfsg/dune/uggrid/gm/rm.h000066400000000000000000000413531513616443000203430ustar00rootroot00000000000000// -*- tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- // vi: set et ts=4 sw=2 sts=2: // SPDX-FileCopyrightInfo: Copyright © DUNE Project contributors, see file LICENSE.md in module root // SPDX-License-Identifier: LGPL-2.1-or-later /*! \file rm.h * \ingroup gm */ /****************************************************************************/ /* */ /* File: rule manager header file */ /* */ /* Purpose: defines data structures for refinement rules */ /* */ /* Author: Stefan Lang */ /* Institut fuer Computeranwendungen III */ /* Universitaet Stuttgart */ /* Pfaffenwaldring 27 */ /* 70550 Stuttgart */ /* */ /* History: 20.11.95 begin, ugp version 3.0 */ /* */ /* Remarks: */ /* */ /****************************************************************************/ /****************************************************************************/ /* */ /* auto include mechanism and other include files */ /* */ /****************************************************************************/ #ifndef __RULEMANAGER__ #define __RULEMANAGER__ #include #include "gm.h" #include "refine.h" #include START_UGDIM_NAMESPACE /****************************************************************************/ /* */ /* defines in the following order */ /* */ /* compile time constants defining static data size (i.e. arrays) */ /* other constants */ /* macros */ /* */ /****************************************************************************/ /* Declaration of DUNE_UGGRID_TET_RULESET has been moved to config.h */ /* uncomment this if you want to use the full rule set for tetrahedra */ /** \brief Defines for edge types */ enum {INNER_EDGE = 1, SIDE_EDGE = 2, HALF_FATHER_EDGE = 3, FATHER_EDGE = 4}; #define NEXTSIDEMASKHEX 0x00000007 #define NEXTSIDEHEX(i,n) (((i) & (NEXTSIDEMASKHEX<<(3*(n))))>>(3*(n))) #define FATHER_SIDE_OFFSET 100 /* greater values indicate outside faces */ #define MAX_NEW_CORNERS(tag) MaxNewCorners[(tag)] /* midpoints on edges and sides plus center */ #define MAX_NEW_EDGES(tag) MaxNewEdges[(tag)] /* maximal new edges of type 1/2 */ #define MAX_RULES(tag) MaxRules[(tag)] /* number of rules for one element type */ #define CENTER_NODE_INDEX(e) CenterNodeIndex[TAG(e)] /* index of centernode in sonandnode and elemcontext */ #define CENTER_NODE_INDEX_TAG(t) CenterNodeIndex[(t)] /* index of centernode in sonandnode and elemcontext */ #define MARK2RULE(e,m) (m) #define MARK2RULEADR(e,m) (&(RefRules[TAG(e)][(m)])) #define RULE2PATTERN(e,r) (RefRules[TAG(e)][(r)].pattern) #define RULE2PAT(e,r) (RefRules[TAG(e)][(r)].pat) #define MARK2PAT(e,r) (RefRules[TAG(e)][(r)].pat) #define MARK2PATTERN(e,m) (RefRules[TAG(e)][(m)].pattern) #define PATTERN2RULE(e,p) (Patterns2Rules((e),(p))) #define RULE2MARK(e,r) (RefRules[TAG(e)][(r)].mark) #define PATTERN2MARK(e,p) (((PATTERN2RULE((e),(p)))>=0) ? (RefRules[TAG(e)][PATTERN2RULE((e),(p))].mark) : -1) #ifdef __SR2201__ #define NODE_OF_RULE(e,m,i) ((*MARK2RULEADR((e),(m))).sonandnode[(i)][0]!=-1) #else #define NODE_OF_RULE(e,m,i) (MARK2RULEADR((e),(m))->sonandnode[(i)][0]!=-1) #endif #define CONCAT(a,b,c) CONCAT_AUX(a,b,c) #define CONCAT_AUX(a,b,c) a ## b ## c /* dimension dependent MAX_CORNERS_OF_ELEM */ #define MAX_CORNERS_OF_ELEM_2D 4 #define MAX_CORNERS_OF_ELEM_3D 8 #define MAX_CORNERS_OF_ELEM_DIM CONCAT(MAX_CORNERS_OF_ELEM_,DIM,D) /* dimension dependent MAX_EDGES_OF_ELEM */ #define MAX_EDGES_OF_ELEM_2D 4 #define MAX_EDGES_OF_ELEM_3D 12 #define MAX_EDGES_OF_ELEM_DIM CONCAT(MAX_EDGES_OF_ELEM_,DIM,D) /* dimension dependent MAX_NEW_CORNERS */ #define MAX_NEW_CORNERS_2D 5 #define MAX_NEW_CORNERS_3D 19 #define MAX_NEW_CORNERS_DIM CONCAT(MAX_NEW_CORNERS_,DIM,D) /* dimension dependent MAX_NEW_EDGES */ #define MAX_NEW_EDGES_2D 12 #define MAX_NEW_EDGES_3D 54 #define MAX_NEW_EDGES_DIM CONCAT(MAX_NEW_EDGES_,DIM,D) /* dimension dependent MAX_SIDES_OF_ELEM */ #define MAX_SIDES_OF_ELEM_2D 4 #define MAX_SIDES_OF_ELEM_3D 6 #define MAX_SIDES_OF_ELEM_DIM CONCAT(MAX_SIDES_OF_ELEM_,DIM,D) /* dimension dependent MAX_SONS */ #define MAX_SONS_2D 4 #define MAX_SONS_3D 12 #define MAX_SONS_DIM CONCAT(MAX_SONS_,DIM,D) #if FATHER_SIDE_OFFSETtag) #define MARK_OF_RULE(r) ((r)->mark) #define CLASS_OF_RULE(r) ((r)->rclass) #define NSONS_OF_RULE(r) ((r)->nsons) #define SON_OF_RULE(r,s) (&((r)->sons[(s)])) #define PATTERN_OF_RULE(r,i) ((r)->pattern[(i)]) #define PAT_OF_RULE(r) ((r)->pat) #define SON_OF_NODE_OF_RULE(r,n) ((r)->sonandnode[(n)][0]) #define SONNODE_OF_NODE_OF_RULE(r,n)((r)->sonandnode[(n)][0]) #define SON_TAG_OF_RULE(r,s) ((r)->sons[(s)].tag) #define SON_TAG(s) ((s)->tag) #define SON_CORNER_OF_RULE(r,s,n) ((r)->sons[(s)].corners[(n)]) #define SON_CORNER(s,n) ((s)->corners[(n)]) #define SON_NB_OF_RULE(r,s,n) ((r)->sons[(s)].nb[(n)]) #define SON_NB(s,n) ((s)->nb[(n)]) #define SON_PATH_OF_RULE(r,s) ((r)->sons[(s)].path) #define SON_PATH(s) ((s)->path) /* macros for referencing of sons paths */ /* 4 high bits for no of neighbours to be passed */ #define PATHDEPTHMASK 0xF0000000 #define PATHDEPTHSHIFT 28 #define PATHDEPTH(i) (((i) & PATHDEPTHMASK)>>PATHDEPTHSHIFT) #define SETPATHDEPTH(i,val) (i) = ((i)&(~PATHDEPTHMASK))|(((val)<>(3*(n))) #define SETNEXTSIDE(i,n,val) (i) = ((i)&(~(NEXTSIDEMASK<<(3*(n)))))|(((val)&NEXTSIDEMASK)<<(3*(n))) #define MAX_PATH_DEPTH (PATHDEPTHSHIFT/3) #define NOCLASS(c) ((c) == 0) #define YELLOWCLASS(c) ((c) & 1) #define GREENCLASS(c) ((c) & 2) #define REDCLASS(c) ((c) & 3) #define SWITCHCLASS(c) ((c) & 4) /****************************************************************************/ /* */ /* data structures exported by the corresponding source file */ /* */ /****************************************************************************/ typedef INT (*FULLREFRULEPTR)(ELEMENT *); typedef struct { /** \brief Fields for environment list variable */ NS_PREFIX ENVVAR v; /* full ref rule specific stuff */ FULLREFRULEPTR theFullRefRule; /* the best full refrule */ } FULLREFRULE; struct sondata { SHORT tag; /* which element type is the son */ SHORT corners[MAX_CORNERS_OF_ELEM_DIM]; /* corners of the son */ SHORT nb[MAX_SIDES_OF_ELEM_DIM]; /* neighbors of this son */ /* < FATHER_SIDE_OFFSET if nb has same father */ /* >= FATHER_SIDE_OFFSET if nb has other father*/ INT path; /* path used in GetSons() for tetras */ }; struct refrule { SHORT tag; /* which element type this rule can refine */ SHORT mark; /* the mark of this rule */ SHORT rclass; /* class of rule:3bits for COPY, IREG, REG */ SHORT nsons; /* number of sons rule creates */ SHORT pattern[MAX_NEW_CORNERS_DIM]; /* stores which edges are refined */ INT pat; /* bitwise format of pattern */ SHORT sonandnode[MAX_NEW_CORNERS_DIM][2]; /* for each new node the number of the son */ /* and the local node number of the node */ struct sondata sons[MAX_SONS_DIM]; }; typedef struct sondata SONDATA; typedef struct refrule REFRULE; /****************************************************************************/ /* */ /* definition of exported global variables */ /* */ /****************************************************************************/ extern INT MaxRules[TAGS]; extern INT MaxNewCorners[TAGS]; extern INT MaxNewEdges[TAGS]; extern INT CenterNodeIndex[TAGS]; extern REFRULE *RefRules[TAGS]; extern const SHORT* Pattern2Rule[TAGS]; extern FULLREFRULEPTR theFullRefRule; /****************************************************************************/ /* */ /* function declarations */ /* */ /****************************************************************************/ INT ShowRefRule (INT tag, INT nb); INT ShowRefRuleX (INT tag, INT nb, PrintfProcPtr Printf); INT InitRuleManager (void); INT Patterns2Rules (ELEMENT *theElement,INT pattern); ELEMENT *ELEMENT_TO_MARK (ELEMENT *theElement); #ifdef UG_DIM_3 INT GetRule_AnisotropicRed (ELEMENT *theElement, INT *Rule); #endif END_UGDIM_NAMESPACE #endif dune-uggrid-2.11.0+dfsg/dune/uggrid/gm/shapes.cc000066400000000000000000000242131513616443000213420ustar00rootroot00000000000000// SPDX-FileCopyrightText: Copyright © DUNE Project contributors, see file LICENSE.md in module root // SPDX-License-Identifier: LGPL-2.1-or-later /****************************************************************************/ /* */ /* File: shapes.c */ /* */ /* Purpose: shape functions for triangles and quadrilaterals */ /* */ /* Author: Peter Bastian */ /* Interdisziplinaeres Zentrum fuer Wissenschaftliches Rechnen */ /* Universitaet Heidelberg */ /* Im Neuenheimer Feld 368 */ /* 6900 Heidelberg */ /* internet: ug@ica3.uni-stuttgart.de */ /* */ /* History: 08.04.92 begin, ug version 2.0 */ /* 20.11.94 moved shapes.c from ug to cd folder */ /* */ /* Remarks: */ /* */ /****************************************************************************/ /****************************************************************************/ /* */ /* include files */ /* system include files */ /* application include files */ /* */ /****************************************************************************/ #include #include #include #include #include #include #include #include #include #include "gm.h" #include "evm.h" #include "shapes.h" USING_UG_NAMESPACE USING_UGDIM_NAMESPACE /****************************************************************************/ /* */ /* defines in the following order */ /* */ /* compile time constants defining static data size (i.e. arrays) */ /* other constants */ /* macros */ /* */ /****************************************************************************/ #define SMALL_DIFF 1e-20 #define MAX_ITER 20 /****************************************************************************/ /* */ /* data structures used in this source file (exported data structures are */ /* in the corresponding include file!) */ /* */ /****************************************************************************/ /****************************************************************************/ /* */ /* definition of exported global variables */ /* */ /****************************************************************************/ /****************************************************************************/ /* */ /* forward declarations of functions used before they are defined */ /* */ /****************************************************************************/ /****************************************************************************/ /** \brief Transform global coordinates to local \param n - number of corners \param Corners - coordinates of corners \param EvalPoint - global coordinates \param LocalCoord - local coordinates This function transforms global coordinates to local in an evaluated point in 3D. \return
                                                      • 0 if ok
                                                      • 1 if error occurred.
                                                      */ /****************************************************************************/ INT NS_DIM_PREFIX UG_GlobalToLocal (INT n, const DOUBLE **Corners, const FieldVector& EvalPoint, FieldVector& LocalCoord) { DOUBLE_VECTOR tmp,diff,M[DIM],IM[DIM]; DOUBLE s,IMdet; INT i; V_DIM_SUBTRACT(EvalPoint,Corners[0],diff); if (n == DIM+1) { TRANSFORMATION(DIM+1,Corners,LocalCoord,M); M_DIM_INVERT(M,IM,IMdet); if (IMdet==0) return (2); MT_TIMES_V_DIM(IM,diff,LocalCoord); return(0); } V_DIM_CLEAR(LocalCoord); TRANSFORMATION(n,Corners,LocalCoord,M); M_DIM_INVERT(M,IM,IMdet); if (IMdet==0) return (3); MT_TIMES_V_DIM(IM,diff,LocalCoord); for (i=0; i
                                                    • 0 if ok
                                                    • 1 if error occurred.
                                                    */ /****************************************************************************/ #ifdef UG_DIM_3 INT NS_DIM_PREFIX TetraSideNormals (ELEMENT *theElement, DOUBLE **theCorners, DOUBLE_VECTOR theNormals[MAX_SIDES_OF_ELEM]) { DOUBLE_VECTOR a, b; DOUBLE h; INT j; for (j=0; j<4; j++) { INT k = element_descriptors[TETRAHEDRON]->side_opp_to_corner[j]; V3_SUBTRACT(theCorners[(j+1)%4],theCorners[(j+2)%4],a) V3_SUBTRACT(theCorners[(j+1)%4],theCorners[(j+3)%4],b) V3_VECTOR_PRODUCT(a,b,theNormals[k]) V3_Normalize(theNormals[k]); V3_SUBTRACT(theCorners[j],theCorners[(j+1)%4],a) V3_SCALAR_PRODUCT(theNormals[k],a,h); if (std::abs(h)
                                                  • 0 if ok
                                                  • 1 if error occurred.
                                                  */ /****************************************************************************/ #ifdef UG_DIM_3 INT NS_DIM_PREFIX TetMaxSideAngle (ELEMENT *theElement, const DOUBLE **theCorners, DOUBLE *MaxAngle) { DOUBLE_VECTOR theNormal[MAX_SIDES_OF_ELEM]; DOUBLE max,help; INT i; if (TetraSideNormals (theElement,(DOUBLE **)theCorners,theNormal)) return (1); max = -1.0; for (i=0; i::pi()*acos(-max); return (0); } #endif /****************************************************************************/ /** \brief Calculates side angle and length of edge of Tetrahedron \param theCorners - list of pointers to phys corner vectors \param Angle - side angle \param Length - sidelength This function calculates the side angle of a tetrahedron and the lengths of the edges belonging to this side. \return
                                                  • 0 if ok
                                                  • 1 if error occurred.
                                                  */ /****************************************************************************/ #ifdef UG_DIM_3 INT NS_DIM_PREFIX TetAngleAndLength (ELEMENT *theElement, const DOUBLE **theCorners, DOUBLE *Angle, DOUBLE *Length) { DOUBLE_VECTOR theNormals[MAX_SIDES_OF_ELEM],theEdge[MAX_EDGES_OF_ELEM]; DOUBLE h; INT j,k; for (j=0; j0.0 && CORNER_OF_EDGE(theElement,k,0)==CORNER_OPP_TO_SIDE(theElement,j)) ) V3_SCALE(-1.0,theNormals[j]); } for (j=0; j #include "gm.h" #include "evm.h" #include START_UGDIM_NAMESPACE /****************************************************************************/ /* */ /* defines in the following order */ /* */ /* compile time constants defining static data size (i.e. arrays) */ /* other constants */ /* macros */ /* */ /****************************************************************************/ #ifdef UG_DIM_2 #define CORNER_COORDINATES_TRIANGLE(e,n,x) \ {(n)=3; \ (x)[0]=CVECT(MYVERTEX(CORNER((e),0))).data(); \ (x)[1]=CVECT(MYVERTEX(CORNER((e),1))).data(); \ (x)[2]=CVECT(MYVERTEX(CORNER((e),2))).data();} #define CORNER_COORDINATES_QUADRILATERAL(e,n,x) \ {(n)=4; \ (x)[0]=CVECT(MYVERTEX(CORNER((e),0))).data(); \ (x)[1]=CVECT(MYVERTEX(CORNER((e),1))).data(); \ (x)[2]=CVECT(MYVERTEX(CORNER((e),2))).data(); \ (x)[3]=CVECT(MYVERTEX(CORNER((e),3))).data();} #define CORNER_COORDINATES(e,n,x) \ {if (TAG((e))==TRIANGLE) \ CORNER_COORDINATES_TRIANGLE((e),(n),(x)) \ else CORNER_COORDINATES_QUADRILATERAL((e),(n),(x))} #endif /* UG_DIM_2 */ #define LOCAL_TO_GLOBAL_TRIANGLE(x,local,global) \ {(global)[0] = (1.0-(local)[0]-(local)[1])*(x)[0][0] \ +(local)[0]*(x)[1][0] + (local)[1]*(x)[2][0]; \ (global)[1] = (1.0-(local)[0]-(local)[1])*(x)[0][1] \ +(local)[0]*(x)[1][1] + (local)[1]*(x)[2][1]; } #define LOCAL_TO_GLOBAL_QUADRILATERAL(x,local,global) \ {(global)[0] = (1.0-(local)[0])*(1.0-(local)[1])*(x)[0][0] \ + (local)[0]*(1.0-(local)[1])*(x)[1][0] \ + (local)[0]*(local)[1]*(x)[2][0] \ + (1.0-(local)[0])*(local)[1]*(x)[3][0]; \ (global)[1] = (1.0-(local)[0])*(1.0-(local)[1])*(x)[0][1] \ + (local)[0]*(1.0-(local)[1])*(x)[1][1] \ + (local)[0]*(local)[1]*(x)[2][1] \ + (1.0-(local)[0])*(local)[1]*(x)[3][1];} #define LOCAL_TO_GLOBAL_2D(n,x,local,global) \ {if ((n) == 3) LOCAL_TO_GLOBAL_TRIANGLE((x),(local),(global)) \ else if ((n) == 4) LOCAL_TO_GLOBAL_QUADRILATERAL((x),(local),(global))} #define AREA_OF_TRIANGLE(x,area) {DOUBLE detJ; DOUBLE_VECTOR a,b; \ V2_SUBTRACT((x)[1],(x)[0],a); \ V2_SUBTRACT((x)[2],(x)[0],b); \ V2_VECTOR_PRODUCT(a,b,detJ); \ (area) = std::abs(detJ) * 0.5;} #define AREA_OF_QUADRILATERAL(x,area) {DOUBLE detJ,ar; DOUBLE_VECTOR a,b; \ V2_SUBTRACT((x)[1],(x)[0],a); \ V2_SUBTRACT((x)[2],(x)[0],b); \ V2_VECTOR_PRODUCT(a,b,detJ); \ ar = std::abs(detJ) * 0.5; \ V2_SUBTRACT((x)[3],(x)[0],a); \ V2_VECTOR_PRODUCT(a,b,detJ); \ (area) = std::abs(detJ) * 0.5 + ar;} #define AREA_OF_ELEMENT_2D(n,x,area) \ {if ((n) == 3) AREA_OF_TRIANGLE((x),(area)) \ else if ((n) == 4) AREA_OF_QUADRILATERAL((x),(area)) } #define TRANSFORMATION_OF_TRIANGLE(x,M) \ { V2_SUBTRACT((x)[1],(x)[0],(M)[0]); \ V2_SUBTRACT((x)[2],(x)[0],(M)[1]); } #define TRANSFORMATION_OF_QUADRILATERAL(x,local,M) \ { DOUBLE a; \ a = 1.0 - (local)[1]; \ (M)[0][0] = a*((x)[1][0]-x[0][0])+(local)[1]*((x)[2][0]-(x)[3][0]); \ (M)[0][1] = a*((x)[1][1]-x[0][1])+(local)[1]*((x)[2][1]-(x)[3][1]); \ a = 1.0 - (local)[0]; \ (M)[1][0] = a*((x)[3][0]-x[0][0])+(local)[0]*((x)[2][0]-(x)[1][0]); \ (M)[1][1] = a*((x)[3][1]-x[0][1])+(local)[0]*((x)[2][1]-(x)[1][1]); } #define TRANSFORMATION_2D(n,x,local,M) \ {if ((n) == 3) {TRANSFORMATION_OF_TRIANGLE((x),(M));} \ else TRANSFORMATION_OF_QUADRILATERAL((x),(local),(M)); } #ifdef UG_DIM_3 #define CORNER_COORDINATES_TETRAHEDRON(e,n,x) \ {(n) = 4; \ (x)[0]=CVECT(MYVERTEX(CORNER((e),0))).data(); \ (x)[1]=CVECT(MYVERTEX(CORNER((e),1))).data(); \ (x)[2]=CVECT(MYVERTEX(CORNER((e),2))).data(); \ (x)[3]=CVECT(MYVERTEX(CORNER((e),3))).data();} #define CORNER_COORDINATES_PYRAMID(e,n,x) \ {(n) = 5; \ (x)[0]=CVECT(MYVERTEX(CORNER((e),0))).data(); \ (x)[1]=CVECT(MYVERTEX(CORNER((e),1))).data(); \ (x)[2]=CVECT(MYVERTEX(CORNER((e),2))).data(); \ (x)[3]=CVECT(MYVERTEX(CORNER((e),3))).data(); \ (x)[4]=CVECT(MYVERTEX(CORNER((e),4))).data();} #define CORNER_COORDINATES_PRISM(e,n,x) \ {(n) = 6; \ (x)[0]=CVECT(MYVERTEX(CORNER((e),0))).data(); \ (x)[1]=CVECT(MYVERTEX(CORNER((e),1))).data(); \ (x)[2]=CVECT(MYVERTEX(CORNER((e),2))).data(); \ (x)[3]=CVECT(MYVERTEX(CORNER((e),3))).data(); \ (x)[4]=CVECT(MYVERTEX(CORNER((e),4))).data(); \ (x)[5]=CVECT(MYVERTEX(CORNER((e),5))).data();} #define CORNER_COORDINATES_HEXAHEDRON(e,n,x) \ {(n) = 8; \ (x)[0]=CVECT(MYVERTEX(CORNER((e),0))).data(); \ (x)[1]=CVECT(MYVERTEX(CORNER((e),1))).data(); \ (x)[2]=CVECT(MYVERTEX(CORNER((e),2))).data(); \ (x)[3]=CVECT(MYVERTEX(CORNER((e),3))).data(); \ (x)[4]=CVECT(MYVERTEX(CORNER((e),4))).data(); \ (x)[5]=CVECT(MYVERTEX(CORNER((e),5))).data(); \ (x)[6]=CVECT(MYVERTEX(CORNER((e),6))).data(); \ (x)[7]=CVECT(MYVERTEX(CORNER((e),7))).data();} #define CORNER_COORDINATES(e,n,x) \ {if (TAG((e))==TETRAHEDRON) CORNER_COORDINATES_TETRAHEDRON((e),(n),(x))\ else if (TAG((e))==PYRAMID) CORNER_COORDINATES_PYRAMID((e),(n),(x)) \ else if (TAG((e))==PRISM) CORNER_COORDINATES_PRISM((e),(n),(x)) \ else CORNER_COORDINATES_HEXAHEDRON((e),(n),(x))} #endif /* UG_DIM_3 */ #define LOCAL_TO_GLOBAL_TETRAHEDRON(x,local,global) \ {(global)[0] = (1.0-(local)[0]-(local)[1]-(local)[2])*(x)[0][0] \ +(local)[0]*(x)[1][0] + (local)[1]*(x)[2][0] + (local)[2]*(x)[3][0]; \ (global)[1] = (1.0-(local)[0]-(local)[1]-(local)[2])*(x)[0][1] \ +(local)[0]*(x)[1][1] + (local)[1]*(x)[2][1] + (local)[2]*(x)[3][1]; \ (global)[2] = (1.0-(local)[0]-(local)[1]-(local)[2])*(x)[0][2] \ +(local)[0]*(x)[1][2] + (local)[1]*(x)[2][2] + (local)[2]*(x)[3][2]; } #define LOCAL_TO_GLOBAL_PYRAMID(x,local,global) \ {DOUBLE a,b,a0,a1,a2,a3; \ a = 1.0 - (local)[0]; \ b = 1.0 - (local)[1]; \ if ((local)[0] > (local)[1]) { \ a0 = a * b - (local)[2] * b; \ a1 = (local)[0] * b - (local)[2]*(local)[1]; \ a2 = (local)[0] * (local)[1] + (local)[2]*(local)[1]; \ a3 = a * (local)[1] - (local)[2] * (local)[1]; \ (global)[0] = \ a0*(x)[0][0]+a1*(x)[1][0]+a2*(x)[2][0]+a3*(x)[3][0]+(local)[2]*(x)[4][0]; \ (global)[1] = \ a0*(x)[0][1]+a1*(x)[1][1]+a2*(x)[2][1]+a3*(x)[3][1]+(local)[2]*(x)[4][1]; \ (global)[2] = \ a0*(x)[0][2]+a1*(x)[1][2]+a2*(x)[2][2]+a3*(x)[3][2]+(local)[2]*(x)[4][2];}\ else { \ a0 = a * b - (local)[2] * a; \ a1 = (local)[0] * b - (local)[2]*(local)[0]; \ a2 = (local)[0] * (local)[1] + (local)[2]*(local)[0]; \ a3 = a * (local)[1] - (local)[2] * (local)[0]; \ (global)[0] = \ a0*(x)[0][0]+a1*(x)[1][0]+a2*(x)[2][0]+a3*(x)[3][0]+(local)[2]*(x)[4][0]; \ (global)[1] = \ a0*(x)[0][1]+a1*(x)[1][1]+a2*(x)[2][1]+a3*(x)[3][1]+(local)[2]*(x)[4][1]; \ (global)[2] = \ a0*(x)[0][2]+a1*(x)[1][2]+a2*(x)[2][2]+a3*(x)[3][2]+(local)[2]*(x)[4][2];}} #define LOCAL_TO_GLOBAL_PRISM(x,local,global) \ {DOUBLE a,b,a0,a1,a2,a3,a4,a5; \ a = 1.0 - (local)[0] - (local)[1]; \ b = 1.0 - (local)[2]; \ a0 = a * b; \ a1 = (local)[0] * b; \ a2 = (local)[1] * b; \ a3 = a * (local)[2]; \ a4 = (local)[0] * (local)[2]; \ a5 = (local)[1] * (local)[2]; \ (global)[0] = \ a0*(x)[0][0]+a1*(x)[1][0]+a2*(x)[2][0]+a3*(x)[3][0]+ \ a4*(x)[4][0]+a5*(x)[5][0]; \ (global)[1] = \ a0*(x)[0][1]+a1*(x)[1][1]+a2*(x)[2][1]+a3*(x)[3][1]+ \ a4*(x)[4][1]+a5*(x)[5][1]; \ (global)[2] = \ a0*(x)[0][2]+a1*(x)[1][2]+a2*(x)[2][2]+a3*(x)[3][2]+ \ a4*(x)[4][2]+a5*(x)[5][2]; } #define LOCAL_TO_GLOBAL_HEXAHEDRON(x,local,global) \ {DOUBLE a,b,c,a0,a1,a2,a3,a4,a5,a6,a7; \ a = 1.0 - (local)[0]; \ b = 1.0 - (local)[1]; \ c = 1.0 - (local)[2]; \ a0 = a * b * c; \ a1 = (local)[0] * b * c; \ a2 = (local)[0] * (local)[1] * c; \ a3 = a * (local)[1] * c; \ a4 = a * b * (local)[2]; \ a5 = (local)[0] * b * (local)[2]; \ a6 = (local)[0] * (local)[1] * (local)[2]; \ a7 = a * (local)[1] * (local)[2]; \ (global)[0] = \ a0*(x)[0][0]+a1*(x)[1][0]+a2*(x)[2][0]+a3*(x)[3][0]+ \ a4*(x)[4][0]+a5*(x)[5][0]+a6*(x)[6][0]+a7*(x)[7][0]; \ (global)[1] = \ a0*(x)[0][1]+a1*(x)[1][1]+a2*(x)[2][1]+a3*(x)[3][1]+ \ a4*(x)[4][1]+a5*(x)[5][1]+a6*(x)[6][1]+a7*(x)[7][1]; \ (global)[2] = \ a0*(x)[0][2]+a1*(x)[1][2]+a2*(x)[2][2]+a3*(x)[3][2]+ \ a4*(x)[4][2]+a5*(x)[5][2]+a6*(x)[6][2]+a7*(x)[7][2]; } #define LOCAL_TO_GLOBAL_3D(n,x,local,global) \ {if ((n) == 4) LOCAL_TO_GLOBAL_TETRAHEDRON((x),(local),(global)) \ else if ((n) == 5) LOCAL_TO_GLOBAL_PYRAMID((x),(local),(global)) \ else if ((n) == 6) LOCAL_TO_GLOBAL_PRISM((x),(local),(global)) \ else if ((n) == 8) LOCAL_TO_GLOBAL_HEXAHEDRON((x),(local),(global))} #define AREA_OF_TETRAHEDRON(x,area) {DOUBLE detJ; DOUBLE_VECTOR a,b,c; \ V3_SUBTRACT((x)[1],(x)[0],a); \ V3_SUBTRACT((x)[2],(x)[0],b); \ V3_VECTOR_PRODUCT(a,b,c); \ V3_SUBTRACT((x)[3],(x)[0],a); \ V3_SCALAR_PRODUCT(a,c,detJ); \ (area) = std::abs(detJ)/6.0;} #define AREA_OF_PYRAMID(x,area) {DOUBLE detJ,ar; DOUBLE_VECTOR a,b,c,d;\ V3_SUBTRACT((x)[1],(x)[0],a); \ V3_SUBTRACT((x)[2],(x)[0],b); \ V3_VECTOR_PRODUCT(a,b,c); \ V3_SUBTRACT((x)[4],(x)[0],d); \ V3_SCALAR_PRODUCT(c,d,detJ); \ ar = std::abs(detJ)/6.0; \ V3_SUBTRACT((x)[3],(x)[0],a); \ V3_VECTOR_PRODUCT(a,b,c); \ V3_SCALAR_PRODUCT(c,d,detJ); \ (area) = std::abs(detJ)/6.0 + ar;} #define AREA_OF_PRISM(x,area) {DOUBLE detJ,ar; DOUBLE_VECTOR a,b,c; \ V3_SUBTRACT((x)[1],(x)[0],a); \ V3_SUBTRACT((x)[2],(x)[0],b); \ V3_VECTOR_PRODUCT(a,b,c); \ V3_SUBTRACT((x)[3],(x)[0],a); \ V3_SCALAR_PRODUCT(a,c,detJ); \ ar = std::abs(detJ)/6.0; \ V3_SUBTRACT((x)[2],(x)[1],a); \ V3_SUBTRACT((x)[3],(x)[1],b); \ V3_VECTOR_PRODUCT(a,b,c); \ V3_SUBTRACT((x)[4],(x)[1],a); \ V3_SCALAR_PRODUCT(a,c,detJ); \ ar += std::abs(detJ)/6.0; \ V3_SUBTRACT((x)[2],(x)[5],a); \ V3_SUBTRACT((x)[3],(x)[5],b); \ V3_VECTOR_PRODUCT(a,b,c); \ V3_SUBTRACT((x)[4],(x)[5],a); \ V3_SCALAR_PRODUCT(a,c,detJ); \ (area) = std::abs(detJ)/6.0 + ar;} #define AREA_OF_HEXAHEDRON(x,area) {DOUBLE detJ,ar; DOUBLE_VECTOR a,b,c; \ V3_SUBTRACT((x)[1],(x)[0],a); \ V3_SUBTRACT((x)[2],(x)[0],b); \ V3_VECTOR_PRODUCT(a,b,c); \ V3_SUBTRACT((x)[5],(x)[0],a); \ V3_SCALAR_PRODUCT(a,c,detJ); \ ar = std::abs(detJ)/6.0; \ V3_SUBTRACT((x)[2],(x)[0],a); \ V3_SUBTRACT((x)[5],(x)[0],b); \ V3_VECTOR_PRODUCT(a,b,c); \ V3_SUBTRACT((x)[6],(x)[0],a); \ V3_SCALAR_PRODUCT(a,c,detJ); \ ar += std::abs(detJ)/6.0; \ V3_SUBTRACT((x)[4],(x)[0],a); \ V3_SUBTRACT((x)[5],(x)[0],b); \ V3_VECTOR_PRODUCT(a,b,c); \ V3_SUBTRACT((x)[6],(x)[0],a); \ V3_SCALAR_PRODUCT(a,c,detJ); \ ar += std::abs(detJ)/6.0; \ V3_SUBTRACT((x)[2],(x)[0],a); \ V3_SUBTRACT((x)[3],(x)[0],b); \ V3_VECTOR_PRODUCT(a,b,c); \ V3_SUBTRACT((x)[6],(x)[0],a); \ V3_SCALAR_PRODUCT(a,c,detJ); \ ar += std::abs(detJ)/6.0; \ V3_SUBTRACT((x)[3],(x)[0],a); \ V3_SUBTRACT((x)[4],(x)[0],b); \ V3_VECTOR_PRODUCT(a,b,c); \ V3_SUBTRACT((x)[6],(x)[0],a); \ V3_SCALAR_PRODUCT(a,c,detJ); \ ar += std::abs(detJ)/6.0; \ V3_SUBTRACT((x)[3],(x)[7],a); \ V3_SUBTRACT((x)[4],(x)[7],b); \ V3_VECTOR_PRODUCT(a,b,c); \ V3_SUBTRACT((x)[6],(x)[7],a); \ V3_SCALAR_PRODUCT(a,c,detJ); \ (area) = std::abs(detJ)/6.0 + ar;} #define AREA_OF_ELEMENT_3D(n,x,area) \ {if ((n) == 4) {AREA_OF_TETRAHEDRON((x),(area));} \ else if ((n) == 5) {AREA_OF_PYRAMID((x),(area));} \ else if ((n) == 6) {AREA_OF_PRISM((x),(area));} \ else if ((n) == 8) {AREA_OF_HEXAHEDRON((x),(area));}} #define TRANSFORMATION_OF_TETRAHEDRON(x,M) \ { V3_SUBTRACT((x)[1],(x)[0],(M)[0]); \ V3_SUBTRACT((x)[2],(x)[0],(M)[1]); \ V3_SUBTRACT((x)[3],(x)[0],(M)[2]);} #define TRANSFORMATION_OF_PYRAMID(x,local,M) \ { DOUBLE a,b,c; \ a = (x)[0][0]-(x)[1][0]+(x)[2][0]-(x)[3][0]; \ b = (x)[0][1]-(x)[1][1]+(x)[2][1]-(x)[3][1]; \ c = (x)[0][2]-(x)[1][2]+(x)[2][2]-(x)[3][2]; \ if ((local)[0] > (local)[1]) { \ (M)[0][0] = (x)[1][0]-(x)[0][0]+(local)[1]*a; \ (M)[0][1] = (x)[1][1]-(x)[0][1]+(local)[1]*b; \ (M)[0][2] = (x)[1][2]-(x)[0][2]+(local)[1]*c; \ (M)[1][0] = (x)[3][0]-(x)[0][0]+((local)[0]+(local)[2])*a; \ (M)[1][1] = (x)[3][1]-(x)[0][1]+((local)[0]+(local)[2])*b; \ (M)[1][2] = (x)[3][2]-(x)[0][2]+((local)[0]+(local)[2])*c; \ (M)[2][0] = (x)[4][0]-(x)[0][0]+(local)[1]*a; \ (M)[2][1] = (x)[4][1]-(x)[0][1]+(local)[1]*b; \ (M)[2][2] = (x)[4][2]-(x)[0][2]+(local)[1]*c;} \ else { \ (M)[0][0] = (x)[1][0]-(x)[0][0]+((local)[1]+(local)[2])*a; \ (M)[0][1] = (x)[1][1]-(x)[0][1]+((local)[1]+(local)[2])*b; \ (M)[0][2] = (x)[1][2]-(x)[0][2]+((local)[1]+(local)[2])*c; \ (M)[1][0] = (x)[3][0]-(x)[0][0]+(local)[0]*a; \ (M)[1][1] = (x)[3][1]-(x)[0][1]+(local)[0]*b; \ (M)[1][2] = (x)[3][2]-(x)[0][2]+(local)[0]*c; \ (M)[2][0] = (x)[4][0]-(x)[0][0]+(local)[0]*a; \ (M)[2][1] = (x)[4][1]-(x)[0][1]+(local)[0]*b; \ (M)[2][2] = (x)[4][2]-(x)[0][2]+(local)[0]*c;} } #define TRANSFORMATION_OF_PRISM(x,local,M) \ { DOUBLE a0,a1,a2,b0,b1,b2; \ a0 = (x)[0][0]-(x)[1][0]-(x)[3][0]+(x)[4][0]; \ a1 = (x)[0][1]-(x)[1][1]-(x)[3][1]+(x)[4][1]; \ a2 = (x)[0][2]-(x)[1][2]-(x)[3][2]+(x)[4][2]; \ b0 = (x)[0][0]-(x)[2][0]-(x)[3][0]+(x)[5][0]; \ b1 = (x)[0][1]-(x)[2][1]-(x)[3][1]+(x)[5][1]; \ b2 = (x)[0][2]-(x)[2][2]-(x)[3][2]+(x)[5][2]; \ (M)[0][0] = (x)[1][0]-(x)[0][0]+(local)[2]*a0; \ (M)[0][1] = (x)[1][1]-(x)[0][1]+(local)[2]*a1; \ (M)[0][2] = (x)[1][2]-(x)[0][2]+(local)[2]*a2; \ (M)[1][0] = (x)[2][0]-(x)[0][0]+(local)[2]*b0; \ (M)[1][1] = (x)[2][1]-(x)[0][1]+(local)[2]*b1; \ (M)[1][2] = (x)[2][2]-(x)[0][2]+(local)[2]*b2; \ (M)[2][0] = (x)[3][0]-(x)[0][0]+(local)[0]*a0+(local)[1]*b0; \ (M)[2][1] = (x)[3][1]-(x)[0][1]+(local)[0]*a1+(local)[1]*b1; \ (M)[2][2] = (x)[3][2]-(x)[0][2]+(local)[0]*a2+(local)[1]*b2;} #define TRANSFORMATION_OF_HEXAHEDRON(x,local,M) \ { DOUBLE a,b,c,a0,a1,a2,a3; \ a = 1.0 - (local)[0]; \ b = 1.0 - (local)[1]; \ c = 1.0 - (local)[2]; \ a0 = b * c; \ a1 = (local)[1] * c; \ a2 = (local)[1] * (local)[2]; \ a3 = b * (local)[2]; \ (M)[0][0] = a0*((x)[1][0]-x[0][0])+a1*((x)[2][0]-(x)[3][0]) \ + a2*((x)[6][0]-x[7][0])+a3*((x)[5][0]-(x)[4][0]); \ (M)[0][1] = a0*((x)[1][1]-x[0][1])+a1*((x)[2][1]-(x)[3][1]) \ + a2*((x)[6][1]-x[7][1])+a3*((x)[5][1]-(x)[4][1]); \ (M)[0][2] = a0*((x)[1][2]-x[0][2])+a1*((x)[2][2]-(x)[3][2]) \ + a2*((x)[6][2]-x[7][2])+a3*((x)[5][2]-(x)[4][2]); \ a0 = a * c; \ a1 = (local)[0] * c; \ a2 = (local)[0] * (local)[2]; \ a3 = a * (local)[2]; \ (M)[1][0] = a0*((x)[3][0]-x[0][0])+a1*((x)[2][0]-(x)[1][0]) \ + a2*((x)[6][0]-x[5][0])+a3*((x)[7][0]-(x)[4][0]); \ (M)[1][1] = a0*((x)[3][1]-x[0][1])+a1*((x)[2][1]-(x)[1][1]) \ + a2*((x)[6][1]-x[5][1])+a3*((x)[7][1]-(x)[4][1]); \ (M)[1][2] = a0*((x)[3][2]-x[0][2])+a1*((x)[2][2]-(x)[1][2]) \ + a2*((x)[6][2]-x[5][2])+a3*((x)[7][2]-(x)[4][2]); \ a0 = a * b; \ a1 = (local)[0] * b; \ a2 = (local)[0] * (local)[1]; \ a3 = a * (local)[1]; \ (M)[2][0] = a0*((x)[4][0]-x[0][0])+a1*((x)[5][0]-(x)[1][0]) \ + a2*((x)[6][0]-x[2][0])+a3*((x)[7][0]-(x)[3][0]); \ (M)[2][1] = a0*((x)[4][1]-x[0][1])+a1*((x)[5][1]-(x)[1][1]) \ + a2*((x)[6][1]-x[2][1])+a3*((x)[7][1]-(x)[3][1]); \ (M)[2][2] = a0*((x)[4][2]-x[0][2])+a1*((x)[5][2]-(x)[1][2]) \ + a2*((x)[6][2]-x[2][2])+a3*((x)[7][2]-(x)[3][2]); } #define TRANSFORMATION_3D(n,x,local,M) \ {if ((n) == 4) {TRANSFORMATION_OF_TETRAHEDRON((x),(M));} \ else if ((n) == 5) {TRANSFORMATION_OF_PYRAMID((x),(local),(M));} \ else if ((n) == 6) {TRANSFORMATION_OF_PRISM((x),(local),(M));} \ else TRANSFORMATION_OF_HEXAHEDRON((x),(local),(M));} #ifdef UG_DIM_2 #define LOCAL_TO_GLOBAL(n,x,local,global) LOCAL_TO_GLOBAL_2D(n,x,local,global) #define AREA_OF_ELEMENT(n,x,area) AREA_OF_ELEMENT_2D(n,x,area) #define TRANSFORMATION(n,x,local,M) TRANSFORMATION_2D(n,x,local,M) #endif /* UG_DIM_2 */ #ifdef UG_DIM_3 #define TRANSFORMATION_BND(n,x,local,M) TRANSFORMATION_2D(n,x,local,M) #define LOCAL_TO_GLOBAL_BND(n,x,local,global) LOCAL_TO_GLOBAL_2D(n,x,local,global) #define AREA_OF_ELEMENT_BND(n,x,area) AREA_OF_ELEMENT_2D(n,x,area) #define AREA_OF_REF_BND(n,area) AREA_OF_REF_2D(n,area) #define LOCAL_TO_GLOBAL(n,x,local,global) LOCAL_TO_GLOBAL_3D(n,x,local,global) #define AREA_OF_ELEMENT(n,x,area) AREA_OF_ELEMENT_3D(n,x,area) #define TRANSFORMATION(n,x,local,M) TRANSFORMATION_3D(n,x,local,M) #endif /* UG_DIM_3 */ #define INVERSE_TRANSFORMATION(n,x,local,Jinv,Jdet) \ { DOUBLE_VECTOR J[DIM]; \ TRANSFORMATION((n),(x),(local),J); \ M_DIM_INVERT(J,(Jinv),(Jdet)); } /****************************************************************************/ /* */ /* data structures exported by the corresponding source file */ /* */ /****************************************************************************/ /****************************************************************************/ /* */ /* definition of exported global variables */ /* */ /****************************************************************************/ /****************************************************************************/ /* */ /* function declarations */ /* */ /****************************************************************************/ INT UG_GlobalToLocal (INT n, const DOUBLE **Corners, const FieldVector& EvalPoint, FieldVector& LocalCoord); #ifdef UG_DIM_3 DOUBLE N (const INT i, const DOUBLE *LocalCoord); INT TetraSideNormals (ELEMENT *theElement, DOUBLE **theCorners, DOUBLE_VECTOR theNormals[MAX_SIDES_OF_ELEM]); INT TetMaxSideAngle (ELEMENT *theElement, const DOUBLE **theCorners, DOUBLE *MaxAngle); INT TetAngleAndLength (ELEMENT *theElement, const DOUBLE **theCorners, DOUBLE *Angle, DOUBLE *Length); #endif END_UGDIM_NAMESPACE #endif dune-uggrid-2.11.0+dfsg/dune/uggrid/gm/ugm.cc000066400000000000000000006147311513616443000206610ustar00rootroot00000000000000// SPDX-FileCopyrightText: Copyright © DUNE Project contributors, see file LICENSE.md in module root // SPDX-License-Identifier: LGPL-2.1-or-later // -*- tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- // vi: set et ts=4 sw=2 sts=2: /****************************************************************************/ /* */ /* File: ugm.c */ /* */ /* Purpose: unstructured grid manager */ /* */ /* Author: Peter Bastian */ /* Interdisziplinaeres Zentrum fuer Wissenschaftliches Rechnen */ /* Universitaet Heidelberg */ /* Im Neuenheimer Feld 368 */ /* 6900 Heidelberg */ /* email: ug@ica3.uni-stuttgart.de */ /* */ /* History: 09.03.92 begin, ug version 2.0 */ /* Aug 28 1996, ug version 3.4 */ /* */ /* Remarks: */ /* */ /****************************************************************************/ /****************************************************************************/ /* */ /* defines to exclude functions */ /* */ /****************************************************************************/ /****************************************************************************/ /* */ /* include files */ /* system include files */ /* application include files */ /* */ /****************************************************************************/ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "cw.h" #include "evm.h" #include "gm.h" #include "rm.h" #include "dlmgr.h" #include "algebra.h" #include "ugm.h" #include "shapes.h" #include "refine.h" #include #include "pargm.h" #ifdef ModelP #include #include #endif #include USING_UG_NAMESPACE USING_UGDIM_NAMESPACE using namespace PPIF; /****************************************************************************/ /* */ /* defines in the following order */ /* */ /* compile time constants defining static data size (i.e. arrays) */ /* other constants */ /* macros */ /* */ /****************************************************************************/ #define RESOLUTION 20 /* resolution for creating boundary midnode */ #define SMALL1 0.001 #define LINKTABLESIZE 32 /* max number of inks per node for ordering */ /** \brief macro for controlling debugging output by conditions on objects */ #define UGM_CDBG(x,y) /****************************************************************************/ /* */ /* data structures used in this source file (exported data structures are */ /* in the corresponding include file!) */ /* */ /****************************************************************************/ /****************************************************************************/ /* */ /* definition of variables global to this source file only (static!) */ /* */ /****************************************************************************/ /** \brief General purpose text buffer */ static char buffer[4*256]; static INT theMGDirID; /* env var ID for the multigrids */ static INT theMGRootDirID; /* env dir ID for the multigrids */ static UINT UsedOBJT; /* for the dynamic OBJECT management */ /****************************************************************************/ /* */ /* forward declarations of functions used before they are defined */ /* */ /****************************************************************************/ static INT DisposeVertex (GRID *theGrid, VERTEX *theVertex); static INT DisposeEdge (GRID *theGrid, EDGE *theEdge); /****************************************************************************/ /** \brief Get an object type id not occupied in theMG * * This function gets an object type id not occupied in theMG. * * @return
                                                    *
                                                  • id of object type if ok
                                                  • *
                                                  • -1 when error occurred
                                                  • *
                                                  */ /****************************************************************************/ GM_OBJECTS NS_DIM_PREFIX GetFreeOBJT () { INT i; /* skip predefined object types, they cannot be re-allocated */ for (i=NPREDEFOBJ; i
                                                • pointer to an object of the requested type
                                                • NULL if object of requested type is not available
                                                • *
                                                */ /****************************************************************************/ #ifdef ModelP static void ConstructDDDObject (DDD::DDDContext& context, void *obj, INT size, INT type) { if (obj!=NULL && type!=NOOBJ) { memset(obj,0,size); /* link this object to DDD management */ if (HAS_DDDHDR(context, type)) { DDD_TYPE dddtype = DDDTYPE(context, type); DDD_HDR dddhdr = (DDD_HDR)(((char *)obj) + DDD_InfoHdrOffset(context, dddtype)); DDD_HdrConstructor(context, dddhdr, dddtype, PrioMaster, 0); } } } #endif void * NS_DIM_PREFIX GetMemoryForObject (MULTIGRID *theMG, INT size, INT type) { void * obj = GetMem(MGHEAP(theMG),size); if (obj != NULL) memset(obj,0,size); #ifdef ModelP ConstructDDDObject(theMG->dddContext(), obj,size,type); #endif return obj; } /****************************************************************************/ /** \brief Put an object in the free list \fn PutFreeObject * @param theMG - pointer to multigrid * @param object - object to insert in free list * @param size - size of the object * @param type - type of the requested object This function puts an object in the free list. @return
                                                • 0 if ok
                                                • 1 when error occurred.
                                                • *
                                                */ /****************************************************************************/ #ifdef ModelP static void DestructDDDObject(DDD::DDDContext& context, void *object, INT type) { if (type!=NOOBJ) { /* unlink object from DDD management */ if (HAS_DDDHDR(context, type)) { DDD_HDR dddhdr = (DDD_HDR) (((char *)object)+DDD_InfoHdrOffset(context, DDDTYPE(context, type))); DDD_HdrDestructor(context, dddhdr); } } } #endif INT NS_DIM_PREFIX PutFreeObject (MULTIGRID *theMG, void *object, INT size, GM_OBJECTS type) { #ifdef ModelP DestructDDDObject(theMG->dddContext(), object,type); #endif DisposeMem(MGHEAP(theMG), object); return 0; } /****************************************************************************/ /** \brief Return pointer to a new boundary vertex structure * * @param theGrid grid where vertex should be inserted * * This function creates and initializes a new boundary vertex structure * and returns a pointer to it. * * @return
                                                  *
                                                • pointer to requested object
                                                • *
                                                • NULL if out of memory
                                                • *
                                                */ /****************************************************************************/ static VERTEX *CreateBoundaryVertex (GRID *theGrid) { VERTEX *pv; INT i; pv = (VERTEX*)GetMemoryForObject(MYMG(theGrid),sizeof(struct bvertex),BVOBJ); if (pv==NULL) return(NULL); VDATA(pv) = NULL; /* initialize data */ CTRL(pv) = 0; SETOBJT(pv,BVOBJ); SETNOOFNODE(pv,0); SETLEVEL(pv,theGrid->level); ID(pv) = (theGrid->mg->vertIdCounter)++; VFATHER(pv) = NULL; #ifdef TOPNODE TOPNODE(pv) = NULL; #endif for (i=0; i
                                              • pointer to requested object
                                              • NULL if out of memory
                                              */ /****************************************************************************/ static VERTEX *CreateInnerVertex (GRID *theGrid) { VERTEX *pv; INT i; pv = (VERTEX*)GetMemoryForObject(MYMG(theGrid),sizeof(struct ivertex),IVOBJ); if (pv==NULL) return(NULL); VDATA(pv) = NULL; /* initialize data */ CTRL(pv) = 0; SETOBJT(pv,IVOBJ); SETNOOFNODE(pv,0); SETLEVEL(pv,theGrid->level); ID(pv) = (theGrid->mg->vertIdCounter)++; VFATHER(pv) = NULL; #ifdef TOPNODE TOPNODE(pv) = NULL; #endif SETMOVE(pv,DIM); #ifdef ModelP DDD_AttrSet(PARHDRV(pv),GRID_ATTR(theGrid)); /* SETVXPRIO(pv,PrioMaster); */ #endif for (i=0; i
                                            • pointer to requested object
                                            • NULL if out of memory
                                            */ /****************************************************************************/ static NODE *CreateNode (GRID *theGrid, VERTEX *vertex, GEOM_OBJECT *Father, INT NodeType) { NODE *pn; pn = (NODE *)GetMemoryForObject(MYMG(theGrid),sizeof(NODE),NDOBJ); if (pn==NULL) return(NULL); /* initialize data */ SETOBJT(pn,NDOBJ); SETLEVEL(pn,theGrid->level); #ifdef ModelP DDD_AttrSet(PARHDR(pn),GRID_ATTR(theGrid)); /* SETPRIO(pn,PrioMaster); */ pn->message_buffer_ = nullptr; pn->message_buffer_size_ = 0; #endif ID(pn) = (theGrid->mg->nodeIdCounter)++; START(pn) = NULL; SONNODE(pn) = NULL; MYVERTEX(pn) = vertex; if (NOOFNODE(vertex)status |= 1; /* recalculate stiffness matrix */ /* insert in vertex list */ GRID_LINK_NODE(theGrid,pn,PrioMaster); return(pn); } /****************************************************************************/ /** \brief Return pointer to a new node structure on an edge * @param theGrid - grid where vertex should be inserted * @param FatherNode - node father This function creates and initializes a new node structure at the midpoint of an element edge and returns a pointer to it. @return
                                            • pointer to requested object
                                            • NULL if out of memory
                                            */ /****************************************************************************/ NODE *NS_DIM_PREFIX CreateSonNode (GRID *theGrid, NODE *FatherNode) { NODE *pn; VERTEX *theVertex; theVertex = MYVERTEX(FatherNode); pn = CreateNode(theGrid,theVertex,(GEOM_OBJECT *)FatherNode,CORNER_NODE); if (pn == NULL) return(NULL); SONNODE(FatherNode) = pn; #ifdef TOPNODE TOPNODE(theVertex) = pn; #endif return(pn); } /****************************************************************************/ /** \brief Return pointer to a new node structure on an edge * @param theGrid - grid where node should be inserted * @param theElement - pointer to an element * @param theVertex - pointer to vertex if already existing * @param edge - id of an element edge This function creates and initializes a new node structure at the midpoint of an element edge and returns a pointer to it. @return
                                            • pointer to requested object
                                            • NULL if out of memory
                                            */ /****************************************************************************/ NODE *NS_DIM_PREFIX CreateMidNode (GRID *theGrid, ELEMENT *theElement, VERTEX *theVertex, INT edge) { BNDP *bndp; DOUBLE *x[MAX_CORNERS_OF_ELEM]; DOUBLE_VECTOR bnd_global,global; DOUBLE diff; INT n,move; const INT co0 = CORNER_OF_EDGE(theElement,edge,0); const INT co1 = CORNER_OF_EDGE(theElement,edge,1); VERTEX* v0 = MYVERTEX(CORNER(theElement,co0)); VERTEX* v1 = MYVERTEX(CORNER(theElement,co1)); V_DIM_LINCOMB(0.5, CVECT(v0), 0.5, CVECT(v1), global); /* set MIDNODE pointer */ EDGE* theEdge = GetEdge(CORNER(theElement,co0),CORNER(theElement,co1)); ASSERT(theEdge!=NULL); /* allocate vertex */ const bool vertex_null = (theVertex==NULL); if (theVertex==NULL) { if ((OBJT(v0) == BVOBJ) && (OBJT(v1) == BVOBJ)) #ifdef UG_DIM_2 if (OBJT(theElement) == BEOBJ) if (SIDE_ON_BND(theElement,edge)) #endif #ifdef UG_DIM_3 if (EDSUBDOM(theEdge) == 0) #endif { bndp = BNDP_CreateBndP(MGHEAP(MYMG(theGrid)),V_BNDP(v0),V_BNDP(v1),0.5); if (bndp != NULL) { theVertex = CreateBoundaryVertex(theGrid); if (theVertex == NULL) return(NULL); if (BNDP_Global(bndp,bnd_global)) return(NULL); if (BNDP_BndPDesc(bndp,&move)) return(NULL); SETMOVE(theVertex,move); V_BNDP(theVertex) = bndp; V_DIM_COPY(bnd_global,CVECT(theVertex)); FieldVector& local = LCVECT(theVertex); V_DIM_EUKLIDNORM_OF_DIFF(bnd_global,global,diff); if (diff > MAX_PAR_DIST) { SETMOVED(theVertex,1); CORNER_COORDINATES(theElement,n,x); UG_GlobalToLocal(n,(const DOUBLE **)x,bnd_global,local); } else V_DIM_LINCOMB(0.5, LOCAL_COORD_OF_ELEM(theElement,co0), 0.5, LOCAL_COORD_OF_ELEM(theElement,co1),local); PRINTDEBUG(gm,1,("local = %f %f %f\n",local[0],local[1],local[2])); } } if (theVertex == NULL) { /* we need an inner vertex */ theVertex = CreateInnerVertex(theGrid); if (theVertex==NULL) return(NULL); V_DIM_COPY(global,CVECT(theVertex)); V_DIM_LINCOMB(0.5, LOCAL_COORD_OF_ELEM(theElement,co0), 0.5, LOCAL_COORD_OF_ELEM(theElement,co1), LCVECT(theVertex)); } VFATHER(theVertex) = theElement; SETONEDGE(theVertex,edge); } /* allocate node */ NODE* theNode = CreateNode(theGrid,theVertex,(GEOM_OBJECT *)theEdge,MID_NODE); if (theNode==NULL && vertex_null) { DisposeVertex(theGrid,theVertex); return(NULL); } MIDNODE(theEdge) = theNode; #ifdef TOPNODE if (TOPNODE(theVertex)==NULL || LEVEL(TOPNODE(theVertex))ppifContext().me(),ID_PRTX(theNode),NTYPE(theNode), OBJT(NFATHER(theNode)),NFATHER(theNode))); return(theNode); } NODE * NS_DIM_PREFIX GetMidNode (const ELEMENT *theElement, INT edge) { EDGE *theEdge; NODE *theNode; VERTEX *theVertex; theEdge = GetEdge(CORNER(theElement,CORNER_OF_EDGE(theElement,edge,0)), CORNER(theElement,CORNER_OF_EDGE(theElement,edge,1))); if (theEdge == NULL) return(NULL); theNode = MIDNODE(theEdge); if (theNode == NULL) return(NULL); /** \todo This is a bad place for the following code (s.l. 981015) */ theVertex = MYVERTEX(theNode); if (theVertex!=NULL && VFATHER(theVertex) == NULL) { /** \todo Strange that this cast has to be here. O.S. 060902 */ VFATHER(theVertex) = (ELEMENT*)theElement; SETONEDGE(theVertex,edge); V_DIM_LINCOMB(0.5, LOCAL_COORD_OF_ELEM(theElement, CORNER_OF_EDGE(theElement,edge,0)), 0.5, LOCAL_COORD_OF_ELEM(theElement, CORNER_OF_EDGE(theElement,edge,1)), LCVECT(theVertex)); } return(theNode); } /****************************************************************************/ /** \brief ??? */ /****************************************************************************/ static INT SideOfNbElement(const ELEMENT *theElement, INT side) { ELEMENT *nb; NODE *nd[MAX_CORNERS_OF_SIDE]; INT i,j,m,n,num; nb = NBELEM(theElement,side); if (nb == NULL) return(MAX_SIDES_OF_ELEM); for (j=0; j
                                          • pointer to requested object
                                          • NULL if out of memory
                                          */ /****************************************************************************/ NODE *NS_DIM_PREFIX CreateSideNode (GRID *theGrid, ELEMENT *theElement, VERTEX *theVertex, INT side) { DOUBLE_VECTOR bnd_global,global; FieldVector local; DOUBLE *x[MAX_CORNERS_OF_ELEM]; NODE *theNode; BNDP *bndp; BNDS *bnds; DOUBLE fac, diff; INT n,j,k,move,vertex_null; n = CORNERS_OF_SIDE(theElement,side); fac = 1.0 / n; V_DIM_CLEAR(local); V_DIM_CLEAR(global); for (j=0; j bnd_local; if (n == 3) bnd_local[0] = bnd_local[1] = 0.33333333333333; else if (n == 4) bnd_local[0] = bnd_local[1] = 0.5; bndp = BNDS_CreateBndP(MGHEAP(MYMG(theGrid)),bnds,bnd_local); if (bndp != NULL) { theVertex = CreateBoundaryVertex(theGrid); if (theVertex == NULL) return(NULL); if (BNDP_BndPDesc(bndp,&move)) return(NULL); SETMOVE(theVertex,move); if (BNDP_Global(bndp,bnd_global)) return(NULL); V_BNDP(theVertex) = bndp; V_DIM_COPY(bnd_global,CVECT(theVertex)); V_DIM_EUKLIDNORM_OF_DIFF(bnd_global,global,diff); if (diff > MAX_PAR_DIST) { SETMOVED(theVertex,1); CORNER_COORDINATES(theElement,k,x); UG_GlobalToLocal(k,(const DOUBLE **)x,bnd_global,local); PRINTDEBUG(gm,1,("local = %f %f %f\n",local[0],local[1],local[2])); } } } } if (theVertex == NULL) { theVertex = CreateInnerVertex(theGrid); if (theVertex == NULL) return(NULL); V_DIM_COPY(global,CVECT(theVertex)); } VFATHER(theVertex) = theElement; SETONSIDE(theVertex,side); SETONNBSIDE(theVertex,SideOfNbElement(theElement,side)); V_DIM_COPY(local,LCVECT(theVertex)); } /* create node */ theNode = CreateNode(theGrid,theVertex, (GEOM_OBJECT *)theElement,SIDE_NODE); if (theNode==NULL && vertex_null) { DisposeVertex(theGrid,theVertex); return(NULL); } #ifdef TOPNODE if (TOPNODE(theVertex) == NULL || LEVEL(TOPNODE(theVertex))status |= 1; return(theNode); } static NODE *GetSideNodeX (const ELEMENT *theElement, INT side, INT n, NODE **MidNodes) { ELEMENT *theFather; NODE *theNode; VERTEX *theVertex; LINK *theLink0,*theLink1,*theLink2,*theLink3; DOUBLE fac; INT i; if (n == 4) { for (theLink0=START(MidNodes[0]); theLink0!=NULL; theLink0=NEXT(theLink0)) { theNode = NBNODE(theLink0); if (NTYPE(theNode) != SIDE_NODE) continue; for (theLink1=START(MidNodes[1]); theLink1!=NULL; theLink1=NEXT(theLink1)) { if (theNode != NBNODE(theLink1)) continue; for (theLink2=START(MidNodes[2]); theLink2!=NULL; theLink2=NEXT(theLink2)) { if (theNode != NBNODE(theLink2)) continue; for (theLink3=START(MidNodes[3]); theLink3!=NULL; theLink3=NEXT(theLink3)) { if (theNode != NBNODE(theLink3)) continue; theVertex = MYVERTEX(theNode); theFather = VFATHER(theVertex); if (theFather == theElement) { #ifndef ModelP /* HEAPFAULT in theFather possible, if in a previous call of DisposeElement some son is not reached by GetAllSons */ assert(ONSIDE(theVertex) == side); #endif SETONSIDE(theVertex,side); return(theNode); } else if (theFather == NBELEM(theElement,side)) { SETONNBSIDE(theVertex,side); return(theNode); } else if (theFather == NULL) { /** \todo Strange that this cast has to be here */ VFATHER(theVertex) = (ELEMENT*)theElement; SETONSIDE(theVertex,side); SETONNBSIDE(theVertex, SideOfNbElement(theElement,side)); fac = 1.0 / n; Dune::FieldVector& local = LCVECT(theVertex); V_DIM_CLEAR(local); for (i=0; i& local = LCVECT(theVertex); V_DIM_CLEAR(local); for (i=0; i
                                        • pointer to center node
                                        • NULL no node found
                                        */ /****************************************************************************/ NODE * NS_DIM_PREFIX GetCenterNode (const ELEMENT *theElement) { INT i,j; NODE *theNode; ELEMENT *SonList[MAX_SONS],*theSon; #ifdef __CENTERNODE__ return(CENTERNODE(theElement)); #endif theNode = NULL; if (GetAllSons(theElement,SonList) != GM_OK) assert(0); for (i=0; i *
                                      • pointer to new node
                                      • *
                                      • NULL: could not allocate
                                      */ /****************************************************************************/ /* #define MOVE_MIDNODE */ NODE * NS_DIM_PREFIX CreateCenterNode (GRID *theGrid, ELEMENT *theElement, VERTEX *theVertex) { DOUBLE_VECTOR diff; INT n,j,moved,vertex_null; VERTEX *VertexOnEdge[MAX_EDGES_OF_ELEM]; NODE *theNode; EDGE *theEdge; DOUBLE fac; DOUBLE *x[MAX_CORNERS_OF_ELEM]; #ifdef MOVE_MIDNODE #ifndef ModelP DOUBLE len_opp,len_bnd; #endif #endif /* check if moved side nodes exist */ CORNER_COORDINATES(theElement,n,x); moved = 0; vertex_null = (theVertex==NULL); if (theVertex==NULL && OBJT(theElement) == BEOBJ) { for (j=0; jstatus |= 1; if (!vertex_null) return(theNode); FieldVector& global = CVECT(theVertex); FieldVector& local = LCVECT(theVertex); V_DIM_CLEAR(local); fac = 1.0 / n; for (j=0; j
                                    • GM_OK if ok
                                    • != GM_OK if not ok
                                    */ /****************************************************************************/ INT NS_DIM_PREFIX GetNodeContext (const ELEMENT *theElement, NODE **theElementContext) { NODE *theNode, **MidNodes, **CenterNode; EDGE *theEdge; INT i,Corner0, Corner1; #ifdef UG_DIM_3 NODE **SideNodes; #endif /* reset context */ for(i=0; i
                                  • pointer to specified object
                                  • NULL if not found
                                  */ /****************************************************************************/ EDGE * NS_DIM_PREFIX GetSonEdge (const EDGE *theEdge) { EDGE *SonEdge=NULL; NODE *Node0,*Node1,*SonNode0,*SonNode1; Node0 = NBNODE(LINK0(theEdge)); Node1 = NBNODE(LINK1(theEdge)); SonNode0 = SONNODE(Node0); SonNode1 = SONNODE(Node1); if (SonNode0!=NULL && SonNode1!=NULL) SonEdge = GetEdge(SonNode0,SonNode1); return(SonEdge); } /****************************************************************************/ /** \brief Return pointer to son edges if it exists * @param theEdge - edge for which son is searched * @param SonEdges - array of pointers will be filled with son edges This function returns the pointer to the son edges if existing. @return
                                  • number of found edges (0,1,2)
                                  */ /****************************************************************************/ INT NS_DIM_PREFIX GetSonEdges (const EDGE *theEdge, EDGE *SonEdges[MAX_SON_EDGES]) { INT nedges; NODE *Node0,*Node1,*SonNode0,*SonNode1,*MidNode; nedges = 0; SonEdges[0] = NULL; SonEdges[1] = NULL; Node0 = NBNODE(LINK0(theEdge)); Node1 = NBNODE(LINK1(theEdge)); if (GID(Node0)
                                • pointer to specified object
                                • NULL if not found
                                */ /****************************************************************************/ EDGE * NS_DIM_PREFIX GetFatherEdge (const EDGE *theEdge) { NODE *theNode0 = NBNODE(LINK0(theEdge)); NODE *theNode1 = NBNODE(LINK1(theEdge)); EDGE *FatherEdge = NULL; /* one node is center node -> no father edge */ if (CENTERTYPE(theNode0) || CENTERTYPE(theNode1)) return(NULL); #ifdef UG_DIM_3 /* one node is side node -> no father edge */ if (SIDETYPE(theNode0) || SIDETYPE(theNode1)) return(NULL); #endif /* both nodes are mid nodes -> no father edge */ if (MIDTYPE(theNode0) && MIDTYPE(theNode1)) return(NULL); /* one node is mid node -> no father edge */ if (MIDTYPE(theNode0) || MIDTYPE(theNode1)) { NODE *FatherNode0,*FatherNode1, *theNode; if (MIDTYPE(theNode1)) { theNode = theNode0; theNode0 = theNode1; theNode1 = theNode; } FatherEdge = (EDGE *) NFATHER(theNode0); if (FatherEdge == NULL) return(NULL); FatherNode0 = NBNODE(LINK0(FatherEdge)); FatherNode1 = NBNODE(LINK1(FatherEdge)); if (SONNODE(FatherNode0)==theNode1 || SONNODE(FatherNode1)==theNode1) return(FatherEdge); else return(NULL); } /* both nodes are corner nodes -> try to get the edge */ if (CORNERTYPE(theNode0) && CORNERTYPE(theNode1)) { if (NFATHER(theNode0)!=NULL && NFATHER(theNode1)!=NULL) return(GetEdge(NFATHER(theNode0),NFATHER(theNode1))); else return(NULL); } /* No father available */ return NULL; } #ifdef UG_DIM_3 /****************************************************************************/ /** \brief Return pointer to father edge if it exists * @param SideNodes - nodes of the side * @param ncorners - number of sidenodes * @param Nodes - corners of edge for which father is searched * @param theEdge - edge for which father is searched This function returns the pointer to the father edge if it exists. @return
                                • pointer to specified object
                                • NULL if not found
                                */ /****************************************************************************/ EDGE * NS_DIM_PREFIX FatherEdge (NODE **SideNodes, INT ncorners, NODE **Nodes, EDGE *theEdge) { INT pos0,pos1; EDGE *fatherEdge = NULL; ASSERT(Nodes[0]!=NULL); ASSERT(Nodes[1]!=NULL); /* one node is side node -> no father edge */ if (NTYPE(Nodes[0])==SIDE_NODE || NTYPE(Nodes[1])==SIDE_NODE) return(NULL); /* both nodes are side nodes -> no father edge */ if (NTYPE(Nodes[0])==MID_NODE && NTYPE(Nodes[1])==MID_NODE) return(NULL); for (pos0=0; pos0=ncorners); ASSERT(pos0<2*ncorners); if ((pos0+1)%ncorners == pos1) { ASSERT(OBJT(NFATHER(SideNodes[pos0%ncorners])) == NDOBJ); fatherEdge = GetEdge((NODE *)NFATHER(SideNodes[pos0%ncorners]), (NODE *)NFATHER(Nodes[1])); ASSERT(fatherEdge!=NULL); } if (pos0%ncorners == pos1) { ASSERT(OBJT(NFATHER(SideNodes[(pos0+1)%ncorners])) == NDOBJ); fatherEdge = GetEdge((NODE *)NFATHER(SideNodes[(pos0+1)%ncorners]), (NODE *)NFATHER(Nodes[1])); ASSERT(fatherEdge!=NULL); } break; case (SIDE_NODE) : /* this edge has no father edge */ fatherEdge = NULL; break; default : assert(0); break; } IFDEBUG(dddif,1) INT i; EDGE* edge0, *edge1; edge0 = edge1 = NULL; /* test whether theEdge lies above fatherEdge */ if (fatherEdge!=NULL) { if (MIDNODE(fatherEdge)!=NULL) { edge0 = GetEdge(MIDNODE(fatherEdge),SONNODE(NBNODE(LINK0(fatherEdge)))); edge1 = GetEdge(MIDNODE(fatherEdge),SONNODE(NBNODE(LINK1(fatherEdge)))); } else edge0 = GetEdge(SONNODE(NBNODE(LINK0(fatherEdge))), SONNODE(NBNODE(LINK1(fatherEdge)))); IFDEBUG(dddif,5) UserWriteF("fatherEdge=%x theEdge=%x edge0=%x edge1=%x\n", fatherEdge,theEdge,edge0,edge1); UserWriteF("Nodes[0]=%d Nodes[1]=%d\n",ID(Nodes[0]),ID(Nodes[1])); UserWriteF("SideNodes\n"); for (i=0; i
                              • pointer to specified object
                              • NULL if not found
                              */ /****************************************************************************/ EDGE * NS_DIM_PREFIX GetEdge (const NODE *from, const NODE *to) { LINK *pl; /* run through neighbor list */ for (pl=START(from); pl!=NULL; pl = NEXT(pl)) if (NBNODE(pl)==to) return(MYEDGE(pl)); /* return not found */ return(NULL); } /****************************************************************************/ /** \brief Return pointer to a new edge structure * @param theGrid - grid where vertex should be inserted * @param theElement - pointer to element * @param edge - number of edge * @param with_vector - also create vector for edge (true/false) This function returns a pointer to a new edge structure. @return
                              • pointer to requested object
                              • NULL if out of memory
                              */ /****************************************************************************/ #ifndef ModelP static #endif EDGE * #ifdef ModelP NS_DIM_PREFIX #endif CreateEdge (GRID *theGrid, ELEMENT *theElement, INT edge, bool with_vector) { ELEMENT *theFather; EDGE *pe,*father_edge; NODE *from,*to,*n1,*n2; LINK *link0,*link1; #ifdef UG_DIM_3 VERTEX *theVertex; NODE *nbn1,*nbn2,*nbn3,*nbn4; INT sc,found,side,k,j; #endif from = CORNER(theElement,CORNER_OF_EDGE(theElement,edge,0)); to = CORNER(theElement,CORNER_OF_EDGE(theElement,edge,1)); /* check if edge exists already */ if( (pe = GetEdge(from, to)) != NULL ) { if (NO_OF_ELEM(pe)mg,sizeof(EDGE)-sizeof(VECTOR*),EDOBJ); if (pe==NULL) return(NULL); /* initialize data */ link0 = LINK0(pe); link1 = LINK1(pe); SETOBJT(pe,EDOBJ); SETLOFFSET(link0,0); SETLOFFSET(link1,1); pe->id = (theGrid->mg->edgeIdCounter)++; SETLEVEL(pe,GLEVEL(theGrid)); #ifdef ModelP DDD_AttrSet(PARHDR(pe), GRID_ATTR(theGrid)); /* SETPRIO(pe,PrioMaster); */ #endif #ifdef IDENT_ONLY_NEW if (GET_IDENT_MODE() == IDENT_ON) SETNEW_EDIDENT(pe,1); #endif UGM_CDBG(pe, UserWriteF(PFMT "create edge=" EDID_FMTX " from=" ID_FMTX "tf=%d to=" ID_FMTX "tt=%d" "elem=" EID_FMTX "edge=%d\n", theGrid->ppifContext().me(),EDID_PRTX(pe),ID_PRTX(from),NTYPE(from),ID_PRTX(to),NTYPE(to), EID_PRTX(theElement),edge); if (0) UserWriteF(PFMT "nfatherf=" ID_FMTX "nfathert=" ID_FMTX " fatheredge=" EDID_FMTX "\n", theGrid->ppifContext().me(),ID_PRTX((NODE*)NFATHER(from)),ID_PRTX((NODE*)NFATHER(to)), EDID_PRTX(GetEdge((NODE*)NFATHER(from),(NODE*)NFATHER(to))));) NBNODE(link0) = to; NBNODE(link1) = from; SET_NO_OF_ELEM(pe,1); SETEDGENEW(pe,1); /* set edge-subdomain from topological information with respect to father-element */ SETEDSUBDOM(pe,SUBDOMAIN(theElement)); theFather = EFATHER(theElement); if (theFather!=NULL) { SETEDSUBDOM(pe,SUBDOMAIN(theFather)); if (NTYPE(from)=0 && (OBJT(theFather)==BEOBJ) && SIDE_ON_BND(theFather,side)) SETEDSUBDOM(pe,0); } break; case (MID_NODE | (MID_NODE<<4)) : father_edge = NFATHEREDGE(n1); assert(father_edge!=NULL); nbn1 = NBNODE(LINK0(father_edge)); nbn2 = NBNODE(LINK1(father_edge)); father_edge = NFATHEREDGE(n2); assert(father_edge!=NULL); nbn3 = NBNODE(LINK0(father_edge)); nbn4 = NBNODE(LINK1(father_edge)); /* do all nodes nbn1, nbn2, nbn3, nbn4 ly on the same side of father? */ side=-1; for (j=0; j=0 && (OBJT(theFather)==BEOBJ) && SIDE_ON_BND(theFather,side)) SETEDSUBDOM(pe,0); break; case (CORNER_NODE | (SIDE_NODE<<4)) : theVertex = MYVERTEX(n2); if (VFATHER(theVertex) == theFather) side = ONSIDE(theVertex); else side = ONNBSIDE(theVertex); if ((OBJT(theFather)==BEOBJ) && SIDE_ON_BND(theFather,side)) for (k=0; k
                            • pointer to specified link
                            • NULL if not found.
                            */ /****************************************************************************/ LINK *GetLink (const NODE *from, const NODE *to) { LINK *pl; /* run through neighbor list */ for (pl=START(from); pl!=NULL; pl = NEXT(pl)) if (NBNODE(pl)==to) return(pl); /* return not found */ return(NULL); } /****************************************************************************/ /** \brief Return a pointer to a new element structure * @param theGrid - grid structure to extend * @param tag - the element type * @param objtype - inner element (IEOBJ) or boundary element (BEOBJ) * @param nodes - list of corner nodes in reference numbering * @param Father - pointer to father element (NULL on base level) * @param with_vector - This function creates and initializes a new element and returns a pointer to it. @return
                            • pointer to requested object
                            • NULL if out of memory
                            */ /****************************************************************************/ ELEMENT * NS_DIM_PREFIX CreateElement (GRID *theGrid, INT tag, INT objtype, NODE **nodes, ELEMENT *Father, bool with_vector) { ELEMENT *pe; INT i,s_id; if (objtype == IEOBJ) pe = (ELEMENT*)GetMemoryForObject(MYMG(theGrid),INNER_SIZE_TAG(tag), MAPPED_INNER_OBJT_TAG(tag)); else if (objtype == BEOBJ) pe = (ELEMENT*)GetMemoryForObject(MYMG(theGrid),BND_SIZE_TAG(tag), MAPPED_BND_OBJT_TAG(tag)); else std::abort(); if (pe==NULL) return(NULL); /* initialize data */ SETNEWEL(pe,1); SETOBJT(pe,objtype); SETTAG(pe,tag); SETLEVEL(pe,theGrid->level); #ifdef ModelP DDD_AttrSet(PARHDRE(pe),GRID_ATTR(theGrid)); /* SETEPRIO(theGrid->dddContext(), pe,PrioMaster); */ PARTITION(pe) = theGrid->ppifContext().me(); #endif ID(pe) = (theGrid->mg->elemIdCounter)++; /* subdomain id */ s_id = (Father != NULL) ? SUBDOMAIN(Father) : 0; SETSUBDOMAIN(pe,s_id); #ifdef __CENTERNODE__ SET_CENTERNODE(pe,NULL); #endif SET_EFATHER(pe,Father); /* set corner nodes */ for (i=0; ilevel>0) { INT where = PRIO2INDEX(PrioMaster); #ifndef ModelP ASSERT(Father != NULL); #endif if (Father != NULL) { if (SON(Father,where) == NULL) SET_SON(Father,where,pe); SETNSONS(Father,NSONS(Father)+1); } } /* return ok */ return(pe); } /****************************************************************************/ /** \brief Creates the element sides of son elements * @param theGrid - grid for which to create * @param theElement - pointer to a boundary element * @param side - side id of a side of the element * @param theSon - pointer to a son element * @param son_side - side id of a side of the son This function creates and initializes an element side of a son element. Here also the side vector (iff at all) is inspected in 'ReinspectSonSideVector'. The latter function eventually reallocates the vector if its size has changed. @return
                            • GM_OK if ok
                            • GM_ERROR when error occurred.
                            */ /****************************************************************************/ INT NS_DIM_PREFIX CreateSonElementSide (GRID *theGrid, ELEMENT *theElement, INT side, ELEMENT *theSon, INT son_side) { INT n,i; BNDS *bnds; BNDP *bndp[MAX_CORNERS_OF_ELEM]; ASSERT (OBJT(theElement) == BEOBJ); ASSERT (ELEM_BNDS(theElement,side) != NULL); /* check if Edges of theElement, which are on the side 'side' have EDSUBDOM 0 */ n = CORNERS_OF_SIDE(theElement,side); for (i=0; ippifContext().me(),EID_PRTX(theElement),EID_PRTX(theSon),VID_PRTX(MYVERTEX(CORNER(theSon,CORNER_OF_SIDE(theSon,son_side,i))))); printf(PFMT "NTYPE = MID_NODE\n",theGrid->ppifContext().me()); theFatherEdge = NFATHEREDGE(theNode); printf(PFMT "EDSUBDOM = %d\n",theGrid->ppifContext().me(),(int)EDSUBDOM(theFatherEdge)); t1 = (OBJT(MYVERTEX(NBNODE(LINK0(theFatherEdge))))==BVOBJ); t2 = (OBJT(MYVERTEX(NBNODE(LINK1(theFatherEdge))))==BVOBJ); printf(PFMT "BVOBJ(theFatherEdge): %d %d\n",theGrid->ppifContext().me(),(int)t1,(int)t2); break; case SIDE_NODE : printf("NTYPE = SIDE_NODE"); break; case CENTER_NODE : printf("NTYPE = CENTER_NODE"); break; } ASSERT(0); } bndp[i] = V_BNDP(MYVERTEX(CORNER(theSon,CORNER_OF_SIDE(theSon,son_side,i)))); } bnds = BNDP_CreateBndS(MGHEAP(MYMG(theGrid)),bndp,n); if (bnds == NULL) RETURN(GM_ERROR); SET_BNDS(theSon,son_side,bnds); #ifdef UG_DIM_2 const EDGE* theEdge = GetEdge(CORNER(theSon,CORNER_OF_EDGE(theSon,son_side,0)), CORNER(theSon,CORNER_OF_EDGE(theSon,son_side,1))); ASSERT(theEdge != NULL); SETEDSUBDOM(theEdge,0); #endif #ifdef UG_DIM_3 /** \todo is this necessary? for (i=0; i
                          • pointer to requested object
                          • NULL if out of memory
                          */ /****************************************************************************/ GRID * NS_DIM_PREFIX CreateNewLevel (MULTIGRID *theMG) { GRID *theGrid; if (TOPLEVEL(theMG)+1>=MAXLEVEL) return(NULL); INT l = TOPLEVEL(theMG)+1; /* allocate grid object */ theGrid = (GRID*)GetMemoryForObject(theMG,sizeof(GRID),GROBJ); if (theGrid==NULL) return(NULL); /* fill in data */ CTRL(theGrid) = 0; SETOBJT(theGrid,GROBJ); GLEVEL(theGrid) = l; NE(theGrid) = 0; /* other counters are init in INIT fcts below */ GSTATUS(theGrid,0); GRID_INIT_ELEMENT_LIST(theGrid); GRID_INIT_NODE_LIST(theGrid); GRID_INIT_VERTEX_LIST(theGrid); GRID_INIT_VECTOR_LIST(theGrid); if (l>0) { DOWNGRID(theGrid) = GRID_ON_LEVEL(theMG,l-1); UPGRID(GRID_ON_LEVEL(theMG,l-1)) = theGrid; UPGRID(theGrid) = NULL; } else if (l==0) { DOWNGRID(theGrid) = NULL; UPGRID(theGrid) = NULL; } else { UPGRID(theGrid) = GRID_ON_LEVEL(theMG,l+1); DOWNGRID(theGrid) = NULL; DOWNGRID(GRID_ON_LEVEL(theMG,l+1)) = theGrid; } MYMG(theGrid) = theMG; GRID_ON_LEVEL(theMG,l) = theGrid; TOPLEVEL(theMG) = l; return(theGrid); } /****************************************************************************/ /** \brief Create a multigrid environment item * @param name - name of the multigrid This function creates a multigrid environment directory. @return
                          • pointer to new MULTIGRID
                          • NULL if error occurred
                          */ /****************************************************************************/ MULTIGRID * NS_DIM_PREFIX MakeMGItem (const char *name, std::shared_ptr ppifContext) { MULTIGRID *theMG; if (ChangeEnvDir("/Multigrids") == NULL) return (NULL); if (strlen(name)>=NAMESIZE || strlen(name)<=1) return (NULL); theMG = (MULTIGRID *) MakeEnvItem(name,theMGDirID,sizeof(MULTIGRID)); if (theMG == NULL) return(NULL); new(theMG) multigrid; #if ModelP theMG->ppifContext_ = ppifContext; theMG->dddContext_ = std::make_shared( theMG->ppifContext_, std::make_shared() ); InitDDD(theMG->dddContext()); globalDDDContext(theMG->dddContext_); #else theMG->ppifContext_ = std::make_shared(); #endif return (theMG); } /****************************************************************************/ /** \todo Please doc me! * @param theMG * @param FromLevel * @param ToLevel * @param mask DESCRIPTION: @return INT */ /****************************************************************************/ INT NS_DIM_PREFIX ClearMultiGridUsedFlags (MULTIGRID *theMG, INT FromLevel, INT ToLevel, INT mask) { int i,level,elem,node,edge,vertex,vector; GRID *theGrid; ELEMENT *theElement; NODE *theNode; EDGE *theEdge; VECTOR *theVector; elem = mask & MG_ELEMUSED; node = mask & MG_NODEUSED; edge = mask & MG_EDGEUSED; vertex = mask & MG_VERTEXUSED; vector = mask & MG_VECTORUSED; for (level=FromLevel; level<=ToLevel; level++) { theGrid = GRID_ON_LEVEL(theMG,level); if (elem || edge) for (theElement=PFIRSTELEMENT(theGrid); theElement!=NULL; theElement=SUCCE(theElement)) { if (elem) SETUSED(theElement,0); if (edge) { for (i=0; i
                        • pointer to MULTIGRID
                        • NULL if not found.
                        */ /****************************************************************************/ MULTIGRID * NS_DIM_PREFIX GetMultigrid (const char *name) { return ((MULTIGRID *) SearchEnv(name,"/Multigrids", theMGDirID,theMGRootDirID)); } /****************************************************************************/ /** \brief Return a pointer to the first multigrid This function returns a pointer to the first multigrid in the /Multigrids directory. @return
                        • pointer to MULTIGRID
                        • NULL if not found.
                        */ /****************************************************************************/ MULTIGRID * NS_DIM_PREFIX GetFirstMultigrid () { ENVDIR *theMGRootDir; MULTIGRID *theMG; theMGRootDir = ChangeEnvDir("/Multigrids"); assert (theMGRootDir!=NULL); theMG = (MULTIGRID *) ENVDIR_DOWN(theMGRootDir); if (theMG != NULL) { #ifdef ModelP InitCurrMG(theMG); #endif } return (theMG); } /****************************************************************************/ /** \brief Return a pointer to the next multigrid * @param theMG - multigrid structure This function returns a pointer to the next multigrid in the /Multigrids directory. @return
                        • pointer to MULTIGRID
                        • NULL if not found.
                        */ /****************************************************************************/ MULTIGRID * NS_DIM_PREFIX GetNextMultigrid (const MULTIGRID *theMG) { MULTIGRID *MG; MG = (MULTIGRID *) NEXT_ENVITEM(theMG); if (MG != NULL) { #ifdef ModelP InitCurrMG(MG); #endif } return (MG); } /****************************************************************************/ /** \brief Return a pointer to new multigrid structure * @param MultigridName - name of multigrid * @param domain - name of domain description from environment * @param problem - name of problem description from environment * @param format - name of format description from environment * @param optimizedIE - allocate NodeElementList This function creates and initializes a new multigrid structure including allocation of heap, combining the domain and the boundary conditions and creation of the fixed corners of the domain. @return
                        • pointer to new object
                        • NULL if an error occurred.
                        */ /****************************************************************************/ MULTIGRID * NS_DIM_PREFIX CreateMultiGrid (char *MultigridName, STD_BVP *theBVP, const char *format, INT optimizedIE, INT insertMesh, std::shared_ptr ppifContext) { HEAP *theHeap; MULTIGRID *theMG; INT i; MESH mesh; INT MarkKey; if (not ppifContext) ppifContext = std::make_shared(); /* allocate multigrid envitem */ theMG = MakeMGItem(MultigridName, ppifContext); if (theMG==NULL) return(NULL); #ifdef ModelP InitCurrMG(theMG); #endif /* allocate the heap */ /* When using the system heap: allocate just enough memory for the actual bookkeeping data structure */ theHeap = NewHeap(SIMPLE_HEAP, sizeof(HEAP), malloc(sizeof(HEAP))); if (theHeap==NULL) { UserWriteF("CreateMultiGrid: cannot allocate %ld bytes\n", sizeof(HEAP)); PrintErrorMessage('E', "CreateMultiGrid","Cannot allocate heap!"); DisposeMultiGrid(theMG); return(NULL); } /* mark temp memory here, release it after coarse grid construction in FixCoarseGrid */ MarkTmpMem(theHeap,&MarkKey); MG_MARK_KEY(theMG) = MarkKey; if (insertMesh) BVP_Init(theBVP,theHeap,&mesh,MarkKey); else BVP_Init(theBVP,theHeap,NULL,MarkKey); if (theBVP==NULL) { PrintErrorMessage('E',"CreateMultiGrid","BVP not found"); return(NULL); } theMG->BVP_Name = "dummy BVP name"; /* 1: general user data space */ // As we are using this version only with DUNE, we will never have UG user data /* 2: user heap */ // As we are using this version only with DUNE, we will never need the user heap /* fill multigrid structure */ theMG->status = 0; MG_COARSE_FIXED(theMG) = 0; theMG->vertIdCounter = 0; theMG->nodeIdCounter = 0; theMG->elemIdCounter = 0; theMG->edgeIdCounter = 0; #ifndef ModelP theMG->vectorIdCounter = 0; #endif theMG->topLevel = -1; MG_BVP(theMG) = theBVP; RESETMGSTATUS(theMG); theMG->theHeap = theHeap; for (i=0; ippifContext().isMaster()) { #endif if (InsertMesh(theMG,&mesh)) { DisposeMultiGrid(theMG); return(NULL); } #ifdef ModelP } #endif ASSERT(mesh.mesh_status!=MESHSTAT_NOTINIT); if (mesh.mesh_status==MESHSTAT_MESH) if (FixCoarseGrid(theMG)) { DisposeMultiGrid(theMG); return(NULL); } } /* return ok */ return(theMG); } /****************************************************************************/ /** \brief Remove edge from the data structure * @param theGrid - grid to remove from * @param theEdge - edge to remove This function remove an edge from the data structure including its vector (if one) and inserts them into the free list. @return
                        • 0 if ok
                        • 1 if an error occurred.
                        */ /****************************************************************************/ static INT DisposeEdge (GRID *theGrid, EDGE *theEdge) { LINK *link0,*link1,*pl; NODE *from,*to; INT found; /* reconstruct data */ link0 = LINK0(theEdge); link1 = LINK1(theEdge); from = NBNODE(link1); to = NBNODE(link0); found = 0; /* delete link0 in from vertex */ if (START(from)==link0) { START(from) = NEXT(link0); found++; } else { for (pl=START(from); pl!=NULL; pl = NEXT(pl)) { if (NEXT(pl)==link0) { NEXT(pl) = NEXT(link0); found++; break; } } } /* delete link1 in to vertex */ if (START(to)==link1) { START(to) = NEXT(link1); found++; } else { for (pl=START(to); pl!=NULL; pl = NEXT(pl)) { if (NEXT(pl)==link1) { NEXT(pl) = NEXT(link1); found++; break; } } } /* reset pointer of midnode to edge */ if (MIDNODE(theEdge) != NULL) SETNFATHER(MIDNODE(theEdge),NULL); PutFreeObject(theGrid->mg,theEdge,sizeof(EDGE)-sizeof(VECTOR*),EDOBJ); /* check error condition */ if (found!=2) RETURN(1); /* return ok */ NE(theGrid)--; return(0); } /****************************************************************************/ /** \brief Remove node including its edges from the data structure * @param theGrid - grid to remove from * @param theNode - node to remove This function removes node including its edges and vector (if one) from the data structure and inserts all objects into the free list. @return
                        • 0 if ok
                        • 1 when error occurred.
                        */ /****************************************************************************/ INT NS_DIM_PREFIX DisposeNode (GRID *theGrid, NODE *theNode) { VERTEX *theVertex; GEOM_OBJECT *father; /* call DisposeElement first! */ assert(START(theNode) == NULL); #ifdef ModelP if (SONNODE(theNode) != NULL) { SETNFATHER(SONNODE(theNode),NULL); } #else assert(SONNODE(theNode) == NULL); #endif /* remove node from node list */ GRID_UNLINK_NODE(theGrid,theNode); theVertex = MYVERTEX(theNode); father = (GEOM_OBJECT *)NFATHER(theNode); if (father != NULL) { switch (NTYPE(theNode)) { case (CORNER_NODE) : ASSERT(OBJT(father) == NDOBJ); SONNODE((NODE *)father) = NULL; #ifdef TOPNODE if (theVertex != NULL) TOPNODE(theVertex) = (NODE *)father; #endif break; case (MID_NODE) : ASSERT(OBJT(father) == EDOBJ); MIDNODE((EDGE *)father) = NULL; break; #ifdef __CENTERNODE__ case (CENTER_NODE) : ASSERT(OBJT(father)==IEOBJ || OBJT(father)==BEOBJ); SET_CENTERNODE((ELEMENT *)father,NULL); break; #endif default : ASSERT(0); break; } } /** \todo delete old vertex handling */ if (0) if (theVertex != NULL) { #ifdef ModelP /* vertices have to be linked and unlinked */ /* relative to the level they are created for */ INT levelofvertex = LEVEL(theVertex); MULTIGRID *MG = MYMG(theGrid); GRID *GridOfVertex = GRID_ON_LEVEL(MG,levelofvertex); if (SONNODE(theNode) == NULL) DisposeVertex(GridOfVertex,theVertex); #else DisposeVertex(theGrid,theVertex); #endif } if (NOOFNODE(theVertex)<1) RETURN(GM_ERROR); if (NOOFNODE(theVertex)==1) DisposeVertex(theGrid,theVertex); else DECNOOFNODE(theVertex); #ifdef ModelP /* free message buffer */ theNode->message_buffer_free(); #endif PutFreeObject(theGrid->mg,theNode,sizeof(NODE),NDOBJ); /* return ok */ return(0); } /****************************************************************************/ /** \brief Remove vertex from the data structure * @param theGrid - grid to remove from * @param theVertex - vertex to remove This function removes a vertex from the data structure and puts it into the free list. @return
                        • 0 if ok
                        • 1 no valid object number
                        */ /****************************************************************************/ static INT DisposeVertex (GRID *theGrid, VERTEX *theVertex) { // The following call to HEAPFAULT triggers a failing assertion in some // distributed settings. I don't know whether this is the sign of a hidden bug // somewhere, or whether HEAPFAULT is an obsolete left-over of UG3's // hand-written manual memory heap. //HEAPFAULT(theVertex); PRINTDEBUG(gm,1,(PFMT "DisposeVertex(): Gridlevel=%d theVertex=" VID_FMTX "\n", theGrid->ppifContext().me(),GLEVEL(theGrid),VID_PRTX(theVertex))); theGrid = GRID_ON_LEVEL(MYMG(theGrid),LEVEL(theVertex)); /* remove vertex from vertex list */ GRID_UNLINK_VERTEX(theGrid,theVertex); if( OBJT(theVertex) == BVOBJ ) { BNDP_Dispose(MGHEAP(MYMG(theGrid)),V_BNDP(theVertex)); PutFreeObject(MYMG(theGrid),theVertex,sizeof(struct bvertex),BVOBJ); } else PutFreeObject(MYMG(theGrid),theVertex,sizeof(struct ivertex),IVOBJ); return(0); } /****************************************************************************/ /** \brief Remove element from the data structure * @param theGrid - grid to remove from * @param theElement - element to remove This function removes an element from the data structure and inserts it into the free list. This includes all elementsides, sidevectors and the elementvector if they exist. @return
                        • 0 if ok
                        • 1 no valid object number.
                        */ /****************************************************************************/ INT NS_DIM_PREFIX DisposeElement (GRID *theGrid, ELEMENT *theElement) { INT j,tag; NODE *theNode; VERTEX *theVertex; EDGE *theEdge; BNDS *bnds; ELEMENT *theFather; ELEMENT *succe = SUCCE(theElement); #ifdef UG_DIM_3 VECTOR *theVector; DOUBLE fac; INT k,m,o,l; #endif GRID_UNLINK_ELEMENT(theGrid,theElement); #ifdef __CENTERNODE__ { theNode = CENTERNODE(theElement); if (theNode != NULL) SETNFATHER(theNode,NULL); } #endif theFather = EFATHER(theElement); if (LEVEL(theElement)>0) { #ifndef ModelP ASSERT(theFather != NULL); #endif /* check intergrid pointer from father */ if (theFather != NULL) { #ifdef ModelP int index = PRIO2INDEX(EPRIO(theElement)); #else int index = 0; #endif ELEMENT *Next = NULL; ASSERT(index!=-1 && index<2); if (SON(theFather,index) == theElement) { if (succe != NULL) { if (EFATHER(succe)==theFather) #ifdef ModelP if (PRIO2INDEX(EPRIO(succe)) == PRIO2INDEX(EPRIO(theElement))) #endif { Next = succe; } } SET_SON(theFather,index,Next); } SETNSONS(theFather,NSONS(theFather)-1); PRINTDEBUG(gm,2,(PFMT "DisposeElement(): elem=" EID_FMTX " father=" EID_FMTX " son0=%x son1=%x\n", theGrid->ppifContext().me(),EID_PRTX(theElement),EID_PRTX(theFather), SON(theFather,0),SON(theFather,1))); } } #ifdef ModelP /* reset father pointers of sons */ /** \todo possibly some son cannot be reached by GetAllSons, */ /* because their father has not been on this proc and */ /* they lost their father pointers */ if (NSONS(theElement)>0) { ELEMENT *SonList[MAX_SONS]; if (GetAllSons(theElement,SonList)) RETURN(GM_FATAL); INT i = 0; while (ippifContext().me(),EID_PRTX(theElement),EID_PRTX(SonList[i]))); SET_EFATHER(SonList[i],NULL); /* reset VFATHER of centernode vertex */ for (j=0; j& local = LCVECT(theVertex); fac = 1.0 / m; V_DIM_CLEAR(local); for (o=0; omessage_buffer_free(); #endif /* dispose element */ /* give it a new tag ! (I know this is somewhat ugly) */ tag = TAG(theElement); if (OBJT(theElement)==BEOBJ) { SETOBJT(theElement,MAPPED_BND_OBJT_TAG(tag)); PutFreeObject(theGrid->mg,theElement, BND_SIZE_TAG(tag),MAPPED_BND_OBJT_TAG(tag)); } else { SETOBJT(theElement,MAPPED_INNER_OBJT_TAG(tag)); PutFreeObject(theGrid->mg,theElement,INNER_SIZE_TAG(tag), MAPPED_INNER_OBJT_TAG(tag)); } return(0); } #ifndef ModelP #define DO_NOT_DISPOSE return (2) #else #define DO_NOT_DISPOSE dispose=0 #endif /****************************************************************************/ /** \brief Construct coarse grid from surface * @param theMG - multigrid to collapse This function constructs coarse grid from surface. ATTENTION: Use refine $g to cover always the whole domain with the grid on each level. @return
                        • 0 if ok
                        • 1 no valid object number
                        • 2 grid structure not empty or level 0
                        */ /****************************************************************************/ INT NS_DIM_PREFIX Collapse (MULTIGRID *theMG) { GRID *theGrid; ELEMENT *theElement; NODE *theNode; EDGE *theEdge; VERTEX *theVertex; #ifdef ModelP VECTOR *vec; #endif INT tl = TOPLEVEL(theMG); INT l,i; #ifdef ModelP DDD_XferBegin(theMG->dddContext()); #ifdef DDDOBJMGR DDD_ObjMgrBegin(); #endif #endif for (l=tl-1; l>=0; l--) { theGrid = GRID_ON_LEVEL(theMG,l); for (theNode=PFIRSTNODE(theGrid); theNode != NULL; theNode = SUCCN(theNode)) { SONNODE(theNode) = NULL; SETNFATHER(theNode,NULL); } for (theElement=PFIRSTELEMENT(theGrid); theElement != NULL; theElement = SUCCE(theElement)) { SETNSONS(theElement,0); SET_SON(theElement,0,NULL); #ifdef ModelP SET_SON(theElement,1,NULL); #endif for (i=0; idddContext()); #endif /* move top level grid to bottom (level 0) */ theGrid = GRID_ON_LEVEL(theMG,tl); theGrid->finer = NULL; theGrid->coarser = NULL; theGrid->level = 0; GRID_ON_LEVEL(theMG,tl) = NULL; GRID_ON_LEVEL(theMG,0) = theGrid; theMG->topLevel = 0; theMG->fullrefineLevel = 0; for (theNode=PFIRSTNODE(theGrid); theNode != NULL; theNode = SUCCN(theNode)) { SETNFATHER(theNode,NULL); SETNTYPE(theNode,LEVEL_0_NODE); SETNCLASS(theNode,3); SETNNCLASS(theNode,0); SETLEVEL(theNode,0); VFATHER(MYVERTEX(theNode)) = NULL; #ifdef ModelP DDD_AttrSet(PARHDR(theNode),GRID_ATTR(theGrid)); #endif } for (theElement=PFIRSTELEMENT(theGrid); theElement != NULL; theElement = SUCCE(theElement)) { SETECLASS(theElement,RED_CLASS); SET_EFATHER(theElement,NULL); SETLEVEL(theElement,0); #ifdef ModelP DDD_AttrSet(PARHDRE(theElement),GRID_ATTR(theGrid)); #endif for (i=0; idddContext()); #endif if (MG_COARSE_FIXED(theMG)) if (CreateAlgebra(theMG)) REP_ERR_RETURN(1); return(0); } /****************************************************************************/ /** \brief Remove top level grid from multigrid structure * @param theMG - multigrid to remove from This function removes the top level grid from multigrid structure. @return
                        • 0 if ok
                        • 1 no valid object number
                        • 2 grid structure not empty or level 0
                        */ /****************************************************************************/ INT NS_DIM_PREFIX DisposeTopLevel (MULTIGRID *theMG) { int l; GRID *theGrid; #ifdef ModelP int dispose = 1; #endif /* level 0 can not be deleted */ l = theMG->topLevel; if (l<=0) DO_NOT_DISPOSE; theGrid = GRID_ON_LEVEL(theMG,l); /* is level empty */ if (PFIRSTELEMENT(theGrid)!=NULL) DO_NOT_DISPOSE; if (PFIRSTVERTEX(theGrid)!=NULL) DO_NOT_DISPOSE; if (PFIRSTNODE(theGrid)!=NULL) DO_NOT_DISPOSE; #ifdef ModelP dispose = UG_GlobalMinINT(theMG->ppifContext(), dispose); if (!dispose) return(2); #endif /* remove from grids array */ GRID_ON_LEVEL(theMG,l) = NULL; GRID_ON_LEVEL(theMG,l-1)->finer = NULL; (theMG->topLevel)--; PutFreeObject(theMG,theGrid,sizeof(GRID),GROBJ); return(0); } /****************************************************************************/ /** \brief Dispose top level grid * @param theGrid - grid to be removed This function removes the top level grid from multigrid structure. @return
                        • 0 if ok
                        • 1 no valid object number
                        • 2 grid structure not empty or level 0
                        */ /****************************************************************************/ INT NS_DIM_PREFIX DisposeGrid (GRID *theGrid) { MULTIGRID *theMG; if (theGrid == NULL) return(0); theMG = MYMG(theGrid); if (GLEVEL(theGrid)<0) return (1); if (theGrid->finer != NULL) return(1); /* clear level */ while (PFIRSTELEMENT(theGrid)!=NULL) if (DisposeElement(theGrid,PFIRSTELEMENT(theGrid))) return(2); while (PFIRSTNODE(theGrid)!=NULL) if (DisposeNode(theGrid,PFIRSTNODE(theGrid))) return(2); while (PFIRSTVERTEX(theGrid)!=NULL) if (DisposeVertex(theGrid,PFIRSTVERTEX(theGrid))) return(4); /* level 0 can not be deleted */ if (GLEVEL(theGrid) > 0) return(DisposeTopLevel(theMG)); /* remove from grids array */ GRID_ON_LEVEL(theMG,0) = NULL; theMG->topLevel = -1; theMG->nodeIdCounter = 0; theMG->vertIdCounter = 0; theMG->elemIdCounter = 0; PutFreeObject(theMG,theGrid,sizeof(GRID),GROBJ); return(0); } /****************************************************************************/ /** \brief Release memory for the whole multigrid structure * @param theMG - multigrid to remove This function releases the memory for the whole multigrid structure. @return
                        • GM_OK if ok
                        • GM_ERROR when error occurred.
                        */ /****************************************************************************/ INT NS_DIM_PREFIX DisposeMultiGrid (MULTIGRID *theMG) { INT level; #ifdef ModelP /* tell DDD that we will 'inconsistently' delete objects. this is a dangerous mode as it switches DDD warnings off. */ DDD_SetOption(theMG->dddContext(), OPT_WARNING_DESTRUCT_HDR, OPT_OFF); #endif for (level = TOPLEVEL(theMG); level >= 0; level --) if (DisposeGrid(GRID_ON_LEVEL(theMG,level))) RETURN(1); #ifdef ModelP /* stop dangerous mode. from now on DDD will issue warnings again. */ DDD_SetOption(theMG->dddContext(), OPT_WARNING_DESTRUCT_HDR, OPT_ON); /* rebuild DDD-interfaces because distributed vectors have been deleted without communication */ DDD_IFRefreshAll(theMG->dddContext()); #endif /** \todo Normally the MG-heap should be cleaned-up before freeing. DDD depends on storage in the heap, even if no DDD objects are allocated!! (due to free-lists, DDD type definitions etc.) therefore, repeated new/close commands are inhibited explicitly in dune/uggrid/parallel/dddif/initddd.c(InitCurrMG()). */ DisposeHeap(MGHEAP(theMG)); /* dispose BVP */ delete MG_BVP(theMG); /* first unlock the mg */ ((ENVITEM*) theMG)->v.locked = false; #ifdef ModelP ExitDDD(theMG->dddContext()); globalDDDContext(nullptr); #endif theMG->~multigrid(); /* delete mg */ if (ChangeEnvDir("/Multigrids")==NULL) RETURN (GM_ERROR); if (RemoveEnvDir ((ENVITEM *)theMG)) RETURN (GM_ERROR); return(GM_OK); } /****************************************************************************/ /** \brief Determine neighbor and side of neighbor that goes back to element * * @param theElement - considered element * @param Side - side of that element * @param theNeighbor - handle to neighbor * @param NeighborSide - number of side of neighbor that goes back to elem * This function determines the neighbor and side of the neighbor that goes back to elem. @return
                        • 0 if ok
                        • 1 when error occurred.
                        */ /****************************************************************************/ INT NS_DIM_PREFIX FindNeighborElement (const ELEMENT *theElement, INT Side, ELEMENT **theNeighbor, INT *NeighborSide) { INT i; /* find neighbor */ *theNeighbor = NBELEM(theElement,Side); if (*theNeighbor == NULL) return (0); /* search the side */ for (i=0; i *
                      • pointer to new node if ok
                      • *
                      • NULL when error occurred
                      • *
                      */ /****************************************************************************/ NODE * NS_DIM_PREFIX InsertInnerNode (GRID *theGrid, const DOUBLE *pos) { VERTEX *theVertex; NODE *theNode; INT i; /* create objects */ theVertex = CreateInnerVertex(theGrid); if (theVertex==NULL) { PrintErrorMessage('E',"InsertInnerNode","cannot create vertex"); return(NULL); } theNode = CreateNode(theGrid,theVertex,NULL,LEVEL_0_NODE); if (theNode==NULL) { DisposeVertex(theGrid,theVertex); PrintErrorMessage('E',"InsertInnerNode","cannot create node"); return(NULL); } /* fill data */ for (i=0; i
                    • GM_OK if ok
                    • GM_ERROR when error occurred.
                    */ /****************************************************************************/ NODE * NS_DIM_PREFIX InsertBoundaryNode (GRID *theGrid, BNDP *bndp) { NODE *theNode; VERTEX *theVertex; INT move; /* create objects */ theVertex = CreateBoundaryVertex(theGrid); if (theVertex==NULL) { BNDP_Dispose(MGHEAP(MYMG(theGrid)),bndp); PrintErrorMessage('E',"InsertBoundaryNode","cannot create vertex"); REP_ERR_RETURN(NULL); } if (BNDP_Global(bndp,CVECT(theVertex))) { DisposeVertex(theGrid,theVertex); return(NULL); } if (BNDP_BndPDesc(bndp,&move)) { DisposeVertex(theGrid,theVertex); return(NULL); } SETMOVE(theVertex,move); V_BNDP(theVertex) = bndp; theNode = CreateNode(theGrid,theVertex,NULL,LEVEL_0_NODE); if (theNode==NULL) { DisposeVertex(theGrid,theVertex); PrintErrorMessage('E',"InsertBoundaryNode","cannot create node"); REP_ERR_RETURN(NULL); } #ifdef TOPNODE TOPNODE(theVertex) = theNode; #endif PRINTDEBUG(dom,1,(" ipn %ld nd %x bndp %x \n", ID(theNode),theNode,V_BNDP(theVertex))); return(theNode); } /****************************************************************************/ /** \brief Delete a node * @param theGrid - grid structure * @param theNode - node to delete This function deletes a node from level 0. @return
                    • GM_OK if ok
                    • GM_ERROR when error occurred.
                    */ /****************************************************************************/ INT NS_DIM_PREFIX DeleteNode (GRID *theGrid, NODE *theNode) { VERTEX *theVertex; ELEMENT *theElement; INT i; if (theNode==NULL) { PrintErrorMessage('E',"DeleteNode","node not found"); RETURN(GM_ERROR); } /* check corner */ theVertex = MYVERTEX(theNode); if (MOVE(theVertex)==0) { PrintErrorMessage('E',"DeleteNode","corners cannot be deleted"); RETURN(GM_ERROR); } /* check if some element needs that node */ for (theElement=FIRSTELEMENT(theGrid); theElement!=NULL; theElement=SUCCE(theElement)) for (i=0; i NeighborSearch_O_nn", "neighbor relation inconsistent"); return(1); } Nbr[i] = theOther; NbrS[i] = jj; } } } } /* ... O(n*n)InsertElement */ #else /*O(n*n)InsertElement ...*/ /* for all sides of the element to be created */ MULTIGRID::FaceNodes faceNodes; for (int i=0; ifacemap.emplace(faceNodes,std::make_pair(theElement,i)); // if this failed (i.e. result.second == false) an entry already exists if (! result.second) { // update neighbor list the other entry, stored in result.first->second auto & data = result.first->second; ELEMENT* theOther = data.first; int idx = data.second; Nbr[i] = theOther; NbrS[i] = idx; theMG->facemap.erase(faceNodes); } } #endif return(0); /*... O(n)InsertElement ...*/ } /*of static INT NeighborSearch_O_n()*/ /****************************************************************************/ /** \todo Please doc me! Neighbor_Direct_Insert - SYNOPSIS: static INT Neighbor_Direct_Insert(INT n, ELEMENT **ElemList, INT *NbgSdList, INT* NbrS, ELEMENT **Nbr); * @param tag Element type * @param ElemList * @param NbgSdList * @param NbrS * @param Nbr DESCRIPTION: @return INT */ /****************************************************************************/ static INT Neighbor_Direct_Insert(INT tag, ELEMENT **ElemList, const INT *NbgSdList, INT* NbrS, ELEMENT **Nbr) { INT i; for (i=0; ifacemap.bucket_count() <= 1) { // try to allocate the right size a-priori to avoid rehashing theMG->facemap.rehash(theMG->nodeIdCounter); // theMG->facemap.max_load_factor(1000); } /* check parameters */ #ifdef UG_DIM_2 switch (n) { case 3 : tag = TRIANGLE; break; case 4 : tag = QUADRILATERAL; break; default : PrintErrorMessage('E',"InsertElement","only triangles and quadrilaterals allowed in 2D"); return(NULL); } #endif #ifdef UG_DIM_3 switch (n) { case 4 : tag = TETRAHEDRON; break; case 5 : tag = PYRAMID; break; case 6 : tag = PRISM; break; case 8 : tag = HEXAHEDRON; break; default : PrintErrorMessage('E',"InsertElement","only tetrahedra, prisms, pyramids, and hexahedra are allowed in the 3D coarse grid"); return(NULL); } #endif /* init vertices */ for (i=0; ierror */ /* or: if bnds_flag==NULL, the domain decides whether there */ /* should be a bnds or not (never an error) */ for (j=0; j= MAX_SIDES_OF_ELEM) { PrintErrorMessage('E',"InsertElement", "neighbor relation inconsistent"); return(NULL); } SET_NBELEM(Neighbor[i],NeighborSide[i],theElement); #ifdef UG_DIM_3 if (VEC_DEF_IN_OBJ_OF_GRID(theGrid,SIDEVEC)) if (DisposeDoubledSideVector(theGrid,Neighbor[i], NeighborSide[i],theElement,i)) return(NULL); #endif } } SET_EFATHER(theElement,NULL); SETECLASS(theElement,RED_CLASS); return(theElement); } /****************************************************************************/ /** \brief Delete an element * @param theMG - multigrid structure * @param theElement - element to delete This function deletes an element from level 0. @return
                    • GM_OK if ok
                    • GM_ERROR when error occurred.
                    */ /****************************************************************************/ INT NS_DIM_PREFIX DeleteElement (MULTIGRID *theMG, ELEMENT *theElement) /* 3D VERSION */ { GRID *theGrid; INT i,j,found; /* check level */ if (TOPLEVEL(theMG)!=0) { PrintErrorMessage('E',"DeleteElement", "only a multigrid with exactly one level can be edited"); RETURN(GM_ERROR); } theGrid = GRID_ON_LEVEL(theMG,0); /* delete pointers in neighbors */ for (i=0; i
                  • GM_OK if ok
                  • GM_ERROR when error occurred.
                  */ /****************************************************************************/ INT NS_DIM_PREFIX InsertMesh (MULTIGRID *theMG, MESH *theMesh) { GRID *theGrid; ELEMENT *theElement; NODE **NList,*Nodes[MAX_CORNERS_OF_ELEM]; VERTEX **VList; INT i,k,n,nv,j,maxlevel,l,move; INT ElemSideOnBnd[MAX_SIDES_OF_ELEM]; INT MarkKey = MG_MARK_KEY(theMG); if (theMesh == NULL) return(GM_OK); if (theMesh->nElements == NULL) { assert(theMesh->VertexLevel==NULL); theGrid = GRID_ON_LEVEL(theMG,0); for (i=0; inBndP; i++) if (InsertBoundaryNode(theGrid,theMesh->theBndPs[i]) == NULL) REP_ERR_RETURN(GM_ERROR); for (i=0; inInnP; i++) if (InsertInnerNode(theGrid,theMesh->Position[i]) == NULL) REP_ERR_RETURN(GM_ERROR); return(GM_OK); } /* prepare */ nv = theMesh->nBndP + theMesh->nInnP; VList = (VERTEX **) GetTmpMem(MGHEAP(theMG),nv*sizeof(VERTEX *),MarkKey); if (VList == NULL) return(GM_ERROR); NList = (NODE **) GetTmpMem(MGHEAP(theMG),nv*sizeof(NODE *),MarkKey); if (NList == NULL) return(GM_ERROR); for (j=0; jVertexLevel!=NULL) { for (i=0; inBndP; i++) { theGrid = GRID_ON_LEVEL(theMG,theMesh->VertexLevel[i]); VList[i] = CreateBoundaryVertex(theGrid); assert(VList[i]!=NULL); if (BNDP_Global(theMesh->theBndPs[i],CVECT(VList[i]))) assert(0); if (BNDP_BndPDesc(theMesh->theBndPs[i],&move)) return(GM_OK); SETMOVE(VList[i],move); V_BNDP(VList[i]) = theMesh->theBndPs[i]; maxlevel = std::max(maxlevel,(INT)theMesh->VertexLevel[i]); } for (i=theMesh->nBndP; iVertexLevel[i]); VList[i] = CreateInnerVertex(theGrid); V_DIM_COPY(theMesh->Position[i-theMesh->nBndP],CVECT(VList[i])); maxlevel = std::max(maxlevel,(INT)theMesh->VertexLevel[i]); } } else { theGrid = GRID_ON_LEVEL(theMG,0); for (i=0; inBndP; i++) { VList[i] = CreateBoundaryVertex(theGrid); assert(VList[i]!=NULL); if (BNDP_Global(theMesh->theBndPs[i],CVECT(VList[i]))) assert(0); if (BNDP_BndPDesc(theMesh->theBndPs[i],&move)) return(GM_OK); SETMOVE(VList[i],move); V_BNDP(VList[i]) = theMesh->theBndPs[i]; } for (i=theMesh->nBndP; iPosition[i-theMesh->nBndP],CVECT(VList[i])); } } if (theMesh->nElements == NULL) return(GM_OK); for (j=1; j<=1; j++) for (k=0; knElements[j]; k++) { if (theMesh->ElementLevel!=NULL) i = theMesh->ElementLevel[j][k]; else i=0; theGrid = GRID_ON_LEVEL(theMG,i); n = theMesh->Element_corners[j][k]; for (l=0; lElement_corner_ids[j][k][l]]; if (curListNode == NULL || LEVEL(curListNode) < i) { Nodes[l] = CreateNode(theGrid,VList[theMesh->Element_corner_ids[j][k][l]],NULL,LEVEL_0_NODE); if (Nodes[l]==NULL) assert(0); NList[theMesh->Element_corner_ids[j][k][l]] = Nodes[l]; if (curListNode == NULL || LEVEL(curListNode) < i-1) { SETNFATHER(Nodes[l],NULL); } else { SETNFATHER(Nodes[l],(GEOM_OBJECT *)curListNode); SONNODE(curListNode) = Nodes[l]; } } else { Nodes[l] = curListNode; } } if (theMesh->ElemSideOnBnd==NULL) theElement = InsertElement (theGrid,n,Nodes,NULL,NULL,NULL); else { for (l=0; lElemSideOnBnd[j][k]&(1<& corner = CVECT(MYVERTEX(CORNER(theElement,i))); V_DIM_ADD(center_of_mass,corner,center_of_mass); } V_DIM_SCALE(1.0/nr_corners,center_of_mass); } /****************************************************************************/ /** \brief Calculate an (hopefully) unique key for the geometric object * @param obj - geometric object which from the key is needed (can be one of VERTEX, ELEMENT, NODE or VECTOR) This function calculates an (hopefully) unique key for VERTEX, ELEMENT, NODE, EDGE and VECTOR typed objects. The heuristic is: calculate a 2D/3D position for the geometric object and transform this position to a single number by a weighted summation of the leading digits of the 2 resp. 3 coordinates and taking from this again the sigificant digits and adding the level number. APPLICATION: Use always an explicit cast to avoid compiler warnings, e.g. NODE *theNode; KeyForObject((KEY_OBJECT *)theNode); * \sa VERTEX, ELEMENT, NODE, EDGE, VECTOR @return * the resulting key */ /****************************************************************************/ INT NS_DIM_PREFIX KeyForObject( KEY_OBJECT *obj ) { int dummy,i; /* dummy variable */ DOUBLE_VECTOR coord; if (obj==NULL) return (-1); switch( OBJT(obj) ) { /* vertex */ case BVOBJ : case IVOBJ : /* both together cover all vertex types */ return LEVEL(obj)+COORDINATE_TO_KEY(CVECT((VERTEX*)obj),&dummy); /* element */ case BEOBJ : case IEOBJ : for (i=0; iBVP_Name.c_str()); else UserWriteF(" %c %-20.20s\n",c,ENVITEM_NAME(theMG)); } /****************************************************************************/ /** \brief List information about refinement type distribution * @param theMG - structure to list * @param gridflag - * @param greenflag * @param lbflag * @param verbose This function lists information about multigrids element types. * \todo Please return value! */ /****************************************************************************/ INT NS_DIM_PREFIX MultiGridStatus (const MULTIGRID *theMG, INT gridflag, INT greenflag, INT lbflag, INT verbose) { INT i,j,sons,maxsons; INT red, green, yellow; INT mg_red,mg_green,mg_yellow; INT mg_greenrulesons[MAXLEVEL+1][MAX_SONS+1],mg_greenrules[MAXLEVEL+1]; INT markcount[MAXLEVEL+1],closuresides[MAXLEVEL+1]; FLOAT sum,sum_div_red,redplusgreen_div_red; FLOAT mg_sum,mg_sum_div_red,mg_redplusgreen_div_red; ELEMENT *theElement; GRID *theGrid; #ifdef ModelP INT MarkKey; INT total_elements,sum_elements; INT master_elements,hghost_elements,vghost_elements,vhghost_elements; #endif #ifdef ModelP const auto& ppifContext = theMG->ppifContext(); const int me = ppifContext.me(); const int procs = ppifContext.procs(); #endif mg_red = mg_green = mg_yellow = mg_sum = 0; mg_sum_div_red = mg_redplusgreen_div_red = 0.0; for (i=0; i infobuffer((procs+1)*(MAXLEVEL+1)*ELEMENT_PRIOS, 0); std::vector lbinfo(procs+1); for (i=0; i 0) { sum_div_red = sum / red; redplusgreen_div_red = ((float)(red+green)) / red; } else { sum_div_red = 0.0; redplusgreen_div_red = 0.0; } if (verbose && gridflag) UserWriteF(" %2d %9d %9d %9d %9.0f %2.3f %2.3f\n", i,red,green,yellow,sum,sum_div_red,redplusgreen_div_red); mg_red += red; mg_green += green; mg_yellow += yellow; mg_sum += sum; } if (mg_red > 0) { mg_sum_div_red = mg_sum / mg_red; mg_redplusgreen_div_red = ((float)(mg_red + mg_green)) / mg_red; } else { mg_sum_div_red = 0.0; mg_redplusgreen_div_red = 0.0; } if (verbose && gridflag) UserWriteF(" ALL %9d %9d %9d %9.0f %2.3f %2.3f\n", mg_red,mg_green,mg_yellow,mg_sum,mg_sum_div_red,mg_redplusgreen_div_red); /* set heap info in refine info */ if (gridflag) { float New; float newpergreen; SETMARKCOUNT(REFINEINFO(theMG),markcount[MAXLEVEL]); New = markcount[MAXLEVEL]*(2<<(DIM-1))*mg_sum_div_red; SETPREDNEW0(REFINEINFO(theMG),New); if (mg_greenrules[MAXLEVEL] > 0) newpergreen = ((float)mg_greenrulesons[MAXLEVEL][MAX_SONS])/mg_greenrules[MAXLEVEL]; else newpergreen = 0; New = markcount[MAXLEVEL]*(2<<(DIM-1))+newpergreen*closuresides[MAXLEVEL]; SETPREDNEW1(REFINEINFO(theMG),New); SETREAL(REFINEINFO(theMG),mg_sum); } /* list heap info */ if (verbose && gridflag) { UserWriteF(" EST %2d ELEMS=%9.0f MARKCOUNT=%9.0f PRED_NEW0=%9.0f PRED_NEW1=%9.0f\n", REFINESTEP(REFINEINFO(theMG)),REAL(REFINEINFO(theMG)),MARKCOUNT(REFINEINFO(theMG)), PREDNEW0(REFINEINFO(theMG)),PREDNEW1(REFINEINFO(theMG))); UserWriteF(" EST TRACE step=%d\n",refine_info.step); for (i=0; i mych(procs, nullptr); for (i=1; i= 3) { UserWriteF(" LEVEL"); for (i=0; i= 2) { float memeff; UserWriteF("%5s %9s %9s %9s %9s %9s %6s\n", "LEVEL","SUM","MASTER","HGHOST","VGHOST","VHGHOST","MEMEFF"); for (i=0; i<=TOPLEVEL(theMG); i++) { sum_elements = lbinfo[procs][ELEMENT_PRIOS*i]+lbinfo[procs][ELEMENT_PRIOS*i+1]+ lbinfo[procs][ELEMENT_PRIOS*i+2]+lbinfo[procs][ELEMENT_PRIOS*i+3]; if (sum_elements > 0) memeff = ((float)lbinfo[procs][ELEMENT_PRIOS*i])/sum_elements*100; else memeff = 0.0; UserWriteF("%4d %9d %9d %9d %9d %9d %3.2f\n",i,sum_elements, lbinfo[procs][ELEMENT_PRIOS*i],lbinfo[procs][ELEMENT_PRIOS*i+1], lbinfo[procs][ELEMENT_PRIOS*i+2],lbinfo[procs][ELEMENT_PRIOS*i+3],memeff); } UserWrite("\n"); UserWriteF("%4s %9s %9s %9s %9s %9s %6s\n", "PROC","SUM","MASTER","HGHOST","VGHOST","VHGHOST","MEMEFF"); for (i=0; i 0) memeff = ((float)lbinfo[i][ELEMENT_PRIOS*MAXLEVEL])/sum_elements*100; else memeff = 0.0; UserWriteF("%4d %9d %9d %9d %9d %9d %3.2f\n",i,sum_elements, lbinfo[i][ELEMENT_PRIOS*MAXLEVEL],lbinfo[i][ELEMENT_PRIOS*MAXLEVEL+1], lbinfo[i][ELEMENT_PRIOS*MAXLEVEL+2],lbinfo[i][ELEMENT_PRIOS*MAXLEVEL+3],memeff); } UserWrite("\n"); } if (lbflag >= 1) { float memeff; for (i=0; i 0) memeff = ((float)master_elements)/total_elements*100; else memeff = 0.0; UserWriteF("%9s %9s %9s %9s %9s %6s\n","TOTAL","MASTER","HGHOST","VGHOST","VHGHOST","MEMEFF"); UserWriteF("%9d %9d %9d %9d %9d %3.2f\n",total_elements,master_elements,hghost_elements, vghost_elements,vhghost_elements,memeff); } } ReleaseTmpMem(MGHEAP(theMG),MarkKey); #endif return (GM_OK); } /****************************************************************************/ /** \brief List general information about grids of multigrid * @param theMG - multigrid structure This function lists general information about the grids of a multigrid. */ /****************************************************************************/ void NS_DIM_PREFIX ListGrids (const MULTIGRID *theMG) { GRID *theGrid; ELEMENT *theElement,*NBElem; VERTEX *myVertex,*nbVertex,*v0,*v1; NODE *theNode,*n0,*n1; EDGE *theEdge; LINK *theLink; VECTOR *vec; DOUBLE hmin,hmax,h; INT l,minl,i,soe,eos,coe,side,e; INT nn,ne,nt,ns,nvec,nc; UserWriteF("grids of '%s':\n",ENVITEM_NAME(theMG)); UserWrite("level maxlevel #vert #node #edge #elem #side #vect #conn"); UserWrite(" minedge maxedge\n"); for (l=0; l<=TOPLEVEL(theMG); l++) { theGrid = GRID_ON_LEVEL(theMG,l); /* calculate minimal and maximal edge */ hmin = MAX_C; hmax = 0.0; for (theNode=FIRSTNODE(theGrid); theNode!=NULL; theNode=SUCCN(theNode)) { myVertex = MYVERTEX(theNode); for (theLink=START(theNode); theLink!=NULL; theLink=NEXT(theLink)) { nbVertex = MYVERTEX(NBNODE(theLink)); V_DIM_EUKLIDNORM_OF_DIFF(CVECT(myVertex),CVECT(nbVertex),h); hmin = std::min(hmin,h); hmax = std::max(hmax,h); } } ns = 0; for (theElement=PFIRSTELEMENT(theGrid); theElement!=NULL; theElement=SUCCE(theElement)) if (OBJT(theElement) == BEOBJ) for (i=0; i0) continue; /* objects of this side will be counted by the neighbour */ eos = EDGES_OF_SIDE(theElement,side); for (i=0; i0) continue; /* objects of this side will be counted by the neighbour */ eos = EDGES_OF_SIDE(theElement,side); for (i=0; ippifContext(), nn); ne = UG_GlobalSumINT(theMG->ppifContext(), ne); nt = UG_GlobalSumINT(theMG->ppifContext(), nt); ns = UG_GlobalSumINT(theMG->ppifContext(), ns); nvec = UG_GlobalSumINT(theMG->ppifContext(), nvec); nc = UG_GlobalSumINT(theMG->ppifContext(), nc); hmin = UG_GlobalMinDOUBLE(theMG->ppifContext(), hmin); hmax = UG_GlobalMaxDOUBLE(theMG->ppifContext(), hmax); UserWrite("\nsurface of all processors up to top level:\n"); UserWriteF("%c %3d %8d %8s %8ld %8s %8ld %8ld %8ld %8s %9.3e %9.3e\n", ' ',minl,TOPLEVEL(theMG), "---",(long)nn," ",(long)nt, (long)ns,(long)nvec," ",(float)hmin,(float)hmax); #endif } /****************************************************************************/ /** \brief List information about node in multigrid * @param theMG - structure containing the node * @param theNode - node to list * @param dataopt - list user data if true * @param bopt - list boundary info if true * @param nbopt - list info about neighbors if true * @param vopt - list more information This function lists information about a node in a multigrid. */ /****************************************************************************/ void NS_DIM_PREFIX ListNode (const MULTIGRID *theMG, const NODE *theNode, INT dataopt, INT bopt, INT nbopt, INT vopt) { VERTEX *theVertex; LINK *theLink; INT i; theVertex = MYVERTEX(theNode); /******************************/ /* print standard information */ /******************************/ /* line 1 */ UserWriteF("NODEID=" ID_FFMTE " CTRL=%8lx VEID=" VID_FMTX " LEVEL=%2d", ID_PRTE(theNode),(long)CTRL(theNode), VID_PRTX(theVertex),LEVEL(theNode)); /* print coordinates of that node */ for(i=0; i
                • 0 if ok
                • 1 if error occurred.
                */ /****************************************************************************/ static INT MaxNodeClass (const ELEMENT *theElement) { INT m = 0; INT i; for (i=0; i
              • 0 if ok
              • 1 if error occurred.
              */ /****************************************************************************/ INT NS_DIM_PREFIX MaxNextNodeClass (const ELEMENT *theElement) { INT m = 0; INT i; for (i=0; i
            • 0 if ok
            • 1 if error occurred.
            */ /****************************************************************************/ INT NS_DIM_PREFIX MinNodeClass (const ELEMENT *theElement) { INT m = 3; INT i; for (i=0; i
          • 0 if ok
          • 1 if error occurred.
          */ /****************************************************************************/ INT NS_DIM_PREFIX MinNextNodeClass (const ELEMENT *theElement) { INT m = 3; INT i; for (i=0; i
        • 0 if ok
        • 1 if error occurred.
        */ /****************************************************************************/ INT NS_DIM_PREFIX SeedNodeClasses (ELEMENT *theElement) { INT i; for (i=0; i
      • 0 if ok
      • 1 if error occurred.
      */ /****************************************************************************/ INT NS_DIM_PREFIX ClearNodeClasses (GRID *theGrid) { NODE *theNode; /* reset class of each Node to 0 */ for (theNode=PFIRSTNODE(theGrid); theNode!=NULL; theNode=SUCCN(theNode)) SETNCLASS(theNode,0); return(0); } #ifdef ModelP static int Gather_NodeClass (DDD::DDDContext&, DDD_OBJ obj, void *data) { NODE *theNode = (NODE *)obj; ((INT *)data)[0] = NCLASS(theNode); return(0); } static int Scatter_NodeClass (DDD::DDDContext&, DDD_OBJ obj, void *data) { NODE *theNode = (NODE *)obj; SETNCLASS(theNode,std::max((INT)NCLASS(theNode),((INT *)data)[0])); return(0); } static int Scatter_GhostNodeClass (DDD::DDDContext&, DDD_OBJ obj, void *data) { NODE *theNode = (NODE *)obj; SETNCLASS(theNode,((INT *)data)[0]); return(0); } #endif /****************************************************************************/ /** \brief Compute Node classes after initialization * @param theGrid - pointer to grid After Node classes have been reset and initialized, this function now computes the class 2 and class 1 Nodes. @return
      • 0 if ok
      • 1 if error occurred
      */ /****************************************************************************/ static INT PropagateNodeClass (GRID *theGrid, INT nclass) { ELEMENT *theElement; INT i; for (theElement=FIRSTELEMENT(theGrid); theElement!= NULL; theElement = SUCCE(theElement)) if (MaxNodeClass(theElement) == nclass) for (i=0; idddContext(); const auto& dddctrl = ddd_ctrl(context); PRINTDEBUG(gm,1,("\n" PFMT "PropagateNodeClasses():" " 1. communication on level %d\n",theGrid->ppifContext().me(),GLEVEL(theGrid))) /* exchange NCLASS of Nodes */ DDD_IFAExchange(context, dddctrl.BorderNodeSymmIF,GRID_ATTR(theGrid),sizeof(INT), Gather_NodeClass, Scatter_NodeClass); #endif /* set Node classes in the algebraic neighborhood to 2 */ if (PropagateNodeClass(theGrid,3)) REP_ERR_RETURN(1); #ifdef ModelP PRINTDEBUG(gm,1,("\n" PFMT "PropagateNodeClasses(): 2. communication\n", theGrid->ppifContext().me())) /* exchange NCLASS of Nodes */ DDD_IFAExchange(context, dddctrl.BorderNodeSymmIF,GRID_ATTR(theGrid),sizeof(INT), Gather_NodeClass, Scatter_NodeClass); #endif /* set Node classes in the algebraic neighborhood to 1 */ if (PropagateNodeClass(theGrid,2)) REP_ERR_RETURN(1); #ifdef ModelP PRINTDEBUG(gm,1,("\n" PFMT "PropagateNodeClasses(): 3. communication\n", theGrid->ppifContext().me())) /* exchange NCLASS of Nodes */ DDD_IFAExchange(context, dddctrl.BorderNodeSymmIF,GRID_ATTR(theGrid),sizeof(INT), Gather_NodeClass, Scatter_NodeClass); /* send NCLASS to ghosts */ DDD_IFAOneway(context, dddctrl.NodeIF,GRID_ATTR(theGrid),IF_FORWARD,sizeof(INT), Gather_NodeClass, Scatter_GhostNodeClass); #endif return(0); } /****************************************************************************/ /** \brief Reset class of the Nodes on the next level * @param theGrid - pointer to grid This function clears NNCLASS flag in all Nodes. This is the first step to compute the class of the dofs on the *NEXT* level, which is also the basis for determining copies. @return
      • 0 if ok
      • 1 if error occurred.
      */ /****************************************************************************/ INT NS_DIM_PREFIX ClearNextNodeClasses (GRID *theGrid) { NODE *theNode; /* reset class of each Node to 0 */ for (theNode=PFIRSTNODE(theGrid); theNode!=NULL; theNode=SUCCN(theNode)) SETNNCLASS(theNode,0); /* now the refinement algorithm will initialize the class 3 Nodes */ /* on the *NEXT* level. */ return(0); } /****************************************************************************/ /** \brief Set 'NNCLASS' in all Nodes associated with element * @param theElement - pointer to element Set 'NNCLASS' in all nodes associated with the element to 3. @return
      • 0 if ok
      • 1 if error occurred.
      */ /****************************************************************************/ INT NS_DIM_PREFIX SeedNextNodeClasses (ELEMENT *theElement) { INT i; for (i=0; i
    • 0 if ok
    • 1 if error occurred
    */ /****************************************************************************/ #ifdef ModelP static int Gather_NextNodeClass (DDD::DDDContext&, DDD_OBJ obj, void *data) { NODE *theNode = (NODE *)obj; ((INT *)data)[0] = NNCLASS(theNode); return(GM_OK); } static int Scatter_NextNodeClass (DDD::DDDContext&, DDD_OBJ obj, void *data) { NODE *theNode = (NODE *)obj; SETNNCLASS(theNode,std::max((INT)NNCLASS(theNode),((INT *)data)[0])); return(GM_OK); } static int Scatter_GhostNextNodeClass (DDD::DDDContext&, DDD_OBJ obj, void *data) { NODE *theNode = (NODE *)obj; SETNNCLASS(theNode,((INT *)data)[0]); return(GM_OK); } #endif static INT PropagateNextNodeClass (GRID *theGrid, INT nnclass) { ELEMENT *theElement; INT i; for (theElement=FIRSTELEMENT(theGrid); theElement!= NULL; theElement = SUCCE(theElement)) if (MaxNextNodeClass(theElement) == nnclass) for (i=0; idddContext(); const auto& dddctrl = ddd_ctrl(context); PRINTDEBUG(gm,1,("\n" PFMT "PropagateNextNodeClasses(): 1. communication\n",theGrid->ppifContext().me())) /* exchange NNCLASS of Nodes */ DDD_IFAExchange(context, dddctrl.BorderNodeSymmIF,GRID_ATTR(theGrid),sizeof(INT), Gather_NextNodeClass, Scatter_NextNodeClass); #endif if (PropagateNextNodeClass(theGrid,3)) REP_ERR_RETURN(1); #ifdef ModelP PRINTDEBUG(gm,1,("\n" PFMT "PropagateNextNodeClasses(): 2. communication\n",theGrid->ppifContext().me())) /* exchange NNCLASS of Nodes */ DDD_IFAExchange(context, dddctrl.BorderNodeSymmIF,GRID_ATTR(theGrid),sizeof(INT), Gather_NextNodeClass, Scatter_NextNodeClass); #endif if (PropagateNextNodeClass(theGrid,2)) REP_ERR_RETURN(1); #ifdef ModelP PRINTDEBUG(gm,1,("\n" PFMT "PropagateNextNodeClasses(): 3. communication\n",theGrid->ppifContext().me())) /* exchange NNCLASS of Nodes */ DDD_IFAExchange(context, dddctrl.BorderNodeSymmIF,GRID_ATTR(theGrid),sizeof(INT), Gather_NextNodeClass, Scatter_NextNodeClass); /* send NNCLASSn to ghosts */ DDD_IFAOneway(context, dddctrl.NodeIF,GRID_ATTR(theGrid),IF_FORWARD,sizeof(INT), Gather_NextNodeClass, Scatter_GhostNextNodeClass); #endif return(0); } /****************************************************************************/ /** \brief Set subdomain id on level 0 edges * @param id - the id of the block to be allocated This function sets the subdomain id taken from the elements for level 0 edges. @return
    • GM_OK if ok
    • GM_ERROR if error occurred
    */ /****************************************************************************/ static INT SetEdgeAndNodeSubdomainFromElements (GRID *theGrid) { ELEMENT *theElement; NODE *n0,*n1; EDGE *ed; INT s_id,s,i,k; /* first set subdomain id for all edges */ for (theElement=PFIRSTELEMENT(theGrid); theElement!=NULL; theElement=SUCCE(theElement)) { /* all edges of the element acquire the subdomain id of the element */ s_id = SUBDOMAIN(theElement); for (k=0; k
  • GM_OK if ok
  • GM_ERROR if error occurred
  • */ /****************************************************************************/ static INT RemoveSpuriousBoundarySides (HEAP *heap, ELEMENT *elem, INT side) { ELEMENT *nb=NBELEM(elem,side); BNDS *nbbside,*bside=ELEM_BNDS(elem,side); INT nbside; ASSERT(bside!=NULL); ASSERT(OBJT(elem)==BEOBJ); ASSERT(nb!=NULL); ASSERT(OBJT(nb)==BEOBJ); /* search nbside */ for (nbside=0; nbside *
  • GM_OK if ok
  • *
  • GM_ERROR if error occurred
  • ** */ /****************************************************************************/ static INT BElem2IElem (GRID *grid, ELEMENT **elemH) { ELEMENT *nb[MAX_SIDES_OF_ELEM],*elem=*elemH,*ielem; NODE *nodes[MAX_CORNERS_OF_ELEM]; INT i,j,nbside[MAX_SIDES_OF_ELEM],s_id; ASSERT(GLEVEL(grid)==0); /* save context */ for (i=0; i
  • GM_OK if ok
  • GM_ERROR if error occurred
  • */ /****************************************************************************/ static INT FinishGrid (MULTIGRID *mg) { GRID *grid; ELEMENT *elem,*nb,*succ; HEAP *heap=MGHEAP(mg); FIFO unused,shell; INT MarkKey = MG_MARK_KEY(mg); INT side,nbid,s_id; INT *sd_table; void *fifoBuffer; /* prepare */ if (TOPLEVEL(mg)<0) REP_ERR_RETURN (GM_ERROR); grid = GRID_ON_LEVEL(mg,0); if (!NT(grid)) return (GM_OK); for (elem=PFIRSTELEMENT(grid); elem!=NULL; elem=SUCCE(elem)) { SETUSED(elem,false); SETTHEFLAG(elem,false); } /* table for subdomain ids */ const INT nsd = 2; sd_table = (INT*)GetTmpMem(heap,nsd*sizeof(INT),MarkKey); if (sd_table==NULL) REP_ERR_RETURN (GM_ERROR); /* init two fifos */ fifoBuffer = (void *)GetTmpMem(heap, sizeof(ELEMENT*)*NT(grid), MarkKey); if (fifoBuffer == NULL) REP_ERR_RETURN (GM_ERROR); fifo_init(&unused, fifoBuffer, sizeof(ELEMENT*)*NT(grid)); fifoBuffer = (void *)GetTmpMem(heap, sizeof(ELEMENT*)*NT(grid), MarkKey); if (fifoBuffer == NULL) REP_ERR_RETURN (GM_ERROR); fifo_init(&shell, fifoBuffer, sizeof(ELEMENT*)*NT(grid)); /* outermost loop handles nonconnected domains */ while (true) { for (elem=PFIRSTELEMENT(grid); elem!=NULL; elem=SUCCE(elem)) if (!USED(elem)) break; if (elem!=NULL) fifo_in(&unused,elem); else break; while (!fifo_empty(&unused)) { /* grab next !USED element */ do elem = (ELEMENT*) fifo_out(&unused); while (USED(elem) && !fifo_empty(&unused)); if (USED(elem)) /* we are done */ break; /* shell algo (using FLAG): neighbours, but not across bside */ fifo_clear(&shell); fifo_in(&shell,elem); SETTHEFLAG(elem,true); for (INT i=0; i<=nsd; i++) sd_table[i] = 0; INT found = false; while (!fifo_empty(&shell)) { elem = (ELEMENT*) fifo_out(&shell); if (OBJT(elem)==BEOBJ) for (side=0; side0); s_id = nbid; found = true; break; } if (nbid==0) { ASSERT(id>0); s_id = id; found = true; break; } ++sd_table[id]; if (sd_table[id]>1) { s_id = id; found = true; break; } } if (found) break; /* push neighbours not across boundary */ if (OBJT(elem)==BEOBJ) { for (side=0; side2) /* FATAL: algorithm relies on assumptions obviously not fulfilled! */ ASSERT(false); /* again shell algo starting from last element */ /* set USED, propagate subdomain ids and remove spurious bsides (has to have NB!) */ /* use PRINTDEBUG */ fifo_clear(&shell); fifo_in(&shell,elem); SETUSED(elem,true); SETSUBDOMAIN(elem,s_id); while (!fifo_empty(&shell)) { elem = (ELEMENT*) fifo_out(&shell); if (OBJT(elem)==BEOBJ) { for (side=0; side=SIDES_OF_ELEM(elem)) if (BElem2IElem(grid,&elem)) REP_ERR_RETURN(1); } if (SetEdgeAndNodeSubdomainFromElements(grid)) REP_ERR_RETURN (GM_ERROR); return (GM_OK); } /****************************************************************************/ /** \brief SetSubdomainIDfromBndInfo - set subdomain id on level 0 elements and edges * @param id - the id of the block to be allocated This function sets the subdomain for level 0 elements and edges. @return
    • GM_OK if ok
    • GM_ERROR if error occurred
    */ /****************************************************************************/ INT NS_DIM_PREFIX SetSubdomainIDfromBndInfo (MULTIGRID *theMG) { HEAP *theHeap; GRID *theGrid; ELEMENT *theElement, *theNeighbor; NODE *theNode; void *fifoBuffer; INT i,n,id,nbid,j; FIFO myfifo; INT MarkKey = MG_MARK_KEY(theMG); /* prepare */ if (TOPLEVEL(theMG)<0) REP_ERR_RETURN (GM_ERROR); theGrid = GRID_ON_LEVEL(theMG,0); n = NT(theGrid); if (n==0) return(0); /* allocate fifo and init */ theHeap = MYMG(theGrid)->theHeap; fifoBuffer = (void *)GetTmpMem(theHeap, sizeof(ELEMENT*)*n, MarkKey); fifo_init(&myfifo, fifoBuffer, sizeof(ELEMENT*)*n); for (theElement=PFIRSTELEMENT(theGrid); theElement!=NULL; theElement=SUCCE(theElement)) SETUSED(theElement,0); /* insert all boundary elements */ for (theElement=PFIRSTELEMENT(theGrid); theElement!=NULL; theElement=SUCCE(theElement)) if (OBJT(theElement)==BEOBJ && !USED(theElement)) { for (i=0; i0); SETSUBDOMAIN(theElement,id); SETUSED(theElement,1); fifo_in(&myfifo,(void *)theElement); PRINTDEBUG(gm,1,("elem %3d sid %d\n",ID(theElement),SUBDOMAIN(theElement))); for (i=0; i
  • GM_OK if ok
  • GM_ERROR if error occurred
  • * */ /****************************************************************************/ INT NS_DIM_PREFIX FixCoarseGrid (MULTIGRID *theMG) { if (MG_COARSE_FIXED(theMG)) return (GM_OK); /** \todo (HRR 971031): check that before check-in! if (FinishGrid(theMG)) REP_ERR_RETURN (GM_ERROR);*/ /** \todo (HRR 971031): remove if above works */ if (SetSubdomainIDfromBndInfo(theMG)) REP_ERR_RETURN (GM_ERROR); /* set this flag here because it is checked by CreateAlgebra */ if (CreateAlgebra(theMG) != GM_OK) REP_ERR_RETURN (GM_ERROR); /* here all temp memory since CreateMultiGrid is released */ ReleaseTmpMem(MGHEAP(theMG),MG_MARK_KEY(theMG)); MG_MARK_KEY(theMG) = 0; return (GM_OK); } /****************************************************************************/ /** \brief Init what is necessary * * This function initializes the grid manager. * * @return
      *
    • GM_OK if ok
    • *
    • > 0 line in which error occurred
    • *
    */ /****************************************************************************/ INT NS_DIM_PREFIX InitUGManager () { INT i; /* install the /Multigrids directory */ if (ChangeEnvDir("/")==NULL) { PrintErrorMessage('F',"InitUGManager","could not changedir to root"); return(__LINE__); } theMGRootDirID = GetNewEnvDirID(); if (MakeEnvItem("Multigrids",theMGRootDirID,sizeof(ENVDIR))==NULL) { PrintErrorMessage('F',"InitUGManager","could not install /Multigrids dir"); return(__LINE__); } theMGDirID = GetNewEnvDirID(); /* init the OBJT management */ UsedOBJT = 0; for (i=0; i #include #include "gm.h" #include "dlmgr.h" START_UGDIM_NAMESPACE /****************************************************************************/ /* */ /* defines in the following order */ /* */ /* compile time constants defining static data size (i.e. arrays) */ /* other constants */ /* macros */ /* */ /****************************************************************************/ #define MAX_PAR_DIST 1.0E-6 /* max.dist between different parameter */ /****************************************************************************/ /* */ /* data structures exported by the corresponding source file */ /* */ /****************************************************************************/ /****************************************************************************/ /* */ /* definition of exported global variables */ /* */ /****************************************************************************/ /****************************************************************************/ /* */ /* function declarations */ /* */ /****************************************************************************/ /* init */ INT InitUGManager (void); INT ExitUGManager (); /* object handling */ GM_OBJECTS GetFreeOBJT (void); /* create basic objects */ /** \todo Commented out because no definitions exist for these declarations #if defined(UG_DIM_2) int GetElemLink (NODE *from, NODE *to, ELEMENT *theElement); ELEMENT *NbElem (const ELEMENT *theElement, int i); void Set_NbElem (ELEMENT *theElement, int i, ELEMENT *Neighbor); #endif */ #ifdef ModelP EDGE * CreateEdge (GRID *theGrid, ELEMENT *theElement, INT i, bool with_vector); #endif ELEMENT * CreateElement (GRID *theGrid, INT tag, INT objtype, NODE **nodes, ELEMENT *Father, bool with_vector); INT CreateSonElementSide (GRID *theGrid, ELEMENT *theElement, INT side, ELEMENT *theSon, INT son_side); GRID *CreateNewLevel (MULTIGRID *theMG); /* dispose basic objects */ INT DisposeElement (GRID *theGrid, ELEMENT *theElement); INT DisposeTopLevel (MULTIGRID *theMG); INT DisposeNode (GRID *theGrid, NODE *theNode); /* miscellaneous */ INT FindNeighborElement (const ELEMENT *theElement, INT Side, ELEMENT **theNeighbor, INT *NeighborSide); INT CheckOrientation (INT n, VERTEX **vertices); INT CheckOrientationInGrid (GRID *theGrid); NODE *CreateSonNode (GRID *theGrid, NODE *FatherNode); NODE *CreateMidNode (GRID *theGrid, ELEMENT *theElement, VERTEX *theVertex, INT edge); NODE *GetCenterNode (const ELEMENT *theElement); NODE *CreateCenterNode (GRID *theGrid, ELEMENT *theElement, VERTEX *theVertex); #ifdef UG_DIM_3 NODE *CreateSideNode (GRID *theGrid, ELEMENT *theElement, VERTEX *theVertex, INT side); NODE *GetSideNode (const ELEMENT *theElement, INT side); #endif INT GetSideIDFromScratch (ELEMENT *theElement, NODE *theNode); NODE *GetMidNode (const ELEMENT *theElement, INT edge); INT GetNodeContext (const ELEMENT *theElement, NODE **theElementContext); void GetNbSideByNodes (ELEMENT *theNeighbor, INT *nbside, ELEMENT *theElement, INT side); void *GetMemoryForObject (MULTIGRID *mg, INT size, INT type); INT PutFreeObject (MULTIGRID *mg, void *object, INT size, GM_OBJECTS type); /* determination of node classes */ INT ClearNodeClasses (GRID *theGrid); INT SeedNodeClasses (ELEMENT *theElement); INT PropagateNodeClasses (GRID *theGrid); INT ClearNextNodeClasses (GRID *theGrid); INT SeedNextNodeClasses (ELEMENT *theElement); INT PropagateNextNodeClasses (GRID *theGrid); INT MaxNextNodeClass (const ELEMENT *theElement); INT MinNodeClass (const ELEMENT *theElement); INT MinNextNodeClass (const ELEMENT *theElement); END_UGDIM_NAMESPACE #endif dune-uggrid-2.11.0+dfsg/dune/uggrid/initug.cc000066400000000000000000000166021513616443000207560ustar00rootroot00000000000000// SPDX-FileCopyrightText: Copyright © DUNE Project contributors, see file LICENSE.md in module root // SPDX-License-Identifier: LGPL-2.1-or-later // -*- tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- // vi: set et ts=4 sw=2 sts=2: /*! \file * \ingroup ug */ /** \addtogroup ug * * @{ */ /****************************************************************************/ /* */ /* File: initug.c */ /* */ /* Purpose: call the init routines of the ug modules */ /* */ /* Author: Henrik Rentz-Reichert */ /* Institut fuer Computeranwendungen III */ /* Universitaet Stuttgart */ /* Pfaffenwaldring 27 */ /* 70569 Stuttgart */ /* email: ug@ica3.uni-stuttgart.de */ /* */ /* History: 27.02.95 begin, ug version 3.0 */ /* */ /* Remarks: */ /* */ /****************************************************************************/ /****************************************************************************/ /* */ /* include files */ /* system include files */ /* application include files */ /* */ /****************************************************************************/ /* ANSI-C includes */ #include #include #include /* low module */ #include #include /* parallelization module */ #ifdef ModelP #include #include using namespace PPIF; #endif /* devices module */ #include /* grid manager module */ #include /* own header */ #include "initug.h" /** \todo delete this */ #include USING_UG_NAMESPACES /****************************************************************************/ /* */ /* defines in the following order */ /* */ /* compile time constants defining static data size (i.e. arrays) */ /* other constants */ /* macros */ /* */ /****************************************************************************/ #define UGDEBUGRFILE "debugfile" /****************************************************************************/ /* */ /* definition of variables global to this source file only (static!) */ /* */ /****************************************************************************/ /****************************************************************************/ /** \brief Call the init functions for all the ug modules * * @param argcp - pointer to argument counter * @param argvp - pointer to argument vector * * This function initializes. * * @return
      *
    • 0 if ok
    • *
    • 1 if error occurred.
    • *
    */ /****************************************************************************/ INT NS_DIM_PREFIX InitUg (int *argcp, char ***argvp) { INT err; #ifdef ModelP /* init ppif module */ if ((err = InitPPIF (argcp, argvp)) != PPIF_SUCCESS) { printf ("ERROR in InitParallel while InitPPIF.\n"); printf ("aborting ug\n"); return (1); } #endif /* init the low module */ if ((err = InitLow ()) != 0) { printf ("ERROR in InitUg while InitLow (line %d): called routine line %d\n", (int) HiWrd (err), (int) LoWrd (err)); printf ("aborting ug\n"); return (1); } /* init the devices module */ if ((err = InitDevices()) != 0) { printf ("ERROR in InitUg while InitDevices (line %d): called routine line %d\n", (int) HiWrd (err), (int) LoWrd (err)); printf ("aborting ug\n"); return (1); } #ifdef Debug { int i; for (i = 1; i < *argcp; i++) if (strncmp ((*argvp)[i], "-dbgfile", 8) == 0) break; if (i < *argcp) { const char* debugfilename = "dune-uggrid.dbg"; if (SetPrintDebugToFile (debugfilename) != 0) { printf ("ERROR while opening debug file '%s'\n", debugfilename); printf ("aborting ug\n"); return (1); } UserWriteF ("debug info is captured to file '%s'\n", debugfilename); } else { SetPrintDebugProc (printf); UserWriteF ("debug info is printed to stdout\n"); } } #endif /* init the gm module */ if ((err = InitGm ()) != 0) { printf ("ERROR in InitUg while InitGm (line %d): called routine line %d\n", (int) HiWrd (err), (int) LoWrd (err)); printf ("aborting ug\n"); return (1); } return (0); } /****************************************************************************/ /** \brief Call of the exitfunctions for all the ug modules * * This function exits ug. It is called at the end of the CommandLoop. * It calls all available exit functions in reverse order of the corresponding * calls in InitUg(). * * @return
      *
    • 0 if ok
    • *
    • 1 if error occurred.
    • *
    */ /****************************************************************************/ INT NS_DIM_PREFIX ExitUg (void) { INT err; /* exit gm module */ PRINTDEBUG (init, 1, (" ExitGm()...\n")) if ((err = ExitGm ()) != 0) { printf ("ERROR in ExitUg while ExitGm (line %d): called routine line %d\n", (int) HiWrd (err), (int) LoWrd (err)); printf ("aborting ug\n"); return (1); } /* exit devices module */ PRINTDEBUG (init, 1, (" ExitDevices()...\n")) if ((err = ExitDevices ()) != 0) { printf ("ERROR in ExitUg while ExitDevices (line %d): called routine line %d\n", (int) HiWrd (err), (int) LoWrd (err)); printf ("aborting ug\n"); return (1); } /* exit low module */ PRINTDEBUG (init, 1, (" ExitLow()...\n")) if ((err = ExitLow ()) != 0) { printf ("ERROR in ExitUg while ExitLow (line %d): called routine line %d\n", (int) HiWrd (err), (int) LoWrd (err)); printf ("aborting ug\n"); return (1); } return (0); } /** @} */ dune-uggrid-2.11.0+dfsg/dune/uggrid/initug.h000066400000000000000000000046251513616443000206220ustar00rootroot00000000000000// -*- tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- // vi: set et ts=4 sw=2 sts=2: // SPDX-FileCopyrightInfo: Copyright © DUNE Project contributors, see file LICENSE.md in module root // SPDX-License-Identifier: LGPL-2.1-or-later /** \defgroup ug The UG Kernel */ /*! \file * \ingroup ug */ /****************************************************************************/ /* */ /* File: initug.h */ /* */ /* Purpose: call the init routines of the ug modules (header file) */ /* */ /* Author: Henrik Rentz-Reichert */ /* Institut fuer Computeranwendungen III */ /* Universitaet Stuttgart */ /* Pfaffenwaldring 27 */ /* 70569 Stuttgart */ /* email: ug@ica3.uni-stuttgart.de */ /* */ /* History: 27.02.95 begin, ug version 3.0 */ /* */ /* Remarks: */ /* */ /****************************************************************************/ #ifndef __INITUG__ #define __INITUG__ #include #include START_UGDIM_NAMESPACE /****************************************************************************/ /* */ /* function declarations */ /* */ /****************************************************************************/ /** \brief Initialisation of the ug library */ INT InitUg (int *argcp, char ***argvp); /** \brief Finalisation of the ug library */ INT ExitUg (void); END_UGDIM_NAMESPACE #endif dune-uggrid-2.11.0+dfsg/dune/uggrid/lib/000077500000000000000000000000001513616443000177115ustar00rootroot00000000000000dune-uggrid-2.11.0+dfsg/dune/uggrid/lib/CMakeLists.txt000066400000000000000000000003611513616443000224510ustar00rootroot00000000000000# SPDX-FileCopyrightText: Copyright © DUNE Project contributors, see file LICENSE.md in module root # SPDX-License-Identifier: LGPL-2.1-or-later install( FILES RefRules.data tetra.rls triangle.rls DESTINATION ${CMAKE_INSTALL_DATADIR}) dune-uggrid-2.11.0+dfsg/dune/uggrid/lib/RefRules.data000066400000000000000000003476471513616443000223200ustar00rootroot00000000000000242 1024 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 -1 0 -1 0 -1 0 -1 0 -1 0 -1 0 -1 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 2 3 20 21 22 23 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 -1 0 -1 0 -1 0 -1 0 -1 0 -1 0 -1 0 2 1 0 0 0 0 0 1 2 2 4 0 2 3 4 3 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 2 3 4 1 1 23 20 21 0 0 2 3 4 22 0 23 20 268435456 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 2 -1 0 -1 0 -1 0 -1 0 -1 0 -1 0 2 0 1 0 0 0 0 2 2 0 5 0 2 3 5 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 2 3 5 22 21 1 20 0 1 3 5 0 21 0 20 23 268435458 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 -1 0 0 3 -1 0 -1 0 -1 0 -1 0 -1 0 2 0 0 1 0 0 0 4 2 1 6 0 2 3 6 2 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 2 3 6 1 22 1 20 21 0 1 3 6 0 0 22 20 23 268435457 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 -1 0 -1 0 0 2 -1 0 -1 0 -1 0 -1 0 2 0 0 0 1 0 0 8 2 2 7 2 2 1 7 3 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 2 3 7 1 22 23 1 21 0 0 1 2 7 20 0 22 23 268435458 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 -1 0 -1 0 -1 0 0 2 -1 0 -1 0 -1 0 2 0 0 0 0 1 0 16 2 2 8 1 2 0 8 3 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 2 3 8 22 21 23 1 0 0 1 2 8 20 21 0 23 268435459 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 -1 0 -1 0 -1 0 -1 0 0 3 -1 0 -1 0 2 0 0 0 0 0 1 32 2 1 9 1 2 0 9 2 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 3 9 0 21 22 1 23 0 0 1 2 9 20 21 22 0 268435458 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 -1 0 -1 0 -1 0 -1 0 -1 0 0 2 -1 0 3 1 1 0 0 0 0 3 2 2 4 0 2 4 5 0 2 3 5 1 2 3 4 3 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 2 3 4 5 1 2 20 21 0 0 2 3 4 22 0 23 20 268435456 3 4 5 1 0 20 21 23 268435457 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 2 0 3 -1 0 -1 0 -1 0 -1 0 -1 0 3 1 1 0 0 0 0 3 2 0 5 0 2 4 5 0 2 3 5 1 2 3 4 3 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 2 3 5 22 21 2 20 0 3 4 5 1 2 20 21 23 536870918 0 3 4 5 23 1 20 0 268435458 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 1 0 3 -1 0 -1 0 -1 0 -1 0 -1 0 3 1 0 1 0 0 0 5 2 2 4 0 2 4 6 0 2 3 6 2 2 3 4 3 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 2 3 4 1 1 23 20 21 0 3 4 6 2 2 20 22 0 268435456 0 3 4 6 23 1 20 22 536870912 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 2 -1 0 1 2 -1 0 -1 0 -1 0 -1 0 3 1 0 1 0 0 0 5 2 1 6 0 2 4 6 0 2 3 6 2 2 3 4 3 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 2 3 6 1 22 1 20 21 0 3 4 6 1 2 20 0 23 268435457 0 3 4 6 23 1 20 22 536870913 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 1 -1 0 0 2 -1 0 -1 0 -1 0 -1 0 3 0 1 1 0 0 0 6 2 0 5 0 2 5 6 0 2 3 5 1 2 3 6 2 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 3 5 6 2 2 20 22 21 0 1 3 5 0 21 2 20 23 536870912 0 3 5 6 1 0 20 22 268435456 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 -1 0 0 1 0 2 -1 0 -1 0 -1 0 -1 0 3 0 1 1 0 0 0 6 2 1 6 0 2 5 6 0 2 3 5 1 2 3 6 2 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 3 5 6 2 2 20 22 21 0 1 3 6 0 2 22 20 23 536870924 1 3 5 6 21 0 20 1 268435456 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 -1 0 0 1 0 2 -1 0 -1 0 -1 0 -1 0 3 1 0 0 1 0 0 9 2 2 4 0 2 2 7 2 2 3 4 3 2 4 7 3 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 2 3 4 1 1 23 20 21 0 3 4 7 2 23 2 22 0 268435456 2 4 7 0 1 23 22 20 536870916 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 2 -1 0 -1 0 1 2 -1 0 -1 0 -1 0 3 1 0 0 1 0 0 9 2 2 4 0 2 2 7 2 2 1 7 3 2 4 7 3 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 2 3 7 1 22 23 1 21 0 1 2 4 7 20 2 23 0 268435458 2 4 7 0 1 23 22 20 536870918 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 2 -1 0 -1 0 0 2 -1 0 -1 0 -1 0 4 0 1 0 1 0 0 10 2 0 5 0 1 5 7 0 2 3 5 1 2 2 7 2 2 1 7 3 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 3 5 7 2 1 3 22 21 0 1 3 5 7 21 0 2 23 268435456 0 1 5 7 20 1 3 23 536870920 2 5 7 0 0 2 22 20 268435457 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 -1 0 0 1 -1 0 0 2 -1 0 -1 0 -1 0 3 0 0 1 1 0 0 12 2 1 6 0 2 6 7 2 2 3 6 2 2 1 7 3 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 2 3 6 1 22 1 20 21 0 1 3 6 7 0 22 2 23 268435457 0 1 6 7 20 1 22 23 536870921 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 -1 0 -1 0 0 2 1 3 -1 0 -1 0 -1 0 3 0 0 1 1 0 0 12 2 1 6 0 2 6 7 2 2 2 7 2 2 1 7 3 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 2 3 7 1 22 23 1 21 0 1 2 6 7 20 22 2 0 268435458 0 1 6 7 20 1 22 23 536870922 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 -1 0 -1 0 1 2 0 2 -1 0 -1 0 -1 0 3 1 0 0 0 1 0 17 2 2 4 0 2 2 8 1 2 3 4 3 2 4 8 3 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 2 3 4 8 1 23 2 21 0 0 2 3 4 22 0 23 20 268435456 1 2 4 8 20 0 23 21 268435458 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 2 -1 0 -1 0 -1 0 0 3 -1 0 -1 0 3 1 0 0 0 1 0 17 2 2 4 0 2 2 8 1 2 0 8 3 2 4 8 3 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 2 3 8 22 21 23 2 0 1 2 4 8 20 2 23 21 536870915 2 4 8 0 1 23 0 20 268435459 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 2 -1 0 -1 0 -1 0 0 3 -1 0 -1 0 3 0 1 0 0 1 0 18 2 0 5 0 2 5 8 1 2 3 5 1 2 0 8 3 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 2 3 5 22 21 1 20 0 3 5 8 0 21 2 23 0 268435458 0 1 5 8 20 21 1 23 536870918 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 -1 0 0 3 -1 0 -1 0 1 2 -1 0 -1 0 3 0 1 0 0 1 0 18 2 0 5 0 2 5 8 1 2 2 8 1 2 0 8 3 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 2 3 8 22 21 23 1 0 2 5 8 0 21 2 0 20 268435459 0 1 5 8 20 21 1 23 536870919 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 -1 0 1 1 -1 0 -1 0 0 3 -1 0 -1 0 4 0 0 1 0 1 0 20 1 6 8 0 2 1 6 0 2 2 8 1 2 3 6 2 2 0 8 3 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 2 3 6 8 22 1 3 21 0 3 6 8 0 0 2 23 22 268435457 0 1 6 8 20 3 1 23 536870917 1 2 6 8 20 0 2 21 268435458 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 -1 0 -1 0 0 2 -1 0 0 3 -1 0 -1 0 3 0 0 0 1 1 0 24 2 2 8 1 2 2 7 2 2 1 7 3 2 7 8 3 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 2 3 7 8 22 23 2 21 0 0 1 2 7 20 2 22 23 536870914 1 2 7 8 1 0 23 21 268435458 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 -1 0 -1 0 -1 0 0 2 0 3 -1 0 -1 0 3 0 0 0 1 1 0 24 2 2 8 1 2 2 7 2 2 0 8 3 2 7 8 3 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 2 3 7 8 22 23 2 21 0 0 1 2 8 20 21 2 23 536870926 0 2 7 8 22 0 23 1 268435458 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 -1 0 -1 0 -1 0 0 2 0 3 -1 0 -1 0 4 1 0 0 0 0 1 33 1 4 9 0 2 2 4 0 2 1 9 1 2 0 9 2 2 3 4 3 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 3 4 9 1 1 3 21 23 0 0 3 4 9 23 0 2 22 268435456 2 4 9 0 3 1 22 20 536870920 1 2 4 9 20 2 0 21 268435457 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 -1 0 -1 0 -1 0 -1 0 0 2 -1 0 3 0 1 0 0 0 1 34 2 0 5 0 2 5 9 1 2 3 5 1 2 0 9 2 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 3 5 9 1 21 2 22 0 1 3 5 0 21 0 20 23 268435456 2 5 9 0 21 0 22 20 268435458 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 -1 0 0 2 -1 0 -1 0 -1 0 0 3 -1 0 3 0 1 0 0 0 1 34 2 0 5 0 2 5 9 1 2 1 9 1 2 0 9 2 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 3 9 0 21 22 2 23 0 2 5 9 0 21 2 22 20 536870922 0 1 5 9 20 21 1 0 268435458 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 -1 0 1 1 -1 0 -1 0 -1 0 0 2 -1 0 3 0 0 1 0 0 1 36 2 1 6 0 2 1 9 1 2 3 6 2 2 6 9 2 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 3 6 9 1 22 2 21 1 0 1 3 6 0 0 22 20 23 268435459 1 2 6 9 20 22 0 21 268435457 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 -1 0 -1 0 0 1 -1 0 -1 0 0 2 -1 0 3 0 0 1 0 0 1 36 2 1 6 0 2 1 9 1 2 0 9 2 2 6 9 2 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 3 9 0 21 22 2 23 0 1 2 6 9 20 22 2 21 536870918 0 1 6 9 20 1 22 0 268435458 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 -1 0 -1 0 1 2 -1 0 -1 0 0 2 -1 0 3 0 0 0 1 0 1 40 2 1 9 1 2 7 9 2 2 2 7 2 2 1 7 3 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 3 7 9 1 22 2 21 23 0 0 1 2 7 20 2 22 23 536870913 1 2 7 9 1 22 0 21 268435457 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 -1 0 -1 0 -1 0 0 1 -1 0 0 2 -1 0 3 0 0 0 1 0 1 40 2 1 9 1 2 0 9 2 2 7 9 2 2 1 7 3 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 3 7 9 1 22 2 21 23 0 0 1 2 9 20 21 22 2 536870921 1 7 9 0 0 22 1 23 268435457 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 -1 0 -1 0 -1 0 0 1 -1 0 0 2 -1 0 3 0 0 0 0 1 1 48 2 8 9 1 2 2 8 1 2 0 9 2 2 0 8 3 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 3 8 9 23 21 2 22 0 0 1 2 8 20 21 2 23 536870926 2 8 9 0 21 0 22 1 268435458 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 -1 0 -1 0 -1 0 -1 0 0 2 0 3 -1 0 3 0 0 0 0 1 1 48 2 8 9 1 2 1 9 1 2 0 9 2 2 0 8 3 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 3 8 9 23 21 2 22 0 0 1 2 9 20 21 22 2 536870922 1 8 9 0 21 0 1 23 268435458 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 -1 0 -1 0 -1 0 -1 0 0 2 0 3 -1 0 4 1 1 1 0 0 0 7 2 5 6 0 2 4 6 0 2 4 5 0 2 3 5 1 2 3 6 2 2 3 4 3 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 3 5 6 2 2 20 22 21 0 3 4 5 1 2 20 21 23 536870924 4 5 6 3 20 0 3 1 268435456 0 3 4 6 23 2 20 22 536870920 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 1 0 1 0 2 -1 0 -1 0 -1 0 -1 0 4 1 1 0 1 0 0 11 2 2 4 0 2 4 5 0 2 3 5 1 2 2 7 2 2 3 4 3 2 4 7 3 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 2 3 4 5 1 2 20 21 0 3 4 7 2 23 3 22 0 268435456 3 4 5 1 0 20 21 23 268435457 2 4 7 0 1 23 22 20 536870916 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 2 0 3 -1 0 1 2 -1 0 -1 0 -1 0 5 1 1 0 1 0 0 11 2 0 5 0 1 5 7 0 2 4 5 0 2 3 5 1 2 2 7 2 2 4 7 3 2 3 4 3 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 3 5 7 2 2 4 22 21 0 3 4 5 1 2 20 21 23 536870924 4 5 7 3 3 0 23 1 268435456 0 4 5 7 20 2 4 23 536870912 2 5 7 0 0 3 22 20 268435457 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 1 0 1 -1 0 0 2 -1 0 -1 0 -1 0 5 1 1 0 1 0 0 11 2 0 5 0 1 5 7 0 2 4 5 0 2 3 5 1 2 2 7 2 2 4 7 3 2 1 7 3 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 3 5 7 2 1 3 22 21 0 1 3 5 7 21 0 2 23 268435456 4 5 7 1 4 1 23 20 536870920 2 5 7 0 0 4 22 20 268435457 0 4 5 7 20 2 3 23 805306376 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 2 0 0 1 -1 0 0 2 -1 0 -1 0 -1 0 5 1 1 0 1 0 0 11 1 5 7 0 2 2 4 0 2 4 5 0 2 3 5 1 2 2 7 2 2 4 7 3 2 1 7 3 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 3 5 7 2 4 1 22 21 0 2 4 5 7 20 3 0 2 268435457 2 4 7 0 1 23 22 20 536870925 4 5 7 1 1 4 23 20 536870917 1 3 5 7 21 0 3 23 268435456 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 1 0 1 -1 0 0 2 -1 0 -1 0 -1 0 9 1 0 1 1 0 0 13 2 1 6 0 1 1 10 0 1 7 10 0 1 2 10 0 1 6 10 0 1 3 10 0 2 4 6 0 1 4 10 0 2 2 7 2 2 6 7 2 2 3 4 3 2 4 7 3 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 4 6 7 20 1 22 23 0 6 7 10 4 7 4 6 0 268435457 2 3 10 1 8 3 5 21 1073741989 3 4 10 1 4 6 2 23 805306405 4 7 10 3 1 8 3 23 536870917 1 2 6 10 20 7 6 2 1342177957 4 6 10 1 1 5 3 20 536870921 6 7 10 2 1 8 5 22 536870913 3 7 10 2 4 7 2 22 805306389 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 -1 0 0 2 0 3 -1 0 -1 0 1 2 9 1 0 1 1 0 0 13 1 7 10 0 1 1 10 0 2 2 4 0 1 2 10 0 1 6 10 0 1 3 10 0 2 4 6 0 1 4 10 0 2 3 6 2 2 6 7 2 2 4 7 3 2 1 7 3 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 4 6 7 20 1 22 23 0 6 7 10 4 8 4 6 0 268435457 2 3 10 1 7 3 5 21 1073741973 3 7 10 1 8 4 2 23 805306389 4 7 10 1 1 3 5 23 536870917 1 2 4 10 20 6 4 2 805306405 4 6 10 2 1 7 5 20 536870921 3 6 10 2 8 6 2 22 1342177429 6 7 10 3 1 3 7 22 536870913 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 -1 0 0 2 0 3 -1 0 -1 0 1 2 4 1 0 1 1 0 0 13 2 2 4 0 2 4 6 0 2 3 6 2 2 6 7 2 2 4 7 3 2 3 4 3 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 2 3 4 1 1 23 20 21 0 3 4 6 2 2 20 22 0 268435456 4 6 7 3 3 22 23 1 536870912 0 4 6 7 20 2 22 23 805306368 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 2 -1 0 1 2 2 2 -1 0 -1 0 -1 0 4 1 0 1 1 0 0 13 2 2 4 0 2 4 6 0 2 2 7 2 2 6 7 2 2 4 7 3 2 3 4 3 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 2 3 4 1 1 23 20 21 0 3 4 7 2 23 2 22 0 268435456 4 6 7 2 3 22 1 20 536870916 0 4 6 7 20 2 22 23 805306372 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 2 -1 0 2 1 1 2 -1 0 -1 0 -1 0 4 1 0 1 1 0 0 13 2 1 6 0 2 4 6 0 2 3 6 2 2 6 7 2 2 4 7 3 2 3 4 3 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 2 3 6 1 22 1 20 21 0 3 4 6 1 2 20 0 23 268435457 4 6 7 3 3 22 23 1 536870913 0 4 6 7 20 2 22 23 805306369 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 1 -1 0 0 2 2 2 -1 0 -1 0 -1 0 4 1 0 1 1 0 0 13 2 1 6 0 2 4 6 0 2 3 6 2 2 6 7 2 2 4 7 3 2 1 7 3 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 2 3 6 1 22 1 20 21 0 1 3 6 7 0 22 2 23 268435457 4 6 7 1 3 1 23 20 536870921 0 4 6 7 20 2 22 23 805306377 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 2 0 -1 0 0 2 1 3 -1 0 -1 0 -1 0 4 1 0 1 1 0 0 13 2 4 6 0 2 2 4 0 2 2 7 2 2 6 7 2 2 4 7 3 2 1 7 3 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 2 3 7 1 22 23 1 21 0 1 2 4 7 20 2 23 0 268435458 4 6 7 2 3 22 1 20 536870918 0 4 6 7 20 2 22 23 805306374 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 2 -1 0 2 1 0 2 -1 0 -1 0 -1 0 4 1 0 1 1 0 0 13 2 1 6 0 2 4 6 0 2 2 7 2 2 6 7 2 2 4 7 3 2 1 7 3 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 2 3 7 1 22 23 1 21 0 1 2 6 7 20 22 2 0 268435458 4 6 7 1 3 1 23 20 536870922 0 4 6 7 20 2 22 23 805306378 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 2 0 -1 0 1 2 0 2 -1 0 -1 0 -1 0 5 0 1 1 1 0 0 14 2 0 5 0 1 5 7 0 2 5 6 0 2 3 5 1 2 3 6 2 2 6 7 2 2 1 7 3 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 3 5 6 2 2 20 22 21 0 1 3 5 7 21 2 4 23 536870920 5 6 7 3 3 22 1 0 268435456 0 5 6 7 20 2 22 4 536870912 0 1 5 7 20 1 3 23 805306408 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 -1 0 0 1 0 2 1 3 -1 0 -1 0 -1 0 5 0 1 1 1 0 0 14 2 0 5 0 1 5 7 0 2 5 6 0 2 3 5 1 2 2 7 2 2 6 7 2 2 1 7 3 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 3 5 7 2 1 3 22 21 0 1 3 5 7 21 0 2 23 268435456 0 1 5 7 20 1 4 23 536870920 5 6 7 2 4 22 0 20 268435457 0 5 6 7 20 3 22 2 805306408 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 -1 0 0 1 3 1 0 2 -1 0 -1 0 -1 0 4 0 1 1 1 0 0 14 2 1 6 0 2 5 6 0 2 3 5 1 2 3 6 2 2 6 7 2 2 1 7 3 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 3 5 6 2 2 20 22 21 0 1 3 6 7 2 22 3 23 536870924 1 3 5 6 21 0 20 1 268435456 0 1 6 7 20 1 22 23 805306412 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 -1 0 0 1 0 2 1 3 -1 0 -1 0 -1 0 5 0 1 1 1 0 0 14 2 1 6 0 1 5 7 0 2 5 6 0 2 3 5 1 2 2 7 2 2 6 7 2 2 1 7 3 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 3 5 7 2 4 1 22 21 0 5 6 7 2 3 22 0 20 268435457 0 1 6 7 20 3 22 23 805306401 1 5 6 7 20 1 2 4 536870913 1 3 5 7 21 0 3 23 268435456 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 -1 0 0 1 1 1 0 2 -1 0 -1 0 -1 0 9 1 1 0 0 1 0 19 1 8 10 0 1 0 10 0 2 2 4 0 1 2 10 0 1 5 10 0 1 3 10 0 2 4 5 0 1 4 10 0 2 3 5 1 2 5 8 1 2 4 8 3 2 0 8 3 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 4 5 8 1 1 21 23 20 0 5 8 10 4 4 7 6 0 268435456 2 3 10 0 3 8 5 22 1073742000 3 5 10 2 4 6 2 21 805306416 3 5 8 10 21 1 8 3 536870912 2 4 10 0 6 7 2 20 1342177968 2 4 5 10 20 1 3 5 536870920 4 8 10 0 1 8 5 23 536870916 3 8 10 0 4 7 2 23 805306400 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 -1 0 -1 0 0 2 -1 0 1 2 9 1 1 0 0 1 0 19 2 0 5 0 1 0 10 0 1 8 10 0 1 2 10 0 1 5 10 0 1 3 10 0 2 4 5 0 1 4 10 0 2 2 8 1 2 5 8 1 2 3 4 3 2 4 8 3 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 4 5 8 1 1 21 23 20 0 5 8 10 4 4 8 6 0 268435456 2 3 10 0 3 7 5 22 1073741984 3 8 10 2 8 4 2 21 805306400 2 5 8 10 21 1 3 5 536870912 2 5 10 0 4 6 2 20 805306416 0 4 5 10 20 1 5 7 536870920 3 4 10 0 8 6 2 23 1342177696 4 8 10 3 1 3 7 23 536870916 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 -1 0 -1 0 0 2 -1 0 1 2 4 1 1 0 0 1 0 19 2 2 4 0 2 4 5 0 2 3 5 1 2 5 8 1 2 4 8 3 2 3 4 3 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 2 3 4 5 1 2 20 21 0 0 2 3 4 22 0 23 20 268435456 3 4 5 8 0 3 21 23 268435457 4 5 8 1 2 21 23 20 536870917 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 2 0 3 -1 0 -1 0 2 3 -1 0 -1 0 4 1 1 0 0 1 0 19 2 2 4 0 2 4 5 0 2 2 8 1 2 5 8 1 2 4 8 3 2 3 4 3 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 2 3 4 8 1 23 2 21 0 0 2 3 4 22 0 23 20 268435456 2 4 5 8 20 3 21 0 268435458 4 5 8 1 2 21 23 20 536870918 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 2 2 2 -1 0 -1 0 0 3 -1 0 -1 0 4 1 1 0 0 1 0 19 2 0 5 0 2 4 5 0 2 3 5 1 2 5 8 1 2 4 8 3 2 3 4 3 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 2 3 5 22 21 2 20 0 3 4 5 8 2 3 21 23 536870918 0 3 4 5 23 1 20 0 268435458 4 5 8 1 1 21 23 20 805306390 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 1 0 3 -1 0 -1 0 1 3 -1 0 -1 0 4 1 1 0 0 1 0 19 2 0 5 0 2 4 5 0 2 3 5 1 2 5 8 1 2 4 8 3 2 0 8 3 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 2 3 5 22 21 1 20 0 3 5 8 0 21 3 23 0 268435458 4 5 8 1 3 21 23 20 805306390 0 4 5 8 20 2 1 23 536870918 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 2 0 0 3 -1 0 -1 0 1 2 -1 0 -1 0 4 1 1 0 0 1 0 19 2 4 5 0 2 2 4 0 2 2 8 1 2 5 8 1 2 4 8 3 2 0 8 3 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 2 3 8 22 21 23 2 0 2 4 5 8 20 3 21 2 536870915 2 4 8 0 1 23 0 20 268435459 4 5 8 1 1 21 23 20 805306387 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 1 1 2 -1 0 -1 0 0 3 -1 0 -1 0 4 1 1 0 0 1 0 19 2 0 5 0 2 4 5 0 2 2 8 1 2 5 8 1 2 4 8 3 2 0 8 3 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 2 3 8 22 21 23 1 0 2 5 8 0 21 3 0 20 268435459 4 5 8 1 3 21 23 20 805306391 0 4 5 8 20 2 1 23 536870919 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 2 0 1 1 -1 0 -1 0 0 3 -1 0 -1 0 4 1 0 1 0 1 0 21 2 2 4 0 2 4 6 0 2 2 8 1 2 3 6 2 2 3 4 3 2 4 8 3 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 2 3 4 8 1 23 3 21 0 3 4 6 2 2 20 22 0 268435456 0 3 4 6 23 1 20 22 536870912 1 2 4 8 20 0 23 21 268435458 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 2 -1 0 1 2 -1 0 0 3 -1 0 -1 0 5 1 0 1 0 1 0 21 2 1 6 0 1 6 8 0 2 4 6 0 2 2 8 1 2 3 6 2 2 4 8 3 2 3 4 3 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 2 3 6 8 22 1 4 21 0 3 4 6 8 2 3 0 23 268435457 0 3 4 6 23 1 20 22 536870913 4 6 8 1 1 4 23 20 536870917 1 2 6 8 20 0 3 21 268435458 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 1 -1 0 0 2 -1 0 0 3 -1 0 -1 0 5 1 0 1 0 1 0 21 1 6 8 0 2 1 6 0 2 4 6 0 2 2 8 1 2 3 6 2 2 4 8 3 2 0 8 3 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 2 3 6 8 22 1 3 21 0 3 6 8 0 0 4 23 22 268435457 4 6 8 1 4 3 23 20 536870922 1 2 6 8 20 0 2 21 268435458 0 4 6 8 20 2 1 23 536870917 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 2 0 -1 0 0 2 -1 0 0 3 -1 0 -1 0 5 1 0 1 0 1 0 21 1 6 8 0 2 2 4 0 2 4 6 0 2 2 8 1 2 3 6 2 2 4 8 3 2 0 8 3 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 2 3 6 8 22 4 2 21 0 1 2 4 8 20 2 23 21 536870922 4 6 8 2 3 0 1 20 268435458 0 4 6 8 20 2 4 23 536870914 3 6 8 0 0 3 23 22 268435457 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 2 -1 0 0 2 -1 0 0 3 -1 0 -1 0 4 0 1 1 0 1 0 22 2 0 5 0 2 5 6 0 2 3 5 1 2 5 8 1 2 3 6 2 2 0 8 3 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 3 5 6 2 2 20 22 21 0 3 5 8 0 21 3 23 2 536870912 0 3 5 6 1 0 20 22 268435456 0 1 5 8 20 21 1 23 805306384 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 -1 0 0 1 0 2 -1 0 1 2 -1 0 -1 0 5 0 1 1 0 1 0 22 1 6 8 0 2 1 6 0 2 5 6 0 2 3 5 1 2 5 8 1 2 3 6 2 2 0 8 3 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 3 5 6 2 2 20 22 21 0 3 6 8 0 2 4 23 22 536870916 5 6 8 3 3 1 21 0 268435456 1 5 6 8 20 2 4 21 536870912 0 1 6 8 20 3 1 23 805306388 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 -1 0 0 1 0 2 -1 0 1 2 -1 0 -1 0 5 0 1 1 0 1 0 22 1 6 8 0 2 1 6 0 2 5 6 0 2 2 8 1 2 5 8 1 2 3 6 2 2 0 8 3 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 2 3 6 8 22 1 3 21 0 3 6 8 0 0 2 23 22 268435457 0 1 6 8 20 4 1 23 536870917 5 6 8 2 4 0 21 20 268435458 1 5 6 8 20 3 2 21 805306389 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 -1 0 3 0 0 2 -1 0 0 3 -1 0 -1 0 5 0 1 1 0 1 0 22 2 0 5 0 1 6 8 0 2 5 6 0 2 2 8 1 2 5 8 1 2 3 6 2 2 0 8 3 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 2 3 6 8 22 4 1 21 0 5 6 8 2 3 0 21 20 268435458 0 1 5 8 20 21 3 23 805306418 0 5 6 8 20 1 4 2 536870914 3 6 8 0 0 3 23 22 268435457 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 -1 0 1 0 0 2 -1 0 0 3 -1 0 -1 0 4 1 0 0 1 1 0 25 2 2 4 0 2 2 8 1 2 2 7 2 2 4 7 3 2 4 8 3 2 7 8 3 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 2 4 7 0 2 23 22 20 0 1 2 4 8 20 2 23 21 536870920 4 7 8 2 23 3 1 0 268435456 2 3 7 8 22 23 2 21 536870916 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 -1 0 -1 0 0 2 1 3 -1 0 -1 0 5 0 1 0 1 1 0 26 2 0 5 0 1 5 7 0 2 5 8 1 2 3 5 1 2 2 7 2 2 1 7 3 2 7 8 3 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 3 5 7 2 1 3 22 21 0 5 7 8 3 4 23 21 0 268435456 0 1 5 7 20 4 3 23 536870917 2 5 7 0 0 2 22 20 268435457 1 5 7 8 2 1 23 21 536870912 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 -1 0 0 1 -1 0 0 2 1 2 -1 0 -1 0 5 0 1 0 1 1 0 26 2 0 5 0 1 5 7 0 2 5 8 1 2 3 5 1 2 2 7 2 2 0 8 3 2 7 8 3 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 3 5 7 2 1 4 22 21 0 5 7 8 3 3 23 21 0 268435456 0 1 5 8 20 21 3 23 805306416 0 5 7 8 4 1 23 2 536870912 2 5 7 0 0 3 22 20 268435457 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 -1 0 0 1 -1 0 0 2 1 2 -1 0 -1 0 5 0 1 0 1 1 0 26 2 0 5 0 1 5 7 0 2 5 8 1 2 2 8 1 2 2 7 2 2 1 7 3 2 7 8 3 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 2 3 7 8 22 23 2 21 0 2 5 7 0 2 4 22 20 536870926 5 7 8 2 3 0 21 1 268435458 1 5 7 8 4 2 23 21 536870914 0 1 5 7 20 3 1 23 805306398 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 -1 0 1 1 -1 0 0 2 0 3 -1 0 -1 0 4 0 1 0 1 1 0 26 2 0 5 0 2 5 8 1 2 2 8 1 2 2 7 2 2 0 8 3 2 7 8 3 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 2 3 7 8 22 23 3 21 0 2 5 8 0 21 2 3 20 536870926 0 1 5 8 20 21 1 23 805306398 0 2 7 8 22 0 23 1 268435458 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 -1 0 1 1 -1 0 0 2 0 3 -1 0 -1 0 5 0 0 1 1 1 0 28 2 1 6 0 1 6 8 0 2 2 8 1 2 3 6 2 2 6 7 2 2 1 7 3 2 7 8 3 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 2 3 6 8 22 1 4 21 0 6 7 8 3 3 23 0 22 268435457 0 1 6 7 20 3 22 23 805306369 1 6 7 8 2 1 23 4 536870913 1 2 6 8 20 0 3 21 268435458 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 -1 0 -1 0 0 2 1 1 0 3 -1 0 -1 0 5 0 0 1 1 1 0 28 1 6 8 0 2 1 6 0 2 2 8 1 2 3 6 2 2 6 7 2 2 0 8 3 2 7 8 3 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 2 3 6 8 22 1 3 21 0 6 7 8 3 4 23 0 22 268435457 0 1 6 8 20 3 4 23 536870922 1 2 6 8 20 0 2 21 268435458 0 6 7 8 22 1 23 2 536870913 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 -1 0 -1 0 0 2 1 1 0 3 -1 0 -1 0 4 0 0 1 1 1 0 28 2 1 6 0 2 2 8 1 2 2 7 2 2 6 7 2 2 1 7 3 2 7 8 3 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 2 3 7 8 22 23 3 21 0 1 2 6 7 20 22 2 3 536870914 0 1 6 7 20 1 22 23 805306402 1 2 7 8 1 0 23 21 268435458 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 -1 0 -1 0 1 2 0 2 0 3 -1 0 -1 0 5 0 0 1 1 1 0 28 1 6 8 0 2 1 6 0 2 2 8 1 2 2 7 2 2 6 7 2 2 0 8 3 2 7 8 3 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 2 3 7 8 22 23 2 21 0 1 2 6 8 20 2 4 21 536870922 6 7 8 2 3 0 1 22 268435458 0 6 7 8 22 2 23 4 536870914 0 1 6 8 20 1 3 23 805306410 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 -1 0 -1 0 1 2 0 2 0 3 -1 0 -1 0 5 1 1 0 0 0 1 35 1 4 9 0 2 2 4 0 2 4 5 0 2 3 5 1 2 5 9 1 2 0 9 2 2 3 4 3 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 4 5 9 3 4 21 1 2 0 0 3 4 9 23 0 3 22 268435458 3 4 5 1 0 20 21 23 268435459 2 4 9 0 4 1 22 20 536870922 2 4 5 9 20 0 21 3 268435456 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 -1 0 -1 0 -1 0 0 2 -1 0 5 1 1 0 0 0 1 35 1 4 9 0 2 4 5 0 2 2 4 0 2 1 9 1 2 5 9 1 2 0 9 2 2 3 4 3 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 3 4 9 1 1 4 21 23 0 0 3 4 9 23 0 2 22 268435456 2 4 9 0 3 1 22 20 536870920 2 4 5 9 20 4 21 2 805306376 4 5 9 1 3 21 0 20 268435457 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 3 2 -1 0 -1 0 -1 0 0 2 -1 0 4 1 1 0 0 0 1 35 2 0 5 0 2 4 5 0 2 5 9 1 2 3 5 1 2 0 9 2 2 3 4 3 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 3 5 9 2 21 3 22 0 3 4 5 1 2 20 21 23 536870916 0 3 4 5 23 1 20 0 268435456 2 5 9 0 21 0 22 20 268435458 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 1 0 2 -1 0 -1 0 -1 0 0 3 -1 0 5 1 1 0 0 0 1 35 2 0 5 0 1 4 9 0 2 4 5 0 2 1 9 1 2 5 9 1 2 0 9 2 2 3 4 3 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 3 4 9 1 4 2 21 23 0 2 5 9 0 21 3 22 20 805306401 4 5 9 1 3 21 0 20 268435457 0 4 5 9 20 2 1 4 536870913 0 3 4 9 23 0 3 22 268435456 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 1 1 -1 0 -1 0 -1 0 0 2 -1 0 5 1 0 1 0 0 1 37 2 4 6 0 2 2 4 0 1 4 9 0 2 1 9 1 2 3 6 2 2 6 9 2 2 3 4 3 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 3 4 9 1 1 4 21 23 0 3 4 6 9 2 3 22 0 268435456 0 3 4 6 23 1 20 22 536870912 4 6 9 2 1 22 4 20 536870916 1 2 4 9 20 3 0 21 268435457 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 -1 0 1 2 -1 0 -1 0 0 2 -1 0 5 1 0 1 0 0 1 37 2 4 6 0 1 4 9 0 2 2 4 0 2 1 9 1 2 0 9 2 2 6 9 2 2 3 4 3 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 3 4 9 1 1 3 21 23 0 0 3 4 9 23 0 4 22 268435456 4 6 9 2 4 22 3 20 536870917 1 2 4 9 20 2 0 21 268435457 0 4 6 9 20 2 22 1 536870920 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 -1 0 2 1 -1 0 -1 0 0 2 -1 0 4 1 0 1 0 0 1 37 2 1 6 0 2 4 6 0 2 1 9 1 2 3 6 2 2 6 9 2 2 3 4 3 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 3 6 9 1 22 3 21 1 0 3 4 6 1 2 20 0 23 268435459 0 3 4 6 23 1 20 22 536870915 1 2 6 9 20 22 0 21 268435457 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 1 -1 0 0 1 -1 0 -1 0 0 2 -1 0 5 1 0 1 0 0 1 37 2 4 6 0 2 1 6 0 1 4 9 0 2 1 9 1 2 0 9 2 2 6 9 2 2 3 4 3 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 3 4 9 1 4 2 21 23 0 1 2 6 9 20 22 2 21 536870917 4 6 9 1 3 1 0 20 268435457 0 4 6 9 20 2 22 4 536870913 0 3 4 9 23 0 3 22 268435456 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 -1 0 1 2 -1 0 -1 0 0 2 -1 0 9 0 1 1 0 0 1 38 2 0 5 0 1 0 10 0 1 9 10 0 1 1 10 0 1 6 10 0 1 3 10 0 2 5 6 0 1 5 10 0 2 5 9 1 2 1 9 1 2 3 6 2 2 6 9 2 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 5 6 9 2 1 22 21 20 0 6 9 10 5 4 7 6 0 268435456 1 3 10 0 8 3 5 23 1073741984 3 6 10 0 4 6 2 22 805306400 6 9 10 3 1 8 3 22 536870912 0 1 5 10 20 7 6 2 1342177952 0 5 6 10 20 1 3 5 536870920 5 9 10 1 1 8 5 21 536870916 1 3 9 10 21 4 7 2 805306384 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 -1 0 0 0 0 1 -1 0 -1 0 0 2 1 2 9 0 1 1 0 0 1 38 1 9 10 0 1 0 10 0 2 1 6 0 1 1 10 0 1 6 10 0 1 3 10 0 2 5 6 0 1 5 10 0 2 5 9 1 2 3 5 1 2 6 9 2 2 0 9 2 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 5 6 9 2 1 22 21 20 0 6 9 10 5 4 8 6 0 268435456 1 3 10 0 7 3 5 23 1073741968 3 9 10 0 8 4 2 22 805306384 6 9 10 0 1 3 5 22 536870912 0 1 6 10 20 6 4 2 805306400 1 5 6 10 20 1 5 7 536870920 1 3 5 10 21 8 6 2 1342177424 5 9 10 3 1 3 7 21 536870916 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 -1 0 0 0 0 1 -1 0 -1 0 0 2 1 2 4 0 1 1 0 0 1 38 2 0 5 0 2 5 6 0 2 3 5 1 2 5 9 1 2 3 6 2 2 6 9 2 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 3 5 6 9 2 3 22 21 0 1 3 5 0 21 2 20 23 536870912 0 3 5 6 1 0 20 22 268435456 5 6 9 2 0 22 21 20 268435457 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 -1 0 0 1 0 2 -1 0 -1 0 0 3 -1 0 4 0 1 1 0 0 1 38 2 0 5 0 2 5 6 0 2 3 5 1 2 5 9 1 2 0 9 2 2 6 9 2 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 3 5 9 1 21 3 22 0 1 3 5 0 21 0 20 23 268435456 5 6 9 2 3 22 21 20 536870918 0 5 6 9 20 2 22 0 268435458 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 -1 0 0 2 2 1 -1 0 -1 0 0 3 -1 0 4 0 1 1 0 0 1 38 2 1 6 0 2 5 6 0 2 3 5 1 2 5 9 1 2 3 6 2 2 6 9 2 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 3 5 6 9 2 3 22 21 0 1 3 6 0 2 22 20 23 536870924 1 3 5 6 21 0 20 1 268435456 5 6 9 2 0 22 21 20 268435457 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 -1 0 0 1 0 2 -1 0 -1 0 0 3 -1 0 4 0 1 1 0 0 1 38 2 1 6 0 2 5 6 0 2 1 9 1 2 5 9 1 2 3 6 2 2 6 9 2 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 3 6 9 1 22 3 21 1 0 1 3 6 0 0 22 20 23 268435459 5 6 9 2 3 22 21 20 536870917 1 5 6 9 20 2 0 21 268435457 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 -1 0 2 0 0 1 -1 0 -1 0 0 2 -1 0 4 0 1 1 0 0 1 38 2 0 5 0 2 5 6 0 2 1 9 1 2 5 9 1 2 0 9 2 2 6 9 2 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 3 9 0 21 22 2 23 0 5 6 9 2 3 22 21 20 805306394 0 1 5 9 20 21 3 0 268435458 0 5 6 9 20 1 22 2 536870922 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 -1 0 1 0 1 1 -1 0 -1 0 0 2 -1 0 4 0 1 1 0 0 1 38 2 5 6 0 2 1 6 0 2 1 9 1 2 5 9 1 2 0 9 2 2 6 9 2 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 3 9 0 21 22 2 23 0 5 6 9 2 3 22 21 20 805306390 0 1 6 9 20 3 22 0 268435458 1 5 6 9 20 1 2 21 536870918 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 -1 0 1 0 1 1 -1 0 -1 0 0 2 -1 0 5 1 0 0 1 0 1 41 1 4 9 0 2 2 4 0 2 1 9 1 2 2 7 2 2 7 9 2 2 3 4 3 2 4 7 3 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 3 4 9 1 1 4 21 23 0 3 4 7 9 23 3 22 0 268435456 2 4 7 0 3 23 22 20 805306420 4 7 9 2 1 22 4 2 536870916 1 2 4 9 20 3 0 21 268435457 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 -1 0 -1 0 1 2 -1 0 0 2 -1 0 5 1 0 0 1 0 1 41 1 4 9 0 2 2 4 0 2 1 9 1 2 0 9 2 2 7 9 2 2 3 4 3 2 4 7 3 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 3 4 9 1 1 3 21 23 0 3 4 7 9 23 4 22 0 268435456 2 4 9 0 3 4 22 20 536870917 1 2 4 9 20 2 0 21 268435457 4 7 9 0 1 22 2 23 536870916 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 -1 0 -1 0 1 2 -1 0 0 2 -1 0 4 1 0 0 1 0 1 41 2 2 4 0 2 1 9 1 2 7 9 2 2 2 7 2 2 4 7 3 2 1 7 3 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 3 7 9 1 22 3 21 23 0 1 2 4 7 20 2 23 3 536870913 2 4 7 0 1 23 22 20 805306385 1 2 7 9 1 22 0 21 268435457 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 2 -1 0 -1 0 0 1 -1 0 0 2 -1 0 5 1 0 0 1 0 1 41 2 2 4 0 1 4 9 0 2 1 9 1 2 0 9 2 2 7 9 2 2 1 7 3 2 4 7 3 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 3 7 9 1 22 2 21 23 0 1 2 4 9 20 4 2 21 536870925 1 4 7 9 23 3 0 1 268435457 4 7 9 0 2 22 4 23 536870917 2 4 9 0 1 3 22 20 805306397 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 2 -1 0 -1 0 0 1 -1 0 0 2 -1 0 5 0 1 0 1 0 1 42 2 0 5 0 1 5 7 0 2 5 9 1 2 3 5 1 2 2 7 2 2 7 9 2 2 1 7 3 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 3 5 7 9 1 4 22 21 0 1 3 5 7 21 0 2 23 268435456 0 1 5 7 20 1 3 23 536870920 2 5 7 0 4 2 22 20 805306408 5 7 9 2 0 22 21 3 268435457 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 -1 0 0 1 -1 0 0 2 -1 0 0 3 -1 0 5 0 1 0 1 0 1 42 2 0 5 0 1 5 7 0 2 5 9 1 2 3 5 1 2 0 9 2 2 7 9 2 2 1 7 3 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 3 5 7 9 1 4 22 21 0 1 3 5 7 21 0 3 23 268435456 2 5 9 0 21 4 22 20 536870921 0 1 5 7 20 1 4 23 536870920 5 7 9 0 0 22 2 3 268435457 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 -1 0 0 1 -1 0 0 2 -1 0 0 3 -1 0 5 0 1 0 1 0 1 42 2 0 5 0 1 5 7 0 2 1 9 1 2 5 9 1 2 2 7 2 2 7 9 2 2 1 7 3 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 3 7 9 1 22 3 21 23 0 2 5 7 0 2 4 22 20 805306421 5 7 9 2 3 22 21 1 536870917 1 5 7 9 4 2 0 21 268435457 0 1 5 7 20 3 1 23 536870913 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 -1 0 1 1 -1 0 0 1 -1 0 0 2 -1 0 4 0 1 0 1 0 1 42 2 0 5 0 2 1 9 1 2 5 9 1 2 0 9 2 2 7 9 2 2 1 7 3 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 3 7 9 1 22 3 21 23 0 2 5 9 0 21 2 22 20 805306409 0 1 5 9 20 21 1 3 536870921 1 7 9 0 0 22 2 23 268435457 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 -1 0 1 1 -1 0 0 1 -1 0 0 2 -1 0 4 0 0 1 1 0 1 44 2 1 6 0 2 1 9 1 2 7 9 2 2 6 7 2 2 6 9 2 2 1 7 3 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 2 6 9 20 22 2 21 0 0 1 6 7 20 2 22 23 536870914 1 6 7 9 1 22 3 0 268435458 3 7 9 1 22 2 21 23 536870922 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 -1 0 -1 0 0 2 1 3 -1 0 0 3 -1 0 5 1 0 0 0 1 1 49 1 4 9 0 2 2 4 0 2 2 8 1 2 8 9 1 2 0 9 2 2 4 8 3 2 3 4 3 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 4 8 9 3 4 21 1 23 0 0 3 4 9 23 0 3 22 268435458 1 2 4 8 20 4 23 21 536870912 2 4 9 0 4 1 22 20 536870922 2 4 8 9 2 0 21 3 268435456 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 -1 0 -1 0 -1 0 0 1 0 2 -1 0 5 1 0 0 0 1 1 49 1 4 9 0 2 2 4 0 2 1 9 1 2 8 9 1 2 0 9 2 2 4 8 3 2 3 4 3 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 4 8 9 3 4 21 1 23 0 0 3 4 9 23 0 2 22 268435458 2 4 9 0 3 1 22 20 536870922 1 2 4 9 20 2 4 21 805306378 1 4 8 9 23 0 21 3 268435456 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 -1 0 -1 0 -1 0 0 1 0 2 -1 0 4 1 0 0 0 1 1 49 2 2 4 0 2 8 9 1 2 2 8 1 2 0 9 2 2 4 8 3 2 0 8 3 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 3 8 9 23 21 3 22 0 1 2 4 8 20 2 23 21 805306382 2 4 8 0 1 23 3 20 536870926 2 8 9 0 21 0 22 2 268435458 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 2 -1 0 -1 0 -1 0 0 2 0 3 -1 0 5 1 0 0 0 1 1 49 1 4 9 0 2 2 4 0 2 1 9 1 2 8 9 1 2 0 9 2 2 0 8 3 2 4 8 3 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 3 8 9 23 21 3 22 0 1 2 4 9 20 4 2 21 805306418 1 4 8 9 23 3 21 1 536870914 4 8 9 0 2 0 4 23 268435458 2 4 9 0 1 3 22 20 536870922 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 2 -1 0 -1 0 -1 0 0 2 0 3 -1 0 4 0 1 0 0 1 1 50 2 0 5 0 2 8 9 1 2 5 9 1 2 5 8 1 2 0 9 2 2 0 8 3 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 5 8 20 21 2 23 0 2 5 9 0 21 2 22 20 536870922 5 8 9 0 21 3 1 0 268435458 0 3 8 9 23 21 2 22 536870918 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 -1 0 0 2 -1 0 -1 0 0 3 1 2 -1 0 5 0 0 1 0 1 1 52 1 6 8 0 2 1 6 0 2 2 8 1 2 8 9 1 2 3 6 2 2 6 9 2 2 0 8 3 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 6 8 9 3 4 21 22 1 0 3 6 8 0 0 2 23 22 268435459 0 1 6 8 20 3 1 23 536870919 1 2 6 8 20 4 2 21 805306391 2 6 8 9 3 0 21 22 268435456 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 -1 0 -1 0 0 0 -1 0 0 1 0 2 -1 0 5 0 0 1 0 1 1 52 1 6 8 0 2 1 6 0 2 1 9 1 2 8 9 1 2 3 6 2 2 6 9 2 2 0 8 3 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 6 8 9 3 4 21 22 1 0 3 6 8 0 0 3 23 22 268435459 1 2 6 9 20 22 4 21 536870924 0 1 6 8 20 4 1 23 536870919 1 6 8 9 3 0 21 2 268435456 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 -1 0 -1 0 0 0 -1 0 0 1 0 2 -1 0 5 0 0 1 0 1 1 52 1 6 8 0 2 1 6 0 2 8 9 1 2 2 8 1 2 0 9 2 2 6 9 2 2 0 8 3 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 3 8 9 23 21 3 22 0 1 2 6 8 20 2 4 21 805306370 2 6 8 9 1 3 21 22 536870914 6 8 9 0 2 0 22 4 268435458 0 1 6 8 20 1 3 23 536870926 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 -1 0 -1 0 1 2 -1 0 0 2 0 3 -1 0 4 0 0 1 0 1 1 52 2 1 6 0 2 8 9 1 2 1 9 1 2 0 9 2 2 6 9 2 2 0 8 3 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 3 8 9 23 21 3 22 0 1 2 6 9 20 22 2 21 805306394 0 1 6 9 20 1 22 3 536870922 1 8 9 0 21 0 2 23 268435458 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 -1 0 -1 0 1 2 -1 0 0 2 0 3 -1 0 9 0 0 0 1 1 1 56 1 9 10 0 1 0 10 0 1 8 10 0 1 1 10 0 1 7 10 0 1 2 10 0 2 8 9 1 2 2 8 1 2 7 9 2 2 0 9 2 2 1 7 3 2 7 8 3 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 7 8 9 3 1 21 22 23 0 8 9 10 7 4 7 6 0 268435456 0 1 2 10 20 3 8 5 1073742000 2 8 10 1 4 6 2 21 805306416 2 8 9 10 21 1 8 3 536870912 1 7 10 0 6 7 2 23 1342178224 7 8 10 1 1 3 5 23 536870920 7 9 10 0 1 8 5 22 536870916 2 9 10 0 4 7 2 22 805306400 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 -1 0 -1 0 -1 0 0 0 0 1 0 2 1 2 9 0 0 0 1 1 1 56 1 9 10 0 1 0 10 0 1 8 10 0 1 1 10 0 1 7 10 0 1 2 10 0 2 1 9 1 2 8 9 1 2 2 7 2 2 7 9 2 2 7 8 3 2 0 8 3 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 7 8 9 3 1 21 22 23 0 8 9 10 7 4 8 6 0 268435456 0 1 2 10 20 3 7 5 1073741984 2 9 10 1 8 4 2 21 805306400 1 8 9 10 21 1 3 5 536870912 1 8 10 0 4 6 2 23 805306416 7 8 10 0 1 5 7 23 536870920 2 7 10 0 8 6 2 22 1342177952 7 9 10 2 1 3 7 22 536870916 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 -1 0 -1 0 -1 0 0 0 0 1 0 2 1 2 4 0 0 0 1 1 1 56 2 8 9 1 2 2 8 1 2 2 7 2 2 7 9 2 2 7 8 3 2 1 7 3 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 7 8 9 3 3 21 22 23 0 0 1 2 7 20 2 22 23 805306368 1 2 7 8 1 3 23 21 536870912 2 7 8 9 2 0 21 22 268435456 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 -1 0 -1 0 -1 0 0 0 0 1 0 2 -1 0 4 0 0 0 1 1 1 56 2 8 9 1 2 1 9 1 2 2 7 2 2 7 9 2 2 7 8 3 2 1 7 3 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 7 8 9 3 3 21 22 23 0 0 1 2 7 20 2 22 23 805306380 1 2 7 9 1 22 3 21 536870924 1 7 8 9 23 0 21 2 268435456 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 -1 0 -1 0 -1 0 0 0 0 1 0 2 -1 0 4 0 0 0 1 1 1 56 2 8 9 1 2 2 8 1 2 2 7 2 2 7 9 2 2 7 8 3 2 0 8 3 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 7 8 9 3 3 21 22 23 0 0 1 2 8 20 21 2 23 805306416 0 2 7 8 22 3 23 1 536870912 2 7 8 9 2 0 21 22 268435456 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 -1 0 -1 0 -1 0 0 0 0 1 0 2 -1 0 4 0 0 0 1 1 1 56 2 8 9 1 2 2 8 1 2 0 9 2 2 7 9 2 2 7 8 3 2 0 8 3 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 7 8 9 3 3 21 22 23 0 0 1 2 8 20 21 2 23 805306424 2 8 9 0 21 3 22 1 536870920 0 7 8 9 23 0 2 22 268435456 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 -1 0 -1 0 -1 0 0 0 0 1 0 2 -1 0 4 0 0 0 1 1 1 56 2 8 9 1 2 1 9 1 2 0 9 2 2 7 9 2 2 7 8 3 2 1 7 3 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 7 8 9 3 3 21 22 23 0 0 1 2 9 20 21 22 2 805306412 1 7 9 0 3 22 1 23 536870924 1 7 8 9 23 0 21 2 268435456 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 -1 0 -1 0 -1 0 0 0 0 1 0 2 -1 0 4 0 0 0 1 1 1 56 2 8 9 1 2 1 9 1 2 0 9 2 2 7 9 2 2 7 8 3 2 0 8 3 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 7 8 9 3 3 21 22 23 0 0 1 2 9 20 21 22 2 805306408 1 8 9 0 21 3 1 23 536870920 0 7 8 9 23 0 2 22 268435456 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 -1 0 -1 0 -1 0 0 0 0 1 0 2 -1 0 6 1 1 1 1 0 0 15 1 5 7 0 2 5 6 0 2 4 6 0 2 4 5 0 2 3 5 1 2 3 6 2 2 6 7 2 2 3 4 3 2 4 7 3 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 4 6 7 20 1 22 23 0 4 5 6 7 20 4 0 2 268435457 4 5 7 3 1 4 23 3 536870925 3 4 5 1 2 20 21 23 805306429 5 6 7 3 1 22 2 5 536870917 3 5 6 2 4 20 22 21 805306421 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 1 1 0 2 0 3 -1 0 -1 0 -1 0 6 1 1 1 1 0 0 15 2 5 6 0 1 5 7 0 2 4 6 0 2 4 5 0 2 3 5 1 2 2 7 2 2 6 7 2 2 3 4 3 2 4 7 3 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 4 6 7 20 1 22 23 0 4 5 6 7 20 5 0 2 268435457 4 5 7 3 1 4 23 3 536870925 3 4 5 1 2 20 21 23 805306429 3 5 7 2 2 5 22 21 805306397 5 6 7 2 1 22 4 20 536870917 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 1 1 0 2 0 3 -1 0 -1 0 -1 0 6 1 1 1 1 0 0 15 1 5 7 0 2 5 6 0 2 4 6 0 2 4 5 0 2 3 5 1 2 2 7 2 2 6 7 2 2 1 7 3 2 4 7 3 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 4 6 7 20 1 22 23 0 4 5 6 7 20 5 0 2 268435457 4 5 7 1 1 3 23 20 536870925 1 3 5 7 21 4 2 23 805306397 3 5 7 2 3 5 22 21 1073741917 5 6 7 2 1 22 4 20 536870917 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 1 1 0 2 0 3 -1 0 -1 0 -1 0 6 1 1 1 1 0 0 15 1 5 7 0 2 5 6 0 2 4 6 0 2 4 5 0 2 3 5 1 2 3 6 2 2 6 7 2 2 1 7 3 2 4 7 3 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 4 6 7 20 1 22 23 0 4 5 6 7 20 4 0 2 268435457 4 5 7 1 1 3 23 20 536870925 1 3 5 7 21 4 2 23 805306397 5 6 7 3 1 22 3 5 536870917 3 5 6 2 4 20 22 21 805306421 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 1 1 0 2 0 3 -1 0 -1 0 -1 0 6 1 1 1 0 1 0 23 1 6 8 0 2 4 6 0 2 5 6 0 2 4 5 0 2 3 5 1 2 5 8 1 2 3 6 2 2 4 8 3 2 3 4 3 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 4 5 8 1 1 21 23 20 0 4 5 6 8 20 2 4 0 268435456 5 6 8 3 1 4 21 3 536870916 3 5 6 2 2 20 22 21 805306420 3 4 6 8 5 1 2 23 536870920 0 3 4 6 23 4 20 22 805306376 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 1 2 -1 0 0 2 -1 0 -1 0 6 1 1 1 0 1 0 23 1 6 8 0 2 4 6 0 2 5 6 0 2 4 5 0 2 3 5 1 2 5 8 1 2 3 6 2 2 4 8 3 2 0 8 3 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 4 5 8 1 1 21 23 20 0 4 5 6 8 20 2 5 0 268435456 5 6 8 3 1 4 21 3 536870916 3 5 6 2 2 20 22 21 805306420 3 6 8 0 2 5 23 22 805306388 0 4 6 8 20 1 4 23 536870920 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 1 2 -1 0 0 2 -1 0 -1 0 6 1 1 1 0 1 0 23 1 6 8 0 2 4 6 0 2 5 6 0 2 4 5 0 2 2 8 1 2 5 8 1 2 3 6 2 2 4 8 3 2 0 8 3 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 4 5 8 1 1 21 23 20 0 4 5 6 8 20 2 5 0 268435456 5 6 8 2 1 3 21 20 536870916 2 3 6 8 22 4 2 21 805306388 3 6 8 0 3 5 23 22 1073741908 0 4 6 8 20 1 4 23 536870920 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 1 2 -1 0 0 2 -1 0 -1 0 6 1 1 1 0 1 0 23 1 6 8 0 2 5 6 0 2 4 6 0 2 4 5 0 2 2 8 1 2 5 8 1 2 3 6 2 2 4 8 3 2 3 4 3 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 4 5 8 1 1 21 23 20 0 4 5 6 8 20 2 4 0 268435456 5 6 8 2 1 3 21 20 536870916 2 3 6 8 22 4 2 21 805306388 3 4 6 8 5 1 3 23 536870920 0 3 4 6 23 4 20 22 805306376 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 1 2 -1 0 0 2 -1 0 -1 0 6 1 1 0 1 1 0 27 2 2 4 0 1 5 7 0 2 4 5 0 2 2 8 1 2 5 8 1 2 2 7 2 2 4 8 3 2 4 7 3 2 7 8 3 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 4 5 8 1 1 21 23 20 0 4 5 7 8 2 4 23 0 268435456 2 4 5 7 20 1 4 3 536870912 2 4 7 0 2 23 22 20 805306416 5 7 8 2 1 5 21 2 536870916 2 3 7 8 22 23 4 21 805306388 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 -1 0 1 2 0 2 -1 0 -1 0 6 1 1 0 1 1 0 27 2 2 4 0 1 5 7 0 2 4 5 0 2 3 5 1 2 5 8 1 2 2 7 2 2 4 8 3 2 4 7 3 2 7 8 3 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 4 5 8 1 1 21 23 20 0 4 5 7 8 2 5 23 0 268435456 2 4 5 7 20 1 4 3 536870912 2 4 7 0 2 23 22 20 805306416 3 5 7 2 5 2 22 21 805306400 5 7 8 3 1 23 21 4 536870916 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 -1 0 1 2 0 2 -1 0 -1 0 6 1 1 0 1 1 0 27 2 0 5 0 1 5 7 0 2 4 5 0 2 3 5 1 2 5 8 1 2 2 7 2 2 4 8 3 2 4 7 3 2 7 8 3 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 4 5 8 1 1 21 23 20 0 4 5 7 8 2 5 23 0 268435456 0 4 5 7 20 1 3 23 536870912 2 5 7 0 4 2 22 20 805306400 3 5 7 2 5 3 22 21 1073741856 5 7 8 3 1 23 21 4 536870916 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 -1 0 1 2 0 2 -1 0 -1 0 6 1 1 0 1 1 0 27 2 0 5 0 1 5 7 0 2 4 5 0 2 2 8 1 2 5 8 1 2 2 7 2 2 4 8 3 2 4 7 3 2 7 8 3 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 4 5 8 1 1 21 23 20 0 4 5 7 8 2 4 23 0 268435456 0 4 5 7 20 1 3 23 536870912 2 5 7 0 4 2 22 20 805306400 5 7 8 2 1 5 21 3 536870916 2 3 7 8 22 23 4 21 805306388 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 -1 0 1 2 0 2 -1 0 -1 0 6 1 0 1 1 1 0 29 2 2 4 0 1 6 8 0 2 4 6 0 2 2 8 1 2 2 7 2 2 6 7 2 2 4 8 3 2 4 7 3 2 7 8 3 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 4 6 7 20 1 22 23 0 4 6 7 8 0 2 23 4 268435457 6 7 8 2 1 3 4 22 536870917 2 3 7 8 22 23 2 21 805306389 4 6 8 2 1 2 5 20 536870925 1 2 4 8 20 4 23 21 805306413 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 -1 0 0 2 0 3 1 3 -1 0 -1 0 6 1 0 1 1 1 0 29 2 1 6 0 1 6 8 0 2 4 6 0 2 2 8 1 2 2 7 2 2 6 7 2 2 4 8 3 2 4 7 3 2 7 8 3 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 4 6 7 20 1 22 23 0 4 6 7 8 0 2 23 5 268435457 6 7 8 2 1 3 4 22 536870917 2 3 7 8 22 23 2 21 805306389 1 2 6 8 20 2 5 21 805306405 4 6 8 1 1 4 23 20 536870925 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 -1 0 0 2 0 3 1 3 -1 0 -1 0 6 1 0 1 1 1 0 29 2 1 6 0 1 6 8 0 2 4 6 0 2 2 8 1 2 3 6 2 2 6 7 2 2 4 8 3 2 4 7 3 2 7 8 3 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 4 6 7 20 1 22 23 0 4 6 7 8 0 2 23 5 268435457 6 7 8 3 1 23 3 22 536870917 2 3 6 8 22 2 4 21 805306405 1 2 6 8 20 3 5 21 1073741989 4 6 8 1 1 4 23 20 536870925 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 -1 0 0 2 0 3 1 3 -1 0 -1 0 6 1 0 1 1 1 0 29 2 2 4 0 1 6 8 0 2 4 6 0 2 2 8 1 2 3 6 2 2 6 7 2 2 4 8 3 2 4 7 3 2 7 8 3 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 4 6 7 20 1 22 23 0 4 6 7 8 0 2 23 4 268435457 6 7 8 3 1 23 3 22 536870917 2 3 6 8 22 2 4 21 805306405 4 6 8 2 1 3 5 20 536870925 1 2 4 8 20 4 23 21 805306413 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 -1 0 0 2 0 3 1 3 -1 0 -1 0 12 0 1 1 1 1 0 30 2 0 5 0 1 0 10 0 1 8 10 0 1 1 10 0 1 7 10 0 1 2 10 0 1 6 10 0 1 3 10 0 2 5 6 0 1 5 10 0 2 5 8 1 2 2 8 1 2 3 6 2 2 6 7 2 2 7 8 3 2 1 7 3 5 8 10 1 7 1 4 21 0 7 8 10 1 9 0 5 23 268435457 0 5 6 10 20 6 3 4 536870922 6 7 10 0 8 5 2 22 805306410 0 1 5 10 20 0 2 5 268435458 1 7 10 0 1 3 4 23 536870921 5 6 10 2 2 11 7 20 805306394 2 5 8 10 21 0 10 6 268435456 6 7 10 3 3 9 11 22 1073741866 7 8 10 3 1 10 8 23 536870913 3 8 10 2 9 7 11 21 536870920 3 6 10 2 8 6 10 22 1073741914 -1 0 0 0 2 2 1 0 0 1 -1 0 0 2 12 0 1 1 1 1 0 30 1 8 10 0 1 0 10 0 2 1 6 0 1 1 10 0 1 7 10 0 1 2 10 0 1 6 10 0 1 3 10 0 2 5 6 0 1 5 10 0 2 5 8 1 2 3 5 1 2 6 7 2 2 2 7 2 2 7 8 3 2 0 8 3 1 5 6 10 20 6 4 1 0 5 8 10 1 8 5 0 21 268435459 6 7 10 0 7 3 4 22 536870922 7 8 10 0 9 5 2 23 805306394 0 1 6 10 20 0 2 5 268435458 1 8 10 0 1 3 4 23 536870919 5 6 10 2 0 7 10 20 268435457 6 7 10 2 2 11 6 22 805306378 3 5 8 10 21 1 9 10 536870915 7 8 10 3 3 8 11 23 1073741850 3 5 10 2 8 6 11 21 536870921 3 7 10 2 9 7 10 22 1073741898 -1 0 0 1 0 2 2 1 1 1 -1 0 0 3 6 0 1 1 1 1 0 30 2 0 5 0 1 5 7 0 2 5 6 0 2 3 5 1 2 5 8 1 2 3 6 2 2 6 7 2 2 1 7 3 2 7 8 3 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 3 5 6 2 2 20 22 21 0 5 7 8 3 5 23 21 2 536870920 5 6 7 3 3 22 1 0 268435456 0 5 6 7 20 2 22 4 536870912 0 1 5 7 20 5 3 23 805306416 1 5 7 8 4 1 23 21 805306376 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 -1 0 0 1 0 2 1 1 1 2 -1 0 -1 0 6 0 1 1 1 1 0 30 2 0 5 0 1 5 7 0 2 5 6 0 2 3 5 1 2 5 8 1 2 3 6 2 2 6 7 2 2 0 8 3 2 7 8 3 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 3 5 6 2 2 20 22 21 0 5 7 8 3 5 23 21 2 536870920 5 6 7 3 4 22 1 0 268435456 0 1 5 8 20 21 5 23 1073742024 0 5 6 7 20 2 22 5 536870912 0 5 7 8 4 1 23 3 805306376 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 -1 0 0 1 0 2 1 1 1 2 -1 0 -1 0 6 0 1 1 1 1 0 30 2 0 5 0 1 5 7 0 2 5 6 0 2 3 5 1 2 5 8 1 2 2 7 2 2 6 7 2 2 1 7 3 2 7 8 3 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 3 5 7 2 1 3 22 21 0 5 7 8 3 5 23 21 0 268435456 0 1 5 7 20 5 4 23 805306417 5 6 7 2 4 22 0 20 268435457 0 5 6 7 20 3 22 2 536870913 1 5 7 8 2 1 23 21 536870912 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 -1 0 0 1 3 1 0 2 1 2 -1 0 -1 0 6 0 1 1 1 1 0 30 2 0 5 0 1 5 7 0 2 5 6 0 2 3 5 1 2 5 8 1 2 2 7 2 2 6 7 2 2 0 8 3 2 7 8 3 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 3 5 7 2 1 4 22 21 0 5 7 8 3 3 23 21 0 268435456 0 1 5 8 20 21 3 23 805306416 0 5 7 8 5 1 23 2 536870912 5 6 7 2 5 22 0 20 268435457 0 5 6 7 20 4 22 3 805306368 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 -1 0 0 1 4 1 0 2 1 2 -1 0 -1 0 6 0 1 1 1 1 0 30 2 1 6 0 1 6 8 0 2 5 6 0 2 3 5 1 2 5 8 1 2 3 6 2 2 6 7 2 2 1 7 3 2 7 8 3 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 3 5 6 2 2 20 22 21 0 6 7 8 3 5 23 2 22 536870916 5 6 8 3 4 1 21 0 268435456 0 1 6 7 20 5 22 23 1073741828 1 5 6 8 20 2 5 21 536870912 1 6 7 8 3 1 23 4 805306372 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 -1 0 0 1 0 2 1 1 1 2 -1 0 -1 0 6 0 1 1 1 1 0 30 1 6 8 0 2 1 6 0 2 5 6 0 2 3 5 1 2 5 8 1 2 3 6 2 2 6 7 2 2 0 8 3 2 7 8 3 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 3 5 6 2 2 20 22 21 0 6 7 8 3 5 23 2 22 536870916 5 6 8 3 3 1 21 0 268435456 1 5 6 8 20 2 4 21 536870912 0 1 6 8 20 3 5 23 805306400 0 6 7 8 22 1 23 4 805306372 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 -1 0 0 1 0 2 1 1 1 2 -1 0 -1 0 6 0 1 1 1 1 0 30 2 1 6 0 1 6 8 0 2 5 6 0 2 2 8 1 2 5 8 1 2 3 6 2 2 6 7 2 2 1 7 3 2 7 8 3 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 2 3 6 8 22 1 4 21 0 6 7 8 3 3 23 0 22 268435457 0 1 6 7 20 3 22 23 805306369 1 6 7 8 2 1 23 5 536870913 5 6 8 2 5 0 21 20 268435458 1 5 6 8 20 4 3 21 805306417 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 -1 0 4 0 0 2 1 1 0 3 -1 0 -1 0 6 0 1 1 1 1 0 30 1 6 8 0 2 1 6 0 2 5 6 0 2 2 8 1 2 5 8 1 2 3 6 2 2 6 7 2 2 0 8 3 2 7 8 3 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 2 3 6 8 22 1 3 21 0 6 7 8 3 5 23 0 22 268435457 0 1 6 8 20 4 5 23 805306402 5 6 8 2 4 0 21 20 268435458 1 5 6 8 20 3 2 21 536870914 0 6 7 8 22 1 23 2 536870913 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 -1 0 3 0 0 2 1 1 0 3 -1 0 -1 0 6 0 1 1 1 1 0 30 2 1 6 0 1 5 7 0 2 5 6 0 2 3 5 1 2 5 8 1 2 2 7 2 2 6 7 2 2 1 7 3 2 7 8 3 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 3 5 7 2 4 1 22 21 0 5 6 7 2 3 22 0 20 268435457 0 1 6 7 20 3 22 23 805306401 1 5 6 7 20 1 2 5 536870913 5 7 8 3 5 23 21 0 268435456 1 5 7 8 3 4 23 21 805306417 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 -1 0 0 1 1 1 0 2 4 2 -1 0 -1 0 6 0 1 1 1 1 0 30 2 1 6 0 1 5 7 0 2 5 6 0 2 2 8 1 2 5 8 1 2 2 7 2 2 6 7 2 2 1 7 3 2 7 8 3 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 2 3 7 8 22 23 3 21 0 5 6 7 2 5 22 3 20 536870926 0 1 6 7 20 5 22 23 1073741966 5 7 8 2 4 0 21 1 268435458 1 5 7 8 5 3 23 21 536870914 1 5 6 7 20 1 2 4 805306382 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 -1 0 1 0 1 1 0 2 0 3 -1 0 -1 0 6 0 1 1 1 1 0 30 2 0 5 0 1 5 7 0 2 5 6 0 2 2 8 1 2 5 8 1 2 2 7 2 2 6 7 2 2 1 7 3 2 7 8 3 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 2 3 7 8 22 23 2 21 0 5 6 7 2 5 22 2 20 536870926 5 7 8 2 3 0 21 1 268435458 1 5 7 8 4 2 23 21 536870914 0 1 5 7 20 3 5 23 805306370 0 5 6 7 20 1 22 4 805306382 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 -1 0 1 0 1 1 0 2 0 3 -1 0 -1 0 6 0 1 1 1 1 0 30 2 0 5 0 1 6 8 0 2 5 6 0 2 2 8 1 2 5 8 1 2 3 6 2 2 6 7 2 2 0 8 3 2 7 8 3 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 2 3 6 8 22 4 1 21 0 5 6 8 2 3 0 21 20 268435458 0 1 5 8 20 21 3 23 805306418 0 5 6 8 20 1 5 2 536870914 6 7 8 3 5 23 0 22 268435457 0 6 7 8 22 4 23 3 805306402 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 -1 0 1 0 0 2 4 1 0 3 -1 0 -1 0 6 0 1 1 1 1 0 30 2 0 5 0 1 6 8 0 2 5 6 0 2 2 8 1 2 5 8 1 2 2 7 2 2 6 7 2 2 0 8 3 2 7 8 3 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 2 3 7 8 22 23 3 21 0 5 6 8 2 5 3 21 20 536870922 0 1 5 8 20 21 5 23 1073742026 6 7 8 2 4 0 1 22 268435458 0 6 7 8 22 3 23 5 536870914 0 5 6 8 20 1 4 2 805306378 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 -1 0 1 0 1 1 0 2 0 3 -1 0 -1 0 6 0 1 1 1 1 0 30 1 6 8 0 2 1 6 0 2 5 6 0 2 2 8 1 2 5 8 1 2 2 7 2 2 6 7 2 2 0 8 3 2 7 8 3 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 2 3 7 8 22 23 2 21 0 5 6 8 2 5 2 21 20 536870922 6 7 8 2 3 0 1 22 268435458 0 6 7 8 22 2 23 4 536870914 0 1 6 8 20 5 3 23 805306418 1 5 6 8 20 1 4 21 805306378 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 -1 0 1 0 1 1 0 2 0 3 -1 0 -1 0 6 1 1 1 0 0 1 39 2 5 6 0 2 4 6 0 1 4 9 0 2 4 5 0 2 3 5 1 2 5 9 1 2 3 6 2 2 6 9 2 2 3 4 3 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 5 6 9 2 1 22 21 20 0 4 5 6 9 20 0 2 4 268435456 3 4 6 9 3 1 22 4 536870920 0 3 4 6 23 2 20 22 805306376 4 5 9 3 1 21 2 5 536870924 3 4 5 1 4 20 21 23 805306428 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 1 -1 0 -1 0 0 2 -1 0 6 1 1 1 0 0 1 39 2 5 6 0 2 4 6 0 1 4 9 0 2 4 5 0 2 5 9 1 2 1 9 1 2 3 6 2 2 6 9 2 2 3 4 3 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 5 6 9 2 1 22 21 20 0 4 5 6 9 20 0 2 5 268435456 3 4 6 9 3 1 22 4 536870920 0 3 4 6 23 2 20 22 805306376 3 4 9 1 2 5 21 23 805306424 4 5 9 1 1 21 4 20 536870924 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 1 -1 0 -1 0 0 2 -1 0 6 1 1 1 0 0 1 39 2 5 6 0 1 4 9 0 2 4 6 0 2 4 5 0 2 5 9 1 2 1 9 1 2 0 9 2 2 6 9 2 2 3 4 3 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 5 6 9 2 1 22 21 20 0 4 5 6 9 20 0 2 5 268435456 0 4 6 9 20 1 22 3 536870920 0 3 4 9 23 4 2 22 805306424 3 4 9 1 3 5 21 23 1073741944 4 5 9 1 1 21 4 20 536870924 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 1 -1 0 -1 0 0 2 -1 0 6 1 1 1 0 0 1 39 2 5 6 0 1 4 9 0 2 4 6 0 2 4 5 0 2 3 5 1 2 5 9 1 2 0 9 2 2 6 9 2 2 3 4 3 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 5 6 9 2 1 22 21 20 0 4 5 6 9 20 0 2 4 268435456 0 4 6 9 20 1 22 3 536870920 0 3 4 9 23 4 2 22 805306424 4 5 9 3 1 21 3 5 536870924 3 4 5 1 4 20 21 23 805306428 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 1 -1 0 -1 0 0 2 -1 0 12 1 1 0 1 0 1 43 1 9 10 0 1 0 10 0 1 7 10 0 1 1 10 0 2 2 4 0 1 2 10 0 1 4 10 0 1 3 10 0 2 4 5 0 1 5 10 0 2 3 5 1 2 5 9 1 2 0 9 2 2 7 9 2 2 1 7 3 2 4 7 3 4 7 10 0 7 1 4 23 0 7 9 10 0 9 5 0 22 268435457 2 4 5 10 20 6 3 4 536870914 2 5 9 10 21 8 5 2 805306402 2 4 10 0 2 0 5 20 268435458 2 9 10 0 3 1 4 22 536870917 4 5 10 1 2 11 7 20 805306386 4 7 10 1 0 10 6 23 268435456 5 9 10 3 3 9 11 21 1073741922 7 9 10 3 1 8 10 22 536870913 3 7 10 1 9 7 11 23 536870916 1 3 5 10 21 8 6 10 1073741906 0 0 2 2 -1 0 0 1 -1 0 1 1 0 2 12 1 1 0 1 0 1 43 2 0 5 0 1 0 10 0 1 9 10 0 1 1 10 0 1 7 10 0 1 2 10 0 1 5 10 0 1 3 10 0 2 4 5 0 1 4 10 0 2 1 9 1 2 5 9 1 2 2 7 2 2 7 9 2 2 3 4 3 2 4 7 3 0 4 5 10 20 6 4 1 0 4 7 10 0 8 5 0 23 268435459 2 5 9 10 21 7 3 4 536870914 7 9 10 2 9 2 5 22 805306402 2 5 10 0 2 0 5 20 268435458 2 7 10 0 3 1 4 22 536870919 4 5 10 1 0 7 10 20 268435457 5 9 10 1 2 11 6 21 805306386 4 7 10 3 1 9 10 23 536870915 7 9 10 3 3 11 8 22 1073741858 3 4 10 1 8 6 11 23 536870921 1 3 9 10 21 9 7 10 1073741906 0 1 0 2 -1 0 1 1 -1 0 2 2 0 3 6 1 1 0 1 0 1 43 2 2 4 0 1 4 9 0 2 4 5 0 2 3 5 1 2 5 9 1 2 2 7 2 2 7 9 2 2 3 4 3 2 4 7 3 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 4 5 9 3 5 21 1 2 0 3 4 7 9 23 4 22 0 268435458 3 4 5 1 0 20 21 23 268435459 2 4 7 0 4 23 22 20 805306422 4 7 9 2 1 22 5 3 536870918 2 4 5 9 20 0 21 4 268435456 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 -1 0 1 2 -1 0 0 2 -1 0 6 1 1 0 1 0 1 43 1 4 9 0 2 2 4 0 2 4 5 0 2 3 5 1 2 5 9 1 2 0 9 2 2 7 9 2 2 3 4 3 2 4 7 3 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 4 5 9 3 4 21 1 2 0 3 4 7 9 23 5 22 0 268435458 3 4 5 1 0 20 21 23 268435459 2 4 9 0 4 5 22 20 536870924 2 4 5 9 20 0 21 3 268435456 4 7 9 0 1 22 3 23 536870918 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 -1 0 1 2 -1 0 0 2 -1 0 6 1 1 0 1 0 1 43 1 4 9 0 2 2 4 0 2 4 5 0 2 5 9 1 2 1 9 1 2 2 7 2 2 7 9 2 2 3 4 3 2 4 7 3 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 3 4 9 1 1 5 21 23 0 3 4 7 9 23 3 22 0 268435456 2 4 7 0 3 23 22 20 805306420 4 7 9 2 1 22 4 2 536870916 2 4 5 9 20 5 21 3 805306404 4 5 9 1 4 21 0 20 268435457 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 4 2 -1 0 1 2 -1 0 0 2 -1 0 6 1 1 0 1 0 1 43 1 4 9 0 2 4 5 0 2 2 4 0 2 5 9 1 2 1 9 1 2 0 9 2 2 7 9 2 2 3 4 3 2 4 7 3 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 3 4 9 1 1 4 21 23 0 3 4 7 9 23 5 22 0 268435456 2 4 9 0 3 5 22 20 805306417 2 4 5 9 20 4 21 2 536870913 4 5 9 1 3 21 0 20 268435457 4 7 9 0 1 22 2 23 536870916 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 3 2 -1 0 1 2 -1 0 0 2 -1 0 6 1 1 0 1 0 1 43 2 0 5 0 1 5 7 0 2 4 5 0 2 3 5 1 2 5 9 1 2 2 7 2 2 7 9 2 2 3 4 3 2 4 7 3 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 3 5 7 9 2 5 22 21 0 3 4 5 1 2 20 21 23 536870924 4 5 7 3 3 0 23 1 268435456 0 4 5 7 20 2 4 23 536870912 2 5 7 0 5 3 22 20 805306400 5 7 9 2 0 22 21 4 268435457 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 1 0 1 -1 0 0 2 -1 0 0 3 -1 0 6 1 1 0 1 0 1 43 2 0 5 0 1 5 7 0 2 4 5 0 2 3 5 1 2 5 9 1 2 0 9 2 2 7 9 2 2 3 4 3 2 4 7 3 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 3 5 7 9 2 5 22 21 0 3 4 5 1 2 20 21 23 536870924 4 5 7 3 4 0 23 1 268435456 2 5 9 0 21 5 22 20 536870921 0 4 5 7 20 2 5 23 536870912 5 7 9 0 0 22 3 4 268435457 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 1 0 1 -1 0 0 2 -1 0 0 3 -1 0 6 1 1 0 1 0 1 43 2 0 5 0 1 5 7 0 2 4 5 0 2 3 5 1 2 5 9 1 2 2 7 2 2 7 9 2 2 1 7 3 2 4 7 3 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 3 5 7 9 1 5 22 21 0 1 3 5 7 21 0 2 23 268435456 4 5 7 1 4 1 23 20 536870920 2 5 7 0 5 4 22 20 1073741960 0 4 5 7 20 2 3 23 805306376 5 7 9 2 0 22 21 3 268435457 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 2 0 0 1 -1 0 0 2 -1 0 0 3 -1 0 6 1 1 0 1 0 1 43 2 0 5 0 1 5 7 0 2 4 5 0 2 3 5 1 2 5 9 1 2 0 9 2 2 7 9 2 2 1 7 3 2 4 7 3 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 3 5 7 9 1 4 22 21 0 1 3 5 7 21 0 3 23 268435456 2 5 9 0 21 4 22 20 536870921 4 5 7 1 5 1 23 20 536870920 5 7 9 0 0 22 2 5 268435457 0 4 5 7 20 3 4 23 805306376 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 3 0 0 1 -1 0 0 2 -1 0 0 3 -1 0 6 1 1 0 1 0 1 43 1 5 7 0 2 2 4 0 2 4 5 0 2 3 5 1 2 5 9 1 2 2 7 2 2 7 9 2 2 1 7 3 2 4 7 3 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 3 5 7 9 4 5 22 21 0 2 4 5 7 20 3 5 2 805306376 2 4 7 0 1 23 22 20 1073742024 4 5 7 1 1 4 23 20 536870920 1 3 5 7 21 0 3 23 268435456 5 7 9 2 0 22 21 1 268435457 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 1 0 1 -1 0 0 2 -1 0 0 3 -1 0 6 1 1 0 1 0 1 43 1 5 7 0 2 4 5 0 2 2 4 0 2 1 9 1 2 5 9 1 2 2 7 2 2 7 9 2 2 1 7 3 2 4 7 3 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 3 7 9 1 22 4 21 23 0 2 4 5 7 20 5 3 2 805306421 2 4 7 0 1 23 22 20 1073742069 5 7 9 2 4 22 21 1 536870917 1 5 7 9 5 3 0 21 268435457 4 5 7 1 1 4 23 20 536870913 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 1 1 2 -1 0 0 1 -1 0 0 2 -1 0 6 1 1 0 1 0 1 43 2 0 5 0 1 5 7 0 2 4 5 0 2 1 9 1 2 5 9 1 2 2 7 2 2 7 9 2 2 1 7 3 2 4 7 3 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 3 7 9 1 22 3 21 23 0 2 5 7 0 2 5 22 20 805306421 5 7 9 2 3 22 21 1 536870917 1 5 7 9 4 2 0 21 268435457 4 5 7 1 5 3 23 20 536870913 0 4 5 7 20 4 1 23 1073741941 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 4 0 1 1 -1 0 0 1 -1 0 0 2 -1 0 6 1 1 0 1 0 1 43 2 0 5 0 1 4 9 0 2 4 5 0 2 5 9 1 2 1 9 1 2 0 9 2 2 7 9 2 2 3 4 3 2 4 7 3 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 3 4 9 1 4 2 21 23 0 2 5 9 0 21 3 22 20 805306401 4 5 9 1 3 21 0 20 268435457 0 4 5 9 20 2 1 5 536870913 3 4 7 9 23 5 22 0 268435456 4 7 9 0 4 22 3 23 805306417 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 1 1 -1 0 4 2 -1 0 0 2 -1 0 6 1 1 0 1 0 1 43 2 0 5 0 1 4 9 0 2 4 5 0 2 1 9 1 2 5 9 1 2 0 9 2 2 7 9 2 2 1 7 3 2 4 7 3 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 3 7 9 1 22 3 21 23 0 2 5 9 0 21 5 22 20 1073741965 4 5 9 1 5 21 3 20 536870925 1 4 7 9 23 4 0 2 268435457 4 7 9 0 3 22 5 23 536870917 0 4 5 9 20 2 1 4 805306381 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 2 0 1 1 -1 0 0 1 -1 0 0 2 -1 0 6 1 1 0 1 0 1 43 1 4 9 0 2 4 5 0 2 2 4 0 2 1 9 1 2 5 9 1 2 0 9 2 2 7 9 2 2 1 7 3 2 4 7 3 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 3 7 9 1 22 2 21 23 0 2 4 5 9 20 5 21 4 1073741861 1 4 7 9 23 3 0 5 268435457 4 7 9 0 2 22 4 23 536870917 2 4 9 0 1 3 22 20 805306405 4 5 9 1 1 21 2 20 536870925 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 1 1 2 -1 0 0 1 -1 0 0 2 -1 0 6 1 0 1 1 0 1 45 2 1 6 0 1 4 9 0 2 4 6 0 2 1 9 1 2 7 9 2 2 6 9 2 2 6 7 2 2 1 7 3 2 4 7 3 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 4 6 7 20 1 22 23 0 4 6 7 9 0 22 4 2 268435457 4 6 9 1 1 3 4 20 536870925 1 2 6 9 20 22 2 21 805306397 1 4 7 9 23 1 5 2 536870921 3 7 9 1 22 4 21 23 805306409 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 -1 0 0 2 0 3 -1 0 1 3 -1 0 6 1 0 1 1 0 1 45 2 1 6 0 2 4 6 0 1 4 9 0 2 1 9 1 2 7 9 2 2 6 9 2 2 6 7 2 2 3 4 3 2 4 7 3 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 4 6 7 20 1 22 23 0 4 6 7 9 0 22 5 2 268435457 4 6 9 1 1 3 4 20 536870925 1 2 6 9 20 22 2 21 805306397 3 4 9 1 5 2 21 23 805306413 3 4 7 9 23 1 22 4 536870921 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 -1 0 0 2 0 3 -1 0 1 3 -1 0 6 1 0 1 1 0 1 45 2 4 6 0 2 2 4 0 1 4 9 0 2 1 9 1 2 7 9 2 2 6 9 2 2 6 7 2 2 3 4 3 2 4 7 3 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 4 6 7 20 1 22 23 0 4 6 7 9 0 22 5 2 268435457 4 6 9 2 1 22 3 20 536870925 1 2 4 9 20 2 4 21 805306413 3 4 9 1 5 3 21 23 1073741997 3 4 7 9 23 1 22 4 536870921 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 -1 0 0 2 0 3 -1 0 1 3 -1 0 6 1 0 1 1 0 1 45 1 4 9 0 2 4 6 0 2 2 4 0 2 1 9 1 2 7 9 2 2 6 9 2 2 6 7 2 2 1 7 3 2 4 7 3 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 4 6 7 20 1 22 23 0 4 6 7 9 0 22 4 2 268435457 4 6 9 2 1 22 3 20 536870925 1 2 4 9 20 2 4 21 805306413 1 4 7 9 23 1 5 3 536870921 3 7 9 1 22 4 21 23 805306409 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 -1 0 0 2 0 3 -1 0 1 3 -1 0 6 0 1 1 1 0 1 46 2 1 6 0 1 5 7 0 2 5 6 0 2 1 9 1 2 5 9 1 2 7 9 2 2 6 7 2 2 6 9 2 2 1 7 3 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 5 6 9 2 1 22 21 20 0 5 6 7 9 4 22 2 0 268435456 1 5 7 9 4 1 3 21 536870920 3 7 9 1 22 2 21 23 805306408 1 5 6 7 20 1 5 2 536870912 0 1 6 7 20 4 22 23 805306400 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 -1 0 0 0 0 1 1 2 -1 0 0 2 -1 0 6 0 1 1 1 0 1 46 2 0 5 0 1 5 7 0 2 5 6 0 2 1 9 1 2 5 9 1 2 7 9 2 2 6 7 2 2 6 9 2 2 1 7 3 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 5 6 9 2 1 22 21 20 0 5 6 7 9 5 22 2 0 268435456 1 5 7 9 4 1 3 21 536870920 3 7 9 1 22 2 21 23 805306408 0 1 5 7 20 2 5 23 805306376 0 5 6 7 20 1 22 4 536870912 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 -1 0 0 0 0 1 1 2 -1 0 0 2 -1 0 6 0 1 1 1 0 1 46 2 0 5 0 1 5 7 0 2 5 6 0 2 3 5 1 2 5 9 1 2 7 9 2 2 6 7 2 2 6 9 2 2 1 7 3 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 5 6 9 2 1 22 21 20 0 5 6 7 9 5 22 2 0 268435456 3 5 7 9 3 1 22 21 536870920 1 3 5 7 21 2 4 23 805306376 0 1 5 7 20 3 5 23 1073741960 0 5 6 7 20 1 22 4 536870912 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 -1 0 0 0 0 1 1 2 -1 0 0 2 -1 0 6 0 1 1 1 0 1 46 2 1 6 0 1 5 7 0 2 5 6 0 2 3 5 1 2 5 9 1 2 7 9 2 2 6 7 2 2 6 9 2 2 1 7 3 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 5 6 9 2 1 22 21 20 0 5 6 7 9 4 22 2 0 268435456 3 5 7 9 3 1 22 21 536870920 1 3 5 7 21 2 4 23 805306376 1 5 6 7 20 1 5 3 536870912 0 1 6 7 20 4 22 23 805306400 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 -1 0 0 0 0 1 1 2 -1 0 0 2 -1 0 6 1 1 0 0 1 1 51 2 0 5 0 1 4 9 0 2 4 5 0 2 8 9 1 2 5 9 1 2 5 8 1 2 0 9 2 2 4 8 3 2 0 8 3 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 4 5 8 1 1 21 23 20 0 5 8 9 4 21 2 4 0 268435456 4 8 9 0 1 3 4 23 536870916 0 3 8 9 23 21 2 22 805306388 0 4 5 9 20 1 5 2 536870920 2 5 9 0 21 4 22 20 805306408 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 -1 0 -1 0 0 2 1 2 -1 0 6 1 1 0 0 1 1 51 1 4 9 0 2 4 5 0 2 2 4 0 2 8 9 1 2 5 9 1 2 5 8 1 2 0 9 2 2 4 8 3 2 0 8 3 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 4 5 8 1 1 21 23 20 0 5 8 9 4 21 2 5 0 268435456 4 8 9 0 1 3 4 23 536870916 0 3 8 9 23 21 2 22 805306388 2 4 9 0 5 2 22 20 805306404 2 4 5 9 20 1 21 4 536870920 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 -1 0 -1 0 0 2 1 2 -1 0 6 1 1 0 0 1 1 51 1 4 9 0 2 2 4 0 2 4 5 0 2 8 9 1 2 5 9 1 2 5 8 1 2 0 9 2 2 4 8 3 2 3 4 3 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 4 5 8 1 1 21 23 20 0 5 8 9 4 21 2 5 0 268435456 4 8 9 3 1 21 3 23 536870916 0 3 4 9 23 2 4 22 805306404 2 4 9 0 5 3 22 20 1073741988 2 4 5 9 20 1 21 4 536870920 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 -1 0 -1 0 0 2 1 2 -1 0 6 1 1 0 0 1 1 51 2 0 5 0 1 4 9 0 2 4 5 0 2 8 9 1 2 5 9 1 2 5 8 1 2 0 9 2 2 4 8 3 2 3 4 3 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 4 5 8 1 1 21 23 20 0 5 8 9 4 21 2 4 0 268435456 4 8 9 3 1 21 3 23 536870916 0 3 4 9 23 2 4 22 805306404 0 4 5 9 20 1 5 3 536870920 2 5 9 0 21 4 22 20 805306408 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 -1 0 -1 0 0 2 1 2 -1 0 12 1 0 1 0 1 1 53 1 9 10 0 1 0 10 0 2 1 6 0 1 1 10 0 1 6 10 0 1 2 10 0 1 8 10 0 1 3 10 0 2 4 6 0 1 4 10 0 2 8 9 1 2 2 8 1 2 6 9 2 2 0 9 2 2 3 4 3 2 4 8 3 6 9 10 2 7 1 4 22 0 2 8 9 10 21 9 0 5 268435457 4 6 10 1 6 4 3 20 536870922 4 8 10 1 8 5 2 23 805306410 1 2 6 10 20 0 2 5 268435458 2 8 10 1 1 3 4 21 536870925 0 4 6 10 20 2 7 11 805306378 6 9 10 0 0 10 6 22 268435456 4 8 10 3 3 9 11 23 1073741866 8 9 10 3 1 10 8 21 536870917 3 9 10 0 9 7 11 22 536870916 3 4 10 0 8 6 10 23 1073742026 2 0 -1 0 0 0 -1 0 1 1 0 1 0 2 12 1 0 1 0 1 1 53 1 9 10 0 1 0 10 0 1 8 10 0 1 1 10 0 2 2 4 0 1 2 10 0 1 6 10 0 1 3 10 0 2 4 6 0 1 4 10 0 2 1 9 1 2 8 9 1 2 3 6 2 2 6 9 2 2 4 8 3 2 0 8 3 4 6 10 2 6 1 4 20 0 6 9 10 2 8 5 0 22 268435457 4 8 10 1 7 3 4 23 536870922 1 8 9 10 21 9 5 2 805306394 1 2 4 10 20 0 2 5 268435458 2 9 10 1 1 3 4 21 536870917 0 4 6 10 20 0 10 7 268435456 4 8 10 0 2 11 6 23 805306378 6 9 10 3 1 9 10 22 536870913 8 9 10 3 3 8 11 21 1073741914 3 6 10 0 8 6 11 22 536870920 3 8 10 0 9 7 10 23 1073741898 0 0 -1 0 0 1 -1 0 2 1 1 1 0 2 6 1 0 1 0 1 1 53 2 2 4 0 2 4 6 0 1 4 9 0 2 2 8 1 2 8 9 1 2 3 6 2 2 6 9 2 2 3 4 3 2 4 8 3 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 4 8 9 3 5 21 1 23 0 3 4 6 9 2 4 22 0 268435458 0 3 4 6 23 1 20 22 536870914 1 2 4 8 20 5 23 21 536870912 4 6 9 2 1 22 5 20 536870918 2 4 8 9 3 0 21 4 268435456 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 -1 0 1 2 -1 0 0 1 0 2 -1 0 6 1 0 1 0 1 1 53 2 4 6 0 2 2 4 0 1 4 9 0 2 1 9 1 2 8 9 1 2 3 6 2 2 6 9 2 2 3 4 3 2 4 8 3 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 4 8 9 3 5 21 1 23 0 3 4 6 9 2 3 22 0 268435458 0 3 4 6 23 1 20 22 536870914 4 6 9 2 1 22 4 20 536870918 1 2 4 9 20 3 5 21 805306406 1 4 8 9 23 0 21 4 268435456 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 -1 0 1 2 -1 0 0 1 0 2 -1 0 6 1 0 1 0 1 1 53 1 4 9 0 2 2 4 0 2 4 6 0 2 2 8 1 2 8 9 1 2 6 9 2 2 0 9 2 2 4 8 3 2 3 4 3 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 4 8 9 3 4 21 1 23 0 0 3 4 9 23 0 5 22 268435458 1 2 4 8 20 4 23 21 536870912 4 6 9 2 5 22 4 20 536870924 2 4 8 9 2 0 21 3 268435456 0 4 6 9 20 3 22 1 536870922 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 -1 0 3 1 -1 0 0 1 0 2 -1 0 6 1 0 1 0 1 1 53 1 4 9 0 2 4 6 0 2 2 4 0 2 1 9 1 2 8 9 1 2 6 9 2 2 0 9 2 2 4 8 3 2 3 4 3 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 4 8 9 3 5 21 1 23 0 0 3 4 9 23 0 4 22 268435458 4 6 9 2 4 22 3 20 805306394 1 2 4 9 20 2 5 21 1073741978 0 4 6 9 20 2 22 1 536870922 1 4 8 9 23 0 21 3 268435456 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 -1 0 2 1 -1 0 0 1 0 2 -1 0 6 1 0 1 0 1 1 53 2 1 6 0 2 4 6 0 1 6 8 0 2 2 8 1 2 8 9 1 2 3 6 2 2 6 9 2 2 3 4 3 2 4 8 3 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 6 8 9 3 5 21 22 1 0 3 4 6 8 2 3 0 23 268435459 0 3 4 6 23 1 20 22 536870915 4 6 8 1 1 4 23 20 536870919 1 2 6 8 20 5 3 21 805306391 2 6 8 9 4 0 21 22 268435456 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 1 -1 0 0 0 -1 0 0 1 0 2 -1 0 6 1 0 1 0 1 1 53 2 1 6 0 2 4 6 0 1 6 8 0 2 1 9 1 2 8 9 1 2 3 6 2 2 6 9 2 2 3 4 3 2 4 8 3 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 6 8 9 3 5 21 22 1 0 3 4 6 8 2 4 0 23 268435459 0 3 4 6 23 1 20 22 536870915 1 2 6 9 20 22 5 21 536870924 4 6 8 1 1 5 23 20 536870919 1 6 8 9 4 0 21 3 268435456 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 1 -1 0 0 0 -1 0 0 1 0 2 -1 0 6 1 0 1 0 1 1 53 1 6 8 0 2 1 6 0 2 4 6 0 2 2 8 1 2 8 9 1 2 3 6 2 2 6 9 2 2 0 8 3 2 4 8 3 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 6 8 9 3 5 21 22 1 0 3 6 8 0 0 4 23 22 268435459 4 6 8 1 4 3 23 20 805306391 1 2 6 8 20 5 2 21 1073741911 0 4 6 8 20 2 1 23 536870919 2 6 8 9 3 0 21 22 268435456 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 2 0 -1 0 0 0 -1 0 0 1 0 2 -1 0 6 1 0 1 0 1 1 53 1 6 8 0 2 1 6 0 2 4 6 0 2 1 9 1 2 8 9 1 2 3 6 2 2 6 9 2 2 0 8 3 2 4 8 3 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 6 8 9 3 4 21 22 1 0 3 6 8 0 0 5 23 22 268435459 1 2 6 9 20 22 4 21 536870924 4 6 8 1 5 4 23 20 536870912 1 6 8 9 3 0 21 2 268435456 0 4 6 8 20 3 1 23 536870919 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 3 0 -1 0 0 0 -1 0 0 1 0 2 -1 0 6 1 0 1 0 1 1 53 1 6 8 0 2 2 4 0 2 4 6 0 2 2 8 1 2 8 9 1 2 3 6 2 2 6 9 2 2 0 8 3 2 4 8 3 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 6 8 9 3 5 21 22 4 0 1 2 4 8 20 2 23 21 1073741975 4 6 8 2 3 5 1 20 805306391 0 4 6 8 20 2 4 23 536870919 3 6 8 0 0 3 23 22 268435459 2 6 8 9 2 0 21 22 268435456 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 2 -1 0 0 0 -1 0 0 1 0 2 -1 0 6 1 0 1 0 1 1 53 1 6 8 0 2 4 6 0 2 2 4 0 2 2 8 1 2 8 9 1 2 0 9 2 2 6 9 2 2 0 8 3 2 4 8 3 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 3 8 9 23 21 4 22 0 1 2 4 8 20 2 23 21 1073741954 4 6 8 2 5 3 1 20 805306370 2 6 8 9 2 4 21 22 536870914 6 8 9 0 3 0 22 5 268435458 0 4 6 8 20 2 4 23 536870926 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 2 -1 0 2 1 -1 0 0 2 0 3 -1 0 6 1 0 1 0 1 1 53 1 6 8 0 2 4 6 0 2 1 6 0 2 2 8 1 2 8 9 1 2 0 9 2 2 6 9 2 2 0 8 3 2 4 8 3 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 3 8 9 23 21 3 22 0 1 2 6 8 20 2 4 21 805306370 2 6 8 9 1 3 21 22 536870914 6 8 9 0 2 0 22 5 268435458 4 6 8 1 5 1 23 20 1073741954 0 4 6 8 20 4 3 23 536870926 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 4 0 -1 0 1 2 -1 0 0 2 0 3 -1 0 6 1 0 1 0 1 1 53 1 4 9 0 2 1 6 0 2 4 6 0 2 1 9 1 2 8 9 1 2 6 9 2 2 0 9 2 2 4 8 3 2 3 4 3 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 4 8 9 3 5 21 4 23 0 1 2 6 9 20 22 2 21 1073741914 4 6 9 1 3 1 5 20 805306394 0 4 6 9 20 2 22 4 536870922 0 3 4 9 23 0 3 22 268435458 1 4 8 9 23 0 21 2 268435456 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 -1 0 1 2 -1 0 0 1 0 2 -1 0 6 1 0 1 0 1 1 53 1 4 9 0 2 4 6 0 2 1 6 0 2 1 9 1 2 8 9 1 2 0 9 2 2 6 9 2 2 0 8 3 2 4 8 3 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 3 8 9 23 21 4 22 0 1 2 6 9 20 22 2 21 1073741938 4 6 9 1 5 1 3 20 805306418 1 4 8 9 23 4 21 2 536870914 4 8 9 0 3 0 5 23 268435458 0 4 6 9 20 2 22 4 536870922 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 2 0 -1 0 1 2 -1 0 0 2 0 3 -1 0 6 1 0 1 0 1 1 53 1 4 9 0 2 4 6 0 2 2 4 0 2 1 9 1 2 8 9 1 2 0 9 2 2 6 9 2 2 0 8 3 2 4 8 3 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 3 8 9 23 21 3 22 0 1 2 4 9 20 4 2 21 805306418 1 4 8 9 23 3 21 1 536870914 4 8 9 0 2 0 5 23 268435458 4 6 9 2 5 22 1 20 1073741938 0 4 6 9 20 4 22 3 536870922 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 2 -1 0 4 1 -1 0 0 2 0 3 -1 0 6 0 1 1 0 1 1 54 2 0 5 0 1 6 8 0 2 5 6 0 2 8 9 1 2 5 8 1 2 5 9 1 2 0 9 2 2 6 9 2 2 0 8 3 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 5 6 9 2 1 22 21 20 0 5 6 8 9 2 4 21 0 268435456 0 5 6 8 20 1 4 3 536870912 0 1 5 8 20 21 2 23 805306416 6 8 9 0 1 5 22 2 536870916 0 3 8 9 23 21 4 22 805306388 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 -1 0 0 0 0 1 -1 0 1 2 0 2 -1 0 6 0 1 1 0 1 1 54 2 0 5 0 1 6 8 0 2 5 6 0 2 8 9 1 2 5 8 1 2 5 9 1 2 3 6 2 2 6 9 2 2 0 8 3 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 5 6 9 2 1 22 21 20 0 5 6 8 9 2 5 21 0 268435456 0 5 6 8 20 1 4 3 536870912 0 1 5 8 20 21 2 23 805306416 3 6 8 0 5 2 23 22 805306400 6 8 9 3 1 21 22 4 536870916 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 -1 0 0 0 0 1 -1 0 1 2 0 2 -1 0 6 0 1 1 0 1 1 54 1 6 8 0 2 1 6 0 2 5 6 0 2 8 9 1 2 5 8 1 2 5 9 1 2 3 6 2 2 6 9 2 2 0 8 3 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 5 6 9 2 1 22 21 20 0 5 6 8 9 2 5 21 0 268435456 1 5 6 8 20 1 3 21 536870912 0 1 6 8 20 2 4 23 805306400 3 6 8 0 5 3 23 22 1073741984 6 8 9 3 1 21 22 4 536870916 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 -1 0 0 0 0 1 -1 0 1 2 0 2 -1 0 6 0 1 1 0 1 1 54 1 6 8 0 2 5 6 0 2 1 6 0 2 8 9 1 2 5 8 1 2 5 9 1 2 0 9 2 2 6 9 2 2 0 8 3 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 5 6 9 2 1 22 21 20 0 5 6 8 9 2 4 21 0 268435456 1 5 6 8 20 1 3 21 536870912 0 1 6 8 20 2 4 23 805306400 6 8 9 0 1 5 22 3 536870916 0 3 8 9 23 21 4 22 805306388 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 -1 0 0 0 0 1 -1 0 1 2 0 2 -1 0 6 1 0 0 1 1 1 57 2 2 4 0 1 4 9 0 2 2 8 1 2 8 9 1 2 7 9 2 2 2 7 2 2 7 8 3 2 4 8 3 2 4 7 3 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 7 8 9 3 1 21 22 23 0 4 7 8 9 23 0 2 4 268435456 2 4 8 9 3 1 21 4 536870920 1 2 4 8 20 2 23 21 805306376 4 7 9 2 1 22 2 5 536870924 2 4 7 0 4 23 22 20 805306428 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 -1 0 -1 0 0 0 0 1 0 2 -1 0 6 1 0 0 1 1 1 57 1 4 9 0 2 2 4 0 2 2 8 1 2 8 9 1 2 7 9 2 2 0 9 2 2 7 8 3 2 4 8 3 2 4 7 3 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 7 8 9 3 1 21 22 23 0 4 7 8 9 23 0 2 5 268435456 2 4 8 9 3 1 21 4 536870920 1 2 4 8 20 2 23 21 805306376 2 4 9 0 2 5 22 20 805306424 4 7 9 0 1 22 4 23 536870924 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 -1 0 -1 0 0 0 0 1 0 2 -1 0 6 1 0 0 1 1 1 57 1 4 9 0 2 2 4 0 2 1 9 1 2 8 9 1 2 7 9 2 2 0 9 2 2 7 8 3 2 4 8 3 2 4 7 3 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 7 8 9 3 1 21 22 23 0 4 7 8 9 23 0 2 5 268435456 1 4 8 9 23 1 21 3 536870920 1 2 4 9 20 4 2 21 805306424 2 4 9 0 3 5 22 20 1073741944 4 7 9 0 1 22 4 23 536870924 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 -1 0 -1 0 0 0 0 1 0 2 -1 0 6 1 0 0 1 1 1 57 1 4 9 0 2 2 4 0 2 1 9 1 2 8 9 1 2 7 9 2 2 2 7 2 2 7 8 3 2 4 8 3 2 4 7 3 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 7 8 9 3 1 21 22 23 0 4 7 8 9 23 0 2 4 268435456 1 4 8 9 23 1 21 3 536870920 1 2 4 9 20 4 2 21 805306424 4 7 9 2 1 22 3 5 536870924 2 4 7 0 4 23 22 20 805306428 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 -1 0 -1 0 0 0 0 1 0 2 -1 0 6 0 1 0 1 1 1 58 2 0 5 0 1 5 7 0 2 8 9 1 2 5 9 1 2 5 8 1 2 0 9 2 2 7 9 2 2 7 8 3 2 0 8 3 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 7 8 9 3 1 21 22 23 0 5 7 8 9 4 0 21 2 268435456 5 7 9 0 1 22 3 4 536870924 2 5 9 0 21 2 22 20 805306412 0 5 7 8 2 1 23 5 536870912 0 1 5 8 20 21 4 23 805306416 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 -1 0 1 0 -1 0 0 0 0 1 0 2 -1 0 6 0 1 0 1 1 1 58 2 0 5 0 1 5 7 0 2 8 9 1 2 5 9 1 2 5 8 1 2 0 9 2 2 7 9 2 2 7 8 3 2 1 7 3 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 7 8 9 3 1 21 22 23 0 5 7 8 9 5 0 21 2 268435456 5 7 9 0 1 22 3 4 536870924 2 5 9 0 21 2 22 20 805306412 0 1 5 7 20 5 2 23 805306428 1 5 7 8 4 1 23 21 536870912 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 -1 0 1 0 -1 0 0 0 0 1 0 2 -1 0 6 0 1 0 1 1 1 58 2 0 5 0 1 5 7 0 2 8 9 1 2 5 9 1 2 5 8 1 2 2 7 2 2 7 9 2 2 7 8 3 2 1 7 3 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 7 8 9 3 1 21 22 23 0 5 7 8 9 5 0 21 2 268435456 5 7 9 2 1 22 21 3 536870924 2 5 7 0 2 4 22 20 805306428 0 1 5 7 20 5 3 23 1073741948 1 5 7 8 4 1 23 21 536870912 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 -1 0 1 0 -1 0 0 0 0 1 0 2 -1 0 6 0 1 0 1 1 1 58 2 0 5 0 1 5 7 0 2 8 9 1 2 5 9 1 2 5 8 1 2 2 7 2 2 7 9 2 2 7 8 3 2 0 8 3 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 7 8 9 3 1 21 22 23 0 5 7 8 9 4 0 21 2 268435456 5 7 9 2 1 22 21 3 536870924 2 5 7 0 2 4 22 20 805306428 0 5 7 8 3 1 23 5 536870912 0 1 5 8 20 21 4 23 805306416 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 -1 0 1 0 -1 0 0 0 0 1 0 2 -1 0 6 0 0 1 1 1 1 60 2 1 6 0 1 6 8 0 2 1 9 1 2 8 9 1 2 6 7 2 2 6 9 2 2 7 9 2 2 7 8 3 2 1 7 3 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 7 8 9 3 1 21 22 23 0 6 7 8 9 2 0 4 22 268435456 1 6 7 8 3 1 23 4 536870912 0 1 6 7 20 2 22 23 805306368 1 6 8 9 2 1 21 5 536870920 1 2 6 9 20 22 4 21 805306424 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 -1 0 -1 0 1 0 0 0 0 1 0 2 -1 0 6 0 0 1 1 1 1 60 2 1 6 0 1 6 8 0 2 2 8 1 2 8 9 1 2 6 7 2 2 6 9 2 2 7 9 2 2 7 8 3 2 1 7 3 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 7 8 9 3 1 21 22 23 0 6 7 8 9 2 0 5 22 268435456 1 6 7 8 3 1 23 4 536870912 0 1 6 7 20 2 22 23 805306368 1 2 6 8 20 5 2 21 805306416 2 6 8 9 4 1 21 22 536870920 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 -1 0 -1 0 1 0 0 0 0 1 0 2 -1 0 6 0 0 1 1 1 1 60 1 6 8 0 2 1 6 0 2 2 8 1 2 8 9 1 2 6 7 2 2 6 9 2 2 7 9 2 2 7 8 3 2 0 8 3 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 7 8 9 3 1 21 22 23 0 6 7 8 9 2 0 5 22 268435456 0 6 7 8 22 1 23 3 536870912 0 1 6 8 20 4 2 23 805306416 1 2 6 8 20 5 3 21 1073741936 2 6 8 9 4 1 21 22 536870920 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 -1 0 -1 0 1 0 0 0 0 1 0 2 -1 0 6 0 0 1 1 1 1 60 1 6 8 0 2 1 6 0 2 1 9 1 2 8 9 1 2 6 7 2 2 6 9 2 2 7 9 2 2 7 8 3 2 0 8 3 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 7 8 9 3 1 21 22 23 0 6 7 8 9 2 0 4 22 268435456 0 6 7 8 22 1 23 3 536870912 0 1 6 8 20 4 2 23 805306416 1 6 8 9 3 1 21 5 536870920 1 2 6 9 20 22 4 21 805306424 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 -1 0 -1 0 1 0 0 0 0 1 0 2 -1 0 7 1 1 1 1 1 0 31 1 6 8 0 2 5 6 0 2 4 5 0 2 4 6 0 2 5 8 1 2 2 8 1 2 2 7 2 2 6 7 2 2 4 7 3 2 4 8 3 2 7 8 3 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 4 5 8 1 2 21 23 20 0 0 4 6 7 20 3 22 23 805306376 4 5 6 8 20 4 3 0 268435456 4 6 7 8 1 5 23 2 536870920 5 6 8 2 2 5 21 20 536870916 6 7 8 2 3 6 4 22 805306392 2 3 7 8 22 23 5 21 1073741912 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 1 2 1 3 0 2 -1 0 -1 0 7 1 1 1 1 1 0 31 1 6 8 0 2 5 6 0 2 4 5 0 2 4 6 0 2 3 5 1 2 5 8 1 2 3 6 2 2 6 7 2 2 4 8 3 2 4 7 3 2 7 8 3 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 4 5 8 1 2 21 23 20 0 0 4 6 7 20 3 22 23 805306376 4 5 6 8 20 5 3 0 268435456 4 6 7 8 1 4 23 2 536870920 6 7 8 3 3 23 5 22 805306392 5 6 8 3 2 4 21 6 536870916 3 5 6 2 5 20 22 21 805306420 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 1 2 1 3 0 2 -1 0 -1 0 7 1 1 1 1 1 0 31 1 6 8 0 2 5 6 0 2 4 5 0 2 4 6 0 2 2 8 1 2 5 8 1 2 3 6 2 2 6 7 2 2 4 8 3 2 4 7 3 2 7 8 3 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 4 5 8 1 2 21 23 20 0 0 4 6 7 20 3 22 23 805306376 4 5 6 8 20 6 3 0 268435456 4 6 7 8 1 4 23 2 536870920 6 7 8 3 3 23 5 22 805306392 2 3 6 8 22 4 6 21 1073741976 5 6 8 2 2 5 21 20 536870916 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 1 2 1 3 0 2 -1 0 -1 0 7 1 1 1 1 1 0 31 2 5 6 0 1 5 7 0 2 4 5 0 2 4 6 0 2 5 8 1 2 3 5 1 2 2 7 2 2 6 7 2 2 4 7 3 2 4 8 3 2 7 8 3 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 4 5 8 1 2 21 23 20 0 0 4 6 7 20 3 22 23 805306400 4 5 7 8 3 6 23 0 268435456 4 5 6 7 20 4 1 2 536870912 5 6 7 2 3 22 5 20 805306384 3 5 7 2 6 4 22 21 1073741968 5 7 8 3 2 23 21 5 536870916 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 1 2 1 3 0 2 -1 0 -1 0 7 1 1 1 1 0 1 47 2 5 6 0 1 5 7 0 2 4 5 0 2 4 6 0 2 1 9 1 2 5 9 1 2 7 9 2 2 6 9 2 2 6 7 2 2 1 7 3 2 4 7 3 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 4 6 7 20 2 22 23 0 5 6 9 2 3 22 21 20 805306421 4 5 6 7 20 3 0 4 268435457 5 6 7 9 2 22 5 1 536870917 4 5 7 1 2 5 23 20 536870925 1 5 7 9 4 3 6 21 805306405 3 7 9 1 22 5 21 23 1073741989 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 1 0 0 2 0 3 -1 0 1 2 -1 0 7 1 1 1 1 0 1 47 2 5 6 0 1 5 7 0 2 4 5 0 2 4 6 0 2 3 5 1 2 5 9 1 2 7 9 2 2 6 9 2 2 6 7 2 2 3 4 3 2 4 7 3 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 4 6 7 20 2 22 23 0 5 6 9 2 3 22 21 20 805306421 4 5 6 7 20 3 0 5 268435457 5 6 7 9 2 22 4 1 536870917 3 5 7 9 5 3 22 21 805306405 4 5 7 3 2 4 23 6 536870925 3 4 5 1 5 20 21 23 805306429 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 1 0 0 2 0 3 -1 0 1 2 -1 0 7 1 1 1 1 0 1 47 2 5 6 0 1 5 7 0 2 4 5 0 2 4 6 0 2 3 5 1 2 5 9 1 2 7 9 2 2 6 9 2 2 6 7 2 2 1 7 3 2 4 7 3 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 4 6 7 20 2 22 23 0 5 6 9 2 3 22 21 20 805306421 4 5 6 7 20 3 0 6 268435457 5 6 7 9 2 22 4 1 536870917 3 5 7 9 5 3 22 21 805306405 1 3 5 7 21 4 6 23 1073741861 4 5 7 1 2 5 23 20 536870925 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 1 0 0 2 0 3 -1 0 1 2 -1 0 7 1 1 1 1 0 1 47 1 4 9 0 2 5 6 0 2 4 5 0 2 4 6 0 2 5 9 1 2 1 9 1 2 7 9 2 2 6 9 2 2 6 7 2 2 3 4 3 2 4 7 3 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 4 6 7 20 2 22 23 0 5 6 9 2 3 22 21 20 805306397 4 6 7 9 0 22 6 3 268435457 4 5 6 9 20 1 2 4 536870925 4 5 9 1 3 21 5 20 805306429 3 4 9 1 6 4 21 23 1073742013 3 4 7 9 23 2 22 5 536870921 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 1 0 0 2 0 3 -1 0 1 2 -1 0 7 1 1 1 0 1 1 55 2 5 6 0 1 4 9 0 2 4 5 0 2 4 6 0 2 8 9 1 2 5 8 1 2 5 9 1 2 3 6 2 2 6 9 2 2 3 4 3 2 4 8 3 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 4 5 8 1 2 21 23 20 0 5 6 9 2 3 22 21 20 805306392 5 8 9 4 21 4 3 0 268435456 4 5 6 9 20 1 5 2 536870920 4 8 9 3 2 21 5 23 536870916 3 4 6 9 6 3 22 4 805306408 0 3 4 6 23 5 20 22 1073741864 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 1 1 -1 0 0 2 1 2 -1 0 7 1 1 1 0 1 1 55 2 5 6 0 1 4 9 0 2 4 5 0 2 4 6 0 2 8 9 1 2 5 8 1 2 5 9 1 2 0 9 2 2 6 9 2 2 0 8 3 2 4 8 3 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 4 5 8 1 2 21 23 20 0 5 6 9 2 3 22 21 20 805306392 5 8 9 4 21 5 3 0 268435456 4 5 6 9 20 1 4 2 536870920 0 4 6 9 20 3 22 5 805306408 4 8 9 0 2 6 4 23 536870916 0 3 8 9 23 21 5 22 805306388 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 1 1 -1 0 0 2 1 2 -1 0 7 1 1 1 0 1 1 55 2 5 6 0 1 4 9 0 2 4 5 0 2 4 6 0 2 8 9 1 2 5 9 1 2 5 8 1 2 0 9 2 2 6 9 2 2 3 4 3 2 4 8 3 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 4 5 8 1 2 21 23 20 0 5 6 9 2 3 22 21 20 805306392 5 8 9 4 21 6 3 0 268435456 4 5 6 9 20 1 4 2 536870920 0 4 6 9 20 3 22 5 805306408 0 3 4 9 23 6 4 22 1073742056 4 8 9 3 2 21 5 23 536870916 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 1 1 -1 0 0 2 1 2 -1 0 7 1 1 1 0 1 1 55 1 6 8 0 2 5 6 0 2 4 5 0 2 4 6 0 2 8 9 1 2 5 9 1 2 5 8 1 2 3 6 2 2 6 9 2 2 0 8 3 2 4 8 3 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 4 5 8 1 2 21 23 20 0 5 6 9 2 3 22 21 20 805306420 4 5 6 8 20 3 6 0 268435456 5 6 8 9 2 4 21 1 536870916 6 8 9 3 3 21 22 5 805306388 3 6 8 0 4 6 23 22 1073742036 0 4 6 8 20 2 5 23 536870920 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 1 1 -1 0 0 2 1 2 -1 0 7 1 1 0 1 1 1 59 2 2 4 0 1 5 7 0 2 4 5 0 2 8 9 1 2 5 9 1 2 5 8 1 2 2 7 2 2 7 9 2 2 7 8 3 2 4 8 3 2 4 7 3 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 7 8 9 3 2 21 22 23 0 4 5 8 1 3 21 23 20 805306416 5 7 8 9 3 0 21 4 268435456 4 5 7 8 5 2 23 1 536870912 5 7 9 2 2 22 21 5 536870924 2 4 5 7 20 3 4 6 805306368 2 4 7 0 5 23 22 20 1073742016 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 1 1 -1 0 0 0 0 1 0 2 -1 0 7 1 1 0 1 1 1 59 2 0 5 0 1 5 7 0 2 4 5 0 2 8 9 1 2 5 9 1 2 5 8 1 2 0 9 2 2 7 9 2 2 7 8 3 2 4 8 3 2 4 7 3 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 7 8 9 3 2 21 22 23 0 4 5 8 1 3 21 23 20 805306416 5 7 8 9 3 0 21 5 268435456 4 5 7 8 4 2 23 1 536870912 0 4 5 7 20 3 5 23 805306368 5 7 9 0 2 22 6 4 536870924 2 5 9 0 21 5 22 20 805306412 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 1 1 -1 0 0 0 0 1 0 2 -1 0 7 1 1 0 1 1 1 59 2 0 5 0 1 5 7 0 2 4 5 0 2 8 9 1 2 5 9 1 2 5 8 1 2 2 7 2 2 7 9 2 2 7 8 3 2 4 8 3 2 4 7 3 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 7 8 9 3 2 21 22 23 0 4 5 8 1 3 21 23 20 805306416 5 7 8 9 3 0 21 6 268435456 4 5 7 8 4 2 23 1 536870912 0 4 5 7 20 3 5 23 805306368 2 5 7 0 6 4 22 20 1073741952 5 7 9 2 2 22 21 5 536870924 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 1 1 -1 0 0 0 0 1 0 2 -1 0 7 1 1 0 1 1 1 59 1 4 9 0 2 2 4 0 2 4 5 0 2 8 9 1 2 5 9 1 2 5 8 1 2 0 9 2 2 7 9 2 2 7 8 3 2 4 8 3 2 4 7 3 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 7 8 9 3 2 21 22 23 0 4 5 8 1 3 21 23 20 805306424 4 7 8 9 23 0 3 6 268435456 5 8 9 4 21 2 4 1 536870920 2 4 5 9 20 3 21 5 805306408 2 4 9 0 4 6 22 20 1073742056 4 7 9 0 2 22 5 23 536870924 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 1 1 -1 0 0 0 0 1 0 2 -1 0 7 1 0 1 1 1 1 61 2 1 6 0 1 4 9 0 2 4 6 0 2 1 9 1 2 8 9 1 2 7 9 2 2 6 7 2 2 6 9 2 2 7 8 3 2 4 7 3 2 4 8 3 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 7 8 9 3 2 21 22 23 0 0 4 6 7 20 3 22 23 805306380 4 7 8 9 23 0 4 3 268435456 4 6 7 9 1 22 2 5 536870924 1 4 8 9 23 2 21 5 536870920 4 6 9 1 3 6 4 20 805306428 1 2 6 9 20 22 5 21 1073741948 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 1 -1 0 1 2 0 0 0 1 0 2 -1 0 7 1 0 1 1 1 1 61 2 2 4 0 1 4 9 0 2 4 6 0 2 2 8 1 2 8 9 1 2 7 9 2 2 6 7 2 2 6 9 2 2 7 8 3 2 4 7 3 2 4 8 3 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 7 8 9 3 2 21 22 23 0 0 4 6 7 20 3 22 23 805306380 4 7 8 9 23 0 5 3 268435456 4 6 7 9 1 22 2 4 536870924 4 6 9 2 3 22 5 20 805306428 2 4 8 9 6 2 21 4 536870920 1 2 4 8 20 5 23 21 805306376 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 1 -1 0 1 2 0 0 0 1 0 2 -1 0 7 1 0 1 1 1 1 61 1 4 9 0 2 2 4 0 2 4 6 0 2 1 9 1 2 8 9 1 2 7 9 2 2 6 7 2 2 6 9 2 2 7 8 3 2 4 7 3 2 4 8 3 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 7 8 9 3 2 21 22 23 0 0 4 6 7 20 3 22 23 805306380 4 7 8 9 23 0 6 3 268435456 4 6 7 9 1 22 2 4 536870924 4 6 9 2 3 22 5 20 805306428 1 2 4 9 20 4 6 21 1073742012 1 4 8 9 23 2 21 5 536870920 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 1 -1 0 1 2 0 0 0 1 0 2 -1 0 7 1 0 1 1 1 1 61 2 1 6 0 1 6 8 0 2 4 6 0 2 2 8 1 2 8 9 1 2 6 7 2 2 7 9 2 2 6 9 2 2 7 8 3 2 4 7 3 2 4 8 3 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 7 8 9 3 2 21 22 23 0 0 4 6 7 20 3 22 23 805306368 6 7 8 9 3 0 6 22 268435456 4 6 7 8 1 2 23 4 536870912 4 6 8 1 3 5 23 20 805306416 1 2 6 8 20 6 4 21 1073741936 2 6 8 9 5 2 21 22 536870920 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 1 -1 0 1 2 0 0 0 1 0 2 -1 0 7 0 1 1 1 1 1 62 2 0 5 0 1 6 8 0 2 5 6 0 2 5 8 1 2 5 9 1 2 8 9 1 2 6 7 2 2 6 9 2 2 7 9 2 2 7 8 3 2 0 8 3 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 7 8 9 3 2 21 22 23 0 5 6 9 2 3 22 21 20 805306424 6 7 8 9 4 0 3 22 268435456 5 6 8 9 5 2 21 1 536870920 0 6 7 8 22 2 23 5 536870912 0 5 6 8 20 3 4 6 805306376 0 1 5 8 20 21 5 23 1073742024 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 -1 0 1 0 1 1 0 0 0 1 0 2 -1 0 7 0 1 1 1 1 1 62 2 1 6 0 1 6 8 0 2 5 6 0 2 5 8 1 2 5 9 1 2 8 9 1 2 6 7 2 2 6 9 2 2 7 9 2 2 7 8 3 2 1 7 3 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 7 8 9 3 2 21 22 23 0 5 6 9 2 3 22 21 20 805306424 6 7 8 9 5 0 3 22 268435456 5 6 8 9 4 2 21 1 536870920 1 5 6 8 20 3 5 21 805306376 1 6 7 8 6 2 23 4 536870912 0 1 6 7 20 5 22 23 805306368 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 -1 0 1 0 1 1 0 0 0 1 0 2 -1 0 7 0 1 1 1 1 1 62 1 6 8 0 2 1 6 0 2 5 6 0 2 5 8 1 2 5 9 1 2 8 9 1 2 6 7 2 2 6 9 2 2 7 9 2 2 7 8 3 2 0 8 3 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 7 8 9 3 2 21 22 23 0 5 6 9 2 3 22 21 20 805306424 6 7 8 9 6 0 3 22 268435456 5 6 8 9 4 2 21 1 536870920 1 5 6 8 20 3 5 21 805306376 0 1 6 8 20 4 6 23 1073741960 0 6 7 8 22 2 23 5 536870912 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 -1 0 1 0 1 1 0 0 0 1 0 2 -1 0 7 0 1 1 1 1 1 62 2 0 5 0 1 5 7 0 2 5 6 0 2 8 9 1 2 5 8 1 2 5 9 1 2 6 7 2 2 6 9 2 2 7 9 2 2 7 8 3 2 1 7 3 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 7 8 9 3 2 21 22 23 0 5 6 9 2 3 22 21 20 805306428 5 7 8 9 6 0 21 3 268435456 5 6 7 9 4 22 2 1 536870924 0 5 6 7 20 3 22 5 805306380 0 1 5 7 20 6 4 23 1073742028 1 5 7 8 5 2 23 21 536870912 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 -1 0 1 0 1 1 0 0 0 1 0 2 -1 0 8 1 1 1 1 1 1 63 2 4 5 0 2 4 6 0 1 6 8 0 2 5 6 0 2 8 9 1 2 5 8 1 2 5 9 1 2 6 7 2 2 7 9 2 2 6 9 2 2 7 8 3 2 4 7 3 2 4 8 3 0 0 0 0 0 0 0 0 0 0 0 0 0 4 6 7 20 4 22 23 0 4 5 8 1 5 21 23 20 805306429 5 6 9 2 6 22 21 20 1073742045 7 8 9 3 7 21 22 23 805306389 4 6 7 8 0 7 23 5 268435457 4 5 6 8 20 6 4 1 536870925 5 6 8 9 5 7 21 2 805306397 6 7 8 9 4 3 6 22 536870917 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 1 1 0 2 0 3 1 2 2 2 -1 0 8 1 1 1 1 1 1 63 2 4 5 0 2 4 6 0 2 5 6 0 1 4 9 0 2 8 9 1 2 5 9 1 2 5 8 1 2 7 9 2 2 6 7 2 2 6 9 2 2 7 8 3 2 4 7 3 2 4 8 3 0 0 0 0 0 0 0 0 0 0 0 0 5 6 9 2 4 22 21 20 0 4 5 8 1 5 21 23 20 805306428 7 8 9 3 6 21 22 23 1073741916 0 4 6 7 20 7 22 23 805306376 4 5 6 9 20 0 7 5 268435456 5 8 9 4 21 6 4 1 536870924 4 7 8 9 23 2 5 7 805306396 4 6 7 9 3 22 6 4 536870920 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 1 2 0 1 2 0 2 -1 0 8 1 1 1 1 1 1 63 2 4 5 0 2 4 6 0 1 5 7 0 2 5 6 0 2 8 9 1 2 5 9 1 2 5 8 1 2 7 9 2 2 6 7 2 2 6 9 2 2 7 8 3 2 4 7 3 2 4 8 3 0 0 0 0 0 0 0 0 0 0 0 0 7 8 9 3 4 21 22 23 0 4 5 8 1 5 21 23 20 805306416 0 4 6 7 20 6 22 23 1073741952 5 6 9 2 7 22 21 20 805306428 5 7 8 9 5 0 21 7 268435456 4 5 7 8 6 4 23 1 536870912 4 5 6 7 20 7 2 5 805306368 5 6 7 9 6 22 4 3 536870924 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 1 1 2 2 0 0 0 1 0 2 -1 0 0 2 3 9 4 10 13 35 5 15 16 38 17 41 50 122 6 19 22 53 23 60 66 126 25 68 72 130 74 134 144 217 7 26 27 79 30 82 86 154 31 95 97 163 101 174 178 221 34 103 106 182 110 188 202 225 112 206 210 229 214 233 237 239 -1 -1 -1 8 -1 11 12 -1 -1 -1 -1 39 -1 45 48 -1 -1 -1 -1 55 -1 61 67 -1 -1 -1 -1 127 -1 133 148 -1 -1 -1 -1 77 -1 84 88 -1 -1 -1 -1 165 -1 171 177 -1 -1 -1 -1 181 -1 196 199 -1 -1 -1 -1 227 -1 231 235 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 21 56 -1 -1 65 123 -1 -1 70 129 -1 -1 142 216 -1 -1 28 80 -1 -1 92 153 -1 -1 99 167 -1 -1 175 219 33 102 -1 -1 109 187 -1 -1 115 203 -1 -1 213 232 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 54 -1 -1 64 -1 -1 -1 -1 128 -1 -1 138 -1 -1 -1 -1 78 -1 -1 91 -1 -1 -1 -1 166 -1 -1 176 -1 -1 -1 -1 -1 -1 183 -1 -1 -1 -1 -1 -1 -1 234 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 18 46 51 121 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 76 131 150 215 -1 -1 -1 -1 29 81 89 151 32 96 98 164 -1 -1 -1 -1 -1 -1 -1 -1 108 186 201 223 118 205 207 228 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 47 49 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 132 149 -1 -1 -1 -1 -1 -1 83 87 -1 -1 -1 -1 155 -1 -1 -1 -1 -1 -1 -1 -1 -1 190 200 -1 -1 -1 -1 230 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 136 218 -1 -1 -1 -1 -1 -1 90 152 -1 -1 100 169 -1 -1 -1 -1 -1 -1 -1 -1 107 185 -1 -1 116 204 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 140 -1 -1 -1 -1 -1 -1 -1 85 -1 -1 -1 -1 170 -1 -1 -1 -1 -1 -1 -1 -1 -1 189 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 14 -1 37 -1 42 -1 119 -1 20 -1 59 -1 63 -1 125 24 -1 71 -1 73 -1 143 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 93 -1 161 -1 173 -1 220 -1 105 -1 179 -1 198 -1 224 114 -1 209 -1 211 -1 236 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 36 -1 44 -1 -1 -1 -1 -1 58 -1 62 -1 -1 -1 -1 -1 -1 -1 -1 135 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 157 -1 172 -1 -1 -1 -1 -1 180 -1 197 -1 -1 -1 -1 -1 -1 -1 -1 238 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 57 -1 -1 -1 124 -1 -1 69 -1 -1 -1 141 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 156 -1 -1 -1 222 -1 104 -1 -1 -1 194 -1 -1 113 -1 -1 -1 212 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 52 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 137 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 159 -1 -1 -1 -1 -1 -1 -1 -1 -1 195 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 43 -1 120 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 75 -1 146 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 94 -1 162 -1 -1 -1 -1 -1 -1 -1 -1 -1 184 -1 226 117 -1 208 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 40 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 147 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 158 -1 -1 -1 -1 -1 -1 -1 -1 -1 192 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 145 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 168 -1 -1 -1 -1 -1 -1 -1 -1 -1 193 -1 -1 111 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 139 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 160 -1 -1 -1 -1 -1 -1 -1 -1 -1 191 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 dune-uggrid-2.11.0+dfsg/dune/uggrid/lib/RefRules.data.license000066400000000000000000000002161513616443000237130ustar00rootroot00000000000000SPDX-FileCopyrightInfo: Copyright © DUNE Project contributors, see file LICENSE.md in module root SPDX-License-Identifier: LGPL-2.1-or-later dune-uggrid-2.11.0+dfsg/dune/uggrid/lib/tetra.rls000066400000000000000000000503201513616443000215520ustar00rootroot00000000000000tolfak 0.5 rule "Free Tetrahedron" quality 1 mappoints (0, 0, 0); (1, 0, 0); (0.5, 0.866, 0); mapfaces (1, 2, 3) del; newpoints (0.5, 0.288, -0.816) { 0.333 X1, 0.333 X2, 0.333 X3 } { 0.333 Y1, 0.333 Y2, 0.333 Y3 } { }; newfaces (4, 1, 2); (4, 2, 3); (4, 3, 1); elements (1, 2, 3, 4); freezone2 { 1 P1 }; { 1 P2 }; { 1 P3 }; { 1.6 P4, -0.2 P1, -0.2 P2, -0.2 P3 }; { -0.5 P1, 0.5 P2, 0.5 P3, 0.5 P4 }; { 0.5 P1, -0.5 P2, 0.5 P3, 0.5 P4 }; { 0.5 P1, 0.5 P2, -0.5 P3, 0.5 P4 }; endrule rule "Tetrahedron 60" quality 1 flags c; mappoints (0, 0, 0); (1, 0, 0); (0.5, 0.866, 0); (0.5, 0.288, -0.816); mapfaces (1, 2, 3) del; (1, 4, 2) del; newpoints newfaces (1, 4, 3); (4, 2, 3); elements (1, 2, 3, 4); freezone2 { 1 P1 }; { 1 P2 }; { 1 P3 }; { 1 P4 }; { 0.6 P3, 0.6 P4, -0.4 P1, 0.2 P2 }; { 0.6 P3, 0.6 P4, -0.4 P2, 0.2 P1 }; freezonelimit { 1 P1 }; { 1 P2 }; { 1 P3 }; { 1 P4 }; { 0.5 P3, 0.5 P4 }; { 0.5 P3, 0.5 P4 }; endrule rule "Tetrahedron 60 with edge(1)" quality 1 flags c; mappoints (0, 0, 0); (1, 0, 0) { 0.8 }; (0.5, 0.866, 0) { 0.8 }; (0.5, 0.288, -0.816) { 0.8 }; mapfaces (1, 2, 3) del; (1, 4, 2) del; mapedges (3, 4); newpoints newfaces (1, 4, 3); (4, 2, 3); elements (1, 2, 3, 4); freezone2 { 1 P1 }; { 1 P2 }; { 1 P3 }; { 1 P4 }; { 0.4 P1, 0.4 P4, 0.4 P3, -0.2 P2 }; { 0.4 P2, 0.4 P4, 0.4 P3, -0.2 P1 }; freezonelimit { 1 P1 }; { 1 P2 }; { 1 P3 }; { 1 P4 }; { 0.3333 P1, 0.3333 P4, 0.3334 P3 }; { 0.3333 P2, 0.3333 P4, 0.3334 P3 }; endrule rule "Tetrahedron Vis a Vis Point (1)" quality 1 mappoints (0, 0, 0); (1, 0, 0) { 0.5 }; (0.5, 0.866, 0) { 0.5 }; (0.5, 0.288, -0.816) { 0.5 }; mapfaces (1, 2, 3) del; newpoints newfaces (4, 3, 1); (4, 2, 3); (4, 1, 2); elements (1, 2, 3, 4); freezone2 { 1 P1 }; { 1 P2 }; { 1 P3 }; { 1 P4 }; { -0.5 P1, 0.5 P2, 0.5 P3, 0.5 P4 }; { 0.5 P1, -0.5 P2, 0.5 P3, 0.5 P4 }; { 0.5 P1, 0.5 P2, -0.5 P3, 0.5 P4 }; { 0.8 P1, -0.1 P2, -0.1 P3, 0.4 P4 }; { -0.1 P1, 0.8 P2, -0.1 P3, 0.4 P4 }; { -0.1 P1, -0.1 P2, 0.8 P3, 0.4 P4 }; endrule rule "Tetrahedron Vis a Vis Point with edge(1)" quality 1 mappoints (0, 0, 0); (1, 0, 0) { 0.5 }; (0.5, 0.866, 0) { 0.5 }; (0.5, 0.288, -0.816) { 0.5 }; mapfaces (1, 2, 3) del; mapedges (1, 4); newpoints newfaces (4, 3, 1); (4, 2, 3); (4, 1, 2); elements (1, 2, 3, 4); freezone2 { 1 P1 }; { 1 P2 }; { 1 P3 }; { 1 P4 }; { -0.35 P1, 0.45 P2, 0.45 P3, 0.45 P4 }; { 0.45 P1, -0.35 P2, 0.45 P3, 0.45 P4 }; { 0.45 P1, 0.45 P2, -0.35 P3, 0.45 P4 }; { -0.05 P1, 0.7 P2, -0.05 P3, 0.4 P4 }; { -0.05 P1, -0.05 P2, 0.7 P3, 0.4 P4 }; endrule rule "Tetrahedron Vis a Vis Point with 2 edges (1)" quality 1 mappoints (0, 0, 0); (1, 0, 0) { 0.5 }; (0.5, 0.866, 0) { 0.5 }; (0.5, 0.288, -0.816) { 0.5 }; mapfaces (1, 2, 3) del; mapedges (1, 4); (2, 4); newpoints newfaces (4, 3, 1); (4, 2, 3); (4, 1, 2); elements (1, 2, 3, 4); freezone2 { 1 P1 }; { 1 P2 }; { 1 P3 }; { 1 P4 }; { -0.35 P1, 0.45 P2, 0.45 P3, 0.45 P4 }; { 0.45 P1, -0.35 P2, 0.45 P3, 0.45 P4 }; { 0.45 P1, 0.45 P2, -0.35 P3, 0.45 P4 }; { -0.05 P1, -0.05 P2, 0.7 P3, 0.4 P4 }; endrule rule "Tetrahedron Vis a Vis Point with 3 edges (1)" quality 1 mappoints (0, 0, 0); (1, 0, 0) { 0.5 }; (0.5, 0.866, 0) { 0.5 }; (0.5, 0.288, -0.816) { 0.5 }; mapfaces (1, 2, 3) del; mapedges (1, 4); (2, 4); (3, 4); newpoints newfaces (4, 3, 1); (4, 2, 3); (4, 1, 2); elements (1, 2, 3, 4); freezone2 { 1 P1 }; { 1 P2 }; { 1 P3 }; { 1 P4 }; { -0.35 P1, 0.45 P2, 0.45 P3, 0.45 P4 }; { 0.45 P1, -0.35 P2, 0.45 P3, 0.45 P4 }; { 0.45 P1, 0.45 P2, -0.35 P3, 0.45 P4 }; endrule rule "Tetrahedron Vis a Vis Triangle (1)" quality 100 mappoints (0, 0, 0); (1, 0, 0) { 0.5 }; (0.5, 0.866, 0) { 0.5 }; (0, 0, -0.816) { 0.5 }; (1, 0, -0.816) { 0.5 }; (0.5, 0.866, -0.816) { 0.5 }; mapfaces (1, 2, 3) del; (4, 6, 5) del; newpoints newfaces (1, 2, 4); (2, 5, 4); (2, 3, 6); (2, 6, 5); (3, 1, 4); (3, 4, 6); elements (1, 2, 3, 4); (4, 2, 3, 6); (4, 2, 6, 5); freezone2 { 1 P1 }; { 1 P2 }; { 1 P3 }; { 1 P4 }; { 1 P5 }; { 1 P6 }; { -0.2 P1, 0.35 P2, 0.35 P3, -0.2 P4, 0.35 P5, 0.35 P6 }; { 0.35 P1, -0.2 P2, 0.35 P3, 0.35 P4, -0.2 P5, 0.35 P6 }; { 0.35 P1, 0.35 P2, -0.2 P3, 0.35 P4, 0.35 P5, -0.2 P6 }; endrule rule "Octaeder 1" quality 100 mappoints (0, 0, 0); (1, 0, 0) { 0.95 }; (0.5, 0.866, 0) { 0.95 }; (0.5, -0.288, -0.816) { 0.5 }; mapfaces (1, 2, 3) del; (1, 4, 2) del; newpoints (1, 0.578, -0.816) { 0.5 X3, 0.5 X4 } { 0.5 Y3, 0.5 Y4} { 0.5 Z3, 0.5 Z4 }; (0, 0.578, -0.816) { 0.5 X3, 0.5 X4 } { 0.5 Y3, 0.5 Y4} { 0.5 Z3, 0.5 Z4 }; newfaces (2, 3, 5); (3, 1, 6); (3, 6, 5); (2, 5, 4); (1, 4, 6); (4, 5, 6); elements (3, 4, 1, 2); (3, 4, 2, 5); (3, 4, 5, 6); (3, 4, 6, 1); freezone (0, 0, 0); (1, 0, 0) { 1 X2 } { } { }; (0.5, 0.866, 0) { 1 X3 } { 1 Y3 } { }; (0.5, -0.288, -0.816) { 1 X4 } { 1 Y4 } { 1 Z4 }; (-0.5, 1, -1.5) { 0.5 X3, 0.5 X4 } { 0.5 Y3, 0.5 Y4 } { 1 Z4 }; ( 1.5, 1, -1.5) { 0.5 X3, 0.5 X4 } { 0.5 Y3, 0.5 Y4 } { 1 Z4 }; endrule rule "Octaeder 2" quality 100 mappoints (0, 0, 0); (1, 0, 0) { 0.95 }; (0.5, 0.866, 0) { 0.95 }; (0.5, -0.288, -0.816) { 0.5 }; (1, 0.578, -0.816) { 0.5 }; mapfaces (1, 2, 3) del; (1, 4, 2) del; newpoints (0, 0.578, -0.816) { 0.5 X3, 0.5 X4 } { 0.5 Y3, 0.5 Y4} { 0.5 Z3, 0.5 Z4 }; newfaces (2, 3, 5); (3, 1, 6); (3, 6, 5); (2, 5, 4); (1, 4, 6); (4, 5, 6); elements (3, 4, 1, 2); (3, 4, 2, 5); (3, 4, 5, 6); (3, 4, 6, 1); freezone (0, 0, 0); (1, 0, 0) { 1 X2 } { } { }; (0.5, 0.866, 0) { 1 X3 } { 1 Y3 } { }; (0.5, -0.288, -0.816) { 1 X4 } { 1 Y4 } { 1 Z4 }; (1, 0.578, -0.816) { 1 X5 } { 1 Y5 } { 1 Z5 }; (0.9, 0.097, -0.544) { 0.333 X2, 0.333 X4, 0.333 X5 } { 0.333 Y2, 0.333 Y4, 0.333 Y5 } { 0.333 Z2, 0.333 Z4, 0.333 Z5 }; (0.9, 0.481, -0.272) { 0.333 X2, 0.333 X3, 0.333 X5 } { 0.333 Y2, 0.333 Y3, 0.333 Y5 } { 0.333 Z2, 0.333 Z3, 0.333 Z5 }; (-0.5, 1, -1.5) { 0.5 X3, 0.5 X4 } { 0.5 Y3, 0.5 Y4 } { 0.5 Z4, 0.5 Z5 }; endrule rule "Octaeder 2a" quality 100 mappoints (0, 0, 0); (1, 0, 0) { 0.95 }; (0.5, 0.866, 0) { 0.95 }; (0.5, -0.288, -0.816) { 0.5 }; (1, 0.578, -0.816) { 0.5 }; mapfaces (1, 2, 3) del; (3, 2, 5) del; newpoints (0, 0.578, -0.816) { -1 X2, 1 X3, 1 X4 } { -1 Y2, 1 Y3, 1 Y4 } { -1 Z2, 1 Z3, 1 Z4 }; newfaces (1, 2, 4); (3, 1, 6); (3, 6, 5); (2, 5, 4); (1, 4, 6); (4, 5, 6); elements (3, 4, 1, 2); (3, 4, 2, 5); (3, 4, 5, 6); (3, 4, 6, 1); freezone (0, 0, 0); (1, 0, 0) { 1 X2 } { } { }; (0.5, 0.866, 0) { 1 X3 } { 1 Y3 } { }; (0.5, -0.288, -0.816) { 1 X4 } { 1 Y4 } { 1 Z4 }; (1, 0.578, -0.816) { 1 X5 } { 1 Y5 } { 1 Z5 }; (0.9, 0.097, -0.544) { 0.333 X2, 0.333 X4, 0.333 X5 } { 0.333 Y2, 0.333 Y4, 0.333 Y5 } { 0.333 Z2, 0.333 Z4, 0.333 Z5 }; (0.5, -0.097, -0.272) { 0.333 X2, 0.333 X4, 0.333 X1 } { 0.333 Y2, 0.333 Y4, 0.333 Y1 } { 0.333 Z2, 0.333 Z4, 0.333 Z1 }; (-0.5, 1, -1.5) { 0.5 X3, 0.5 X4 } { 0.5 Y3, 0.5 Y4 } { 0.5 Z4, 0.5 Z5 }; endrule rule "Pyramid 1" quality 100 mappoints (0, 0, 0); (1, 0, 0) { 1 }; (0.5, 0.866, 0) { 1 }; (0.5, -0.288, -0.816) { 1 }; mapfaces (1, 2, 3) del; (1, 4, 2) del; newpoints (1, 0.578, -0.816) { 0.5 X3, 0.5 X4 } { 0.5 Y3, 0.5 Y4} { 0.5 Z3, 0.5 Z4 }; newfaces (1, 4, 3); (2, 3, 5); (2, 5, 4); (4, 5, 3); elements (1, 2, 3, 4); (4, 2, 3, 5); freezone (0, 0, 0); (1, 0, 0) { 1 X2 } { } { }; (0.5, 0.866, 0) { 1 X3 } { 1 Y3 } { }; (0.5, -0.288, -0.816) { 1 X4 } { 1 Y4 } { 1 Z4 }; (0, 1, -1) { 0.5 X3, 0.5 X4 } { 1 Y3 } { 1 Z4 }; (1.5, 1, -1.5) { 0.5 X3, 0.5 X4 } { 0.5 Y3, 0.5 Y4} { 0.5 Z3, 0.5 Z4 }; endrule rule "Tetrahedron 2 times 60" quality 1 mappoints (0, 0, 0); (1, 0, 0) { 0.3 }; (0.5, 0.866, 0) { 0.3 }; (0.5, 0.288, -0.816) { 0.3 }; mapfaces (1, 2, 3) del; (1, 4, 2) del; (2, 4, 3) del; newpoints newfaces (1, 4, 3); elements (1, 2, 3, 4); freezone2 { 1 P1 }; { 1 P2 }; { 1 P3 }; { 1 P4 }; { 0.4 P1, 0.4 P4, 0.4 P3, -0.2 P2 }; freezonelimit { 1 P1 }; { 1 P2 }; { 1 P3 }; { 1 P4 }; { 0.3333 P1, 0.3333 P4, 0.3334 P3 }; endrule rule "Fill Tetrahedron (1)" quality 1 mappoints (0, 0, 0); (1, 0, 0) { 0.2 }; (0.5, 0.866, 0) { 0.2 }; (0.5, 0.288, -0.816) { 0.2 }; mapfaces (1, 2, 3) del; (1, 4, 2) del; (2, 4, 3) del; (3, 4, 1) del; newpoints newfaces elements (1, 2, 3, 4); freezone2 { 1 P1 }; { 1 P2 }; { 1 P3 }; { 1 P4 }; endrule rule "Tetrahedron 120 (1)" quality 1 mappoints (0, 0, 0); (1, 0, 0) { 1 }; (0.5, 0.866, 0) { 1 }; (0.5, -0.674, -0.544) { 1 }; mapfaces (1, 2, 3) del; (1, 4, 2) del; newpoints (0.5, 0.288, -0.816) { -0.5 X1, -0.5 X2, 1 X3, 1 X4 } { -0.5 Y1, -0.5 Y2, 1 Y3, 1 Y4} { -0.5 Z1, -0.5 Z2, 1 Z3, 1 Z4}; newfaces (1, 5, 3); (3, 5, 2); (1, 4, 5); (2, 5, 4); elements (1, 2, 3, 5); (1, 4, 2, 5); freezone2 { 1 P1 }; { 1 P2 }; { 1 P3 }; { 1 P4 }; { 1.3 P5, -0.3 P1 }; { 1.3 P5, -0.3 P2 }; endrule rule "Tetrahedron 2 times 120 (1)" quality 1 mappoints (0, 0, 0); (1, 0, 0) { 1 }; (0.5, 0.866, 0) { 1 }; (0.5, -0.674, -0.544) { 0.8 }; (1.334, 0.77, -0.544) { 0.8 }; mapfaces (1, 2, 3) del; (1, 4, 2) del; (3, 2, 5) del; newpoints (0.5, 0.288, -0.816) { 0.25 X1, -0.5 X2, 0.25 X3, 0.5 X4, 0.5 X5 } { 0.25 Y1, -0.5 Y2, 0.25 Y3, 0.5 Y4, 0.5 Y5 } { 0.25 Z1, -0.5 Z2, 0.25 Z3, 0.5 Z4, 0.5 Z5 }; newfaces (6, 3, 1); (6, 1, 4); (6, 4, 2); (6, 2, 5); (6, 5, 3); elements (1, 2, 3, 6); (1, 4, 2, 6); (2, 5, 3, 6); freezone2 { 1 P1 }; { 1 P2 }; { 1 P3 }; { 1 P4 }; { 1 P5 }; { 1.4 P6, -0.4 P2 }; { 1.4 P6, -0.4 P1 }; { 1.4 P6, -0.4 P3 }; endrule rule "Tetrahedron 60 (3)" quality 100 mappoints (0, 0, 0); (1, 0, 0) { 0.8 }; (0.5, 0.866, 0) { 0.8 }; (0.5, 0.288, -0.816) { 0.8 }; mapfaces (1, 2, 3) del; (1, 4, 2) del; newpoints newfaces (1, 4, 3); (4, 2, 3); elements (1, 2, 3, 4); freezone2 { 1 P1 }; { 1 P2 }; { 1 P3 }; { 1 P4 }; { 0.55 P3, 0.55 P4, -0.1 P1 }; { 0.55 P3, 0.55 P4, -0.1 P2 }; endrule rule "Tetrahedron 60 with edge(3)" quality 100 mappoints (0, 0, 0); (1, 0, 0) { 0.8 }; (0.5, 0.866, 0) { 0.8 }; (0.5, 0.288, -0.816) { 0.8 }; mapfaces (1, 2, 3) del; (1, 4, 2) del; mapedges (3, 4); newpoints newfaces (1, 4, 3); (4, 2, 3); elements (1, 2, 3, 4); freezone2 { 1 P1 }; { 1 P2 }; { 1 P3 }; { 1 P4 }; { 0.35 P1, 0.35 P4, 0.35 P3, -0.05 P2 }; { 0.35 P2, 0.35 P4, 0.35 P3, -0.05 P1 }; endrule rule "Tetrahedron 2 times 60 (3)" quality 100 mappoints (0, 0, 0); (1, 0, 0) { 0.8 }; (0.5, 0.866, 0) { 0.8 }; (0.5, 0.288, -0.816) { 0.8 }; mapfaces (1, 2, 3) del; (1, 4, 2) del; (2, 4, 3) del; newpoints newfaces (1, 4, 3); elements (1, 2, 3, 4); freezone2 { 1 P1 }; { 1 P2 }; { 1 P3 }; { 1 P4 }; { 0.35 P1, 0.35 P4, 0.35 P3, -0.05 P2 }; endrule rule "Tetrahedron Vis a Vis Point (3)" quality 100 mappoints (0, 0, 0); (1, 0, 0) { 0.5 }; (0.5, 0.866, 0) { 0.5 }; (0.5, 0.288, -0.816) { 0.5 }; mapfaces (1, 2, 3) del; newpoints newfaces (4, 3, 1); (4, 2, 3); (4, 1, 2); elements (1, 2, 3, 4); freezone2 { 1 P1 }; { 1 P2 }; { 1 P3 }; { 1 P4 }; { -0.2 P1, 0.4 P2, 0.4 P3, 0.4 P4 }; { 0.4 P1, -0.2 P2, 0.4 P3, 0.4 P4 }; { 0.4 P1, 0.4 P2, -0.2 P3, 0.4 P4 }; { 0.7 P1, -0.05 P2, -0.05 P3, 0.4 P4 }; { -0.05 P1, 0.7 P2, -0.05 P3, 0.4 P4 }; { -0.05 P1, -0.05 P2, 0.7 P3, 0.4 P4 }; endrule rule "Tetrahedron Vis a Vis Point with edge(3)" quality 3 mappoints (0, 0, 0); (1, 0, 0) { 0.5 }; (0.5, 0.866, 0) { 0.5 }; (0.5, 0.288, -0.816) { 0.5 }; mapfaces (1, 2, 3) del; mapedges (1, 4); newpoints newfaces (4, 3, 1); (4, 2, 3); (4, 1, 2); elements (1, 2, 3, 4); freezone2 { 1 P1 }; { 1 P2 }; { 1 P3 }; { 1 P4 }; { -0.2 P1, 0.4 P2, 0.4 P3, 0.4 P4 }; { 0.4 P1, -0.2 P2, 0.4 P3, 0.4 P4 }; { 0.4 P1, 0.4 P2, -0.2 P3, 0.4 P4 }; { -0.05 P1, 0.7 P2, -0.05 P3, 0.4 P4 }; { -0.05 P1, -0.05 P2, 0.7 P3, 0.4 P4 }; endrule rule "Fill open Tetrahedron (7)" quality 100 mappoints (0, 0, 0); (1, 0, 0) { 0.5 }; (0.5, 0.866, 0) { 0.5 }; (0.5, 0.288, -0.816) { 0.5 }; mapfaces (1, 2, 3) del; (1, 4, 2) del; (2, 4, 3) del; newpoints newfaces (3, 1, 4); elements (1, 2, 3, 4); freezone (0, 0, 0); (1, 0, 0) { 1 X2 } { } { }; (0.5, 0.866, 0) { 1 X3 } { 1 Y3 } { }; (0.5, 0.288, -0.816) { 1 X4 } { 1 Y4 } { 1 Z4 }; endrule rule "four Tetrahedron non convex (4)" quality 4 flags l; mappoints (0, 0, 0); (1, 0, 0) { 0.5 }; (0.5, 1, 0) { 0.5 }; (0.5, 0, -1) { 0.5 }; (0.5, 0.3, -0.3) { 0.5 }; mapfaces (1, 2, 3) del; (1, 4, 2) del; (1, 5, 4) del; (1, 3, 5) del; newpoints (0.5, 0.1, -0.1) { 0.333 X1, 0.333 X2, 0.334 X5 } { 0.333 Y1, 0.333 Y2, 0.334 Y5 } { 0.333 Z1, 0.333 Z2, 0.334 Z5 }; newfaces (6, 2, 3) del; (6, 4, 2) del; (6, 5, 4) del; (6, 3, 5) del; elements (1, 2, 3, 6); (1, 4, 2, 6); (1, 5, 4, 6); (1, 3, 5, 6); freezone2 { 1 P1 }; { 1 P2 }; { 1 P3 }; { 1 P4 }; { 1 P5 }; { 1.5 P6, -0.5 P1 }; freezonelimit { 1 P1 }; { 1 P2 }; { 1 P3 }; { 1 P4 }; { 1 P5 }; { 1 P6 }; freeset 1 6 2 3; freeset 1 6 3 5; freeset 1 6 5 4; freeset 1 6 4 2; endrule rule "five Tetrahedron non convex (4)" quality 4 flags l; mappoints (0, 0, 0); (1, 0, 0) { 0.5 }; (0.5, 1, 0) { 0.5 }; (0, 0.8, -0.2) { 0.5 }; (0, 0.2, -0.8) { 0.5 }; (0.5, 0, -1) { 0.5 }; mapfaces (1, 2, 3) del; (1, 3, 4) del; (1, 4, 5) del; (1, 5, 6) del; (1, 6, 2) del; newpoints (0.1, 0.1, -0.1) { 0.75 X1, 0.05 X2, 0.05 X3, 0.05 X4, 0.05 X5, 0.05 X6 } { 0.75 Y1, 0.05 Y2, 0.05 Y3, 0.05 Y4, 0.05 Y5, 0.05 Y6 } { 0.75 Z1, 0.05 Z2, 0.05 Z3, 0.05 Z4, 0.05 Z5, 0.05 Z6 }; newfaces (7, 2, 3); (7, 3, 4); (7, 4, 5); (7, 5, 6); (7, 6, 2); elements (1, 2, 3, 7); (1, 3, 4, 7); (1, 4, 5, 7); (1, 5, 6, 7); (1, 6, 2, 7); freezone2 { 1 P1 }; { 1 P2 }; { 1 P3 }; { 1 P4 }; { 1 P5 }; { 1 P6 }; { 1.5 P7, -0.5 P1 }; freezonelimit { 1 P1 }; { 1 P2 }; { 1 P3 }; { 1 P4 }; { 1 P5 }; { 1 P6 }; { 1 P7 }; freeset 1 7 2 3; freeset 1 7 3 4; freeset 1 7 4 5; freeset 1 7 5 6; freeset 1 7 6 2; endrule rule "four Tetrahedron non convex (6)" quality 6 flags l; mappoints (0, 0, 0); (1, 0, 0) { 0.5 }; (0.5, 1, 0) { 0.5 }; (0.5, 0, -1) { 0.5 }; (0.5, 0.3, -0.3) { 0.5 }; mapfaces (1, 2, 3) del; (1, 4, 2) del; (1, 5, 4) del; (1, 3, 5) del; newpoints (0.095, 0.003, -0.003) { 0.9 X1, 0.09 X2, 0.01 X5 } { 0.9 Y1, 0.09 Y2, 0.01 Y5 } { 0.9 Z1, 0.09 Z2, 0.01 Z5 }; newfaces (6, 2, 3) del; (6, 4, 2) del; (6, 5, 4) del; (6, 3, 5) del; elements (1, 2, 3, 6); (1, 4, 2, 6); (1, 5, 4, 6); (1, 3, 5, 6); freezone2 { 1 P1 }; { 1 P2 }; { 1 P3 }; { 1 P4 }; { 1 P5 }; { 1.499 P6, -0.5 P1, 0.001 P2 }; freezonelimit { 1 P1 }; { 1 P2 }; { 1 P3 }; { 1 P4 }; { 1 P5 }; { 1 P6 }; freeset 1 6 2 3; freeset 1 6 3 5; freeset 1 6 5 4; freeset 1 6 4 2; endrule rule "four Tetrahedron non convex (6)" quality 100 mappoints (0, 0, 0); (1, 0, 0) { 0.5 }; (0.5, 1, 0) { 0.5 }; (0.5, 0, -1) { 0.5 }; (0.5, 0.4, -0.4) { 0.5 }; mapfaces (1, 2, 3) del; (1, 4, 2) del; (4, 5, 2) del; (5, 3, 2) del; newpoints (0.925, 0.02, -0.02) { 0.05 X1, 0.9 X2, 0.05 X5 } { 0.05 Y1, 0.9 Y2, 0.05 Y5 } { 0.05 Z1, 0.9 Z2, 0.05 Z5 }; newfaces (3, 1, 6); (1, 4, 6); (4, 5, 6); (5, 3, 6); elements (3, 1, 2, 6); (1, 4, 2, 6); (4, 5, 2, 6); (5, 3, 2, 6); orientations (3, 1, 2, 5); (1, 4, 2, 5); (2, 4, 5, 1); (3, 2, 5, 1); (5, 4, 2, 3); freezone2 { 1 P1 }; { 1 P2 }; { 1 P3 }; { 1 P4 }; { 1 P5 }; { 1.5 P6, -0.5 P2 }; freezonelimit { 1 P1 }; { 1 P2 }; { 1 P3 }; { 1 P4 }; { 1 P5 }; { 1 P6 }; freeset 3 1 2 6; freeset 1 4 2 6; freeset 4 5 2 6; freeset 5 3 2 6; endrule rule "three Tetrahedron non convex (4)" quality 4 flags l; mappoints (0, 0, 0); (1, 0, 0) { 0.5 }; (0.5, 1, 0) { 0.5 }; (0.5, 0, -1) { 0.5 }; mapfaces (1, 2, 3) del; (1, 4, 2) del; (1, 3, 4) del; newpoints (0.5, 0.25, -0.25) { 0.25 X1, 0.25 X2, 0.25 X3, 0.25 X4 } { 0.25 Y1, 0.25 Y2, 0.25 Y3, 0.25 Y4 } { 0.25 Z1, 0.25 Z2, 0.25 Z3, 0.25 Z4 }; newfaces (5, 2, 3); (5, 4, 2); (5, 3, 4); elements (2, 3, 1, 5); (3, 4, 1, 5); (4, 2, 1, 5; orientations (1, 2, 4, 3); freezone2 { 1 P1 }; { 1 P2 }; { 1 P3 }; { 1 P4 }; { 1.5 P5, -0.5 P1 }; freezonelimit { 1 P1 }; { 1 P2 }; { 1 P3 }; { 1 P4 }; { 1 P5 }; freeset 1 2 3 5; freeset 1 3 4 5; freeset 1 4 2 5; endrule rule "three Tetrahedron non convex (6)" quality 100 mappoints (0, 0, 0); (1, 0, 0) { 0.5 }; (0.5, 1, 0) { 0.5 }; (0.5, 0, -1) { 0.5 }; mapfaces (1, 2, 3) del; (1, 4, 2) del; (1, 3, 4) del; newpoints (0.2, 0.1, -0.1) { 0.7 X1, 0.1 X2, 0.1 X3, 0.1 X4 } { 0.7 Y1, 0.1 Y2, 0.1 Y3, 0.1 Y4 } { 0.7 Z1, 0.1 Z2, 0.1 Z3, 0.1 Z4 }; newfaces (5, 2, 3); (5, 4, 2); (5, 3, 4); elements (2, 3, 1, 5); (3, 4, 1, 5); (4, 2, 1, 5; orientations (1, 2, 3, 4); freezone2 { 1 P1 }; { 1 P2 }; { 1 P3 }; { 1 P4 }; { 1.5 P5, -0.5 P1 }; freezonelimit { 1 P1 }; { 1 P2 }; { 1 P3 }; { 1 P4 }; { 1 P5 }; freeset 1 2 3 5; freeset 1 3 4 5; freeset 1 4 2 5; endrule rule "four Tetrahedron non convex (6)" quality 100 mappoints (0, 0, 0); (1, 0, 0) { 0.5 }; (0.5, 1, 0) { 0.5 }; (0.5, 0, -1) { 0.5 }; (0.5, 0.4, -0.4) { 0.5 }; mapfaces (1, 2, 3) del; (1, 4, 2) del; (4, 5, 2) del; (5, 3, 2) del; newpoints (0.7, 0.08, -0.08) { 0.6 X2, 0.2 X5 } { 0.2 Y5 } { 0.2 Z5 }; newfaces (3, 1, 6); (1, 4, 6); (4, 5, 6); (5, 3, 6); elements (3, 1, 2, 6); (1, 4, 2, 6); (4, 5, 2, 6); (5, 3, 2, 6); orientations (3, 1, 2, 5); (5, 1, 2, 4); freezone (0, 0, 0); (1, 0, 0) { 1 X2 } { } { }; (0.5, 1, 0) { 1 X3 } { 1 Y3 } { }; (0.5, 0, -1) { 1 X4 } { 1 Y4 } { 1 Z4 }; (0.5, 0.4, -0.4) { 1 X5 } { 1 Y5 } { 1 Z5 }; (0.55, 0.12, -0.12) { 0.4 X2, 0.3 X5 } { 0.3 Y5 } { 0.3 Z5 }; freeset 3 1 2 6; freeset 1 4 2 6; freeset 4 5 2 6; freeset 5 3 2 6; endrule rule "Fill wide open Tetrahedron (8)" quality 100 mappoints (0, 0, 0); (1, 0, 0) { 0.5 }; (0.5, 0.866, 0) { 0.5 }; (0.5, 0.288, -0.816) { 0.5 }; mapfaces (1, 2, 3) del; (1, 4, 2) del; newpoints newfaces (3, 1, 4); (3, 4, 2); elements (1, 2, 3, 4); freezone (0, 0, 0); (1, 0, 0) { 1 X2 } { } { }; (0.5, 0.866, 0) { 1 X3 } { 1 Y3 } { }; (0.5, 0.288, -0.816) { 1 X4 } { 1 Y4 } { 1 Z4 }; endrule rule "Cut only (9)" quality 100 mappoints (0, 0, 0); (1, 0, 0) { 0.5 }; (0.5, 0.866, 0) { 0.2 }; (0.5, 0, -0.866) { 0.2 }; (0.5, 0.866, -0.866) { 0.2 }; mapfaces (1, 2, 3); (1, 4, 2); newpoints newfaces (1, 2, 5); (2, 1, 5); elements freezone (0, 0, 0); (1, 0, 0) { 1 X2 } { 1 Y2 } { 1 Z2 }; (0.5, 0.866, -0.866) { 1 X5 } { 1 Y5 } { 1 Z5 }; (0.5, 0.28578, -0.29155) { .33333 X2, 0.33333 X5 } { 0.33333 Y5, 0.00333 Z5 } { 0.33333 Z5, -0.00333 Y5 }; (0.5, 0,29155, -0.28578) { .33333 X2, 0.33333 X5 } { 0.33333 Y5, -0.00333 Z5 } { 0.33333 Z5, 0.00333 Y5 }; orientations (1, 2, 3, 5); (1, 4, 2, 5); endrule rule "Tetrahedron 2 in 60 (12)" quality 100 mappoints (0, 0, 0); (1, 0, 0) { 0.5 }; (0.5, 1, 0) { 0.5 }; (0.5, 0, -1) { 0.5 }; mapfaces (1, 2, 3) del; (1, 4, 2) del; newpoints (0.5, 0.1, -0.1) { 0.4 X1, 0.4 X2, 0.1 X3, 0.1 X4 } { 0.4 Y1, 0.4 Y2, 0.1 Y3, 0.1 Y4 } { 0.4 Z1, 0.4 Z2, 0.1 Z3, 0.1 Z4 }; newfaces (5, 2, 3); (5, 3, 1); (5, 4, 2); (5, 1, 4); elements (1, 2, 3, 5); (1, 2, 5, 4); freezone2 { 1 P1 }; { 1 P2 }; { 1 P3 }; { 1 P4 }; { 1.5 P5, -0.25 P1, -0.25 P2 }; freezonelimit { 1 P1 }; { 1 P2 }; { 1 P3 }; { 1 P4 }; { 1 P5 }; freeset 1 2 3 5; freeset 1 2 4 5; endrule rule "Tetrahedron 120, but more than 180 (13)" quality 100 mappoints (0, 0, 0); (1, 0, 0) { 1 }; (0.5, 0.866, 0) { 1 }; (0.5, -0.866, 0) { 1 }; mapfaces (1, 2, 3) del; (1, 4, 2); newpoints (0.5, 0, -0.3) { 0.5 X3, 0.5 X4 } { 0.5 Y3, 0.5 Y4} { 0.5 Z3, 0.5 Z4 }; newfaces (1, 5, 3); (3, 5, 2); (2, 5, 1); elements (1, 2, 3, 5); freezone (0, 0, 0); (1, 0, 0) { 1 X2 } { } { }; (0.5, 0.866, 0) { 1 X3 } { 1 Y3 } { }; (0.5, -0.1, -0.4) { 0.5 X3, 0.5 X4 } { 0.5 Y3, 0.5 Y4} { 0.5 Z3, 0.5 Z4 }; endrule rule "Free Tetrahedron (14)" quality 100 mappoints (0, 0, 0); (1, 0, 0) { 1.0 }; (0.5, 0.866, 0) { 1.0 }; mapfaces (1, 2, 3) del; newpoints (0.5, 0.288, -0.2) { 0.333 X2, 0.333 X3 } { 0.333 Y3 } { }; newfaces (4, 1, 2); (4, 2, 3); (4, 3, 1); elements (1, 2, 3, 4); freezone (0, 0, 0); (1, 0, 0) { 1 X2 } { } { }; (0.5, 0.866, 0) { 1 X3 } { 1 Y3 } { }; (0.5, 0.288, -0.25) { 0.333 X2, 0.333 X3 } { 0.333 Y3 } { }; endrule rule "Free Tetrahedron (15)" quality 100 mappoints (0, 0, 0); (1, 0, 0) { 1.0 }; (0.5, 0.866, 0) { 1.0 }; mapfaces (1, 2, 3) del; newpoints (0.5, 0.288, -0.1) { 0.333 X2, 0.333 X3 } { 0.333 Y3 } { }; newfaces (4, 1, 2); (4, 2, 3); (4, 3, 1); elements (1, 2, 3, 4); freezone (0, 0, 0); (1, 0, 0) { 1 X2 } { } { }; (0.5, 0.866, 0) { 1 X3 } { 1 Y3 } { }; (0.5, 0.288, -0.15) { 0.333 X2, 0.333 X3 } { 0.333 Y3 } { }; endrule dune-uggrid-2.11.0+dfsg/dune/uggrid/lib/tetra.rls.license000066400000000000000000000002161513616443000231720ustar00rootroot00000000000000SPDX-FileCopyrightInfo: Copyright © DUNE Project contributors, see file LICENSE.md in module root SPDX-License-Identifier: LGPL-2.1-or-later dune-uggrid-2.11.0+dfsg/dune/uggrid/lib/triangle.rls000066400000000000000000000065031513616443000222440ustar00rootroot00000000000000rule "Free Triangle (1)" quality 1 mappoints (0, 0); (1, 0) { 1.0, 0, 1.0 }; maplines (1, 2) del; newpoints (0.5, 0.866) { 0.5 X2 } { }; newlines (1, 3); (3, 2); freearea (0, 0); (1, 0) { 1 X2 } { }; (1.667, 0.577) { 1.667 X2 } { }; (1.667, 2.2) { 1.667 X2 } { }; (-0.667, 2.2) { -0.667 X2 } { }; (-0.667, 0.577) { -0.667 X2 } { }; elements (1, 2, 3); endrule rule "Right 60 (1)" quality 1 mappoints (0, 0); (1, 0) { 0.5, 0, 1.0 }; (0.5, 0.866) { 0.6, 0, 0.8 }; maplines (1, 2) del; (2, 3) del; newpoints newlines (1, 3); freearea (0, 0); (1, 0) { 1 X2 } { }; (0.5, 0.866) { 1 X3 } { 1 Y3 }; (-0.125, 0.6495) { -0.5 X2, 0.75 X3 } { -0.5 Y2, 0.75 Y3 }; elements (1, 2, 3); endrule rule "Left 60 (1)" quality 1 mappoints (0, 0); (1, 0); (0.5, 0.866); maplines (1, 2) del; (3, 1) del; newpoints newlines (3, 2); freearea (0, 0); (1, 0) { 1 X2 } { }; (1.125, 0.6495) { 0.75 X2, 0.75 X3 } { -0.5 Y2, 0.75 Y3 }; (0.5, 0.866) { 1 X3 } { 1 Y3 }; elements (1, 2, 3); endrule rule "Right 120 (1)" quality 1 mappoints (0, 0); (1, 0); (1.5, 0.866); maplines (1, 2) del; (2, 3) del; newpoints (0.5, 0.866) { 1 X3, -1 X2 } { 1 Y3 }; newlines (1, 4); (4, 3); freearea (0, 0); (1, 0) { 1 X2 } { }; (1.5, 0.866) { 1 X3 } { 1 Y3 }; (1, 1.732) { -2 X2, 2 X3 } { 2 Y3 }; (0, 1.732) { -3 X2, 2 X3 } { 2 Y3 }; (-0.5, 0.866) { -2 X2, 1 X3 } {1 Y3 }; elements (1, 2, 4); (2, 3, 4); endrule rule "Left Right 120 (1)" quality 1 mappoints (0, 0); (1, 0); (-0.5, 0.866); (1.5, 0.866); maplines (1, 2) del; (3, 1) del; (2, 4) del; newpoints (0.5, 0.866) { 0.5 X3, 0.5 X4 } { 0.5 Y3, 0.5 Y4 }; newlines (3, 5); (5, 4); freearea (0, 0); (1, 0) { 1 X2 } { }; (1.5, 0.866) { 1 X4 } { 1 Y4 }; (1, 1.299) { -0.5 X2, 0.375 X3, 1.125 X4 } { -0.5 Y2, 0.375 Y3, 1.125 Y4 }; (0, 1.299) { 1.125 X3, 0.375 X4 } { 1.125 Y3, 0.375 Y4 }; (-0.5, 0.866) { 1 X3 } { 1 Y3 }; elements (1, 2, 5); (3, 1, 5); (2, 4, 5); endrule rule "Fill Triangle" quality 1 mappoints (0, 0); (1, 0); (0.5, 0.866); maplines (1, 2) del; (2, 3) del; (3, 1) del; newpoints newlines freearea (0, 0); (1, 0) { 1 X2 } { 1 Y2 }; (0.5, 0.866) { 1 X3 } { 1 Y3 }; elements (1, 2, 3); endrule rule "Vis A Vis (1)" quality 1 mappoints (0, 0); (1, 0); (0.5, 0.866); maplines (1, 2) del; newpoints newlines (1, 3); (3, 2); freearea (0, 0); (1, 0) { 1 X2 } { }; (1.2, 0.693) { 0.8 X2, 0.8 X3 } { 0.8 Y2, 0.8 Y3 }; (0.5, 0.866) { 1 X3 } { 1 Y3 }; (-0.2, 0.693) { -0.6 X2, 0.8 X3 } { -0.6 Y2, 0.8 Y3 }; elements (1, 2, 3); endrule rule "2 h Vis A Vis (1)" quality 1 mappoints (0, 0); (1, 0); (1, 1.732); (0, 1.732); maplines (1, 2) del; (3, 4) del; newpoints (0.5, 0.866) { 0.25 X3, 0.25 X4 } { 0.25 Y2, 0.25 Y3, 0.25 Y4 }; newlines (1, 5); (5, 4); (3, 5); (5, 2); freearea (0, 0); (1, 0) { 1 X2 } { 1 Y2 }; (1.5, 0.866) { 0.75 X2, 0.75 X3, -0.25 X4 } { 0.75 Y2, 0.75 Y3, -0.25 Y4 }; (1, 1.732) { 1 X3 } { 1 Y3 }; (0, 1.732) { 1 X4 } { 1 Y4 }; (-0.5, 0.866) { 0.75 X4, -0.25 X2, -0.25 X3 } { 0.75 Y4, -0.25 Y3 }; elements (1, 2, 5); (3, 4, 5); endrule rule "Right 60 (10)" quality 10 mappoints (0, 0); (1, 0) { 0.5, 0, 1.0 }; (0.5, 0.866) { 0.6, 0, 0.8 }; maplines (1, 2) del; (2, 3) del; newpoints newlines (1, 3); freearea (0, 0); (1, 0) { 1 X2 } { }; (0.5, 0.866) { 1 X3 } { 1 Y3 }; (0.175, 0.4763) { -0.1 X2, 0.55 X3 } { -0.1 Y2, 0.55 Y3 }; elements (1, 2, 3); endrule dune-uggrid-2.11.0+dfsg/dune/uggrid/lib/triangle.rls.license000066400000000000000000000002161513616443000236600ustar00rootroot00000000000000SPDX-FileCopyrightInfo: Copyright © DUNE Project contributors, see file LICENSE.md in module root SPDX-License-Identifier: LGPL-2.1-or-later dune-uggrid-2.11.0+dfsg/dune/uggrid/low/000077500000000000000000000000001513616443000177445ustar00rootroot00000000000000dune-uggrid-2.11.0+dfsg/dune/uggrid/low/CMakeLists.txt000066400000000000000000000007361513616443000225120ustar00rootroot00000000000000# SPDX-FileCopyrightText: Copyright © DUNE Project contributors, see file LICENSE.md in module root # SPDX-License-Identifier: LGPL-2.1-or-later add_subdirectory(test) target_sources(duneuggrid PRIVATE bio.cc debug.cc fifo.cc fileopen.cc heaps.cc initlow.cc misc.cc ugenv.cc) install(FILES architecture.h debug.h dimension.h fileopen.h heaps.h misc.h namespace.h ugenv.h ugtypes.h DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}/dune/uggrid/low) dune-uggrid-2.11.0+dfsg/dune/uggrid/low/architecture.h000066400000000000000000000021051513616443000225750ustar00rootroot00000000000000// -*- tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- // vi: set et ts=4 sw=2 sts=2: // SPDX-FileCopyrightInfo: Copyright © DUNE Project contributors, see file LICENSE.md in module root // SPDX-License-Identifier: LGPL-2.1-or-later /* provides, based on config.h, a consistent interface for system dependent stuff */ #ifndef UG_ARCHITECTURE_H #define UG_ARCHITECTURE_H /* SMALL..: least number s.t. 1 + SMALL../SMALL_FAC != 1 */ #define SMALL_FAC 10 #include constexpr float MAX_F = std::numeric_limits::max(); constexpr float SMALL_F = std::numeric_limits::epsilon() * SMALL_FAC; constexpr float MAX_C = std::numeric_limits::max(); constexpr float SMALL_C = std::numeric_limits::epsilon() * SMALL_FAC; constexpr double MAX_D = std::numeric_limits::max(); constexpr double SMALL_D = std::numeric_limits::epsilon() * SMALL_FAC; /* data alignment of 8 should suffice on all architecture */ /* !!! set after testing? */ #define ALIGNMENT 8 /* power of 2 and >= sizeof(int) ! */ #endif dune-uggrid-2.11.0+dfsg/dune/uggrid/low/bio.cc000066400000000000000000000256001513616443000210270ustar00rootroot00000000000000// SPDX-FileCopyrightText: Copyright © DUNE Project contributors, see file LICENSE.md in module root // SPDX-License-Identifier: LGPL-2.1-or-later // -*- tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- // vi: set et ts=4 sw=2 sts=2: /*! \file bio.c * \ingroup low */ /** \addtogroup low * * @{ */ /****************************************************************************/ /* */ /* File: bio.c */ /* */ /* Purpose: basic input/output */ /* */ /* Author: Klaus Johannsen */ /* Institut fuer Computeranwendungen III */ /* Universitaet Stuttgart */ /* Pfaffenwaldring 27 */ /* 70550 Stuttgart */ /* email: ug@ica3.uni-stuttgart.de */ /* */ /* History: 09.12.96 begin, */ /* */ /* Remarks: */ /* */ /****************************************************************************/ /****************************************************************************/ /* */ /* include files */ /* system include files */ /* application include files */ /* */ /****************************************************************************/ #include #include #include #include "bio.h" USING_UG_NAMESPACE /****************************************************************************/ /* */ /* defines in the following order */ /* */ /* compile time constants defining static data size (i.e. arrays) */ /* other constants */ /* macros */ /* */ /****************************************************************************/ /****************************************************************************/ /* */ /* data structures used in this source file (exported data structures are */ /* in the corresponding include file!) */ /* */ /****************************************************************************/ typedef int (*R_mint_proc)(int n, int *intList); typedef int (*W_mint_proc)(int n, const int *intList); typedef int (*R_mdouble_proc)(int n, double *doubleList); typedef int (*W_mdouble_proc)(int n, const double *doubleList); typedef int (*R_string_proc)(char *string); typedef int (*W_string_proc)(const char *string); /****************************************************************************/ /* */ /* definition of exported global variables */ /* */ /****************************************************************************/ /****************************************************************************/ /* */ /* definition of variables global to this source file only (static!) */ /* */ /****************************************************************************/ /* file */ static FILE *stream; static int n_byte; static fpos_t pos; /* low level read/write functions */ static R_mint_proc Read_mint; static W_mint_proc Write_mint; static R_mdouble_proc Read_mdouble; static W_mdouble_proc Write_mdouble; static R_string_proc Read_string; static W_string_proc Write_string; /****************************************************************************/ /* */ /* forward declarations of functions used before they are defined */ /* */ /****************************************************************************/ /****************************************************************************/ /* */ /* ascii i/o */ /* */ /****************************************************************************/ static int ASCII_Read_mint (int n, int *intList) { int i; for (i=0; i0) { if (fgetc(stream)==EOF) return (1); jump--; } return (0); } /** @} */ dune-uggrid-2.11.0+dfsg/dune/uggrid/low/bio.h000066400000000000000000000123041513616443000206660ustar00rootroot00000000000000// -*- tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- // vi: set et ts=4 sw=2 sts=2: // SPDX-FileCopyrightInfo: Copyright © DUNE Project contributors, see file LICENSE.md in module root // SPDX-License-Identifier: LGPL-2.1-or-later /*! \file bio.h * \ingroup low */ /** \addtogroup low * * @{ */ /****************************************************************************/ /* */ /* File: bio.h */ /* */ /* Purpose: header file for bio.c */ /* */ /* Author: Klaus Johannsen */ /* Institut fuer Computeranwendungen III */ /* Universitaet Stuttgart */ /* Pfaffenwaldring 27 */ /* 70550 Stuttgart */ /* email: ug@ica3.uni-stuttgart.de */ /* */ /* History: 09.12.96 begin */ /* */ /* Remarks: */ /* */ /****************************************************************************/ /****************************************************************************/ /* */ /* auto include mechanism and other include files */ /* */ /****************************************************************************/ #ifndef __BIO__ #define __BIO__ #include #include "namespace.h" START_UG_NAMESPACE /****************************************************************************/ /* */ /* configuration of interface */ /* */ /****************************************************************************/ /****************************************************************************/ /* */ /* defines in the following order */ /* */ /* compile time constants defining static data size (i.e. arrays) */ /* other constants */ /* macros */ /* */ /****************************************************************************/ /* mode of file */ #define BIO_ASCII 1 #define BIO_BIN 2 /****************************************************************************/ /* */ /* data structures exported by the corresponding source file */ /* */ /****************************************************************************/ /****************************************************************************/ /* */ /* definition of exported global variables */ /* */ /****************************************************************************/ /****************************************************************************/ /* */ /* function declarations */ /* */ /****************************************************************************/ /** \ingroup low \brief Hallo Welt! */ int Bio_Initialize (FILE *file, int mode, char rw); int Bio_Read_mint (int n, int *intList); int Bio_Write_mint (int n, int *intList); int Bio_Read_mdouble (int n, double *doubleList); int Bio_Write_mdouble (int n, double *doubleList); int Bio_Read_string (char *string); int Bio_Write_string (const char *string); int Bio_Jump_From (void); int Bio_Jump_To (void); int Bio_Jump (int dojump); END_UG_NAMESPACE /** @} */ #endif dune-uggrid-2.11.0+dfsg/dune/uggrid/low/debug.cc000066400000000000000000000162621513616443000213500ustar00rootroot00000000000000// SPDX-FileCopyrightText: Copyright © DUNE Project contributors, see file LICENSE.md in module root // SPDX-License-Identifier: LGPL-2.1-or-later // -*- tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- // vi: set et ts=4 sw=2 sts=2: /****************************************************************************/ /* */ /* File: debug.c */ /* */ /* Purpose: ug internal debugger functions */ /* */ /* Author: Stefan Lang */ /* Institut fuer Computeranwendungen III */ /* Universitaet Stuttgart */ /* Pfaffenwaldring 27 */ /* 70550 Stuttgart */ /* email: stefan@ica3.uni-stuttgart.de */ /* phone: 0049-(0)711-685-7003 */ /* fax : 0049-(0)711-685-7000 */ /* */ /* History: 10.07.95 begin */ /* */ /* Remarks: */ /* */ /****************************************************************************/ /****************************************************************************/ /* */ /* include files */ /* system include files */ /* application include files */ /* */ /****************************************************************************/ #include #ifdef Debug #define compile_debug #include #include #include #include #include "fileopen.h" #include "debug.h" #include USING_UG_NAMESPACE /****************************************************************************/ /* */ /* defines in the following order */ /* */ /* compile time constants defining static data size (i.e. arrays) */ /* other constants */ /* macros */ /* */ /****************************************************************************/ /****************************************************************************/ /* */ /* data structures used in this source file (exported data structures are */ /* in the corresponding include file!) */ /* */ /****************************************************************************/ /****************************************************************************/ /* */ /* definition of exported global variables */ /* */ /****************************************************************************/ int NS_PREFIX Debuginit = 0; int NS_PREFIX Debugdddif = 0; /* temporary setting for debugging ModelP */ int NS_PREFIX Debugdev = 0; int NS_PREFIX Debugdom = 0; int NS_PREFIX Debuggm = 0; int NS_PREFIX Debuglow = 0; int NS_PREFIX rep_err_count; int NS_PREFIX rep_err_line[REP_ERR_MAX]; const char* NS_PREFIX rep_err_file[REP_ERR_MAX]; /****************************************************************************/ /* */ /* definition of variables global to this source file only (static!) */ /* */ /****************************************************************************/ static PrintfProcPtr printdebug=printf; static FILE *debugfile=NULL; static char *debugfilename; /****************************************************************************/ /* */ /* forward declarations of functions used before they are defined */ /* */ /****************************************************************************/ /****************************************************************************/ /* */ /* Function: PrintDebug */ /* */ /* Purpose: Print debugging information to ugshell or logfile */ /* */ /* Input: arguments are passed to PrintDebug in a printf like manner. */ /* char *format: format, which contains the debugging info */ /* ... : list of arguments for format string */ /* */ /* Output: void */ /* */ /****************************************************************************/ int NS_PREFIX PrintDebug (const char *format, ...) { char buffer[4096]; va_list args; va_start(args,format); vsprintf(buffer,format,args); #ifdef ModelP if (PPIF::me==PPIF::master) { #endif /* use specific debug function for displaying */ (*printdebug)(buffer); WriteLogFile((const char *)buffer); #ifdef ModelP } else { printf(buffer); fflush(stdout); WriteLogFile(buffer); } #endif va_end(args); return (0); } void NS_PREFIX SetPrintDebugProc (PrintfProcPtr print) { printdebug = print; } int NS_PREFIX PrintDebugToFile (const char *format, ...) { va_list args; /* initialize args */ va_start(args,format); vfprintf(debugfile,format,args); fflush(debugfile); /* garbage collection */ va_end(args); return (0); } int NS_PREFIX SetPrintDebugToFile (const char *fname) { if (debugfile!=NULL) return (1); if ((debugfile=fileopen(fname,"w"))==NULL) return (1); debugfilename = strdup(fname); SetPrintDebugProc(PrintDebugToFile); return (0); } int PostprocessDebugFile (const char *newname) { # ifndef ModelP char c; if (debugfile==NULL) return (1); if (debugfilename==NULL) return (1); if (fclose(debugfile)) return (1); if ((debugfile=fileopen(debugfilename,"r"))==NULL) return (1); if ((c=getc(debugfile))==EOF) { /* remove empty file */ if (fclose(debugfile)) return (1); if (remove(debugfilename)) return (1); } else if (newname!=NULL) { /* rename nonemty file */ if (fclose(debugfile)) return (1); remove(newname); if (rename(debugfilename,newname)) return (1); } # endif return (0); } INT PrintRepErrStack (PrintfProcPtr print) { if (rep_err_count==0) print("no errors are reported\n"); else { INT i; print("reported errors are:\n\n"); for (i=0; i #define IFDEBUG(m,n) if (Debug ## m >=(n)) { #define PRINTDEBUG(m,n,s) IFDEBUG(m,n) PrintDebug s; ENDDEBUG #define PRINTDEBUG_EXT(m,n,s) IFDEBUG(m,n) PrintDebug("-" STR(m) "-"); PrintDebug s; ENDDEBUG #define ENDDEBUG } #define RETURN(rcode) {INT rc; rc = rcode; assert(!rc); return (rc);} #define ASSERT(exp) assert(exp) #define REP_ERR_INC {rep_err_line[rep_err_count] = __LINE__; \ rep_err_file[rep_err_count] = this_file; \ rep_err_count = (rep_err_count+1)%REP_ERR_MAX;} #ifdef ModelP #define REP_ERR_RETURN(err) { assert(((err)==0));return (err);} #define REP_ERR_RETURN_PTR(p) { assert(((p)!=NULL));return (p);} #else #define REP_ERR_RETURN(err) { if (err) REP_ERR_INC return (err);} #define REP_ERR_RETURN_PTR(p) { if (p == NULL) REP_ERR_INC return (p);} #endif #define REP_ERR_ENCOUNTERED (rep_err_count) #define REP_ERR_RESET rep_err_count = 0; #else /* Debug */ #define IFDEBUG(m,n) if (1==0) { #define ENDDEBUG } #define PRINTDEBUG(m,n,s) /* no debugging */ #define PRINTDEBUG_EXT(m,n,s) /* no debugging */ #define RETURN(rcode) return (rcode) #define ASSERT(exp) #define REP_ERR_RETURN(err) {return (err);} #define REP_ERR_RETURN_PTR(p) {return (p);} #define REP_ERR_ENCOUNTERED (false) #define REP_ERR_INC #define REP_ERR_RESET #define PrintDebug(...) #endif /* Debug */ START_UG_NAMESPACE /****************************************************************************/ /* */ /* data structures exported by the corresponding source file */ /* */ /****************************************************************************/ typedef int (*PrintfProcPtr)(const char *, ...); /****************************************************************************/ /* */ /* definition of exported global variables */ /* */ /****************************************************************************/ #ifdef Debug extern int Debuginit; extern int Debugdddif; extern int Debugdev; extern int Debuggm; extern int Debuglow; extern int Debugdom; /* for reporting of errors (using the REP_ERR_RETURN-macro) */ extern int rep_err_count; extern int rep_err_line[REP_ERR_MAX]; extern const char *rep_err_file[REP_ERR_MAX]; #endif /****************************************************************************/ /* */ /* function declarations */ /* */ /****************************************************************************/ #ifdef Debug void SetPrintDebugProc (PrintfProcPtr print); int PrintDebug (const char *format, ...); int PrintDebugToFile (const char *format, ...); int SetPrintDebugToFile (const char *fname); int PostprocessDebugFile (const char *newname); INT PrintRepErrStack (PrintfProcPtr print); #endif END_UG_NAMESPACE #endif dune-uggrid-2.11.0+dfsg/dune/uggrid/low/dimension.h000066400000000000000000000013711513616443000221040ustar00rootroot00000000000000// -*- tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- // vi: set et ts=4 sw=2 sts=2: // SPDX-FileCopyrightInfo: Copyright © DUNE Project contributors, see file LICENSE.md in module root // SPDX-License-Identifier: LGPL-2.1-or-later /** \file \brief Provide the usual preprocessor-defines for the dimension and complain if the dimension was set incorrectly. */ #ifndef DIMENSION_H #define DIMENSION_H #ifdef UG_DIM_2 #ifdef UG_DIM_3 #error **** define EITHER dimension UG_DIM_2 OR UG_DIM_3 **** #endif #define DIM 2 #define DIM_OF_BND 1 #endif #ifdef UG_DIM_3 #define DIM 3 #define DIM_OF_BND 2 #endif #ifndef UG_DIM_2 #ifndef UG_DIM_3 #error **** define at least dimension two OR three **** #endif #endif #endif dune-uggrid-2.11.0+dfsg/dune/uggrid/low/fifo.cc000066400000000000000000000141151513616443000212000ustar00rootroot00000000000000// SPDX-FileCopyrightText: Copyright © DUNE Project contributors, see file LICENSE.md in module root // SPDX-License-Identifier: LGPL-2.1-or-later // -*- tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- // vi: set et ts=4 sw=2 sts=2: /** \file \brief Functions to handle a fifo (first in, first out) structure */ /****************************************************************************/ /* */ /* File: fifo.c */ /* */ /* Purpose: general purpose first in first out queue */ /* */ /* Author: Peter Bastian */ /* Interdisziplinaeres Zentrum fuer Wissenschaftliches Rechnen */ /* Universitaet Heidelberg */ /* Im Neuenheimer Feld 368 */ /* 6900 Heidelberg */ /* */ /* History: 30.01.92 begin, ug version 2.0 */ /* */ /* Revision: 07.09.95 */ /* */ /****************************************************************************/ /****************************************************************************/ /* */ /* include files */ /* system include files */ /* application include files */ /* */ /****************************************************************************/ #include #include #include "ugtypes.h" #include "fifo.h" USING_UG_NAMESPACE /****************************************************************************/ /* */ /* definition of variables global to this source file only (static!) */ /* */ /****************************************************************************/ /****************************************************************************/ /** \brief Initialize fifo data structure \param myfifo - pointer to a fifo record \param buffer - pointer to a memory area for the fifo \param size - size of the buffer in bytes This function initializes 'fifo' (first in, first out) data structure. RETURN VALUE: .n size of fifo record .n 0 if size lower or equal to zero */ /****************************************************************************/ INT NS_PREFIX fifo_init (FIFO *myfifo, void *buffer, INT size) { myfifo->size = size / sizeof(void *); if (myfifo->size<=0) return(0); myfifo->elements = (void **) buffer; myfifo->start = myfifo->end = myfifo->used = 0; return(myfifo->size); } /****************************************************************************/ /** \brief Reset a previously initialized FIFO structure \param myfifo - pointer to FIFO structure This function resets a previously initialized FIFO structure. */ /****************************************************************************/ void NS_PREFIX fifo_clear (FIFO *myfifo) { myfifo->start = myfifo->end = myfifo->used = 0; } /****************************************************************************/ /** \brief Test if fifo is empty \param myfifo - pointer to fifo structure This function tests if fifo is empty. RETURN VALUE: .n 0 if fifo is not empty .n 1 if fifo is empty */ /****************************************************************************/ INT NS_PREFIX fifo_empty (const FIFO *myfifo) { if (myfifo->used==0) return(1); else return(0); } /****************************************************************************/ /** \brief Test if fifo is full \param myfifo - pointer to FIFO structure This function tests if fifo is full. RETURN VALUE: .n 0 if fifo is not empty .n 1 if fifo is empty */ /****************************************************************************/ INT NS_PREFIX fifo_full (const FIFO *myfifo) { if (myfifo->used==myfifo->size) return(1); else return(0); } /****************************************************************************/ /** \brief Insert an element in the fifo \param myfifo - pointer to FIFO structure \param newelement - pointer to the new element (any type!) This function inserts an element in the fifo. RETURN VALUE: .n 1 if error occurred. .n 0 if OK */ /****************************************************************************/ INT NS_PREFIX fifo_in (FIFO *myfifo, void *newelement) { if (myfifo->usedsize) { (myfifo->elements)[myfifo->end] = newelement; myfifo->end = (myfifo->end+1)%myfifo->size; myfifo->used++; return(0); } else return(1); } /****************************************************************************/ /** \brief Get an element from the fifo \param myfifo - pointer to fifo structure This function gets an element from the fifo. RETURN VALUE: .n pointer to the element to take out from the fifo .n NULL if fifo is empty */ /****************************************************************************/ void *NS_PREFIX fifo_out (FIFO *myfifo) { INT i; if (myfifo->used==0) return(NULL); else { i = myfifo->start; myfifo->start = (myfifo->start+1)%myfifo->size; myfifo->used--; return (myfifo->elements[i]); } } dune-uggrid-2.11.0+dfsg/dune/uggrid/low/fifo.h000066400000000000000000000064541513616443000210510ustar00rootroot00000000000000// -*- tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- // vi: set et ts=4 sw=2 sts=2: // SPDX-FileCopyrightInfo: Copyright © DUNE Project contributors, see file LICENSE.md in module root // SPDX-License-Identifier: LGPL-2.1-or-later /** \file \brief Header file for general purpose fifo (first in, first out) structure */ /****************************************************************************/ /* */ /* File: fifo.h */ /* */ /* Purpose: header file for general purpose fifo */ /* */ /* Author: Peter Bastian */ /* Interdisziplinaeres Zentrum fuer Wissenschaftliches Rechnen */ /* Universitaet Heidelberg */ /* Im Neuenheimer Feld 368 */ /* 6900 Heidelberg */ /* */ /* History: 30.01.92 begin, ug version 2.0 */ /* */ /* Revision: 07.09.95 */ /* */ /****************************************************************************/ /****************************************************************************/ /* */ /* auto include mechanism and other include files */ /* */ /****************************************************************************/ #ifndef __FIFO__ #define __FIFO__ #include "ugtypes.h" #include "namespace.h" START_UG_NAMESPACE /****************************************************************************/ /* */ /* data structures exported by the corresponding source file */ /* */ /****************************************************************************/ typedef struct { INT start,end,size,used; void **elements; } FIFO ; /****************************************************************************/ /* */ /* function declarations */ /* */ /****************************************************************************/ INT fifo_init (FIFO *myfifo, void *buffer, INT size); void fifo_clear (FIFO *myfifo); INT fifo_empty (const FIFO *myfifo); INT fifo_full (const FIFO *myfifo); INT fifo_in (FIFO *myfifo, void *newelement); void *fifo_out (FIFO *myfifo); END_UG_NAMESPACE #endif dune-uggrid-2.11.0+dfsg/dune/uggrid/low/fileopen.cc000066400000000000000000000725761513616443000220750ustar00rootroot00000000000000// SPDX-FileCopyrightText: Copyright © DUNE Project contributors, see file LICENSE.md in module root // SPDX-License-Identifier: LGPL-2.1-or-later // -*- tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- // vi: set et ts=4 sw=2 sts=2: /****************************************************************************/ /* */ /* File: fileopen.c */ /* */ /* Purpose: definition of a fopen fct. that accepts UNIX-style pathnames */ /* */ /* Author: Henrik Rentz-Reichert */ /* Institut fuer Computeranwendungen III */ /* Universitaet Stuttgart */ /* Pfaffenwaldring 27 */ /* 70569 Stuttgart */ /* email: ug@ica3.uni-stuttgart.de */ /* */ /* History: 02.02.95 new for ug version 3.0 */ /* */ /* Remarks: */ /* */ /****************************************************************************/ /****************************************************************************/ /* */ /* include files */ /* system include files */ /* application include files */ /* */ /****************************************************************************/ /* standard C library */ #include #include #include #include #include #include #include #include "ugtypes.h" /* includes for filesize(), filetype() */ #ifdef __MACINTOSH__ #include #include #include #include #include /* NB: On Macs the structs of are defined locally in */ #else #include #include #endif /* low module */ /* avoid assertion in REP_ERR_RETURN for ModelP and GUI */ #if defined(ModelP) && defined(__GUI__) #define PARALLEL #undef ModelP #endif #include "debug.h" #ifdef PARALLEL #define ModelP #undef PARALLEL #endif #include "ugenv.h" #include #include "fileopen.h" #if defined __HP__ || __SGI__ || __PARAGON__ || __DEC__ || __SUN__ || __PC__ || __LINUXPPC__ #include #endif USING_UG_NAMESPACE /****************************************************************************/ /* */ /* defines in the following order */ /* */ /* compile time constants defining static data size (i.e. arrays) */ /* other constants */ /* macros */ /* */ /****************************************************************************/ #define MAXPATHLENGTH 256 #define MAXPATHS 16 #define MAX_PATH_LEN 1024 #define BASE_PATH_SIZE 512 #ifndef __MACINTOSH__ #define ConvertUNIX_2_MachinePath(fname) fname #define ConvertMachine_2_UNIXPath(fname) fname #endif /****************************************************************************/ /* */ /* data structures used in this source file (exported data structures are */ /* in the corresponding include file!) */ /* */ /****************************************************************************/ typedef char PATH[MAXPATHLENGTH]; typedef struct { /* env item */ ENVVAR v; INT nPaths; /* number of paths stored */ PATH path[1]; /* begin of path list */ } PATHS; /****************************************************************************/ /* */ /* definition of variables global to this source file only (static!) */ /* */ /****************************************************************************/ static INT thePathsDirID; static INT thePathsVarID; static char BasePath[BASE_PATH_SIZE] = "./"; /****************************************************************************/ /* */ /* Function: GetPaths */ /* */ /* Purpose: find the Paths environment item with name */ /* */ /* Input: name of the Paths to find */ /* */ /* Output: PATHS *: pointer to the multigrid struct */ /* NULL: if an error occurred */ /* */ /****************************************************************************/ static PATHS *GetPaths (const char *name) { return ((PATHS *) SearchEnv(name,"/Paths",thePathsVarID,thePathsDirID)); } /****************************************************************************/ /*D ConvertUNIX_2_MachinePath - convert UNIX-style file paths to machine format SYNOPSIS: const char *ConvertUNIX_2_MachinePath (const char *fname) PARAMETERS: . fname - filename with path convention in UNIX-style DESCRIPTION: Convert UNIX-style paths to machine format. If '__MACINTOSH__' is defined (Apple Macintosh computer) the UNIX-sytle path is converted to Macintosh-style. For other platforms 'ConvertUNIX_2_MachinePath' returns 'fname' (macro). RETURN VALUE: char * .n converted file name (NULL if error) D*/ /****************************************************************************/ #ifdef __MACINTOSH__ /* Macintosh computers */ static const char *ConvertUNIX_2_MachinePath (const char *fname) { static char fullpath[MAXPATHLENGTH]; int pos; if (*fname=='/') /* root not defined on Macintosh computers */ return (NULL); if (*fname=='~') /* home directory not defined on Macintosh computers */ return (NULL); /* something to convert? */ if (strchr(fname,'/')==NULL) return (fname); pos = 0; while ((*fname!='\0') && (pos ":" */ fullpath[pos++] = ':'; fname += 2; } else fullpath[pos++] = *(fname++); break; case '/' : /* "/" --> ":" */ fullpath[pos++] = ':'; while (*fname=='/') fname++; break; default : fullpath[pos++] = *(fname++); } if (pos>=MAXPATHLENGTH) /* filename too long */ return (NULL); /* 0-terminate string */ fullpath[pos] = '\0'; return (fullpath); } static const char* ConvertMachine_2_UNIXPath (const char* fname) { static char fullpath[MAXPATHLENGTH]; int pos; /* something to convert? */ if (strchr(fname,':')==NULL) return (fname); pos = 0; while ((*fname!='\0') && (pos=MAXPATHLENGTH) /* filename too long */ return (NULL); /* 0-terminate string */ fullpath[pos] = '\0'; return (fullpath); } #endif const char * NS_PREFIX BasedConvertedFilename (const char *fname) /* NOTE: once a filename has passed through BasedConvertedFilename() it is forbidden to call BasedConvertedFilename() a second time for this filename due to static result string. */ { PRINTDEBUG(low,2,("BasedConvertedFilename: fname= '%s'\n",fname)); if (fname[0]!='/' && fname[0]!='~') /* use BasePath only if no absolute path specified */ { static char based_filename[MAXPATHLENGTH]; assert(fname!=based_filename); /* avoid that the result of a previous call to BasedConvertedFilename() is fed back; in this case the new result would interfere with the given input name and corrupt the result (for example only ./ would be returned)*/ strcpy(based_filename,BasePath); strcat(based_filename,fname); SimplifyPath(based_filename); PRINTDEBUG(low,1,("BasedConvertedFilename: based_filename= '%s'\n",based_filename)); return ConvertUNIX_2_MachinePath(based_filename); } else { PRINTDEBUG(low,1,("BasedConvertedFilename: filename not based= '%s'\n",fname)); return ConvertUNIX_2_MachinePath(fname); } } static int rename_if_necessary( const char *fname, int do_rename) { FILE *f; if (do_rename && (f=fopen(fname,"r"))!=NULL) { time_t Time; struct stat fstat; char new_fname[128]; fclose(f); strcpy(new_fname,fname); strcat(new_fname,"."); if (stat(fname, &fstat)<0) return(1); Time = fstat.st_mtime; strftime(new_fname+strlen(fname)+1,64,"%y%m%d%H%M%S",localtime(&Time)); if (rename(fname,new_fname)!=0) return(1); } return (0); /* ok */ } /****************************************************************************/ /*D mkdir_r - create a directory incl. renaming option SYNOPSIS: int mkdir_r (const char *fname, mode_t mode, int do_rename) PARAMETERS: . fname - directory name with path convention in UNIX-style; may not be passed through BasedConvertedFilename() . mode - creation mode in UNIX-style (see mkdir(2)) . do_rename - if true an already existing subdirectory will be renamed DESCRIPTION: This function creates an directory and renames an already existing one instead of overwriting it if specified. fname may not be passed through BasedConvertedFilename(). RETURN VALUE: int .n 0 successful completion .n != 0 error occurred SEE ALSO: mkdir(2), fopen_r D*/ /****************************************************************************/ int NS_PREFIX mkdir_r (const char *fname, std::filesystem::perms mode, int do_rename) { const char *converted_name = BasedConvertedFilename(fname); std::error_code ec; if (do_rename) { if (rename_if_necessary( converted_name, do_rename)!=0) return (1); if (std::filesystem::create_directory(converted_name, ec)) std::filesystem::permissions(converted_name, mode, ec); } else { switch (filetype(fname)) /* filetype needs an NOT BasedConvertedFilename'ed filename */ { case FT_UNKNOWN : /* file doesn't exist, thus create it */ if (std::filesystem::create_directory(converted_name, ec)) std::filesystem::permissions(converted_name, mode, ec); case FT_DIR : return ec.value(); /* OK, directory exists already */ case FT_FILE : UserWriteF("mkdir_r(): file %s exists already as ordinary file; can't create directory with same name.\n",converted_name); return 1; case FT_LINK : UserWriteF("mkdir_r(): file %s exists already as a link; can't create directory with same name.\n",converted_name); return 1; default : UserWriteF("mkdir_r(): unknown file type %d for file %s\n",filetype(fname),converted_name); return 1; } } return ec.value(); } /****************************************************************************/ /*D fopen_r - create a file incl. renaming option SYNOPSIS: int fopen_r (const char *fname, const char *mode, int do_rename) PARAMETERS: . fname - file name with path convention in UNIX-style . mode - file opening mode in UNIX-style (see fopen(2)) . do_rename - if true an already existing file will be renamed DESCRIPTION: This function opens a file and renames an already existing one instead of overwriting it if specified. RETURN VALUE: int .n 0 successful completion .n != 0 error occurred SEE ALSO: fopen(2), mkdir_r D*/ /****************************************************************************/ FILE * NS_PREFIX fopen_r (const char *fname, const char *mode, int do_rename) { if (rename_if_necessary( fname, do_rename)!=0) return (NULL); return fopen(fname,mode); } /****************************************************************************/ /*D filetype - get type of a file with given name SYNOPSIS: int filetype (const char *fname) PARAMETERS: . fname - filename with path convention in UNIX-style; it may not be passed through BasedConvertedFilename() DESCRIPTION: This function returns the type of the given file or FT_UNKNOWN if an error occurs. fname may not be passed through BasedConvertedFilename(). RETURN VALUE: int .n file type (one of FT_UNKNOWN, FT_FILE, FT_DIR, FT_LINK) SEE ALSO: fopen, fileopen D*/ /****************************************************************************/ int NS_PREFIX filetype (const char *fname) { struct stat fstat; int r; /* get Unix file descriptor */ PRINTDEBUG(low,1,("filetype\n")); if ((r=stat(BasedConvertedFilename(fname), &fstat))<0) return(FT_UNKNOWN); #ifdef __CC__ switch (fstat.st_mode & _S_IFMT) { case _S_IFREG : return FT_FILE; case _S_IFDIR : return FT_DIR; #ifdef S_IFLNK case _S_IFLNK : return FT_LINK; #endif } #else switch (fstat.st_mode & S_IFMT) { case S_IFREG : return FT_FILE; case S_IFDIR : return FT_DIR; #ifdef S_IFLNK case S_IFLNK : return FT_LINK; #endif } #endif return(FT_UNKNOWN); } /****************************************************************************/ /*D ReadSearchingPaths - read searching paths from a defaults file SYNOPSIS: INT ReadSearchingPaths (const char *filename, const char *paths) PARAMETERS: . filename - search paths in a defaults file with this name (most likely to be `the` --> 'defaults' file, use 'DEFAULTSFILENAME') . paths - name of the paths item looked for in a defaults file DESCRIPTION: From a defaultsfile using --> 'GetDefaultValue' the specified paths item is read containing one or more paths sperated by blanks (tab or space). The paths are stored in an environment item with that same name in the environment directory '/Paths'. The function --> 'FileOpenUsingSearchPaths' is looking up the paths to be tried there. RETURN VALUE: INT .n 1: failed to 'GetDefaultValue' .n 2: more than 'MAXPATHS' specified in the defaults file .n 3: failed to 'MakePathsItem' .n 0: ok SEE ALSO: FileOpenUsingSearchPaths D*/ /****************************************************************************/ INT NS_PREFIX ReadSearchingPaths (const char *filename, const char *paths) { return (1); } /****************************************************************************/ /*D DirCreateUsingSearchPaths - create a directory searching in the directories specified in the environment item '/Paths/' SYNOPSIS: int DirCreateUsingSearchPaths (const char *fname, const char *paths); PARAMETERS: . fname - subdirectory name to be created . paths - try paths specified in the environment item '/Paths/' which was set by --> 'ReadSearchingPaths' DESCRIPTION: The functions tries to create a directory with 'filename' using one by one the paths specified in the environment item '/Paths/' which was set by --> 'ReadSearchingPaths'. It is used in several places in ug (all paths are read from the standard --> 'defaults' file)":" .n 'scriptpaths' is used by the interpreter for script execution .n 'gridpaths' is used by ugio to read grids from (they are stored in the .n first path RETURN VALUE: int .n 0 successful completion .n != 0 error occurred SEE ALSO: DirCreateUsingSearchPaths_r, mkdir(2) D*/ /****************************************************************************/ int NS_PREFIX DirCreateUsingSearchPaths (const char *fname, const char *paths) { return DirCreateUsingSearchPaths_r ( fname, paths, false); /* no renaming */ } /****************************************************************************/ /*D DirCreateUsingSearchPaths_r - create a subdirectory searching in the directories specified in the environment item '/Paths/' incl. renaming option SYNOPSIS: int DirCreateUsingSearchPaths (const char *fname, const char *paths, int rename); PARAMETERS: . fname - subdirectory name to be created . paths - try paths specified in the environment item '/Paths/' which was set by --> 'ReadSearchingPaths' . rename - if true an already existing subdirectory will be renamed DESCRIPTION: The functions tries to create a subdirectory with 'filename' using one by one the paths specified in the environment item '/Paths/' which was set by --> 'ReadSearchingPaths'. It is used in several places in ug (all paths are read from the standard --> 'defaults' file)":" .n 'srciptpaths' is used by the interpreter for script execution .n 'gridpaths' is used by ugio to read grids from (they are stored in the .n first path RETURN VALUE: int .n 0 successful completion .n != 0 error occurred SEE ALSO: DirCreateUsingSearchPaths, mkdir(2) D*/ /****************************************************************************/ int NS_PREFIX DirCreateUsingSearchPaths_r (const char *fname, const char *paths, int rename) { INT fnamelen = strlen(fname); using perms = std::filesystem::perms; perms mode = perms::owner_write | perms::owner_read | perms::owner_exec | perms::group_read | perms::group_exec; PRINTDEBUG(low,1,("DirCreateUsingSearchPaths\n")); if (paths == nullptr) { if (mkdir_r(fname, mode, rename) != 0) return (1); return (0); } const PATHS *thePaths = GetPaths(paths); if (thePaths == nullptr) return (1); for (INT i = 0; i < thePaths->nPaths; i++) { /* test whether parent directory exists */ FILE *parentDir = fopen(thePaths->path[i],"r"); if (parentDir == nullptr) continue; /* this parent directory doesn't exist; try the next one */ if (fclose(parentDir) != 0) return (1); if (strlen(thePaths->path[i])+fnamelen>MAXPATHLENGTH) return (1); char fullname[MAXPATHLENGTH]; strcpy(fullname,thePaths->path[i]); strcat(fullname,fname); if (mkdir_r(fullname,mode,rename) != 0) return (1); return (0); /* subdirectory created successfully */ } return (1); } /****************************************************************************/ /*D FileOpenUsingSearchPaths - open file searching in the directories specified in the environment item '/Paths/' SYNOPSIS: FILE *FileOpenUsingSearchPaths (const char *fname, const char *mode, const char *paths) PARAMETERS: . fname - file name to be opened . mode - see ANSI-C 'fopen' . paths - try paths specified in the environment item '/Paths/' which was set by --> 'ReadSearchingPaths' DESCRIPTION: The functions tries to open the file with 'filename' using one by one the paths specified in the environment item '/Paths/' which was set by --> 'ReadSearchingPaths'. It is used in several places in ug (all paths are read from the standard --> 'defaults' file)":" .n 'srciptpaths' is used by the interpreter for script execution .n 'gridpaths' is used by ugio to read grids from (they are stored in the .n first path RETURN VALUE: FILE * .n pointer to file opened, 'NULL' if error SEE ALSO: FileOpenUsingSearchPaths_r, FileOpenUsingSearchPath, FileOpenUsingSearchPath_r, GetPaths, ReadSearchingPaths, fileopen D*/ /****************************************************************************/ FILE * NS_PREFIX FileOpenUsingSearchPaths (const char *fname, const char *mode, const char *paths) { return FileOpenUsingSearchPaths_r( fname, mode, paths, false ); /* no renaming */ } /****************************************************************************/ /*D FileOpenUsingSearchPaths_r - open file searching in the directories specified in the environment item '/Paths/' incl. renaming option SYNOPSIS: FILE *FileOpenUsingSearchPaths_r (const char *fname, const char *mode, const char *paths, int rename) PARAMETERS: . fname - file name to be opened . mode - see ANSI-C 'fopen' . paths - try paths specified in the environment item '/Paths/' which was set by --> 'ReadSearchingPaths' . rename - if true an already existing file will be renamed (wise only for writing) DESCRIPTION: The functions tries to open the file with 'filename' using one by one the paths specified in the environment item '/Paths/' which was set by --> 'ReadSearchingPaths'. It is used in several places in ug (all paths are read from the standard --> 'defaults' file)":" .n 'srciptpaths' is used by the interpreter for script execution .n 'gridpaths' is used by ugio to read grids from (they are stored in the .n first path RETURN VALUE: FILE * .n pointer to file opened, 'NULL' if error SEE ALSO: FileOpenUsingSearchPaths, FileOpenUsingSearchPath, FileOpenUsingSearchPath_r, GetPaths, ReadSearchingPaths, fileopen D*/ /****************************************************************************/ FILE * NS_PREFIX FileOpenUsingSearchPaths_r (const char *fname, const char *mode, const char *paths, int rename) { INT fnamelen = strlen(fname); const PATHS *thePaths = GetPaths(paths); if (thePaths == nullptr) return nullptr; for (INT i = 0; i < thePaths->nPaths; i++) { if (strlen(thePaths->path[i])+fnamelen>MAXPATHLENGTH) return nullptr; char fullname[MAXPATHLENGTH]; strcpy(fullname,thePaths->path[i]); strcat(fullname,fname); FILE *theFile = fileopen_r(fullname,mode,rename); if (theFile != nullptr) return theFile; } return nullptr; } /****************************************************************************/ /*D FileOpenUsingSearchPath - try to open a file in the specified path SYNOPSIS: FILE *FileOpenUsingSearchPath (const char *fname, const char *mode, const char *path) PARAMETERS: . fname - open file with this name . mode - see ANSI-C 'fopen' . path - path to which fname is to be appended DESCRIPTION: Try to open a file in the specified path. RETURN VALUE: FILE * .n pointer to file opened, 'NULL' if error SEE ALSO: FileOpenUsingSearchPath_r, FileOpenUsingSearchPaths, FileOpenUsingSearchPaths_r, fileopen D*/ /****************************************************************************/ FILE * NS_PREFIX FileOpenUsingSearchPath (const char *fname, const char *mode, const char *path) { return FileOpenUsingSearchPath_r( fname, mode, path, false ); /* no renaming */ } /****************************************************************************/ /*D FileOpenUsingSearchPath_r - try to open a file in the specified path and renaming option SYNOPSIS: FILE *FileOpenUsingSearchPath_r (const char *fname, const char *mode, const char *path, int rename) PARAMETERS: . fname - open file with this name . mode - see ANSI-C 'fopen' . path - path to which fname is to be appended . rename - if true an already existing file will be renamed (wise only for writing) DESCRIPTION: Try to open a file in the specified path. RETURN VALUE: FILE * .n pointer to file opened, 'NULL' if error SEE ALSO: FileOpenUsingSearchPath, FileOpenUsingSearchPaths, FileOpenUsingSearchPaths_r, fileopen D*/ /****************************************************************************/ FILE * NS_PREFIX FileOpenUsingSearchPath_r (const char *fname, const char *mode, const char *path, int rename) { FILE *theFile; char fullname[MAXPATHLENGTH]; if (strlen(path)+strlen(fname)>MAXPATHLENGTH) return (NULL); strcpy(fullname,path); strcat(fullname,fname); if ((theFile=fileopen_r(fullname,mode,rename))!=NULL) return (theFile); return (NULL); } /****************************************************************************/ /*D FileTypeUsingSearchPaths - give type of file searching in the directories specified in the environment item '/Paths/' SYNOPSIS: int FileTypeUsingSearchPaths (const char *fname, const char *paths) PARAMETERS: . fname - file name to be opened . paths - try paths specified in the environment item '/Paths/' which was set by --> 'ReadSearchingPaths' DESCRIPTION: The functions tries to determine the file type of the file named 'filename' using one by one the paths specified in the environment item '/Paths/' which was set by --> 'ReadSearchingPaths'. It is used in several places in ug (all paths are read from the standard --> 'defaults' file)":" .n 'srciptpaths' is used by the interpreter for script execution .n 'gridpaths' is used by ugio to read grids from (they are stored in the .n first path) RETURN VALUE: int .n file type (one of FT_UNKNOWN, FT_FILE, FT_DIR, FT_LINK) SEE ALSO: ReadSearchingPaths, filetype D*/ /****************************************************************************/ int NS_PREFIX FileTypeUsingSearchPaths (const char *fname, const char *paths) { INT fnamelen = strlen(fname); const PATHS *thePaths = GetPaths(paths); if (thePaths == nullptr) return (FT_UNKNOWN); for (INT i = 0; i < thePaths->nPaths; i++) { if (strlen(thePaths->path[i])+fnamelen>MAXPATHLENGTH) return (FT_UNKNOWN); char fullname[MAXPATHLENGTH]; strcpy(fullname,thePaths->path[i]); strcat(fullname,fname); int ftype = filetype(fullname); if (ftype != FT_UNKNOWN) return (ftype); } return (FT_UNKNOWN); } bool NS_PREFIX AppendTrailingSlash (char *path) { if (path[0]!='\0' && path[strlen(path)-1]!='/') { strcat(path,"/"); return true; } return false; } char * NS_PREFIX SimplifyPath (char *path) { const char *pf; char *pt; PRINTDEBUG(low,2,("SimplifyPath: original path= '%s'\n",path)); /* cancel ./ (not first one) */ pf = pt = strchr(path,'/'); if (pf!=NULL) { while (*pf) { if (pf[0]=='.' && pf[1]=='/') if (*(pf-1)=='/') { /* eat ./ */ pf += 2; continue; } if (pt!=pf) *pt = *pf; pf++; pt++; } *pt = '\0'; } PRINTDEBUG(low,2,("SimplifyPath: path= '%s'\n",path)); /* cancel ../ where possible */ pf = pt = path; for (; *pf; pf++,pt++) { if (pf[0]=='.' && pf[1]=='.' && pf[2]=='/') if (pf==path || *(pf-1)=='/') { char *pd = pt-1; while (pd>path) if (*(--pd)=='/') break; if (*pd=='/' && !(pd[0]=='/' && pd[1]=='.' && pd[2]=='.' && pd[3]=='/')) { /* eat ../ and reset pt */ pf += 2; pt = pd; continue; } } *pt = *pf; } *pt = '\0'; return path; } /****************************************************************************/ /*D InitFileOpen - init 'fileopen.c' SYNOPSIS: INT InitFileOpen () PARAMETERS: -- DESCRIPTION: An environment directory '/Paths' is created where the paths read by 'ReadSearchingPaths' are stored. RETURN VALUE: INT .n __LINE__: could not create '/Paths' .n 0: ok D*/ /****************************************************************************/ INT NS_PREFIX InitFileOpen () { /* install the /Paths directory */ if (ChangeEnvDir("/")==NULL) return(__LINE__); thePathsDirID = GetNewEnvDirID(); if (MakeEnvItem("Paths",thePathsDirID,sizeof(ENVDIR))==NULL) return(__LINE__); thePathsVarID = GetNewEnvVarID(); return (0); } dune-uggrid-2.11.0+dfsg/dune/uggrid/low/fileopen.h000066400000000000000000000165431513616443000217270ustar00rootroot00000000000000// -*- tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- // vi: set et ts=4 sw=2 sts=2: // SPDX-FileCopyrightInfo: Copyright © DUNE Project contributors, see file LICENSE.md in module root // SPDX-License-Identifier: LGPL-2.1-or-later /****************************************************************************/ /* */ /* File: fileopen.h */ /* */ /* Author: Henrik Rentz-Reichert */ /* Institut fuer Computeranwendungen III */ /* Universitaet Stuttgart */ /* Pfaffenwaldring 27 */ /* 70569 Stuttgart */ /* email: ug@ica3.uni-stuttgart.de */ /* */ /* History: 13.02.95 begin, ug version 3.0 */ /* */ /* Remarks: */ /* */ /****************************************************************************/ /****************************************************************************/ /* */ /* auto include mechanism and other include files */ /* */ /****************************************************************************/ #ifndef __FILEOPEN__ #define __FILEOPEN__ #include #include #include #include "ugtypes.h" #include "namespace.h" START_UG_NAMESPACE /****************************************************************************/ /* */ /* defines in the following order */ /* */ /* compile time constants defining static data size (i.e. arrays) */ /* other constants */ /* macros */ /* */ /****************************************************************************/ /* return constants for filetype() */ enum FileTypes { FT_UNKNOWN, FT_FILE, FT_DIR, FT_LINK }; #define fileopen(fname,mode) fopen_r(BasedConvertedFilename(fname),(mode),0) #define fileopen_r(fname,mode,r) fopen_r(BasedConvertedFilename(fname),(mode),(r)) /****************************************************************************/ /* */ /* data structures exported by the corresponding source file */ /* */ /****************************************************************************/ /****************************************************************************/ /* */ /* definition of exported global variables */ /* */ /****************************************************************************/ /****************************************************************************/ /* */ /* function declarations */ /* */ /****************************************************************************/ const char* BasedConvertedFilename (const char *fname); int filetype (const char *fname); INT ReadSearchingPaths (const char *filename, const char *pathsvar); int DirCreateUsingSearchPaths (const char *fname, const char *paths); int DirCreateUsingSearchPaths_r (const char *fname, const char *paths, int rename); FILE *FileOpenUsingSearchPaths (const char *fname, const char *mode, const char *pathsvar); FILE *FileOpenUsingSearchPaths_r (const char *fname, const char *mode, const char *pathsvar, int rename); FILE *FileOpenUsingSearchPath (const char *fname, const char *mode, const char *path); FILE *FileOpenUsingSearchPath_r (const char *fname, const char *mode, const char *path, int rename); int FileTypeUsingSearchPaths (const char *fname, const char *pathsvar); FILE *fopen_r (const char *fname, const char *mode, int do_rename); int mkdir_r (const char *fname, std::filesystem::perms mode, int do_rename); bool AppendTrailingSlash (char *path); char* SimplifyPath (char *path); INT InitFileOpen (void); END_UG_NAMESPACE #endif dune-uggrid-2.11.0+dfsg/dune/uggrid/low/heaps.cc000066400000000000000000000222041513616443000213530ustar00rootroot00000000000000// SPDX-FileCopyrightText: Copyright © DUNE Project contributors, see file LICENSE.md in module root // SPDX-License-Identifier: LGPL-2.1-or-later // -*- tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- // vi: set et ts=4 sw=2 sts=2: /****************************************************************************/ /* */ /* File: heaps.c */ /* */ /* Purpose: low-level memory management for ug 2.0 */ /* */ /* Author: Peter Bastian/Henrik Rentz-Reichert */ /* Institut fuer Computeranwendungen III */ /* Universitaet Stuttgart */ /* Pfaffenwaldring 27 */ /* 70569 Stuttgart */ /* email: ug@ica3.uni-stuttgart.de */ /* */ /* History: 29.01.92 begin, ug version 2.0 */ /* 02.02.95 begin, ug version 3.0 */ /* */ /* Revision: 04.09.95 */ /* */ /****************************************************************************/ /****************************************************************************/ /* */ /* include files in the order */ /* system include files */ /* application include files */ /* */ /****************************************************************************/ #include #include #include #include #include #include #include "ugtypes.h" #include "architecture.h" #include "heaps.h" #include "misc.h" #include "debug.h" #include #include "namespace.h" USING_UG_NAMESPACE /****************************************************************************/ /* */ /* defines in the following order */ /* */ /* compile time constants defining static data size (i.e. arrays) */ /* other constants */ /* macros */ /* */ /****************************************************************************/ /****************************************************************************/ /** \brief Install a new heap structure \param type - type of heap \param size - size of new heap in bytes \param buffer - 4-aligned memory for the heap This function installs a new heap structure. Valid 'type' is either 'SIMPLE_HEAP' or 'GENERAL_HEAP'. The allocation of memory starts at the address given by '*buffer' and is of 'size' bytes. \return
    • pointer to HEAP
    • NULL if not enough space available
    */ /****************************************************************************/ HEAP *NS_PREFIX NewHeap (enum HeapType type, MEM size, void *buffer) { HEAP *theHeap; /* check size */ if (buffer==NULL) return(NULL); if (sizetype = type; theHeap->size = size; theHeap->markKey = 0; /* No constructor is ever called for theHeap. Consequently, no constructor * has been called for its member markedMemory, either. Here we force this * constructor call using placement new. */ new(theHeap->markedMemory) std::vector[MARK_STACK_SIZE+1]; /* return heap structure */ return(theHeap); } /****************************************************************************/ /** \brief Clean up and deallocate a heap structure \param theHeap The heap to be deallocated This method properly cleans up a HEAP data structure, and then frees the memory. */ /****************************************************************************/ void NS_PREFIX DisposeHeap (HEAP *theHeap) { if (theHeap != NULL) { /* When using the system heap, the HEAP data structure contains an array of * std::vectors, which have all be created using placement new. Therefore, * before freeing the memory of a HEAP we have to call the destructors of * these std::vectors explicitly. Otherwise we get memory leaks. */ using namespace std; for (INT i=0; imarkedMemory[i].~vector(); free(theHeap); } } /****************************************************************************/ /** \brief Allocate memory from heap \param theHeap - heap structure which manages memory allocation \param n - number of bytes to allocate this function now only forwards to `malloc`. */ void *NS_PREFIX GetMem (HEAP *theHeap, MEM n) { return malloc(n); } /****************************************************************************/ /** \brief Allocate memory and register it for rollback \param theHeap - heap structure which manages memory allocation \param n - number of bytes to allocate \param key - key with which we can identify the rollback record this function allocates memory on the heap and tags it with the `key`. */ void *NS_PREFIX GetTmpMem (HEAP *theHeap, MEM n, INT key) { if (theHeap->type==SIMPLE_HEAP) { ASSERT(key == theHeap->markKey); /* we have to keep track of allocated memory, in order to do a proper rollback */ void* ptr = GetMem(theHeap,n); theHeap->markedMemory[key].push_back(ptr); return theHeap->markedMemory[key].back(); } /* no key for GENERAL_HEAP */ return (GetMem(theHeap,n)); } /****************************************************************************/ /** \brief Free memory previously allocated from that heap \param theHeap - heap structure which manages memory allocation \param buffer - memory area previously allocated This function creates free memory previously allocated from that heap. */ /****************************************************************************/ void NS_PREFIX DisposeMem (HEAP *theHeap, void *buffer) { free(buffer); } /****************************************************************************/ /** \copydoc Allocate memory from heap \param theHeap - heap structure which manages memory allocation \param size - number of bytes to allocate \note the allocated memory is initialized to zero \return pointer to an object of the requested size */ /****************************************************************************/ void *NS_PREFIX GetFreelistMemory (HEAP *theHeap, INT size) { void* obj = malloc(size); if (obj != NULL) memset(obj,0,size); return(obj); } /****************************************************************************/ /** \brief Mark heap position for future release \param theHeap - heap to mark This function marks heap position for future release. Only valid in the 'SIMPLE_HEAP' type. \return
    • 0 if OK
    • 1 if mark stack full or wrong heap type
    */ /****************************************************************************/ INT NS_PREFIX MarkTmpMem (HEAP *theHeap, INT *key) { assert(theHeap->type==SIMPLE_HEAP); if (theHeap->type!=SIMPLE_HEAP) return(1); if(theHeap->markKey >= MARK_STACK_SIZE) return 1; theHeap->markKey++; *key = theHeap->markKey; return 0; } /****************************************************************************/ /** \brief Release to next stack position \param theHeap - heap to release This function releases to the next stack position. Only valid in the 'SIMPLE_HEAP' type. \return
    • 0 if OK
    • 1 if mark stack empty or wrong heap type.
    */ /****************************************************************************/ INT NS_PREFIX ReleaseTmpMem (HEAP *theHeap, INT key) { if (theHeap->type!=SIMPLE_HEAP) return 1; if (theHeap->markKey == 0) return 0; if (key > theHeap->markKey) return 1; /* Free all memory associated to 'key' */ for (void* ptr : theHeap->markedMemory[key]) free(ptr); theHeap->markedMemory[key].resize(0); if (key < theHeap->markKey) return 2; while (theHeap->markKey > 0 && theHeap->markedMemory[theHeap->markKey].size() == 0) theHeap->markKey--; return 0; } dune-uggrid-2.11.0+dfsg/dune/uggrid/low/heaps.h000066400000000000000000000140471513616443000212230ustar00rootroot00000000000000// -*- tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- // vi: set et ts=4 sw=2 sts=2: // SPDX-FileCopyrightInfo: Copyright © DUNE Project contributors, see file LICENSE.md in module root // SPDX-License-Identifier: LGPL-2.1-or-later /*! \file heaps.h * \ingroup low */ /** \addtogroup low * * @{ */ /****************************************************************************/ /* */ /* File: heaps.h */ /* */ /* Purpose: low-level memory management for ug */ /* */ /* Author: Peter Bastian */ /* Interdisziplinaeres Zentrum fuer Wissenschaftliches Rechnen */ /* Universitaet Heidelberg */ /* Im Neuenheimer Feld 368 */ /* 6900 Heidelberg */ /* */ /* History: 29.01.92 begin, ug version 2.0 */ /* */ /* Revision: 04.09.95 */ /* */ /****************************************************************************/ /****************************************************************************/ /* */ /* auto include mechanism and other include files */ /* */ /****************************************************************************/ #ifndef __HEAPS__ #define __HEAPS__ #include #include "ugtypes.h" #include "namespace.h" START_UG_NAMESPACE /****************************************************************************/ /* */ /* defines in the following order */ /* */ /* compile time constants defining static data size (i.e. arrays) */ /* other constants */ /* macros */ /* */ /****************************************************************************/ /****************************************************************************/ /* defines for the simple and general heap management */ /****************************************************************************/ /** \brief Smallest heap to allocate */ #define MIN_HEAP_SIZE 256 /** \brief Max depth of mark/release calls */ #define MARK_STACK_SIZE 128 enum HeapType {GENERAL_HEAP, /**< Heap with alloc/free mechanism */ SIMPLE_HEAP /**< Heap with mark/release mechanism*/ }; /****************************************************************************/ /****************************************************************************/ /** @name Defines and macros for the virtual heap management */ /** \brief That many blocks can be allocated */ #define MAXNBLOCKS 50 /** \brief Pass to init routine if no heap yet */ #define SIZE_UNKNOWN 0 /** \brief Ok return code for virtual heap mgmt*/ #define BHM_OK 0 /** \brief Return codes of DefineBlock */ enum {HEAP_FULL = 1, /**< Return code if storage exhausted */ BLOCK_DEFINED = 2, /**< Return code if block already defined*/ NO_FREE_BLOCK = 3 /**< Return code if no free block found */ }; /* return codes of FreeBlock */ /** \brief Return code if the block is not defined */ #define BLOCK_NOT_DEFINED 1 /* @} */ /****************************************************************************/ /* */ /* data structures exported by the corresponding source file */ /* */ /****************************************************************************/ typedef unsigned long MEM; /****************************************************************************/ /* structs and typedefs for the simple and general heap management */ /****************************************************************************/ typedef struct { enum HeapType type; MEM size; INT markKey; std::vector markedMemory[MARK_STACK_SIZE+1]; } HEAP; /****************************************************************************/ /* */ /* function declarations */ /* */ /****************************************************************************/ /** @name Functions for the simple and general heap management */ /* @{ */ HEAP *NewHeap (enum HeapType type, MEM size, void *buffer); void DisposeHeap (HEAP *theHeap); void *GetMem (HEAP *theHeap, MEM n); void *GetFreelistMemory (HEAP *theHeap, INT size); void DisposeMem (HEAP *theHeap, void *buffer); INT MarkTmpMem (HEAP *theHeap, INT *key); void *GetTmpMem (HEAP *theHeap, MEM n, INT key); INT ReleaseTmpMem (HEAP *theHeap, INT key); /* @} */ END_UG_NAMESPACE /** @} */ #endif dune-uggrid-2.11.0+dfsg/dune/uggrid/low/initlow.cc000066400000000000000000000102471513616443000217440ustar00rootroot00000000000000// SPDX-FileCopyrightText: Copyright © DUNE Project contributors, see file LICENSE.md in module root // SPDX-License-Identifier: LGPL-2.1-or-later // -*- tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- // vi: set et ts=4 sw=2 sts=2: /*! \file initlow.c * \ingroup low */ /** \addtogroup low * * @{ */ /****************************************************************************/ /* */ /* File: initlow.c */ /* */ /* Purpose: call the init routines of the low module */ /* */ /* Author: Henrik Rentz-Reichert */ /* Institut fuer Computeranwendungen III */ /* Universitaet Stuttgart */ /* Pfaffenwaldring 27 */ /* 70569 Stuttgart */ /* email: ug@ica3.uni-stuttgart.de */ /* */ /* History: 27.02.95 begin, ug version 3.0 */ /* */ /* Remarks: */ /* */ /****************************************************************************/ /****************************************************************************/ /* */ /* include files */ /* system include files */ /* application include files */ /* */ /****************************************************************************/ /* ANSI-C includes */ #include #include /* low module */ #include "ugtypes.h" #include "misc.h" #include "heaps.h" #include "ugenv.h" #include "fileopen.h" /* own header */ #include "initlow.h" USING_UG_NAMESPACE /****************************************************************************/ /* */ /* definition of variables global to this source file only (static!) */ /* */ /****************************************************************************/ #ifdef ModelP #define DEFAULTENVSIZE 512000 /* size of environment if no default value */ #else #define DEFAULTENVSIZE 128000 /* size of environment if no default value */ #endif /****************************************************************************/ /** \brief Call the inits for the low module * * This function calls the inits for the low module. * * @return
      *
    • 0 if ok
    • *
    • 1 if error occurred
    • *
    */ /****************************************************************************/ INT NS_PREFIX InitLow () { INT err; /* init ugenv.c */ if ((err=InitUgEnv())!=0) { SetHiWrd(err,__LINE__); return (err); } /* init fileopen */ if ((err=InitFileOpen())!=0) { SetHiWrd(err,__LINE__); return (err); } return (0); } /****************************************************************************/ /** \brief Call the exits for the low module * * This function calls the exit methods for the low module. * * @return
      *
    • 0 if ok
    • *
    • 1 if error occurred
    • *
    */ /****************************************************************************/ INT NS_PREFIX ExitLow () { INT err; /* exit env */ if ((err=ExitUgEnv())!=0) { SetHiWrd(err,__LINE__); return (err); } return (0); } /** @} */ dune-uggrid-2.11.0+dfsg/dune/uggrid/low/initlow.h000066400000000000000000000045241513616443000216070ustar00rootroot00000000000000// -*- tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- // vi: set et ts=4 sw=2 sts=2: // SPDX-FileCopyrightInfo: Copyright © DUNE Project contributors, see file LICENSE.md in module root // SPDX-License-Identifier: LGPL-2.1-or-later /** \defgroup low Low-Level Stuff * \ingroup ug * * * @{ * */ /** * \file initlow.h */ /****************************************************************************/ /* */ /* File: initlow.h */ /* */ /* Purpose: call the init routines of the low module (header file) */ /* */ /* Author: Henrik Rentz-Reichert */ /* Institut fuer Computeranwendungen III */ /* Universitaet Stuttgart */ /* Pfaffenwaldring 27 */ /* 70569 Stuttgart */ /* email: ug@ica3.uni-stuttgart.de */ /* */ /* History: 27.02.95 begin, ug version 3.0 */ /* */ /* Remarks: */ /* */ /****************************************************************************/ #ifndef __INITLOW__ #define __INITLOW__ #include "ugtypes.h" #include "namespace.h" START_UG_NAMESPACE /****************************************************************************/ /* */ /* function declarations */ /* */ /****************************************************************************/ /** \brief Initialisation of the low module */ INT InitLow (void); INT ExitLow(); END_UG_NAMESPACE /** @} */ #endif dune-uggrid-2.11.0+dfsg/dune/uggrid/low/misc.cc000066400000000000000000000215741513616443000212170ustar00rootroot00000000000000// SPDX-FileCopyrightText: Copyright © DUNE Project contributors, see file LICENSE.md in module root // SPDX-License-Identifier: LGPL-2.1-or-later // -*- tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- // vi: set et ts=4 sw=2 sts=2: /****************************************************************************/ /* */ /* File: misc.c */ /* */ /* Purpose: miscellaneous routines */ /* */ /* Author: Klaus Johannsen */ /* Institut fuer Computeranwendungen */ /* Universitaet Stuttgart */ /* Pfaffenwaldring 27 */ /* 70569 Stuttgart */ /* internet: ug@ica3.uni-stuttgart.de */ /* */ /* History: 08.12.94 begin, ug3-version */ /* */ /* Revision: 07.09.95 */ /* */ /****************************************************************************/ /****************************************************************************/ /* */ /* include files */ /* system include files */ /* application include files */ /* */ /****************************************************************************/ #include #include #include #include #include #include #include #include #include #include "ugtypes.h" #include "architecture.h" #include "misc.h" #include "heaps.h" USING_UG_NAMESPACE /****************************************************************************/ /* */ /* defines in the following order */ /* */ /* compile time constants defining static data size (i.e. arrays) */ /* other constants */ /* macros */ /* */ /****************************************************************************/ /****************************************************************************/ /* */ /* data structures used in this source file (exported data structures are */ /* in the corresponding include file!) */ /* */ /****************************************************************************/ /****************************************************************************/ /* */ /* definition of exported global variables */ /* */ /****************************************************************************/ #ifndef ModelP int PPIF::me = 0; /* to have in the serial case this variable as a dummy */ int PPIF::master = 0; /* to have in the serial case this variable as a dummy */ int PPIF::procs = 1; /* to have in the serial case this variable as a dummy */ int NS_PREFIX _proclist_ = -1; /* to have in the serial case this variable as a dummy */ int NS_PREFIX _partition_ = 0; /* to have in the serial case this variable as a dummy */ #endif /****************************************************************************/ /****************************************************************************/ /****************************************************************************/ /**** ****/ /**** general routines ****/ /**** ****/ /****************************************************************************/ /****************************************************************************/ /****************************************************************************/ #define FMTBUFFSIZE 1031 static char newfmt[FMTBUFFSIZE]; /****************************************************************************/ /** \brief Expand (make explicit) charset-ranges in scanf This function expands (make explicit) charset-ranges in scanf. For example '%[...a-d...]' --> '%[...abcd...]'. \return .n new pointer to char */ /****************************************************************************/ char * NS_PREFIX expandfmt (const char *fmt) { const char *pos; char *newpos; char leftchar,rightchar; int newlen; /* calculate min size of newfmt */ newlen = strlen(fmt); assert (newlen[ */ while (*pos!='\0') { /* copy til '%' */ while (*pos!='%' && *pos!='\0') *(newpos++) = *(pos++); if (*pos=='\0') break; *(newpos++) = *(pos++); /* copy til !isdigit */ while (isdigit(*pos) && *pos!='\0') *(newpos++) = *(pos++); if (*pos=='\0') break; if (*pos!='[') continue; *(newpos++) = *(pos++); /* ']' following '[' is included in the charset */ if ((*pos)==']') *(newpos++) = *(pos++); /* '^]' following '[' is included in the charset */ else if ((*pos)=='^' && (*(pos+1))==']') { *(newpos++) = *(pos++); *(newpos++) = *(pos++); } while (*pos!=']' && *pos!='\0') { /* now we are inside the charset '[...]': */ /* treat character ranges indicated by '-' */ while (*pos!='-' && *pos!=']' && *pos!='\0') *(newpos++) = *(pos++); if (*pos=='\0') break; if ((*pos)==']') continue; /* gotya: is left char < right char? */ leftchar = *(pos-1); rightchar = *(pos+1); if (leftchar=='[' || rightchar==']') { *(newpos++) = *(pos++); continue; } if (leftchar>=rightchar) { *(newpos++) = *(pos++); continue; } if (leftchar+1==rightchar) { /* for example '...b-c...' */ pos++; continue; } /* calc new size and expand range */ newlen += rightchar-leftchar-2; assert (newlen #include "heaps.h" #include "namespace.h" START_UG_NAMESPACE /****************************************************************************/ /* */ /* defines in the following order */ /* */ /* compile time constants defining static data size (i.e. arrays) */ /* other constants */ /* macros */ /* */ /****************************************************************************/ /* cleanup old definitions of macros */ #define POW2(i) (1<<(i)) #define SET_FLAG(flag,bitpattern) (flag |= (bitpattern)) #define CLEAR_FLAG(flag,bitpattern) (flag &= ~(bitpattern)) #define READ_FLAG(flag,bitpattern) ((flag & (bitpattern))>0) #define HiWrd(aLong) (((aLong) >> 16) & 0xFFFF) #define LoWrd(aLong) ((aLong) & 0xFFFF) #define SetHiWrd(aLong,n) aLong = (((n)&0xFFFF)<<16)|((aLong)&0xFFFF) #define SetLoWrd(aLong,n) aLong = ((n)&0xFFFF)|((aLong)&0xFFFF0000) /* concatenation macros for preprocessor */ #define XCAT(a,b) a ## b #define XCAT3(a,b,c) a ## b ## c #define CAT(a,b) XCAT(a,b) #define CAT3(a,b,c) XCAT3(a,b,c) /* expand macro and transfer expanded to string */ #define XSTR(s) # s #define STR(s) XSTR(s) /****************************************************************************/ /* */ /* definition of exported global variables */ /* */ /****************************************************************************/ #ifndef ModelP END_UG_NAMESPACE namespace PPIF { extern int me; /* to have in the serial case this variable as a dummy */ extern int master; /* to have in the serial case this variable as a dummy */ extern int procs; /* to have in the serial case this variable as a dummy */ } /* end namespace PPIF */ START_UG_NAMESPACE extern int _proclist_; /* to have in the serial case this variable as a dummy*/ extern int _partition_; /* to have in the serial case this variable as a dummy*/ #endif /****************************************************************************/ /* */ /* function declarations */ /* */ /****************************************************************************/ /* general routines */ char *expandfmt (const char *fmt); const char *strntok (const char *str, const char *sep, int n, char *token); END_UG_NAMESPACE #endif dune-uggrid-2.11.0+dfsg/dune/uggrid/low/namespace.h000066400000000000000000000041061513616443000220520ustar00rootroot00000000000000// -*- tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- // vi: set et ts=4 sw=2 sts=2: // SPDX-FileCopyrightInfo: Copyright © DUNE Project contributors, see file LICENSE.md in module root // SPDX-License-Identifier: LGPL-2.1-or-later /** \file Defines macros to put symbols into namespaces if C++ compiler is used. Everything is put into the namespace Dune::UG, dimension-dependent functions into Dune::UG::D2 or Dune::UG::D3 in a header-files use: #include "namespace.h" START_UG_NAMESPACE ... END_UG_NAMESPACE for stuff that is independent of the space dimension or #include "namespace.h" START_UGDIM_NAMESPACE ... END_UGDIM_NAMESPACE else. In the implementation: #include "namespace.h" // of course USING_UG_NAMESPACE // for stuff from the namespace UG or USING_UGDIM_NAMESPACE // for stuff from UG::D3 resp. UG::D2 Write int NS_PREFIX function(...) { ... }; if function is declared in UG and int NS_DIM_PREFIX function(...) { ... }; if it is declared in a namespace with dimension. */ #ifndef UG_NAMESPACE_H #define UG_NAMESPACE_H #define START_UG_NAMESPACE namespace Dune::UG { #define END_UG_NAMESPACE } #define END_UGDIM_NAMESPACE }} #define NS_PREFIX Dune::UG:: #define USING_UG_NAMESPACE using namespace Dune::UG; #ifdef UG_DIM_3 #define START_UGDIM_NAMESPACE namespace Dune::UG { namespace D3 { #define USING_UGDIM_NAMESPACE using namespace Dune::UG::D3; #define USING_UG_NAMESPACES namespace Dune::UG {namespace D3 {} } using namespace Dune::UG; using namespace Dune::UG::D3; #define NS_DIM_PREFIX Dune::UG::D3:: #else #define START_UGDIM_NAMESPACE namespace Dune::UG { namespace D2 { #define USING_UGDIM_NAMESPACE using namespace Dune::UG::D2; #define USING_UG_NAMESPACES namespace Dune::UG {namespace D2 {} } using namespace Dune::UG; using namespace Dune::UG::D2; #define NS_DIM_PREFIX Dune::UG::D2:: #endif /* check if the required symbols exist */ #if !defined(NS_PREFIX) || !defined(START_UG_NAMESPACE) || !defined(END_UG_NAMESPACE) # error missing symbol! #endif #endif dune-uggrid-2.11.0+dfsg/dune/uggrid/low/test/000077500000000000000000000000001513616443000207235ustar00rootroot00000000000000dune-uggrid-2.11.0+dfsg/dune/uggrid/low/test/CMakeLists.txt000066400000000000000000000003371513616443000234660ustar00rootroot00000000000000# SPDX-FileCopyrightText: Copyright © DUNE Project contributors, see file LICENSE.md in module root # SPDX-License-Identifier: LGPL-2.1-or-later dune_add_test(SOURCES test-fifo.cc LINK_LIBRARIES duneuggrid) dune-uggrid-2.11.0+dfsg/dune/uggrid/low/test/test-fifo.cc000066400000000000000000000045611513616443000231400ustar00rootroot00000000000000// SPDX-FileCopyrightText: Copyright © DUNE Project contributors, see file LICENSE.md in module root // SPDX-License-Identifier: LGPL-2.1-or-later #include "config.h" #include #include #include "../fifo.h" using namespace Dune; TestSuite test_fifo() { TestSuite test; using namespace UG; FIFO fifo; const INT size = 32; int items[size]; for (int i = 0; i < size; ++i) items[i] = i; auto buffer = std::make_unique(size); { const auto result = fifo_init(&fifo, buffer.get(), size * sizeof(void*)); test.require(result, "require that fifo_init() succeeds"); } test.check(fifo_empty(&fifo), "New FIFO must be empty"); test.check(!fifo_full(&fifo), "New FIFO must not be full"); test.check(fifo_out(&fifo) == nullptr, "New FIFO must not return an element"); { const auto result = fifo_in(&fifo, &items[0]); test.check(!result, "Inserting an element must succeed"); } test.check(!fifo_empty(&fifo), "FIFO must not be empty after inserting an element"); test.check(!fifo_full(&fifo), "FIFO must not be full after inserting an element"); { const auto v = static_cast(fifo_out(&fifo)); test.check(v == &items[0], "FIFO must return the item inserted before"); } test.check(fifo_empty(&fifo), "FIFO must be empty after removing the element again"); test.check(!fifo_full(&fifo), "FIFO must not be full after removing the element again"); for (auto& item : items) { bool result = fifo_in(&fifo, &item); test.check(!result, "Inserting elements must succeed"); } test.check(!fifo_empty(&fifo), "FIFO must not be empty after filling it"); test.check(fifo_full(&fifo), "FIFO must be full after filling it"); { bool result = fifo_in(&fifo, &items[0]); test.check(result, "Inserting into a full FIFO must fail"); } for (auto& item : items) { const auto v = static_cast(fifo_out(&fifo)); test.check(v == &item, "FIFO must return correct item"); } test.check(fifo_empty(&fifo), "FIFO must be empty after removing all elements"); test.check(!fifo_full(&fifo), "FIFO must not be full after removing all elements"); test.check(fifo_out(&fifo) == nullptr, "fifo_out() must return nullptr after removing all elements"); fifo_clear(&fifo); return test; } int main() { TestSuite test; test.subTest(test_fifo()); return test.exit(); } dune-uggrid-2.11.0+dfsg/dune/uggrid/low/ugenv.cc000066400000000000000000000443031513616443000214030ustar00rootroot00000000000000// SPDX-FileCopyrightText: Copyright © DUNE Project contributors, see file LICENSE.md in module root // SPDX-License-Identifier: LGPL-2.1-or-later // -*- tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- // vi: set et ts=4 sw=2 sts=2: /****************************************************************************/ /* */ /* File: ugenv.c */ /* */ /* Purpose: implements the ug environment mechanism */ /* */ /* Author: Peter Bastian */ /* Interdisziplinaeres Zentrum fuer Wissenschaftliches Rechnen */ /* Universitaet Heidelberg */ /* Im Neuenheimer Feld 368 */ /* 6900 Heidelberg */ /* */ /* History: 18.02.92 begin, ug version 2.0 */ /* */ /* Revision: 08.09.95 */ /* */ /****************************************************************************/ /****************************************************************************/ /* */ /* include files */ /* system include files */ /* application include files */ /* */ /****************************************************************************/ #include #include #include #include #include #include "ugtypes.h" #include "heaps.h" #include "misc.h" #include "ugenv.h" /** \todo this is a hierarchy conflict, remove. (VR) */ #include USING_UG_NAMESPACE /****************************************************************************/ /* */ /* defines in the following order */ /* */ /* compile time constants defining static data size (i.e. arrays) */ /* other constants */ /* macros */ /* */ /****************************************************************************/ #define MAXENVPATH 32 /* max depth of the environment tree*/ /****************************************************************************/ /* */ /* definition of variables global to this source file only (static!) */ /* */ /****************************************************************************/ /** \brief Path to current directory We only need the first entry to be zero-initialized. */ static std::array path{nullptr}; static int pathIndex; /* entry to path array */ /****************************************************************************/ /** \brief Initialize the Environment and the heap * @param heapSize - size of the heap in bytes This function initializes the Environment and the heap. @return
      *
    • 0 if OK *
    • '__LINE__' if not enough memory, error in initializing or allocating a heap structure
    */ /****************************************************************************/ INT NS_PREFIX InitUgEnv () { ENVDIR *root; /* Environment heap already initialized? */ if (path[0]) return 0; /* allocate root directory */ if ((root=(ENVDIR*)malloc(sizeof(ENVDIR)))==NULL) return(__LINE__); root->type = ROOT_DIR; root->next = root->previous = root->down = NULL; strcpy(root->name,"root"); /* set path[0] */ pathIndex = 0; path[0] = root; /* return ok */ return(0); } /****************************************************************************/ /** \brief Change environment directory This function changes environment directory. @return
      *
    • pointer to new environment directory
    • *
    • NULL if directory not found.
    */ /****************************************************************************/ ENVDIR * NS_PREFIX ChangeEnvDir (const char *s) { std::array newPath; ENVDIR *theDir; INT i,k,len; char token[NAMESIZE]; if (s==NULL) return (NULL); /* avoid trivial case */ if ((len=strlen(s))==0) return(NULL); /* check max possible length */ if (len>=MAXENVPATH*NAMESIZE) return (NULL); /* look at first character */ if (strncmp(s,DIRSEP,1)==0) { /* start from root directory */ newPath[0] = path[0]; i = 0; } else { /* start from current directory */ for (k=0; k<=pathIndex; k++) newPath[k] = path[k]; i = pathIndex; } /* loop through input string */ do { if ((s = strntok(s,DIRSEP,NAMELEN,token))==NULL) return (NULL); if (*token=='\0') continue; /* process token */ if (strcmp(token,"..")==0) { /* one level up */ if (i>0) i--; } else { /* find subdirectory */ if (i+1>=MAXENVPATH) return(NULL); /* path too long */ theDir = (ENVDIR *) newPath[i]->down; /* search next level*/ while (theDir!=NULL) { if (theDir->type%2==1) /* is type odd ? */ { if (strcmp(token,theDir->name)==0) /* name equal ? */ break; /* directory found */ } theDir = (ENVDIR *) theDir->next; } if (theDir==NULL) return(NULL); /* not found error */ newPath[++i] = theDir; /* extend path */ } } while (*s!='\0'); /* path found, copy to current path */ for (k=0; k<=i; k++) path[k] = newPath[k]; /* copy path */ pathIndex = i; /* return current directory */ return(path[pathIndex]); } /****************************************************************************/ /** \brief GetCurrentDir - Get current environment directory @return
    • pointer to current environment directory
    */ /****************************************************************************/ ENVDIR * NS_PREFIX GetCurrentDir () { return(path[pathIndex]); } /****************************************************************************/ /** \brief Assemble pathname of current directory @param s - pointer to buffer for the string */ /****************************************************************************/ void NS_PREFIX GetPathName (char *s) { int i; strcpy(s,DIRSEP); for (i=1; i<=pathIndex; i++) { strcat(s,path[i]->name); strcat(s,DIRSEP); } } /****************************************************************************/ /** \brief Allocate a new environment item in the current directory * * @param name - name of the new item * @param type - type of item (5 types possible) * @param size - size of item in bytes * * This function allocates a new environment item in the current directory. * * @return
      *
    • pointer to new item *
    • NULL if name too long or already in use, type equal to 'ROOT_DIR', not enough memory *
    • in the environment heap or other error occurs.
    */ /****************************************************************************/ ENVITEM * NS_PREFIX MakeEnvItem (const char *name, const INT type, const INT size) { ENVITEM *newItem,*lastItem; ENVDIR *currentDir; /* check if name too long */ if (strlen(name)+1>NAMESIZE) return(NULL); /* check if name not already used in this directory */ currentDir = path[pathIndex]; lastItem = currentDir->down; #ifdef Debug for (ENVITEM* anItem = lastItem; anItem != nullptr; anItem = anItem->v.next) { if ((anItem->v.type==type)&&(strcmp(anItem->v.name,name)==0)) { UserWriteF("MakeEnvItem(): item '%s' already defined\n",anItem->v.name); return(NULL); } lastItem = anItem; } #endif /* allocate memory from environment heap */ switch (type) { case ROOT_DIR : return(NULL); default : if (type%2==0) { /* new variable */ newItem=(ENVITEM*) malloc(size); if (newItem==NULL) { UserWriteF("MakeEnvItem(): envHeap out of memory\n"); return(NULL); } memset(newItem,0,size); } else { /* new directory */ if (pathIndex+1>=MAXENVPATH) return(NULL); newItem=(ENVITEM*) malloc(size); if (newItem==NULL) { UserWriteF("MakeEnvItem(): envHeap out of memory\n"); return(NULL); } memset(newItem,0,size); newItem->d.down = NULL; } break; } /* initialize item */ newItem->v.type = type; newItem->v.locked = 1; strcpy(newItem->v.name,name); /* put in list */ if (lastItem==NULL) { /* directory is empty */ currentDir->down = newItem; newItem->v.next = newItem->v.previous = NULL; } else { /* insert before first item */ newItem->v.previous = NULL; currentDir->down->v.previous = newItem; newItem->v.next = currentDir->down; currentDir->down = newItem; } /* return pointer to new item */ return(newItem); } /****************************************************************************/ /** \brief Deallocate an environment item in the current directory @param theItem - pointer to item This function deallocates an environment item in the current directory. Directories may only be deleted if they are empty. @return
      *
    • 0 if OK *
    • 1 if item not found in current directory *
    • 2 if attempt is done to delete non empty directory *
    • 3 if attempt is done to delete locked item.
    */ /****************************************************************************/ INT NS_PREFIX RemoveEnvItem (ENVITEM *theItem) { ENVITEM *anItem; ENVDIR *currentDir; /* check if item is in current directory */ currentDir = path[pathIndex]; anItem = currentDir->down; while (anItem!=NULL) { if (anItem==theItem) break; anItem = anItem->v.next; } if (anItem==NULL) return(1); /* check if item is allowed to be deleted */ if (theItem->v.locked) return(3); if ((theItem->v.type%2==1)&&(theItem->d.down!=NULL)) return(2); /* remove item from double linked list */ if (theItem->v.previous==NULL) currentDir->down = theItem->v.next; else theItem->v.previous->v.next = theItem->v.next; if (theItem->v.next!=NULL) theItem->v.next->v.previous = theItem->v.previous; /* deallocate memory */ free(theItem); /* return ok */ return(0); } static INT RemoveEnvDirContent (ENVITEM *theItem) { ENVITEM *Item,*Next; for (Item = theItem; Item != NULL; Item = Next) { Next = NEXT_ENVITEM(Item); if (IS_ENVDIR(Item)) RemoveEnvDirContent(ENVITEM_DOWN(Item)); free(Item); } return(0); } /****************************************************************************/ /** \brief Deallocate an environment directory * @param theItem - pointer to item This function deallocates an environment directory. @return
    • 0 if OK
    • 1 if item not found in current directory
    • 2 if theItem is not a directory
    • 3 if attempt is done to delete locked item
    */ /****************************************************************************/ INT NS_PREFIX RemoveEnvDir (ENVITEM *theItem) { ENVITEM *anItem; ENVDIR *currentDir; /* check if item is in current directory */ currentDir = path[pathIndex]; anItem = currentDir->down; while (anItem!=NULL) { if (anItem==theItem) break; anItem = anItem->v.next; } if (anItem==NULL) return(1); if (!IS_ENVDIR(theItem)) return(2); if (theItem->v.locked) return(3); RemoveEnvDirContent(ENVITEM_DOWN(theItem)); /* remove item from double linked list */ if (theItem->v.previous==NULL) currentDir->down = theItem->v.next; else theItem->v.previous->v.next = theItem->v.next; if (theItem->v.next!=NULL) theItem->v.next->v.previous = theItem->v.previous; /* deallocate memory */ free(theItem); return(0); } /****************************************************************************/ /** \brief Move an environment item in the tree structure * @param item - pointer to item * @param old - directory containing the item * @param new - directory to which item has to be moved (if NULL move to root) This function moves an environment item (or subtree) in the tree structure. @return
      *
    • 0 if OK
    */ /****************************************************************************/ INT NS_PREFIX MoveEnvItem (ENVITEM *item, ENVDIR *oldDir, ENVDIR *newDir) { ENVITEM *anItem; if (newDir==NULL) newDir = path[0]; for (anItem=ENVDIR_DOWN(oldDir); anItem!=NULL; anItem=NEXT_ENVITEM(anItem)) if (anItem==item) break; if (anItem==NULL) return(1); /* remove from old directory */ if (PREV_ENVITEM(item)!=NULL) NEXT_ENVITEM(PREV_ENVITEM(item)) = NEXT_ENVITEM(item); else ENVDIR_DOWN(oldDir) = NEXT_ENVITEM(item); if (NEXT_ENVITEM(item)!=NULL) PREV_ENVITEM(NEXT_ENVITEM(item)) = PREV_ENVITEM(item); /* insert in new directory */ PREV_ENVITEM(item) = NULL; NEXT_ENVITEM(item) = ENVDIR_DOWN(newDir); ENVDIR_DOWN(newDir) = item; return (0); } /****************************************************************************/ /** \brief Search for a given name in the tree * @param name - name of item searched for * @param type - one of the five basic types * @param dirtype - directory type to scan or SEARCHALL This function searches a given name in the tree, sets current directory to directory of the item found and returns the item. @return
      *
    • pointer to the item in the tree *
    • NULL if name not found or where not OK.
    */ /****************************************************************************/ static ENVITEM *SearchTree (const char *name, INT type, INT dirtype) { ENVDIR *currentDir; ENVITEM *theItem,*result; currentDir = path[pathIndex]; /* first loop in current directory */ theItem = currentDir->down; while (theItem!=NULL) { if (theItem->v.type == type) if (strcmp(theItem->v.name,name)==0) return(theItem); theItem = theItem->v.next; } /* try recursive search */ theItem = currentDir->down; while (theItem!=NULL) { if (theItem->v.type%2 == 1) { /* this is a directory */ if ((theItem->d.type==dirtype)||(dirtype==SEARCHALL)) { path[++pathIndex] = (ENVDIR *) theItem; if ((result=SearchTree(name,type,dirtype))!=NULL) return(result); pathIndex--; } } theItem = theItem->v.next; } /* return not found */ return(NULL); } /****************************************************************************/ /** \brief Search for a given name in the tree * * @param name - name of item searched for * @param type - one of the five basic types * @param where - path to directory where recursive search starts * @param dirtype - directory type to scan or SEARCHALL * * This function searches a given name in the tree, sets current directory * to directory of the item found and returns the item. * * @return
    • pointer to item in the tree
    • NULL if name not found or where not OK.
    */ /****************************************************************************/ ENVITEM * NS_PREFIX SearchEnv (const char *name, const char *where, INT type, INT dirtype) { /* check if search directory is changed */ if (strcmp(where,".")!=0) if (ChangeEnvDir(where)==NULL) return(NULL); /* recursive search */ return(SearchTree(name,type,dirtype)); } /****************************************************************************/ /** \brief For backward compatibility: Print size and used of environment heap to string * @param s - string to print on This function used to print size and used percentage of the environment heap to a string. Ever since the operating system heap is used this information is not available anymore. */ /****************************************************************************/ void NS_PREFIX EnvHeapInfo (char *s) { sprintf(s,"no heap information available\n"); } /****************************************************************************/ /** \brief Return a unique 'ID' for a new 'ENVDIR' type This function returns a unique 'ID' for a new 'ENVDIR' type. @return 'ID' for the new 'ENVDIR' */ /****************************************************************************/ INT NS_PREFIX GetNewEnvDirID (void) { /* NB: ENVDIRs have odd types and start with 1 */ static INT theNewEnvDirID = 1; theNewEnvDirID += 2; return (theNewEnvDirID); } /****************************************************************************/ /** \brief Return a unique 'ID' for a new 'ENVVAR' type This function returns a unique 'ID' for a new 'ENVVAR' type. @return 'ID' for the new 'ENVVAR' */ /****************************************************************************/ INT NS_PREFIX GetNewEnvVarID () { /* NB: ENVVARs have even types and start with 2 */ static INT theNewEnvVarID = 0; theNewEnvVarID += 2; return (theNewEnvVarID); } INT NS_PREFIX ExitUgEnv() { RemoveEnvDirContent((ENVITEM*)path[0]); path[0] = NULL; return 0; } dune-uggrid-2.11.0+dfsg/dune/uggrid/low/ugenv.h000066400000000000000000000207011513616443000212410ustar00rootroot00000000000000// -*- tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- // vi: set et ts=4 sw=2 sts=2: // SPDX-FileCopyrightInfo: Copyright © DUNE Project contributors, see file LICENSE.md in module root // SPDX-License-Identifier: LGPL-2.1-or-later /****************************************************************************/ /* */ /* File: ugenv.h */ /* */ /* Purpose: header file for ug environment manager */ /* */ /* Author: Peter Bastian */ /* Interdisziplinaeres Zentrum fuer Wissenschaftliches Rechnen */ /* Universitaet Heidelberg */ /* Im Neuenheimer Feld 368 */ /* 6900 Heidelberg */ /* */ /* History: 06.02.92 begin, ug version 2.0 */ /* */ /* Revision: 08.09.95 */ /* */ /****************************************************************************/ /** \file \brief General data management concept in a tree structure The environment management of ug provides the possibility to store data in a tree structure. The data structures of the environment allow to create directories and items of specified size. Both data structures start with a general head (among others a name by which one can refer to it). The remaining memory up to the specified size can be used in arbitrary way. The head is identical with the struct ENVVAR. All items are members of doubly linked lists. The data structure for the directory ENVDIR has just an extra component to the start of a list which is the directory contents (and can consist of directories itself, of course). The tree starts with a root directory "/" and there is always a current or working directory. Paths are specified in UNIX-style. The current directory can be changed using 'ChangeEnvDir' while 'GetCurrentDir' returns a pointer to the current directory. The routine 'MakeEnvItem' creates the specified item in the current directory and it is possible to 'RemoveEnvItem's created previously. Finally 'SearchEnv' offers the possibility to hierarchically search the environment tree for an item specified by its name. */ /****************************************************************************/ /* */ /* auto include mechanism and other include files */ /* */ /****************************************************************************/ #ifndef __UGENV__ #define __UGENV__ #include "ugtypes.h" #include "namespace.h" START_UG_NAMESPACE /*****************************************************************************/ /* */ /* defines in the following order */ /* */ /* compile time constants defining static data size (i.e. arrays) */ /* other constants */ /* macros */ /* */ /*****************************************************************************/ /* CAUTION: when changing NAMESIZE also change scanf sizes!!! */ enum {NAMESIZE = 128}; /* max length of name string */ enum {NAMELEN = 127}; /* NAMESIZE-1 */ #define NAMELENSTR "127" /* NAMESIZE-1 as string */ enum {SEARCHALL = -1}; /*!< Scan through all directories */ #define DIRSEP "/" /* character separating directories */ /* directories with odd numbers */ #define ROOT_DIR 1 /* indicates root directory */ /** \brief Return pointer to the first 'ENVITEM' contained in the directory. */ #define ENVITEM_DOWN(p) (((ENVITEM *)(p))->d.down) /** \brief Return pointer to the first 'ENVDIR' contained in the directory. */ #define ENVDIR_DOWN(p) ((p)->down) /** \brief Return pointer to the next 'ENVITEM' in the doubly linked list */ #define NEXT_ENVITEM(p) (((ENVITEM *)(p))->v.next) /** \brief Return pointer to the previous 'ENVITEM' in the doubly linked list. */ #define PREV_ENVITEM(p) (((ENVITEM *)(p))->v.previous) /** \brief Return the type of the 'ENVITEM' (odd: 'ENVDIR', even: 'ENVVAR'). */ #define ENVITEM_TYPE(p) (((ENVITEM *)(p))->v.type) #define IS_ENVDIR(p) (ENVITEM_TYPE(p)%2==1) /** \brief This macro returns a pointer to the name string of the 'ENVITEM'. */ #define ENVITEM_NAME(p) (((ENVITEM *)(p))->v.name) /** \brief 'RemoveEnvItem' checks this and returns an error if true. */ #define ENVITEM_LOCKED(p) (((ENVITEM *)(p))->v.locked) /****************************************************************************/ /* */ /* data structures exported by the corresponding source file */ /* */ /****************************************************************************/ /** \brief User-defined variable */ typedef struct { /** \brief even number by GetNewEnvVarID */ INT type; /** \brief May not be changed or deleted */ INT locked; /** \brief Doubly linked list of environment items */ union envitem *next; union envitem *previous; /** \brief Name of that item. May be longer, but of no interest for env*/ char name[NAMESIZE]; } ENVVAR; /** \brief Directory */ typedef struct { /** \brief odd number by GetNewEnvDirID */ INT type; /** \brief May not be changed or deleted */ INT locked; /** \brief Doubly linked list of environment items */ union envitem *next; union envitem *previous; /** \brief Name of that item */ char name[NAMESIZE]; /** \brief One level down in the tree */ union envitem *down; } ENVDIR; union envitem { ENVVAR v; ENVDIR d; }; typedef union envitem ENVITEM; /****************************************************************************/ /* */ /* function declarations */ /* */ /****************************************************************************/ /* initialize environment */ INT InitUgEnv (); /* Free all memory allocated for the environment */ INT ExitUgEnv(); /* change directory allows /, .., etc */ ENVDIR *ChangeEnvDir (const char *s); /* get the current working directory */ ENVDIR *GetCurrentDir (void); /* get path name of the current directory */ void GetPathName (char *s); /* create a new environment item with user defined size */ ENVITEM *MakeEnvItem (const char *name, const INT type, const INT size); /* remove an item */ INT RemoveEnvItem (ENVITEM *theItem); /* remove an complete directory */ INT RemoveEnvDir (ENVITEM *theItem); /* move an envitem to a new directory */ INT MoveEnvItem (ENVITEM *item, ENVDIR *oldDir, ENVDIR *newDir); /* search the environment for an item */ ENVITEM *SearchEnv (const char *name, const char *where, INT type, INT dirtype); /* print used and size of environment heap */ void EnvHeapInfo (char *s); /* return a unique ID for a new ENVDIR/ENVVAR type */ INT GetNewEnvDirID (void); INT GetNewEnvVarID (void); END_UG_NAMESPACE #endif dune-uggrid-2.11.0+dfsg/dune/uggrid/low/ugtypes.h000066400000000000000000000015421513616443000216170ustar00rootroot00000000000000// -*- tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- // vi: set et ts=4 sw=2 sts=2: // SPDX-FileCopyrightInfo: Copyright © DUNE Project contributors, see file LICENSE.md in module root // SPDX-License-Identifier: LGPL-2.1-or-later /** \file \brief Globally set data types The basic types (normally 'short', 'int', 'float' and 'double') are replaced by 'SHORT', 'INT', 'FLOAT' and 'DOUBLE'. The type 'DOUBLE' is used for all Cartesian coordinates of the (x,y[,z])-directions of the grids. */ #ifndef UGTYPES_H #define UGTYPES_H #include "namespace.h" START_UG_NAMESPACE /* standard types */ typedef short SHORT; /* these types are used for several bitfields. I'd guess that it needs at least 32 bits... */ typedef int INT; typedef unsigned int UINT; typedef float FLOAT; typedef double DOUBLE; END_UG_NAMESPACE #endif dune-uggrid-2.11.0+dfsg/dune/uggrid/parallel/000077500000000000000000000000001513616443000207375ustar00rootroot00000000000000dune-uggrid-2.11.0+dfsg/dune/uggrid/parallel/CMakeLists.txt000066400000000000000000000003721513616443000235010ustar00rootroot00000000000000# SPDX-FileCopyrightText: Copyright © DUNE Project contributors, see file LICENSE.md in module root # SPDX-License-Identifier: LGPL-2.1-or-later add_subdirectory(ddd) add_subdirectory(ppif) if(UG_ENABLE_PARALLEL) add_subdirectory(dddif) endif() dune-uggrid-2.11.0+dfsg/dune/uggrid/parallel/ddd/000077500000000000000000000000001513616443000214725ustar00rootroot00000000000000dune-uggrid-2.11.0+dfsg/dune/uggrid/parallel/ddd/CHANGES000066400000000000000000001125411513616443000224710ustar00rootroot00000000000000 --------------------------- CHANGES 1.8.25 -> 1.9 --------------------------- 990211 kb added some memory checks and initialization routines. - due to C.Wieners, some neuralgic parts of the code have been equipped with assert and memset calls in order to find possible serious application bugs easier in future. - GetIFMem in if/ifuse.c. - NewCoupling in mgr/cplmgr.c. --------------------------- CHANGES 1.8.24 -> 1.8.25 --------------------------- 990202 kb fixed bug which lead to PrioBegin/End error. - the std-interface was not sorted correctly, because of invalid initialization of the CPLDIR-flags. This is fixed now. - added some debug info in prio/pcmds.c --------------------------- CHANGES 1.8.23 -> 1.8.24 --------------------------- 980922 kb new option OPT_CPLMGR_USE_FREELIST. - if this option is set to OPT_ON (default), the Coupling-Manager will allocate all COUPLING-structs in segmented lists with freelist management. For applications which use a simple malloc- style MemMgr interface, this will lead to more performance due to allocation of larger blocks and avoidance of many malloc/free operations. If the application itself implements a powerful memory management, this option could be turned to OPT_OFF. Then, each COUPLING struct is allocated/freed separately. --------------------------- CHANGES 1.8.22 -> 1.8.23 --------------------------- 980909 kb new DDD module 'Prio'. - when using the Xfer-module just for changing the priorities of distributed objects, a lot of communication and computation overhead is generated, which is not necessary due to the lack of information propagation. - the new Prio-environment provides two functions DDD_PrioBegin()/DDD_PrioEnd() for starting and ending a Prio-environment and a third function DDD_PrioChange() for issuing PrioChange-commands. - this environment is able to communicate the changed priorities directly via communication using the standard interface. 980720 kb Renumbered error codes in TypeMgr. - this update serves as a preparation for a more solid error code numbering scheme with well-documented errors. This is the beginning. 980707 kb DDD_XferEnd will try to recover. - using the exception-capability of DDD_Notify, XferEnd will try to give up if it cannot allocate necessary resources (most of all, memory allocation). If a certain point of-no-return hasn't been reached in the course of the Xfer-operation, the distributed algorithm is able to shutdown safely without changing the DDD data structures. This might be used to recover from a low-memory situation by speculative XferEnds. 980707 kb DDD_Notify has exception-capability. - during the global communication in Notify, each processor may initiate a global exception message instead of taking part in a normal Notify-operation. The DDD_Notify() call won't return the number of receive messages for the local processors, but will return the largest exception number instead (with changed sign). 980706 kb memory-intensive DDD functions can return success codes now. - NOTE: the API has changed! DDD_XferEnd, DDD_JoinEnd and DDD_IdentifyEnd are returning a DDD_RET code now. - in future versions DDD will become more robust in terms of memory shortage. Up to now, the functions mentioned above are throwing corefiles on memory shortage, this will be replaced by returning DDD_RET_ERROR_NOMEM. --------------------------- CHANGES 1.8.21 -> 1.8.22 --------------------------- 980702 kb reduced overall memory requirements. - DDD_PROC is now an 'unsigned short'. - Xfer-Unpack needs less memory due to casting of PRIO and ATTR values to char in NewCpl-structures. --------------------------- CHANGES 1.8.20 -> 1.8.21 --------------------------- 980527 kb bugfix in Ident memory handling. --------------------------- CHANGES 1.8.19 -> 1.8.20 --------------------------- 980525 kb changed memory handling in Ident. - similar to changes in Xfer module for ddd-1.8.18, the Identify-module memory management has been revised. Memory allocation and freeing may now be done more specifically. --------------------------- CHANGES 1.8.18 -> 1.8.19 --------------------------- 980519 kb bugfix in memory handling. - the send-message buffers during ConsCheck where allocated from a wrong source. 980518 kb reduced size of Xfer-messages. - during Xfer, message buffers are allocated for send and receive messages. The size of these message buffers (and the size of the transferred messages) depend mostly on the number of objects which must be transferred. Each message contains an ObjectTable, which serves as a directory for the objects contained in that messages. This object table has been reduced by about 12%. --------------------------- CHANGES 1.8.17 -> 1.8.18 --------------------------- 980514 kb complete redesign of memory handling. - memory handling, esp. during DDD_XferEnd() is done more specifically, now. Each call to AllocTMEM and FreeTMEM is given an additional parameter 'kind', which tells the memory manager what kind of memory is allocated. A simple memory manager can ignore this and call malloc() and free(). - Also module Join has been changed accordingly. - NOTE: the memory manager (MemMgr) interface has changed, some calls have more parameters! --------------------------- CHANGES 1.8.16 -> 1.8.17 --------------------------- 980505 kb bugfix in DDD_XferObjIsResent(). --------------------------- CHANGES 1.8.15 -> 1.8.16 --------------------------- 980427 kb added new error control feature for Ident-module. - when using MPI on workstations, messages with different lengths can be sent and received. This results in quiet error situations, when the number of Identify-calls on pairs of processors is not equal. Now, the overall length of each message is sent as first data item, so that DDD can check this value and abort with an error, if necessary. Thus, many errors might be detected now which could previously lead to a lot of follow-up errors. 980427 kb additions for CPP_FRONTEND. - now, the c++demo application is running with DDD and CPP_FRONTEND. - the calling of DDD Handlers has been reworked. Virtual member function calls are avoided completely (an option to use them will be implemented in the future). - the application programmer has to provide a DELETE-handler for each class derived from DDD_Object, which only contains a 'delete this'. This should be automated in future versions. --------------------------- CHANGES 1.8.14 -> 1.8.15 --------------------------- 980316 kb new command DDD_XferObjIsResent(). - returns XFER_RESENT_TRUE for objects which will receive an additional copy during XferEnd() (sent by another processor). --------------------------- CHANGES 1.8.13 -> 1.8.14 --------------------------- 980313 kb new command DDD_XferIsPrunedDelete(). - returns XFER_PRUNED_TRUE for objects with pruned DDD_XferDeleteObj() commands, XFER_PRUNED_FALSE otherwise. --------------------------- CHANGES 1.8.12 -> 1.8.13 --------------------------- 980128 kb new DDD module 'Join'. - the Join module supports joining local object copies to distributed objects by contacting one of the distributed copies on an arbitrary processor which owns a copy. - the current implementation is preliminary, not tested with large applications and not tuned for efficiency. - if you are able to avoid Join and use Identify, do this. Join is an expensive operation. 980121 kb added healing-feature to ConsCheck. - with the "healing"-feature, the ConsCheck is able to detect local coupling inconsistencies and fix them by calling AddCoupling. However, such inconsistencies indicate consistency problems elsewhere (most of the cases the application based on DDD), which should be fixed by thinking hard and reimplement code which uses DDD functionality. Therefore, the healing feature has been switched off and kept in code just in case we need it at some (improbable) point in future. --------------------------- CHANGES 1.8.11 -> 1.8.12 --------------------------- 971024 kb improved memory handling. - use compiler-switch XferMemFromHeap to instruct the Xfer module using the MemMgr's Heap-functions (Mark/Alloc/Release) to get memory for receive buffers and other data. Note: this feature is not yet in its final state and will be extended in future versions. - use compiler-switch ConsMemFromHeap to instruct the ConsCheck module using the MemMgr's Heap-functions (Mark/Alloc/Release) to get memory for receive buffers and other data. Note: this feature is not yet in its final state and will be extended in future versions. 971023 kb xfer more efficient, in space and time. - used new container classes for several data structures in Xfer. - now, DDD_XferCopyObj calls will be merged on the fly, as a result the XFERCOPY-handlers will only be called if the corresponding call to DDD_XferCopyObj is either new or wins against an existing call with respect to priority- merge. 971020 kb new base level of container class data structures. - introduced new object-oriented style via C preprocessor. implemented several efficient container classes with this style. --------------------------- CHANGES 1.8.10 -> 1.8.11 --------------------------- 971010 kb added error checks for various calls to PPIF. - in several modules, PPIF functions had been called without checking for error conditions afterwards. Now, error checking has been added which will HARD_EXIT after PPIF reports an error. 971010 kb fixed bug ('semantical problem') in xfer/unpack.c. - during calls to AddDataScatter and other handlers, the order of calls for two or more incoming copies of one distributed DDD object could be: 1.XFER_REJECT, 2.XFER_NEW ... This was wrong, because the first handler call should be for the XFER_NEW object, the following calls for the XFER_REJECT objects. This has been fixed now for all handlers which get a 'newness'-argument. 971009 kb added documentation. - using the inline documentation and much additional texts (which are currently not in the distribution), a postscript file is generated (doc/ddd_doc.ps). This contains the reference manual, user's manual, tutorial, error-list, and implementation details ('inside ddd'). Currently, only the reference manual is in a fairly advanced state. 971009 kb added DDD_XferWithAddData(). - this function returns a boolean value telling the caller if additional data will be really sent or just discarded. --------------------------- CHANGES 1.8.9 -> 1.8.10 --------------------------- 971007 kb Global coupling-table is now enlarged dynamically. - the upper limit MAX_CPL has been removed. each time the maximal number of couplings on a processor is reached, its coupling table (and depending on this, other tables) is doubled in size. this is to make DDD more robust also on very, very big machines. 971007 kb LowComm is now able to handle low-memory situations. - if LowComm cannot get enough memory from the MemMgr-layer, it will try now to wait for running messages and free their send buffers. After that, enough memory should be available. The Xfer-implementation had to be changed slightly to use this feature. --------------------------- CHANGES 1.8.8 -> 1.8.9 --------------------------- 970909 kb added inline documentation. - in some later version, the DDD sources will be completely documented by inline descriptions in DOC++ (ZIB Berlin) style. This is work in progress. 970908 kb removed need for (very) large object table. - in all earlier versions, DDD maintained on each processor a pointer array referencing all DDD objects on that processor. the need for these arrays has been removed in 1.8.9. Compile-switch WithFullObjectTable may be used to enable the large object tables again, this might be useful for debugging. Without this compile-switch being set, DDD will _not_ have any knowledge about objects which do not have coupling (i.e. local objects). When copies of such objects are created, or those objects are involved in Identify-procedures, they will be put under DDD control. Otherwise, the application layer has to maintain the storage for these objects. --------------------------- CHANGES 1.8.7 -> 1.8.8 --------------------------- 970704 kb bugfix in Xfer module. - reference-merging does now work also with rule XFER-C2 in all situations. --------------------------- CHANGES 1.8.6 -> 1.8.7 --------------------------- 970702 kb bugfix in Interface module. - when a processor moved all its objects to another proc, in versions before 1.8.7 the interface representation hasn't been deleted. this is fixed now. 970702 kb bugfix in Identify module. - the changes of 970528 seem to work correctly now. did some software reorganisation. --------------------------- CHANGES 1.8.5 -> 1.8.6 --------------------------- 970701 kb added check for PPIF initialization in DDD_Init(). 970528 kb reinvented STAT statistical evaluation. - the DDD_StatXXX functionality will be used extensively in future versions in order to provide an interface for performance measuring and other accounting information from DDD to application level. 970528 kb tuning in Identify module. - replaced sorting of array with big entries by sorting of array with pointers to big entries. better performance on systems with poor memcpy-implementation. - NOTE: this can lead to errors on complicated identification tasks. (normally it should work, however). keep that in mind. 970417 kb added DDD_TYPE_BY_HANDLER for EL_OBJPTR in TypeDefine. - normally, for EL_OBJPTR defined during TypeDefine the DDD_TYPE of the referenced object has to be given. - now, one can replace this argument (a DDD_TYPE) by the constant DDD_TYPE_BY_HANDLER, and an additional argument which is a function pointer to a handler function of the type HandlerGetRefType, i.e. (see ddd.h) DDD_TYPE (*HandlerGetRefType) (DDD_OBJ o1, DDD_OBJ o2) - DDD will call this handler whenever it needs to evaluate the referenced type. then, o1 is the object containing the reference, o2 is the referenced object (for which the type must be given). the function must return the actual type of o2. - when defining arrays of EL_OBJPTR, the handler function will be called for each reference in turn. 970417 kb change in priority consistency during xfer. - when a local object is XFER_UPGRADEd during xfer/unpack, its priority has been set immediately (until 1.8.5). - for calling the user-defined handler SETPRIORITY, the old prio-value had been restored into the object's DDD_HEADER; after the call to the handler (if any), the new priority value was inserted again. - from 1.8.6 on: the priority isn't set immediately, but only after the call to SETPRIORITY. This implements the following priority consistency model: BEFORE AND DURING the call to the SETPRIORITY handler, the object has its old priority. AFTER calling the SETPRIORITY handler, the object has its new priority. 970416 kb fixed some bugs found by evaluation version of Purify. --------------------------- CHANGES 1.8.4 -> 1.8.5 --------------------------- 970414 kb fixed serious bug in xfer/unpack. NEVER USE 1.8.4! 970411 kb added new option OPT_XFER_PRUNE_DELETE. - with this option set to OPT_ON, DelCmds during transfer will discarded, if a XferCopyObj command for the same distributed object exists. Therefore, the object will not be deleted and created afterwards. - the priority merging of the two objects will be as given in the specification, i.e., the new object will be accepted disregarding its priority. 970327 kb fixed serious bug in xfer/unpack.c. - bug could occur with procs>=4 - now coupling consistency should work properly. - efficiency (runtime, message size and storage) is not quite clear for large problems. TODO: this must be checked. --------------------------- CHANGES 1.8.3 -> 1.8.4 --------------------------- 970310 kb additional options OPT_INFO_XFER, with values XFER_SHOW_xxx. - can be used to control memory allocation in Xfer module. 970310 kb additional error messages in ident.c. 970310 kb bugfix in basic/topo.c (error occurred with procs>64). --------------------------- CHANGES 1.8.2 -> 1.8.3 --------------------------- 970306 kb increased MAX_TRIES timeout value to 50M. 970305 kb added CtrlTimeouts(Detailed) switch in if/if.h. - this may be used for checking the interface timeout values. - CtrlTimeouts displays the timeout value after each IF communication (on each proc one line for send/receive) - CtrlTimeoutsDetailed displays the timeout values for each message during a IF communication (on each proc one line for send/receive of any message) --------------------------- CHANGES 1.8.1 -> 1.8.2 --------------------------- 970304 kb increased size of notify buffer to 2*(n*(n-1)/2) (for message send/receive). --------------------------- CHANGES 1.8 -> 1.8.1 --------------------------- 970303 kb added new function DDD_IFInfoMemory(). - this function returns the number of bytes used for representing a given DDD interface. - available in all FRONTENDs. 970303 kb cleanup of memory management. - removed some memory leaks. - improved performance by introducing segments of memory instead of doing many, many alloc/free requests. this was done in xfer/sll.ct (for auxiliary data structures in Xfer), and in xfer/supp.c (for AddData structures). - memory for DDD interfaces is constructed exactly as large as needed. up to now, memory has been wasted (esp. when there were many DDD-types as distributed objects). memory usage for interfaces will be about factor 6-8 smaller now. 970217 kb removed lots of warnings with C++ on SGI. --------------------------- CHANGES 1.7.8 -> 1.8 --------------------------- 970217 kb started to C++-ize PPIF and extended functionality. 970212 kb added powerful memory-management debugging tool. - some switches (CheckPMEM, CheckAMEM, CheckTMEM) can be set at compile time in dddi.h in order to control the memory usage of the DDD-library. each allocated chunk will be sizeof(size_t) bigger, in the additional section the size of the allocated memory is stored. this is used for printing of MALL and FREE output. 970212 kb revised handler handling. :-) - now, for each DDD-handler there is a corresponding SetHandler function (e.g., DDD_SetHandlerUPDATE for UPDATE-handler). The first argument of each handler function is the DDD_TYPE for which the new handler should be registered, the second argument is a pointer to the handler function itself (e.g., of type HandlerUPDATE). - in ddd.h there is a list of prototypes for all handlers, i.e., now the compiler can do static type checking for handler functions and their parameters. - the old functionality DDD_HandlerRegister with variable argument list is supported for downward compatibility. 970212 kb introduced OLDSTYLE-warnings. - for functions which are supported for downward compatibility only and which will be removed in some future version, a warning is issued each time the function is called. - additionally, some hints are added how to upgrade to new version. - with DDD_OPTION OPT_WARNING_OLDSTYLE these warnings can be switched off. 970212 kb revised handler calls in F_FRONTEND. - now all relevant handlers are called also in F_FRONTEND version (with call-by-reference parameters). 970211 kb implemented object-oriented CPP_FRONTEND prototype. - supports C-style objects (as structs or classes) and Fortran-style objects (as collections of distributed arrays). - implementation as object-oriented class hierarchy encapsulated the ANSI C implementation of DDD. - class DDD_Library with a single instance represents the DDD library. - class DDD_Object represents a distributed object. - class DDD_IndexObject represents a object stored in array-like manner. - template classes DDD_ObjectOf and DDD_IndexObjectOf may be used for very elegant parallelization of sequential object-oriented codes. - class DDD_Interface encapsulates a DDD interface, communication can be done via DDD_GatherScatter-objects. - now, C_FRONTEND, F_FRONTEND and CPP_FRONTEND in one single code. - see coming documentation and demo examples for using CPP_FRONTEND. --------------------------- CHANGES 1.7.7 -> 1.7.8 --------------------------- 970205 kb added many USER_DATA streams feature. - all IDs in interval [DDD_USER_DATA, DDD_USER_DATA_MAX] may be used for sending byte streams as AddData. 970204 kb started with CPP_FRONTEND, designed some classes in ddd.h. 970204 kb revision for global ID construction. - the definition of MAX_PROCBITS_IN_GID has been moved to dddi.h. this gives the number of bits inside each global ID. - the number of bits for the processor number inside the global ID is a limit for the maximum number of processors. now this number is checked in DDD_Init() with error message and exit. - the overflow of global IDs is checked and DDD is exited with an error message. this will occur after 2^(32-MAX_PROCBITS_IN_GID) calls to DDD_HdrConstructor(). --------------------------- CHANGES 1.7.6 -> 1.7.7 --------------------------- 970131 kb new element type EL_GBITS. - with EL_GBITS, one can define components of DDD-types bitwise. 1=GDATA, 0=LDATA. for DDD_TypeDefine, a line for defining a bitwise element looks like this: EL_GBITS, &a, sizeof(a), bitarray where a is a structure component, sizeof(a) its size, and bitarray a character-array (unsigned char *) with length sizeof(a), where the bits are set according to GDATA or LDATA property. - not implemented for F_FRONTEND. --------------------------- CHANGES 1.7.5 -> 1.7.6 --------------------------- 970129 kb new interface for general PriorityMerge. - default for merging of priorities is MAXIMUM. - a new default can be set by DDD_PrioMergeDefault() - special exceptions can be introduced by DDD_PrioMergeDefine() - the current setting is displayed by DDD_PrioMergeDisplay() - the PrioMerge operation might be tested from application level via DDD_PrioMerge(). - all PrioMerge operations work with DDD_TYPE as first argument, i.e., one can define arbitrary PrioMerge logic for each DDD_TYPE. - the Xfer-Module has been adapted so that it supports the general PrioMerge settings. 970129 kb replaced all exit(1) calls by macro call HARD_EXIT. - the current default for HARD_EXIT is assert(0), thus, one will get a core file after every DDD error. - later (in production versions) one can replace this by simple exit(1) or similar. 970129 kb added new parameter newness to calls of scatter-handlers. - HANDLER_XFERSCATTER and HANDLER_XFERSCATTERX get an additional parameter 'newness', which is one of { XFER_REJECT, XFER_UPGRADE, XFER_NEW }, depending on an incoming objects status. - this should be documented in RefMan. NOTE: changing of XFERSCATTER parameterlist in applications necessary! --------------------------- CHANGES 1.7.4 -> 1.7.5 --------------------------- 970128 kb added OPT_INFO_XFER. - this runtime option shows additional (statistical) information during XferBegin/XferEnd. default is OPT_OFF. 970128 kb changed interface display functions and added some output. - DDD_IFDisplay now takes an argument DDD_IF in order to display only one interface. - DDD_IFDisplayAll is a new function displaying all interfaces (formerly DDD_IFDisplay) - DDD_IFSetName allows to define a textual description for interfaces, which is displayed by DDD_IFDisplay and DDD_IFDisplayAll. NOTE: this change requires renaming of function DDD_IFDisplay in all applications! --------------------------- CHANGES 1.7.3 -> 1.7.4 --------------------------- 970124 kb fixed bug in interface communication. - IF_Axxx (i.e. communication by attribute) crashed when IF-parts without objects existed. 970124 kb increased size of NOTIFY-table. --------------------------- CHANGES 1.7.2 -> 1.7.3 --------------------------- 970121 kb changed order of handler calls in xfer-unpack implementation. - now MKCONS handler gets second parameter 'newness'. XFER_UPGRADE for objects upgraded according RULE C3. XFER_NEW for new objects. - this should be documented in RefMan. NOTE: changing of MKCONS parameterlist in applications necessary! --------------------------- CHANGES 1.7.1 -> 1.7.2 --------------------------- 970115 kb changed xfer-unpack implementation. - up to ddd-1.7.1, the unpack-handlers (i.e. UPDATE, XFERSCATTER, SETPRIORITY, OBJMKCONS) where called for each incoming message in turn. now, all UPDATE handlers are called, then all XFERSCATTER handlers and so on (SETPRIORITY, OBJMKCONS). - this is a temporary solution. in later versions, the handler calls will be reworked; efficiency will be improved by cleaning up the loop structure in xfer-unpack. --------------------------- CHANGES 1.7 -> 1.7.1 --------------------------- 970110 kb re-implementation of current interface functionality. - only one implementation for 24 DDD_IFxxx interface functions (via templates). - the following possibilities can be used now: { C_FRONTEND, F_FRONTEND} x { Exchange, Oneway, ExecLocal} x { one DDD_ATTR, all DDD_ATTRs } x { normal gather/scatter-params, extended gather/scatter-params } - the next step will be implementation of maskable DDD_ATTRs. 970110 kb standard interface cannot be used for communication. - user must define an interface in order to communicate. the standard interface is only used for creating the user interfaces and cannot be used with DDD_IF.. commands anymore. - object shortcuts will not be computed for the standard interface. 970110 kb added second call to handler HANDLER_SETPRIORITY. - now the SETPRIORITY-handler is called when a local object's priority is set by DDD_PrioritySet() and when an object's priority is upgraded due to an incoming object with same gid, but higher (or equal) priority. - this feature is a temporary setting. in some later version, we will rework all handler calls during xfer-unpack in order to clean up "historical" developments. --------------------------- CHANGES 1.6.10 -> 1.7 --------------------------- 961220 kb added option OPT_WARNING_REF_COLLISION, with default OPT_ON. - each EL_OBJPTR (i.e. each reference) inside a DDD object must be NULL_REF or a pointer to a valid DDD-object. when two or more local objects of one distributed object exist, each reference element must contain either NULL_REF or a reference to THE SAME valid DDD-object. if this is not the case, a warning 'reference collision' will be issued by DDD. this option may be used for switching this warning off, which might be dangerous due to possible data inconsistencies. 961219 kb switched on merge-mode for xfer-unpack. - now references of incoming objects and objects already on the local processor are merged. --------------------------- CHANGES 1.6.9 -> 1.6.10 --------------------------- 961209 kb new function DDD_InfoNCopies(). - returns number of copies of a local object. The local object itself is not included. 961128 kb integrated changes from F_FRONTEND branch. - now F_FRONTEND is available with reference conversion, part of the interface communication functions and tested with 1-2 simple applications. updated README, arch and ppif. --------------------------- CHANGES 1.6.8 -> 1.6.9 --------------------------- 961128 kb bugfixes in Identify-module. --------------------------- CHANGES 1.6.7 -> 1.6.8 --------------------------- 961127 kb changed prototype of DDD_IFDefine. - second parameter is DDD_TYPE*, forth and sixth parameters are DDD_PRIO*. This change requires changes in all applications. changed value of DDD_USER_DATA to positive value. - also usage of DDD_USER_DATA in Xfer-module has been adapted. still more functionality for Identify-module. - now OPT_IDENTIFY_MODE may be set to two different values: - in IDMODE_LISTS, the order of Identify-command issuing is relevant, i.e., tupel1=(5,3) and tupel2(3,5) are different. - in IDMODE_SETS, the order of Identify-commands in each tuple is ignored; the IdentifyModule itself reorders each tupel's entries. then, tupel1 and tupel2 from the above example are the same. 961126 kb additional functionality for Identify-module. - in calls to DDD_IdentifyObject, now objects can be used as identifiers which are also identified in the current IdentifyBegin/IdentifyEnd step. I.e., identification can use hierarchical IdentifyObject-calls, objects can be used as identifiers which itself haven't been identified before! - communication has been tuned, now REALLY only gid and prio is sent for each object which must be identified. - lots of debugging levels introduced. --------------------------- CHANGES 1.6.6 -> 1.6.7 --------------------------- 961026 kb some changes due to comments from Klaus-Dieter Oertel. - changed typedefs for DDD_PRIO, DDD_ATTR etc to unsigned int - added functions to encapsulate PPIF's global variables me, master, procs (DDD_InfoMe etc) 961016 kb added changes from ug-ddd-version into actual ddd-repository. - some new interface functions, an interface checker - moved HANDLER_PRIORITYSET from prio.c into xfer.c - new functions DDD_SearchHdr and DDD_InfoIsLocal 961019 kb added PITFALLS file to collect common errors by DDD users. --------------------------- CHANGES 1.6.5 -> 1.6.6 --------------------------- 960906 kb added consistent object deletion during xfer (from HANDLER_DELETE). added HANDLER_SETPRIORITY. changes for NEC-SX4 compilation. added new functions DDD_IFExecLocal and DDD_IFAExecLocal. 960905 kb xfer-module completely rewritten. - complete coupling consistency with 2 communication phases. - spread-communication of prior versions had been removed. - xfer-module now implements the written xfer-specification. - dddic checked approx. 100000 testcases for xfer of one distributed object, without errors. - data structures are based on templates now, which implement linked list with free lists. - abstractions have been worked out more carefully. - testing was successful for fedemo. 960813 kb cplmsg.c, added new information about coupling consistency during transfer. 960722 kb lowcomm.c, new low communication layer. - lowcomm supports messages consisting of several tables and/or data chunks. it also encapsulates n-to-n-messaging; it notifies the receiving procs, allocates message buffers, computes message sizes. - reworked xfer-module and ConsCheck in order to use the new lowcomm layer. therefore, these modules have been restructured completely. 960715 kb topo.c, reworked channel handling. code for using DDD_GetChannels() is much smaller now. 960712 kb introduced general message structure, now Notify() doesn't rely on special messages for Xfer, Spread, Cons etc anymore. 960703 kb xfer, split XferInfo-list into two, one for objects and one for couplings. --------------------------- CHANGES 1.6.4 -> 1.6.5 --------------------------- 960618 kb restructured Makefile.ddd, in order to establish new structure of arch/ppif/ddd and applications. --------------------------- CHANGES 1.6.3 -> 1.6.4 --------------------------- 960611 kb typemgr.c, changed behaviour on errors. - now every error during TypeMgr operations leads to exit(1) of program. 960610 kb pack.c/unpack.c, enabled runtime activation of xfer debug output. - the contents of messages being sent/received during xfer may be printed out by activating DDD option OPT_DEBUG_XFERMESGS. 960607 kb added object size testing to XferCopyObjX and ObjGet. - via DDD options OPT_WARNING_SMALLSIZE and OPT_WARNING_VARSIZE_OBJ issuing of warnings on size!=desc->size events can be controlled. 960607 kb xfer.c, added handler HANDLER_DELETE for different way of object deletion. - HANDLER_DELETE is an alternative way of deleting objects; the necessary DDD_HdrDestructor must be called by the applications HANDLER_DELETE handler. - the handler definition in ddd.h had been reworked in order to get more independent of future additions to handler list. 960604 kb fixed bug in compiler.h. - alignment entry for __INDIGO__ was 4 (8 is the correct value) --------------------------- CHANGES 1.6.2 -> 1.6.3 --------------------------- 960528 kb integrated changes for F_FRONTEND. - this includes all work by Jens Boenisch, together with some integration work and debugging by kb. simple test programs in fortran with ddd are working now. - the main point NOT implemented in this version is handling of 'pointers', i.e., how f77-indices are translated into ddd references and globalized/localized during xfer. this work will be done during the next implementation phase of F_FRONTEND. - main features working right now: TypeMgr, ObjMgr, IFDefine, Xfer without references. --------------------------- CHANGES 1.6.1 -> 1.6.2 --------------------------- 960512 kb unpack.c, complete rewrite - LocalObjectsList() caused a serious efficiency problem. it was called several times during each transfer. therefore, the complexity of xfer was #local_objects*log(#local_objects)*C, where C is a (not very small) constant. in order to provide an efficient solution, the unpack-module has been rewritten completely. now a list of new (incoming) objects is constructed an sorted; this lead to a complexity which is independent of #local_objects, and is depending only on the number of objects in interface, instead. debugging and testing had been done quite thoroughly. --------------------------- CHANGES 1.6 -> 1.6.1 --------------------------- 960507 kb ifcreate.c, improved memory complexity - due to bad estimates of memory needed for representing the interfaces (as lists of coupling pointers), mmuch memory had had been wasted at runtime (about 0.5MB per interface and processor). this has been fixed by maintaining a coupling counter per processor, which can be used to compute the exact size of the standard interface and from this the maximum size for each defined interface. these sizes are usually much smaller than the rough estimates before this fix. --------------------------- CHANGES 1.5 -> 1.6 --------------------------- 960402 kb typemgr.c, added EL_CONTINUE feature - DDD_TypeDefine() calls may be ended by EL_CONTINUE now (instead of EL_END), which ends up with partially defined DDD_TYPEs. these partially defined DDD_TYPEs may be defined further by more calls to DDD_TypeDefine(). --------------------------- 960209 kb ident.c, fixed two bugs: - VChannel allocation was blocking in some cases; fix: replaced VChannel allocation by GetChannel() from topo.c - asynchronous info functions didn't cooperate with get_SHMEM-ppif for T3D. (SHMEM-ppif had stronger synchronization requirements than expected). fix: sorted Info-functions, first poll receives, then poll sends. --------------------------- 960207 kb unpack.c, fixed bug - when 0-pointer was unpacked, the HDR2OBJ conversion was called. this is not valid for 0-pointers. fix: inserted if-statement. --------------------------- 960110 kb renamed main.c to ddd.c. --------------------------- CHANGES 1.4 -> 1.5 --------------------------- 960110 kb objmgr.c, second complete rewrite - reorganized DDD_HDR constructors - introduced 3 interfaces for object construction/destruction --------------------------- 960113 kb ifuse.c, removed bug in DDD_IFOneway() --------------------------- 960117 kb IF-module - created new files ifcmds.c and ifobjsc.c - introduced obj-shortcut-tables for quick reference during interface-communication - created shortcut-table-invalidation/validation-interface --------------------------- CHANGES 1.3 -> 1.4 --------------------------- 951103 kb DDD_StructRegister - second argument (ddd_hdr) vanished - use EL_DDDHDR instead (in element list) - possibility to recursively register known DDD_TYPEs, via entering their id in the EL_xxx field - better error checking and reporting - DDD_HDR itself is a DDD-object (DDD_TYPE=0) - C++ support: inheritance of DDD-objects is possible, virtual inheritance gives a warning (nty) - added mask for easy and efficient object copying - restructured code (C++style) --------------------------- 951103 kb objmgr.c, complete rewrite. - now object-oriented style is supported: constructors, new-operators etc - handler interface rewritten - downward compatibility with V1.3: DDD_ObjGet still supported - CopyConstructor uses copymask from DDD_StructRegister - changed definition of handlers (and their names, just to be sure) --------------------------- 951106 kb main.c, changed parameters of DDD_Init to void DDD_Init (int *argcp, char ***argvp) for compatibility with MPI and similar parallel programming models. Involves changes of parameters of InitPPIF and all its current implementations. --------------------------- 951116 kb created typemgr.c (from main.c) - removed DDD_StructRegister, DDD_StructDisplay. - created new TypeMgr interface DDD_TypeDeclare(), DDD_TypeDefine(), DDD_TypeDisplay(). - when defining types, the targets for all references (EL_OBJPTR) have to be specified --------------------------- 951117 kb arbitrary DDD_HEADER offsets - from now on DDD_HEADER may have arbitrary offset for each DDD_TYPE --------------------------- 951121 kb changed OBJ_DESCR to TYPE_DESC, EL_DESCR to ELEM_DESC, objstruct to theTypeDefs --------------------------- 951122 kb renamed DDD_DisplayIF() to DDD_IFDisplay() --------------------------- dune-uggrid-2.11.0+dfsg/dune/uggrid/parallel/ddd/CMakeLists.txt000066400000000000000000000012531513616443000242330ustar00rootroot00000000000000# SPDX-FileCopyrightText: Copyright © DUNE Project contributors, see file LICENSE.md in module root # SPDX-License-Identifier: LGPL-2.1-or-later add_subdirectory(include) install(FILES dddconstants.hh dddcontext.hh dddtypes.hh dddtypes_impl.hh DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}/dune/uggrid/parallel/ddd) if(UG_ENABLE_PARALLEL) add_subdirectory(analyser) add_subdirectory(basic) add_subdirectory(ctrl) add_subdirectory(ident) add_subdirectory(if) add_subdirectory(join) add_subdirectory(mgr) add_subdirectory(prio) add_subdirectory(xfer) target_sources_dims(duneuggrid PRIVATE ddd.cc) endif() target_sources(duneuggrid PRIVATE dddcontext.cc) dune-uggrid-2.11.0+dfsg/dune/uggrid/parallel/ddd/HOWTO000066400000000000000000000021501513616443000223130ustar00rootroot00000000000000 ------------------------------------------ Some additional documentation. ------------------------------------------ HOWTO release a new version and export it. Example for release number 1.7.0. Change to src directory. cvs commit (Enter appropriate comments). Edit CHANGES file and record global changes. cvs commit CHANGES (Enter comment 'new version 1.7.0.'). Change to main directory. date >> VERSION cvs commit VERSION (Enter comment 'new version 1.7.0.'). cvs tag DDD1_7_0 cd .. cvs export -d ddd-1.7.0 -rDDD1_7_0 ddd 990202 kb ------------------------------------------ HOWTO import new version into UG. (move this HOWTO to somewhere else...) Act as described above. Change to exported directory ddd-1.7.0. Change to src directory. cvs import UG/ug/parallel/ddd ugddd DDD1_7_0 Enter comment 'new version ddd-1.7.0' and additional information about changes in this release. Hope that there are no conflicts. 990202 kb ------------------------------------------ dune-uggrid-2.11.0+dfsg/dune/uggrid/parallel/ddd/PITFALLS000066400000000000000000000016521513616443000226370ustar00rootroot00000000000000 this file collects common errors by ddd users, which are caused by typical ddd pitfalls. --------------------------------------------------------------- alignment/non-alignment of buffer pointers. 960919 kb The handlers for gathering/scattering data during IF-communication are called with non-aligned pointers into the buffer. Therefore, the application program can send n bytes per object in the interface without wasting message buffer space. However, the handlers for gathering/scattering data objects into messages during Xfer (caused by calling DDD_XferAddData()) are called with aligned pointers. This is due to allow access to the copy of the data object inside the message buffer (which correct alignments). --------------------------------------------------------------- dune-uggrid-2.11.0+dfsg/dune/uggrid/parallel/ddd/TODO000066400000000000000000000067271513616443000221760ustar00rootroot00000000000000 --------------------------------------------------------------------- DDD TODO-LIST 971008 kb created Apart from many TODOs spread out in the source code there are some more features which are still missing. --------------------------------------------------------------------- --------------------------------------------------------------------- 1. Dynamic ddd_CplTable. ddd_CplTable, ddd_NCplTable and ddd_ObjTable are allocated dynamically since 1.8.10. However, the strategy is double-on-overflow, which temporarily needs more memory than with double-sized tables. There should be an option (at compile-time) to switch the strategy to kind-of segmented, i.e., segments of fixed size are allocated and freed on demand. Then, accessing the tables will be more time-expensive, but we could handle more delicate low-memory situations. --------------------------------------------------------------------- 2. DDD_NCopiesPrio(). Implement a function returning the number of object copies with a given priority. --------------------------------------------------------------------- 3. XferCopyObjX and additional bytes. XferCopyObjX sends objects which are bigger than their declared DDD_TYPE. There should be a way to specify whether the additional data bytes are LDATA or GDATA or a mixture of both. --------------------------------------------------------------------- 4. IF-communication and DDD_ATTR. In all IF-communication functions there could be an additional function with masked DDD_ATTR, i.e. a value and a mask. With this feature one could communicate over a set of DDD_ATTR-subinterfaces. --------------------------------------------------------------------- 5. Integration check via DDD_HEADER checksums in debug-mode. There should be a debug-mode which allows to detect memory errors (bad pointers). In this debug-mode, each DDD_HEADER contains a checksum variable, which is a parity-like encoding of the data in the DDD_HEADER. Before each time the HEADER data is accessed (i.e., read _and_ write access), the checksum is computed and compared with the stored one. Errors according to bad pointers and memory faults could be found more easily. --------------------------------------------------------------------- 6. Communicators. MPI-like communicators into DDD. This should be supported already by PPIF. (i.e. groups of processors execute certain DDD functions, like Interface-comm, Xfer, Identify). --------------------------------------------------------------------- 7. Make Notify-module faster. Perhaps it is possible to schedule the small messages in Notify not only through the PPIF-tree, but also to immediate processor neighbours, where this is possible. This possibly can eliminate bottlenecks on the master processor. --------------------------------------------------------------------- 8. F_FRONTEND: ARCH_FLINK. Introduce ARCH_FLINK definition in all arch subdirectories. This could be necessary for the F_FRONTEND production version. --------------------------------------------------------------------- 9. AddData without previous XferCopyObj. It should be possible to start the Xfer-communication directly with calls to DDD_XferAddData (with previous specification of a destination processor). This would enable simple Xfers based on objects w/o DDD_HEADER. --------------------------------------------------------------------- dune-uggrid-2.11.0+dfsg/dune/uggrid/parallel/ddd/analyser/000077500000000000000000000000001513616443000233105ustar00rootroot00000000000000dune-uggrid-2.11.0+dfsg/dune/uggrid/parallel/ddd/analyser/CMakeLists.txt000066400000000000000000000003021513616443000260430ustar00rootroot00000000000000# SPDX-FileCopyrightText: Copyright © DUNE Project contributors, see file LICENSE.md in module root # SPDX-License-Identifier: LGPL-2.1-or-later target_sources_dims(duneuggrid PRIVATE inv.cc) dune-uggrid-2.11.0+dfsg/dune/uggrid/parallel/ddd/analyser/inv.cc000066400000000000000000000117601513616443000244200ustar00rootroot00000000000000// SPDX-FileCopyrightText: Copyright © DUNE Project contributors, see file LICENSE.md in module root // SPDX-License-Identifier: LGPL-2.1-or-later // -*- tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- // vi: set et ts=4 sw=2 sts=2: /****************************************************************************/ /* */ /* File: inventor.c */ /* */ /* Purpose: visualization in IRIS Inventor format */ /* */ /* Author: Klaus Birken */ /* Rechenzentrum Uni Stuttgart */ /* Universitaet Stuttgart */ /* Allmandring 30 */ /* 70550 Stuttgart */ /* internet: birken@rus.uni-stuttgart.de */ /* */ /* History: 95/03/28 kb begin */ /* */ /* Remarks: */ /* */ /****************************************************************************/ /****************************************************************************/ /* */ /* include files */ /* system include files */ /* application include files */ /* */ /****************************************************************************/ /* standard C library */ #include #include #include #include #include USING_UG_NAMESPACE using namespace PPIF; START_UGDIM_NAMESPACE /****************************************************************************/ /* */ /* data structures */ /* */ /****************************************************************************/ /* graph of DDD_TYPEs, with directed edges according to references */ struct TYPE_EDGE { DDD_TYPE reftype; /* referenced type */ int n; /* number of references */ TYPE_EDGE *next; /* linked list */ }; struct TYPE_NODE { const TYPE_DESC *def; /* pointer to DDD_TYPE */ TYPE_EDGE *refs; /* linked list of referenced types */ }; /****************************************************************************/ /* */ /* subroutines */ /* */ /****************************************************************************/ static TYPE_EDGE *GetTypeEdge (TYPE_NODE *tn, DDD_TYPE reftype) { TYPE_EDGE *te; for(te=tn->refs; te!=NULL && te->reftype!=reftype; te=te->next) ; if (te==NULL) { te = (TYPE_EDGE *)AllocTmp(sizeof(TYPE_EDGE)); te->reftype = reftype; te->n = 0; te->next = tn->refs; tn->refs = te; } return(te); } static void AnalyseTypes(const DDD::DDDContext& context) { int i; /* create graph of DDD_TYPE ref-relations */ for(i=0; inElements; e++) { const ELEM_DESC *el = &(td->element[e]); if (el->type==EL_OBJPTR) { TYPE_EDGE *te = GetTypeEdge(&tn, EDESC_REFTYPE(el)); te->n += (el->size / sizeof(void *)); } } printf("%4d: type %s (%03d) refs:\n", context.me(), td->name, i); { TYPE_EDGE *te; for(te=tn.refs; te!=NULL; te=te->next) { printf(" %s (%03d), n=%d\n", context.typeDefs()[te->reftype].name, te->reftype, te->n); } } } } /****************************************************************************/ void DDD_GraphicalAnalyser (DDD::DDDContext& context, char *filename) { FILE *fp; fp = fopen(filename, "w"); if (context.isMaster()) { AnalyseTypes(context); } fclose(fp); } END_UGDIM_NAMESPACE dune-uggrid-2.11.0+dfsg/dune/uggrid/parallel/ddd/basic/000077500000000000000000000000001513616443000225535ustar00rootroot00000000000000dune-uggrid-2.11.0+dfsg/dune/uggrid/parallel/ddd/basic/CMakeLists.txt000066400000000000000000000006011513616443000253100ustar00rootroot00000000000000# SPDX-FileCopyrightText: Copyright © DUNE Project contributors, see file LICENSE.md in module root # SPDX-License-Identifier: LGPL-2.1-or-later add_subdirectory(test) target_sources(duneuggrid PRIVATE io.cc lowcomm.cc notify.cc reduct.cc topo.cc) install(FILES notify.h lowcomm.h oopp.h ooppcc.h DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}/dune/uggrid/parallel/ddd/basic) dune-uggrid-2.11.0+dfsg/dune/uggrid/parallel/ddd/basic/io.cc000066400000000000000000000200221513616443000234650ustar00rootroot00000000000000// SPDX-FileCopyrightText: Copyright © DUNE Project contributors, see file LICENSE.md in module root // SPDX-License-Identifier: LGPL-2.1-or-later // -*- tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- // vi: set et ts=4 sw=2 sts=2: /****************************************************************************/ /* */ /* File: io.c */ /* */ /* Purpose: routines for I/O used by DDD */ /* */ /* Author: Klaus Birken */ /* */ /* History: 92/01/29 PrintErrorMessage by Peter Bastian */ /* 95/03/21 kb added PrintString() */ /* */ /* Remarks: */ /* */ /****************************************************************************/ /****************************************************************************/ /* */ /* include files */ /* system include files */ /* application include files */ /* */ /****************************************************************************/ #include #include #include #include #include #include #include #include #include /* PPIF namespace: */ using namespace PPIF; namespace DDD { void (*DDD_UserLineOutFunction)(const char *s); /****************************************************************************/ /* */ /* definition of static variables */ /* */ /****************************************************************************/ /****************************************************************************/ /* */ /* Function: DDD_PrintLine */ /* */ /* Purpose: print interface, all output lines will be routed to here */ /* */ /* Input: char *s: string to be printed */ /* */ /* Output: none */ /* */ /****************************************************************************/ void DDD_PrintLine (const char *s) { /* newline character will be included in s */ if (DDD_UserLineOutFunction!=NULL) { DDD_UserLineOutFunction(s); } else { printf("%s", s); } } /****************************************************************************/ /* */ /* Function: DDD_Flush */ /* */ /* Purpose: flush output device */ /* */ /* Input: none */ /* */ /* Output: none */ /* */ /****************************************************************************/ void DDD_Flush (void) { fflush(stdout); } /****************************************************************************/ /* */ /* Function: DDD_SyncAll */ /* */ /* Purpose: flush output devices and synchronize */ /* */ /* Input: none */ /* */ /* Output: none */ /* */ /****************************************************************************/ void DDD_SyncAll(const DDD::DDDContext& context) { DDD_Flush(); Synchronize(context.ppifContext()); } /****************************************************************************/ /* */ /* Function: DDD_PrintDebug */ /* */ /* Purpose: print interface for debug output */ /* */ /* Input: char *s: string to be printed */ /* */ /* Output: none */ /* */ /****************************************************************************/ void DDD_PrintDebug (const char *s) { /* newline character will be included in s */ DDD_PrintLine(s); DDD_Flush(); } /****************************************************************************/ /* */ /* Function: DDD_PrintError */ /* */ /* Purpose: print formatted error message on user screen */ /* */ /* Input: char class: 'W' Warning, 'E' Error, 'F' Fatal */ /* int errno: error number */ /* char *text: error message text */ /* */ /* Output: none */ /* */ /****************************************************************************/ void DDD_PrintError (char error_class, int error_no, const char *text) { char buffer[256]; const char* classText; switch (error_class) { case 'W' : classText = "WARNING"; break; case 'E' : classText = "ERROR"; break; case 'F' : classText = "FATAL"; break; default : classText = "USER"; break; } snprintf(buffer,256,"DDD %s %05d: %s\n",classText,error_no,text); DDD_PrintLine(buffer); } } /* namespace DDD */ dune-uggrid-2.11.0+dfsg/dune/uggrid/parallel/ddd/basic/lowcomm.cc000066400000000000000000001204601513616443000245420ustar00rootroot00000000000000// SPDX-FileCopyrightText: Copyright © DUNE Project contributors, see file LICENSE.md in module root // SPDX-License-Identifier: LGPL-2.1-or-later // -*- tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- // vi: set et ts=4 sw=2 sts=2: /****************************************************************************/ /* */ /* File: lowcomm.c */ /* */ /* Purpose: lowlevel communication layer */ /* */ /* Author: Klaus Birken */ /* Institut fuer Computeranwendungen III */ /* Universitaet Stuttgart */ /* Pfaffenwaldring 27 */ /* 70569 Stuttgart */ /* internet: birken@ica3.uni-stuttgart.de */ /* */ /* History: 960715 kb begin */ /* 971007 kb reworked */ /* */ /* Remarks: */ /* This module provides two basic abstractions: */ /* - sending of messages without explicit receive calls */ /* - message types consisting of a set of components, where */ /* components are tables (with entries of equal sizes) and */ /* raw data chunks. */ /* */ /* The LowComm subsystem uses the Notify-subsystem in order to */ /* tell receiving processors that corresponding send-calls had */ /* been issued. */ /* */ /* The structure of each message is: */ /* */ /* description | type */ /* -------------------------------------------+--------- */ /* magic number | ULONG */ /* #components | ULONG */ /* offset component1 (from beginning of Msg) | ULONG */ /* length component1 (in bytes) | ULONG */ /* nItems component1 | ULONG */ /* ... | ... */ /* offset componentN | ULONG */ /* length componentN | ULONG */ /* nItems componentN | ULONG */ /* component1 */ /* ... */ /* componentN */ /* */ /* The LowComm subsystem is able to handle low-memory situations,*/ /* where the available memory is not enough for all send- and */ /* receive-buffers. See LC_MsgAlloc for details. */ /* */ /****************************************************************************/ /****************************************************************************/ /* */ /* include files */ /* system include files */ /* application include files */ /* */ /****************************************************************************/ /* standard C library */ #include #include #include #include #include #include #include #include #include #include #include #include #include "lowcomm.h" #include "notify.h" #include USING_UG_NAMESPACES /* PPIF namespace: */ using namespace PPIF; #define DebugLowComm 10 /* 0 is all, 10 is off */ namespace DDD { namespace Basic { /****************************************************************************/ /* */ /* defines in the following order */ /* */ /* compile time constants defining static data size (i.e. arrays) */ /* other constants */ /* macros */ /* */ /****************************************************************************/ /* maximum number of components in a message */ #define MAX_COMPONENTS 8 /* dummy magic number for messages */ #define MAGIC_DUMMY 0x1234 /* number of entries per chunk in message header */ #define HDR_ENTRIES_PER_CHUNK 3 enum CompType { CT_NONE, CT_TABLE, CT_CHUNK }; /****************************************************************************/ /* */ /* data structures */ /* */ /****************************************************************************/ struct COMP_DESC { const char *name; /* textual description of component */ int type; /* type of this component */ size_t entry_size; /* size per entry (for tables) */ }; struct MSG_TYPE { const char *name; /* textual description of msgtype */ int nComps; /* number of components */ std::array comp; /* component array */ MSG_TYPE *next; /* linked list of all message types */ }; struct CHUNK_DESC { size_t size; /* size of chunk (in bytes) */ ULONG entries; /* number of valid entries (for tables) */ ULONG offset; /* offset of chunk in MSG */ }; enum MsgState { MSTATE_NEW, MSTATE_FREEZED, MSTATE_ALLOCATED, MSTATE_COMM, MSTATE_READY }; struct MSG_DESC { int msgState; /* message state of this message (one of MsgState) */ MSG_TYPE *msgType; /* message type of this message */ ULONG magic; /* magic number */ CHUNK_DESC *chunks; /* array of chunks */ size_t bufferSize; /* size of message buffer (in bytes) */ char *buffer; /* address of message buffer */ MSG_DESC *next; /* linked list inside Send/Recv-queue */ DDD_PROC proc; msgid msgId; }; struct TABLE_DESC { size_t entry_size; /* size of one table entry */ int nMax; /* number of entries in table */ int nValid; /* number of valid entries */ }; } /* namespace Basic */ } /* namespace DDD */ /****************************************************************************/ /* */ /* routines */ /* */ /****************************************************************************/ namespace DDD { using namespace DDD::Basic; /** Initiates LowComm subsystem. This function has to be called exactly once in order to initialize the LowComm subsystem. After a call to this function, the functionality of the LowComm can be used. @param aAllocFunc memory allocation function used as the default @param aFreeFunc memory free function used as the default */ void LC_Init(DDD::DDDContext& context, AllocFunc aAllocFunc, FreeFunc aFreeFunc) { auto& lcContext = context.lowCommContext(); lcContext.DefaultAlloc = aAllocFunc; lcContext.DefaultFree = aFreeFunc; LC_SetMemMgrDefault(context); } /** Exits LowComm subsystem. This function frees memory allocated by the LowComm subsystem and shuts down its communication structures. */ void LC_Exit(DDD::DDDContext& context) { auto& lcContext = context.lowCommContext(); { auto md = lcContext.FreeMsgDescs; while (md != nullptr) { const auto next = md->next; delete md; md = next; } lcContext.FreeMsgDescs = nullptr; } { auto mt = lcContext.MsgTypes; while (mt != nullptr) { const auto next = mt->next; delete mt; mt = next; } lcContext.MsgTypes = nullptr; } } /** Customizing memory management for LowComm subsystem. Currently this function supports only alloc/free of buffers for messages to be sent. */ void LC_SetMemMgrSend(DDD::DDDContext& context, AllocFunc aAllocFunc, FreeFunc aFreeFunc) { auto& lcContext = context.lowCommContext(); lcContext.SendAlloc = aAllocFunc; lcContext.SendFree = aFreeFunc; } /** Customizing memory management for LowComm subsystem. Currently this function supports only alloc/free of buffers for messages to be received. */ void LC_SetMemMgrRecv(DDD::DDDContext& context, AllocFunc aAllocFunc, FreeFunc aFreeFunc) { auto& lcContext = context.lowCommContext(); lcContext.RecvAlloc = aAllocFunc; lcContext.RecvFree = aFreeFunc; } /** Set memory management for LowComm subsystem to its default state. Set alloc/free of message buffers to the functions provided to \lcfunk{Init}. */ void LC_SetMemMgrDefault(DDD::DDDContext& context) { auto& lcContext = context.lowCommContext(); lcContext.SendAlloc = lcContext.DefaultAlloc; lcContext.SendFree = lcContext.DefaultFree; lcContext.RecvAlloc = lcContext.DefaultAlloc; lcContext.RecvFree = lcContext.DefaultFree; } /****************************************************************************/ /* auxiliary functions */ static MSG_DESC *NewMsgDesc (DDD::DDDContext& context) { auto& lcContext = context.lowCommContext(); MSG_DESC *md; if (lcContext.FreeMsgDescs != nullptr) { /* get item from freelist */ md = lcContext.FreeMsgDescs; lcContext.FreeMsgDescs = lcContext.FreeMsgDescs->next; } else { /* freelist is empty */ md = new MSG_DESC; } return(md); } static void FreeMsgDesc (DDD::DDDContext& context, MSG_DESC *md) { auto& lcContext = context.lowCommContext(); /* sort into freelist */ md->next = lcContext.FreeMsgDescs; lcContext.FreeMsgDescs = md; } /****************************************************************************/ /* this function has internal access only because LowComm initiates asynchronous receive calls itself. */ static LC_MSGHANDLE LC_NewRecvMsg (DDD::DDDContext& context, LC_MSGTYPE mtyp, DDD_PROC source, size_t size) { auto& lcContext = context.lowCommContext(); MSG_DESC *msg = NewMsgDesc(context); # if DebugLowComm<=6 Dune::dverb << "LC_NewRecvMsg(" << mtyp->name << ") source=" << source << "\n"; # endif msg->msgState = MSTATE_NEW; msg->msgType = mtyp; msg->proc = source; msg->bufferSize = size; /* allocate chunks array */ msg->chunks = new CHUNK_DESC[mtyp->nComps]; /* enter message into recv queue */ msg->next = lcContext.RecvQueue; lcContext.RecvQueue = msg; return msg; } static void LC_DeleteMsg (DDD::DDDContext& context, LC_MSGHANDLE md) { delete[] md->chunks; FreeMsgDesc(context, md); } static void LC_DeleteMsgBuffer (const DDD::DDDContext& context, LC_MSGHANDLE md) { const auto& lcContext = context.lowCommContext(); if (lcContext.SendFree != nullptr) (*lcContext.SendFree)(md->buffer); } static void LC_MsgRecv (MSG_DESC *md) { int i, j; /* get message address */ const ULONG *hdr = (ULONG *)md->buffer; /* get number of chunks */ int n = (int)(hdr[1]); /* magic number is hdr[0] */ if (hdr[0] != MAGIC_DUMMY) DUNE_THROW(Dune::Exception, "invalid magic number for message from " << md->proc); /* number of chunks must be consistent with message type */ if (n!=md->msgType->nComps) DUNE_THROW(Dune::Exception, "wrong number of chunks (got " << n << ", expected " << md->msgType->nComps << ") in message from " << md->proc); /* get chunk descriptions from message header */ for(j=2, i=0; ichunks[i].offset = hdr[j++]; md->chunks[i].size = (size_t)(hdr[j++]); md->chunks[i].entries = hdr[j++]; } #if DebugLowComm<=2 Dune:dvverb << "LC_MsgRecv() from=" << md->proc << " ready\n"; #endif } /****************************************************************************/ /* */ /* Function: LC_PollSend */ /* */ /* Purpose: polls all message-sends one time and returns remaining */ /* outstanding messages. whenever a message-send has been */ /* completed, its message buffer is freed. */ /* */ /* Input: - */ /* */ /* Output: remaining outstanding messages */ /* */ /****************************************************************************/ static int LC_PollSend(const DDD::DDDContext& context) { const auto& lcContext = context.lowCommContext(); MSG_DESC *md; int remaining, error; remaining = 0; for(md=lcContext.SendQueue; md != nullptr; md=md->next) { if (md->msgState==MSTATE_COMM) { error = InfoASend(context.ppifContext(), VCHAN_TO(context, md->proc), md->msgId); if (error==-1) DUNE_THROW(Dune::Exception, "InfoASend() failed for message to proc=" << md->proc); if (error==1) { /* free message buffer */ LC_DeleteMsgBuffer(context, (LC_MSGHANDLE)md); md->msgState=MSTATE_READY; } else { /* we keep this message in SendQueue */ remaining++; } } } #if DebugLowComm<=3 Dune::dvverb << "LC_PollSend, " << remaining << " msgs remaining\n"; #endif return(remaining); } /****************************************************************************/ /* */ /* Function: LC_PollRecv */ /* */ /* Purpose: polls all message-recvs one time and returns remaining */ /* outstanding messages. this function doesn't free the message */ /* buffers. */ /* */ /* Input: - */ /* */ /* Output: remaining outstanding messages */ /* */ /****************************************************************************/ static int LC_PollRecv(const DDD::DDDContext& context) { const auto& lcContext = context.lowCommContext(); MSG_DESC *md; int remaining, error; remaining = 0; for(md=lcContext.RecvQueue; md != nullptr; md=md->next) { if (md->msgState==MSTATE_COMM) { error = InfoARecv(context.ppifContext(), VCHAN_TO(context, md->proc), md->msgId); if (error==-1) DUNE_THROW(Dune::Exception, "InfoARecv() failed for recv from proc=" << md->proc); if (error==1) { LC_MsgRecv(md); md->msgState=MSTATE_READY; } else { remaining++; } } } #if DebugLowComm<=3 Dune::dvverb << "LC_PollRecv, " << remaining << " msgs remaining\n"; #endif return(remaining); } /****************************************************************************/ /* */ /* Function: LC_FreeSendQueue */ /* */ /****************************************************************************/ static void LC_FreeSendQueue (DDD::DDDContext& context) { auto& lcContext = context.lowCommContext(); MSG_DESC *md, *next=NULL; for(md=lcContext.SendQueue; md != nullptr; md=next) { /* the following assertion is too picky. Freeing of message queues should be possible in all msgStates. */ /*assert(md->msgState==MSTATE_READY);*/ next = md->next; LC_DeleteMsg(context, (LC_MSGHANDLE)md); } lcContext.SendQueue = nullptr; lcContext.nSends = 0; } /****************************************************************************/ /* */ /* Function: LC_FreeRecvQueue */ /* */ /****************************************************************************/ static void LC_FreeRecvQueue (DDD::DDDContext& context) { auto& lcContext = context.lowCommContext(); MSG_DESC *md, *next=NULL; for(md=lcContext.RecvQueue; md != nullptr; md=next) { /* the following assertion is too picky. Freeing of message queues should be possible in all msgStates. */ /*assert(md->msgState==MSTATE_READY);*/ next = md->next; LC_DeleteMsg(context, (LC_MSGHANDLE)md); } lcContext.RecvQueue = nullptr; lcContext.nRecvs = 0; } /****************************************************************************/ /* LC_MsgFreeze and LC_MsgAlloc are the two parts of LC_MsgPrepareSend(). */ /* returns size of message buffer */ size_t LC_MsgFreeze (LC_MSGHANDLE md) { int i, n = md->msgType->nComps; assert(md->msgState==MSTATE_NEW); /* compute size of header */ md->bufferSize = 2 * sizeof(ULONG); md->bufferSize += (n * HDR_ENTRIES_PER_CHUNK * sizeof(ULONG)); /* compute size and offset for each chunk */ for(i=0; ichunks[i].offset = md->bufferSize; md->bufferSize += md->chunks[i].size; } md->msgState=MSTATE_FREEZED; return(md->bufferSize); } int LC_MsgAlloc(DDD::DDDContext& context, LC_MSGHANDLE md) { auto& lcContext = context.lowCommContext(); ULONG *hdr; int i, j, n = md->msgType->nComps; int remaining=1, give_up = false; assert(md->msgState==MSTATE_FREEZED); /* the following code tries to allocate the message buffer. if this fails, the previously started asynchronous sends are polled, in order to free their message buffers. if there are no remaining async-sends, we give up. */ do { /* allocate buffer for messages */ md->buffer = (char *) (*lcContext.SendAlloc)(md->bufferSize); if (md->buffer==NULL) { if (remaining==0) give_up = true; else { # if DebugLowComm<=7 Dune::dinfo << "LC_MsgAlloc(" << md->msgType->name << ") detected low memory.\n"; # endif /* couldn't get msg-buffer. try to poll previous messages. */ /* first, poll receives to avoid communication deadlock. */ LC_PollRecv(context); /* now, try to poll sends and free their message buffers */ remaining = LC_PollSend(context); # if DebugLowComm<=6 Dune::dverb << "LC_MsgAlloc(" << md->msgType->name << ") preliminary poll, sends_left=" << remaining << "\n"; # endif } } } while (md->buffer==NULL && !give_up); if (give_up) { # if DebugLowComm<=7 Dune::dinfo << "LC_MsgAlloc(" << md->msgType->name << ") giving up, no memory.\n"; # endif return(false); } /* enter control data into message header */ hdr = (ULONG *)md->buffer; j=0; hdr[j++] = MAGIC_DUMMY; /* magic number */ hdr[j++] = n; /* enter chunk descriptions into message header */ for(i=0; ichunks[i].offset; hdr[j++] = md->chunks[i].size; hdr[j++] = md->chunks[i].entries; } md->msgState=MSTATE_ALLOCATED; return(true); } /* allocation of receive message buffers. NOTE: one big memory block is allocated and used for all message buffers. */ static RETCODE LC_PrepareRecv(DDD::DDDContext& context) { auto& lcContext = context.lowCommContext(); MSG_DESC *md; size_t sumSize; char *buffer; int error; /* compute sum of message buffer sizes */ for(sumSize=0, md=lcContext.RecvQueue; md != nullptr; md=md->next) { assert(md->msgState==MSTATE_NEW); sumSize += md->bufferSize; } /* allocate buffer for messages */ lcContext.theRecvBuffer = (char *) (*lcContext.RecvAlloc)(sumSize); if (lcContext.theRecvBuffer == nullptr) { Dune::dwarn << "Out of memory in LC_PrepareRecv " << "(size of message buffer: " << sumSize << ")"; RET_ON_ERROR; } /* initiate receive calls */ buffer = lcContext.theRecvBuffer; for(md=lcContext.RecvQueue; md != nullptr; md=md->next) { md->buffer = buffer; buffer += md->bufferSize; md->msgId = RecvASync(context.ppifContext(), VCHAN_TO(context, md->proc), md->buffer, md->bufferSize, &error); md->msgState=MSTATE_COMM; } RET_ON_OK; } /****************************************************************************/ /* MSG_TYPE definition functions */ /****************************************************************************/ /* */ /* Function: LC_NewMsgType */ /* */ /****************************************************************************/ /** Declares new message-type. Before messages may be sent and received with the LowComm subsystem, at least one {\em message-type} must be defined by a global call to this function. Subsequently, calls to \lcfunk{NewMsgTable} and \lcfunk{NewMsgChunk} can be used in order to define the structure of the new message-type. Each message-type in the LowComm subsystem consists of a set of {\em message-components}. Possible message-components are: {\em tables} (with entries of equal size) and raw {\em data chunks}. The set of message-components has the same structure for all messages of the same type, but the number of table entries and the size of the data chunks differ from message to message. @return identifier of new message-type @param aName name of message-type. This string is used for debugging and logging output. */ LC_MSGTYPE LC_NewMsgType(DDD::DDDContext& context, const char *aName) { auto& lcContext = context.lowCommContext(); MSG_TYPE *mt; mt = new MSG_TYPE; mt->name = aName; mt->nComps = 0; /* insert into linked list of message types */ mt->next = lcContext.MsgTypes; lcContext.MsgTypes = mt; return mt; } /****************************************************************************/ /* */ /* Function: LC_NewMsgChunk */ /* */ /****************************************************************************/ /** Add data chunk to current set of a message-type's message-components. This function is called after a previous call to \lcfunk{NewMsgType} in order to add a new message-component to the message-type. The component added by this function is a chunk of raw data. The size of the chunk is not specified here, use \lcfunk{SetChunkSize} for specifying the data chunk size for a given (concrete) message. See \lcfunk{NewMsgTable} for adding message-tables, which are a different kind of message-component. @return identifier of new message-component @param aName name of new message component @param mtyp previously declared message-type */ LC_MSGCOMP LC_NewMsgChunk (const char *aName, LC_MSGTYPE mtyp) { LC_MSGCOMP id = mtyp->nComps++; if (id>=MAX_COMPONENTS) DUNE_THROW(Dune::Exception, "too many message components (max. " << MAX_COMPONENTS << ")"); mtyp->comp[id].type = CT_CHUNK; mtyp->comp[id].name = aName; return(id); } /****************************************************************************/ /* */ /* Function: LC_NewMsgTable */ /* */ /****************************************************************************/ /** Add table to current set of a message-type's message-components. This function is called after a previous call to \lcfunk{NewMsgType} in order to add a new message-component to the message-type. The component added by this function is a table of data, where each table entry has the same size. The overall size of the whole table is not specified here, but only the size for one table entry. Use \lcfunk{SetTableSize} for setting the number of reserved table entries in a given (concrete) message; use \lcfunk{SetTableLen} in order to specify the number of valid entries in a given message. See \lcfunk{NewMsgChunk} for adding data chunks, which are a different kind of message-component. @return identifier of new message-component @param aName name of new message component @param mtyp previously declared message-type @param aSize size of each table entry (in byte) */ LC_MSGCOMP LC_NewMsgTable (const char *aName, LC_MSGTYPE mtyp, size_t aSize) { LC_MSGCOMP id = mtyp->nComps++; if (id>=MAX_COMPONENTS) DUNE_THROW(Dune::Exception, "too many message components (max. " << MAX_COMPONENTS << ")"); mtyp->comp[id].type = CT_TABLE; mtyp->comp[id].entry_size = aSize; mtyp->comp[id].name = aName; return(id); } /****************************************************************************/ /****************************************************************************/ /* */ /* Function: LC_NewSendMsg */ /* */ /****************************************************************************/ /** Create new message on sending processor. This function creates a new message handle on the sending processor and links it into the LowComm send-queue. The message has a given message-type and a given destination processor. Before the message is actually sent (by calling \lcfunk{MsgSend}), the sizes of the message's components must be set (\lcfunk{SetTableSize}, \lcfunk{SetChunkSize}) and the message buffer must be prepared (via \lcfunk{MsgPrepareSend}). After that, the message's tables and chunks can be filled with data and the message sending process can be initiated by \lcfunk{MsgSend}. @return identifier of new message @param mtyp message-type for new message @param aDest destination processor of new message */ LC_MSGHANDLE LC_NewSendMsg(DDD::DDDContext& context, LC_MSGTYPE mtyp, DDD_PROC aDest) { auto& lcContext = context.lowCommContext(); MSG_DESC *msg = NewMsgDesc(context); # if DebugLowComm<=6 Dune::dverb << "LC_NewSendMsg(" << mtyp->name << ") dest=" << aDest << " nSends=" << (lcContext.nSends+1) << "\n"; # endif msg->msgState = MSTATE_NEW; msg->msgType = mtyp; msg->proc = aDest; msg->bufferSize = 0; /* allocate chunks array */ msg->chunks = new CHUNK_DESC[mtyp->nComps]; /* enter message into send queue */ msg->next = lcContext.SendQueue; lcContext.SendQueue = msg; lcContext.nSends++; return msg; } void LC_SetChunkSize (LC_MSGHANDLE md, LC_MSGCOMP id, size_t size) { assert(md->msgState==MSTATE_NEW); assert(id < md->msgType->nComps); md->chunks[id].size = size; md->chunks[id].entries = 1; } void LC_SetTableSize (LC_MSGHANDLE md, LC_MSGCOMP id, ULONG entries) { assert(md->msgState==MSTATE_NEW); assert(id < md->msgType->nComps); md->chunks[id].size = ((int)entries) * md->msgType->comp[id].entry_size; md->chunks[id].entries = entries; } /****************************************************************************/ /* */ /* Function: LC_MsgPrepareSend */ /* */ /****************************************************************************/ /* returns size of message buffer */ size_t LC_MsgPrepareSend (DDD::DDDContext& context, LC_MSGHANDLE msg) { size_t size = LC_MsgFreeze(msg); if (! LC_MsgAlloc(context, msg)) throw std::bad_alloc(); return(size); } DDD_PROC LC_MsgGetProc (const LC_MSGHANDLE md) { return md->proc; } void *LC_GetPtr (LC_MSGHANDLE md, LC_MSGCOMP id) { return ((void *)(((char *)md->buffer) + md->chunks[id].offset)); } void LC_SetTableLen (LC_MSGHANDLE md, LC_MSGCOMP id, ULONG n) { ULONG *hdr = (ULONG *)md->buffer; hdr[HDR_ENTRIES_PER_CHUNK*id+4] = n; md->chunks[id].entries = n; } ULONG LC_GetTableLen (LC_MSGHANDLE md, LC_MSGCOMP id) { return((ULONG)md->chunks[id].entries); } void LC_MsgSend(const DDD::DDDContext& context, LC_MSGHANDLE md) { int error; assert(md->msgState==MSTATE_ALLOCATED); /* initiate asynchronous send */ md->msgId = SendASync(context.ppifContext(), VCHAN_TO(context, md->proc), md->buffer, md->bufferSize, &error); md->msgState=MSTATE_COMM; } size_t LC_GetBufferSize (const LC_MSGHANDLE md) { return(md->bufferSize); } /****************************************************************************/ /****************************************************************************/ /* */ /* Function: LC_Connect */ /* */ /****************************************************************************/ int LC_Connect(DDD::DDDContext& context, LC_MSGTYPE mtyp) { auto& lcContext = context.lowCommContext(); DDD_PROC *partners = DDD_ProcArray(context); NOTIFY_DESC *msgs = DDD_NotifyBegin(context, lcContext.nSends); MSG_DESC *md; int i, p; const auto procs = context.procs(); if (lcContext.nSends<0 || lcContext.nSends>procs-1) DUNE_THROW(Dune::Exception, "cannot send " << lcContext.nSends << "messages " "(must be less than " << (procs-1) << ")"); # if DebugLowComm<=9 Dune::dinfo << "LC_Connect(" << mtyp->name << ") nSends=" << lcContext.nSends << " ...\n"; # endif /* fill notify array */ for(i=0, p=0, md=lcContext.SendQueue; md != nullptr; i++, md=md->next) { msgs[i].proc = md->proc; msgs[i].size = md->bufferSize; /* enhance list of communication partners (destinations) */ partners[p++] = md->proc; } /* inform message receivers */ lcContext.nRecvs = DDD_Notify(context); if (lcContext.nRecvs<0) { /* some processor raised an exception */ Dune::dwarn << "Notify() raised exception #" << (-lcContext.nRecvs) << " in LC_Connect()\n"; /* automatically call LC_Cleanup() */ DDD_NotifyEnd(context); LC_Cleanup(context); return lcContext.nRecvs; } if (lcContext.nRecvs>procs-1) { Dune::dwarn << "cannot receive " << lcContext.nRecvs << " messages (must be less than " << (procs-1) << ")\n"; DDD_NotifyEnd(context); return(EXCEPTION_LOWCOMM_CONNECT); } # if DebugLowComm<=7 Dune::dinfo << "LC_Connect() nSends=" << lcContext.nSends << " nRecvs=" << lcContext.nRecvs << "\n"; # endif /* create array of receive message handles */ if (lcContext.nRecvs>0) lcContext.theRecvArray = new LC_MSGHANDLE[lcContext.nRecvs]; /* create recv messages from notify array */ for(i=0; i < lcContext.nRecvs; i++) { /* create recv message handle and store it in MSGHANDLE array */ lcContext.theRecvArray[i] = LC_NewRecvMsg(context, mtyp, msgs[i].proc, msgs[i].size); /* enhance list of communication partners (sources) */ partners[p++] = msgs[i].proc; } DDD_NotifyEnd(context); /* get necessary connections to comm-partners */ if (p>0) { if (! IS_OK(DDD_GetChannels(context, lcContext.nRecvs+lcContext.nSends))) { DDD_PrintError('E', 6620, "couldn't get channels in LC_Connect()"); return(EXCEPTION_LOWCOMM_CONNECT); } } # if DebugLowComm<=5 DDD_DisplayTopo(context); # endif if (lcContext.nRecvs>0) { if (! IS_OK(LC_PrepareRecv(context))) return(EXCEPTION_LOWCOMM_CONNECT); } # if DebugLowComm<=9 Dune::dinfo << "LC_Connect() ready\n"; # endif return lcContext.nRecvs; } /****************************************************************************/ /* */ /* Function: LC_Abort */ /* */ /****************************************************************************/ int LC_Abort(DDD::DDDContext& context, int exception) { int retException; if (exception>EXCEPTION_LOWCOMM_USER) DUNE_THROW(Dune::Exception, "exception must be <= EXCEPTION_LOWCOMM_USER"); DDD_NotifyBegin(context, exception); # if DebugLowComm<=9 Dune::dwarn << "LC_Abort() exception=" << exception << " ...\n"; # endif /* inform message receivers */ retException = DDD_Notify(context); DDD_NotifyEnd(context); # if DebugLowComm<=9 Dune::dwarn << "LC_Abort() ready, exception=" << retException << "\n"; # endif /* automatically call LC_Cleanup() */ LC_Cleanup(context); return(retException); } /****************************************************************************/ /* */ /* Function: LC_Communicate */ /* */ /****************************************************************************/ LC_MSGHANDLE *LC_Communicate(const DDD::DDDContext& context) { auto& lcContext = context.lowCommContext(); # if DebugLowComm<=9 Dune::dinfo << "LC_Communicate() ...\n"; # endif /* poll asynchronous send and receives */ int leftSend = lcContext.nSends; int leftRecv = lcContext.nRecvs; do { if (leftRecv>0) leftRecv = LC_PollRecv(context); if (leftSend>0) leftSend = LC_PollSend(context); } while (leftRecv>0 || leftSend>0); # if DebugLowComm<=9 Dune::dinfo << "LC_Communicate() ready\n"; # endif return lcContext.theRecvArray; } /****************************************************************************/ /* */ /* Function: LC_Cleanup */ /* */ /****************************************************************************/ void LC_Cleanup(DDD::DDDContext& context) { auto& lcContext = context.lowCommContext(); # if DebugLowComm<=9 Dune::dinfo << "LC_Cleanup() ...\n"; # endif if (lcContext.nRecvs>0) { if (lcContext.RecvFree != nullptr) (lcContext.RecvFree)(lcContext.theRecvBuffer); lcContext.theRecvBuffer = nullptr; } if (lcContext.theRecvArray != nullptr) { delete[] lcContext.theRecvArray; lcContext.theRecvArray = nullptr; } /* free recv queue */ LC_FreeRecvQueue(context); /* free send queue */ LC_FreeSendQueue(context); # if DebugLowComm<=9 Dune::dinfo << "LC_Cleanup() ready\n"; # endif } /****************************************************************************/ #define LC_COLWIDTH 10 static const char* LC_DefaultName = ""; /* construct name or default name */ static const char* LC_Name(const char* name) { return name ? name : LC_DefaultName; } static void LC_PrintMsgList (MSG_DESC *list) { using std::setw; std::ostream& out = std::cout; MSG_DESC *md; MSG_TYPE *last_mt=NULL; size_t sum, comp_size[MAX_COMPONENTS]; int i; for(md=list; md != nullptr; md=md->next) { MSG_TYPE *mt = md->msgType; if (mt!=last_mt) { /* msg-type changes, print new header */ /* first, close part of msg-list with summary */ if (last_mt!=NULL) { out << " = |"; sum = 0; for(i=0; inComps; i++) { out << setw(9) << comp_size[i]; sum += comp_size[i]; /* horizontal sum */ } out << setw(9) << sum << "\n"; } /* then, construct header */ { std::string name = LC_Name(mt->name); out << setw(9) << name.substr(0, 9) << " |"; } for(i=0; inComps; i++) { if (mt->comp[i].name!=NULL) { std::string name = LC_Name(mt->comp[i].name); out << setw(9) << name.substr(0, 9); } else out << setw(9) << i; comp_size[i] = 0; } out << " =\n"; last_mt = mt; } /* construct info about message components */ out << setw(9) << md->proc << " |"; sum = 0; for(i=0; inComps; i++) { size_t s = md->chunks[i].size; out << setw(9) << s; sum += s; /* horizontal sum */ comp_size[i] += s; /* vertical sum */ } out << setw(9) << sum << "\n"; } /* close last part of msg-list with summary */ if (last_mt!=NULL) { out << " = |"; sum = 0; for(i=0; inComps; i++) { out << setw(9) << comp_size[i]; sum += comp_size[i]; /* horizontal sum */ } out << setw(9) << sum << "\n"; } } void LC_PrintSendMsgs(const DDD::DDDContext& context) { LC_PrintMsgList(context.lowCommContext().SendQueue); } void LC_PrintRecvMsgs(const DDD::DDDContext& context) { LC_PrintMsgList(context.lowCommContext().RecvQueue); } /****************************************************************************/ } /* namespace DDD */ dune-uggrid-2.11.0+dfsg/dune/uggrid/parallel/ddd/basic/lowcomm.h000066400000000000000000000131661513616443000244100ustar00rootroot00000000000000// -*- tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- // vi: set et ts=4 sw=2 sts=2: // SPDX-FileCopyrightInfo: Copyright © DUNE Project contributors, see file LICENSE.md in module root // SPDX-License-Identifier: LGPL-2.1-or-later /****************************************************************************/ /* */ /* File: lowcomm.h */ /* */ /* Purpose: lowlevel communication layer */ /* */ /* Author: Klaus Birken */ /* Institut fuer Computeranwendungen III */ /* Universitaet Stuttgart */ /* Pfaffenwaldring 27 */ /* 70569 Stuttgart */ /* internet: birken@ica3.uni-stuttgart.de */ /* */ /* History: 960715 kb begin */ /* */ /* Remarks: */ /* */ /****************************************************************************/ /****************************************************************************/ /* */ /* auto include mechanism and other include files */ /* */ /****************************************************************************/ #ifndef __DDD_LOWCOMM_H__ #define __DDD_LOWCOMM_H__ #include namespace DDD { /****************************************************************************/ /* */ /* defines in the following order */ /* */ /* compile time constants defining static data size (i.e. arrays) */ /* other constants */ /* macros */ /* */ /****************************************************************************/ #define EXCEPTION_LOWCOMM_CONNECT -10 /* lowcomm users should use exceptions EXCEPTION_LOWCOMM_USER or lower */ #define EXCEPTION_LOWCOMM_USER -100 /****************************************************************************/ /* */ /* data structures exported by the corresponding source file */ /* */ /****************************************************************************/ typedef unsigned long ULONG; using MSG_DESC = DDD::Basic::MSG_DESC; using LC_MSGHANDLE = DDD::Basic::LC_MSGHANDLE; using MSG_TYPE = DDD::Basic::MSG_TYPE; using LC_MSGTYPE = DDD::Basic::LC_MSGTYPE; using LC_MSGCOMP = DDD::Basic::LC_MSGCOMP; /* function pointer types for alloc and free */ using AllocFunc = DDD::Basic::AllocFunc; using FreeFunc = DDD::Basic::FreeFunc; /****************************************************************************/ /* */ /* function declarations */ /* */ /****************************************************************************/ /* lowcomm.c */ void LC_Init(DDD::DDDContext& context, AllocFunc,FreeFunc); void LC_Exit(DDD::DDDContext& context); void LC_SetMemMgrSend(DDD::DDDContext&, AllocFunc,FreeFunc); void LC_SetMemMgrRecv(DDD::DDDContext&, AllocFunc,FreeFunc); void LC_SetMemMgrDefault(DDD::DDDContext&); LC_MSGTYPE LC_NewMsgType (DDD::DDDContext& context, const char *); LC_MSGCOMP LC_NewMsgTable (const char *, LC_MSGTYPE, size_t); LC_MSGCOMP LC_NewMsgChunk (const char *, LC_MSGTYPE); void LC_MsgSend (const DDD::DDDContext& context, LC_MSGHANDLE); int LC_Connect(DDD::DDDContext& context, LC_MSGTYPE); int LC_Abort(DDD::DDDContext& context, int); LC_MSGHANDLE *LC_Communicate(const DDD::DDDContext& context); void LC_Cleanup(DDD::DDDContext& context); LC_MSGHANDLE LC_NewSendMsg(DDD::DDDContext& context, LC_MSGTYPE, DDD_PROC); ULONG LC_GetTableLen (LC_MSGHANDLE, LC_MSGCOMP); void * LC_GetPtr (LC_MSGHANDLE, LC_MSGCOMP); DDD_PROC LC_MsgGetProc (LC_MSGHANDLE); size_t LC_MsgPrepareSend(DDD::DDDContext& context, LC_MSGHANDLE); size_t LC_MsgFreeze (LC_MSGHANDLE); int LC_MsgAlloc(DDD::DDDContext& context, LC_MSGHANDLE); void LC_SetTableLen (LC_MSGHANDLE, LC_MSGCOMP, ULONG); void LC_SetTableSize (LC_MSGHANDLE, LC_MSGCOMP, ULONG); void LC_SetChunkSize (LC_MSGHANDLE, LC_MSGCOMP, size_t); size_t LC_GetBufferSize (LC_MSGHANDLE); void LC_PrintSendMsgs(const DDD::DDDContext& context); void LC_PrintRecvMsgs(const DDD::DDDContext& context); } /* namespace DDD */ #endif dune-uggrid-2.11.0+dfsg/dune/uggrid/parallel/ddd/basic/notify.cc000066400000000000000000000323741513616443000244030ustar00rootroot00000000000000// SPDX-FileCopyrightText: Copyright © DUNE Project contributors, see file LICENSE.md in module root // SPDX-License-Identifier: LGPL-2.1-or-later // -*- tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- // vi: set et ts=4 sw=2 sts=2: /****************************************************************************/ /* */ /* File: notify.c */ /* */ /* Purpose: notifies destinations for communication with globally */ /* unknown topology */ /* */ /* Author: Klaus Birken */ /* Rechenzentrum Uni Stuttgart */ /* Universitaet Stuttgart */ /* Allmandring 30 */ /* 70550 Stuttgart */ /* internet: birken@rus.uni-stuttgart.de */ /* */ /* History: 94/01/17 kb begin */ /* 95/04/06 kb added SpreadNotify */ /* 96/07/12 kb united xxxNotify functions to one DDD_Notify() */ /* */ /* Remarks: */ /* */ /****************************************************************************/ /****************************************************************************/ /* */ /* include files */ /* system include files */ /* application include files */ /* */ /****************************************************************************/ /* standard C library */ #include #include #include #include #include #include #include #include #include "notify.h" #include #include USING_UG_NAMESPACES /* PPIF namespace: */ using namespace PPIF; #define DebugNotify 10 /* 0 is all, 10 is off */ #define PROC_INVALID_TEMP -1 /****************************************************************************/ /* */ /* routines */ /* */ /****************************************************************************/ namespace DDD { using namespace DDD::Basic; static int MAX_INFOS(int procs) { return procs * std::max(1+procs, 10); } void NotifyInit(DDD::DDDContext& context) { auto& ctx = context.notifyContext(); const auto procs = context.procs(); /* allocate memory */ ctx.theRouting.resize(procs); ctx.maxInfos = MAX_INFOS(procs); /* TODO maximum value, just for testing */ /* init local array for all Info records */ ctx.allInfoBuffer.resize(ctx.maxInfos); /* allocate array of NOTIFY_DESCs */ ctx.theDescs.resize(procs-1); } void NotifyExit(DDD::DDDContext& context) { auto& ctx = context.notifyContext(); /* free memory */ ctx.theRouting.clear(); ctx.allInfoBuffer.clear(); ctx.theDescs.clear(); } /****************************************************************************/ static bool sort_XferInfos(const NOTIFY_INFO& a, const NOTIFY_INFO& b) { return std::tie(a.to, a.from) < std::tie(b.to, b.from); } static bool sort_XferFlags(const NOTIFY_INFO& a, const NOTIFY_INFO& b) { return a.flag < b.flag; } static NOTIFY_INFO *NotifyPrepare (DDD::DDDContext& context) { auto& ctx = context.notifyContext(); const auto& me = context.me(); #if DebugNotify<=4 printf("%4d: NotifyPrepare\n", me); fflush(stdout); #endif /* init local array for all Info records */ NOTIFY_INFO* allInfos = ctx.allInfoBuffer.data(); /* init local routing array */ ctx.theRouting[me] = -1; /* dummy Info if there is no message to be send */ allInfos[0].from = me; allInfos[0].to = PROC_INVALID_TEMP; allInfos[0].size = 0; allInfos[0].flag = NotifyTypes::DUMMY; ctx.lastInfo = 1; return allInfos; } /****************************************************************************/ /* If the parameter 'exception' is !=0, this processor invokes a global exception, which will cause all processors to abort this notify procedure and return the exception code with flipped sign. If more processors issue exception codes, the maximum will be communicated. */ static int NotifyTwoWave(DDD::DDDContext& context, NOTIFY_INFO *allInfos, int lastInfo, int exception) { auto& ctx = context.notifyContext(); const auto& me = context.me(); const auto& degree = context.ppifContext().degree(); NOTIFY_INFO *newInfos; int l, i, j, n, unknownInfos, myInfos; int local_exception = exception; #if DebugNotify<=4 printf("%4d: NotifyTwoWave, lastInfo=%d\n", me, lastInfo); fflush(stdout); #endif /* BOTTOM->TOP WAVE */ /* get local Info lists from downtree */ for(l=degree-1; l>=0; l--) { GetConcentrate(context.ppifContext(), l, &n, sizeof(int)); if (n<0) { /* exception from downtree, propagate */ if (-n > local_exception) local_exception = -n; } if (lastInfo+n >= ctx.maxInfos) { DDD_PrintError('E', 6321, "msg-info array overflow in NotifyTwoWave"); local_exception = EXCEPTION_NOTIFY; /* receive data, but put it onto dummy position */ GetConcentrate(context.ppifContext(), l, allInfos, n*sizeof(NOTIFY_INFO)); } else { if (n>0) GetConcentrate(context.ppifContext(), l, &(allInfos[lastInfo]), n*sizeof(NOTIFY_INFO)); } /* construct routing table */ for(i=0; i0) lastInfo += n; } if (! local_exception) { /* determine target direction in tree */ /* TODO: eventually extra solution for root node! (it knows all flags are MYSELF or KNOWN!) */ std::sort(allInfos, allInfos + lastInfo, sort_XferInfos); i = j = 0; unknownInfos = lastInfo; myInfos = 0; while (iBOTTOM WAVE */ /* get Infos local to my subtree from uptree */ unknownInfos = 0; GetSpread(context.ppifContext(), &unknownInfos, sizeof(int)); if (unknownInfos<0) { /* exception from downtree, propagate */ if (-unknownInfos > local_exception) local_exception = -unknownInfos; } if (unknownInfos>0) { GetSpread(context.ppifContext(), newInfos, unknownInfos*sizeof(NOTIFY_INFO)); lastInfo += unknownInfos; } if (! local_exception) { /* sort Infos according to routing */ std::sort( allInfos, allInfos + lastInfo, [&ctx](const NOTIFY_INFO& a, const NOTIFY_INFO& b) { return ctx.theRouting[a.to] < ctx.theRouting[b.to]; }); #if DebugNotify<=1 for(i=0; i0) Spread(context.ppifContext(), l, &allInfos[i-j], j*sizeof(NOTIFY_INFO)); } /* reuse theDescs-array for registering messages to be received */ for(i=0; i context.procs()-1) { DDD_PrintError('E', 6340, "more send-messages than other processors in DDD_NotifyBegin"); return nullptr; } return ctx.theDescs.data(); } void DDD_NotifyEnd(DDD::DDDContext&) { /* free'ing of theDescs is done in NotifyExit() */ } int DDD_Notify(DDD::DDDContext& context) { auto& ctx = context.notifyContext(); int i, nRecvMsgs; const auto me = context.me(); const auto procs = context.procs(); /* get storage for local info list */ NOTIFY_INFO* allInfos = NotifyPrepare(context); if (allInfos == nullptr) return(ERROR); if (ctx.nSendDescs<0) { /* this processor is trying to send a global notification message. this is necessary for communicating fatal error conditions to all other processors. */ Dune::dwarn << "DDD_Notify: proc " << me << " is sending global exception #" << (-ctx.nSendDescs) << "\n"; /* notify partners */ nRecvMsgs = NotifyTwoWave(context, allInfos, ctx.lastInfo, -ctx.nSendDescs); } else { /* convert message list to local Info list */ for(i=0; i=procs) { Dune::dwarn << "DDD_Notify: proc " << me << " is trying to send message to proc " << ctx.theDescs[i].proc << "\n"; return(ERROR); } allInfos[ctx.lastInfo].from = me; allInfos[ctx.lastInfo].to = ctx.theDescs[i].proc; allInfos[ctx.lastInfo].size = ctx.theDescs[i].size; allInfos[ctx.lastInfo].flag = NotifyTypes::UNKNOWN; ctx.lastInfo++; } /* notify partners */ nRecvMsgs = NotifyTwoWave(context, allInfos, ctx.lastInfo, 0); } # if DebugNotify<=4 for(i=0; i #include namespace DDD { /****************************************************************************/ /* */ /* data structures */ /* */ /****************************************************************************/ #define EXCEPTION_NOTIFY -1 /****************************************************************************/ /* */ /* data structures */ /* */ /****************************************************************************/ using NOTIFY_DESC = DDD::Basic::NOTIFY_DESC; /****************************************************************************/ /* */ /* function declarations */ /* */ /****************************************************************************/ void NotifyInit(DDD::DDDContext& context); void NotifyExit(DDD::DDDContext& context); NOTIFY_DESC *DDD_NotifyBegin(DDD::DDDContext& context, int); void DDD_NotifyEnd(DDD::DDDContext& context); int DDD_Notify(DDD::DDDContext& context); } /* namespace DDD */ #endif dune-uggrid-2.11.0+dfsg/dune/uggrid/parallel/ddd/basic/oopp.h000066400000000000000000000115371513616443000237100ustar00rootroot00000000000000// -*- tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- // vi: set et ts=4 sw=2 sts=2: // SPDX-FileCopyrightInfo: Copyright © DUNE Project contributors, see file LICENSE.md in module root // SPDX-License-Identifier: LGPL-2.1-or-later /****************************************************************************/ /* */ /* File: oopp.h */ /* */ /* Purpose: macros for implementing some rudimentary object-oriented */ /* techniques via the C preprocessor. */ /* */ /* Author: Klaus Birken */ /* Institut fuer Computeranwendungen III */ /* Universitaet Stuttgart */ /* Pfaffenwaldring 27 */ /* 70569 Stuttgart */ /* email: birken@ica3.uni-stuttgart.de */ /* phone: 0049-(0)711-685-7007 */ /* fax : 0049-(0)711-685-7000 */ /* */ /* History: 970720 kb begin */ /* */ /* Remarks: */ /* */ /****************************************************************************/ #ifndef __OOPP_H__ #define __OOPP_H__ /****************************************************************************/ /* */ /* basic text manipulation macros */ /* */ /****************************************************************************/ #define _CCAT(a,b) a ## b #define CCAT(a,b) _CCAT(a,b) #define CALL(a,b) CCAT(CCAT(a,_),b) /****************************************************************************/ /* */ /* class declaration */ /* */ /****************************************************************************/ /* from now on, we assume a previous '#define ClassPrefix XXX' */ /* construction of class-name */ #ifdef ClassPrefix #define CN(C) CCAT(ClassPrefix,C) #else #define CN(C) C #endif /* from now on, we suppose a '#define ClassName XXX' for a given class */ #define Class CN(ClassName) /* internal class-name */ #define ClassPtr Class* #define ClassRef ClassPtr /* #define VoidRef void * */ #define Class_Data_Begin struct Class { #define Class_Data_End }; #define Method(M) CCAT(CCAT(ClassName,_),M) /* support for easy 'This' */ #define This _oopp_this /* #define DefThis ClassRef #define ParamThis ClassRef This */ #define DefThis Class * #define ParamThis Class * This /****************************************************************************/ /* */ /* standard class methods */ /* */ /****************************************************************************/ /*** constructor (NewClass) ***/ /* macros for prototype */ #define Method_New_ ClassPtr CCAT(New_,ClassName) #define Method_New(O) ClassPtr CCAT(CCAT(New_,ClassName),O) /* overload */ /* macros for implementation */ #define Construct(item,check) \ ClassPtr item=(ClassPtr) OO_Allocate (sizeof(Class)); \ { check; } #define Destruct(item) OO_Free(item) /****************************************************************************/ /* */ /* inheritance */ /* */ /****************************************************************************/ #define BaseClass(BC) typedef CN (BC) Class /****************************************************************************/ #endif dune-uggrid-2.11.0+dfsg/dune/uggrid/parallel/ddd/basic/ooppcc.h000066400000000000000000000551441513616443000242200ustar00rootroot00000000000000// -*- tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- // vi: set et ts=4 sw=2 sts=2: // SPDX-FileCopyrightInfo: Copyright © DUNE Project contributors, see file LICENSE.md in module root // SPDX-License-Identifier: LGPL-2.1-or-later /****************************************************************************/ /* */ /* File: ooppcc.h */ /* */ /* Purpose: macros and templates for oopp-container classes. */ /* (object-oriented pre-processing container classes). */ /* */ /* Author: Klaus Birken */ /* Institut fuer Computeranwendungen III */ /* Universitaet Stuttgart */ /* Pfaffenwaldring 27 */ /* 70569 Stuttgart */ /* email: birken@ica3.uni-stuttgart.de */ /* phone: 0049-(0)711-685-7007 */ /* fax : 0049-(0)711-685-7000 */ /* */ /* History: 970902 kb begin */ /* 971015 kb added ArrayOf, BTreeOf */ /* 971020 kb added SetOf */ /* */ /* Remarks: */ /* */ /****************************************************************************/ /****************************************************************************/ #ifdef PtrOf /****************************************************************************/ #define Ptr(T) CN(CCAT(T,Ptr)) /* class name for ptr */ #define CPtr CCAT(PtrOf,Ptr) /* an object's pointer class is simply a C pointer to the object */ typedef PtrOf * CPtr; /****************************************************************************/ #undef CPtr #undef PtrOf #endif /****************************************************************************/ /****************************************************************************/ #ifdef SegmListOf /****************************************************************************/ #define SegmList(T) CN(CCAT(T,SegmList)) /* class names for segmlist and segment */ #define CSegm CCAT(SegmListOf,Segm) #define CSegmList CCAT(SegmListOf,SegmList) #ifndef SegmSize /* define default size of each segment */ #define SegmSize 256 #endif /*** one segment ***/ #define ClassName CSegm Class_Data_Begin CN(SegmListOf) data[SegmSize]; int nItems; ClassPtr next; Class_Data_End Method_New_ (_NEWPARAMS_OR_VOID); void Method(Free) (DefThis); void Method(Print) (DefThis _PRINTPARAMS); #ifdef ContainerImplementation Method_New_ (_NEWPARAMS_OR_VOID) { Construct(This, _CHECKALLOC(This)); This->nItems = 0; return(This); } void Method(Free) (ParamThis) { Destruct(This); } #endif #undef ClassName /*** the segm-list ***/ #define ClassName CSegmList Class_Data_Begin CSegm *first; int nItems; int nSegms; int nDiscarded; Class_Data_End Method_New_ (_NEWPARAMS_OR_VOID); void Method(Free) (DefThis); CN(SegmListOf) *Method(NewItem) (DefThis); void Method(DiscardItem) (DefThis); void Method(Reset) (DefThis); int Method(GetNItems) (DefThis); int Method(GetNDiscarded) (DefThis); void Method(GetResources) (DefThis, int *, int *, size_t *, size_t *); #ifdef ContainerImplementation Method_New_ (_NEWPARAMS_OR_VOID) { Construct(This, _CHECKALLOC(This)); This->first = NULL; This->nItems = 0; This->nSegms = 0; This->nDiscarded = 0; return(This); } void Method(Free) (ParamThis) { CALL(CSegmList,Reset) (This); Destruct(This); } CN(SegmListOf) *Method(NewItem) (ParamThis) { CN(SegmListOf) *item; CSegm *segm = This->first; if (segm==NULL || segm->nItems==SegmSize) { segm = CALL(New,CSegm) (); if (segm==NULL) return(NULL); segm->next = This->first; This->first = segm; This->nSegms++; } /* get item address in current segment */ item = &(segm->data[segm->nItems++]); /* count item */ This->nItems++; return(item); } int Method(GetNItems) (ParamThis) { return(This->nItems); } int Method(GetNDiscarded) (ParamThis) { return(This->nDiscarded); } void Method(DiscardItem) (ParamThis) { assert(This!=NULL); assert(This->first!=NULL); assert(This->first->nItems > 0); This->first->nItems--; This->nItems--; This->nDiscarded++; } void Method(Reset) (ParamThis) { CSegm *segm, *next; segm = This->first; next = NULL; while (segm!=NULL) { next = segm->next; CALL(CSegm,Free) (segm); segm = next; } This->first = NULL; This->nItems = 0; This->nSegms = 0; This->nDiscarded = 0; } void Method(GetResources) (ParamThis, int *nSegms, int *nItems, size_t *alloc_mem, size_t *used_mem) { size_t allocated=0, used=0; CSegm *segm; for (segm=This->first; segm!=NULL; segm=segm->next) { /* compute memory usage */ allocated += sizeof(CSegm); used += (sizeof(CSegm) - (sizeof(CN(SegmListOf)) * (SegmSize-segm->nItems))); } *nSegms = This->nSegms; *nItems = This->nItems; *alloc_mem = allocated; *used_mem = used; } #endif #undef ClassName /****************************************************************************/ #undef CSegm #undef CSegmList #undef SegmSize #undef SegmListOf #endif /****************************************************************************/ /****************************************************************************/ #ifdef ListOf /****************************************************************************/ #define List(T) CN(CCAT(T,List)) /* class names for list and list item */ #define CListItem CCAT(ListOf,ListItem) #define CList CCAT(ListOf,List) /* method pointers */ #define Find_Method CCAT(ListOf,FindMethod) typedef int (*Find_Method)(CN(ListOf) *); /*** Item of list class ***/ #define ClassName CListItem Class_Data_Begin CN(ListOf) *data; ClassPtr next; Class_Data_End Method_New_ (CN(ListOf) * _NEWPARAMS); void Method(Print) (DefThis _PRINTPARAMS); #ifdef ContainerImplementation Method_New_ (CN(ListOf) *data _NEWPARAMS) { Construct(This, _CHECKALLOC(This)); This->data = data; This->next = NULL; return(This); } void Method(Print) (ParamThis _PRINTPARAMS) { CALL(ListOf,Print) (This->data _PRINTNEXT); } #endif #undef ClassName /*** List class ***/ #define ClassName CList Class_Data_Begin CN(CListItem) *first; CN(CListItem) *last; Class_Data_End Method_New_ (_NEWPARAMS_OR_VOID); void Method(Print) (DefThis _PRINTPARAMS); ClassRef Method(Append) (DefThis, CN(ListOf) *); CN(ListOf) *Method(Find) (DefThis, Find_Method); #ifdef ContainerImplementation Method_New_ (_NEWPARAMS_OR_VOID) { Construct(This, _CHECKALLOC(This)); This->first = NULL; This->last = NULL; return(This); } void Method(Print) (ParamThis _PRINTPARAMS) { CN(CListItem) *item; for(item=This->first; item!=NULL; item=item->next) CALL(CListItem,Print) (item _PRINTSAME); } ClassRef Method(Append) (ParamThis, CN(ListOf) *data) { CN(CListItem) *item; if (data==NULL) return(This); /* create item and link it into list */ item = CALL(New,CListItem) (data); assert(item!=NULL); if (This->first==NULL) { This->first = item; This->last = item; } else { This->last->next = item; This->last = item; } return(This); } CN(ListOf) * Method(Find) (ParamThis, Find_Method find_data) { CN(CListItem) *item; for (item=This->first; item!=NULL; item=item->next) { if ((*find_data)(item->data)) return(item->data); } return(NULL); } #endif #undef ClassName /*** List iterator class ***/ /* iterator is simply a pointer to a CListItem */ #define ListIter(T) CN(CCAT(T,ListIter)) typedef CN (CListItem) * ListIter (ListOf); #ifndef __ListIterator__ #define __ListIterator__ /* forward iterator */ #define ListFirst(list) ((list)->first) #define ListNext(iter) ((iter)->next) #define ListIsDone(iter) ((iter)==NULL) #define ListCurrent(iter) ((iter)->data) #endif /****************************************************************************/ #undef CListItem #undef CList #undef Find_Method #undef ListOf #endif /****************************************************************************/ /****************************************************************************/ #ifdef BTreeOf /****************************************************************************/ /* class names for btree and btree node */ #define CBTreeNode CCAT(BTreeOf,BTreeNode) #define CBTree CCAT(BTreeOf,BTree) /* method pointers */ #define Iterate_Method CCAT(BTreeOf,IterateMethod) typedef void (*Iterate_Method)(CN(BTreeOf) *); /* not used #define Compare_Method CCAT(BTreeOf,CompareMethod) typedef int (*Compare_Method) (CN(BTreeOf) *, CN(BTreeOf) *); */ #ifndef BTreeOrder /* define default order of BTree */ #define BTreeOrder 8 #endif /* now the definitions for _all_ BTrees */ #ifndef BTreeGeneral #define BTreeGeneral enum BTreeConstant { BTREE_ERROR, BTREE_INSERTED, BTREE_FOUND, BTREE_SPLIT_ME }; #endif /*** node of BTree class ***/ #define ClassName CBTreeNode Class_Data_Begin int nSons; ClassPtr sons[BTreeOrder+1]; CN(BTreeOf) *data[BTreeOrder]; Class_Data_End /* no method declaration here, all methods are static */ #ifdef ContainerImplementation static Method_New_ (CN(BTreeOf) *item, ClassPtr son_l, ClassPtr son_r _NEWPARAMS) { Construct(This, _CHECKALLOC(This)); This->nSons = 2; This->sons[0] = son_l; This->sons[1] = son_r; This->data[0] = item; return(This); } static void Method(Print) (ParamThis _PRINTPARAMS) { int i; if (This==NULL) return; _INDENT; fprintf(fp, "NODE nSons=%d\n", This->nSons); for(i=0; inSons-1; i++) { if (This->sons[i]!=NULL) Method(Print) (This->sons[i] _PRINTNEXT); _INDENT1; CALL(BTreeOf,Print) (This->data[i] _PRINTNEXT); } if (This->sons[i]!=NULL) Method(Print) (This->sons[i] _PRINTNEXT); } static void Method(Free) (ParamThis) { int i; /* free all son nodes */ for(i=0; inSons; i++) { if (This->sons[i]!=NULL) { Method(Free) (This->sons[i]); } } /* destruct this node */ Destruct(This); } static ClassPtr Method(Split) (ParamThis, CN(BTreeOf) **split_item) { int split, l, r; Construct(rnode, _CHECKALLOC(rnode)); /* compute split index, left part is at most one item smaller */ split = ((BTreeOrder+1)>>1)-1; /*printf("\t\tsplit_index = %d\n", split);*/ for(l=split+1, r=0; lnSons-1; l++, r++) { rnode->sons[r] = This->sons[l]; rnode->data[r] = This->data[l]; } rnode->sons[r] = This->sons[l]; rnode->nSons = This->nSons-split-1; This->nSons = split+1; /*BTreeNodePrint(lnode,9);*/ /*BTreeNodePrint(rnode,9);*/ /* set return values */ *split_item = This->data[split]; return(rnode); } static void Method(FreeIndex) (ParamThis, int idx) { int j, n=This->nSons; This->sons[n] = This->sons[n-1]; for(j=n-1; j>idx; j--) { This->sons[j] = This->sons[j-1]; This->data[j] = This->data[j-1]; } This->nSons++; } static enum BTreeConstant Method(Insert) (ParamThis, /*Compare_Method cmp_func,*/ CN(BTreeOf) *item, const DDD::DDDContext* context) { int i, nData = This->nSons-1; enum BTreeConstant ret; /* find position in node */ if (nData < 4) { /* only a few entries -> use linear search */ bool found=false; for(i=0; idata[i], item);*/ /* NOTE: the order of arguments for Compare is crucial! first comes the existing key/item, 2nd the new one. */ int cmp = CALL(CN(BTreeOf), Compare) (This->data[i], item, context); if (cmp==0) { /* already inserted, return and report FOUND */ return(BTREE_FOUND); } if (cmp>0) found = true; } if (found) i--; } else { /* many entries -> use binary search */ int l=0, r=nData-1; do { int m = (l+r)>>1; /* NOTE: the order of arguments for Compare is crucial! first comes the existing key/item, 2nd the new one. */ int cmp = CALL(CN(BTreeOf), Compare) (This->data[m], item, context); if (cmp==0) { /* already inserted, return and report FOUND */ return(BTREE_FOUND); } if (cmp<0) l = m+1; else r = m-1; } while (l<=r); /* the correct position is between keys r and l (in that order!) */ /* i will be set to the index at the right of the correct position */ i = l; } if (This->sons[i]!=NULL) { /* case A: key must be in subtree i, recurse into it */ ret = Method(Insert) (This->sons[i], /*cmp_func,*/ item, context); if (ret==BTREE_SPLIT_ME) { ClassPtr new_r; CN(BTreeOf) *split_item; new_r = Method(Split) (This->sons[i], &split_item); assert(new_r!=NULL); if (idata[i] = split_item; This->sons[i+1] = new_r; } else { This->data[i] = split_item; This->sons[i+1] = new_r; This->nSons++; } if (This->nSonsdata[i] = item; } else { This->data[i] = item; This->sons[i+1] = NULL; This->nSons++; } ret = (This->nSonsnSons-1; i++) { if (This->sons[i]!=NULL) { Method(Iterate) (This->sons[i], iter_method); } /* call iterator method */ (*iter_method)(This->data[i]); } if (This->sons[i]!=NULL) { Method(Iterate) (This->sons[i], iter_method); } } static CN(BTreeOf) **Method(Linearize) (ParamThis, CN(BTreeOf) **ptr) { int i; for(i=0; inSons-1; i++) { if (This->sons[i]!=NULL) { ptr = Method(Linearize) (This->sons[i], ptr); } *ptr++ = This->data[i]; } if (This->sons[i]!=NULL) { ptr = Method(Linearize) (This->sons[i], ptr); } return(ptr); } static void Method(GetResources) (ParamThis, int *nNodes, size_t *alloc_mem, size_t *used_mem) { size_t allocated=0, used=0; int i, nodes=0; for(i=0; inSons; i++) { if (This->sons[i]!=NULL) { int i1; size_t s1, s2; Method(GetResources) (This->sons[i], &i1, &s1, &s2); nodes += i1; allocated += s1; used += s2; } } *nNodes = nodes + 1; *alloc_mem = allocated + sizeof(CBTreeNode); *used_mem = used + ((1 + 2*This->nSons) * (sizeof(void *))); } #endif #undef ClassName /*** BTree class ***/ #define ClassName CBTree Class_Data_Begin CN(CBTreeNode) *root; int nItems; const DDD::DDDContext* context; /*Compare_Method compare_func;*/ Class_Data_End Method_New_ (/*Compare_Method*/ _NEWPARAMS_OR_VOID); void Method(Free) (DefThis); void Method(Print) (DefThis _PRINTPARAMS); void Method(Reset) (DefThis); int Method(Insert) (DefThis, CN(BTreeOf) *); void Method(Iterate) (DefThis, Iterate_Method); std::vector Method(GetArray) (DefThis); void Method(GetResources) (DefThis, int *, int *, size_t *, size_t *); #ifdef ContainerImplementation Method_New_ (/*Compare_Method compare_func*/ _NEWPARAMS_OR_VOID) { Construct(This, _CHECKALLOC(This)); This->root = NULL; This->nItems = 0; This->context = nullptr; /*This->compare_func = compare_func;*/ return(This); } void Method(Free) (ParamThis) { CALL(CBTree, Reset)(This); Destruct(This); } void Method(Print) (ParamThis _PRINTPARAMS) { CALL(CBTreeNode,Print) (This->root _PRINTSAME); } void Method(Reset) (ParamThis) { if (This->root!=NULL) { CALL(CBTreeNode,Free) (This->root); } This->root = NULL; This->nItems = 0; } int Method(Insert) (ParamThis, CN(BTreeOf) *item) { enum BTreeConstant ret; if (This->root==NULL) { This->root = CALL(New,CBTreeNode) (item,NULL,NULL); assert(This->root!=NULL); This->nItems++; return(true); } ret = CALL(CBTreeNode,Insert) (This->root, /*This->compare_func,*/ item, This->context); if (ret==BTREE_SPLIT_ME) { CBTreeNode *new_l, *new_r; CN(BTreeOf) *split_item; new_l = This->root; new_r = CALL(CBTreeNode,Split) (new_l, &split_item); assert(new_r!=NULL); This->root = CALL(New,CBTreeNode) (split_item, new_l, new_r); assert(This->root!=NULL); } if (ret!=BTREE_FOUND) This->nItems++; /* return true if item was really inserted */ return(ret!=BTREE_FOUND); } void Method(Iterate) (ParamThis, Iterate_Method iter_method) { if (This->root!=NULL) CALL(CBTreeNode,Iterate) (This->root, iter_method); } std::vector Method(GetArray) (ParamThis) { std::vector array(This->nItems); if (This->nItems != 0) { BTreeOf** ptr = array.data(); CALL(CBTreeNode,Linearize) (This->root, ptr); } return array; } void Method(GetResources) (ParamThis, int *nNodes, int *nItems, size_t *alloc_mem, size_t *used_mem) { size_t allocated=0, used=0; int nodes=0; if (This->root!=NULL) { CALL(CBTreeNode,GetResources) (This->root, &nodes, &allocated, &used); } *nNodes = nodes; *nItems = This->nItems; *alloc_mem = allocated + sizeof(CBTree); *used_mem = used + sizeof(CBTree); } #endif #undef ClassName /****************************************************************************/ #undef CBTreeNode #undef CBTree /*#undef Compare_Method*/ #undef BTreeOrder #undef BTreeOf #endif /****************************************************************************/ /****************************************************************************/ #ifdef SetOf #ifndef CSet /****************************************************************************/ /* this class is implemented by using a SegmList for storing the actual data and a BTree for fast access, sorting and uniqueness. */ /* class name for set */ #define CSet CCAT(SetOf,Set) /* set default values for parameters */ #ifndef Set_SegmSize #define Set_SegmSize 256 /* default size of each segment in SegmList */ #endif #ifndef Set_BTreeOrder #define Set_BTreeOrder 32 /* default order of BTree */ #endif /* instantiate all template types we will need lateron */ #define PtrOf SetOf #define SegmListOf SetOf #define SegmSize Set_SegmSize #define BTreeOf SetOf #define BTreeOrder Set_BTreeOrder #include "ooppcc.h" /****************************************************************************/ #define Set(T) CN(CCAT(T,Set)) /* class names for set, segmlist and btree */ #define CSet CCAT(SetOf,Set) #define CSegmList CCAT(SetOf,SegmList) #define CBTree CCAT(SetOf,BTree) /*** Set class ***/ #define ClassName CSet Class_Data_Begin CSegmList *list; CBTree *tree; CN(SetOf) *last_item; /* temp storage for last call to NewItem() */ Class_Data_End Method_New_ (_NEWPARAMS_OR_VOID); void Method(Free) (DefThis); void Method(Print) (DefThis _PRINTPARAMS); void Method(Reset) (DefThis); CN(SetOf) *Method(NewItem) (DefThis); int Method(ItemOK) (DefThis); int Method(GetNItems) (DefThis); int Method(GetNDiscarded) (DefThis); std::vector Method(GetArray) (DefThis); void Method(GetResources) (DefThis, int *, int *, int *, size_t *, size_t *); #ifdef ContainerImplementation Method_New_ (_NEWPARAMS_OR_VOID) { Construct(This, _CHECKALLOC(This)); This->list = CALL(New, CSegmList) (); assert(This->list!=NULL); This->tree = CALL(New, CBTree) (); assert(This->tree!=NULL); This->last_item = NULL; return(This); } void Method(Free) (ParamThis) { CALL(CSegmList,Free) (This->list); CALL(CBTree,Free) (This->tree); Destruct(This); } void Method(Print) (ParamThis _PRINTPARAMS) { /* CALL(CSegmList,Print) (This->list _PRINTNEXT); */ CALL(CBTree,Print) (This->tree _PRINTNEXT); } void Method(Reset) (ParamThis) { CALL(CSegmList,Reset) (This->list); CALL(CBTree,Reset) (This->tree); } CN(SetOf) *Method(NewItem) (ParamThis) { This->last_item = CALL(CSegmList,NewItem) (This->list); return(This->last_item); } int Method(ItemOK) (ParamThis) { if (CALL(CBTree,Insert) (This->tree, This->last_item)) { /* item could be inserted in btree, hence it was a new one. */ return(true); } /* item was in tree already, it was an old one. */ CALL(CSegmList,DiscardItem) (This->list); return(false); } int Method(GetNItems) (ParamThis) { return(CALL(CSegmList,GetNItems) (This->list)); } int Method(GetNDiscarded) (ParamThis) { return(CALL(CSegmList,GetNDiscarded) (This->list)); } std::vector Method(GetArray) (ParamThis) { return(CALL(CBTree,GetArray) (This->tree)); } void Method(GetResources) (ParamThis, int *nSegms, int *nItems, int *nNodes, size_t *alloc_mem, size_t *used_mem) { size_t allocated=0, used=0; CALL(CSegmList,GetResources) (This->list, nSegms, nItems, &allocated, &used); *alloc_mem = allocated; *used_mem = used; CALL(CBTree,GetResources) (This->tree, nNodes, nItems, &allocated, &used); *alloc_mem += allocated; *used_mem += used; *alloc_mem += sizeof(CSet); *used_mem += sizeof(CSet); } #endif #undef ClassName /****************************************************************************/ #undef CSegmList #undef CBTree #undef CSet #undef SetOf #endif #endif /****************************************************************************/ /****************************************************************************/ dune-uggrid-2.11.0+dfsg/dune/uggrid/parallel/ddd/basic/reduct.cc000066400000000000000000000067431513616443000243620ustar00rootroot00000000000000// SPDX-FileCopyrightText: Copyright © DUNE Project contributors, see file LICENSE.md in module root // SPDX-License-Identifier: LGPL-2.1-or-later // -*- tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- // vi: set et ts=4 sw=2 sts=2: /****************************************************************************/ /* */ /* File: reduct.c */ /* */ /* Purpose: standard parallel routines not supported by ddd */ /* reduction operations (GlobalSum, GlobalMax etc) */ /* */ /* Author: Klaus Birken */ /* Rechenzentrum Uni Stuttgart */ /* Universitaet Stuttgart */ /* Allmandring 30 */ /* 70550 Stuttgart */ /* internet: birken@rus.uni-stuttgart.de */ /* */ /* History: 940128 kb begin */ /* 960902 kb copied from fedemo, adapted */ /* */ /* Remarks: */ /* */ /****************************************************************************/ /****************************************************************************/ /* */ /* include files */ /* system include files */ /* application include files */ /* */ /****************************************************************************/ #include "config.h" #include #include #include #include namespace DDD { /****************************************************************************/ /* */ /* routines */ /* */ /****************************************************************************/ /* some useful functions by Peter Bastian, from ugp/ug/ugcom.c */ int ddd_GlobalMaxInt(const DDD::DDDContext& context, int i) { MPI_Allreduce(MPI_IN_PLACE, &i, 1, MPI_INT, MPI_MAX, context.ppifContext().comm()); return i; } int ddd_GlobalMinInt(const DDD::DDDContext& context, int i) { MPI_Allreduce(MPI_IN_PLACE, &i, 1, MPI_INT, MPI_MIN, context.ppifContext().comm()); return i; } int ddd_GlobalSumInt(const DDD::DDDContext& context, int x) { MPI_Allreduce(MPI_IN_PLACE, &x, 1, MPI_INT, MPI_SUM, context.ppifContext().comm()); return x; } } /* namespace DDD */ dune-uggrid-2.11.0+dfsg/dune/uggrid/parallel/ddd/basic/test/000077500000000000000000000000001513616443000235325ustar00rootroot00000000000000dune-uggrid-2.11.0+dfsg/dune/uggrid/parallel/ddd/basic/test/CMakeLists.txt000066400000000000000000000003371513616443000262750ustar00rootroot00000000000000# SPDX-FileCopyrightText: Copyright © DUNE Project contributors, see file LICENSE.md in module root # SPDX-License-Identifier: LGPL-2.1-or-later dune_add_test(SOURCES testbtree.cc LINK_LIBRARIES duneuggrid) dune-uggrid-2.11.0+dfsg/dune/uggrid/parallel/ddd/basic/test/testbtree.cc000066400000000000000000000050651513616443000260500ustar00rootroot00000000000000// SPDX-FileCopyrightText: Copyright © DUNE Project contributors, see file LICENSE.md in module root // SPDX-License-Identifier: LGPL-2.1-or-later // -*- 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 namespace DDD { struct DDDContext; } /* namespace DDD */ /* some macros for customizing oopp */ #define _NEWPARAMS #define _NEWPARAMS_OR_VOID void #define __INDENT(n) { int i; for(i=0; ivalue); } int TestTreeElement_Compare(TestTreeElement* a, TestTreeElement* b, const DDD::DDDContext*) { if (a->value < b->value) return -1; else if (a->value > b->value) return 1; return 0; } int main(int argc, char** argv) { TestTreeElementBTree* foo = New_TestTreeElementBTree(); for (int i=0; i<40; i+=2) { TestTreeElement* newItem = new TestTreeElement; newItem->value = i; TestTreeElementBTree_Insert(foo, newItem); } for (int i=1; i<40; i+=2) { TestTreeElement* newItem = new TestTreeElement; newItem->value = i; TestTreeElementBTree_Insert(foo, newItem); } TestTreeElementBTree_Print(foo, 0, stdout); TestTreeElementBTree_Reset(foo); return 0; } dune-uggrid-2.11.0+dfsg/dune/uggrid/parallel/ddd/basic/topo.cc000066400000000000000000000144621513616443000240520ustar00rootroot00000000000000// SPDX-FileCopyrightText: Copyright © DUNE Project contributors, see file LICENSE.md in module root // SPDX-License-Identifier: LGPL-2.1-or-later // -*- tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- // vi: set et ts=4 sw=2 sts=2: /****************************************************************************/ /* */ /* File: topo.c */ /* */ /* Purpose: maintains communication structure for data-dependent */ /* communication topology */ /* */ /* Author: Klaus Birken */ /* Rechenzentrum Uni Stuttgart */ /* Universitaet Stuttgart */ /* Allmandring 30 */ /* 70550 Stuttgart */ /* internet: birken@rus.uni-stuttgart.de */ /* */ /* History: 93/11/30 kb begin */ /* 95/10/05 kb added channel disconnection to TopoExit */ /* */ /* Remarks: */ /* */ /****************************************************************************/ /****************************************************************************/ /* */ /* include files */ /* system include files */ /* application include files */ /* */ /****************************************************************************/ /* standard C library */ #include #include #include #include #include #include #include #include #include #include #include #include USING_UG_NAMESPACES /* PPIF namespace: */ using namespace PPIF; namespace DDD { /****************************************************************************/ /* */ /* routines */ /* */ /****************************************************************************/ /* TODO memory usage is O(P) in current implementation! */ void ddd_TopoInit(DDD::DDDContext& context) { auto& ctx = context.topoContext(); const auto procs = context.procs(); /* get one channel pointer for each partner */ ctx.theTopology.assign(procs, nullptr); /* get proc array with maxsize = 2 * number of procs */ ctx.theProcArray.resize(2 * procs); } void ddd_TopoExit(DDD::DDDContext& context) { auto& ctx = context.topoContext(); ctx.theProcArray.clear(); /* disconnect channels */ for (const auto ch : ctx.theTopology) { if (ch != nullptr) { DiscASync(context.ppifContext(), ch); while (InfoADisc(context.ppifContext(), ch)!=1) ; } } ctx.theTopology.clear(); } /****************************************************************************/ DDD_PROC* DDD_ProcArray(DDD::DDDContext& context) { return context.topoContext().theProcArray.data(); } RETCODE DDD_GetChannels(DDD::DDDContext& context, int nPartners) { auto& ctx = context.topoContext(); int i, nConn; if (nPartners > 2*(context.procs()-1)) { DDD_PrintError('E', 1520, "topology error in DDD_GetChannels"); RET_ON_ERROR; } std::vector theProcFlags(nPartners); nConn = 0; for(i=0; i0) { for(i=0; i"; else { if (i==p) out << "--"; else out << " "; } } out << std::endl; } } DDD_SyncAll(context); } /****************************************************************************/ } /* namespace DDD */ dune-uggrid-2.11.0+dfsg/dune/uggrid/parallel/ddd/ctrl/000077500000000000000000000000001513616443000224365ustar00rootroot00000000000000dune-uggrid-2.11.0+dfsg/dune/uggrid/parallel/ddd/ctrl/CMakeLists.txt000066400000000000000000000004731513616443000252020ustar00rootroot00000000000000# SPDX-FileCopyrightText: Copyright © DUNE Project contributors, see file LICENSE.md in module root # SPDX-License-Identifier: LGPL-2.1-or-later target_sources_dims(duneuggrid PRIVATE cons.cc debug.cc stat.cc) install(FILES stat.h DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}/dune/uggrid/parallel/ddd/ctrl) dune-uggrid-2.11.0+dfsg/dune/uggrid/parallel/ddd/ctrl/cons.cc000066400000000000000000000467141513616443000237230ustar00rootroot00000000000000// SPDX-FileCopyrightText: Copyright © DUNE Project contributors, see file LICENSE.md in module root // SPDX-License-Identifier: LGPL-2.1-or-later // -*- tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- // vi: set et ts=4 sw=2 sts=2: /****************************************************************************/ /* */ /* File: cons.c */ /* */ /* Purpose: consistency checker for ddd structures */ /* */ /* Author: Klaus Birken */ /* Rechenzentrum Uni Stuttgart */ /* Universitaet Stuttgart */ /* Allmandring 30 */ /* 70550 Stuttgart */ /* internet: birken@rus.uni-stuttgart.de */ /* */ /* History: 94/03/21 kb begin */ /* 960718 kb introduced lowcomm-layer (sets of messages) */ /* */ /* Remarks: */ /* */ /****************************************************************************/ /****************************************************************************/ /* */ /* include files */ /* system include files */ /* application include files */ /* */ /****************************************************************************/ /* standard C library */ #include #include #include #include #include #include #include #include #include #include #include USING_UG_NAMESPACES /* PPIF namespace: */ using namespace PPIF; START_UGDIM_NAMESPACE /****************************************************************************/ /* */ /* defines in the following order */ /* */ /* compile time constants defining static data size (i.e. arrays) */ /* other constants */ /* macros */ /* */ /****************************************************************************/ /* PAIRS: check existence of object for each coupling ALLTOALL: check if all coupling lists are equal */ #define CHECK_CPL_PAIRS #define CHECK_CPL_ALLTOALL /****************************************************************************/ /* */ /* data structures */ /* */ /****************************************************************************/ struct CONS_INFO { DDD_GID gid; DDD_TYPE typ; DDD_PROC dest; DDD_PROC proc; DDD_PRIO prio; }; struct CONSMSG { DDD_PROC dest; CONSMSG *next; CONS_INFO *consArray; int nItems; /* lowcomm message handle */ LC_MSGHANDLE msg_h; }; /****************************************************************************/ /* */ /* routines */ /* */ /****************************************************************************/ void ddd_ConsInit(DDD::DDDContext& context) { auto& ctx = context.consContext(); ctx.consmsg_t = LC_NewMsgType(context, "ConsCheckMsg"); ctx.constab_id = LC_NewMsgTable("ConsTab", ctx.consmsg_t, sizeof(CONS_INFO)); } void ddd_ConsExit(DDD::DDDContext&) {} /****************************************************************************/ static int ConsBuildMsgInfos(DDD::DDDContext& context, CONS_INFO *allItems, int nXferItems, CONSMSG **theMsgs) { CONSMSG *cm, *lastCm; int i, lastdest, nMsgs; auto& ctx = context.consContext(); lastdest = -1; lastCm = cm = NULL; nMsgs = 0; for(i=0; inItems = 0; cm->consArray = &allItems[i]; cm->dest = allItems[i].dest; cm->next = lastCm; lastCm = cm; lastdest = cm->dest; nMsgs++; } cm->nItems++; } *theMsgs = cm; /* initiate send messages */ for(cm=*theMsgs; cm!=NULL; cm=cm->next) { /* create new send message */ cm->msg_h = LC_NewSendMsg(context, ctx.consmsg_t, cm->dest); /* init table inside message */ LC_SetTableSize(cm->msg_h, ctx.constab_id, cm->nItems); /* prepare message for sending away */ LC_MsgPrepareSend(context, cm->msg_h); } return(nMsgs); } static void ConsSend(DDD::DDDContext& context, CONSMSG *theMsgs) { auto& ctx = context.consContext(); for(CONSMSG* cm=theMsgs; cm != nullptr; cm=cm->next) { /* copy data into message */ memcpy(LC_GetPtr(cm->msg_h, ctx.constab_id), cm->consArray, sizeof(CONS_INFO)*cm->nItems); /* send message */ LC_MsgSend(context, cm->msg_h); } } static int ConsCheckSingleMsg (DDD::DDDContext& context, LC_MSGHANDLE xm, DDD_HDR *locObjs) { CONS_INFO *theCplBuf; int i, j, nItems; int error_cnt = 0; auto& ctx = context.consContext(); const auto& me = context.me(); nItems = (int) LC_GetTableLen(xm, ctx.constab_id); theCplBuf = (CONS_INFO *) LC_GetPtr(xm, ctx.constab_id); /* sprintf(cBuffer, "%4d: checking message from proc %d (%d items)\n", me, LC_MsgGetProc(xm), nItems); DDD_PrintDebug(cBuffer); */ const int nObjs = context.nObjs(); /* test whether there are consistent objects for all couplings */ for(i=0, j=0; i cplBuf(lenCplBuf); /* copy CONS_INFOs into message buffer */ for(i=0, j=0; i < nCpls; i++) { for(cpl=IdxCplList(context, i); cpl!=NULL; cpl=CPL_NEXT(cpl)) { if ((DDD_PROC)CPL_PROC(cpl) >= procs) { error_cnt++; Dune::dwarn << "DDD-GCC Warning: invalid proc=" << CPL_PROC(cpl) << " (" << OBJ_GID(cpl->obj) << "/" << OBJ_GID(objTable[i]) << ")\n"; } cplBuf[j].gid = OBJ_GID(cpl->obj); cplBuf[j].typ = OBJ_TYPE(cpl->obj); cplBuf[j].dest = CPL_PROC(cpl); cplBuf[j].proc = CPL_PROC(cpl); cplBuf[j].prio = cpl->prio; j++; } } assert(j==lenCplBuf); /* sort couplings */ std::sort(cplBuf.begin(), cplBuf.end(), sort_CplBufDest); /* accumulate messages (one for each partner); inform receivers */ ConsBuildMsgInfos(context, cplBuf.data(), cplBuf.size(), &sendMsgs); /* init communication topology */ nRecvMsgs = LC_Connect(context, ctx.consmsg_t); if (nRecvMsgs==ERROR) { error_cnt = -1; goto exit_ConsCheckGlobalCpl; } /* build and send messages */ ConsSend(context, sendMsgs); /* communicate set of messages (send AND receive) */ recvMsgs = LC_Communicate(context); /* perform checking of received data */ if (nRecvMsgs>0) { std::vector locObjs = LocalObjectsList(context); for(i=0; inext; FreeTmpReq(sendMsgs, sizeof(CONSMSG), TMEM_CONS); } return(error_cnt); } /****************************************************************************/ static int Cons2CheckSingleMsg (DDD::DDDContext& context, LC_MSGHANDLE xm, DDD_HDR *locObjs) { CONS_INFO *theCplBuf; int i, inext=0, j, nItems; int error_cnt = 0; auto& ctx = context.consContext(); const auto& me = context.me(); nItems = (int) LC_GetTableLen(xm, ctx.constab_id); theCplBuf = (CONS_INFO *) LC_GetPtr(xm, ctx.constab_id); /* sprintf(cBuffer, "%4d: checking message from proc %d (%d items)\n", me, LC_MsgGetProc(xm), nItems); DDD_PrintDebug(cBuffer); */ const int nObjs = context.nObjs(); /* test whether there are consistent objects for all couplings */ for(i=0, j=0; iproc) { ifound = i2; break; } } if (ifound==-1) { Dune::dwarn << "healing with AddCpl(" << theCplBuf[i].gid << ", " << theCplBuf[i2].proc << ", " << theCplBuf[i2].prio << ")\n"; AddCoupling(context, locObjs[j], theCplBuf[i2].proc, theCplBuf[i2].prio); } } } #endif /* ConsCheckWithAutomaticHealing */ for(; inext cplBuf(lenCplBuf); /* copy CONS_INFOs into message buffer */ for(i=0, j=0; i < nCpls; i++) { for(cpl=IdxCplList(context, i); cpl!=NULL; cpl=CPL_NEXT(cpl)) { cplBuf[j].gid = OBJ_GID(cpl->obj); cplBuf[j].typ = OBJ_TYPE(cpl->obj); cplBuf[j].dest = CPL_PROC(cpl); cplBuf[j].proc = me; cplBuf[j].prio = OBJ_PRIO(cpl->obj); j++; for(cpl2=IdxCplList(context, i); cpl2!=NULL; cpl2=CPL_NEXT(cpl2)) { cplBuf[j].gid = OBJ_GID(cpl->obj); cplBuf[j].typ = OBJ_TYPE(cpl->obj); cplBuf[j].dest = CPL_PROC(cpl); cplBuf[j].proc = CPL_PROC(cpl2); cplBuf[j].prio = cpl2->prio; j++; } } } assert(j==lenCplBuf); /* sort couplings */ std::sort(cplBuf.begin(), cplBuf.end(), sort_CplBufDest); /* accumulate messages (one for each partner); inform receivers */ ConsBuildMsgInfos(context, cplBuf.data(), cplBuf.size(), &sendMsgs); /* init communication topology */ nRecvMsgs = LC_Connect(context, ctx.consmsg_t); /* build and send messages */ ConsSend(context, sendMsgs); /* communicate set of messages (send AND receive) */ recvMsgs = LC_Communicate(context); /* perform checking of received data */ if (nRecvMsgs>0) { std::vector locObjs = LocalObjectsList(context); for(i=0; inext; FreeTmpReq(sendMsgs, sizeof(CONSMSG), TMEM_CONS); } return(error_cnt); } /****************************************************************************/ static int ConsCheckDoubleObj(const DDD::DDDContext& context) { std::vector locObjs = LocalObjectsList(context); const int nObjs = context.nObjs(); int error_cnt = 0; for(int i=1; i < nObjs; i++) { if (OBJ_GID(locObjs[i-1])==OBJ_GID(locObjs[i])) { error_cnt++; Dune::dwarn << " DDD-GCC Warning: obj " << OBJ_GID(locObjs[i]) << " on " << context.me() << " doubled\n"; } } return(error_cnt); } /****************************************************************************/ /* */ /* Function: DDD_ConsCheck */ /* */ /****************************************************************************/ /** Check DDD runtime consistency. This function performs a combined local/global consistency check on the object data structures and interfaces managed by DDD. This may be used for debugging purposes; if errors are detected, then some understanding of internal DDD structures will be useful. The following single aspects will be checked: \begin{itemize} \item double existence of {\em global ID} numbers in each processor's set of local objects. \item consistency of coupling lists and object copies \item non-symmetric interfaces between processor pairs \item non-symmetric number of items in each interface \end{itemize} @returns total number of errors (sum of all procs) */ int DDD_ConsCheck(DDD::DDDContext& context) { int cpl_errors; int total_errors=0; DDD_Flush(); Synchronize(context.ppifContext()); if (DDD_GetOption(context, OPT_QUIET_CONSCHECK)==OPT_OFF) { if (context.isMaster()) DDD_PrintLine(" DDD-GCC (Global Consistency Check)\n"); } total_errors += ConsCheckDoubleObj(context); #ifdef CHECK_CPL_PAIRS cpl_errors = ConsCheckGlobalCpl(context); #endif #ifdef CHECK_CPL_ALLTOALL cpl_errors = Cons2CheckGlobalCpl(context); #endif if (cpl_errors==-1) { Dune::dgrave << " DDD-GCC Error: out of memory in ConsCheckGlobalCpl()\n"; total_errors++; } else total_errors += cpl_errors; total_errors += DDD_CheckInterfaces(context); /* compute sum of errors over all processors */ total_errors = ddd_GlobalSumInt(context, total_errors); DDD_Flush(); Synchronize(context.ppifContext()); if (DDD_GetOption(context, OPT_QUIET_CONSCHECK)==OPT_OFF) { if (context.isMaster()) Dune::dwarn << " DDD-GCC ready (" << total_errors << " errors)\n"; } return(total_errors); } END_UGDIM_NAMESPACE dune-uggrid-2.11.0+dfsg/dune/uggrid/parallel/ddd/ctrl/debug.cc000066400000000000000000000143431513616443000240400ustar00rootroot00000000000000// SPDX-FileCopyrightText: Copyright © DUNE Project contributors, see file LICENSE.md in module root // SPDX-License-Identifier: LGPL-2.1-or-later // -*- tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- // vi: set et ts=4 sw=2 sts=2: /****************************************************************************/ /* */ /* File: debug.c */ /* */ /* Purpose: produces lists for debugging DDD data structures */ /* */ /* Author: Klaus Birken */ /* Rechenzentrum Uni Stuttgart */ /* Universitaet Stuttgart */ /* Allmandring 30 */ /* 70550 Stuttgart */ /* internet: birken@rus.uni-stuttgart.de */ /* */ /* History: 94/07/04 kb begin */ /* */ /* Remarks: */ /* */ /****************************************************************************/ /****************************************************************************/ /* */ /* include files */ /* system include files */ /* application include files */ /* */ /****************************************************************************/ /* standard C library */ #include #include #include #include #include #include #include #include /* PPIF namespace: */ using namespace PPIF; START_UGDIM_NAMESPACE /****************************************************************************/ /* */ /* defines in the following order */ /* */ /* compile time constants defining static data size (i.e. arrays) */ /* other constants */ /* macros */ /* */ /****************************************************************************/ /****************************************************************************/ /* */ /* data structures */ /* */ /****************************************************************************/ /****************************************************************************/ /* */ /* definition of exported global variables */ /* */ /****************************************************************************/ /****************************************************************************/ /* */ /* definition of variables global to this source file only (static!) */ /* */ /****************************************************************************/ /****************************************************************************/ /* */ /* routines */ /* */ /****************************************************************************/ /****************************************************************************/ /* */ /* Function: ListLocalObjects */ /* */ /* Purpose: display list of all local objects */ /* */ /* Input: - */ /* */ /* Output: - */ /* */ /****************************************************************************/ static bool sort_LocalObjs(const DDD_HDR& a, const DDD_HDR& b) { return std::tie(OBJ_TYPE(a), OBJ_GID(a)) < std::tie(OBJ_TYPE(b), OBJ_GID(b)); } void DDD_ListLocalObjects(const DDD::DDDContext& context) { using std::setw; std::ostream& out = std::cout; std::vector locObjs = LocalObjectsList(context); if (locObjs.empty()) return; std::sort(locObjs.begin(), locObjs.end(), sort_LocalObjs); for(int i=0; i < context.nObjs(); i++) { const auto& o = locObjs[i]; out << "#" << setw(4) << " adr=" << o << " gid=" << OBJ_GID(o) << " type=" << OBJ_TYPE(o) << " prio=" << OBJ_PRIO(o) << " attr=" << OBJ_ATTR(o) << "\n"; } } END_UGDIM_NAMESPACE dune-uggrid-2.11.0+dfsg/dune/uggrid/parallel/ddd/ctrl/stat.cc000066400000000000000000000121221513616443000237160ustar00rootroot00000000000000// SPDX-FileCopyrightText: Copyright © DUNE Project contributors, see file LICENSE.md in module root // SPDX-License-Identifier: LGPL-2.1-or-later // -*- tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- // vi: set et ts=4 sw=2 sts=2: /****************************************************************************/ /* */ /* File: stat.c */ /* */ /* Purpose: DDD statistical evaluation */ /* */ /* Author: Klaus Birken */ /* Rechenzentrum Uni Stuttgart */ /* Universitaet Stuttgart */ /* Allmandring 30 */ /* 70550 Stuttgart */ /* internet: birken@rus.uni-stuttgart.de */ /* */ /* History: 95/01/16 kb begin */ /* */ /* Remarks: */ /* */ /****************************************************************************/ /****************************************************************************/ /* */ /* include files */ /* system include files */ /* application include files */ /* */ /****************************************************************************/ /* standard C library */ #include #include #include #include #include /****************************************************************************/ /* */ /* defines in the following order */ /* */ /* compile time constants defining static data size (i.e. arrays) */ /* other constants */ /* macros */ /* */ /****************************************************************************/ /****************************************************************************/ /* */ /* definition of exported global variables */ /* */ /****************************************************************************/ /* Storage for statistical data (compile with option -DStatistics) Caution: statistics should be used via macros in dddi.h! */ #ifdef Statistics STAT_DATA stat_data; #endif /****************************************************************************/ /* */ /* definition of variables global to this source file only (static!) */ /* */ /****************************************************************************/ /****************************************************************************/ /* */ /* routines */ /* */ /****************************************************************************/ START_UGDIM_NAMESPACE void ddd_StatInit (void) { #ifdef Statistics stat_data.curr_module = 0; #endif } void ddd_StatExit (void) {} /****************************************************************************/ double DDD_StatClock (int module, int index) { STAT_SET_MODULE(module); return(STAT_GETTIMER(index)); } long DDD_StatCount (int module, int index) { STAT_SET_MODULE(module); return(STAT_GETCOUNT(index)); } const char *DDD_StatClockDesc (int module, int index) { STAT_SET_MODULE(module); return(""); } const char *DDD_StatCountDesc (int module, int index) { STAT_SET_MODULE(module); return(""); } /****************************************************************************/ END_UGDIM_NAMESPACE dune-uggrid-2.11.0+dfsg/dune/uggrid/parallel/ddd/ctrl/stat.h000066400000000000000000000170051513616443000235650ustar00rootroot00000000000000// -*- tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- // vi: set et ts=4 sw=2 sts=2: // SPDX-FileCopyrightInfo: Copyright © DUNE Project contributors, see file LICENSE.md in module root // SPDX-License-Identifier: LGPL-2.1-or-later /****************************************************************************/ /* */ /* File: stat.h */ /* */ /* Purpose: DDD statistical evaluation, header file */ /* */ /* Author: Klaus Birken */ /* Rechenzentrum Uni Stuttgart */ /* Universitaet Stuttgart */ /* Allmandring 30 */ /* 70550 Stuttgart */ /* internet: birken@rus.uni-stuttgart.de */ /* */ /* */ /* History: 95/01/16 kb begin */ /* */ /* Remarks: */ /* */ /****************************************************************************/ /****************************************************************************/ /* */ /* auto include mechanism and other include files */ /* */ /****************************************************************************/ #ifndef __DDD_STAT_H__ #define __DDD_STAT_H__ #include START_UGDIM_NAMESPACE /****************************************************************************/ /* */ /* compile time constants defining array sizes */ /* */ /****************************************************************************/ #define STAT_NTIME 64 #define STAT_NITEM 64 /****************************************************************************/ /* */ /* data structures exported by the corresponding source file */ /* */ /****************************************************************************/ /****************************************************************************/ /* STATISTICS: global record for statistical data */ /****************************************************************************/ struct STAT_DATA { /* current DDD module */ int curr_module; /* temporary starttime timer 1-4 */ double starttime[DDD_MODULES][4]; /* miscellaneous time measurements */ double durations[DDD_MODULES][STAT_NTIME]; /* miscellaneous count measurements */ long items[DDD_MODULES][STAT_NITEM]; }; /****************************************************************************/ /* */ /* definition of exported global variables */ /* */ /****************************************************************************/ /* from stat.c statistical data (compile with option -DStatistics) */ #ifdef Statistics extern STAT_DATA stat_data; #endif /****************************************************************************/ /* */ /* macros */ /* */ /****************************************************************************/ #ifdef Statistics /*** macros for "DDD with statistic evaluation" ***/ # define STAT_SET_MODULE(m) stat_data.curr_module = (m) # define STAT_GET_MODULE(m) (m) = stat_data.curr_module # define STAT_RESETX(n) \ stat_data.starttime[stat_data.curr_module][(n)] = CURRENT_TIME # define STAT_RESET STAT_RESETX(0) # define STAT_RESET1 STAT_RESETX(0) # define STAT_RESET2 STAT_RESETX(1) # define STAT_RESET3 STAT_RESETX(2) # define STAT_RESET4 STAT_RESETX(3) # define STAT_TIMERX(n,d) \ stat_data.durations[stat_data.curr_module][(d)] = \ CURRENT_TIME-stat_data.starttime[stat_data.curr_module][(n)] # define STAT_TIMER(d) STAT_TIMERX(0,d) # define STAT_TIMER1(d) STAT_TIMERX(0,d) # define STAT_TIMER2(d) STAT_TIMERX(1,d) # define STAT_TIMER3(d) STAT_TIMERX(2,d) # define STAT_TIMER4(d) STAT_TIMERX(3,d) # define STAT_INCTIMERX(n,d) \ stat_data.durations[stat_data.curr_module][(d)] += \ CURRENT_TIME-stat_data.starttime[stat_data.curr_module][(n)] # define STAT_INCTIMER(d) STAT_INCTIMERX(0,d) # define STAT_INCTIMER1(d) STAT_INCTIMERX(0,d) # define STAT_INCTIMER2(d) STAT_INCTIMERX(1,d) # define STAT_INCTIMER3(d) STAT_INCTIMERX(2,d) # define STAT_INCTIMER4(d) STAT_INCTIMERX(3,d) # define STAT_SETTIMER(d,v) \ stat_data.durations[stat_data.curr_module][(d)] = (v) # define STAT_GETTIMER(d) \ stat_data.durations[stat_data.curr_module][(d)] # define STAT_SETCOUNT(d,v) \ stat_data.items[stat_data.curr_module][(d)] = (v) # define STAT_GETCOUNT(d) \ stat_data.items[stat_data.curr_module][(d)] # define STAT_ZEROTIMER { int i; for (i=0; i #include #include #include #include #include #include #include #include "dddi.h" #include #include #include #include #include USING_UG_NAMESPACE using namespace PPIF; START_UGDIM_NAMESPACE /****************************************************************************/ /* */ /* defines in the following order */ /* */ /* compile time constants defining static data size (i.e. arrays) */ /* other constants */ /* macros */ /* */ /****************************************************************************/ #define BUFFER_SIZE_FACTOR 3 #define MIN_BUFFER_SIZE 256 /****************************************************************************/ /* */ /* definition of static variables */ /* */ /****************************************************************************/ /** * number of users of DDD. * Managed by calls to `DDD_Init` and `DDD_Exit`. * Resources are only freed by `DDD_Exit` when `dddUsers` is zero. * * This variable will be removed once no global state for DDD remains. */ static unsigned int dddUsers = 0; /****************************************************************************/ /* */ /* routines */ /* */ /****************************************************************************/ static void *LowComm_DefaultAlloc (size_t s) { return memmgr_AllocTMEM(s, TMEM_LOWCOMM); } static void LowComm_DefaultFree (void *buffer) { memmgr_FreeTMEM(buffer, TMEM_LOWCOMM); } /****************************************************************************/ /* */ /* Function: DDD_Init */ /* */ /****************************************************************************/ /** Initialisation of the DDD library. This function has to be called before any other function of the DDD library is called. It initializes the underlying PPIF-library, sets all DDD options to their default values and initiates all DDD subsystems. As some of the memory handler calls will be initiated during the execution of this function, the memory manager has to be initialized before calling \funk{Init}. */ void DDD_Init(DDD::DDDContext& context) { dddUsers += 1; /* init lineout-interface to stdout */ DDD_UserLineOutFunction = NULL; /* check max. number of procs (limited by GID construction) */ if (context.procs() > MAX_PROCS) DUNE_THROW(Dune::Exception, "too many processors, cannot construct global IDs"); /* reset all global counters */ context.nObjs(0); context.couplingContext().nCpls = 0; context.couplingContext().nCplItems = 0; /* init all DDD components */ NotifyInit(context); LC_Init(context, LowComm_DefaultAlloc, LowComm_DefaultFree); ddd_StatInit(); ddd_TypeMgrInit(context); ddd_ObjMgrInit(context); ddd_CplMgrInit(context); ddd_TopoInit(context); ddd_IdentInit(context); ddd_IFInit(context); ddd_XferInit(context); ddd_PrioInit(context); ddd_JoinInit(context); ddd_ConsInit(context); /* set options on default values */ DDD_SetOption(context, OPT_WARNING_VARSIZE_OBJ, OPT_ON); DDD_SetOption(context, OPT_WARNING_SMALLSIZE, OPT_ON); DDD_SetOption(context, OPT_WARNING_PRIOCHANGE, OPT_ON); DDD_SetOption(context, OPT_WARNING_DESTRUCT_HDR, OPT_ON); DDD_SetOption(context, OPT_DEBUG_XFERMESGS, OPT_OFF); DDD_SetOption(context, OPT_QUIET_CONSCHECK, OPT_OFF); DDD_SetOption(context, OPT_IDENTIFY_MODE, IDMODE_LISTS); DDD_SetOption(context, OPT_WARNING_REF_COLLISION, OPT_ON); DDD_SetOption(context, OPT_INFO_XFER, XFER_SHOW_NONE); DDD_SetOption(context, OPT_INFO_JOIN, JOIN_SHOW_NONE); DDD_SetOption(context, OPT_WARNING_OLDSTYLE, OPT_ON); DDD_SetOption(context, OPT_INFO_IF_WITH_ATTR, OPT_OFF); DDD_SetOption(context, OPT_XFER_PRUNE_DELETE, OPT_OFF); DDD_SetOption(context, OPT_IF_REUSE_BUFFERS, OPT_OFF); DDD_SetOption(context, OPT_IF_CREATE_EXPLICIT, OPT_OFF); DDD_SetOption(context, OPT_CPLMGR_USE_FREELIST, OPT_ON); } /****************************************************************************/ /* */ /* Function: DDD_Exit */ /* */ /****************************************************************************/ /** Clean-up of the DDD library. This function frees memory previously allocated by DDD and finally finishes up the PPIF library. After the call to \funk{Exit} further usage of the DDD library is no longer possible during this program run. The clean-up of the memory manager should happen afterwards and is left to the DDD application programmer. */ void DDD_Exit(DDD::DDDContext& context) { dddUsers -= 1; if (dddUsers > 0) return; /* close up all DDD components */ ddd_ConsExit(context); ddd_JoinExit(context); ddd_PrioExit(context); ddd_XferExit(context); ddd_IFExit(context); ddd_IdentExit(context); ddd_TopoExit(context); ddd_CplMgrExit(context); ddd_ObjMgrExit(context); ddd_TypeMgrExit(context); ddd_StatExit(); LC_Exit(context); NotifyExit(context); } /****************************************************************************/ /* */ /* Function: DDD_Status */ /* */ /****************************************************************************/ /** Show global status information. This function displays information concerning both the compile-time parameters of the DDD-library and some important runtime-variables. Overview of compile time parameters that will be displayed: \begin{tabular}{l|l} Parameter & Description\\ \hline DDD-Version & current library version number\\ ## #MAX_TYPEDESC# & maximum number of #DDD_TYPE# IDs\\ ## #MAX_OBJ# & maximum number of DDD-objects on one processor\\ ## #MAX_CPL# & maximum number of couplings on one processor\\ ## \end{tabular} */ void DDD_Status(const DDD::DDDContext& context) { using std::setw; std::ostream& out = std::cout; out << "| DDD_Status for proc=" << setw(3) << context.me() << ", DDD-Version " << DDD_VERSION << "\n" << "|\n" << "| MAX_ELEMDESC = " << setw(4) << TYPE_DESC::MAX_ELEMDESC << "\n" << "| MAX_TYPEDESC = " << setw(4) << MAX_TYPEDESC << "\n" << "| MAX_PROCS = " << setw(4) << MAX_PROCS << "\n" << "| MAX_PRIO = " << setw(4) << MAX_PRIO << "\n" << "|\n"; #ifdef WithFullObjectTable out << "| MAX_OBJ = " << setw(8) << context.objTable().size() << " MAX_CPL = " << context.couplingContext().cplTable.size() << "\n"; #else out << "| MAX_CPL = " << context.couplingContext().cplTable.size() << "\n"; #endif out << "| nObjs = " << setw(8) << context.nObjs() << " nCpls = " << setw(8) << context.couplingContext().nCpls << " nCplItems = " << setw(8) << context.couplingContext().nCplItems << "\n" << "|\n" << "| Timeouts:\n" << "| IFComm: " << setw(12) << MAX_TRIES << "\n" << "|\n" << "| Compile-Time Options: "; # ifdef Statistics out << "Statistics "; # endif out << "\n"; } /****************************************************************************/ /* */ /* Function: DDD_LineOutRegister */ /* */ /****************************************************************************/ /** Redirect text output. This function sets the DDD-textport to a given handler function. The handler should be declared as follows: #void func(char *line_of_text)# Instead of printing text for error, debugging and info messages directly to {\em standard output}, DDD will redirect all output one line at a time and send it to the handler {\em func}. This can be used to send each processor's output into a separate file. @param func handler function which should be used for text redirection */ void DDD_LineOutRegister (void (*func)(const char *s)) { DDD_UserLineOutFunction = func; } /****************************************************************************/ /* */ /* Function: DDD_SetOption */ /* */ /****************************************************************************/ /** Set a DDD-option to a given value. The current behaviour of the DDD library can be configured at runtime by setting a variety of options to given values. For each option, there is a default setting and a set of possible values. See \Ref{DDD Options} for a description of all possible options with their default settings and meaning. @param option DDD option specifier @param value option value, possible values depend on option specifier */ void DDD_SetOption (DDD::DDDContext& context, DDD_OPTION option, int value) { if (option>=OPT_END) { Dune::dwarn << "DDD_SetOption: invalid DDD_OPTION\n"; return; } context.options()[option] = value; } /****************************************************************************/ /* */ /* Function: DDD_GetOption (not exported) */ /* */ /* Purpose: get DDD runtime options */ /* */ /* Input: option: OptionType of option to get */ /* */ /* Output: value of option */ /* */ /****************************************************************************/ int DDD_GetOption(const DDD::DDDContext& context, DDD_OPTION option) { if (option>=OPT_END) { Dune::dwarn << "DDD_GetOption: invalid DDD_OPTION\n"; return 0; } return context.options()[option]; } END_UGDIM_NAMESPACE dune-uggrid-2.11.0+dfsg/dune/uggrid/parallel/ddd/dddconstants.hh000066400000000000000000000012321513616443000245010ustar00rootroot00000000000000// SPDX-FileCopyrightText: Copyright © DUNE Project contributors, see file LICENSE.md in module root // SPDX-License-Identifier: LGPL-2.1-or-later #ifndef DUNE_UGGRID_PARALLEL_DDD_DDDCONSTANTS_HH #define DUNE_UGGRID_PARALLEL_DDD_DDDCONSTANTS_HH 1 #include namespace DDD { /** maximum number of TYPE_DESC */ static const int MAX_TYPEDESC = 32; /** maximum number of interfaces */ static const std::size_t MAX_IF = 32; /** maximum length of interface description string */ static const std::size_t IF_NAMELEN = 80; /** size of segment of couplings (for memory allocation) */ static const std::size_t CPLSEGM_SIZE = 512; } /* namespace DDD */ #endif dune-uggrid-2.11.0+dfsg/dune/uggrid/parallel/ddd/dddcontext.cc000066400000000000000000000012741513616443000241450ustar00rootroot00000000000000// SPDX-FileCopyrightText: Copyright © DUNE Project contributors, see file LICENSE.md in module root // SPDX-License-Identifier: LGPL-2.1-or-later #include "config.h" #include #include namespace DDD { DDDContext::DDDContext( const std::shared_ptr& ppifContext, const std::shared_ptr& data) : ppifContext_(ppifContext) , data_(data) { /* Nothing. */ } int DDDContext::me() const { return ppifContext().me(); } int DDDContext::procs() const { return ppifContext().procs(); } bool DDDContext::isMaster() const { return ppifContext().isMaster(); } } /* namespace DDD */ dune-uggrid-2.11.0+dfsg/dune/uggrid/parallel/ddd/dddcontext.hh000066400000000000000000000173531513616443000241640ustar00rootroot00000000000000// SPDX-FileCopyrightText: Copyright © DUNE Project contributors, see file LICENSE.md in module root // SPDX-License-Identifier: LGPL-2.1-or-later #ifndef DUNE_UGGRID_PARALLEL_DDD_DDDCONTEXT_HH #define DUNE_UGGRID_PARALLEL_DDD_DDDCONTEXT_HH 1 #include #include #include #include #include #include #include namespace DDD { namespace Basic { struct LowCommContext { MSG_TYPE *MsgTypes = nullptr; MSG_DESC *SendQueue = nullptr; MSG_DESC *RecvQueue = nullptr; int nSends = 0; int nRecvs = 0; char *theRecvBuffer; LC_MSGHANDLE *theRecvArray = nullptr; MSG_DESC *FreeMsgDescs = nullptr; AllocFunc DefaultAlloc, SendAlloc, RecvAlloc; FreeFunc DefaultFree, SendFree, RecvFree; }; struct NotifyContext { std::vector allInfoBuffer; std::vector theDescs; std::vector theRouting; int maxInfos; int lastInfo; int nSendDescs; }; struct TopoContext { std::vector theTopology; std::vector theProcArray; }; } /* namespace Basic */ namespace Ctrl { struct ConsContext { Basic::LC_MSGTYPE consmsg_t; Basic::LC_MSGCOMP constab_id; }; } /* namespace Ctrl */ namespace Ident { struct IdentContext { ID_PLIST* thePLists; int cntIdents; int nPLists; IdentMode identMode; }; } /* namespace Ident */ namespace If { struct IfCreateContext { IF_DEF theIf[MAX_IF]; int nIfs; }; struct IfUseContext { int send_mesgs; }; } /* namespace If */ namespace Join { struct JoinContext { /** mode of join module */ JoinMode joinMode; /* description for phase1 message */ Basic::LC_MSGTYPE phase1msg_t; Basic::LC_MSGCOMP jointab_id; /* description for phase2 message */ Basic::LC_MSGTYPE phase2msg_t; Basic::LC_MSGCOMP addtab_id; /* description for phase3 message */ Basic::LC_MSGTYPE phase3msg_t; Basic::LC_MSGCOMP cpltab_id; /* entry points for global sets */ JIJoinSet *setJIJoin; JIAddCplSet *setJIAddCpl2; JIAddCplSet *setJIAddCpl3; }; } /* namespace Join */ namespace Mgr { struct CplmgrContext { CplSegm *segmCpl = nullptr; COUPLING *memlistCpl = nullptr; int *localIBuffer; int nCplSegms; }; struct ObjmgrContext { DDD_GID theIdCount; }; struct TypemgrContext { int nDescr; }; } /* namespace Mgr */ namespace Prio { struct PrioContext { PrioMode prioMode; }; } /* namespace Prio */ namespace Xfer { struct CmdmsgContext { Basic::LC_MSGTYPE cmdmsg_t; Basic::LC_MSGCOMP undelete_id; }; struct CplmsgContext { Basic::LC_MSGTYPE cplmsg_t; Basic::LC_MSGCOMP delcpl_id; Basic::LC_MSGCOMP modcpl_id; Basic::LC_MSGCOMP addcpl_id; }; /** * global data for xfer module */ struct XferContext { /** mode of xfer module */ XferMode xferMode; /* description for object message */ Basic::LC_MSGTYPE objmsg_t; Basic::LC_MSGCOMP symtab_id, objtab_id; Basic::LC_MSGCOMP newcpl_id, oldcpl_id; Basic::LC_MSGCOMP objmem_id; /* entry points for global sets */ XICopyObjSet *setXICopyObj; XISetPrioSet *setXISetPrio; XICopyObj* theXIAddData; AddDataSegm* segmAddData = nullptr; SizesSegm* segmSizes = nullptr; #define SLL_MEMBERS(T) Segm##T* segms##T; T* list##T; int n##T; SLL_MEMBERS(XIDelCmd) SLL_MEMBERS(XIDelObj) SLL_MEMBERS(XINewCpl) SLL_MEMBERS(XIOldCpl) SLL_MEMBERS(XIAddCpl) SLL_MEMBERS(XIDelCpl) SLL_MEMBERS(XIModCpl) #undef SLL_MEMBERS }; } /* namespace Xfer */ struct CouplingContext { std::vector cplTable; std::vector nCplTable; /** number of coupling lists */ int nCpls; /* number of couplings */ int nCplItems; }; class DDDContext { public: DDDContext(const std::shared_ptr& ppifContext, const std::shared_ptr& data); const PPIF::PPIFContext& ppifContext() const { return *ppifContext_; } PPIF::PPIFContext& ppifContext() { return *ppifContext_; } /** * \see PPIF::PPIFContext::me() */ int me() const; /** * \see PPIF::PPIFContext::procs() */ int procs() const; /** * \see PPIF::PPIFContext::isMaster() */ bool isMaster() const; /** * return pointer to user data */ void* data() { return data_.get(); } /** * return const pointer to user data */ const void* data() const { return data_.get(); } Basic::LowCommContext& lowCommContext() { return lowCommContext_; } const Basic::LowCommContext& lowCommContext() const { return lowCommContext_; } Basic::NotifyContext& notifyContext() { return notifyContext_; } Basic::TopoContext& topoContext() { return topoContext_; } const Basic::TopoContext& topoContext() const { return topoContext_; } Ctrl::ConsContext& consContext() { return consContext_; } Ident::IdentContext& identContext() { return identContext_; } const Ident::IdentContext& identContext() const { return identContext_; } If::IfCreateContext& ifCreateContext() { return ifCreateContext_; } const If::IfCreateContext& ifCreateContext() const { return ifCreateContext_; } If::IfUseContext& ifUseContext() { return ifUseContext_; } Join::JoinContext& joinContext() { return joinContext_; } const Join::JoinContext& joinContext() const { return joinContext_; } Mgr::CplmgrContext& cplmgrContext() { return cplmgrContext_; } const Mgr::CplmgrContext& cplmgrContext() const { return cplmgrContext_; } Mgr::ObjmgrContext& objmgrContext() { return objmgrContext_; } Mgr::TypemgrContext& typemgrContext() { return typemgrContext_; } const Mgr::TypemgrContext& typemgrContext() const { return typemgrContext_; } Prio::PrioContext& prioContext() { return prioContext_; } const Prio::PrioContext& prioContext() const { return prioContext_; } Xfer::CmdmsgContext& cmdmsgContext() { return cmdmsgContext_; } const Xfer::CmdmsgContext& cmdmsgContext() const { return cmdmsgContext_; } Xfer::CplmsgContext& cplmsgContext() { return cplmsgContext_; } const Xfer::CplmsgContext& cplmsgContext() const { return cplmsgContext_; } Xfer::XferContext& xferContext() { return xferContext_; } const Xfer::XferContext& xferContext() const { return xferContext_; } CouplingContext& couplingContext() { return couplingContext_; } const CouplingContext& couplingContext() const { return couplingContext_; } const std::vector& objTable() const { return objTable_; } std::vector& objTable() { return objTable_; } int nObjs() const { return nObjs_; } void nObjs(int n) { nObjs_ = n; } std::array& typeDefs() { return typeDefs_; } const std::array& typeDefs() const { return typeDefs_; } std::array& options() { return options_; } const std::array& options() const { return options_; } protected: std::shared_ptr ppifContext_; std::shared_ptr data_; Basic::LowCommContext lowCommContext_; Basic::NotifyContext notifyContext_; Basic::TopoContext topoContext_; Ctrl::ConsContext consContext_; Ident::IdentContext identContext_; If::IfCreateContext ifCreateContext_; If::IfUseContext ifUseContext_; Join::JoinContext joinContext_; Mgr::CplmgrContext cplmgrContext_; Mgr::ObjmgrContext objmgrContext_; Mgr::TypemgrContext typemgrContext_; Prio::PrioContext prioContext_; CouplingContext couplingContext_; Xfer::CmdmsgContext cmdmsgContext_; Xfer::CplmsgContext cplmsgContext_; Xfer::XferContext xferContext_; std::vector objTable_; int nObjs_; std::array typeDefs_; std::array options_; }; } /* namespace DDD */ #endif dune-uggrid-2.11.0+dfsg/dune/uggrid/parallel/ddd/dddi.h000066400000000000000000000517531513616443000225620ustar00rootroot00000000000000// -*- tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- // vi: set et ts=4 sw=2 sts=2: // SPDX-FileCopyrightInfo: Copyright © DUNE Project contributors, see file LICENSE.md in module root // SPDX-License-Identifier: LGPL-2.1-or-later /****************************************************************************/ /* */ /* File: dddi.h */ /* */ /* Purpose: internal header file for ddd module */ /* */ /* Author: Klaus Birken */ /* Rechenzentrum Uni Stuttgart */ /* Universitaet Stuttgart */ /* Allmandring 30 */ /* 70550 Stuttgart */ /* internet: birken@rus.uni-stuttgart.de */ /* */ /* */ /* History: 93/11/22 kb begin */ /* 95/10/05 kb added casts to mem-management macros */ /* */ /* Remarks: */ /* */ /****************************************************************************/ /* #define CheckIFMEM #define CheckPMEM #define CheckCplMEM #define CheckMsgMEM #define CheckTmpMEM #define CheckHeapMem */ /****************************************************************************/ /* */ /* auto include mechanism and other include files */ /* */ /****************************************************************************/ #ifndef __DDDI_H__ #define __DDDI_H__ #include #include #include #include #include #include #include #include #include #include #include #include START_UGDIM_NAMESPACE using namespace DDD; /* macro for exiting program in case of a severe error condition */ #define HARD_EXIT assert(0) /* #define HARD_EXIT exit(1) */ /* macros for correct return or premature abort of a procedure */ #define RET_ON_OK return (true) #define RET_ON_ERROR return (false) #define IS_OK(p) ((p)==true) /****************************************************************************/ /* */ /* defines in the following order */ /* */ /* compile time constants defining static data size (i.e. arrays) */ /* other constants */ /* macros */ /* */ /****************************************************************************/ /*** DDD internal parameters ***/ #define MAX_PRIO 32 /* max. number of DDD_PRIO */ #define MAX_CPL_START 65536 /* max. number of local objects with coupling */ #ifdef WithFullObjectTable #define MAX_OBJ_START 262144 /* max. number of locally registered objects */ #else #define MAX_OBJ_START MAX_CPL_START #endif #define MAX_TRIES 50000000 /* max. number of tries until timeout in IF-comm */ #ifdef DDD_MAX_PROCBITS_IN_GID #define MAX_PROCBITS_IN_GID DDD_MAX_PROCBITS_IN_GID #else #define MAX_PROCBITS_IN_GID 24 /* this allows 2^24 procs and 2^40 objects */ #endif /* use maximum as default, if no Priomerge-matrix is available */ #define PRIOMERGE_DEFAULT PRIOMERGE_MAXIMUM /*** DDD internal constants ***/ /* maximum number of procs allowed (limited by GID construction) */ #define MAX_PROCS (1<_next) #define CPL_PROC(cpl) ((cpl)->_proc) /* macros for accessing ELEM_DESC */ #define EDESC_REFTYPE(ed) ((ed)->_reftype) #define EDESC_SET_REFTYPE(ed,rt) (ed)->_reftype=(rt) /****************************************************************************/ /* */ /* definitions previously hold in misc.h */ /* */ /****************************************************************************/ #ifndef MIN #define MIN(x,y) (((x)<(y)) ? (x) : (y)) #endif #ifndef MAX #define MAX(x,y) (((x)>(y)) ? (x) : (y)) #endif /* round up to next alignment border */ #ifndef CEIL #define CEIL(n) ((n)+((ALIGNMENT-((n)&(ALIGNMENT-1)))&(ALIGNMENT-1))) #endif /* round down to next alignment border */ #ifndef FLOOR #define FLOOR(n) ((n)&ALIGNMASK) #endif #define YES 1 #define ON 1 #define NO 0 #define OFF 0 /****************************************************************************/ /* */ /* macros */ /* */ /****************************************************************************/ /* internal access of DDD_HEADER members */ #define ACCESS_HDR(o,c) ((o)->c) /* type of object */ #define OBJ_TYPE(o) ACCESS_HDR(o,typ) /* priority of object */ #define OBJ_PRIO(o) ACCESS_HDR(o,prio) /* attr of object */ #define OBJ_ATTR(o) ACCESS_HDR(o,attr) /* global id of object */ #define OBJ_GID(o) ACCESS_HDR(o,gid) #define OBJ_GID_FMT DDD_GID_FMT /* get index into global object table */ #define OBJ_INDEX(o) ACCESS_HDR(o,myIndex) /* internal flags of object */ #define OBJ_FLAGS(o) ACCESS_HDR(o,flags) /****************************************************************************/ /* usage of flags in DDD_HEADER */ #define MASK_OBJ_PRUNED 0x00000001 #define OBJ_PRUNED(c) (((int)(OBJ_FLAGS(c)))&MASK_OBJ_PRUNED) #define SET_OBJ_PRUNED(c,d) (OBJ_FLAGS(c)) = ((OBJ_FLAGS(c))&(~MASK_OBJ_PRUNED))|((d)&MASK_OBJ_PRUNED) #define MASK_OBJ_RESENT 0x00000002 #define SHIFT_OBJ_RESENT 1 #define OBJ_RESENT(c) ((((int)(OBJ_FLAGS(c)))&MASK_OBJ_RESENT)>>SHIFT_OBJ_RESENT) #define SET_OBJ_RESENT(c,d) (OBJ_FLAGS(c)) = ((OBJ_FLAGS(c))&(~MASK_OBJ_RESENT))|(((d)<_flags))&MASKCPLDIR) #define SETCPLDIR(c,d) ((c)->_flags) = (((c)->_flags)&(~MASKCPLDIR))|((d)&MASKCPLDIR) /* usage of 0x10 for remembering the memory origin for the COUPLING struct */ #define MASKCPLMEM 0x00000010 #define CPLMEM_EXTERNAL 0x00 #define CPLMEM_FREELIST 0x10 #define CPLMEM(c) (((int)((c)->_flags))&MASKCPLMEM) #define SETCPLMEM_EXTERNAL(c) ((c)->_flags) = (((c)->_flags)&(~MASKCPLMEM))|(CPLMEM_EXTERNAL) #define SETCPLMEM_FREELIST(c) ((c)->_flags) = (((c)->_flags)&(~MASKCPLMEM))|(CPLMEM_FREELIST) /* convert DDD_OBJ to DDD_HDR and vice versa */ #define OBJ2HDR(obj,desc) ((DDD_HDR)(((char *)obj)+((desc)->offsetHeader))) #define HDR2OBJ(hdr,desc) ((DDD_OBJ)(((char *)hdr)-((desc)->offsetHeader))) #define OBJ_OBJ(context, hdr) ((DDD_OBJ)(((char *)hdr)- \ (context.typeDefs()[OBJ_TYPE(hdr)].offsetHeader))) /****************************************************************************/ /* macros for access of coupling tables */ /* get boolean: does object have couplings? */ #define ObjHasCpl(context, o) (OBJ_INDEX(o) < context.couplingContext().nCpls) /* get #couplings per object */ #define ObjNCpl(context, o) (ObjHasCpl(context, o) ? context.couplingContext().nCplTable[OBJ_INDEX(o)] : 0) #define IdxNCpl(context, i) (context.couplingContext().nCplTable[i]) /* get pointer to object's coupling list */ #define ObjCplList(context, o) (ObjHasCpl(context, o) ? context.couplingContext().cplTable[OBJ_INDEX(o)] : nullptr) #define IdxCplList(context, i) (context.couplingContext().cplTable[i]) /* DDD_HDR may be invalid */ #define MarkHdrInvalid(hdr) OBJ_INDEX(hdr)=(INT_MAX-1) #define IsHdrInvalid(hdr) OBJ_INDEX(hdr)==(INT_MAX-1) #ifndef WithFullObjectTable #define MarkHdrLocal(hdr) OBJ_INDEX(hdr)=(INT_MAX) #define IsHdrLocal(hdr) OBJ_INDEX(hdr)==(INT_MAX) #endif /****************************************************************************/ /** get default VChan to processor p */ inline const VChannelPtr VCHAN_TO(const DDD::DDDContext& context, DDD_PROC p) { return context.topoContext().theTopology[p]; } /****************************************************************************/ /* types for StdIf-communication functions (see if/ifstd.ct) */ typedef int (*ExecProcHdrPtr)(DDD::DDDContext& context, DDD_HDR); typedef int (*ExecProcHdrXPtr)(DDD::DDDContext& context, DDD_HDR, DDD_PROC, DDD_PRIO); typedef int (*ComProcHdrPtr)(DDD::DDDContext& context, DDD_HDR, void *); typedef int (*ComProcHdrXPtr)(DDD::DDDContext& context, DDD_HDR, void *, DDD_PROC, DDD_PRIO); /****************************************************************************/ /* */ /* memory management */ /* */ /****************************************************************************/ #if defined(CheckPMEM) || defined(CheckIFMEM) || defined(CheckCplMEM) || defined(CheckMsgMEM) || defined(CheckTmpMEM) || defined(CheckHeapMem) static void *dummy_ptr; static char *mem_ptr; #ifndef SST #define SST (CEIL(sizeof(size_t))) #define GET_SSTVAL(adr) *(size_t *)(((char *)adr)-SST) #endif #endif /*** mapping memory allocation calls to memmgr_ calls ***/ #define AllocObj(s,t,p,a) memmgr_AllocOMEM((size_t)s,(int)t,(int)p,(int)a) #ifdef CheckPMEM #define AllocFix(s) \ (dummy_ptr = (mem_ptr=(char *)memmgr_AllocPMEM(SST+(size_t)s)) != NULL ? \ mem_ptr+SST : NULL); \ if (mem_ptr!=NULL) GET_SSTVAL(dummy_ptr) = s; \ printf("MALL PFix adr=%08x size=%ld file=%s line=%d\n", \ dummy_ptr,s,__FILE__,__LINE__) #else #define AllocFix(s) memmgr_AllocPMEM((size_t)s) #endif #ifdef CheckMsgMEM #define AllocMsg(s) \ (dummy_ptr = (mem_ptr=(char *)memmgr_AllocTMEM(SST+(size_t)s, TMEM_MSG)) \ != NULL ? \ mem_ptr+SST : NULL); \ if (mem_ptr!=NULL) GET_SSTVAL(dummy_ptr) = s; \ printf("MALL TMsg adr=%08x size=%ld file=%s line=%d\n", \ dummy_ptr,s,__FILE__,__LINE__) #else #define AllocMsg(s) memmgr_AllocTMEM((size_t)s, TMEM_MSG) #endif #ifdef CheckTmpMEM #define AllocTmp(s) \ (dummy_ptr = (mem_ptr=(char *)memmgr_AllocTMEM(SST+(size_t)s, TMEM_ANY)) \ != NULL ? \ mem_ptr+SST : NULL); \ if (mem_ptr!=NULL) GET_SSTVAL(dummy_ptr) = s; \ printf("MALL TTmp adr=%08x size=%ld file=%s line=%d\n", \ dummy_ptr,s,__FILE__,__LINE__) #define AllocTmpReq(s,r) \ (dummy_ptr = (mem_ptr=(char *)memmgr_AllocTMEM(SST+(size_t)s, r)) \ != NULL ? \ mem_ptr+SST : NULL); \ if (mem_ptr!=NULL) GET_SSTVAL(dummy_ptr) = s; \ printf("MALL TTmp adr=%08x size=%ld kind=%d file=%s line=%d\n", \ dummy_ptr,s,r,__FILE__,__LINE__) #else #define AllocTmp(s) memmgr_AllocTMEM((size_t)s, TMEM_ANY) #define AllocTmpReq(s,r) memmgr_AllocTMEM((size_t)s, r) #endif #ifdef CheckCplMEM #define AllocCpl(s) \ (dummy_ptr = (mem_ptr=(char *)memmgr_AllocAMEM(SST+(size_t)s)) != NULL ? \ mem_ptr+SST : NULL); \ if (mem_ptr!=NULL) GET_SSTVAL(dummy_ptr) = s; \ printf("MALL ACpl adr=%08x size=%ld file=%s line=%d\n", \ dummy_ptr,s,__FILE__,__LINE__) #else #define AllocCpl(s) memmgr_AllocAMEM((size_t)s) #endif #ifdef CheckIFMEM #define AllocIF(s) \ (dummy_ptr = (mem_ptr=(char *)memmgr_AllocAMEM(SST+(size_t)s)) != NULL ? \ mem_ptr+SST : NULL); \ if (mem_ptr!=NULL) GET_SSTVAL(dummy_ptr) = s; \ printf("MALL AIF adr=%08x size=%ld file=%s line=%d\n", \ dummy_ptr,s,__FILE__,__LINE__) #else #define AllocIF(s) memmgr_AllocAMEM((size_t)s) #endif /*** mapping memory free calls to memmgr calls ***/ #define FreeObj(mem,s,t) memmgr_FreeOMEM(mem,(size_t)s,(int)t) #ifdef CheckPMEM #define FreeFix(mem) { \ size_t s=GET_SSTVAL(mem); \ memmgr_FreePMEM(((char *)mem)-SST); \ printf("FREE PFix adr=%08x size=%ld file=%s line=%d\n",\ mem,s,__FILE__,__LINE__); } #else #define FreeFix(mem) memmgr_FreePMEM(mem) #endif #ifdef CheckMsgMEM #define FreeMsg(mem,size) { \ size_t s=GET_SSTVAL(mem); \ memmgr_FreeTMEM(((char *)mem)-SST, TMEM_MSG); \ printf("FREE TMsg adr=%08x size=%ld file=%s line=%d\n",\ mem,s,__FILE__,__LINE__); } #else #define FreeMsg(mem,size) memmgr_FreeTMEM(mem, TMEM_MSG) #endif #ifdef CheckTmpMEM #define FreeTmp(mem,size) { \ size_t s=GET_SSTVAL(mem); \ memmgr_FreeTMEM(((char *)mem)-SST,TMEM_ANY); \ printf("FREE TTmp adr=%08x size=%ld file=%s line=%d\n",\ mem,s,__FILE__,__LINE__); } #define FreeTmpReq(mem,size,r) { \ size_t s=GET_SSTVAL(mem); \ memmgr_FreeTMEM(((char *)mem)-SST,r); \ printf("FREE TTmp adr=%08x size=%ld kind=%d file=%s line=%d\n",\ mem,s,r,__FILE__,__LINE__); } #else #define FreeTmp(mem,size) memmgr_FreeTMEM(mem,TMEM_ANY) #define FreeTmpReq(mem,size,r) memmgr_FreeTMEM(mem,r) #endif #ifdef CheckCplMEM #define FreeCpl(mem) { \ size_t s=GET_SSTVAL(mem); \ memmgr_FreeAMEM(((char *)mem)-SST); \ printf("FREE ACpl adr=%08x size=%ld file=%s line=%d\n",\ mem,s,__FILE__,__LINE__); } #else #define FreeCpl(mem) memmgr_FreeAMEM(mem) #endif #ifdef CheckIFMEM #define FreeIF(mem) { \ size_t s=GET_SSTVAL(mem); \ memmgr_FreeAMEM(((char *)mem)-SST); \ printf("FREE AIF adr=%08x size=%ld file=%s line=%d\n",\ mem,s,__FILE__,__LINE__); } #else #define FreeIF(mem) memmgr_FreeAMEM(mem) #endif /****************************************************************************/ /* */ /* function declarations */ /* */ /****************************************************************************/ /* ddd.c */ int DDD_GetOption(const DDD::DDDContext& context, DDD_OPTION); /* typemgr.c */ void ddd_TypeMgrInit(DDD::DDDContext& context); void ddd_TypeMgrExit(DDD::DDDContext& context); int ddd_TypeDefined (TYPE_DESC *); /* objmgr.c */ void ddd_ObjMgrInit(DDD::DDDContext& context); void ddd_ObjMgrExit(DDD::DDDContext& context); void ddd_EnsureObjTabSize(DDD::DDDContext& context, int); /* cplmgr.c */ void ddd_CplMgrInit(DDD::DDDContext& context); void ddd_CplMgrExit(DDD::DDDContext& context); COUPLING *AddCoupling(DDD::DDDContext& context, DDD_HDR, DDD_PROC, DDD_PRIO); COUPLING *ModCoupling(DDD::DDDContext& context, DDD_HDR, DDD_PROC, DDD_PRIO); void DelCoupling(DDD::DDDContext& context, DDD_HDR, DDD_PROC); void DisposeCouplingList(DDD::DDDContext& context, COUPLING *); void DDD_InfoCoupling(const DDD::DDDContext& context, DDD_HDR); /* mgr/prio.c */ enum PrioMergeVals PriorityMerge (const TYPE_DESC*, DDD_PRIO, DDD_PRIO, DDD_PRIO *); /* if/if.c */ void ddd_IFInit(DDD::DDDContext& context); void ddd_IFExit(DDD::DDDContext& context); void IFAllFromScratch(DDD::DDDContext&); void DDD_InfoIFImpl(DDD::DDDContext& context, DDD_IF); void IFInvalidateShortcuts(DDD::DDDContext& context, DDD_TYPE); int DDD_CheckInterfaces(DDD::DDDContext& context); /* if/ifcmds.c */ void ddd_StdIFExchange (DDD::DDDContext& context, size_t, ComProcHdrPtr,ComProcHdrPtr); void ddd_StdIFExecLocal (DDD::DDDContext& context, ExecProcHdrPtr); void ddd_StdIFExchangeX (DDD::DDDContext& context, size_t, ComProcHdrXPtr,ComProcHdrXPtr); void ddd_StdIFExecLocalX (DDD::DDDContext& context, ExecProcHdrXPtr); /* xfer/xfer.c */ void ddd_XferInit(DDD::DDDContext& context); void ddd_XferExit(DDD::DDDContext& context); int ddd_XferActive(const DDD::DDDContext& context); void ddd_XferRegisterDelete(DDD::DDDContext& context, DDD_HDR); /* xfer/cmds.c */ void DDD_XferPrioChange(DDD::DDDContext& context, DDD_HDR, DDD_PRIO); /* prio/pcmds.c */ void ddd_PrioInit(DDD::DDDContext& context); void ddd_PrioExit(DDD::DDDContext& context); bool ddd_PrioActive(const DDD::DDDContext& context); /* join/join.c */ void ddd_JoinInit(DDD::DDDContext& context); void ddd_JoinExit(DDD::DDDContext& context); bool ddd_JoinActive(const DDD::DDDContext& context); /* ident/ident.c */ void ddd_IdentInit(DDD::DDDContext& context); void ddd_IdentExit(DDD::DDDContext& context); /* basic/cons.c */ void ddd_ConsInit(DDD::DDDContext& context); void ddd_ConsExit(DDD::DDDContext& context); END_UGDIM_NAMESPACE namespace DDD { /* basic/topo.c */ void ddd_TopoInit(DDD::DDDContext& context); void ddd_TopoExit(DDD::DDDContext& context); DDD_PROC* DDD_ProcArray(DDD::DDDContext& context); RETCODE DDD_GetChannels(DDD::DDDContext& context, int); void DDD_DisplayTopo(const DDD::DDDContext& context); } /* namespace DDD */ START_UGDIM_NAMESPACE /* mgr/objmgr.c */ void DDD_HdrConstructorCopy(DDD::DDDContext& context, DDD_HDR, DDD_PRIO); void ObjCopyGlobalData (TYPE_DESC *, DDD_OBJ, DDD_OBJ, size_t); std::vector LocalObjectsList(const DDD::DDDContext& context); std::vector LocalCoupledObjectsList(const DDD::DDDContext& context); END_UGDIM_NAMESPACE namespace DDD { /* basic/reduct.c */ int ddd_GlobalSumInt(const DDD::DDDContext& context, int); int ddd_GlobalMaxInt(const DDD::DDDContext& context, int); int ddd_GlobalMinInt(const DDD::DDDContext& context, int); } /* namespace DDD */ START_UGDIM_NAMESPACE /* ctrl/stat.c */ void ddd_StatInit (void); void ddd_StatExit (void); END_UGDIM_NAMESPACE #endif dune-uggrid-2.11.0+dfsg/dune/uggrid/parallel/ddd/dddtypes.hh000066400000000000000000000070441513616443000236400ustar00rootroot00000000000000// SPDX-FileCopyrightText: Copyright © DUNE Project contributors, see file LICENSE.md in module root // SPDX-License-Identifier: LGPL-2.1-or-later #ifndef DUNE_UGGRID_PARALLEL_DDD_DDDTYPES_HH #define DUNE_UGGRID_PARALLEL_DDD_DDDTYPES_HH 1 #include #include namespace DDD { class DDDContext; using DDD_GID = std::uint_least64_t; using DDD_TYPE = unsigned int; using DDD_IF = unsigned int; using DDD_PROC = unsigned int; using DDD_PRIO = unsigned int; using DDD_ATTR = unsigned int; using DDD_OBJ = char*; struct DDD_HEADER; using DDD_HDR = DDD_HEADER*; /* handler prototypes */ /* handlers related to certain DDD_TYPE (i.e., member functions) */ using HandlerLDATACONSTRUCTOR = void (*)(DDDContext& context, DDD_OBJ); using HandlerDESTRUCTOR = void (*)(DDDContext& context, DDD_OBJ); using HandlerDELETE = void (*)(DDDContext& context, DDD_OBJ); using HandlerUPDATE = void (*)(DDDContext& context, DDD_OBJ); using HandlerOBJMKCONS = void (*)(DDDContext& context, DDD_OBJ, int); using HandlerSETPRIORITY = void (*)(DDDContext& context, DDD_OBJ, DDD_PRIO); using HandlerXFERCOPY = void (*)(DDDContext& context, DDD_OBJ, DDD_PROC, DDD_PRIO); using HandlerXFERDELETE = void (*)(DDDContext& context, DDD_OBJ); using HandlerXFERGATHER = void (*)(DDDContext& context, DDD_OBJ, int, DDD_TYPE, void *); using HandlerXFERSCATTER = void (*)(DDDContext& context, DDD_OBJ, int, DDD_TYPE, void *, int); using HandlerXFERGATHERX = void (*)(DDDContext& context, DDD_OBJ, int, DDD_TYPE, char **); using HandlerXFERSCATTERX = void (*)(DDDContext& context, DDD_OBJ, int, DDD_TYPE, char **, int); using HandlerXFERCOPYMANIP = void (*)(DDDContext& context, DDD_OBJ); /* handlers not related to DDD_TYPE (i.e., global functions) */ using HandlerGetRefType = DDD_TYPE (*)(DDDContext& context, DDD_OBJ, DDD_OBJ); using ExecProcPtr = int (*)(DDDContext& context, DDD_OBJ); using ExecProcXPtr = int (*)(DDDContext& context, DDD_OBJ, DDD_PROC, DDD_PRIO); using ComProcPtr2 = int (*)(DDDContext& context, DDD_OBJ, void *); using ComProcXPtr = int (*)(DDDContext& context, DDD_OBJ, void *, DDD_PROC, DDD_PRIO); /* PRIVATE INTERFACE */ using RETCODE = int; struct COUPLING; struct ELEM_DESC; struct TYPE_DESC; namespace Basic { /* * types used by lowcomm */ /** * opaque data type for message types */ struct MSG_TYPE; /** * opaque data type for messages */ struct MSG_DESC; /** * handle for messages */ using LC_MSGHANDLE = MSG_DESC*; /** * handle for message types (on send AND recv side) */ using LC_MSGTYPE = MSG_TYPE*; /** * component of message (on send AND recv side) */ using LC_MSGCOMP = int; using AllocFunc = void* (*)(std::size_t); using FreeFunc = void (*)(void*); /* * types used by notify */ struct NOTIFY_DESC; struct NOTIFY_INFO; } /* namespace Basic */ namespace Ident { enum class IdentMode : unsigned char; struct ID_PLIST; } /* namespace Ident */ namespace Join { enum class JoinMode : unsigned char; struct JIJoinSet; struct JIAddCplSet; } /* namespace Join */ namespace Prio { enum class PrioMode : unsigned char; } /* namespace Prio */ namespace Xfer { enum class XferMode : unsigned char; struct AddDataSegm; struct SizesSegm; struct XICopyObj; struct XICopyObjSet; struct XISetPrioSet; // From sll.ht instances: #define SLL_TYPES(T) struct Segm##T; struct T; SLL_TYPES(XIDelCmd) SLL_TYPES(XIDelObj) SLL_TYPES(XINewCpl) SLL_TYPES(XIOldCpl) SLL_TYPES(XIAddCpl) SLL_TYPES(XIDelCpl) SLL_TYPES(XIModCpl) #undef SLL_TYPES } /* namespace Xfer */ } /* namespace DDD */ #endif dune-uggrid-2.11.0+dfsg/dune/uggrid/parallel/ddd/dddtypes_impl.hh000066400000000000000000000166461513616443000246710ustar00rootroot00000000000000// SPDX-FileCopyrightText: Copyright © DUNE Project contributors, see file LICENSE.md in module root // SPDX-License-Identifier: LGPL-2.1-or-later #ifndef DUNE_UGGRID_PARALLEL_DDD_DDDTYPES_IMPL_HH #define DUNE_UGGRID_PARALLEL_DDD_DDDTYPES_IMPL_HH 1 #include #include #include #include "dddconstants.hh" #include "dddtypes.hh" namespace DDD { /** options for DDD_SetOption */ enum DDD_OPTION { OPT_IDENTIFY_MODE=0, ///< one of the IDMODE_xxx constants OPT_WARNING_VARSIZE_OBJ=8, ///< warning on differing obj sizes OPT_WARNING_SMALLSIZE, ///< warning on obj sizes smaller than declared OPT_WARNING_PRIOCHANGE, ///< warning on inconsistency in prio-change OPT_WARNING_DESTRUCT_HDR, ///< warning on inconsistency in HdrDestructor OPT_WARNING_REF_COLLISION, ///< warning on collision in reference-localize OPT_WARNING_OLDSTYLE, ///< warning on usage of old-style ddd-funcs OPT_QUIET_CONSCHECK=16, ///< do ConsCheck in a quiet manner OPT_DEBUG_XFERMESGS, ///< print debug info for xfer messages OPT_INFO_XFER, ///< display some statistical info during xfer OPT_INFO_JOIN, ///< display some statistical info during join OPT_INFO_IF_WITH_ATTR, ///< display interfaces detailed (with attrs) OPT_XFER_PRUNE_DELETE, ///< prune del-cmd in del/xfercopy-combination OPT_IF_REUSE_BUFFERS, ///< reuse interface buffs as long as possible OPT_IF_CREATE_EXPLICIT, ///< dont (re-)create interfaces automatically OPT_CPLMGR_USE_FREELIST, ///< use freelist for coupling-memory (default) OPT_END }; /** * \brief DDD object header, include this into all parallel object structures * * Some remarks: * * - don't touch the member elements of DDD_HEADER in the * application program, they will be changed in further * DDD versions! * * - use DDD functional interface for accessing the header fields; * elements which are not accessible via the DDD functional interface * should not be accessed by the application program anyway, */ struct DDD_HEADER { /* control word elements */ unsigned char typ; unsigned char prio; unsigned char attr; unsigned char flags; /** global object array index */ unsigned int myIndex; /** global id */ DDD_GID gid; /* 4 unused bytes in current impl. */ char empty[4]; }; /** * \brief record for coupling of local object with foreign objects */ struct COUPLING { COUPLING* _next; unsigned short _proc; unsigned char prio; unsigned char _flags; DDD_HDR obj; }; /** * \brief description of one element in DDD object structure description * * \todo in CPP_FRONTEND only one of the versions for C_FRONTEND and * F_FRONTEND is needed, depending on setting of desc->storage. * this should be a union for memory efficiency reasons. */ struct ELEM_DESC { /** element offset from object address */ int offset; /** gbits array, if type==EL_GBITS */ std::unique_ptr gbits; /** size of this element */ std::size_t size; /** type of element, one of EL_xxx */ int type; /* if type==EL_OBJPTR, the following entries will be used: */ /** DDD_TYPE of ref. destination */ DDD_TYPE _reftype; /* if reftype==DDD_TYPE_BY_HANDLER, we must use a handler for * determining the reftype on-the-fly (additional parameter during * TypeDefine with EL_OBJPTR) */ HandlerGetRefType reftypeHandler; }; /** * \brief single DDD object structure description */ struct TYPE_DESC { /** current TypeMode (DECLARE/DEFINE) */ int mode; /** textual object description */ const char* name; /** number of current call to TypeDefine */ int currTypeDefCall; /* if C_FRONTEND or (CPP_FRONTEND and storage==STORAGE_STRUCT): */ /** flag: real ddd type (with header)? */ bool hasHeader; /** offset of header from begin of obj */ int offsetHeader; /** max. number of elements per TYPE_DESC */ static const int MAX_ELEMDESC = 64; /** element description array */ ELEM_DESC element[MAX_ELEMDESC]; /** number of elements in object */ int nElements; /** size of object, correctly aligned */ std::size_t size; /* pointer to handler functions: */ HandlerLDATACONSTRUCTOR handlerLDATACONSTRUCTOR; HandlerDESTRUCTOR handlerDESTRUCTOR; HandlerDELETE handlerDELETE; HandlerUPDATE handlerUPDATE; HandlerOBJMKCONS handlerOBJMKCONS; HandlerSETPRIORITY handlerSETPRIORITY; HandlerXFERCOPY handlerXFERCOPY; HandlerXFERDELETE handlerXFERDELETE; HandlerXFERGATHER handlerXFERGATHER; HandlerXFERSCATTER handlerXFERSCATTER; HandlerXFERGATHERX handlerXFERGATHERX; HandlerXFERSCATTERX handlerXFERSCATTERX; HandlerXFERCOPYMANIP handlerXFERCOPYMANIP; /** 2D matrix for comparing priorities */ std::unique_ptr prioMatrix; /** default mode for PrioMerge */ int prioDefault; /* redundancy for efficiency: */ /** number of outside references */ int nPointers; /** mask for fast type-dependent copy */ std::unique_ptr cmask; }; namespace Basic { struct NOTIFY_DESC { DDD_PROC proc; size_t size; }; enum class NotifyTypes : unsigned short { MYSELF, KNOWN, DUMMY, UNKNOWN }; struct NOTIFY_INFO { short from, to; /* source and destination processor */ NotifyTypes flag; /* one of NotifyTypes */ size_t size; /* message size */ }; } /* namespace Basic */ namespace If { using IFObjPtr = DDD_OBJ; /** * single part of interface, all couplings have same attr */ struct IF_ATTR { IF_ATTR* next = nullptr; /* note: the cplXX resp. objXX arrays are NOT contiguous in memory */ COUPLING **cplAB = nullptr, **cplBA = nullptr, **cplABA = nullptr; /* object shortcut */ IFObjPtr *objAB, *objBA, *objABA; int nItems = 0; int nAB = 0; int nBA = 0; int nABA = 0; DDD_ATTR attr; explicit IF_ATTR(DDD_ATTR attr) : attr(attr) { /* Nothing */ } }; /** * descriptor of message and its contents/buffers for IF-communic. */ struct IF_PROC { IF_PROC* next; IF_ATTR *ifAttr; int nAttrs; /* note: the cplXX resp. objXX arrays ARE contiguous in memory */ COUPLING **cpl, **cplAB = nullptr, **cplBA = nullptr, **cplABA = nullptr; /* object shortcut */ IFObjPtr *obj = nullptr, *objAB, *objBA, *objABA; int nItems = 0, nAB = 0, nBA = 0, nABA = 0; DDD_PROC proc; PPIF::VChannelPtr vc; PPIF::msgid msgIn; PPIF::msgid msgOut; std::vector bufIn; std::vector bufOut; }; /** * descriptor for one single interface */ struct IF_DEF { IF_PROC *ifHead = nullptr; /** list of couplings belonging to interface */ COUPLING **cpl = nullptr; /** overall number of items in this interface */ int nItems = 0; /** shortcut: list of object addresses in interf */ IFObjPtr *obj = nullptr; /* flag: is obj-table valid? */ bool objValid = false; int nIfHeads = 0; int nObjStruct; int nPrioA; int nPrioB; DDD_TYPE O[16]; DDD_PRIO A[16]; DDD_PRIO B[16]; /* data for efficiency tuning */ int maskO; /* data for nice user interaction */ /** string for interface identification */ char name[IF_NAMELEN+1]; }; } /* namespace If */ namespace Mgr { /** segment of Cpls */ struct CplSegm { CplSegm *next; int nItems; COUPLING item[CPLSEGM_SIZE]; }; } /* namespace Mgr */ } /* namespace DDD */ #endif dune-uggrid-2.11.0+dfsg/dune/uggrid/parallel/ddd/ident/000077500000000000000000000000001513616443000225755ustar00rootroot00000000000000dune-uggrid-2.11.0+dfsg/dune/uggrid/parallel/ddd/ident/CMakeLists.txt000066400000000000000000000003041513616443000253320ustar00rootroot00000000000000# SPDX-FileCopyrightText: Copyright © DUNE Project contributors, see file LICENSE.md in module root # SPDX-License-Identifier: LGPL-2.1-or-later target_sources_dims(duneuggrid PRIVATE ident.cc) dune-uggrid-2.11.0+dfsg/dune/uggrid/parallel/ddd/ident/ident.cc000066400000000000000000001264531513616443000242220ustar00rootroot00000000000000// SPDX-FileCopyrightText: Copyright © DUNE Project contributors, see file LICENSE.md in module root // SPDX-License-Identifier: LGPL-2.1-or-later // -*- tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- // vi: set et ts=4 sw=2 sts=2: /****************************************************************************/ /* */ /* File: ident.c */ /* */ /* Purpose: object identification for ddd module */ /* */ /* Author: Klaus Birken */ /* Rechenzentrum Uni Stuttgart */ /* Universitaet Stuttgart */ /* Allmandring 30 */ /* 70550 Stuttgart */ /* internet: birken@rus.uni-stuttgart.de */ /* */ /* History: 93/11/30 kb begin */ /* 94/04/25 kb major revision, all Identfy-functions impl. */ /* 96/02/08 kb fixed bug in vchannel handling (due to T3D) */ /* 96/11/25 kb added indirect identification */ /* */ /* Remarks: */ /* */ /****************************************************************************/ #define DebugIdent 10 /* 10 is off */ /****************************************************************************/ /* in debuglevel DebugIdentCons, additional data is sent with the identify-messages, in order to check the consistency of the identification tuples. this is for configuring the debug actions only. */ #define DebugIdentCons 8 /****************************************************************************/ /* */ /* include files */ /* system include files */ /* application include files */ /* */ /****************************************************************************/ /* standard C library */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include /* for object-orientated style via preprocessor */ USING_UG_NAMESPACE /* PPIF namespace: */ using namespace PPIF; namespace DDD { namespace Ident { /****************************************************************************/ /* */ /* defines in the following order */ /* */ /* compile time constants defining static data size (i.e. arrays) */ /* other constants */ /* macros */ /* */ /****************************************************************************/ /* types of IDENTINFO items, ID_OBJECT must be the smallest value!! */ #define ID_OBJECT 1 #define ID_NUMBER 2 #define ID_STRING 3 #define TUPLE_LEN(t) ((int)((t)&0x3f)) /* overall mode of identification */ enum class IdentMode : unsigned char { IMODE_IDLE = 0, /* waiting for next DDD_IdentifyBegin() */ IMODE_CMDS, /* after DDD_IdentifyBegin(), before DDD_IdentifyEnd() */ IMODE_BUSY /* during DDD_IdentifyEnd() */ }; /***/ /* some macros for customizing oopp */ #define _NEWPARAMS #define _NEWPARAMS_OR_VOID void #define __INDENT(n) { int i; for(i=0; i } /* namespace */ /****************************************************************************/ /* ID_PLIST: */ /****************************************************************************/ struct ID_PLIST { DDD_PROC proc; int nEntries; int nIdentObjs; ID_PLIST *next; IdEntrySegmList *entries; IDENTINFO **local_ids; ID_TUPLE *indexmap; /* index-mapping of local_ids array */ MSGITEM *msgin, *msgout; msgid idin, idout; }; } /* namespace Ident */ } /* namespace DDD */ /****************************************************************************/ /* */ /* routines */ /* */ /****************************************************************************/ START_UGDIM_NAMESPACE using namespace DDD::Ident; /****************************************************************************/ /* management functions for IdentMode. these functions control the mode the ident-module is currently in. this is used for error detection, but also for correct detection of coupling inconsistencies and recovery. */ static const char *IdentModeName(IdentMode mode) { switch(mode) { case IdentMode::IMODE_IDLE : return "idle-mode"; case IdentMode::IMODE_CMDS : return "commands-mode"; case IdentMode::IMODE_BUSY : return "busy-mode"; } return "unknown-mode"; } static void IdentSetMode(DDD::DDDContext& context, IdentMode mode) { context.identContext().identMode = mode; # if DebugIdent<=8 Dune::dinfo << "IdentMode=" << IdentModeName(mode) << "\n"; # endif } static IdentMode IdentSuccMode(IdentMode mode) { switch(mode) { case IdentMode::IMODE_IDLE : return IdentMode::IMODE_CMDS; case IdentMode::IMODE_CMDS : return IdentMode::IMODE_BUSY; case IdentMode::IMODE_BUSY : return IdentMode::IMODE_IDLE; } DUNE_THROW(Dune::InvalidStateException, "invalid IdentMode"); } /* static int IdentMode (void) { return identMode; } */ static bool IdentActive(const DDD::DDDContext& context) { return context.identContext().identMode != IdentMode::IMODE_IDLE; } static bool IdentStepMode(DDD::DDDContext& context, IdentMode old) { auto& identMode = context.identContext().identMode; if (identMode != old) DUNE_THROW(Dune::Exception, "wrong Ident-mode (currently in " << IdentModeName(identMode) << ", expected " << IdentModeName(old) << ")"); IdentSetMode(context, IdentSuccMode(identMode)); return true; } /****************************************************************************/ static void PrintPList (ID_PLIST *plist) { using std::setw; std::ostream& out = std::cout; out << "PList proc=" << setw(4) << plist->proc << " entries=" << setw(5) << plist->nEntries << "\n"; } /****************************************************************************/ static int compareId (const IDENTINFO *el1, const IDENTINFO *el2) { int cmp; /* first compare id type (NUMBER, STRING or OBJECT) */ if (el1->typeId < el2->typeId) return(-1); if (el1->typeId > el2->typeId) return(1); /* same typeIds, compare identification then */ switch (el1->typeId) { case ID_NUMBER : if (el1->id.number < el2->id.number) return(-1); if (el1->id.number > el2->id.number) return(1); break; case ID_STRING : cmp = strcmp(el1->id.string, el2->id.string); if (cmp!=0) return(cmp); break; case ID_OBJECT : if (el1->id.object < el2->id.object) return(-1); if (el1->id.object > el2->id.object) return(1); break; } return(0); } /****************************************************************************/ /* two functions for sorting IdentifyXXX-requests into tuples: sort_intoTuplesLists keeps order of IdentifyXXX-issueing by application program, i.e., the ordering is relevant sort_intoTuplesSets reorders the IdentifyXXX-items inside each tuple itself; at this level the ordering is done only by typeId, where ID_OBJECT comes first. lateron the IdentifyObject-items will be sorted according to their gid (for objects with loi==0) or the index of the loi-1 object (for objects with loi>0) */ static bool sort_intoTuplesLists(const IDENTINFO* a, const IDENTINFO* b) { /* sort according to (old) global ids */ /* if equal, keep ordering of input */ return std::tie(a->msg.gid, a->entry) < std::tie(b->msg.gid, b->entry); } static bool sort_intoTuplesSets(const IDENTINFO* a, const IDENTINFO* b) { /* sort according to (old) global ids */ /* if equal, sort according to identificator itself */ if (a->msg.gid < b->msg.gid) return true; else if (a->msg.gid > b->msg.gid) return false; else return compareId(a, b) < 0; } /****************************************************************************/ static int sort_tupleOrder (const void *e1, const void *e2) { ID_TUPLE *el1, *el2; int nIds; DDD_HDR el1hdr, el2hdr; el1 = (ID_TUPLE *) e1; el2 = (ID_TUPLE *) e2; /* sort according to tuple id */ if (el1->tId < el2->tId) return(-1); if (el1->tId > el2->tId) return(1); /* ids are equal, sort according tuple value */ /* recode tuple length from lowest 6 bits */ nIds = TUPLE_LEN(el1->tId); /* compare until one tuple entry differs */ for (int i = 0; i < nIds; i++) { int cmp = compareId(el1->infos[i], el2->infos[i]); if (cmp != 0) return(cmp); } /* if tuples are equal by all means up to now, we sort according to DDD_TYPE of local object. hence, we can identify two pairs of local objects with the same tuple. this has to be omitted if objects with different types should be identifiable. KB 960814 */ el1hdr = el1->infos[0]->hdr; el2hdr = el2->infos[0]->hdr; if (OBJ_TYPE(el1hdr) < OBJ_TYPE(el2hdr)) return(-1); if (OBJ_TYPE(el1hdr) > OBJ_TYPE(el2hdr)) return(1); if (el1hdr!=el2hdr) { /* for(i=0; iinfos[i]->id.object, el1->loi, el2->infos[i]->id.object, el2->loi); } */ DUNE_THROW(Dune::Exception, "same identification tuple for objects " << OBJ_GID(el1hdr) << " and " << OBJ_GID(el2hdr)); } return(0); } /****************************************************************************/ static void SetLOI (IDENTINFO *ii, int loi) { ID_REFDBY *rby; ID_TUPLE *tuple = ii->tuple; /* printf("%4d: %08x SetLOI(%d, %d)\n", me, ii->msg.gid, loi, ii->loi); */ /* set loi to maximum of current and new value */ tuple->loi = MAX(loi, tuple->loi); /* primitive cycle detection */ if (tuple->loi > 64) DUNE_THROW(Dune::Exception, "IdentifyObject-cycle, objects " << ii->msg.gid << " and " << ii->id.object); for(rby=tuple->refd; rby!=NULL; rby=rby->next) { SetLOI(rby->by, loi+1); /* TODO detection of cycles */ } } static void ResolveDependencies ( ID_TUPLE *tuples, int nTuples, IDENTINFO **id, int nIds, int nIdentObjs) { int i, j; if (nIdentObjs==0) return; std::vector refd; refd.reserve(nIdentObjs); /* build array of pointers to objects being used for identification */ std::copy_if( id, id + nIds, std::back_inserter(refd), [](const IDENTINFO* ii) { return ii->typeId == ID_OBJECT; } ); assert(refd.size() == nIdentObjs); /* sort it according to GID of referenced objects */ std::sort( refd.begin(), refd.end(), [](const IDENTINFO* a, const IDENTINFO* b) { return a->id.object < b->id.object; }); /* for(j=0; jid.object, OBJ_GID(refd[j]->hdr)); */ for(i=0, j=0; iid.object < tuples[i].infos[0]->msg.gid) j++; while (jid.object == tuples[i].infos[0]->msg.gid) { ID_REFDBY *rby = new ID_REFDBY; /* remember that idp[i] is referenced by refd[j] */ rby->by = refd[j]; rby->next = tuples[i].refd; tuples[i].refd = rby; j++; } } for(i=0; inext) { /* if loi>0, this subtree has been loi-ed before */ if (tuples[i].loi==0) SetLOI(rby->by, tuples[i].loi+1); } } # if DebugIdent<=2 /* display */ for(i=0; imsg.gid, tuples[i].loi); for(rby=tuples[i].refd; rby!=NULL; rby=rby->next) { printf("%08x referenced by %08x\n", tuples[i].infos[0]->msg.gid, rby->by->msg.gid); } } # endif } static void CleanupLOI (ID_TUPLE *tuples, int nTuples) { int i; for(i=0; inext; /* TODO use freelists */ delete rby; } } } /****************************************************************************/ /* tuple-id doesn't contain information about the data in the tuple, it does only contain information about the structure of a tuple! */ static void TupleInit (ID_TUPLE *tuple, IDENTINFO **id, int nIds) { int i, nObjIds; unsigned long tId; /* init tuple auxiliary data */ tuple->loi = 0; tuple->refd = NULL; /* compute tuple id */ tId = 0; nObjIds = 0; for(i=0; itypeId; /* count entries with ID_OBJECT */ if (id[i]->typeId==ID_OBJECT) nObjIds++; } /* code length of tuple into lowest 6 bits */ tId = (tId<<6) | nIds; /* printf("%4d: compute tuple id = %08x\n", me, tId); */ /* insert tuple id, number of ID_OBJECT-entries, and link to array of pointers to the tuple's IDENTINFO structs */ tuple->tId = tId; tuple->nObjIds = nObjIds; tuple->infos = id; /* set link from IDENTINFOs to tuple */ for(i=0; ituple = tuple; } } static int IdentifySort (const DDD::DDDContext& context, IDENTINFO **id, int nIds, int nIdentObjs, MSGITEM *items_out, ID_TUPLE **indexmap_out, DDD_PROC dest ) { int i, j, last, nTuples; int keep_order_inside_tuple; /* sort to recognize identification tuples */ /* in case of IDMODE_LISTS, the original ordering inside each tuple is kept. for IDMODE_SETS, each tuple is sorted according to the identificators themselves. */ STAT_RESET3; switch (DDD_GetOption(context, OPT_IDENTIFY_MODE)) { case IDMODE_LISTS : std::sort(id, id + nIds, sort_intoTuplesLists); keep_order_inside_tuple = true; break; case IDMODE_SETS : std::sort(id, id + nIds, sort_intoTuplesSets); keep_order_inside_tuple = false; break; default : DUNE_THROW(Dune::Exception, "unknown OPT_IDENTIFY_MODE"); } STAT_INCTIMER3(T_QSORT_TUPLE); /* compute number of tuples and allocate tuple array */ for(i=0, last=0, nTuples=1; imsg.gid > id[last]->msg.gid) { nTuples++; last=i; } } ID_TUPLE* tuples = new ID_TUPLE[nTuples]; /* init tuples (e.g., compute tuple ids) */ for(i=0, last=0, j=0; imsg.gid > id[last]->msg.gid) { TupleInit(&(tuples[j]), &(id[last]), i-last); j++; last=i; } } TupleInit(&(tuples[j]), &(id[last]), nIds-last); /* now, 'tuples' is an array of identification tuples, sorted according the gid of the object the tuple has been specified for. i.e., in a more abstract way tuples is a list of object gids which will be identified. */ /* resolve dependencies caused by IdentifyObject, and set level-of-indirection accordingly */ STAT_RESET3; ResolveDependencies(tuples, nTuples, id, nIds, nIdentObjs); STAT_INCTIMER3(T_RESOLVE_DEP); /* the setting for loi is used for the next sorting procedure, first level of indirection comes first. */ /* sort array for loi */ STAT_RESET3; std::sort( tuples, tuples + nTuples, [](const ID_TUPLE& a, const ID_TUPLE& b) { return a.loi < b.loi; } ); STAT_INCTIMER3(T_QSORT_LOI); STAT_RESET3; i=0; j=0; do { while (j 1) qsort(tuples+i, j-i, sizeof(ID_TUPLE), sort_tupleOrder); /* inherit index to tuples referencing this one */ while (inext) { /* dont use gid of referenced object (because it will be known only after identification), but its position in the identification table instead! */ /* printf("%4d: insertRef dest=%d loi=%d i=%d, %08x <- %08x\n", me, dest, tuples[i].loi, i, OBJ_GID(tuples[i].infos[0]->hdr), OBJ_GID(rby->by->hdr)); */ rby->by->id.object = i; /* if the ordering is not significant, we must reorder the tuple after this operation. (i.e., for IDMODE_SETS). */ } i++; } /* now i==j */ } while (imsg.gid, j, tuples[j].loi); # endif /* for(k=0;kid.object); } */ items_out[j] = tuples[j].infos[0]->msg; # if DebugIdent<=DebugIdentCons /* send additional data for cons-checking */ items_out[j].tuple = tuples[j].tId; # endif } STAT_INCTIMER3(T_CONSTRUCT_ARRAY); CleanupLOI(tuples, nTuples); /* return indexmap table, in order to keep ordering of tuples */ /* note: this array has to be freed in the calling function! */ *indexmap_out = tuples; return(nTuples); } static int InitComm(DDD::DDDContext& context, int nPartners) { auto& ctx = context.identContext(); ID_PLIST *plist; int i, err; DDD_PROC *partners = DDD_ProcArray(context); /* fill partner processor numbers into array */ for(plist=ctx.thePLists, i=0; inext) partners[i] = plist->proc; if (! IS_OK(DDD_GetChannels(context, nPartners))) { return(false); } /* initiate asynchronous receives and sends */ for(plist=ctx.thePLists; plist!=NULL; plist=plist->next) { long *len_adr; plist->idin = RecvASync(context.ppifContext(), VCHAN_TO(context, plist->proc), ((char *)plist->msgin) - sizeof(long), sizeof(MSGITEM)*plist->nEntries + sizeof(long), &err); /* store number of entries at beginning of message */ len_adr = (long *) (((char *)plist->msgout) - sizeof(long)); *len_adr = plist->nEntries; plist->idout = SendASync(context.ppifContext(), VCHAN_TO(context, plist->proc), ((char *)plist->msgout) - sizeof(long), sizeof(MSGITEM)*plist->nEntries + sizeof(long), &err); } return(true); } /****************************************************************************/ /* this routine checks whether number of idents per proc is indeed pairwise consistent. */ static void idcons_CheckPairs(DDD::DDDContext& context) { auto& ctx = context.identContext(); NOTIFY_DESC *msgs = DDD_NotifyBegin(context, ctx.nPLists); ID_PLIST *plist; int i, j, nRecvs, err=false; for(i=0, plist=ctx.thePLists; plist!=NULL; plist=plist->next, i++) { msgs[i].proc = plist->proc; msgs[i].size = plist->nEntries; } /* communicate */ nRecvs = DDD_Notify(context); if (nRecvs==ERROR) DUNE_THROW(Dune::Exception, "Notify failed in Ident-ConsCheck"); /* perform checking */ for(plist=ctx.thePLists; plist!=NULL; plist=plist->next) { for(j=0; jproc) break; } if (j==nRecvs) { Dune::dgrave << "Identify: no Ident-calls from proc " << plist->proc << ", expected " << plist->nEntries << "\n"; err=true; } else if (msgs[j].size!=plist->nEntries) { Dune::dgrave << "Identify: " << msgs[j].size << " Ident-calls from proc " << plist->proc << ", expected " << plist->nEntries << "\n"; err=true; } } DDD_NotifyEnd(context); if (err) { DUNE_THROW(Dune::Exception, "found errors in IdentifyEnd()"); } else { Dune::dwarn << "Ident-ConsCheck level 0: ok\n"; } } /****************************************************************************/ /****************************************************************************/ /* */ /* Function: DDD_IdentifyEnd */ /* */ /****************************************************************************/ /** End of identication phase. This function starts the object identification process. After a call to this function (on all processors) all {\bf Identify}-commands since the last call to \funk{IdentifyBegin} are executed. This involves a set of local communications between the processors. */ DDD_RET DDD_IdentifyEnd(DDD::DDDContext& context) { auto& ctx = context.identContext(); ID_PLIST *plist, *pnext=NULL; int cnt, j; /* REMARK: dont use the id->msg.msg.prio fields until they are explicitly set at line L1! */ STAT_SET_MODULE(DDD_MODULE_IDENT); STAT_ZEROALL; # if DebugIdent<=9 printf("DDD_IdentifyEnd.\n"); fflush(stdout); # endif /* step mode and check whether call to IdentifyEnd is valid */ if (!IdentStepMode(context, IdentMode::IMODE_CMDS)) DUNE_THROW(Dune::Exception, "DDD_IdentifyEnd() aborted"); # if DebugIdent<=9 idcons_CheckPairs(context); # endif STAT_RESET1; /* for each id_plist entry */ for(plist=ctx.thePLists, cnt=0; plist!=NULL; plist=plist->next, cnt++) { /* allocate message buffers */ /* use one alloc for three buffers */ plist->local_ids = (IDENTINFO **) std::malloc( sizeof(IDENTINFO *)*plist->nEntries + /* for local id-infos */ sizeof(long) + /* len of incoming msg */ sizeof(MSGITEM) *plist->nEntries + /* for incoming msg */ sizeof(long) + /* len of outgoing msg */ sizeof(MSGITEM) *plist->nEntries /* for outgoing msg */ ); if (plist->local_ids==NULL) throw std::bad_alloc(); plist->msgin = (MSGITEM *) (((char *)&plist->local_ids[plist->nEntries]) + sizeof(long)); plist->msgout = (MSGITEM *) (((char *)&plist->msgin[plist->nEntries]) + sizeof(long)); /* construct pointer array to IDENTINFO structs */ /* AND: fill in current priority from object's header */ { IdEntrySegm *li; int i = 0; for(li=plist->entries->first; li!=NULL; li=li->next) { int entry; for(entry=0; entrynItems; entry++) { IdEntry *id = &(li->data[entry]); plist->local_ids[i] = &(id->msg); id->msg.msg.prio = OBJ_PRIO(id->msg.hdr); /* L1 */ i++; } } } /* sort outgoing items */ STAT_RESET2; plist->nEntries = IdentifySort(context, plist->local_ids, plist->nEntries, plist->nIdentObjs, plist->msgout, /* output: msgbuffer outgoing */ &plist->indexmap, /* output: mapping of indices to local_ids array */ plist->proc); STAT_INCTIMER2(T_PREPARE_SORT); # if DebugIdent<=5 PrintPList(plist); # endif } STAT_TIMER1(T_PREPARE); STAT_SETCOUNT(N_PARTNERS, cnt); /* initiate comm-channels and send/receive calls */ STAT_RESET1; if (!InitComm(context, cnt)) DUNE_THROW(Dune::Exception, "DDD_IdentifyEnd() aborted"); /* each pair of processors now has a plist with one copy on each side. the actual OBJ_GID is computed as the minimum of the two local object ids on each processor. */ # if DebugIdent<=4 printf("DDD_IdentifyEnd. PLists ready.\n"); fflush(stdout); # endif /* poll receives */ for(plist=ctx.thePLists, j=0; jmsgin!=NULL) { int ret; if ((ret=InfoARecv(context.ppifContext(), VCHAN_TO(context, plist->proc), plist->idin))==1) { /* process single plist */ MSGITEM *msgin = plist->msgin; ID_TUPLE *msgout = plist->indexmap; /* check control data */ long *len_adr = (long *) (((char *)msgin) - sizeof(long)); if (*len_adr != plist->nEntries) DUNE_THROW(Dune::Exception, "Identify: " << ((int) *len_adr) << " identified objects" << " from proc " << plist->proc << ", expected " << plist->nEntries); for (int i = 0; i < plist->nEntries; i++, msgin++, msgout++) { # if DebugIdent<=1 printf("identifying %08x with %08x/%d to %08x\n", OBJ_GID(msgout->infos[0]->hdr), msgin->gid, plist->proc, MIN(OBJ_GID(msgout->infos[0]->hdr), msgin->gid)); # endif # if DebugIdent<=DebugIdentCons if (msgout->tId != msgin->tuple) { DUNE_THROW(Dune::Exception, "inconsistent tuples, gid " << OBJ_GID(msgout->infos[0]->hdr) << " on " << context.me() << ", gid " << msgin->gid << " on " << plist->proc); } # endif /* compute new GID from minimum of both current GIDs */ OBJ_GID(msgout->infos[0]->hdr) = MIN(OBJ_GID(msgout->infos[0]->hdr), msgin->gid); /* add a coupling for new object copy */ AddCoupling(context, msgout->infos[0]->hdr, plist->proc, msgin->prio); } /* free indexmap (=tuple) array */ delete[] plist->indexmap; /* mark plist as finished */ plist->msgin=NULL; j++; } else { if (ret==-1) DUNE_THROW(Dune::Exception, "couldn't receive message from " << plist->proc); } } /* next plist, perhaps restart */ plist=plist->next; if (plist==NULL) plist=ctx.thePLists; }; STAT_TIMER1(T_COMM_AND_IDENT); /* poll sends */ for(plist=ctx.thePLists; plist!=0; plist=pnext) { pnext = plist->next; /* wait for correct send and free buffer */ while(InfoASend(context.ppifContext(), VCHAN_TO(context, plist->proc), plist->idout)!=1) ; /* now, the plist->entries list isn't needed anymore, free */ IdEntrySegmList_Free(plist->entries); std::free(plist->local_ids); delete plist; }; # if DebugIdent<=8 printf("DDD_IdentifyEnd. Rebuilding interfaces.\n"); fflush(stdout); # endif /* rebuild interfaces after topological change */ STAT_RESET1; IFAllFromScratch(context); STAT_TIMER1(T_BUILD_IF); # if DebugIdent<=9 printf("DDD_IdentifyEnd. Ready.\n"); fflush(stdout); # endif IdentStepMode(context, IdentMode::IMODE_BUSY); return(DDD_RET_OK); } /****************************************************************************/ static IdEntry *IdentifyIdEntry(DDD::DDDContext& context, DDD_HDR hdr, DDD_PROC proc, int typeId) { auto& ctx = context.identContext(); IdEntry *id; ID_PLIST *plist; /* check whether Identify-call is valid */ if (!IdentActive(context)) DUNE_THROW(Dune::Exception, "Missing DDD_IdentifyBegin(), aborted"); if (proc == context.me()) DUNE_THROW(Dune::Exception, "cannot identify " << OBJ_GID(hdr) << " with myself"); if (proc >= context.procs()) DUNE_THROW(Dune::Exception, "cannot identify " << OBJ_GID(hdr) << " with processor " << proc); /* search current plist entries */ for(plist=ctx.thePLists; plist!=NULL; plist=plist->next) { if (plist->proc==proc) break; } if (plist==NULL) { /* get new id_plist record */ plist = new ID_PLIST; plist->proc = proc; plist->nEntries = 0; plist->entries = New_IdEntrySegmList(); plist->nIdentObjs = 0; plist->next = ctx.thePLists; ctx.thePLists = plist; ctx.nPLists++; } /* insert into current plist */ id = IdEntrySegmList_NewItem(plist->entries); id->msg.typeId = typeId; id->msg.hdr = hdr; id->msg.msg.gid = OBJ_GID(hdr); plist->nEntries++; if (id->msg.typeId==ID_OBJECT) { plist->nIdentObjs++; } /* NOTE: priority can change between Identify-command and IdentifyEnd! therefore, scan priorities at the beginning of IdentifyEnd, and not here. KB 970730. id->msg.msg.prio = OBJ_PRIO(hdr); */ id->msg.entry = ctx.cntIdents++; return(id); } /****************************************************************************/ /* */ /* Function: DDD_IdentifyNumber */ /* */ /****************************************************************************/ /** DDD Object identification via integer number. After an initial call to \funk{IdentifyBegin}, this function identifies two object copies on separate processors. It has to be called on both processors with the same identification value. The necessary actions (e.g. message transfer) are executed via the final call to \funk{IdentifyEnd}; therefore a whole set of \funk{Identify}-operations is accumulated. After the identification both objects have the same DDD global object ID, which is build using the minimum of both local object IDs. The identification specified here may be detailed even further by additional calls to {\bf Identify}-operations with the same local object. This will construct an identification tuple from all {\bf Identify}-commands for this local object. @param hdr DDD local object which has to be identified with another object @param proc Owner (processor number) of corresponding local object. This processor has to issue a corresponding call to this {\bf DDD\_Identify}-function. @param ident Identification value. This is an arbitrary number to identify two corresponding operations on different processors. */ void DDD_IdentifyNumber(DDD::DDDContext& context, DDD_HDR hdr, DDD_PROC proc, int ident) { IdEntry *id; id = IdentifyIdEntry(context, hdr, proc, ID_NUMBER); if (id==NULL) throw std::bad_alloc(); id->msg.id.number = ident; #if DebugIdent<=2 printf("%4d: IdentifyNumber %08x %02d with %4d num %d\n", context.me(), OBJ_GID(hdr), OBJ_TYPE(hdr), proc, id->msg.id.number); #endif } /****************************************************************************/ /* */ /* Function: DDD_IdentifyString */ /* */ /****************************************************************************/ /** DDD Object identification via character string. After an initial call to \funk{IdentifyBegin}, this function identifies two object copies on separate processors. It has to be called on both processors with the same identification string. The necessary actions (e.g. message transfer) are executed via the final call to \funk{IdentifyEnd}; therefore a whole set of \funk{Identify}-operations is accumulated. After the identification both objects have the same DDD global object ID, which is build using the minimum of both local object IDs. The identification specified here may be detailed even further by additional calls to {\bf Identify}-operations with the same local object. This will construct an identification tuple from all {\bf Identify}-commands for this local object. @param hdr DDD local object which has to be identified with another object @param proc Owner (processor number) of corresponding local object. This processor has to issue a corresponding call to this {\bf DDD\_Identify}-function. @param ident Identification value. This is an arbitrary string to identify two corresponding operations on different processors. */ void DDD_IdentifyString(DDD::DDDContext& context, DDD_HDR hdr, DDD_PROC proc, char *ident) { IdEntry *id; id = IdentifyIdEntry(context, hdr, proc, ID_STRING); if (id==NULL) throw std::bad_alloc(); id->msg.id.string = ident; #if DebugIdent<=2 printf("%4d: IdentifyString %08x %02d with %4d str %s\n", context.me(), OBJ_GID(hdr), OBJ_TYPE(hdr), proc, id->msg.id.string); #endif } /****************************************************************************/ /* */ /* Function: DDD_IdentifyObject */ /* */ /****************************************************************************/ /** DDD Object identification via another DDD Object. After an initial call to \funk{IdentifyBegin}, this function identifies two object copies on separate processors. It has to be called on both processors with the same identification object. The necessary actions (e.g. message transfer) are executed via the final call to \funk{IdentifyEnd}; therefore a whole set of \funk{Identify}-operations is accumulated. After the identification both objects have the same DDD global object ID, which is build using the minimum of both local object IDs. The identification object {\em ident} must be either a distributed object known to both processors issuing the \funk{IdentifyObject}-command or a local object which is not known to these two processors, but which will also be identified during the current {\bf Identify}-process. The identification specified here may be detailed even further by additional calls to {\bf Identify}-operations with the same local object. This will construct an identification tuple from all {\bf Identify}-commands for this local object. @param hdr DDD local object which has to be identified with another object @param proc Owner (processor number) of corresponding local object. This processor has to issue a corresponding call to this {\bf DDD\_Identify}-function. @param ident Identification object. This is an arbitrary global object which is known to both processors involved to identify the two corresponding operations on these processors. */ void DDD_IdentifyObject(DDD::DDDContext& context, DDD_HDR hdr, DDD_PROC proc, DDD_HDR ident) { IdEntry *id; id = IdentifyIdEntry(context, hdr, proc, ID_OBJECT); if (id==NULL) throw std::bad_alloc(); /* use OBJ_GID as estimate for identification value, this estimate might be replaced when the corresponding object is identified itself. then its index in the identify-message will be used. remember identification value in order to replace above estimate, if necessary (i.e., remember ptr to ddd-hdr) */ id->msg.id.object = OBJ_GID(ident); #if DebugIdent<=2 printf("%4d: IdentifyObject %08x %02d with %4d gid %08x\n", context.me(), OBJ_GID(hdr), OBJ_TYPE(hdr), proc, id->msg.id.object); #endif } /****************************************************************************/ /* */ /* Function: DDD_IdentifyBegin */ /* */ /****************************************************************************/ /** Begin identification phase. A call to this function establishes a global identification operation. It should be issued on all processors. After this call an arbitrary series of {\bf Identify}-commands may be issued. The global identification operation is carried out via a \funk{IdentifyEnd} call on each processor. All identification commands given for one local object will be collected into an {\em identification tuple}. Thus, object identificators can be constructed from several simple identification calls. DDD option #IDENTIFY_MODE# may be set before the \funk{IdentifyEnd} call in order to specify how the order of simple identificators is handled for each complex identification tuple: \begin{description} \item[#IDMODE_LISTS#:]% The order of all identification commands for one local object is kept. Both processors with corresponding complex identificators must issue the identification commands in the same order. % \item[#IDMODE_SETS#:]% The order of all identification commands for one local object is not relevant. The DDD identification module sorts the commands inside each complex identificator. Both processors with corresponding identification tuples may issue the identification commands in any order. \end{description} */ void DDD_IdentifyBegin(DDD::DDDContext& context) { auto& ctx = context.identContext(); /* step mode and check whether call to IdentifyBegin is valid */ if (!IdentStepMode(context, IdentMode::IMODE_IDLE)) DUNE_THROW(Dune::Exception, "DDD_IdentifyBegin() aborted"); ctx.thePLists = nullptr; ctx.nPLists = 0; ctx.cntIdents = 0; } /****************************************************************************/ void ddd_IdentInit(DDD::DDDContext& context) { IdentSetMode(context, IdentMode::IMODE_IDLE); } void ddd_IdentExit(DDD::DDDContext&) {} /****************************************************************************/ END_UGDIM_NAMESPACE dune-uggrid-2.11.0+dfsg/dune/uggrid/parallel/ddd/if/000077500000000000000000000000001513616443000220705ustar00rootroot00000000000000dune-uggrid-2.11.0+dfsg/dune/uggrid/parallel/ddd/if/CMakeLists.txt000066400000000000000000000005271513616443000246340ustar00rootroot00000000000000# SPDX-FileCopyrightText: Copyright © DUNE Project contributors, see file LICENSE.md in module root # SPDX-License-Identifier: LGPL-2.1-or-later target_sources_dims(duneuggrid PRIVATE ifcheck.cc ifcmds.cc ifcreate.cc ifobjsc.cc ifuse.cc) install(FILES if.h DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}/dune/uggrid/parallel/ddd/if) dune-uggrid-2.11.0+dfsg/dune/uggrid/parallel/ddd/if/if.h000066400000000000000000000113611513616443000226410ustar00rootroot00000000000000// -*- tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- // vi: set et ts=4 sw=2 sts=2: // SPDX-FileCopyrightInfo: Copyright © DUNE Project contributors, see file LICENSE.md in module root // SPDX-License-Identifier: LGPL-2.1-or-later /****************************************************************************/ /* */ /* File: if.h */ /* */ /* Purpose: include file for DDD interface module */ /* */ /* Author: Klaus Birken */ /* Rechenzentrum Uni Stuttgart */ /* Universitaet Stuttgart */ /* Allmandring 30 */ /* 70550 Stuttgart */ /* internet: birken@rus.uni-stuttgart.de */ /* */ /* History: 94/09/21 kb extracted from if.c */ /* 96/01/16 kb added DDD_OBJ shortcut to ifHead and ifAttr */ /* */ /* Remarks: */ /* */ /****************************************************************************/ #ifndef __DDD_IF_H__ #define __DDD_IF_H__ #include #include /****************************************************************************/ /* */ /* defines in the following order */ /* */ /* compile time constants defining static data size (i.e. arrays) */ /* other constants */ /* macros */ /* */ /****************************************************************************/ START_UGDIM_NAMESPACE using namespace DDD::If; /* #define CtrlTimeouts #define CtrlTimeoutsDetailed */ enum CplDir { DirAB = 0x01, DirBA = 0x02, DirABA = DirAB|DirBA }; /* macros for easier coding of replicated source code */ /* loop over one interface (all ifHeads) */ #define ForIF(context, id, iter) \ for((iter)=context.ifCreateContext().theIf[(id)].ifHead; \ (iter)!=NULL; \ (iter)=(iter)->next) /****************************************************************************/ /* */ /* function declarations */ /* */ /****************************************************************************/ /* ifuse.c */ void IFGetMem (IF_PROC *, size_t, int, int); int IFInitComm(DDD::DDDContext& context, DDD_IF); void IFExitComm(DDD::DDDContext& context, DDD_IF); void IFInitSend(DDD::DDDContext& context, IF_PROC *); int IFPollSend(DDD::DDDContext& context, DDD_IF); char * IFCommLoopObj (DDD::DDDContext& context, ComProcPtr2, IFObjPtr *, char *, size_t, int); char * IFCommLoopCpl (DDD::DDDContext& context, ComProcPtr2, COUPLING **, char *, size_t, int); char * IFCommLoopCplX (DDD::DDDContext& context, ComProcXPtr, COUPLING **, char *, size_t , int); void IFExecLoopObj (DDD::DDDContext& context, ExecProcPtr, IFObjPtr *, int); void IFExecLoopCplX (DDD::DDDContext& context, ExecProcXPtr, COUPLING **, int); char * IFCommHdrLoopCpl (DDD::DDDContext& context, ComProcHdrPtr, COUPLING **, char *, size_t, int); char * IFCommHdrLoopCplX (DDD::DDDContext& context, ComProcHdrXPtr, COUPLING **, char *, size_t, int); void IFExecHdrLoopCpl (DDD::DDDContext& context, ExecProcHdrPtr, COUPLING **, int); void IFExecHdrLoopCplX (DDD::DDDContext& context, ExecProcHdrXPtr, COUPLING **, int); /* ifobjsc.c */ void IFCreateObjShortcut(DDD::DDDContext& context, DDD_IF); void IFCheckShortcuts(DDD::DDDContext& context, DDD_IF); /****************************************************************************/ END_UGDIM_NAMESPACE #endif dune-uggrid-2.11.0+dfsg/dune/uggrid/parallel/ddd/if/ifcheck.cc000066400000000000000000000120771513616443000240020ustar00rootroot00000000000000// SPDX-FileCopyrightText: Copyright © DUNE Project contributors, see file LICENSE.md in module root // SPDX-License-Identifier: LGPL-2.1-or-later // -*- tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- // vi: set et ts=4 sw=2 sts=2: /****************************************************************************/ /* */ /* File: ifcheck.c */ /* */ /* Purpose: routines concerning interfaces between processors */ /* checking routines */ /* */ /* Author: Klaus Birken */ /* Institut fuer Computeranwendungen III */ /* Universitaet Stuttgart */ /* Pfaffenwaldring 27 */ /* 70550 Stuttgart */ /* email: birken@ica3.uni-stuttgart.de */ /* */ /* History: 960926 kb begin */ /* */ /* Remarks: */ /* */ /****************************************************************************/ /****************************************************************************/ /* */ /* include files */ /* system include files */ /* application include files */ /* */ /****************************************************************************/ /* standard C library */ #include #include #include #include #include #include #include #include "if.h" using namespace PPIF; /* general error string */ #define ERRSTR " DDD-IFC Warning: " START_UGDIM_NAMESPACE /****************************************************************************/ /* */ /* definition of static variables */ /* */ /****************************************************************************/ /****************************************************************************/ /* */ /* routines */ /* */ /****************************************************************************/ static int DDD_CheckInterface(DDD::DDDContext& context, DDD_IF ifId) { using std::setw; auto& theIF = context.ifCreateContext().theIf; const auto& me = context.me(); int errors=0; IF_PROC *h; NOTIFY_DESC *msgs = DDD_NotifyBegin(context, theIF[ifId].nIfHeads); int nRecvs, k; /* fill NOTIFY_DESCS */ k=0; ForIF(context, ifId, h) { msgs[k].proc = h->proc; msgs[k].size = h->nItems; k++; } nRecvs = DDD_Notify(context); if (nRecvs==ERROR) { Dune::dwarn << "Notify failed on proc " << me << "\n"; errors++; } else { if (nRecvs!=theIF[ifId].nIfHeads) { Dune::dwarn << ERRSTR "IF " << setw(2) << ifId << "not symmetric on proc " << me << " (" << nRecvs << " != " << theIF[ifId].nIfHeads << ")\n"; errors++; } ForIF(context, ifId, h) { for(k=0; kproc) { if (msgs[k].size!=h->nItems) { Dune::dwarn << ERRSTR "IF " << setw(2) << ifId << " proc " << me << "->" << msgs[k].proc << " has non-symmetric items (" << h->nItems << " != " << msgs[k].size << ")\n"; errors++; } } } } } DDD_NotifyEnd(context); return(errors); } /****************************************************************************/ int DDD_CheckInterfaces(DDD::DDDContext& context) { const auto& nIFs = context.ifCreateContext().nIfs; int errors = 0; for(int i = 0; i < nIFs; ++i) { errors += DDD_CheckInterface(context, i); } return(errors); } /****************************************************************************/ END_UGDIM_NAMESPACE dune-uggrid-2.11.0+dfsg/dune/uggrid/parallel/ddd/if/ifcmd.ct000066400000000000000000000321051513616443000235030ustar00rootroot00000000000000// SPDX-FileCopyrightText: Copyright © DUNE Project contributors, see file LICENSE.md in module root // SPDX-License-Identifier: LGPL-2.1-or-later /****************************************************************************/ /* */ /* File: ifcmd.ct */ /* */ /* Purpose: template routines for interface functions */ /* */ /* Author: Klaus Birken */ /* Institut fuer Computeranwendungen III */ /* Universitaet Stuttgart */ /* Pfaffenwaldring 27 */ /* 70569 Stuttgart */ /* internet: birken@ica3.uni-stuttgart.de */ /* */ /* History: 970110 kb begin */ /* */ /* Remarks: */ /* */ /****************************************************************************/ /****************************************************************************/ /* */ /* derived macros */ /* */ /****************************************************************************/ #define _CAT(a,b) a ## b #define CAT(a,b) _CAT(a,b) #ifdef IF_WITH_ATTR #define PART ifAttr #else #define PART ifHead #endif #ifdef IF_WITH_XARGS #define EXEC_LOOP(context, a,b,c) NS_DIM_PREFIX IFExecLoopCplX(context, a,b,c) #define COMM_LOOP(context, a,b,c,d,e) NS_DIM_PREFIX IFCommLoopCplX(context, a,b,c,d,e) #define D_AB(p) (p->cplAB) #define D_BA(p) (p->cplBA) #define D_ABA(p) (p->cplABA) #else #define EXEC_LOOP(context, a,b,c) NS_DIM_PREFIX IFExecLoopObj(context, a,b,c) #define COMM_LOOP(context, a,b,c,d,e) NS_DIM_PREFIX IFCommLoopObj(context, a,b,c,d,e) #define D_AB(p) (p->objAB) #define D_BA(p) (p->objBA) #define D_ABA(p) (p->objABA) #endif #define IF_FUNCNAME CAT(DDD_IF,IF_NAME) /****************************************************************************/ /* */ /* auxiliary macros */ /* */ /****************************************************************************/ #ifndef IF_AUX_MACROS #define IF_AUX_MACROS #define CONCAT(txt,fct) txt FUNCNAME_STR(fct) #define FUNCNAME_STR(f) #f #endif /****************************************************************************/ /* */ /* routines */ /* */ /****************************************************************************/ /****************************************************************************/ #ifdef IF_EXECLOCAL /** Local execution on \ddd{Interface}. This function executes a given handler for each object inside a \ddd{Interface}. }*/ #else #if defined(IF_ONEWAY) /** Oneway-communication across a \ddd{Interface}. This function initiates a communication across a previously defined DDD interface. It has to be issued on all processors. The communication is carried out one-directional, dependent on parameter {\em aDir}. In case of #IF_FORWARD# information will flow from object set A to object set B, in case of #IF_BACKWARD# it will be vice versa (see \funk{IFDefine}). }*/ #else /** Bidirectional communication across a \ddd{Interface}. This function initiates a communication across a previously defined DDD interface. It has to be issued on all processors. The communication is carried out in both directions, i.e.~from object set A to object set B and vice versa (see \funk{IFDefine}). }*/ #endif /*{ The user-defined function {\em gather\_proc} is called for each object inside the interface. It has to pack all necessary information into a special memory location. Afterwards the actual communication based on the current processor topology happens. After all data had been scheduled onto the destination processors, it has to be incorporated into the destination part of the DDD interface via the user-defined function {\em scatter\_proc}. Both communication procedures should have the following declaration: #int (*ComProcPtr) (DDD_OBJ obj, void *data)# }*/ #endif /*{ \todo{further description} }*/ #ifdef IF_WITH_XARGS /*{ \todo{Doku extended args} }*/ #endif /*{ @param aIF the \ddd{Interface} to be used. }*/ #ifdef IF_WITH_ATTR /*{ @param aAttr the \ddd{Attribute} which specifies the sub-interface. }*/ #endif #ifdef IF_EXECLOCAL /*{ @param ExecProc handler which is executed for each object in the interface. }*/ #else #ifdef IF_ONEWAY /*{ @param aDir the communication direction (#IF_FORWARD# or #IF_BACKWARD#) }*/ #endif /*{ @param aSize amount of data for each object in the interface (number of bytes) }*/ #endif /*{ */ void IF_FUNCNAME ( DDD::DDDContext& context, NS_DIM_PREFIX DDD_IF aIF, #ifdef IF_WITH_ATTR NS_DIM_PREFIX DDD_ATTR aAttr, #endif #ifdef IF_EXECLOCAL #ifdef IF_WITH_XARGS NS_DIM_PREFIX ExecProcXPtr ExecProc) #else NS_DIM_PREFIX ExecProcPtr ExecProc) #endif #else #ifdef IF_ONEWAY NS_DIM_PREFIX DDD_IF_DIR aDir, #endif size_t aSize, #ifdef IF_WITH_XARGS NS_DIM_PREFIX ComProcXPtr Gather, NS_DIM_PREFIX ComProcXPtr Scatter) #else NS_DIM_PREFIX ComProcPtr2 Gather, NS_DIM_PREFIX ComProcPtr2 Scatter) #endif #endif { using std::setw; NS_DIM_PREFIX IF_PROC *ifHead; /* prohibit using standard interface (IF0) */ if (aIF==NS_DIM_PREFIX STD_INTERFACE) DUNE_THROW(Dune::Exception, "cannot use standard interface"); /* shortcuts can only be used without extended handler arguments */ #ifndef IF_WITH_XARGS /* if shortcut tables are invalid -> recompute */ NS_DIM_PREFIX IFCheckShortcuts(context, aIF); #endif #ifdef IF_EXECLOCAL ForIF(context, aIF, ifHead) { #ifdef IF_WITH_ATTR NS_DIM_PREFIX IF_ATTR *ifAttr = ifHead->ifAttr; while ((ifAttr!=NULL) && (ifAttr->attr!=aAttr)) ifAttr = ifAttr->next; if (ifAttr==NULL) continue; #endif EXEC_LOOP(context, ExecProc, D_BA(PART), PART->nBA); EXEC_LOOP(context, ExecProc, D_AB(PART), PART->nAB); EXEC_LOOP(context, ExecProc, D_ABA(PART), PART->nABA); } #else /* ! IF_EXECLOCAL */ /* STAT_ZEROTIMER; STAT_RESET1; STAT_SETCOUNT(20,0); STAT_SETCOUNT(21,0); STAT_SETCOUNT(22,0); */ /* allocate storage for in and out buffers */ ForIF(context, aIF, ifHead) { #ifdef IF_ONEWAY int nOut, nIn; #endif #ifdef IF_WITH_ATTR /* reset buffers */ ifHead->bufIn.clear(); ifHead->bufOut.clear(); /* if no ATTR can be found, buffers will be empty */ NS_DIM_PREFIX IF_ATTR *ifAttr = ifHead->ifAttr; while ((ifAttr!=NULL) && (ifAttr->attr!=aAttr)) ifAttr = ifAttr->next; if (ifAttr==NULL) continue; #endif #ifdef IF_EXCHANGE NS_DIM_PREFIX IFGetMem(ifHead, aSize, PART->nItems, PART->nItems); #endif #ifdef IF_ONEWAY if (aDir==NS_DIM_PREFIX IF_FORWARD) { nOut = PART->nAB; nIn = PART->nBA; } else { nOut = PART->nBA; nIn = PART->nAB; } IFGetMem(ifHead, aSize, nIn+PART->nABA, nOut+PART->nABA); #endif /* STAT_SETCOUNT(20,STAT_GETCOUNT(20)+ifHead->nItems); STAT_SETCOUNT(21,STAT_GETCOUNT(21)+2); STAT_SETCOUNT(22,STAT_GETCOUNT(22)+ ifHead->bufIn.size() + ifHead->bufOut.size()); */ } /* STAT_TIMER1(63); */ /* init communication, initiate receives */ int recv_mesgs = NS_DIM_PREFIX IFInitComm(context, aIF); /* build messages using gather-handler and send them away */ ForIF(context, aIF, ifHead) { char *buffer; #ifdef IF_ONEWAY int nOut; #ifdef IF_WITH_XARGS NS_DIM_PREFIX COUPLING **datOut; #else NS_DIM_PREFIX IFObjPtr *datOut; #endif #endif #ifdef IF_WITH_ATTR NS_DIM_PREFIX IF_ATTR *ifAttr = ifHead->ifAttr; while ((ifAttr!=NULL) && (ifAttr->attr!=aAttr)) ifAttr = ifAttr->next; if (ifAttr==NULL) continue; #endif buffer = ifHead->bufOut.data(); #ifdef IF_EXCHANGE /* exchange BA and AB during send */ buffer= COMM_LOOP(context, Gather, D_BA(PART), buffer, aSize, PART->nBA); buffer= COMM_LOOP(context, Gather, D_AB(PART), buffer, aSize, PART->nAB); #endif #ifdef IF_ONEWAY if (aDir==NS_DIM_PREFIX IF_FORWARD) { nOut = PART->nAB; datOut = D_AB(PART); } else { nOut = PART->nBA; datOut = D_BA(PART); } buffer= COMM_LOOP(context, Gather, datOut, buffer, aSize, nOut); #endif buffer= COMM_LOOP(context, Gather, D_ABA(PART), buffer, aSize, PART->nABA); NS_DIM_PREFIX IFInitSend(context, ifHead); } /* poll receives and scatter data */ unsigned long tries; for(tries=0; tries0; tries++) { /* poll receive calls */ ForIF(context, aIF, ifHead) { if (not ifHead->bufIn.empty() && ifHead->msgIn!=NO_MSGID) { int error = InfoARecv(context.ppifContext(), ifHead->vc, ifHead->msgIn); if (error==-1) DUNE_THROW(Dune::Exception, "InfoARecv failed for recv to proc=" << ifHead->proc); if (error==1) { char *buffer; #ifdef IF_ONEWAY int nIn; #ifdef IF_WITH_XARGS NS_DIM_PREFIX COUPLING **datIn; #else NS_DIM_PREFIX IFObjPtr *datIn; #endif #endif #ifdef CtrlTimeoutsDetailed printf("%4d: IFCTRL %02d received msg from " "%4d after %10ld, size %ld\n", context.me(), aIF, ifHead->proc, (unsigned long)tries, (unsigned long)ifHead->bufIn.size()); #endif recv_mesgs--; ifHead->msgIn=NO_MSGID; #ifdef IF_WITH_ATTR NS_DIM_PREFIX IF_ATTR *ifAttr = ifHead->ifAttr; while ((ifAttr!=NULL) && (ifAttr->attr!=aAttr)) ifAttr = ifAttr->next; if (ifAttr==nullptr) continue; #endif buffer = ifHead->bufIn.data(); /* get data using scatter-handler */ #ifdef IF_EXCHANGE buffer = COMM_LOOP(context, Scatter, D_AB(PART), buffer, aSize, PART->nAB); buffer = COMM_LOOP(context, Scatter, D_BA(PART), buffer, aSize, PART->nBA); #endif #ifdef IF_ONEWAY if (aDir==NS_DIM_PREFIX IF_FORWARD) { nIn = PART->nBA; datIn = D_BA(PART); } else { nIn = PART->nAB; datIn = D_AB(PART); } buffer = COMM_LOOP(context, Scatter, datIn, buffer, aSize, nIn); #endif buffer = COMM_LOOP(context, Scatter, D_ABA(PART), buffer, aSize, PART->nABA); } } } } /* finally poll send completion */ if (recv_mesgs>0) { Dune::dwarn << FUNCNAME_STR(IF_FUNCNAME) ": receive-timeout for IF " << setw(2) << aIF << "\n"; ForIF(context, aIF, ifHead) { if (not ifHead->bufIn.empty() && ifHead->msgIn!=NO_MSGID) { Dune::dwarn << " waiting for message (from proc " << ifHead->proc << ", size " << ifHead->bufIn.size() << ")\n"; } } } else { #ifdef CtrlTimeouts printf("%4d: IFCTRL %02d received msg all after %10ld tries\n", context.me(), aIF, (unsigned long)tries); #endif if (! NS_DIM_PREFIX IFPollSend(context, aIF)) { Dune::dwarn << FUNCNAME_STR(IF_FUNCNAME) ": send-timeout for IF " << setw(2) << aIF << "\n"; ForIF(context, aIF, ifHead) { if (not ifHead->bufOut.empty() && ifHead->msgOut!=NO_MSGID) { Dune::dwarn << " waiting for send completion (to proc " << ifHead->proc << ", size " << ifHead->bufOut.size() << ")\n"; } } } } /* free memory */ NS_DIM_PREFIX IFExitComm(context, aIF); /*STAT_TIMER1(60);*/ #endif /* IF_EXECLOCAL */ } /****************************************************************************/ /* undefs for all input macros and defines */ #undef IF_NAME #undef IF_FUNCNAME #ifdef IF_ONEWAY #undef IF_ONEWAY #endif #ifdef IF_EXCHANGE #undef IF_EXCHANGE #endif #ifdef IF_EXECLOCAL #undef IF_EXECLOCAL #endif #ifdef IF_WITH_ATTR #undef IF_WITH_ATTR #endif #ifdef IF_WITH_XARGS #undef IF_WITH_XARGS #endif #ifdef IF_CBR #undef IF_CBR #endif /* undefs for derived macros */ #undef PART #undef EXEC_LOOP #undef COMM_LOOP #undef D_AB #undef D_BA #undef D_ABA #undef _CAT #undef CAT /****************************************************************************/ dune-uggrid-2.11.0+dfsg/dune/uggrid/parallel/ddd/if/ifcmds.cc000066400000000000000000000141201513616443000236420ustar00rootroot00000000000000// SPDX-FileCopyrightText: Copyright © DUNE Project contributors, see file LICENSE.md in module root // SPDX-License-Identifier: LGPL-2.1-or-later // -*- tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- // vi: set et ts=4 sw=2 sts=2: /****************************************************************************/ /* */ /* File: ifcmds.c */ /* */ /* Purpose: routines concerning interfaces between processors */ /* part 2: usage of DDD interfaces */ /* */ /* Author: Klaus Birken */ /* Rechenzentrum Uni Stuttgart */ /* Universitaet Stuttgart */ /* Allmandring 30 */ /* 70550 Stuttgart */ /* internet: birken@rus.uni-stuttgart.de */ /* */ /* History: 93/11/30 kb begin */ /* 94/03/03 kb complete rewrite */ /* 94/09/12 kb IFExchange & IFOneway rewrite, two bugs fixed */ /* 94/09/21 kb created from if.c */ /* 95/01/13 kb added range functionality */ /* 95/07/26 kb overlapping of gather/scatter and communication */ /* 96/01/24 kb added use of object shortcut tables */ /* */ /* Remarks: */ /* */ /****************************************************************************/ /****************************************************************************/ /* */ /* include files */ /* system include files */ /* application include files */ /* */ /****************************************************************************/ /* standard C library */ #include #include #include #include #include #include #include #include #include "if.h" using namespace PPIF; /****************************************************************************/ /* */ /* definition of static variables */ /* */ /****************************************************************************/ START_UGDIM_NAMESPACE /****************************************************************************/ /* */ /* routines */ /* */ /****************************************************************************/ /* description of input defines for ifcmd.ct IF_NAME: name of interface function IF_CBR: call by reference, otherwise call by address (CPP_FRONTEND) TODO: more doc! */ /* with normal arguments for gather/scatter */ #define IF_NAME Exchange #define IF_EXCHANGE #include "ifcmd.ct" #define IF_NAME Oneway #define IF_ONEWAY #include "ifcmd.ct" #define IF_NAME ExecLocal #define IF_EXECLOCAL #include "ifcmd.ct" #define IF_NAME AExchange #define IF_EXCHANGE #define IF_WITH_ATTR #include "ifcmd.ct" #define IF_NAME AOneway #define IF_ONEWAY #define IF_WITH_ATTR #include "ifcmd.ct" #define IF_NAME AExecLocal #define IF_EXECLOCAL #define IF_WITH_ATTR #include "ifcmd.ct" /* with extended arguments for gather/scatter */ #define IF_NAME ExchangeX #define IF_EXCHANGE #define IF_WITH_XARGS #include "ifcmd.ct" #define IF_NAME OnewayX #define IF_ONEWAY #define IF_WITH_XARGS #include "ifcmd.ct" #define IF_NAME ExecLocalX #define IF_EXECLOCAL #define IF_WITH_XARGS #include "ifcmd.ct" #define IF_NAME AExchangeX #define IF_EXCHANGE #define IF_WITH_ATTR #define IF_WITH_XARGS #include "ifcmd.ct" #define IF_NAME AOnewayX #define IF_ONEWAY #define IF_WITH_ATTR #define IF_WITH_XARGS #include "ifcmd.ct" #define IF_NAME AExecLocalX #define IF_EXECLOCAL #define IF_WITH_ATTR #define IF_WITH_XARGS #include "ifcmd.ct" /****************************************************************************/ /* description of input defines for ifstd.ct IF_NAME: name of interface function These includes generate internal functions for communication on the STD_INTERFACE (IF0). The Gather/Scatter-functions for the STD_INTERFACE will get the DDD_HDR as a parameter, not the DDD_OBJ. TODO: more doc! */ /* with normal arguments for gather/scatter */ #define IF_NAME Exchange #define IF_EXCHANGE #include "ifstd.ct" #define IF_NAME ExecLocal #define IF_EXECLOCAL #include "ifstd.ct" /* with extended arguments for gather/scatter */ #define IF_NAME ExchangeX #define IF_EXCHANGE #define IF_WITH_XARGS #include "ifstd.ct" #define IF_NAME ExecLocalX #define IF_EXECLOCAL #define IF_WITH_XARGS #include "ifstd.ct" /****************************************************************************/ END_UGDIM_NAMESPACE dune-uggrid-2.11.0+dfsg/dune/uggrid/parallel/ddd/if/ifcreate.cc000066400000000000000000000657361513616443000242020ustar00rootroot00000000000000// SPDX-FileCopyrightText: Copyright © DUNE Project contributors, see file LICENSE.md in module root // SPDX-License-Identifier: LGPL-2.1-or-later // -*- tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- // vi: set et ts=4 sw=2 sts=2: /****************************************************************************/ /* */ /* File: ifcreate.c */ /* */ /* Purpose: routines concerning interfaces between processors */ /* part 1: creating and maintaining interfaces */ /* */ /* Author: Klaus Birken */ /* Rechenzentrum Uni Stuttgart */ /* Universitaet Stuttgart */ /* Allmandring 30 */ /* 70550 Stuttgart */ /* internet: birken@rus.uni-stuttgart.de */ /* */ /* History: 93/11/30 kb begin */ /* 94/03/03 kb complete rewrite */ /* 94/09/12 kb IFExchange & IFOneway rewrite, two bugs fixed */ /* 94/09/21 kb created from if.c */ /* 95/01/13 kb added range functionality */ /* 96/01/08 kb renamed range to attr */ /* 96/01/16 kb added DDD_OBJ shortcut to avoid indirect addr. */ /* 96/05/07 kb removed need for global const MAX_COUPLING */ /* */ /* Remarks: */ /* */ /****************************************************************************/ /****************************************************************************/ /* */ /* include files */ /* system include files */ /* application include files */ /* */ /****************************************************************************/ /* standard C library */ #include #include #include #include #include #include #include #include #include #include #include #include #include "if.h" USING_UG_NAMESPACE /* PPIF namespace: */ using namespace PPIF; START_UGDIM_NAMESPACE /****************************************************************************/ /* */ /* routines */ /* */ /****************************************************************************/ /****************************************************************************/ /* */ /* Function: sort_IFCouplings */ /* */ /* Purpose: qsort procedure for sorting interface couplings. */ /* coupling list will be ordered according to: */ /* 1. processor number of represented object copy */ /* (increasing order) */ /* 2. direction of interface according to priorities */ /* (increasing order) */ /* 3. attr property of objects */ /* (decreasing order) */ /* 4. global ids of objects */ /* (increasing order) */ /* */ /* Input: two couplings `a`, `b` */ /* */ /* Output: `a < b` */ /* */ /****************************************************************************/ static bool sort_IFCouplings (const COUPLING* a, const COUPLING* b) { const auto aDir = CPLDIR(a), bDir = CPLDIR(b); // a, b switched in the third component as decreasing order is used for attr return std::tie(CPL_PROC(a), aDir, OBJ_ATTR(b->obj), OBJ_GID(a->obj)) < std::tie(CPL_PROC(b), bDir, OBJ_ATTR(a->obj), OBJ_GID(b->obj)); } static void IFDeleteAll(DDD::DDDContext& context, DDD_IF ifId) { auto& theIF = context.ifCreateContext().theIf; IF_PROC *ifh, *ifhNext; IF_ATTR *ifr, *ifrNext; /* free IF_PROC memory */ ifh=theIF[ifId].ifHead; while (ifh!=NULL) { ifhNext = ifh->next; /* free IF_ATTR memory */ ifr=ifh->ifAttr; while (ifr!=NULL) { ifrNext = ifr->next; delete ifr; ifr = ifrNext; } delete ifh; ifh = ifhNext; } /* free memory for coupling table */ if (theIF[ifId].cpl!=NULL) { FreeIF(theIF[ifId].cpl); theIF[ifId].cpl=NULL; } /* free memory for shortcut object table */ if (theIF[ifId].obj!=NULL) { FreeIF(theIF[ifId].obj); theIF[ifId].obj=NULL; } /* reset pointers */ theIF[ifId].ifHead = NULL; theIF[ifId].nIfHeads = 0; } /* TODO el-set relation, VERY inefficient! */ static bool is_elem (DDD_PRIO el, int n, const DDD_PRIO *set) { for(int i=0; inext) { partners[i] = ifh->proc; } if (! IS_OK(DDD_GetChannels(context, theIF[ifId].nIfHeads))) { RET_ON_ERROR; } for(ifh=theIF[ifId].ifHead; ifh!=NULL; ifh=ifh->next) { ifh->vc = VCHAN_TO(context, ifh->proc); } /* ReleaseHeap(); */ RET_ON_OK; } /****************************************************************************/ /* collect couplings into interface array, for standard interface */ static COUPLING ** IFCollectStdCouplings(DDD::DDDContext& context) { const auto& nCplItems = context.couplingContext().nCplItems; if (nCplItems == 0) return nullptr; /* get memory for couplings inside STD_IF */ COUPLING** cplarray = (COUPLING **) AllocIF(sizeof(COUPLING *)*nCplItems); if (cplarray==NULL) throw std::bad_alloc(); /* collect couplings */ int n = 0; const auto& nCpls = context.couplingContext().nCpls; for(int index=0; index < nCpls; index++) { for(COUPLING* cpl=IdxCplList(context, index); cpl!=NULL; cpl=CPL_NEXT(cpl)) { cplarray[n] = cpl; SETCPLDIR(cpl,0); n++; } } /* printf("%04d: n=%d, nCplItems=%d\n",context.me(),n,nCplItems); */ assert(n==nCplItems); return cplarray; } /****************************************************************************/ static RETCODE IFCreateFromScratch(DDD::DDDContext& context, COUPLING **tmpcpl, DDD_IF ifId) { auto& theIF = context.ifCreateContext().theIf; IF_PROC *ifHead = nullptr, *lastIfHead; IF_ATTR *ifAttr = nullptr, *lastIfAttr = nullptr; int n, i; DDD_PROC lastproc; [[maybe_unused]] int STAT_MOD; const auto& objTable = context.objTable(); STAT_GET_MODULE(STAT_MOD); STAT_SET_MODULE(DDD_MODULE_IF); /* first delete possible old interface */ IFDeleteAll(context, ifId); STAT_RESET1; if (ifId==STD_INTERFACE) { theIF[ifId].cpl = IFCollectStdCouplings(context); n = context.couplingContext().nCplItems; } else { int index; /* collect relevant couplings into tmpcpl array */ n=0; const auto& nCpls = context.couplingContext().nCpls; for(index=0; index < nCpls; index++) { /* determine whether object belongs to IF */ if ((1<prio, theIF[ifId].nPrioA, theIF[ifId].A); const bool cplInB = is_elem(cpl->prio, theIF[ifId].nPrioB, theIF[ifId].B); /* compute possible IF directions */ const int dir = ((objInA&&cplInB) ? DirAB : 0) | ((objInB&&cplInA) ? DirBA : 0); if (dir != 0) { SETCPLDIR(cpl,dir); tmpcpl[n] = cpl; n++; } } } } } if (n>0) { /* re-alloc cpllist, now with correct size */ theIF[ifId].cpl = (COUPLING **) AllocIF(sizeof(COUPLING *)*n); if (theIF[ifId].cpl==NULL) { Dune::dwarn << "IFCreateFromScratch: " STR_NOMEM " for IF " << std::setw(2) << ifId << "\n"; RET_ON_ERROR; } /* copy data from temporary array */ memcpy((void *)theIF[ifId].cpl, (void *)tmpcpl, sizeof(COUPLING *)*n); } else { theIF[ifId].cpl = NULL; } } STAT_TIMER1(T_CREATE_COLLECT); /* sort IF couplings */ STAT_RESET1; if (n>1) std::sort(theIF[ifId].cpl, theIF[ifId].cpl + n, sort_IFCouplings); STAT_TIMER1(T_CREATE_SORT); /* create IF_PROCs */ STAT_RESET1; lastproc = PROC_INVALID; lastIfHead = NULL; theIF[ifId].nIfHeads = 0; for(i=0; iobj); if (CPL_PROC(cpl) != lastproc) { /* create new IfHead */ theIF[ifId].nIfHeads++; ifHead = new IF_PROC; ifHead->cpl = cplp; ifHead->proc = CPL_PROC(cpl); ifHead->next = lastIfHead; lastIfHead = ifHead; lastproc = ifHead->proc; ifHead->nAttrs = 1; ifHead->ifAttr = ifAttr = new IF_ATTR(attr); lastIfAttr = ifAttr; } /* count #items per processor */ ifHead->nItems++; /* keep current ifAttr or find new one? */ if (attr!=ifAttr->attr) { IF_ATTR *ifR; /* does ifAttr already exist? */ ifR = ifHead->ifAttr; while ((ifR!=NULL) && (ifR->attr!=attr)) { ifR=ifR->next; } if (ifR!=NULL) { /* reuse existing ifAttr */ ifAttr = ifR; } else { /* create new ifAttr */ ifHead->nAttrs++; ifAttr = new IF_ATTR(attr); lastIfAttr->next = ifAttr; lastIfAttr = ifAttr; } } /* count #items per processor and attr */ ifAttr->nItems++; /* count #items per directions AB, BA or ABA and set beginnings of AB/BA/ABA subarrays */ if (ifId!=STD_INTERFACE) { switch (CPLDIR(cpl)) { case DirAB : ifHead->nAB++; if (ifHead->cplAB==0) ifHead->cplAB = cplp; ifAttr->nAB++; if (ifAttr->cplAB==0) ifAttr->cplAB = cplp; break; case DirBA : ifHead->nBA++; if (ifHead->cplBA==0) ifHead->cplBA = cplp; ifAttr->nBA++; if (ifAttr->cplBA==0) ifAttr->cplBA = cplp; break; case DirABA : ifHead->nABA++; if (ifHead->cplABA==0) ifHead->cplABA = cplp; ifAttr->nABA++; if (ifAttr->cplABA==0) ifAttr->cplABA = cplp; break; } } } STAT_TIMER1(T_CREATE_BUILD); /* remember anchor of ifHead list */ if (theIF[ifId].nIfHeads>0) { theIF[ifId].ifHead = ifHead; } /* store overall number of coupling items */ theIF[ifId].nItems = n; /* establish obj-table as an addressing shortcut */ STAT_RESET1; IFCreateObjShortcut(context, ifId); STAT_TIMER1(T_CREATE_SHORTCUT); STAT_RESET1; if (! IS_OK(update_channels(context, ifId))) { DDD_PrintError('E', 4003, "couldn't create communication channels"); RET_ON_ERROR; } STAT_TIMER1(T_CREATE_COMM); /* TODO das handling der VCs muss noch erheblich verbessert werden */ /* TODO Still very inefficient because we have to search for is_elem */ STAT_SET_MODULE(STAT_MOD); RET_ON_OK; } /****************************************************************************/ /* */ /* DDD_IFDefine */ /* */ /****************************************************************************/ /** Definition of a DDD Interface. This function defines a new \ddd{interface}. Its argument list contains three arrays: the first one specifies a subset of the global DDD object set, the second and third ones specify a subset of all DDD priorities. After the initial creation of the new interface its ID is returned. During all following DDD operations ({\bf Identify}- as well as {\bf Transfer}-operations) the interface will be kept consistent, and can be used for communication via \funk{IFExchange} and \funk{IFOneway} and analogous functions. @param nO number of entries in array {\it O[\ ]} (as specified with second argument). @param O array of DDD type IDs; the new interface will only contain objects with one of these types. @param nA number of entries in array {\it A[\ ]} (as specified with forth argument). @param A first array of DDD priorities; the object set A from the new interface will only contain objects with one of these priorities. @param nB number of entries in array {\it B[\ ]} (as specified with sixth argument). @param B second array of DDD priorities; the object set B from the new interface will only contain objects with one of these priorities. */ DDD_IF DDD_IFDefine ( DDD::DDDContext& context, int nO, DDD_TYPE O[], int nA, DDD_PRIO A[], int nB, DDD_PRIO B[]) { auto& ctx = context.ifCreateContext(); auto& theIF = ctx.theIf; auto& nIFs = ctx.nIfs; int i; if (nIFs==MAX_IF) { DDD_PrintError('E', 4100, "no more interfaces in DDD_IFDefine"); return(0); } /* construct interface definition */ theIF[nIFs].nObjStruct = nO; theIF[nIFs].nPrioA = nA; theIF[nIFs].nPrioB = nB; memcpy(theIF[nIFs].O, O, nO*sizeof(DDD_TYPE)); memcpy(theIF[nIFs].A, A, nA*sizeof(DDD_PRIO)); memcpy(theIF[nIFs].B, B, nB*sizeof(DDD_PRIO)); if (nO>1) std::sort(theIF[nIFs].O, theIF[nIFs].O + nO); if (nA>1) std::sort(theIF[nIFs].A, theIF[nIFs].A + nA); if (nB>1) std::sort(theIF[nIFs].B, theIF[nIFs].B + nB); /* reset name string */ theIF[nIFs].name[0] = 0; /* compute hash tables for fast access */ theIF[nIFs].maskO = 0; for(i=0; i 0) { /* allocate temporary cpl-list, this will be too large for average interfaces. */ std::vector tmpcpl(nCplItems); if (! IS_OK(IFCreateFromScratch(context, tmpcpl.data(), nIFs))) { DDD_PrintError('E', 4101, "cannot create interface in DDD_IFDefine"); return(0); } } else { if (! IS_OK(IFCreateFromScratch(context, NULL, nIFs))) { DDD_PrintError('E', 4102, "cannot create interface in DDD_IFDefine"); return(0); } } nIFs++; return(nIFs-1); } static void StdIFDefine(DDD::DDDContext& context) { auto& theIF = context.ifCreateContext().theIf; /* exception: no OBJSTRUCT or priority entries */ theIF[STD_INTERFACE].nObjStruct = 0; theIF[STD_INTERFACE].nPrioA = 0; theIF[STD_INTERFACE].nPrioB = 0; theIF[STD_INTERFACE].maskO = 0xffff; /* reset name string */ theIF[STD_INTERFACE].name[0] = '\0'; /* create initial interface state */ theIF[STD_INTERFACE].ifHead = NULL; if (! IS_OK(IFCreateFromScratch(context, NULL, STD_INTERFACE))) DUNE_THROW(Dune::Exception, "cannot create standard interface during IF initialization"); } void DDD_IFSetName(DDD::DDDContext& context, DDD_IF ifId, const char *name) { auto& theIF = context.ifCreateContext().theIf; /* copy name string */ strncpy(theIF[ifId].name, name, IF_NAMELEN-1); } /****************************************************************************/ static void writeCoupling(const DDD::DDDContext& context, const IF_PROC& ifh, const COUPLING& cpl, const char* obj, std::ostream& out) { using std::setw; out << "| gid=" << OBJ_GID(cpl.obj) << " proc=" << setw(4) << CPL_PROC(&cpl) << " prio=" << setw(2) << cpl.prio << "osc=" << obj << "/" << OBJ_OBJ(context, cpl.obj) << "\n"; } void DDD_InfoIFImpl(DDD::DDDContext& context, DDD_IF ifId) { using std::setw; std::ostream& out = std::cout; auto& theIF = context.ifCreateContext().theIf; out << "|\n| DDD_IFInfoImpl for proc=" << context.me() << ", IF " << ifId << "\n"; out << "| cpl=" << theIF[ifId].cpl << " nIfHeads=" << theIF[ifId].nIfHeads << " first=" << theIF[ifId].ifHead << "\n"; for(const IF_PROC* ifh=theIF[ifId].ifHead; ifh!=nullptr; ifh=ifh->next) { out << "| head=" << ifh << " cpl=" << ifh->cpl << " p=" << setw(3) << ifh->proc << " nItems=" << setw(5) << ifh->nItems << " nAttrs=" << setw(3) << ifh->nAttrs << "\n"; out << "| nAB= " << setw(5) << ifh->nAB << "\n"; for(int i = 0; i < ifh->nAB; ++i) writeCoupling(context, *ifh, *ifh->cplAB[i], ifh->objAB[i], out); out << "| nBA= " << setw(5) << ifh->nBA << "\n"; for(int i = 0; i < ifh->nBA; ++i) writeCoupling(context, *ifh, *ifh->cplBA[i], ifh->objBA[i], out); out << "| nABA=" << setw(5) << ifh->nABA << "\n"; for(int i = 0; i < ifh->nABA; ++i) writeCoupling(context, *ifh, *ifh->cplABA[i], ifh->objABA[i], out); } out << "|\n"; } static void IFDisplay (const DDD::DDDContext& context, DDD_IF i) { using std::setw; std::ostream& out = std::cout; const auto& ctx = context.ifCreateContext(); const auto& theIF = ctx.theIf; out << "| IF " << i << " "; if (i==STD_INTERFACE) { out << "including all (" << setw(8) << std::hex << theIF[i].maskO << std::dec << ")\n" << "| prio all to all\n"; } else { out << "including "; for(int j=0; jnext) { if (DDD_GetOption(context, OPT_INFO_IF_WITH_ATTR)==OPT_OFF) out << "| " << setw(3) << ifh->nItems << "=" << setw(3) << ifh->nAB << "," << setw(3) << ifh->nBA << "," << setw(3) << ifh->nABA << " - " << setw(2) << ifh->proc << "\n"; else { out << "| " << setw(3) << ifh->nItems << "=" << setw(3) << ifh->nAB << "," << setw(3) << ifh->nBA << "," << setw(3) << ifh->nABA << " - " << setw(2) << ifh->proc << " - #a=" << setw(5) << ifh->nAttrs << "\n"; for (const IF_ATTR* ifr=ifh->ifAttr; ifr!=NULL; ifr=ifr->next) { out << "| a " << setw(3) << ifr->nItems << "=" << setw(3) << ifr->nAB << "," << setw(3) << ifr->nBA << "," << setw(3) << ifr->nABA << " - " << setw(4) << ifr->attr << "\n"; } } } } /****************************************************************************/ /* */ /* DDD_IFDisplay */ /* */ /****************************************************************************/ /** Display overview of single DDD interface. This function displays an overview table for one DDD-interface, its definition parameters and the current number of constituing objects on the calling processor. For each neighbour processor corresponding to that interface a relation line is displayed, which contains the overall number of objects inside the interface, the number of oneway relations outwards, the number of oneway relations inwards, the number of exchange relations and the neighbour processor number. @param aIF the \ddd{interface} ID. */ void DDD_IFDisplay(const DDD::DDDContext& context, DDD_IF aIF) { if (aIF >= context.ifCreateContext().nIfs) { Dune::dwarn << "DDD_IFDisplay: invalid IF " << std::setw(2) << aIF << "\n"; return; } std::cout << "|\n| DDD_IF-Info for proc=" << context.me() << "\n"; IFDisplay(context, aIF); std::cout << "|\n"; } /****************************************************************************/ /* */ /* DDD_IFDisplayAll */ /* */ /****************************************************************************/ /** Display overview of all DDD interfaces. This function displays an overview table containing all DDD-interfaces, their definition parameters and the current number of constituing objects on the calling processor. For each interface and each neighbour processor corresponding to that interface a relation line is displayed, which contains the overall number of objects inside the interface, the number of oneway relations outwards, the number of oneway relations inwards, the number of exchange relations and the neighbour processor number. */ void DDD_IFDisplayAll(const DDD::DDDContext& context) { std::cout << "|\n| DDD_IF-Info for proc=" << context.me() << " (all)\n"; const auto& nIFs = context.ifCreateContext().nIfs; for(int i=0; i < nIFs; ++i) { IFDisplay(context, i); } std::cout << "|\n"; } static void IFRebuildAll(DDD::DDDContext& context) { /* create standard interface */ if (! IS_OK(IFCreateFromScratch(context, NULL, STD_INTERFACE))) DUNE_THROW(Dune::Exception, "cannot create standard interface in IFRebuildAll"); const auto& nIFs = context.ifCreateContext().nIfs; if (nIFs>1) { int i; const auto& nCplItems = context.couplingContext().nCplItems; if (nCplItems > 0) { /* allocate temporary cpl-list, this will be too large for average interfaces. */ std::vector tmpcpl(nCplItems); /* TODO: Exploit that STD_IF is a superset of all interfaces */ for(i=1; inext) { sum += sizeof(IF_ATTR) * ifp->nAttrs; /* component ifAttr */ } return(sum); } size_t DDD_IFInfoMemory(const DDD::DDDContext& context, DDD_IF ifId) { if (ifId >= context.ifCreateContext().nIfs) DUNE_THROW(Dune::Exception, "invalid interface " << ifId); return IFInfoMemory(context, ifId); } size_t DDD_IFInfoMemoryAll(const DDD::DDDContext& context) { const auto& nIFs = context.ifCreateContext().nIfs; size_t sum = 0; for(int i = 0; i < nIFs; ++i) { sum += IFInfoMemory(context, i); } return(sum); } END_UGDIM_NAMESPACE /****************************************************************************/ dune-uggrid-2.11.0+dfsg/dune/uggrid/parallel/ddd/if/ifobjsc.cc000066400000000000000000000153231513616443000240220ustar00rootroot00000000000000// SPDX-FileCopyrightText: Copyright © DUNE Project contributors, see file LICENSE.md in module root // SPDX-License-Identifier: LGPL-2.1-or-later // -*- tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- // vi: set et ts=4 sw=2 sts=2: /****************************************************************************/ /* */ /* File: ifobjsc.c */ /* */ /* Purpose: routines concerning interfaces between processors */ /* part 4: routines for creation and management of */ /* object shortcut tables */ /* */ /* Author: Klaus Birken */ /* Rechenzentrum Uni Stuttgart */ /* Universitaet Stuttgart */ /* Allmandring 30 */ /* 70550 Stuttgart */ /* internet: birken@rus.uni-stuttgart.de */ /* */ /* History: 96/01/24 kb copied from ifcreate.c */ /* */ /* Remarks: */ /* */ /****************************************************************************/ /****************************************************************************/ /* */ /* include files */ /* system include files */ /* application include files */ /* */ /****************************************************************************/ /* standard C library */ #include #include #include #include #include "if.h" USING_UG_NAMESPACE START_UGDIM_NAMESPACE /****************************************************************************/ /* */ /* definition of static variables */ /* */ /****************************************************************************/ /****************************************************************************/ /* */ /* routines */ /* */ /****************************************************************************/ /* convert cpl-IF-table into obj-IF-table */ static void IFComputeShortcutTable(DDD::DDDContext& context, DDD_IF ifId) { auto& theIF = context.ifCreateContext().theIf; int nItems = theIF[ifId].nItems; COUPLING **cpls = theIF[ifId].cpl; IFObjPtr *objs = theIF[ifId].obj; /* mark obj-shortcut-table as valid */ theIF[ifId].objValid = true; if (nItems==0) return; /* fill in object pointers, this is the 4-fold indirection step */ for(int i = 0; i < nItems; ++i) { objs[i] = OBJ_OBJ(context, cpls[i]->obj); } } /****************************************************************************/ /* create direct link from ifHead and ifAttr to objects, avoid one indirect addressing step across couplings. each cpl-entry in an interface has one corresponding obj-entry */ void IFCreateObjShortcut(DDD::DDDContext& context, DDD_IF ifId) { auto& theIF = context.ifCreateContext().theIf; COUPLING **cplarray = theIF[ifId].cpl; IFObjPtr *objarray; IF_PROC *ifHead; /* dont create shortcuts for STD_INTERFACE */ if (ifId==STD_INTERFACE) return; /* are there any items? */ if (theIF[ifId].nItems == 0) return; /* get memory for addresses of objects inside IF */ objarray = (IFObjPtr *) AllocIF(sizeof(IFObjPtr)*theIF[ifId].nItems); if (objarray==NULL) throw std::bad_alloc(); theIF[ifId].obj = objarray; IFComputeShortcutTable(context, ifId); ForIF(context, ifId, ifHead) { IF_ATTR *ifAttr; /* compute pointers to subarrays */ ifHead->obj = objarray + (ifHead->cpl - cplarray); ifHead->objAB = objarray + (ifHead->cplAB - cplarray); ifHead->objBA = objarray + (ifHead->cplBA - cplarray); ifHead->objABA = objarray + (ifHead->cplABA - cplarray); /* compute pointers from ifAttrs to subarrays */ for(ifAttr=ifHead->ifAttr; ifAttr!=0; ifAttr=ifAttr->next) { ifAttr->objAB = objarray + (ifAttr->cplAB - cplarray); ifAttr->objBA = objarray + (ifAttr->cplBA - cplarray); ifAttr->objABA = objarray + (ifAttr->cplABA - cplarray); } } } /****************************************************************************/ /* if object addresses in memory are changed, then the shortcut-tables will get invalid. this routine does the invalidation. */ void IFInvalidateShortcuts(DDD::DDDContext& context, DDD_TYPE invalid_type) { auto& theIF = context.ifCreateContext().theIf; const auto& nIFs = context.ifCreateContext().nIfs; /* test all interfaces */ for(int i = 0; i < nIFs; ++i) { if (i==STD_INTERFACE) continue; if (theIF[i].objValid) { /* determine whether object belongs to IF */ if ((1<cpl) #define IF_FUNCNAME CAT(ddd_StdIF,IF_NAME) /****************************************************************************/ /* */ /* auxiliary macros */ /* */ /****************************************************************************/ #ifndef IF_AUX_MACROS #define IF_AUX_MACROS #define CONCAT(txt,fct) txt FUNCNAME_STR(fct) #define FUNCNAME_STR(f) #f #endif /****************************************************************************/ /* */ /* routines */ /* */ /****************************************************************************/ void IF_FUNCNAME ( DDD::DDDContext& context, #ifdef IF_EXECLOCAL #ifdef IF_WITH_XARGS NS_DIM_PREFIX ExecProcHdrXPtr ExecProc) #else NS_DIM_PREFIX ExecProcHdrPtr ExecProc) #endif #else size_t aSize, #ifdef IF_WITH_XARGS NS_DIM_PREFIX ComProcHdrXPtr Gather, NS_DIM_PREFIX ComProcHdrXPtr Scatter) #else NS_DIM_PREFIX ComProcHdrPtr Gather, NS_DIM_PREFIX ComProcHdrPtr Scatter) #endif #endif { using std::setw; NS_DIM_PREFIX DDD_IF aIF = NS_DIM_PREFIX STD_INTERFACE; NS_DIM_PREFIX IF_PROC *ifHead; #ifdef IF_EXECLOCAL ForIF(context, aIF, ifHead) { EXEC_LOOP(context, ExecProc, D_ABA(PART), PART->nItems); } #else /* ! IF_EXECLOCAL */ /* allocate storage for in and out buffers */ ForIF(context, aIF, ifHead) { #ifdef IF_EXCHANGE NS_DIM_PREFIX IFGetMem(ifHead, aSize, PART->nItems, PART->nItems); #endif } /* init communication, initiate receives */ int recv_mesgs = NS_DIM_PREFIX IFInitComm(context, aIF); /* build messages using gather-handler and send them away */ ForIF(context, aIF, ifHead) { char *buffer; buffer = ifHead->bufOut.data(); buffer= COMM_LOOP(context, Gather, D_ABA(PART), buffer, aSize, PART->nItems); NS_DIM_PREFIX IFInitSend(context, ifHead); } /* poll receives and scatter data */ unsigned long tries; for(tries=0; tries0; tries++) { /* poll receive calls */ ForIF(context, aIF, ifHead) { if (not ifHead->bufIn.empty() && ifHead->msgIn!=NO_MSGID) { int error = InfoARecv(context.ppifContext(), ifHead->vc, ifHead->msgIn); if (error==-1) DUNE_THROW(Dune::Exception, "InfoARecv() failed for recv to proc=" << ifHead->proc); if (error==1) { char *buffer; #ifdef CtrlTimeoutsDetailed printf("%4d: IFCTRL %02d received msg from " "%4d after %10ld, size %ld\n", context.me(), aIF, ifHead->proc, (unsigned long)tries, (unsigned long)ifHead->bufIn.size()); #endif recv_mesgs--; ifHead->msgIn=NO_MSGID; buffer = ifHead->bufIn.data(); /* get data using scatter-handler */ buffer = COMM_LOOP(context, Scatter, D_ABA(PART), buffer, aSize, PART->nItems); } } } } /* finally poll send completion */ if (recv_mesgs>0) { Dune::dwarn << FUNCNAME_STR(IF_FUNCNAME) ": receive-timeout for IF " << setw(2) << "\n"; ForIF(context, aIF, ifHead) { if (not ifHead->bufIn.empty() && ifHead->msgIn!=NO_MSGID) { Dune::dwarn << " waiting for message (from proc " << ifHead->proc << ", size " << ifHead->bufIn.size() << ")\n"; } } } else { #ifdef CtrlTimeouts printf("%4d: IFCTRL %02d received msg all after %10ld tries\n", context.me(), aIF, (unsigned long)tries); #endif if (! NS_DIM_PREFIX IFPollSend(context, aIF)) { Dune::dwarn << FUNCNAME_STR(IF_FUNCNAME) ": send-timeout for IF " << setw(2) << aIF << "\n"; ForIF(context, aIF, ifHead) { if (not ifHead->bufOut.empty() && ifHead->msgOut!=NO_MSGID) { Dune::dwarn << " waiting for send completion (to proc " << ifHead->proc << ", size " << ifHead->bufOut.size() << ")\n"; } } } } /* free memory */ NS_DIM_PREFIX IFExitComm(context, aIF); /*STAT_TIMER1(60);*/ #endif /* IF_EXECLOCAL */ } /****************************************************************************/ /* undefs for all input macros and defines */ #undef IF_NAME #undef IF_FUNCNAME #ifdef IF_EXCHANGE #undef IF_EXCHANGE #endif #ifdef IF_EXECLOCAL #undef IF_EXECLOCAL #endif #ifdef IF_WITH_XARGS #undef IF_WITH_XARGS #endif #ifdef IF_CBR #undef IF_CBR #endif /* undefs for derived macros */ #undef PART #undef EXEC_LOOP #undef COMM_LOOP #undef D_AB #undef D_BA #undef D_ABA #undef _CAT #undef CAT /****************************************************************************/ dune-uggrid-2.11.0+dfsg/dune/uggrid/parallel/ddd/if/ifuse.cc000066400000000000000000000261021513616443000235130ustar00rootroot00000000000000// SPDX-FileCopyrightText: Copyright © DUNE Project contributors, see file LICENSE.md in module root // SPDX-License-Identifier: LGPL-2.1-or-later // -*- tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- // vi: set et ts=4 sw=2 sts=2: /****************************************************************************/ /* */ /* File: ifuse.c */ /* */ /* Purpose: routines concerning interfaces between processors */ /* part 2: usage of DDD interfaces */ /* */ /* Author: Klaus Birken */ /* Rechenzentrum Uni Stuttgart */ /* Universitaet Stuttgart */ /* Allmandring 30 */ /* 70550 Stuttgart */ /* internet: birken@rus.uni-stuttgart.de */ /* */ /* History: 93/11/30 kb begin */ /* 94/03/03 kb complete rewrite */ /* 94/09/12 kb IFExchange & IFOneway rewrite, two bugs fixed */ /* 94/09/21 kb created from if.c */ /* 95/01/13 kb added range functionality */ /* 95/07/26 kb overlapping of gather/scatter and communication */ /* */ /* Remarks: */ /* */ /****************************************************************************/ /****************************************************************************/ /* */ /* include files */ /* system include files */ /* application include files */ /* */ /****************************************************************************/ /* standard C library */ #include #include #include #include #include #include #include #include "if.h" USING_UG_NAMESPACE /* PPIF namespace: */ using namespace PPIF; START_UGDIM_NAMESPACE /****************************************************************************/ /* */ /* routines */ /* */ /****************************************************************************/ /* allocate memory for message buffers, one for send, one for receive */ void IFGetMem (IF_PROC *ifHead, size_t itemSize, int lenIn, int lenOut) { size_t sizeIn = itemSize * lenIn; size_t sizeOut = itemSize * lenOut; /* set memory to initial value, in order to find any bugs lateron */ ifHead->bufIn.assign(sizeIn, 0); ifHead->bufOut.assign(sizeOut, 0); } /* initiate asynchronous receive calls, return number of messages to be received */ int IFInitComm(DDD::DDDContext& context, DDD_IF ifId) { IF_PROC *ifHead; int error; int recv_mesgs; auto& ctx = context.ifUseContext(); /* MarkHeap(); */ recv_mesgs = 0; /* get memory and initiate receive calls */ ForIF(context, ifId, ifHead) { if (not ifHead->bufIn.empty()) { ifHead->msgIn = RecvASync(context.ppifContext(), ifHead->vc, ifHead->bufIn.data(), ifHead->bufIn.size(), &error); if (ifHead->msgIn==0) DUNE_THROW(Dune::Exception, "RecvASync() failed"); recv_mesgs++; } } ctx.send_mesgs = 0; return recv_mesgs; } /* cleanup memory */ void IFExitComm(DDD::DDDContext& context, DDD_IF ifId) { if (DDD_GetOption(context, OPT_IF_REUSE_BUFFERS) == OPT_OFF) { IF_PROC *ifHead; ForIF(context, ifId, ifHead) { ifHead->bufIn.clear(); ifHead->bufIn.shrink_to_fit(); ifHead->bufOut.clear(); ifHead->bufOut.shrink_to_fit(); } } /* ReleaseHeap(); */ } /* initiate single asynchronous send call */ void IFInitSend(DDD::DDDContext& context, IF_PROC *ifHead) { int error; auto& ctx = context.ifUseContext(); if (not ifHead->bufOut.empty()) { ifHead->msgOut = SendASync(context.ppifContext(), ifHead->vc, ifHead->bufOut.data(), ifHead->bufOut.size(), &error); if (ifHead->msgOut==0) DUNE_THROW(Dune::Exception, "SendASync() failed"); ctx.send_mesgs++; } } /* poll asynchronous send calls, return if ready */ int IFPollSend(DDD::DDDContext& context, DDD_IF ifId) { unsigned long tries; auto& ctx = context.ifUseContext(); for(tries=0; tries0; tries++) { IF_PROC *ifHead; /* poll send calls */ ForIF(context, ifId, ifHead) { if (not ifHead->bufOut.empty() && ifHead->msgOut!= NO_MSGID) { int error = InfoASend(context.ppifContext(), ifHead->vc, ifHead->msgOut); if (error==-1) DUNE_THROW(Dune::Exception, "InfoASend() failed for send to proc=" << ifHead->proc); if (error==1) { ctx.send_mesgs--; ifHead->msgOut=NO_MSGID; #ifdef CtrlTimeoutsDetailed printf("%4d: IFCTRL %02d send-completed to " "%4d after %10ld, size %ld\n", context.me(), ifId, ifHead->proc, (unsigned long)tries, (unsigned long)ifHead->bufOut.size()); #endif } } } } #ifdef CtrlTimeouts if (ctx.send_mesgs==0) { printf("%4d: IFCTRL %02d send-completed all after %10ld tries\n", context.me(), ifId, (unsigned long)tries); } #endif return(ctx.send_mesgs==0); } /****************************************************************************/ /* do loop over single list of couplings, copy object data from/to message buffer fast version: uses object pointer shortcut */ char *IFCommLoopObj (DDD::DDDContext& context, ComProcPtr2 LoopProc, IFObjPtr *obj, char *buffer, size_t itemSize, int nItems) { for(int i=0; i CPL -> DDD_HDR.typ -> header offset -> object address) */ char *IFCommLoopCpl (DDD::DDDContext& context, ComProcPtr2 LoopProc, COUPLING **cpl, char *buffer, size_t itemSize, int nItems) { for(int i=0; iobj), buffer); return(buffer); } /* do loop over single list of couplings, copy object data from/to message buffer extended version: call ComProc with extended parameters (necessary) indirect addressing! (-> CPL -> DDD_HDR.typ -> header offset -> object address) */ char *IFCommLoopCplX (DDD::DDDContext& context, ComProcXPtr LoopProc, COUPLING **cpl, char *buffer, size_t itemSize, int nItems) { for(int i=0; iobj), buffer, CPL_PROC(cpl[i]), cpl[i]->prio); return(buffer); } /* simple variant of above routine. dont communicate, but call an application's routine. */ void IFExecLoopCplX (DDD::DDDContext& context, ExecProcXPtr LoopProc, COUPLING **cpl, int nItems) { for(int i=0; iobj), CPL_PROC(cpl[i]), cpl[i]->prio); } /****************************************************************************/ /*** interface loop functions for STD_INTERFACE communication. (not DDD_OBJ will be passed as a parameter, but DDD_HDR instead). ***/ /* do loop over single list of couplings, copy object data from/to message buffer */ char *IFCommHdrLoopCpl (DDD::DDDContext& context, ComProcHdrPtr LoopProc, COUPLING **cpl, char *buffer, size_t itemSize, int nItems) { for(int i=0; iobj, buffer); return(buffer); } /* simple variant of above routine. dont communicate, but call an application's routine. */ void IFExecHdrLoopCpl (DDD::DDDContext& context, ExecProcHdrPtr LoopProc, COUPLING **cpl, int nItems) { for(int i=0; iobj); } /* do loop over single list of couplings, copy object data from/to message buffer extended version: call ComProc with extended parameters */ char *IFCommHdrLoopCplX (DDD::DDDContext& context, ComProcHdrXPtr LoopProc, COUPLING **cpl, char *buffer, size_t itemSize, int nItems) { for(int i=0; iobj, buffer, CPL_PROC(cpl[i]), cpl[i]->prio); return(buffer); } /* simple variant of above routine. dont communicate, but call an application's routine. extended version: call ExecProc with extended parameters */ void IFExecHdrLoopCplX (DDD::DDDContext& context, ExecProcHdrXPtr LoopProc, COUPLING **cpl, int nItems) { for(int i=0; iobj, CPL_PROC(cpl[i]), cpl[i]->prio); } /****************************************************************************/ END_UGDIM_NAMESPACE dune-uggrid-2.11.0+dfsg/dune/uggrid/parallel/ddd/include/000077500000000000000000000000001513616443000231155ustar00rootroot00000000000000dune-uggrid-2.11.0+dfsg/dune/uggrid/parallel/ddd/include/CMakeLists.txt000066400000000000000000000003651513616443000256610ustar00rootroot00000000000000# SPDX-FileCopyrightText: Copyright © DUNE Project contributors, see file LICENSE.md in module root # SPDX-License-Identifier: LGPL-2.1-or-later install(FILES ddd.h DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}/dune/uggrid/parallel/ddd/include) dune-uggrid-2.11.0+dfsg/dune/uggrid/parallel/ddd/include/ddd.h000066400000000000000000000472211513616443000240270ustar00rootroot00000000000000// -*- tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- // vi: set et ts=4 sw=2 sts=2: // SPDX-FileCopyrightInfo: Copyright © DUNE Project contributors, see file LICENSE.md in module root // SPDX-License-Identifier: LGPL-2.1-or-later /****************************************************************************/ /* */ /* File: ddd.h */ /* */ /* Purpose: header file for ddd module */ /* */ /* Author: Klaus Birken */ /* Rechenzentrum Uni Stuttgart */ /* Universitaet Stuttgart */ /* Allmandring 30 */ /* 70550 Stuttgart */ /* internet: birken@rus.uni-stuttgart.de */ /* */ /* */ /* History: 93/11/22 kb begin */ /* 94/06/27 kb revision for usage in C++ context */ /* 94/08/22 kb major revision, corresp. to Ref.Man. V1.0 */ /* 94/09/13 kb added DDD_Status */ /* 95/01/13 kb added range functionality */ /* 95/01/16 kb added Statistics features */ /* 95/01/18 kb moved Statistics to dddaddon.h */ /* 95/02/06 kb added extended Ifs */ /* 95/03/08 kb added UserData features */ /* 95/03/21 kb added variable-sized Objects */ /* 95/05/22 kb added var-sized AddData features */ /* 95/11/04 kb complete redesign of ObjMgr and Registering */ /* 95/11/06 kb changed parameters of DDD_Init() */ /* 95/11/15 kb ddd_hdr with arbitrary offset (started) */ /* 96/01/08 kb renamed range to attr */ /* 96/05/12 kb xfer-unpack rewritten */ /* 96/06/05 kb changed handler management */ /* 96/09/06 kb xfer-module completely rewritten */ /* 96/11/28 kb merged F_FRONTEND functionality from code branch */ /* 97/02/10 kb started with CPP_FRONTEND implementation */ /* 98/01/28 kb new ddd-environment: Join. */ /* 98/05/14 kb redesigned memory handling. */ /* 98/07/20 kb new ddd-environment: Prio. */ /* */ /* Remarks: */ /* */ /****************************************************************************/ #ifndef __DDD__ #define __DDD__ /* for size_t */ #include #include #include #include #include START_UGDIM_NAMESPACE using namespace DDD; #define DDD_VERSION "1.9" /* F77SYM(lsym,usym) macro is defined in compiler.h. 961127 KB */ /****************************************************************************/ /* */ /* compile time constants defining static data size (i.e. arrays) */ /* other constants */ /* */ /****************************************************************************/ /* return types for DDD functions */ enum DDD_RET { DDD_RET_OK = 0, /* function was executed ok */ DDD_RET_ERROR_UNKNOWN = 1, /* unknown error condition */ DDD_RET_ERROR_NOMEM = 2 /* function aborted due to mem shortage */ }; /* types of elements for StructRegister */ /* (use negative values for combination with positive DDD_TYPEs) */ enum DDD_ELEM_TYPE { EL_DDDHDR = 0, /* element type: DDD header */ EL_GDATA = -1, /* element type: global data */ EL_LDATA = -2, /* element type: local data */ EL_GBITS = -3, /* element type: bitwise, 1=global */ EL_DATAPTR = -4, /* element type: data pointer */ EL_OBJPTR = -5, /* element type: object pointer */ EL_CONTINUE = -6, /* continued element definition list */ EL_END = -7 /* end of element definition list */ }; /* NOTE: changes must be also done in fddd.f */ enum OptConsts { OPT_OFF = 0, OPT_ON }; enum OptConstIdent { IDMODE_LISTS = 1, /* ordering of each identify-tupel is relevant */ IDMODE_SETS /* ordering of each identify-tupel is not sensitive */ }; enum OptConstXfer { XFER_SHOW_NONE = 0x0000, /* show no statistical infos */ XFER_SHOW_OBSOLETE = 0x0001, /* show #obsolete xfer-commands */ XFER_SHOW_MEMUSAGE = 0x0002, /* show sizes of message buffers */ XFER_SHOW_MSGSALL = 0x0004 /* show message contents by LowComm stats */ }; enum OptConstJoin { JOIN_SHOW_NONE = 0x0000, /* show no statistical infos */ JOIN_SHOW_OBSOLETE = 0x0001, /* show #obsolete join-commands */ JOIN_SHOW_MEMUSAGE = 0x0002, /* show sizes of message buffers */ JOIN_SHOW_MSGSALL = 0x0004 /* show message contents by LowComm stats */ }; /* direction of interface communication (DDD_IFOneway) */ /* NOTE: changes must be also done in fddd.f */ enum DDD_IF_DIR { IF_FORWARD = 1, /* communicate from A to B */ IF_BACKWARD = 2 /* communicate from B to A */ }; /* ID of (predefined) standard interface */ enum IFConstants { STD_INTERFACE = 0 }; /* DDD_TYPE DDD_USER_DATA: send stream of bytes with XferAddData */ enum XferConstants { /* DDD_TYPE DDD_USER_DATA: send stream of bytes with XferAddData */ /* application may add small integers in order to get more stream-of-byte channels, up to DDD_USER_DATA_MAX */ DDD_USER_DATA = 0x4000, DDD_USER_DATA_MAX = 0x4fff, /* additional parameter for user defined handlers in xfer */ /* object has been rejected due to RULE C3 */ XFER_REJECT = 0x9000, /* object has been upgraded due to RULE C3 */ XFER_UPGRADE, /* object has been downgraded due to PruneDel */ XFER_DOWNGRADE, /* object is totally new */ XFER_NEW, /* return value for DDD_XferIsPrunedDelete */ XFER_PRUNED_TRUE = 0x9100, XFER_PRUNED_FALSE, XFER_PRUNED_ERROR, /* return value for DDD_XferObjIsResent */ XFER_RESENT_TRUE = 0x9200, XFER_RESENT_FALSE, XFER_RESENT_ERROR }; /* several default modes for priority handling */ enum PrioMatrixDefaults { PRIOMERGE_MAXIMUM = 0, PRIOMERGE_MINIMUM }; /* constants for management of temporary memory allocation/deletion */ enum TMemRequests { TMEM_ANY = 0x0000, TMEM_MSG, TMEM_OBJLIST, TMEM_CPL, TMEM_XFER = 0x1000, TMEM_LOWCOMM, TMEM_JOIN = 0x2000, TMEM_CONS = 0x3000, TMEM_IDENT = 0x4000 }; /****************************************************************************/ /* */ /* data structures and new types */ /* */ /****************************************************************************/ /* new DDD types, used during access of DDD functional interface */ using DDD_GID = DDD::DDD_GID; static_assert( std::is_same::value, "printf conversion specifier below expects DDD_GID to be uint_least64_t"); #define DDD_GID_FMT "%08" PRIxLEAST64 #define DDD_GID_TO_INT(A) (A) using DDD_TYPE = DDD::DDD_TYPE; using DDD_IF = DDD::DDD_IF; using DDD_PROC = DDD::DDD_PROC; using DDD_PRIO = DDD::DDD_PRIO; using DDD_ATTR = DDD::DDD_ATTR; using DDD_OBJ = DDD::DDD_OBJ; using DDD_HEADER = DDD::DDD_HEADER; using DDD_HDR = DDD::DDD_HDR; /* NULL values for DDD types */ #define DDD_TYPE_NULL 0 #define DDD_PROC_NULL 0 #define DDD_PRIO_NULL 0 #define DDD_ATTR_NULL 0 /* special feature: hybrid reftype at TypeDefine-time */ #define DDD_TYPE_BY_HANDLER 127 /* must be > MAX_TYPEDESC */ /****************************************************************************/ /* */ /* macros */ /* */ /****************************************************************************/ /* external access of elements in DDD_HEADER */ #define DDD_InfoPriority(ddd_hdr) ((ddd_hdr)->prio) #define DDD_InfoGlobalId(ddd_hdr) ((ddd_hdr)->gid) #define DDD_InfoAttr(ddd_hdr) ((ddd_hdr)->attr) #define DDD_InfoType(ddd_hdr) ((ddd_hdr)->typ) /****************************************************************************/ /* */ /* declaration of DDD functional interface */ /* */ /****************************************************************************/ /* General DDD Module */ void DDD_Init(DDD::DDDContext& context); void DDD_Exit(DDD::DDDContext& context); void DDD_Status(const DDD::DDDContext& context); void DDD_SetOption(DDD::DDDContext& context, DDD_OPTION, int); /* Redirect line-oriented output, new in V1.2 */ void DDD_LineOutRegister (void (*func)(const char *s)); /* Type Manager Module */ DDD_TYPE DDD_TypeDeclare(DDD::DDDContext& context, const char *name); int DDD_InfoHdrOffset(const DDD::DDDContext& context, DDD_TYPE); void DDD_TypeDefine(DDD::DDDContext& context, DDD_TYPE, ...); void DDD_TypeDisplay(const DDD::DDDContext& context, DDD_TYPE); int DDD_InfoTypes(const DDD::DDDContext& context); /* newstyle, type-secure setting of handlers */ void DDD_SetHandlerLDATACONSTRUCTOR(DDD::DDDContext& context, DDD_TYPE, HandlerLDATACONSTRUCTOR); void DDD_SetHandlerDESTRUCTOR (DDD::DDDContext& context, DDD_TYPE, HandlerDESTRUCTOR); void DDD_SetHandlerDELETE (DDD::DDDContext& context, DDD_TYPE, HandlerDELETE); void DDD_SetHandlerUPDATE (DDD::DDDContext& context, DDD_TYPE, HandlerUPDATE); void DDD_SetHandlerOBJMKCONS (DDD::DDDContext& context, DDD_TYPE, HandlerOBJMKCONS); void DDD_SetHandlerSETPRIORITY (DDD::DDDContext& context, DDD_TYPE, HandlerSETPRIORITY); void DDD_SetHandlerXFERCOPY (DDD::DDDContext& context, DDD_TYPE, HandlerXFERCOPY); void DDD_SetHandlerXFERDELETE (DDD::DDDContext& context, DDD_TYPE, HandlerXFERDELETE); void DDD_SetHandlerXFERGATHER (DDD::DDDContext& context, DDD_TYPE, HandlerXFERGATHER); void DDD_SetHandlerXFERSCATTER (DDD::DDDContext& context, DDD_TYPE, HandlerXFERSCATTER); void DDD_SetHandlerXFERGATHERX (DDD::DDDContext& context, DDD_TYPE, HandlerXFERGATHERX); void DDD_SetHandlerXFERSCATTERX (DDD::DDDContext& context, DDD_TYPE, HandlerXFERSCATTERX); void DDD_SetHandlerXFERCOPYMANIP (DDD::DDDContext& context, DDD_TYPE, HandlerXFERCOPYMANIP); void DDD_PrioMergeDefault (DDD::DDDContext& context, DDD_TYPE, int); void DDD_PrioMergeDefine (DDD::DDDContext& context, DDD_TYPE, DDD_PRIO, DDD_PRIO, DDD_PRIO); DDD_PRIO DDD_PrioMerge (DDD::DDDContext& context, DDD_TYPE, DDD_PRIO, DDD_PRIO); void DDD_PrioMergeDisplay (DDD::DDDContext& context, DDD_TYPE); /* Object Properties */ #ifndef DUNE_UGGRID_DDD_InfoProcListRange /** \brief feature test macro for `DDD_InfoProcListRange` */ # define DUNE_UGGRID_DDD_InfoProcListRange 202209L #endif /** * \brief entry in the list returned by `DDD_InfoProcListRange` */ struct DDD_InfoProcListEntry { /** \brief processor */ DDD_PROC proc; /** \brief priority */ DDD_PRIO prio; }; /** * \brief iterator for (process, priority) tuples for couplings * * See `DDD_InfoProcListRange` for more details. */ class DDD_InfoProcListIterator { const COUPLING* cpl_; public: using value_type = DDD_InfoProcListEntry; DDD_InfoProcListIterator(const COUPLING* cpl) noexcept : cpl_(cpl) { /* Nothing */ } value_type operator*() const noexcept { return { cpl_->_proc, cpl_->prio }; } void operator++() noexcept { cpl_ = cpl_->_next; } explicit operator bool() const noexcept { return static_cast(cpl_); } #if __cplusplus >= 202002L bool operator==(const DDD_InfoProcListIterator&) const noexcept = default; #else bool operator==(const DDD_InfoProcListIterator& other) const noexcept { return cpl_ == other.cpl_; } bool operator!=(const DDD_InfoProcListIterator& other) const noexcept { return cpl_ != other.cpl_; } #endif }; /** * \brief range with (process, priority) tuples for couplings of the given `hdr` * * This range provides access to the `process` and `priority` of all couplings * for the object identified by `hdr`. In addition it provides an optional dummy * coupling for the local process; this can be controlled with the `skipDummy` * parameter. */ class DDD_InfoProcListRange { COUPLING dummy_; bool includeDummy_; public: /** * \brief construct range with (process, priority) tuples for couplings of the given `hdr` * * \param context DDD context * \param hdr parallel object whose couplings will be used * \param includeDummy whether to include a dummy coupling for the local process */ DDD_InfoProcListRange(DDDContext& context, const DDD_HDR hdr, bool includeDummy = true) noexcept; /** \brief Returns iterator to the begin of the range */ DDD_InfoProcListIterator begin() const noexcept { return {includeDummy_ ? &dummy_ : dummy_._next}; } /** \brief Returns iterator to the end of the range */ DDD_InfoProcListIterator end() const noexcept { return {nullptr}; } /** \brief Return whether the range is empty. */ bool empty() const noexcept { return begin() == end(); } }; void DDD_PrioritySet(DDD::DDDContext& context, DDD_HDR, DDD_PRIO); void DDD_AttrSet (DDD_HDR, DDD_ATTR); /* this shouldn't be allowed */ DDD_PROC DDD_InfoProcPrio(const DDD::DDDContext& context, DDD_HDR, DDD_PRIO); bool DDD_InfoIsLocal(const DDD::DDDContext& context, DDD_HDR); int DDD_InfoNCopies(const DDD::DDDContext& context, DDD_HDR); size_t DDD_InfoCplMemory(const DDD::DDDContext& context); /* Identification Environment Module */ void DDD_IdentifyBegin(DDD::DDDContext& context); DDD_RET DDD_IdentifyEnd(DDD::DDDContext& context); void DDD_IdentifyNumber(DDD::DDDContext& context, DDD_HDR, DDD_PROC, int); void DDD_IdentifyString(DDD::DDDContext& context, DDD_HDR, DDD_PROC, char *); void DDD_IdentifyObject(DDD::DDDContext& context, DDD_HDR, DDD_PROC, DDD_HDR); /* Interface Module */ DDD_IF DDD_IFDefine (DDD::DDDContext& context, int, DDD_TYPE O[], int, DDD_PRIO A[], int, DDD_PRIO B[]); void DDD_IFSetName (DDD::DDDContext& context, DDD_IF, const char *); void DDD_IFDisplayAll(const DDD::DDDContext& context); void DDD_IFDisplay(const DDD::DDDContext& context, DDD_IF); size_t DDD_IFInfoMemoryAll(const DDD::DDDContext& context); size_t DDD_IFInfoMemory(const DDD::DDDContext& context, DDD_IF); void DDD_IFRefreshAll(DDD::DDDContext& context); void DDD_IFExchange (DDD::DDDContext& context, DDD_IF, size_t, ComProcPtr2,ComProcPtr2); void DDD_IFOneway (DDD::DDDContext& context, DDD_IF, DDD_IF_DIR,size_t, ComProcPtr2,ComProcPtr2); void DDD_IFExecLocal (DDD::DDDContext& context, DDD_IF, ExecProcPtr); void DDD_IFAExchange (DDD::DDDContext& context, DDD_IF,DDD_ATTR, size_t, ComProcPtr2,ComProcPtr2); void DDD_IFAOneway (DDD::DDDContext& context, DDD_IF,DDD_ATTR,DDD_IF_DIR,size_t, ComProcPtr2,ComProcPtr2); void DDD_IFAExecLocal (DDD::DDDContext& context, DDD_IF,DDD_ATTR, ExecProcPtr); void DDD_IFExchangeX (DDD::DDDContext& context, DDD_IF, size_t, ComProcXPtr,ComProcXPtr); void DDD_IFOnewayX (DDD::DDDContext& context, DDD_IF, DDD_IF_DIR,size_t, ComProcXPtr,ComProcXPtr); void DDD_IFExecLocalX (DDD::DDDContext& context, DDD_IF, ExecProcXPtr); void DDD_IFAExchangeX (DDD::DDDContext& context, DDD_IF,DDD_ATTR, size_t, ComProcXPtr,ComProcXPtr); void DDD_IFAOnewayX (DDD::DDDContext& context, DDD_IF,DDD_ATTR,DDD_IF_DIR,size_t, ComProcXPtr,ComProcXPtr); void DDD_IFAExecLocalX(DDD::DDDContext& context, DDD_IF,DDD_ATTR, ExecProcXPtr); /* Transfer Environment Module */ bool DDD_XferWithAddData(const DDD::DDDContext& context); void DDD_XferAddData(DDD::DDDContext& context, int, DDD_TYPE); void DDD_XferAddDataX(DDD::DDDContext& context, int, DDD_TYPE, size_t sizes[]); int DDD_XferIsPrunedDelete(const DDD::DDDContext& context, DDD_HDR); int DDD_XferObjIsResent(const DDD::DDDContext& context, DDD_HDR); void DDD_XferBegin(DDD::DDDContext& context); DDD_RET DDD_XferEnd(DDD::DDDContext& context); void DDD_XferCopyObj (DDD::DDDContext& context, DDD_HDR, DDD_PROC, DDD_PRIO); void DDD_XferCopyObjX (DDD::DDDContext& context, DDD_HDR, DDD_PROC, DDD_PRIO, size_t); void DDD_XferDeleteObj (DDD::DDDContext& context, DDD_HDR); void DDD_XferPrioChange(DDD::DDDContext& context, DDD_HDR, DDD_PRIO); /* Prio Environment Module */ void DDD_PrioBegin(DDD::DDDContext& context); DDD_RET DDD_PrioEnd(DDD::DDDContext& context); void DDD_PrioChange(const DDD::DDDContext& context, DDD_HDR, DDD_PRIO); /* Join Environment Module */ void DDD_JoinBegin(DDD::DDDContext& context); DDD_RET DDD_JoinEnd(DDD::DDDContext& context); void DDD_JoinObj(DDD::DDDContext& context, DDD_HDR, DDD_PROC, DDD_GID); /* Object Manager */ DDD_OBJ DDD_ObjNew (size_t, DDD_TYPE, DDD_PRIO, DDD_ATTR); void DDD_ObjDelete (DDD_OBJ, size_t, DDD_TYPE); void DDD_HdrConstructor(DDD::DDDContext& context, DDD_HDR, DDD_TYPE, DDD_PRIO, DDD_ATTR); void DDD_HdrConstructorMove(DDD::DDDContext& context, DDD_HDR, DDD_HDR); void DDD_HdrDestructor(DDD::DDDContext& context, DDD_HDR); DDD_OBJ DDD_ObjGet (DDD::DDDContext& context, size_t, DDD_TYPE, DDD_PRIO, DDD_ATTR); void DDD_ObjUnGet (DDD::DDDContext& context, DDD_HDR, size_t); /* Maintenance & Debugging */ int DDD_ConsCheck(DDD::DDDContext& context); /* returns total #errors since V1.6.6 */ void DDD_ListLocalObjects(const DDD::DDDContext& context); DDD_HDR DDD_SearchHdr(DDD::DDDContext&, DDD_GID); /****************************************************************************/ END_UGDIM_NAMESPACE #endif dune-uggrid-2.11.0+dfsg/dune/uggrid/parallel/ddd/include/dddaddon.h000066400000000000000000000106261513616443000250340ustar00rootroot00000000000000// -*- tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- // vi: set et ts=4 sw=2 sts=2: // SPDX-FileCopyrightInfo: Copyright © DUNE Project contributors, see file LICENSE.md in module root // SPDX-License-Identifier: LGPL-2.1-or-later /****************************************************************************/ /* */ /* DDD V1.1 */ /* */ /* File: dddaddon.h */ /* */ /* Purpose: header file for ddd additional functionality */ /* i.e.: */ /* 1) Statistical evaluation and performance measures */ /* */ /* Author: Klaus Birken */ /* Rechenzentrum Uni Stuttgart */ /* Universitaet Stuttgart */ /* Allmandring 30 */ /* 70550 Stuttgart */ /* internet: birken@rus.uni-stuttgart.de */ /* */ /* */ /* History: 95/01/18 kb begin */ /* */ /* Remarks: */ /* */ /****************************************************************************/ #ifndef __DDDADDON__ #define __DDDADDON__ START_UGDIM_NAMESPACE /* #ifdef __cplusplus extern "C" { #endif */ /****************************************************************************/ /* */ /* definition of constants */ /* */ /****************************************************************************/ enum { DDD_MODULE_MGR, DDD_MODULE_XFER, DDD_MODULE_IDENT, DDD_MODULE_IF, DDD_MODULES }; /* for DDD_MODULE_IDENT */ /* times */ enum { T_PREPARE, T_PREPARE_SORT, T_QSORT_TUPEL, T_RESOLVE_DEP, T_QSORT_LOI, T_BUILD_GRAPH, T_CONSTRUCT_ARRAY, T_COMM_AND_IDENT, T_BUILD_IF }; /* numbers */ enum { N_PARTNERS }; /* for DDD_MODULE_IF */ /* times */ enum { T_CREATE_COLLECT, T_CREATE_SORT, T_CREATE_BUILD, T_CREATE_SHORTCUT, T_CREATE_COMM }; /* numbers */ /*enum { }; */ /* for DDD_MODULE_XFER */ /* times */ enum { T_XFER_PREP_CMDS, T_XFER_PREP_MSGS, T_XFER_PACK_SEND, T_XFER_WHILE_COMM, T_XFER_WAIT_RECV, T_XFER_UNPACK, T_XFER_PREP_CPL, T_XFER_CPLMSG, T_XFER_BUILD_IF }; /* numbers */ /*enum { }; */ /****************************************************************************/ /* */ /* definition of exported global variables */ /* */ /****************************************************************************/ /****************************************************************************/ /* */ /* declaration of DDD-addon functional interface */ /* */ /****************************************************************************/ /* Statistic Evaluation and Performance Measurements */ double DDD_StatClock (int module, int index); long DDD_StatCount (int module, int index); const char * DDD_StatClockDesc (int module, int index); const char * DDD_StatCountDesc (int module, int index); /* #ifdef __cplusplus } #endif */ END_UGDIM_NAMESPACE #endif dune-uggrid-2.11.0+dfsg/dune/uggrid/parallel/ddd/include/dddio.h000066400000000000000000000064201513616443000243530ustar00rootroot00000000000000// -*- tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- // vi: set et ts=4 sw=2 sts=2: // SPDX-FileCopyrightInfo: Copyright © DUNE Project contributors, see file LICENSE.md in module root // SPDX-License-Identifier: LGPL-2.1-or-later /****************************************************************************/ /* */ /* File: dddio.h */ /* */ /* Purpose: I/O routines used by DDD */ /* */ /* Author: Klaus Birken */ /* Rechenzentrum Uni Stuttgart */ /* Universitaet Stuttgart */ /* Allmandring 30 */ /* 70550 Stuttgart */ /* internet: birken@rus.uni-stuttgart.de */ /* */ /* */ /* History: 30.01.92 begin, ug version 2.0 (Peter Bastian) */ /* 93/11/26 kb PrintErrorMessage copied from ug version 2.0 */ /* Remarks: */ /* */ /****************************************************************************/ /****************************************************************************/ /* */ /* auto include mechanism and other include files */ /* */ /****************************************************************************/ #ifndef __DDDIO__ #define __DDDIO__ #include namespace DDD { /****************************************************************************/ /* */ /* user-defined lineout-function prototype */ /* */ /****************************************************************************/ extern void (*DDD_UserLineOutFunction)(const char *s); /****************************************************************************/ /* */ /* function declarations */ /* */ /****************************************************************************/ void DDD_PrintLine (const char *s); void DDD_PrintDebug (const char *s); void DDD_PrintError (char error_class, int error_no, const char *text); void DDD_Flush (void); void DDD_SyncAll(const DDD::DDDContext& context); } /* namespace DDD */ #endif dune-uggrid-2.11.0+dfsg/dune/uggrid/parallel/ddd/include/memmgr.h000066400000000000000000000060041513616443000245520ustar00rootroot00000000000000// -*- tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- // vi: set et ts=4 sw=2 sts=2: // SPDX-FileCopyrightInfo: Copyright © DUNE Project contributors, see file LICENSE.md in module root // SPDX-License-Identifier: LGPL-2.1-or-later /****************************************************************************/ /* */ /* File: memmgr.h */ /* */ /* Purpose: header file for ddd memory management interface */ /* */ /* Author: Klaus Birken */ /* Rechenzentrum Uni Stuttgart */ /* Universitaet Stuttgart */ /* Allmandring 30 */ /* 70550 Stuttgart */ /* internet: birken@rus.uni-stuttgart.de */ /* */ /* */ /* History: 94/04/27 kb begin */ /* */ /* Remarks: */ /* */ /****************************************************************************/ /****************************************************************************/ /* */ /* auto include mechanism and other include files */ /* */ /****************************************************************************/ #ifndef __MEMMGR__ #define __MEMMGR__ #include START_UGDIM_NAMESPACE /****************************************************************************/ /* */ /* function declarations */ /* */ /****************************************************************************/ void *memmgr_AllocOMEM (size_t size, int Typeid, int prio, int attr); void memmgr_FreeOMEM (void *mem, size_t size, int Typeid); void *memmgr_AllocPMEM (long unsigned int size); void memmgr_FreePMEM (void *mem); void *memmgr_AllocAMEM (long unsigned int size); void memmgr_FreeAMEM (void *mem); void *memmgr_AllocTMEM (long unsigned int size, int kind); void memmgr_FreeTMEM (void *mem, int kind); END_UGDIM_NAMESPACE #endif dune-uggrid-2.11.0+dfsg/dune/uggrid/parallel/ddd/join/000077500000000000000000000000001513616443000224315ustar00rootroot00000000000000dune-uggrid-2.11.0+dfsg/dune/uggrid/parallel/ddd/join/CMakeLists.txt000066400000000000000000000004611513616443000251720ustar00rootroot00000000000000# SPDX-FileCopyrightText: Copyright © DUNE Project contributors, see file LICENSE.md in module root # SPDX-License-Identifier: LGPL-2.1-or-later target_sources_dims(duneuggrid PRIVATE jcmds.cc join.cc) install(FILES join.h DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}/dune/uggrid/parallel/ddd/join) dune-uggrid-2.11.0+dfsg/dune/uggrid/parallel/ddd/join/jcmds.cc000066400000000000000000001070151513616443000240440ustar00rootroot00000000000000// SPDX-FileCopyrightText: Copyright © DUNE Project contributors, see file LICENSE.md in module root // SPDX-License-Identifier: LGPL-2.1-or-later // -*- tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- // vi: set et ts=4 sw=2 sts=2: /****************************************************************************/ /* */ /* File: jcmds.c */ /* */ /* Purpose: DDD-commands for Join Environment */ /* */ /* Author: Klaus Birken */ /* Institut fuer Computeranwendungen III */ /* Universitaet Stuttgart */ /* Pfaffenwaldring 27 */ /* 70569 Stuttgart */ /* email: birken@ica3.uni-stuttgart.de */ /* phone: 0049-(0)711-685-7007 */ /* fax : 0049-(0)711-685-7000 */ /* */ /* History: 980126 kb begin */ /* */ /* Remarks: */ /* */ /****************************************************************************/ /****************************************************************************/ /* */ /* include files */ /* system include files */ /* application include files */ /* */ /****************************************************************************/ /* standard C library */ #include #include #include #include #include #include #include #include #include #include #include "join.h" USING_UG_NAMESPACE using namespace PPIF; START_UGDIM_NAMESPACE using namespace DDD::Join; /****************************************************************************/ /* */ /* data structures */ /* */ /****************************************************************************/ /****************************************************************************/ /* */ /* definition of exported global variables */ /* */ /****************************************************************************/ /****************************************************************************/ /* */ /* definition of variables global to this source file only (static!) */ /* */ /****************************************************************************/ /****************************************************************************/ /* */ /* routines */ /* */ /****************************************************************************/ /* prepare messages for phase 1. */ static int PreparePhase1Msgs (DDD::DDDContext& context, std::vector& arrayJoin, JOINMSG1 **theMsgs, size_t *memUsage) { auto& ctx = context.joinContext(); int i, last_i, nMsgs; JIJoin** itemsJ = arrayJoin.data(); const int nJ = arrayJoin.size(); # if DebugJoin<=3 printf("%4d: PreparePhase1Msgs, nJoins=%d\n", me, nJ); fflush(stdout); # endif /* init return parameters */ *theMsgs = NULL; *memUsage = 0; if (nJ==0) /* no messages */ return(0); /* check whether Join objects are really local (without copies) */ /* and set local GID to invalid (will be set to new value lateron) */ for(i=0; ihdr)) DUNE_THROW(Dune::Exception, "cannot join " << OBJ_GID(itemsJ[i]->hdr) << ", object already distributed"); OBJ_GID(itemsJ[i]->hdr) = GID_INVALID; } /* set local GID to new value */ for(i=0; ihdr); /* check for double Joins with different new_gid */ if (local_gid!=GID_INVALID && local_gid!=itemsJ[i]->new_gid) DUNE_THROW(Dune::Exception, "several (inconsistent) DDD_JoinObj-commands " "for local object " << local_gid); OBJ_GID(itemsJ[i]->hdr) = itemsJ[i]->new_gid; } nMsgs = 0; last_i = i = 0; do { size_t bufSize; /* skip until dest-processor is different */ while (idest == itemsJ[last_i]->dest)) i++; /* create new message */ JOINMSG1* jm = new JOINMSG1; jm->nJoins = i-last_i; jm->arrayJoin = &(itemsJ[last_i]); jm->dest = itemsJ[last_i]->dest; jm->next = *theMsgs; *theMsgs = jm; nMsgs++; /* create new send message */ jm->msg_h = LC_NewSendMsg(context, ctx.phase1msg_t, jm->dest); /* init table inside message */ LC_SetTableSize(jm->msg_h, ctx.jointab_id, jm->nJoins); /* prepare message for sending away */ bufSize = LC_MsgPrepareSend(context, jm->msg_h); *memUsage += bufSize; if (DDD_GetOption(context, OPT_INFO_JOIN) & JOIN_SHOW_MEMUSAGE) { Dune::dwarn << "DDD MESG [" << std::setw(3) << context.me() << "]: SHOW_MEM " << "send msg phase1 dest=" << std::setw(4) << jm->dest << " size=" << std::setw(10) << bufSize << "\n"; } last_i = i; } while (last_i < nJ); return(nMsgs); } /****************************************************************************/ /* */ /* Function: PackPhase1Msgs */ /* */ /* Purpose: allocate one message buffer for each outgoing message, */ /* fill buffer with message contents and initiate asynchronous */ /* send for each message. */ /* */ /* Input: theMsgs: list of message-send-infos */ /* */ /* Output: - */ /* */ /****************************************************************************/ static void PackPhase1Msgs (DDD::DDDContext& context, JOINMSG1 *theMsgs) { auto& ctx = context.joinContext(); JOINMSG1 *jm; for(jm=theMsgs; jm!=NULL; jm=jm->next) { TEJoin *theJoinTab; int i; /* copy data into message */ theJoinTab = (TEJoin *)LC_GetPtr(jm->msg_h, ctx.jointab_id); for(i=0; inJoins; i++) { theJoinTab[i].gid = jm->arrayJoin[i]->new_gid; theJoinTab[i].prio = OBJ_PRIO(jm->arrayJoin[i]->hdr); } LC_SetTableLen(jm->msg_h, ctx.jointab_id, jm->nJoins); /* send away */ LC_MsgSend(context, jm->msg_h); } } /* unpack phase1 messages. */ static void UnpackPhase1Msgs (DDD::DDDContext& context, LC_MSGHANDLE *theMsgs, int nRecvMsgs, DDD_HDR *localCplObjs, int nLCO, JIPartner **p_joinObjs, int *p_nJoinObjs) { auto& ctx = context.joinContext(); const auto& me = context.me(); JIPartner *joinObjs; int nJoinObjs = 0; int m, jo; /* init return values */ *p_joinObjs = NULL; *p_nJoinObjs = 0; for(m=0; m(ctx.setJIAddCpl2)); ji->dest = CPL_PROC(cpl); ji->te.gid = theJoin[i].gid; ji->te.proc = LC_MsgGetProc(jm); ji->te.prio = theJoin[i].prio; if (! JIAddCplSet_ItemOK(reinterpret_cast(ctx.setJIAddCpl2))) continue; # if DebugJoin<=1 printf("%4d: Phase1 Join for " DDD_GID_FMT " from %d, " "send AddCpl to %d.\n", me, theJoin[i].gid, ji->te.proc, ji->dest); # endif } /* send phase3-JIAddCpl back to Join-proc */ for(cpl=ObjCplList(context, localCplObjs[j]); cpl!=NULL; cpl=CPL_NEXT(cpl)) { JIAddCpl *ji = JIAddCplSet_NewItem(reinterpret_cast(ctx.setJIAddCpl3)); ji->dest = LC_MsgGetProc(jm); ji->te.gid = OBJ_GID(localCplObjs[j]); ji->te.proc = CPL_PROC(cpl); ji->te.prio = cpl->prio; if (! JIAddCplSet_ItemOK(reinterpret_cast(ctx.setJIAddCpl3))) continue; } } else { DUNE_THROW(Dune::Exception, "no object " << theJoin[i].gid << " for join from " << LC_MsgGetProc(jm)); } } } /* return immediately if no join-objects have been found */ if (nJoinObjs==0) return; /* allocate array of objects, which has been contacted by a join */ joinObjs = new JIPartner[nJoinObjs]; /* set return values */ *p_joinObjs = joinObjs; *p_nJoinObjs = nJoinObjs; /* add one local coupling for each Join */ for(m=0, jo=0; m(ctx.setJIAddCpl3)); ji->dest = LC_MsgGetProc(jm); ji->te.gid = OBJ_GID(theJoin[i].hdr); ji->te.proc = me; ji->te.prio = OBJ_PRIO(theJoin[i].hdr); JIAddCplSet_ItemOK(reinterpret_cast(ctx.setJIAddCpl3)); } joinObjs[jo].hdr = theJoin[i].hdr; joinObjs[jo].proc = LC_MsgGetProc(jm); jo++; } } /* sort joinObjs-array according to gid */ if (nJoinObjs>1) { std::sort( joinObjs, joinObjs + nJoinObjs, [](const JIPartner& a, const JIPartner& b) { return OBJ_GID(a.hdr) < OBJ_GID(b.hdr); }); } } /****************************************************************************/ /* prepare messages for phase 2. */ static int PreparePhase2Msgs (DDD::DDDContext& context, std::vector& arrayAddCpl, JOINMSG2 **theMsgs, size_t *memUsage) { auto& ctx = context.joinContext(); const auto& me = context.me(); int i, last_i, nMsgs; JIAddCpl** itemsAC = arrayAddCpl.data(); const int nAC = arrayAddCpl.size(); # if DebugJoin<=3 printf("%4d: PreparePhase2Msgs, nAddCpls=%d\n", me, nAC); fflush(stdout); # endif /* init return parameters */ *theMsgs = NULL; *memUsage = 0; if (nAC==0) /* no messages */ return(0); nMsgs = 0; last_i = i = 0; do { size_t bufSize; /* skip until dest-processor is different */ while (idest == itemsAC[last_i]->dest)) i++; /* create new message */ JOINMSG2* jm = new JOINMSG2; jm->nAddCpls = i-last_i; jm->arrayAddCpl = &(itemsAC[last_i]); jm->dest = itemsAC[last_i]->dest; jm->next = *theMsgs; *theMsgs = jm; nMsgs++; /* create new send message */ jm->msg_h = LC_NewSendMsg(context, ctx.phase2msg_t, jm->dest); /* init table inside message */ LC_SetTableSize(jm->msg_h, ctx.addtab_id, jm->nAddCpls); /* prepare message for sending away */ bufSize = LC_MsgPrepareSend(context, jm->msg_h); *memUsage += bufSize; if (DDD_GetOption(context, OPT_INFO_JOIN) & JOIN_SHOW_MEMUSAGE) { Dune::dwarn << "DDD MESG [" << std::setw(3) << me << "]: SHOW_MEM " << "send msg phase2 dest=" << std::setw(4) << jm->dest << " size=" << std::setw(10) << bufSize << "\n"; } last_i = i; } while (last_i < nAC); return(nMsgs); } /****************************************************************************/ /* */ /* Function: PackPhase2Msgs */ /* */ /* Purpose: allocate one message buffer for each outgoing message, */ /* fill buffer with message contents and initiate asynchronous */ /* send for each message. */ /* */ /* Input: theMsgs: list of message-send-infos */ /* */ /* Output: - */ /* */ /****************************************************************************/ static void PackPhase2Msgs(DDD::DDDContext& context, JOINMSG2 *theMsgs) { auto& ctx = context.joinContext(); JOINMSG2 *jm; for(jm=theMsgs; jm!=NULL; jm=jm->next) { TEAddCpl *theAddTab; int i; /* copy data into message */ theAddTab = (TEAddCpl *)LC_GetPtr(jm->msg_h, ctx.addtab_id); for(i=0; inAddCpls; i++) { /* copy complete TEAddCpl item */ theAddTab[i] = jm->arrayAddCpl[i]->te; } LC_SetTableLen(jm->msg_h, ctx.addtab_id, jm->nAddCpls); /* send away */ LC_MsgSend(context, jm->msg_h); } } /* unpack phase2 messages. */ static void UnpackPhase2Msgs (DDD::DDDContext& context, LC_MSGHANDLE *theMsgs2, int nRecvMsgs2, JIPartner *joinObjs, int nJoinObjs, DDD_HDR *localCplObjs, int nLCO) { auto& ctx = context.joinContext(); int m; for(m=0; m(ctx.setJIAddCpl3)); ji->dest = joinObjs[jo].proc; ji->te.gid = theAC[i].gid; ji->te.proc = theAC[i].proc; ji->te.prio = theAC[i].prio; JIAddCplSet_ItemOK(reinterpret_cast(ctx.setJIAddCpl3)); # if DebugJoin<=1 printf("%4d: Phase2 forward AddCpl(%08x,%d,%d) to %d.\n", context.me(), theAC[i].gid, theAC[i].proc, theAC[i].prio, ji->dest); # endif jo++; } } else { /* this should never happen. AddCpl send from invalid proc. */ assert(0); } } } } /****************************************************************************/ /* prepare messages for phase 3. */ static int PreparePhase3Msgs (DDD::DDDContext& context, std::vector& arrayAddCpl, JOINMSG3 **theMsgs, size_t *memUsage) { auto& ctx = context.joinContext(); const auto& me = context.me(); int i, last_i, nMsgs; JIAddCpl** itemsAC = arrayAddCpl.data(); const int nAC = arrayAddCpl.size(); # if DebugJoin<=3 printf("%4d: PreparePhase3Msgs, nAddCpls=%d\n", me, nAC); fflush(stdout); # endif /* init return parameters */ *theMsgs = NULL; *memUsage = 0; if (nAC==0) /* no messages */ return(0); nMsgs = 0; last_i = i = 0; do { size_t bufSize; /* skip until dest-processor is different */ while (idest == itemsAC[last_i]->dest)) i++; /* create new message */ JOINMSG3* jm = new JOINMSG3; jm->nAddCpls = i-last_i; jm->arrayAddCpl = &(itemsAC[last_i]); jm->dest = itemsAC[last_i]->dest; jm->next = *theMsgs; *theMsgs = jm; nMsgs++; /* create new send message */ jm->msg_h = LC_NewSendMsg(context, ctx.phase3msg_t, jm->dest); /* init table inside message */ LC_SetTableSize(jm->msg_h, ctx.cpltab_id, jm->nAddCpls); /* prepare message for sending away */ bufSize = LC_MsgPrepareSend(context, jm->msg_h); *memUsage += bufSize; if (DDD_GetOption(context, OPT_INFO_JOIN) & JOIN_SHOW_MEMUSAGE) { Dune::dwarn << "DDD MESG [" << std::setw(3) << me << "]: SHOW_MEM " << "send msg phase3 dest=" << std::setw(4) << jm->dest << " size=" << std::setw(10) << bufSize << "\n"; } last_i = i; } while (last_i < nAC); return(nMsgs); } /****************************************************************************/ /* */ /* Function: PackPhase3Msgs */ /* */ /* Purpose: allocate one message buffer for each outgoing message, */ /* fill buffer with message contents and initiate asynchronous */ /* send for each message. */ /* */ /* Input: theMsgs: list of message-send-infos */ /* */ /* Output: - */ /* */ /****************************************************************************/ static void PackPhase3Msgs(DDD::DDDContext& context, JOINMSG3 *theMsgs) { auto& ctx = context.joinContext(); JOINMSG3 *jm; for(jm=theMsgs; jm!=NULL; jm=jm->next) { TEAddCpl *theAddTab; int i; /* copy data into message */ theAddTab = (TEAddCpl *)LC_GetPtr(jm->msg_h, ctx.cpltab_id); for(i=0; inAddCpls; i++) { /* copy complete TEAddCpl item */ theAddTab[i] = jm->arrayAddCpl[i]->te; } LC_SetTableLen(jm->msg_h, ctx.cpltab_id, jm->nAddCpls); /* send away */ LC_MsgSend(context, jm->msg_h); } } /****************************************************************************/ /* unpack phase3 messages. */ static void UnpackPhase3Msgs (DDD::DDDContext& context, LC_MSGHANDLE *theMsgs, int nRecvMsgs, std::vector& arrayJoin) { auto& ctx = context.joinContext(); JIJoin** itemsJ = arrayJoin.data(); const int nJ = arrayJoin.size(); int m; for(m=0; mhdr) < theAC[i].gid)) j++; if ((jhdr) == theAC[i].gid)) { /* found local object which is AddCpl target */ AddCoupling(context, itemsJ[j]->hdr, theAC[i].proc, theAC[i].prio); # if DebugJoin<=1 printf("%4d: Phase3 execute AddCpl(%08x,%d,%d) (from %d).\n", context.me(), OBJ_GID(itemsJ[j]->hdr), theAC[i].proc, theAC[i].prio, LC_MsgGetProc(jm)); # endif } else { /* this should never happen. AddCpl send for unknown obj. */ assert(0); } } } } /****************************************************************************/ /* */ /* Function: DDD_JoinEnd */ /* */ /****************************************************************************/ /** End of join phase. This function starts the actual join process. After a call to this function (on all processors) all {\bf Join}-commands since the last call to \funk{JoinBegin} are executed. This involves a set of local communications between the processors. */ DDD_RET DDD_JoinEnd(DDD::DDDContext& context) { auto& ctx = context.joinContext(); int obsolete, nRecvMsgs1, nRecvMsgs2, nRecvMsgs3; JOINMSG1 *sendMsgs1=NULL, *sm1=NULL; JOINMSG2 *sendMsgs2=NULL, *sm2=NULL; JOINMSG3 *sendMsgs3=NULL, *sm3=NULL; LC_MSGHANDLE *recvMsgs1=NULL, *recvMsgs2=NULL, *recvMsgs3=NULL; size_t sendMem=0, recvMem=0; JIPartner *joinObjs = NULL; int nJoinObjs; const auto& nCpls = context.couplingContext().nCpls; STAT_SET_MODULE(DDD_MODULE_JOIN); STAT_ZEROALL; /* step mode and check whether call to JoinEnd is valid */ if (!JoinStepMode(context, JoinMode::JMODE_CMDS)) DUNE_THROW(Dune::Exception, "DDD_JoinEnd() aborted"); /* PREPARATION PHASE */ /* get sorted array of JIJoin-items */ std::vector arrayJIJoin = JIJoinSet_GetArray(reinterpret_cast(ctx.setJIJoin)); obsolete = JIJoinSet_GetNDiscarded(reinterpret_cast(ctx.setJIJoin)); /* COMMUNICATION PHASE 1 all processors, where JoinObj-commands have been issued, send information about these commands to the target processors together with the GID of the objects on the target procs and the local priority. */ STAT_RESET; /* prepare msgs for JIJoin-items */ PreparePhase1Msgs(context, arrayJIJoin, &sendMsgs1, &sendMem); /* DisplayMemResources(); */ /* init communication topology */ nRecvMsgs1 = LC_Connect(context, ctx.phase1msg_t); STAT_TIMER(T_JOIN_PREP_MSGS); STAT_RESET; /* build phase1 msgs on sender side and start send */ PackPhase1Msgs(context, sendMsgs1); STAT_TIMER(T_JOIN_PACK_SEND); /* now messages are in the net, use spare time */ STAT_RESET; /* get sorted list of local objects with couplings */ std::vector localCplObjs = LocalCoupledObjectsList(context); if (obsolete>0) { if (DDD_GetOption(context, OPT_INFO_JOIN) & JOIN_SHOW_OBSOLETE) { int all = JIJoinSet_GetNItems(reinterpret_cast(ctx.setJIJoin)); using std::setw; Dune::dwarn << "DDD MESG [" << setw(3) << context.me() << "]: " << setw(4) << obsolete << " from " << setw(4) << all << " join-cmds obsolete.\n"; } } STAT_TIMER(T_JOIN); /* nothing more to do until incoming messages arrive */ /* display information about send-messages on lowcomm-level */ if (DDD_GetOption(context, OPT_INFO_JOIN) & JOIN_SHOW_MSGSALL) { DDD_SyncAll(context); if (context.isMaster()) Dune::dwarn << "DDD JOIN_SHOW_MSGSALL: Phase1Msg.Send\n"; LC_PrintSendMsgs(context); } /* wait for communication-completion (send AND receive) */ STAT_RESET; recvMsgs1 = LC_Communicate(context); STAT_TIMER(T_JOIN_WAIT_RECV); /* display information about message buffer sizes */ if (DDD_GetOption(context, OPT_INFO_JOIN) & JOIN_SHOW_MEMUSAGE) { int k; /* sum up sizes of receive mesg buffers */ for(k=0; k arrayJIAddCpl2 = JIAddCplSet_GetArray(reinterpret_cast(ctx.setJIAddCpl2)); STAT_RESET; /* prepare msgs for JIAddCpl-items */ PreparePhase2Msgs(context, arrayJIAddCpl2, &sendMsgs2, &sendMem); /* DisplayMemResources(); */ /* init communication topology */ nRecvMsgs2 = LC_Connect(context, ctx.phase2msg_t); STAT_TIMER(T_JOIN_PREP_MSGS); STAT_RESET; /* build phase2 msgs on sender side and start send */ PackPhase2Msgs(context, sendMsgs2); STAT_TIMER(T_JOIN_PACK_SEND); /* now messages are in the net, use spare time */ /* reorder Join-commands according to new_gid */ /* this ordering is needed in UnpackPhase3 */ if (arrayJIJoin.size() > 1) { std::sort( arrayJIJoin.begin(), arrayJIJoin.end(), [](const JIJoin* a, const JIJoin* b) { return a->new_gid < b->new_gid; }); } /* nothing more to do until incoming messages arrive */ /* display information about send-messages on lowcomm-level */ if (DDD_GetOption(context, OPT_INFO_JOIN) & JOIN_SHOW_MSGSALL) { DDD_SyncAll(context); if (context.isMaster()) Dune::dwarn <<"DDD JOIN_SHOW_MSGSALL: Phase2Msg.Send\n"; LC_PrintSendMsgs(context); } /* wait for communication-completion (send AND receive) */ STAT_RESET; recvMsgs2 = LC_Communicate(context); STAT_TIMER(T_JOIN_WAIT_RECV); /* display information about message buffer sizes */ if (DDD_GetOption(context, OPT_INFO_JOIN) & JOIN_SHOW_MEMUSAGE) { int k; /* sum up sizes of receive mesg buffers */ for(k=0; knext; delete sendMsgs2; } /* COMMUNICATION PHASE 3 all processors which received notification of JoinObj-commands during phase 1 send AddCpl-requests to the procs where the JoinObj-commands have been issued. One AddCpl-request is sent for each cpl in the local objects coupling list. One AddCpl-request is sent for each AddCpl-request received during phase 2. (i.e., two kinds of AddCpl-requests are send to the processors on which the JoinObj-commands have been issued. */ /* get sorted array of JIAddCpl-items */ std::vector arrayJIAddCpl3 = JIAddCplSet_GetArray(reinterpret_cast(ctx.setJIAddCpl3)); STAT_RESET; /* prepare msgs for JIAddCpl-items */ PreparePhase3Msgs(context, arrayJIAddCpl3, &sendMsgs3, &sendMem); /* DisplayMemResources(); */ /* init communication topology */ nRecvMsgs3 = LC_Connect(context, ctx.phase3msg_t); STAT_TIMER(T_JOIN_PREP_MSGS); STAT_RESET; /* build phase3 msgs on sender side and start send */ PackPhase3Msgs(context, sendMsgs3); STAT_TIMER(T_JOIN_PACK_SEND); /* now messages are in the net, use spare time */ /* ... */ /* nothing more to do until incoming messages arrive */ /* display information about send-messages on lowcomm-level */ if (DDD_GetOption(context, OPT_INFO_JOIN) & JOIN_SHOW_MSGSALL) { DDD_SyncAll(context); if (context.isMaster()) Dune::dwarn << "DDD JOIN_SHOW_MSGSALL: Phase3Msg.Send\n"; LC_PrintSendMsgs(context); } /* wait for communication-completion (send AND receive) */ STAT_RESET; recvMsgs3 = LC_Communicate(context); STAT_TIMER(T_JOIN_WAIT_RECV); /* display information about message buffer sizes */ if (DDD_GetOption(context, OPT_INFO_JOIN) & JOIN_SHOW_MEMUSAGE) { int k; /* sum up sizes of receive mesg buffers */ for(k=0; knext; delete sendMsgs3; } /* free temporary storage */ JIJoinSet_Reset(reinterpret_cast(ctx.setJIJoin)); JIAddCplSet_Reset(reinterpret_cast(ctx.setJIAddCpl2)); JIAddCplSet_Reset(reinterpret_cast(ctx.setJIAddCpl3)); if (joinObjs!=NULL) delete[] joinObjs; for(; sendMsgs1!=NULL; sendMsgs1=sm1) { sm1 = sendMsgs1->next; delete sendMsgs1; } # if DebugJoin<=4 Dune::dverb << "JoinEnd, before IFAllFromScratch().\n"; # endif /* re-create all interfaces and step JMODE */ STAT_RESET; IFAllFromScratch(context); STAT_TIMER(T_JOIN_BUILD_IF); JoinStepMode(context, JoinMode::JMODE_BUSY); return(DDD_RET_OK); } /****************************************************************************/ /* */ /* Function: DDD_JoinObj */ /* */ /****************************************************************************/ /** Join local object with a distributed object. \todoTBC @param hdr DDD local object which should be joined. */ void DDD_JoinObj(DDD::DDDContext& context, DDD_HDR hdr, DDD_PROC dest, DDD_GID new_gid) { auto& ctx = context.joinContext(); const auto procs = context.procs(); if (!ddd_JoinActive(context)) DUNE_THROW(Dune::Exception, "Missing DDD_JoinBegin()"); if (dest>=procs) DUNE_THROW(Dune::Exception, "cannot join " << OBJ_GID(hdr) << " with " << new_gid << " on processor " << dest << " (procs=" << procs << ")"); if (dest==context.me()) DUNE_THROW(Dune::Exception, "cannot join " << OBJ_GID(hdr) << " with myself"); if (ObjHasCpl(context, hdr)) DUNE_THROW(Dune::Exception, "cannot join " << OBJ_GID(hdr) << ", object already distributed"); JIJoin* ji = JIJoinSet_NewItem(reinterpret_cast(ctx.setJIJoin)); ji->hdr = hdr; ji->dest = dest; ji->new_gid = new_gid; if (! JIJoinSet_ItemOK(reinterpret_cast(ctx.setJIJoin))) return; # if DebugJoin<=2 Dune:dvverb << "DDD_JoinObj " << OBJ_GID(hdr) << ", dest=" << dest << ", new_gid=" << new_gid << "\n"; # endif } /****************************************************************************/ /* */ /* Function: DDD_JoinBegin */ /* */ /****************************************************************************/ /** Starts join phase. A call to this function establishes a global join operation. It must be issued on all processors. After this call an arbitrary series of {\bf Join}-commands may be issued. The global transfer operation is carried out via a \funk{JoinEnd} call on each processor. */ void DDD_JoinBegin(DDD::DDDContext& context) { /* step mode and check whether call to JoinBegin is valid */ if (!JoinStepMode(context, JoinMode::JMODE_IDLE)) DUNE_THROW(Dune::Exception, "DDD_JoinBegin() aborted"); } END_UGDIM_NAMESPACE dune-uggrid-2.11.0+dfsg/dune/uggrid/parallel/ddd/join/join.cc000066400000000000000000000200251513616443000236760ustar00rootroot00000000000000// SPDX-FileCopyrightText: Copyright © DUNE Project contributors, see file LICENSE.md in module root // SPDX-License-Identifier: LGPL-2.1-or-later // -*- tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- // vi: set et ts=4 sw=2 sts=2: /****************************************************************************/ /* */ /* File: join.c */ /* */ /* Purpose: main module for object join environment */ /* */ /* Author: Klaus Birken */ /* Institut fuer Computeranwendungen III */ /* Universitaet Stuttgart */ /* Pfaffenwaldring 27 */ /* 70569 Stuttgart */ /* email: birken@ica3.uni-stuttgart.de */ /* phone: 0049-(0)711-685-7007 */ /* fax : 0049-(0)711-685-7000 */ /* */ /* History: 980122 kb begin */ /* */ /* Remarks: */ /* */ /****************************************************************************/ /****************************************************************************/ /* */ /* include files */ /* system include files */ /* application include files */ /* */ /****************************************************************************/ /* standard C library */ #include #include #include #include #include #include USING_UG_NAMESPACE START_UGDIM_NAMESPACE /* NOTE: all container-classes from ooppcc.h are implemented in this source file by setting the following define. */ #define ContainerImplementation #define _CHECKALLOC(ptr) assert(ptr!=NULL) END_UGDIM_NAMESPACE #include "join.h" START_UGDIM_NAMESPACE /****************************************************************************/ /* */ /* class member function implementations */ /* */ /****************************************************************************/ #define ClassName JIJoin /* compare-method in order to eliminate double JIJoin-items. the items are sorted according to key (dest,remote_gid), all in ascending order. */ int Method(Compare) (ClassPtr item1, ClassPtr item2, const DDD::DDDContext*) { if (item1->dest < item2->dest) return(-1); if (item1->dest > item2->dest) return(1); if (item1->new_gid < item2->new_gid) return(-1); if (item1->new_gid > item2->new_gid) return(1); /* items have equal gid and dest, so they are considered as equal. */ return(0); } void Method(Print) (ParamThis _PRINTPARAMS) { fprintf(fp, "JIJoin local_gid=" OBJ_GID_FMT " dest=%d new_gid=" DDD_GID_FMT "\n", OBJ_GID(This->hdr), This->dest, This->new_gid); } #undef ClassName #define ClassName JIAddCpl /* compare-method in order to eliminate double JIAddCpl-items. the items are sorted according to key (dest,gid), all in ascending order. */ int Method(Compare) (ClassPtr item1, ClassPtr item2, const DDD::DDDContext*) { if (item1->dest < item2->dest) return(-1); if (item1->dest > item2->dest) return(1); if (item1->te.gid < item2->te.gid) return(-1); if (item1->te.gid > item2->te.gid) return(1); if (item1->te.proc < item2->te.proc) return(-1); if (item1->te.proc > item2->te.proc) return(1); /* items have equal gid and dest, so they are considered as equal. */ return(0); } void Method(Print) (ParamThis _PRINTPARAMS) { fprintf(fp, "JIAddCpl gid=" DDD_GID_FMT " dest=%d proc=%d prio=%d\n", This->te.gid, This->dest, This->te.proc, This->te.prio); } #undef ClassName /****************************************************************************/ /* */ /* routines */ /* */ /****************************************************************************/ /* management functions for JoinMode. these functions control the mode the join-module is currently in. this is used for error detection, but also for correct detection of coupling inconsistencies and recovery. */ const char *JoinModeName(JoinMode mode) { switch(mode) { case JoinMode::JMODE_IDLE : return "idle-mode"; case JoinMode::JMODE_CMDS : return "commands-mode"; case JoinMode::JMODE_BUSY : return "busy-mode"; } return "unknown-mode"; } static void JoinSetMode (DDD::DDDContext& context, JoinMode mode) { auto& ctx = context.joinContext(); ctx.joinMode = mode; # if DebugJoin<=8 Dune::dinfo << "JoinMode=" << JoinModeName(ctx.joinMode) << "\n"; # endif } static JoinMode JoinSuccMode (JoinMode mode) { switch(mode) { case JoinMode::JMODE_IDLE : return JoinMode::JMODE_CMDS; case JoinMode::JMODE_CMDS : return JoinMode::JMODE_BUSY; case JoinMode::JMODE_BUSY : return JoinMode::JMODE_IDLE; } DUNE_THROW(Dune::InvalidStateException, "invalid JoinMode"); } bool ddd_JoinActive(const DDD::DDDContext& context) { return context.joinContext().joinMode != JoinMode::JMODE_IDLE; } bool JoinStepMode(DDD::DDDContext& context, JoinMode old) { auto& ctx = context.joinContext(); if (ctx.joinMode != old) { Dune::dwarn << "wrong join-mode (currently in " << JoinModeName(ctx.joinMode) << ", expected " << JoinModeName(old) << ")\n"; return false; } JoinSetMode(context, JoinSuccMode(ctx.joinMode)); return true; } /****************************************************************************/ void ddd_JoinInit(DDD::DDDContext& context) { auto& ctx = context.joinContext(); /* init control structures for JoinInfo-items in messages */ ctx.setJIJoin = reinterpret_cast(New_JIJoinSet()); ctx.setJIAddCpl2 = reinterpret_cast(New_JIAddCplSet()); ctx.setJIAddCpl3 = reinterpret_cast(New_JIAddCplSet()); JoinSetMode(context, JoinMode::JMODE_IDLE); ctx.phase1msg_t = LC_NewMsgType(context, "Join1Msg"); ctx.jointab_id = LC_NewMsgTable("GidTab", ctx.phase1msg_t, sizeof(TEJoin)); ctx.phase2msg_t = LC_NewMsgType(context, "Join2Msg"); ctx.addtab_id = LC_NewMsgTable("AddCplTab", ctx.phase2msg_t, sizeof(TEAddCpl)); ctx.phase3msg_t = LC_NewMsgType(context, "Join3Msg"); ctx.cpltab_id = LC_NewMsgTable("AddCplTab", ctx.phase3msg_t, sizeof(TEAddCpl)); } void ddd_JoinExit(DDD::DDDContext& context) { auto& ctx = context.joinContext(); JIJoinSet_Free(reinterpret_cast(ctx.setJIJoin)); JIAddCplSet_Free(reinterpret_cast(ctx.setJIAddCpl2)); JIAddCplSet_Free(reinterpret_cast(ctx.setJIAddCpl3)); } END_UGDIM_NAMESPACE dune-uggrid-2.11.0+dfsg/dune/uggrid/parallel/ddd/join/join.h000066400000000000000000000237041513616443000235470ustar00rootroot00000000000000// -*- tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- // vi: set et ts=4 sw=2 sts=2: // SPDX-FileCopyrightInfo: Copyright © DUNE Project contributors, see file LICENSE.md in module root // SPDX-License-Identifier: LGPL-2.1-or-later /****************************************************************************/ /* */ /* File: join.h */ /* */ /* Purpose: header file for join environment */ /* */ /* Author: Klaus Birken */ /* Institut fuer Computeranwendungen III */ /* Universitaet Stuttgart */ /* Pfaffenwaldring 27 */ /* 70569 Stuttgart */ /* email: birken@ica3.uni-stuttgart.de */ /* phone: 0049-(0)711-685-7007 */ /* fax : 0049-(0)711-685-7000 */ /* */ /* History: 980126 kb begin */ /* */ /* Remarks: */ /* */ /****************************************************************************/ /****************************************************************************/ /* */ /* auto include mechanism and other include files */ /* */ /****************************************************************************/ #ifndef __JOIN_H__ #define __JOIN_H__ #include #define DebugJoin 10 /* 0 is all, 10 is off */ #include #include /* for object-orientated style via preprocessor */ /****************************************************************************/ /* */ /* defines in the following order */ /* */ /* compile time constants defining static data size (i.e. arrays) */ /* other constants */ /* macros */ /* */ /****************************************************************************/ /* some macros for customizing oopp */ #define _NEWPARAMS #define _NEWPARAMS_OR_VOID void #define __INDENT(n) { int i; for(i=0; i /****************************************************************************/ /* JIPartner: description of phase1 message on sender side */ /****************************************************************************/ struct JIPartner { DDD_HDR hdr; /* local obj which has been contacted by join */ DDD_PROC proc; /* proc which initiated join */ }; /****************************************************************************/ /* JIAddCpl: remote command to add cpl for join-obj during phase 2 */ /****************************************************************************/ struct TEAddCpl { DDD_GID gid; /* gid of object to add coupling */ DDD_PROC proc; /* proc of new coupling */ DDD_PRIO prio; /* prio of new coupling */ }; #define ClassName JIAddCpl Class_Data_Begin DDD_PROC dest; /* receiver of this item */ TEAddCpl te; /* table entry (for message) */ Class_Data_End void Method(Print) (DefThis _PRINTPARAMS); int Method(Compare) (ClassPtr, ClassPtr, const DDD::DDDContext*); #undef ClassName /* define container class */ #ifndef SetOf /* necessary for inline documentation only */ #define SetOf JIAddCpl #define Set_SegmSize 256 #define Set_BTreeOrder 32 #endif #include /****************************************************************************/ /* JOINMSG1: description of phase1 message on sender side */ /****************************************************************************/ struct TEJoin { DDD_GID gid; /* gid of distributed obj to join with */ DDD_PRIO prio; /* prio of new local object which is joined */ DDD_HDR hdr; /* hdr of local DDD object (only for receiver) */ }; struct JOINMSG1 { DDD_PROC dest; /* receiver of message */ JOINMSG1 *next; JIJoinPtr *arrayJoin; int nJoins; /* lowcomm message handle */ LC_MSGHANDLE msg_h; }; /****************************************************************************/ /* JOINMSG2: description of phase2 message on sender side */ /****************************************************************************/ struct JOINMSG2 { DDD_PROC dest; /* receiver of message */ JOINMSG2 *next; JIAddCplPtr *arrayAddCpl; int nAddCpls; /* lowcomm message handle */ LC_MSGHANDLE msg_h; }; /****************************************************************************/ /* JOINMSG3: description of phase3 message on sender side */ /****************************************************************************/ struct JOINMSG3 { DDD_PROC dest; /* receiver of message */ JOINMSG3 *next; JIAddCplPtr *arrayAddCpl; int nAddCpls; /* lowcomm message handle */ LC_MSGHANDLE msg_h; }; /****************************************************************************/ /* */ /* function declarations */ /* */ /****************************************************************************/ /* join.c, used only by cmds.c */ /* XICopyObj **CplClosureEstimate(DDD::DDDContext& context, XICopyObjPtrArray *, int *); int PrepareObjMsgs(XICopyObjPtrArray *, XINewCpl **, int, XIOldCpl **, int, XFERMSG **, size_t *); void ExecLocalXIDelCmd(XIDelCmd **, int); void ExecLocalXISetPrio(XISetPrioPtrArray *, XIDelObj **,int, XICopyObj **,int); void ExecLocalXIDelObj(XIDelObj **, int, XICopyObj **,int); void PropagateCplInfos(XISetPrio **, int, XIDelObj **, int, TENewCpl *, int); */ bool JoinStepMode(DDD::DDDContext& context, JoinMode); /* pack.c, used only by cmds.c */ /* void XferPackMsgs (XFERMSG *); */ /* unpack.c, used only by cmds.c */ /* void XferUnpack (LC_MSGHANDLE *, int, DDD_HDR *, int, XISetPrioPtrArray *, XIDelObj **, int, XICopyObjPtrArray *, XICopyObj **, int); */ /* ctrl.c */ /* void XferDisplayMsg (DDD::DDDContext& context, char *comment, LC_MSGHANDLE); */ END_UGDIM_NAMESPACE #endif dune-uggrid-2.11.0+dfsg/dune/uggrid/parallel/ddd/memmgrs/000077500000000000000000000000001513616443000231415ustar00rootroot00000000000000dune-uggrid-2.11.0+dfsg/dune/uggrid/parallel/ddd/memmgrs/memmgr_std.cc000066400000000000000000000067171513616443000256210ustar00rootroot00000000000000// SPDX-FileCopyrightText: Copyright © DUNE Project contributors, see file LICENSE.md in module root // SPDX-License-Identifier: LGPL-2.1-or-later // -*- tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- // vi: set et ts=4 sw=2 sts=2: /****************************************************************************/ /* */ /* File: memmgr_std.c */ /* */ /* Purpose: basic memory management module */ /* (with standard malloc() calls) */ /* */ /* Author: Klaus Birken */ /* Rechenzentrum Uni Stuttgart */ /* Universitaet Stuttgart */ /* Allmandring 30 */ /* 70550 Stuttgart */ /* internet: birken@rus.uni-stuttgart.de */ /* */ /* History: 94/04/27 kb begin */ /* 96/01/20 kb updated to DDD V1.5 */ /* */ /* Remarks: */ /* */ /****************************************************************************/ /****************************************************************************/ /* */ /* include files */ /* system include files */ /* application include files */ /* */ /****************************************************************************/ /* standard C library */ #include #include #include #include /****************************************************************************/ /* */ /* routines */ /* */ /****************************************************************************/ START_UGDIM_NAMESPACE void *memmgr_AllocPMEM (size_t size) { return std::malloc(size); } void memmgr_FreePMEM (void *buffer) { std::free(buffer); } void *memmgr_AllocOMEM (size_t size, int ddd_typ, int proc, int attr) { return std::malloc(size); } void memmgr_FreeOMEM (void *buffer, size_t size, int ddd_typ) { std::free(buffer); } void *memmgr_AllocAMEM (size_t size) { return std::malloc(size); } void memmgr_FreeAMEM (void *buffer) { std::free(buffer); } void *memmgr_AllocTMEM (size_t size) { return std::malloc(size); } void memmgr_FreeTMEM (void *buffer) { std::free(buffer); } END_UGDIM_NAMESPACE dune-uggrid-2.11.0+dfsg/dune/uggrid/parallel/ddd/mgr/000077500000000000000000000000001513616443000222575ustar00rootroot00000000000000dune-uggrid-2.11.0+dfsg/dune/uggrid/parallel/ddd/mgr/CMakeLists.txt000066400000000000000000000003641513616443000250220ustar00rootroot00000000000000# SPDX-FileCopyrightText: Copyright © DUNE Project contributors, see file LICENSE.md in module root # SPDX-License-Identifier: LGPL-2.1-or-later target_sources_dims(duneuggrid PRIVATE attr.cc cplmgr.cc objmgr.cc prio.cc typemgr.cc) dune-uggrid-2.11.0+dfsg/dune/uggrid/parallel/ddd/mgr/attr.cc000066400000000000000000000111411513616443000235360ustar00rootroot00000000000000// SPDX-FileCopyrightText: Copyright © DUNE Project contributors, see file LICENSE.md in module root // SPDX-License-Identifier: LGPL-2.1-or-later // -*- tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- // vi: set et ts=4 sw=2 sts=2: /****************************************************************************/ /* */ /* File: attr.c */ /* */ /* Purpose: object attr management for ddd */ /* */ /* Author: Klaus Birken */ /* Rechenzentrum Uni Stuttgart */ /* Universitaet Stuttgart */ /* Allmandring 30 */ /* 70550 Stuttgart */ /* internet: birken@rus.uni-stuttgart.de */ /* */ /* History: 94/04/25 kb begin */ /* 96/01/08 kb renamed range to attr */ /* */ /* Remarks: */ /* */ /****************************************************************************/ /****************************************************************************/ /* */ /* include files */ /* system include files */ /* application include files */ /* */ /****************************************************************************/ /* standard C library */ #include #include #include #include START_UGDIM_NAMESPACE /****************************************************************************/ /* */ /* defines in the following order */ /* */ /* compile time constants defining static data size (i.e. arrays) */ /* other constants */ /* macros */ /* */ /****************************************************************************/ /****************************************************************************/ /* */ /* data structures */ /* */ /****************************************************************************/ /****************************************************************************/ /* */ /* definition of static variables */ /* */ /****************************************************************************/ /****************************************************************************/ /* */ /* routines */ /* */ /****************************************************************************/ /* not allowed. do this only on object construction. 960603 kb enabled DDD_AttrSet, due to ug has to use it. (TODO remove this dangerous exception!) */ void DDD_AttrSet (DDD_HDR hdr, DDD_ATTR attr) { OBJ_ATTR(hdr) = attr; /* TODO: does attr has to be told the other copies via communication?? */ } END_UGDIM_NAMESPACE dune-uggrid-2.11.0+dfsg/dune/uggrid/parallel/ddd/mgr/cplmgr.cc000066400000000000000000000535471513616443000240700ustar00rootroot00000000000000// SPDX-FileCopyrightText: Copyright © DUNE Project contributors, see file LICENSE.md in module root // SPDX-License-Identifier: LGPL-2.1-or-later // -*- tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- // vi: set et ts=4 sw=2 sts=2: /****************************************************************************/ /* */ /* File: cplmgr.c */ /* */ /* Purpose: management of couplings */ /* */ /* Author: Klaus Birken */ /* Rechenzentrum Uni Stuttgart */ /* Universitaet Stuttgart */ /* Allmandring 30 */ /* 70550 Stuttgart */ /* internet: birken@rus.uni-stuttgart.de */ /* */ /* History: 93/11/30 kb begin */ /* 94/08/24 kb added DDD_InfoProcList() */ /* */ /* Remarks: */ /* */ /****************************************************************************/ /****************************************************************************/ /* */ /* include files */ /* system include files */ /* application include files */ /* */ /****************************************************************************/ /* standard C library */ #include #include #include #include #include #include #include #include #include #include USING_UG_NAMESPACES /* PPIF namespace: */ using namespace PPIF; #define DebugCoupling 10 /* 10 is off */ START_UGDIM_NAMESPACE using CplSegm = DDD::Mgr::CplSegm; /* the storage of COUPLING items is done with the following scheme: allocation in segments of couplings, freeing into freelist. ALLOC: try first to get one item out of freelist (memlistCpl), if that's not possible, get one from current segment; alloc segments from MemMgr. FREE: put coupling into freelist. */ static CplSegm *NewCplSegm(DDD::DDDContext& context) { auto& mctx = context.cplmgrContext(); CplSegm *segm; segm = (CplSegm *) AllocTmpReq(sizeof(CplSegm), TMEM_CPL); if (segm==NULL) throw std::bad_alloc(); segm->next = mctx.segmCpl; mctx.segmCpl = segm; segm->nItems = 0; mctx.nCplSegms++; return(segm); } static void FreeCplSegms(DDD::DDDContext& context) { auto& mctx = context.cplmgrContext(); CplSegm *segm = mctx.segmCpl; CplSegm *next = NULL; while (segm!=NULL) { next = segm->next; FreeTmpReq(segm, sizeof(CplSegm), TMEM_CPL); segm = next; } mctx.segmCpl = nullptr; mctx.nCplSegms = 0; mctx.memlistCpl = nullptr; } /****************************************************************************/ /* auxiliary function to init Coupling memory and initial data */ static void InitNewCoupling (COUPLING* cpl) { /* set coupling to initial value, in order to find any bugs lateron. (hint by C.Wieners) */ memset(cpl, 0, sizeof(COUPLING)); /* init private data */ cpl->_flags = 0; } static COUPLING *NewCoupling (DDD::DDDContext& context) { auto& ctx = context.couplingContext(); auto& mctx = context.cplmgrContext(); COUPLING *cpl; if (DDD_GetOption(context, OPT_CPLMGR_USE_FREELIST)==OPT_ON) { /* allocate coupling from segments (which are allocated from segment-freelists) */ if (mctx.memlistCpl == nullptr) { CplSegm *segm = mctx.segmCpl; if (segm==NULL || segm->nItems==CPLSEGM_SIZE) { segm = NewCplSegm(context); } cpl = &(segm->item[segm->nItems++]); } else { cpl = mctx.memlistCpl; mctx.memlistCpl = CPL_NEXT(cpl); } /* init coupling memory and its private data */ InitNewCoupling(cpl); /* remember memory origin for later disposal */ SETCPLMEM_FREELIST(cpl); } else { /* allocate coupling directly */ cpl = (COUPLING *) AllocTmpReq(sizeof(COUPLING), TMEM_CPL); if (cpl==NULL) throw std::bad_alloc(); /* init coupling memory and its private data */ InitNewCoupling(cpl); /* remember memory origin for later disposal */ SETCPLMEM_EXTERNAL(cpl); } ctx.nCplItems += 1; return(cpl); } static void DisposeCoupling (DDD::DDDContext& context, COUPLING *cpl) { auto& ctx = context.couplingContext(); auto& mctx = context.cplmgrContext(); if (CPLMEM(cpl)==CPLMEM_FREELIST) { CPL_NEXT(cpl) = mctx.memlistCpl; mctx.memlistCpl = cpl; } else { FreeTmpReq(cpl, sizeof(COUPLING), TMEM_CPL); } ctx.nCplItems -= 1; } /****************************************************************************/ static void AllocCplTables (DDD::DDDContext& context, long n) { auto& ctx = context.couplingContext(); /* allocate coupling table */ ctx.cplTable.resize(n); ctx.nCplTable.resize(n); } static void IncreaseCplTabSize(DDD::DDDContext& context) { auto& ctx = context.couplingContext(); /* compute new size (currently: double size) */ const std::size_t n = ctx.cplTable.size() * 2; /* allocate new coupling table */ ctx.cplTable.resize(n); ctx.nCplTable.resize(n); /* issue a warning in order to inform user */ Dune::dwarn << "increased coupling table, now " << n << " entries\n"; ddd_EnsureObjTabSize(context, n); } /****************************************************************************/ /* */ /* Function: AddCoupling */ /* */ /* Purpose: get new coupling record and init contents */ /* if coupling is already there, no additional coupling is */ /* created. priority is adapted in this case. */ /* */ /* Input: hdr: DDD-header of object with new coupling */ /* proc: owner of copy to be registered */ /* prio: priority of copy */ /* */ /* Output: ptr to new cpl record (or old one, if existed before) */ /* NULL on error */ /* */ /****************************************************************************/ COUPLING *AddCoupling(DDD::DDDContext& context, DDD_HDR hdr, DDD_PROC proc, DDD_PRIO prio) { auto& ctx = context.couplingContext(); COUPLING *cp, *cp2; int objIndex; int freeCplIdx = ctx.nCpls; assert(proc!=context.me()); # if DebugCoupling<=1 Dune::dvverb << "AddCoupling " << OBJ_GID(hdr) << " proc=" << proc << " prio=" << prio << "\n"; # endif /* find or free position in coupling array */ objIndex = OBJ_INDEX(hdr); if (! ObjHasCpl(context, hdr)) { if (freeCplIdx == ctx.cplTable.size()) { /* try to make CplTables larger ... */ IncreaseCplTabSize(context); } auto& objTable = context.objTable(); #ifdef WithFullObjectTable DDD_HDR oldObj = objTable[freeCplIdx]; /* exchange object without coupling and object with coupling */ /* free position freeCplIdx, move corresponding hdr reference elsewhere. */ objTable[objIndex] = oldObj; OBJ_INDEX(oldObj) = objIndex; #else assert(IsHdrLocal(hdr)); /* hdr has been local, therefore not known by DDD, we have to register it now. */ context.nObjs(context.nObjs() + 1); #endif assert(freeCplIdx < context.objTable().size()); objTable[freeCplIdx] = hdr; OBJ_INDEX(hdr) = freeCplIdx; objIndex = freeCplIdx; IdxCplList(context, objIndex) = nullptr; IdxNCpl(context, objIndex) = 0; ctx.nCpls += 1; } else { for(cp2=IdxCplList(context, objIndex); cp2!=NULL; cp2=CPL_NEXT(cp2)) { if (CPL_PROC(cp2)==proc) { cp2->prio = prio; return(cp2); } } } /* create new coupling record */ cp = NewCoupling(context); if (cp==NULL) { DDD_PrintError('E', 2500, STR_NOMEM " in AddCoupling"); return(NULL); } /* init contents */ cp->obj = hdr; CPL_PROC(cp) = proc; cp->prio = prio; /* insert into theCpl array */ CPL_NEXT(cp) = IdxCplList(context, objIndex); IdxCplList(context, objIndex) = cp; IdxNCpl(context, objIndex)++; return(cp); } /****************************************************************************/ /* */ /* Function: ModCoupling */ /* */ /* Purpose: find existing coupling record and modify priority */ /* this function does coupling upgrade/downgrade without */ /* complaining. */ /* */ /* Input: hdr: DDD-header of object with new coupling */ /* proc: owner of copy to be modified */ /* prio: new priority of copy */ /* */ /* Output: ptr to old cpl record */ /* NULL on error */ /* */ /****************************************************************************/ COUPLING *ModCoupling(DDD::DDDContext& context, DDD_HDR hdr, DDD_PROC proc, DDD_PRIO prio) { int objIndex; assert(proc!=context.me()); # if DebugCoupling<=1 Dune::dvverb << "ModCoupling " << OBJ_GID(hdr) << " proc=" << proc << " prio=" << prio << "\n"; # endif /* find or free position in coupling array */ objIndex = OBJ_INDEX(hdr); if (! ObjHasCpl(context, hdr)) { /* there are no couplings for this object! */ Dune::dwarn << "ModCoupling: no couplings for " << OBJ_GID(hdr) << "\n"; return(NULL); } else { /* look if coupling exists and change it */ for (COUPLING *cp2 = IdxCplList(context, objIndex); cp2 != NULL; cp2 = CPL_NEXT(cp2)) { if (CPL_PROC(cp2)==proc) { cp2->prio = prio; return(cp2); } } } /* coupling not found */ DUNE_THROW(Dune::Exception, "no coupling from " << proc << " for " << OBJ_GID(hdr)); } /****************************************************************************/ /* */ /* Function: DelCoupling */ /* */ /* Purpose: remove coupling record from object */ /* */ /* Input: hdr: DDD-header of object with old coupling */ /* proc: owner of copy to be un-registered */ /* */ /* Output: - */ /* */ /****************************************************************************/ void DelCoupling (DDD::DDDContext& context, DDD_HDR hdr, DDD_PROC proc) { COUPLING *cpl, *cplLast; auto& objTable = context.objTable(); const int objIndex = OBJ_INDEX(hdr); auto& ctx = context.couplingContext(); if (objIndex < ctx.nCpls) { for(cpl=IdxCplList(context, objIndex), cplLast=NULL; cpl!=NULL; cpl=CPL_NEXT(cpl)) { if(CPL_PROC(cpl)==proc) { if (cplLast==NULL) { IdxCplList(context, objIndex) = CPL_NEXT(cpl); } else { CPL_NEXT(cplLast) = CPL_NEXT(cpl); } # if DebugCoupling<=1 Dune::dvverb << "DelCoupling " << OBJ_GID(hdr) << " on proc=" << proc << ", now " << (IdxNCpl(context, objIndex)-1) << " cpls\n"; # endif DisposeCoupling(context, cpl); IdxNCpl(context, objIndex)--; if (IdxNCpl(context, objIndex)==0) { ctx.nCpls -= 1; #ifdef WithFullObjectTable OBJ_INDEX(hdr) = ctx.nCpls; OBJ_INDEX(objTable[ctx.nCpls]) = objIndex; objTable[objIndex] = objTable[ctx.nCpls]; objTable[ctx.nCpls] = hdr; #else /* we will not register objects without coupling, so we have to forget about hdr and mark it as local. */ context.nObjs(context.nObjs() - 1); assert(context.nObjs() == ctx.nCpls); objTable[objIndex] = objTable[ctx.nCpls]; OBJ_INDEX(objTable[ctx.nCpls]) = objIndex; MarkHdrLocal(hdr); #endif IdxCplList(context, objIndex) = IdxCplList(context, ctx.nCpls); IdxNCpl(context, objIndex) = IdxNCpl(context, ctx.nCpls); } break; } cplLast = cpl; } } } /****************************************************************************/ /* */ /* Function: DisposeCouplingList */ /* */ /* Purpose: dispose complete coupling list */ /* */ /* Input: cpl: first element of coupling list */ /* */ /* Output: - */ /* */ /****************************************************************************/ void DisposeCouplingList (DDD::DDDContext& context, COUPLING *cpl) { COUPLING *c, *next; c = cpl; while (c!=NULL) { next = CPL_NEXT(c); DisposeCoupling(context, c); c = next; } } /* * DDD_InfoProcListRange */ DDD_InfoProcListRange::DDD_InfoProcListRange(DDDContext& context, const DDD_HDR hdr, bool includeDummy) noexcept : includeDummy_(includeDummy) { dummy_._proc = context.me(); dummy_.prio = OBJ_PRIO(hdr); const auto objIndex = OBJ_INDEX(hdr); if (objIndex < context.couplingContext().nCpls) { dummy_._next = IdxCplList(context, objIndex); } else { dummy_._next = nullptr; } } /****************************************************************************/ /* */ /* Function: DDD_InfoProcPrio */ /* */ /* Purpose: return first processor number with a given priority */ /* */ /* Input: hdr: DDD-header of object with coupling */ /* prio: priority to search for */ /* */ /* Output: id of processor which holds the object copy with prio */ /* (or procs if no such copy exists) */ /* */ /****************************************************************************/ DDD_PROC DDD_InfoProcPrio(const DDD::DDDContext& context, DDD_HDR hdr, DDD_PRIO prio) { COUPLING *cpl; int objIndex = OBJ_INDEX(hdr); /* append descriptions of foreign copies */ if (objIndex < context.couplingContext().nCpls) { for(cpl=IdxCplList(context, objIndex); cpl!=NULL; cpl=CPL_NEXT(cpl)) { if (cpl->prio == prio) return(CPL_PROC(cpl)); } } /* eventually local copy has priority we are looking for */ if (OBJ_PRIO(hdr)==prio) return context.me(); return context.procs(); } bool DDD_InfoIsLocal(const DDD::DDDContext& context, DDD_HDR hdr) { return(! ObjHasCpl(context, hdr)); } int DDD_InfoNCopies(const DDD::DDDContext& context, DDD_HDR hdr) { /* COUPLING *cpl; int n = 0; if (ObjHasCpl(context, hdr)) { for(cpl=IdxCplList(context, OBJ_INDEX(hdr)); cpl!=NULL; cpl=CPL_NEXT(cpl)) n++; } */ return(ObjNCpl(context, hdr)); } /****************************************************************************/ /* */ /* Function: DDD_InfoCoupling */ /* */ /* Purpose: displays list of coupling for certain object */ /* */ /* Input: hdr: DDD-header of object with coupling */ /* */ /* Output: - */ /* */ /****************************************************************************/ void DDD_InfoCoupling(const DDD::DDDContext& context, DDD_HDR hdr) { int objIndex = OBJ_INDEX(hdr); const auto& nCpls = context.couplingContext().nCpls; std::cout << "InfoCoupling for object " << OBJ_GID(hdr) << " (" << objIndex << "/" << nCpls << ")\n"; if (objIndex < nCpls) { for(const COUPLING* cpl=IdxCplList(context, objIndex); cpl!=NULL; cpl=CPL_NEXT(cpl)) std::cout << " cpl " << cpl << " proc=" << CPL_PROC(cpl) << " prio=" << cpl->prio << "\n"; } } /****************************************************************************/ /* */ /* Function: DDD_InfoCplMemory */ /* */ /* Purpose: returns number of bytes used for coupling data */ /* */ /* Input: - */ /* */ /* Output: size of memory used for couplings */ /* */ /****************************************************************************/ size_t DDD_InfoCplMemory(const DDD::DDDContext& context) { return sizeof(CplSegm) * context.cplmgrContext().nCplSegms; } /****************************************************************************/ /* */ /* Function: CplMgrInit and CplMgrExit */ /* */ /* Purpose: init/exit coupling manager */ /* */ /* Input: - */ /* */ /* Output: - */ /* */ /****************************************************************************/ void ddd_CplMgrInit(DDD::DDDContext& context) { auto& mctx = context.cplmgrContext(); /* allocate first (smallest) coupling tables */ AllocCplTables(context, MAX_CPL_START); mctx.localIBuffer = (int*)AllocFix((2*context.procs()+1)*sizeof(int)); if (mctx.localIBuffer == nullptr) throw std::bad_alloc(); mctx.memlistCpl = nullptr; mctx.segmCpl = nullptr; mctx.nCplSegms = 0; } void ddd_CplMgrExit(DDD::DDDContext& context) { auto& ctx = context.couplingContext(); auto& mctx = context.cplmgrContext(); FreeFix(mctx.localIBuffer); FreeCplSegms(context); ctx.cplTable.clear(); ctx.nCplTable.clear(); } /****************************************************************************/ END_UGDIM_NAMESPACE dune-uggrid-2.11.0+dfsg/dune/uggrid/parallel/ddd/mgr/objmgr.cc000066400000000000000000000730721513616443000240570ustar00rootroot00000000000000// SPDX-FileCopyrightText: Copyright © DUNE Project contributors, see file LICENSE.md in module root // SPDX-License-Identifier: LGPL-2.1-or-later // -*- tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- // vi: set et ts=4 sw=2 sts=2: /****************************************************************************/ /* */ /* File: objmgr.c */ /* */ /* Purpose: creation and deletion of objects */ /* */ /* Author: Klaus Birken */ /* Rechenzentrum Uni Stuttgart */ /* Universitaet Stuttgart */ /* Allmandring 30 */ /* 70550 Stuttgart */ /* internet: birken@rus.uni-stuttgart.de */ /* */ /* History: 94/02/21 kb begin */ /* 95/11/03 kb complete redesign of objmgr-interface, C++ style */ /* 95/11/15 kb arbitrary offset for DDD_HEADER */ /* */ /* Remarks: */ /* */ /****************************************************************************/ /****************************************************************************/ /* */ /* include files */ /* system include files */ /* application include files */ /* */ /****************************************************************************/ /* standard C library */ #include #include #include #include #include #include #include #include #include USING_UG_NAMESPACES /* PPIF namespace: */ using namespace PPIF; START_UGDIM_NAMESPACE /* #define DebugCreation #define DebugDeletion */ /****************************************************************************/ /* */ /* defines in the following order */ /* */ /* compile time constants defining static data size (i.e. arrays) */ /* other constants */ /* macros */ /* */ /****************************************************************************/ #define MakeUnique(context, n) (((n)<>MAX_PROCBITS_IN_GID) /****************************************************************************/ /* */ /* routines */ /* */ /****************************************************************************/ static bool sort_ObjListGID (const DDD_HDR& a, const DDD_HDR& b) { return OBJ_GID(a) < OBJ_GID(b); } std::vector LocalObjectsList(const DDD::DDDContext& context) { const int nObjs = context.nObjs(); std::vector locObjs(nObjs); const auto& objTable = context.objTable(); std::copy(objTable.begin(), objTable.begin() + nObjs, locObjs.begin()); std::sort(locObjs.begin(), locObjs.end(), sort_ObjListGID); return locObjs; } std::vector LocalCoupledObjectsList(const DDD::DDDContext& context) { const auto& nCpls = context.couplingContext().nCpls; std::vector locObjs(nCpls); const auto& objTable = context.objTable(); std::copy(objTable.begin(), objTable.begin() + nCpls, locObjs.begin()); std::sort(locObjs.begin(), locObjs.end(), sort_ObjListGID); return locObjs; } /****************************************************************************/ void ddd_EnsureObjTabSize(DDD::DDDContext& context, int n) { auto& objTable = context.objTable(); /* if size is large enough, we are already finished. */ if (objTable.size() >= n) return; objTable.resize(n); /* issue a warning in order to inform user */ Dune::dwarn << "increased object table, now " << n << " entries\n"; } /****************************************************************************/ /* Description of ObjMgr Interfaces Raw-Memory-Interface: DDD_ObjNew, DDD_ObjDelete Constructor-Interface: DDD_HdrConstructor, DDD_HdrDestructor Application-Interface: DDD_Get, DDD_UnGet */ /****************************************************************************/ /* */ /* Function: DDD_ObjNew */ /* */ /****************************************************************************/ /* Purpose: get raw memory for new DDD-object. */ /* */ /* Input: size: memory size of object */ /* typ: DDD_TYPE of object */ /* prio: DDD_PRIO of object */ /* attr: attribute of distributed object */ /* */ /* Output: pointer to raw memory */ /* */ /****************************************************************************/ /** Allocate raw memory for new \ddd{object}. This function dynamically creates raw memory for a new \ddd{object}. Therefore, the user-supplied memory manager function \memmgrfunk{AllocOMEM} is called to allocate the necessary memory. Although the caller must supply the object's priority and attribute, its header will not be initialized by \funk{ObjNew}; the parameters are used for smart memory allocation, only. The function \funk{ObjNew} and \funk{ObjDelete}, its corresponding deletion function, form the ObjManager's {\em raw memory interface}. DDD users who use the #C_FRONTEND# may prefer the more elaborate {\em application interface}, consisting of the functions \funk{ObjGet} and \funk{ObjUnGet}. DDD users who use the language C++ (object-oriented style) with #CPP_FRONTEND# will use the {\em raw memory interface} together with the {\em constructor/destructor interface} (\funk{HdrConstructor}, \funk{HdrDestructor}, \funk{HdrConstructorMove}) in order to integrate DDD into C++ style object management easily. For variable-sized \ddd{objects}, the parameter {\em aSize} may differ from the size specified during the corresponding \funk{TypeDefine}-call. @return pointer to free memory block for the \ddd{object} @param aSize memory size of the new object @param aType \ddd{type} of the new object @param aPrio \ddd{priority} of the new object @param aAttr \ddd{attribute} of the new object */ DDD_OBJ DDD_ObjNew (size_t aSize, DDD_TYPE aType, DDD_PRIO aPrio, DDD_ATTR aAttr) { DDD_OBJ obj; /* check input parameters */ if (aPrio>=MAX_PRIO) DUNE_THROW(Dune::Exception, "priority must be less than " << MAX_PRIO); if (aType>=MAX_TYPEDESC) DUNE_THROW(Dune::Exception, "DDD-type must be less than " << MAX_TYPEDESC); /* get object memory */ obj = (DDD_OBJ) AllocObj(aSize, aType, aPrio, aAttr); if (obj==NULL) throw std::bad_alloc(); # ifdef DebugCreation Dune::dinfo << "DDD_ObjNew(aSize=" << aSize << ", type=" << aType << ", prio=" << aPrio << ", attr=" << aAttr << ") ADR=" << obj << "\n"; # endif return(obj); } /****************************************************************************/ /* */ /* Function: DDD_ObjDelete */ /* */ /* Purpose: free raw memory from DDD-object */ /* */ /* Input: obj: object header address */ /* size: memory size of object */ /* typ: DDD_TYPE of object */ /* */ /* Output: - */ /* */ /****************************************************************************/ void DDD_ObjDelete (DDD_OBJ obj, size_t size, DDD_TYPE typ) { FreeObj((void *)obj, size, typ); } /****************************************************************************/ /* */ /* Function: DDD_HdrConstructor */ /* */ /****************************************************************************/ /** Initiate object's \ddd{header}. This function registers a \ddd{object} via constructing its DDD-header. Each \ddd{object} is given a unique {\em global ID}, which is stored in the DDD-header together with the object's properties (type\_id, prio, attr) and additional data used by DDD. The function \funk{HdrConstructor} and its corresponding deletion function \funk{HdrDestructor} form the ObjManager's {\em constructor/destructor interface}. This interface will be useful for C++ users, together with the {\em raw memory interface} functions \funk{ObjNew} and \funk{ObjDelete}. DDD users who use the language C may prefer the more elaborate {\em application interface}, consisting of the functions \funk{ObjGet} and \funk{ObjUnGet}. Due to the construction of global IDs, an overflow error may occur after many calls to \funk{HdrConstructor} (\MaxUniqueGids\ times in \Version). @param aHdr pointer to the \ddd{header} which should be constructed @param aType \ddd{type} of \ddd{object} @param aPrio \ddd{priority} of \ddd{object} @param aAttr \ddd{attribute} of \ddd{object} */ void DDD_HdrConstructor (DDD::DDDContext& context, DDD_HDR aHdr, DDD_TYPE aType, DDD_PRIO aPrio, DDD_ATTR aAttr) { auto& ctx = context.objmgrContext(); /* check input parameters */ if (aPrio>=MAX_PRIO) DUNE_THROW(Dune::Exception, "priority must be less than " << MAX_PRIO); #ifdef WithFullObjectTable /* in case of FullObjectTable, we register each header in the global ddd_ObjTable. */ auto& objTable = context.objTable(); /* check whether there are available objects */ if (context.nObjs() == objTable.size()) { /* TODO update docu */ /* this is a fatal case. we can't register more objects here */ /* TODO one could try to expand the global tables here. */ DUNE_THROW(Dune::Exception, "no more objects in DDD_HdrConstructor"); } /* insert into theObj array */ objTable[context.nObjs()] = aHdr; OBJ_INDEX(aHdr) = context.nObjs(); context.nObjs(context.nObjs() + 1); #else /* if we dont have WithFullObjectTable, pure local objects without copies on other processors aren't registered by DDD. Therefore, they don't have a valid OBJ_INDEX field. */ MarkHdrLocal(aHdr); #endif /* init object header with defaults */ OBJ_TYPE(aHdr) = aType; OBJ_PRIO(aHdr) = aPrio; OBJ_ATTR(aHdr) = aAttr; OBJ_FLAGS(aHdr) = 0; /* create unique GID */ OBJ_GID(aHdr) = MakeUnique(context, ctx.theIdCount++); /* check overflow of global id numbering */ if (MakeUnique(context, ctx.theIdCount) <= MakeUnique(context, ctx.theIdCount-1)) { /* TODO update docu */ /* TODO one could try to renumber all objects here. */ DUNE_THROW(Dune::Exception, "global ID overflow DDD_HdrConstructor"); } # ifdef DebugCreation Dune::dinfo << "DDD_HdrConstructor(adr=" << aHdr << ", type=" << aType << ", prio=" << aPrio << ", attr=" << aAttr << "), GID=" << OBJ_GID(aHdr) << " INDEX=" << OBJ_INDEX(aHdr) << "\n"; # endif } /****************************************************************************/ /* */ /* Function: DDD_HdrDestructor */ /* */ /****************************************************************************/ /** Remove object's header from DDD management. This function removes an object from DDD-management via destructing its \ddd{header}. {\em Note:} The \ddd{object} will be destroyed, but its copies on remote processors will not be informed by \funk{HdrDestructor}. There are two consistent possibilities to delete \ddd{objects} which have copies on remote processors: \begin{itemize} \item In order to delete only this local object copy, use \funk{XferDelete} during a DDD Transfer-operation. This will inform the remote copies of the deletion. \item In order to delete a distributed object (\ie, all its object copies), use function \funk{ObjUnGet} (when using the {\em application interface}) or a combination of functions \funk{HdrDestructor} / \funk{ObjDelete} (when not using the {\em application interface}) for all copies. \end{itemize} The function \funk{HdrDestructor} and its corresponding creation function \funk{HdrConstructor} form the ObjManager's {\em constructor/destructor interface}. This interface will be useful for C++ users, together with the {\em raw memory interface} functions \funk{ObjNew} and \funk{ObjDelete}. DDD users who use the language C may prefer the more elaborate {\em application interface}, consisting of the functions \funk{ObjGet} and \funk{ObjUnGet}. @param hdr the object's DDD Header */ void DDD_HdrDestructor(DDD::DDDContext& context, DDD_HDR hdr) { auto& objTable = context.objTable(); auto& nCpls = context.couplingContext().nCpls; COUPLING *cpl; int objIndex, xfer_active = ddd_XferActive(context); # ifdef DebugDeletion Dune::dinfo << "DDD_HdrDestructor(adr=" << hdr << ", typ=" << OBJ_TYPE(hdr) << ", prio=" << OBJ_PRIO(hdr) << ", attr=" << OBJ_ATTR(hdr) << "), GID=" << OBJ_GID(hdr) << " INDEX=" << OBJ_INDEX(hdr) << "\n"; # endif if (IsHdrInvalid(hdr)) { /* DDD_HDR is invalid, so destructor is useless */ return; } /* formally, the object's GID should be returned here */ /* if currently in xfer, register deletion for other processors */ if (xfer_active) ddd_XferRegisterDelete(context, hdr); objIndex = OBJ_INDEX(hdr); if (objIndex < nCpls) { /* this is an object with couplings */ cpl = IdxCplList(context, objIndex); /* if not during xfer, deletion may be inconsistent */ if (!xfer_active) { /* deletion is dangerous, distributed object might get inconsistent. */ if (DDD_GetOption(context, OPT_WARNING_DESTRUCT_HDR)==OPT_ON) Dune::dwarn << "DDD_HdrDestructor: inconsistency by deleting gid=" << OBJ_GID(hdr) << "\n"; } nCpls -= 1; context.nObjs(context.nObjs() - 1); /* fill slot of deleted obj with last cpl-obj */ objTable[objIndex] = objTable[nCpls]; IdxCplList(context, objIndex) = IdxCplList(context, nCpls); IdxNCpl(context, objIndex) = IdxNCpl(context, nCpls); OBJ_INDEX(objTable[objIndex]) = objIndex; #ifdef WithFullObjectTable /* fill slot of last cpl-obj with last obj */ if (nCpls < context.nObjs()) { objTable[nCpls] = objTable[context.nObjs()]; OBJ_INDEX(objTable[nCpls]) = nCpls; } #else assert(nCpls == context.nObjs()); #endif /* dispose all couplings */ DisposeCouplingList(context, cpl); } else { #ifdef WithFullObjectTable /* this is an object without couplings */ /* deletion is not dangerous (no consistency problem) */ context.nObjs(context.nObjs() - 1); /* fill slot of deleted obj with last obj */ objTable[objIndex] = objTable[context.nObjs()]; OBJ_INDEX(objTable[objIndex]) = objIndex; #endif } /* invalidate this DDD_HDR */ MarkHdrInvalid(hdr); } /****************************************************************************/ /* */ /* Function: DDD_ObjGet */ /* */ /* Purpose: get new DDD object for a given DDD_TYPE */ /* */ /* DDD_ObjGet allows different size for each object instance, */ /* differing from the size computed during DDD_TypeDefine */ /* */ /* Input: typ: DDD_TYPE of object */ /* */ /* Output: pointer to memory, which is raw except from the */ /* constructed DDD_HDR. */ /* */ /****************************************************************************/ DDD_OBJ DDD_ObjGet (DDD::DDDContext& context, size_t size, DDD_TYPE typ, DDD_PRIO prio, DDD_ATTR attr) { DDD_OBJ obj; const TYPE_DESC& desc = context.typeDefs()[typ]; /* check input parameters */ if (prio<0 || prio>=MAX_PRIO) DUNE_THROW(Dune::Exception, "priority must be less than " << MAX_PRIO); /* get raw memory */ obj = (DDD_OBJ) DDD_ObjNew(size, typ, prio, attr); if (obj==NULL) throw std::bad_alloc(); if ((desc.size != size) && (DDD_GetOption(context, OPT_WARNING_VARSIZE_OBJ)==OPT_ON)) { DDD_PrintError('W', 2200, "object size differs from declared size in DDD_ObjGet"); } if ((desc.size > size) && (DDD_GetOption(context, OPT_WARNING_SMALLSIZE)==OPT_ON)) { DDD_PrintError('W', 2201, "object size smaller than declared size in DDD_ObjGet"); } /* call DDD_HdrConstructor */ DDD_HdrConstructor(context, OBJ2HDR(obj, &desc), typ, prio, attr); return(obj); } /****************************************************************************/ /* */ /* Function: DDD_ObjUnGet */ /* */ /* Purpose: remove object from DDD management and free its memory */ /* */ /* Input: obj: object header address */ /* */ /* Output: - */ /* */ /****************************************************************************/ void DDD_ObjUnGet (DDD::DDDContext& context, DDD_HDR hdr, size_t size) { DDD_TYPE typ = OBJ_TYPE(hdr); const TYPE_DESC& desc = context.typeDefs()[typ]; DDD_OBJ obj = HDR2OBJ(hdr, &desc); if ((desc.size != size) && (DDD_GetOption(context, OPT_WARNING_VARSIZE_OBJ)==OPT_ON)) { DDD_PrintError('W', 2299, "object size differs from declared size in DDD_ObjUnGet"); } /* call DDD_HDR-destructor */ DDD_HdrDestructor(context, hdr); /* free raw memory */ DDD_ObjDelete(obj, size, typ); } /****************************************************************************/ /* */ /* Function: DDD_HdrConstructorCopy */ /* */ /* Purpose: create DDD_HDR copy from message original */ /* */ /* Input: newhdr: new DDD_HDR */ /* prio: DDD_PRIO of new copy */ /* */ /* Output: - */ /* */ /****************************************************************************/ void DDD_HdrConstructorCopy (DDD::DDDContext& context, DDD_HDR newhdr, DDD_PRIO prio) { /* check input parameters */ if (prio>=MAX_PRIO) DUNE_THROW(Dune::Exception, "priority must be less than " << MAX_PRIO); #ifdef WithFullObjectTable auto& objTable = context.objTable(); /* check whether there are available objects */ if (context.nObjs() == context.objTable().size()) { /* TODO update docu */ /* this is a fatal case. we can't register more objects here */ DDD_PrintError('F', 2220, "no more objects in DDD_HdrConstructorCopy"); /* TODO one could try to expand the global tables here. */ } /* insert into theObj array */ objTable[context.nObjs()] = newhdr; OBJ_INDEX(newhdr) = context.nObjs(); context.nObjs(context.nObjs() + 1); #else MarkHdrLocal(newhdr); assert(context.nObjs() == context.couplingContext().nCpls); #endif /* init LDATA components. GDATA components will be copied elsewhere */ OBJ_PRIO(newhdr) = prio; # ifdef DebugCreation Dune::dinfo << "DDD_HdrConstructorCopy(adr=" << newhdr << ", prio=" << prio << "), GID= " << OBJ_GID(newhdr) << " INDEX=" << OBJ_INDEX(newhdr) << " ATTR=" << OBJ_ATTR(newhdr) << "\n"; # endif } /****************************************************************************/ /* */ /* Function: DDD_HdrConstructorMove */ /* */ /* Purpose: create DDD_HDR copy inside local memory, */ /* simultaneously destruct original DDD_HDR */ /* */ /* Input: newhdr: new DDD_HDR */ /* oldhdr: old DDD_HDR */ /* */ /* Output: - */ /* */ /****************************************************************************/ void DDD_HdrConstructorMove (DDD::DDDContext& context, DDD_HDR newhdr, DDD_HDR oldhdr) { int objIndex = OBJ_INDEX(oldhdr); const auto& nCpls = context.couplingContext().nCpls; /* copy all components */ OBJ_INDEX(newhdr) = OBJ_INDEX(oldhdr); OBJ_TYPE(newhdr) = OBJ_TYPE(oldhdr); OBJ_PRIO(newhdr) = OBJ_PRIO(oldhdr); OBJ_ATTR(newhdr) = OBJ_ATTR(oldhdr); OBJ_FLAGS(newhdr) = OBJ_FLAGS(oldhdr); OBJ_GID(newhdr) = OBJ_GID(oldhdr); /* change all references from DDD to oldhdr */ /* change entry of theObj array */ auto& objTable = context.objTable(); #ifdef WithFullObjectTable objTable[objIndex] = newhdr; #else if (objIndex < nCpls) objTable[objIndex] = newhdr; #endif /* change pointers from couplings to object */ if (objIndex < nCpls) { COUPLING *cpl = IdxCplList(context, objIndex); for(; cpl!=NULL; cpl=CPL_NEXT(cpl)) { cpl->obj = newhdr; } /* invalidate update obj-shortcut tables from IF module */ IFInvalidateShortcuts(context, OBJ_TYPE(newhdr)); } /* invalidate old DDD_HDR */ MarkHdrInvalid(oldhdr); } /****************************************************************************/ /* */ /* Function: ObjCopyGlobalData */ /* */ /* Purpose: copy DDD-object from message to memory. elements marked */ /* EL_LDATA (local data) will not be copied. this is done */ /* in an efficient way by using the DDD_TYPEs copy-mask (which */ /* has been set up during StructRegister()). */ /* */ /* CopyByMask() is a support function doing the actual work. */ /* This function could be more efficient by copying more than */ /* one byte at a time. */ /* */ /* Input: target: DDD_OBJ address of target memory */ /* source: DDD_OBJ address of source object */ /* size: size of object in bytes (might be != desc->size) */ /* */ /* Output: - */ /* */ /****************************************************************************/ static void CopyByMask (TYPE_DESC *desc, DDD_OBJ target, DDD_OBJ source) { unsigned char *s=(unsigned char *)source, *t=(unsigned char *)target; int i; # ifdef DebugCreation Dune::dinfo << "CopyByMask(" << desc->name << ", size=" << desc->size << ", to=" << target << ", from=" << source << ")\n"; # endif unsigned char* maskp = desc->cmask.get(); /* copy all bits set in cmask from source to target */ for(i=0; isize; i++) { unsigned char negmask = *maskp^0xff; *t = (*s & *maskp) | (*t & negmask); t++; s++; maskp++; /* Paragon didn't manage postfix increment */ } } void ObjCopyGlobalData (TYPE_DESC *desc, DDD_OBJ target, DDD_OBJ source, size_t size) { /* normally size will be equal to desc->size (for fixed-sized objects). for variable-sized objects size depends on what the sender put into the message */ CopyByMask(desc, target, source); /* copy remainder as EL_GDATA */ if (size > desc->size) { memcpy(((char *)target)+desc->size, ((char *)source)+desc->size, size-desc->size); } # ifdef DebugCreation const auto& hdr = OBJ2HDR(target, desc); Dune::dinfo << "ObjCopyGlobalData(" << hdr << " <- " << source << ", size=" << size << "), TYP=" << OBJ_TYPE(hdr) << " GID=" << OBJ_GID(hdr) << " INDEX=" << OBJ_INDEX(hdr) << "\n"; # endif } /****************************************************************************/ DDD_HDR DDD_SearchHdr(DDD::DDDContext& context, DDD_GID gid) { auto& objTable = context.objTable(); const int nObjs = context.nObjs(); int i; i=0; while (i < nObjs && OBJ_GID(objTable[i])!=gid) i++; if (i < nObjs) { return(objTable[i]); } else return(NULL); } /****************************************************************************/ void ddd_ObjMgrInit(DDD::DDDContext& context) { auto& ctx = context.objmgrContext(); /* sanity check: does the DDD_PROC type have enough bits? */ if (sizeof(DDD_PROC)*8 < MAX_PROCBITS_IN_GID) DDD_PrintError('F', 666, "DDD_PROC isn't large enough for MAX_PROCBITS_IN_GID bits"); ctx.theIdCount = 1; /* start with 1, for debugging reasons */ /* allocate first (smallest) object table */ context.objTable().resize(MAX_OBJ_START); } void ddd_ObjMgrExit(DDD::DDDContext& context) { context.objTable().clear(); } /****************************************************************************/ END_UGDIM_NAMESPACE dune-uggrid-2.11.0+dfsg/dune/uggrid/parallel/ddd/mgr/prio.cc000066400000000000000000000316321513616443000235440ustar00rootroot00000000000000// SPDX-FileCopyrightText: Copyright © DUNE Project contributors, see file LICENSE.md in module root // SPDX-License-Identifier: LGPL-2.1-or-later // -*- tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- // vi: set et ts=4 sw=2 sts=2: /****************************************************************************/ /* */ /* File: prio.c */ /* */ /* Purpose: priority management for ddd */ /* */ /* Author: Klaus Birken */ /* Rechenzentrum Uni Stuttgart */ /* Universitaet Stuttgart */ /* Allmandring 30 */ /* 70550 Stuttgart */ /* internet: birken@rus.uni-stuttgart.de */ /* */ /* History: 94/04/25 kb begin */ /* */ /* Remarks: */ /* */ /****************************************************************************/ /****************************************************************************/ /* */ /* include files */ /* system include files */ /* application include files */ /* */ /****************************************************************************/ /* standard C library */ #include #include #include #include #include #include #include #include #include #include USING_UG_NAMESPACE /* PPIF namespace: */ using namespace PPIF; START_UGDIM_NAMESPACE /****************************************************************************/ /* */ /* defines in the following order */ /* */ /* compile time constants defining static data size (i.e. arrays) */ /* other constants */ /* macros */ /* */ /****************************************************************************/ /* get index for one-dimensional storage of twodimensional symm. matrix, which is stored as lower triangle and diagonal col must be <= row ! */ #define PM_ENTRY(pm,row,col) (pm[((((row)+1)*(row))/2)+(col)]) #define PM_SIZE ((MAX_PRIO*(MAX_PRIO+1))/2) /* get priority-merge value for given default mode */ #define PM_GETDEFAULT(mm,p1,p2,pres) \ switch (mm) { \ case PRIOMERGE_MAXIMUM : pres = MAX(p1,p2); break; \ case PRIOMERGE_MINIMUM : pres = MIN(p1,p2); break; \ default : pres = 0; break; \ } /****************************************************************************/ /* */ /* data structures */ /* */ /****************************************************************************/ /****************************************************************************/ /* */ /* definition of static variables */ /* */ /****************************************************************************/ /****************************************************************************/ /* */ /* routines */ /* */ /****************************************************************************/ void DDD_PrioritySet(DDD::DDDContext& context, DDD_HDR hdr, DDD_PRIO prio) { /* check input parameters */ if (prio>=MAX_PRIO) DUNE_THROW(Dune::Exception, "priority must be less than " << MAX_PRIO); # ifdef LogObjects Dune::dinfo << "LOG DDD_PrioritySet " << OBJ_GID(hdr) << " old=" << OBJ_PRIO(hdr) << " new=" << prio << "\n"; # endif if (ddd_XferActive(context)) { /* we are during Xfer, therefore initiate PrioChange operation */ DDD_XferPrioChange(context, hdr, prio); } else if(ddd_PrioActive(context)) { /* we are in a Prio-environment, therefore initiate consistent PrioChange operation */ DDD_PrioChange(context, hdr, prio); } else { if (! ObjHasCpl(context, hdr)) { /* just one local object, we can simply change its priority */ OBJ_PRIO(hdr) = prio; } else { /* distributed object will get inconsistent here. issue warning. */ if (DDD_GetOption(context, OPT_WARNING_PRIOCHANGE)==OPT_ON) Dune::dwarn << "DDD_PrioritySet: creating inconsistency for gid=" << OBJ_GID(hdr) << "\n"; /* change priority, nevertheless */ OBJ_PRIO(hdr) = prio; } } } /****************************************************************************/ /* compute the result of merging two priorities. this function merges two priorities p1 and p2 for object of DDD_TYPE desc. the default merge operation is used (PRIOMERGE_DEFAULT). if a merge-matrix has been specified, this matrix will be used. on return, *pres will contain the resulting priority. the return value is: PRIO_UNKNOWN can't decide which priority wins. PRIO_FIRST first priority wins. PRIO_SECOND second priority wins. PRIO_ERROR an error has occurred. */ enum PrioMergeVals PriorityMerge(const TYPE_DESC* desc, DDD_PRIO p1, DDD_PRIO p2, DDD_PRIO *pres) { /* check if matrix is available */ if (desc->prioMatrix == nullptr) { PM_GETDEFAULT(desc->prioDefault, p1, p2, *pres); if (*pres==MAX_PRIO) return PRIO_ERROR; } else { if (p2<=p1) { *pres = PM_ENTRY(desc->prioMatrix,p1,p2); } else { *pres = PM_ENTRY(desc->prioMatrix,p2,p1); } } if (*pres==p1 || *pres!=p2) return(PRIO_FIRST); if (*pres==p2 || *pres!=p1) return(PRIO_SECOND); return(PRIO_UNKNOWN); } /****************************************************************************/ /* allocate prioMatrix and set default entries */ static int SetPrioMatrix (TYPE_DESC *desc, int priomerge_mode) { int r, c; if (desc->prioMatrix==nullptr) { /* prioMatrix has not been allocated before */ desc->prioMatrix = std::make_unique(PM_SIZE); } for(r=0; rprioMatrix, r, c) = pres; } } /* remember default setting */ desc->prioDefault = priomerge_mode; return true; } /****************************************************************************/ /* check prioMatrix */ static int CheckPrioMatrix (TYPE_DESC *desc) { int r, c; if (desc->prioMatrix==nullptr) /* no prioMatrix defined, ok */ return true; /* check: entries i must be 0<=iprioMatrix,r,c); if (p>=MAX_PRIO) DUNE_THROW(Dune::Exception, "PriorityMerge(" << r << "," << c << ") yields" << p << " larger than " << (MAX_PRIO-1)); } } /* TODO: check for associativity */ return true; } /****************************************************************************/ void DDD_PrioMergeDefault (DDD::DDDContext& context, DDD_TYPE type_id, int priomerge_mode) { if (! SetPrioMatrix(&context.typeDefs()[type_id], priomerge_mode)) DUNE_THROW(Dune::Exception, "unknown defaultprio-mergemode in DDD_TYPE " << type_id); } void DDD_PrioMergeDefine (DDD::DDDContext& context, DDD_TYPE type_id, DDD_PRIO p1, DDD_PRIO p2, DDD_PRIO pres) { TYPE_DESC *desc = &context.typeDefs()[type_id]; /* check for correct type */ if (! ddd_TypeDefined(desc)) DUNE_THROW(Dune::Exception, "undefined DDD_TYPE"); /* create prioMatrix on demand */ if (desc->prioMatrix == nullptr) { if (! SetPrioMatrix(desc, PRIOMERGE_DEFAULT)) DUNE_THROW(Dune::Exception, "error for DDD_TYPE " << type_id); } /* check input priorities */ if (p1>=MAX_PRIO) DUNE_THROW(Dune::Exception, "invalid priority p1=" << p1); if (p2>=MAX_PRIO) DUNE_THROW(Dune::Exception, "invalid priority p2=" << p2); if (pres>=MAX_PRIO) DUNE_THROW(Dune::Exception, "invalid priority pres=" << pres); /* set prioMatrix entry */ if (p2<=p1) { PM_ENTRY(desc->prioMatrix,p1,p2) = pres; } else { PM_ENTRY(desc->prioMatrix,p2,p1) = pres; } /* finally always check prioMatrix, just to be sure */ if (!CheckPrioMatrix(desc)) DUNE_THROW(Dune::Exception, "error(s) in merge-check for DDD_TYPE " << type_id); } /****************************************************************************/ /* call merge operation from application program */ DDD_PRIO DDD_PrioMerge (DDD::DDDContext& context, DDD_TYPE type_id, DDD_PRIO p1, DDD_PRIO p2) { TYPE_DESC *desc = &context.typeDefs()[type_id]; DDD_PRIO newprio; /* check for correct type */ if (! ddd_TypeDefined(desc)) DUNE_THROW(Dune::Exception, "undefined DDD_TYPE"); if (p1>=MAX_PRIO) DUNE_THROW(Dune::Exception, "invalid priority p1=" << p1); if (p2>=MAX_PRIO) DUNE_THROW(Dune::Exception, "invalid priority p2=" << p2); if (PriorityMerge(desc, p1, p2, &newprio) == PRIO_ERROR) DUNE_THROW(Dune::Exception, "cannot merge priorities"); return newprio; } /****************************************************************************/ static const char* prioMergeDefaultName(int prioDefault) { switch (prioDefault) { case PRIOMERGE_MAXIMUM: return "MAX"; case PRIOMERGE_MINIMUM: return "MIN"; default: return "(ERROR)"; } } void DDD_PrioMergeDisplay (DDD::DDDContext& context, DDD_TYPE type_id) { std::ostream& out = std::cout; TYPE_DESC* desc = &context.typeDefs()[type_id]; int r, c; if (context.me() != 0) return; /* check for correct type */ if (! ddd_TypeDefined(desc)) DUNE_THROW(Dune::Exception, "undefined DDD_TYPE"); out << "/ PrioMergeDisplay for '" << desc->name << "', default mode " << prioMergeDefaultName(desc->prioDefault) << "\n"; if (desc->prioMatrix == nullptr) { out << "\\ \t(no special cases defined)\n"; return; } /* find out which rows/columns we will have to print */ std::array changed_rows; for(r=0; rprioDefault, r, c, p_dflt); PriorityMerge(desc, r, c, &p_actual); if (p_dflt != p_actual) changed_rows[r] = true; } } /* print */ using std::setw; out << "|\t "; for(c=0; cprioDefault, r, c, p_dflt); PriorityMerge(desc, r, c, &p_actual); if (p_dflt != p_actual) out << " " << setw(3) << p_actual << " "; else out << "(" << setw(3) << p_actual << ") "; } out << "\n"; } out << "\\\n"; } /****************************************************************************/ END_UGDIM_NAMESPACE dune-uggrid-2.11.0+dfsg/dune/uggrid/parallel/ddd/mgr/typemgr.cc000066400000000000000000001013431513616443000242570ustar00rootroot00000000000000// SPDX-FileCopyrightText: Copyright © DUNE Project contributors, see file LICENSE.md in module root // SPDX-License-Identifier: LGPL-2.1-or-later // -*- tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- // vi: set et ts=4 sw=2 sts=2: /****************************************************************************/ /* */ /* File: typemgr.c */ /* */ /* Purpose: declaring and defining DDD_TYPEs */ /* */ /* Author: Klaus Birken */ /* Rechenzentrum Uni Stuttgart */ /* Universitaet Stuttgart */ /* Allmandring 30 */ /* 70550 Stuttgart */ /* internet: birken@rus.uni-stuttgart.de */ /* */ /* History: 93/11/22 kb begin */ /* 94/09/13 kb added DDD_Status */ /* 95/11/03 kb complete rewrite of StructRegister code */ /* 95/11/16 kb copied from main.c, introduced clean type concept*/ /* 95/12/07 jb added fortran frontend */ /* 96/04/02 kb added EL_CONTINUE feature to TypeDefine() */ /* 97/02/12 kb added CPP_FRONTEND */ /* */ /* Remarks: */ /* */ /****************************************************************************/ /****************************************************************************/ /* */ /* include files */ /* system include files */ /* application include files */ /* */ /****************************************************************************/ /* standard C library */ #include #include #include #include #include #include #include #include #include #include #include #include #include USING_UG_NAMESPACES /* PPIF namespace: */ using namespace PPIF; START_UGDIM_NAMESPACE /* #define DebugTypeDefine #define DebugCopyMask #define DebugNoStructCompress */ /****************************************************************************/ /* */ /* definition of constants */ /* */ /****************************************************************************/ enum DDD_TypeModes { DDD_TYPE_INVALID = 0, /* DDD_TYPE not declared, not defined */ DDD_TYPE_DECLARED, /* DDD_TYPE declared, but not defined */ DDD_TYPE_CONTDEF, /* DDD_TYPE declared and partially defined */ DDD_TYPE_DEFINED /* DDD_TYPE declared and defined */ }; /****************************************************************************/ /* */ /* routines */ /* */ /****************************************************************************/ static void InitHandlers (TYPE_DESC *); int ddd_TypeDefined (TYPE_DESC *desc) { return(desc->mode==DDD_TYPE_DEFINED); } /****************************************************************************/ /* print out trailing part of error message during TypeDefine process error occurred during TypeDefine for desc, with argument argno */ class RegisterError { public: RegisterError(TYPE_DESC *desc, int argno) : desc(desc) , argno(argno) {} friend std::ostream& operator<<(std::ostream& out, const RegisterError& e) { if (e.argno != 0) out << ", arg " << e.argno << " of "; else out << " in "; out << "DDD_TypeDefine(\"" << e.desc->name << "/" << e.desc->currTypeDefCall << "\")"; return out; } private: TYPE_DESC* desc; int argno; }; /* check ELEM_DESC for plausibility */ static int CheckBounds (TYPE_DESC *desc, ELEM_DESC *el, int argno) { if (el->offset < 0) { Dune::dwarn << "negative offset" << RegisterError(desc, argno) << "\n"; return(ERROR); } if (el->size<=0) { Dune::dwarn << "illegal element size" << RegisterError(desc, argno) << "\n"; return (ERROR); } return 0; } /* check ELEM_DESC list of given TYPE_DESC for bad overlapping */ static int CheckOverlapEls (TYPE_DESC *desc) { int i; int ok = true; for(i=0; inElements; i++) { ELEM_DESC *e1 = &desc->element[i]; if (inElements-1) { ELEM_DESC *e2 = &desc->element[i+1]; if (e1->offset+e1->size > e2->offset) { ok = false; Dune::dwarn << "element too big (offset=" << e1->offset << ")" << RegisterError(desc, 0) << "\n"; } } else { if (e1->offset+e1->size > desc->size) { ok = false; Dune::dwarn << "element too big (offset=" << e1->offset << ")" << RegisterError(desc, 0) << "\n"; } } } return ok; } /* constructor for ELEM_DESC */ static void ConstructEl (ELEM_DESC *elem, int t, int o, size_t s, DDD_TYPE rt) { elem->type = t; elem->offset = o; elem->size = s; /* for OBJPTR elements, store referenced DDD_TYPE here. the default is EL_DDDHDR, i.e., if this feature is not used, the DDD_HDR will be assumed to be at the beginning of each structure (offsetHeader==0). */ EDESC_SET_REFTYPE(elem, rt); elem->reftypeHandler = NULL; /* for GBITS elements, store array of bits. 1=GDATA, 0=LDATA. */ if (t==EL_GBITS) { elem->gbits = std::make_unique(s); } } /* register previously defined TYPE_DESC during TypeDefine */ static int RecursiveRegister (DDD::DDDContext& context, TYPE_DESC *desc, int i, DDD_TYPE typ, int offs, int argno) { TYPE_DESC *d2 = &context.typeDefs()[typ]; int j; /* inherit elements of other ddd-type */ for(j=0; jnElements && i < TYPE_DESC::MAX_ELEMDESC; j++, i++) { ConstructEl(&desc->element[i], d2->element[j].type, d2->element[j].offset + offs, d2->element[j].size, EDESC_REFTYPE(&(d2->element[j]))); if (CheckBounds(desc, &desc->element[i], argno) == ERROR) return(ERROR); } /* inherit other properties */ desc->nPointers += d2->nPointers; if (d2->hasHeader) { if (!desc->hasHeader) { desc->hasHeader = true; desc->offsetHeader = d2->offsetHeader + offs; } else { if (desc->offsetHeader == d2->offsetHeader+offs) { Dune::dwarn << "two DDD_HDRs, same offset" << RegisterError(desc, argno) << "\n"; } else { Dune::dwarn << "only one DDD_HDR allowed" << RegisterError(desc, argno) << "\n"; return(ERROR); } } } return i; } /* constructor for TYPE_DESC */ static void ConstructDesc (TYPE_DESC *desc) { InitHandlers(desc); desc->nPointers = 0; desc->nElements = 0; desc->cmask = nullptr; desc->hasHeader = false; desc->offsetHeader = 0; } #ifndef DebugNoStructCompress /* remove first element in given ELEM_DESC-list, adjust remaining elements */ static void DeleteFirstEl (ELEM_DESC *elarray, int n) { int i; for(i=1; ielement; /* sort element array by offset */ std::sort( elems, elems + desc->nElements, [](const ELEM_DESC& a, const ELEM_DESC& b) { return a.offset < b.offset; } ); /* check for overlapping elements */ if (! CheckOverlapEls(desc)) return false; # ifndef DebugNoStructCompress { /* compile this only if Debug-flag not set */ int i; /* compress element description */ for(i=0; inElements-1; i++) { size_t realsize; /* 1) type must be equal */ if (elems[i].type != elems[i+1].type) continue; /* 2) nothing can melt into DDD_HEADER */ if (desc->hasHeader && elems[i+1].offset==desc->offsetHeader) continue; /* 3) gap between elements is allowed only for EL_LDATA */ if ((elems[i].offset+elems[i].size != elems[i+1].offset) && (elems[i].type!=EL_LDATA) ) continue; /* 4) EL_OBJPTRs with different reftypes can't be compressed */ if (elems[i].type==EL_OBJPTR && ((EDESC_REFTYPE(elems+i)!= EDESC_REFTYPE(elems+(i+1))) || (EDESC_REFTYPE(elems+i)==DDD_TYPE_BY_HANDLER)) ) continue; /* 5) EL_GBITS can't be compressed */ if (elems[i].type == EL_GBITS) continue; /* all conditions fit: compress elements */ realsize = elems[i+1].offset - elems[i].offset; elems[i].size = realsize + elems[i+1].size; desc->nElements--; DeleteFirstEl(&elems[i+1], desc->nElements - i); i--; /* skip one element back and try again */ } } # endif return true; } /* compute copy-mask (for efficiency) and attach it to TYPE_DESC */ static void AttachMask(const DDD::DDDContext& context, TYPE_DESC *desc) { unsigned char mask; /* get storage for mask */ desc->cmask = std::make_unique(desc->size); /* set default: EL_LDATA for unspecified regions (gaps) */ for (std::size_t i=0; isize; i++) { desc->cmask[i] = 0x00; /* dont-copy-flag */ } /* create mask from element list */ for (int i=0; inElements; i++) { ELEM_DESC *e = &desc->element[i]; unsigned char* mp = desc->cmask.get() + e->offset; switch (e->type) { case EL_LDATA : case EL_OBJPTR : /* OBJPTR are LDATA!!! */ mask = 0x00; /* dont-copy-flag */ break; case EL_GDATA : case EL_DATAPTR : mask = 0xff; /* copy-flag */ break; } for (std::size_t k=0; ksize; k++) { if (e->type==EL_GBITS) { mp[k] = e->gbits[k]; /* copy bitwise */ } else { mp[k] = mask; } } } # ifdef DebugCopyMask if (context.isMaster()) { using std::setfill; using std::setw; Dune::dinfo << "AttachMask for " << desc->name ":"; for(i=0; isize; i++) { if (i%8==0) Dune::dinfo << "\n " << setw(4) << i << ": "; Dune::dinfo << setfill('0') << setw(2) << desc->cmask[i] << setfill(' ') << " "; } Dune::dinfo << "\n"; } # endif } /****************************************************************************/ /* */ /* Function: DDD_TypeDefine */ /* */ /* Purpose: define object structure at runtime */ /* */ /* Input: context typ, t0, p0, s0, [r0 [, rh0]], t1, p1, s1 ... */ /* with typ: previously declared DDD_TYPE */ /* t: element type */ /* p: offset of member in data structure */ /* s: size of element in byte */ /* r: (only for EL_OBJPTR): referenced DDD_TYPE */ /* rt: (only for EL_OBJPTR and DDD_TYPE_BY_HANDLER): */ /* handler for getting reftype on-the-fly. */ /* */ /* Output: - */ /* */ /****************************************************************************/ void DDD_TypeDefine(DDD::DDDContext& context, DDD_TYPE typ, ...) { auto& nDescr = context.typemgrContext().nDescr; size_t argsize; size_t argoffset; int argtyp, argno; DDD_TYPE argrefs; int i, nPtr; va_list ap; char *gbits; /* TODO: only master should be able to define types, other procs should receive the correct definition from master. (with the current implementation inconsistencies might occur) */ /* test whether typ is valid */ if (typ>=nDescr) DUNE_THROW(Dune::Exception, "invalid DDD_TYPE"); /* get object description */ TYPE_DESC* desc = &context.typeDefs()[typ]; desc->currTypeDefCall++; if (desc->mode!=DDD_TYPE_DECLARED && desc->mode!=DDD_TYPE_CONTDEF) { if (desc->mode==DDD_TYPE_DEFINED) DUNE_THROW(Dune::Exception, "DDD_TYPE already defined"); else DUNE_THROW(Dune::Exception, "undeclared DDD_TYPE"); } /* initialize TYPE_DESC struct, only on first call */ if (desc->currTypeDefCall==1) ConstructDesc(desc); if (typ==0) /* i.e. typ==EL_DDDHDR */ { /* DDD_HDR also contains a DDD_HDR (sic!) */ desc->hasHeader = true; } # ifdef DebugTypeDefine Dune::dinfo << " DDD_TypeDefine(" << desc->name << "/" << desc->currTypeDefCall << ")\n"; # endif /* start variable arguments after "typ"-parameter */ va_start(ap, typ); argno = 1; /* loop over variable argument list */ i = desc->nElements; while ((i < TYPE_DESC::MAX_ELEMDESC) && ((argtyp= va_arg(ap, int))!=EL_END) && (argtyp!=EL_CONTINUE)) { HandlerGetRefType arg_rt_handler = NULL; /* get the offset of the member in the object */ argoffset = va_arg(ap, size_t); argno+=2; /* handle several types of ELEM_DESCs */ switch (argtyp) { /* 1) ELEM_DESC is a pointer [array] */ case EL_OBJPTR : case EL_DATAPTR : /* get third argument of this definition line */ argsize = va_arg(ap, size_t); argno++; /* EL_OBJPTR have to be specified with target type */ if (argtyp==EL_OBJPTR) { /* get fourth argument: referenced DDD_TYPE */ argrefs = (DDD_TYPE) va_arg(ap, int); argno++; /* check whether target type is DDD_TYPE_BY_HANDLER */ /* this is currently supported only by C_FRONTEND */ if (argrefs==DDD_TYPE_BY_HANDLER) { arg_rt_handler = va_arg(ap, HandlerGetRefType); argno++; } else { /* check whether target type is valid */ if (argrefs>=nDescr || context.typeDefs()[argrefs].mode==DDD_TYPE_INVALID) { DUNE_THROW(Dune::Exception, "referencing invalid DDD_TYPE" << RegisterError(desc,argno)); } } } else { /* to target type for EL_DATAPTR */ argrefs = EL_DDDHDR; } /* compute #pointers (in array) */ nPtr = argsize / sizeof(void *); /* check for plausibility */ if (nPtr*sizeof(void *) != argsize) { DUNE_THROW(Dune::Exception, "invalid sizeof" << RegisterError(desc,argno)); } /* remember #pointers */ desc->nPointers += nPtr; /* initialize ELEM_DESC */ ConstructEl(&desc->element[i], argtyp, argoffset, argsize, argrefs); /* set reftype-handler function pointer, if any */ if (argrefs==DDD_TYPE_BY_HANDLER) desc->element[i].reftypeHandler = arg_rt_handler; if (CheckBounds(desc, &desc->element[i], argno) == ERROR) return; i++; # ifdef DebugTypeDefine Dune::dinfo << " PTR, " << std::setw(5) << argoffset << ", " << std::setw(6) << argsize << "\n"; # endif break; /* 2) ELEM_DESC is global or local data */ case EL_GDATA : case EL_LDATA : /* get third argument of this definition line */ argsize = va_arg(ap, size_t); argno++; /* initialize ELEM_DESC */ ConstructEl(&desc->element[i], argtyp, argoffset, argsize, 0); if (CheckBounds(desc, &desc->element[i], argno) == ERROR) return; i++; # ifdef DebugTypeDefine Dune::dinfo << " DAT, " << std::setw(5) << argoffset << ", " << std::setw(6) << argsize << "\n"; # endif break; /* 3) ELEM_DESC is bitwise global or local */ case EL_GBITS : /* get third argument of this definition line */ argsize = va_arg(ap, size_t); argno++; /* initialize ELEM_DESC */ ConstructEl(&desc->element[i], argtyp, argoffset, argsize, 0); /* read forth arg from cmdline */ gbits = va_arg(ap, char *); argno++; /* fill gbits array, read forth arg from cmdline */ memcpy(desc->element[i].gbits.get(), gbits, argsize); if (CheckBounds(desc, &desc->element[i], argno) == ERROR) return; # ifdef DebugTypeDefine Dune::dinfo << " BITS, " << std::setw(5) << argoffset << ", " << std::setw(6) << argsize << ", "; Dune::dinfo << std::setfill('0') << std::hex; for(int ii=0; iielement[i].gbits[ii]) << " "; Dune::dinfo << std::setfill(' ') << std::dec << "\n"; # endif i++; break; /* 4) ELEM_DESC is a recursively defined DDD_TYPE */ default : /* hierarchical registering of known ddd_types */ /* no third argument here */ /* check for plausibility of given DDD_TYPE */ if (argtyp<0 || argtyp>=nDescr || argtyp==typ) { DUNE_THROW(Dune::Exception, "undefined DDD_TYPE=" << argtyp << RegisterError(desc,argno-1)); } /* check whether given DDD_TYPE has been defined already */ if (context.typeDefs()[argtyp].mode==DDD_TYPE_DEFINED) { /* do recursive TypeDefine */ i = RecursiveRegister(context, desc, i, argtyp, argoffset, argno); if (i==ERROR) HARD_EXIT; /* return; */ #ifdef DebugTypeDefine Dune::dinfo << " " << std::setw(3) << argtyp << ", " << std::setw(5) << argoffset << ", " << std::setw(6) << context.typeDefs()[argtyp].size << "\n"; #endif } else { DUNE_THROW(Dune::Exception, "undefined DDD_TYPE " << context.typeDefs()[argtyp].name << RegisterError(desc,argno-1)); } break; } } /* check whether loop has come to a correct end */ if (i >= TYPE_DESC::MAX_ELEMDESC && argtyp!=EL_END && argtyp!=EL_CONTINUE) DUNE_THROW(Dune::Exception, "too many elements" << RegisterError(desc, 0)); /* remember #elements in TYPE_DESC */ desc->nElements = i; if (argtyp==EL_END) /* and not EL_CONTINUE */ { /* compute aligned object length */ desc->size = va_arg(ap, size_t); desc->size = CEIL(desc->size); /* do normalization */ if (! NormalizeDesc(desc)) HARD_EXIT; /*return;*/ /* attach copy-mask for efficient copying */ AttachMask(context, desc); /* change TYPE_DESC state to DEFINED */ desc->mode = DDD_TYPE_DEFINED; } else /* argtyp==EL_CONTINUE */ { /* change TYPE_DESC state to CONTDEF */ desc->mode = DDD_TYPE_CONTDEF; } va_end(ap); } /****************************************************************************/ /* */ /* Function: DDD_TypeDeclare */ /* */ /* Purpose: declare DDD_TYPE at runtime */ /* */ /* Input: name: object name string */ /* */ /* Output: id of object-description */ /* -1 on error */ /* */ /****************************************************************************/ DDD_TYPE DDD_TypeDeclare(DDD::DDDContext& context, const char *name) { auto& nDescr = context.typemgrContext().nDescr; TYPE_DESC* desc = &context.typeDefs()[nDescr]; /* check whether there is one more DDD_TYPE */ if (nDescr==MAX_TYPEDESC) DUNE_THROW(Dune::Exception, "no more free DDD_TYPEs"); /* set status to DECLARED and remember textual type name */ desc->mode = DDD_TYPE_DECLARED; desc->name = name; desc->prioMatrix = nullptr; desc->prioDefault = PRIOMERGE_DEFAULT; /* increase #DDD_TYPEs, but return previously defined one */ nDescr++; return(nDescr-1); } /****************************************************************************/ /* */ /* Function: DDD_TypeDisplay */ /* */ /* Purpose: show defined DDD_TYPE */ /* */ /* Input: id: DDD_TYPE which will be shown */ /* */ /* Output: - */ /* */ /****************************************************************************/ void DDD_TypeDisplay(const DDD::DDDContext& context, DDD_TYPE id) { using std::setw; /* only master should display DDD_TYPEs */ if (context.isMaster()) { /* check for plausibility */ if (id >= context.typemgrContext().nDescr) DUNE_THROW(Dune::Exception, "invalid DDD_TYPE " << id); const TYPE_DESC* desc = &context.typeDefs()[id]; if (desc->mode != DDD_TYPE_DEFINED) DUNE_THROW(Dune::Exception, "undefined DDD_TYPE " << id); /* print header */ std::ostream& out = std::cout; out << "/ Structure of " << (desc->hasHeader ? "DDD" : "data") << "--object '" << desc->name <<"', id " << id << ", " << desc->size << " byte\n" << "|--------------------------------------------------------------\n"; /* print one line for each element */ for (int i = 0; i < desc->nElements; i++) { const ELEM_DESC *e = &desc->element[i]; int realnext = (i==desc->nElements-1) ? desc->size : (e+1)->offset; int estinext = e->offset+e->size; /* handle gap at the beginning */ if (i==0 && e->offset!=0) out << "|" << setw(5) << 0 << " " << setw(5) << e->offset << " gap (local data)\n"; /* do visual compression of elems inherited from DDD_HDR */ if (id==EL_DDDHDR || (!desc->hasHeader) || e->offset < desc->offsetHeader || e->offset >= desc->offsetHeader + context.typeDefs()[EL_DDDHDR].size) { out << "|" << setw(5) << e->offset << " " << setw(5) << e->size << " "; /* print one line according to type */ switch (e->type) { case EL_GDATA : out << "global data\n"; break; case EL_LDATA : out << "local data\n"; break; case EL_DATAPTR : out << "data pointer\n"; break; case EL_OBJPTR : if (EDESC_REFTYPE(e)!=DDD_TYPE_BY_HANDLER) out << "obj pointer (refs " << context.typeDefs()[EDESC_REFTYPE(e)].name << ")\n"; else out << "obj pointer (reftype on-the-fly)\n"; break; case EL_GBITS : out << "bitwise global: "; out << std::setfill('0') << std::hex; for (size_t ii=0; iisize; ii++) out << setw(2) << int(e->gbits[ii]) << " "; out << std::setfill(' ') << std::dec << "\n"; break; } /* handle gap */ if (estinext != realnext) out << "|" << setw(5) << estinext << " " << setw(5) << (realnext-estinext) << " gap (local data)\n"; } else { /* handle included DDD_HDR */ if (e->offset == desc->offsetHeader) out << "|" << setw(5) << e->offset << " " << setw(5) << context.typeDefs()[EL_DDDHDR].size << " ddd-header\n"; } } out << "\\--------------------------------------------------------------\n"; } } static void InitHandlers (TYPE_DESC *desc) { /* set all handler functions to default (=none) */ desc->handlerLDATACONSTRUCTOR = NULL; desc->handlerDESTRUCTOR = NULL; desc->handlerDELETE = NULL; desc->handlerUPDATE = NULL; desc->handlerOBJMKCONS = NULL; desc->handlerSETPRIORITY = NULL; desc->handlerXFERCOPY = NULL; desc->handlerXFERDELETE = NULL; desc->handlerXFERGATHER = NULL; desc->handlerXFERSCATTER = NULL; desc->handlerXFERGATHERX = NULL; desc->handlerXFERSCATTERX = NULL; desc->handlerXFERCOPYMANIP = NULL; } #define DEFINE_DDD_SETHANDLER(name) \ void DDD_SetHandler##name(DDD::DDDContext& context, DDD_TYPE type_id, Handler##name funcptr) { \ TYPE_DESC& desc = context.typeDefs()[type_id]; \ assert(desc.mode == DDD_TYPE_DEFINED); \ desc.handler##name = funcptr; \ } DEFINE_DDD_SETHANDLER(LDATACONSTRUCTOR) DEFINE_DDD_SETHANDLER(DESTRUCTOR) DEFINE_DDD_SETHANDLER(DELETE) DEFINE_DDD_SETHANDLER(UPDATE) DEFINE_DDD_SETHANDLER(OBJMKCONS) DEFINE_DDD_SETHANDLER(SETPRIORITY) DEFINE_DDD_SETHANDLER(XFERCOPY) DEFINE_DDD_SETHANDLER(XFERDELETE) DEFINE_DDD_SETHANDLER(XFERGATHER) DEFINE_DDD_SETHANDLER(XFERSCATTER) DEFINE_DDD_SETHANDLER(XFERGATHERX) DEFINE_DDD_SETHANDLER(XFERSCATTERX) DEFINE_DDD_SETHANDLER(XFERCOPYMANIP) #undef DEFINE_DDD_SETHANDLER /****************************************************************************/ /* */ /* Function: DDD_InfoTypes */ /* */ /* Purpose: returns number of declared types */ /* */ /* Input: - */ /* */ /* Output: number of declared types */ /* */ /****************************************************************************/ int DDD_InfoTypes(const DDD::DDDContext& context) { return context.typemgrContext().nDescr; } /****************************************************************************/ /* */ /* Function: DDD_InfoHdrOffset */ /* */ /* Purpose: returns offset of DDD_HEADER for a given DDD_TYPE in bytes */ /* NOTE: output will be invalid for DDD_TYPEs without header! */ /* */ /* Input: typeId: DDD_TYPE for which header offset is returned */ /* */ /* Output: nheader offset for given type */ /* */ /****************************************************************************/ int DDD_InfoHdrOffset(const DDD::DDDContext& context, DDD_TYPE typeId) { const TYPE_DESC& desc = context.typeDefs()[typeId]; return desc.offsetHeader; } /****************************************************************************/ /* */ /* Function: ddd_TypeMgrInit */ /* */ /* Purpose: init TypeMgr module */ /* (DDD_HEADER is declared and defined as first DDD_TYPE) */ /* */ /* Input: - */ /* */ /* Output: - */ /* */ /****************************************************************************/ void ddd_TypeMgrInit(DDD::DDDContext& context) { /* set all theTypeDefs to INVALID, i.e., no DDD_TYPE has been defined */ for (TYPE_DESC& typeDef : context.typeDefs()) { typeDef.mode = DDD_TYPE_INVALID; typeDef.currTypeDefCall = 0; } /* reset declared types */ context.typemgrContext().nDescr = 0; /* init DDD_HEADER as first type, with DDD_TYPE=0 */ { DDD_TYPE hdr_type; /* hdr_type will be EL_DDDHDR (=0) per default */ hdr_type = DDD_TypeDeclare(context, "DDD_HDR"); DDD_TypeDefine(context, hdr_type, EL_GDATA, offsetof(DDD_HEADER,typ), sizeof(DDD_HEADER::typ), EL_LDATA, offsetof(DDD_HEADER,prio), sizeof(DDD_HEADER::prio), EL_GDATA, offsetof(DDD_HEADER,attr), sizeof(DDD_HEADER::attr), EL_LDATA, offsetof(DDD_HEADER,flags), sizeof(DDD_HEADER::flags), EL_LDATA, offsetof(DDD_HEADER,myIndex), sizeof(DDD_HEADER::myIndex), EL_GDATA, offsetof(DDD_HEADER,gid), sizeof(DDD_HEADER::gid), EL_END, sizeof(DDD_HEADER) ); } } /****************************************************************************/ /* */ /* Function: ddd_TypeMgrExit */ /* */ /* Purpose: exit and clean up TypeMgr module */ /* */ /* Input: - */ /* */ /* Output: - */ /* */ /****************************************************************************/ void ddd_TypeMgrExit(DDD::DDDContext& context) { /* free memory */ for (auto& typeDef : context.typeDefs()) { typeDef.cmask = nullptr; } } /****************************************************************************/ END_UGDIM_NAMESPACE dune-uggrid-2.11.0+dfsg/dune/uggrid/parallel/ddd/prio/000077500000000000000000000000001513616443000224435ustar00rootroot00000000000000dune-uggrid-2.11.0+dfsg/dune/uggrid/parallel/ddd/prio/CMakeLists.txt000066400000000000000000000003041513616443000252000ustar00rootroot00000000000000# SPDX-FileCopyrightText: Copyright © DUNE Project contributors, see file LICENSE.md in module root # SPDX-License-Identifier: LGPL-2.1-or-later target_sources_dims(duneuggrid PRIVATE pcmds.cc) dune-uggrid-2.11.0+dfsg/dune/uggrid/parallel/ddd/prio/pcmds.cc000066400000000000000000000254641513616443000240730ustar00rootroot00000000000000// SPDX-FileCopyrightText: Copyright © DUNE Project contributors, see file LICENSE.md in module root // SPDX-License-Identifier: LGPL-2.1-or-later // -*- tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- // vi: set et ts=4 sw=2 sts=2: /****************************************************************************/ /* */ /* File: pcmds.c */ /* */ /* Purpose: DDD-commands for Prio Environment */ /* */ /* Author: Klaus Birken */ /* Institut fuer Computeranwendungen III */ /* Universitaet Stuttgart */ /* Pfaffenwaldring 27 */ /* 70569 Stuttgart */ /* email: birken@ica3.uni-stuttgart.de */ /* phone: 0049-(0)711-685-7007 */ /* fax : 0049-(0)711-685-7000 */ /* */ /* History: 980720 kb begin */ /* */ /* Remarks: */ /* */ /****************************************************************************/ /****************************************************************************/ /* */ /* include files */ /* system include files */ /* application include files */ /* */ /****************************************************************************/ /* standard C library */ #include #include #include #include #include #include #include #define DebugPrio 10 /* 0 is all, 10 is off */ /****************************************************************************/ /* */ /* defines in the following order */ /* */ /* compile time constants defining static data size (i.e. arrays) */ /* other constants */ /* macros */ /* */ /****************************************************************************/ namespace DDD { namespace Prio { /* overall mode of prio-environment */ enum class PrioMode : unsigned char { PMODE_IDLE = 0, /* waiting for next DDD_PrioBegin() */ PMODE_CMDS, /* after DDD_PrioBegin(), before DDD_PrioEnd() */ PMODE_BUSY /* during DDD_PrioEnd() */ }; } /* namespace Prio */ } /* namespace DDD */ START_UGDIM_NAMESPACE using DDD::Prio::PrioMode; /* management functions for PrioMode. these functions control the mode the prio-module is currently in. this is used for error detection, but also for correct detection of coupling inconsistencies and recovery. */ static const char* PrioModeName (PrioMode mode) { switch(mode) { case PrioMode::PMODE_IDLE : return "idle-mode"; case PrioMode::PMODE_CMDS : return "commands-mode"; case PrioMode::PMODE_BUSY : return "busy-mode"; } return "unknown-mode"; } static void PrioSetMode (DDD::DDDContext& context, PrioMode mode) { auto& ctx = context.prioContext(); ctx.prioMode = mode; # if DebugPrio<=8 Dune::dinfo << "PrioMode=" << PrioModeName(ctx.prioMode) << "\n"; # endif } static PrioMode PrioSuccMode (PrioMode mode) { switch(mode) { case PrioMode::PMODE_IDLE: return PrioMode::PMODE_CMDS; case PrioMode::PMODE_CMDS: return PrioMode::PMODE_BUSY; case PrioMode::PMODE_BUSY: return PrioMode::PMODE_IDLE; default: std::abort(); } } bool ddd_PrioActive (const DDD::DDDContext& context) { return context.prioContext().prioMode != PrioMode::PMODE_IDLE; } static bool PrioStepMode(DDD::DDDContext& context, PrioMode old) { auto& ctx = context.prioContext(); if (ctx.prioMode!=old) { Dune::dwarn << "wrong prio-mode (currently in " << PrioModeName(ctx.prioMode) << ", expected " << PrioModeName(old) << ")\n"; return false; } PrioSetMode(context, PrioSuccMode(ctx.prioMode)); return true; } /****************************************************************************/ void ddd_PrioInit(DDD::DDDContext& context) { PrioSetMode(context, PrioMode::PMODE_IDLE); } void ddd_PrioExit(DDD::DDDContext&) {} /****************************************************************************/ /* */ /* Function: DDD_PrioChange */ /* */ /****************************************************************************/ /** Consistent change of a local object's priority during DDD Prio Environment. Local objects which are part of a distributed object must notify other copies about local priority changes. DDD will send appropriate messages to the owner processors of the other copies. This function is regarded as a {\bf Prio}-operation due to its influence on DDD management information on neighbouring processors. Therefore the function has to be issued between a starting \funk{PrioBegin} and a final \funk{PrioEnd} call. @param hdr DDD local object whose priority should be changed. @param prio new priority for this local object. */ void DDD_PrioChange (const DDD::DDDContext& context, DDD_HDR hdr, DDD_PRIO prio) { #if DebugPrio<=2 DDD_PRIO old_prio = OBJ_PRIO(hdr); #endif if (!ddd_PrioActive(context)) DUNE_THROW(Dune::Exception, "Missing DDD_PrioBegin()"); /* change priority of object directly, for local objects this is all what we need. */ { /* DDD_PRIO newprio; PriorityMerge(&context.typeDefs()[OBJ_TYPE(hdr)], OBJ_PRIO(hdr), prio, &newprio); OBJ_PRIO(hdr) = newprio; */ OBJ_PRIO(hdr) = prio; } /* handle distributed objects if (ObjHasCpl(context, hdr)) { nothing to do here: for distributed objects, we will communicate the prio via standard interface later. } */ # if DebugPrio<=2 Dune::dvverb << "DDD_PrioChange " << OBJ_GID(hdr) << ", old_prio=" << old_prio << ", new_prio=" << OBJ_PRIO(hdr) << "\n"; # endif } /****************************************************************************/ /* */ /* Function: DDD_PrioEnd */ /* */ /****************************************************************************/ static int GatherPrio (DDD::DDDContext&, DDD_HDR obj, void *data, DDD_PROC proc, DDD_PRIO prio) { # if DebugPrio<=1 Dune::dvverb << "DDD_PrioEnd/GatherPrio " << OBJ_GID(obj) << ", prio=" << OBJ_PRIO(obj) << ". Send to copy on proc " << proc << "/p" << prio << "\n"; # endif *((DDD_PRIO *)data) = OBJ_PRIO(obj); return(0); } static int ScatterPrio (DDD::DDDContext& context, DDD_HDR obj, void *data, DDD_PROC proc, DDD_PRIO prio) { DDD_PRIO real_prio = *((DDD_PRIO *)data); /* if prio on other processor has been changed, we adapt it here. */ if (real_prio!=prio) { # if DebugPrio<=1 Dune::dvverb << "DDD_PrioEnd/ScatterPrio " << OBJ_GID(obj) << "/" << OBJ_PRIO(obj) << ", copy on proc " << proc << "/p" << prio << " changed prio " << prio << " -> " << real_prio << "\n"; # endif ModCoupling(context, obj, proc, real_prio); } # if DebugPrio<=1 else { Dune::dvverb << "DDD_PrioEnd/ScatterPrio " << OBJ_GID(obj) << "/" << OBJ_PRIO(obj) << ", copy on proc " << proc << "/p" << prio << " keeps prio " << prio << "\n"; } # endif return(0); } /** End of PrioEnvironment. This function starts the actual process of changing priorities. After a call to this function (on all processors) all \funk{PrioChange}-commands since the last call to \funk{PrioBegin} are executed. This involves a set of interface communications between the processors. */ DDD_RET DDD_PrioEnd(DDD::DDDContext& context) { /* step mode and check whether call to PrioEnd is valid */ if (!PrioStepMode(context, PrioMode::PMODE_CMDS)) DUNE_THROW(Dune::Exception, "DDD_PrioEnd() aborted"); ddd_StdIFExchangeX(context, sizeof(DDD_PRIO), GatherPrio, ScatterPrio); /* free temporary storage */ STAT_RESET; IFAllFromScratch(context); STAT_TIMER(T_PRIO_BUILD_IF); PrioStepMode(context, PrioMode::PMODE_BUSY); return(DDD_RET_OK); } /****************************************************************************/ /* */ /* Function: DDD_PrioBegin */ /* */ /****************************************************************************/ /** Starts a PrioEnvironment. A call to this function establishes a global operation of changing priorities. It must be issued on all processors. After this call an arbitrary series of \funk{PrioChange}-commands may be issued. The global transfer operation is carried out via a \funk{PrioEnd} call on each processor. */ void DDD_PrioBegin(DDD::DDDContext& context) { /* step mode and check whether call to JoinBegin is valid */ if (!PrioStepMode(context, PrioMode::PMODE_IDLE)) DUNE_THROW(Dune::Exception, "DDD_PrioBegin() aborted"); } END_UGDIM_NAMESPACE dune-uggrid-2.11.0+dfsg/dune/uggrid/parallel/ddd/xfer/000077500000000000000000000000001513616443000224365ustar00rootroot00000000000000dune-uggrid-2.11.0+dfsg/dune/uggrid/parallel/ddd/xfer/CMakeLists.txt000066400000000000000000000005701513616443000252000ustar00rootroot00000000000000# SPDX-FileCopyrightText: Copyright © DUNE Project contributors, see file LICENSE.md in module root # SPDX-License-Identifier: LGPL-2.1-or-later target_sources_dims(duneuggrid PRIVATE cmdmsg.cc cmds.cc cplmsg.cc ctrl.cc pack.cc supp.cc unpack.cc xfer.cc) install(FILES sll.h xfer.h DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}/dune/uggrid/parallel/ddd/xfer) dune-uggrid-2.11.0+dfsg/dune/uggrid/parallel/ddd/xfer/cmdmsg.cc000066400000000000000000000304551513616443000242260ustar00rootroot00000000000000// SPDX-FileCopyrightText: Copyright © DUNE Project contributors, see file LICENSE.md in module root // SPDX-License-Identifier: LGPL-2.1-or-later // -*- tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- // vi: set et ts=4 sw=2 sts=2: /****************************************************************************/ /* */ /* File: cmdmsg.c */ /* */ /* Purpose: ddd command transfer: */ /* send messages with commands to owners of other local */ /* object copies. this is used for sending XferCopy commands */ /* to owners of local copies, in order to prevent deletion */ /* and creation of the same object copy during xfer. */ /* (used only if OPT_XFER_PRUNE_DELETE is set to OPT_ON) */ /* */ /* Author: Klaus Birken */ /* Institut fuer Computeranwendungen III */ /* Universitaet Stuttgart */ /* Pfaffenwaldring 27 */ /* 70569 Stuttgart */ /* internet: birken@ica3.uni-stuttgart.de */ /* */ /* History: 970411 kb created */ /* */ /* Remarks: */ /* */ /****************************************************************************/ /****************************************************************************/ /* */ /* include files */ /* system include files */ /* application include files */ /* */ /****************************************************************************/ /* standard C library */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include "xfer.h" USING_UG_NAMESPACE using namespace PPIF; START_UGDIM_NAMESPACE /****************************************************************************/ /* */ /* data structures */ /* */ /****************************************************************************/ /* CMDMSG: complete description of message on sender side */ struct CMDMSG { DDD_PROC proc; DDD_GID *aUnDelete = nullptr; int nUnDelete = 0; /* lowcomm message handle */ LC_MSGHANDLE msg_h; CMDMSG(DDD_PROC dest) : proc(dest) {} }; using CmdmsgList = std::forward_list; /****************************************************************************/ /* */ /* routines */ /* */ /****************************************************************************/ void CmdMsgInit(DDD::DDDContext& context) { auto& ctx = context.cmdmsgContext(); ctx.cmdmsg_t = LC_NewMsgType(context, "CmdMsg"); ctx.undelete_id = LC_NewMsgTable("UndelTab", ctx.cmdmsg_t, sizeof(DDD_GID)); } void CmdMsgExit(DDD::DDDContext& context) {} /****************************************************************************/ static std::pair PrepareCmdMsgs (DDD::DDDContext& context, const std::vector& arrayCO) { auto& ctx = context.cmdmsgContext(); if (arrayCO.empty()) return {0, CmdmsgList()}; # if DebugCmdMsg<=3 Dune::dvverb << "PreparePrune, nCopyObj=" << arrayCO.size() << "\n"; # endif /* run through CopyObj table, mark all entries that have a coupling with same proc as destination. */ int markedCO = 0; for(auto co : arrayCO) { DDD_PROC pCO = co->dest; COUPLING *cpl; /* run through coupling list of corresponding obj, find coupling to destination of XferCopyObj command */ cpl = ObjCplList(context, co->hdr); while (cpl!=NULL && CPL_PROC(cpl)!=pCO) cpl=CPL_NEXT(cpl); if (cpl!=NULL) { /* found coupling -> mark CopyObj */ SET_CO_SELF(co, 1); markedCO++; } else { SET_CO_SELF(co, 0); } } if (markedCO==0) return {0, CmdmsgList()}; std::vector gids(markedCO); CmdmsgList msgs; int nMsgs = 0; /* run through CopyObj table again, consider only marked items, each time a new proc-nr is encountered in one of these tables, create a new CMDMSG item. (the lists have been sorted according to proc-nr previously.) */ int j=0; for(auto co : arrayCO) { if (CO_SELF(co)) { gids[j] = co->gid; if (msgs.empty() or msgs.front().proc != co->dest) { msgs.emplace_front(co->dest); nMsgs++; msgs.front().aUnDelete = &gids[j]; } msgs.front().nUnDelete++; j++; } } /* initiate send messages */ for(auto& xm : msgs) { /* create new send message */ xm.msg_h = LC_NewSendMsg(context, ctx.cmdmsg_t, xm.proc); /* init tables inside message */ LC_SetTableSize(xm.msg_h, ctx.undelete_id, xm.nUnDelete); /* prepare message for sending away */ LC_MsgPrepareSend(context, xm.msg_h); DDD_GID* array = (DDD_GID *)LC_GetPtr(xm.msg_h, ctx.undelete_id); memcpy((char *)array, (char *)xm.aUnDelete, sizeof(DDD_GID)*xm.nUnDelete); } return {nMsgs, std::move(msgs)}; } static void CmdMsgSend(DDD::DDDContext& context, const CmdmsgList& msgs) { for(const auto& msg : msgs) { /* schedule message for send */ LC_MsgSend(context, msg.msg_h); } } /****************************************************************************/ static int CmdMsgUnpack (DDD::DDDContext& context, LC_MSGHANDLE *theMsgs, int nRecvMsgs, XIDelCmd **itemsDC, int nDC) { auto& ctx = context.cmdmsgContext(); int i, k, jDC, iDC, pos, nPruned; int lenGidTab = 0; for(i=0; i unionGidTab(lenGidTab); for(i=0, pos=0; i0) { memcpy((char *) (unionGidTab.data()+pos), (char *) LC_GetPtr(xm, ctx.undelete_id), sizeof(DDD_GID) * len); pos += len; } } assert(pos==lenGidTab); /* sort GidTab */ std::sort(unionGidTab.begin(), unionGidTab.end()); #ifdef SUPPORT_RESENT_FLAG { int iLCO, nLCO = context.couplingContext().nCpls; std::vector localCplObjs = LocalCoupledObjectsList(context); /* set RESENT flag for objects which will receive another copy */ iLCO=0; for(k=0; khdr); while (khdr, 1); # if DebugCmdMsg<=1 Dune::dvverb << "PruneDelCmds. pruned " << gidDC << "\n"; # endif } else { itemsDC[jDC] = itemsDC[iDC]; jDC++; } } nPruned = nDC-jDC; # if DebugCmdMsg<=3 Dune::dvverb << "PruneDelCmds. nPruned=" << nPruned << "/" << nDC << "\n"; # endif return(nPruned); } /****************************************************************************/ static void CmdMsgDisplay(DDD::DDDContext& context, const char *comment, LC_MSGHANDLE xm) { auto& ctx = context.cmdmsgContext(); using std::setw; std::ostream& out = std::cout; DDD_GID *theGid; int proc = LC_MsgGetProc(xm); int lenGid = (int) LC_GetTableLen(xm, ctx.undelete_id); std::ostringstream prefixStream; prefixStream << setw(3) << context.me() << "-" << comment << setw(3) << proc << " "; const std::string& prefix = prefixStream.str(); /* get table addresses inside message */ theGid = (DDD_GID *) LC_GetPtr(xm, ctx.undelete_id); out << prefix << " 04 Gid.size=" << setw(5) << lenGid << "\n"; for(int i=0; i& arrayCO) { auto& ctx = context.cmdmsgContext(); /* accumulate messages (one for each partner) */ int nSendMsgs; CmdmsgList sendMsgs; std::tie(nSendMsgs, sendMsgs) = PrepareCmdMsgs(context, arrayCO); #if DebugCmdMsg>2 if (DDD_GetOption(context, OPT_DEBUG_XFERMESGS)==OPT_ON) #endif { for (const auto& msg : sendMsgs) CmdMsgDisplay(context, "PS", msg.msg_h); } /* init communication topology */ int nRecvMsgs = LC_Connect(context, ctx.cmdmsg_t); /* build and send messages */ CmdMsgSend(context, sendMsgs); /* communicate set of messages (send AND receive) */ LC_MSGHANDLE* recvMsgs = LC_Communicate(context); int nPruned = CmdMsgUnpack(context, recvMsgs, nRecvMsgs, itemsDC, nDC); /* for(int i=0; i=2 if (DDD_GetOption(context, OPT_DEBUG_XFERMESGS)==OPT_ON) #endif CmdMsgDisplay(context, "PR", recvMsgs[i]); } */ /* cleanup low-comm layer */ LC_Cleanup(context); return(nPruned); } /****************************************************************************/ END_UGDIM_NAMESPACE dune-uggrid-2.11.0+dfsg/dune/uggrid/parallel/ddd/xfer/cmds.cc000066400000000000000000001345741513616443000237110ustar00rootroot00000000000000// SPDX-FileCopyrightText: Copyright © DUNE Project contributors, see file LICENSE.md in module root // SPDX-License-Identifier: LGPL-2.1-or-later // -*- tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- // vi: set et ts=4 sw=2 sts=2: /****************************************************************************/ /* */ /* File: cmds.c */ /* */ /* Purpose: DDD-commands for Transfer Module */ /* */ /* Author: Klaus Birken */ /* Rechenzentrum Uni Stuttgart */ /* Universitaet Stuttgart */ /* Allmandring 30 */ /* 70550 Stuttgart */ /* internet: birken@rus.uni-stuttgart.de */ /* */ /* History: 931130 kb begin (xfer.c) */ /* 950321 kb added variable sized objects (XferCopyObjX) */ /* 950405 kb V1.3: extracted from xfer.c */ /* 960703 kb split XferInfo-list into ObjXfer and CplXfer */ /* 960718 kb introduced lowcomm-layer (sets of messages) */ /* */ /* Remarks: */ /* */ /****************************************************************************/ /****************************************************************************/ /* */ /* include files */ /* system include files */ /* application include files */ /* */ /****************************************************************************/ /* standard C library */ #include #include #include #include #include #include #include #include #include #include "xfer.h" USING_UG_NAMESPACE using namespace PPIF; START_UGDIM_NAMESPACE /****************************************************************************/ /* */ /* data structures */ /* */ /****************************************************************************/ /****************************************************************************/ /* */ /* definition of variables global to this source file only (static!) */ /* */ /****************************************************************************/ /****************************************************************************/ /* */ /* routines */ /* */ /****************************************************************************/ static int sort_XIDelCmd (const void *e1, const void *e2) { XIDelCmd *item1 = *((XIDelCmd **)e1); XIDelCmd *item2 = *((XIDelCmd **)e2); /* ascending GID is needed for ExecLocalXIDelCmds */ if (OBJ_GID(item1->hdr) < OBJ_GID(item2->hdr)) return(-1); if (OBJ_GID(item1->hdr) > OBJ_GID(item2->hdr)) return(1); return(0); } static int sort_XIDelObj (const void *e1, const void *e2) { XIDelObj *item1 = *((XIDelObj **)e1); XIDelObj *item2 = *((XIDelObj **)e2); /* ascending GID is needed for ExecLocalXIDelObjs */ if (item1->gid < item2->gid) return(-1); if (item1->gid > item2->gid) return(1); return(0); } static int sort_XINewCpl (const void *e1, const void *e2) { XINewCpl *item1 = *((XINewCpl **)e1); XINewCpl *item2 = *((XINewCpl **)e2); /* receiving processor */ if (item1->to < item2->to) return(-1); if (item1->to > item2->to) return(1); return(0); } static int sort_XIOldCpl (const void *e1, const void *e2) { XIOldCpl *item1 = *((XIOldCpl **)e1); XIOldCpl *item2 = *((XIOldCpl **)e2); DDD_GID gid1, gid2; /* receiving processor */ if (item1->to < item2->to) return(-1); if (item1->to > item2->to) return(1); /* ascending GID is needed for UnpackOldCplTab on receiver side */ gid1 = item1->te.gid; gid2 = item2->te.gid; if (gid1 < gid2) return(-1); if (gid1 > gid2) return(1); return(0); } static int sort_XIDelCpl (const void *e1, const void *e2) { XIDelCpl *item1 = *((XIDelCpl **)e1); XIDelCpl *item2 = *((XIDelCpl **)e2); DDD_GID gid1, gid2; /* receiving processor */ if (item1->to < item2->to) return(-1); if (item1->to > item2->to) return(1); /* ascending GID is needed by CplMsgUnpack on receiver side */ gid1 = item1->te.gid; gid2 = item2->te.gid; if (gid1 < gid2) return(-1); if (gid1 > gid2) return(1); return(0); } static int sort_XIModCpl (const void *e1, const void *e2) { XIModCpl *item1 = *((XIModCpl **)e1); XIModCpl *item2 = *((XIModCpl **)e2); DDD_GID gid1, gid2; /* receiving processor */ if (item1->to < item2->to) return(-1); if (item1->to > item2->to) return(1); /* ascending GID is needed by CplMsgUnpack on receiver side */ gid1 = item1->te.gid; gid2 = item2->te.gid; if (gid1 < gid2) return(-1); if (gid1 > gid2) return(1); /* sorting according to priority is not necessary anymore, equal items with different priorities will be sorted out according to PriorityMerge(). KB 970129 if (item1->te.prio < item2->te.prio) return(-1); if (item1->te.prio > item2->te.prio) return(1); */ return(0); } static int sort_XIAddCpl (const void *e1, const void *e2) { XIAddCpl *item1 = *((XIAddCpl **)e1); XIAddCpl *item2 = *((XIAddCpl **)e2); DDD_GID gid1, gid2; /* receiving processor */ if (item1->to < item2->to) return(-1); if (item1->to > item2->to) return(1); /* ascending GID is needed by CplMsgUnpack on receiver side */ gid1 = item1->te.gid; gid2 = item2->te.gid; if (gid1 < gid2) return(-1); if (gid1 > gid2) return(1); return(0); } /****************************************************************************/ /* eliminate double XIDelCmd-items. the items have been sorted according to key (gid), all in ascending order. if gid (i.e., hdr) is equal, the item is skipped. this implements rule XFER-D1. the number of valid items is returned. */ static int unify_XIDelCmd (const DDD::DDDContext&, XIDelCmd **i1, XIDelCmd **i2) { return ((*i1)->hdr != (*i2)->hdr); } /* eliminate double XIModCpl-items. merge priorities from similar XIModCpl-items. the items have been sorted according to key (to,gid), all in ascending order. if to or gid are different, then at least the first item is relevant. if both are equal, we merge priorities and get a new priority together with the information whether first item wins over second. if first item wins, it is switched into second position and the second item (now on first position) is rejected. if second item wins, first item is rejected. in both cases, we use the new priority for next comparison. */ static int unify_XIModCpl (const DDD::DDDContext& context, XIModCpl **i1p, XIModCpl **i2p) { XIModCpl *i1 = *i1p, *i2 = *i2p; DDD_PRIO newprio; int ret; /* if items are different in gid or dest, take first item */ if ((i1->to != i2->to) || (i1->te.gid != i2->te.gid)) return true; /* items have equal to and gid, we must check priority */ ret = PriorityMerge(&context.typeDefs()[i1->typ], i1->te.prio, i2->te.prio, &newprio); if (ret==PRIO_FIRST || ret==PRIO_UNKNOWN) { /* i1 is winner, take it, switch it into second position, signal rejection of i2 (now on first position). use new priority */ i1->te.prio = newprio; *i1p = i2; *i2p = i1; /* switch pointers */ } else { /* i1 lost, i2 is winner. throw away i1, but use new priority for next comparison */ i2->te.prio = newprio; } return false; } /* TODO remove this */ void GetSizesXIAddData (const DDD::DDDContext& context, int *, int *, size_t *, size_t *); /* compute and display memory resources used */ static void DisplayMemResources(const DDD::DDDContext& context) { const auto& ctx = context.xferContext(); int nSegms=0, nItems=0, nNodes=0; size_t memAllocated=0, memUsed=0; GetSizesXIAddData(context, &nSegms, &nItems, &memAllocated, &memUsed); if (nSegms>0) printf("XferEnd, XIAddData segms=%d items=%d allocated=%ld used=%ld\n", nSegms, nItems, (long)memAllocated, (long)memUsed); XICopyObjSet_GetResources(reinterpret_cast(ctx.setXICopyObj), &nSegms, &nItems, &nNodes, &memAllocated, &memUsed); if (nSegms>0) { printf("XferEnd, XICopyObj " "segms=%d items=%d nodes=%d allocated=%ld used=%ld\n", nSegms, nItems, nNodes, (long)memAllocated, (long)memUsed); } #ifdef XICOPYOBJ_DETAILED_RESOURCES /* this is a different version, split up into BTree and SegmList */ XICopyObjSegmList_GetResources(reinterpret_cast(ctx.setXICopyObj)->list, &nSegms, &nItems, &memAllocated, &memUsed); if (nSegms>0) printf("XferEnd, XICopyObj segms=%d items=%d allocated=%ld used=%ld\n", nSegms, nItems, (long)memAllocated, (long)memUsed); XICopyObjBTree_GetResources(reinterpret_cast(ctx.setXICopyObj)->tree, &nNodes, &nItems, &memAllocated, &memUsed); if (nItems>0) printf("XferEnd, XICopyObj nodes=%d items=%d allocated=%ld used=%ld\n", nNodes, nItems, (long)memAllocated, (long)memUsed); #endif XISetPrioSet_GetResources(reinterpret_cast(ctx.setXISetPrio), &nSegms, &nItems, &nNodes, &memAllocated, &memUsed); if (nSegms>0) { printf("XferEnd, XISetPrio " "segms=%d items=%d nodes=%d allocated=%ld used=%ld\n", nSegms, nItems, nNodes, (long)memAllocated, (long)memUsed); } #define SLL_GET_SIZES(T) do { \ GetSizes##T(context, &nSegms, &nItems, &memAllocated, &memUsed); \ if (nSegms>0) \ printf("XferEnd, " #T " segms=%d items=%d allocated=%ld used=%ld\n", \ nSegms, nItems, (long)memAllocated, (long)memUsed); \ } while(false) SLL_GET_SIZES(XIDelCmd); SLL_GET_SIZES(XIDelObj); SLL_GET_SIZES(XINewCpl); SLL_GET_SIZES(XIOldCpl); SLL_GET_SIZES(XIDelCpl); SLL_GET_SIZES(XIModCpl); SLL_GET_SIZES(XIAddCpl); #undef SLL_GET_SIZES } /****************************************************************************/ /* */ /* Function: DDD_XferEnd */ /* */ /****************************************************************************/ /** End of transfer phase. This function starts the object transfer process. After a call to this function (on all processors) all {\bf Transfer}-commands since the last call to \funk{XferBegin} are executed. This involves a set of local communications between the processors. */ DDD_RET DDD_XferEnd(DDD::DDDContext& context) { auto& ctx = context.xferContext(); const auto& me = context.me(); DDD_RET ret_code = DDD_RET_OK; XICopyObj **arrayNewOwners = NULL; int nNewOwners; XIDelCmd **arrayXIDelCmd = NULL; int remXIDelCmd, prunedXIDelCmd; XIDelObj **arrayXIDelObj = NULL; std::vector arrayXISetPrio; XINewCpl **arrayXINewCpl = NULL; XIOldCpl **arrayXIOldCpl = NULL; XIDelCpl **arrayXIDelCpl = NULL; int remXIDelCpl; XIModCpl **arrayXIModCpl = NULL; int remXIModCpl; XIAddCpl **arrayXIAddCpl = NULL; int obsolete, nRecvMsgs; XFERMSG *sendMsgs=NULL, *sm=NULL; LC_MSGHANDLE *recvMsgs = NULL; std::vector localCplObjs; size_t sendMem=0, recvMem=0; int DelCmds_were_pruned; STAT_SET_MODULE(DDD_MODULE_XFER); STAT_ZEROALL; const auto procs = context.procs(); const auto& nCpls = context.couplingContext().nCpls; /* step mode and check whether call to XferEnd is valid */ if (!XferStepMode(context, DDD::Xfer::XferMode::XMODE_CMDS)) DUNE_THROW(Dune::Exception, "DDD_XferEnd() aborted"); /* PREPARATION PHASE */ STAT_RESET; /* get sorted array of XICopyObj-items */ std::vector arrayXICopyObj = XICopyObjSet_GetArray(reinterpret_cast(ctx.setXICopyObj)); obsolete = XICopyObjSet_GetNDiscarded(reinterpret_cast(ctx.setXICopyObj)); /* debugging output, write all XICopyObjs to file if (XICopyObjSet_GetNItems(ctx.setXICopyObj)>0) { FILE *ff = fopen("xfer.dump","w"); XICopyObjSet_Print(ctx.setXICopyObj, 2, ff); fclose(ff); } */ /* (OPTIONAL) COMMUNICATION PHASE 0 */ if (DDD_GetOption(context, OPT_XFER_PRUNE_DELETE)==OPT_ON) { /* for each XferDelete-Cmd: if there exists at least one XferCopy-cmd with destination=me, then the XferDelete-Cmd is discarded. NOTE: the priorities behave like in the specification, i.e., incoming objects with lower priority than the local (deleted) object won't be rejected. */ /* create sorted array of XIDelCmd-items, and unify it */ /* in case of pruning set to OPT_OFF, this sorting/unifying step is done lateron. */ arrayXIDelCmd = SortedArrayXIDelCmd(context, sort_XIDelCmd); if (arrayXIDelCmd==NULL && ctx.nXIDelCmd>0) { Dune::dwarn << "out of memory in DDD_XferEnd(), giving up.\n"; ret_code = DDD_RET_ERROR_NOMEM; LC_Abort(context, EXCEPTION_LOWCOMM_USER); goto exit; } remXIDelCmd = UnifyXIDelCmd(context, arrayXIDelCmd, unify_XIDelCmd); obsolete += (ctx.nXIDelCmd-remXIDelCmd); /* do communication and actual pruning */ prunedXIDelCmd = PruneXIDelCmd(context, arrayXIDelCmd, remXIDelCmd, arrayXICopyObj); obsolete += prunedXIDelCmd; remXIDelCmd -= prunedXIDelCmd; DelCmds_were_pruned = true; } else { DelCmds_were_pruned = false; } /* if (nXIDelCmd>0||remXIDelCmd>0||prunedXIDelCmd>0) printf("%4d: XIDelCmd. all=%d rem=%d pruned=%d\n", me, nXIDelCmd, remXIDelCmd, prunedXIDelCmd); */ /* COMMUNICATION PHASE 1 */ STAT_RESET; /* send Cpl-info about new objects to owners of other local copies */ arrayNewOwners = CplClosureEstimate(context, arrayXICopyObj, &nNewOwners); if (nNewOwners>0 && arrayNewOwners==NULL) { Dune::dwarn << "out of memory in DDD_XferEnd(), giving up.\n"; ret_code = DDD_RET_ERROR_NOMEM; LC_Abort(context, EXCEPTION_LOWCOMM_USER); goto exit; } /* create sorted array of XINewCpl- and XIOldCpl-items. TODO. if efficiency is a problem here, use b-tree or similar data structure to improve performance. */ arrayXINewCpl = SortedArrayXINewCpl(context, sort_XINewCpl); if (arrayXINewCpl==NULL && ctx.nXINewCpl>0) { Dune::dwarn << "out of memory in DDD_XferEnd(), giving up.\n"; ret_code = DDD_RET_ERROR_NOMEM; LC_Abort(context, EXCEPTION_LOWCOMM_USER); goto exit; } arrayXIOldCpl = SortedArrayXIOldCpl(context, sort_XIOldCpl); if (arrayXIOldCpl==NULL && ctx.nXIOldCpl>0) { Dune::dwarn << "out of memory in DDD_XferEnd(), giving up.\n"; ret_code = DDD_RET_ERROR_NOMEM; LC_Abort(context, EXCEPTION_LOWCOMM_USER); goto exit; } /* prepare msgs for objects and XINewCpl-items */ PrepareObjMsgs(context, arrayXICopyObj, arrayXINewCpl, ctx.nXINewCpl, arrayXIOldCpl, ctx.nXIOldCpl, &sendMsgs, &sendMem); /* DisplayMemResources(context); */ /* init communication topology */ nRecvMsgs = LC_Connect(context, ctx.objmsg_t); STAT_TIMER(T_XFER_PREP_MSGS); if (nRecvMsgs<0) { /* some processor raised an exception */ if (nRecvMsgs==EXCEPTION_LOWCOMM_CONNECT) { /* the dangerous exception: it occurred only locally, the other procs doesn't know about it */ Dune::dwarn << "local exception during LC_Connect() in DDD_XferEnd(), giving up.\n"; /* in this state the local processor hasn't initiated any send or receive calls. however, there may be (and almost ever: there will be!) other processors which already initiated their receive calls. This is a tragic situation without a possibility to escape. */ HARD_EXIT; } else { /* all other exceptions are known globally, shutdown safely */ Dune::dwarn << "error during LC_Connect() in DDD_XferEnd(), giving up.\n"; ret_code = DDD_RET_ERROR_UNKNOWN; goto exit; } } /*** all exceptional errors which occur from here down to the point of no return (some lines below) could be cleaned up locally, but the communication situation cannot be cleaned up with the current functionality of PPIF (i.e., discarding of pending communication calls). therefore, the local processor will be able to shutdown safely, but other processors might hang. ***/ STAT_RESET; /* build obj msgs on sender side and start send */ if (! IS_OK(XferPackMsgs(context, sendMsgs))) { Dune::dwarn << "error during message packing in DDD_XferEnd(), giving up.\n"; LC_Cleanup(context); ret_code = DDD_RET_ERROR_UNKNOWN; goto exit; } STAT_TIMER(T_XFER_PACK_SEND); /* now messages are in the net, use spare time */ /* create sorted array of XISetPrio-items, and unify it */ STAT_RESET; arrayXISetPrio = XISetPrioSet_GetArray(reinterpret_cast(ctx.setXISetPrio)); obsolete += XISetPrioSet_GetNDiscarded(reinterpret_cast(ctx.setXISetPrio)); if (!DelCmds_were_pruned) { /* create sorted array of XIDelCmd-items, and unify it */ arrayXIDelCmd = SortedArrayXIDelCmd(context, sort_XIDelCmd); if (arrayXIDelCmd==NULL && ctx.nXIDelCmd>0) { Dune::dwarn << "out of memory in DDD_XferEnd(), giving up.\n"; LC_Cleanup(context); ret_code = DDD_RET_ERROR_NOMEM; goto exit; } remXIDelCmd = UnifyXIDelCmd(context, arrayXIDelCmd, unify_XIDelCmd); obsolete += (ctx.nXIDelCmd-remXIDelCmd); } /*** this is the point of no return. the next function manipulates the data structure irreversibly. ***/ /* execute local commands */ /* NOTE: messages have been build before in order to allow deletion of objects. */ ExecLocalXIDelCmd(context, arrayXIDelCmd, remXIDelCmd); /* now all XIDelObj-items have been created. these come from: 1. application->DDD_XferDeleteObj->XIDelCmd->HdrDestructor-> ->XferRegisterDelete 2. HANDLER_DELETE->HdrDestructor (for dependent object)-> ->XferRegisterDelete */ /* create sorted array of XIDelObj-items */ arrayXIDelObj = SortedArrayXIDelObj(context, sort_XIDelObj); ExecLocalXISetPrio(context, arrayXISetPrio, arrayXIDelObj, ctx.nXIDelObj, arrayNewOwners, nNewOwners); ExecLocalXIDelObj(context, arrayXIDelObj, ctx.nXIDelObj, arrayNewOwners, nNewOwners); if (obsolete>0) { if (DDD_GetOption(context, OPT_INFO_XFER) & XFER_SHOW_OBSOLETE) { int all = ctx.nXIDelObj+ XISetPrioSet_GetNItems(reinterpret_cast(ctx.setXISetPrio))+ XICopyObjSet_GetNItems(reinterpret_cast(ctx.setXICopyObj)); using std::setw; Dune::dwarn << "DDD MESG [" << setw(3) << me << "]: " << setw(4) << obsolete << " from " << setw(4) << all << " xfer-cmds obsolete.\n"; } } STAT_TIMER(T_XFER_WHILE_COMM); /* nothing more to do until incoming messages arrive */ /* display information about send-messages on lowcomm-level */ if (DDD_GetOption(context, OPT_INFO_XFER) & XFER_SHOW_MSGSALL) { DDD_SyncAll(context); if (context.isMaster()) Dune::dwarn << "DDD XFER_SHOW_MSGSALL: ObjMsg.Send\n"; LC_PrintSendMsgs(context); } /* wait for communication-completion (send AND receive) */ STAT_RESET; recvMsgs = LC_Communicate(context); STAT_TIMER(T_XFER_WAIT_RECV); /* display information about message buffer sizes */ if (DDD_GetOption(context, OPT_INFO_XFER) & XFER_SHOW_MEMUSAGE) { int k; /* sum up sizes of receive mesg buffers */ for(k=0; k0 && arrayXIDelCpl[remXIDelCpl-1]->to == procs) remXIDelCpl--; remXIModCpl = UnifyXIModCpl(context, arrayXIModCpl, unify_XIModCpl); STAT_TIMER(T_XFER_PREP_CPL); /* printf("%4d: %d XIDelCpls obsolete\n", me, nXIDelCpl-remXIDelCpl); */ /* COMMUNICATION PHASE 2 */ STAT_RESET; CommunicateCplMsgs(context, arrayXIDelCpl, remXIDelCpl, arrayXIModCpl, remXIModCpl, arrayXIAddCpl, ctx.nXIAddCpl, localCplObjs.data(), nCpls); STAT_TIMER(T_XFER_CPLMSG); /* CLEAN-UP PHASE 2 */ exit: /* free temporary storage */ XICopyObjSet_Reset(reinterpret_cast(ctx.setXICopyObj)); if (arrayNewOwners!=NULL) OO_Free (arrayNewOwners /*,0*/); FreeAllXIAddData(context); XISetPrioSet_Reset(reinterpret_cast(ctx.setXISetPrio)); if (arrayXIDelCmd!=NULL) OO_Free (arrayXIDelCmd /*,0*/); FreeAllXIDelCmd(context); if (arrayXIDelObj!=NULL) OO_Free (arrayXIDelObj /*,0*/); FreeAllXIDelObj(context); if (arrayXINewCpl!=NULL) OO_Free (arrayXINewCpl /*,0*/); FreeAllXINewCpl(context); if (arrayXIOldCpl!=NULL) OO_Free (arrayXIOldCpl /*,0*/); FreeAllXIOldCpl(context); if (arrayXIDelCpl!=NULL) OO_Free (arrayXIDelCpl /*,0*/); FreeAllXIDelCpl(context); if (arrayXIModCpl!=NULL) OO_Free (arrayXIModCpl /*,0*/); FreeAllXIModCpl(context); if (arrayXIAddCpl!=NULL) OO_Free (arrayXIAddCpl /*,0*/); FreeAllXIAddCpl(context); for(; sendMsgs!=NULL; sendMsgs=sm) { sm = sendMsgs->next; OO_Free (sendMsgs /*,0*/); } # if DebugXfer<=4 Dune::dverb << "XferEnd, before IFAllFromScratch().\n"; # endif if (ret_code==DDD_RET_OK) { /* re-create all interfaces and step XMODE */ STAT_RESET; IFAllFromScratch(context); STAT_TIMER(T_XFER_BUILD_IF); } XferStepMode(context, DDD::Xfer::XferMode::XMODE_BUSY); return(ret_code); } /* ablage fuer debug-ausgabe # if DebugXfer<=4 sprintf(cBuffer,"%4d: XferEnd, after XferDeleteObjects(): " "send=%d recv=%d\n", me, nSendMsgs, nRecvMsgs); DDD_PrintDebug(cBuffer); # endif */ /****************************************************************************/ /* */ /* Function: DDD_XferPrioChange */ /* */ /****************************************************************************/ /** Consistent change of a local object's priority during DDD Transfer. Local objects which are part of a distributed object must notify other copies about local priority changes. This is accomplished by issuing \funk{XferPrioChange}-commands during the transfer phase; DDD will send appropriate messages to the owner processors of the other copies. This function is regarded as a {\bf Transfer}-operation due to its influence on DDD management information on neighbouring processors. Therefore the function has to be issued between a starting \funk{XferBegin} and a final \funk{XferEnd} call. @param hdr DDD local object whose priority should be changed. @param prio new priority of that local object. */ void DDD_XferPrioChange (DDD::DDDContext& context, DDD_HDR hdr, DDD_PRIO prio) { auto& ctx = context.xferContext(); XISetPrio *xi = XISetPrioSet_NewItem(reinterpret_cast(ctx.setXISetPrio)); xi->hdr = hdr; xi->gid = OBJ_GID(hdr); xi->prio = prio; if (! XISetPrioSet_ItemOK(reinterpret_cast(ctx.setXISetPrio))) return; # if DebugXfer<=2 Dune::dvverb << "DDD_XferPrioChange " << OBJ_GID(hdr) << ", prio=" << prio << "\n"; # endif } static void XferInitCopyInfo (DDD::DDDContext& context, DDD_HDR hdr, TYPE_DESC *desc, size_t size, DDD_PROC dest, DDD_PRIO prio) { auto& ctx = context.xferContext(); if (!ddd_XferActive(context)) DUNE_THROW(Dune::Exception, "Missing DDD_XferBegin()"); if (dest >= context.procs()) DUNE_THROW(Dune::Exception, "cannot transfer " << OBJ_GID(hdr) << " to processor " << dest << " (procs=" << context.procs() << ")"); if (prio>=MAX_PRIO) DUNE_THROW(Dune::Exception, "priority must be less than " << MAX_PRIO << " (prio=" << prio << ")"); if (dest==context.me()) { /* XFER-C4: XferCopyObj degrades to SetPrio command */ XISetPrio *xi = XISetPrioSet_NewItem(reinterpret_cast(ctx.setXISetPrio)); xi->hdr = hdr; xi->gid = OBJ_GID(hdr); xi->prio = prio; if (! XISetPrioSet_ItemOK(reinterpret_cast(ctx.setXISetPrio))) { /* item has been inserted already, don't store it twice. */ /* even don't call XFERCOPY-handler, this is a real API change! */ /* xi->prio will be set to PRIO_INVALID if the priority of the previously existing XICopyObj-item wins the PriorityMerge in the corresponding Compare function (see supp.c). Then, we in fact won't need calling the XFERCOPY-handler here, because it doesn't give new information. If xi->prio is not PRIO_INVALID, then the XICopyObj-item xi wins the merge and the XFERCOPY-handler has to be called a second time, now with a higher priority. */ if (xi->prio==PRIO_INVALID) return; } /* although XferCopyObj degrades to SetPrio, call XFERCOPY-handler! */ /* reset for eventual AddData-calls during handler execution */ ctx.theXIAddData = nullptr; /* call application handler for xfer of dependent objects */ if (desc->handlerXFERCOPY) { DDD_OBJ obj = HDR2OBJ(hdr,desc); desc->handlerXFERCOPY(context, obj, dest, prio); } /* theXIAddData might be changed during handler execution */ ctx.theXIAddData = nullptr; } else { /* this is a real transfer to remote proc */ XICopyObj *xi = XICopyObjSet_NewItem(reinterpret_cast(ctx.setXICopyObj)); xi->hdr = hdr; xi->gid = OBJ_GID(hdr); xi->dest = dest; xi->prio = prio; if (! XICopyObjSet_ItemOK(reinterpret_cast(ctx.setXICopyObj))) { /* item has been inserted already, don't store it twice. */ /* even don't call XFERCOPY-handler, this is a real API change! */ /* xi->prio will be set to PRIO_INVALID if the priority of the previously existing XICopyObj-item wins the PriorityMerge in the corresponding Compare function (see supp.c). Then, we in fact won't need calling the XFERCOPY-handler here, because it doesn't give new information. If xi->prio is not PRIO_INVALID, then the XICopyObj-item xi wins the merge and the XFERCOPY-handler has to be called a second time, now with a higher priority. */ if (xi->prio==PRIO_INVALID) return; } xi->size = size; xi->add = NULL; xi->addLen = 0; /* set XferAddInfo for evtl AddData-calls during handler execution */ ctx.theXIAddData = xi; /* call application handler for xfer of dependent objects */ if (desc->handlerXFERCOPY) { DDD_OBJ obj = HDR2OBJ(hdr,desc); desc->handlerXFERCOPY(context, obj, dest, prio); } /* theXIAddData might be changed during handler execution */ ctx.theXIAddData = xi; } } /****************************************************************************/ /* */ /* Function: DDD_XferCopyObj */ /* */ /****************************************************************************/ /** Transfer-command for copying a local DDD object to another processor. After an initial call to \funk{XferBegin}, this function creates a copy of one local DDD object on another processor with a certain priority. The necessary actions (packing/unpacking of object data, message transfer) are executed via the final call to \funk{XferEnd}; therefore a whole set of {\bf Transfer}-operations is accumulated. Caution: As the original object data is not copied throughout this call due to efficiency reasons (transferring a large number of objects would result in a huge amount of memory copy operations), the object may not be changed or deleted until the actual transfer has happened. Otherwise the changes will be sent, too. Two different mechanisms allow the transfer of data depending on the stated object: \begin{itemize} \item Right after the function \funk{XferCopyObj} has been called, the optional handler #HANDLER_XFERCOPY# is executed by DDD. Basically this mechanism allows the transfer of dependent DDD objects (or: hierarchies of objects), although arbitrary actions may occur inside the handler. No relationship between the {\em primary} object and the additional objects can be expressed, as many different destination processors might be involved. % \item Via an arbitrary number of additional calls to \funk{XferAddData} arrays of {\em data objects} (i.e.~without the usual DDD object header) may be sent. Using this mechanism the data objects are strongly linked to the {\em primary} object; all data objects are transferred to the same destination processor. \end{itemize} After the object copy has been established on the destination processor, first the optional handler #HANDLER_LDATACONSTRUCTOR# is called to update the LDATA parts of that object (e.g.~locally linked lists). Afterwards the optional handler #HANDLER_OBJMKCONS# is called to establish consistency for that object (e.g.~backward references on the new object copy). For handlers related to function \funk{XferAddData} refer to its description. @param hdr DDD local object which has to be copied. @param proc destination processor which will receive the object copy. @param prio DDD priority of new object copy. */ void DDD_XferCopyObj (DDD::DDDContext& context, DDD_HDR hdr, DDD_PROC proc, DDD_PRIO prio) { TYPE_DESC *desc = &context.typeDefs()[OBJ_TYPE(hdr)]; # if DebugXfer<=2 Dune::dvverb << "DDD_XferCopyObj " << OBJ_GID(hdr) << ", proc=" << proc << " prio=" << prio << "\n"; # endif XferInitCopyInfo(context, hdr, desc, desc->size, proc, prio); } /****************************************************************************/ /* */ /* Function: DDD_XferCopyObjX */ /* */ /****************************************************************************/ /** Transfer-command for objects of varying sizes. This function is an extension of \funk{XferCopyObj}. For objects with same DDD type but with variable size in memory, one can give the real size as forth parameter to \funk{XferCopyObjX}. The DDD Transfer module will use that size value instead of using the size computed in \funk{TypeDefine} after the definition of the object's DDD type. @param hdr DDD local object which has to be copied. @param proc destination processor which will receive the object copy. @param prio DDD priority of new object copy. @param size real size of local object. */ void DDD_XferCopyObjX (DDD::DDDContext& context, DDD_HDR hdr, DDD_PROC proc, DDD_PRIO prio, size_t size) { TYPE_DESC *desc = &context.typeDefs()[OBJ_TYPE(hdr)]; # if DebugXfer<=2 Dune::dvverb << "DDD_XferCopyObjX " << OBJ_GID(hdr) << ", proc=" << proc << " prio=" << prio << " size=" << size << "\n"; # endif if ((desc->size!=size) && (DDD_GetOption(context, OPT_WARNING_VARSIZE_OBJ)==OPT_ON)) Dune::dwarn << "object size differs from declared size in DDD_XferCopyObjX\n"; if ((desc->size>size) && (DDD_GetOption(context, OPT_WARNING_SMALLSIZE)==OPT_ON)) Dune::dwarn << "object size smaller than declared size in DDD_XferCopyObjX\n"; XferInitCopyInfo(context, hdr, desc, size, proc, prio); } /****************************************************************************/ /* */ /* Function: DDD_XferAddData */ /* */ /****************************************************************************/ /** Transfer array of additional data objects with a DDD local object. This function transfers an array of additional data objects corresponding to one DDD object to the same destination processor. Therefore the latest call to \funk{XferCopyObj} defines the {\em primary} object and the destination. An arbitrary number of \funk{XferAddData}-calls may be issued to transfer various data object arrays at once. This serves as a mechanism to send object references which cannot be handled by the native DDD pointer conversion technique. Just before the actual {\bf Transfer}-operation is executed, the (optional) handler #HANDLER_XFERGATHER# will be called to fill the data object array into some reserved storage space. After the {\bf Xfer}-operation the handler #HANDLER_XFERSCATTER# is called on the receiving processor to rebuild the data objects. As the data objects had to be registered and equipped with a usual {\em type\_id} (as with the DDD objects), the standard DDD pointer conversion will also take place for the data objects. @param cnt number of data objects in array (i.e.~array length). @param typ DDD type of data objects. All data objects inside one array should have the same object type. This object type is defined by registering the object structure via \funk{TypeDefine} as usual, but without including the DDD object header. */ void DDD_XferAddData (DDD::DDDContext& context, int cnt, DDD_TYPE typ) { auto& ctx = context.xferContext(); XFERADDDATA *xa; # if DebugXfer<=2 Dune::dvverb << "DDD_XferAddData cnt=" << cnt << " typ=" << typ << "\n"; # endif if (not ctx.theXIAddData) return; xa = NewXIAddData(context); if (xa==NULL) throw std::bad_alloc(); xa->addCnt = cnt; xa->addTyp = typ; xa->sizes = NULL; if (typDDD_USER_DATA_MAX) { /* normal dependent object */ const TYPE_DESC& descDepTyp = context.typeDefs()[typ]; xa->addLen = CEIL(descDepTyp.size) * cnt; xa->addNPointers = (descDepTyp.nPointers) * cnt; } else { /* stream of bytes, since V1.2 */ /* many streams, since V1.7.8 */ xa->addLen = CEIL(cnt); xa->addNPointers = 0; } ctx.theXIAddData->addLen += xa->addLen; } /****************************************************************************/ /* */ /* Function: DDD_XferAddDataX */ /* */ /****************************************************************************/ /** Transfer array of additional, variable-sized data objects. \todo{not documented yet.} */ void DDD_XferAddDataX (DDD::DDDContext& context, int cnt, DDD_TYPE typ, size_t *sizes) { auto& ctx = context.xferContext(); XFERADDDATA *xa; # if DebugXfer<=2 Dune::dvverb << "DDD_XferAddData cnt=" << cnt << " typ=" << typ << "\n"; # endif if (not ctx.theXIAddData) return; xa = NewXIAddData(context); if (xa==NULL) HARD_EXIT; xa->addCnt = cnt; xa->addTyp = typ; if (typDDD_USER_DATA_MAX) { /* copy sizes array */ xa->sizes = AddDataAllocSizes(context, cnt); memcpy(xa->sizes, sizes, sizeof(int)*cnt); /* normal dependent object */ const TYPE_DESC& descDepTyp = context.typeDefs()[typ]; xa->addLen = 0; for (int i = 0; i < cnt; i++) { xa->addLen += CEIL(sizes[i]); } xa->addNPointers = descDepTyp.nPointers * cnt; } else { /* stream of bytes, since V1.2 */ /* many streams, since V1.7.8 */ xa->addLen = CEIL(cnt); xa->addNPointers = 0; } ctx.theXIAddData->addLen += xa->addLen; } /** Tell application if additional data will be sent. If the application issues a \funk{XferCopyObj} command with the local processor as the destination processor, no object copy will be created. Therefore, also additional data objects will not be sent and the corresponding #XFER_GATHER#/#XFER_SCATTER# handlers will not be called. This function returns a boolean value indicating whether the last \funk{XferCopyObj}-command will need the specification of additional data objects. The application program may use this function in order to avoid unnecessary work, \eg, for counting the number of additional data objects. @return #true# if additional data objects will be gathered, sent and scattered; #false# otherwise. */ bool DDD_XferWithAddData(const DDD::DDDContext& context) { /* if theXIAddData==NULL, the XferAddData-functions will do nothing -> the Gather/Scatter-handlers will not be called. */ return context.xferContext().theXIAddData != nullptr; } /****************************************************************************/ /* */ /* Function: DDD_XferDeleteObj */ /* */ /****************************************************************************/ /** Transfer-command for deleting a local DDD object. This function is regarded as a {\bf Transfer}-operation due to its influence on DDD management information on neighbouring processors. Therefore the function has to be issued between a starting \funk{XferBegin} and a final \funk{XferEnd} call. During the actual {\bf Transfer}-operation all data corresponding to that object and the object memory itself will be deleted. @param hdr DDD local object which has to be deleted. */ void DDD_XferDeleteObj (DDD::DDDContext& context, DDD_HDR hdr) { TYPE_DESC *desc = &context.typeDefs()[OBJ_TYPE(hdr)]; XIDelCmd *dc = NewXIDelCmd(context); if (dc==NULL) HARD_EXIT; dc->hdr = hdr; # if DebugXfer<=2 Dune::dvverb << "DDD_XferDeleteObj " << OBJ_GID(hdr) << "\n"; # endif /* call application handler for deletion of dependent objects */ if (desc->handlerXFERDELETE!=NULL) { desc->handlerXFERDELETE(context, HDR2OBJ(hdr,desc)); } } /****************************************************************************/ /* */ /* Function: DDD_XferBegin */ /* */ /****************************************************************************/ /** Starts transfer phase. A call to this function establishes a global transfer operation. It should be issued on all processors. After this call an arbitrary series of {\bf Xfer}-commands may be issued. The global transfer operation is carried out via a \funk{XferEnd} call on each processor. */ void DDD_XferBegin(DDD::DDDContext& context) { auto& ctx = context.xferContext(); ctx.theXIAddData = nullptr; /* step mode and check whether call to XferBegin is valid */ if (!XferStepMode(context, DDD::Xfer::XferMode::XMODE_IDLE)) DUNE_THROW(Dune::Exception, "DDD_XferBegin() aborted"); } /****************************************************************************/ /* */ /* Function: DDD_XferIsPrunedDelete */ /* */ /****************************************************************************/ /** Returns information about pruned \funk{XferDeleteObj} command. If a \funk{XferDeleteObj} command has been pruned (i.e., option #OPT_XFER_PRUNE_DELETE# is set to #OPT_ON# and another processor issued a \funk{XferCopyObj}, command which sends an object copy to the local processor), then this function will return #XFER_PRUNED_TRUE#, otherwise it returns #XFER_PRUNED_FALSE#. If an error condition occurs (e.g., when it is called at the wrong time), the function returns #XFER_PRUNED_ERROR#. @param hdr DDD local object which has to be deleted. @return one of #XFER_PRUNED_xxx# */ int DDD_XferIsPrunedDelete(const DDD::DDDContext& context, DDD_HDR hdr) { if (XferMode(context) != DDD::Xfer::XferMode::XMODE_BUSY) { return(XFER_PRUNED_ERROR); } if (OBJ_PRUNED(hdr)) return(XFER_PRUNED_TRUE); return(XFER_PRUNED_FALSE); } /****************************************************************************/ /* */ /* Function: DDD_XferObjIsResent */ /* */ /****************************************************************************/ #ifdef SUPPORT_RESENT_FLAG /** Returns if an object will receive an additional copy. If another processor issued a \funk{XferCopyObj} in order to send a further copy of the given local object to the local processor, this function will return #XFER_RESENT_TRUE#. Otherwise this function will return #XFER_RESENT_FALSE#. If an error condition occurs (e.g., when it is called at the wrong time), the function returns #XFER_RESENT_ERROR#. This function will only work with option #OPT_XFER_PRUNE_DELETE# set to #OPT_ON#. Otherwise, there will be no kind of communication to supply this information. @param hdr DDD local object which has to be deleted. @return one of #XFER_RESENT_xxx# */ int DDD_XferObjIsResent(const DDD::DDDContext& context, DDD_HDR hdr) { if (XferMode(context) != DDD::Xfer::XferMode::XMODE_BUSY) { return(XFER_RESENT_ERROR); } if (DDD_GetOption(context, OPT_XFER_PRUNE_DELETE)==OPT_OFF) { return(XFER_RESENT_ERROR); } if (OBJ_RESENT(hdr)) return(XFER_RESENT_TRUE); return(XFER_RESENT_FALSE); } #endif /* SUPPORT_RESENT_FLAG */ END_UGDIM_NAMESPACE dune-uggrid-2.11.0+dfsg/dune/uggrid/parallel/ddd/xfer/cplmsg.cc000066400000000000000000000321311513616443000242320ustar00rootroot00000000000000// SPDX-FileCopyrightText: Copyright © DUNE Project contributors, see file LICENSE.md in module root // SPDX-License-Identifier: LGPL-2.1-or-later // -*- tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- // vi: set et ts=4 sw=2 sts=2: /****************************************************************************/ /* */ /* File: cplmsg.c */ /* */ /* Purpose: ddd object transfer: */ /* last messages in order to create coupling consistency. */ /* */ /* Author: Klaus Birken */ /* Rechenzentrum Uni Stuttgart */ /* Universitaet Stuttgart */ /* Allmandring 30 */ /* 70550 Stuttgart */ /* internet: birken@rus.uni-stuttgart.de */ /* */ /* History: 960712 kb created */ /* 960718 kb introduced lowcomm-layer (sets of messages) */ /* */ /* Remarks: */ /* */ /****************************************************************************/ /****************************************************************************/ /* */ /* include files */ /* system include files */ /* application include files */ /* */ /****************************************************************************/ /* standard C library */ #include #include #include #include #include #include #include #include #include #include #include "xfer.h" USING_UG_NAMESPACE using namespace PPIF; START_UGDIM_NAMESPACE /****************************************************************************/ /* */ /* data structures */ /* */ /****************************************************************************/ /* CPLMSG: complete description of message on sender side */ struct CPLMSG { DDD_PROC proc; XIDelCpl **xferDelCpl = nullptr; int nDelCpl = 0; XIModCpl **xferModCpl = nullptr; int nModCpl = 0; XIAddCpl **xferAddCpl = nullptr; int nAddCpl = 0; /* lowcomm message handle */ LC_MSGHANDLE msg_h; CPLMSG(DDD_PROC dest) : proc(dest) {} }; using CplmsgList = std::forward_list; /****************************************************************************/ /* */ /* routines */ /* */ /****************************************************************************/ void CplMsgInit(DDD::DDDContext& context) { auto& ctx = context.cplmsgContext(); ctx.cplmsg_t = LC_NewMsgType(context, "CplMsg"); ctx.delcpl_id = LC_NewMsgTable("DelCpl", ctx.cplmsg_t, sizeof(TEDelCpl)); ctx.modcpl_id = LC_NewMsgTable("ModCpl", ctx.cplmsg_t, sizeof(TEModCpl)); ctx.addcpl_id = LC_NewMsgTable("AddCpl", ctx.cplmsg_t, sizeof(TEAddCpl)); } void CplMsgExit(DDD::DDDContext&) {} /****************************************************************************/ static std::pair PrepareCplMsgs ( DDD::DDDContext& context, XIDelCpl **itemsDC, int nDC, XIModCpl **itemsMC, int nMC, XIAddCpl **itemsAC, int nAC) { auto& ctx = context.cplmsgContext(); const auto procs = context.procs(); # if DebugCplMsg<=3 Dune::dverb << "PrepareCplMsgs, nXIDelCpl=" << nDC << " nXIModCpl=" << nMC << " nXIAddCpl=" << nAC << "\n"; # endif CplmsgList msgs; int nMsgs = 0; auto msgForProc = [&](DDD_PROC dest) -> CPLMSG& { if (msgs.empty() or msgs.front().proc != dest) { msgs.emplace_front(dest); ++nMsgs; } return msgs.front(); }; /* run through all tables simultaneously, each time a new proc-nr is encountered in one of these tables, create a new CPLMSG item. (the lists have been sorted according to proc-nr previously.) */ int iDC=0, iMC=0, iAC=0; while (iDCto : procs; DDD_PROC pMC = (iMCto : procs; DDD_PROC pAC = (iACto : procs; /* check DelCpl-items */ if (pDC<=pMC && pDC<=pAC && pDCto==pDC; i++) ; xm.nDelCpl = i-iDC; iDC = i; } /* check ModCpl-items */ if (pMC<=pDC && pMC<=pAC && pMCto==pMC; i++) ; xm.nModCpl = i-iMC; iMC = i; } /* check AddCpl-items */ if (pAC<=pDC && pAC<=pMC && pACto==pAC; i++) ; xm.nAddCpl = i-iAC; iAC = i; } if (pDC==procs) iDC = nDC; if (pMC==procs) iMC = nMC; if (pAC==procs) iAC = nAC; } /* initiate send messages */ for(auto& xm : msgs) { /* create new send message */ xm.msg_h = LC_NewSendMsg(context, ctx.cplmsg_t, xm.proc); /* init tables inside message */ LC_SetTableSize(xm.msg_h, ctx.delcpl_id, xm.nDelCpl); LC_SetTableSize(xm.msg_h, ctx.modcpl_id, xm.nModCpl); LC_SetTableSize(xm.msg_h, ctx.addcpl_id, xm.nAddCpl); /* prepare message for sending away */ LC_MsgPrepareSend(context, xm.msg_h); } return {nMsgs, std::move(msgs)}; } static void CplMsgSend(DDD::DDDContext& context, const CplmsgList& msgs) { auto& ctx = context.cplmsgContext(); for(const auto& msg : msgs) { TEDelCpl *arrayDC = (TEDelCpl *)LC_GetPtr(msg.msg_h, ctx.delcpl_id); TEModCpl *arrayMC = (TEModCpl *)LC_GetPtr(msg.msg_h, ctx.modcpl_id); TEAddCpl *arrayAC = (TEAddCpl *)LC_GetPtr(msg.msg_h, ctx.addcpl_id); /* copy data into message */ for(int i=0; i < msg.nDelCpl; i++) { arrayDC[i] = msg.xferDelCpl[i]->te; } for(int i=0; i < msg.nModCpl; i++) { arrayMC[i] = msg.xferModCpl[i]->te; } for(int i=0; i < msg.nAddCpl; i++) { arrayAC[i] = msg.xferAddCpl[i]->te; } /* schedule message for send */ LC_MsgSend(context, msg.msg_h); } } /****************************************************************************/ static void CplMsgUnpackSingle (DDD::DDDContext& context, LC_MSGHANDLE xm, DDD_HDR *localCplObjs, int nLCO) { auto& ctx = context.cplmsgContext(); TEDelCpl *theDelCpl; TEModCpl *theModCpl; TEAddCpl *theAddCpl; int i, j, nDelCpl, nModCpl, nAddCpl; DDD_PROC proc = LC_MsgGetProc(xm); /* get number and address of del-items */ nDelCpl = (int) LC_GetTableLen(xm, ctx.delcpl_id); nModCpl = (int) LC_GetTableLen(xm, ctx.modcpl_id); nAddCpl = (int) LC_GetTableLen(xm, ctx.addcpl_id); theDelCpl = (TEDelCpl *) LC_GetPtr(xm, ctx.delcpl_id); theModCpl = (TEModCpl *) LC_GetPtr(xm, ctx.modcpl_id); theAddCpl = (TEAddCpl *) LC_GetPtr(xm, ctx.addcpl_id); /* modify couplings according to mod-list */ for(i=0, j=0; i2 if (DDD_GetOption(context, OPT_DEBUG_XFERMESGS)==OPT_ON) #endif { for (const auto& msg : sendMsgs) CplMsgDisplay(context, "CS", msg.msg_h); } /* display information about send-messages on lowcomm-level */ if (DDD_GetOption(context, OPT_INFO_XFER) & XFER_SHOW_MSGSALL) { DDD_SyncAll(context); if (context.isMaster()) Dune::dwarn << "DDD XFER_SHOW_MSGSALL: CplMsg.Send\n"; LC_PrintSendMsgs(context); } /* communicate set of messages (send AND receive) */ LC_MSGHANDLE* recvMsgs = LC_Communicate(context); /* display information about recv-messages on lowcomm-level */ if (DDD_GetOption(context, OPT_INFO_XFER) & XFER_SHOW_MSGSALL) { DDD_SyncAll(context); if (context.isMaster()) Dune::dwarn << "DDD XFER_SHOW_MSGSALL: CplMsg.Recv\n"; LC_PrintRecvMsgs(context); } for(int i=0; i #include #include #include #include #include #include #include "xfer.h" using namespace PPIF; START_UGDIM_NAMESPACE /* #define DebugAllPointers */ /****************************************************************************/ /* */ /* definition of static variables */ /* */ /****************************************************************************/ /****************************************************************************/ /* */ /* routines */ /* */ /****************************************************************************/ #ifdef DebugAllPointers static void XferPtr (DDD::DDDContext& context, LC_MSGHANDLE xm, const std::string& prefix, std::ostream& out) { SYMTAB_ENTRY *theSymTab; OBJTAB_ENTRY *theObjTab; char *theObjects; int i; int lenSymTab = (int) LC_GetTableLen(xm, ctx.symtab_id); int lenObjTab = (int) LC_GetTableLen(xm, ctx.objtab_id); /* get table addresses inside message buffer */ theSymTab = (SYMTAB_ENTRY *) LC_GetPtr(xm, ctx.symtab_id); theObjTab = (OBJTAB_ENTRY *) LC_GetPtr(xm, ctx.objtab_id); theObjects = (char *) LC_GetPtr(xm, ctx.objmem_id); /* build symbol table */ for(i=0; itype != EL_OBJPTR) continue; for(int l=0; lsize; l+=sizeof(void *)) { /* ref points to a reference inside objmem */ DDD_OBJ *ref = (DDD_OBJ *)(((char *)obj)+theElem->offset+l); /* reference had been replaced by SymTab-index */ INT stIdx = ((int)*ref)-1; if (stIdx < 0) continue; /* get corresponding symtab entry */ const SYMTAB_ENTRY *st = &(theSymTab[stIdx]); using std::dec; using std::hex; using std::setw; out << prefix << " 20 " << " obj=" << setw(3) << theObjTab[i].offset << " " << setw(3) << stIdx << hex << " st=" << setw(8) << st << " gid=" << setw(8) << st->gid << "(" << setw(x) << st->adr.hdr << "==" << setw(8) << st->adr.ref << ")\n" << dec; } } } } #endif void XferDisplayMsg (DDD::DDDContext& context, const char *comment, LC_MSGHANDLE xm) { using std::setw; std::ostream& out = std::cout; auto& ctx = context.xferContext(); SYMTAB_ENTRY *theSymTab; OBJTAB_ENTRY *theObjTab; TENewCpl *theNewCpl; TEOldCpl *theOldCpl; char *theObjects; int i, proc = LC_MsgGetProc(xm); int lenSymTab = (int) LC_GetTableLen(xm, ctx.symtab_id); int lenObjTab = (int) LC_GetTableLen(xm, ctx.objtab_id); int lenNewCpl = (int) LC_GetTableLen(xm, ctx.newcpl_id); int lenOldCpl = (int) LC_GetTableLen(xm, ctx.oldcpl_id); std::ostringstream prefixStream; prefixStream << " " << setw(3) << context.me() << "-" << comment << "-" << setw(3) << proc << " "; const std::string& prefix = prefixStream.str(); /* get table addresses inside message */ theSymTab = (SYMTAB_ENTRY *)LC_GetPtr(xm, ctx.symtab_id); theObjTab = (OBJTAB_ENTRY *)LC_GetPtr(xm, ctx.objtab_id); theNewCpl = (TENewCpl *) LC_GetPtr(xm, ctx.newcpl_id); theOldCpl = (TEOldCpl *) LC_GetPtr(xm, ctx.oldcpl_id); theObjects= (char *)LC_GetPtr(xm, ctx.objmem_id); /* because of LC layer, this data can't be accessed anymore. KB 960718 sprintf(cBuffer, "%s 00 MsgBuf=%08x\n", buf, xmdata); DDD_PrintDebug(cBuffer); sprintf(cBuffer, "%s 00 SymTab %04d\n", buf, theHeader->beginSymTab); DDD_PrintDebug(cBuffer); sprintf(cBuffer, "%s 01 ObjTab %04d\n", buf, theHeader->beginObjTab); DDD_PrintDebug(cBuffer); sprintf(cBuffer, "%s 02 CplTab %04d\n", buf, theHeader->beginCplTab); DDD_PrintDebug(cBuffer); sprintf(cBuffer, "%s 03 DelTab %04d\n", buf, theHeader->beginDelTab); DDD_PrintDebug(cBuffer); sprintf(cBuffer, "%s 04 ObjMem %04d\n", buf, theHeader->beginObjMem); DDD_PrintDebug(cBuffer); */ out << prefix << " 05 ObjTab.size=" << setw(5) << lenObjTab << "\n"; out << prefix << " 06 SymTab.size=" << setw(5) << lenSymTab << "\n"; out << prefix << " 07 NewCpl.size=" << setw(5) << lenNewCpl << "\n"; out << prefix << " 08 OldCpl.size=" << setw(5) << lenOldCpl << "\n"; for(i=0; i #include #include #include #include #include #include #include #include #include "xfer.h" #include #include USING_UG_NAMESPACE START_UGDIM_NAMESPACE /****************************************************************************/ /* */ /* defines in the following order */ /* */ /* compile time constants defining static data size (i.e. arrays) */ /* other constants */ /* macros */ /* */ /****************************************************************************/ /****************************************************************************/ /* */ /* data structures */ /* */ /****************************************************************************/ /****************************************************************************/ /* */ /* definition of exported global variables */ /* */ /****************************************************************************/ /****************************************************************************/ /* */ /* definition of variables global to this source file only (static!) */ /* */ /****************************************************************************/ /****************************************************************************/ /* */ /* routines */ /* */ /****************************************************************************/ static bool sort_SymTabEntries (const SYMTAB_ENTRY& a, const SYMTAB_ENTRY& b) { return a.gid < b.gid; } /****************************************************************************/ /* */ /* Function: BuildSymTab */ /* */ /* Purpose: compute message SymTab entries for one single ddd-object. */ /* */ /* Input: desc: descriptor of object */ /* obj: DDD_OBJ ptr to ddd-object (in local mem) or NULL */ /* copy: copy of ddd-object (inside message buffer) */ /* theSymTab: actual portion of message SymTab */ /* */ /* Output: number of new entries into SymTab */ /* */ /****************************************************************************/ static int BuildSymTab (DDD::DDDContext& context, TYPE_DESC *desc, DDD_OBJ obj, const char *copy, SYMTAB_ENTRY *theSymTab) { ELEM_DESC *theElem; int e, actSym; /* reset local portion of SymTab */ actSym = 0; /* prepare map of structure elements */ theElem = desc->element; /* loop over all pointers inside of object obj */ for(e=0; enElements; e++, theElem++) { if (theElem->type==EL_OBJPTR) { TYPE_DESC *refdesc; int l; int rt_on_the_fly = (EDESC_REFTYPE(theElem)==DDD_TYPE_BY_HANDLER); /* determine reftype of this elem */ if (! rt_on_the_fly) { /* we know the reftype of this element in advance */ refdesc = &context.typeDefs()[EDESC_REFTYPE(theElem)]; } /* else: determine reftype on the fly by calling handler */ /* loop over single pointer array */ for(l=0; lsize; l+=sizeof(void *)) { /* get address of outside reference */ DDD_OBJ *ref = (DDD_OBJ *)(copy+theElem->offset+l); /* create symbol table entry */ if (*ref!=NULL) { DDD_HDR refhdr; if (rt_on_the_fly) { DDD_TYPE rt; /* determine reftype on the fly by calling handler */ assert(obj!=NULL); /* we need a real object here */ rt = theElem->reftypeHandler(context, obj, *ref); if (rt>=MAX_TYPEDESC) DUNE_THROW(Dune::Exception, "invalid referenced DDD_TYPE returned by handler"); refdesc = &context.typeDefs()[rt]; } /* get header of referenced object */ refhdr = OBJ2HDR(*ref,refdesc); /* remember the GID of the referenced object */ theSymTab[actSym].gid = OBJ_GID(refhdr); /* remember the address of the reference (in obj-copy) */ theSymTab[actSym].adr.ref = ref; actSym++; } } } } /* return SymTab increment */ return(actSym); } /****************************************************************************/ /* */ /* Function: GetDepData */ /* */ /* Purpose: fill object-dependent data into message. an appl. routine */ /* will be called to fill in the data actually. pointers are */ /* localized and the message SymTab is actualized. */ /* */ /* Input: data: portion of message buffer reserved for dependent data */ /* desc: descriptor of object */ /* obj: current ddd-object */ /* theSymTab: actual portion of message SymTab */ /* xi: single xferinfo for current ddd-object */ /* */ /* Output: number of new entries into SymTab */ /* */ /****************************************************************************/ static int GetDepData (DDD::DDDContext& context, char *data, TYPE_DESC *desc, DDD_OBJ obj, SYMTAB_ENTRY *theSymTab, XICopyObj *xi) { XFERADDDATA *xa; char *chunk, *adr, **table1, *next_chunk; int chunks, i, actSym, *table2; if (xi->addLen==0) return(0); chunks = 0; actSym = 0; /* first entry will be number of dependency chunks */ chunk = data + CEIL(sizeof(int)); /* loop through whole dependency data descriptor */ for(xa=xi->add; xa!=NULL; xa=xa->next) { /* first entries of chunk are addCnt and addTyp */ ((int *)chunk)[0] = xa->addCnt; ((DDD_TYPE *)chunk)[1] = xa->addTyp; if (xa->sizes==NULL) { chunk += CEIL(sizeof(int)+sizeof(DDD_TYPE)); /* then all records should be gathered via handler */ if (desc->handlerXFERGATHER) { desc->handlerXFERGATHER( context, obj, xa->addCnt, xa->addTyp, (void *)chunk); } if (xa->addTypaddTyp>DDD_USER_DATA_MAX) { /* insert pointers into symtab */ TYPE_DESC* descDep = &context.typeDefs()[xa->addTyp]; for(i=0; iaddCnt; i++) { actSym += BuildSymTab(context, descDep, NULL, chunk, &(theSymTab[actSym])); chunk += CEIL(descDep->size); } } else { /* no regular type -> send byte stream with length addCnt */ chunk += CEIL(xa->addCnt); } } else { /* var-sized AddData items */ ((int *)chunk)[0] *= -1; chunk += CEIL(sizeof(int)+sizeof(DDD_TYPE)); /* create pointer array inside message */ table1 = (char **)chunk; chunk += CEIL(sizeof(int)*xa->addCnt); for(i=0, adr=chunk; iaddCnt; i++) { table1[i] = adr; adr += CEIL(xa->sizes[i]); } next_chunk = adr; /* then all records should be gathered via handler */ if (desc->handlerXFERGATHERX) { desc->handlerXFERGATHERX( context, obj, xa->addCnt, xa->addTyp, table1); } /* convert pointer table into offset table */ table2 = (int *)table1; TYPE_DESC* descDep = &context.typeDefs()[xa->addTyp]; adr = chunk; for(i=0; iaddCnt; i++) { /* insert pointers into symtab */ if (xa->addTypaddTyp>DDD_USER_DATA_MAX) { actSym += BuildSymTab(context, descDep, NULL, table1[i], &(theSymTab[actSym])); } table2[i] = (int)(table1[i]-adr); } chunk = next_chunk; } /* count chunks */ chunks++; } /* remember number of chunks at the beginning of the deplist */ ((int *)data)[0] = chunks; return(actSym); } /****************************************************************************/ /* */ /* Function: XferPackSingleMsgs */ /* */ /* Purpose: build up one outgoing message completely, fill data into */ /* message buffer. objects and couplings will be packed, and */ /* several message tables will be constructed. pointers are */ /* localized inside the message. several applications handlers */ /* are called to fill in dependent data. */ /* */ /* Input: msg: single message-send-info structure */ /* */ /* Output: - */ /* */ /****************************************************************************/ static void XferPackSingleMsg (DDD::DDDContext& context, XFERMSG *msg) { auto& ctx = context.xferContext(); SYMTAB_ENTRY *theSymTab; OBJTAB_ENTRY *theObjTab; TENewCpl *theNewCpl; TEOldCpl *theOldCpl; char *theObjects, *currObj; int i, actSym, actNewCpl, actOldCpl, actObj; /* get table addresses inside message */ theSymTab = (SYMTAB_ENTRY *)LC_GetPtr(msg->msg_h, ctx.symtab_id); theObjTab = (OBJTAB_ENTRY *)LC_GetPtr(msg->msg_h, ctx.objtab_id); theNewCpl = (TENewCpl *) LC_GetPtr(msg->msg_h, ctx.newcpl_id); theOldCpl = (TEOldCpl *) LC_GetPtr(msg->msg_h, ctx.oldcpl_id); theObjects= (char *)LC_GetPtr(msg->msg_h, ctx.objmem_id); /* build several tables inside message */ actSym = actNewCpl = actOldCpl = actObj = 0; currObj = theObjects; for(i=0; inObjItems; i++) /* for all XICopyObj-items */ { XICopyObj *xi = msg->xferObjArray[i]; DDD_HDR hdr = xi->hdr; TYPE_DESC *desc = &context.typeDefs()[OBJ_TYPE(hdr)]; DDD_OBJ obj = HDR2OBJ(hdr,desc); /*COUPLING *cpl;*/ DDD_HDR copyhdr; /* build coupling table */ /* skip cpl which describes object itself (receive proc) */ /* for(cpl=THECOUPLING(hdr); cpl!=NULL; cpl=cpl->next) { if (cpl->proc!=msg->proc) { theNewCpl[actNewCpl].gid = OBJ_GID(hdr); theNewCpl[actNewCpl].proc = cpl->proc; theNewCpl[actNewCpl].prio = cpl->prio; actNewCpl++; } } */ /* one coupling for object itself (send proc) */ /* theNewCpl[actNewCpl].gid = OBJ_GID(hdr); theNewCpl[actNewCpl].proc = context.me(); theNewCpl[actNewCpl].prio = OBJ_PRIO(hdr); actNewCpl++; */ copyhdr = OBJ2HDR(currObj,desc); /* update object table */ theObjTab[actObj].h_offset = (int)(((char *)copyhdr)-theObjects); theObjTab[actObj].hdr = NULL; theObjTab[actObj].addLen = xi->addLen; theObjTab[actObj].size = xi->size; /* needed for variable-sized objects */ actObj++; /* copy object into message. in the following xi->size equals desc->len for fixed-size objects. */ /*STAT_RESET3;*/ /* NOTE: object memory is copied _completely_, i.e., also LDATA- components are copied into message and sent to destination. then, on the receiving processor the data is sorted out... */ memcpy(currObj, obj, xi->size); /* insert priority into copy */ OBJ_PRIO(copyhdr) = xi->prio; /* call application handler for direct manipulation */ /* KB 941110: moved from objmgr.c */ /* Caution: this is a very, very dirty situation. HANDLER_XFERCOPYMANIP is able to manipulate the obj-copy inside the message. this handler should be removed in future DDD versions. */ if (desc->handlerXFERCOPYMANIP) { /* NOTE: OBJ_TYPE could change during the execution of HANDLER_XFERCOPYMANIP. however, the position of DDD_HEADER inside the object should not change. therefore, we can remember the offsetHeader here and use it afterwards to adjust the desc. */ int offset = desc->offsetHeader; /* now call handler */ desc->handlerXFERCOPYMANIP(context, currObj); /* adjust new description according to new type */ desc = &context.typeDefs()[OBJ_TYPE((DDD_HDR)(currObj+offset))]; } /* build symbol table portion from object copy */ actSym += BuildSymTab(context, desc, obj, (char *)currObj, &(theSymTab[actSym])); /* advance to next free object slot in message, c.f. alignment */ currObj += CEIL(xi->size); /* gather additional data */ if (xi->addLen>0) { actSym += GetDepData(context, currObj, desc, obj, &(theSymTab[actSym]), xi); currObj += xi->addLen; } } /* for all XINewCpl items in this message */ for(i=0; inNewCpl; i++) { theNewCpl[actNewCpl] = msg->xferNewCpl[i]->te; actNewCpl++; } /* for all XIOldCpl items in this message */ for(i=0; inOldCpl; i++) { theOldCpl[actOldCpl] = msg->xferOldCpl[i]->te; actOldCpl++; } /* sort SymTab, ObjTab and CplTab */ /* sort SymTab according to the global ids stored there */ std::sort(theSymTab, theSymTab + actSym, sort_SymTabEntries); /* sort ObjTab according to their global ids */ /* sorting of objtab is necessary!! (see AcceptObjFromMsg) KB 960812 */ const auto sort_ObjTabEntries = [=](const OBJTAB_ENTRY& a, const OBJTAB_ENTRY& b) { /* sort with ascending gid */ return OTE_GID(theObjects, &a) < OTE_GID(theObjects, &b); }; std::sort(theObjTab, theObjTab + msg->nObjects, sort_ObjTabEntries); /* substitute all pointers by index into SymTab */ for(std::uintptr_t mi=0; mimsg_h, ctx.symtab_id, actSym); LC_SetTableLen(msg->msg_h, ctx.objtab_id, msg->nObjects); LC_SetTableLen(msg->msg_h, ctx.newcpl_id, actNewCpl); LC_SetTableLen(msg->msg_h, ctx.oldcpl_id, actOldCpl); #if DebugXfer>1 if (DDD_GetOption(context, OPT_DEBUG_XFERMESGS)==OPT_ON) #endif XferDisplayMsg(context, "OS", msg->msg_h); } /****************************************************************************/ /* */ /* Function: XferPackMsgs */ /* */ /* Purpose: allocate one message buffer for each outgoing message, */ /* fill buffer with message contents and initiate asynchronous */ /* send for each message. */ /* */ /* Input: theMsgs: list of message-send-infos */ /* */ /* Output: RET_ON_ERROR if error occurred, RET_ON_OK otherwise */ /* */ /****************************************************************************/ RETCODE XferPackMsgs (DDD::DDDContext& context, XFERMSG *theMsgs) { XFERMSG *xm; #if DebugPack<=3 Dune::dverb << "XferPackMsgs" << std::endl; #endif /* allocate buffer, pack messages and send away */ for(xm=theMsgs; xm!=NULL; xm=xm->next) { if (! LC_MsgAlloc(context, xm->msg_h)) { Dune::dwarn << STR_NOMEM " in XferPackMsgs (size=" << LC_GetBufferSize(xm->msg_h) << ")\n"; RET_ON_ERROR; } XferPackSingleMsg(context, xm); LC_MsgSend(context, xm->msg_h); } RET_ON_OK; } END_UGDIM_NAMESPACE dune-uggrid-2.11.0+dfsg/dune/uggrid/parallel/ddd/xfer/sll.ct000066400000000000000000000166271513616443000235740ustar00rootroot00000000000000// SPDX-FileCopyrightText: Copyright © DUNE Project contributors, see file LICENSE.md in module root // SPDX-License-Identifier: LGPL-2.1-or-later /****************************************************************************/ /* */ /* File: sll.ct */ /* */ /* Purpose: template routines for linked lists with freelist */ /* */ /* Author: Klaus Birken */ /* Institut fuer Computeranwendungen III */ /* Universitaet Stuttgart */ /* Pfaffenwaldring 27 */ /* 70569 Stuttgart */ /* internet: birken@ica3.uni-stuttgart.de */ /* */ /* History: 960826 kb created */ /* 970303 kb added memory management in segms */ /* */ /* Remarks: */ /* */ /****************************************************************************/ /****************************************************************************/ /* */ /* definition of exported global variables */ /* */ /****************************************************************************/ /* segment of items */ struct Segm(T) { Segm(T) *next; int nItems; T item[SEGM_SIZE]; }; /****************************************************************************/ /* */ /* routines */ /* */ /****************************************************************************/ static Segm(T) *NewSegm(T) (DDD::DDDContext& context) { auto& ctx = context.xferContext(); Segm(T) *segm; segm = (Segm(T) *) OO_Allocate (sizeof(Segm(T))); if (segm==NULL) { DDD_PrintError('F', 6060, STR_NOMEM " during XferEnd()"); return(NULL); } segm->next = reinterpret_cast(ctx.segms(T)); ctx.segms(T) = reinterpret_cast(segm); segm->nItems = 0; return(segm); } static void FreeSegms(T) (DDD::DDDContext& context) { auto& ctx = context.xferContext(); Segm(T) *segm = reinterpret_cast(ctx.segms(T)); Segm(T) *next = NULL; while (segm!=NULL) { next = segm->next; OO_Free (segm /*,sizeof(Segm(T))*/ ); segm = next; } ctx.segms(T) = nullptr; } T *New(T) (DDD::DDDContext& context) { auto& ctx = context.xferContext(); Segm(T) *segm = reinterpret_cast(ctx.segms(T)); T *item; if (segm==NULL || segm->nItems==SEGM_SIZE) { segm = NewSegm(T) (context); if (segm==NULL) return(NULL); } item = &(segm->item[segm->nItems++]); /* insert item into linked list and count it */ item->sll_next = reinterpret_cast(ctx.list(T)); ctx.list(T) = reinterpret_cast(item); ctx.n(T)++; #ifdef SLL_WithOrigOrder /* insert unique counter */ item->sll_n = ctx.n(T); #endif return(item); } /* create pointer array from linked list and sort it according to given comparison function compar(). */ T **SortedArray(T) (DDD::DDDContext& context, int (*compar) (const void *, const void *)) { auto& ctx = context.xferContext(); T **array; if (ctx.n(T)>0) { /* alloc array */ array = (T **) OO_Allocate(sizeof(T *) * ctx.n(T)); if (array==NULL) { DDD_PrintError('F', 6061, STR_NOMEM " during XferEnd()"); return(NULL); } /* fill array with pointer */ int i = 0; for (T* item = reinterpret_cast(ctx.list(T)); i < ctx.n(T); item = item->sll_next, i++) { array[i] = item; } /* sort by using compar function */ if (ctx.n(T)>1) qsort(array, ctx.n(T), sizeof(T *), compar); } else { array = NULL; } return(array); } /****************************************************************************/ #ifdef SLL_WithOrigOrder /* sort array of items into order of their New(T) command execution. the counter-component T.n is used for doing this. */ static int sort_OrigOrder(T) (const void *e1, const void *e2) { T *item1 = *((T **)e1); T *item2 = *((T **)e2); if (item1->sll_n < item2->sll_n) return(-1); if (item1->sll_n > item2->sll_n) return(1); return(0); } void OrigOrder(T) (DDD::DDDContext& context, T **array, int n) { qsort(array, n, sizeof(T *), sort_OrigOrder(T)); } #endif /****************************************************************************/ /* unify array of items. the array is compressed, the resulting number of valid items is returned. compar() is a comparison function which returns whether two items are equal or not. compar(a,b) should return FALSE if a should be skipped and eventually b could be chosen TRUE if a must be taken. the array of items must be sorted in order to allow compar() to decide correctly. */ int Unify(T) (const DDD::DDDContext& context, T **array, int (*compar) (const DDD::DDDContext&, T **, T **)) { const auto& ctx = context.xferContext(); int i, cntValid; for(i=0, cntValid=0; i0) { array[cntValid] = array[ctx.n(T)-1]; cntValid++; } return(cntValid); } /****************************************************************************/ /* init linked list */ void Init(T) (DDD::DDDContext& context) { auto& ctx = context.xferContext(); ctx.list(T) = nullptr; ctx.n(T) = 0; ctx.segms(T) = nullptr; /* free(T) = NULL; */ } /* free all items */ void FreeAll(T) (DDD::DDDContext& context) { auto& ctx = context.xferContext(); ctx.list(T) = nullptr; ctx.n(T) = 0; FreeSegms(T) (context); } /* get quantitative resource usage */ void GetSizes(T) (const DDD::DDDContext& context, int *nSegms, int *nItems, size_t *alloc_mem, size_t *used_mem) { const auto& ctx = context.xferContext(); size_t allocated=0, used=0; int ns=0, ni=0; Segm(T) *segm; for (segm=reinterpret_cast(ctx.segms(T)); segm!=NULL; segm=segm->next) { /* count number of segments and number of items */ ns++; ni+=segm->nItems; /* compute memory usage */ allocated += sizeof(Segm(T)); used += (sizeof(Segm(T)) - (sizeof(T)*(SEGM_SIZE-segm->nItems))); } *nSegms = ns; *nItems = ni; *alloc_mem = allocated; *used_mem = used; } /****************************************************************************/ #ifdef SLL_WithOrigOrder #undef SLL_WithOrigOrder #endif /****************************************************************************/ dune-uggrid-2.11.0+dfsg/dune/uggrid/parallel/ddd/xfer/sll.h000066400000000000000000000073161513616443000234100ustar00rootroot00000000000000// -*- tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- // vi: set et ts=4 sw=2 sts=2: // SPDX-FileCopyrightInfo: Copyright © DUNE Project contributors, see file LICENSE.md in module root // SPDX-License-Identifier: LGPL-2.1-or-later /****************************************************************************/ /* */ /* File: sll.h */ /* */ /* Purpose: header file for sll templates */ /* */ /* Author: Klaus Birken */ /* Institut fuer Computeranwendungen III */ /* Universitaet Stuttgart */ /* Pfaffenwaldring 27 */ /* 70569 Stuttgart */ /* internet: birken@ica3.uni-stuttgart.de */ /* */ /* History: 960826 kb begin */ /* */ /* Remarks: */ /* */ /****************************************************************************/ /****************************************************************************/ /* */ /* auto include mechanism and other include files */ /* */ /****************************************************************************/ #ifndef __SLL_H__ #define __SLL_H__ /****************************************************************************/ /* size of segments for memory allocation */ #define SEGM_SIZE 256 /****************************************************************************/ #define SLL_INFO(T) \ T* sll_next /* linked list */ #define SLL_INFO_WITH_COUNTER(T) \ int sll_n; /* unique index number */ \ T* sll_next /* linked list */ /****************************************************************************/ /* macros for template support: datatypes */ #define _Segm(T) Segm ## T #define Segm(T) _Segm(T) /* macros for template support: variables */ #define _segms(T) segms ## T #define segms(T) _segms(T) #define _list(T) list ## T #define list(T) _list(T) #define _n(T) n ## T #define n(T) _n(T) /* macros for template support: functions */ #define _NewSegm(T) NewSegm ## T #define NewSegm(T) _NewSegm(T) #define _FreeSegms(T) FreeSegms ## T #define FreeSegms(T) _FreeSegms(T) #define _New(T) New ## T #define New(T) _New(T) #define _SortedArray(T) SortedArray ## T #define SortedArray(T) _SortedArray(T) #define _sort_OrigOrder(T) sort_OrigOrder ## T #define sort_OrigOrder(T) _sort_OrigOrder(T) #define _OrigOrder(T) OrigOrder ## T #define OrigOrder(T) _OrigOrder(T) #define _Unify(T) Unify ## T #define Unify(T) _Unify(T) #define _Init(T) Init ## T #define Init(T) _Init(T) #define _FreeAll(T) FreeAll ## T #define FreeAll(T) _FreeAll(T) #define _GetSizes(T) GetSizes ## T #define GetSizes(T) _GetSizes(T) /****************************************************************************/ #endif dune-uggrid-2.11.0+dfsg/dune/uggrid/parallel/ddd/xfer/sll.ht000066400000000000000000000051631513616443000235720ustar00rootroot00000000000000// SPDX-FileCopyrightText: Copyright © DUNE Project contributors, see file LICENSE.md in module root // SPDX-License-Identifier: LGPL-2.1-or-later /****************************************************************************/ /* */ /* File: sll.ht */ /* */ /* Purpose: single linked list templates, header file */ /* */ /* Author: Klaus Birken */ /* Institut fuer Computeranwendungen III */ /* Universitaet Stuttgart */ /* Pfaffenwaldring 27 */ /* 70569 Stuttgart */ /* internet: birken@ica3.uni-stuttgart.de */ /* */ /* History: 960826 kb created */ /* */ /* Remarks: */ /* */ /****************************************************************************/ /****************************************************************************/ /* */ /* function declarations */ /* */ /****************************************************************************/ /* from sll.ct */ T *New(T) (DDD::DDDContext&); T **SortedArray(T) (DDD::DDDContext&, int (*) (const void *, const void *)); int Unify(T) (const DDD::DDDContext&, T **, int (*) (const DDD::DDDContext&, T **, T **)); #ifdef SLL_WithOrigOrder void OrigOrder(T) (DDD::DDDContext&, T **, int); #endif void Init(T) (DDD::DDDContext&); void FreeAll(T) (DDD::DDDContext&); void GetSizes(T) (const DDD::DDDContext&, int *, int *, size_t *, size_t *); /****************************************************************************/ /* undefine switches and helper macros */ #ifdef SLL_WithOrigOrder #undef SLL_WithOrigOrder #endif /****************************************************************************/ dune-uggrid-2.11.0+dfsg/dune/uggrid/parallel/ddd/xfer/supp.cc000066400000000000000000000263601513616443000237430ustar00rootroot00000000000000// SPDX-FileCopyrightText: Copyright © DUNE Project contributors, see file LICENSE.md in module root // SPDX-License-Identifier: LGPL-2.1-or-later // -*- tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- // vi: set et ts=4 sw=2 sts=2: /****************************************************************************/ /* */ /* File: supp.c */ /* */ /* Purpose: support routines for Transfer Module */ /* */ /* Author: Klaus Birken */ /* Rechenzentrum Uni Stuttgart */ /* Universitaet Stuttgart */ /* Allmandring 30 */ /* 70550 Stuttgart */ /* internet: birken@rus.uni-stuttgart.de */ /* */ /* History: 93/11/30 kb begin (xfer.c) */ /* 95/03/21 kb added variable sized objects (XferCopyObjX) */ /* 95/04/05 kb V1.3: extracted from xfer.c */ /* */ /* Remarks: */ /* */ /****************************************************************************/ /****************************************************************************/ /* */ /* include files */ /* system include files */ /* application include files */ /* */ /****************************************************************************/ /* standard C library */ #include #include #include #include #include #include USING_UG_NAMESPACE /* NOTE: all container-classes from ooppcc.h are implemented in this source file by setting the following define. */ #define ContainerImplementation /* this is the hardliner version, for debugging only #define _CHECKALLOC(ptr) assert(ptr!=NULL) */ #define _CHECKALLOC(ptr) if (ptr==NULL) return (NULL) #include "xfer.h" /****************************************************************************/ /* */ /* definition of constants, macros */ /* */ /****************************************************************************/ #define ADDDATASEGM_SIZE 256 #define SIZESSEGM_SIZE 2048 /****************************************************************************/ /* */ /* data types */ /* */ /****************************************************************************/ namespace DDD { namespace Xfer { /* segment of AddDatas */ struct AddDataSegm { AddDataSegm *next; int nItems; XFERADDDATA item[ADDDATASEGM_SIZE]; }; /* segment of AddData-Sizes */ struct SizesSegm { SizesSegm *next; int current; int data[SIZESSEGM_SIZE]; }; } /* namespace Xfer */ } /* namespace DDD */ START_UGDIM_NAMESPACE using namespace DDD::Xfer; /****************************************************************************/ /* */ /* class member function implementations */ /* */ /****************************************************************************/ #define ClassName XICopyObj /* compare-method in order to eliminate double XICopyObj-items. merge priorities from similar XICopyObj-items. the items are sorted according to key (dest,gid), all in ascending order. if dest and gid are equal, we merge priorities and get a new priority together with the information whether first item wins over second. in both cases, we use the new priority for next comparison. this implements rule XFER-C1. */ int Method(Compare) (ClassPtr item1, ClassPtr item2, const DDD::DDDContext* context) { DDD_PRIO newprio; int ret; if (item1->dest < item2->dest) return(-1); if (item1->dest > item2->dest) return(1); if (item1->gid < item2->gid) return(-1); if (item1->gid > item2->gid) return(1); /* items have equal gid and dest, so they are considered as equal. */ /* however, we must check priority, and patch both items with the new priority after merge. */ ret = PriorityMerge(&context->typeDefs()[OBJ_TYPE(item1->hdr)], item1->prio, item2->prio, &newprio); item1->prio = newprio; if (ret==PRIO_FIRST || ret==PRIO_UNKNOWN) { /* tell XferInitCopyInfo() that item is rejected */ item2->prio = PRIO_INVALID; } else { /* communicate new priority to XferInitCopyInfo() */ item2->prio = newprio; } return(0); } void Method(Print) (ParamThis _PRINTPARAMS) { fprintf(fp, "XICopyObj dest=%d gid=" DDD_GID_FMT " prio=%d\n", This->dest, This->gid, This->prio); } #undef ClassName /****************************************************************************/ #define ClassName XISetPrio /* compare-method in order to eliminate double XISetPrio-items. merge priorities from similar XISetPrio-items. the items are sorted according to key (gid), all in ascending order. if both gids are equal, we merge priorities and get a new priority together with the information whether first item wins over second. in both cases, we use the new priority for next comparison. this implements rule XFER-P1. */ int Method(Compare) (ClassPtr item1, ClassPtr item2, const DDD::DDDContext* context) { DDD_PRIO newprio; int ret; /* ascending GID is needed for ExecLocalXI___ */ if (item1->gid < item2->gid) return(-1); if (item1->gid > item2->gid) return(1); /* items have equal gid and dest, so they are considered as equal. */ /* however, we must check priority, and patch both items with the new priority after merge. */ ret = PriorityMerge(&context->typeDefs()[OBJ_TYPE(item1->hdr)], item1->prio, item2->prio, &newprio); item1->prio = item2->prio = newprio; if (ret==PRIO_FIRST || ret==PRIO_UNKNOWN) { /* tell XferInitCopyInfo() that item is rejected */ item2->prio = PRIO_INVALID; } else { /* communicate new priority to XferInitCopyInfo() */ item2->prio = newprio; } return(0); } void Method(Print) (ParamThis _PRINTPARAMS) { fprintf(fp, "XISetPrio gid=" DDD_GID_FMT " prio=%d\n", This->gid, This->prio); } #undef ClassName /****************************************************************************/ /* include templates */ #define T XIDelCmd #define SLL_WithOrigOrder #include "sll.ct" #undef T #define T XIDelObj #include "sll.ct" #undef T #define T XINewCpl #include "sll.ct" #undef T #define T XIOldCpl #include "sll.ct" #undef T #define T XIAddCpl #include "sll.ct" #undef T #define T XIDelCpl #include "sll.ct" #undef T #define T XIModCpl #include "sll.ct" #undef T /****************************************************************************/ static AddDataSegm *NewAddDataSegm(DDD::DDDContext& context) { auto& ctx = context.xferContext(); AddDataSegm *segm; segm = (AddDataSegm *) OO_Allocate(sizeof(AddDataSegm)); if (segm==NULL) throw std::bad_alloc(); segm->next = ctx.segmAddData; ctx.segmAddData = segm; segm->nItems = 0; return(segm); } static void FreeAddDataSegms(DDD::DDDContext& context) { auto& ctx = context.xferContext(); AddDataSegm *segm = ctx.segmAddData; AddDataSegm *next = NULL; while (segm!=NULL) { next = segm->next; OO_Free (segm /*,sizeof(AddDataSegm)*/); segm = next; } ctx.segmAddData = nullptr; } /****************************************************************************/ static SizesSegm *NewSizesSegm(DDD::DDDContext& context) { auto& ctx = context.xferContext(); SizesSegm *segm; segm = (SizesSegm *) OO_Allocate (sizeof(SizesSegm)); if (segm==NULL) throw std::bad_alloc(); segm->next = ctx.segmSizes; ctx.segmSizes = segm; segm->current = 0; return(segm); } static void FreeSizesSegms(DDD::DDDContext& context) { auto& ctx = context.xferContext(); SizesSegm *segm = ctx.segmSizes; SizesSegm *next = NULL; while (segm!=NULL) { next = segm->next; OO_Free (segm /*,sizeof(SizesSegm)*/); segm = next; } ctx.segmSizes = nullptr; } /****************************************************************************/ XFERADDDATA *NewXIAddData(DDD::DDDContext& context) { auto& ctx = context.xferContext(); AddDataSegm *segm = ctx.segmAddData; XFERADDDATA *xa; if (segm==NULL || segm->nItems==ADDDATASEGM_SIZE) { segm = NewAddDataSegm(context); } xa = &(segm->item[segm->nItems++]); xa->next = ctx.theXIAddData->add; ctx.theXIAddData->add = xa; return(xa); } void FreeAllXIAddData(DDD::DDDContext& context) { FreeAddDataSegms(context); FreeSizesSegms(context); } /****************************************************************************/ int *AddDataAllocSizes (DDD::DDDContext& context, int cnt) { auto& ctx = context.xferContext(); SizesSegm *segm = ctx.segmSizes; int *pos; if (segm==NULL || segm->current+cnt>=SIZESSEGM_SIZE) { segm = NewSizesSegm(context); } pos = segm->data + segm->current; segm->current += cnt; return(pos); } /****************************************************************************/ /* get quantitative resource usage */ void GetSizesXIAddData(const DDD::DDDContext& context, int *nSegms, int *nItems, size_t *alloc_mem, size_t *used_mem) { const auto& ctx = context.xferContext(); size_t allocated=0, used=0; int ns=0, ni=0; { for (const AddDataSegm* segm=ctx.segmAddData; segm!=NULL; segm=segm->next) { /* count number of segments and number of items */ ns++; ni+=segm->nItems; /* compute memory usage */ allocated += sizeof(AddDataSegm); used += (sizeof(AddDataSegm) - (sizeof(XFERADDDATA)*(ADDDATASEGM_SIZE-segm->nItems))); } } /* TODO: add resources for SizesSegm */ *nSegms = ns; *nItems = ni; *alloc_mem = allocated; *used_mem = used; } /****************************************************************************/ END_UGDIM_NAMESPACE dune-uggrid-2.11.0+dfsg/dune/uggrid/parallel/ddd/xfer/unpack.cc000066400000000000000000001422731513616443000242370ustar00rootroot00000000000000// SPDX-FileCopyrightText: Copyright © DUNE Project contributors, see file LICENSE.md in module root // SPDX-License-Identifier: LGPL-2.1-or-later /****************************************************************************/ /* */ /* File: unpack.c */ /* */ /* Purpose: receives and unpacks messages */ /* */ /* Author: Klaus Birken */ /* Rechenzentrum Uni Stuttgart */ /* Universitaet Stuttgart */ /* Allmandring 30 */ /* 70550 Stuttgart */ /* internet: birken@rus.uni-stuttgart.de */ /* */ /* History: 940201 kb begin */ /* 960508 kb restructured completely. efficiency improvement. */ /* 960718 kb introduced lowcomm-layer (sets of messages) */ /* */ /* Remarks: */ /* */ /****************************************************************************/ /****************************************************************************/ /* */ /* include files */ /* system include files */ /* application include files */ /* */ /****************************************************************************/ /* standard C library */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "xfer.h" USING_UG_NAMESPACE using namespace PPIF; START_UGDIM_NAMESPACE /* TODO kb 961210 #define DEBUG_MERGE_MODE */ #define MERGE_MODE_IN_TESTZUSTAND /*#define DebugCouplingCons*/ /* #define AddCoupling(context, a,b,c) printf("%4d: AC %05d, %d/%d %08x\n",context.me(),__LINE__,b,c,(int) AddCoupling(context, a,b,c)) */ static void NEW_AddCpl(DDD::DDDContext& context, DDD_PROC destproc, DDD_GID objgid, DDD_PROC cplproc, DDD_PRIO cplprio) { XIAddCpl *xc = NewXIAddCpl(context); assert(xc); xc->to = destproc; xc->te.gid = objgid; xc->te.proc = cplproc; xc->te.prio = cplprio; } static bool sort_TENewCpl (const TENewCpl& a, const TENewCpl& b) { /* sorting according to priority is not necessary anymore, equal items with different priorities will be sorted out according to PriorityMerge(). KB 970326 if (ci1->prio < ci2->prio) return(-1); if (ci1->prio > ci2->prio) return(1); */ return std::tie(a._gid, a._dest) < std::tie(b._gid, b._dest); } static bool sort_ObjTabPtrs (const OBJTAB_ENTRY* a, const OBJTAB_ENTRY* b) { /* sort with ascending gid */ /* sort with decreasing priority */ /* not necessary anymore. see first phase of AcceptReceivedObjects() for details. KB 970128 if (OBJ_PRIO(ci1) < OBJ_PRIO(ci2)) return(1); if (OBJ_PRIO(ci1) > OBJ_PRIO(ci2)) return(-1); */ return OBJ_GID(a->hdr) < OBJ_GID(b->hdr); } /****************************************************************************/ /* convert indices to symtab into references (pointers). the object objmem gets all references from template msgmem. msgmem and objmem may point to the same storage (this feature is used by PutDepData() ). */ static void LocalizeObject (DDD::DDDContext& context, bool merge_mode, TYPE_DESC *desc, const char *msgmem, DDD_OBJ objmem, const SYMTAB_ENTRY *theSymTab) { ELEM_DESC *theElem; int e; DDD_OBJ obj = objmem; /* prepare map of structure elements */ theElem = desc->element; /* loop over all pointers inside of object obj */ for(e=0; enElements; e++, theElem++) { if (theElem->type==EL_OBJPTR) { TYPE_DESC *refdesc; int rt_on_the_fly = (EDESC_REFTYPE(theElem)==DDD_TYPE_BY_HANDLER); const char *msgrefarray = msgmem+theElem->offset; char *objrefarray = objmem+theElem->offset; /* determine reftype of this elem */ if (! rt_on_the_fly) { refdesc = &context.typeDefs()[EDESC_REFTYPE(theElem)]; } /* else determine reftype on the fly */ /* loop over single pointer array */ for(std::size_t l=0; lsize; l+=sizeof(void*)) { INT stIdx; /* ref points to a reference inside objmem */ DDD_OBJ *ref = (DDD_OBJ *) (objrefarray+l); /* reference had been replaced by SymTab-index */ stIdx = (*(std::uintptr_t *)(msgrefarray+l)) - 1; /* test for Localize execution in merge_mode */ if (merge_mode && (*ref!=NULL)) { if (rt_on_the_fly) { /* determine reftype on the fly by calling handler */ DDD_TYPE rt; assert(obj!=NULL); rt = theElem->reftypeHandler(context, obj, *ref); if (rt>=MAX_TYPEDESC) DUNE_THROW(Dune::Exception, "invalid referenced DDD_TYPE returned by handler"); refdesc = &context.typeDefs()[rt]; } /* if we are in merge_mode, we do not update existing references. */ #ifdef DEBUG_MERGE_MODE printf("loc-merge curr=%08x keep e=%d l=%d\n", OBJ_GID(OBJ2HDR(*ref,refdesc)), e,l); #endif /* it may happen here that different references are in incoming and existing object. this is implicitly resolved by using the existing reference and ignoring the incoming one. if the REF_COLLISION option is set, we will issue a warning. */ if (stIdx>=0 && DDD_GetOption(context, OPT_WARNING_REF_COLLISION)==OPT_ON) { /* get corresponding symtab entry */ if (theSymTab[stIdx].adr.hdr!=OBJ2HDR(*ref,refdesc)) { Dune::dwarn << "LocalizeObject: " << "reference collision in " << OBJ_GID(OBJ2HDR(obj,desc)) << " (old=" << OBJ_GID(OBJ2HDR(*ref,refdesc)) << ", inc=" << OBJ_GID(theSymTab[stIdx].adr.hdr) << ")\n"; /* assert(0); ??? */ } } continue; } /* at this point, we are either not in merge_mode or we are in merge_mode, but existing reference is zero. NOTE: only in merge_mode the objmem array points to the reference array inside the local local object! */ if (stIdx>=0) { /* get corresponding symtab entry */ const SYMTAB_ENTRY *st = &(theSymTab[stIdx]); /* convert reference from header to object itself and replace index by pointer; if header==NULL, referenced object is not known and *ref should therefore be NULL, too! */ #ifdef MERGE_MODE_IN_TESTZUSTAND if (merge_mode) { if (st->adr.hdr!=NULL) { #ifdef DEBUG_MERGE_MODE printf("loc-merge curr=%08x " "have_sym e=%d l=%d to %08x\n", *ref, e,l,OBJ_GID(st->adr.hdr)); #endif /* distinction for efficiency: if we know refdesc in advance, we can compute DDD_OBJ more efficient. */ if (!rt_on_the_fly) { *ref = HDR2OBJ(st->adr.hdr,refdesc); } else { *ref = OBJ_OBJ(context, st->adr.hdr); } } #ifdef DEBUG_MERGE_MODE else { printf( "loc-merge curr=%08x " "have_sym e=%d l=%d to NULL\n", *ref, e, l); } #endif } else #endif { if (st->adr.hdr!=NULL) { /* distinction for efficiency: if we know refdesc in advance, we can compute DDD_OBJ more efficient. */ if (!rt_on_the_fly) { *ref = HDR2OBJ(st->adr.hdr,refdesc); } else { *ref = OBJ_OBJ(context, st->adr.hdr); } } else *ref = NULL; } } else { #ifdef MERGE_MODE_IN_TESTZUSTAND if (merge_mode) { #ifdef DEBUG_MERGE_MODE printf("loc-merge curr=%08x " "no_sym e=%d l=%d\n", *ref, e,l); #endif } else #endif { *ref = NULL; } } } } } } /****************************************************************************/ static void PutDepData (DDD::DDDContext& context, char *data, const TYPE_DESC *desc, DDD_OBJ obj, const SYMTAB_ENTRY *theSymTab, int newness) { /* get overall number of chunks */ const int chunks = ((int *)data)[0]; char* chunk = data + CEIL(sizeof(int)); char* curr = nullptr; /* loop through all chunks */ for(int j=0; j=0) { if (addTypDDD_USER_DATA_MAX) { /* convert pointers using SymTab */ TYPE_DESC* descDep = &context.typeDefs()[addTyp]; curr = chunk; for(int i=0; inPointers>0) { LocalizeObject(context, false, descDep, curr, (DDD_OBJ)curr, theSymTab); } curr += CEIL(descDep->size); } } else { /* addType>=DDD_USER_DATA && addType <= DDD_USER_DATA_MAX -> scatter stream of bytes with len addCnt */ curr = chunk + CEIL(addCnt); } /* scatter data via handler */ if (desc->handlerXFERSCATTER) { desc->handlerXFERSCATTER(context, obj, addCnt, addTyp, (void *)chunk, newness); } } else { /* variable sized chunks */ addCnt *= -1; /* convert offset table into pointer table */ TYPE_DESC* descDep = &context.typeDefs()[addTyp]; char** table = (char **)chunk; chunk += CEIL(sizeof(int)*addCnt); char* adr = chunk; for(int i=0; iDDD_USER_DATA_MAX) { curr = table[i]; if (descDep->nPointers>0) LocalizeObject(context, false, descDep, curr, (DDD_OBJ)curr, theSymTab); } } /* scatter data via handler */ if (desc->handlerXFERSCATTERX) { desc->handlerXFERSCATTERX(context, obj, addCnt, addTyp, table, newness); } } chunk = curr; } } /****************************************************************************/ static void AcceptObjFromMsg ( DDD::DDDContext& context, OBJTAB_ENTRY *theObjTab, int lenObjTab, const char *theObjects, const DDD_HDR *localCplObjs, int nLocalCplObjs) { int i, j; for(i=0, j=0; ihdr)]; if (ote->is_new == OTHERMSG) { /* object is in another message with higher priority */ continue; } while ((jhdr))) j++; if ((jhdr))) { /* object already here, compare priorities. this is the implementation of rule XFER-C3. */ DDD_PRIO newprio; /* if local object should have been XferDelete'd, but the delete-cmd had been pruned (see cmdmsg.c), a flag has been set in its header. we have to ensure here that all incoming objects win against pruned-deleted ones, because the object serves only as 'cache' for data (esp. pointers) */ if (OBJ_PRUNED(localCplObjs[j])) { # if DebugUnpack<=1 Dune::dvverb << "NewPrio wins due to PruneDel. " << OBJ_GID(ote->hdr) << "\n"; # endif /* reset flag */ SET_OBJ_PRUNED(localCplObjs[j], 0); /* simply copy new priority, disregard old one */ newprio = OBJ_PRIO(ote->hdr); ote->is_new = PRUNEDNEW; } else { enum PrioMergeVals ret = PriorityMerge(desc, OBJ_PRIO(ote->hdr), OBJ_PRIO(localCplObjs[j]), &newprio); if (ret==PRIO_FIRST || ret==PRIO_UNKNOWN) /* incoming is higher or equal */ { DDD_OBJ copy; # if DebugUnpack<=1 Dune::dvverb << "NewPrio wins. " << OBJ_GID(ote->hdr) << "\n"; # endif /* new priority wins -> recreate */ /* all GDATA-parts are overwritten by contents of message */ copy = OTE_OBJ(context, theObjects,ote); ObjCopyGlobalData(desc, HDR2OBJ(localCplObjs[j],desc), copy, ote->size); ote->is_new = PARTNEW; } else /* existing is higher than incoming */ { # if DebugUnpack<=1 Dune::dvverb << "OldPrio wins. " << OBJ_GID(ote->hdr) << "\n"; # endif /* new priority loses -> keep existing obj */ ote->is_new = NOTNEW; } } /* store pointer to local object */ /* overwrite pointer to hdr inside message */ if (OBJ_TYPE(ote->hdr) != OBJ_TYPE(localCplObjs[j])) { printf("ERROR, copying changed the object type!\n"); printf(" was: %s, becomes: %s\n", context.typeDefs()[OBJ_TYPE(ote->hdr)].name, context.typeDefs()[OBJ_TYPE(localCplObjs[j])].name); assert(OBJ_TYPE(ote->hdr) == OBJ_TYPE(localCplObjs[j])); } ote->hdr = localCplObjs[j]; /* store old priority and set new one */ OTE_PRIO(theObjects,ote) = newprio; ote->oldprio = OBJ_PRIO(localCplObjs[j]); /* the next line is not useful. the current priority of the involved object will be changed to newprio-value after calling of handler SETPRIORITY. KB 970417 */ /* OBJ_PRIO(localCplObjs[j]) = newprio; */ } else { DDD_OBJ msgcopy, newcopy; DDD_PRIO new_prio = OBJ_PRIO(ote->hdr); # if DebugUnpack<=1 Dune::dvverb << "NewObject " << OBJ_GID(ote->hdr) << ", prio=" << new_prio << "\n"; # endif /* new object, create local copy */ msgcopy = OTE_OBJ(context, theObjects,ote); newcopy = DDD_ObjNew(ote->size, OBJ_TYPE(ote->hdr), new_prio, OBJ_ATTR(ote->hdr)); /* overwrite pointer to hdr inside message */ ote->hdr = OBJ2HDR(newcopy,desc); /* copy GDATA */ ObjCopyGlobalData(desc, newcopy, msgcopy, ote->size); ote->is_new = TOTALNEW; /* construct HDR */ DDD_HdrConstructorCopy(context, ote->hdr, new_prio); /* construct LDATA */ if (desc->handlerLDATACONSTRUCTOR) desc->handlerLDATACONSTRUCTOR(context, newcopy); } } } static void AcceptReceivedObjects (DDD::DDDContext& context, const LC_MSGHANDLE *theMsgs, int nRecvMsgs, OBJTAB_ENTRY **allRecObjs, int nRecObjs, const DDD_HDR *localCplObjs, int nLocalCplObjs) { /* allRecObjs is a pointer array to all OBJTAB_ENTRYs received in incoming messages. it is sorted according to (gid/ascending). 1. collision detection for incoming objects with same gid: accept object with merged priority. if several such objects exist, an arbitrary one is chosen. discard all other objects with same gid. (RULE XFER-C2) 2. transfer objects from message into local memory. 3. propagate hdr-pointer to all OBJTAB_ENTRYs with equal gid. */ auto& ctx = context.xferContext(); int i; if (nRecObjs==0) return; /* 1. collision detection */ for(i=nRecObjs-1; i>0; i--) { if (OBJ_GID(allRecObjs[i]->hdr) != OBJ_GID(allRecObjs[i-1]->hdr)) { allRecObjs[i]->is_new = THISMSG; } else { DDD_PRIO newprio; int ret; ret = PriorityMerge(&context.typeDefs()[OBJ_TYPE(allRecObjs[i]->hdr)], OBJ_PRIO(allRecObjs[i]->hdr), OBJ_PRIO(allRecObjs[i-1]->hdr), &newprio); if (ret==PRIO_FIRST || ret==PRIO_UNKNOWN) { /* item i is winner */ OBJTAB_ENTRY *tmp; OBJ_PRIO(allRecObjs[i]->hdr) = newprio; /* switch first item i in second position i-1 */ /* item on first position will be discarded */ tmp = allRecObjs[i]; allRecObjs[i] = allRecObjs[i-1]; allRecObjs[i-1] = tmp; } else { /* item i-1 is winner */ OBJ_PRIO(allRecObjs[i-1]->hdr) = newprio; } /* mark item i invalid */ allRecObjs[i]->is_new = OTHERMSG; } } allRecObjs[0]->is_new = THISMSG; /* now the first item in a series of items with equal gid is the THISMSG-item, the following are OTHERMSG-items */ /* 2. transfer from message into local memory */ for(i=0; iis_new == OTHERMSG) { /* propagate hdr-pointer */ allRecObjs[i]->hdr = allRecObjs[i-1]->hdr; } } } /****************************************************************************/ static void AddAndSpread (DDD::DDDContext& context, DDD_HDR hdr, DDD_GID gid, DDD_PROC dest, DDD_PRIO prio, XICopyObj **itemsNO, int nNO) { int k; if (hdr!=NULL) AddCoupling(context, hdr, dest, prio); for(k=0; kdest != dest) NEW_AddCpl(context, itemsNO[k]->dest, gid, dest, prio); } } /* this function updates the couplings of local objects. the inputs for deciding which couplings have to be added are: for prev. existing objects: - sending to NEWOWNER-destinations - incoming NewCpl-items for previously existing objects for new (incoming) objects: - incoming NewCpl-items for new objects as a side effect this function sends XIAddCpl-items to NEWOWNER-procs. */ enum UpdateCpl_Cases { UCC_NONE, UCC_NO, UCC_NC, UCC_NO_AND_NC }; static void UpdateCouplings ( DDD::DDDContext& context, TENewCpl *itemsNC, int nNC, /* NewCpl */ OBJTAB_ENTRY **itemsO, int nO, /* Objects */ const DDD_HDR *itemsLCO, int nLCO, /* local objs with coupling */ XIDelObj **itemsDO, int nDO, /* XIDelObj */ XICopyObj **itemsNO, int nNO) /* NewOwners */ { const auto& me = context.me(); const auto& procs = context.procs(); int iNC, iO, iDO, iNO, iLCO; /* each NewCpl either corresponds to an incoming object or to a local object, but not both. */ /*** loop for all incoming objects ***/ for(iO=0, iNC=0, iDO=0; iOhdr; DDD_GID gid = OBJ_GID(hdr); /* scan DelObj-entries for given gid */ while (iDOgid < gid) iDO++; /* if there is a DelObj-item with same gid, then the object has been deleted and send by a remote proc afterwards. we must: - restore old couplings locally - invalidate XIDelCpl-items */ if (iDOgid == gid) { XIDelCpl *dc = itemsDO[iDO]->delcpls; for( ; dc!=NULL; dc=dc->next) { /* restore previous coupling */ if (dc->prio!=PRIO_INVALID) AddCoupling(context, hdr, dc->to, dc->prio); /* invalidate XIDelCpl-item */ dc->to=procs; } /* restore only one time */ itemsDO[iDO]->delcpls = NULL; } /* scan NewCpl-entries for given gid */ while (iNCgid==itemsNO[iNO]->gid) iNO++; lastNO = iNO; nNOset = 1+lastNO-firstNO; setNO = itemsNO+firstNO; /* scan all NewCpl-items with same gid, and set first/last indices */ firstNC = iNC; while (iNCgid; moreNC = (iNCgid < gidNO) iDO++; if (! (iDOgid==gidNO)) { /* there is no DelObj-item */ hdrNO = setNO[0]->hdr; } /* scan received objects */ while (iOhdr) < gidNO) iO++; if (iOhdr)==gidNO) { /* obj has been deleted and received again */ assert(hdrNO==NULL || hdrNO==itemsO[iO]->hdr); hdrNO = itemsO[iO]->hdr; } } switch (curr_case) { case UCC_NONE : /* no other case is valid -> do nothing */ break; case UCC_NO : /* there is a NewOwner set without NewCpl set */ { int jNO; for(jNO=0; jNOdest, setNO[jNO]->prio, setNO, nNOset); } /* step to next gid */ iNO = lastNO+1; iNC = firstNC; } break; case UCC_NC : /* there is a NewCpl set without NewOwner set */ { int jNC; for(jNC=firstNC; jNC<=lastNC; jNC++) { if (hdrNC!=NULL) AddCoupling(context, hdrNC, NewCpl_GetDest(itemsNC[jNC]), NewCpl_GetPrio(itemsNC[jNC])); /* else: dont need to AddCpl to deleted object */ } /* step to next gid */ iNC = lastNC+1; iNO = firstNO; } break; case UCC_NO_AND_NC : /* there are both NewCpl and NewOwner sets */ { DDD_HDR hdr; int jNO, jNC; /* same gids -> same object and header */ assert(hdrNO==NULL || hdrNC==NULL || hdrNO==hdrNC); if (hdrNO==NULL) hdr = hdrNC; else hdr = hdrNO; jNC = firstNC; for(jNO=0; jNOdest) { AddAndSpread(context, hdr, gidNO, NewCpl_GetDest(itemsNC[jNC]), NewCpl_GetPrio(itemsNC[jNC]), setNO, nNOset); jNC++; } if (jNC<=lastNC && NewCpl_GetDest(itemsNC[jNC]) == setNO[jNO]->dest) { /* found NewCpl-item */ DDD_PRIO newprio; PriorityMerge(&context.typeDefs()[NewCpl_GetType(itemsNC[jNC])], setNO[jNO]->prio, NewCpl_GetPrio(itemsNC[jNC]), &newprio); AddAndSpread(context, hdr, gidNO, setNO[jNO]->dest, newprio, setNO, nNOset); jNC++; } else { /* there is no NewCpl-item for given dest */ AddAndSpread(context, hdr, gidNO, setNO[jNO]->dest, setNO[jNO]->prio, setNO, nNOset); } } while (jNC<=lastNC) { AddAndSpread(context, hdr, gidNO, NewCpl_GetDest(itemsNC[jNC]), NewCpl_GetPrio(itemsNC[jNC]), setNO, nNOset); jNC++; } /* step to next gid */ iNO = lastNO+1; iNC = lastNC+1; } break; default : assert(0); break; } } } /* this function handles local objects, which had been here before xfer. during xfer, another object with same gid was received and lead to a higher priority. this priority change must be communicated to all destination-procs, to which the local processor sent a copy during xfer. */ static void PropagateIncomings ( DDD::DDDContext& context, XICopyObj **arrayNO, int nNO, OBJTAB_ENTRY **allRecObjs, int nRecObjs) { int iRO, iNO; for(iRO=0, iNO=0; iROis_new; if (newness==PARTNEW || newness==PRUNEDNEW || newness==TOTALNEW) { COUPLING *cpl; /* object has been local before, but changed its prio */ OBJTAB_ENTRY *ote = allRecObjs[iRO]; /* scan received objects */ while ((iNOgid < OBJ_GID(ote->hdr))) iNO++; /* communicate to all NEWOWNER-destinations */ while (iNOgid == OBJ_GID(ote->hdr)) { if (newness==PARTNEW || newness==PRUNEDNEW) { XIModCpl *xc = NewXIModCpl(context); if (xc==NULL) throw std::bad_alloc(); xc->to = arrayNO[iNO]->dest; /* receiver of XIModCpl*/ xc->te.gid = OBJ_GID(ote->hdr); /* the object's gid */ xc->te.prio = OBJ_PRIO(ote->hdr); /* the obj's new prio */ xc->typ = OBJ_TYPE(ote->hdr); /* the obj's ddd-type */ } iNO++; } /* communicate to all procs in coupling */ for(cpl=ObjCplList(context, ote->hdr); cpl!=NULL; cpl=CPL_NEXT(cpl)) { /* if (newness==PARTNEW || newness==PRUNEDNEW) { */ XIModCpl *xc = NewXIModCpl(context); if (xc==NULL) throw std::bad_alloc(); xc->to = CPL_PROC(cpl); /* receiver of XIModCpl*/ xc->te.gid = OBJ_GID(ote->hdr); /* the object's gid */ xc->te.prio = OBJ_PRIO(ote->hdr); /* the obj's new prio */ xc->typ = OBJ_TYPE(ote->hdr); /* the obj's ddd-type */ /* } */ } } } } /****************************************************************************/ static void LocalizeSymTab (DDD::DDDContext& context, LC_MSGHANDLE xm, OBJTAB_ENTRY **allRecObjs, int nRecObjs, const DDD_HDR *localCplObjs, int nLocalCplObjs) { auto& ctx = context.xferContext(); SYMTAB_ENTRY *theSymTab; int i, j; int lenSymTab = (int) LC_GetTableLen(xm, ctx.symtab_id); /* get table addresses inside message buffer */ theSymTab = (SYMTAB_ENTRY *) LC_GetPtr(xm, ctx.symtab_id); /* insert pointers to known objects into SymTab */ for(i=0, j=0; ihdr)hdr)==theSymTab[i].gid)) { theSymTab[i].adr.hdr = allRecObjs[j]->hdr; } } } static void LocalizeObjects (DDD::DDDContext& context, LC_MSGHANDLE xm, bool required_newness) { auto& ctx = context.xferContext(); const SYMTAB_ENTRY *theSymTab; const OBJTAB_ENTRY *theObjTab; const char *theObjects; int i; int lenObjTab = (int) LC_GetTableLen(xm, ctx.objtab_id); /* get table addresses inside message buffer */ theSymTab = (const SYMTAB_ENTRY *) LC_GetPtr(xm, ctx.symtab_id); theObjTab = (const OBJTAB_ENTRY *) LC_GetPtr(xm, ctx.objtab_id); theObjects = (const char *) LC_GetPtr(xm, ctx.objmem_id); for(i=0; inPointers>0) { LocalizeObject(context, false, desc, (char *)(OTE_OBJ(context, theObjects,&(theObjTab[i]))), obj, theSymTab); } } #ifdef MERGE_MODE_IN_TESTZUSTAND if (required_newness && theObjTab[i].is_new!=TOTALNEW) { /* implemented merge_mode for Localize. references from all copies will be merged into the local copy. 960813 KB */ TYPE_DESC *desc = &context.typeDefs()[OBJ_TYPE(theObjTab[i].hdr)]; DDD_OBJ obj = HDR2OBJ(theObjTab[i].hdr, desc); if (desc->nPointers>0) { #ifdef DEBUG_MERGE_MODE printf("LocalizeObject in merge_mode, %08x prio %d\n", OBJ_GID(theObjTab[i].hdr), OBJ_PRIO(theObjTab[i].hdr)); #endif /* execute Localize in merge_mode */ LocalizeObject(context, true, desc, (char *)(OTE_OBJ(context, theObjects,&(theObjTab[i]))), obj, theSymTab); } } #endif } } static void CallUpdateHandler (DDD::DDDContext& context, LC_MSGHANDLE xm) { auto& ctx = context.xferContext(); OBJTAB_ENTRY *theObjTab; int lenObjTab = (int) LC_GetTableLen(xm, ctx.objtab_id); int i; /* get table addresses inside message buffer */ theObjTab = (OBJTAB_ENTRY *) LC_GetPtr(xm, ctx.objtab_id); /* initialize new objects corresponding to application: update */ for(i=0; i0) { int newness = -1; if (required_newness) { if (theObjTab[i].is_new==TOTALNEW) { newness = XFER_NEW; } } else { if (theObjTab[i].is_new!=TOTALNEW) { switch (theObjTab[i].is_new) { case OTHERMSG : newness=XFER_REJECT; break; case NOTNEW : newness=XFER_REJECT; break; case PARTNEW : newness=XFER_UPGRADE; break; case PRUNEDNEW : newness=XFER_UPGRADE; break; /* TODO: for PRUNEDNEW we should merge prios; might be XFER_DOWNGRADE... */ } } } if (newness!=-1) { TYPE_DESC *desc = &context.typeDefs()[OBJ_TYPE(theObjTab[i].hdr)]; DDD_OBJ obj = HDR2OBJ(theObjTab[i].hdr, desc); char *data; /* compute begin of data section. theObjTab[i].size is equal to desc->len for fixed sized objects and different for variable sized objects */ data = (char *)(OTE_OBJ(context, theObjects,&(theObjTab[i])) + CEIL(theObjTab[i].size)); PutDepData(context, data, desc, obj, theSymTab, newness); } } } } /* in order to allow application reactions on a priority change, the SETPRIORITY-handler is called. TODO: is this really a reason for calling SETPRIORITY? or should there be a separate handler for this task? NOTE: due to the current implementation, the new priority has already been set in the local object's DDD_HEADER. but the SETPRIORITY-handler has to get the old priority inside the object and the new one as second argument. so we restore the old prio before calling the handler and set the newprio afterwards. */ static void CallSetPriorityHandler (DDD::DDDContext& context, LC_MSGHANDLE xm) { auto& ctx = context.xferContext(); OBJTAB_ENTRY *theObjTab; int lenObjTab = (int) LC_GetTableLen(xm, ctx.objtab_id); int i; char *theObjects; /* get table addresses inside message buffer */ theObjTab = (OBJTAB_ENTRY *) LC_GetPtr(xm, ctx.objtab_id); theObjects = (char *) LC_GetPtr(xm, ctx.objmem_id); for(i=0; i& theSP, XIDelObj **arrayDO, int nDO, const std::vector& arrayCO, XICopyObj **arrayNewOwners, int nNewOwners) { auto& ctx = context.xferContext(); TENewCpl *allNewCpl; OBJTAB_ENTRY **unionObjTab; int lenObjTab, lenSymTab, nNewCpl; int i, pos1, pos2; XISetPrio** arraySP = theSP.data(); const int nSP = theSP.size(); lenObjTab=lenSymTab=nNewCpl=0; for(i=0; i0) { allNewCpl = (TENewCpl *) OO_Allocate (sizeof(TENewCpl)*nNewCpl); if (allNewCpl == nullptr) throw std::bad_alloc(); } else { allNewCpl = NULL; } if (lenObjTab>0) { unionObjTab = (OBJTAB_ENTRY **) OO_Allocate (sizeof(OBJTAB_ENTRY *)*lenObjTab); if (unionObjTab == nullptr) throw std::bad_alloc(); } else { unionObjTab = NULL; } /*STAT_TIMER3(25); STAT_RESET3;*/ /* create union tables: allNewCpl, unionObjTab */ for(i=0, pos1=pos2=0; i0) { memcpy(allNewCpl+pos1, LC_GetPtr(xm,ctx.newcpl_id), sizeof(TENewCpl)*len); pos1 += len; } len = (int) LC_GetTableLen(xm, ctx.objtab_id); if (len>0) { OBJTAB_ENTRY *msg_ot = (OBJTAB_ENTRY *) LC_GetPtr(xm,ctx.objtab_id); OBJTAB_ENTRY **all_ot = unionObjTab+pos2; int oti; for(oti=0; otihdr = OTE_HDR(theObjects,msg_ot); } pos2 += len; } } if (nNewCpl>0) { nNewCpl = CompressNewCpl(context, allNewCpl, nNewCpl); } if (lenObjTab>0) { std::sort(unionObjTab, unionObjTab + lenObjTab, sort_ObjTabPtrs); } # if DebugUnpack<=2 for(i=0; i0) { AcceptReceivedObjects( context, theMsgs, nRecvMsgs, unionObjTab, lenObjTab, localCplObjs, nLocalCplObjs ); } /* TODO: the following loops can be implemented more efficiently. in each loop, there is another loop across all objects inside the message. for each object, the TypeDesc is computed. the typedesc pointers should be computed once and stored somewhere. kb 970115 */ /* insert local references into symtabs */ for(i=0; i1 if (DDD_GetOption(context, OPT_DEBUG_XFERMESGS)==OPT_ON) # endif { for(i=0; i #include #include #include #include #include #include #include #include #include "xfer.h" using namespace PPIF; START_UGDIM_NAMESPACE /****************************************************************************/ /* */ /* routines */ /* */ /****************************************************************************/ static bool sort_NewOwners (const XICopyObj* a, const XICopyObj* b) { return std::tie(a->gid, a->dest) < std::tie(b->gid, b->dest); } /****************************************************************************/ /* collect a temporary list of XINewCpl-items. for each XICopyObj-command whose destination doesn't have an object copy already do: create a set of XINewCpl-items, one for every processor which owns a copy of the local object. this is an estimate, because without communication the sending processor cannot know whether the object copy will be accepted. this final information will be transferred in a second pass, as soon as the receiver has decided whether he accepts the incoming object or not (depending on rules XFER-C2, XFER-C3, XFER-C4, XFER-P and XFER-D). */ XICopyObj **CplClosureEstimate (DDD::DDDContext& context, const std::vector& arrayItems, int *nRet) { const auto& me = context.me(); int i, nNewOwners; XICopyObj **arrayNewOwners = NULL; XICopyObj* const* items = arrayItems.data(); const int n = arrayItems.size(); nNewOwners=0; for(i=0; idest; /* destination proc */ COUPLING *cpl, *xicpl = ObjCplList(context, xi->hdr); DDD_GID xigid = xi->gid; DDD_TYPE xitype = OBJ_TYPE(xi->hdr); SET_CO_NEWOWNER(xi); /* look if there's a coupling for dest */ for(cpl=xicpl; cpl!=NULL; cpl=CPL_NEXT(cpl)) { if (dest==CPL_PROC(cpl)) { /* got one coupling, destination is not a new owner */ CLEAR_CO_NEWOWNER(xi); /* destination proc had a copy before xfer */ /* check whether priority of that copy will change */ /* if (WhichPrioWins(xi->prio, cpl->prio)==1) { */ /* new prio will win on other proc -> adapt coupling */ /* printf("%4d: XXXCoupling %08x proc=%d prio=%d\n", me,xigid,dest,xi->prio); cpl->prio = xi->prio; } */ /* this should be the only coupling for that proc. leave loop prematurely. */ break; } } if (CO_NEWOWNER(xi)) { nNewOwners++; /* destination proc didn't have a copy before xfer */ /* inform other owners of local copies (XINewCpl) */ for(cpl=xicpl; cpl!=NULL; cpl=CPL_NEXT(cpl)) { XINewCpl *xc = NewXINewCpl(context); if (xc==NULL) throw std::bad_alloc(); xc->to = CPL_PROC(cpl); /* receiver of XINewCpl */ NewCpl_SetDest(xc->te,dest); /* destination of XICopyObj*/ NewCpl_SetGid(xc->te,xigid); /* the object's gid */ NewCpl_SetPrio(xc->te,xi->prio); /* new obj's priority */ NewCpl_SetType(xc->te,xitype); /* the object's type */ } /* send current couplings (XIOldCpl) to new destination */ /* note: destination proc can get this information multiple times, once for each incoming object with same gid (from different senders) */ for(cpl=xicpl; cpl!=NULL; cpl=CPL_NEXT(cpl)) { XIOldCpl *xc = NewXIOldCpl(context); if (xc==NULL) throw std::bad_alloc(); xc->to = dest; /* receiver of XIOldCpl */ xc->te.gid = xigid; /* the object's gid */ xc->te.proc = CPL_PROC(cpl); /* coupling proc */ xc->te.prio = cpl->prio; /* coupling priority */ } /* send one coupling (XIOldCpl) for local copy */ { XIOldCpl *xc = NewXIOldCpl(context); if (xc==NULL) throw std::bad_alloc(); xc->to = dest; /* receiver of XIOldCpl */ xc->te.gid = xigid; /* the object's gid */ xc->te.proc = me; /* coupling proc */ xc->te.prio = OBJ_PRIO(xi->hdr); /* coupling priority */ } } } *nRet = nNewOwners; /* printf("%4d: nNewOwners=%d\n", me, nNewOwners); */ /* check multiple new-owner-destinations for same gid */ if (nNewOwners>0) { int j, k; arrayNewOwners = (XICopyObj **) OO_Allocate (sizeof(XICopyObj *)* nNewOwners); if (arrayNewOwners==NULL) { DDD_PrintError('E', 6102, STR_NOMEM " in XferEnd()"); return NULL; } /* fill pointer array XICopyObj-items marked CO_NEWOWNER */ for(j=0, k=0; jgid; for(k=j+1; kgid != gid1) break; no2type = OBJ_TYPE(no2->hdr); /* inform other new-owners of same obj (also XINewCpl!) */ /* tell no1-dest that no2-dest gets a copy with no2->prio */ { XINewCpl *xc = NewXINewCpl(context); if (xc==NULL) throw std::bad_alloc(); xc->to = no1->dest; /* receiver of XINewCpl */ NewCpl_SetDest(xc->te,no2->dest); /* dest of XICopyObj */ NewCpl_SetGid(xc->te,gid1); /* the obj's gid */ NewCpl_SetPrio(xc->te,no2->prio); /* new obj's priority*/ NewCpl_SetType(xc->te,no2type); /* the obj's type */ } /* tell no2->dest that no1-dest gets a copy with no1->prio */ { XINewCpl *xc = NewXINewCpl(context); if (xc==NULL) throw std::bad_alloc(); xc->to = no2->dest; /* receiver of XINewCpl */ NewCpl_SetDest(xc->te,no1->dest); /* dest of XICopyObj */ NewCpl_SetGid(xc->te,gid1); /* the obj's gid */ NewCpl_SetPrio(xc->te,no1->prio); /* new obj's priority*/ NewCpl_SetType(xc->te,no2type); /* the obj's type */ } } } } return(arrayNewOwners); } /****************************************************************************/ /* auxiliary functions for PrepareObjMsgs() */ static void BuildDepDataInfo (XFERMSG *xm, XICopyObj *xi) { XFERADDDATA *xa; int ptr, chunks; /* count characteristic values for each chunk */ chunks = ptr = 0; for(xa=xi->add; xa!=NULL; xa=xa->next) { ptr += xa->addNPointers; /* add control information size for var-sized AddData-Items */ if (xa->sizes!=NULL) xi->addLen += CEIL(sizeof(int) * xa->addCnt); chunks++; } /* add size of control information */ if (xi->addLen>0) xi->addLen += CEIL(sizeof(int)) + chunks*CEIL(2*sizeof(int)); /* add to current message size information */ xm->size += xi->addLen; xm->nPointers += ptr; } static XFERMSG *CreateXferMsg (DDD_PROC dest, XFERMSG *lastxm) { XFERMSG *xm; xm = (XFERMSG *) OO_Allocate (sizeof(XFERMSG)); if (xm==NULL) { DDD_PrintError('E', 6100, STR_NOMEM " in PrepareObjMsgs"); return NULL; } xm->nPointers = 0; xm->nObjects = 0; xm->proc = dest; xm->size = 0; xm->xferObjArray = NULL; xm->xferNewCpl = NULL; xm->xferOldCpl = NULL; xm->nObjItems = 0; xm->nNewCpl = 0; xm->nOldCpl = 0; xm->next = lastxm; return xm; } static XFERMSG *AccumXICopyObj (const DDD::DDDContext& context, XFERMSG *currxm, int *nMsgs, int *nItems, XICopyObj **items, DDD_PROC dest, int nmax) { XFERMSG *xm; int i; if (currxm!=NULL && currxm->proc==dest) { /* there is a XFERMSG with correct processor number -> reuse it */ xm = currxm; } else { /* create new XFERMSG structure */ xm = CreateXferMsg(dest, currxm); (*nMsgs)++; } # if DebugXfer<=2 Dune::dvverb << "PrepareObjMsgs, XferMsg" << " proc=" << dest << " nmax=" << nmax << "\n"; # endif for (i=0; idest==dest; i++) { XICopyObj *xi = items[i]; DDD_HDR hdr = xi->hdr; const TYPE_DESC& desc = context.typeDefs()[OBJ_TYPE(hdr)]; # if DebugXfer<=0 Dune::dvverb << "PrepareObjMsgs, proc=" << dest << " i=" i << "/" << nmax << " (" << xi->gid << ")\n"; # endif /* accumulate xfer-items in message-info */ xm->nObjects++; /* length of object itself, possibly variable */ xm->size += CEIL(xi->size); xm->nPointers += desc.nPointers; if (xi->add != NULL) BuildDepDataInfo(xm, xi); } *nItems = i; return xm; } static XFERMSG *AccumXINewCpl (XFERMSG *currxm, int *nMsgs, int *nItems, XINewCpl **items, DDD_PROC dest, int nmax) { XFERMSG *xm; int i; if (currxm!=NULL && currxm->proc==dest) { /* there is a XFERMSG with correct processor number -> reuse it */ xm = currxm; } else { /* create new XFERMSG structure */ xm = CreateXferMsg(dest, currxm); (*nMsgs)++; } # if DebugXfer<=2 Dune::dvverb << "PrepareObjMsgs, XferMsg" << " proc=" << dest << " nmax=" << nmax << "\n"; # endif for (i=0; ito==dest; i++) { # if DebugXfer<=0 XINewCpl *xi = items[i]; Dune::dvverb << "PrepareObjMsgs, proc=" << dest << " i=" i << "/" << nmax << " (" << NewCpl_GetGid(xi->te) << ")\n"; # endif } *nItems = i; return xm; } static XFERMSG *AccumXIOldCpl (XFERMSG *currxm, int *nMsgs, int *nItems, XIOldCpl **items, DDD_PROC dest, int nmax) { XFERMSG *xm; int i; if (currxm!=NULL && currxm->proc==dest) { /* there is a XFERMSG with correct processor number -> reuse it */ xm = currxm; } else { /* create new XFERMSG structure */ xm = CreateXferMsg(dest, currxm); (*nMsgs)++; } # if DebugXfer<=2 Dune::dvverb << "PrepareObjMsgs, XferMsg" << " proc=" << dest << " nmax=" << nmax << "\n"; # endif for (i=0; ito==dest; i++) { # if DebugXfer<=0 XIOldCpl *xi = items[i]; Dune::dvverb << "PrepareObjMsgs, proc=" << dest << " i=" i << "/" << nmax << " (" << xi->te.gid << ")\n"; # endif } *nItems = i; return xm; } /****************************************************************************/ /* prepare messages for phase 1. object copies will be sent as well as the estimated coupling closure from CplClosureEstimate(). */ int PrepareObjMsgs (DDD::DDDContext& context, std::vector& arrayO, XINewCpl **itemsNC, int nNC, XIOldCpl **itemsOC, int nOC, XFERMSG **theMsgs, size_t *memUsage) { auto& ctx = context.xferContext(); const auto& procs = context.procs(); XFERMSG *xm=NULL; int iO, iNC, iOC, nMsgs=0; XICopyObj** itemsO = arrayO.data(); const int nO = arrayO.size(); # if DebugXfer<=3 Dune::dverb << "PrepareObjMsgs," << " nXICopyObj=" << nO << " nXINewCpl=" << nNC << " nXIOldCpl=" << nOC << "\n"; # endif /* run through both itemsO and itemsNC/itemsOC simultaneously, each time a new proc-nr is encountered in one of these lists, create a new XFERMSG item. (the lists have been sorted according to proc-nr previously.) */ iO=0; iNC=0; iOC=0; while (iOdest : procs; DDD_PROC pNC = (iNCto : procs; DDD_PROC pOC = (iOCto : procs; if (pO<=pNC && pO<=pOC && pOxferObjArray = itemsO+iO; xm->nObjItems = n; iO += n; } if (pNC<=pO && pNC<=pOC && pNCxferNewCpl = itemsNC+iNC; xm->nNewCpl = n; iNC += n; } if (pOC<=pO && pOC<=pNC && pOCxferOldCpl = itemsOC+iOC; xm->nOldCpl = n; iOC += n; } if (pO==procs) iO = nO; if (pNC==procs) iNC = nNC; if (pOC==procs) iOC = nOC; } *theMsgs = xm; /* compute brutto message size from netto message size */ for(xm=*theMsgs; xm!=NULL; xm=xm->next) { size_t bufSize; xm->msg_h = LC_NewSendMsg(context, ctx.objmsg_t, xm->proc); LC_SetTableSize(xm->msg_h, ctx.symtab_id, xm->nPointers); LC_SetTableSize(xm->msg_h, ctx.objtab_id, xm->nObjects); LC_SetTableSize(xm->msg_h, ctx.newcpl_id, xm->nNewCpl); LC_SetTableSize(xm->msg_h, ctx.oldcpl_id, xm->nOldCpl); LC_SetChunkSize(xm->msg_h, ctx.objmem_id, xm->size); bufSize = LC_MsgFreeze(xm->msg_h); *memUsage += bufSize; if (DDD_GetOption(context, OPT_INFO_XFER) & XFER_SHOW_MEMUSAGE) { using std::setw; Dune::dwarn << "DDD MESG [" << setw(3) << "]: SHOW_MEM send msg " << " dest=" << setw(4) << xm->proc << " size=" << setw(10) << bufSize << "\n"; } } # if DebugXfer<=3 Dune::dverb << "PrepareObjMsgs, nMsgs=" << nMsgs << "\n"; # endif return(nMsgs); } /****************************************************************************/ /* execute SetPrio-commands and create those XIModCpl-items, which can be computed without knowledge of information sent by other procs during first message phase. */ void ExecLocalXISetPrio ( DDD::DDDContext& context, const std::vector& arrayP, XIDelObj **itemsD, int nD, XICopyObj **itemsNO, int nNO) { int iP, iD, iNO; XISetPrio* const* itemsP = arrayP.data(); const int nP = arrayP.size(); /* execute SetPrio only if no corresponding DelObj exists! */ for(iP=0, iD=0, iNO=0; iPhdr; DDD_GID gid = sp->gid; DDD_PRIO newprio = sp->prio; while ((iDgidgidis_valid = (! ((iDgid==gid))); if (sp->is_valid) { /* SetPrio, but _no_ DelObj: execute SetPrio */ DDD_TYPE typ = OBJ_TYPE(hdr); const TYPE_DESC& desc = context.typeDefs()[typ]; /* call application handler for changing prio of dependent objects */ if (desc.handlerSETPRIORITY) { DDD_OBJ obj = HDR2OBJ(hdr, &desc); desc.handlerSETPRIORITY(context, obj, newprio); } /* change actual priority to new value */ OBJ_PRIO(hdr) = newprio; /* generate XIModCpl-items */ /* 1. for all existing couplings */ for (COUPLING *cpl = ObjCplList(context, hdr); cpl != NULL; cpl = CPL_NEXT(cpl)) { XIModCpl *xc = NewXIModCpl(context); if (xc==NULL) throw std::bad_alloc(); xc->to = CPL_PROC(cpl); /* receiver of XIModCpl */ xc->te.gid = gid; /* the object's gid */ xc->te.prio = newprio; /* the object's new prio */ xc->typ = typ; /* the object's type */ } /* 2. for all CopyObj-items with new-owner destinations */ while (iNOgid==gid) { XIModCpl *xc = NewXIModCpl(context); if (xc==NULL) throw std::bad_alloc(); xc->to = itemsNO[iNO]->dest; /* receiver of XIModCpl */ xc->te.gid = gid; /* the object's gid */ xc->te.prio = newprio; /* the object's new prio */ xc->typ = typ; /* the object's type */ iNO++; } } /* else: SetPrio _and_ DelObj, SetPrio is invalid, DelObj will be executed lateron (this is rule XFER-M1). */ } } /* execute local DelObj-commands and create those XIDelCpl-items, which can be computed without knowledge of information sent by other procs during first message phase. */ void ExecLocalXIDelCmd (DDD::DDDContext& context, XIDelCmd **itemsD, int nD) { int iD; XIDelCmd **origD; if (nD==0) return; /* reconstruct original order of DelObj commands */ origD = (XIDelCmd **) OO_Allocate (sizeof(XIDelCmd *) * nD); if (origD==NULL) throw std::bad_alloc(); /* copy pointer array and resort it */ memcpy(origD, itemsD, sizeof(XIDelCmd *) * nD); OrigOrderXIDelCmd(context, origD, nD); /* loop in original order (order of Del-cmd issuing) */ for(iD=0; iDhdr; DDD_TYPE typ = OBJ_TYPE(hdr); const TYPE_DESC& desc = context.typeDefs()[typ]; DDD_OBJ obj = HDR2OBJ(hdr, &desc); /* do deletion */ if (desc.handlerDELETE) desc.handlerDELETE(context, obj); else { /* TODO the following three calls should be collected in one ObjMgr function */ /* destruct LDATA and GDATA */ if (desc.handlerDESTRUCTOR) desc.handlerDESTRUCTOR(context, obj); /* HdrDestructor will call ddd_XferRegisterDelete() */ DDD_HdrDestructor(context, hdr); DDD_ObjDelete(obj, desc.size, typ); } } OO_Free (origD /*,0*/); } void ExecLocalXIDelObj ( DDD::DDDContext& context, XIDelObj **itemsD, int nD, XICopyObj **itemsNO, int nNO) { int iD, iNO; /* create XIDelCpl for all DelObj-commands (sorted acc. to gid) */ for(iD=0, iNO=0; iDgid; /* skip XICopyObj-items until entries for gid found */ while (iNOgidgid==gid) { XIDelCpl *xc = NewXIDelCpl(context); if (xc==NULL) throw std::bad_alloc(); xc->to = itemsNO[iNO]->dest; /* receiver of XIDelCpl */ xc->prio = PRIO_INVALID; /* dont remember priority */ xc->te.gid = gid; /* the object's gid */ /* we must remember couplings for eventual restoring (if this object is received from another proc) */ xc->next = itemsD[iD]->delcpls; itemsD[iD]->delcpls = xc; iNO++; } } } /****************************************************************************/ /* create those XI???Cpl-items, which require knowledge of information sent by other procs during first message phase. */ void PropagateCplInfos ( DDD::DDDContext& context, XISetPrio **itemsP, int nP, XIDelObj **itemsD, int nD, TENewCpl *arrayNC, int nNC) { int iP, iD, iNC; /* step 1: create XIModCpl-items from SetPrio-cmds (only if no DelObj-items exist) */ for(iP=0, iNC=0; iPis_valid) { DDD_HDR hdr = sp->hdr; DDD_GID gid = sp->gid; DDD_PRIO newprio = sp->prio; /* skip TENewCpl-entries until one for gid found */ while (iNCto = NewCpl_GetDest(arrayNC[iNC]); xc->te.gid = gid; /* the object's gid */ xc->te.prio = newprio; /* the object's new prio */ xc->typ = OBJ_TYPE(hdr); /* the object's type */ iNC++; } } } /* step 2: create XIDelCpl-items from DelObj-cmds */ for(iD=0, iNC=0; iDgid; /* skip TENewCpl-entries until one for gid found */ while (iNCto = NewCpl_GetDest(arrayNC[iNC]); /* receiver of XIDelCpl */ xc->prio = PRIO_INVALID; xc->te.gid = gid; /* the object's gid */ /* printf("%4d: DelCpl 3 %08x %d %d\n",me,gid,xc->to,xc->prio); */ iNC++; } } } /****************************************************************************/ /* this function is called by DDD_HdrDestructor! */ void ddd_XferRegisterDelete (DDD::DDDContext& context, DDD_HDR hdr) { COUPLING *cpl; XIDelObj *xi; /* create new XIDelObj */ xi = NewXIDelObj(context); if (xi==NULL) throw std::bad_alloc(); xi->gid = OBJ_GID(hdr); xi->delcpls = NULL; /* now generate XIDelCpl-items, one for each existing coupling. these items serve as notification of this delete operation for remote processors with same object. these items are also a intermediate storage for the object's coupling list, in case the object is received after deletion and the coupling list must be restored. */ for(cpl=ObjCplList(context, hdr); cpl!=NULL; cpl=CPL_NEXT(cpl)) { XIDelCpl *xc = NewXIDelCpl(context); if (xc==NULL) throw std::bad_alloc(); xc->to = CPL_PROC(cpl); /* receiver of XIDelCpl */ xc->prio = cpl->prio; /* remember priority */ xc->te.gid = OBJ_GID(hdr); /* the object's gid */ /* we must remember couplings for eventual restoring (if this object is received from another proc) */ xc->next = xi->delcpls; xi->delcpls = xc; } } /****************************************************************************/ /* management functions for XferMode. these functions control the mode the xfer-module is currently in. this is used for error detection, but also for correct detection of coupling inconsistencies and recovery. */ const char *XferModeName (enum XferMode mode) { switch(mode) { case DDD::Xfer::XferMode::XMODE_IDLE : return "idle-mode"; case DDD::Xfer::XferMode::XMODE_CMDS : return "commands-mode"; case DDD::Xfer::XferMode::XMODE_BUSY : return "busy-mode"; } return "unknown-mode"; } static void XferSetMode(DDD::DDDContext& context, enum XferMode mode) { auto& ctx = context.xferContext(); ctx.xferMode = mode; # if DebugXfer<=8 Dune::dwarn << "XferMode=" << XferModeName(ctx.xferMode) << "\n"; # endif } static enum XferMode XferSuccMode (enum XferMode mode) { switch(mode) { case DDD::Xfer::XferMode::XMODE_IDLE : return DDD::Xfer::XferMode::XMODE_CMDS; case DDD::Xfer::XferMode::XMODE_CMDS : return DDD::Xfer::XferMode::XMODE_BUSY; case DDD::Xfer::XferMode::XMODE_BUSY : return DDD::Xfer::XferMode::XMODE_IDLE; } DUNE_THROW(Dune::InvalidStateException, "invalid XferMode"); } enum XferMode XferMode (const DDD::DDDContext& context) { return context.xferContext().xferMode; } int ddd_XferActive(const DDD::DDDContext& context) { return context.xferContext().xferMode != DDD::Xfer::XferMode::XMODE_IDLE; } int XferStepMode (DDD::DDDContext& context, enum XferMode old) { const auto& ctx = context.xferContext(); if (ctx.xferMode!=old) { Dune::dwarn << "wrong xfer-mode (currently in " << XferModeName(ctx.xferMode) << ", expected " << XferModeName(old) << ")\n"; return false; } XferSetMode(context, XferSuccMode(ctx.xferMode)); return true; } /****************************************************************************/ void ddd_XferInit(DDD::DDDContext& context) { auto& ctx = context.xferContext(); /* init control structures for XferInfo-items in first (?) message */ ctx.setXICopyObj = reinterpret_cast(New_XICopyObjSet()); reinterpret_cast(ctx.setXICopyObj)->tree->context = &context; ctx.setXISetPrio = reinterpret_cast(New_XISetPrioSet()); reinterpret_cast(ctx.setXISetPrio)->tree->context = &context; InitXIDelCmd(context); InitXIDelObj(context); InitXINewCpl(context); InitXIOldCpl(context); /* init control structures for XferInfo-items for second (?) message */ InitXIDelCpl(context); InitXIModCpl(context); InitXIAddCpl(context); XferSetMode(context, DDD::Xfer::XferMode::XMODE_IDLE); ctx.objmsg_t = LC_NewMsgType(context, "XferMsg"); ctx.symtab_id = LC_NewMsgTable("SymTab", ctx.objmsg_t, sizeof(SYMTAB_ENTRY)); ctx.objtab_id = LC_NewMsgTable("ObjTab", ctx.objmsg_t, sizeof(OBJTAB_ENTRY)); ctx.newcpl_id = LC_NewMsgTable("NewCpl", ctx.objmsg_t, sizeof(TENewCpl)); ctx.oldcpl_id = LC_NewMsgTable("OldCpl", ctx.objmsg_t, sizeof(TEOldCpl)); ctx.objmem_id = LC_NewMsgChunk("ObjMem", ctx.objmsg_t); /* not used anymore ctx.deltab_id = LC_NewMsgTable(ctx.objmsg_t, sizeof(DELTAB_ENTRY)); ctx.priotab_id = LC_NewMsgTable(ctx.objmsg_t, sizeof(CPLTAB_ENTRY)); */ CplMsgInit(context); CmdMsgInit(context); } void ddd_XferExit(DDD::DDDContext& context) { auto& ctx = context.xferContext(); CmdMsgExit(context); CplMsgExit(context); XICopyObjSet_Free(reinterpret_cast(ctx.setXICopyObj)); XISetPrioSet_Free(reinterpret_cast(ctx.setXISetPrio)); } END_UGDIM_NAMESPACE dune-uggrid-2.11.0+dfsg/dune/uggrid/parallel/ddd/xfer/xfer.h000066400000000000000000000501311513616443000235530ustar00rootroot00000000000000// -*- tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- // vi: set et ts=4 sw=2 sts=2: // SPDX-FileCopyrightInfo: Copyright © DUNE Project contributors, see file LICENSE.md in module root // SPDX-License-Identifier: LGPL-2.1-or-later /****************************************************************************/ /* */ /* File: xfer.h */ /* */ /* Purpose: header file for xfer module */ /* */ /* Author: Klaus Birken */ /* Rechenzentrum Uni Stuttgart */ /* Universitaet Stuttgart */ /* Allmandring 30 */ /* 70550 Stuttgart */ /* internet: birken@rus.uni-stuttgart.de */ /* */ /* */ /* History: 931122 kb begin */ /* 950404 kb copied from dddi.h */ /* 960718 kb introduced lowcomm-layer (sets of messages) */ /* */ /* Remarks: */ /* */ /****************************************************************************/ /****************************************************************************/ /* */ /* auto include mechanism and other include files */ /* */ /****************************************************************************/ #ifndef __XFER_H__ #define __XFER_H__ #include #define DebugXfer 10 /* 0 is all, 10 is off */ #define DebugPack 6 /* off: 6 */ #define DebugUnpack 5 /* off: 5 */ #define DebugCmdMsg 10 /* off: 10 */ #define DebugCplMsg 10 /* off: 10 */ #include #include /* for object-orientated style via preprocessor */ #include "sll.h" /* TODO: remove this in future versions */ START_UGDIM_NAMESPACE #define SUPPORT_RESENT_FLAG /* define this to use as small types as possible. for debugging, try it without this define */ #define SMALL_TYPES_BY_CASTS /****************************************************************************/ /* */ /* defines in the following order */ /* */ /* compile time constants defining static data size (i.e. arrays) */ /* other constants */ /* macros */ /* */ /****************************************************************************/ /* some macros for customizing oopp */ #define _NEWPARAMS #define _NEWPARAMS_OR_VOID void #define __INDENT(n) { int i; for(i=0; i proc */ DDD_PRIO prio; /* priority for new object copy */ size_t size; /* V1.2: needed for variable-sized objects */ int addLen; XFERADDDATA *add; /* additional data items */ int flags; }; } /* namespace Xfer */ } /* namespace DDD */ START_UGDIM_NAMESPACE using DDD::Xfer::XFERADDDATA; using DDD::Xfer::XICopyObj; #define ClassName XICopyObj void Method(Print) (DefThis _PRINTPARAMS); int Method(Compare) (ClassPtr, ClassPtr, const DDD::DDDContext* context); #undef ClassName /* define container class */ #ifndef SetOf /* necessary for inline documentation only */ #define SetOf XICopyObj #define Set_SegmSize 256 #define Set_BTreeOrder 32 #endif #include /* usage of flags in XICopyObj */ /* usage of 0x01 while PruneXIDelCpl, temporarily */ #define MASK_CO_SELF 0x00000001 #define CO_SELF(c) (((int)((c)->flags))&MASK_CO_SELF) #define SET_CO_SELF(c,d) ((c)->flags) = \ ((((c)->flags)&(~MASK_CO_SELF)) | ((d)&MASK_CO_SELF)) /* usage of 0x02 for new_owner: did destination proc know the object's gid before? */ #define MASK_CO_NEWOWNER 0x00000002 #define CO_NEWOWNER(c) (((int)((c)->flags))&MASK_CO_NEWOWNER) #define SET_CO_NEWOWNER(c) ((c)->flags) = (((c)->flags) | MASK_CO_NEWOWNER) #define CLEAR_CO_NEWOWNER(c) ((c)->flags) = (((c)->flags)&(~MASK_CO_NEWOWNER)) /****************************************************************************/ /* XIDelObj: */ /****************************************************************************/ /* XIDelCmd represents a XferDeleteObj-cmd by the application program */ struct XIDelCmd { SLL_INFO_WITH_COUNTER(XIDelCmd); DDD_HDR hdr; }; /* include template */ #define T XIDelCmd #define SLL_WithOrigOrder #include "sll.ht" #undef T struct XIDelCpl; /* XIDelObj represents an object-delete-action (cf. XferRegisterDelete()) */ struct XIDelObj { SLL_INFO(XIDelObj); DDD_GID gid; /* gid of local object */ /* hdr is explicitly not stored here, because object may be deleted when this XIDelObj-item is evaluated. */ XIDelCpl *delcpls; /* couplings of deleted object */ }; /* include template */ #define T XIDelObj #include "sll.ht" #undef T /****************************************************************************/ /* XISetPrio: */ /****************************************************************************/ #define ClassName XISetPrio Class_Data_Begin DDD_HDR hdr; /* local obj for which prio should be set */ DDD_GID gid; /* gid of local object */ DDD_PRIO prio; /* new priority */ int is_valid; /* invalid iff there's a DelObj for same gid */ Class_Data_End void Method(Print) (DefThis _PRINTPARAMS); int Method(Compare) (ClassPtr, ClassPtr, const DDD::DDDContext*); #undef ClassName /* define container class */ #ifndef SetOf /* necessary for inline documentation only */ #define SetOf XISetPrio #define Set_SegmSize 256 #define Set_BTreeOrder 32 #endif #include /****************************************************************************/ /* XINewCpl: */ /****************************************************************************/ struct TENewCpl { DDD_GID _gid; /* obj-gid for which new copy will be created */ DDD_PROC _dest; /* destination of new object copy */ DDD_PRIO_SMALL _prio; /* priority of new object copy */ DDD_TYPE_SMALL _type; /* ddd-type of gid for PriorityMerge on receiver*/ }; #define NewCpl_GetGid(i) ((i)._gid) #define NewCpl_SetGid(i,d) ((i)._gid = (d)) #define NewCpl_GetDest(i) ((i)._dest) #define NewCpl_SetDest(i,d) ((i)._dest = (d)) #ifdef SMALL_TYPES_BY_CASTS #define NewCpl_GetPrio(i) ((DDD_PRIO)(i)._prio) #define NewCpl_SetPrio(i,d) ((i)._prio = (DDD_PRIO_SMALL)(d)) #define NewCpl_GetType(i) ((DDD_TYPE)(i)._type) #define NewCpl_SetType(i,d) ((i)._type = (DDD_TYPE_SMALL)(d)) #else #define NewCpl_GetPrio(i) ((i)._prio) #define NewCpl_SetPrio(i,d) ((i)._prio = (d)) #define NewCpl_GetType(i) ((i)._type) #define NewCpl_SetType(i,d) ((i)._type = (d)) #endif struct XINewCpl { SLL_INFO(XINewCpl); DDD_PROC to; /* receiver of this item */ TENewCpl te; /* table entry (for message) */ }; /* include template */ #define T XINewCpl #include "sll.ht" #undef T /****************************************************************************/ /* XIOldCpl: */ /****************************************************************************/ struct TEOldCpl { DDD_GID gid; /* obj-gid of local copy */ DDD_PROC proc; /* owner of that local object */ DDD_PRIO prio; /* priority of that local object */ }; struct XIOldCpl { SLL_INFO(XIOldCpl); DDD_PROC to; /* receiver of this item */ TEOldCpl te; /* table entry (for message) */ }; /* include template */ #define T XIOldCpl #include "sll.ht" #undef T /****************************************************************************/ /* XIAddCpl: */ /****************************************************************************/ struct TEAddCpl { DDD_GID gid; /* obj-gid of new local object */ DDD_PROC proc; /* owner of new object copy */ DDD_PRIO prio; /* priority of new local object */ }; struct XIAddCpl { SLL_INFO(XIAddCpl); DDD_PROC to; /* receiver of this item */ TEAddCpl te; /* table entry (for message) */ }; /* include template */ #define T XIAddCpl #include "sll.ht" #undef T /****************************************************************************/ /* XIDelCpl: */ /****************************************************************************/ struct TEDelCpl { DDD_GID gid; /* obj-gid of deleted local object */ }; struct XIDelCpl { SLL_INFO(XIDelCpl); DDD_PROC to; /* receiver of this item */ TEDelCpl te; /* table entry (for message) */ DDD_PRIO prio; /* prio of deleted coupling */ XIDelCpl* next; /* linked list of XIDelCpls */ }; /* include template */ #define T XIDelCpl #include "sll.ht" #undef T /****************************************************************************/ /* XIModCpl: */ /****************************************************************************/ struct TEModCpl { DDD_GID gid; /* obj-gid of corresponding object */ DDD_PRIO prio; /* new priority for this obj on sending proc */ }; struct XIModCpl { SLL_INFO(XIModCpl); DDD_PROC to; /* receiver of this item */ TEModCpl te; /* table entry (for message) */ DDD_TYPE typ; /* type of corresponding object */ }; /* include template */ #define T XIModCpl #include "sll.ht" #undef T /****************************************************************************/ /* XFERMSG: complete description about message on sender side */ /****************************************************************************/ struct XFERMSG { DDD_PROC proc; /* receiver of message */ size_t size; /* size of message data */ XFERMSG* next; XICopyObjPtr *xferObjArray; int nObjItems; XINewCpl **xferNewCpl; int nNewCpl; XIOldCpl **xferOldCpl; int nOldCpl; int nPointers; int nObjects; /* lowcomm message handle */ LC_MSGHANDLE msg_h; }; /****************************************************************************/ /* SYMTAB_ENTRY: single entry of symbol table inside message */ /****************************************************************************/ struct SYMTAB_ENTRY { DDD_GID gid; union { DDD_HDR hdr; /* used on receiver side only */ DDD_OBJ *ref; /* used on sender side only */ } adr; /* undefined during transfer */ }; /****************************************************************************/ /* OBJTAB_ENTRY: single entry of object table inside message */ /****************************************************************************/ struct OBJTAB_ENTRY { int h_offset; /* header offset from beginObjMem */ int addLen; /* length of additional data */ size_t size; /* size of object, ==desc->len for fixed-sized objects */ DDD_HDR hdr; /* TODO this is probably not used on sender side */ /* TODO: the following data is only used on receiver side */ char is_new; char oldprio; }; /* NOTE: the following macros require the DDD_HEADER being copied directly into the message! (with its LDATA!) */ #define OTE_HDR(objmem,ote) ((DDD_HDR)(((char *)(objmem))+((ote)->h_offset))) #define OTE_OBJ(context, objmem,ote) OBJ_OBJ(context, OTE_HDR(objmem,ote)) #define OTE_GID(objmem,ote) OBJ_GID(OTE_HDR(objmem,ote)) #define OTE_PRIO(objmem,ote) OBJ_PRIO(OTE_HDR(objmem,ote)) #define OTE_TYPE(objmem,ote) OBJ_TYPE(OTE_HDR(objmem,ote)) #define OTE_ATTR(objmem,ote) OBJ_ATTR(OTE_HDR(objmem,ote)) #define OTE_GID_FMT OBJ_GID_FMT /****************************************************************************/ /* DELTAB_ENTRY: single entry of deletion table inside message */ /****************************************************************************/ struct DELTAB_ENTRY { DDD_GID gid; DDD_PROC proc; }; /****************************************************************************/ /* XFER_PER_PROC: data needed on a per-proc basis during xfer */ /****************************************************************************/ struct XFER_PER_PROC { int dummy; /* not used yet */ }; /****************************************************************************/ /* */ /* function declarations */ /* */ /****************************************************************************/ /* supp.c */ XFERADDDATA *NewXIAddData(DDD::DDDContext& context); void FreeAllXIAddData(DDD::DDDContext& context); int *AddDataAllocSizes(DDD::DDDContext& context, int); /* and others, via template mechanism */ /* cplmsg.c */ void CommunicateCplMsgs (DDD::DDDContext& context, XIDelCpl **, int, XIModCpl **, int, XIAddCpl **, int, DDD_HDR *, int); void CplMsgInit(DDD::DDDContext& context); void CplMsgExit(DDD::DDDContext& context); /* cmdmsg.c */ int PruneXIDelCmd (DDD::DDDContext& context, XIDelCmd **, int, const std::vector&); void CmdMsgInit(DDD::DDDContext& context); void CmdMsgExit(DDD::DDDContext& context); /* xfer.c, used only by cmds.c */ XICopyObj **CplClosureEstimate(DDD::DDDContext& context, const std::vector&, int *); int PrepareObjMsgs(DDD::DDDContext& context, std::vector&, XINewCpl **, int, XIOldCpl **, int, XFERMSG **, size_t *); void ExecLocalXIDelCmd(DDD::DDDContext& context, XIDelCmd **, int); void ExecLocalXISetPrio(DDD::DDDContext& context, const std::vector&, XIDelObj **,int, XICopyObj **,int); void ExecLocalXIDelObj(DDD::DDDContext& context, XIDelObj **, int, XICopyObj **,int); void PropagateCplInfos(DDD::DDDContext& context, XISetPrio **, int, XIDelObj **, int, TENewCpl *, int); enum XferMode XferMode (const DDD::DDDContext& context); int XferStepMode(DDD::DDDContext& context, enum XferMode); /* pack.c, used only by cmds.c */ RETCODE XferPackMsgs (DDD::DDDContext& context, XFERMSG *); /* unpack.c, used only by cmds.c */ void XferUnpack (DDD::DDDContext& context, LC_MSGHANDLE *, int, const DDD_HDR *, int, std::vector&, XIDelObj **, int, const std::vector&, XICopyObj **, int); /* ctrl.c */ void XferDisplayMsg(DDD::DDDContext& context, const char *comment, LC_MSGHANDLE); END_UGDIM_NAMESPACE #endif dune-uggrid-2.11.0+dfsg/dune/uggrid/parallel/dddif/000077500000000000000000000000001513616443000220115ustar00rootroot00000000000000dune-uggrid-2.11.0+dfsg/dune/uggrid/parallel/dddif/CMakeLists.txt000066400000000000000000000007461513616443000245600ustar00rootroot00000000000000# SPDX-FileCopyrightText: Copyright © DUNE Project contributors, see file LICENSE.md in module root # SPDX-License-Identifier: LGPL-2.1-or-later target_sources_dims(duneuggrid PRIVATE compat.cc debugger.cc gridcons.cc handler.cc identify.cc identify.h initddd.cc lb.cc lbrcb.cc memmgr.cc overlap.cc partition.cc pgmcheck.cc priority.cc support.cc trans.cc) install(FILES parallel.h DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}/dune/uggrid/parallel/dddif/) dune-uggrid-2.11.0+dfsg/dune/uggrid/parallel/dddif/compat.cc000066400000000000000000000034441513616443000236100ustar00rootroot00000000000000// SPDX-FileCopyrightText: Copyright © DUNE Project contributors, see file LICENSE.md in module root // SPDX-License-Identifier: LGPL-2.1-or-later #include #include "parallel.h" #include START_UGDIM_NAMESPACE std::shared_ptr globalDDDContext_ = nullptr; DDD::DDDContext& globalDDDContext() { assert(globalDDDContext_); return *globalDDDContext_; } void globalDDDContext(const std::shared_ptr& context) { globalDDDContext_ = context; auto& dddctrl = ddd_ctrl(*context); ElementIF = dddctrl.ElementIF; ElementSymmIF = dddctrl.ElementSymmIF; ElementVIF = dddctrl.ElementVIF; ElementSymmVIF = dddctrl.ElementSymmVIF; ElementVHIF = dddctrl.ElementVHIF; ElementSymmVHIF = dddctrl.ElementSymmVHIF; BorderNodeIF = dddctrl.BorderNodeIF; BorderNodeSymmIF = dddctrl.BorderNodeSymmIF; OuterNodeIF = dddctrl.OuterNodeIF; NodeVIF = dddctrl.NodeVIF; NodeIF = dddctrl.NodeIF; NodeAllIF = dddctrl.NodeAllIF; BorderVectorIF = dddctrl.BorderVectorIF; BorderVectorSymmIF = dddctrl.BorderVectorSymmIF; OuterVectorIF = dddctrl.OuterVectorIF; OuterVectorSymmIF = dddctrl.OuterVectorSymmIF; VectorVIF = dddctrl.VectorVIF; VectorVAllIF = dddctrl.VectorVAllIF; VectorIF = dddctrl.VectorIF; EdgeIF = dddctrl.EdgeIF; BorderEdgeSymmIF = dddctrl.BorderEdgeSymmIF; EdgeHIF = dddctrl.EdgeHIF; EdgeVHIF = dddctrl.EdgeVHIF; EdgeSymmVHIF = dddctrl.EdgeSymmVHIF; } void globalDDDContext(std::nullptr_t) { globalDDDContext_ = nullptr; } static ComProcPtr realGather; static ComProcPtr realScatter; static int realGatherWrapper(DDD::DDDContext&, DDD_OBJ obj, void* data) { return realGather(obj, data); } static int realScatterWrapper(DDD::DDDContext&, DDD_OBJ obj, void* data) { return realGather(obj, data); } END_UGDIM_NAMESPACE dune-uggrid-2.11.0+dfsg/dune/uggrid/parallel/dddif/debugger.cc000066400000000000000000000357161513616443000241200ustar00rootroot00000000000000// SPDX-FileCopyrightText: Copyright © DUNE Project contributors, see file LICENSE.md in module root // SPDX-License-Identifier: LGPL-2.1-or-later // -*- tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- // vi: set et ts=4 sw=2 sts=2: /****************************************************************************/ #ifdef ModelP #include #include #include #include #include #include #include #include "debugger.h" #include "parallel.h" USING_UG_NAMESPACES using namespace PPIF; /****************************************************************************/ /****************************************************************************/ /* dddif_DisplayMemoryUsage - SYNOPSIS: static void dddif_DisplayMemoryUsage (void); PARAMETERS: . void DESCRIPTION: RETURN VALUE: void */ /****************************************************************************/ static void dddif_DisplayMemoryUsage (const DDD::DDDContext& context) { UserWriteF("mem for interfaces: %8ld bytes\n", (unsigned long) DDD_IFInfoMemoryAll(context) ); UserWriteF("mem for couplings: %8ld bytes\n", (unsigned long) DDD_InfoCplMemory(context) ); } /****************************************************************************/ /* ddd_pstat - SYNOPSIS: void ddd_pstat (const DDD::DDDContext& context, char *arg); PARAMETERS: . context . arg DESCRIPTION: RETURN VALUE: void */ /****************************************************************************/ void NS_DIM_PREFIX ddd_pstat(DDD::DDDContext& context, char *arg) { int cmd; if (arg==NULL) return; cmd = arg[0]; switch (cmd) { case 'X' : dddif_PrintGridRelations(ddd_ctrl(context).currMG); break; case 'm' : dddif_DisplayMemoryUsage(context); break; case 'c' : DDD_ConsCheck(context); UserWrite("\n"); break; case 's' : DDD_Status(context); UserWrite("\n"); break; case 't' : if (context.isMaster()) { const auto& dddctrl = ddd_ctrl(context); /* display ddd types */ DDD_TypeDisplay(context, dddctrl.TypeVector); DDD_TypeDisplay(context, dddctrl.TypeIVertex); DDD_TypeDisplay(context, dddctrl.TypeBVertex); DDD_TypeDisplay(context, dddctrl.TypeNode); #ifdef UG_DIM_3 DDD_TypeDisplay(context, dddctrl.TypeEdge); #endif #ifdef UG_DIM_2 DDD_TypeDisplay(context, dddctrl.TypeTrElem); DDD_TypeDisplay(context, dddctrl.TypeTrBElem); DDD_TypeDisplay(context, dddctrl.TypeQuElem); DDD_TypeDisplay(context, dddctrl.TypeQuBElem); #endif #ifdef UG_DIM_3 DDD_TypeDisplay(context, dddctrl.TypeTeElem); DDD_TypeDisplay(context, dddctrl.TypeTeBElem); DDD_TypeDisplay(context, dddctrl.TypePyElem); DDD_TypeDisplay(context, dddctrl.TypePyBElem); DDD_TypeDisplay(context, dddctrl.TypePrElem); DDD_TypeDisplay(context, dddctrl.TypePrBElem); DDD_TypeDisplay(context, dddctrl.TypeHeElem); DDD_TypeDisplay(context, dddctrl.TypeHeBElem); #endif /* display dependent types */ #ifdef UG_DIM_2 DDD_TypeDisplay(context, dddctrl.TypeEdge); #endif } break; case 'i' : { DDD_IF ifId = atoi(arg+1); if (ifId<=0) DDD_IFDisplayAll(context); else DDD_IFDisplay(context, ifId); UserWrite("\n"); } break; case 'l' : DDD_ListLocalObjects(context); UserWrite("\n"); break; case 'b' : buggy(ddd_ctrl(context).currMG); UserWrite("BUGGY: returning control to caller\n"); break; } } /****************************************************************************/ /* buggy - interactive debugging tool for distributed grids ug/ddd 960603 kb copied from pceq, modified, integrated */ /****************************************************************************/ /****************************************************************************/ /* buggy_ShowCopies - SYNOPSIS: static void buggy_ShowCopies (DDD_HDR hdr); PARAMETERS: . hdr - DESCRIPTION: RETURN VALUE: void */ /****************************************************************************/ static void buggy_ShowCopies (DDD::DDDContext& context, DDD_HDR hdr) { for (auto&& [proc, prio] : DDD_InfoProcListRange(context, hdr)) { printf("%4d: copy on %3d with prio %d\n", context.me(), proc, prio); } } /****************************************************************************/ /****************************************************************************/ /* buggy_ElemShow - SYNOPSIS: static void buggy_ElemShow (ELEMENT *e); PARAMETERS: . e - DESCRIPTION: RETURN VALUE: void */ /****************************************************************************/ static void buggy_ElemShow (ELEMENT *e) { ELEMENT *SonList[MAX_SONS]; int i; printf(" ID=%06d LEVEL=%02d corners=%03d\n", ID(e), LEVEL(e), CORNERS_OF_ELEM(e)); if (EFATHER(e)) printf(" father=" DDD_GID_FMT "\n", DDD_InfoGlobalId(PARHDRE(EFATHER(e)))); if (PREDE(e)) printf(" pred=" DDD_GID_FMT "\n", DDD_InfoGlobalId(PARHDRE(PREDE(e)))); if (SUCCE(e)) printf(" succ=" DDD_GID_FMT "\n", DDD_InfoGlobalId(PARHDRE(SUCCE(e)))); for(i=0; idddContext(); int level, found; found = false; for(level=0; level<=TOPLEVEL(theMG); level++) { GRID *theGrid = GRID_ON_LEVEL(theMG,level); ELEMENT *e; NODE *n; /* search for element */ for(e=PFIRSTELEMENT(theGrid); e!=NULL; e=SUCCE(e)) { if (DDD_InfoGlobalId(PARHDRE(e))==gid) { printf("ELEMENT gid=" DDD_GID_FMT ", adr=%p, level=%d\n", gid, (void*) e, level); buggy_ShowCopies(context, PARHDRE(e)); buggy_ElemShow(e); found = true; } } /* search for node */ for(n=PFIRSTNODE(theGrid); n!=NULL; n=SUCCN(n)) { if (DDD_InfoGlobalId(PARHDR(n))==gid) { printf("NODE gid=" DDD_GID_FMT ", adr=%p, level=%d\n", gid, (void*) n, level); buggy_ShowCopies(context, PARHDR(n)); buggy_NodeShow(n); found = true; } } } if (!found) { DDD_HDR hdr = DDD_SearchHdr(theMG->dddContext(), gid); if (hdr!=NULL) { printf("DDDOBJ gid=" DDD_GID_FMT ", typ=%d, level=%d\n", gid, DDD_InfoType(hdr), DDD_InfoAttr(hdr)); buggy_ShowCopies(context, hdr); } else { printf("unknown gid=" DDD_GID_FMT "\n", gid); } } } /****************************************************************************/ /* static void bug_eg_item (Elem *item) { char fname[30]; FILE *f; sprintf(fname,"buggy%08x.%03d.gnu",item->InfoGlobalId(),me); f = fopen(fname,"w"); if (f==0) { Cout<conn_dn()); Side *side; for(; siter; ++siter) { side = siter.rel()->obj(); Cout << me<<" side "<< hex << side->InfoGlobalId() <conn_dn()); Node *node; for(; niter; ++niter) { node = niter.rel()->obj(); Cout << me <<" node " << hex << node->InfoGlobalId() << dec << cr; fprintf(f,"%f %f\n",node->x[0],node->x[1]); } fprintf(f,"\n"); } } } fclose(f); } static void bug_elem_graphics (GridSegment &target, unsigned int gid) { Elem *item=0; { Iterator(Elem) iter(target.elem_list()); for (; iter && item==0; ++iter) { if (iter.obj()->InfoGlobalId()==gid) { item = iter.obj(); } } } if (item==0) { Iterator(Elem) iter(target.ghostlist); for (; iter && item==0; ++iter) { if (iter.obj()->InfoGlobalId()==gid) { item = iter.obj(); } } } if (item==0) { Cout< change current processor\n" " * l list DDD objects on current proc\n" " * change to object with gid\n" " * ? or h this help message\n" " *\n"); } /****************************************************************************/ /****************************************************************************/ /* buggy - SYNOPSIS: void buggy (MULTIGRID *theMG); PARAMETERS: . the MG DESCRIPTION: RETURN VALUE: void */ /****************************************************************************/ void NS_DIM_PREFIX buggy (MULTIGRID *theMG) { char buff[100]; DDD_GID gid; int proc, cmd, received; Synchronize(theMG->ppifContext()); const int me = theMG->ppifContext().me(); if (me==0) { printf("%04d: started buggy.\n", me); fflush(stdout); } proc = 0; gid = 0x0; do { if (me==0) { do { printf("%04d: buggy> ", proc); fflush(stdout); received = scanf("%s", buff); } while (received > 0 && buff[0] == 0); switch (buff[0]) { case 'x' : case 'q' : proc = -1; cmd = 0; break; case 'p' : proc = (int) strtol(buff+1, 0, 0); cmd = 1; break; case 'l' : cmd = 2; break; case '?' : case 'h' : cmd=99; break; default : cmd = 3; gid = /*(DDD_GID)*/ strtol(buff, 0, 0); } } Broadcast(theMG->ppifContext(), &cmd, sizeof(int)); Broadcast(theMG->ppifContext(), &proc, sizeof(int)); Broadcast(theMG->ppifContext(), &gid, sizeof(unsigned int)); if (me==proc) { switch (cmd) { case 99 : buggy_help(); break; case 2 : DDD_ListLocalObjects(theMG->dddContext()); break; default : buggy_Search(theMG, gid); /* bug_ghost(target, gid); bug_side(target, gid); */ break; } } fflush(stdout); Synchronize(theMG->ppifContext()); } while (proc>=0); } /****************************************************************************/ /* */ /* Function: PrintGridRelations */ /* */ /* Purpose: print certain information about a grid in order to test */ /* the formal approach to parallelisation. */ /* */ /****************************************************************************/ #define PREFIX "__" void NS_DIM_PREFIX dddif_PrintGridRelations (MULTIGRID *theMG) { ELEMENT *e, *enb; GRID *theGrid = GRID_ON_LEVEL(theMG,TOPLEVEL(theMG)); INT j; const auto& me = theMG->dddContext().me(); for(e=FIRSTELEMENT(theGrid); e!=NULL; e=SUCCE(e)) { printf(PREFIX "master(e" EGID_FMT ", p%02d).\n", EGID(e), me); for(j=0; j START_UGDIM_NAMESPACE void buggy (MULTIGRID *); void dddif_PrintGridRelations (MULTIGRID *); END_UGDIM_NAMESPACE #endif dune-uggrid-2.11.0+dfsg/dune/uggrid/parallel/dddif/gridcons.cc000066400000000000000000000344501513616443000241360ustar00rootroot00000000000000// SPDX-FileCopyrightText: Copyright © DUNE Project contributors, see file LICENSE.md in module root // SPDX-License-Identifier: LGPL-2.1-or-later // -*- tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- // vi: set et ts=4 sw=2 sts=2: /****************************************************************************/ /* */ /* File: gridcons.c */ /* */ /* Purpose: functions for managing consistency of distributed grids */ /* */ /* Author: Stefan Lang, Klaus Birken */ /* Institut fuer Computeranwendungen III */ /* Universitaet Stuttgart */ /* Pfaffenwaldring 27 */ /* 70550 Stuttgart */ /* */ /* History: 960906 kb begin */ /* */ /* Remarks: */ /* */ /****************************************************************************/ #ifdef ModelP /****************************************************************************/ /* */ /* include files */ /* system include files */ /* application include files */ /* */ /****************************************************************************/ #include #include #include "parallel.h" #include #include #include #include #include #include #include #include /* UG namespaces: */ USING_UG_NAMESPACES #ifdef Debug using namespace PPIF; #endif /****************************************************************************/ /* */ /* defines in the following order */ /* */ /* compile time constants defining static data size (i.e. arrays) */ /* other constants */ /* macros */ /* */ /****************************************************************************/ #ifdef DDD_PRIO_ENV #define DDD_XferBegin DDD_PrioBegin #define DDD_XferEnd DDD_PrioEnd #endif /****************************************************************************/ /* */ /* data structures used in this source file (exported data structures are */ /* in the corresponding include file!) */ /* */ /****************************************************************************/ /****************************************************************************/ /* */ /* definition of exported global variables */ /* */ /****************************************************************************/ /****************************************************************************/ /* */ /* forward declarations of functions used before they are defined */ /* */ /****************************************************************************/ /****************************************************************************/ /* ConstructConsistentGridLevel - SYNOPSIS: void ConstructConsistentGridLevel (GRID *theGrid); PARAMETERS: . theGrid DESCRIPTION: Provide a consistent grid level. Do not call for a single grid level, but always for the whole multigrid from bottom to top, since otherwise consistency is not ensured! RETURN VALUE: void */ /****************************************************************************/ static void ConstructConsistentGridLevel (GRID *theGrid) { INT j; EDGE *theEdge; /* this is the simplest fix for VFATHER zombies */ /* just reset all VFATHER pointers and set them */ /* only by master nodes of this or upper levels. */ /* A more complicated fix would be to set the */ /* priorities of the vertices correctly. */ /* (980126 s.l.) */ for (VERTEX* theVertex = PFIRSTVERTEX(theGrid); theVertex != NULL; theVertex = SUCCV(theVertex)) { VFATHER(theVertex) = NULL; /* if (VXGHOST(theVertex)) VFATHER(theVertex) = NULL; else if (OBJT(theVertex) == BVOBJ) if (MOVED(theVertex)) { INT n; DOUBLE *x[MAX_CORNERS_OF_ELEM]; ELEMENT* theElement = VFATHER(theVertex); if (theElement == NULL) continue; HEAPFAULT(theElement); CORNER_COORDINATES(theElement,n,x); UG_GlobalToLocal(n,(const DOUBLE **)x, CVECT(theVertex),LCVECT(theVertex)); } */ } /* reconstruct VFATHER pointers and */ /* make ghost neighborships symmetric (only for 3d)*/ /* * Also: If there are SideVectors, set the VCOUNT field correctly (i.e., the number * of elements that reference a given SideVector). This information has been transferred as-is * during load balancing, but may be wrong on new ghost elements. */ for (ELEMENT* theElement = PFIRSTELEMENT(theGrid); theElement!=NULL; theElement=SUCCE(theElement)) { /* This is the SideVector part */ #ifdef UG_DIM_3 if (VEC_DEF_IN_OBJ_OF_GRID(theGrid,SIDEVEC)) for (INT i=0; i=SIDES_OF_ELEM(NbElement)) SET_NBELEM(theElement,i,NULL); } } #endif */ ELEMENT* theFather = EFATHER(theElement); /* no reconstruction of VFATHER possible */ if (theFather == NULL) continue; for (INT i=0; i=EDGES_OF_ELEM(theFather)) { for (j=0; jmidnode != NULL) PRINTDEBUG(dddif,1, (PFMT " ConstructConsistentGrid(): elem=" EID_FMTX " i=%d n1=" ID_FMTX " n2=" ID_FMTX " midnode= " ID_FMTX "\n", me,theFather,EID_PRTX(theFather),j, ID_PRTX(NBNODE(LINK0(theEdge))), ID_PRTX(NBNODE(LINK1(theEdge))), ID_PRTX(theEdge->midnode))) #endif } PRINTDEBUG(dddif,1, ("ConstructConsistentGrid(): WARN " " theNode= " ID_FMTX " vertex= " VID_FMTX " recalculation of VFATHER impossible\n", ID_PRTX(NBNODE(LINK0(theEdge))), VID_PRTX(theVertex))); /* if it couldn't be recalculated reset it */ VFATHER(theVertex) = NULL; break; } /* reconstruct local coordinates of vertex */ co0 = CORNER_OF_EDGE(theFather,j,0); co1 = CORNER_OF_EDGE(theFather,j,1); /* local coordinates have to be local towards pe */ V_DIM_LINCOMB(0.5, LOCAL_COORD_OF_ELEM(theFather,co0), 0.5, LOCAL_COORD_OF_ELEM(theFather,co1), LCVECT(theVertex)); SETONEDGE(theVertex,j); break; } #ifdef UG_DIM_3 case (SIDE_NODE) : { /* always compute new coords for this case! */ INT k; if (TAG(theFather) == PYRAMID) k=0; else k = GetSideIDFromScratch(theElement,theNode); ASSERT(k < SIDES_OF_ELEM(theFather)); SETONSIDE(theVertex,k); INT m = CORNERS_OF_SIDE(theFather,k); Dune::FieldVector& local = LCVECT(theVertex); DOUBLE fac = 1.0 / m; V_DIM_CLEAR(local); for (INT o=0; odddContext()); SetGhostObjectPriorities(theGrid); DDD_XferEnd(theGrid->dddContext()); DDD_XferBegin(theGrid->dddContext()); SetBorderPriorities(theGrid); DDD_XferEnd(theGrid->dddContext()); ConstructConsistentGridLevel(theGrid); } /****************************************************************************/ /* ConstructConsistentMultiGrid - SYNOPSIS: void ConstructConsistentMultiGrid (MULTIGRID *theMG); PARAMETERS: . theMG DESCRIPTION: Provide a consistent multigrid. RETURN VALUE: void */ /****************************************************************************/ void NS_DIM_PREFIX ConstructConsistentMultiGrid (MULTIGRID *theMG) { INT l; /* this is done in three waves: */ /* 1. set priorities of objects */ /* 2. set border priorities */ /* 3. repair grid inconsistencies */ /* 1. set priorities of objects */ DDD_XferBegin(theMG->dddContext()); for (l=0; l<=TOPLEVEL(theMG); l++) { GRID *theGrid = GRID_ON_LEVEL(theMG,l); SetGhostObjectPriorities(theGrid); } DDD_XferEnd(theMG->dddContext()); /* 2. set border priorities */ DDD_XferBegin(theMG->dddContext()); for (l=0; l<=TOPLEVEL(theMG); l++) { GRID *theGrid = GRID_ON_LEVEL(theMG,l); SetBorderPriorities(theGrid); } DDD_XferEnd(theMG->dddContext()); /* 3. repair grid inconsistencies */ for (l=0; l<=TOPLEVEL(theMG); l++) { GRID *theGrid = GRID_ON_LEVEL(theMG,l); ConstructConsistentGridLevel(theGrid); } } #endif dune-uggrid-2.11.0+dfsg/dune/uggrid/parallel/dddif/handler.cc000066400000000000000000001626371513616443000237540ustar00rootroot00000000000000// SPDX-FileCopyrightText: Copyright © DUNE Project contributors, see file LICENSE.md in module root // SPDX-License-Identifier: LGPL-2.1-or-later // -*- tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- // vi: set et ts=4 sw=2 sts=2: /****************************************************************************/ /* */ /* File: handler.c */ /* */ /* Purpose: defines the handlers used by ddd during data management. */ /* */ /* */ /* Author: Stefan Lang */ /* Institut fuer Computeranwendungen III */ /* Universitaet Stuttgart */ /* Pfaffenwaldring 27 */ /* 70550 Stuttgart */ /* email: stefan@ica3.uni-stuttgart.de */ /* phone: 0049-(0)711-685-7003 */ /* fax : 0049-(0)711-685-7000 */ /* */ /* History: 10.05.95 begin, ugp version 3.0 */ /* */ /* Remarks: */ /* */ /****************************************************************************/ #ifdef ModelP /****************************************************************************/ /* */ /* include files */ /* system include files */ /* application include files */ /* */ /****************************************************************************/ #include #include #include #include #include #include #include #include "parallel.h" #include #include #include #include #include #include #include #include #include #include #include #include /* UG namespaces: */ USING_UG_NAMESPACES /* PPIF namespace */ using namespace PPIF; /****************************************************************************/ /* */ /* defines in the following order */ /* */ /* compile time constants defining static data size (i.e. arrays) */ /* other constants */ /* macros */ /* */ /****************************************************************************/ #ifdef Debug #define DEBUGNSONS(e,f,m) { \ if (f!=NULL) \ { \ if (CheckNSons(f,m)) \ UserWriteF(PFMT "inserted elem=" EID_FMTX\ "\n",me,EID_PRTX(e)); \ } \ } #else #define DEBUGNSONS(pe,f,m) #endif #define CEIL(n) ((n)+((ALIGNMENT-((n)&(ALIGNMENT-1)))&(ALIGNMENT-1))) /****************************************************************************/ /* */ /* data structures used in this source file (exported data structures are */ /* in the corresponding include file!) */ /* */ /****************************************************************************/ /****************************************************************************/ /* */ /* definition of exported global variables */ /* */ /****************************************************************************/ /****************************************************************************/ /* */ /* definition of variables global to this source file only (static!) */ /* */ /****************************************************************************/ /****************************************************************************/ /* */ /* forward declarations of functions used before they are defined */ /* */ /****************************************************************************/ static void PrintSons (ELEMENT *theElement) { ELEMENT *SonList[MAX_SONS]; int i; if (GetAllSons(theElement,SonList)) ASSERT(0); for (i=0; i TOPLEVEL(mg)) { PRINTDEBUG(dddif,1,(PFMT " CreateNewLevel toplevel=%d level=%d",me,TOPLEVEL(mg),level)); if (CreateNewLevel(mg)==NULL) assert(0); } return GRID_ON_LEVEL(mg,level); } /****************************************************************************/ /* */ /* For data management during redistribution and communication */ /* DDD needs for each DDD (data) object several handlers. */ /* These are: */ /* HANDLER_LDATACONSTRUCTOR, handler: init object's LDATA parts */ /* HANDLER_UPDATE, handler: update objects internals */ /* HANDLER_OBJMKCONS, handler: make obj consistent */ /* HANDLER_DESTRUCTOR, handler: destruct object */ /* HANDLER_XFERCOPY, handler: copy cmd during xfer */ /* HANDLER_XFERDELETE, handler: delete cmd during xfer */ /* HANDLER_XFERGATHER, handler: send additional data */ /* HANDLER_XFERSCATTER, handler: recv additional data */ /* */ /* */ /* For each of the ddd (data) objects the handlers needed for the */ /* specific object are defined below in the order handlers for */ /* */ /* DDD objects: */ /* *dimension independent */ /* TypeVector, TypeIVertex, TypeBVertex, TypeNode */ /* *dimension dependent */ /* 2-Dim: */ /* TypeTrElem, TypeTrBElem, */ /* TypeQuElem, TypeQuBElem */ /* 3-Dim: */ /* TypeTeElem, TypeTeBElem */ /* TypePyElem, TypePyBElem */ /* TypePrElem, TypePrBElem */ /* TypeHeElem, TypeHeBElem */ /* TypeEdge */ /* */ /* DDD data objects: */ /* 2-Dim: */ /* TypeEdge */ /* */ /* NOT all handlers are to be specified for each object! */ /* */ /****************************************************************************/ /****************************************************************************/ /****************************************************************************/ /* */ /* handlers for typevector */ /* */ /****************************************************************************/ /****************************************************************************/ static void VectorUpdate (DDD::DDDContext& context, DDD_OBJ obj) { VECTOR *pv = (VECTOR *)obj; INT level = ATTR_TO_GLEVEL(DDD_InfoAttr(PARHDR(pv))); GRID *theGrid = GRID_ON_LEVEL(ddd_ctrl(context).currMG,level); const DDD_PRIO prio = PRIO(pv); PRINTDEBUG(dddif,1,(PFMT " VectorUpdate(): v=" VINDEX_FMTX " VEOBJ=%d\n",me,VINDEX_PRTX(pv),OBJT(pv))) /* insert in vector list */ GRID_LINK_VECTOR(theGrid,pv,prio); } static void VectorXferCopy(DDD::DDDContext& context, DDD_OBJ obj, DDD_PROC proc, DDD_PRIO prio) { VECTOR *pv = (VECTOR *)obj; INT level = ATTR_TO_GLEVEL(DDD_InfoAttr(PARHDR(pv))); INT flag; PRINTDEBUG(dddif,1,(PFMT " VectorXferCopy(): v=" VINDEX_FMTX " proc=%d " "prio=%d\n",me,VINDEX_PRTX(pv),proc,prio)) flag = (!GHOSTPRIO(prio)); #ifndef __EXCHANGE_CONNECTIONS__ flag = (flag && (level < 0)); #endif /* else { GRID *theGrid = GRID_ON_LEVEL(ddd_ctrl(context).currMG,level); MATRIX *theMatrix,*next; for (theMatrix=VSTART(pv); theMatrix!=NULL; theMatrix = next) { next = MNEXT(theMatrix); if (DisposeConnection(theGrid,MMYCON(theMatrix))) ASSERT(0); } } */ } static void VectorPriorityUpdate (DDD::DDDContext& context, DDD_OBJ obj, DDD_PRIO isnew) { VECTOR *pv = (VECTOR *)obj; INT level = ATTR_TO_GLEVEL(DDD_InfoAttr(PARHDR(pv))); GRID *theGrid = GRID_ON_LEVEL(ddd_ctrl(context).currMG,level); DDD_PRIO old = PRIO(pv); PRINTDEBUG(dddif,2,(PFMT " VectorPriorityUpdate(): v=" VINDEX_FMTX " old=%d new=%d level=%d attr=%d\n", me,VINDEX_PRTX(pv),old,isnew,level, (int)DDD_InfoAttr(PARHDR(pv)))); if (pv == NULL) return; if (old == isnew) return; if (old == PrioNone) { /* only valid for masters */ ASSERT(isnew == PrioMaster); return; } if (isnew == PrioNone) { /* only valid when prio undefined */ printf("prio=%d\n",old); fflush(stdout); ASSERT(old <= 0); return; } #ifdef __EXCHANGE_CONNECTIONS__ IFDEBUG(dddif,1) if (isnew == PrioMaster) { if (VSTART(pv) == NULL) { PRINTDEBUG(dddif,0,(PFMT " VectorPriorityUpdate(): ERROR v=" VINDEX_FMTX " old=%d new=%d matrix list empty\n", me,VINDEX_PRTX(pv),old,isnew)) } } ENDDEBUG #endif GRID_UNLINK_VECTOR(theGrid,pv); GRID_LINK_VECTOR(theGrid,pv,isnew); } /****************************************************************************/ /****************************************************************************/ /* */ /* handlers for typeivertex */ /* */ /****************************************************************************/ /****************************************************************************/ /****************************************************************************/ /****************************************************************************/ /* */ /* handlers for typebvertex */ /* */ /****************************************************************************/ /****************************************************************************/ static void BVertexLDataConstructor (DDD::DDDContext&, DDD_OBJ obj) { VERTEX *theVertex = (VERTEX *) obj; PRINTDEBUG(dddif,1,(PFMT " BVertexLDataConstructor(): v=" VID_FMTX " I/BVOBJ=%d\n",me,VID_PRTX(theVertex),OBJT(theVertex))) V_BNDP(theVertex) = NULL; } static void VertexUpdate (DDD::DDDContext& context, DDD_OBJ obj) { VERTEX *theVertex = (VERTEX *) obj; INT level = LEVEL(theVertex); GRID *theGrid = GRID_ON_LEVEL(ddd_ctrl(context).currMG,level); INT prio = VXPRIO(theVertex); PRINTDEBUG(dddif,1,(PFMT " VertexUpdate(): v=" VID_FMTX " I/BVOBJ=%d\n", me,VID_PRTX(theVertex),OBJT(theVertex))) GRID_LINK_VERTEX(theGrid,theVertex,prio); /* this assertion is not correct, since there may be an arbitrary number of */ /* calls to NodeUpdate(), which increments NOOFNODE */ /* ASSERT(NOOFNODE(theVertex) == 0); */ /* update ID of vertex */ /* TODO: change to global id */ /* TODO: delete ID(theVertex) = (theGrid->mg->vertIdCounter)++; */ } static void VertexObjMkCons (DDD::DDDContext&, DDD_OBJ obj, int newness) { [[maybe_unused]] VERTEX *theVertex = (VERTEX *) obj; PRINTDEBUG(dddif,1,(PFMT " VertexObjMkCons(): v=" VID_FMTX " I/BVOBJ=%d newness=%d\n", me,VID_PRTX(theVertex),OBJT(theVertex),newness)) } static void BVertexXferCopy (DDD::DDDContext& context, DDD_OBJ obj, DDD_PROC proc, DDD_PRIO prio) { VERTEX *theVertex = (VERTEX *) obj; PRINTDEBUG(dddif,1,(PFMT " BVertexXferCopy(): v=" VID_FMTX " I/BVOBJ=%d proc=%d prio=%d \n", me,VID_PRTX(theVertex),OBJT(theVertex),proc,prio)) BVertexXferBndP(context, V_BNDP(theVertex),proc,prio); } static void BVertexGather (DDD::DDDContext&, DDD_OBJ obj, int cnt, DDD_TYPE type_id, void *Data) { BVertexGatherBndP (V_BNDP((VERTEX *)obj),cnt,(char*)Data); } /* Handlers used by Dune to implement dynamic load balancing: * Dune writes the data into the objects' 'message_buffer' * variable, then we take it from there. * The first sizeof(int) bytes of the message_buffer is the length of * the message (without the size of the int). */ template static void DuneEntityGather (DDD::DDDContext&, DDD_OBJ obj, int cnt, DDD_TYPE type_id, void *Data) { char* data = static_cast(Data); const Entity* entity = reinterpret_cast(obj); const auto size = entity->message_buffer_size(); std::memcpy(data, &size, sizeof size); data += sizeof size; std::memcpy(data, entity->message_buffer(), size); } template static void DuneEntityScatter (DDD::DDDContext&, DDD_OBJ obj, int cnt, DDD_TYPE type_id, void *Data, int newness) { const char* data = static_cast(Data); Entity* entity = reinterpret_cast(obj); std::size_t size; std::memcpy(&size, data, sizeof size); data += sizeof size; char* buffer = static_cast(std::malloc(size)); std::memcpy(buffer, data, size); entity->message_buffer(buffer, size); } static void BVertexScatter (DDD::DDDContext& context, DDD_OBJ obj, int cnt, DDD_TYPE type_id, void *Data, int newness) { BVertexScatterBndP(context, &(V_BNDP((VERTEX *)obj)),cnt,(char*)Data); } static void VertexPriorityUpdate (DDD::DDDContext& context, DDD_OBJ obj, DDD_PRIO new_) { VERTEX *theVertex = (VERTEX *)obj; INT level = LEVEL(theVertex); GRID *theGrid = GetGridOnDemand(ddd_ctrl(context).currMG,level); DDD_PRIO old = VXPRIO(theVertex); PRINTDEBUG(dddif,2,(PFMT " VertexPriorityUpdate(): v=" VID_FMTX " old=%d new=%d level=%d\n",me,VID_PRTX(theVertex),old,new_,level)) if (theVertex == NULL) return; if (old == new_) return; if (old == PrioNone) { /* only valid for masters */ ASSERT(new_ == PrioMaster); return; } if (new_ == PrioNone) { /* only valid when prio undefined */ printf("prio=%d\n",old); fflush(stdout); ASSERT(old <= 0); return; } GRID_UNLINK_VERTEX(theGrid,theVertex); GRID_LINK_VERTEX(theGrid,theVertex,new_); } /****************************************************************************/ /****************************************************************************/ /* */ /* handlers for typenode */ /* */ /****************************************************************************/ /****************************************************************************/ static void NodeDestructor(DDD::DDDContext&, DDD_OBJ obj) { NODE *node = (NODE *) obj; node->message_buffer_free(); PRINTDEBUG(dddif,2,(PFMT " NodeDestructor(): n=" ID_FMTX " NDOBJ=%d\n", me,ID_PRTX(node),OBJT(node))) } static void NodeObjInit(DDD::DDDContext&, DDD_OBJ obj) { NODE *node = (NODE *) obj; node->message_buffer(nullptr, 0); PRINTDEBUG(dddif,2,(PFMT " NodeObjInit(): n=" ID_FMTX " NDOBJ=%d\n", me,ID_PRTX(node),OBJT(node))) } static void NodeObjMkCons (DDD::DDDContext& context, DDD_OBJ obj, int newness) { #if defined(Debug) || defined(TOPNODE) || defined(UG_DIM_2) NODE *theNode = (NODE *) obj; #endif PRINTDEBUG(dddif,2,(PFMT " NodeObjMkCons(): n=" ID_FMTX " NDOBJ=%d\n", me,ID_PRTX(theNode),OBJT(theNode))) #ifdef TOPNODE /* set topnode pointer of vertex */ if (TOPNODE(MYVERTEX(theNode)) == NULL) TOPNODE(MYVERTEX(theNode)) = theNode; else { NODE *TopNode = TOPNODE(MYVERTEX(theNode)); INT level = LEVEL(TopNode); if (level < LEVEL(theNode)) TOPNODE(MYVERTEX(theNode)) = theNode; } #endif /* TODO: this needs to be done here not in NodeUpdate() for 2D, */ /* since father would be overwritten by ElemScatterEdge() */ #ifdef UG_DIM_2 if (NFATHER(theNode) != NULL) { switch (NTYPE(theNode)) { case (CORNER_NODE) : ASSERT(OBJT(NFATHER(theNode)) == NDOBJ); SONNODE((NODE *)NFATHER(theNode)) = theNode; break; case (MID_NODE) : ASSERT(OBJT(NFATHER(theNode)) == EDOBJ); MIDNODE((EDGE *)NFATHER(theNode)) = theNode; break; default : ASSERT(0); break; } } #endif } /****************************************************************************/ /* */ /* Function: NodeUpdate */ /* */ /* Purpose: update information related to a node. */ /* current implementation only for level 0 grids */ /* */ /* Input: DDD_OBJ obj: the node to handle */ /* */ /* Output: void */ /* */ /****************************************************************************/ static void NodeUpdate (DDD::DDDContext& context, DDD_OBJ obj) { NODE *theNode = (NODE *)obj; VERTEX *theVertex = MYVERTEX(theNode); INT level = LEVEL(theNode); GRID *theGrid = GRID_ON_LEVEL(ddd_ctrl(context).currMG,level); INT prio = PRIO(theNode); PRINTDEBUG(dddif,1,(PFMT " NodeUpdate(): n=" ID_FMTX " NDOBJ=%d\n", me,ID_PRTX(theNode),OBJT(theNode))) /* insert in listpart */ GRID_LINK_NODE(theGrid,theNode,prio); /* TODO: can this be done in NodeObjMkCons() also */ /* to unify 2 and 3D case */ #ifdef UG_DIM_3 if (NFATHER(theNode) != NULL) { switch (NTYPE(theNode)) { case (CORNER_NODE) : ASSERT(OBJT(NFATHER(theNode)) == NDOBJ); SONNODE((NODE *)NFATHER(theNode)) = theNode; break; case (MID_NODE) : ASSERT(OBJT((EDGE *)NFATHER(theNode)) == EDOBJ); MIDNODE((EDGE *)NFATHER(theNode)) = theNode; break; default : ASSERT(0); break; } } #endif if (NOOFNODE(theVertex)mg->nodeIdCounter)++; */ } /****************************************************************************/ /* */ /* Function: NodeXferCopy */ /* */ /* Purpose: initiate dependent copy of data related to a node. */ /* */ /* Input: DDD_OBJ obj: the object which is transferred to proc */ /* int proc: destination processor for that object */ /* int prio: priority of object new local object */ /* */ /* Output: void */ /* */ /****************************************************************************/ static void NodeXferCopy (DDD::DDDContext& context, DDD_OBJ obj, DDD_PROC proc, DDD_PRIO prio) { NODE *theNode = (NODE *)obj; PRINTDEBUG(dddif,1,(PFMT " NodeXferCopy(): n=" ID_FMTX " proc=%d prio=%d\n", me,ID_PRTX(theNode),proc,prio)); /* copy vertex */ PRINTDEBUG(dddif,2,(PFMT " NodeXferCopy(): n=" ID_FMTX " Xfer v=" VID_FMTX "\n",me,ID_PRTX(theNode),VID_PRTX(MYVERTEX(theNode)))) #ifdef Debug if (NFATHER(theNode) != NULL) { PRINTDEBUG(dddif,1,(PFMT " NodeXferCopy(): n=" ID_FMTX " NTYPE=%d OBJT=%d\n", me,ID_PRTX(theNode),NTYPE(theNode), OBJT(NFATHER(theNode)))); switch (NTYPE(theNode)) { case (CORNER_NODE) : ASSERT(OBJT(NFATHER(theNode)) == NDOBJ); break; case (MID_NODE) : ASSERT(OBJT(NFATHER(theNode)) == EDOBJ); break; default : ASSERT(0); break; } } #endif if (DDD_XferWithAddData(context)) { /* Extra data for Dune */ DDD_XferAddData(context, sizeof(theNode->message_buffer_size()) + theNode->message_buffer_size(), DDD_USER_DATA); } DDD_XferCopyObj(context, PARHDRV(MYVERTEX(theNode)), proc, prio); } static void NodePriorityUpdate (DDD::DDDContext& context, DDD_OBJ obj, DDD_PRIO new_) { NODE *pn = (NODE *)obj; INT level = LEVEL(pn); GRID *theGrid = GetGridOnDemand(ddd_ctrl(context).currMG,level); const DDD_PRIO old = PRIO(pn); PRINTDEBUG(dddif,2,(PFMT " NodePriorityUpdate(): n=" ID_FMTX " old=%d new=%d " "level=%d\n",me,ID_PRTX(pn),old,new_,level)) if (pn == NULL) return; if (old == new_) return; if (old == PrioNone) { /* only valid for masters */ ASSERT(new_ == PrioMaster); return; } if (new_ == PrioNone) { /* only valid when prio undefined */ printf("prio=%d\n",old); fflush(stdout); ASSERT(old <= 0); return; } /* insert in new list part */ GRID_UNLINK_NODE(theGrid,pn); GRID_LINK_NODE(theGrid,pn,new_); } DDD_TYPE NS_DIM_PREFIX NFatherObjType(DDD::DDDContext& context, DDD_OBJ obj, DDD_OBJ ref) { const auto& dddctrl = ddd_ctrl(context); NODE *theNode = (NODE *)obj; switch (NTYPE(theNode)) { case (CORNER_NODE) : #ifdef Debug if (OBJT((NODE *)ref) != NDOBJ) UserWriteF("NFatherObjType(): wrong OBJT=%d\n",OBJT((NODE *)ref)); #endif ASSERT(OBJT((NODE *)ref) == NDOBJ); return(dddctrl.TypeNode); case (MID_NODE) : #ifdef Debug if (OBJT((EDGE *)ref) != EDOBJ) UserWriteF("NFatherObjType(): wrong OBJT=%d\n",OBJT((EDGE *)ref)); #endif ASSERT(OBJT((EDGE *)ref) == EDOBJ); return(dddctrl.TypeEdge); default : abort(); } } /****************************************************************************/ /****************************************************************************/ /* */ /* handlers for typeelement */ /* */ /****************************************************************************/ /****************************************************************************/ /****************************************************************************/ /* */ /* Function: ElementLDataConstructor */ /* */ /* Purpose: update information related to an element. */ /* current implementation only for level 0 grids */ /* */ /* Input: DDD_OBJ obj: the element to handle */ /* */ /* Output: void */ /* */ /****************************************************************************/ static void ElementLDataConstructor (DDD::DDDContext& context, DDD_OBJ obj) { INT i; ELEMENT *pe = (ELEMENT *)obj; [[maybe_unused]] INT level = LEVEL(pe); /* TODO: delete GRID *theGrid = GetGridOnDemand(ddd_ctrl(context).currMG,level); INT prio = EPRIO(pe); */ pe->message_buffer(nullptr, 0); PRINTDEBUG(dddif,2,(PFMT " ElementLDataConsX(): pe=" EID_FMTX " EOBJ=%d l=%d\n",me,EID_PRTX(pe),OBJT(pe),level)) /* TODO: delete GRID_LINK_ELEMENT(theGrid,pe,prio); */ if (OBJT(pe)==BEOBJ) { for (i=0; img->elemIdCounter)++; */ } /****************************************************************************/ /* */ /* Function: ElementUpdate */ /* */ /* Purpose: update information related to an element. */ /* current implementation only for level 0 grids */ /* */ /* Input: DDD_OBJ obj: the element to handle */ /* */ /* Output: void */ /* */ /****************************************************************************/ static void ElementUpdate (DDD::DDDContext&, DDD_OBJ obj) { [[maybe_unused]] ELEMENT *pe = (ELEMENT *)obj; PRINTDEBUG(dddif,1,(PFMT " ElementUpdate(): pe=" EID_FMTX " EOBJ=%d\n",me,EID_PRTX(pe),OBJT(pe))) /* TODO: delete this SETNSONS(pe,0); */ /* TODO: this is not true any more, since elements pe, which are new and have local non-new sons, have already gotten their NSONS through ElementrPriorityUpdate() of the sons!!! ASSERT(NSONS(pe) == 0); */ } /****************************************************************************/ /* */ /* Function: ElementDelete */ /* */ /* Purpose: remove element from UG data structure. */ /* current implementation only for level 0 grids */ /* */ /* Input: DDD_OBJ obj: the element to handle */ /* */ /* Output: void */ /* */ /****************************************************************************/ static void ElementDelete (DDD::DDDContext& context, DDD_OBJ obj) { ELEMENT *pe = (ELEMENT *)obj; INT level = LEVEL(pe); GRID *theGrid = GRID_ON_LEVEL(ddd_ctrl(context).currMG,level); /* dispose element without connections (false) */ if (DisposeElement(theGrid, pe)) ASSERT(0); } /****************************************************************************/ /* */ /* Function: ElementXferCopy */ /* */ /* Purpose: initiate dependent copy of data related to an element. */ /* this handler is implemented for an arbitrary element type. */ /* */ /* Input: DDD_OBJ obj: the object which is transferred to proc */ /* int proc: destination processor for that object */ /* int prio: priority of object new local object */ /* */ /* Output: void */ /* */ /****************************************************************************/ static void ElementXferCopy (DDD::DDDContext& context, DDD_OBJ obj, DDD_PROC proc, DDD_PRIO prio) { auto& dddctrl = ddd_ctrl(context); INT i,nsides; ELEMENT *pe = (ELEMENT *)obj; NODE *node; BNDS *bnds[MAX_SIDES_OF_ELEM]; PRINTDEBUG(dddif,1,(PFMT " ElementXferCopy(): " "pe=" EID_FMTX " proc=%d prio=%d EOBJT=%d\n", me,EID_PRTX(pe),proc,prio,OBJT(pe))) /* add element sides */ /* must be done before any XferCopyObj-call! herein */ /* or directly after XferCopyObj-call */ if (OBJT(pe)==BEOBJ) { nsides = SIDES_OF_ELEM(pe); for (i=0; imessage_buffer_size()) + pe->message_buffer_size(), DDD_USER_DATA); /* add edges of element */ /* must be done before any XferCopyObj-call! herein */ /* or directly after XferCopyObj-call for this element */ #ifdef UG_DIM_2 DDD_XferAddData(context, EDGES_OF_ELEM(pe), dddctrl.TypeEdge); #endif } /* copy corner nodes */ for(i=0; i unpack */ /* XFER_UPGRADE: new MIDNODE pointers might be non NULL */ /* if (newness == XFER_REJECT) return; */ /* retrieve edges from message */ for (i=0; imidnode)) /* this is the 2D case for edge creation: */ /* CreateEdge increments the NO_OF_ELEM count */ /* NO_OF_ELEM counter gets wrong if an element */ /* is unpacked several times. */ ASSERT(NBNODE(LINK0(ecopy)) != NULL); ASSERT(NBNODE(LINK1(ecopy)) != NULL); if (newness == XFER_NEW) { enew = CreateEdge(theGrid,pe,i, false); SETEDSUBDOM(enew,EDSUBDOM(ecopy)); } else { enew = GetEdge(NBNODE(LINK0(ecopy)), NBNODE(LINK1(ecopy))); if (enew == NULL) { enew = CreateEdge(theGrid,pe,i,false); SETEDSUBDOM(enew,EDSUBDOM(ecopy)); /* TODO: remove this check if the first call is with XFER_NEW */ ASSERT(0); DEC_NO_OF_ELEM(enew); } } PRINTDEBUG(dddif,2,(PFMT " ElemScatterEdge(): elem=" EID_FMTX " create edge=%x for n0=" EID_FMTX " n1=" ID_FMTX "\n", me,EID_PRTX(pe),enew, ID_PRTX(NBNODE(LINK0(ecopy))), ID_PRTX(NBNODE(LINK1(ecopy))))); if (enew == NULL) { PRINTDEBUG(dddif,1,(PFMT " ElemScatterEdge(): ERROR pe=" EID_FMTX " i=%d %s returned NULL\n", me,EID_PRTX(pe),i,(newness==XFER_NEW) ? "CreateEdge()" : "GetEdge()")); ASSERT(0); } #ifdef Debug { EDGE *edge0,*edge1; edge0 = GetEdge(NBNODE(LINK0(ecopy)),NBNODE(LINK1(ecopy))); edge1 = GetEdge(NBNODE(LINK1(ecopy)),NBNODE(LINK0(ecopy))); if (edge0 != edge1) { PRINTDEBUG(dddif,1,(PFMT " ElemScatterEdge(): n0=" ID_FMTX " n1=" ID_FMTX " edge0=%08x BUT edge1=%08x\n",me, ID_PRTX(NBNODE(LINK0(ecopy))), ID_PRTX(NBNODE(LINK1(ecopy))), edge0,edge1)); ASSERT(0); } } #endif /* copy midnode pointer */ if (MIDNODE(ecopy) != NULL) { VERTEX *theVertex; INT co0,co1; MIDNODE(enew) = MIDNODE(ecopy); theVertex = MYVERTEX(MIDNODE(enew)); /* reconstruct local coordinates of vertex */ co0 = CORNER_OF_EDGE(pe,i,0); co1 = CORNER_OF_EDGE(pe,i,1); ASSERT(theVertex != NULL); /* local coordinates have to be local towards pe */ if (EMASTER(pe)) { if (MOVED(theVertex)) { DOUBLE *x[MAX_CORNERS_OF_ELEM]; INT n; CORNER_COORDINATES(pe,n,x); UG_GlobalToLocal(n,(const DOUBLE **)x, CVECT(theVertex),LCVECT(theVertex)); } else V_DIM_LINCOMB(0.5, LOCAL_COORD_OF_ELEM(pe,co0), 0.5, LOCAL_COORD_OF_ELEM(pe,co1), LCVECT(theVertex)); /* make vertex information consistent */ VFATHER(theVertex) = pe; SETONEDGE(theVertex,i); } /* set nfather pointer of midnode */ ASSERT(enew != NULL); ASSERT(ID(MIDNODE(enew)) != -1); SETNFATHER(MIDNODE(enew),(GEOM_OBJECT *)enew); PRINTDEBUG(dddif,1,(PFMT " ElemScatterEdge(): n=" ID_FMTX " NTYPE=%d OBJT=%d father " ID_FMTX " \n", me,ID_PRTX(MIDNODE(enew)),NTYPE(MIDNODE(enew)), OBJT(NFATHER(MIDNODE(enew))), NFATHER(MIDNODE(enew)))); } /* copy edge vector pointer */ if (newness == XFER_NEW) if (ddd_ctrl(context).edgeData) if (EDVECTOR(ecopy) != NULL) { EDVECTOR(enew) = EDVECTOR(ecopy); VOBJECT(EDVECTOR(enew)) = (GEOM_OBJECT *)enew; } } } #endif /* end UG_DIM_2 */ /****************************************************************************/ static void ElemGatherI (DDD::DDDContext& context, DDD_OBJ obj, int cnt, DDD_TYPE type_id, void *data) { if (type_id == DDD_USER_DATA) { DuneEntityGather(context, obj, cnt, type_id, data); return; } #ifdef UG_DIM_2 /* now: type_id is always TypeEdge */ ElemGatherEdge(context, (ELEMENT *)obj, cnt, (char *)data); #endif } static void ElemScatterI (DDD::DDDContext& context, DDD_OBJ obj, int cnt, DDD_TYPE type_id, void *data, int newness) { if (type_id == DDD_USER_DATA) { DuneEntityScatter(context, obj, cnt, type_id, data, newness); return; } #ifdef UG_DIM_2 /* type_id is always TypeEdge */ ElemScatterEdge(context, (ELEMENT *)obj, cnt, (char *)data, newness); #endif } static void ElemGatherB (DDD::DDDContext& context, DDD_OBJ obj, int cnt, DDD_TYPE type_id, void *data) { INT i,nsides; BNDS *bnds[MAX_SIDES_OF_ELEM]; ELEMENT *pe = (ELEMENT *)obj; if (type_id == DDD_DOMAIN_DATA) { nsides = SIDES_OF_ELEM(pe); for (i=0; i(context, obj, cnt, type_id, data); return; } /* now: type_id is TypeEdge or other */ #ifdef UG_DIM_2 if (type_id==ddd_ctrl(context).TypeEdge) { ElemGatherEdge(context, pe, cnt, (char *)data); } #endif } static void ElemScatterB (DDD::DDDContext& context, DDD_OBJ obj, int cnt, DDD_TYPE type_id, void *data, int newness) { INT i,nsides; BNDS *bnds[MAX_SIDES_OF_ELEM]; ELEMENT *pe = (ELEMENT *)obj; if (type_id == DDD_DOMAIN_DATA) { nsides = SIDES_OF_ELEM(pe); for (i=0; i(context, obj, cnt, type_id, data, newness); return; } /* now: type_id is TypeEdge or other */ #ifdef UG_DIM_2 if (type_id==ddd_ctrl(context).TypeEdge) { ElemScatterEdge(context, pe, cnt, (char *)data, newness); } #endif } /****************************************************************************/ static void ElementObjMkCons (DDD::DDDContext& context, DDD_OBJ obj, int newness) { INT lostson = 0; ELEMENT *pe = (ELEMENT *)obj; ELEMENT *succe = SUCCE(pe); ELEMENT *Next = NULL; INT prio = EPRIO(pe); ELEMENT *theFather = EFATHER(pe); ELEMENT *NbElement; INT level = LEVEL(pe); GRID *theGrid = GetGridOnDemand(ddd_ctrl(context).currMG,level); PRINTDEBUG(dddif,1,(PFMT " ElementObjMkCons(): pe=" EID_FMTX " newness=%d\n", me,EID_PRTX(pe),newness)) DEBUGNSONS(pe,theFather,"ElementObjMkCons begin:"); /* correct nb relationships between ghostelements */ if (EGHOST(pe)) { for (INT i = 0; i < SIDES_OF_ELEM(pe); i++) { NbElement = NBELEM(pe,i); if (NbElement!=NULL && EGHOST(NbElement)) { INT j = 0; for (j = 0; j < SIDES_OF_ELEM(NbElement); j++) if (NBELEM(NbElement,j) == pe) break; /* no backptr reset nb pointer */ if (j >= SIDES_OF_ELEM(NbElement)) SET_NBELEM(pe,i,NULL); } } } /* reconstruct pointer from vectors */ if (ddd_ctrl(context).elemData) VOBJECT(EVECTOR(pe)) = (GEOM_OBJECT*)pe; #ifdef UG_DIM_3 if (ddd_ctrl(context).sideData) for (INT i = 0; i < SIDES_OF_ELEM(pe); i++) { VOBJECT(SVECTOR(pe,i)) = (GEOM_OBJECT*)pe; SETVECTORSIDE(SVECTOR(pe,i), i); } #endif /* if called with prio old=ghost and new=ghost, then you have eventually to unlink and link an element again to avoid decoupling of element and its father. Sample scenario: father=a son=x are on proc p. father is deleted and removes his reference in son, but father and son are sent again to p. Son x gets his father pointer again. Son needs to be rearranged in element list to be surely a son of father. This applies only for ghost sons, since master sons avoid deleting of their fathers?! */ if (newness != XFER_NEW) { if (prio == PrioMaster) return; else if (theFather != NULL) { ELEMENT *SonList[MAX_SONS]; /* check whether NSONS of father must be incremented */ if (GetAllSons(theFather,SonList)) ASSERT(0); int i = 0; while (i correct NSONS */ next = SUCCE(pe); while (next!=NULL && PRIO2INDEX(EPRIO(next))==PRIO2INDEX(prio) && theFather==EFATHER(next)) { SETNSONS(theFather,NSONS(theFather)+1); next = SUCCE(next); } } SETNSONS(theFather,NSONS(theFather)+1); } else { /* link coarse grid element or ghost element */ GRID_LINK_ELEMENT(theGrid,pe,prio); #ifdef Debug if (level > 0) /* only ghost elements may have no father */ assert(EGHOST(pe)); #endif } } #ifdef UG_DIM_3 /* update element count of edges for new created elements */ if (newness == XFER_NEW) /* increment elem counter in edges */ for (INT i = 0; i < EDGES_OF_ELEM(pe); i++) { EDGE *theEdge; NODE *theNode0 = CORNER(pe,CORNER_OF_EDGE(pe,i,0)); NODE *theNode1 = CORNER(pe,CORNER_OF_EDGE(pe,i,1)); ASSERT(theNode0!=NULL && theNode1!=NULL); PRINTDEBUG(dddif,4,(PFMT " ElementObjMkCons(): pe=" EID_FMTX " INC_NO_OF_ELEM for n0=" ID_FMTX " n1=" ID_FMTX "\n", me,EID_PRTX(pe),ID_PRTX(theNode0),ID_PRTX(theNode1))) theEdge = GetEdge(theNode0,theNode1); if (theEdge == NULL) { PRINTDEBUG(dddif,0,(PFMT " ElementObjMkCons(): pe=" EID_FMTX "/%d/%d INC_NO_OF_ELEM for n0=" ID_FMTX " n1=" ID_FMTX " FAILED\n", me,EID_PRTX(pe),ECLASS(pe),REFINE(EFATHER(pe)), ID_PRTX(theNode0),ID_PRTX(theNode1))) assert(0); } INC_NO_OF_ELEM(theEdge); } #endif DEBUGNSONS(pe,theFather,"end ElementObjMkCons"); } static void ElementPriorityUpdate (DDD::DDDContext& context, DDD_OBJ obj, DDD_PRIO new_) { ELEMENT *pe = (ELEMENT *)obj; ELEMENT *theFather = EFATHER(pe); ELEMENT *succe = SUCCE(pe); INT level = LEVEL(pe); GRID *theGrid = GetGridOnDemand(ddd_ctrl(context).currMG,level); const DDD_PRIO old = EPRIO(pe); INT lostson = 1; PRINTDEBUG(dddif,1,(PFMT " ElementPriorityUpdate(): e=" EID_FMTX " old=%d new=%d level=%d\n",me,EID_PRTX(pe),old,new_,level)) if (pe == NULL) return; /* if called with prio old=ghost and new=ghost, then you have to unlink and link again to avoid decoupling of son and father. Sample scenario: father=a son=x are on proc p. father is deleted and removes his reference in son, but father and son are sent again to p. Son x gets his father pointer again. Son needs to be rearranged in element to list be surely a son of father. This applies only for ghost sons, since master sons avoid deleting of their fathers?! */ if (old == PrioNone) { /* only valid for masters */ ASSERT(new_ == PrioMaster); return; } if (new_ == PrioNone) { /* only valid when prio undefined */ printf("prio=%d\n",old); fflush(stdout); ASSERT(old <= 0); return; } /* check whether element and father are decoupled */ if (theFather != NULL) { ELEMENT *SonList[MAX_SONS]; int i; if (GetAllSons(theFather,SonList)) ASSERT(0); i = 0; while (i 0) { assert(EGHOSTPRIO(new_)); assert(EGHOST(pe)); } */ } } } /****************************************************************************/ /****************************************************************************/ /* */ /* handlers for typeedge */ /* */ /****************************************************************************/ /****************************************************************************/ static void EdgeUpdate (DDD::DDDContext& context, DDD_OBJ obj) { EDGE *pe = (EDGE *)obj; INT level = LEVEL(NBNODE(LINK0(pe))); GRID *theGrid = GetGridOnDemand(ddd_ctrl(context).currMG,level); PRINTDEBUG(dddif,1,(PFMT " EdgeUpdate(): edge=%x/%08x EDOBJT=%d " " NO_OF_ELEM=%d\n", me,pe,DDD_InfoGlobalId(PARHDR(pe)),OBJT(pe),NO_OF_ELEM(pe))) { /* insert in link lists of nodes */ LINK* link0 = LINK0(pe); LINK* link1 = LINK1(pe); PRINTDEBUG(dddif,2,(PFMT " EdgeUpdate(): edge=%x/%08x node0=" ID_FMTX " node1=" ID_FMTX "\n", me,pe,DDD_InfoGlobalId(PARHDR(pe)), ID_PRTX(NBNODE(link1)),ID_PRTX(NBNODE(link0)))) NODE* node0 = NBNODE(link1); NODE* node1 = NBNODE(link0); NEXT(link0) = START(node0); START(node0) = link0; NEXT(link1) = START(node1); START(node1) = link1; /* reset element counter SET_NO_OF_ELEM(pe,0); */ } /* set nfather pointer of midnode */ if (MIDNODE(pe) != NULL) { ASSERT(ID(MIDNODE(pe)) != -1); ASSERT(NTYPE((MIDNODE(pe))) == MID_NODE); SETNFATHER(MIDNODE(pe),(GEOM_OBJECT *)pe); } ASSERT(OBJT(pe) == EDOBJ); /* increment counter */ NE(theGrid)++; } static void EdgePriorityUpdate (DDD::DDDContext& context, DDD_OBJ obj, DDD_PRIO new_) { EDGE *theEdge = (EDGE *)obj; INT level = LEVEL(theEdge); [[maybe_unused]] INT old = PRIO(theEdge); GetGridOnDemand(ddd_ctrl(context).currMG,level); PRINTDEBUG(dddif,2,(PFMT " EdgePriorityUpdate(): n=" ID_FMTX " old=%d new_=%d " "level=%d\n",me,ID_PRTX(theEdge),old,new_,level)) } static void EdgeObjMkCons (DDD::DDDContext& context, DDD_OBJ obj, int newness) { EDGE *theEdge = (EDGE *) obj; PRINTDEBUG(dddif,2,(PFMT " EdgeObjMkCons(): n=" ID_FMTX " EDOBJ=%d\n", me,ID_PRTX(theEdge),OBJT(theEdge))) /* set pointer of vector to its edge */ if (ddd_ctrl(context).edgeData && EDVECTOR(theEdge)) VOBJECT(EDVECTOR(theEdge)) = (GEOM_OBJECT*)theEdge; ASSERT(OBJT(theEdge) == EDOBJ); } static void EdgeXferCopy (DDD::DDDContext& context, DDD_OBJ obj, DDD_PROC proc, DDD_PRIO prio) { [[maybe_unused]] EDGE *pe = (EDGE *)obj; PRINTDEBUG(dddif,1,(PFMT " EdgeXferCopy(): edge=%x/%08x proc=%d prio=%d\n", me,pe,DDD_InfoGlobalId(PARHDR(pe)),proc,prio)); ASSERT(OBJT(pe) == EDOBJ); } /****************************************************************************/ /****************************************************************************/ /* */ /* general handlers */ /* */ /****************************************************************************/ /****************************************************************************/ void NS_DIM_PREFIX ObjectPriorityUpdate (DDD::DDDContext& context, DDD_OBJ obj, DDD_PRIO new_) { char type = OBJT(obj); switch(type) { case VEOBJ : VectorPriorityUpdate(context, obj,new_); break; case IVOBJ : case BVOBJ : VertexPriorityUpdate(context, obj,new_); break; case NDOBJ : NodePriorityUpdate(context, obj,new_); break; case IEOBJ : case BEOBJ : ElementPriorityUpdate(context, obj,new_); break; case EDOBJ : EdgePriorityUpdate(context, obj,new_); break; default : std::abort(); } } /****************************************************************************/ /* init handlers for all element */ static void ElemHandlerInit (DDD::DDDContext& context, DDD_TYPE etype, INT handlerSet) { DDD_SetHandlerLDATACONSTRUCTOR(context, etype, ElementLDataConstructor); DDD_SetHandlerDELETE (context, etype, ElementDelete); DDD_SetHandlerXFERCOPY (context, etype, ElementXferCopy); DDD_SetHandlerSETPRIORITY (context, etype, ElementPriorityUpdate); #ifdef UG_DIM_3 DDD_SetHandlerUPDATE (context, etype, ElementUpdate); #endif switch (handlerSet) { /* TODO: not needed any more ?? case HSET_XFER: DDD_SetHandlerOBJMKCONS(context, etype, ElementObjMkCons_Xfer); break; case HSET_REFINE: DDD_SetHandlerOBJMKCONS(context, etype, ElementObjMkCons_Refine); break; */ default : DDD_SetHandlerOBJMKCONS(context, etype, ElementObjMkCons); break; } } /* init handlers for inner element */ static void IElemHandlerInit (DDD::DDDContext& context, DDD_TYPE etype, INT handlerSet) { /* init standard elem handlers */ ElemHandlerInit(context, etype, handlerSet); /* init additional handlers, necessary for inside management */ DDD_SetHandlerXFERGATHER (context, etype, ElemGatherI); DDD_SetHandlerXFERSCATTER(context, etype, ElemScatterI); } /* init handlers for boundary element */ static void BElemHandlerInit (DDD::DDDContext& context, DDD_TYPE etype, INT handlerSet) { /* init standard elem handlers */ ElemHandlerInit(context, etype, handlerSet); /* init additional handlers, necessary for boundary management */ DDD_SetHandlerXFERGATHER (context, etype, ElemGatherB); DDD_SetHandlerXFERSCATTER(context, etype, ElemScatterB); } /****************************************************************************/ /* init all handlers necessary for grid xfer */ void NS_DIM_PREFIX ddd_HandlerInit (DDD::DDDContext& context, INT handlerSet) { auto& dddctrl = ddd_ctrl(context); DDD_SetHandlerUPDATE (context, dddctrl.TypeVector, VectorUpdate); DDD_SetHandlerXFERCOPY (context, dddctrl.TypeVector, VectorXferCopy); DDD_SetHandlerSETPRIORITY (context, dddctrl.TypeVector, VectorPriorityUpdate); /* TODO: not used DDD_SetHandlerDELETE (context, dddctrl.TypeVector, VectorDelete); */ DDD_SetHandlerUPDATE (context, dddctrl.TypeIVertex, VertexUpdate); DDD_SetHandlerSETPRIORITY (context, dddctrl.TypeIVertex, VertexPriorityUpdate); DDD_SetHandlerLDATACONSTRUCTOR (context, dddctrl.TypeBVertex, BVertexLDataConstructor); DDD_SetHandlerUPDATE (context, dddctrl.TypeBVertex, VertexUpdate); DDD_SetHandlerXFERCOPY (context, dddctrl.TypeBVertex, BVertexXferCopy); DDD_SetHandlerXFERGATHER (context, dddctrl.TypeBVertex, BVertexGather); DDD_SetHandlerXFERSCATTER (context, dddctrl.TypeBVertex, BVertexScatter); DDD_SetHandlerSETPRIORITY (context, dddctrl.TypeBVertex, VertexPriorityUpdate); DDD_SetHandlerXFERGATHER (context, dddctrl.TypeNode, DuneEntityGather); DDD_SetHandlerXFERSCATTER (context, dddctrl.TypeNode, DuneEntityScatter); DDD_SetHandlerLDATACONSTRUCTOR (context, dddctrl.TypeNode, NodeObjInit); DDD_SetHandlerDESTRUCTOR (context, dddctrl.TypeNode, NodeDestructor); DDD_SetHandlerOBJMKCONS (context, dddctrl.TypeNode, NodeObjMkCons); DDD_SetHandlerUPDATE (context, dddctrl.TypeNode, NodeUpdate); DDD_SetHandlerXFERCOPY (context, dddctrl.TypeNode, NodeXferCopy); DDD_SetHandlerSETPRIORITY (context, dddctrl.TypeNode, NodePriorityUpdate); #ifdef UG_DIM_2 IElemHandlerInit(context, dddctrl.TypeTrElem, handlerSet); BElemHandlerInit(context, dddctrl.TypeTrBElem, handlerSet); IElemHandlerInit(context, dddctrl.TypeQuElem, handlerSet); BElemHandlerInit(context, dddctrl.TypeQuBElem, handlerSet); #endif #ifdef UG_DIM_3 IElemHandlerInit(context, dddctrl.TypeTeElem, handlerSet); BElemHandlerInit(context, dddctrl.TypeTeBElem, handlerSet); IElemHandlerInit(context, dddctrl.TypePyElem, handlerSet); BElemHandlerInit(context, dddctrl.TypePyBElem, handlerSet); IElemHandlerInit(context, dddctrl.TypePrElem, handlerSet); BElemHandlerInit(context, dddctrl.TypePrBElem, handlerSet); IElemHandlerInit(context, dddctrl.TypeHeElem, handlerSet); BElemHandlerInit(context, dddctrl.TypeHeBElem, handlerSet); #endif DDD_SetHandlerUPDATE (context, dddctrl.TypeEdge, EdgeUpdate); DDD_SetHandlerOBJMKCONS (context, dddctrl.TypeEdge, EdgeObjMkCons); DDD_SetHandlerXFERCOPY (context, dddctrl.TypeEdge, EdgeXferCopy); DDD_SetHandlerSETPRIORITY (context, dddctrl.TypeEdge, EdgePriorityUpdate); DomHandlerInit(handlerSet); } #endif /* ModelP */ dune-uggrid-2.11.0+dfsg/dune/uggrid/parallel/dddif/identify.cc000066400000000000000000001572221513616443000241440ustar00rootroot00000000000000// SPDX-FileCopyrightText: Copyright © DUNE Project contributors, see file LICENSE.md in module root // SPDX-License-Identifier: LGPL-2.1-or-later // -*- tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- // vi: set et ts=4 sw=2 sts=2: /****************************************************************************/ /* */ /* File: identify.c */ /* */ /* Purpose: identification of distributed ug objects */ /* */ /* Author: Stefan Lang */ /* Institut fuer Computeranwendungen III */ /* Universitaet Stuttgart */ /* Pfaffenwaldring 27 */ /* 70550 Stuttgart */ /* email: ug@ica3.uni-stuttgart.de */ /* */ /* History: 26.11.96 begin, first version extracted from refine.c */ /* */ /* Remarks: */ /* */ /****************************************************************************/ #ifdef ModelP /****************************************************************************/ /* */ /* include files */ /* system include files */ /* application include files */ /* */ /****************************************************************************/ #include #include #include #include #include #include #include #include #include #include #include "identify.h" #include "parallel.h" /* UG namespaces: */ USING_UG_NAMESPACES /* PPIF namespace: */ using namespace PPIF; /****************************************************************************/ /* */ /* defines in the following order */ /* */ /* compile time constants defining static data size (i.e. arrays) */ /* other constants */ /* macros */ /* */ /****************************************************************************/ /* flags for identification */ enum {CLEAR = 0, IDENT = 1}; /* maximum count of objects for identification */ #define MAX_OBJECT 3 /* maximum count of tokens for identification */ #define MAX_TOKEN 10 /* determine the ddd header for identification of a node */ #define NIDENT_HDR(node) ( (CORNERTYPE(node)) ? \ PARHDR((NODE *)NFATHER(node)) : PARHDR(node) ) /* mapping of flags used for identification */ #define NIDENT(p) THEFLAG(p) #define SETNIDENT(p,n) SETTHEFLAG(p,n) #define EDIDENT(p) THEFLAG(p) #define SETEDIDENT(p,n) SETTHEFLAG(p,n) /* strong checking of identification (0=off 1==on) */ #define NIDENTASSERT 1 #define EDIDENTASSERT 1 /****************************************************************************/ /* */ /* data structures used in this source file (exported data structures are */ /* in the corresponding include file!) */ /* */ /****************************************************************************/ /****************************************************************************/ /* */ /* definition of exported global variables */ /* */ /****************************************************************************/ INT NS_DIM_PREFIX ident_mode = IDENT_OFF; /****************************************************************************/ /* */ /* definition of variables global to this source file only (static!) */ /* */ /****************************************************************************/ /* this function is called for low level identification */ static INT (*Ident_FctPtr)(DDD::DDDContext& context, DDD_HDR *IdentObjectHdr, INT nobject, const DDD_InfoProcListRange& proclist, DDD_PRIO skiptag, DDD_HDR *IdentHdr, INT nident) = NULL; static int check_nodetype = 0; #ifdef Debug static INT debug = 0; static INT identlevel = 0; #endif /****************************************************************************/ /* */ /* forward declarations of functions used before they are defined */ /* */ /****************************************************************************/ /****************************************************************************/ /* ResetIdentFlags - SYNOPSIS: static void ResetIdentFlags (GRID *UpGrid); PARAMETERS: . UpGrid DESCRIPTION: RETURN VALUE: void */ /****************************************************************************/ static void ResetIdentFlags (GRID *Grid) { /* clear all IDENT flags */ for (NODE* theNode=FIRSTNODE(Grid); theNode!=NULL; theNode=SUCCN(theNode)) { SETNIDENT(theNode,CLEAR); SETUSED(theNode,0); for (LINK* theLink=START(theNode); theLink!=NULL; theLink=NEXT(theLink)) { EDGE* theEdge = MYEDGE(theLink); SETEDIDENT(theEdge,CLEAR); } } } #ifdef Debug /****************************************************************************/ /* Print_Identify_ObjectList - SYNOPSIS: static INT Print_Identify_ObjectList (DDD_HDR *IdentObjectHdr, INT nobject, const DDD_InfoProcListRange& proclist, DDD_PRIO skiptag, DDD_HDR *IdentHdr, INT nident); PARAMETERS: . IdentObjectHdr . nobject . proclist . skiptag . IdentHdr . nident DESCRIPTION: RETURN VALUE: INT */ /****************************************************************************/ static INT Print_Identify_ObjectList (DDD_HDR *IdentObjectHdr, INT nobject, const DDD_InfoProcListRange& proclist, DDD_PRIO skiptag, DDD_HDR *IdentHdr, INT nident) { ASSERT(nobject>0); ASSERT(nident>0); ASSERT(!proclist.empty()); /* print the interesting call parameters */ PrintDebug ("%d: Print_Identify_ObjectList(): nobject=%d nident=%d" " skiptag=%d\n",me,nobject,nident,skiptag); /* print line prefix */ PrintDebug ("%d: l=%d",me,identlevel); /* print the objects used for identify */ PrintDebug (" IdentHdr:"); for (INT i=0; i0); ASSERT(nident>0); ASSERT(!proclist.empty()); /* print the interesting call parameters */ PrintDebug ("%d: Print_Identified_ObjectList(): nobject=%d nident=%d" " skiptag=%d\n",me,nobject,nident,skiptag); /* print the objects to identify */ PrintDebug ("%d: l=%d IdentObjectHdr:",me,identlevel); for (INT i=0; i0); ASSERT(nident>0); ASSERT(!proclist.empty()); #ifdef Debug IFDEBUG(dddif,1) Print_Identify_ObjectList(IdentObjectHdr,nobject,proclist,skiptag, IdentHdr,nident); ENDDEBUG #endif INT n = 0; for (auto&& [proc, prio] : proclist) { ASSERT(n < context.procs()); if (prio == skiptag) continue; /* identify the object */ for (INT j=0; j0); return 0; } #ifdef UG_DIM_3 static void IdentifySideVector (DDD::DDDContext& context, ELEMENT* theElement, ELEMENT *theNeighbor, ELEMENT *Son, INT SonSide) { INT nident = 0; DDD_HDR IdentObjectHdr[MAX_OBJECT]; DDD_HDR IdentHdr[MAX_TOKEN]; IdentObjectHdr[0] = PARHDR(SVECTOR(Son,SonSide)); /* identify using corner nodes */ for (INT k=0; kdddContext(); INT nobject,nident; DDD_HDR IdentObjectHdr[MAX_OBJECT]; DDD_HDR IdentHdr[MAX_TOKEN]; nobject = nident = 0; /* is this node identified? */ #ifdef Debug if (debug == 1) { if (NIDENT(theNode) == CLEAR) return; } else #endif /* return if not needed any more */ if (!USED(theNode)) return; /* return if already identified */ if (NIDENT(theNode) == IDENT) return; /* only new created nodes are identified */ if (!NEW_NIDENT(theNode)) return; switch (NTYPE(theNode)) { case (CORNER_NODE) : { /* identification of cornernodes is done */ /* in Identify_SonNodes() */ return; PRINTDEBUG(dddif,1,("%d: Identify CORNERNODE gid=%08x node=%d\n", me, DDD_InfoGlobalId(PARHDR(theNode)), node)); IdentObjectHdr[nobject++] = PARHDR(theNode); /* identify to proclist of node */ const auto& proclist = DDD_InfoProcListRange(context, PARHDR((NODE *)NFATHER(theNode)), false); /* identify using father node */ IdentHdr[nident++] = PARHDR((NODE *)NFATHER(theNode)); Ident_FctPtr(context, IdentObjectHdr, nobject, proclist, PrioHGhost, IdentHdr, nident); break; } case (MID_NODE) : { #ifdef UG_DIM_2 NODE **EdgeNodes = Nodes; #endif EDGE *theEdge; #ifdef UG_DIM_3 NODE *EdgeNodes[MAX_SIDE_NODES]; /* identification of cornernodes is done */ /* in Identify_SonEdges() */ return; EdgeNodes[0] = Nodes[node-ncorners]; EdgeNodes[1] = Nodes[(node-ncorners+1)%ncorners]; EdgeNodes[2] = theNode; #endif ASSERT(EdgeNodes[0]!=NULL); ASSERT(EdgeNodes[1]!=NULL); ASSERT(EdgeNodes[2]!=NULL); PRINTDEBUG(dddif,1,("%d: Identify MIDNODE gid=%08x node=%d\n", me, DDD_InfoGlobalId(PARHDR(theNode)), node)); /* identify midnode, vertex, vector */ IdentObjectHdr[nobject++] = PARHDR(theNode); IdentObjectHdr[nobject++] = PARHDRV(MYVERTEX(theNode)); #ifdef UG_DIM_2 if (!NEW_NIDENT(theNode)) break; #endif /* Identify to proclist of edge */ theEdge = GetEdge((NODE *)NFATHER(EdgeNodes[0]), (NODE *)NFATHER(EdgeNodes[1])); ASSERT(theEdge!=NULL); const auto& proclist = DDD_InfoProcListRange(context, PARHDR(theEdge), false); /* identify using edge nodes */ IdentHdr[nident++] = PARHDR((NODE *)NFATHER(EdgeNodes[0])); IdentHdr[nident++] = PARHDR((NODE *)NFATHER(EdgeNodes[1])); /* this is the buggy case IdentHdr[nident++] = PARHDR(EdgeNodes[0]); IdentHdr[nident++] = PARHDR(EdgeNodes[1]); */ Ident_FctPtr(context, IdentObjectHdr, nobject, proclist, PrioHGhost, IdentHdr, nident); break; } #ifdef UG_DIM_3 case (SIDE_NODE) : { PRINTDEBUG(dddif,1,("%d: Identify SIDENODE gid=%08x node=%d\n", me,DDD_InfoGlobalId(PARHDR(theNode)),node)); /* identify sidenode and vertex */ IdentObjectHdr[nobject++] = PARHDR(theNode); IdentObjectHdr[nobject++] = PARHDRV(MYVERTEX(theNode)); /* identify to proclist of neighbor element */ const auto& proclist = DDD_InfoProcListRange(context, PARHDRE(theNeighbor), false); /* identify using corner nodes of side */ for (INT i=0; idddContext(); #ifdef UG_DIM_2 /* no identfication to nonrefined neighbors */ if (MARK(theNeighbor) == NO_REFINEMENT) return(0); #endif #ifdef UG_DIM_3 /* identification of sonedges is done in Identify_SonEdges() */ { EDGE* FatherEdge = GetFatherEdge(theEdge); if (FatherEdge != NULL) return(0); } #endif /* only newly created edges are identified */ if (!NEW_EDIDENT(theEdge)) return(0); /* edge unlocked -> no debugging occurs */ #ifdef Debug if (debug == 1) { if (EDIDENT(theEdge) == CLEAR) return(0); } else #endif /* edge locked -> already identified */ if (EDIDENT(theEdge) == IDENT) return(0); #ifdef UG_DIM_3 IdentObjectHdr[nobject++] = PARHDR(theEdge); #endif /* identify to proclist of neighbor */ const auto& proclist = DDD_InfoProcListRange(context, PARHDRE(theNeighbor), false); /* now choose identificator objects */ NODE* theNode0 = NBNODE(LINK0(theEdge)); NODE* theNode1 = NBNODE(LINK1(theEdge)); ASSERT(!CENTERTYPE(theNode0)); ASSERT(!CENTERTYPE(theNode1)); if (CORNERTYPE(theNode0)) { ASSERT(NFATHER(theNode0)!=NULL); IdentHdr[nident++] = PARHDR((NODE *)NFATHER(theNode0)); } #ifdef UG_DIM_3 /* since midnodes are identified later in Debug case */ /* choose fatheredge here (s.l. 980227) */ else if (MIDTYPE(theNode0)) { ASSERT(NFATHER(theNode0)!=NULL); IdentHdr[nident++] = PARHDR((EDGE *)NFATHER(theNode0)); } #endif else { /* side node */ #ifdef UG_DIM_3 ASSERT(SIDETYPE(theNode0)); #endif IdentHdr[nident++] = PARHDR(theNode0); } if (CORNERTYPE(theNode1)) { ASSERT(NFATHER(theNode1)!=NULL); IdentHdr[nident++] = PARHDR((NODE *)NFATHER(theNode1)); } #ifdef UG_DIM_3 /* since midnodes are identified later in Debug case */ /* choose fatheredge here (s.l. 980227) */ else if (MIDTYPE(theNode1)) { ASSERT(NFATHER(theNode1)!=NULL); IdentHdr[nident++] = PARHDR((EDGE *)NFATHER(theNode1)); } #endif else { /* side node */ #ifdef UG_DIM_3 ASSERT(SIDETYPE(theNode1)); #endif IdentHdr[nident++] = PARHDR(theNode1); } if (nobject > 0) Ident_FctPtr(context, IdentObjectHdr, nobject, proclist, PrioHGhost, IdentHdr, nident); /* debugging unlocks the edge */ #ifdef Debug if (debug == 1) { SETEDIDENT(theEdge,CLEAR); } else #endif /* lock this edge for identification */ SETEDIDENT(theEdge,IDENT); return 0; } /****************************************************************************/ /* IdentifyEdge - SYNOPSIS: static INT IdentifyEdge (ELEMENT *theElement, ELEMENT *theNeighbor, NODE **SideNodes, INT ncorners, ELEMENT *Son, INT SonSide, INT edgeofside, INT Vec); PARAMETERS: . theElement . theNeighbor . SideNodes . ncorners . Son . SonSide . edgeofside . Vec DESCRIPTION: RETURN VALUE: INT */ /****************************************************************************/ static INT IdentifyEdge (GRID *theGrid, ELEMENT *theElement, ELEMENT *theNeighbor, NODE **SideNodes, INT ncorners, ELEMENT *Son, INT SonSide, INT edgeofside, INT Vec) { NODE *Nodes[2]; EDGE *theEdge; INT nobject,nident; #ifdef UG_DIM_3 INT edge,corner0,corner1; #endif DDD_HDR IdentObjectHdr[MAX_OBJECT]; DDD_HDR IdentHdr[MAX_TOKEN]; auto& context = theGrid->dddContext(); nobject = nident = 0; #ifdef UG_DIM_2 Nodes[0] = CORNER(Son,CORNER_OF_EDGE(Son,SonSide,0)); Nodes[1] = CORNER(Son,CORNER_OF_EDGE(Son,SonSide,1)); #endif #ifdef UG_DIM_3 edge = EDGE_OF_SIDE(Son,SonSide,edgeofside); corner0 = CORNER_OF_EDGE(Son,edge,0); corner1 = CORNER_OF_EDGE(Son,edge,1); Nodes[0] = CORNER(Son,corner0); Nodes[1] = CORNER(Son,corner1); PRINTDEBUG(dddif,5,("%4d: edge=%d corner0=%d corner1=%d Nodes[0]=%d " "Nodes[1]=%d\n", me,edge, corner0, corner1, ID(Nodes[0]), ID(Nodes[1]))); #endif ASSERT(Nodes[0]!=NULL); ASSERT(Nodes[1]!=NULL); theEdge = GetEdge(Nodes[0],Nodes[1]); ASSERT(theEdge!=NULL); #ifdef UG_DIM_2 /* no identfication to nonrefined neighbors */ if (MARK(theNeighbor) == NO_REFINEMENT) return(0); #endif #ifdef UG_DIM_3 /* identification of sonedges is done in Identify_SonEdges() */ if (0) if (CORNERTYPE(Nodes[0]) && CORNERTYPE(Nodes[1])) { [[maybe_unused]] EDGE *FatherEdge; FatherEdge = GetEdge((NODE *)NFATHER(Nodes[0]),(NODE *)NFATHER(Nodes[1])); ASSERT(FatherEdge != NULL); return(0); /* if (FatherEdge != NULL) return(0); */ } { EDGE *FatherEdge; FatherEdge = GetFatherEdge(theEdge); if (FatherEdge != NULL) return(0); } #endif /* only newly created edges are identified */ if (!NEW_EDIDENT(theEdge)) return(0); /* edge unlocked -> no debugging occurs */ #ifdef Debug if (debug == 1) { if (EDIDENT(theEdge) == CLEAR) return(0); } else #endif /* edge locked -> already identified */ if (EDIDENT(theEdge) == IDENT) return(0); PRINTDEBUG(dddif,1,("%d: Identify EDGE edgeofside=%d pe=%08x/%x eID=%d" " ntype0=%d ntype1=%d Vec=%d\n",me,edgeofside, DDD_InfoGlobalId(PARHDRE(Son)),Son,ID(Son), NTYPE(Nodes[0]), NTYPE(Nodes[1]), Vec)) #ifdef UG_DIM_3 IdentObjectHdr[nobject++] = PARHDR(theEdge); #endif #ifdef UG_DIM_2 /* identify to proclist of neighbor */ const auto& proclist = DDD_InfoProcListRange(context, PARHDRE(theNeighbor), false); #endif /* identify to proclist of father edge or neighbor*/ #ifdef UG_DIM_3 DDD_HDR hdr; if (0) { EDGE *fatherEdge = NULL; /* check whether edge inside the side of the element */ fatherEdge = FatherEdge(SideNodes,ncorners,Nodes,theEdge); if (fatherEdge != NULL) hdr = PARHDR(fatherEdge); else hdr = PARHDRE(theNeighbor); } hdr = PARHDRE(theNeighbor); const auto& proclist = DDD_InfoProcListRange(context, hdr, false); #endif if (CORNERTYPE(Nodes[0])) IdentHdr[nident++] = PARHDR((NODE *)NFATHER(Nodes[0])); #ifdef UG_DIM_3 /* since midnodes are identified later in Debug case */ /* choose fatheredge here (s.l. 980227) */ else if (MIDTYPE(Nodes[0])) IdentHdr[nident++] = PARHDR((EDGE *)NFATHER(Nodes[0])); #endif else IdentHdr[nident++] = PARHDR(Nodes[0]); if (CORNERTYPE(Nodes[1])) IdentHdr[nident++] = PARHDR((NODE *)NFATHER(Nodes[1])); #ifdef UG_DIM_3 /* since midnodes are identified later in Debug case */ /* choose fatheredge here (s.l. 980227) */ else if (MIDTYPE(Nodes[1])) IdentHdr[nident++] = PARHDR((EDGE *)NFATHER(Nodes[1])); #endif else IdentHdr[nident++] = PARHDR(Nodes[1]); if (nobject > 0) Ident_FctPtr(context, IdentObjectHdr, nobject, proclist, PrioHGhost, IdentHdr, nident); /* debugging unlocks the edge */ #ifdef Debug if (debug == 1) { SETEDIDENT(theEdge,CLEAR); } else #endif /* lock this edge for identification */ SETEDIDENT(theEdge,IDENT); return 0; } /****************************************************************************/ /* IdentifyObjectsOfElementSide - SYNOPSIS: static INT IdentifyObjectsOfElementSide(GRID *theGrid, ELEMENT *theElement, INT i, ELEMENT *theNeighbor); PARAMETERS: . theGrid . theElement . i . theNeighbor DESCRIPTION: RETURN VALUE: INT */ /****************************************************************************/ static INT IdentifyObjectsOfElementSide(GRID *theGrid, ELEMENT *theElement, INT i, ELEMENT *theNeighbor) { INT nodes; #ifdef Debug INT n = 0; #endif NODE *SideNodes[MAX_SIDE_NODES]; INT ncorners; NODE *theNode; GetSonSideNodes(theElement,i,&nodes,SideNodes,0); ncorners = CORNERS_OF_SIDE(theElement,i); PRINTDEBUG(dddif,1,("%d: IdentifyObjectsOfElementSide():identify NODES " "ncorners=%d nodes=%d\n",me,ncorners,nodes)); /* identify nodes, vertices and node vectors of son elements */ for (INT j = 0; j < MAX_SIDE_NODES; j++) { theNode = SideNodes[j]; if (theNode == NULL) continue; // identify new node including its vertex IdentifyNode(theGrid,theNeighbor, theNode, SideNodes, j, ncorners); #ifdef Debug n++; #endif } ASSERT(n == nodes); /* identify edge vectors (2D); edges, edge and side vectors (3D) */ if (/*VEC_DEF_IN_OBJ_OF_GRID(theGrid,EDGEVEC) ||*/ DIM==3) { ELEMENT *SonList[MAX_SONS]; INT SonsOfSide,SonSides[MAX_SONS]; PRINTDEBUG(dddif,1,("%d: IdentifyObjectsOfElementSide(): identify " "EDGES and VECTORS\n",me)); if (Get_Sons_of_ElementSide(theElement,i,&SonsOfSide, SonList,SonSides,1,0)!=GM_OK) RETURN(GM_FATAL); for (INT j = 0; j < SonsOfSide; j++) { if (/*VEC_DEF_IN_OBJ_OF_GRID(theGrid,EDGEVEC) ||*/ DIM==3) { INT edgeofside; INT nedges = EDGES_OF_SIDE(SonList[j],SonSides[j]); /* identify the edge and vector */ for (edgeofside=0; edgeofsidedddContext(); IdentifySideVector(context, theElement,theNeighbor,SonList[j],SonSides[j]); } #endif } } return GM_OK; } /****************************************************************************/ /* IdentifyDistributedObjects - SYNOPSIS: INT IdentifyDistributedObjects (MULTIGRID *theMG, INT FromLevel, INT ToLevel); PARAMETERS: . theMG . FromLevel . ToLevel DESCRIPTION: RETURN VALUE: INT */ /****************************************************************************/ static INT IdentifyDistributedObjects (MULTIGRID *theMG, INT FromLevel, INT ToLevel) { DDD_PRIO prio; PRINTDEBUG(dddif,1,("%d: IdentifyDistributedObjects(): FromLevel=%d " "ToLevel=%d\n",me,FromLevel,ToLevel)); /* identify distributed objects */ for (INT l=FromLevel; ldddContext(); const auto& dddctrl = ddd_ctrl(context); #ifdef IDENT_ONLY_NEW DDD_IFAOnewayX(context, dddctrl.NodeAllIF,GRID_ATTR(theGrid),IF_FORWARD,sizeof(int), Gather_NewNodeInfo,Scatter_NewNodeInfo); if (UPGRID(theGrid) != NULL) { check_nodetype = CORNER_NODE; if (NIDENTASSERT) DDD_IFAOnewayX(context, dddctrl.NodeAllIF,GRID_ATTR(UPGRID(theGrid)),IF_FORWARD,sizeof(int), Gather_NodeInfo,Scatter_NodeInfo); if (0) DDD_IFAOnewayX(context, dddctrl.NodeAllIF,GRID_ATTR(UPGRID(theGrid)),IF_FORWARD,sizeof(int), Gather_TestNodeInfo,Scatter_TestNodeInfo); } DDD_IFAOnewayX(context, dddctrl.NodeAllIF,GRID_ATTR(theGrid),IF_FORWARD,2*sizeof(int), Gather_IdentSonNode,Scatter_IdentSonNode); #else DDD_IFAOnewayX(context, dddctrl.NodeAllIF,GRID_ATTR(theGrid),IF_FORWARD,sizeof(int), Gather_SonNodeInfo,Scatter_SonNodeInfo); #endif return GM_OK; } /****************************************************************************/ /* Identify_SonEdges - identify son edges SYNOPSIS: INT Identify_SonEdges (GRID *theGrid); PARAMETERS: . theGrid DESCRIPTION: RETURN VALUE: INT */ /****************************************************************************/ INT Identify_SonEdges (GRID *theGrid) { auto& context = theGrid->dddContext(); const auto& dddctrl = ddd_ctrl(context); #ifdef IDENT_ONLY_NEW DDD_IFAOnewayX(context, dddctrl.EdgeSymmVHIF,GRID_ATTR(theGrid),IF_FORWARD,sizeof(int), Gather_NewObjectInfo,Scatter_NewObjectInfo); if (UPGRID(theGrid) != NULL) { check_nodetype = MID_NODE; DDD_IFAOnewayX(context, dddctrl.NodeAllIF,GRID_ATTR(UPGRID(theGrid)),IF_FORWARD,sizeof(int), Gather_NodeInfo,Scatter_NodeInfo); if (EDIDENTASSERT) DDD_IFAOnewayX(context, dddctrl.EdgeSymmVHIF,GRID_ATTR(UPGRID(theGrid)),IF_FORWARD,sizeof(int), Gather_EdgeInfo,Scatter_EdgeInfo); if (0) DDD_IFAOnewayX(context, dddctrl.EdgeSymmVHIF,GRID_ATTR(UPGRID(theGrid)),IF_FORWARD,sizeof(int), Gather_TestEdgeInfo,Scatter_TestEdgeInfo); } DDD_IFAOnewayX(context, dddctrl.EdgeSymmVHIF,GRID_ATTR(theGrid),IF_FORWARD,sizeof(int), Gather_IdentSonObjects,Scatter_IdentSonObjects); #else /* identify the sonedges */ DDD_IFAOnewayX(context, dddctrl.EdgeSymmVHIF,GRID_ATTR(theGrid),IF_FORWARD,sizeof(int), Gather_SonEdgeInfo,Scatter_SonEdgeInfo); #endif return GM_OK; } /****************************************************************************/ /* Identify_SonObjects - identify son objects SYNOPSIS: INT Identify_SonObjects (GRID *theGrid); PARAMETERS: . theGrid DESCRIPTION: This function identifies all objects which are not symmetrically created during grid adaption. These are edges and nodes of the type used by yellow elements, son nodes of type CORNERNODE and son edges. RETURN VALUE: INT */ /****************************************************************************/ #define NODESFIRST 1 INT NS_DIM_PREFIX Identify_SonObjects (GRID *theGrid) { #ifdef Debug identlevel = GLEVEL(theGrid)+1; #endif if (NODESFIRST) { if (Identify_SonNodes (theGrid) != GM_OK) RETURN(GM_ERROR); } else { if (Identify_SonEdges (theGrid) != GM_OK) RETURN(GM_ERROR); } if (IDENT_IN_STEPS) { DDD_IdentifyEnd(theGrid->dddContext()); DDD_IdentifyBegin(theGrid->dddContext()); } if (!NODESFIRST) { if (Identify_SonNodes (theGrid) != GM_OK) RETURN(GM_ERROR); } else { if (Identify_SonEdges (theGrid) != GM_OK) RETURN(GM_ERROR); } return GM_OK; } /****************************************************************************/ /* Identify_Objects_of_ElementSide - SYNOPSIS: INT Identify_Objects_of_ElementSide(GRID *theGrid, ELEMENT *theElement, INT i); PARAMETERS: . theGrid . theElement . i DESCRIPTION: RETURN VALUE: INT */ /****************************************************************************/ INT NS_DIM_PREFIX Identify_Objects_of_ElementSide(GRID *theGrid, ELEMENT *theElement, INT i) { ELEMENT* theNeighbor = NBELEM(theElement,i); if (theNeighbor == NULL) return GM_OK; const DDD_PRIO prio = EPRIO(theNeighbor); /* identification is only needed if theNeighbor removed his refinement */ /* or was not refined before, thus has NSONS==0, if NSONS>0 the objects */ /* shared between the element sides are already identified and no new */ /* objects are created for this element side which need identification */ /* (980217 s.l.) */ /* if (!EHGHOSTPRIO(prio) || NSONS(theNeighbor)!=0) return(GM_OK); */ if (!EHGHOSTPRIO(prio) || !MARKED(theNeighbor)) return(GM_OK); #ifdef Debug identlevel = GLEVEL(theGrid); #endif if (IdentifyObjectsOfElementSide(theGrid,theElement,i,theNeighbor)) RETURN(GM_FATAL); return GM_OK; } /****************************************************************************/ /* IdentifyInit- SYNOPSIS: void IdentifyInit (MULTIGRID *theMG); PARAMETERS: . theMG DESCRIPTION: RETURN VALUE: void */ /****************************************************************************/ void NS_DIM_PREFIX IdentifyInit (MULTIGRID *theMG) { #ifdef Debug debug = 0; #endif /* allocate a control word entry to lock nodes */ if (AllocateControlEntry(NODE_CW,NEW_NIDENT_LEN,&ce_NEW_NIDENT) != GM_OK) assert(0); /* allocate a control word entry to lock edges */ if (AllocateControlEntry(EDGE_CW,NEW_EDIDENT_LEN,&ce_NEW_EDIDENT) != GM_OK) assert(0); for (INT i=0; i<=TOPLEVEL(theMG); i++) ResetIdentFlags(GRID_ON_LEVEL(theMG,i)); /* set Ident_FctPtr to identification mode */ Ident_FctPtr = Identify_by_ObjectList; } /****************************************************************************/ /* IdentifyExit - SYNOPSIS: void IdentifyExit (void); PARAMETERS: . void DESCRIPTION: RETURN VALUE: void */ /****************************************************************************/ void NS_DIM_PREFIX IdentifyExit (void) { FreeControlEntry(ce_NEW_NIDENT); FreeControlEntry(ce_NEW_EDIDENT); } #endif /* end ModelP */ dune-uggrid-2.11.0+dfsg/dune/uggrid/parallel/dddif/identify.h000066400000000000000000000145771513616443000240130ustar00rootroot00000000000000// -*- tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- // vi: set et ts=4 sw=2 sts=2: // SPDX-FileCopyrightInfo: Copyright © DUNE Project contributors, see file LICENSE.md in module root // SPDX-License-Identifier: LGPL-2.1-or-later /****************************************************************************/ /* */ /* File: identify.h */ /* */ /* Purpose: identification of distributed objects */ /* */ /* Author: Stefan Lang */ /* Institut fuer Computeranwendungen III */ /* Universitaet Stuttgart */ /* Pfaffenwaldring 27 */ /* 70550 Stuttgart */ /* email: ug@ica3.uni-stuttgart.de */ /* */ /* History: 26.11.96 begin */ /* */ /* Remarks: */ /* */ /****************************************************************************/ /****************************************************************************/ /* */ /* auto include mechanism and other include files */ /* */ /****************************************************************************/ #ifndef __IDENT_H__ #define __IDENT_H__ #include START_UGDIM_NAMESPACE /****************************************************************************/ /* */ /* defines in the following order */ /* */ /* compile time constants defining static data size (i.e. arrays) */ /* other constants */ /* macros */ /* */ /****************************************************************************/ /* define for identification in several stages to 1 */ /* only for debugging purposes useful! */ #define IDENT_IN_STEPS 0 /* settings for ident_mode */ #define IDENT_OFF 0 #define IDENT_ON 1 #define SET_IDENT_MODE(n) {ident_mode = (n);} #define GET_IDENT_MODE() (ident_mode) /****************************************************************************/ /* */ /* data structures exported by the corresponding source file */ /* */ /****************************************************************************/ /****************************************************************************/ /* */ /* definition of exported global variables */ /* */ /****************************************************************************/ extern INT ident_mode; /****************************************************************************/ /* */ /* function declarations */ /* */ /****************************************************************************/ INT Identify_SonObjects (GRID *theGrid); END_UGDIM_NAMESPACE #endif dune-uggrid-2.11.0+dfsg/dune/uggrid/parallel/dddif/initddd.cc000066400000000000000000001135711513616443000237470ustar00rootroot00000000000000// SPDX-FileCopyrightText: Copyright © DUNE Project contributors, see file LICENSE.md in module root // SPDX-License-Identifier: LGPL-2.1-or-later // -*- tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- // vi: set et ts=4 sw=2 sts=2: /****************************************************************************/ /* */ /* File: initddd.c */ /* */ /* Purpose: register ug structs for handling them by ddd */ /* */ /* Author: Stefan Lang, Klaus Birken */ /* Institut fuer Computeranwendungen III */ /* Universitaet Stuttgart */ /* Pfaffenwaldring 27 */ /* 70550 Stuttgart */ /* */ /* History: 09.05.95 begin, ugp version 3.0 */ /* */ /* Remarks: */ /* */ /****************************************************************************/ #ifdef ModelP /****************************************************************************/ /* */ /* include files */ /* system include files */ /* application include files */ /* */ /****************************************************************************/ #include #include #include #include "parallel.h" #include #include #include /* for GetFreeOBJT() */ #include #include /* UG namespaces: */ USING_UG_NAMESPACES /* PPIF namespace: */ using namespace PPIF; /****************************************************************************/ /* */ /* defines in the following order */ /* */ /* compile time constants defining static data size (i.e. arrays) */ /* other constants */ /* macros */ /* */ /****************************************************************************/ /* macro for easier definition of DDD_TYPEs */ #define ELDEF(type,member) offsetof(type,member), sizeof(type :: member) /* macro for easy definition of type mapping UG<->DDD */ #define MAP_TYPES(ugt,dddt) { int _ugt=(ugt); \ ddd_ctrl(context).ugtypes[(dddt)] = _ugt; \ ddd_ctrl(context).types[_ugt] = (dddt); \ } /****************************************************************************/ /* */ /* data structures used in this source file (exported data structures are */ /* in the corresponding include file!) */ /* */ /****************************************************************************/ /****************************************************************************/ /* */ /* definition of exported global variables */ /* */ /****************************************************************************/ /* DDD interfaces needed for distributed computation */ DDD_IF NS_DIM_PREFIX ElementIF, NS_DIM_PREFIX ElementSymmIF, NS_DIM_PREFIX ElementVIF, NS_DIM_PREFIX ElementSymmVIF, NS_DIM_PREFIX ElementVHIF, NS_DIM_PREFIX ElementSymmVHIF; DDD_IF NS_DIM_PREFIX BorderNodeIF, NS_DIM_PREFIX BorderNodeSymmIF, NS_DIM_PREFIX OuterNodeIF, NS_DIM_PREFIX NodeVIF, NS_DIM_PREFIX NodeIF, NS_DIM_PREFIX NodeAllIF; DDD_IF NS_DIM_PREFIX BorderVectorIF, NS_DIM_PREFIX BorderVectorSymmIF, NS_DIM_PREFIX OuterVectorIF, NS_DIM_PREFIX OuterVectorSymmIF, NS_DIM_PREFIX VectorVIF, NS_DIM_PREFIX VectorVAllIF, NS_DIM_PREFIX VectorIF; /* DDD interfaces for node communication */ DDD_IF NS_DIM_PREFIX Node_InteriorBorder_All_IF; /* DDD interfaces for facet (side vector) communication */ DDD_IF NS_DIM_PREFIX Facet_InteriorBorder_All_IF; /* DDD interfaces for edge communication */ DDD_IF NS_DIM_PREFIX EdgeIF, NS_DIM_PREFIX BorderEdgeSymmIF, NS_DIM_PREFIX EdgeHIF, NS_DIM_PREFIX EdgeVHIF, NS_DIM_PREFIX EdgeSymmVHIF; /****************************************************************************/ /* */ /* definition of variables global to this source file only (static!) */ /* */ /****************************************************************************/ /****************************************************************************/ /* */ /* forward declarations of functions used before they are defined */ /* */ /****************************************************************************/ enum ElemTypeFlag { Inside, Boundary }; /****************************************************************************/ /* void ddd_InitGenericElement - SYNOPSIS: static void ddd_InitGenericElement (INT tag, DDD_TYPE dddType, int etype); PARAMETERS: . tag . dddType . etype DESCRIPTION: RETURN VALUE: void */ /****************************************************************************/ static void ddd_InitGenericElement(DDD::DDDContext& context, INT tag, DDD_TYPE dddType, int etype) { auto& dddctrl = ddd_ctrl(context); GENERAL_ELEMENT *desc = element_descriptors[tag]; UINT gbits = 0; size_t ps = sizeof(void *); size_t r = offsetof(generic_element,refs); /* compute global fields of control word entry */ gbits = ~(((1<corners_of_elem, dddctrl.TypeNode, EL_OBJPTR, r+father_offset[tag]*sizeof(void*), ps, dddType, EL_LDATA, r+sons_offset[tag]*sizeof(void*), ps*2, EL_OBJPTR, r+nb_offset[tag]*sizeof(void*), ps*desc->sides_of_elem, dddType, EL_CONTINUE); /* optional components */ if (ddd_ctrl(context).elemData) DDD_TypeDefine(context, dddType, EL_OBJPTR, r+ 0 *sizeof(void*), ps*1, dddctrl.TypeVector, EL_CONTINUE); #ifdef UG_DIM_3 if (ddd_ctrl(context).sideData) DDD_TypeDefine(context, dddType, EL_OBJPTR, r+svector_offset[tag]*sizeof(void*), ps*desc->sides_of_elem, dddctrl.TypeVector, EL_CONTINUE); #endif if (etype==Inside) { DDD_TypeDefine(context, dddType, EL_END, static_cast(desc->inner_size)); /* init type mapping arrays */ MAP_TYPES(MAPPED_INNER_OBJT_TAG(tag), dddType); ddd_ctrl(context).dddObj[MAPPED_INNER_OBJT_TAG(tag)] = true; } else { DDD_TypeDefine(context, dddType, EL_LDATA, r+side_offset[tag]*sizeof(void*), ps*desc->sides_of_elem, EL_END, static_cast(desc->bnd_size)); /* init type mapping arrays */ MAP_TYPES(MAPPED_BND_OBJT_TAG(tag), dddType); ddd_ctrl(context).dddObj[MAPPED_BND_OBJT_TAG(tag)] = true; } /* set mergemode to maximum */ DDD_PrioMergeDefault(context, dddType, PRIOMERGE_MAXIMUM); /* TODO: set prios DDD_PrioMergeDefine(context, dddType, PrioHGhost, PrioVGhost, PrioVHGhost); DDD_PrioMergeDefine(context, dddType, PrioHGhost, PrioVHGhost, PrioVHGhost); DDD_PrioMergeDefine(context, dddType, PrioVGhost, PrioVHGhost, PrioVHGhost); DDD_PrioMergeDefine(context, dddType, PrioHGhost, PrioMaster, PrioMaster); DDD_PrioMergeDefine(context, dddType, PrioVGhost, PrioMaster, PrioMaster); DDD_PrioMergeDefine(context, dddType, PrioVHGhost, PrioMaster, PrioMaster); */ } /****************************************************************************/ /* */ /* Function: ddd_DeclareTypes */ /* */ /* Purpose: declare ug data structures as DDD_TYPES */ /* */ /* Input: void */ /* */ /* Output: void */ /* */ /* */ /****************************************************************************/ /****************************************************************************/ /* void ddd_DeclareTypes - declare ug data structures as DDD_TYPES SYNOPSIS: static void ddd_DeclareTypes (void); PARAMETERS: . void DESCRIPTION: This function declares ug data structures as DDD_TYPES RETURN VALUE: void */ /****************************************************************************/ static void ddd_DeclareTypes(DDD::DDDContext& context) { /* NOTE: (960410 KB) - handling of Vector and Matrix types may be wrong, types array entries might be used differently by ug (e.g., during allocation/deallocation). TODO ueberpruefen! (beziehung algebra.c <-> ugm.c) - UGTypes for elements will be computed later. therefore the initialization of types[] entries for elements is done (after the UGTypes are known) during ddd_InitGenericElement. TODO remove this clumsy exception! how? - variables TypeXXXX containing the proper DDD_TYPEs may be superfluous. It would be possible to replace all occurrences by macros like DDDType(VEOBJ), which would be implemented as #define DDDType(ugtype) (ddd_ctrl(context).types[ugtype]) TODO check this! pros: no double information. currently, TypeXXX may differ from corresponding ddd_ctrl(context).types[] entry. cons: will this be compatible with alloc/dealloc and TypeDefine of ug-general-elements? */ auto& dddctrl = ddd_ctrl(context); /* 1. DDD objects (with DDD_HEADER) */ dddctrl.TypeVector = DDD_TypeDeclare(context, "Vector"); MAP_TYPES(VEOBJ, dddctrl.TypeVector); dddctrl.dddObj[VEOBJ] = true; dddctrl.TypeIVertex = DDD_TypeDeclare(context, "IVertex"); MAP_TYPES(IVOBJ, dddctrl.TypeIVertex); dddctrl.dddObj[IVOBJ] = true; dddctrl.TypeBVertex = DDD_TypeDeclare(context, "BVertex"); MAP_TYPES(BVOBJ, dddctrl.TypeBVertex); dddctrl.dddObj[BVOBJ] = true; dddctrl.TypeNode = DDD_TypeDeclare(context, "Node"); MAP_TYPES(NDOBJ, dddctrl.TypeNode); dddctrl.dddObj[NDOBJ] = true; #ifdef UG_DIM_2 dddctrl.TypeTrElem = DDD_TypeDeclare(context, "TrElem"); dddctrl.TypeTrBElem = DDD_TypeDeclare(context, "TrBElem"); dddctrl.TypeQuElem = DDD_TypeDeclare(context, "QuElem"); dddctrl.TypeQuBElem = DDD_TypeDeclare(context, "QuBElem"); #endif /* TWODIM */ #ifdef UG_DIM_3 dddctrl.TypeTeElem = DDD_TypeDeclare(context, "TeElem"); dddctrl.TypeTeBElem = DDD_TypeDeclare(context, "TeBElem"); dddctrl.TypePyElem = DDD_TypeDeclare(context, "PyElem"); dddctrl.TypePyBElem = DDD_TypeDeclare(context, "PyBElem"); dddctrl.TypePrElem = DDD_TypeDeclare(context, "PrElem"); dddctrl.TypePrBElem = DDD_TypeDeclare(context, "PrBElem"); dddctrl.TypeHeElem = DDD_TypeDeclare(context, "HeElem"); dddctrl.TypeHeBElem = DDD_TypeDeclare(context, "HeBElem"); #endif /* THREEDIM */ /* edge type not unique: */ /* edge is DDD object for 2D and 3D */ /* edge is DDD data object for 2D */ dddctrl.TypeEdge = DDD_TypeDeclare(context, "Edge"); MAP_TYPES(EDOBJ, dddctrl.TypeEdge); dddctrl.dddObj[EDOBJ] = true; /* 2. DDD data objects (without DDD_HEADER) */ dddctrl.TypeBndP = DDD_TypeDeclare(context, "BndP"); static const INT objtBndP = GetFreeOBJT(); MAP_TYPES(objtBndP, dddctrl.TypeBndP); dddctrl.TypeBndS = DDD_TypeDeclare(context, "BndS"); static const INT objtBndS = GetFreeOBJT(); MAP_TYPES(objtBndS, dddctrl.TypeBndS); } /****************************************************************************/ /* ddd_DefineTypes - define previously declared DDD_TYPES SYNOPSIS: static void ddd_DefineTypes (void); PARAMETERS: . void DESCRIPTION: This function defines previously declared DDD_TYPES Note: this function depends on previous definition of all necessary ug-generic-elements. RETURN VALUE: void */ /****************************************************************************/ static void ddd_DefineTypes(DDD::DDDContext& context) { auto& dddctrl = ddd_ctrl(context); INT size; UINT gbits = 0; /* 1. DDD objects (with DDD_HEADER) */ /* * A side vector's `VECTORSIDE` depends on which of the `objects` is used * as a representative. To ensure consistency, both are handled in the same * place (`ElementObjMkCons`). */ gbits = ~(((1 << VECTORSIDE_LEN)-1) << VECTORSIDE_SHIFT); DDD_TypeDefine(context, dddctrl.TypeVector, EL_DDDHDR, offsetof(VECTOR,ddd), EL_GBITS, ELDEF(VECTOR,control), &gbits, /* object must be LDATA, because reftype may be a non-DDD-object */ /* (e.g., edge). therefore, 'object' must be updated by MKCONS- */ /* handler of associated object. 960404 KB */ /* TODO: decide whether LDATA or OBJPTR for different VectorTypes*/ /* EL_OBJPTR, ELDEF(VECTOR,object), TypeNode, */ EL_LDATA, ELDEF(VECTOR,object), EL_LDATA, ELDEF(VECTOR,pred), EL_LDATA, ELDEF(VECTOR,succ), EL_GDATA, ELDEF(VECTOR,index), EL_GDATA, ELDEF(VECTOR,leafIndex), /* TODO: value wird noch ausgelassen. Feld variabler Laenge? */ /* bei Entscheidung 'value': kein weiteres Feld bei ent. 'userdata *': EL_GDATA-feld */ EL_GDATA, ELDEF(VECTOR,value), EL_END, sizeof(VECTOR) ); /* set mergemode to maximum */ DDD_PrioMergeDefault(context, dddctrl.TypeVector, PRIOMERGE_MAXIMUM); /* compute global fields it control word entry */ gbits = ~((((1<HGhost/VHGhost"); A[0] = PrioMaster; A[1] = PrioHGhost; A[2] = PrioVHGhost; B[0] = PrioMaster; B[1] = PrioHGhost; B[2] = PrioVHGhost; dddctrl.ElementSymmIF = DDD_IFDefine(context, nO,O,3,A,3,B); DDD_IFSetName(context, dddctrl.ElementSymmIF, "ElementSymmIF: Master/HGhost/VHGhost"); A[0] = PrioMaster; B[0] = PrioVGhost; B[1] = PrioVHGhost; dddctrl.ElementVIF = DDD_IFDefine(context, nO,O,1,A,2,B); DDD_IFSetName(context, dddctrl.ElementVIF, "ElementVIF: Master->VGhost/VHGhost"); A[0] = PrioMaster; A[1] = PrioVGhost; A[2] = PrioVHGhost; B[0] = PrioMaster; B[1] = PrioVGhost; B[2] = PrioVHGhost; dddctrl.ElementSymmVIF = DDD_IFDefine(context, nO,O,3,A,3,B); DDD_IFSetName(context, dddctrl.ElementSymmVIF, "ElementSymmVIF: Master/VGhost/VHGhost"); A[0] = PrioMaster; B[0] = PrioVGhost; B[1] = PrioHGhost; B[2] = PrioVHGhost; dddctrl.ElementVHIF = DDD_IFDefine(context, nO,O,1,A,3,B); DDD_IFSetName(context, dddctrl.ElementVHIF, "ElementVHIF: Master->VGhost/HGhost/VHGhost"); A[0] = PrioMaster; A[1] = PrioVGhost; A[2] = PrioHGhost; A[3] = PrioVHGhost; B[0] = PrioMaster; B[1] = PrioVGhost; B[2] = PrioHGhost; B[3] = PrioVHGhost; dddctrl.ElementSymmVHIF = DDD_IFDefine(context, nO,O,4,A,4,B); DDD_IFSetName(context, dddctrl.ElementSymmVHIF, "ElementSymmVHIF: Master/VGhost/HGhost/VHGhost"); /* define node interfaces */ O[0] = dddctrl.TypeNode; A[0] = PrioBorder; B[0] = PrioMaster; dddctrl.BorderNodeIF = DDD_IFDefine(context, 1,O,1,A,1,B); DDD_IFSetName(context, dddctrl.BorderNodeIF, "BorderNodeIF: Border->Master"); A[0] = PrioMaster; A[1] = PrioBorder; B[0] = PrioMaster; B[1] = PrioBorder; dddctrl.BorderNodeSymmIF = DDD_IFDefine(context, 1,O,2,A,2,B); DDD_IFSetName(context, dddctrl.BorderNodeSymmIF, "BorderNodeSymmIF: Border/Master"); A[0] = PrioMaster; B[0] = PrioHGhost; B[1] = PrioVHGhost; dddctrl.OuterNodeIF = DDD_IFDefine(context, 1,O,1,A,2,B); DDD_IFSetName(context, dddctrl.OuterNodeIF, "OuterNodeIF: Master->HGhost/VGhost"); A[0] = PrioMaster; B[0] = PrioVGhost; B[1] = PrioVHGhost; dddctrl.NodeVIF = DDD_IFDefine(context, 1,O,1,A,2,B); DDD_IFSetName(context, dddctrl.NodeVIF, "NodeVIF: Master->VGhost/VHGhost"); A[0] = PrioMaster; B[0] = PrioVGhost; B[1] = PrioHGhost; B[2] = PrioVHGhost; dddctrl.NodeIF = DDD_IFDefine(context, 1,O,1,A,3,B); DDD_IFSetName(context, dddctrl.NodeIF, "NodeIF: Master->VGhost/HGhost/VHGhost"); A[0] = PrioMaster; A[1] = PrioBorder; A[2] = PrioVGhost; A[3] = PrioHGhost; A[4] = PrioVHGhost; B[0] = PrioMaster; B[1] = PrioBorder; B[2] = PrioVGhost; B[3] = PrioHGhost; B[4] = PrioVHGhost; dddctrl.NodeAllIF = DDD_IFDefine(context, 1,O,5,A,5,B); DDD_IFSetName(context, dddctrl.NodeAllIF, "NodeAllIF: All/All"); // The Dune InteriorBorder_All_Interface for nodes A[0] = PrioMaster; A[1] = PrioBorder; B[0] = PrioMaster; B[1] = PrioBorder; B[2] = PrioVGhost; B[3] = PrioHGhost; B[4] = PrioVHGhost; dddctrl.Node_InteriorBorder_All_IF = DDD_IFDefine(context, 1,O,2,A,5,B); DDD_IFSetName(context, dddctrl.Node_InteriorBorder_All_IF, "Node_InteriorBorder_All_IF: Master/Border->Master/Border/VGhost/HGhost/VHGhost"); /* define vector interfaces */ O[0] = dddctrl.TypeVector; A[0] = PrioBorder; B[0] = PrioMaster; dddctrl.BorderVectorIF = DDD_IFDefine(context, 1,O,1,A,1,B); DDD_IFSetName(context, dddctrl.BorderVectorIF, "BorderVectorIF: Border->Master"); A[0] = PrioMaster; A[1] = PrioBorder; B[0] = PrioMaster; B[1] = PrioBorder; dddctrl.BorderVectorSymmIF = DDD_IFDefine(context, 1,O,2,A,2,B); DDD_IFSetName(context, dddctrl.BorderVectorSymmIF, "BorderVectorSymmIF: Master/Border"); A[0] = PrioMaster; B[0] = PrioHGhost; B[1] = PrioVHGhost; dddctrl.OuterVectorIF = DDD_IFDefine(context, 1,O,1,A,2,B); DDD_IFSetName(context, dddctrl.OuterVectorIF, "OuterVectorIF: Master->HGhost/VHGhost"); A[0] = PrioMaster; A[1] = PrioBorder; A[2] = PrioHGhost; A[3] = PrioVHGhost; B[0] = PrioMaster; B[1] = PrioBorder; B[2] = PrioHGhost; B[3] = PrioVHGhost; dddctrl.OuterVectorSymmIF = DDD_IFDefine(context, 1,O,4,A,4,B); DDD_IFSetName(context, dddctrl.OuterVectorSymmIF, "OuterVectorSymmIF: Master/Border/HGhost/VHGhost"); A[0] = PrioMaster; B[0] = PrioVGhost; B[1] = PrioVHGhost; dddctrl.VectorVIF = DDD_IFDefine(context, 1,O,1,A,2,B); DDD_IFSetName(context, dddctrl.VectorVIF, "VectorVIF: Master->VGhost/VHGhost"); A[0] = PrioMaster; A[1] = PrioBorder; A[2] = PrioVGhost; A[3] = PrioVHGhost; B[0] = PrioMaster; B[1] = PrioBorder; dddctrl.VectorVAllIF = DDD_IFDefine(context, 1,O,4,A,2,B); DDD_IFSetName(context, dddctrl.VectorVAllIF, "VectorVAllIF: Master/Border/VGhost/VHGhost->Master/Border"); A[0] = PrioMaster; B[0] = PrioVGhost; B[1] = PrioVHGhost; B[2] = PrioHGhost; dddctrl.VectorIF = DDD_IFDefine(context, 1,O,1,A,3,B); DDD_IFSetName(context, dddctrl.VectorIF, "VectorIF: Master->VGhost/VHGhost/HGhost"); // The Dune InteriorBorder_All_Interface for facets A[0] = PrioMaster; A[1] = PrioBorder; B[0] = PrioMaster; B[1] = PrioBorder; B[2] = PrioVGhost; B[3] = PrioHGhost; B[4] = PrioVHGhost; dddctrl.Facet_InteriorBorder_All_IF = DDD_IFDefine(context, 1,O,2,A,5,B); DDD_IFSetName(context, dddctrl.Facet_InteriorBorder_All_IF, "Facet_InteriorBorder_All_IF: Master/Border->Master/Border/VGhost/HGhost/VHGhost"); // The Dune All_All_Interface for facets A[0] = PrioMaster; A[1] = PrioBorder; A[2] = PrioVGhost; A[3] = PrioHGhost; A[4] = PrioVHGhost; B[0] = PrioMaster; B[1] = PrioBorder; B[2] = PrioVGhost; B[3] = PrioHGhost; B[4] = PrioVHGhost; dddctrl.Facet_All_All_IF = DDD_IFDefine(context, 1,O,5,A,5,B); DDD_IFSetName(context, dddctrl.Facet_All_All_IF, "Facet_All_All_IF: Master/Border/VGhost/HGhost/VHGhost->Master/Border/VGhost/HGhost/VHGhost"); /* define vertex interfaces */ O[0] = dddctrl.TypeIVertex; O[1] = dddctrl.TypeBVertex; A[0] = PrioMaster; B[0] = PrioMaster; dddctrl.VertexIF = DDD_IFDefine(context, 2,O,1,A,1,B); DDD_IFSetName(context, dddctrl.VertexIF, "VertexIF: Master<->Master"); /* define edge interfaces */ O[0] = dddctrl.TypeEdge; A[0] = PrioMaster; B[0] = PrioMaster; dddctrl.EdgeIF = DDD_IFDefine(context, 1,O,1,A,1,B); DDD_IFSetName(context, dddctrl.EdgeIF, "EdgeIF: Master<->Master"); A[0] = PrioMaster; A[1] = PrioBorder; B[0] = PrioMaster; B[1] = PrioBorder; dddctrl.BorderEdgeSymmIF = DDD_IFDefine(context, 1,O,2,A,2,B); DDD_IFSetName(context, dddctrl.BorderEdgeSymmIF, "BorderEdgeSymmIF: Master/Border"); A[0] = PrioMaster; A[1] = PrioBorder; B[0] = PrioMaster; B[1] = PrioBorder; B[2] = PrioHGhost; B[3] = PrioVHGhost; dddctrl.EdgeHIF = DDD_IFDefine(context, 1,O,2,A,4,B); DDD_IFSetName(context, dddctrl.EdgeHIF, "EdgeHIF: Master/Border->Master/Border/PrioHGhost/PrioVHGhost"); A[0] = PrioMaster; A[1] = PrioBorder; B[0] = PrioMaster; B[1] = PrioBorder; B[2] = PrioVGhost; B[3] = PrioHGhost; B[4] = PrioVHGhost; dddctrl.EdgeVHIF = DDD_IFDefine(context, 1,O,2,A,5,B); DDD_IFSetName(context, dddctrl.EdgeVHIF, "EdgeVHIF: Master/Border->Master/Border/VGhost/HGhost/VHGhost"); A[0] = PrioMaster; A[1] = PrioBorder; A[2] = PrioVGhost; A[3] = PrioHGhost; A[4] = PrioVHGhost; B[0] = PrioMaster; B[1] = PrioBorder; B[2] = PrioVGhost; B[3] = PrioHGhost; B[4] = PrioVHGhost; dddctrl.EdgeSymmVHIF = DDD_IFDefine(context, 1,O,5,A,5,B); DDD_IFSetName(context, dddctrl.EdgeSymmVHIF, "EdgeSymmVHIF: Master/Border/VGhost/HGhost/VHGhost"); } /****************************************************************************/ /* InitDDDTypes - define DDD_TYPEs SYNOPSIS: static void InitDDDTypes (DDD::DDDContext& context); PARAMETERS: . context DESCRIPTION: This function must be called once before creation of DDD-objects. It depends on correct and complete initialization of all ug-generic-elements, therefore it must be called after completion of InitElementTypes(). As InitElementTypes() will be called whenever new Multigrids are created/opened, an execution guard prevents this function from multiple execution. RETURN VALUE: void */ /****************************************************************************/ static void InitDDDTypes(DDD::DDDContext& context) { auto& dddctrl = ddd_ctrl(context); /* prevent from multiple execution */ if (dddctrl.allTypesDefined) return; dddctrl.allTypesDefined = true; ddd_DefineTypes(context); /* display ddd types */ IFDEBUG(dddif,1) DDD_TypeDisplay(context, dddctrl.TypeVector); DDD_TypeDisplay(context, dddctrl.TypeIVertex); DDD_TypeDisplay(context, dddctrl.TypeBVertex); DDD_TypeDisplay(context, dddctrl.TypeNode); DDD_TypeDisplay(context, dddctrl.TypeEdge); #ifdef UG_DIM_2 DDD_TypeDisplay(context, dddctrl.TypeTrElem); DDD_TypeDisplay(context, dddctrl.TypeTrBElem); DDD_TypeDisplay(context, dddctrl.TypeQuElem); DDD_TypeDisplay(context, dddctrl.TypeQuBElem); #endif #ifdef UG_DIM_3 DDD_TypeDisplay(context, dddctrl.TypeTeElem); DDD_TypeDisplay(context, dddctrl.TypeTeBElem); DDD_TypeDisplay(context, dddctrl.TypePyElem); DDD_TypeDisplay(context, dddctrl.TypePyBElem); DDD_TypeDisplay(context, dddctrl.TypePrElem); DDD_TypeDisplay(context, dddctrl.TypePrBElem); DDD_TypeDisplay(context, dddctrl.TypeHeElem); DDD_TypeDisplay(context, dddctrl.TypeHeBElem); #endif /* display dependent types */ #ifdef UG_DIM_2 DDD_TypeDisplay(context, dddctrl.TypeEdge); #endif ENDDEBUG ddd_HandlerInit(context, HSET_XFER); } /****************************************************************************/ /* InitCurrMG - initialize the current multigrid which is handled by DDD SYNOPSIS: void InitCurrMG (MULTIGRID *MG); PARAMETERS: . MG DESCRIPTION: This function initializes the current multigrid which is handled by DDD RETURN VALUE: void */ /****************************************************************************/ void NS_DIM_PREFIX InitCurrMG (MULTIGRID *MG) { auto& dddctrl = ddd_ctrl(MG->dddContext()); dddctrl.currMG = MG; dddctrl.nodeData = 0; dddctrl.edgeData = 0; dddctrl.elemData = 0; dddctrl.sideData = VEC_DEF_IN_OBJ_OF_MG(dddctrl.currMG,SIDEVEC); InitDDDTypes(MG->dddContext()); } /****************************************************************************/ /* CheckInitParallel - check for correct initialization of dddif subsystem SYNOPSIS: static int CheckInitParallel (void); PARAMETERS: . void DESCRIPTION: This function performs checks for correct initialization of dddif subsystem RETURN VALUE: int error value */ /****************************************************************************/ static int CheckInitParallel(const DDD::DDDContext& context) { int i; /* check for valid UGTYPE for given DDD_TYPE */ if (OBJT_MAX == MAXOBJECTS) { printf("ERROR in InitParallel: OBJT_MAX!=MAXOBJECTS\n"); return(__LINE__); } for(i=1; i=0; i++) { /* check for valid UGTYPE for given DDD_TYPE */ if (UGTYPE(context, i) > OBJT_MAX) { printf("ERROR in InitParallel: OBJT=%d > OBJT_MAX=%d\n", UGTYPE(context, i), OBJT_MAX); return(__LINE__); } /* check for correct mapping and re-mapping */ if (DDDTYPE(context, UGTYPE(context, i))!=i) { printf("ERROR in InitParallel: invalid type mapping for OBJT=%d\n", UGTYPE(context, i)); return(__LINE__); } } /* no errors */ return(0); } /****************************************************************************/ /* InitDDD - initialize the ddd library SYNOPSIS: int InitDDD (int *argc, char ***argv); PARAMETERS: . argc - pointer to number of arguments . argv - pointer to list of argument pointers DESCRIPTION: This function initializes the ddd library by defining the ug internal issues: format of handled structs, description of handlers, definition of interfaces RETURN VALUE: int */ /****************************************************************************/ int NS_DIM_PREFIX InitDDD(DDD::DDDContext& context) { auto& dddctrl = ddd_ctrl(context); INT err; int i; /* init DDD and set options */ DDD_Init(context); /* we are using varsized DDD objects, turn warnings off */ DDD_SetOption(context, OPT_WARNING_VARSIZE_OBJ, OPT_OFF); DDD_SetOption(context, OPT_WARNING_SMALLSIZE, OPT_OFF); /* no internal free list */ DDD_SetOption(context, OPT_CPLMGR_USE_FREELIST, OPT_OFF); /* show messages during transfer, for debugging */ DDD_SetOption(context, OPT_DEBUG_XFERMESGS, OPT_OFF); /* TODO: remove this, reference collision with Edge orientation in 3D */ DDD_SetOption(context, OPT_WARNING_REF_COLLISION, OPT_OFF); /* treat identify tokens for one object as set */ DDD_SetOption(context, OPT_IDENTIFY_MODE, IDMODE_SETS); /* dont delete objects when another copy comes in during Xfer */ DDD_SetOption(context, OPT_XFER_PRUNE_DELETE, OPT_ON); /* initialize type mapping arrays */ for(i=0; i #include #include "parallel.h" #include #include #include #include /* UG namespaces: */ USING_UG_NAMESPACES /* PPIF namespaces: */ using namespace PPIF; START_UGDIM_NAMESPACE /****************************************************************************/ /* */ /* defines in the following order */ /* */ /* compile time constants defining static data size (i.e. arrays) */ /* other constants */ /* macros */ /* */ /****************************************************************************/ /****************************************************************************/ /* */ /* data structures used in this source file (exported data structures are */ /* in the corresponding include file!) */ /* */ /****************************************************************************/ /****************************************************************************/ /* */ /* definition of exported global variables */ /* */ /****************************************************************************/ /****************************************************************************/ /* */ /* forward declarations of functions used before they are defined */ /* */ /****************************************************************************/ /****************************************************************************/ /* TransferGridComplete- SYNOPSIS: static int TransferGridComplete (MULTIGRID *theMG, INT level); PARAMETERS: . theMG . level DESCRIPTION: RETURN VALUE: int */ /****************************************************************************/ static int TransferGridComplete (MULTIGRID *theMG, INT level) { ELEMENT *e; GRID *theGrid = GRID_ON_LEVEL(theMG,level); if (theGrid==NULL) { const auto& me = theMG->dddContext().me(); UserWriteF(PFMT "TransferGridComplete(): no grid on level=%d\n",me,level); return(0); } /* assign elements of level 0 */ if (theMG->dddContext().isMaster()) { for (e=FIRSTELEMENT(theGrid); e!=NULL; e=SUCCE(e)) PARTITION(e) = 1; } IFDEBUG(dddif,1); for (e=FIRSTELEMENT(theGrid); e!=NULL; e=SUCCE(e)) { UserWriteF("elem %08x has dest=%d\n", DDD_InfoGlobalId(PARHDRE(e)), PARTITION(e)); } ENDDEBUG return(0); } /****************************************************************************/ /* TransferGridToMaster - SYNOPSIS: static int TransferGridToMaster (MULTIGRID *theMG, INT fl, INT tl); PARAMETERS: . theMG . fl . tl DESCRIPTION: RETURN VALUE: int */ /****************************************************************************/ static int TransferGridToMaster (MULTIGRID *theMG, INT fl, INT tl) { /* send all levels to master */ if (not theMG->dddContext().isMaster()) { for (int l = fl; l <= tl; l++) { const GRID *theGrid = GRID_ON_LEVEL(theMG,l); /* create element copies */ for (ELEMENT *e = FIRSTELEMENT(theGrid); e != NULL; e = SUCCE(e)) { PARTITION(e) = 0; } } } return(0); } /****************************************************************************/ /* CollectElementsNearSegment - SYNOPSIS: static int CollectElementsNearSegment(MULTIGRID *theMG, int level, int dest); PARAMETERS: . theMG . level . part . dest DESCRIPTION: RETURN VALUE: int */ /****************************************************************************/ static int CollectElementsNearSegment(MULTIGRID *theMG, int fl, int tl, int dest) { ELEMENT *theElement; INT side,sid,nbsid,level; for (level=fl; level<=tl; level ++) for (theElement=FIRSTELEMENT(GRID_ON_LEVEL(theMG,level)); theElement!=NULL; theElement=SUCCE(theElement)) if (OBJT(theElement) == BEOBJ) for (side=0; side& coord = CVECT(MYVERTEX(CORNER(theElement,i))); xmax = std::max(xmax,coord[0]); ymax = std::max(ymax,coord[1]); } ASSERT(xmax>0.0 && xmax<1.00001); /* this function works only for the unit square! */ ASSERT(ymax>0.0 && ymax<1.00001); /*printf( PFMT "element coord %g %g %d %d\n", me, xmax, ymax, hor_boxes, vert_boxes );*/ /* the according subdomain is determined by the upper right corner the idea: for each dimension: calculate from the element coord the position in the corresponding array dimension then map the array coordinates onto a PE number */ PARTITION(theElement) = (int)((ymax-0.00001)*vert_boxes) * hor_boxes + (int)((xmax-0.00001)*hor_boxes); /*printf( PFMT "element partition %d\n", me, PARTITION(theElement) );*/ } return(0); } static void CreateDD(MULTIGRID *theMG, INT level, int hor_boxes, int vert_boxes ) /* the final call to TransferGridFromLevel() must be done by the current caller */ { INT elements; GRID *theGrid; theGrid = GRID_ON_LEVEL(theMG,level); if( hor_boxes*vert_boxes >= 4 ) { elements = NT(theGrid); elements = UG_GlobalMaxINT(theMG->ppifContext(), elements); if( elements > 20000 ) { /* we have a case with too heavy load for DDD; thus subdivide */ /* find a coarser auxiliary partition */ int hor = hor_boxes; int vert = vert_boxes; if( hor%2 == 0 ) hor /= 2; /* hor_boxes can be halfened */ else if( vert%2 == 0 ) vert /= 2; /* vert_boxes can be halfened */ else assert(0); /* further consideration for subdividing necessary */ CreateDD(theMG, level, hor, vert ); /* simplify the problem */ TransferGridFromLevel(theMG,level); } } PartitionElementsForDD(theGrid, hor_boxes, vert_boxes ); } static int SimpleSubdomainDistribution (MULTIGRID *theMG, INT Procs, INT from, INT to) { INT i; ELEMENT *e; for (i=from; i<=to; i++) for (e=FIRSTELEMENT(GRID_ON_LEVEL(theMG,i)); e!=NULL; e=SUCCE(e)) PARTITION(e)=SUBDOMAIN(e)-1; return(0); } /****************************************************************************/ /* lbs - interface for simple or special load balancing functionality SYNOPSIS: void lbs (char *argv, MULTIGRID *theMG); PARAMETERS: . argv . theMG DESCRIPTION: RETURN VALUE: void */ /****************************************************************************/ void lbs (const char *argv, MULTIGRID *theMG) { int n,mode,param,fromlevel,tolevel,hor_boxes,vert_boxes,dest; const auto& me = theMG->dddContext().me(); const auto procs = theMG->dddContext().procs(); mode = param = fromlevel = tolevel = 0; n = sscanf(argv,"%d %d %d",¶m,&fromlevel,&tolevel); UserWriteF(PFMT "lbs() param=%d",me,param); if (n > 1) UserWriteF(" fromlevel=%d",fromlevel); if (n > 2) UserWriteF(" tolevel=%d",tolevel); UserWriteF("\n"); /* param>100 is used as switch for DDD xfer statistics */ if (param>=100) mode = param-100; else mode = param; /* switch DDD infos on */ if (param>=100) DDD_SetOption(theMG->dddContext(), OPT_INFO_XFER, XFER_SHOW_MEMUSAGE); switch (mode) { /* dies balanciert ein GRID mit RCB */ case (0) : BalanceGridRCB(theMG,0); fromlevel = 0; break; /* dies verschickt ein GRID komplett */ case (1) : TransferGridComplete(theMG,fromlevel); break; /* dies verschickt ein verteiltes GRID zum master */ case (2) : TransferGridToMaster(theMG,fromlevel,tolevel); fromlevel = 0; break; /* dies balanciert ein GRID mit RCB ab fromlevel */ case (3) : if (fromlevel>=0 && fromlevel<=TOPLEVEL(theMG)) { BalanceGridRCB(theMG,fromlevel); } else { UserWriteF(PFMT "lbs(): gridlevel=%d not " "existent!\n",me,fromlevel); } break; /* dies balanciert ein GRID mit RCB ab fromlevel */ case (4) : if ((fromlevel>=0 && fromlevel<=TOPLEVEL(theMG)) || (tolevel>=0 && tolevel<=TOPLEVEL(theMG)) || tolevel < fromlevel) { int j; for (j=fromlevel; j<=tolevel; j++) BalanceGridRCB(theMG,j); /* TransferGrid(theMG,fromlevel,tolevel); */ } else { UserWriteF(PFMT "lbs(): ERROR fromlevel=%d " "tolevel=%d\n",me,fromlevel,tolevel); } break; case (5) : n = sscanf(argv,"%d %d %d %d", ¶m,&dest,&fromlevel,&tolevel); if (n < 4) tolevel = TOPLEVEL(theMG); if (n < 3) fromlevel = 0; if (n < 2) break; CollectElementsNearSegment(theMG,fromlevel,tolevel,dest); UserWriteF(PFMT "lbs() collect to proc %d\n", me,dest); break; /* dies erzeugt eine regelmaessige Domain Decomposition */ case (6) : if (sscanf(argv,"%d %d %d",¶m,&hor_boxes,&vert_boxes) != 3) break; ASSERT(hor_boxes*vert_boxes == procs ); fromlevel = TOPLEVEL(theMG); CreateDD(theMG,fromlevel,hor_boxes,vert_boxes); break; case (8) : { SimpleSubdomainDistribution(theMG,procs,fromlevel,tolevel); break; } default : UserWriteF(PFMT "lbs(): strategy (%d) is not implemented!\n", mode); break; } TransferGridFromLevel(theMG,fromlevel); /* switch DDD infos off */ if (param>=100) DDD_SetOption(theMG->dddContext(), OPT_INFO_XFER, XFER_SHOW_NONE); } END_UGDIM_NAMESPACE #endif /* ModelP */ dune-uggrid-2.11.0+dfsg/dune/uggrid/parallel/dddif/lbrcb.cc000066400000000000000000000177001513616443000234110ustar00rootroot00000000000000// SPDX-FileCopyrightText: Copyright © DUNE Project contributors, see file LICENSE.md in module root // SPDX-License-Identifier: LGPL-2.1-or-later // -*- tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- // vi: set et ts=4 sw=2 sts=2: /****************************************************************************/ /* File: lbrcb.c */ /* Purpose: simple static load balancing scheme for testing initial */ /* grid distribution */ /****************************************************************************/ #ifdef ModelP #include #include #include #include #include #include #include #include #include "parallel.h" #include #include #include #include USING_UG_NAMESPACES using namespace PPIF; START_UGDIM_NAMESPACE // only used in this source file struct LB_INFO { ELEMENT *elem; Dune::FieldVector center; }; /** * Bisects a 2D processor array along the longest axis * * std::array specifies a part of a 2D processor array * with the entries (x, y, dx, dy), where * (x, y): bottom left position in 2D processor array * (dx, dy): size of the 2D processor array */ static std::array, 2> BisectProcessorArray (const std::array& procs) { const int dx = procs[2]; const int dy = procs[3]; if (dx >= dy) { const int part0Size = dx/2; const int part1Size = dx-part0Size; return {{{ procs[0], procs[1], part0Size, dy }, { procs[0]+part0Size, procs[1], part1Size, dy }}}; } else { const int part0Size = dy/2; const int part1Size = dy-part0Size; return {{{ procs[0], procs[1], dx, part0Size }, { procs[0], procs[1]+part0Size, dx, part1Size }}}; } } /** * Compute the number of processor in a processor grid */ static int NumProcessorsInPart (const std::array& procs) { return procs[2]*procs[3]; } /** * Compute the ratio of a processor splitting done by BisectProcessorArray * returns real number between 0 and 1 */ static DOUBLE ComputeProcessorSplitRatio (const std::array, 2>& parts) { const int numProcsPart0 = NumProcessorsInPart(parts[0]); const int numProcsPart1 = NumProcessorsInPart(parts[1]); return static_cast(numProcsPart0) / static_cast(numProcsPart0 + numProcsPart1); } /****************************************************************************/ /* RecursiveCoordinateBisection - balance all local triangles PARAMETERS: . begin - iterator to LB_INFO vector . end - iterator to LB_INFO vector . procs - (px, py, dx, dy) processor grid, where (px, py): bottom left position in 2D processor array (dx, dy): size of the 2D processor array . bisectionAxis - axis along which we sort: 0=x, 1=y, 2=z DESCRIPTION: This function, a simple load balancing algorithm, balances all local triangles using a 'recursive coordinate bisection' scheme, RETURN VALUE: void */ /****************************************************************************/ static void RecursiveCoordinateBisection (const PPIF::PPIFContext& ppifContext, const std::vector::iterator& begin, const std::vector::iterator& end, const std::array procs, int bisectionAxis = 0) { // empty element range for these processors: nothing to do if (begin == end) return; // we found a single destination rank for this element subrange: end recursion if (NumProcessorsInPart(procs) <= 1) { for (auto it = begin; it != end; ++it) { const int destinationRank = procs[1]*ppifContext.dimX()+procs[0]; PARTITION(it->elem) = destinationRank; } return; } // bisect processors and bisect element accordingly const auto procPartitions = BisectProcessorArray(procs); const auto splitRatio = ComputeProcessorSplitRatio(procPartitions); const auto numElements = std::distance(begin, end); const auto middle = begin + static_cast(numElements*splitRatio); // partial sort such that middle iterator points to the bisection element std::nth_element(begin, middle, end, [bisectionAxis](const auto& a, const auto& b) { auto eps = (b.center-a.center); eps *= 1e-7; for (int dimIdx = 0; dimIdx < DIM; ++dimIdx) { const int i = (dimIdx+bisectionAxis)%DIM; if (a.center[i] < b.center[i] - eps[i]) return true; if (a.center[i] > b.center[i] + eps[i]) return false; } return false; } ); // we simply alternate between the axis hoping for a decent partition // this could be probably improved by sorting along the longest axis but // computing the longest axis is expensive if we have to compute the grids bounding box every time const int nextBisectionAxis = (bisectionAxis+1)%DIM; RecursiveCoordinateBisection(ppifContext, begin, middle, procPartitions[0], nextBisectionAxis); RecursiveCoordinateBisection(ppifContext, middle, end, procPartitions[1], nextBisectionAxis); } /** * Compute an element's center of mass */ static Dune::FieldVector CenterOfMass (ELEMENT *e) { Dune::FieldVector center(0.0); const auto corners = CORNERS_OF_ELEM(e); for(int i=0; idddContext(); const PPIF::PPIFContext& ppifContext = theMG->ppifContext(); /* distributed grids cannot be redistributed by this function */ if (not context.isMaster() && FIRSTELEMENT(theGrid) != NULL) DUNE_THROW(Dune::NotImplemented, "Redistributing distributed grids using recursive coordinate bisection is not implemented!"); if (context.isMaster()) { if (NT(theGrid) == 0) { UserWriteF("WARNING in BalanceGridRCB: no elements in grid\n"); return; } std::vector lbinfo(NT(theGrid)); int i = 0; for (auto e=FIRSTELEMENT(theGrid); e!=NULL; e=SUCCE(e)) { lbinfo[i].elem = e; lbinfo[i].center = CenterOfMass(e); ++i; } RecursiveCoordinateBisection(ppifContext, lbinfo.begin(), lbinfo.end(), {0, 0, ppifContext.dimX(), ppifContext.dimY()}); IFDEBUG(dddif,1) for (auto e=FIRSTELEMENT(theGrid); e!=NULL; e=SUCCE(e)) UserWriteF("elem %08x has dest=%d\n", DDD_InfoGlobalId(PARHDRE(e)), PARTITION(e)); ENDDEBUG for (auto e=FIRSTELEMENT(theGrid); e!=NULL; e=SUCCE(e)) InheritPartition (e); } } END_UGDIM_NAMESPACE #endif /* ModelP */ dune-uggrid-2.11.0+dfsg/dune/uggrid/parallel/dddif/memmgr.cc000066400000000000000000000147001513616443000236060ustar00rootroot00000000000000// SPDX-FileCopyrightText: Copyright © DUNE Project contributors, see file LICENSE.md in module root // SPDX-License-Identifier: LGPL-2.1-or-later // -*- tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- // vi: set et ts=4 sw=2 sts=2: /****************************************************************************/ /* */ /* File: memmgr.c */ /* */ /* Purpose: memory management module */ /* */ /* Author: Klaus Birken */ /* Rechenzentrum Uni Stuttgart */ /* Universitaet Stuttgart */ /* Allmandring 30 */ /* 70550 Stuttgart */ /* internet: birken@rus.uni-stuttgart.de */ /* */ /* History: 94/04/27 kb begin */ /* */ /* Remarks: */ /* */ /****************************************************************************/ #ifdef ModelP /****************************************************************************/ /* */ /* include files */ /* system include files */ /* application include files */ /* */ /****************************************************************************/ /* standard C library */ #include #include #include #include #include #include #include #include #include "parallel.h" #include #include /* UG namespaces */ USING_UG_NAMESPACES /* PPIF namespace */ using namespace PPIF; START_UGDIM_NAMESPACE #define HARD_EXIT abort() /*#define HARD_EXIT exit(1)*/ /****************************************************************************/ /* */ /* routines */ /* */ /****************************************************************************/ /****************************************************************************/ /* memmgr_AllocOMEM - SYNOPSIS: void *memmgr_AllocOMEM (size_t size, int ddd_type, int prio, int attr); PARAMETERS: . size . ddd_type . prio . attr DESCRIPTION: RETURN VALUE: void */ /****************************************************************************/ void * memmgr_AllocOMEM (size_t size, int ddd_type, int prio, int attr) { void* p = std::malloc(size); std::memset(p, 0, size); return p; } /****************************************************************************/ /* memmgr_FreeOMEM - SYNOPSIS: void memmgr_FreeOMEM (void *buffer, size_t size, int ddd_type); PARAMETERS: . buffer . size . ddd_type DESCRIPTION: RETURN VALUE: void */ /****************************************************************************/ void memmgr_FreeOMEM (void *buffer, size_t size, int ddd_type) { std::free(buffer); } /****************************************************************************/ /* memmgr_AllocPMEM - SYNOPSIS: void *memmgr_AllocPMEM (unsigned long size); PARAMETERS: . size DESCRIPTION: RETURN VALUE: void */ /****************************************************************************/ void * memmgr_AllocPMEM (unsigned long size) { return std::malloc(size); } /****************************************************************************/ /* memmgr_FreePMEM - SYNOPSIS: void memmgr_FreePMEM (void *buffer); PARAMETERS: . buffer DESCRIPTION: RETURN VALUE: void */ /****************************************************************************/ void memmgr_FreePMEM (void *buffer) { std::free(buffer); } /****************************************************************************/ /* memmgr_AllocAMEM - SYNOPSIS: void *memmgr_AllocAMEM (unsigned long size); PARAMETERS: . size DESCRIPTION: RETURN VALUE: void */ /****************************************************************************/ void * memmgr_AllocAMEM (unsigned long size) { return std::malloc(size); } /****************************************************************************/ /* memmgr_FreeAMEM - SYNOPSIS: void memmgr_FreeAMEM (void *buffer); PARAMETERS: . buffer DESCRIPTION: RETURN VALUE: void */ /****************************************************************************/ void memmgr_FreeAMEM (void *buffer) { std::free(buffer); } /****************************************************************************/ /* memmgr_AllocTMEM - SYNOPSIS: void *memmgr_AllocTMEM (unsigned long size); PARAMETERS: . size DESCRIPTION: RETURN VALUE: void */ /****************************************************************************/ void * memmgr_AllocTMEM (unsigned long size, int kind) { void* p = std::malloc(size); std::memset(p, 0, size); return p; } /****************************************************************************/ /* memmgr_FreeTMEM - SYNOPSIS: void memmgr_FreeTMEM (void *buffer); PARAMETERS: . buffer DESCRIPTION: RETURN VALUE: void */ /****************************************************************************/ void memmgr_FreeTMEM (void *buffer, int kind) { std::free(buffer); } END_UGDIM_NAMESPACE #endif /* ModelP */ dune-uggrid-2.11.0+dfsg/dune/uggrid/parallel/dddif/overlap.cc000066400000000000000000000575531513616443000240070ustar00rootroot00000000000000// SPDX-FileCopyrightText: Copyright © DUNE Project contributors, see file LICENSE.md in module root // SPDX-License-Identifier: LGPL-2.1-or-later // -*- tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- // vi: set et ts=4 sw=2 sts=2: /****************************************************************************/ /* */ /* File: overlap.c */ /* */ /* Purpose: management of grid overlap during adaption */ /* */ /* Author: Stefan Lang */ /* Institut fuer Computeranwendungen III */ /* Universitaet Stuttgart */ /* Pfaffenwaldring 27 */ /* 70569 Stuttgart */ /* */ /* History: 970204 sl begin */ /* */ /****************************************************************************/ #ifdef ModelP /****************************************************************************/ /* */ /* include files */ /* system include files */ /* application include files */ /* */ /****************************************************************************/ /* standard C library */ #include #include #include #include #include #include /* low module */ #include #include #include #include #include /* dev module */ #include /* gm module */ #include #include #include #include #include #include #include /* parallel modules */ #include #include #include "identify.h" #include "parallel.h" /* UG namespaces: */ USING_UG_NAMESPACES /* PPIF namespace: */ using namespace PPIF; START_UGDIM_NAMESPACE /****************************************************************************/ /* */ /* defines in the following order */ /* */ /* compile time constants defining static data size (i.e. arrays) */ /* other constants */ /* macros */ /* */ /****************************************************************************/ /* undefine if overlap should be only updated where needed */ /* This does not work since the connection of the overlap needs the fatherelements on both sides (ghost and master sons) and this is not ensured. #define UPDATE_FULLOVERLAP */ /****************************************************************************/ /* */ /* data structures used in this source file (exported data structures are */ /* in the corresponding include file!) */ /* */ /****************************************************************************/ /****************************************************************************/ /* */ /* definition of exported global variables */ /* */ /****************************************************************************/ /****************************************************************************/ /* */ /* definition of variables global to this source file only (static!) */ /* */ /****************************************************************************/ /****************************************************************************/ /* */ /* forward declarations of functions used before they are defined */ /* */ /****************************************************************************/ /****************************************************************************/ /* UpdateElementOverlap - SYNOPSIS: static INT UpdateElementOverlap (ELEMENT *theElement); PARAMETERS: . theElement DESCRIPTION: RETURN VALUE: INT */ /****************************************************************************/ static INT UpdateElementOverlap (DDD::DDDContext& context, ELEMENT *theElement) { INT i,s,prio; INT SonsOfSide,SonSides[MAX_SONS]; ELEMENT *theNeighbor,*theSon; ELEMENT *SonList[MAX_SONS]; /* yellow_class specific code: */ /* update need to be done for all elements with THEFLAG set, */ /* execpt for yellow copies, since their neighbor need not be */ /* refined (s.l. 971029) */ #ifndef UPDATE_FULLOVERLAP if (!THEFLAG(theElement) && REFINECLASS(theElement)!=YELLOW_CLASS) return(GM_OK); #endif /* if (!THEFLAG(theElement)) return(GM_OK); */ for (i=0; i=context.procs()) break; XFERECOPYX(context, theSon,EPROCPRIO(context, theNeighbor,PrioMaster),PrioHGhost, (OBJT(theSon)==BEOBJ) ? BND_SIZE_TAG(TAG(theSon)) : INNER_SIZE_TAG(TAG(theSon))); /* send son to all elements where theNeighbor is master, vghost or vhghost */ if (0) { for (auto&& [proc, currentPrio] : DDD_InfoProcListRange(context, PARHDRE(theNeighbor), false)) { if (!EHGHOSTPRIO(currentPrio)) { XFERECOPYX(context, theSon,proc,PrioHGhost, (OBJT(theSon)==BEOBJ) ? BND_SIZE_TAG(TAG(theSon)) : INNER_SIZE_TAG(TAG(theSon))); } } } } } return(GM_OK); } /****************************************************************************/ /* UpdateGridOverlap - SYNOPSIS: INT UpdateGridOverlap (GRID *theGrid); PARAMETERS: . theGrid DESCRIPTION: RETURN VALUE: INT */ /****************************************************************************/ INT UpdateGridOverlap (GRID *theGrid) { DDD::DDDContext& context = theGrid->dddContext(); ELEMENT *theElement; for (theElement=FIRSTELEMENT(theGrid); theElement!=NULL; theElement=SUCCE(theElement)) { if (IS_REFINED(theElement)) UpdateElementOverlap(context, theElement); } return(GM_OK); } /****************************************************************************/ /* UpdateMultiGridOverlap - SYNOPSIS: static INT UpdateMultiGridOverlap (MULTIGRID *theMG, INT FromLevel); PARAMETERS: . theMG . FromLevel DESCRIPTION: RETURN VALUE: INT */ /****************************************************************************/ static INT UpdateMultiGridOverlap (MULTIGRID *theMG, INT FromLevel) { ddd_HandlerInit(theMG->dddContext(), HSET_REFINE); for (INT l = FromLevel; l < TOPLEVEL(theMG); l++) { GRID *theGrid = GRID_ON_LEVEL(theMG,l); UpdateGridOverlap(theGrid); } return(GM_OK); } /****************************************************************************/ /* DropUsedFlags - SYNOPSIS: static INT DropUsedFlags (GRID *theGrid); PARAMETERS: . theGrid DESCRIPTION: RETURN VALUE: INT */ /****************************************************************************/ static INT DropUsedFlags (GRID *theGrid) { ELEMENT *theElement; for (theElement=PFIRSTELEMENT(theGrid); theElement!=NULL; theElement=SUCCE(theElement)) { if (USED(theElement) == 1) { REFINE_ELEMENT_LIST(1,theElement,"drop mark"); ASSERT(EFATHER(theElement)!=NULL); /* this father has to be connected */ SETUSED(EFATHER(theElement),1); SETUSED(theElement,0); } } return(GM_OK); } /****************************************************************************/ /* ConnectGridOverlap - SYNOPSIS: INT ConnectGridOverlap (GRID *theGrid); PARAMETERS: . theGrid DESCRIPTION: RETURN VALUE: INT */ /****************************************************************************/ INT ConnectGridOverlap (GRID *theGrid) { INT i,j,Sons_of_Side,prio; INT SonSides[MAX_SIDE_NODES]; ELEMENT *theElement; ELEMENT *theNeighbor; ELEMENT *theSon; ELEMENT *Sons_of_Side_List[MAX_SONS]; for (theElement=PFIRSTELEMENT(theGrid); theElement!=NULL; theElement=SUCCE(theElement)) { prio = EPRIO(theElement); /* connect only FROM hgost copies */ if (!IS_REFINED(theElement) || !EHGHOSTPRIO(prio)) continue; PRINTDEBUG(gm,1,("Connecting e=%08x/%x ID=%d eLevel=%d\n", DDD_InfoGlobalId(PARHDRE(theElement)), theElement,ID(theElement), LEVEL(theElement))); for (i=0; i=SIDES_OF_ELEM(NbSon)) SET_NBELEM(theSon,j,NULL); } */ } if (!ok) { if (ECLASS(theSon) == YELLOW_CLASS) { UserWriteF("ConnectGridOverlap(): disposing useless yellow ghost e=" EID_FMTX "f=" EID_FMTX "this ghost is useless!\n", EID_PRTX(theSon),EID_PRTX(theElement)); DisposeElement(UPGRID(theGrid),theSon); } else { UserWriteF("ConnectGridOverlap(): ERROR e=" EID_FMTX "f=" EID_FMTX "this ghost is useless!\n", EID_PRTX(theSon),EID_PRTX(theElement)); /* TODO: better do this assert(0); */ } } } } } return(GM_OK); } /****************************************************************************/ /* ConnectMultiGridOverlap - SYNOPSIS: static INT ConnectMultiGridOverlap (MULTIGRID *theMG, INT FromLevel); PARAMETERS: . theMG . FromLevel DESCRIPTION: RETURN VALUE: INT */ /****************************************************************************/ static INT ConnectMultiGridOverlap (MULTIGRID *theMG, INT FromLevel) { INT l; GRID *theGrid; /* drop used marks to fathers */ for (l=FromLevel+1; l<=TOPLEVEL(theMG); l++) { theGrid = GRID_ON_LEVEL(theMG,l); if (DropUsedFlags(theGrid)) RETURN(GM_FATAL); } /* connect sons of elements with used flag set */ for (l=FromLevel; l& songlobal = CVECT(MYVERTEX(SonNode)); V_DIM_LINCOMB(0.5, CVECT(MYVERTEX(EdgeNode0)), 0.5, CVECT(MYVERTEX(EdgeNode1)),global); V_DIM_EUKLIDNORM_OF_DIFF(songlobal,global,diff); if (diff <= MAX_PAR_DIST) { assert(found == 0); assert (MIDNODE(theEdge)==NULL || MIDNODE(theEdge) == SonNode); #ifdef UG_DIM_2 IFDEBUG(dddif,1) printf("ConnectOverlapVerticalGrid(): new " " midnode relation between theEdge=%p" " SonNode=" ID_FMTX "Vertex=" VID_FMTX "\n", (void*) theEdge,ID_PRTX(SonNode), VID_PRTX(MYVERTEX(SonNode))); ENDDEBUG #endif #ifdef UG_DIM_3 printf("ConnectOverlapVerticalGrid(): new " " midnode relation between theEdge=" ID_FMTX " SonNode=" ID_FMTX "\n", ID_PRTX(theEdge),ID_PRTX(SonNode)); #endif SETNFATHER(SonNode,(GEOM_OBJECT *)theEdge); MIDNODE(theEdge) = SonNode; found ++; /* reconstruct vertex information */ theVertex = MYVERTEX(SonNode); V_DIM_LINCOMB(0.5, LOCAL_COORD_OF_ELEM(theElement,edgenode0), 0.5, LOCAL_COORD_OF_ELEM(theElement,edgenode1), LCVECT(theVertex)); SETONEDGE(theVertex,k); VFATHER(theVertex) = theElement; } } break; } case SIDE_NODE : case CENTER_NODE : /* do nothing */ break; default : assert(0); } } } } return(GM_OK); } static INT ConnectOverlapVerticalMultiGrid (MULTIGRID *theMG) { for (INT i = 0; i <= TOPLEVEL(theMG); i++) { GRID *theGrid = GRID_ON_LEVEL(theMG,i); if (ConnectOverlapVerticalGrid(theGrid)) return(GM_ERROR); } return(GM_OK); } END_UGDIM_NAMESPACE #endif dune-uggrid-2.11.0+dfsg/dune/uggrid/parallel/dddif/parallel.h000066400000000000000000000457731513616443000237760ustar00rootroot00000000000000// -*- tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- // vi: set et ts=4 sw=2 sts=2: // SPDX-FileCopyrightInfo: Copyright © DUNE Project contributors, see file LICENSE.md in module root // SPDX-License-Identifier: LGPL-2.1-or-later /****************************************************************************/ /* */ /* File: parallel.h */ /* */ /* Purpose: defines for parallel ugp version 3 */ /* */ /* Author: Stefan Lang, Klaus Birken */ /* Institut fuer Computeranwendungen III */ /* Universitaet Stuttgart */ /* Pfaffenwaldring 27 */ /* 70550 Stuttgart */ /* email: stefan@ica3.uni-stuttgart.de */ /* phone: 0049-(0)711-685-7003 */ /* fax : 0049-(0)711-685-7000 */ /* */ /* History: 09.05.95 begin, ugp version 3.0 */ /* */ /* Remarks: */ /* */ /****************************************************************************/ /****************************************************************************/ /* */ /* auto include mechanism and other include files */ /* */ /****************************************************************************/ #ifndef __PARALLEL_H__ #define __PARALLEL_H__ #include #ifdef ModelP # include # include #endif #include #include #ifdef ModelP #include #endif #include #include START_UGDIM_NAMESPACE /****************************************************************************/ /* */ /* defines in the following order */ /* */ /* compile time constants defining static data size (i.e. arrays) */ /* other constants */ /* macros */ /* */ /****************************************************************************/ #ifndef DUNE_UGGRID_HAVE_DDDCONTEXT # define DUNE_UGGRID_HAVE_DDDCONTEXT 1 #endif #define MAXDDDTYPES 32 enum HandlerSets { HSET_XFER = 0, HSET_REFINE }; #ifdef ModelP /* CE for nodes */ /* not used, kb 961216 #define KEEP_VECTOR 0*/ /* this is a node with vector */ /*#define DEL_VECTOR 1*/ /* this is a node without vector */ /* status output from different parallel phases */ /* #define STAT_OUT */ /* define DDD_PRIO_ENV to change priority using fast PrioBegin/End env. */ /* #define DDD_PRIO_ENV */ #ifdef DDD_PRIO_ENV #define DDD_PrioritySet(context, h,p) {ObjectPriorityUpdate(context, (DDD_OBJ)h,p); DDD_PrioChange(context, h,p);} #endif #define UGTYPE(context, t) (ddd_ctrl(context).ugtypes[(t)]) #define DDDTYPE(context, t) (ddd_ctrl(context).types[(t)]) #define HAS_DDDHDR(context, t) (ddd_ctrl(context).dddObj[(t)]) #define DDD_DOMAIN_DATA DDD_USER_DATA+1 #define DDD_EXTRA_DATA DDD_USER_DATA+2 /* macros for ddd object info */ /* for elements */ #define EPRIO(e) (Priorities)DDD_InfoPriority(PARHDRE(e)) #define SETEPRIO(context, e,p) DDD_PrioritySet(context, PARHDRE(e),p) #define SETEPRIOX(context, e,p) if (EPRIO(e)!=p) DDD_PrioritySet(context, PARHDRE(e),p) #define EMASTER(e) (EPRIO(e) == PrioMaster) #define EGHOST(e) (EPRIO(e)==PrioHGhost || EPRIO(e)==PrioVGhost ||\ EPRIO(e)==PrioVHGhost) #define EVHGHOST(e) (EPRIO(e)==PrioVHGhost) #define EVGHOST(e) (EPRIO(e)==PrioVGhost || EPRIO(e)==PrioVHGhost) #define EHGHOST(e) (EPRIO(e)==PrioHGhost || EPRIO(e)==PrioVHGhost) #define EGID(e) DDD_InfoGlobalId(PARHDRE(e)) #define EPROCLIST(context, e) DDD_InfoProcListRange(context, PARHDRE(e)) #define EPROCPRIO(context, e,p) DDD_InfoProcPrio(context, PARHDRE(e),p) #define ENCOPIES(context, e) DDD_InfoNCopies(context, PARHDRE(e)) #define EATTR(e) DDD_InfoAttr(PARHDRE(e)) #define XFEREDELETE(context, e) DDD_XferDeleteObj(context, PARHDRE(e)) #define XFERECOPY(context, e,dest,prio) DDD_XferCopyObj(context, PARHDRE(e),dest,prio) #define XFERECOPYX(context, e,dest,prio,size) DDD_XferCopyObjX(context, PARHDRE(e),dest,prio,size) /* for nodes, vectors, edges (edges only 3D) */ #define PRIO(e) DDD_InfoPriority(PARHDR(e)) #define SETPRIO(context, e,p) DDD_PrioritySet(context, PARHDR(e),p) #define SETPRIOX(context, e,p) if (PRIO(e)!=p) DDD_PrioritySet(context, PARHDR(e),p) #define MASTER(e) (PRIO(e)==PrioMaster || PRIO(e)==PrioBorder) #define GHOST(e) (PRIO(e)==PrioHGhost || PRIO(e)==PrioVGhost ||\ PRIO(e)==PrioVHGhost) #define VHGHOST(e) (PRIO(e)==PrioVHGhost) #define VGHOST(e) (PRIO(e)==PrioVGhost || PRIO(e)==PrioVHGhost) #define HGHOST(e) (PRIO(e)==PrioHGhost || PRIO(e)==PrioVHGhost) #define GID(e) DDD_InfoGlobalId(PARHDR(e)) #define PROCLIST(context, e) DDD_InfoProcListRange(context, PARHDR(e)) #define PROCPRIO(context, e,p) DDD_InfoProcPrio(context, PARHDR(e),p) #define NCOPIES(context, e) DDD_InfoNCopies(context, PARHDR(e)) #define ATTR(e) DDD_InfoAttr(PARHDR(e)) #define XFERDELETE(context, e) DDD_XferDeleteObj(context, PARHDR(e)) #define XFERCOPY(context, e,dest,prio) DDD_XferCopyObj(context, PARHDR(e),dest,prio) #define XFERCOPYX(context, e,dest,prio,size) DDD_XferCopyObjX(context, PARHDR(e),dest,prio,size) /* for vertices */ #define VXPRIO(e) DDD_InfoPriority(PARHDRV(e)) #define SETVXPRIO(context, e,p) DDD_PrioritySet(context, PARHDRV(e),p) #define SETVXPRIOX(context, e,p) if (VXPRIO(e)!=p) DDD_PrioritySet(context, PARHDRV(e),p) #define VXMASTER(e) (VXPRIO(e)==PrioMaster || VXPRIO(e)==PrioBorder) #define VXGHOST(e) (VXPRIO(e)==PrioHGhost || VXPRIO(e)==PrioVGhost ||\ VXPRIO(e)==PrioVHGhost) #define VXVHGHOST(e) (VXPRIO(e)==PrioVHGhost) #define VXVGHOST(e) (VXPRIO(e)==PrioVGhost || VXPRIO(e)==PrioVHGhost) #define VXHGHOST(e) (VXPRIO(e)==PrioHGhost || VXPRIO(e)==PrioVHGhost) #define VXGID(e) DDD_InfoGlobalId(PARHDRV(e)) #define VXPROCLIST(context, e) DDD_InfoProcListRange(context, PARHDRV(e)) #define VXPROCPRIO(context, e,p) DDD_InfoProcPrio(context, PARHDRV(e),p) #define VXNCOPIES(context, e) DDD_InfoNCopies(context, PARHDRV(e)) #define VXATTR(e) DDD_InfoAttr(PARHDRV(e)) #define XFERVXDELETE(context, e) DDD_XferDeleteObj(context, PARHDRV(e)) #define XFERVXCOPY(context, e,dest,prio) DDD_XferCopyObj(context, PARHDRV(e),dest,prio,size) #define XFERVXCOPYX(context, e,dest,prio,size) DDD_XferCopyObjX(context, PARHDRV(e),dest,prio,size) /* macros for priorities */ /* for elements */ #define EMASTERPRIO(p) (p==PrioMaster) #define EGHOSTPRIO(p) (p==PrioHGhost || p==PrioVGhost || p==PrioVHGhost) #define EVHGHOSTPRIO(p) (p==PrioVHGhost) #define EVGHOSTPRIO(p) (p==PrioVGhost || p==PrioVHGhost) #define EHGHOSTPRIO(p) (p==PrioHGhost || p==PrioVHGhost) /* for nodes, vertices, vectors, edges (edges only 3D) */ #define MASTERPRIO(p) (p==PrioMaster || p==PrioBorder) #define GHOSTPRIO(p) (p==PrioHGhost || p==PrioVGhost || p==PrioVHGhost) #define VHGHOSTPRIO(p) (p==PrioVHGhost) #define VGHOSTPRIO(p) (p==PrioVGhost || p==PrioVHGhost) #define HGHOSTPRIO(p) (p==PrioHGhost || p==PrioVHGhost) #define EGID_FMT DDD_GID_FMT #define GID_FMT DDD_GID_FMT /* This exchanges in the load balancing the connections too. #define __EXCHANGE_CONNECTIONS__ */ #endif /* ModelP */ /****************************************************************************/ /* */ /* data structures exported by the corresponding source file */ /* */ /****************************************************************************/ /****************************************************************************/ /* */ /* definition of exported global variables */ /* */ /****************************************************************************/ #ifdef ModelP /* DDD Interfaces */ extern DDD_IF ElementIF, ElementSymmIF, ElementVIF, ElementSymmVIF, ElementVHIF, ElementSymmVHIF; extern DDD_IF BorderNodeIF, BorderNodeSymmIF, OuterNodeIF, NodeVIF, NodeIF, NodeAllIF, Node_InteriorBorder_All_IF; extern DDD_IF BorderVectorIF, BorderVectorSymmIF, OuterVectorIF, OuterVectorSymmIF, VectorVIF, VectorVAllIF, VectorIF; extern DDD_IF Facet_All_All_IF, Facet_InteriorBorder_All_IF; extern DDD_IF EdgeIF, BorderEdgeSymmIF, EdgeHIF, EdgeVHIF, EdgeSymmVHIF; /* DDD Global Controls */ struct DDD_CTRL { /* data from ug */ MULTIGRID *currMG; int nodeData; int edgeData; int elemData; int sideData; INT ugtypes[MAXDDDTYPES]; /* dddtype -> ugtype */ DDD_TYPE types[MAXOBJECTS]; /* ugtype -> dddtype */ bool dddObj[MAXOBJECTS]; /* status of DDDIF */ bool allTypesDefined; /* DDD objects */ DDD_TYPE TypeVector; DDD_TYPE TypeIVertex, TypeBVertex; DDD_TYPE TypeNode; DDD_TYPE TypeUnknown; #ifdef UG_DIM_2 DDD_TYPE TypeTrElem, TypeTrBElem, TypeQuElem, TypeQuBElem; #endif #ifdef UG_DIM_3 DDD_TYPE TypeTeElem, TypeTeBElem; DDD_TYPE TypePyElem, TypePyBElem; DDD_TYPE TypePrElem, TypePrBElem; DDD_TYPE TypeHeElem, TypeHeBElem; #endif /* DDD data objects */ DDD_TYPE TypeBndP; DDD_TYPE TypeEdge; DDD_TYPE TypeBndS; /* DDD Interfaces */ DDD_IF ElementIF, ElementSymmIF, ElementVIF, ElementSymmVIF, ElementVHIF, ElementSymmVHIF; DDD_IF BorderNodeIF, BorderNodeSymmIF, OuterNodeIF, NodeVIF, NodeIF, NodeAllIF, Node_InteriorBorder_All_IF; DDD_IF BorderVectorIF, BorderVectorSymmIF, OuterVectorIF, OuterVectorSymmIF, VectorVIF, VectorVAllIF, VectorIF; DDD_IF Facet_All_All_IF, Facet_InteriorBorder_All_IF; DDD_IF VertexIF; DDD_IF EdgeIF, BorderEdgeSymmIF, EdgeHIF, EdgeVHIF, EdgeSymmVHIF; }; #endif /****************************************************************************/ /* */ /* function declarations */ /* */ /****************************************************************************/ #ifdef ModelP /** * accessor function for DDD user context */ inline const DDD_CTRL& ddd_ctrl(const DDD::DDDContext& context) { return *static_cast(context.data()); } /** * accessor function for DDD user context */ inline DDD_CTRL& ddd_ctrl(DDD::DDDContext& context) { return *static_cast(context.data()); } /* from initddd.c */ int InitDDD(DDD::DDDContext& context); int ExitDDD(DDD::DDDContext& context); void InitCurrMG (MULTIGRID *); /* from debugger.c */ void ddd_pstat (DDD::DDDContext& context, char *); /* from lb.c */ void lbs (const char *argv, MULTIGRID *theMG); /* from handler.c */ void ddd_HandlerInit (DDD::DDDContext& context, INT); DDD_TYPE NFatherObjType (DDD::DDDContext& context, DDD_OBJ obj, DDD_OBJ ref); void ObjectPriorityUpdate (DDD::DDDContext& context, DDD_OBJ obj, DDD_PRIO newPrio); /* from lbrcb.c */ void BalanceGridRCB (MULTIGRID *, int); /* from gridcons.c */ void ConstructConsistentGrid (GRID *theGrid); void ConstructConsistentMultiGrid (MULTIGRID *theMG); /* from pgmcheck.c */ INT CheckProcListCons(const DDD_InfoProcListRange& proclist, DDD_PRIO uniqueTag); INT CheckInterfaces (GRID *theGrid); /* from priority.c */ INT SetGridBorderPriorities (GRID *theGrid); void SetGhostObjectPriorities (GRID *theGrid); /* from trans.c */ int TransferGrid (MULTIGRID *theMG); int TransferGridFromLevel (MULTIGRID *theMG, INT level); /* from identify.c */ void IdentifyInit (MULTIGRID *theMG); void IdentifyExit (void); INT Identify_Objects_of_ElementSide (GRID *theGrid, ELEMENT *theElement, INT i); INT Identify_SonNodesAndSonEdges (GRID *theGrid); /* from overlap.c */ INT UpdateGridOverlap (GRID *theGrid); INT ConnectGridOverlap (GRID *theGrid); INT ConnectVerticalOverlap (MULTIGRID *theMG); /* from priority.c */ void SetGhostObjectPriorities (GRID *theGrid); INT SetBorderPriorities (GRID *theGrid); INT SetGridBorderPriorities (GRID *theGrid); /* from partition.c */ INT CheckPartitioning (MULTIGRID *theMG); INT RestrictPartitioning (MULTIGRID *theMG); /* from pgmcheck.c */ INT CheckInterfaces (GRID *theGrid); /* * COMPATIBILITY FUNCTIONS FOR OLDER dune-grid RELEASES */ /** * get global DDD context. * This only exists for compatibility with old versions of dune-grid. */ DDD::DDDContext& globalDDDContext(); /** * set global DDD context. * This only exists for compatibility with old versions of dune-grid. */ void globalDDDContext(const std::shared_ptr& context); /** * invalidate global DDD context. * This only exists for compatibility with old versions of dune-grid. */ void globalDDDContext(std::nullptr_t); using ComProcPtr = int (*)(DDD_OBJ, void *); #endif /* ModelP */ END_UGDIM_NAMESPACE #endif /* __PARALLEL_H__ */ dune-uggrid-2.11.0+dfsg/dune/uggrid/parallel/dddif/partition.cc000066400000000000000000000312051513616443000243320ustar00rootroot00000000000000// SPDX-FileCopyrightText: Copyright © DUNE Project contributors, see file LICENSE.md in module root // SPDX-License-Identifier: LGPL-2.1-or-later // -*- tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- // vi: set et ts=4 sw=2 sts=2: /****************************************************************************/ /* */ /* File: partition.c */ /* */ /* Purpose: check and restrict partitioning for grid adaption */ /* */ /* Author: Stefan Lang */ /* Institut fuer Computeranwendungen III */ /* Universitaet Stuttgart */ /* Pfaffenwaldring 27 */ /* 70569 Stuttgart */ /* */ /* History: 970204 sl begin */ /* */ /* */ /****************************************************************************/ #ifdef ModelP /****************************************************************************/ /* */ /* include files */ /* system include files */ /* application include files */ /* */ /****************************************************************************/ /* standard C library */ #include #include #include #include #include #include /* low module */ #include #include #include #include #include /* dev module */ #include /* gm module */ #include #include #include #include #include #include #include /* parallel modules */ #include #include #include "identify.h" #include "parallel.h" /* UG namespaces: */ USING_UG_NAMESPACES /* PPIF namespace: */ using namespace PPIF; /****************************************************************************/ /* */ /* defines in the following order */ /* */ /* compile time constants defining static data size (i.e. arrays) */ /* other constants */ /* macros */ /* */ /****************************************************************************/ /* undefine if overlap should be only updated where needed */ /* This does not work since the connection of the overlap needs the fatherelements on both sides (ghost and master sons) and this is not ensured. #define UPDATE_FULLOVERLAP */ /****************************************************************************/ /* */ /* data structures used in this source file (exported data structures are */ /* in the corresponding include file!) */ /* */ /****************************************************************************/ /****************************************************************************/ /* */ /* definition of exported global variables */ /* */ /****************************************************************************/ /****************************************************************************/ /* */ /* definition of variables global to this source file only (static!) */ /* */ /****************************************************************************/ /****************************************************************************/ /* */ /* forward declarations of functions used before they are defined */ /* */ /****************************************************************************/ /****************************************************************************/ /* CheckPartitioning - check whether all master copies have master copies of the sons SYNOPSIS: INT CheckPartitioning (MULTIGRID *theMG); PARAMETERS: . theMG DESCRIPTION: This function checks whether all master copies of elements which may be involved in next refinement step have master copies of the sons (if existing) at the same processor. RETURN VALUE: INT .n GM_OK - ok .n GM_ERROR - error */ /****************************************************************************/ INT NS_DIM_PREFIX CheckPartitioning (MULTIGRID *theMG) { INT i,_restrict_; ELEMENT *theElement; ELEMENT *theFather; _restrict_ = 0; /* reset used flags */ for (i=TOPLEVEL(theMG); i>0; i--) { const GRID *theGrid = GRID_ON_LEVEL(theMG,i); for (theElement=FIRSTELEMENT(theGrid); theElement!=NULL; theElement=SUCCE(theElement)) { if (LEAFELEM(theElement)) { theFather = theElement; while (EMASTER(theFather) && ECLASS(theFather)!=RED_CLASS && LEVEL(theFather)>0) { theFather = EFATHER(theFather); } /* if element with red element class does not exist */ /* or is ghost -> partitioning must be restricted */ if (!EMASTER(theFather)) { UserWriteF("elem=" EID_FMTX " cannot be refined\n", EID_PRTX(theFather)); _restrict_ = 1; continue; } if (COARSEN(theFather)) { /* level 0 elements cannot be coarsened */ if (LEVEL(theFather)<=1) continue; if (!EMASTER(EFATHER(theFather))) { UserWriteF("elem=" EID_FMTX " cannot be coarsened\n", EID_PRTX(theFather)); _restrict_ = 1; } } } } } _restrict_ = UG_GlobalMaxINT(theMG->ppifContext(), _restrict_); if (theMG->dddContext().isMaster() && _restrict_==1) { UserWriteF("CheckPartitioning(): partitioning is not valid for refinement\n"); UserWriteF(" cleaning up ...\n"); } return(_restrict_); } /****************************************************************************/ /* Gather_ElementRestriction - SYNOPSIS: static int Gather_ElementRestriction (DDD_OBJ obj, void *data); PARAMETERS: . obj . data DESCRIPTION: RETURN VALUE: int */ /****************************************************************************/ static int Gather_ElementRestriction (DDD::DDDContext&, DDD_OBJ obj, void *data) { ELEMENT *theElement = (ELEMENT *)obj; PRINTDEBUG(gm,4,(PFMT "Gather_ElementRestriction(): e=" EID_FMTX "\n", me,EID_PRTX(theElement))) ((int *)data)[0] = USED(theElement); return(GM_OK); } /****************************************************************************/ /* Scatter_ElementRestriction - SYNOPSIS: static int Scatter_ElementRestriction (DDD_OBJ obj, void *data); PARAMETERS: . obj . data DESCRIPTION: RETURN VALUE: int */ /****************************************************************************/ static int Scatter_ElementRestriction (DDD::DDDContext&, DDD_OBJ obj, void *data) { ELEMENT *theElement = (ELEMENT *)obj; PRINTDEBUG(gm,4,(PFMT "Scatter_ElementRestriction(): e=" EID_FMTX "\n", me,EID_PRTX(theElement))) if (EMASTER(theElement)) { PRINTDEBUG(gm,4,(PFMT "Scatter_ElementRestriction(): restricting sons of e=" EID_FMTX "\n", me,EID_PRTX(theElement))) int used = std::max((INT)USED(theElement),((int *)data)[0]); SETUSED(theElement,used); } return(GM_OK); } /****************************************************************************/ /* Gather_RestrictedPartition - SYNOPSIS: static int Gather_RestrictedPartition (DDD_OBJ obj, void *data, DDD_PROC proc, DDD_PRIO prio); PARAMETERS: . obj . data . proc . prio DESCRIPTION: RETURN VALUE: int */ /****************************************************************************/ static int Gather_RestrictedPartition (DDD::DDDContext&, DDD_OBJ obj, void *data, DDD_PROC proc, DDD_PRIO prio) { ELEMENT *theElement = (ELEMENT *)obj; if (EMASTER(theElement)) { PRINTDEBUG(gm,4,(PFMT "Gather_RestrictedPartition(): e=" EID_FMTX "\n", me,EID_PRTX(theElement))) ((int *)data)[0] = PARTITION(theElement); } return(GM_OK); } /****************************************************************************/ /* Scatter_RestrictedPartition - SYNOPSIS: static int Scatter_RestrictedPartition (DDD_OBJ obj, void *data, DDD_PROC proc, DDD_PRIO prio); PARAMETERS: . obj . data . proc . prio DESCRIPTION: RETURN VALUE: int */ /****************************************************************************/ static int Scatter_RestrictedPartition (DDD::DDDContext&, DDD_OBJ obj, void *data, DDD_PROC proc, DDD_PRIO prio) { ELEMENT *theElement = (ELEMENT *)obj; ELEMENT *SonList[MAX_SONS]; if (USED(theElement) && EMASTERPRIO(prio)) { PRINTDEBUG(gm,4,(PFMT "Scatter_ElementRestriction(): restricting sons of e=" EID_FMTX "\n", me,EID_PRTX(theElement))) int partition = ((int *)data)[0]; /* send master sons to master element partition */ if (GetSons(theElement,SonList)) RETURN(GM_ERROR); for (int i = 0; SonList[i] != NULL; i++) PARTITION(SonList[i]) = partition; } return(GM_OK); } /****************************************************************************/ /* RestrictPartitioning - SYNOPSIS: INT RestrictPartitioning (MULTIGRID *theMG); PARAMETERS: . theMG DESCRIPTION: RETURN VALUE: INT */ /****************************************************************************/ INT NS_DIM_PREFIX RestrictPartitioning (MULTIGRID *theMG) { auto& context = theMG->dddContext(); const auto& dddctrl = ddd_ctrl(context); INT i,j; ELEMENT *theElement; ELEMENT *theFather; ELEMENT *SonList[MAX_SONS]; GRID *theGrid; /* reset used flags */ for (i=TOPLEVEL(theMG); i>=0; i--) { theGrid = GRID_ON_LEVEL(theMG,i); for (theElement=PFIRSTELEMENT(theGrid); theElement!=NULL; theElement=SUCCE(theElement)) { SETUSED(theElement,0); } } /* set flags on elements which violate restriction */ for (i=TOPLEVEL(theMG); i>=0; i--) { theGrid = GRID_ON_LEVEL(theMG,i); for (theElement=FIRSTELEMENT(theGrid); theElement!=NULL; theElement=SUCCE(theElement)) { if (GLEVEL(theGrid) == 0) break; if (LEAFELEM(theElement) || USED(theElement)) { theFather = theElement; while (EMASTER(theFather) && ECLASS(theFather)!=RED_CLASS && LEVEL(theFather)>0) { theFather = EFATHER(theFather); } /* if father with red refine class is not master */ /* partitioning must be restricted */ if (!EMASTER(theFather)) { /* the sons of father will be sent to partition of father */ SETUSED(theFather,1); } /* if element is marked for coarsening and father */ /* of element is not master -> restriction is needed */ if (COARSEN(theFather)) { /* level 0 elements are not coarsened */ if (LEVEL(theFather)<=1) continue; if (!EMASTER(EFATHER(theFather))) SETUSED(EFATHER(theFather),1); } } } /* transfer restriction flags to master copies of father */ DDD_IFAOneway(context, dddctrl.ElementVHIF,GRID_ATTR(theGrid),IF_BACKWARD,sizeof(INT), Gather_ElementRestriction, Scatter_ElementRestriction); } /* send restricted sons to partition of father */ for (i=0; i<=TOPLEVEL(theMG); i++) { theGrid = GRID_ON_LEVEL(theMG,i); /* transfer (new) partitions of elements to non master copies */ DDD_IFAOnewayX(context, dddctrl.ElementVHIF,GRID_ATTR(theGrid),IF_FORWARD,sizeof(INT), Gather_RestrictedPartition, Scatter_RestrictedPartition); for (theElement=PFIRSTELEMENT(theGrid); theElement!=NULL; theElement=SUCCE(theElement)) { if (!USED(theElement)) continue; /* push partition to the sons */ GetAllSons(theElement,SonList); for (j=0; SonList[j]!=NULL; j++) { SETUSED(SonList[j],1); if (EMASTER(SonList[j])) PARTITION(SonList[j]) = PARTITION(theElement); } } } if (TransferGrid(theMG) != 0) RETURN(GM_FATAL); return(GM_OK); } #endif dune-uggrid-2.11.0+dfsg/dune/uggrid/parallel/dddif/pgmcheck.cc000066400000000000000000000527061513616443000241130ustar00rootroot00000000000000// SPDX-FileCopyrightText: Copyright © DUNE Project contributors, see file LICENSE.md in module root // SPDX-License-Identifier: LGPL-2.1-or-later // -*- tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- // vi: set et ts=4 sw=2 sts=2: /****************************************************************************/ /* */ /* File: pgmcheck.c */ /* */ /* Purpose: functions for checking parallel consistency */ /* */ /* Author: Stefan Lang */ /* Institut fuer Computeranwendungen III */ /* Universitaet Stuttgart */ /* Pfaffenwaldring 27 */ /* 70550 Stuttgart */ /* email: birken@ica3.uni-stuttgart.de */ /* phone: 0049-(0)711-685-7003 */ /* fax : 0049-(0)711-685-7000 */ /* */ /* History: 980204 sl begin */ /* */ /* Remarks: */ /* */ /****************************************************************************/ #ifdef ModelP /****************************************************************************/ /* */ /* include files */ /* system include files */ /* application include files */ /* */ /****************************************************************************/ #include #include #include "parallel.h" #include #include #include #include #include #include #include #include /* UG namespaces: */ USING_UG_NAMESPACES /* PPIF namespace: */ using namespace PPIF; /****************************************************************************/ /* */ /* defines in the following order */ /* */ /* compile time constants defining static data size (i.e. arrays) */ /* other constants */ /* macros */ /* */ /****************************************************************************/ #define CHECK_OBJECT_PRIO(o,prio,master,ghost,id,s,_nerr_) \ do { \ if (USED(o)==1 && ! master (o)) \ { \ UserWriteF("MASTER %s=" id ## _FMTX " has WRONG prio=%d\n", \ s, id ## _PRTX(o),prio(o)); \ _nerr_++; \ } \ if (USED( o )==0 && ! ghost ( o )) \ { \ UserWriteF("GHOST %s=" id ## _FMTX " has WRONG prio=%d\n", \ s, id ## _PRTX( o ),prio(o)); \ _nerr_++; \ } \ } while (0) /****************************************************************************/ /* */ /* data structures used in this source file (exported data structures are */ /* in the corresponding include file!) */ /* */ /****************************************************************************/ /****************************************************************************/ /* */ /* definition of exported global variables */ /* */ /****************************************************************************/ /****************************************************************************/ /* */ /* definition of variables global to this source file only (static!) */ /* */ /****************************************************************************/ /* count for errors to report from communication scatter functions */ static INT check_distributed_objects_errors = 0; /****************************************************************************/ /* */ /* forward declarations of functions used before they are defined */ /* */ /****************************************************************************/ /****************************************************************************/ /* CheckProcListCons - SYNOPSIS: INT CheckProcListCons (const DDD_InfoProcListRange& proclist, DDD_PRIO uniqueTag); PARAMETERS: . proclist . uniqueTag DESCRIPTION: RETURN VALUE: INT */ /****************************************************************************/ INT NS_DIM_PREFIX CheckProcListCons (const DDD_InfoProcListRange& proclist, DDD_PRIO uniqueTag) { int nunique = 0; /* check uniqueness */ for (auto&& [proc, prio] : proclist) { if (prio == uniqueTag) ++nunique; } /* nunique must be 1 for master elements */ /* nunique can be 0/1 for (inner) nodes */ /* with PrioBorder/PrioMaster */ return nunique; } /****************************************************************************/ /* ListProcList - SYNOPSIS: INT ListProcList (const DDD_InfoProcListRange& proclist, DDD_PRIO uniqueTag); PARAMETERS: . proclist . uniqueTag DESCRIPTION: RETURN VALUE: INT */ /****************************************************************************/ static INT ListProcList (const DDD_InfoProcListRange& proclist, DDD_PRIO uniqueTag) { for (auto&& [proc, prio] : proclist) { if (prio == uniqueTag) UserWriteF(" proc=%d", proc); } return 0; } /****************************************************************************/ /* CheckVectorPrio - SYNOPSIS: INT CheckVectorPrio (ELEMENT *theElement, VECTOR *theVector); PARAMETERS: . theElement . theVector DESCRIPTION: RETURN VALUE: INT */ /****************************************************************************/ static INT CheckVectorPrio (DDD::DDDContext& context, ELEMENT *theElement, VECTOR *theVector) { INT nmaster; INT nerrors = 0; /* check vector prio */ CHECK_OBJECT_PRIO(theVector,PRIO,MASTER,GHOST,VINDEX,"Vector",nerrors); /* master copy has to be unique */ const auto& proclist = DDD_InfoProcListRange(context, PARHDR(theVector)); if ((nmaster = CheckProcListCons(proclist, PrioMaster)) > 1) { UserWriteF("VECTOR=" ID_FMTX " ERROR: master copy not unique, nmaster=%d:", ID_PRTX(theVector),nmaster); ListProcList(proclist, PrioMaster); UserWriteF("\n"); nerrors++; } return nerrors; } /****************************************************************************/ /* CheckNodePrio - SYNOPSIS: INT CheckNodePrio (ELEMENT *theElement, NODE *theNode); PARAMETERS: . theElement . theNode DESCRIPTION: RETURN VALUE: INT */ /****************************************************************************/ static INT CheckNodePrio (DDD::DDDContext& context, ELEMENT *theElement, NODE *theNode) { INT nmaster; INT nerrors = 0; /* check node prio */ CHECK_OBJECT_PRIO(theNode,PRIO,MASTER,GHOST,ID,"NODE",nerrors); /* master copy has to be unique */ const auto& proclist = DDD_InfoProcListRange(context, PARHDR(theNode)); if ((nmaster = CheckProcListCons(proclist, PrioMaster)) > 1) { UserWriteF("NODE=" ID_FMTX " ERROR: master copy not unique, nmaster=%d:", ID_PRTX(theNode),nmaster); ListProcList(proclist, PrioMaster); UserWriteF("\n"); nerrors++; } return(nerrors); } /****************************************************************************/ /* CheckEdgePrio - SYNOPSIS: INT CheckEdgePrio (ELEMENT *theElement, EDGE *theEdge); PARAMETERS: . theElement . theEdge DESCRIPTION: RETURN VALUE: INT */ /****************************************************************************/ static INT CheckEdgePrio (DDD::DDDContext& context, ELEMENT *theElement, EDGE *theEdge) { INT nerrors = 0; #ifdef UG_DIM_3 INT nmaster; /* check edge prio */ CHECK_OBJECT_PRIO(theEdge,PRIO,MASTER,GHOST,ID,"EDGE",nerrors); /* master copy has to be unique */ const auto& proclist = DDD_InfoProcListRange(context, PARHDR(theEdge)); if ((nmaster = CheckProcListCons(proclist, PrioMaster)) > 1) { UserWriteF("EDGE=" EDID_FMTX " ERROR: master copy not unique, nmaster=%d:", EDID_PRTX(theEdge),nmaster); ListProcList(proclist, PrioMaster); UserWriteF("\n"); nerrors++; } #endif if (ddd_ctrl(context).edgeData) if (EDVECTOR(theEdge) != NULL) nerrors += CheckVectorPrio(context, theElement,EDVECTOR(theEdge)); return(nerrors); } /****************************************************************************/ /* CheckElementPrio - SYNOPSIS: INT CheckElementPrio (ELEMENT *theElement); PARAMETERS: . theElement DESCRIPTION: RETURN VALUE: INT */ /****************************************************************************/ static INT CheckElementPrio (DDD::DDDContext& context, ELEMENT *theElement) { INT i,nmaster,prio,valid_copy; INT nerrors = 0; NODE *theNode; EDGE *theEdge; ELEMENT *SonList[MAX_SONS]; const auto& me = context.me(); if (PARTITION(theElement)==me && !EMASTER(theElement)) { UserWriteF(PFMT "#FATAL# MASTER ELEM=" EID_FMTX " has WRONG part=%d prio=%d\n", me,EID_PRTX(theElement),PARTITION(theElement),EPRIO(theElement)); nerrors++; } if (PARTITION(theElement)!=me && !EGHOST(theElement)) { UserWriteF(PFMT "#FATAL# GHOST ELEM=" EID_FMTX " has WRONG part=%d prio=%d\n", me,EID_PRTX(theElement),PARTITION(theElement),EPRIO(theElement)); nerrors++; /* test ghost prio */ prio = 0; for (i=0; i0) remotegid = ((DDD_GID *)data)[i]-1; if (MidNode != NULL) { if (remotegid != GID(MidNode)) { UserWriteF("EDGE=" ID_FMTX " #ERROR#: MIDNODE=" ID_FMTX " gids don't match " "local=%08x remote=%08x remoteproc/prio=%d/%d\n", ID_PRTX(theEdge),ID_PRTX(MidNode), GID(MidNode),remotegid,proc,prio); check_distributed_objects_errors++; assert(0); } } else { if (remotegid != 0) { UserWriteF("EDGE=" ID_FMTX " #ERROR#: MIDNODE=NULL gids don't match " "local=%08x remote=%08x remoteproc/prio=%d/%d\n", ID_PRTX(theEdge),0,remotegid,proc,prio); check_distributed_objects_errors++; assert(0); } } i++; return 0; } #endif static INT CheckDistributedObjects (GRID *theGrid) { auto& context = theGrid->dddContext(); const auto& dddctrl = ddd_ctrl(context); INT nerrors; #ifdef UG_DIM_2 INT size = MAX_CORNERS_OF_ELEM; /* compare the 3/4 node ids */ #endif #ifdef UG_DIM_3 INT size = MAX_CORNERS_OF_ELEM+MAX_EDGES_OF_ELEM; /* compare 8 nodes + 12 edges */ #endif check_distributed_objects_errors = 0; // void DDD_IFAOnewayX (DDD::DDDContext&, DDD_IF, DDD_ATTR, DDD_IF_DIR, size_t, ComProcXPtr, ComProcXPtr); DDD_IFAOnewayX(context, dddctrl.ElementSymmVHIF,GRID_ATTR(theGrid),IF_BACKWARD,size*sizeof(DDD_GID), Gather_ElemObjectGids, Scatter_ElemObjectGids); #ifdef UG_DIM_3 if (0) DDD_IFAOnewayX(context, dddctrl.BorderEdgeSymmIF,GRID_ATTR(theGrid),IF_BACKWARD,3*sizeof(DDD_GID), Gather_EdgeObjectGids, Scatter_EdgeObjectGids); #endif nerrors = check_distributed_objects_errors; return(nerrors); } /****************************************************************************/ /* CheckInterfaces - SYNOPSIS: INT CheckInterfaces (GRID *theGrid); PARAMETERS: . theGrid DESCRIPTION: RETURN VALUE: INT */ /****************************************************************************/ INT NS_DIM_PREFIX CheckInterfaces (GRID *theGrid) { auto& context = theGrid->dddContext(); auto& dddctrl = ddd_ctrl(context); INT i,j; ELEMENT *theElement; NODE *theNode; EDGE *theEdge; int nerrors = 0; /* reset USED flag of all grid objects */ /* set USED flag of master grid objects */ for (j=0; j<2; j++) { for (theElement =(j==0 ? PFIRSTELEMENT(theGrid) : FIRSTELEMENT(theGrid)); theElement!=NULL; theElement=SUCCE(theElement)) { SETUSED(theElement,j); if (dddctrl.elemData) if (EVECTOR(theElement) != NULL) SETUSED(EVECTOR(theElement),j); #ifdef UG_DIM_3 if (dddctrl.sideData) { for (i=0; idddContext(), theElement); } /* check uniqueness of global ids for distributed nodes and edges */ nerrors += CheckDistributedObjects(theGrid); /* check ddd interface consistency */ DDD_SetOption(theGrid->dddContext(), OPT_QUIET_CONSCHECK, OPT_ON); nerrors += DDD_ConsCheck(theGrid->dddContext()); DDD_SetOption(theGrid->dddContext(), OPT_QUIET_CONSCHECK, OPT_OFF); return(nerrors); } #endif dune-uggrid-2.11.0+dfsg/dune/uggrid/parallel/dddif/priority.cc000066400000000000000000000372301513616443000242060ustar00rootroot00000000000000// SPDX-FileCopyrightText: Copyright © DUNE Project contributors, see file LICENSE.md in module root // SPDX-License-Identifier: LGPL-2.1-or-later // -*- tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- // vi: set et ts=4 sw=2 sts=2: /****************************************************************************/ /* */ /* File: priority.c */ /* */ /* Purpose: functions for managing priorities of distributed objects */ /* */ /* Author: Stefan Lang */ /* Institut fuer Computeranwendungen III */ /* Universitaet Stuttgart */ /* Pfaffenwaldring 27 */ /* 70550 Stuttgart */ /* email: birken@ica3.uni-stuttgart.de */ /* */ /* History: 980201 sl begin */ /* */ /* Remarks: */ /* */ /****************************************************************************/ #ifdef ModelP /****************************************************************************/ /* */ /* include files */ /* system include files */ /* application include files */ /* */ /****************************************************************************/ #include #include #include "parallel.h" #include #include #include #include #include #include #include #include /* UG namespaces: */ USING_UG_NAMESPACES /* PPIF namespace: */ using namespace PPIF; /****************************************************************************/ /* */ /* defines in the following order */ /* */ /* compile time constants defining static data size (i.e. arrays) */ /* other constants */ /* macros */ /* */ /****************************************************************************/ /* macros for merge new priority with objects existing one */ /* valid only for all types of ghost priorities */ #define PRIO_CALC(e) ((USED(e) && THEFLAG(e)) ? PrioVHGhost : \ (THEFLAG(e)) ? PrioVGhost : (USED(e)) ? \ PrioHGhost : (assert(0),0)) #define SETPRIOPV SETPRIOX /* macros for setting object priorities with related objects */ inline void NODE_PRIORITY_SET(DDD::DDDContext& context, GRID* grid, NODE* node, INT prio) { /* set priorities of node */ SETPRIOX(context, node, prio); } inline void PRIO_SET_EDGE(DDD::DDDContext& context, EDGE* edge, INT prio) { SETPRIOX(context, edge, prio); } inline void EDGE_PRIORITY_SET(DDD::DDDContext& context, GRID* grid, EDGE* edge, INT prio) { /* set priorities of node for 3D */ PRIO_SET_EDGE(context, edge, prio); } /****************************************************************************/ /* */ /* data structures used in this source file (exported data structures are */ /* in the corresponding include file!) */ /* */ /****************************************************************************/ /****************************************************************************/ /* */ /* definition of exported global variables */ /* */ /****************************************************************************/ /****************************************************************************/ /* */ /* forward declarations of functions used before they are defined */ /* */ /****************************************************************************/ /* for all PrioMaster-nodes with remote copies, set exactly one to PrioMaster, the other copies to PrioBorder in order to establish the BorderNodeIF. this is done for one grid. */ /****************************************************************************/ /* ComputeNodeBorderPrios - SYNOPSIS: static int ComputeNodeBorderPrios (DDD_OBJ obj); PARAMETERS: . obj - DESCRIPTION: RETURN VALUE: int */ /****************************************************************************/ static int ComputeNodeBorderPrios (DDD::DDDContext& context, DDD_OBJ obj) { NODE *node = (NODE *)obj; int min_proc = context.procs(); /* minimum processor number will get Master-node, all others get Border-nodes */ for (auto&& [proc, prio] : DDD_InfoProcListRange(context, PARHDR(node))) { if (prio == PrioMaster && proc < min_proc) min_proc = proc; } if (min_proc == context.procs()) return(0); if (context.me() != min_proc) SETPRIO(context, node, PrioBorder); return 0; } /****************************************************************************/ /* ComputeVectorBorderPrios - SYNOPSIS: static int ComputeVectorBorderPrios (DDD_OBJ obj); PARAMETERS: . obj - DESCRIPTION: RETURN VALUE: int */ /****************************************************************************/ static int ComputeVectorBorderPrios (DDD::DDDContext& context, DDD_OBJ obj) { VECTOR *vector = (VECTOR *)obj; int min_proc = context.procs(); /* minimum processor number will get Master-node, all others get Border-nodes */ for (auto&& [proc, prio] : DDD_InfoProcListRange(context, PARHDR(vector))) { if (prio == PrioMaster && proc < min_proc) min_proc = proc; } if (min_proc == context.procs()) return(0); if (context.me() != min_proc) SETPRIO(context, vector, PrioBorder); return 0; } /****************************************************************************/ /* ComputeEdgeBorderPrios - SYNOPSIS: static int ComputeEdgeBorderPrios (DDD_OBJ obj); PARAMETERS: . obj - DESCRIPTION: RETURN VALUE: void */ /****************************************************************************/ static int ComputeEdgeBorderPrios (DDD::DDDContext& context, DDD_OBJ obj) { EDGE *edge = (EDGE *)obj; int min_proc = context.procs(); /* minimum processor number will get Master-node, all others get Border-nodes */ for (auto&& [proc, prio] : DDD_InfoProcListRange(context, PARHDR(edge))) { if (prio == PrioMaster && proc < min_proc) min_proc = proc; } if (min_proc == context.procs()) return(0); if (context.me() != min_proc) SETPRIO(context, edge, PrioBorder); return 0; } /****************************************************************************/ /* SetGhostObjectPriorities - SYNOPSIS: void SetGhostObjectPriorities (GRID *theGrid); PARAMETERS: . theGrid DESCRIPTION: RETURN VALUE: void */ /****************************************************************************/ void NS_DIM_PREFIX SetGhostObjectPriorities (GRID *theGrid) { ELEMENT *theElement,*theNeighbor,*SonList[MAX_SONS]; NODE *theNode; EDGE *theEdge; INT i,prio,hghost,vghost; auto& context = theGrid->dddContext(); const auto& me = context.me(); /* reset USED flag for objects of ghostelements */ for (theElement=PFIRSTELEMENT(theGrid); theElement!=NULL; theElement=SUCCE(theElement)) { SETUSED(theElement,0); SETTHEFLAG(theElement,0); for (i=0; idddContext(); const auto& dddctrl = ddd_ctrl(context); DDD_IFAExecLocal(context, dddctrl.BorderNodeSymmIF,GRID_ATTR(theGrid), ComputeNodeBorderPrios); /* TODO: distinguish two cases: 1. only nodevectors then setting of vector prios can be done in ComputeNodeBorderPrios without extra communiction 2. with other vectortypes (side and/or edgevectors) use ComputeVectorBorderPrios */ DDD_IFAExecLocal(context, dddctrl.BorderVectorSymmIF,GRID_ATTR(theGrid), ComputeVectorBorderPrios); DDD_IFAExecLocal(context, dddctrl.BorderEdgeSymmIF,GRID_ATTR(theGrid), ComputeEdgeBorderPrios); return(GM_OK); } /****************************************************************************/ /* SetGridBorderPriorities - SYNOPSIS: INT SetGridBorderPriorities (GRID *theGrid); PARAMETERS: . theGrid DESCRIPTION: RETURN VALUE: INT */ /****************************************************************************/ INT NS_DIM_PREFIX SetGridBorderPriorities (GRID *theGrid) { /* set border priorities on next higher level */ if (SetBorderPriorities(UPGRID(theGrid)) != GM_OK) return(GM_FATAL); return(GM_OK); } #endif dune-uggrid-2.11.0+dfsg/dune/uggrid/parallel/dddif/source.cc000066400000000000000000000076661513616443000236370ustar00rootroot00000000000000// SPDX-FileCopyrightText: Copyright © DUNE Project contributors, see file LICENSE.md in module root // SPDX-License-Identifier: LGPL-2.1-or-later // -*- tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- // vi: set et ts=4 sw=2 sts=2: /****************************************************************************/ /* */ /* File: source.c */ /* */ /* Purpose: standard source file template */ /* */ /* Author: Peter Bastian/Klaus Johannsen */ /* Institut fuer Computeranwendungen III */ /* Universitaet Stuttgart */ /* Pfaffenwaldring 27 */ /* 70550 Stuttgart */ /* email: peter@ica3.uni-stuttgart.de */ /* klaus@ica3.uni-stuttgart.de */ /* phone: 0049-(0)711-685-7003 */ /* fax : 0049-(0)711-685-7000 */ /* */ /* History: 29.01.92 begin, ug version 2.0 */ /* */ /* Remarks: */ /* */ /****************************************************************************/ /****************************************************************************/ /* */ /* include files */ /* system include files */ /* application include files */ /* */ /****************************************************************************/ /****************************************************************************/ /* */ /* defines in the following order */ /* */ /* compile time constants defining static data size (i.e. arrays) */ /* other constants */ /* macros */ /* */ /****************************************************************************/ /****************************************************************************/ /* */ /* data structures used in this source file (exported data structures are */ /* in the corresponding include file!) */ /* */ /****************************************************************************/ /****************************************************************************/ /* */ /* definition of exported global variables */ /* */ /****************************************************************************/ #include /****************************************************************************/ /* */ /* definition of variables global to this source file only (static!) */ /* */ /****************************************************************************/ /****************************************************************************/ /* */ /* forward declarations of functions used before they are defined */ /* */ /****************************************************************************/ /****************************************************************************/ /* */ /* Function: @ */ /* */ /* Purpose: */ /* */ /* Input: */ /* */ /* Output: */ /* */ /* */ /****************************************************************************/ dune-uggrid-2.11.0+dfsg/dune/uggrid/parallel/dddif/support.cc000066400000000000000000000267621513616443000240510ustar00rootroot00000000000000// SPDX-FileCopyrightText: Copyright © DUNE Project contributors, see file LICENSE.md in module root // SPDX-License-Identifier: LGPL-2.1-or-later // -*- tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- // vi: set et ts=4 sw=2 sts=2: /****************************************************************************/ /* */ /* File: reduct.c */ /* */ /* Purpose: standard parallel routines not supported by ddd */ /* reduction operations (GlobalSum, GlobalMax etc) */ /* */ /* Author: Klaus Birken */ /* Rechenzentrum Uni Stuttgart */ /* Universitaet Stuttgart */ /* Allmandring 30 */ /* 70550 Stuttgart */ /* internet: birken@rus.uni-stuttgart.de */ /* */ /* History: 940128 kb begin */ /* 960902 kb copied from fedemo, adapted */ /* */ /* Remarks: */ /* */ /****************************************************************************/ /****************************************************************************/ /* */ /* include files */ /* system include files */ /* application include files */ /* */ /****************************************************************************/ /* standard C library */ #include #include #include #include #include #ifdef ModelP # include # include #endif #include #include #include #include #include /* UG namespaces: */ USING_UG_NAMESPACES /* PPIF namespaces: */ using namespace PPIF; START_UGDIM_NAMESPACE /****************************************************************************/ /* */ /* routines */ /* */ /****************************************************************************/ /* some useful functions by Peter Bastian, from ugp/ug/ugcom.c */ #ifdef ModelP static_assert( std::is_same::value, "The implementation assumes that `int` and `INT` are the same type."); static_assert( std::is_same::value, "The implementation assumes that `double` and `DOUBLE` are the same type."); /****************************************************************************/ /*D UG_GlobalMaxINT - get maximum for INT value SYNOPSIS: INT UG_GlobalMaxINT (INT i) PARAMETERS: . i - calculate maximum for this value DESCRIPTION: This function calculates the maximum of i over all processors. RETURN VALUE: The maximum value of i over all processors. D*/ /****************************************************************************/ INT UG_GlobalMaxINT(const PPIF::PPIFContext& context, INT i) { MPI_Allreduce(MPI_IN_PLACE, &i, 1, MPI_INT, MPI_MAX, context.comm()); return i; } /****************************************************************************/ /*D UG_GlobalMinINT - get global minimum for INT value SYNOPSIS: INT UG_GlobalMaxINT (INT i) PARAMETERS: . i - calculate minimum for this value DESCRIPTION: This function calculates the minimum of i over all processors. RETURN VALUE: The minimum value of i over all processors D*/ /****************************************************************************/ INT UG_GlobalMinINT (const PPIF::PPIFContext& context, INT i) { MPI_Allreduce(MPI_IN_PLACE, &i, 1, MPI_INT, MPI_MIN, context.comm()); return i; } /****************************************************************************/ /*D UG_GlobalSumINT - get global sum for INT value SYNOPSIS: INT UG_GlobalSumINT (INT i) PARAMETERS: . i - calculate sum for this variable DESCRIPTION: This function calculates the sum of i over all processors. RETURN VALUE: The sum of i over all processors D*/ /****************************************************************************/ INT UG_GlobalSumINT (const PPIF::PPIFContext& context, INT x) { MPI_Allreduce(MPI_IN_PLACE, &x, 1, MPI_INT, MPI_SUM, context.comm()); return x; } /****************************************************************************/ /*D UG_GlobalMaxNINT - get maximum for n integer values SYNOPSIS: void UG_GlobalMaxNINT (INT n, INT *x) PARAMETERS: . n - number of elements in array x to be used . x - array of size n DESCRIPTION: This function calculates the maximum of x[i] over all processors for all i from 0 to n-1. x is overwritten with the maximum value. RETURN VALUE: none D*/ /****************************************************************************/ void UG_GlobalMaxNINT(const PPIF::PPIFContext& context, INT n, INT *x) { MPI_Allreduce(MPI_IN_PLACE, x, n, MPI_INT, MPI_MAX, context.comm()); } /****************************************************************************/ /*D UG_GlobalMinNINT - get minimum for n integer values SYNOPSIS: void UG_GlobalMinNINT (INT n, INT *x) PARAMETERS: . n - number of elements in array x to be used . x - array of size n DESCRIPTION: This function calculates the minimum of x[i] over all processors for all i from 0 to n-1. x is overwritten with the minimum value. RETURN VALUE: none D*/ /****************************************************************************/ void UG_GlobalMinNINT(const PPIF::PPIFContext& context, INT n, INT *x) { MPI_Allreduce(MPI_IN_PLACE, x, n, MPI_INT, MPI_MIN, context.comm()); } /****************************************************************************/ /*D UG_GlobalSumNINT - calculate global sum for n integer values SYNOPSIS: void UG_GlobalSumNINT (INT n, INT *x) PARAMETERS: . n - number of elements in array x to be used . x - array of size n DESCRIPTION: This function calculates the sum of x[i] over all processors for each i from 0 to n-1. x is overwritten with the result. RETURN VALUE: none D*/ /****************************************************************************/ void UG_GlobalSumNINT (const PPIF::PPIFContext& context, INT n, INT *xs) { MPI_Allreduce(MPI_IN_PLACE, xs, n, MPI_INT, MPI_SUM, context.comm()); } /****************************************************************************/ /*D UG_GlobalMaxDOUBLE - get global maximum for DOUBLE value SYNOPSIS: DOUBLE UG_GlobalMaxDOUBLE (DOUBLE x) PARAMETERS: . x - calculate maximum for this value DESCRIPTION: This function calculates the maximum of x over all processors. RETURN VALUE: The maximum value of x over all processors. D*/ /****************************************************************************/ DOUBLE UG_GlobalMaxDOUBLE (const PPIF::PPIFContext& context, DOUBLE x) { MPI_Allreduce(MPI_IN_PLACE, &x, 1, MPI_DOUBLE, MPI_MAX, context.comm()); return x; } /****************************************************************************/ /*D UG_GlobalMinDOUBLE - get global minimum for DOUBLE value SYNOPSIS: DOUBLE UG_GlobalMinDOUBLE (DOUBLE x) PARAMETERS: . x - calculate minimum for this value DESCRIPTION: This function calculates the minimum of x over all processors. RETURN VALUE: The minimum value of x over all processors. D*/ /****************************************************************************/ DOUBLE UG_GlobalMinDOUBLE (const PPIF::PPIFContext& context, DOUBLE x) { MPI_Allreduce(MPI_IN_PLACE, &x, 1, MPI_DOUBLE, MPI_MIN, context.comm()); return x; } /****************************************************************************/ /*D UG_GlobalSumDOUBLE - get global sum for DOUBLE value SYNOPSIS: DOUBLE UG_GlobalSumDOUBLE (DOUBLE i) PARAMETERS: . i - calculate sum for this variable DESCRIPTION: This function calculates the sum of i over all processors. RETURN VALUE: The sum of i over all processors D*/ /****************************************************************************/ DOUBLE UG_GlobalSumDOUBLE (const PPIF::PPIFContext& context, DOUBLE x) { MPI_Allreduce(MPI_IN_PLACE, &x, 1, MPI_DOUBLE, MPI_SUM, context.comm()); return x; } /****************************************************************************/ /*D UG_GlobalMaxNDOUBLE - get maximum over n integer values SYNOPSIS: void UG_GlobalMaxNDOUBLE (INT n, DOUBLE *x) PARAMETERS: . n - number of elements in array x to be used . x - array of size n DESCRIPTION: This function calculates the maximum of x[i] over all processors for all i from 0 to n-1. x is overwritten with the maximum value. RETURN VALUE: none D*/ /****************************************************************************/ void UG_GlobalMaxNDOUBLE (const PPIF::PPIFContext& context, INT n, DOUBLE *x) { MPI_Allreduce(MPI_IN_PLACE, x, n, MPI_DOUBLE, MPI_MAX, context.comm()); } /****************************************************************************/ /*D UG_GlobalMinNDOUBLE - get minimum over n integer values SYNOPSIS: void UG_GlobalMinNDOUBLE (INT n, DOUBLE *x) PARAMETERS: . n - number of elements in array x to be used . x - array of size n DESCRIPTION: This function calculates the minimum of x[i] over all processors for all i from 0 to n-1. x is overwritten with the minimum value. RETURN VALUE: none D*/ /****************************************************************************/ void UG_GlobalMinNDOUBLE (const PPIF::PPIFContext& context, INT n, DOUBLE *x) { MPI_Allreduce(MPI_IN_PLACE, x, n, MPI_DOUBLE, MPI_MIN, context.comm()); } /****************************************************************************/ /*D UG_GlobalSumNDOUBLE - calculate global sum for n DOUBLE values SYNOPSIS: void UG_GlobalSumNDOUBLE (INT n, DOUBLE *x) PARAMETERS: . n - number of elements in array x to be used . x - array of size n DESCRIPTION: This function calculates the sum of x[i] over all processors for each i from 0 to n-1. x is overwritten with the result. RETURN VALUE: none D*/ /****************************************************************************/ void UG_GlobalSumNDOUBLE (const PPIF::PPIFContext& context, INT n, DOUBLE *x) { MPI_Allreduce(MPI_IN_PLACE, x, n, MPI_DOUBLE, MPI_SUM, context.comm()); } #endif /* ModelP */ END_UGDIM_NAMESPACE dune-uggrid-2.11.0+dfsg/dune/uggrid/parallel/dddif/trans.cc000066400000000000000000000447221513616443000234600ustar00rootroot00000000000000// SPDX-FileCopyrightText: Copyright © DUNE Project contributors, see file LICENSE.md in module root // SPDX-License-Identifier: LGPL-2.1-or-later // -*- tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- // vi: set et ts=4 sw=2 sts=2: /****************************************************************************/ /* */ /* File: trans.c */ /* */ /* Purpose: create new grid distribution according to lb-marks of master */ /* elements. */ /* */ /* Author: Klaus Birken, Stefan Lang */ /* Institut fuer Computeranwendungen III */ /* Universitaet Stuttgart */ /* Pfaffenwaldring 27 */ /* 70569 Stuttgart */ /* email: ug@ica3.uni-stuttgart.de */ /* */ /* History: 961216 kb begin */ /* */ /* Remarks: */ /* */ /****************************************************************************/ #ifdef ModelP /****************************************************************************/ /* */ /* include files */ /* system include files */ /* application include files */ /* */ /****************************************************************************/ #include #include #include #include "parallel.h" #include #include #include #include #include #include #include #include #include #include /* UG namespaces: */ USING_UG_NAMESPACES /* PPIF namespace: */ using namespace PPIF; /****************************************************************************/ /* */ /* defines in the following order */ /* */ /* compile time constants defining static data size (i.e. arrays) */ /* other constants */ /* macros */ /* */ /****************************************************************************/ enum GhostCmds { GC_Keep, GC_ToMaster, GC_Delete }; #define XferElement(context, elem,dest,prio) \ { PRINTDEBUG(dddif,1,("%4d: XferElement(): XferCopy elem=" EID_FMTX " dest=%d prio=%d\n", \ me,EID_PRTX(elem), dest, prio)); \ XFERECOPYX(context, (elem), dest, prio, \ (OBJT(elem)==BEOBJ) ? \ BND_SIZE_TAG(TAG(elem)) : \ INNER_SIZE_TAG(TAG(elem))); } #ifdef DDD_PRIO_ENV #undef DDD_PrioritySet #endif /****************************************************************************/ /* */ /* data structures used in this source file (exported data structures are */ /* in the corresponding include file!) */ /* */ /****************************************************************************/ /****************************************************************************/ /* */ /* definition of exported global variables */ /* */ /****************************************************************************/ /****************************************************************************/ /* */ /* definition of variables global to this source file only (static!) */ /* */ /****************************************************************************/ /****************************************************************************/ /* */ /* forward declarations of functions used before they are defined */ /* */ /****************************************************************************/ /****************************************************************************/ /****************************************************************************/ /* Gather_ElemDest - SYNOPSIS: static int Gather_ElemDest (DDD_OBJ obj, void *data); PARAMETERS: . obj . data DESCRIPTION: RETURN VALUE: int */ /****************************************************************************/ static int Gather_ElemDest (DDD::DDDContext&, DDD_OBJ obj, void *data) { ELEMENT *theElement = (ELEMENT *)obj; *(DDD_PROC *)data = PARTITION(theElement); return 0; } /****************************************************************************/ /* Scatter_ElemDest - SYNOPSIS: static int Scatter_ElemDest (DDD_OBJ obj, void *data); PARAMETERS: . obj . data DESCRIPTION: RETURN VALUE: int */ /****************************************************************************/ static int Scatter_ElemDest (DDD::DDDContext&, DDD_OBJ obj, void *data) { ELEMENT *theElement = (ELEMENT *)obj; PARTITION(theElement) = *(DDD_PROC *)data; return 0; } /****************************************************************************/ /* UpdateGhostDests - SYNOPSIS: static int UpdateGhostDests (MULTIGRID *theMG); PARAMETERS: . theMG DESCRIPTION: RETURN VALUE: int */ /****************************************************************************/ static int UpdateGhostDests (MULTIGRID *theMG) { auto& context = theMG->dddContext(); const auto& dddctrl = ddd_ctrl(context); DDD_IFOneway(context, dddctrl.ElementIF, IF_FORWARD, sizeof(DDD_PROC), Gather_ElemDest, Scatter_ElemDest); DDD_IFOneway(context, dddctrl.ElementVIF, IF_FORWARD, sizeof(DDD_PROC), Gather_ElemDest, Scatter_ElemDest); return 0; } /****************************************************************************/ /****************************************************************************/ /* Gather_GhostCmd - SYNOPSIS: static int Gather_GhostCmd (DDD_OBJ obj, void *data, DDD_PROC proc, DDD_PRIO prio); PARAMETERS: . obj . data . proc . prio DESCRIPTION: RETURN VALUE: int */ /****************************************************************************/ static int Gather_GhostCmd (DDD::DDDContext&, DDD_OBJ obj, void *data, DDD_PROC proc, DDD_PRIO prio) { ELEMENT *theElement = (ELEMENT *)obj; INT j; /* TODO: not needed anymore. kb 9070108 */ if (PARTITION(theElement) == proc) { *((int *)data) = GC_ToMaster; return(0); } if (PARTITION(theElement) != proc) { *((int *)data) = GC_Delete; for(j=0; j 0) { if (GetAllSons(theElement,SonList) != 0) return(1); i = 0; while (i 0) { ASSERT(theFather != NULL); if (PARTITION(theFather) == proc) { *((int *)data) = GC_Keep; return (0); } } */ return (0); } return(1); } /****************************************************************************/ /* Scatter_VHGhostCmd - SYNOPSIS: static int Scatter_VHGhostCmd (DDD_OBJ obj, void *data, DDD_PROC proc, DDD_PRIO prio); PARAMETERS: . obj . data . proc . prio DESCRIPTION: RETURN VALUE: int */ /****************************************************************************/ static int Scatter_VHGhostCmd (DDD::DDDContext& context, DDD_OBJ obj, void *data, DDD_PROC proc, DDD_PRIO prio) { const auto& me = context.me(); ELEMENT *theElement = (ELEMENT *)obj; ELEMENT *SonList[MAX_SONS]; /* if element is needed after transfer here */ if ((*(int *)data) == GC_Keep) return(0); /* element becomes master copy */ if (PARTITION(theElement) == me) return(0); /* if a son resides as master keep element as vghost */ if (GetAllSons(theElement,SonList) != GM_OK) return(0); INT i = 0; while (idddContext(); const auto& dddctrl = ddd_ctrl(context); DDD_IFOnewayX(context, dddctrl.ElementVHIF, IF_FORWARD, sizeof(int), Gather_VHGhostCmd, Scatter_VHGhostCmd); return(0); } /****************************************************************************/ /* XferGridWithOverlap - send elements to other procs, keep overlapping region of one element, maintain correct priorities at interfaces. SYNOPSIS: static void XferGridWithOverlap (GRID *theGrid); PARAMETERS: . theGrid DESCRIPTION: This function sends elements to other procs, keeps overlapping region of one element and maintains correct priorities at interfaces. The destination procs have been computed by the RecursiveCoordinateBisection function and put into the elements' PARTITION-entries. RETURN VALUE: void */ /****************************************************************************/ static int XferGridWithOverlap (GRID *theGrid) { ELEMENT *theElement, *theFather, *theNeighbor; ELEMENT *SonList[MAX_SONS]; INT i,j,overlap_elem,part; INT migrated = 0; DDD::DDDContext& context = theGrid->dddContext(); const auto& me = context.me(); for(theElement=FIRSTELEMENT(theGrid); theElement!=NULL; theElement=SUCCE(theElement)) { /* goal processor */ part = PARTITION(theElement); /* create Master copy */ XferElement(context, theElement, part, PrioMaster); #ifdef STAT_OUT /* count elems */ if (part != me) migrated++; #endif } /* create grid overlap */ for(theElement=FIRSTELEMENT(theGrid); theElement!=NULL; theElement=SUCCE(theElement)) { overlap_elem = 0; /* create 1-overlapping of horizontal elements */ for(j=0; j 0) { if (GetAllSons(theElement,SonList) != 0) assert(0); i = 0; while (i 0) { /* element is needed, set new prio */ switch (overlap_elem) { case (1) : SETEPRIO(context, theElement,PrioHGhost); break; case (2) : SETEPRIO(context, theElement,PrioVGhost); break; case (3) : SETEPRIO(context, theElement,PrioVGhost); break; default : assert(0); } } else { /* element isn't needed */ PRINTDEBUG(dddif,2,("%d: XferGridWithOverlap(): XferDel elem=%d to p=%d prio=%d\n", me,EGID(theElement),PARTITION(theElement),PrioHGhost)); XFEREDELETE(context, theElement); } } } return(migrated); } /****************************************************************************/ /****************************************************************************/ /* InheritPartitionBottomTop - SYNOPSIS: static void InheritPartitionBottomTop (ELEMENT *e); PARAMETERS: . e DESCRIPTION: RETURN VALUE: void */ /****************************************************************************/ static void InheritPartitionBottomTop (ELEMENT *e) { int i; ELEMENT *SonList[MAX_SONS]; if (GetSons(e,SonList) != GM_OK) assert(0); for(i=0; idddContext(), HSET_XFER); /* start physical transfer */ DDD_XferBegin(theMG->dddContext()); { /* send 'commands' to ghosts in old partitioning */ ComputeGhostCmds(theMG); /* send all grids */ for (INT g=0; g<=TOPLEVEL(theMG); g++) { GRID *theGrid = GRID_ON_LEVEL(theMG,g); if (NT(theGrid)>0) { #ifdef STAT_OUT migrated += XferGridWithOverlap(theGrid); #else XferGridWithOverlap(theGrid); #endif } } } DDD_XferEnd(theMG->dddContext()); #ifdef STAT_OUT trans_end = CURRENT_TIME; #endif /* set priorities of border nodes */ /* TODO this is an extra communication. eventually integrate this with grid distribution phase. */ ConstructConsistentMultiGrid(theMG); /* the grid has changed at least on one processor, thus reset MGSTATUS on all processors */ RESETMGSTATUS(theMG); #ifdef STAT_OUT cons_end = CURRENT_TIME; /* sum up moved elements */ migrated = UG_GlobalSumINT(theMG->ppifContext(), migrated); UserWriteF("MIGRATION: migrated=%d t_migrate=%.2f t_cons=%.2f\n", migrated,trans_end-trans_begin,cons_end-trans_end); #endif #ifdef Debug if (0) DDD_ConsCheck(theMG->dddContext()); #endif return 0; } /****************************************************************************/ /* TransferGrid - SYNOPSIS: int TransferGrid (MULTIGRID *theMG); PARAMETERS: . theMG DESCRIPTION: RETURN VALUE: int */ /****************************************************************************/ int NS_DIM_PREFIX TransferGrid (MULTIGRID *theMG) { return TransferGridFromLevel(theMG,0); } /****************************************************************************/ #endif /* ModelP */ dune-uggrid-2.11.0+dfsg/dune/uggrid/parallel/ppif/000077500000000000000000000000001513616443000216755ustar00rootroot00000000000000dune-uggrid-2.11.0+dfsg/dune/uggrid/parallel/ppif/CMakeLists.txt000066400000000000000000000006171513616443000244410ustar00rootroot00000000000000# SPDX-FileCopyrightText: Copyright © DUNE Project contributors, see file LICENSE.md in module root # SPDX-License-Identifier: LGPL-2.1-or-later if(UG_ENABLE_PARALLEL) target_sources(duneuggrid PRIVATE ppif.cc) endif() target_sources(duneuggrid PRIVATE ppifcontext.cc) install(FILES ppif.h ppifcontext.hh ppiftypes.hh DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}/dune/uggrid/parallel/ppif) dune-uggrid-2.11.0+dfsg/dune/uggrid/parallel/ppif/ppif.cc000066400000000000000000000374261513616443000231560ustar00rootroot00000000000000// SPDX-FileCopyrightText: Copyright © DUNE Project contributors, see file LICENSE.md in module root // SPDX-License-Identifier: LGPL-2.1-or-later // -*- tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- // vi: set et ts=4 sw=2 sts=2: /****************************************************************************/ /* */ /* File: mpi-ppif.c */ /* */ /* Purpose: parallel processor interface */ /* Provides a portable interface to message passing MIMD */ /* architectures. PPIF is divided into three parts: */ /* */ /* (1) Administration */ /* (2) Communication */ /* (3) Miscellaneous */ /* */ /* The interface assumes that the parallel machine has */ /* the following properties: */ /* */ /* (1) it is physically connected at least as a 2 or 3 dim. array*/ /* (2) it has a fast virtual channel communication mechanism */ /* (3) it has an asynchronous communication mechanism */ /* */ /* MPI Implementation */ /* */ /* Author: Jens Boenisch */ /* Rechenzentrum Uni Stuttgart */ /* Universitaet Stuttgart */ /* Allmandring 3a */ /* 7000 Stuttgart 80 */ /* internet: boenisch@rus.uni-stuttgart.de */ /* */ /* History: 17 Aug 1992, begin */ /* 18 Feb 1993, Indigo version */ /* 02 Jun 1993, Paragon OSF/1 version */ /* 14 Sep 1995, MPI version */ /* 29 Jan 2003, pV3 concentrator support */ /* */ /* Remarks: */ /* */ /****************************************************************************/ /****************************************************************************/ /* */ /* include files */ /* system include files */ /* application include files */ /* */ /****************************************************************************/ /* standard C library */ #include #include #include #include #include #include #include #include "ppif.h" #include "ppifcontext.hh" using namespace PPIF; /****************************************************************************/ /* */ /* defines in the following order */ /* */ /* compile time constants defining static data size (i.e. arrays) */ /* other constants */ /* macros */ /* */ /****************************************************************************/ #define MAXT 15 /* maximum number of downtree nodes max */ /* log2(P) */ #define ID_TREE 101 /* channel id: tree */ #define PPIF_SUCCESS 0 /* Return value for success */ #define PPIF_FAILURE 1 /* Return value for failure */ /****************************************************************************/ /* */ /* data structures */ /* */ /****************************************************************************/ namespace PPIF { struct VChannel { int p; int chanid; }; struct Msg { MPI_Request req; }; } /* namespace PPIF */ /****************************************************************************/ /* */ /* definition of static variables */ /* */ /****************************************************************************/ /****************************************************************************/ /* */ /* definition of exported global variables */ /* */ /****************************************************************************/ /* id's */ int PPIF::me; /* my processor id */ int PPIF::master; /* id of master processor */ int PPIF::procs; /* number of processors in the network */ /****************************************************************************/ /* */ /* routines for handling virtual channels */ /* */ /****************************************************************************/ static VChannelPtr NewVChan (int p, int id) { VChannelPtr myChan = new PPIF::VChannel; myChan->p = p; myChan->chanid = id; return myChan; } static void DeleteVChan (VChannelPtr myChan) { delete myChan; } static std::shared_ptr ppifContext_; void PPIF::ppifContext(const std::shared_ptr& context) { ppifContext_ = context; me = context->me(); master = context->master(); procs = context->procs(); } void PPIF::ppifContext(std::nullptr_t) { ppifContext_ = nullptr; me = 0; master = 0; procs = 1; } const std::shared_ptr& PPIF::ppifContext() { return ppifContext_; } /****************************************************************************/ /* */ /* Function: InitPPIF */ /* */ /* Purpose: initialize parallel processor interface */ /* set exported variables, allocate tree communication structure */ /* */ /* Input: void */ /* */ /* Output: int 0: ok */ /* int!=0: error */ /* */ /****************************************************************************/ /* Factor N into two integers that are as close together as possible */ static void Factor (int N, int *pn, int *pm) { int n = (int)ceil (sqrt ((double) N)); int m = (int)floor (sqrt ((double) N)); while (n*m != N) { if (n*m < N) n++; else m--; } *pn = n; *pm = m; } void PPIF::InitPPIF(PPIFContext& context) { const auto me = context.me(); const auto procs = context.procs(); context.dims_[2] = 1; Factor(procs, &context.dims_[0], &context.dims_[1]); /* tree configuration */ auto& degree = context.degree_; auto& uptree = context.uptree_; auto& downtree = context.downtree_; degree = 0; const int sonl = 2*me + 1; const int sonr = 2*me + 2; if (sonl0) { if (! uptree) /* InitPPIF is being called for the first time */ uptree = NewVChan((me-1)/2,ID_TREE); } else { uptree = NULL; } auto& slvcnt = context.slvcnt_; int succ=1; for(int i=0; ip, ID_TREE, context.comm(), MPI_STATUS_IGNORE); succ += slvcnt[i]; } if (me>0) { MPI_Send ((void *) &succ, (int) sizeof(int), MPI_BYTE, (int)(me-1)/2, ID_TREE, context.comm()); } } int PPIF::InitPPIF (int *, char ***) { auto context = ppifContext(); if (not context) context = std::make_shared(); ppifContext(context); return PPIF_SUCCESS; } void PPIF::ExitPPIF(PPIF::PPIFContext& context) { /* Deallocate tree structure */ DeleteVChan(context.uptree_); context.uptree_ = nullptr; /* I currently think that only the first two entries of downtree can contain * valid entries, but I am not entirely sure. */ DeleteVChan(context.downtree_[0]); DeleteVChan(context.downtree_[1]); context.downtree_[0] = context.downtree_[1] = nullptr; } int PPIF::ExitPPIF () { if (ppifContext()) { ppifContext(nullptr); } return PPIF_SUCCESS; } /****************************************************************************/ /* */ /* Tree oriented functions */ /* */ /****************************************************************************/ int PPIF::Broadcast (const PPIFContext& context, void *data, int size) { if (MPI_SUCCESS != MPI_Bcast (data, size, MPI_BYTE, context.master(), context.comm()) ) return (PPIF_FAILURE); return (PPIF_SUCCESS); } int PPIF::Concentrate (const PPIFContext& context, void *data, int size) { if (not context.isMaster()) if (SendSync (context, context.uptree(), data, size) < 0) return (PPIF_FAILURE); return (PPIF_SUCCESS); } int PPIF::GetConcentrate(const PPIFContext& context, int slave, void *data, int size) { if (slave < context.degree()) if (RecvSync (context, context.downtree()[slave], data, size) < 0) return (PPIF_FAILURE); return (PPIF_SUCCESS); } int PPIF::Spread(const PPIFContext& context, int slave, void *data, int size) { if (slave < context.degree()) if (SendSync(context, context.downtree()[slave], data, size) < 0) return (PPIF_FAILURE); return (PPIF_SUCCESS); } int PPIF::GetSpread(const PPIFContext& context, void *data, int size) { if (not context.isMaster()) if (RecvSync(context, context.uptree(), data, size) < 0) return (PPIF_FAILURE); return (PPIF_SUCCESS); } int PPIF::Synchronize(const PPIFContext& context) { if (MPI_SUCCESS != MPI_Barrier (context.comm()) ) return (PPIF_FAILURE); return (PPIF_SUCCESS); } /****************************************************************************/ /* */ /* Synchronous communication */ /* */ /****************************************************************************/ VChannelPtr PPIF::ConnSync(const PPIFContext&, int p, int id) { return NewVChan(p, id); } int PPIF::DiscSync(const PPIFContext&, VChannelPtr v) { DeleteVChan(v); return (0); } int PPIF::SendSync(const PPIFContext& context, VChannelPtr v, void *data, int size) { if (MPI_SUCCESS == MPI_Ssend (data, size, MPI_BYTE, v->p, v->chanid, context.comm()) ) return (size); else return (-1); } int PPIF::RecvSync(const PPIFContext& context, VChannelPtr v, void *data, int size) { int count = -1; MPI_Status status; if (MPI_SUCCESS == MPI_Recv (data, size, MPI_BYTE, v->p, v->chanid, context.comm(), &status) ) MPI_Get_count (&status, MPI_BYTE, &count); return (count); } /****************************************************************************/ /* */ /* Asynchronous communication */ /* */ /****************************************************************************/ VChannelPtr PPIF::ConnASync(const PPIFContext&, int p, int id) { return NewVChan(p, id); } int PPIF::InfoAConn(const PPIFContext&, const VChannelPtr v) { return (v ? 1 : -1); } int PPIF::DiscASync(const PPIFContext&, VChannelPtr v) { DeleteVChan (v); return (PPIF_SUCCESS); } int PPIF::InfoADisc(const PPIFContext&, const VChannelPtr v) { return (true); } msgid PPIF::SendASync(const PPIFContext& context, VChannelPtr v, void *data, int size, int *error) { msgid m = new PPIF::Msg; if (m) { if (MPI_SUCCESS == MPI_Isend (data, size, MPI_BYTE, v->p, v->chanid, context.comm(), &m->req) ) { *error = false; return m; } } *error = true; return NULL; } msgid PPIF::RecvASync(const PPIFContext& context, VChannelPtr v, void *data, int size, int *error) { msgid m = new PPIF::Msg; if (m) { if (MPI_SUCCESS == MPI_Irecv (data, size, MPI_BYTE, v->p, v->chanid, context.comm(), &m->req) ) { *error = false; return m; } } *error = true; return (NULL); } int PPIF::InfoASend(const PPIFContext&, VChannelPtr v, msgid m) { int complete; if (m) { if (MPI_SUCCESS == MPI_Test (&m->req, &complete, MPI_STATUS_IGNORE) ) { if (complete) delete m; return (complete); /* complete is true for completed send, false otherwise */ } } return (-1); /* return -1 for FAILURE */ } int PPIF::InfoARecv(const PPIFContext&, VChannelPtr v, msgid m) { int complete; if (m) { if (MPI_SUCCESS == MPI_Test (&m->req, &complete, MPI_STATUS_IGNORE) ) { if (complete) delete m; return (complete); /* complete is true for completed receive, false otherwise */ } } return (-1); /* return -1 for FAILURE */ } dune-uggrid-2.11.0+dfsg/dune/uggrid/parallel/ppif/ppif.h000066400000000000000000000141361513616443000230110ustar00rootroot00000000000000// -*- tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- // vi: set et ts=4 sw=2 sts=2: // SPDX-FileCopyrightInfo: Copyright © DUNE Project contributors, see file LICENSE.md in module root // SPDX-License-Identifier: LGPL-2.1-or-later /****************************************************************************/ /* */ /* File: ppif.h */ /* */ /* Purpose: header file for parallel processor interface */ /* */ /* Author: Peter Bastian / Klaus Birken */ /* */ /* History: 17 Aug 1992 begin */ /* 14 Sep 1993 pass argc, argv from main to InitPPIF */ /* 16 Sep 1993 async send/recv return msgid now */ /* 951106 kb changed parameters for InitPPIF() */ /* 970213 kb added C++ class interface */ /* */ /* Remarks: */ /* */ /****************************************************************************/ /****************************************************************************/ /* */ /* auto include mechanism and other include files */ /* */ /****************************************************************************/ #ifndef __PPIF__ #define __PPIF__ #include #include /****************************************************************************/ /* */ /* data structures exported by the corresponding source file */ /* */ /****************************************************************************/ using VChannelPtr = PPIF::VChannelPtr; using msgid = PPIF::msgid; namespace PPIF { enum directions {north,east,south,west,up,down}; #define PPIF_SUCCESS 0 /* Return value for success */ #define PPIF_FAILURE 1 /* Return value for failure */ /****************************************************************************/ /* */ /* definition of exported global variables */ /* */ /****************************************************************************/ /* id's */ extern int me; /* my processor id */ extern int master; /* id of master processor */ extern int procs; /* number of processors in the network */ /****************************************************************************/ /* */ /* function declarations */ /* */ /****************************************************************************/ /** * set context used by PPIF. * * This also updates the legacy global variables `me`, `master`, and `procs`. * * \warn context should be managed by the caller */ void ppifContext(const std::shared_ptr& context); /** * reset context used by PPIF. */ void ppifContext(std::nullptr_t); /** * get context used by PPIF * * \warn context should be managed by the called */ const std::shared_ptr& ppifContext(); /* initialization & shutdown */ void InitPPIF (PPIFContext& context); int InitPPIF (int *argcp, char ***argvp); void ExitPPIF (PPIFContext& context); int ExitPPIF (void); /* tree oriented functions */ int Broadcast (const PPIFContext& context, void* data, int size); int Concentrate (const PPIFContext& context, void *data, int size); int GetConcentrate (const PPIFContext& context, int slave, void *data, int size); int Spread (const PPIFContext& context, int slave, void *data, int size); int GetSpread (const PPIFContext& context, void *data, int size); int Synchronize (const PPIFContext& context); /* synchronous communication */ VChannelPtr ConnSync (const PPIFContext& context, int p, int id); int DiscSync (const PPIFContext& context, VChannelPtr vc); int SendSync (const PPIFContext& context, VChannelPtr vc, void *data, int size); int RecvSync (const PPIFContext& context, VChannelPtr vc, void *data, int size); /* asynchronous communication */ VChannelPtr ConnASync (const PPIFContext& context, int p, int id); int DiscASync (const PPIFContext& context, VChannelPtr vc); msgid SendASync (const PPIFContext& context, VChannelPtr vc, void *data, int size, int *error); msgid RecvASync (const PPIFContext& context, VChannelPtr vc, void *data, int size, int *error); int InfoAConn (const PPIFContext& context, VChannelPtr vc); int InfoADisc (const PPIFContext& context, VChannelPtr vc); int InfoASend (const PPIFContext& context, VChannelPtr vc, msgid m); int InfoARecv (const PPIFContext& context, VChannelPtr vc, msgid m); } // end namespace PPIF /****************************************************************************/ #endif dune-uggrid-2.11.0+dfsg/dune/uggrid/parallel/ppif/ppifcontext.cc000066400000000000000000000013451513616443000245520ustar00rootroot00000000000000// SPDX-FileCopyrightText: Copyright © DUNE Project contributors, see file LICENSE.md in module root // SPDX-License-Identifier: LGPL-2.1-or-later #include "config.h" #include "ppifcontext.hh" namespace PPIF { #if ModelP PPIFContext ::PPIFContext() : PPIFContext(MPI_COMM_WORLD) { /* Nothing */ } #else PPIFContext ::PPIFContext() { /* Nothing */ } #endif PPIFContext ::~PPIFContext() { #if ModelP ExitPPIF(*this); int finalized; MPI_Finalized(&finalized); if (not finalized) MPI_Comm_free(&comm_); #endif } #if ModelP PPIFContext ::PPIFContext(const MPI_Comm& comm) { MPI_Comm_dup(comm, &comm_); MPI_Comm_rank(comm_, &me_); MPI_Comm_size(comm_, &procs_); InitPPIF(*this); } #endif } /* namespace PPIF */ dune-uggrid-2.11.0+dfsg/dune/uggrid/parallel/ppif/ppifcontext.hh000066400000000000000000000047231513616443000245670ustar00rootroot00000000000000// SPDX-FileCopyrightText: Copyright © DUNE Project contributors, see file LICENSE.md in module root // SPDX-License-Identifier: LGPL-2.1-or-later #ifndef DUNE_UGGRID_PARALLEL_PPIF_PPIFCONTEXT_HH #define DUNE_UGGRID_PARALLEL_PPIF_PPIFCONTEXT_HH 1 #include #include #if ModelP # include #endif #include namespace PPIF { /** * context object for low-level parallel communication */ class PPIFContext { public: /** * constructor. * * By default `MPI_COMM_WORLD` is used for communication. * * \note This is a MPI collective operation (invokes `MPI_Comm_dup`) */ PPIFContext(); /** * destructor * * \note This is a MPI collective operation (invokes `MPI_Comm_free`) */ ~PPIFContext(); /** * our rank; in the interval [0, procs) */ int me() const { return me_; } /** * rank of the master process (usually 0) */ int master() const { return master_; } /** * returns `true` if local process is master */ bool isMaster() const { return me() == master(); } /** * number of processes */ int procs() const { return procs_; } protected: int me_ = 0; int master_ = 0; int procs_ = 1; #if ModelP || DOXYGEN public: /** * maximum number of downtree nodes max * log2(P) */ static const int MAXT = 15; /** * constructor. * * \note This is a MPI collective operation (invokes `MPI_Comm_dup`) */ explicit PPIFContext(const MPI_Comm& comm); /** * MPI communicator */ MPI_Comm comm() const { return comm_; } int dimX() const { return dims_[0]; } int dimY() const { return dims_[1]; } int dimZ() const { return dims_[2]; } /** * degree of downtree nodes */ int degree() const { return degree_; } /** * channel uptree */ VChannelPtr uptree() const { return uptree_; } /** * channels downtree (may be empty) */ const std::array& downtree() const { return downtree_; } /** * number of processors in subtree */ const std::array& slvcnt() const { return slvcnt_; } protected: MPI_Comm comm_ = MPI_COMM_NULL; std::array dims_ = {{1, 1, 1}}; int degree_ = 0; VChannelPtr uptree_ = nullptr; std::array downtree_ = {}; std::array slvcnt_ = {}; friend void InitPPIF(PPIFContext&); friend void ExitPPIF(PPIFContext&); #endif }; } /* namespace PPIF */ #endif dune-uggrid-2.11.0+dfsg/dune/uggrid/parallel/ppif/ppiftypes.hh000066400000000000000000000012621513616443000242420ustar00rootroot00000000000000// SPDX-FileCopyrightText: Copyright © DUNE Project contributors, see file LICENSE.md in module root // SPDX-License-Identifier: LGPL-2.1-or-later #ifndef DUNE_UGGRID_PARALLEL_PPIF_PPIFTYPES_HH #define DUNE_UGGRID_PARALLEL_PPIF_PPIFTYPES_HH 1 #include namespace PPIF { /** * opaque type for communication channels */ struct VChannel; using VChannelPtr = VChannel*; /** * opaque type for messages */ struct Msg; using msgid = Msg*; constexpr static msgid NO_MSGID = nullptr; /** * indicate support for context objects in PPIF */ #ifndef DUNE_UGGRID_HAVE_PPIFCONTEXT # define DUNE_UGGRID_HAVE_PPIFCONTEXT 1 #endif class PPIFContext; } /* namespace PPIF */ #endif dune-uggrid-2.11.0+dfsg/dune/uggrid/ugdevices.cc000066400000000000000000000251021513616443000214300ustar00rootroot00000000000000// SPDX-FileCopyrightText: Copyright © DUNE Project contributors, see file LICENSE.md in module root // SPDX-License-Identifier: LGPL-2.1-or-later // -*- tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- // vi: set et ts=4 sw=2 sts=2: /****************************************************************************/ /* */ /* File: ugdevices.c */ /* */ /* Purpose: Initialization and hardware independent part of devices */ /* */ /* Author: Peter Bastian/Klaus Johannsen */ /* Institut fuer Computeranwendungen III */ /* Universitaet Stuttgart */ /* Pfaffenwaldring 27 */ /* 70569 Stuttgart */ /* email: ug@ica3.uni-stuttgart.de */ /* */ /* History: 29.01.92 begin, ug version 2.0 */ /* */ /* Remarks: was "devices.c" in earlier versions of UG */ /* */ /****************************************************************************/ /****************************************************************************/ /* */ /* include files */ /* system include files */ /* application include files */ /* */ /****************************************************************************/ #include #include #include #include #include #include /* low module */ #include #include #include #include #include #include /* dev module */ #include /* dddif module */ #ifdef ModelP #include using namespace PPIF; #endif USING_UG_NAMESPACE /****************************************************************************/ /* */ /* definition of variables global to this source file only (static!) */ /* */ /****************************************************************************/ /* the mute level is set by the MuteCommand and used for output control. convention: 0 is default, <0 produces less output, >0 produces more output. The default is -1001, which equals total silence. */ static INT mutelevel=-1001; static FILE *logFile=NULL; /* log file pointer */ /****************************************************************************/ /*D OpenLogFile - open a log file SYNOPSIS: INT OpenLogFile (const char *name, int rename); PARAMETERS: . name - . rename - DESCRIPTION: This function opens a log file where all output to 'UserWrite', 'UserWriteF' and 'PrintErrorMessage' is protocoled. RETURN VALUE: INT .n 0 if operation ok .n 1 if a file is already open .n 2 if file open failed. D*/ /****************************************************************************/ INT NS_PREFIX OpenLogFile (const char *name, int rename) { char logpath[256]; if (logFile!=NULL) return(1); /* get path to logfile directory */ logFile = FileOpenUsingSearchPath_r(name,"w",logpath,rename); if (logFile==NULL) return(2); return(0); } /****************************************************************************/ /*D CloseLogFile - Close log file SYNOPSIS: INT CloseLogFile (void); PARAMETERS: . void DESCRIPTION: This function closes the log file. RETURN VALUE: INT .n 0 if operation ok .n 1 if an error occurred. D*/ /****************************************************************************/ INT NS_PREFIX CloseLogFile (void) { if (logFile==NULL) return(1); fclose(logFile); logFile = NULL; return(0); } /****************************************************************************/ /*D SetLogFile - set log file ptr SYNOPSIS: INT SetLogFile (FILE *file); PARAMETERS: . file - DESCRIPTION: This function et log file ptr. RETURN VALUE: INT .n 0 if operation ok .n 1 if an error occurred. D*/ /****************************************************************************/ INT NS_PREFIX SetLogFile (FILE *file) { logFile = file; return(0); } /****************************************************************************/ /*D WriteLogFile - Write to (open) log file SYNOPSIS: INT WriteLogFile (const char *text); PARAMETERS: . text - DESCRIPTION: This function writes to (open) log file. RETURN VALUE: INT .n 0 if operation ok .n 1 if error occurred. D*/ /****************************************************************************/ INT NS_PREFIX WriteLogFile (const char *text) { if (logFile==NULL) return(1); if ( fputs(text,logFile) < 0 ) { UserWrite( "ERROR in writing logfile\n" ); #ifdef Debug printf( "ERROR in writing logfile\n" ); fflush(logFile); #endif return 1; } #ifdef Debug fflush(logFile); #endif return(0); } /****************************************************************************/ /*D UserWrite - Write a string to shell window SYNOPSIS: void UserWrite (const char *s); PARAMETERS: . s - DESCRIPTION: This function writes a string to shell window with log file mechanism. RETURN VALUE: void D*/ /****************************************************************************/ void NS_PREFIX UserWrite (const char *s) { if (mutelevel>-1000) printf("%s", s); if (logFile!=NULL) { if ( fputs(s,logFile) < 0 ) { UserWrite( "ERROR in writing logfile\n" ); #ifdef Debug printf( "ERROR in writing logfile\n" ); fflush(logFile); #endif } #ifdef Debug fflush(logFile); #endif } } /****************************************************************************/ /*D UserWriteF - write a formatted string to shell window SYNOPSIS: int UserWriteF (const char *format, ...); PARAMETERS: . format - . ... - list of arguments for format string DESCRIPTION: This function writes a formatted string to shell window with log file mechanism. RETURN VALUE: int .n 0 if ok .n 1 if error occurred. D*/ /****************************************************************************/ #define VAR_ARG_BUFLEN 512 int NS_PREFIX UserWriteF (const char *format, ...) { char buffer[VAR_ARG_BUFLEN]; va_list args; /* initialize args */ va_start(args,format); #ifndef NDEBUG int count = vsnprintf(buffer,VAR_ARG_BUFLEN,format,args); assert(count-1000) printf("%s", buffer); if (logFile!=NULL) { if ( fputs(buffer,logFile) < 0 ) { UserWrite( "ERROR in writing logfile\n" ); #ifdef Debug printf( "ERROR in writing logfile\n" ); fflush(logFile); #endif va_end(args); return 1; } #ifdef Debug fflush(logFile); #endif } /* garbage collection */ va_end(args); return (0); } /****************************************************************************/ /** \brief Formatted error output (also to log file) * * @param type - 'W','E','F' * @param procName - name of procedure where error occurred * @param text - additional explanation * * This function formats error output (also to log file). * * \sa PrintErrorMessageF */ /****************************************************************************/ void NS_PREFIX PrintErrorMessage (char type, const char *procName, const char *text) { char classText[32]; INT oldmutelevel; oldmutelevel = mutelevel; switch (type) { case 'W' : strcpy(classText,"WARNING"); break; case 'E' : strcpy(classText,"ERROR"); mutelevel = 0; break; case 'F' : strcpy(classText,"FATAL"); mutelevel = 0; break; default : strcpy(classText,"USERERROR"); break; } UserWriteF("%s in %.20s: %.200s\n",classText,procName,text); mutelevel = oldmutelevel; } /****************************************************************************/ /*D PrintErrorMessageF - Formatted error output with fotmatted message (also to log file) SYNOPSIS: void PrintErrorMessageF (char type, const char *procName, const char *format, ...); PARAMETERS: * @param type - 'W','E','F' * @param procName - name of procedure where error occurred * @param format - additional formatted explanation (like printf) DESCRIPTION: This function formats error output (also to log file). After expanding message 'PrintErrorMessage' is called. RETURN VALUE: void * \sa PrintErrorMessage D*/ /****************************************************************************/ void NS_PREFIX PrintErrorMessageF (char type, const char *procName, const char *format, ...) { char buffer[256]; va_list args; /* initialize args */ va_start(args,format); vsnprintf(buffer,256,format,args); PrintErrorMessage(type,procName,buffer); /* garbage collection */ va_end(args); } /****************************************************************************/ /*D InitDevices - Initialize all devices at startup SYNOPSIS: INT InitDevices(); DESCRIPTION: This function initializes all devices at startup. It must be extended when an output device is added. RETURN VALUE: INT .n 0 if ok .n 1 if some error occurred. D*/ /****************************************************************************/ INT NS_PREFIX InitDevices() { return 0; } INT NS_PREFIX ExitDevices (void) { return(0); /* no error */ } dune-uggrid-2.11.0+dfsg/dune/uggrid/ugdevices.h000066400000000000000000000053651513616443000213030ustar00rootroot00000000000000// -*- tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- // vi: set et ts=4 sw=2 sts=2: // SPDX-FileCopyrightInfo: Copyright © DUNE Project contributors, see file LICENSE.md in module root // SPDX-License-Identifier: LGPL-2.1-or-later /****************************************************************************/ /* */ /* File: ugdevices.h */ /* */ /* Purpose: implements a simple but portable graphical user interface */ /* */ /* Author: Peter Bastian */ /* Institut fuer Computeranwendungen III */ /* Universitaet Stuttgart */ /* Pfaffenwaldring 27 */ /* 70569 Stuttgart */ /* email: ug@ica3.uni-stuttgart.de */ /* */ /* History: 14.06.93 begin, ug version ug21Xmas3d */ /* 16.12.94 restructured for ug version 3.0 */ /* */ /* Remarks: was "devices.h" in earlier version of UG */ /* */ /****************************************************************************/ #ifndef __DEVICESH__ #define __DEVICESH__ #include #include #include #include START_UG_NAMESPACE /* initialization and clean up */ INT InitDevices(); INT ExitDevices (void); /* text output to shell with log file mechanism */ void UserWrite (const char *s); int UserWriteF (const char *format, ...); void PrintErrorMessage (char type, const char *procName, const char *text); void PrintErrorMessageF (char type, const char *procName, const char *format, ...); INT OpenLogFile (const char *name, int rename); INT CloseLogFile (void); INT SetLogFile (FILE *file); INT WriteLogFile (const char *text); END_UG_NAMESPACE #endif dune-uggrid-2.11.0+dfsg/mainpage.doc000066400000000000000000000257671513616443000172200ustar00rootroot00000000000000// SPDX-FileCopyrightInfo: Copyright © DUNE Project contributors, see file LICENSE.md in module root // SPDX-License-Identifier: LGPL-2.1-or-later /*! \mainpage UG-4.0 Reference Manual * * * \section intro Introduction * * This is the introduction. * * \section mods Modules *
    • \ref ug
      • \ref dev
      • \ref dom
        • \ref std
      • \ref gm
      • \ref graphics
      • \ref low
      • \ref np
      • \ref ui
    \section chapter2 Overview of UGs data structures This page will give an overview of the data types defined in UG that are used to represent meshes and geometries. All data types discussed here are defined in the header file gm.h of the grid manager module. A description of the individual data types can be found in separate pages for each data type. UGs data structure is very flexible and covers two- and threedimensional elements and a general sparse matrix structure. You can have different numbers of degrees of freedom in nodes, edges, sides and elements of a three-dimensional mesh. Therefore the data structure can be used e.g. also for non-conforming or mixed finite element discretizations. To structure the data you can group vectors by using BLOCKVECTORs; this yields blockmatrices too. UGs refinement module can refine and coarsen a given mesh structure. In order to do that it needs a complete description of the geometry of the domain. For full flexibility, the geometry is defined by patches, which are mappings from a d-1 dimensional parameter space to d dimensional euclidean space. If we imagine a three-dimensional mesh we can identify a hierarchy of geometrical objects like `elements, sides, edges` and `nodes`. By element we mean just a simple geometric shape like a triangle, a quadrilateral, a tetrahedron or a hexahedron. In our notation the element does not include the number of degrees of freedom or the definition of the shape functions as it is common in the Finite Element context. A side is meant to be a face of an element, that is a d-1 dimensional object if we have a mesh in d dimensions (d=2,3). An edge is a connection of two nodes, i.~e. a one-dimensional object and a node is a point in space (as far as geometry is concerned). Note that in two space dimensions sides coincide with edges, or we can say that a side consists of one edge and two nodes in that case. The TeX version of this page contains a graphical representation of the data structure. Size limitations of the data structure are described in a separate page LIMITS. All data types have names with uppercase letters. Now we give a brief description of all data types for which a separate page is provided. . DOMAIN - Structure that describes a two- or threedimensional domain. . BOUNDARY_SEGMENT - A DOMAIN is constructed from several BOUNDARY_SEGMENT objects. UG can handle also `internal` boundaries, e.g. for material interfaces. . PROBLEM - Stores references to user defined coefficient functions. The purpose of these functions depends on the problem class library. A problem corresponds to a DOMAIN and provides a BOUNDARY_CONDITION for each BOUNDARY_SEGMENT besides the coefficient functions. There may be several problems defined on a domain. . BOUNDARY_CONDITION - For each BOUNDARY_SEGMENT a corresponding BOUNDARY_CONDITION object must be allocated. . FORMAT - This structure parametrizes the data structure. The format determines the layout of the sparse matrix data structure and how it is determined from the mesh data. . ELEMENT - UGs data structure is element oriented, so this is the basic data type from which other objects can be reached locally. The variable element concept allows several element types (e.g. triangles and quadrilaterals) in one mesh. Elements give you access to the corresponding nodes and to neighboring elements. . NODE - Corners of the elements are described by the NODE structure. Only the information that is different per level is stored here. E.g. geometric information for a node e.g. is stored only once in a VERTEX object. Several NODE objects share share one VERTEX if they are at the same position on different levels. . VERTEX - Geometric data of a NODE. This contains x,y (,z), i.e global coordinates, the position in the coarser grid level (local coordinates) and boundary information if the node is on the boundary (see VSEGMENT). . LINK - The mesh structure implies a neighbor relationship on the NODE objects (the `mesh graph`). Since the mesh is unstructured a linked list must be used to provide references to all neighbors. The LINK data type forms that list and each LINK object represents one neighbor. . EDGE - The LINK structure represents a directed edge of the mesh graph from some node `a` to node `b`. The LINK from node `b` to node `a` must always exist since the neighbor relation is symmetric and therefore the two LINK objects are combined to form an (undirected) EDGE object. . GEOM_OBJECT - This is an union of ELEMENT, NODE and EDGE, the basic geometric objects. . VECTOR - This structure is part of UGs sparse matrix data structure. Degrees of freedom (and additional values) associated with `one geometric object` (ELEMENT, NODE, EDGE and also sides in 3D for which there is no extra data type) are stored in a VECTOR object. In each VECTOR starts a list of MATRIX objects representing the rows of the global stiffness matrix corresponding to all degrees of freedom in the VECTOR. . MATRIX - Contains all matrix entries coupling the degrees of freedom in two VECTOR objects. MATRIX objects come in pairs connecting two VECTOR objects in both directions. If the VECTOR objects are identical (which is the case for diagonal entries) then there is only one MATRIX. The graph induced by the MATRIX-VECTOR structure is completely independent from the mesh graph represented by the LINK-NODE structure. . CONNECTION - The two (or one, s.a.) MATRIX objects connecting two VECTOR objects are combined to a CONNECTION object. This is similar to the combination of two LINK objects in an EDGE. . GRID - All objects allocated on one grid level can be accessed via the GRID structure. . MULTIGRID - Several grid levels are combined to form a MULTIGRID structure. It also provides access to the data structure parameters (FORMAT), the geometry (DOMAIN) and the problem description (PROBLEM). The MULTIGRID structure is basically an environment item (see ENVIRONMENT). Several MULTIGRID objects can be handled simultaneously by the grid manager module. `IMPORTANT:` The access to all components of the data types is realized with macros. Through the use of macros the data structure can be changed without changing the code that uses it. \sa LIMITS, all data types mentioned above. .p DataStructure.eps .cb Graphical representation of the data structure with references. .ce \section LIMITS Constants defining limitations of the data structure There are some constants defining limitations of the data structure. They are explained here. The actual value of the definition should be extracted from the source code via the uggrep shell script provided with UG. `In file gm.h` . MAXLEVEL - Maximum number of grid levels allowed in MULTIGRID. . MAXOBJECTS - Maximum number of different objects in free list. . MAX_SIDES_OF_ELEM - Maximum number of sides of an element (of any type). . MAX_EDGES_OF_ELEM - Maximum number of edges of an element (of any type). . MAX_CORNERS_OF_ELEM - Maximum number of corners of an element (of any type). . MAX_EDGES_OF_SIDE - Maximum number of edges per side. . MAX_CORNERS_OF_SIDE - Maximum number of corners per side. . MAX_CORNERS_OF_EDGE - Maximum number of corners per edge (is always 2). . MAX_SIDES_OF_EDGE - In 3D two sides always have on edge in common. . MAX_SONS - Maximum number of sons per element. . MAXMATRICES - Maximum number of MATRIX types with different size. . MAXCONNECTIONS - Maximum number of different CONNECTION types. . MSIZEMAX - Maximum size of a MATRIX object in bytes. . NO_OF_ELEM_MAX - Maximum number of elements touching the same edge. `In file switch.h` . MAXVECTORS - Maximum number of different VECTOR types. \section REFINEMENT The interface to the grid refinement module The interface to the grid refinement will change in the near future. Therefore only a rudimentary documentation is provided. UGs local refinement capability is element oriented, i.e. the error estimator (part of the problem class) selects all or part of the elements for refinement. To that end the error estimator calls the function \verbatim INT MarkForRefinement (ELEMENT *theElement, INT rule, INT side); \endverbatim where rule is one of the following rules \verbatim NO_REFINEMENT COPY RED BLUE BISECTION_1 BISECTION_2_Q BISECTION_2_T1 BISECTION_2_T2 BISECTION_3 UNREFINE \endverbatim and side is some orientation necessary for those rules that are not invariant under rotation (e.g. the edge to bisect). The RED rule selects standard isotropic refinement independent of the element type. Triangles are subdivided in four triangles by connecting the edge midpoints, quadrilaterals are subdivided by connecting edge midpoints with the centroid and tetrahedral elements are subdivided using the refinement strategy of J. Bey. For RED refinement the side information is arbitrary. The MarkForRefinement function may only be called for those elements where \verbatim INT EstimateHere (ELEMENT *theElement); \endverbatim returns true. EstimateHere is true for the leave elements of the element hierarchy, i.e. those elements that are not further refined. Care must be taken when the estimator for an element needs also information on the solution in neighboring elements (see e.g. the implementation of the error estimator in the diff2d package). After the desired elements have been tagged for refinement the refine of the UG command language is used to actually refine the elements. \subsection Example Example2 The following function selects all (possible) elements in a MULTIGRID for refinement and returns the number of elements selected for refinement. \verbatim static INT MarkAll (MULTIGRID *theMG) { GRID *theGrid; ELEMENT *theElement; int k,j; INT cnt; // get number of levels j = TOPLEVEL(theMG); // cnt will hold the number elements to be refined cnt = 0; // mark elements for (k=0; k<=j; k++) { theGrid = GRID_ON_LEVEL(theMG,k); for (theElement=FIRSTELEMENT(theGrid); theElement!=NULL; theElement=SUCCE(theElement)) if (EstimateHere(theElement)) { cnt++; MarkForRefinement(theElement,RED,0); } } // return cnt return(cnt); } \endverbatim \sa MarkForRefinement(), EstimateHere(), refine() REFERENCES: [1] J. Bey: Tetrahedral Grid Refinement. To be published in Computing. [2] J. Bey: AGM^3D Manual. Technical Report, Universität Tübingen, 1994. [3] R.E. Bank, A.H. Sherman, A. Weiser: Refinement Algorithms and Data Structures for Regular Local Mesh Refinement. In: Scientific Computing, IMACS, North-Holland, Amsterdam, 1983. */