From: Cédric Aguerre Date: Mon, 30 Nov 2015 15:55:49 +0000 (+0100) Subject: fix conflict X-Git-Tag: V8_0_0a1~5^2~17 X-Git-Url: http://git.salome-platform.org/gitweb/?a=commitdiff_plain;h=1265469b53d28caba60f60b34e8238b26dd119a2;p=modules%2Fmed.git fix conflict --- 1265469b53d28caba60f60b34e8238b26dd119a2 diff --cc medtool/doc/user/doxygen/Doxyfile_med_user.in index 6c4cc970d,000000000..dbb6c5596 mode 100644,000000..100644 --- a/medtool/doc/user/doxygen/Doxyfile_med_user.in +++ b/medtool/doc/user/doxygen/Doxyfile_med_user.in @@@ -1,282 -1,0 +1,286 @@@ +# Copyright (C) 2007-2015 CEA/DEN, EDF R&D, OPEN CASCADE +# +# 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +# +# See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com +# + +# Doxyfile 0.1 +#--------------------------------------------------------------------------- +# General configuration options +#--------------------------------------------------------------------------- +# +PROJECT_NAME = "SALOME MED Users' Guide" +PROJECT_NUMBER = +OUTPUT_DIRECTORY = doc_ref_user +OUTPUT_LANGUAGE = English +EXTRACT_ALL = YES +EXTRACT_PRIVATE = NO +EXTRACT_STATIC = NO +HIDE_UNDOC_MEMBERS = YES +HIDE_UNDOC_CLASSES = YES +BRIEF_MEMBER_DESC = NO +REPEAT_BRIEF = YES +ALWAYS_DETAILED_SEC = NO +FULL_PATH_NAMES = NO +STRIP_FROM_PATH = +INTERNAL_DOCS = NO +STRIP_CODE_COMMENTS = YES +CASE_SENSE_NAMES = YES +SHORT_NAMES = NO +HIDE_SCOPE_NAMES = NO +VERBATIM_HEADERS = NO +SHOW_INCLUDE_FILES = NO +JAVADOC_AUTOBRIEF = NO +INHERIT_DOCS = YES +MARKDOWN_SUPPORT = YES +INLINE_INFO = NO +SORT_MEMBER_DOCS = NO +DISTRIBUTE_GROUP_DOC = NO +TAB_SIZE = 8 +GENERATE_TODOLIST = YES +GENERATE_TESTLIST = YES +GENERATE_BUGLIST = YES +ALIASES = +ENABLED_SECTIONS = user MEDCOUPLING_ug +MAX_INITIALIZER_LINES = 30 +OPTIMIZE_OUTPUT_FOR_C = NO +SHOW_USED_FILES = NO +SORT_BRIEF_DOCS = YES +#--------------------------------------------------------------------------- +# configuration options related to warning and progress messages +#--------------------------------------------------------------------------- +QUIET = NO +WARNINGS = YES +WARN_IF_UNDOCUMENTED = YES +WARN_FORMAT = "$file:$line: $text" +WARN_LOGFILE = log_user +#--------------------------------------------------------------------------- +# configuration options related to the input files +#--------------------------------------------------------------------------- + +INPUT = @CMAKE_CURRENT_SOURCE_DIR@/doxfiles/index.dox \ + @CMAKE_CURRENT_SOURCE_DIR@/doxfiles/faq.dox \ + @CMAKE_CURRENT_SOURCE_DIR@/doxfiles/start \ + @CMAKE_CURRENT_SOURCE_DIR@/doxfiles/tutorial.dox \ + @CMAKE_CURRENT_SOURCE_DIR@/doxfiles/gui.dox \ + @CMAKE_CURRENT_SOURCE_DIR@/doxfiles/reference \ + @CMAKE_CURRENT_SOURCE_DIR@/doxfiles/reference/arrays \ + @CMAKE_CURRENT_SOURCE_DIR@/doxfiles/reference/meshes \ + @CMAKE_CURRENT_SOURCE_DIR@/doxfiles/reference/fields \ + @CMAKE_CURRENT_SOURCE_DIR@/doxfiles/reference/medloader \ + @CMAKE_CURRENT_SOURCE_DIR@/doxfiles/reference/interpolation \ + @CMAKE_CURRENT_SOURCE_DIR@/doxfiles/reference/cpp \ + @CMAKE_CURRENT_SOURCE_DIR@/doxfiles/reference/distrib \ + @CMAKE_CURRENT_SOURCE_DIR@/doxfiles/reference/misc \ + @CMAKE_CURRENT_SOURCE_DIR@/doxfiles/examples/examples.dox \ + @CMAKE_CURRENT_BINARY_DIR@/medcouplingexamplesPY.dox \ + @CMAKE_CURRENT_BINARY_DIR@/medcouplingexamplesCPP.dox \ + @CMAKE_CURRENT_SOURCE_DIR@/doxfiles/appendix \ + @CMAKE_CURRENT_SOURCE_DIR@/fakesources \ + @PROJECT_SOURCE_DIR@/src/ParaMEDMEM \ + @PROJECT_SOURCE_DIR@/src/INTERP_KERNEL \ + @PROJECT_SOURCE_DIR@/src/INTERP_KERNEL/Bases \ + @PROJECT_SOURCE_DIR@/src/INTERP_KERNEL/Geometric2D \ + @PROJECT_SOURCE_DIR@/src/MEDCoupling \ + @PROJECT_SOURCE_DIR@/src/MEDLoader \ + @PROJECT_SOURCE_DIR@/src/MEDCouplingCorba + +FILE_PATTERNS = InterpKernelDEC.* \ + OverlapDEC.* \ + DEC.* \ ++ DECOptions.* \ + DisjointDEC.* \ ++ *Topology.* \ + MPIProcessorGroup.* \ ++ ProcessorGroup.* \ + MPIAccess.* \ + StructuredCoincidentDEC.* \ + ExplicitCoincidentDEC.* \ + NonCoincidentDEC.* \ + CommInterface.* \ + ICoCo*.* \ + NormalizedGeometricTypes \ + NormalizedUnstructuredMesh.* \ + Interpolation2D.* \ + Interpolation3D.* \ + Interpolation3DSurf.* \ + InterpolationMatrix.* \ + PlanarIntersector.* \ + TargetIntersector.* \ + Interpolation.* \ + InterpolationOptions.* \ + InterpKernelGeo2DAbstractEdge.* \ + InterpKernelGeo2DEdge.* \ + InterpKernelGeo2DEdgeArcCircle.* \ + InterpKernelGeo2DEdgeLin.* \ + InterpKernelGeo2DComposedEdge.* \ + InterpKernelGeo2DElementaryEdge.* \ + InterpKernelGeo2DNode.* \ + InterpKernelGeo2DQuadraticPolygon.* \ + ParaFIELD.* \ ++ ParaMESH.* \ + MEDCouplingMesh.* \ + MEDCouplingUMesh.* \ + MEDCoupling1GTUMesh.* \ + MEDCouplingPointSet.* \ + MEDCouplingCMesh.* \ + MEDCouplingIMesh.* \ + MEDCouplingStructuredMesh.* \ + MEDCouplingCurveLinearMesh.* \ + MEDCouplingExtrudedMesh.* \ + MEDCouplingFieldDouble.* \ + MEDCouplingField.* \ + MEDCouplingNatureOfFieldEnum \ + MEDCouplingNatureOfField.hxx \ + MEDCouplingFieldTemplate.* \ + MEDCouplingFieldDiscretization.* \ + MEDCouplingTimeDiscretization.* \ + MEDCouplingAMRAttribute.* \ + MEDCouplingCartesianAMRMesh.* \ + MEDCouplingTimeLabel.* \ + MEDCouplingRefCountObject.* \ + MEDCouplingAutoRefCountObjectPtr.* \ + MEDCouplingMemArray.* \ + MEDCouplingGaussLocalization.* \ + MEDCouplingRemapper.* \ + MEDLoader.* \ + MEDFileData.* \ + MEDFileParameter.* \ + MEDFileMesh.* \ + MEDFileField.* \ + *Servant.* \ + *.dox +RECURSIVE = YES +EXCLUDE = CVS +EXCLUDE_PATTERNS = *~ +EXAMPLE_PATH = @PROJECT_SOURCE_DIR@/src/ParaMEDMEM \ + @PROJECT_SOURCE_DIR@/src/MEDCoupling/Test \ + @PROJECT_SOURCE_DIR@/src/MEDCoupling_Swig \ + @PROJECT_SOURCE_DIR@/src/MEDLoader/Swig +EXAMPLE_PATTERNS = *.cxx *.py +EXAMPLE_RECURSIVE = NO +IMAGE_PATH = @CMAKE_CURRENT_SOURCE_DIR@/figures +INPUT_FILTER = +FILTER_SOURCE_FILES = NO +#--------------------------------------------------------------------------- +# configuration options related to source browsing +#--------------------------------------------------------------------------- +SOURCE_BROWSER = NO +INLINE_SOURCES = NO +REFERENCED_BY_RELATION = YES +REFERENCES_RELATION = YES +#--------------------------------------------------------------------------- +# configuration options related to the alphabetical class index +#--------------------------------------------------------------------------- +ALPHABETICAL_INDEX = YES +COLS_IN_ALPHA_INDEX = 5 +IGNORE_PREFIX = +#--------------------------------------------------------------------------- +# configuration options related to the HTML output +#--------------------------------------------------------------------------- +GENERATE_HTML = YES +HTML_OUTPUT = html +HTML_HEADER = @CMAKE_CURRENT_BINARY_DIR@/static/header.html +HTML_FOOTER = @CMAKE_CURRENT_SOURCE_DIR@/static/footer.html +HTML_EXTRA_STYLESHEET = @CMAKE_CURRENT_SOURCE_DIR@/static/salome_extra.css +GENERATE_HTMLHELP = NO +GENERATE_CHI = YES +BINARY_TOC = NO +TOC_EXPAND = YES +DISABLE_INDEX = NO +ENUM_VALUES_PER_LINE = 4 +GENERATE_TREEVIEW = YES +TREEVIEW_WIDTH = 250 + +#--------------------------------------------------------------------------- +#SORT related options +#--------------------------------------------------------------------------- +SORT_GROUP_NAMES = NO + +#--------------------------------------------------------------------------- +# configuration options related to the LaTeX output +#--------------------------------------------------------------------------- +GENERATE_LATEX = YES +LATEX_OUTPUT = latex +COMPACT_LATEX = YES +PAPER_TYPE = a4wide +EXTRA_PACKAGES = +LATEX_HEADER = +PDF_HYPERLINKS = NO +USE_PDFLATEX = NO +LATEX_BATCHMODE = NO +#--------------------------------------------------------------------------- +# configuration options related to the RTF output +#--------------------------------------------------------------------------- +GENERATE_RTF = NO +RTF_OUTPUT = rtf +COMPACT_RTF = NO +RTF_HYPERLINKS = NO +RTF_STYLESHEET_FILE = +RTF_EXTENSIONS_FILE = +#--------------------------------------------------------------------------- +# configuration options related to the man page output +#--------------------------------------------------------------------------- +GENERATE_MAN = NO +MAN_OUTPUT = man +MAN_EXTENSION = .3 +MAN_LINKS = NO +#--------------------------------------------------------------------------- +# configuration options related to the XML output +#--------------------------------------------------------------------------- +GENERATE_XML = YES +XML_OUTPUT = xml +XML_PROGRAMLISTING = NO +#--------------------------------------------------------------------------- +# Configuration options related to the preprocessor +#--------------------------------------------------------------------------- +ENABLE_PREPROCESSING = YES +MACRO_EXPANSION = YES +EXPAND_ONLY_PREDEF = YES +SEARCH_INCLUDES = YES +INCLUDE_PATH = +INCLUDE_FILE_PATTERNS = +PREDEFINED = +EXPAND_AS_DEFINED = MEDCOUPLING_EXPORT MEDCOUPLINGREMAPPER_EXPORT MEDLOADER_EXPORT +SKIP_FUNCTION_MACROS = YES +#--------------------------------------------------------------------------- +# Configuration::additions related to external references +#--------------------------------------------------------------------------- +TAGFILES = +GENERATE_TAGFILE = +ALLEXTERNALS = NO +PERL_PATH = /usr/bin/perl +#--------------------------------------------------------------------------- +# Configuration options related to the dot tool +#--------------------------------------------------------------------------- +CLASS_DIAGRAMS = YES +HAVE_DOT = YES +CLASS_GRAPH = YES +COLLABORATION_GRAPH = YES +TEMPLATE_RELATIONS = YES +HIDE_UNDOC_RELATIONS = YES +INCLUDE_GRAPH = YES +INCLUDED_BY_GRAPH = YES +GRAPHICAL_HIERARCHY = YES +DOT_PATH = +DOT_FONTNAME = Arial +DOTFILE_DIRS = +GENERATE_LEGEND = YES +DOT_CLEANUP = YES +#--------------------------------------------------------------------------- +# Configuration::additions related to the search engine +#--------------------------------------------------------------------------- +SEARCHENGINE = NO diff --cc medtool/doc/user/doxygen/doxfiles/examples/medcouplingexamplesmeshes.doxy index e09432473,000000000..166b7a209 mode 100644,000000..100644 --- a/medtool/doc/user/doxygen/doxfiles/examples/medcouplingexamplesmeshes.doxy +++ b/medtool/doc/user/doxygen/doxfiles/examples/medcouplingexamplesmeshes.doxy @@@ -1,675 -1,0 +1,676 @@@ + +\section ExamplesMeshes Meshes + +\subsection ExamplesMeshesCreate Create + +\subsubsection medcouplingcppexamplesUmeshStdBuild1 Standard build of an unstructured mesh from scratch + +Firstly retrieve basic data in full interlace mode for coordinates, and nodal connectivity cell per cell. +\snippet MEDCouplingExamplesTest.cxx CppSnippetUMeshStdBuild1_1 + +Then create ParaMEDMEM::MEDCouplingUMesh instance giving its mesh dimension (2 here) and a name. + +\snippet MEDCouplingExamplesTest.cxx CppSnippetUMeshStdBuild1_2 + +Gives an upper bound of the number of cells to be inserted into the unstructured mesh. +\n Then enter nodal connectivity of all cells, cell per cell using ParaMEDMEM::MEDCouplingUMesh::insertNextCell method. +\n When the nodal connectivity cell per cell has been finished, call ParaMEDMEM::MEDCouplingUMesh::finishInsertingCells method in order to restore \b mesh instance. + +\snippet MEDCouplingExamplesTest.cxx CppSnippetUMeshStdBuild1_3 + +At this level the connectivity part of the mesh \b mesh as been defined. Now let's set the coordinates using array \b coords defined above. + +\snippet MEDCouplingExamplesTest.cxx CppSnippetUMeshStdBuild1_4 + +At this level mesh is usable. When this mesh is no more needed simply call decrRef to decrement its reference counter. + +\snippet MEDCouplingExamplesTest.cxx CppSnippetUMeshStdBuild1_5 + + +\subsubsection medcouplingcppexamplesUmeshAdvBuild1 Advanced build of an unstructured mesh from scratch + +Firstly retrieve basic data in full interlace mode for coordinates, and nodal connectivity cell per cell, cell type \b included (3 for INTERP_KERNEL::NORM_TRI3 and 4 for INTERP_KERNEL::QUAD4). +\snippet MEDCouplingExamplesTest.cxx CppSnippetUMeshAdvBuild1_1 + +Then create ParaMEDMEM::MEDCouplingUMesh instance giving its mesh dimension (2 here) and a name. + +\snippet MEDCouplingExamplesTest.cxx CppSnippetUMeshAdvBuild1_2 + +Then enter nodal connectivity at once. + +\snippet MEDCouplingExamplesTest.cxx CppSnippetUMeshAdvBuild1_3 + +At this level the connectivity part of the mesh \b mesh as been defined. Now let's set the coordinates using array \b coords defined above. + +\snippet MEDCouplingExamplesTest.cxx CppSnippetUMeshAdvBuild1_4 + +At this level mesh is usable. When this mesh is no more needed simply call decrRef() to decrement its reference counter. + +\snippet MEDCouplingExamplesTest.cxx CppSnippetUMeshAdvBuild1_5 + + +\subsubsection medcouplingcppexamplesCmeshStdBuild1 Standard build of an cartesian mesh from scratch + +We are going to build a 2D cartesian mesh, constituted from 9 nodes along X axis, and 7 nodes along Y axis. + +Firstly retrieve for each direction the discretization and build a \ref ParaMEDMEM::DataArrayDouble "DataArrayDouble instance" on the corresponding direction. + +\snippet MEDCouplingExamplesTest.cxx CppSnippetCMeshStdBuild1_1 + +Then create ParaMEDMEM::MEDCouplingCMesh instance giving the 2 instances of \ref ParaMEDMEM::DataArrayDouble "DataArrayDouble" obtained above. + +There are 2 techniques to get it. + +Either : + +\snippet MEDCouplingExamplesTest.cxx CppSnippetCMeshStdBuild1_2 + +Or : + +\snippet MEDCouplingExamplesTest.cxx CppSnippetCMeshStdBuild1_2bis + +\c mesh is now available for use : + +\snippet MEDCouplingExamplesTest.cxx CppSnippetCMeshStdBuild1_3 + - When this mesh is no more needed simply call decrRef to decrement its reference counter. ++When this mesh is no more needed simply call decrRef to decrement its reference counter (nothing ++to be done in Python). + +\snippet MEDCouplingExamplesTest.cxx CppSnippetCMeshStdBuild1_4 + + +\subsubsection cpp_mcumesh_buildBoundaryMesh Getting a bounding mesh + +First, we create a 2D mesh with 3 QUAD4 and 2 TRI3 cells. +\snippet MEDCouplingExamplesTest.cxx CppSnippet_MEDCouplingUMesh_buildBoundaryMesh_1 +Now we use +\ref ParaMEDMEM::MEDCouplingUMesh::buildBoundaryMesh "buildBoundaryMesh()" to get a mesh +of lower dimension bounding \b mesh. +\snippet MEDCouplingExamplesTest.cxx CppSnippet_MEDCouplingUMesh_buildBoundaryMesh_2 +Depending on the value of a parameter, +\ref ParaMEDMEM::MEDCouplingUMesh::buildBoundaryMesh "buildBoundaryMesh()" +creates the mesh sharing the node coordinates array with \b mesh or not. + + +\subsubsection cpp_mcumesh_buildFacePartOfMySelfNode Retrieving a lower dimension mesh based on given nodes + +First, we create a 2D mesh with 3 QUAD4 and 2 TRI3 cells. +\snippet MEDCouplingExamplesTest.cxx CppSnippet_MEDCouplingUMesh_buildFacePartOfMySelfNode_1 +In the following code we retrieve nodes of the cell #0 an then we call +\ref ParaMEDMEM::MEDCouplingUMesh::buildFacePartOfMySelfNode "buildFacePartOfMySelfNode()" +twice with these nodes and with varying last parameter \b allNodes as input. +\snippet MEDCouplingExamplesTest.cxx CppSnippet_MEDCouplingUMesh_buildFacePartOfMySelfNode_2 +
If the last parameter is \c true +\ref ParaMEDMEM::MEDCouplingUMesh::buildFacePartOfMySelfNode "buildFacePartOfMySelfNode()" looks +for segements whose all nodes are given to it, hence it finds segments bounding the cell #0 only. +
If the last parameter is \c false +\ref ParaMEDMEM::MEDCouplingUMesh::buildFacePartOfMySelfNode "buildFacePartOfMySelfNode()" looks +for any segment whose nodes are given to it, hence it adds more segments to \b mesh2. + + +\subsubsection cpp_mcumesh_buildPartOfMySelfNode Copying cells selected by nodes + +First, we create a 2D mesh with 3 QUAD4 and 2 TRI3 cells. +\snippet MEDCouplingExamplesTest.cxx CppSnippet_MEDCouplingUMesh_buildPartOfMySelfNode_1 +In the following code we retrieve nodes of the cell #0 an then we call +\ref ParaMEDMEM::MEDCouplingUMesh::buildPartOfMySelfNode "buildPartOfMySelfNode()" +twice with these nodes and with varying last parameter \b allNodes as input. +\snippet MEDCouplingExamplesTest.cxx CppSnippet_MEDCouplingUMesh_buildPartOfMySelfNode_2 +
If the last parameter is \c true +\ref ParaMEDMEM::MEDCouplingUMesh::buildPartOfMySelfNode "buildPartOfMySelfNode()" looks +for cells whose all nodes are given to it, hence it finds the cell #0 only. +
If the last parameter is \c false +\ref ParaMEDMEM::MEDCouplingUMesh::buildPartOfMySelfNode "buildPartOfMySelfNode()" looks +for any cell whose nodes are given to it, hence it finds all cells of \b mesh because all +cells share the node #4. + + +\subsubsection cpp_mcumesh_buildPartOfMySelf Getting a part of mesh + +First, we create a 2D mesh with 3 QUAD4 and 2 TRI3 cells. +\snippet MEDCouplingExamplesTest.cxx CppSnippet_MEDCouplingUMesh_buildPartOfMySelf_1 +Now we use +\ref ParaMEDMEM::MEDCouplingUMesh::buildPartOfMySelf "buildPartOfMySelf()" to get a mesh +containing only two cells of \b mesh. +\snippet MEDCouplingExamplesTest.cxx CppSnippet_MEDCouplingUMesh_buildPartOfMySelf_2 + + +\subsection ExamplesMeshesModify Modify + +\subsubsection cpp_mcumesh_findAndCorrectBadOriented3DExtrudedCells Fixing orientation of "extruded" volumes + +First, we create a mesh with 2 incorrectly oriented "extruded" volumes. +\snippet MEDCouplingExamplesTest.cxx CppSnippet_MEDCouplingUMesh_findAndCorrectBadOriented3DExtrudedCells_1 +Now we check that +\ref ParaMEDMEM::MEDCouplingUMesh::findAndCorrectBadOriented3DExtrudedCells "findAndCorrectBadOriented3DExtrudedCells()" +finds and fixes the reversed cells. +\snippet MEDCouplingExamplesTest.cxx CppSnippet_MEDCouplingUMesh_findAndCorrectBadOriented3DExtrudedCells_2 + + +\subsubsection cpp_mcumesh_arePolyhedronsNotCorrectlyOriented Fixing orientation of polyhedra + +First, we create a mesh with 2 polyhedra, one of which is incorrectly oriented. We create +two "extruded" polyhedra and then convert them to correctly defined polyhedra. +\snippet MEDCouplingExamplesTest.cxx CppSnippet_MEDCouplingUMesh_arePolyhedronsNotCorrectlyOriented_1 +Now we check that +\ref ParaMEDMEM::MEDCouplingUMesh::arePolyhedronsNotCorrectlyOriented "arePolyhedronsNotCorrectlyOriented()" +finds one reversed cell. After that we fix it using +\ref ParaMEDMEM::MEDCouplingUMesh::orientCorrectlyPolyhedrons "orientCorrectlyPolyhedrons()" and +re-check the orientation of polyhedra. +\snippet MEDCouplingExamplesTest.cxx CppSnippet_MEDCouplingUMesh_arePolyhedronsNotCorrectlyOriented_2 + + +\subsubsection cpp_mcumesh_are2DCellsNotCorrectlyOriented Fixing orientation of faces + +First, we create a 2D mesh in 3D space with 3 QUAD4 and 2 TRI3 cells. Orientation of the cell #1 is +reversed comparing with others. +\snippet MEDCouplingExamplesTest.cxx CppSnippet_MEDCouplingUMesh_are2DCellsNotCorrectlyOriented_1 +Now we check that +\ref ParaMEDMEM::MEDCouplingUMesh::are2DCellsNotCorrectlyOriented "are2DCellsNotCorrectlyOriented()" +finds one reversed face. After that we fix the incorrectly oriented cell using +\ref ParaMEDMEM::MEDCouplingUMesh::orientCorrectly2DCells "orientCorrectly2DCells()" and +re-check the orientation of cells. +\snippet MEDCouplingExamplesTest.cxx CppSnippet_MEDCouplingUMesh_are2DCellsNotCorrectlyOriented_2 + + +\subsubsection cpp_mcumesh_renumberNodesInConn Renumbering nodes in the connectivity array + +First, we create a 2D mesh with 1 QUAD4 cell and with undefined coordinates of nodes. +\snippet MEDCouplingExamplesTest.cxx CppSnippet_MEDCouplingUMesh_renumberNodesInConn_1 +Now we use +\ref ParaMEDMEM::MEDCouplingUMesh::renumberNodesInConn "renumberNodesInConn()" +to get the following nodal connectivity of a sole cell: 0,1,2,3. +\snippet MEDCouplingExamplesTest.cxx CppSnippet_MEDCouplingUMesh_renumberNodesInConn_2 +\b old2newIds array defines how node ids are changed: +- new id of node #0 is -1, +- new id of node #1 is 3, +- new id of node #2 is 4, +- new id of node #3 is 1, +- new id of node #4 is 0. + + +\subsubsection cpp_mcumesh_renumberNodes Renumbering nodes + +First, we create a 2D mesh with 4 nodes and no cells. +\snippet MEDCouplingExamplesTest.cxx CppSnippet_MEDCouplingUMesh_renumberNodes_1 +Next, we use +\ref ParaMEDMEM::MEDCouplingUMesh::renumberNodes "renumberNodes()" +to permute nodes so that +- old node #0 becomes #2, +- old node #1 remains #1, +- old node #2 becomes #0, +- old node #3 is removed. + +Number of nodes becomes 3. +\snippet MEDCouplingExamplesTest.cxx CppSnippet_MEDCouplingUMesh_renumberNodes_2 + +Next we compare behavior of +\ref ParaMEDMEM::MEDCouplingUMesh::renumberNodes "renumberNodes()" and that of +\ref ParaMEDMEM::MEDCouplingUMesh::renumberNodes2 "renumberNodes2()" which, in contrast to +\ref ParaMEDMEM::MEDCouplingUMesh::renumberNodes "renumberNodes()", +moves merged nodes to their barycenter.
+We set #2 as new id of old node #3 and expect that +\ref ParaMEDMEM::MEDCouplingUMesh::renumberNodes2 "renumberNodes2()" moves old nodes #0 +and #3 to their barycenter (-0.3,0.0) which becomes position of node #2.
+\snippet MEDCouplingExamplesTest.cxx CppSnippet_MEDCouplingUMesh_renumberNodes_3 + + +\subsubsection cpp_mcumesh_mergeNodes Merging equal nodes + +First, we create a 2D mesh with 1 QUAD4 and 2 TRI3 cells. The cells are based on 6 nodes +of which 2 nodes fully coincide (#3 and #4) and 3 nodes are equal with precision 0.003. +\snippet MEDCouplingExamplesTest.cxx CppSnippet_MEDCouplingUMesh_mergeNodes_1 +Now we merge node duplicates using +\ref ParaMEDMEM::MEDCouplingUMesh::mergeNodes "mergeNodes()" and check values it returns. +\snippet MEDCouplingExamplesTest.cxx CppSnippet_MEDCouplingUMesh_mergeNodes_2 +Contents of \b arr shows ids of old nodes after the merging. The nodes considered equal +one to the other have the same id in \b arr. + +Next we compare behavior of +\ref ParaMEDMEM::MEDCouplingUMesh::mergeNodes "mergeNodes()" and that of +\ref ParaMEDMEM::MEDCouplingUMesh::mergeNodes2 "mergeNodes2()" which, in contrast to +\ref ParaMEDMEM::MEDCouplingUMesh::mergeNodes "mergeNodes()", +moves merged nodes to their barycenter.
We expect that +\ref ParaMEDMEM::MEDCouplingUMesh::mergeNodes2 "mergeNodes2()" moves old nodes #0, #2 +and #5 to their barycenter equal to position of node #2.
+First we check that +\ref ParaMEDMEM::MEDCouplingUMesh::mergeNodes "mergeNodes()" does not move nodes +coincident with the node #2 to the position of node #2, and then we check that +\ref ParaMEDMEM::MEDCouplingUMesh::mergeNodes "mergeNodes2()" does move. +(We check only the second (Y) component of node coordinates since the first component of +these nodes is exactly same.) +\snippet MEDCouplingExamplesTest.cxx CppSnippet_MEDCouplingUMesh_mergeNodes_3 + + +\subsubsection cpp_mcumesh_zipConnectivityTraducer Removing cell duplicates + +First, we create a 2D mesh with 3 QUAD4 and 2 TRI3 cells, so that +- the cell #2 has the same nodal connectivity as the cell #1 does, +- the cell #3 has the same nodal connectivity as the cell #0 does, +- the cell #4 is based on the same nodes as the cell #0 but nodes order is different. + +\snippet MEDCouplingExamplesTest.cxx CppSnippet_MEDCouplingUMesh_zipConnectivityTraducer_1 +Now we use +\ref ParaMEDMEM::MEDCouplingUMesh::zipConnectivityTraducer "zipConnectivityTraducer()" +to remove duplicate cells. Then we check that two cells, having exactly same nodal +connectivity with other cells, have been removed. +\snippet MEDCouplingExamplesTest.cxx CppSnippet_MEDCouplingUMesh_zipConnectivityTraducer_2 +Contents of \b arr shows ids of cells after duplicates removal. If a value (cell id) +equals to its index in \b arr, this means that the cell is not a duplicate of any cell +with lower id. Else, the value gives a cell id to which this cell is equal.
+Thus, the cells #0 and #1 have no preceding equal cell since \b arr[i] == i.
+The cell #2 equals to the cell #1 (== \b arr[2] ).
+The cell #3 equals to the cell #0 (== \b arr[3] ).
+The cell #4 has no equal cell. This is because the cell comparison technique specified +when we called +\ref ParaMEDMEM::MEDCouplingUMesh::zipConnectivityTraducer "zipConnectivityTraducer()" +was 0 ("exact"), if we had used the technique 2 ("nodal"), \b arr[4] would be 0. + + +\subsubsection cpp_mcumesh_zipCoordsTraducer Removing unused nodes + +First, we create a 2D mesh with 3 QUAD4 and 2 TRI3 cells. +\snippet MEDCouplingExamplesTest.cxx CppSnippet_MEDCouplingUMesh_zipCoordsTraducer_1 +Now we create \b mesh2 including all nodes but only two cells of \b mesh, and we use \ref +ParaMEDMEM::MEDCouplingUMesh::zipCoordsTraducer "zipCoordsTraducer()" to remove unused +nodes from \b mesh2. +\ref ParaMEDMEM::MEDCouplingUMesh::zipCoordsTraducer "zipCoordsTraducer()" returns an array +with -1 for unused nodes and new ids for used ones. +\snippet MEDCouplingExamplesTest.cxx CppSnippet_MEDCouplingUMesh_zipCoordsTraducer_2 + + +\subsubsection cpp_mcumesh_getNodeIdsInUse Retrieving unused nodes + +First, we create a 2D mesh with 3 QUAD4 and 2 TRI3 cells. +\snippet MEDCouplingExamplesTest.cxx CppSnippet_MEDCouplingUMesh_getNodeIdsInUse_1 +Now we create \b mesh2 including all nodes but only two cells of \b mesh, and we use \ref +ParaMEDMEM::MEDCouplingUMesh::getNodeIdsInUse "getNodeIdsInUse()" to get nodes of \b mesh2 +used in its two cells. +\ref ParaMEDMEM::MEDCouplingUMesh::getNodeIdsInUse "getNodeIdsInUse()" returns an array +with -1 for unused nodes and new ids for used ones. +\snippet MEDCouplingExamplesTest.cxx CppSnippet_MEDCouplingUMesh_getNodeIdsInUse_2 +Now we use \b newNbOfNodes returned by +\ref ParaMEDMEM::MEDCouplingUMesh::getNodeIdsInUse "getNodeIdsInUse()" to convert \b arr +to "New to Old" mode. +\snippet MEDCouplingExamplesTest.cxx CppSnippet_MEDCouplingUMesh_getNodeIdsInUse_3 + + +\subsubsection cpp_mcumesh_convertToPolyTypes Conversion of cells to "poly" types + +First, we create a 2D mesh with 3 QUAD4 and 2 TRI3 cells. +\snippet MEDCouplingExamplesTest.cxx CppSnippet_MEDCouplingUMesh_convertToPolyTypes_1 +Now we convert cells #1 and #3 to type POLYGON and check the result +\snippet MEDCouplingExamplesTest.cxx CppSnippet_MEDCouplingUMesh_convertToPolyTypes_2 + + +\subsubsection cpp_mcpointset_scale Scaling the mesh + +First, we create a 2D mesh with 4 nodes and no cells. +\snippet MEDCouplingExamplesTest.cxx CppSnippet_MEDCouplingPointSet_scale_1 +Then we scale it by a factor of 2 with a center (0.,0.). +\snippet MEDCouplingExamplesTest.cxx CppSnippet_MEDCouplingPointSet_scale_2 +Finally we check that all node coordinates have changed by more than 0.9. +\snippet MEDCouplingExamplesTest.cxx CppSnippet_MEDCouplingPointSet_scale_3 + + +\subsubsection cpp_mcpointset_translate Translating the mesh + +First, we create a 2D mesh with 4 nodes and no cells. +\snippet MEDCouplingExamplesTest.cxx CppSnippet_MEDCouplingPointSet_translate_1 +Then we translate it by a vector (1.,1.). +\snippet MEDCouplingExamplesTest.cxx CppSnippet_MEDCouplingPointSet_translate_2 +Finally we check that all node coordinates have changed by more than 0.9. +\snippet MEDCouplingExamplesTest.cxx CppSnippet_MEDCouplingPointSet_translate_3 + + +\subsubsection cpp_mcpointset_rotate Rotating the mesh + +First, we create a 2D mesh with 4 nodes and no cells. +\snippet MEDCouplingExamplesTest.cxx CppSnippet_MEDCouplingPointSet_rotate_1 +Then we rotate it around a point (0.,0.) by 90 degrees clockwise. +\snippet MEDCouplingExamplesTest.cxx CppSnippet_MEDCouplingPointSet_rotate_2 +Next, we make a 3D mesh from the 2D one and rotate it around the Z axis by 90 degrees +counter-clockwise. +\snippet MEDCouplingExamplesTest.cxx CppSnippet_MEDCouplingPointSet_rotate_3 +Finally we transform the mesh back to 2D space and check that all nodes get back to the +initial location. +\snippet MEDCouplingExamplesTest.cxx CppSnippet_MEDCouplingPointSet_rotate_4 + + +\subsection ExamplesMeshesAccess Access + +\subsubsection cpp_mccmesh_getCoordsAt Getting node coordinates along an axis + +We create an 1D Cartesian mesh and retrieves node coordinates using +\ref ParaMEDMEM::MEDCouplingCMesh::getCoordsAt "getCoordsAt()". +\snippet MEDCouplingExamplesTest.cxx CppSnippet_MEDCouplingCMesh_getCoordsAt_1 + + +\subsubsection cpp_mcpointset_getcoordinatesofnode Getting coordinates of a node + +The following code creates a 2D \ref ParaMEDMEM::MEDCouplingUMesh +"MEDCouplingUMesh" with 3 nodes and no cells. +\snippet MEDCouplingExamplesTest.cxx CppSnippet_MEDCouplingPointSet_getCoordinatesOfNode_1 +Here we get coordinates of the second node and check its two coordinates. +\snippet MEDCouplingExamplesTest.cxx CppSnippet_MEDCouplingPointSet_getCoordinatesOfNode_2 + + +\subsubsection cpp_mcumesh_areCellsIncludedIn Cells correspondence in two meshes + +First, we create a 2D \b mesh1 with 3 QUAD4 and 2 TRI3 cells. +\snippet MEDCouplingExamplesTest.cxx CppSnippet_MEDCouplingUMesh_areCellsIncludedIn_1 +Then we create a \b mesh2 which includes cells #4, #2 and #0 of \b mesh1. The two meshes +share the same node coordinates array. +\snippet MEDCouplingExamplesTest.cxx CppSnippet_MEDCouplingUMesh_areCellsIncludedIn_2 +Now we ascertain that +- \ref ParaMEDMEM::MEDCouplingUMesh::areCellsIncludedIn "areCellsIncludedIn()" +detects that all cells of \b mesh2 are present in \b mesh1, +- the correspondence array \b corr2to1, which gives cell ids of \b mesh2 within +\b mesh1, is equal to the array \b cells2 which selected cells from \b mesh1 for creation +of \b mesh2. + +\snippet MEDCouplingExamplesTest.cxx CppSnippet_MEDCouplingUMesh_areCellsIncludedIn_3 +Now we apply +\ref ParaMEDMEM::MEDCouplingUMesh::areCellsIncludedIn "areCellsIncludedIn()" +in a reverse direction and ascertain that it returns \c false. +\snippet MEDCouplingExamplesTest.cxx CppSnippet_MEDCouplingUMesh_areCellsIncludedIn_4 +The contents of the correspondence +array \b corr1to2 [2, 3, 1, 4, 0] means the following. +- The cell #0 of \b mesh1 is equal to the cell #2 (== \b corr1to2[ 0 ]) of \b mesh2. +- The cell #1 of \b mesh1 is missing from \b mesh2 (as \b corr1to2[ 1 ] >= \b mesh2->getNumberOfCells()). +- The cell #2 of \b mesh1 is equal to the cell #1 (== \b corr1to2[ 2 ]) of \b mesh2. +- The cell #3 of \b mesh1 is missing from \b mesh2 (as \b corr1to2[ 3 ] >= \b mesh2->getNumberOfCells()). +- The cell #4 of \b mesh1 is equal to the cell #0 (== \b corr1to2[ 4 ]) of \b mesh2. + + +\subsubsection cpp_mcumesh_checkDeepEquivalWith Deep comparison of meshes + +First, we create two 2D meshes with two triangles, so that +- their nodes are almost same but permuted, +- the first triangle is based exactly on the same nodes (taking the permutation into account), +- an order of nodes in the second triangle is changed. + +\snippet MEDCouplingExamplesTest.cxx CppSnippet_MEDCouplingUMesh_checkDeepEquivalWith_1 +Then we check that +- \ref ParaMEDMEM::MEDCouplingUMesh::checkDeepEquivalWith "checkDeepEquivalWith()" +considers the meshes equal (i.e. it does not throw any exception) if it is called with a cell +comparison policy \b cellCompPol == 1 +- mapping from \b mesh1 to \b mesh2 for both nodes and cells is as expected. + +\snippet MEDCouplingExamplesTest.cxx CppSnippet_MEDCouplingUMesh_checkDeepEquivalWith_2 +Next we ascertain that +\ref ParaMEDMEM::MEDCouplingUMesh::checkDeepEquivalOnSameNodesWith "checkDeepEquivalOnSameNodesWith()" +consider \b mesh1 and \b mesh2 different as they do not share the same nodal connectivity +array.
+After that we make the meshes share the node coordinates array and insert new +triangles based on the same nodes but in different order. This is to ascertain that +\ref ParaMEDMEM::MEDCouplingUMesh::checkDeepEquivalOnSameNodesWith "checkDeepEquivalOnSameNodesWith()" +called with the weakest cell comparison policy considers the meshes equal. +\snippet MEDCouplingExamplesTest.cxx CppSnippet_MEDCouplingUMesh_checkDeepEquivalWith_3 + + +\subsubsection cpp_mcumesh_getPartBarycenterAndOwner Getting barycenters of cells + +First, we create a 2D mesh with 3 QUAD4 and 2 TRI3 cells. +\snippet MEDCouplingExamplesTest.cxx CppSnippet_MEDCouplingUMesh_getPartMeasureField_1 +Now we use +\ref ParaMEDMEM::MEDCouplingUMesh::getPartBarycenterAndOwner "getPartBarycenterAndOwner()" to get +barycenters of all but the first cell. +\snippet MEDCouplingExamplesTest.cxx CppSnippet_MEDCouplingUMesh_getPartMeasureField_3 +The returned array contains 4 tuples per 2 components. + + +\subsubsection cpp_mcumesh_getCellsContainingPoints Finding cells containing a point (multi-point case) + +First, we create a 2D mesh with 3 QUAD4 and 2 TRI3 cells. +\snippet MEDCouplingExamplesTest.cxx CppSnippet_MEDCouplingUMesh_getCellsContainingPoints_1 +Then we use +\ref ParaMEDMEM::MEDCouplingUMesh::getCellsContainingPoints "getCellsContainingPoints()" to +get cells in contact with tree points. Two of them are in contact with some cells and one is not. +\snippet MEDCouplingExamplesTest.cxx CppSnippet_MEDCouplingUMesh_getCellsContainingPoints_2 +The contents of the result arrays \b cells ([4, 0, 1]) and \b cellsIndex ([0, 0, 1, 3]) +mean the following. +- Point #0 is in contact with none (== \b cellsIndx[1] - \b cellsIndx[0]) cell. +- Point #1 is in contact with 1 (== \b cellsIndx[2] - \b cellsIndx[1]) cell whose id is #4 + (== \b cells[ \b cellsIndx[ 1 ]]). +- Point #2 is in contact with 2 (== \b cellsIndx[3] - \b cellsIndx[2]) cells whose ids are #0 + (== \b cells[ \b cellsIndx[ 2 ]]) and #1 (== \b cells[ \b cellsIndx[ 2 ] + 1 ]). + + +\subsubsection cpp_mcumesh_getCellsContainingPoint Finding cells containing a point + +First, we create a 2D mesh with 3 QUAD4 and 2 TRI3 cells. +\snippet MEDCouplingExamplesTest.cxx CppSnippet_MEDCouplingUMesh_getCellsContainingPoint_1 +Then we use +\ref ParaMEDMEM::MEDCouplingUMesh::getCellsContainingPoint "getCellsContainingPoint()" to +get cells in contact with a small ball (point with precision) located near the node #4 and +shifted from this node by its radius \b eps. +\snippet MEDCouplingExamplesTest.cxx CppSnippet_MEDCouplingUMesh_getCellsContainingPoint_2 +Since the node #4 is shared by all cells, size of the vector \b cellIds must be equal to +the number of cells in \b mesh. + + +\subsubsection cpp_mcumesh_buildPartOrthogonalField Getting normals of cells + +First, we create a 2D mesh with 3 QUAD4 and 2 TRI3 cells. Orientation of the cell #1 is +reversed. +\snippet MEDCouplingExamplesTest.cxx CppSnippet_MEDCouplingUMesh_buildPartOrthogonalField_1 +Now we use +\ref ParaMEDMEM::MEDCouplingUMesh::buildPartOrthogonalField "buildPartOrthogonalField()" to get +normal vectors to the cells. +\snippet MEDCouplingExamplesTest.cxx CppSnippet_MEDCouplingUMesh_buildPartOrthogonalField_2 + + +\subsubsection cpp_mcumesh_getPartMeasureField Getting volumes of cells + +First, we create a 2D mesh with 3 QUAD4 and 2 TRI3 cells. Orientation of the cell #1 is +reversed. +\snippet MEDCouplingExamplesTest.cxx CppSnippet_MEDCouplingUMesh_getPartMeasureField_1 +Now we use +\ref ParaMEDMEM::MEDCouplingUMesh::getPartMeasureField "getPartMeasureField()" to get +volumes of all but the first cell. If we call +\ref ParaMEDMEM::MEDCouplingUMesh::getPartMeasureField "getPartMeasureField()" with \b +isAbs == \c true, the area of the cell #1 is returned positive, else, negative that +reflects its inverse orientation. +\snippet MEDCouplingExamplesTest.cxx CppSnippet_MEDCouplingUMesh_getPartMeasureField_2 + + +\subsubsection cpp_mcumesh_getCellsInBoundingBox Getting cells using the bounding box + +First, we create a 2D mesh with 1 TRI3 cell. Bounding box of this cell is [0.,0., 1.,1]. +\snippet MEDCouplingExamplesTest.cxx CppSnippet_MEDCouplingUMesh_getCellsInBoundingBox_1 +Now we check how +\ref ParaMEDMEM::MEDCouplingUMesh::getCellsInBoundingBox "getCellsInBoundingBox()" +searches for cells using the bounding box. We use a bounding box touching the bounding box +of the sole cell at one point (1.,1.). +\snippet MEDCouplingExamplesTest.cxx CppSnippet_MEDCouplingUMesh_getCellsInBoundingBox_2 +If \ref ParaMEDMEM::MEDCouplingUMesh::getCellsInBoundingBox "getCellsInBoundingBox()" is +called with parameter \b eps == 0.0, the cell is not found because the two bounding boxes +(one of the cell and the one passed as parameter) do not overlap.
+If \ref ParaMEDMEM::MEDCouplingUMesh::getCellsInBoundingBox "getCellsInBoundingBox()" is +called with parameter \b eps == 0.1, the cell is found because \b eps is used to increase +the bounding box of the cell and thus the two bounding boxes intersect each other.
+ + +\subsubsection cpp_mcumesh_findBoundaryNodes Getting boundary nodes + +First, we create a 2D mesh with 3 QUAD4 and 2 TRI3 cells. +\snippet MEDCouplingExamplesTest.cxx CppSnippet_MEDCouplingUMesh_findBoundaryNodes_1 +Now we use +\ref ParaMEDMEM::MEDCouplingUMesh::findBoundaryNodes "findBoundaryNodes()" to get ids +of boundary nodes. +\snippet MEDCouplingExamplesTest.cxx CppSnippet_MEDCouplingUMesh_findBoundaryNodes_2 +\ref ParaMEDMEM::MEDCouplingUMesh::findBoundaryNodes "findBoundaryNodes()" returns all +node ids except the node #4 which is in the middle of \b mesh. + + +\subsubsection cpp_mcumesh_getCellIdsLyingOnNodes Getting cells by nodes + +First, we create a 2D mesh with 3 QUAD4 and 2 TRI3 cells. +\snippet MEDCouplingExamplesTest.cxx CppSnippet_MEDCouplingUMesh_getCellIdsLyingOnNodes_1 +In the following code we retrieve nodes of the cell #0 an then we call +\ref ParaMEDMEM::MEDCouplingUMesh::getCellIdsLyingOnNodes "getCellIdsLyingOnNodes()" +twice with these nodes and with varying last parameter \b allNodes as input. +\snippet MEDCouplingExamplesTest.cxx CppSnippet_MEDCouplingUMesh_getCellIdsLyingOnNodes_2 +
If the last parameter is \c true +\ref ParaMEDMEM::MEDCouplingUMesh::getCellIdsLyingOnNodes "getCellIdsLyingOnNodes()" looks +for cells whose all nodes are given to it, hence it finds the cell #0 only. +
If the last parameter is \c false +\ref ParaMEDMEM::MEDCouplingUMesh::getCellIdsLyingOnNodes "getCellIdsLyingOnNodes()" looks +for any cell whose nodes are given to it, hence it finds all cells of \b mesh because all +cells share the node #4. + + +\subsubsection cpp_mcumesh_getCellIdsFullyIncludedInNodeIds Getting cells by nodes + +First, we create a 2D mesh with 3 QUAD4 and 2 TRI3 cells. +\snippet MEDCouplingExamplesTest.cxx CppSnippet_MEDCouplingUMesh_getCellIdsFullyIncludedInNodeIds_1 +In the following code we retrieve nodes of two cells an then we use +\ref ParaMEDMEM::MEDCouplingUMesh::getCellIdsFullyIncludedInNodeIds +"getCellIdsFullyIncludedInNodeIds()" to find these cells by their nodes. +\snippet MEDCouplingExamplesTest.cxx CppSnippet_MEDCouplingUMesh_getCellIdsFullyIncludedInNodeIds_2 + + +\subsubsection cpp_mcumesh_buildDescendingConnectivity2 Retrieving the descending connectivity with orientation + +First, we create a 2D mesh with 3 QUAD4 and 2 TRI3 cells. +\snippet MEDCouplingExamplesTest.cxx CppSnippet_MEDCouplingUMesh_buildDescendingConnectivity2_1 +Now we get and check the descending connectivity. +\snippet MEDCouplingExamplesTest.cxx CppSnippet_MEDCouplingUMesh_buildDescendingConnectivity2_2 +Here we get connectivity of the cell #2 (#3 in FORTRAN mode) of \b mesh2 to see how +mutual orientation of cells in \b mesh and \b mesh2 is defined. +\snippet MEDCouplingExamplesTest.cxx CppSnippet_MEDCouplingUMesh_buildDescendingConnectivity2_3 +The contents of the result arrays \b desc and \b descIndx mean the following. +- The cell #0 of \b mesh (QUAD4) is bound by 4 (== \b descIndx[1] - \b descIndx[0]) + segments (SEG2) of \b mesh2 whose ids in FORTRAN mode are + - #1 (== \b desc[ \b descIndx[ 0 ]]), + - #2 (== \b desc[ \b descIndx[ 0 ] + 1 ]), + - #3 (== \b desc[ \b descIndx[ 0 ] + 2 ]) and + - #4 (== \b desc[ \b descIndx[ 0 ] + 3 ]). +
Ids are positive since order of nodes in the corresponding cells of \b mesh and \b mesh2 + are same. For example nodes of SEG2 #3 are [4,1] and nodes of QUAD4 #0 are [0,3,\b 4,\b 1]. +- The cell #1 of \b mesh (TRI3) is bound by 3 (== \b descIndx[2] - \b descIndx[1]) segements of + \b mesh2 whose ids in FORTRAN mode are: + - #-3 (== \b desc[ \b descIndx[ 1 ]]), + - #5 (== \b desc[ \b descIndx[ 1 ] + 1 ]) and + - #6 (== \b desc[ \b descIndx[ 1 ] + 2 ]). +
The id -3 means that order of nodes in SEG2 #3 ([4,1]) is different from the order of + these nodes in TRI3 #1: [\b 1,\b 4,2]. +- etc. + +The contents of the result arrays \b revDesc and \b revDescIndx mean the following. +- The cell #0 of \b mesh2 (SEG2) bounds 1 (== \b revDescIndx[1] - \b revDescIndx[0]) cell of \b + mesh whose id is: + - # 0 (== \b revDesc[ \b revDescIndx[ 0 ]]). +- The cell #1 of \b mesh2 bounds 2 (== \b revDescIndx[2] - \b revDescIndx[1]) cells of \b + mesh whose ids are: + - # 0 (== \b revDesc[ \b revDescIndx[ 1 ]]) and + - # 1 (== \b revDesc[ \b revDescIndx[ 1 ] + 1 ]). +- etc. + + +\subsubsection cpp_mcumesh_buildDescendingConnectivity Retrieving the descending connectivity + +First, we create a 2D mesh with 3 QUAD4 and 2 TRI3 cells. +\snippet MEDCouplingExamplesTest.cxx CppSnippet_MEDCouplingUMesh_buildDescendingConnectivity_1 +Now we get and check the descending connectivity. +\snippet MEDCouplingExamplesTest.cxx CppSnippet_MEDCouplingUMesh_buildDescendingConnectivity_2 +The contents of the result arrays \b desc and \b descIndx mean the following. +- The cell #0 of \b mesh (QUAD4) is bound by 4 (== \b descIndx[1] - \b descIndx[0]) + segments (SEG2) of \b mesh2 whose ids are + - #0 (== \b desc[ \b descIndx[ 0 ]]), + - #1 (== \b desc[ \b descIndx[ 0 ] + 1 ]), + - #2 (== \b desc[ \b descIndx[ 0 ] + 2 ]) and + - #3 (== \b desc[ \b descIndx[ 0 ] + 3 ]). +- The cell #1 of \b mesh (TRI3) is bound by 3 (== \b descIndx[2] - \b descIndx[1]) segements of + \b mesh2 whose ids are: + - #2 (== \b desc[ \b descIndx[ 1 ]]), + - #4 (== \b desc[ \b descIndx[ 1 ] + 1 ]) and + - #5 (== \b desc[ \b descIndx[ 1 ] + 2 ]). +- etc. + +The contents of the result arrays \b revDesc and \b revDescIndx mean the following. +- The cell #0 of \b mesh2 (SEG2) bounds 1 (== \b revDescIndx[1] - \b revDescIndx[0]) cell of \b + mesh whose id is: + - # 0 (== \b revDesc[ \b revDescIndx[ 0 ]]). +- The cell #1 of \b mesh2 bounds 2 (== \b revDescIndx[2] - \b revDescIndx[1]) cells of \b + mesh whose ids are: + - # 0 (== \b revDesc[ \b revDescIndx[ 1 ]]) and + - # 1 (== \b revDesc[ \b revDescIndx[ 1 ] + 1 ]). +- etc. + + +\subsubsection cpp_mcumesh_getReverseNodalConnectivity Getting the reverse nodal connectivity + +First, we create a 2D mesh with 3 QUAD4 and 2 TRI3 cells. +\snippet MEDCouplingExamplesTest.cxx CppSnippet_MEDCouplingUMesh_getReverseNodalConnectivity_1 +Now we get and check its reverse nodal connectivity. +\snippet MEDCouplingExamplesTest.cxx CppSnippet_MEDCouplingUMesh_getReverseNodalConnectivity_2 +The contents of the result arrays mean the following. +- Node #0 is shared by 1 (== \b revNodalIndx[1] - \b revNodalIndx[0]) cell whose id is #0 + (== \b revNodal[ \b revNodalIndx[ 0 ]]). +- Node #1 is shared by 2 (== \b revNodalIndx[2] - \b revNodalIndx[1]) cells whose ids are #0 + (== \b revNodal[ \b revNodalIndx[ 1 ]]) and #1 (== \b revNodal[ \b revNodalIndx[ 1 ] + 1 ]). +- etc. + + +\subsubsection cpp_mcpointset_getBoundingBox Getting a minimum box bounding nodes + +First, we create a 3D mesh with 2 nodes, so that the first one has minimal coordinates and +the second one has maximal coordinates. +\snippet MEDCouplingExamplesTest.cxx CppSnippet_MEDCouplingPointSet_getBoundingBox_1 +Now we get a bounding box enclosing these nodes. This bounding box should contain +coordinates of our two nodes (but in "no interlace" mode), as the nodes coincide with +points returned by the bounding box. +\snippet MEDCouplingExamplesTest.cxx CppSnippet_MEDCouplingPointSet_getBoundingBox_2 + + +\subsubsection cpp_mcpointset_getnodeidsnearpoint Getting nodes close to a point + +The following code creates a 2D \ref ParaMEDMEM::MEDCouplingUMesh +"MEDCouplingUMesh" with 5 nodes and no cells. +\snippet MEDCouplingExamplesTest.cxx CppSnippet_MEDCouplingPointSet_getNodeIdsNearPoint_1 +Now we define an array of coordinates of a point close to nodes #0, #2 and #4. + +Thus we expect that +\ref ParaMEDMEM::MEDCouplingPointSet::getNodeIdsNearPoint "getNodeIdsNearPoint()" that +we are going to use, +if called with \b eps = 0.003, would return ids of nodes #0, #2 and #4. +\snippet MEDCouplingExamplesTest.cxx CppSnippet_MEDCouplingPointSet_getNodeIdsNearPoint_2 + + +\subsubsection cpp_mcpointset_getnodeidsnearpoints Getting nodes close to some points + +The following code creates a 2D \ref ParaMEDMEM::MEDCouplingUMesh +"MEDCouplingUMesh" with 7 nodes and no cells. +\snippet MEDCouplingExamplesTest.cxx CppSnippet_MEDCouplingPointSet_getNodeIdsNearPoints_1 +Now we define an array of coordinates of 3 points near which we want to find nodes of the mesh. +- Point #0 is at distance 0.001 from the node #1. +- Point #1 is rather far from all nodes. +- Point #2 is close to nodes #3, #4 and #5. + +Thus we expect that +\ref ParaMEDMEM::MEDCouplingPointSet::getNodeIdsNearPoints "getNodeIdsNearPoints()" that +we are going to use, +if called with \b eps = 0.003, would return ids of close nodes #1, #3, #4 and #5. +\snippet MEDCouplingExamplesTest.cxx CppSnippet_MEDCouplingPointSet_getNodeIdsNearPoints_2 +\b idsIndex returns [0, 1, 1, 4] which means that: +- Point #0 is close to 1 (== \b idsIndex[1] - \b idsIndex[0]) node whose id is +\b ids[ \b idsIndex[ 0 ]]. +- Point #1 is close to 0 (== \b idsIndex[2] - \b idsIndex[1]) nodes. +- Point #2 is close to 3 (== \b idsIndex[3] - \b idsIndex[2]) nodes whose ids are +\b ids[ \b idsIndex[ 2 ]], \b ids[ \b idsIndex[ 2 ] + 1 ] and \b ids[ \b idsIndex[ 2 ] + 2 ]. + + +\subsubsection cpp_mcpointset_findcommonnodes Finding coincident nodes + +First, we create a mesh with 6 nodes, of which two nodes (#3 and #4) are fully coincident +and 3 nodes (#0, #2 and #5) have distance less than 0.004 between them. +\snippet MEDCouplingExamplesTest.cxx CppSnippet_MEDCouplingPointSet_findCommonNodes_1 +Then, we use \ref ParaMEDMEM::MEDCouplingPointSet::findCommonNodes() "findCommonNodes()" to find +coincident nodes, and check that (1) calling +\ref ParaMEDMEM::MEDCouplingPointSet::findCommonNodes() "findCommonNodes()" with \b prec +== 1e-13 finds the two fully coincident nodes only and (2) +\ref ParaMEDMEM::MEDCouplingPointSet::findCommonNodes() "findCommonNodes"(0.004) finds 5 +equal nodes. +\snippet MEDCouplingExamplesTest.cxx CppSnippet_MEDCouplingPointSet_findCommonNodes_2 diff --cc medtool/doc/user/doxygen/doxfiles/reference/distrib/parallel.dox index d53c9965f,000000000..0c197817a mode 100644,000000..100644 --- a/medtool/doc/user/doxygen/doxfiles/reference/distrib/parallel.dox +++ b/medtool/doc/user/doxygen/doxfiles/reference/distrib/parallel.dox @@@ -1,33 -1,0 +1,81 @@@ +/*! +\page parallel Parallelism + - \section para-over Base elements ++\section para-over Building blocks + +Several classes and methods are available in the MED library to ease the exchange of information - in a parallel context. - For historical reasons, they are all in the same namespace as the non-parallel MEDCoupling functionalities, ++in a parallel context. The DECs (\ref para-dec "detailed further down") then use those classes to enable ++the parallel remapping (projection) of a field. ++For historical reasons, all those items are in the same namespace as the non-parallel MEDCoupling functionalities, +%ParaMEDMEM. + +The core elements of the API are: - - \ref ParaFIELD-det "ParaFIELD", the parallel instanciation of a MEDCoupling field - - \ref CommInterface-det "CommInterface", communication interface to the gateway to the MPI library - - \ref MPIProcessorGroup-det "MPIProcessorGroup", a group of processor in a parallel computation - - along with all the DEC explained below. ++- \ref CommInterface-det "CommInterface", this is the wrapper around the MPI library, and an instance ++of this object is required in many constructors of the following objects. ++- \ref ParaMESH-det "ParaMESH", the parallel instanciation of a \ref meshes "MEDCoupling mesh" ++- \ref ParaFIELD-det "ParaFIELD", the parallel instanciation of a \ref fields "MEDCoupling field" ++- \ref MPIProcessorGroup-det "MPIProcessorGroup" (which inherits from the abstract ++\ref ParaMEDMEM::ProcessorGroup "ProcessorGroup"), a group of processors (typically MPI nodes) + ++In an advanced usage, the topology of the nodes in the computation is accessed through the following elements: ++- \ref BlockTopology-det "BlockTopology", specification of a topology based on the (structured) mesh. ++The mesh is divided in block (typically a split along the first axis) which are allocated on the various ++processors. ++- %ExplicitTopology (not fully supported yet and only used internally), specification of user-defined ++topology, still based on the mesh. ++- \ref ComponentTopology-det "ComponentTopology", specification of a topology allowing the split of ++several field *components* among different processors. The mesh is not the support of the topology anymore. ++ +\section para-dec Data Exchange Channel - DEC + - A Data Exchange Channel allows the transfer of information between two processor groups. - There are several variants of DEC depending on what you are aiming at: ++A Data Exchange Channel (%DEC) allows the transfer and/or the interpolation (remapping) of field data between several ++processors in a parallel (MPI) context. ++Some DECs perform a simple renumbering and copy of the data, and some are capable of functionalities similar to the ++\ref remapper "sequential remapper". + - - \ref DisjointDEC-det "DisjointDEC" - - \ref InterpKernelDEC-det "InterpKernelDEC" - - \ref NonCoincidentDEC-det "NonCoincidentDEC" - - \ref OverlapDEC-det "OverlapDEC" - - \ref ExplicitCoincidentDEC-det "ExplicitCoincidentDEC" - - \ref StructuredCoincidentDEC-det "StructuredCoincidentDEC" - - TODO: more on DEC. ++We list here the main characteristics of the DECs, the list being structured in the same ++way as the class hierarchy: ++ ++- \ref DisjointDEC-det "DisjointDEC", works with two disjoint groups of processors. This is an abstract class. ++ - \ref InterpKernelDEC-det "InterpKernelDEC", inherits the properties of the \c %DisjointDEC. The projection ++ methodology is based on the algorithms of %INTERP_KERNEL, that is to say, they work in a similar fashion than ++ what the \ref remapper "sequential remapper" does. The following \ref discretization "projection methods" ++ are supported: P0->P0 (the most common case), P1->P0, P0->P1. ++ - \ref StructuredCoincidentDEC-det "StructuredCoincidentDEC", also inherits the properties ++ of the \c %DisjointDEC, but this one is \b not based on the %INTERP_KERNEL algorithms. ++ This DEC does a simple data transfer between two fields having a common (coincident) structured support, ++ but different topologies (i.e. the structured domain is split differently among the processors for the ++ two fields). Only the cell identifiers are handled, and no kind of interpolation (in the sense of the ++ computation of a weight matrix) is performed. It is a "mere" reallocation of data from one domain ++ partitioning to another. ++ - \b ExplicitCoincidentDEC : as above, but based on an explicit topology. This DEC is used internally but ++ rarely directly in the public API. ++- \ref OverlapDEC-det "OverlapDEC", works with a single processor group, but each processor detains ++both (part of) the source and target fields. This %DEC can really be seen as the true parallelisation of the ++\ref remapper "sequential remapper". Similarly to the \ref InterpKernelDEC-det "InterpKernelDEC" ++the projection methodology is based on the algorithms of %INTERP_KERNEL, that is to say, ++it works in a similar fashion than what the \ref remapper "sequential remapper" does. ++- \b NonCoincidentDEC (deprecated for now) ++ ++Besides, all the DECs inherit from the class \ref ParaMEDMEM::DECOptions "DECOptions" which provides ++the necessary methods to adjust the parameters used in the transfer/remapping. ++ ++The most commonly used %DEC is the \c %InterpKernelDEC, and here is a simple example to of its usage: ++ ++ \code ++... ++InterpKernelDEC dec(groupA, groupB); // groupA and groupB are two MPIProcessorGroup ++dec.attachLocalField(field); // field is a ParaFIELD, a MEDCouplingField or an ICoCo::MEDField ++dec.synchronize(); // compute the distributed interpolation matrix ++if (groupA.containsMyRank()) ++dec.recvData(); // effectively transfer the field (receiving side) ++else if (groupB.containsMyRank()) ++dec.sendData(); // effectively transfer the field (sending side) ++... ++\endcode + ++\n ++\n ++\n + +*/ diff --cc medtool/doc/user/doxygen/doxfiles/reference/fields/discretization.dox index 907890bae,000000000..6789241ce mode 100644,000000..100644 --- a/medtool/doc/user/doxygen/doxfiles/reference/fields/discretization.dox +++ b/medtool/doc/user/doxygen/doxfiles/reference/fields/discretization.dox @@@ -1,21 -1,0 +1,56 @@@ +/*! +\page discretization Spatial and temporal discretizations + - TODO: enhance this page ++When defining a field in MEDCoupling, the notions of spatial and temporal discretizations play ++a crucial role. ++ ++The spatial discretization details the relationship between the field and its support mesh ++and the temporal discretization gives an indication of the time coverage represented ++by the field. + +\section field-space Spatial discretization +A field can be supported by: - - the nodes (vertices) of the mesh: built with the - \ref ParaMEDMEM::MEDCouplingFieldDouble::New "ON_NODES" keyword. This is sometimes called a P1 field. ++- the nodes (vertices) of the mesh: this is built with the ++\ref ParaMEDMEM::TypeOfField "ON_NODES" keyword in the ++\ref ParaMEDMEM::MEDCouplingFieldDouble::New(TypeOfField , TypeOfTimeDiscretization) "constructor of a field". ++ +- the cells (or "elements") of the mesh: built with the - \ref ParaMEDMEM::MEDCouplingFieldDouble::New "ON_CELLS" keyword. This is sometimes called a P0 field. - - or more complex items (Gauss points, etc ...) ++\ref ParaMEDMEM::TypeOfField "ON_CELLS" keyword in the ++\ref ParaMEDMEM::MEDCouplingFieldDouble::New(TypeOfField , TypeOfTimeDiscretization) "constructor of a field". ++- or more complex items: ++ - Gauss points: built with \ref ParaMEDMEM::TypeOfField "ON_GAUSS_PT" ++ - Gauss points on nodes per element: built with \ref ParaMEDMEM::TypeOfField "ON_GAUSS_NE" ++ - Kriging points: built with \ref ParaMEDMEM::TypeOfField "ON_NODES_KR" ++ ++The spatial discretization is at the center of the \ref interpolation "interpolation" mechanisms, ++since one of the main interpolation paramter is indeed specifying from which source discretization ++to which target discretization one wants to go. For example: ++- a P0->P0 interpolation means that a field on cells will be transfered to another cell-based field; ++- a P1->P0 interpolation means that a field on nodes this time will be transfered to a cell-based field. ++- etc ... ++ ++Finally, in the code itself, the class \ref ParaMEDMEM::MEDCouplingFieldDiscretization "MEDCouplingFieldDiscretization" ++is the concrete representation of this concept. + +\section field-time Temporal discretization + - A field has a temporal discretization. It can be one of: - - \ref ParaMEDMEM::MEDCouplingFieldDouble::New "NO_TIME" - - \ref ParaMEDMEM::MEDCouplingFieldDouble::New "ONE_TIME" - - \ref ParaMEDMEM::MEDCouplingFieldDouble::New "CONST_ON_TIME_INTERVAL" ++Similarly to the spatial discretization, a field object in MEDCoupling has a time discretization ++representing the time range that is covered by the data. It is also specified in the ++\ref ParaMEDMEM::MEDCouplingFieldDouble::New(TypeOfField , TypeOfTimeDiscretization) "constructor of a field". ++ ++It can be one of: ++- \ref ParaMEDMEM::TypeOfTimeDiscretization "NO_TIME", in this case no time is attached to the field, and no ++time-related operation is permitted (for example unable to call ++\ref ParaMEDMEM::MEDCouplingFieldDouble::getValueOn "getValueOn()") ++- \ref ParaMEDMEM::TypeOfTimeDiscretization "ONE_TIME", the field data represent a single time step. ++- \ref ParaMEDMEM::TypeOfTimeDiscretization "LINEAR_TIME", the field data contains \b two arrays, stamped with two ++different time points. A linear interpolation of the field values between those two time steps is then possible. ++- \ref ParaMEDMEM::TypeOfTimeDiscretization "CONST_ON_TIME_INTERVAL", the field data contains a single array ++of data, but a start- and end-time can be specified, thus declaring that the field represent a constant ++set of data during this time interval. All time evaluation function then just check that the given time ++fits in the interval. ++ ++Finally, in the code itself, the class \ref ParaMEDMEM::MEDCouplingTimeDiscretization "MEDCouplingTimeDiscretization" ++is the concrete representation of this concept. + +*/ diff --cc medtool/doc/user/doxygen/doxfiles/reference/interpolation/Geometric2D.dox index eb0e25daf,000000000..a00934f61 mode 100644,000000..100644 --- a/medtool/doc/user/doxygen/doxfiles/reference/interpolation/Geometric2D.dox +++ b/medtool/doc/user/doxygen/doxfiles/reference/interpolation/Geometric2D.dox @@@ -1,237 -1,0 +1,237 @@@ +/*! +\page interpkernelGeo2D Geometric2D Intersector + +Like other intersectors the aim of this intersector is to compute intersection between 2 +polygons.\n +The specificity of this intersector is to deal with \b any \b type of +polygons even those with \b quadratic \b edges. +Its quite generic architecture allows him to deal with some other +potentially useful functions.\n +This page described Geometric2D intersector basic principles and +specific usage. + +\section interpkernelGeo2DIntro Introduction + +The principle used in this intersector to perform boolean operation on geometry is geometric-modeler like. +The data structure used to describe polygons is boundary description. That is to say the internal +representation of a polygon is its edges composing it. + +\subsection interpkernelGeo2DNamingConv Naming conventions + + - An \ref INTERP_KERNEL::Edge "edge" is defined by a start + node, a end node and a curve equation (linear or arc of + circle). \b WARNING : start node and end node \b HAVE \b TO \b BE + different and distant at least equal to precision set. + - An \ref INTERP_KERNEL::ElementaryEdge "elementary edge" is an edge \b NOT \b splittable \b without \b applying + \b mathematical \b intersection \b computation. + - A \ref INTERP_KERNEL::ComposedEdge "composed edge" is a collection of consecutive edges hierarchically \b splittable + \b without \b any \b mathematical \b intersection \b computation. + +Consecutive means that in a composed edge if edge \a e2 follows edge +\a e1, the end node of \a e1 is geometrically equal to start node of +\a e2. + +\subsection interpkernelGeo2DBasicConcepts Basic concepts + +A \ref INTERP_KERNEL::QuadraticPolygon "quadratic polygon" is a +specialization of a +\ref INTERP_KERNEL::ComposedEdge "composed edge" in that it is +closed. Closed means that the start node of first edge is equal to end +node of last edge.\n +A \ref INTERP_KERNEL::ComposedEdge "composed edge" is considered as a +collection of \ref INTERP_KERNEL::Edge "abstract edges". An +\ref INTERP_KERNEL::Edge "abstract edge" is either an \ref +INTERP_KERNEL::ElementaryEdge "elementary edge" or itself a \ref +INTERP_KERNEL::ComposedEdge "composed edge".\n A composite pattern has +been used here. + +Each \ref INTERP_KERNEL::ElementaryEdge " elementary edge" and each +\ref INTERP_KERNEL::Node "nodes" have a flag that states if during +the split process if it is \b out, \b on, \b in or \b unknown. + +\section interpkernelGeo2DBoolOp Boolean operation algorithm + +\subsection interpkernelGeo2DBoolOpPrinc Basics + +The boolean operation (intersection) between two polygons is used in P0 P0 interpolation. + +The process of boolean operations between two polygons P1 and P2 is done in three steps : + + -# \ref interpkernelGeo2DBoolOpStep1 "splitting". + -# \ref interpkernelGeo2DBoolOpStep2 "edges localization". + -# \ref interpkernelGeo2DBoolOpStep3 "result polygons building". + +\subsection interpkernelGeo2DBoolOpStep1 Step1 : splitting. + +The principle used to do boolean operations between 2 polygons P1 and +P2 is to intersect each edge of P1 with each edge of P2. \n After this +edge-splitting, polygon P1 is splitted, so that each +\ref INTERP_KERNEL::ElementaryEdge "elementary edge" constituting P1 +is either \b in, \b out or \b on polygon P2. And inversely, polygon P2 is splitted so that each +\ref INTERP_KERNEL::ElementaryEdge "elementary edge" constituting P2 +is either \b in, \b out or \b on polygon P1. + +During split process, when, without any CPU overhead, the location can be +deduced, the nodes and edges are localized. + +This step of splitting is common to all boolean operations.\n +The method in charge of that is INTERP_KERNEL::QuadraticPolygon::splitPolygonsEachOther. + +\subsection interpkernelGeo2DBoolOpStep2 Step2 : Edges localization. + +Perform localization of each splitted edge. As \ref interpkernelGeo2DBoolOpStep1 "split process" it + is common to all boolean operations. + +When the location of edges has \b not been +already deduced in previous computation and there is no predecessor, the +\ref interpkernelGeo2DAlgLoc "localization is done in absolute". +After it deduces the localization relatively to the previous edge +thanks to node localization.\n The relative localization is done +following these rules : + + * + * + * + * + * + * + * + * + * + * + *
Previous Edge LocCurrent start node Loc Current edge Loc
UNKNOWN ANY UNKNOWN -> \ref interpkernelGeo2DAlgLoc "Absolute search"
OUT ON IN
OUT ON_TANGENT OUT
IN ON OUT
IN ON_TANGENT IN
OUT OUT OUT
IN IN IN
ON ANY UNKNOWN -> \ref interpkernelGeo2DAlgLoc "Absolute search"
+ +The method in charge of that is INTERP_KERNEL::QuadraticPolygon::performLocatingOperation. + +\subsection interpkernelGeo2DBoolOpStep3 Step3 : Result polygon building. + +This stage links each edge with wanted loc. \b Contrary to last 2 steps it is obviously boolean +operation dependant. Let's take the case of the intersection that is used in +P0->P0 interpolation. \n The principle of result polygon building is to build polygon by taking +edges localized as \b in or \b on. + +Generally, the principle is to take an edge in \a P1 with wanted loc and linking +direct neighbour-edges (with correct loc) until closing a polygon. If +not, using \a P2 edges to try to close polygon. The process is +repeated until all edges with correct loc have been consumed. + +The method in charge of that is INTERP_KERNEL::QuadraticPolygon::buildIntersectionPolygons. + +\section interpkernelGeo2DAlg Underlying algorithms + +\subsection interpkernelGeo2DAlgLoc Absolute localization algorithm + +This algorithm is called when splitting process has been done, and +that we are sure that the edge is either \b fully \b in ,or \b fully \b on or \b fully +\b out. + +The principle chosen to know if an edge \a E is completely included in an +any polygon \a P is to see if its barycenter \a B is inside this any +polygon \a P. +After, for each nodes \f$ P_i \f$ of polygon \a P we store angle in \f$ [-\pi/2,\pi/2 ] \f$ +that represents the slope of line \f$ (BP_i) \f$.\n +Then a line \a L going through \a B with a slope being as far as +possible from all slopes found above. Then the algorithm goes along \a L +and number of times \a N it intersects \b non-tangentially the any polygon \a P. + +If \a N is odd \a B (and then \a E) is IN. +If \a N is even \a B (and then \a E) is OUT. + +This computation is \b very \b expensive, that why some tricks as described in +\ref interpkernelGeo2DBoolOpStep2 "localization techniques" are used to call as few as possible +during intersecting process. + +\subsection interpkernelGeo2DAlgIntsect Intersection algorithms + +The only mathematical intersections performed are edges intersections. +The algorithms used are : + + -# Lin-Lin intersection : http://mathworld.wolfram.com/Line-LineIntersection.html + -# Lin-Arc intersection : http://mathworld.wolfram.com/Circle-LineIntersection.html + -# Arc-Arc intersection : http://mathworld.wolfram.com/Circle-CircleIntersection.html + +\subsection interpkernelGeo2DAlgOthers Other algorithms + +As internal architecture is quite general, it is possible to have more than classical intersection on any polygons : + - - \ref INTERP_KERNEL::ComposedEdge::getAreaOfZone "area" computation is available. - - \ref INTERP_KERNEL::QuadraticPolygon::getPerimeterFast "perimeter" computation. - - \ref INTERP_KERNEL::QuadraticPolygon::getHydraulicDiameter "Hydraulic diameter" computation. ++ - \ref INTERP_KERNEL::ComposedEdge::getArea "area" computation is available. ++ - \ref INTERP_KERNEL::ComposedEdge::getPerimeter "perimeter" computation. ++ - \ref INTERP_KERNEL::ComposedEdge::getHydraulicDiameter "Hydraulic diameter" computation. + +\section interpkernelGeo2DUsage Usage + +This intersector is usable standalone. To use a set of user friendly methods have been implemented. + + - INTERP_KERNEL::QuadraticPolygon::buildArcCirclePolygon method builds from a \c std::vector of INTERP_KERNEL::Node* \a V, an instance of QuadraticPolygon \a P. + \a P will have \f$ N_{edges} = V.size()/2 \f$ edges. Quadratic edge \f$ Edge_i i \in [0,N_{edges}-1] \f$ starts with node V[i], ends with node V[i+1] and has a middle in + \f$ V[i+N_{edge}] \f$. \n If start, end and middle nodes of edge \f$ Edge_i \f$ are aligned by a precision specified by INTERP_KERNEL::QUADRATIC_PLANAR::setArcDetectionPrecision. + - INTERP_KERNEL::QuadraticPolygon::buildLinearPolygon method builds from a \c std::vector of INTERP_KERNEL::Node* \a V, an instance of QuadraticPolygon \a + P. \a P will have \f$ N_edges = V.size() \f$ edges. Linear edge \f$ Edge_i i \in [0,N_{edges}-1] \f$ starts with node V[i] and ends with node V[i+1]. + +The orientation of polygons (clockwise, inverse clockwise) impact computation only on the sign of areas. During intersection of 2 polygons their orientation can be different. + +The usage is simple : + +\code +... +// defining a precision +INTERP_KERNEL::QUADRATIC_PLANAR::setPrecision(1e-5); +INTERP_KERNEL::QUADRATIC_PLANAR::setArcDetectionPrecision(1e-5); +// +INTERP_KERNEL::QuadraticPolygon *polygon1=...; +bool isQuadratic=...//Depends on the nature of your cell. If your cell is MED_QUAD8 or MED_TRIA6 for example isQuadratic=true. +const double *externalTabXCoords=...; +const double *externalTabYCoords=...; +std::vector nodes; +INTERP_KERNEL::QuadraticPolygon *polygon2=0; +for(int i=0;iintersectWith(*polygon2); +double dhydPol1=polygon1->getHydraulicDiameter(); +double areaPol1=polygon1->getAreaOfZone(); +//clean-up +delete polygon1; +delete polygon2; +... +\endcode + +\section interpkernelGeo2DExample Example of result + +Here an example of 2 polygons. The left one \a P1 has 4 edges and the +right one \a P2 has 4 edges too. + +\anchor interpkernelGeo2DEx1 +\image html SampGeo2D1.png "An example of intersection of 2 polygons." +\image latex SampGeo2D1.eps "An example of intersection of 2 polygons." + +After \ref interpkernelGeo2DBoolOpStep1 "spliting process" \a P1 has 6 edges and \a P2 has 6 edges too. + +\anchor interpkernelGeo2DEx2 +\image html SampGeo2D2.png "After spliting process two edges of P1 have been located has out." +\image latex SampGeo2D2.eps "After spliting process two edges of P1 have been located has out." + +\note BLUE is for OUT, GREEN for IN and RED for ON. + +For each 6 edges \ref interpkernelGeo2DBoolOpStep2 "locate" them. + +\anchor interpkernelGeo2DEx3 +\image html SampGeo2D3.png "Result after locating phase." +\image latex SampGeo2D3.eps "Result after locating phase." + +Too finish \ref interpkernelGeo2DBoolOpStep3 "closing" polygons. + +\anchor interpkernelGeo2DEx4 +\image html SampGeo2D4.png "Close-up of final result after close polygons phase." +\image latex SampGeo2D4.eps "Close-up of final result after close polygons phase." + +\note The result polygon is constituted of 2 sub-edges coming from \a P1 +and 1 sub-edge from \a P2 closing the polygon. For the 2 edges of \a P1 +they are green because they are fully included in \a P2. Inversely, +the only sub-edge coming from \a P2 is fully included in \a P1. + +*/ diff --cc medtool/doc/user/doxygen/doxfiles/reference/interpolation/interpolation.dox index ef9db963e,000000000..e8319c70d mode 100644,000000..100644 --- a/medtool/doc/user/doxygen/doxfiles/reference/interpolation/interpolation.dox +++ b/medtool/doc/user/doxygen/doxfiles/reference/interpolation/interpolation.dox @@@ -1,25 -1,0 +1,27 @@@ +/*! + +\page interpolation Interpolation + - Interpolation (or projection) methods is a key feature of the MEDCoupling library. ++Interpolation (or projection) methods are a key feature of the MEDCoupling library. +It allows to "transfer" the values of a field on a given source mesh to another, newly created field +on a target mesh. + +The two meshes/fields need not to have the same \ref MEDCouplingMeshes "mesh/spatial dimension", nor do they need to have the same \ref discretization "discretization". + ++ ++ +- \subpage intro-interp +- \subpage InterpKerRemapGlobal +- \subpage NatureOfField +- \subpage remapper +- \subpage InterpKerIntersectors + +If you are looking for a parallel utilisation of the above, take a look at: + +- \ref parallel + +Some implementation details of the C++ code can be found in appendix: + +- \ref interpkernel + +*/ diff --cc medtool/doc/user/doxygen/doxfiles/reference/interpolation/intersectors.dox index c38a87965,000000000..1729060bd mode 100644,000000..100644 --- a/medtool/doc/user/doxygen/doxfiles/reference/interpolation/intersectors.dox +++ b/medtool/doc/user/doxygen/doxfiles/reference/interpolation/intersectors.dox @@@ -1,17 -1,0 +1,18 @@@ +/*! + - \page InterpKerIntersectors Intersectors ++\page InterpKerIntersectors Intersectors and point locators + +The various interpolation methods often require the computation of the intersection between - a cell of the source mesh and a cell of the target mesh. The intersectors implemented in the ++a cell of the source mesh and a cell of the target mesh, or the localization of a point ++inside another mesh. The intersectors implemented in the +library take care of this job. + +Before reading on, remember the definition of a \ref glossary "P0 and P1 field". + +- \subpage intersec-specifics +- \subpage interpkernelGeo2D - - \subpage barycoords (used in some P1 intersectors) ++- \subpage barycoords (used in some P1 intersectors/locators) + +Some implementation details of the C++ code can also be found here: \ref interpkernel + +*/ diff --cc medtool/doc/user/doxygen/doxy2swig/doxy2swig.cmake index 1e3ed568a,000000000..b497ef358 mode 100644,000000..100644 --- a/medtool/doc/user/doxygen/doxy2swig/doxy2swig.cmake +++ b/medtool/doc/user/doxygen/doxy2swig/doxy2swig.cmake @@@ -1,113 -1,0 +1,113 @@@ +# Copyright (C) 2012-2015 CEA/DEN, EDF R&D +# +# 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +# +# See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com +# + +## +## This module is dedicated to the generation of specific SWIG files (".i") containing +## the docstrings built from the C++ doxygen documentation. +## + +SET(_DOXY2SWIG ${PROJECT_SOURCE_DIR}/doc/user/doxygen/doxy2swig/doxy2swig.py) +SET(_SWIG_DOC_SUFFIX "doc_class_") + +# +# MEDCoupling classes to include +# +SET(_classes_MEDCoupling - ParaMEDMEM_1_1MEDCouplingPointSet - ParaMEDMEM_1_1MEDCouplingUMesh - ParaMEDMEM_1_1MEDCouplingCMesh - ParaMEDMEM_1_1MEDCouplingRemapper - ParaMEDMEM_1_1DataArray - ParaMEDMEM_1_1DataArrayInt ++# ParaMEDMEM_1_1MEDCouplingPointSet ++# ParaMEDMEM_1_1MEDCouplingUMesh ++# ParaMEDMEM_1_1MEDCouplingCMesh ++# ParaMEDMEM_1_1MEDCouplingRemapper ++# ParaMEDMEM_1_1DataArray ++# ParaMEDMEM_1_1DataArrayInt + ParaMEDMEM_1_1DataArrayDouble + ) + +# +# MEDLoader classes to include +# +SET(_classes_MEDLoader - MEDLoader - ParaMEDMEM_1_1MEDFileMeshes - ParaMEDMEM_1_1MEDFileMesh - ParaMEDMEM_1_1MEDFileUMesh ++# MEDLoader ++# ParaMEDMEM_1_1MEDFileMeshes ++# ParaMEDMEM_1_1MEDFileMesh ++# ParaMEDMEM_1_1MEDFileUMesh + ParaMEDMEM_1_1MEDFileCMesh + ) + +## +## Generates the ".i" files from a list of C++ classes. +## +## \param[in] target_doc main target for the stantard doxygen generation +## \param[in] target_swig dummy target encompassing the final build of all SWIG files +## \param[in] cls_list list of classes for which to generate SWIG files +## \param[in] swig_main_file main SWIG file including the other generated SWIG files +## \param[out] swig_files list of generated SWIG files +## +MACRO(SALOME_MED_SWIG_DOCSTRING_GENERATE target_doc target_swig cls_list swig_main_file swig_files) + # List of generated SWIG files (.i) for doc purposes only: + SET(${swig_files}) + FOREACH(_cls IN LISTS ${cls_list}) + SET(_xml_file "${CMAKE_CURRENT_BINARY_DIR}/../doxygen/doc_ref_user/xml/class${_cls}.xml") + SET(_swig_file_base "${_SWIG_DOC_SUFFIX}${_cls}.i") + SET(_swig_file "${PROJECT_BINARY_DIR}/doc/${_swig_file_base}" ) + + # SWIG doc files will always be generated *after* Doxygen is run: + ### WARNING: ADD_CUSTOM_COMMAND(TARGET xxx POST_BUILD ...) command + ### must be in exactly the same subdir as the initial target construction command. + ### That's why this file is included with an INCLUDE() rather than using ADD_SUBDIRECTORY + # Note: we touch the main .i file to be sure to retrigger swig when the doc in a included + # class changes. + ADD_CUSTOM_COMMAND(OUTPUT ${_swig_file} + COMMAND ${PYTHON_EXECUTABLE} ${_DOXY2SWIG} "-n" ${_xml_file} ${_swig_file} + COMMAND ${CMAKE_COMMAND} -E touch_nocreate ${swig_main_file} + DEPENDS ${_xml_file} + COMMENT "Generating docstring SWIG file (from Doxygen's XML): ${_swig_file_base}" + VERBATIM + ) + ADD_CUSTOM_TARGET(${_swig_file_base} DEPENDS ${_swig_file}) + # The doxy2swig script is executed once the doxygen documentation has been generated ... + ADD_DEPENDENCIES(${_swig_file_base} ${target_doc}) + # ... and the meta target 'swig_ready' (here ${target_swig}) is ready when all .i files + # have been generated: + ADD_DEPENDENCIES(${target_swig} ${_swig_file_base}) + + LIST(APPEND ${swig_files} ${_swig_file_base}) + ENDFOREACH() +ENDMACRO(SALOME_MED_SWIG_DOCSTRING_GENERATE) + + +## +## Configures the MEDCoupling_doc.i or MEDLoader_doc.i file so that they include +## the list of SWIG files generated by the macro above. +## +## \param[in] target_doc main target for the stantard doxygen generation +## \param[in] target_swig dummy target encompassing the final build of all SWIG files +## \param[in] root_name either 'MEDCoupling' or 'MEDLoader' +## +MACRO(SALOME_MED_SWIG_DOCSTRING_CONFIGURE target_doc target_swig root_name) + SET(_all_swig_docs) + SET(_swig_include_set) + SET(_in_file doxy2swig/${root_name}_doc.i.in) + SET(_out_file ${PROJECT_BINARY_DIR}/doc/${root_name}_doc.i) + SALOME_MED_SWIG_DOCSTRING_GENERATE(${target_doc} ${target_swig} _classes_${root_name} ${_out_file} _all_swig_docs) + FOREACH(f IN LISTS _all_swig_docs) + SET(_swig_include_set "${_swig_include_set}\n%include \"${f}\"") + ENDFOREACH() + CONFIGURE_FILE(${_in_file} ${_out_file} @ONLY) +ENDMACRO(SALOME_MED_SWIG_DOCSTRING_CONFIGURE) + diff --cc medtool/doc/user/doxygen/fakesources/MEDCouplingFieldDouble.C index b5d74a3a9,000000000..69e14afcd mode 100644,000000..100644 --- a/medtool/doc/user/doxygen/fakesources/MEDCouplingFieldDouble.C +++ b/medtool/doc/user/doxygen/fakesources/MEDCouplingFieldDouble.C @@@ -1,394 -1,0 +1,393 @@@ +// Copyright (C) 2013-2015 CEA/DEN, EDF R&D, OPEN CASCADE +// +// 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +// +// See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com +// + +// This file contains some code used only for +// * generation of documentation for inline methods, +// * groupping methods into "Basic API", "Advanced" and "Others..." sections + + +namespace ParaMEDMEM +{ + /*! + * Returns a new MEDCouplingFieldDouble containing sum values of corresponding values of + * \a this and a given field ( _f_ [ i, j ] = _this_ [ i, j ] + _other_ [ i, j ] ). + * Number of tuples and components in the two fields must be the same. + * \param [in] other - the input field. + * \return MEDCouplingFieldDouble * - the new instance of MEDCouplingFieldDouble. + * The caller is to delete this result field using decrRef() as it is no more + * needed. + * \throw If the fields are not strictly compatible (areStrictlyCompatible()), i.e. they + * differ not only in values. + */ + MEDCouplingFieldDouble *MEDCouplingFieldDouble::operator+(const MEDCouplingFieldDouble& other) const throw(INTERP_KERNEL::Exception) {} + /*! + * Returns a new MEDCouplingFieldDouble containing subtraction of corresponding values of + * \a this and a given field ( _f_ [ i, j ] = _this_ [ i, j ] - _other_ [ i, j ] ). + * Number of tuples and components in the two fields must be the same. + * \param [in] other - the field to subtract from \a this one. + * \return MEDCouplingFieldDouble * - the new instance of MEDCouplingFieldDouble. + * The caller is to delete this result field using decrRef() as it is no more + * needed. + * \throw If the fields are not strictly compatible (areStrictlyCompatible()), i.e. they + * differ not only in values. + */ + MEDCouplingFieldDouble *MEDCouplingFieldDouble::operator-(const MEDCouplingFieldDouble& other) const throw(INTERP_KERNEL::Exception) {} + /*! + * Returns a new MEDCouplingFieldDouble containing product values of \a this and a + * given field. There are 2 valid cases. + * 1. The fields have same number of tuples and components. Then each value of + * the result field (_f_) is a product of the corresponding values of _this_ and + * _other_, i.e. _f_ [ i, j ] = _this_ [ i, j ] * _other_ [ i, j ]. + * 2. The fields have same number of tuples and one field, say _other_, has one + * component. Then + * _f_ [ i, j ] = _this_ [ i, j ] * _other_ [ i, 0 ]. + * + * The two fields must have same number of tuples and same underlying mesh. + * \param [in] other - a factor field. + * \return MEDCouplingFieldDouble * - the new instance of MEDCouplingFieldDouble. + * The caller is to delete this result field using decrRef() as it is no more + * needed. + * \throw If the fields are not compatible for production (areCompatibleForMul()), + * i.e. they differ not only in values and possibly number of components. + */ + MEDCouplingFieldDouble *MEDCouplingFieldDouble::operator*(const MEDCouplingFieldDouble& other) const throw(INTERP_KERNEL::Exception) {} + /*! + * Returns a new MEDCouplingFieldDouble containing division of \a this and a given + * field. There are 2 valid cases. + * 1. The fields have same number of tuples and components. Then each value of + * the result field (_f_) is a division of the corresponding values of \a this and + * \a other, i.e. _f_ [ i, j ] = _this_ [ i, j ] / _other_ [ i, j ]. + * 2. The fields have same number of tuples and _other_ has one component. Then + * _f_ [ i, j ] = _this_ [ i, j ] / _other_ [ i, 0 ]. + * + * \param [in] other - a denominator field. + * \return MEDCouplingFieldDouble * - the new instance of MEDCouplingFieldDouble. + * The caller is to delete this result field using decrRef() as it is no more + * needed. + * \throw If the fields are not compatible for division (areCompatibleForDiv()), + * i.e. they differ not only in values and possibly in number of components. + */ + MEDCouplingFieldDouble *MEDCouplingFieldDouble::operator/(const MEDCouplingFieldDouble& other) const throw(INTERP_KERNEL::Exception) {} + /*! + * Returns a new MEDCouplingFieldDouble containing a dot product of \a this and a given field, + * so that the i-th tuple of the result field (_f_) is a sum of products of j-th components of + * i-th tuples of two fields (\f$ f_i = \sum_ {}^n f1_j * f2_j \f$). + * Number of tuples and components in the two fields must be the same. + * \param [in] other - the input field. + * \return MEDCouplingFieldDouble * - the new instance of MEDCouplingFieldDouble. + * The caller is to delete this result field using decrRef() as it is no more + * needed. + * \throw If the fields are not strictly compatible (areStrictlyCompatible()), i.e. they + * differ not only in values. + */ + MEDCouplingFieldDouble *MEDCouplingFieldDouble::dot(const MEDCouplingFieldDouble& other) const throw(INTERP_KERNEL::Exception) {} + /*! + * Returns a new MEDCouplingFieldDouble containing a cross product of \a this and + * a given field, so that the i-th tuple of the result field is a 3D vector which + * is a cross product of two vectors defined by the i-th tuples of the two fields. + * Number of tuples in the fields must be the same. + * Number of components in the fields must be 3. + * \param [in] other - the input field. + * \return MEDCouplingFieldDouble * - the new instance of MEDCouplingFieldDouble. + * The caller is to delete this result field using decrRef() as it is no more + * needed. + * \throw If \a this->getNumberOfComponents() != 3 + * \throw If \a other->getNumberOfComponents() != 3 + * \throw If the fields are not strictly compatible (areStrictlyCompatible()), i.e. they + * differ not only in values. + */ + MEDCouplingFieldDouble *MEDCouplingFieldDouble::crossProduct(const MEDCouplingFieldDouble& other) const throw(INTERP_KERNEL::Exception) {} + /*! + * Returns a new MEDCouplingFieldDouble containing maximal values of \a this and a + * given field. Number of tuples and components in the two fields must be the same. + * \param [in] other - the field to compare values with \a this one. + * \return MEDCouplingFieldDouble * - the new instance of MEDCouplingFieldDouble. + * The caller is to delete this result field using decrRef() as it is no more + * needed. + * \throw If the fields are not strictly compatible (areStrictlyCompatible()), i.e. they + * differ not only in values. + */ + MEDCouplingFieldDouble *MEDCouplingFieldDouble::max(const MEDCouplingFieldDouble& other) const throw(INTERP_KERNEL::Exception) {} + /*! + * Returns a new MEDCouplingFieldDouble containing minimal values of \a this and a + * given field. Number of tuples and components in the two fields must be the same. + * \param [in] other - the field to compare values with \a this one. + * \return MEDCouplingFieldDouble * - the new instance of MEDCouplingFieldDouble. + * The caller is to delete this result field using decrRef() as it is no more + * needed. + * \throw If the fields are not strictly compatible (areStrictlyCompatible()), i.e. they + * differ not only in values. + */ + MEDCouplingFieldDouble *MEDCouplingFieldDouble::min(const MEDCouplingFieldDouble& other) const throw(INTERP_KERNEL::Exception) {} + /*! + * Returns the data array of \a this field. + * \return const DataArrayDouble * - a const pointer to the data array of \a this field. + */ + const DataArrayDouble *MEDCouplingFieldDouble::getArray() const {} + /*! + * Returns the data array of \a this field apt for modification. + * \return DataArrayDouble * - a non-const pointer to the data array of \a this field. + */ + DataArrayDouble *MEDCouplingFieldDouble::getArray() {} + /*! + * Sets a precision used to compare time values. + * \param [in] val - the precision value. + */ + void MEDCouplingFieldDouble::setTimeTolerance(double val) {} + /*! + * Returns a precision used to compare time values. + * \return double - the precision value. + */ + double MEDCouplingFieldDouble::getTimeTolerance() const {} + /*! + * Sets the number of iteration where the data array of \a this field has been calculated. + * For examples of field construction, see \ref MEDCouplingFirstSteps3. + * \param [in] it - the iteration number. + */ + void MEDCouplingFieldDouble::setIteration(int it) throw(INTERP_KERNEL::Exception) {} + /*! + * Sets the number of iteration where the second data array of \a this field has been calculated. + * For examples of field construction, see \ref MEDCouplingFirstSteps3. + * \param [in] it - the iteration number. + */ + void MEDCouplingFieldDouble::setEndIteration(int it) throw(INTERP_KERNEL::Exception) {} + /*! + * Sets the order number of iteration where the data array of \a this field has been calculated. + * For examples of field construction, see \ref MEDCouplingFirstSteps3. + * \param [in] order - the order number. + */ + void MEDCouplingFieldDouble::setOrder(int order) throw(INTERP_KERNEL::Exception) {} + /*! + * Sets the order number of iteration where the second data array of \a this field has + * been calculated. + * \param [in] order - the order number. + */ + void MEDCouplingFieldDouble::setEndOrder(int order) throw(INTERP_KERNEL::Exception) {} + /*! + * Sets the time when the data array of \a this field has been calculated. + * For examples of field construction, see \ref MEDCouplingFirstSteps3. + * \param [in] val - the time value. + */ + void MEDCouplingFieldDouble::setTimeValue(double val) throw(INTERP_KERNEL::Exception) {} + /*! + * Sets the time when the second data array of \a this field has been calculated. + * \param [in] val - the time value. + */ + void MEDCouplingFieldDouble::setEndTimeValue(double val) throw(INTERP_KERNEL::Exception) {} + /*! + * Sets time, number of iteration and order number of iteration when the data array + * of \a this field has been calculated. + * For examples of field construction, see \ref MEDCouplingFirstSteps3. + * \param [in] val - the time value. + * \param [in] iteration - the iteration number. + * \param [in] order - the order number. + */ + void MEDCouplingFieldDouble::setTime(double val, int iteration, int order) {} + /*! + * Returns time, number of iteration and order number of iteration when the data array + * of \a this field has been calculated. + * For examples of field construction, see \ref MEDCouplingFirstSteps3. + * \param [out] iteration - the iteration number. + * \param [out] order - the order number. + * \return double - the time value. + */ + double MEDCouplingFieldDouble::getTime(int& iteration, int& order) const {} + /*! + * Returns a value indexed by a tuple id and a component id. + * \param [in] tupleId - the id of the tuple of interest. + * \param [in] compoId - the id of the component of interest. + * \return double - the field value. + */ + double MEDCouplingFieldDouble::getIJ(int tupleId, int compoId) const {} +} + +namespace ParaMEDMEM +{ +/*! \name Basic API */ +///@{ +MEDCouplingFieldDouble::AddFields(const MEDCouplingFieldDouble *f1, const MEDCouplingFieldDouble *f2); +MEDCouplingFieldDouble::CrossProductFields(const MEDCouplingFieldDouble *f1, const MEDCouplingFieldDouble *f2); +MEDCouplingFieldDouble::DivideFields(const MEDCouplingFieldDouble *f1, const MEDCouplingFieldDouble *f2); +MEDCouplingFieldDouble::DotFields(const MEDCouplingFieldDouble *f1, const MEDCouplingFieldDouble *f2); +MEDCouplingFieldDouble::MaxFields(const MEDCouplingFieldDouble *f1, const MEDCouplingFieldDouble *f2); +MEDCouplingFieldDouble::MeldFields(const MEDCouplingFieldDouble *f1, const MEDCouplingFieldDouble *f2); +MEDCouplingFieldDouble::MergeFields(const MEDCouplingFieldDouble *f1, const MEDCouplingFieldDouble *f2); +MEDCouplingFieldDouble::MergeFields(const std::vector& a); +MEDCouplingFieldDouble::MinFields(const MEDCouplingFieldDouble *f1, const MEDCouplingFieldDouble *f2); +MEDCouplingFieldDouble::MultiplyFields(const MEDCouplingFieldDouble *f1, const MEDCouplingFieldDouble *f2); +MEDCouplingFieldDouble::New(TypeOfField type, TypeOfTimeDiscretization td=ONE_TIME); +MEDCouplingFieldDouble::New(const MEDCouplingFieldTemplate& ft, TypeOfTimeDiscretization td=ONE_TIME); +MEDCouplingFieldDouble::SubstractFields(const MEDCouplingFieldDouble *f1, const MEDCouplingFieldDouble *f2); +MEDCouplingFieldDouble::WriteVTK(const char *fileName, const std::vector& fs); +MEDCouplingFieldDouble::accumulate(double *res) const; +MEDCouplingFieldDouble::accumulate(int compId) const; +MEDCouplingFieldDouble::advancedRepr() const; +MEDCouplingFieldDouble::applyFunc(const std::string &func); +MEDCouplingFieldDouble::applyFunc(int nbOfComp, FunctionToEvaluate func); +MEDCouplingFieldDouble::applyFunc(int nbOfComp, const std::string &func); +MEDCouplingFieldDouble::applyFunc(int nbOfComp, double val); +MEDCouplingFieldDouble::applyFunc2(int nbOfComp, const std::string &func); +MEDCouplingFieldDouble::applyFunc3(int nbOfComp, const std::vector& varsOrder, const std::string &func); +MEDCouplingFieldDouble::applyLin(double a, double b, int compoId); +MEDCouplingFieldDouble::buildNewTimeReprFromThis(TypeOfTimeDiscretization td, bool deepCopy) const; +MEDCouplingFieldDouble::buildSubPart(const DataArrayInt *part) const; +MEDCouplingFieldDouble::buildSubPart(const int *partBg, const int *partEnd) const; +MEDCouplingFieldDouble::changeNbOfComponents(int newNbOfComp, double dftValue=0.); +MEDCouplingFieldDouble::changeUnderlyingMesh(const MEDCouplingMesh *other, int levOfCheck, double precOnMesh, double eps=1e-15); +MEDCouplingFieldDouble::checkCoherency() const; +MEDCouplingFieldDouble::clone(bool recDeepCpy) const; +MEDCouplingFieldDouble::cloneWithMesh(bool recDeepCpy) const; +MEDCouplingFieldDouble::copyTinyAttrFrom(const MEDCouplingFieldDouble *other); +MEDCouplingFieldDouble::copyTinyStringsFrom(const MEDCouplingField *other); +MEDCouplingFieldDouble::crossProduct(const MEDCouplingFieldDouble& other) const; +MEDCouplingFieldDouble::deepCpy() const; +MEDCouplingFieldDouble::determinant() const; +MEDCouplingFieldDouble::deviator() const; +MEDCouplingFieldDouble::dot(const MEDCouplingFieldDouble& other) const; +MEDCouplingFieldDouble::doublyContractedProduct() const; +MEDCouplingFieldDouble::eigenValues() const; +MEDCouplingFieldDouble::eigenVectors() const; +MEDCouplingFieldDouble::fillFromAnalytic(int nbOfComp, FunctionToEvaluate func); +MEDCouplingFieldDouble::fillFromAnalytic(int nbOfComp, const std::string &func); +MEDCouplingFieldDouble::fillFromAnalytic2(int nbOfComp, const std::string &func); +MEDCouplingFieldDouble::fillFromAnalytic3(int nbOfComp, const std::vector& varsOrder, const std::string &func); +MEDCouplingFieldDouble::getArray() const; +MEDCouplingFieldDouble::getArray(); +MEDCouplingFieldDouble::getAverageValue() const; +MEDCouplingFieldDouble::getIJ(int tupleId, int compoId) const; +MEDCouplingFieldDouble::getIJK(int cellId, int nodeIdInCell, int compoId) const; +MEDCouplingFieldDouble::getIdsInRange(double vmin, double vmax) const; +MEDCouplingFieldDouble::getMaxValue() const; +MEDCouplingFieldDouble::getMaxValue2(DataArrayInt*& tupleIds) const; +MEDCouplingFieldDouble::getMinValue() const; +MEDCouplingFieldDouble::getMinValue2(DataArrayInt*& tupleIds) const; +MEDCouplingFieldDouble::getNumberOfComponents() const; +MEDCouplingFieldDouble::getNumberOfTuples() const; +MEDCouplingFieldDouble::getNumberOfValues() const; +MEDCouplingFieldDouble::getTime(int& iteration, int& order) const; +MEDCouplingFieldDouble::getTimeDiscretization() const; +MEDCouplingFieldDouble::getTimeTolerance() const; +MEDCouplingFieldDouble::getTimeUnit() const; +MEDCouplingFieldDouble::getValueOn(const double *spaceLoc, double *res) const; +MEDCouplingFieldDouble::getValueOn(const double *spaceLoc, double time, double *res) const; +MEDCouplingFieldDouble::getValueOnMulti(const double *spaceLoc, int nbOfPoints) const; +MEDCouplingFieldDouble::getValueOnPos(int i, int j, int k, double *res) const; +MEDCouplingFieldDouble::getWeightedAverageValue(double *res, bool isWAbs=true) const; +MEDCouplingFieldDouble::getWeightedAverageValue(int compId, bool isWAbs=true) const; +MEDCouplingFieldDouble::integral(bool isWAbs, double *res) const; +MEDCouplingFieldDouble::integral(int compId, bool isWAbs) const; +MEDCouplingFieldDouble::inverse() const; +MEDCouplingFieldDouble::isEqualWithoutConsideringStr(const MEDCouplingField *other, double meshPrec, double valsPrec) const; +MEDCouplingFieldDouble::keepSelectedComponents(const std::vector& compoIds) const; +MEDCouplingFieldDouble::magnitude() const; +MEDCouplingFieldDouble::max(const MEDCouplingFieldDouble& other) const; +MEDCouplingFieldDouble::maxPerTuple() const; +MEDCouplingFieldDouble::mergeNodes(double eps, double epsOnVals=1e-15); +MEDCouplingFieldDouble::mergeNodes2(double eps, double epsOnVals=1e-15); +MEDCouplingFieldDouble::min(const MEDCouplingFieldDouble& other) const; +MEDCouplingFieldDouble::norm2() const; +MEDCouplingFieldDouble::normL1(double *res) const; +MEDCouplingFieldDouble::normL1(int compId) const; +MEDCouplingFieldDouble::normL2(double *res) const; +MEDCouplingFieldDouble::normL2(int compId) const; +MEDCouplingFieldDouble::normMax() const; +MEDCouplingFieldDouble::renumberCells(const int *old2NewBg, bool check=true); +MEDCouplingFieldDouble::renumberNodes(const int *old2NewBg, double eps=1e-15); +MEDCouplingFieldDouble::setArray(DataArrayDouble *array); +MEDCouplingFieldDouble::setArrays(const std::vector& arrs); +MEDCouplingFieldDouble::setEndArray(DataArrayDouble *array); +MEDCouplingFieldDouble::setEndIteration(int it); +MEDCouplingFieldDouble::setIteration(int it); +MEDCouplingFieldDouble::setNature(NatureOfField nat); +MEDCouplingFieldDouble::setOrder(int order); +MEDCouplingFieldDouble::setSelectedComponents(const MEDCouplingFieldDouble *f, const std::vector& compoIds); +MEDCouplingFieldDouble::setTime(double val, int iteration, int order); +MEDCouplingFieldDouble::setTimeTolerance(double val); +MEDCouplingFieldDouble::setTimeUnit(const char *unit); +MEDCouplingFieldDouble::setTimeValue(double val); +MEDCouplingFieldDouble::simpleRepr() const; +MEDCouplingFieldDouble::simplexize(int policy); +MEDCouplingFieldDouble::sortPerTuple(bool asc); +MEDCouplingFieldDouble::substractInPlaceDM(const MEDCouplingFieldDouble *f, int levOfCheck, double precOnMesh, double eps=1e-15); +MEDCouplingFieldDouble::trace() const; +MEDCouplingFieldDouble::updateTime() const; +MEDCouplingFieldDouble::writeVTK(const char *fileName) const; +MEDCouplingFieldDouble::zipConnectivity(int compType, double epsOnVals=1e-15); +MEDCouplingFieldDouble::zipCoords(double epsOnVals=1e-15); + MEDCouplingFieldDouble & MEDCouplingFieldDouble::operator=(double value); + MEDCouplingFieldDouble * MEDCouplingFieldDouble::operator*(const MEDCouplingFieldDouble& other) const; + MEDCouplingFieldDouble * MEDCouplingFieldDouble::operator+(const MEDCouplingFieldDouble& other) const; + MEDCouplingFieldDouble * MEDCouplingFieldDouble::operator-(const MEDCouplingFieldDouble& other) const; + MEDCouplingFieldDouble * MEDCouplingFieldDouble::operator/(const MEDCouplingFieldDouble& other) const; + const MEDCouplingFieldDouble & MEDCouplingFieldDouble::operator*=(const MEDCouplingFieldDouble& other); + const MEDCouplingFieldDouble & MEDCouplingFieldDouble::operator+=(const MEDCouplingFieldDouble& other); + const MEDCouplingFieldDouble & MEDCouplingFieldDouble::operator-=(const MEDCouplingFieldDouble& other); + const MEDCouplingFieldDouble & MEDCouplingFieldDouble::operator/=(const MEDCouplingFieldDouble& other); +///@} +/*! \name Advanced API */ +///@{ +MEDCouplingFieldDouble::renumberCellsWithoutMesh(const int *old2NewBg, bool check=true); +MEDCouplingFieldDouble::renumberNodesWithoutMesh(const int *old2NewBg, int newNbOfNodes, double eps=1e-15); +///@} + +/*! \name Others... */ +///@{ + MEDCouplingFieldDouble::negate() const; + MEDCouplingFieldDouble::operator^(const MEDCouplingFieldDouble& other) const; + MEDCouplingFieldDouble::operator^=(const MEDCouplingFieldDouble& other); + MEDCouplingFieldDouble::PowFields(const MEDCouplingFieldDouble *f1, const MEDCouplingFieldDouble *f2); +MEDCouplingFieldDouble::buildSubPartRange(int begin, int end, int step) const; +MEDCouplingFieldDouble::MEDCouplingFieldDouble(NatureOfField n, MEDCouplingTimeDiscretization *td, MEDCouplingFieldDiscretization *type); +MEDCouplingFieldDouble::MEDCouplingFieldDouble(TypeOfField type, TypeOfTimeDiscretization td); +MEDCouplingFieldDouble::MEDCouplingFieldDouble(const MEDCouplingFieldDouble& other, bool deepCopy); +MEDCouplingFieldDouble::MEDCouplingFieldDouble(const MEDCouplingFieldTemplate& ft, TypeOfTimeDiscretization td); +MEDCouplingFieldDouble::applyFuncFast32(const std::string &func); +MEDCouplingFieldDouble::applyFuncFast64(const std::string &func); +MEDCouplingFieldDouble::areCompatibleForDiv(const MEDCouplingField *other) const; +MEDCouplingFieldDouble::areCompatibleForMeld(const MEDCouplingFieldDouble *other) const; +MEDCouplingFieldDouble::areCompatibleForMerge(const MEDCouplingField *other) const; +MEDCouplingFieldDouble::areCompatibleForMul(const MEDCouplingField *other) const; +MEDCouplingFieldDouble::areStrictlyCompatible(const MEDCouplingField *other) const; +MEDCouplingFieldDouble::copyAllTinyAttrFrom(const MEDCouplingFieldDouble *other); +MEDCouplingFieldDouble::extractSlice3D(const double *origin, const double *vec, double eps) const; +MEDCouplingFieldDouble::finishUnserialization(const std::vector& tinyInfoI, const std::vector& tinyInfoD, const std::vector& tinyInfoS); +MEDCouplingFieldDouble::getArrays() const; +MEDCouplingFieldDouble::getEndArray() const; +MEDCouplingFieldDouble::getEndArray(); +MEDCouplingFieldDouble::getEndTime(int& iteration, int& order) const; - MEDCouplingFieldDouble::getHeapMemorySize() const; +MEDCouplingFieldDouble::getStartTime(int& iteration, int& order) const; +MEDCouplingFieldDouble::getTimeDiscretizationUnderGround() const; +MEDCouplingFieldDouble::getTimeDiscretizationUnderGround(); +MEDCouplingFieldDouble::getTinySerializationDbleInformation(std::vector& tinyInfo) const; +MEDCouplingFieldDouble::getTinySerializationIntInformation(std::vector& tinyInfo) const; +MEDCouplingFieldDouble::getTinySerializationStrInformation(std::vector& tinyInfo) const; +MEDCouplingFieldDouble::isEqualIfNotWhy(const MEDCouplingField *other, double meshPrec, double valsPrec, std::string& reason) const; +MEDCouplingFieldDouble::reprQuickOverview(std::ostream& stream) const; +MEDCouplingFieldDouble::resizeForUnserialization(const std::vector& tinyInfoI, DataArrayInt *&dataInt, std::vector& arrays); +MEDCouplingFieldDouble::serialize(DataArrayInt *&dataInt, std::vector& arrays) const; +MEDCouplingFieldDouble::setEndOrder(int order); +MEDCouplingFieldDouble::setEndTime(double val, int iteration, int order); +MEDCouplingFieldDouble::setEndTimeValue(double val); +MEDCouplingFieldDouble::setStartTime(double val, int iteration, int order); +MEDCouplingFieldDouble::synchronizeTimeWithMesh(); +MEDCouplingFieldDouble::synchronizeTimeWithSupport(); +MEDCouplingFieldDouble::~MEDCouplingFieldDouble(); +MEDCouplingFieldDouble::_time_discr; +///@} +} diff --cc medtool/doc/user/doxygen/fakesources/MEDCouplingMemArray.C index fa7bac3f8,000000000..26f45eab2 mode 100644,000000..100644 --- a/medtool/doc/user/doxygen/fakesources/MEDCouplingMemArray.C +++ b/medtool/doc/user/doxygen/fakesources/MEDCouplingMemArray.C @@@ -1,611 -1,0 +1,611 @@@ +// Copyright (C) 2013-2015 CEA/DEN, EDF R&D, OPEN CASCADE +// +// 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +// +// See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com +// + +// This file contains some code used only for +// * generation of documentation for inline methods of DataArray* classes +// * groupping methods into "Basic API", "Advanced" and "Others..." sections + + +namespace ParaMEDMEM +{ +/*! + * Returns the attribute \a _name of \a this array. + * See \ref MEDCouplingArrayBasicsName "DataArrays infos" for more information. + * \return std::string - array name + */ +std::string DataArray::getName() const {} + +/*! + * Returns number of components of \a this array. + * See \ref MEDCouplingArrayBasicsTuplesAndCompo "DataArrays infos" for more information. + * \return int - number of components + */ +int DataArray::getNumberOfComponents() const {} + +/*! + * Returns number of tuples of \a this array. + * See \ref MEDCouplingArrayBasicsName "DataArrays infos" for more information. + * \return int - number of tuples + */ +int DataArray::getNumberOfTuples() const {} + +/*! + * Returns number of elements of \a this array. + * See \ref MEDCouplingArrayBasicsName "DataArrays infos" for more information. + * \return int - number of elements == this->getNumberOfTuples() * + * this->getNumberOfComponents() + */ +int DataArray::getNbOfElems() const {} + +/*! + * Throws an exception if number of elements in \a this array differs from a given one. + * See \ref MEDCouplingArrayBasicsName "DataArrays infos" for more information. + * \param [in] nbOfElems - expected array size. + * \param [in] msg - message to return within the thrown exception. + * \throw if this->getNbOfElems() != nbOfElems. + */ +void DataArray::checkNbOfElems(int nbOfElems, const char *msg) const {} + +/*! + * Returns values of a specified tuple. + * \param [in] tupleId - index of the tuple of interest. + * \param [out] res - C array returning values of the \a tupleId-th tuple. The \a res + * must be allocated by the caller and be of size not less than \a + * this->getNumberOfComponents(). + */ +void DataArrayDouble::getTuple(int tupleId, double *res) const {} + +/*! + * Returns a value of a specified element of \a this array. + * \param [in] tupleId - index of the tuple of interest. + * \param [in] compoId - index of the component of interest. + * \return double - the value of \a compoId-th component of \a tupleId-th tuple. + */ +double DataArrayDouble::getIJ(int tupleId, int compoId) const {} + +/*! + * Returns a pointer to the first element of the raw data of \a this array. + * \return double* - the pointer to the value of 0-th tuple and 0-th component. + */ +double * DataArrayDouble::getPointer() {} + +/*! + * Returns a const pointer to the first element of the raw data of \a this array. + * \return const double* - the pointer to the value of 0-th tuple and 0-th component. + */ +const double * DataArrayDouble::getConstPointer() const {} + +/*! + * Assigns a given value to a specified element of \a this array. + * \param [in] tupleId - index of the tuple to modify. + * \param [in] compoId - index of the component to modify. + * \param [in] newVal - the value to assign to the value at \a compoId-th component + * of \a tupleId-th tuple. + */ +void DataArrayDouble::setIJ(int tupleId, int compoId, double newVal) {} + +/*! + * Assigns a given value to a specified element of \a this array which is not marked + * as changed. + * \param [in] tupleId - index of the tuple to modify. + * \param [in] compoId - index of the component to modify. + * \param [in] newVal - the value to assign to the value at \a compoId-th component + * of \a tupleId-th tuple. + */ +void DataArrayDouble::setIJSilent(int tupleId, int compoId, double newVal) {} + +/*! + * Copies values from another array starting from a specified element of \a this. + * \param [in] id - index of element to assign the value \a element0 to. + * \param [in] element0 - value to assign to the \a id-th element of \a this. + * \param [in] others - values to assign to elements following the \a id-th + * element of \a this. + * \param [in] sizeOfOthers - number of values to copy from \a others. + */ +void DataArrayDouble::writeOnPlace(int id, double element0, const double *others, int sizeOfOthers) {} + +/*! + * Does nothing because this class does not aggregate any TimeLabel instance. + */ +void DataArrayDouble::updateTime() const {} + +/*! + * Returns values of a specified tuple. + * \param [in] tupleId - index of the tuple of interest. + * \param [out] res - C array returning values of the \a tupleId-th tuple. The \a res + * must be allocated by the caller and be of size not less than \a + * this->getNumberOfComponents(). + * \if ENABLE_EXAMPLES + * \ref py_mcdataarrayint_getTuple "Here is a Python example". + * \endif + */ +void DataArrayInt::getTuple(int tupleId, int *res) const {} + +/*! + * Returns a value of a specified element of \a this array. + * \param [in] tupleId - index of the tuple of interest. + * \param [in] compoId - index of the component of interest. + * \return int - the value of \a compoId-th component of \a tupleId-th tuple. + */ +int DataArrayInt::getIJ(int tupleId, int compoId) const {} + + +/*! + * Assigns a given value to a specified element of \a this array. + * \param [in] tupleId - index of the tuple to modify. + * \param [in] compoId - index of the component to modify. + * \param [in] newVal - the value to assign to the value at \a compoId-th component + * of \a tupleId-th tuple. + * \warning As this method declares \a this array as modified, it is more optimal to use + * setIJSilent() for modification of muliple values of array and to call + * declareAsNew() after the modification is done. + */ +void DataArrayInt::setIJ(int tupleId, int compoId, int newVal) {} + + +/*! + * Assigns a given value to a specified element of \a this array which is \b not marked + * as changed. + * \param [in] tupleId - index of the tuple to modify. + * \param [in] compoId - index of the component to modify. + * \param [in] newVal - the value to assign to the value at \a compoId-th component + * of \a tupleId-th tuple. + */ +void DataArrayInt::setIJSilent(int tupleId, int compoId, int newVal) {} + +/*! + * Returns a pointer to the first element of the raw data of \a this array. + * \return int* - the pointer to the value of 0-th tuple and 0-th component. + */ +int * DataArrayInt::getPointer() {} + +/*! + * Returns a const pointer to the first element of the raw data of \a this array. + * \return const int* - the pointer to the value of 0-th tuple and 0-th component. + */ +const int * DataArrayInt::getConstPointer() const {} + +/*! + * Copies values from another array starting from a given element of \a this. + * \param [in] id - index of element to assign the value \a element0 to. + * \param [in] element0 - value to assign to the \a id-th element of \a this. + * \param [in] others - values to assign to elements following the \a id-th + * element of \a this. + * \param [in] sizeOfOthers - number of values to copy from \a others. + */ +void DataArrayInt::writeOnPlace(int id, int element0, const int *others, int sizeOfOthers) {} + +} + +namespace ParaMEDMEM +{ +//================================================================================ +/////////////////////// DataArray GROUPPING ////////////////////////////////////// +//================================================================================ + +/*! \name Basic API */ +///@{ +DataArray::setName(const char *name); +DataArray::copyStringInfoFrom(const DataArray& other); +DataArray::areInfoEquals(const DataArray& other) const; +DataArray::getName() const; +DataArray::setInfoOnComponents(const std::vector& info); +DataArray::getVarOnComponent(int i) const; +DataArray::getUnitOnComponent(int i) const; +DataArray::setInfoOnComponent(int i, const char *info); +DataArray::getNumberOfComponents() const; +DataArray::getNumberOfTuples() const; +DataArray::getNbOfElems() const; +DataArray::checkNbOfElems(int nbOfElems, const char *msg) const; +DataArray::GetVarNameFromInfo(const std::string& info); +DataArray::GetUnitFromInfo(const std::string& info); +///@} + +/*! \name Others... */ +///@{ +DataArray::getHeapMemorySizeWithoutChildren() const; +DataArray::copyPartOfStringInfoFrom(const DataArray& other, const std::vector& compoIds); +DataArray::copyPartOfStringInfoFrom2(const std::vector& compoIds, const DataArray& other); +DataArray::areInfoEqualsIfNotWhy(const DataArray& other, std::string& reason) const; +DataArray::reprWithoutNameStream(std::ostream& stream) const; +DataArray::cppRepr(const char *varName) const; +DataArray::getInfoOnComponents() const; +DataArray::getInfoOnComponents(); +DataArray::getVarsOnComponent() const; +DataArray::getUnitsOnComponent() const; +DataArray::getInfoOnComponent(int i) const; +DataArray::checkNbOfTuples(int nbOfTuples, const char *msg) const; +DataArray::checkNbOfComps(int nbOfCompo, const char *msg) const; - DataArray::checkNbOfTuplesAndComp(const DataArray& other, const char *msg) const throw(INTERP_KERNEL::Exception); - DataArray::checkNbOfTuplesAndComp(int nbOfTuples, int nbOfCompo, const char *msg) const throw(INTERP_KERNEL::Exception); ++//DataArray::checkNbOfTuplesAndComp(const DataArray& other, const char *msg) const throw(INTERP_KERNEL::Exception); ++//DataArray::checkNbOfTuplesAndComp(int nbOfTuples, int nbOfCompo, const char *msg) const throw(INTERP_KERNEL::Exception); +DataArray::GetNumberOfItemGivenBES(int begin, int end, int step, const char *msg); +DataArray::GetNumberOfItemGivenBESRelative(int begin, int end, int step, const char *msg); +DataArray::GetPosOfItemGivenBESRelativeNoThrow(int value, int begin, int end, int step); +DataArray::reprCppStream(const char *varName, std::ostream& stream) const; +DataArray::DataArray(); +DataArray::CheckValueInRange(int ref, int value, const char *msg); +DataArray::CheckValueInRangeEx(int value, int start, int end, const char *msg); +DataArray::CheckClosingParInRange(int ref, int value, const char *msg); +std::string DataArray::_name; +std::vector DataArray::_info_on_compo; +///@} + +//================================================================================ +/////////////////////// DataArrayDouble GROUPPING //////////////////////////////// +//================================================================================ + +/*! \name Basic API */ +///@{ +DataArrayDouble::isAllocated() const; - DataArrayDouble::setInfoAndChangeNbOfCompo(const std::vector& info); ++//DataArrayDouble::setInfoAndChangeNbOfCompo(const std::vector& info); +DataArrayDouble::doubleValue() const; +DataArrayDouble::empty() const; +DataArrayDouble::deepCpy() const; +DataArrayDouble::performCpy(bool deepCpy) const; +DataArrayDouble::cpyFrom(const DataArrayDouble& other); +DataArrayDouble::alloc(int nbOfTuple, int nbOfCompo); +DataArrayDouble::allocIfNecessary(int nbOfTuple, int nbOfCompo); +DataArrayDouble::fillWithZero(); +DataArrayDouble::fillWithValue(double val); +DataArrayDouble::iota(double init=0.); +DataArrayDouble::isUniform(double val, double eps) const; +DataArrayDouble::sort(bool asc=true); +DataArrayDouble::reverse(); +DataArrayDouble::checkMonotonic(bool increasing, double eps) const; +DataArrayDouble::isMonotonic(bool increasing, double eps) const; +DataArrayDouble::repr() const; +DataArrayDouble::isEqual(const DataArrayDouble& other, double prec) const; +DataArrayDouble::isEqualWithoutConsideringStr(const DataArrayDouble& other, double prec) const; +DataArrayDouble::reAlloc(int nbOfTuples); +DataArrayDouble::convertToIntArr() const; +DataArrayDouble::fromNoInterlace() const; +DataArrayDouble::toNoInterlace() const; +DataArrayDouble::renumberInPlace(const int* old2New); +DataArrayDouble::renumberInPlaceR(const int* new2Old); +DataArrayDouble::renumber(const int* old2New) const; +DataArrayDouble::renumberR(const int* new2Old) const; +DataArrayDouble::renumberAndReduce(const int* old2New, int newNbOfTuple) const; +DataArrayDouble::selectByTupleId(const int* new2OldBg, const int* new2OldEnd) const; +DataArrayDouble::selectByTupleIdSafe(const int* new2OldBg, const int* new2OldEnd) const; +DataArrayDouble::selectByTupleId2(int bg, int end2, int step) const; +DataArrayDouble::selectByTupleRanges(const std::vector >& ranges) const; +DataArrayDouble::substr(int tupleIdBg, int tupleIdEnd=-1) const; +DataArrayDouble::rearrange(int newNbOfCompo); +DataArrayDouble::transpose(); +DataArrayDouble::changeNbOfComponents(int newNbOfComp, double dftValue) const; +DataArrayDouble::keepSelectedComponents(const std::vector& compoIds) const; +DataArrayDouble::meldWith(const DataArrayDouble* other); +DataArrayDouble::findCommonTuples(double prec, int limitTupleId, DataArrayInt *&comm, DataArrayInt *&commIndex) const; +DataArrayDouble::getDifferentValues(double prec, int limitTupleId=-1) const; +DataArrayDouble::setSelectedComponents(const DataArrayDouble* a, const std::vector& compoIds); +DataArrayDouble::setPartOfValues1(const DataArrayDouble* a, int bgTuples, int endTuples, int stepTuples, int bgComp, int endComp, int stepComp, bool strictCompoCompare=true); +DataArrayDouble::setPartOfValuesSimple1(double a, int bgTuples, int endTuples, int stepTuples, int bgComp, int endComp, int stepComp); +DataArrayDouble::setPartOfValues2(const DataArrayDouble* a, const int* bgTuples, const int* endTuples, const int* bgComp, const int* endComp, bool strictCompoCompare=true); +DataArrayDouble::setPartOfValuesSimple2(double a, const int* bgTuples, const int* endTuples, const int* bgComp, const int* endComp); +DataArrayDouble::setPartOfValues3(const DataArrayDouble* a, const int* bgTuples, const int* endTuples, int bgComp, int endComp, int stepComp, bool strictCompoCompare=true); +DataArrayDouble::setPartOfValuesSimple3(double a, const int* bgTuples, const int* endTuples, int bgComp, int endComp, int stepComp); +DataArrayDouble::getTuple(int tupleId, double* res) const; +DataArrayDouble::getIJ(int tupleId, int compoId) const; +DataArrayDouble::back() const; +DataArrayDouble::getIJSafe(int tupleId, int compoId) const; +DataArrayDouble::setIJ(int tupleId, int compoId, double newVal); +DataArrayDouble::setIJSilent(int tupleId, int compoId, double newVal); +DataArrayDouble::writeOnPlace(int id, double element0, const double* others, int sizeOfOthers); +DataArrayDouble::checkNoNullValues() const; +DataArrayDouble::getMinMaxPerComponent(double* bounds) const; +DataArrayDouble::getMaxValue(int& tupleId) const; +DataArrayDouble::getMaxValueInArray() const; +DataArrayDouble::getMinValue(int& tupleId) const; +DataArrayDouble::getMinValueInArray() const; +DataArrayDouble::getMaxValue2(DataArrayInt*& tupleIds) const; +DataArrayDouble::getMinValue2(DataArrayInt*& tupleIds) const; +DataArrayDouble::getAverageValue() const; +DataArrayDouble::norm2() const; +DataArrayDouble::normMax() const; +DataArrayDouble::accumulate(double* res) const; +DataArrayDouble::accumulate(int compId) const; +DataArrayDouble::fromPolarToCart() const; +DataArrayDouble::fromCylToCart() const; +DataArrayDouble::fromSpherToCart() const; +DataArrayDouble::doublyContractedProduct() const; +DataArrayDouble::determinant() const; +DataArrayDouble::eigenValues() const; +DataArrayDouble::eigenVectors() const; +DataArrayDouble::inverse() const; +DataArrayDouble::trace() const; +DataArrayDouble::deviator() const; +DataArrayDouble::magnitude() const; +DataArrayDouble::maxPerTuple() const; +DataArrayDouble::sortPerTuple(bool asc); +DataArrayDouble::abs(); +DataArrayDouble::applyLin(double a, double b, int compoId); +DataArrayDouble::applyLin(double a, double b); +DataArrayDouble::applyInv(double numerator); +DataArrayDouble::negate() const; - DataArrayDouble::applyFunc(int nbOfComp, const char* func) const; - DataArrayDouble::applyFunc(const char* func) const; - DataArrayDouble::applyFunc2(int nbOfComp, const char* func) const; - DataArrayDouble::applyFunc3(int nbOfComp, const std::vector& varsOrder, const char* func) const; ++DataArrayDouble::applyFunc(int nbOfComp, const std::string& func, bool isSafe=true) const; ++DataArrayDouble::applyFunc(const std::string& func, bool isSafe=true) const; ++DataArrayDouble::applyFunc2(int nbOfComp, const std::string& func, bool isSafe=true) const; ++DataArrayDouble::applyFunc3(int nbOfComp, const std::vector& varsOrder, const std::string& func, bool isSafe=true) const; +DataArrayDouble::getIdsInRange(double vmin, double vmax) const; +DataArrayDouble::addEqual(const DataArrayDouble* other); +DataArrayDouble::substractEqual(const DataArrayDouble* other); +DataArrayDouble::multiplyEqual(const DataArrayDouble* other); +DataArrayDouble::divideEqual(const DataArrayDouble* other); +DataArrayDouble::updateTime() const; +DataArrayDouble::New(); +DataArrayDouble::Aggregate(const DataArrayDouble* a1, const DataArrayDouble* a2); +DataArrayDouble::Aggregate(const std::vector& arr); +DataArrayDouble::Meld(const DataArrayDouble* a1, const DataArrayDouble* a2); +DataArrayDouble::Meld(const std::vector& arr); +DataArrayDouble::Dot(const DataArrayDouble* a1, const DataArrayDouble* a2); +DataArrayDouble::CrossProduct(const DataArrayDouble* a1, const DataArrayDouble* a2); +DataArrayDouble::Max(const DataArrayDouble* a1, const DataArrayDouble* a2); +DataArrayDouble::Min(const DataArrayDouble* a1, const DataArrayDouble* a2); +DataArrayDouble::Add(const DataArrayDouble* a1, const DataArrayDouble* a2); +DataArrayDouble::Substract(const DataArrayDouble* a1, const DataArrayDouble* a2); +DataArrayDouble::Multiply(const DataArrayDouble* a1, const DataArrayDouble* a2); +DataArrayDouble::Divide(const DataArrayDouble* a1, const DataArrayDouble* a2); +///@} + +/*! \name Advanced API */ +///@{ +DataArrayDouble::checkAllocated() const; +DataArrayDouble::setPartOfValuesAdv(const DataArrayDouble* a, const DataArrayInt* tuplesSelec); +DataArrayDouble::setContigPartOfSelectedValues(int tupleIdStart, const DataArrayDouble* a, const DataArrayInt* tuplesSelec); +DataArrayDouble::setContigPartOfSelectedValues2(int tupleIdStart, const DataArrayDouble* a, int bg, int end2, int step); +DataArrayDouble::applyFunc(int nbOfComp, FunctionToEvaluate func) const; +///@} + +/*! \name Others... */ +///@{ +DataArrayDouble::getNumberOfTuples() const; +DataArrayDouble::getNbOfElems() const; - DataArrayDouble::getHeapMemorySize() const; ++//DataArrayDouble::getHeapMemorySize() const; +DataArrayDouble::reserve(int nbOfElems); +DataArrayDouble::pushBackSilent(double val); +DataArrayDouble::popBackSilent(); +DataArrayDouble::pack() const; +DataArrayDouble::getNbOfElemAllocated() const; +DataArrayDouble::reprZip() const; +DataArrayDouble::writeVTK(std::ostream& ofs, int indent, const char* nameInFile) const; +DataArrayDouble::reprStream(std::ostream& stream) const; +DataArrayDouble::reprZipStream(std::ostream& stream) const; +DataArrayDouble::reprWithoutNameStream(std::ostream& stream) const; +DataArrayDouble::reprZipWithoutNameStream(std::ostream& stream) const; +DataArrayDouble::reprCppStream(const char* varName, std::ostream& stream) const; +DataArrayDouble::isEqualIfNotWhy(const DataArrayDouble& other, double prec, std::string& reason) const; +DataArrayDouble::duplicateEachTupleNTimes(int nbTimes) const; +DataArrayDouble::setPartOfValues4(const DataArrayDouble* a, int bgTuples, int endTuples, int stepTuples, const int* bgComp, const int* endComp, bool strictCompoCompare=true); +DataArrayDouble::setPartOfValuesSimple4(double a, int bgTuples, int endTuples, int stepTuples, const int* bgComp, const int* endComp); +DataArrayDouble::getPointer(); +DataArrayDouble::SetArrayIn(DataArrayDouble* newArray, DataArrayDouble* &arrayToSet); +DataArrayDouble::iterator(); +DataArrayDouble::getConstPointer() const; +DataArrayDouble::begin() const; +DataArrayDouble::end() const; +DataArrayDouble::useArray(const double* array, bool ownership, DeallocType type, int nbOfTuple, int nbOfCompo); +DataArrayDouble::useExternalArrayWithRWAccess(const double* array, int nbOfTuple, int nbOfCompo); +DataArrayDouble::insertAtTheEnd(InputIterator first, InputIterator last); +DataArrayDouble::computeBBoxPerTuple(double epsilon=0.0) const; +DataArrayDouble::computeTupleIdsNearTuples(const DataArrayDouble* other, double eps, DataArrayInt *& c, DataArrayInt *& cI) const; +DataArrayDouble::recenterForMaxPrecision(double eps); +DataArrayDouble::distanceToTuple(const double* tupleBg, const double* tupleEnd, int& tupleId) const; +DataArrayDouble::buildEuclidianDistanceDenseMatrix() const; +DataArrayDouble::buildEuclidianDistanceDenseMatrixWith(const DataArrayDouble* other) const; - DataArrayDouble::applyFuncFast32(const char* func); - DataArrayDouble::applyFuncFast64(const char* func); ++DataArrayDouble::applyFuncFast32(const std::string& func); ++DataArrayDouble::applyFuncFast64(const std::string& func); +DataArrayDouble::getTinySerializationIntInformation(std::vector& tinyInfo) const; +DataArrayDouble::getTinySerializationStrInformation(std::vector& tinyInfo) const; +DataArrayDouble::resizeForUnserialization(const std::vector& tinyInfoI); +DataArrayDouble::finishUnserialization(const std::vector& tinyInfoI, const std::vector& tinyInfoS); + +DataArrayDouble::findCommonTuplesAlg(const double* bbox, int nbNodes, int limitNodeId, double prec, DataArrayInt* c, DataArrayInt* cI) const; + +DataArrayDouble::FindTupleIdsNearTuplesAlg(const BBTree& myTree, const double* pos, int nbOfTuples, double eps, DataArrayInt* c, DataArrayInt* cI); +DataArrayDouble::DataArrayDouble(); +MemArray DataArrayDouble::_mem; +///@} + +//================================================================================ +/////////////////////// DataArrayInt GROUPPING /////////////////////////////////// +//================================================================================ + +/*! \name Advanced API */ +///@{ +DataArrayInt::checkAllocated() const; +DataArrayInt::getHashCode() const; +DataArrayInt::buildPermutationArr(const DataArrayInt& other) const; +DataArrayInt::transformWithIndArr(const int* indArrBg, const int* indArrEnd); +DataArrayInt::transformWithIndArrR(const int* indArrBg, const int* indArrEnd) const; +DataArrayInt::splitByValueRange(const int* arrBg, const int* arrEnd,DataArrayInt *& castArr, DataArrayInt *& rankInsideCast, DataArrayInt *& castsPresent) const; +DataArrayInt::setPartOfValuesAdv(const DataArrayInt* a, const DataArrayInt* tuplesSelec); +DataArrayInt::setContigPartOfSelectedValues(int tupleIdStart, const DataArrayInt*a, const DataArrayInt* tuplesSelec); +DataArrayInt::setContigPartOfSelectedValues2(int tupleIdStart, const DataArrayInt* a, int bg, int end2, int step); +DataArrayInt::SetArrayIn(DataArrayInt* newArray, DataArrayInt* &arrayToSet); +///@} + +/*! \name Basic API */ +///@{ +DataArrayInt::isAllocated() const; - DataArrayInt::setInfoAndChangeNbOfCompo(const std::vector& info); ++//DataArrayInt::setInfoAndChangeNbOfCompo(const std::vector& info); +DataArrayInt::intValue() const; +DataArrayInt::empty() const; +DataArrayInt::deepCpy() const; +DataArrayInt::performCpy(bool deepCpy) const; +DataArrayInt::cpyFrom(const DataArrayInt& other); +DataArrayInt::alloc(int nbOfTuple, int nbOfCompo); +DataArrayInt::allocIfNecessary(int nbOfTuple, int nbOfCompo); +DataArrayInt::isEqual(const DataArrayInt& other) const; +DataArrayInt::isEqualWithoutConsideringStr(const DataArrayInt& other) const; +DataArrayInt::isEqualWithoutConsideringStrAndOrder(const DataArrayInt& other) const; +DataArrayInt::sort(bool asc=true); +DataArrayInt::reverse(); +DataArrayInt::fillWithZero(); +DataArrayInt::fillWithValue(int val); +DataArrayInt::iota(int init=0); +DataArrayInt::repr() const; +DataArrayInt::invertArrayO2N2N2O(int newNbOfElem) const; +DataArrayInt::invertArrayN2O2O2N(int oldNbOfElem) const; +DataArrayInt::reAlloc(int nbOfTuples); +DataArrayInt::convertToDblArr() const; +DataArrayInt::fromNoInterlace() const; +DataArrayInt::toNoInterlace() const; +DataArrayInt::renumberInPlace(const int* old2New); +DataArrayInt::renumberInPlaceR(const int* new2Old); +DataArrayInt::renumber(const int* old2New) const; +DataArrayInt::renumberR(const int* new2Old) const; +DataArrayInt::renumberAndReduce(const int* old2NewBg, int newNbOfTuple) const; +DataArrayInt::selectByTupleId(const int* new2OldBg, const int* new2OldEnd) const; +DataArrayInt::selectByTupleIdSafe(const int* new2OldBg, const int* new2OldEnd) const; +DataArrayInt::selectByTupleId2(int bg, int end, int step) const; +DataArrayInt::selectByTupleRanges(const std::vector >& ranges) const; +DataArrayInt::checkAndPreparePermutation() const; +DataArrayInt::changeSurjectiveFormat(int targetNb, DataArrayInt *&arr, DataArrayInt *&arrI) const; +DataArrayInt::buildPermArrPerLevel() const; +DataArrayInt::isIdentity() const; +DataArrayInt::isUniform(int val) const; +DataArrayInt::substr(int tupleIdBg, int tupleIdEnd=-1) const; +DataArrayInt::rearrange(int newNbOfCompo); +DataArrayInt::transpose(); +DataArrayInt::changeNbOfComponents(int newNbOfComp, int dftValue) const; +DataArrayInt::keepSelectedComponents(const std::vector& compoIds) const; +DataArrayInt::meldWith(const DataArrayInt* other); +DataArrayInt::setSelectedComponents(const DataArrayInt* a, const std::vector& compoIds); +DataArrayInt::setPartOfValues1(const DataArrayInt* a, int bgTuples, int endTuples, int stepTuples, int bgComp, int endComp, int stepComp, bool strictCompoCompare=true); +DataArrayInt::setPartOfValuesSimple1(int a, int bgTuples, int endTuples, int stepTuples, int bgComp, int endComp, int stepComp); +DataArrayInt::setPartOfValues2(const DataArrayInt* a, const int* bgTuples, const int* endTuples, const int* bgComp, const int* endComp, bool strictCompoCompare=true); +DataArrayInt::setPartOfValuesSimple2(int a, const int* bgTuples, const int* endTuples, const int* bgComp, const int* endComp); +DataArrayInt::setPartOfValues3(const DataArrayInt* a, const int* bgTuples, const int* endTuples, int bgComp, int endComp, int stepComp, bool strictCompoCompare=true); +DataArrayInt::setPartOfValuesSimple3(int a, const int* bgTuples, const int* endTuples, int bgComp, int endComp, int stepComp); +DataArrayInt::getTuple(int tupleId, int* res) const; +DataArrayInt::getIJ(int tupleId, int compoId) const; +DataArrayInt::getIJSafe(int tupleId, int compoId) const; +DataArrayInt::back() const; +DataArrayInt::setIJ(int tupleId, int compoId, int newVal); +DataArrayInt::setIJSilent(int tupleId, int compoId, int newVal); +DataArrayInt::getPointer(); +DataArrayInt::getConstPointer() const; +DataArrayInt::getIdsEqual(int val) const; +DataArrayInt::getIdsNotEqual(int val) const; +DataArrayInt::getIdsEqualList(const int* valsBg, const int* valsEnd) const; +DataArrayInt::getIdsNotEqualList(const int* valsBg, const int* valsEnd) const; +DataArrayInt::changeValue(int oldValue, int newValue); +DataArrayInt::presenceOfValue(int value) const; +DataArrayInt::presenceOfValue(const std::vector& vals) const; +DataArrayInt::getMaxValue(int& tupleId) const; +DataArrayInt::getMaxValueInArray() const; +DataArrayInt::getMinValue(int& tupleId) const; +DataArrayInt::getMinValueInArray() const; +DataArrayInt::abs(); +DataArrayInt::applyLin(int a, int b, int compoId); +DataArrayInt::applyLin(int a, int b); +DataArrayInt::applyInv(int numerator); +DataArrayInt::negate() const; +DataArrayInt::applyDivideBy(int val); +DataArrayInt::applyModulus(int val); +DataArrayInt::applyRModulus(int val); +DataArrayInt::buildComplement(int nbOfElement) const; +DataArrayInt::buildSubstraction(const DataArrayInt* other) const; +DataArrayInt::buildUnion(const DataArrayInt* other) const; +DataArrayInt::buildIntersection(const DataArrayInt* other) const; +DataArrayInt::deltaShiftIndex() const; +DataArrayInt::computeOffsets(); +DataArrayInt::computeOffsets2(); +DataArrayInt::buildExplicitArrByRanges(const DataArrayInt* offsets) const; +DataArrayInt::useArray(const int* array, bool ownership, DeallocType type, int nbOfTuple, int nbOfCompo); +DataArrayInt::writeOnPlace(int id, int element0, const int* others, int sizeOfOthers); +DataArrayInt::addEqual(const DataArrayInt* other); +DataArrayInt::substractEqual(const DataArrayInt* other); +DataArrayInt::multiplyEqual(const DataArrayInt* other); +DataArrayInt::divideEqual(const DataArrayInt* other); +DataArrayInt::modulusEqual(const DataArrayInt* other); +DataArrayInt::updateTime() const; +DataArrayInt::New(); +DataArrayInt::BuildOld2NewArrayFromSurjectiveFormat2(int nbOfOldTuples, const int* arr, const int* arrIBg, const int* arrIEnd, int &newNbOfTuples); +DataArrayInt::Aggregate(const DataArrayInt* a1, const DataArrayInt* a2, int offsetA2); +DataArrayInt::Aggregate(const std::vector& arr); +DataArrayInt::Meld(const DataArrayInt* a1, const DataArrayInt* a2); +DataArrayInt::Meld(const std::vector& arr); +DataArrayInt::MakePartition(const std::vector& groups, int newNb, std::vector< std::vector >& fidsOfGroups); +DataArrayInt::BuildUnion(const std::vector& arr); +DataArrayInt::BuildIntersection(const std::vector& arr); +DataArrayInt::Add(const DataArrayInt* a1, const DataArrayInt* a2); +DataArrayInt::Substract(const DataArrayInt* a1, const DataArrayInt* a2); +DataArrayInt::Multiply(const DataArrayInt* a1, const DataArrayInt* a2); +DataArrayInt::Divide(const DataArrayInt* a1, const DataArrayInt* a2); +DataArrayInt::Modulus(const DataArrayInt* a1, const DataArrayInt* a2); +DataArrayInt::CheckAndPreparePermutation(const int* start, const int* end); +DataArrayInt::Range(int begin, int end, int step); +///@} + +/*! \name Others... */ +///@{ +DataArrayInt::getNumberOfTuples() const; +DataArrayInt::getNbOfElems() const; - DataArrayInt::getHeapMemorySize() const; ++//DataArrayInt::getHeapMemorySize() const; +DataArrayInt::reserve(int nbOfElems); +DataArrayInt::pushBackSilent(int val); +DataArrayInt::popBackSilent(); +DataArrayInt::pack() const; +DataArrayInt::getNbOfElemAllocated() const; +DataArrayInt::isEqualIfNotWhy(const DataArrayInt& other, std::string& reason) const; +DataArrayInt::checkMonotonic(bool increasing) const; +DataArrayInt::isMonotonic(bool increasing) const; +DataArrayInt::checkStrictlyMonotonic(bool increasing) const; +DataArrayInt::isStrictlyMonotonic(bool increasing) const; +DataArrayInt::reprZip() const; +DataArrayInt::writeVTK(std::ostream& ofs, int indent, const char* type, const char* nameInFile) const; +DataArrayInt::reprStream(std::ostream& stream) const; +DataArrayInt::reprZipStream(std::ostream& stream) const; +DataArrayInt::reprWithoutNameStream(std::ostream& stream) const; +DataArrayInt::reprZipWithoutNameStream(std::ostream& stream) const; +DataArrayInt::reprCppStream(const char* varName, std::ostream& stream) const; +DataArrayInt::invertArrayO2N2N2OBis(int newNbOfElem) const; +DataArrayInt::setPartOfValues4(const DataArrayInt* a, int bgTuples, int endTuples, int stepTuples, const int* bgComp, const int* endComp, bool strictCompoCompare=true); +DataArrayInt::setPartOfValuesSimple4(int a, int bgTuples, int endTuples, int stepTuples, const int* bgComp, const int* endComp); +DataArrayInt::iterator(); +DataArrayInt::begin() const; +DataArrayInt::end() const; +DataArrayInt::locateTuple(const std::vector& tupl) const; +DataArrayInt::locateValue(int value) const; +DataArrayInt::locateValue(const std::vector& vals) const; +DataArrayInt::search(const std::vector& vals) const; +DataArrayInt::presenceOfTuple(const std::vector& tupl) const; +DataArrayInt::accumulate(int* res) const; +DataArrayInt::accumulate(int compId) const; +DataArrayInt::getIdsInRange(int vmin, int vmax) const; +DataArrayInt::buildSubstractionOptimized(const DataArrayInt* other) const; +DataArrayInt::buildUnique() const; +DataArrayInt::findRangeIdForEachTuple(const DataArrayInt* ranges) const; +DataArrayInt::findIdInRangeForEachTuple(const DataArrayInt* ranges) const; +DataArrayInt::duplicateEachTupleNTimes(int nbTimes) const; +DataArrayInt::getDifferentValues() const; +> DataArrayInt::partitionByDifferentValues(std::vector& differentIds) const; +DataArrayInt::useExternalArrayWithRWAccess(const int* array, int nbOfTuple, int nbOfCompo); +tor> +DataArrayInt::insertAtTheEnd(InputIterator first, InputIterator last); +DataArrayInt::getTinySerializationIntInformation(std::vector& tinyInfo) const; +DataArrayInt::getTinySerializationStrInformation(std::vector& tinyInfo) const; +DataArrayInt::resizeForUnserialization(const std::vector& tinyInfoI); +DataArrayInt::finishUnserialization(const std::vector& tinyInfoI, const std::vector& tinyInfoS); +DataArrayInt::DataArrayInt(); +MemArray DataArrayInt::_mem; +///@} + +} diff --cc medtool/doc/user/doxygen/fakesources/MEDCouplingMesh.C index eabd7a9ca,000000000..4809eec6b mode 100644,000000..100644 --- a/medtool/doc/user/doxygen/fakesources/MEDCouplingMesh.C +++ b/medtool/doc/user/doxygen/fakesources/MEDCouplingMesh.C @@@ -1,178 -1,0 +1,178 @@@ +// Copyright (C) 2013-2015 CEA/DEN, EDF R&D, OPEN CASCADE +// +// 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +// +// See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com +// + +// This file contains some code used only for +// * generation of documentation for inline methods of DataArray* classes +// * groupping methods into "Basic API", "Advanced" and "Others..." sections + + +namespace ParaMEDMEM +{ + //================================================================================ + /*! + * Checks if \a this and another MEDCouplingMesh are equal without considering + * textual data like mesh name, names of spatial components etc. + * \param [in] other - an instance of MEDCouplingMesh to compare with \a this one. + * \param [in] prec - precision value used to compare node coordinates. + * \return bool - \c true if the two meshes are equal, \c false else. + */ + //================================================================================ + + bool MEDCouplingMesh::isEqualWithoutConsideringStr(const MEDCouplingMesh *other, double prec) const {} + + /*! + * Checks if \a this and \a other meshes are geometrically equivalent, else an + * exception is thrown. The meshes are + * considered equivalent if (1) \a this mesh contains the same nodes as the \a other + * mesh (with a specified precision) and (2) \a this mesh contains the same cells as + * the \a other mesh (with use of a specified cell comparison technique). The mapping + * from \a other to \a this for nodes and cells is returned via out parameters. + * \param [in] other - the mesh to compare with. + * \param [in] cellCompPol - id [0-2] of cell comparison method. See meaning of + * each method in description of MEDCouplingUMesh::zipConnectivityTraducer(). + * \param [in] prec - the precision used to compare nodes of the two meshes. + * \param [out] cellCor - a cell permutation array in "Old to New" mode. The caller is + * to delete this array using decrRef() as it is no more needed. + * \param [out] nodeCor - a node permutation array in "Old to New" mode. The caller is + * to delete this array using decrRef() as it is no more needed. + * \throw If the two meshes do not match. + */ + void MEDCouplingMesh::checkDeepEquivalWith(const MEDCouplingMesh *other, int cellCompPol, double prec,DataArrayInt *&cellCor, DataArrayInt *&nodeCor) const throw(INTERP_KERNEL::Exception) {} + + /*! + * Checks if \a this and \a other meshes are geometrically equivalent, else an + * exception is thrown. The meshes are considered equivalent if (1) they share the same + * node coordinates array(s) and (2) they contain the same cells (with use of a specified + * cell comparison technique). The mapping from cells of the \a other to ones of \a this + * is returned via an out parameter. + * \param [in] other - the mesh to compare with. + * \param [in] cellCompPol - id [0-2] of cell comparison method. See the meaning of + * each method in description of MEDCouplingUMesh::zipConnectivityTraducer(). + * \param [in] prec - a not used parameter. + * \param [out] cellCor - the permutation array in "Old to New" mode. The caller is + * to delete this array using decrRef() as it is no more needed. + * \throw If the two meshes do not match. + */ + void MEDCouplingMesh::checkDeepEquivalOnSameNodesWith(const MEDCouplingMesh *other, int cellCompPol, double prec,DataArrayInt *&cellCor) const throw(INTERP_KERNEL::Exception) {} +} + +namespace ParaMEDMEM +{ +//================================================================================ +/////////////////////// GROUPPING members of MEDCouplingMesh ///////////////////// +//================================================================================ +/*! \name Basic API */ +///@{ + MEDCouplingMesh::MergeMeshes(const MEDCouplingMesh *mesh1, const MEDCouplingMesh *mesh2); + MEDCouplingMesh::MergeMeshes(std::vector& meshes); + MEDCouplingMesh::checkDeepEquivalOnSameNodesWith(const MEDCouplingMesh *other, int cellCompPol, double prec,DataArrayInt *&cellCor) const; + MEDCouplingMesh::checkDeepEquivalWith(const MEDCouplingMesh *other, int cellCompPol, double prec,DataArrayInt *&cellCor, DataArrayInt *&nodeCor) const; + MEDCouplingMesh::fillFromAnalytic(TypeOfField t, int nbOfComp, FunctionToEvaluate func) const; - MEDCouplingMesh::fillFromAnalytic(TypeOfField t, int nbOfComp, const char *func) const; - MEDCouplingMesh::fillFromAnalytic2(TypeOfField t, int nbOfComp, const char *func) const; - MEDCouplingMesh::fillFromAnalytic3(TypeOfField t, int nbOfComp, const std::vector& varsOrder, const char *func) const; ++ MEDCouplingMesh::fillFromAnalytic(TypeOfField t, int nbOfComp, const std::string& func) const; ++ MEDCouplingMesh::fillFromAnalytic2(TypeOfField t, int nbOfComp, const std::string& func) const; ++ MEDCouplingMesh::fillFromAnalytic3(TypeOfField t, int nbOfComp, const std::vector& varsOrder, const std::string& func) const; + MEDCouplingMesh::getCellsContainingPoint(const double *pos, double eps, std::vector& elts) const; + MEDCouplingMesh::getCellsContainingPoints(const double *pos, int nbOfPoints, double eps, std::vector& elts, std::vector& eltsIndex) const; + MEDCouplingMesh::isEqual(const MEDCouplingMesh *other, double prec) const; + MEDCouplingMesh::isEqualWithoutConsideringStr(const MEDCouplingMesh *other, double prec) const = 0; + MEDCouplingMesh::writeVTK(const char *fileName) const; +///@} + +/*! \name Advanced API */ +///@{ + MEDCouplingMesh::getCellIdsFullyIncludedInNodeIds(const int *partBg, const int *partEnd) const; +///@} + +/*! \name Others... */ +///@{ + MEDCouplingMesh::GetDimensionOfGeometricType(INTERP_KERNEL::NormalizedCellType type); + MEDCouplingMesh::GetReprOfGeometricType(INTERP_KERNEL::NormalizedCellType type); + MEDCouplingMesh::MEDCouplingMesh(); + MEDCouplingMesh::~MEDCouplingMesh(); + MEDCouplingMesh::MEDCouplingMesh(const MEDCouplingMesh& other); + MEDCouplingMesh::advancedRepr() const = 0; + MEDCouplingMesh::areCompatibleForMerge(const MEDCouplingMesh *other) const; + MEDCouplingMesh::buildOrthogonalField() const = 0; + MEDCouplingMesh::buildPart(const int *start, const int *end) const = 0; + MEDCouplingMesh::buildPartAndReduceNodes(const int *start, const int *end, DataArrayInt*& arr) const = 0; + MEDCouplingMesh::buildUnstructured() const; + MEDCouplingMesh::checkCoherency() const; + MEDCouplingMesh::checkCoherency1(double eps=1e-12) const; + MEDCouplingMesh::checkCoherency2(double eps=1e-12) const; + MEDCouplingMesh::checkFastEquivalWith(const MEDCouplingMesh *other, double prec) const; + MEDCouplingMesh::checkGeoEquivalWith(const MEDCouplingMesh *other, int levOfCheck, double prec,DataArrayInt *&cellCor, DataArrayInt *&nodeCor) const; + MEDCouplingMesh::checkTypeConsistencyAndContig(const std::vector& code, const std::vector& idsPerType) const; + MEDCouplingMesh::computeIsoBarycenterOfNodesPerCell() const; + MEDCouplingMesh::computeNbOfNodesPerCell() const; + MEDCouplingMesh::copyTinyInfoFrom(const MEDCouplingMesh *other); + MEDCouplingMesh::copyTinyStringsFrom(const MEDCouplingMesh *other); + MEDCouplingMesh::deepCpy() const = 0; + MEDCouplingMesh::getAllGeoTypes() const = 0; + MEDCouplingMesh::getBarycenterAndOwner() const = 0; + MEDCouplingMesh::getBoundingBox(double *bbox) const = 0; + MEDCouplingMesh::getCellContainingPoint(const double *pos, double eps) const = 0; + MEDCouplingMesh::getCoordinatesAndOwner() const = 0; + MEDCouplingMesh::getCoordinatesOfNode(int nodeId, std::vector& coo) const; + MEDCouplingMesh::getDescription() const; + MEDCouplingMesh::getDistributionOfTypes() const; - MEDCouplingMesh::getHeapMemorySize() const; ++// MEDCouplingMesh::getHeapMemorySize() const; + MEDCouplingMesh::getMeasureField(bool isAbs) const = 0; + MEDCouplingMesh::getMeasureFieldOnNode(bool isAbs) const = 0; + MEDCouplingMesh::getMeshDimension() const = 0; + MEDCouplingMesh::getName() const; + MEDCouplingMesh::getNodeIdsOfCell(int cellId, std::vector& conn) const = 0; + MEDCouplingMesh::getNumberOfCells() const = 0; + MEDCouplingMesh::getNumberOfCellsWithType(INTERP_KERNEL::NormalizedCellType type) const = 0; + MEDCouplingMesh::getNumberOfNodes() const = 0; + MEDCouplingMesh::getSpaceDimension() const = 0; + MEDCouplingMesh::getTime(int& iteration, int& order) const; + MEDCouplingMesh::getTimeUnit() const; + MEDCouplingMesh::getTinySerializationInformation(std::vector& tinyInfoD, std::vector& tinyInfo, std::vector& littleStrings) const = 0; + MEDCouplingMesh::getType() const = 0; + MEDCouplingMesh::getTypeOfCell(int cellId) const = 0; + MEDCouplingMesh::getVTKDataSetType() const; + MEDCouplingMesh::giveCellsWithType(INTERP_KERNEL::NormalizedCellType type) const; + MEDCouplingMesh::isEqualIfNotWhy(const MEDCouplingMesh *other, double prec, std::string& reason) const; + MEDCouplingMesh::isStructured() const; + MEDCouplingMesh::mergeMyselfWith(const MEDCouplingMesh *other) const = 0; + MEDCouplingMesh::renumberCells(const int *old2NewBg, bool check=true); + MEDCouplingMesh::reprQuickOverview(std::ostream& stream) const; + MEDCouplingMesh::resizeForUnserialization(const std::vector& tinyInfo, DataArrayInt *a1, DataArrayDouble *a2, std::vector& littleStrings) const = 0; + MEDCouplingMesh::rotate(const double *center, const double *vector, double angle) = 0; + MEDCouplingMesh::scale(const double *point, double factor) = 0; + MEDCouplingMesh::serialize(DataArrayInt *&a1, DataArrayDouble *&a2) const = 0; + MEDCouplingMesh::setDescription(const char *descr); + MEDCouplingMesh::setName(const char *name); + MEDCouplingMesh::setTime(double val, int iteration, int order); + MEDCouplingMesh::setTimeUnit(const char *unit); + MEDCouplingMesh::simpleRepr() const = 0; + MEDCouplingMesh::simplexize(int policy); + MEDCouplingMesh::splitProfilePerType(const DataArrayInt *profile, std::vector& code, std::vector& idsInPflPerType, std::vector& idsPerType) const; + MEDCouplingMesh::translate(const double *vector) = 0; + MEDCouplingMesh::unserialization(const std::vector& tinyInfoD, const std::vector& tinyInfo, const DataArrayInt *a1, DataArrayDouble *a2,const std::vector& littleStrings) = 0; - MEDCouplingMesh::writeVTKAdvanced(const char *fileName, const std::string& cda, const std::string& pda) const; ++ //MEDCouplingMesh::writeVTKAdvanced(const char *fileName, const std::string& cda, const std::string& pda) const; + MEDCouplingMesh::writeVTKLL(std::ostream& ofs, const std::string& cellData, const std::string& pointData) const; + MEDCouplingMesh::_description; + MEDCouplingMesh::_iteration; + MEDCouplingMesh::_name; + MEDCouplingMesh::_order; + MEDCouplingMesh::_time; + MEDCouplingMesh::_time_unit; +///@} +} diff --cc medtool/doc/user/doxygen/fakesources/MEDCouplingUMesh.C index c17e7b296,000000000..443b632c7 mode 100644,000000..100644 --- a/medtool/doc/user/doxygen/fakesources/MEDCouplingUMesh.C +++ b/medtool/doc/user/doxygen/fakesources/MEDCouplingUMesh.C @@@ -1,343 -1,0 +1,343 @@@ +// Copyright (C) 2013-2015 CEA/DEN, EDF R&D, OPEN CASCADE +// +// 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +// +// See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com +// + +// Copyright (C) 2013 CEA/DEN, EDF R&D, OPEN CASCADE +// +// 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. +// +// 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +// +// See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com +// + +// This file contains some code used only for +// * generation of documentation for inline methods of MEDCouplingUMesh class, +// * groupping methods into "Basic API", "Advanced" and "Others..." sections + +namespace ParaMEDMEM +{ + /*! + * Returns the nodal connectivity array. For more info on how data in stored in + * this array, see \ref MEDCouplingUMeshAdvBuild. + * \return const DataArrayInt * - a pointer to the nodal connectivity array + * referred by \a this mesh. + */ + const DataArrayInt * MEDCouplingUMesh::getNodalConnectivity() const {} + /*! + * Returns the nodal connectivity index array. For more info on how data in stored in + * this array, see \ref MEDCouplingUMeshAdvBuild. + * \return const DataArrayInt * - a pointer to the nodal connectivity index array + * referred by \a this mesh. + */ + const DataArrayInt * MEDCouplingUMesh::getNodalConnectivityIndex() const {} + /*! + * Returns the nodal connectivity array. For more info on how data in stored in + * this array, see \ref MEDCouplingUMeshAdvBuild. + * \return const DataArrayInt * - a pointer to the nodal connectivity array + * referred by \a this mesh. + */ + DataArrayInt * MEDCouplingUMesh::getNodalConnectivity() {} + /*! + * Returns the nodal connectivity index array. For more info on how data in stored in + * this array, see \ref MEDCouplingUMeshAdvBuild. + * \return const DataArrayInt * - a pointer to the nodal connectivity index array + * referred by \a this mesh. + */ + DataArrayInt * MEDCouplingUMesh::getNodalConnectivityIndex() {} +} + +namespace ParaMEDMEM +{ +//================================================================================ +/////////////////////// MEDCouplingUMesh GROUPPING /////////////////////////////// +//================================================================================ + +/*! \name Basic API */ +///@{ +MEDCouplingUMesh::FuseUMeshesOnSameCoords(const std::vector& meshes, int compType, std::vector& corr); +MEDCouplingUMesh::Intersect2DMeshes(const MEDCouplingUMesh *m1, const MEDCouplingUMesh *m2, double eps, DataArrayInt *&cellNb1, DataArrayInt *&cellNb2); +MEDCouplingUMesh::MergeNodesOnUMeshesSharingSameCoords(const std::vector& meshes, double eps); +MEDCouplingUMesh::MergeUMeshes(const MEDCouplingUMesh *mesh1, const MEDCouplingUMesh *mesh2); +MEDCouplingUMesh::MergeUMeshes(std::vector& a); +MEDCouplingUMesh::MergeUMeshesOnSameCoords(const MEDCouplingUMesh *mesh1, const MEDCouplingUMesh *mesh2); +MEDCouplingUMesh::MergeUMeshesOnSameCoords(const std::vector& meshes); +MEDCouplingUMesh::PutUMeshesOnSameAggregatedCoords(const std::vector& meshes); +MEDCouplingUMesh::allocateCells(int nbOfCells); +MEDCouplingUMesh::are2DCellsNotCorrectlyOriented(const double *vec, bool polyOnly, std::vector& cells) const; +MEDCouplingUMesh::areCellsIncludedIn(const MEDCouplingUMesh *other, int compType, DataArrayInt *& arr) const; +MEDCouplingUMesh::arePolyhedronsNotCorrectlyOriented(std::vector& cells) const; +MEDCouplingUMesh::buildBoundaryMesh(bool keepCoords) const; +MEDCouplingUMesh::buildDescendingConnectivity(DataArrayInt *desc, DataArrayInt *descIndx, DataArrayInt *revDesc, DataArrayInt *revDescIndx) const; +MEDCouplingUMesh::buildDescendingConnectivity2(DataArrayInt *desc, DataArrayInt *descIndx, DataArrayInt *revDesc, DataArrayInt *revDescIndx) const; +MEDCouplingUMesh::buildDirectionVectorField() const; +MEDCouplingUMesh::buildFacePartOfMySelfNode(const int *begin, const int *end, bool fullyIn) const; +MEDCouplingUMesh::buildOrthogonalField() const; +MEDCouplingUMesh::buildPartOfMySelf(const int *begin, const int *end, bool keepCoords=true) const; - MEDCouplingUMesh::buildPartOfMySelfNode(const int *begin, const int *end, bool fullyIn) const; ++//MEDCouplingUMesh::buildPartOfMySelfNode(const int *begin, const int *end, bool fullyIn) const; +MEDCouplingUMesh::buildPartOrthogonalField(const int *begin, const int *end) const; +MEDCouplingUMesh::buildSlice3D(const double *origin, const double *vec, double eps, DataArrayInt *&cellIds) const; +MEDCouplingUMesh::buildSlice3DSurf(const double *origin, const double *vec, double eps, DataArrayInt *&cellIds) const; +MEDCouplingUMesh::checkCoherency() const; +MEDCouplingUMesh::checkCoherency1(double eps=1e-12) const; +MEDCouplingUMesh::checkCoherency2(double eps=1e-12) const; - MEDCouplingUMesh::checkDeepEquivalOnSameNodesWith(const MEDCouplingMesh *other, int cellCompPol, double prec,DataArrayInt *&cellCor) const; - MEDCouplingUMesh::checkDeepEquivalWith(const MEDCouplingMesh *other, int cellCompPol, double prec,DataArrayInt *&cellCor, DataArrayInt *&nodeCor) const; ++//MEDCouplingUMesh::checkDeepEquivalOnSameNodesWith(const MEDCouplingMesh *other, int cellCompPol, double prec,DataArrayInt *&cellCor) const; ++//MEDCouplingUMesh::checkDeepEquivalWith(const MEDCouplingMesh *other, int cellCompPol, double prec,DataArrayInt *&cellCor, DataArrayInt *&nodeCor) const; +MEDCouplingUMesh::checkFastEquivalWith(const MEDCouplingMesh *other, double prec) const; +MEDCouplingUMesh::clone(bool recDeepCpy) const; +MEDCouplingUMesh::computeIsoBarycenterOfNodesPerCell() const; +MEDCouplingUMesh::convertAllToPoly(); +MEDCouplingUMesh::convertQuadraticCellsToLinear(); +MEDCouplingUMesh::convertToPolyTypes(const int *cellIdsToConvertBg, const int *cellIdsToConvertEnd); +MEDCouplingUMesh::deepCpy() const; +MEDCouplingUMesh::findAndCorrectBadOriented3DExtrudedCells(); +MEDCouplingUMesh::findBoundaryNodes() const; +MEDCouplingUMesh::finishInsertingCells(); +MEDCouplingUMesh::getAllGeoTypes() const; +MEDCouplingUMesh::getAspectRatioField() const; +MEDCouplingUMesh::getBarycenterAndOwner() const; +MEDCouplingUMesh::getCellContainingPoint(const double *pos, double eps) const; +MEDCouplingUMesh::getCellIdsCrossingPlane(const double *origin, const double *vec, double eps) const; - MEDCouplingUMesh::getCellIdsFullyIncludedInNodeIds(const int *partBg, const int *partEnd) const; - MEDCouplingUMesh::getCellIdsLyingOnNodes(const int *begin, const int *end, bool fullyIn) const; ++//MEDCouplingUMesh::getCellIdsFullyIncludedInNodeIds(const int *partBg, const int *partEnd) const; ++//MEDCouplingUMesh::getCellIdsLyingOnNodes(const int *begin, const int *end, bool fullyIn) const; +MEDCouplingUMesh::getCellsContainingPoint(const double *pos, double eps, std::vector& elts) const; +MEDCouplingUMesh::getCellsContainingPoints(const double *pos, int nbOfPoints, double eps, std::vector& elts, std::vector& eltsIndex) const; +MEDCouplingUMesh::getCellsInBoundingBox(const INTERP_KERNEL::DirectedBoundingBox& bbox, double eps); +MEDCouplingUMesh::getCellsInBoundingBox(const double *bbox, double eps) const; +MEDCouplingUMesh::getEdgeRatioField() const; +MEDCouplingUMesh::getMeasureField(bool isAbs) const; +MEDCouplingUMesh::getMeasureFieldOnNode(bool isAbs) const; +MEDCouplingUMesh::getMeshDimension() const; +MEDCouplingUMesh::getNodalConnectivity() const; +MEDCouplingUMesh::getNodalConnectivity(); +MEDCouplingUMesh::getNodalConnectivityIndex() const; +MEDCouplingUMesh::getNodalConnectivityIndex(); +MEDCouplingUMesh::getNodeIdsInUse(int& nbrOfNodesInUse) const; +MEDCouplingUMesh::getNodeIdsOfCell(int cellId, std::vector& conn) const; +MEDCouplingUMesh::getNumberOfCells() const; +MEDCouplingUMesh::getPartBarycenterAndOwner(const int *begin, const int *end) const; +MEDCouplingUMesh::getPartMeasureField(bool isAbs, const int *begin, const int *end) const; +MEDCouplingUMesh::getReverseNodalConnectivity(DataArrayInt *revNodal, DataArrayInt *revNodalIndx) const; +MEDCouplingUMesh::getSkewField() const; +MEDCouplingUMesh::getTypeOfCell(int cellId) const; +MEDCouplingUMesh::getTypesOfPart(const int *begin, const int *end) const; +MEDCouplingUMesh::getWarpField() const; +MEDCouplingUMesh::insertNextCell(INTERP_KERNEL::NormalizedCellType type, int size, const int *nodalConnOfCell); +MEDCouplingUMesh::isEqualWithoutConsideringStr(const MEDCouplingMesh *other, double prec) const; - MEDCouplingUMesh::mergeNodes(double precision, bool& areNodesMerged, int& newNbOfNodes); - MEDCouplingUMesh::mergeNodes2(double precision, bool& areNodesMerged, int& newNbOfNodes); ++//MEDCouplingUMesh::mergeNodes(double precision, bool& areNodesMerged, int& newNbOfNodes); ++//MEDCouplingUMesh::mergeNodes2(double precision, bool& areNodesMerged, int& newNbOfNodes); +MEDCouplingUMesh::orientCorrectly2DCells(const double *vec, bool polyOnly); +MEDCouplingUMesh::orientCorrectlyPolyhedrons(); - MEDCouplingUMesh::renumberNodes(const int *newNodeNumbers, int newNbOfNodes); - MEDCouplingUMesh::renumberNodes2(const int *newNodeNumbers, int newNbOfNodes); ++//MEDCouplingUMesh::renumberNodes(const int *newNodeNumbers, int newNbOfNodes); ++//MEDCouplingUMesh::renumberNodes2(const int *newNodeNumbers, int newNbOfNodes); +MEDCouplingUMesh::renumberNodesInConn(const int *newNodeNumbersO2N); +MEDCouplingUMesh::reprQuickOverview(std::ostream& stream) const; +MEDCouplingUMesh::setConnectivity(DataArrayInt *conn, DataArrayInt *connIndex, bool isComputingTypes=true); +MEDCouplingUMesh::setMeshDimension(int meshDim); +MEDCouplingUMesh::sortCellsInMEDFileFrmt(); - MEDCouplingUMesh::tryToShareSameCoordsPermute(const MEDCouplingPointSet& other, double epsilon); ++//MEDCouplingUMesh::tryToShareSameCoordsPermute(const MEDCouplingPointSet& other, double epsilon); +MEDCouplingUMesh::unPolyze(); - MEDCouplingUMesh::zipConnectivityTraducer(int compType, int startCellId=0); ++//MEDCouplingUMesh::zipConnectivityTraducer(int compType, int startCellId=0); +MEDCouplingUMesh::zipCoordsTraducer(); + ///@} + + /*! \name Advanced API */ +///@{ +MEDCouplingUMesh::areOnlySimplexCells() const; +MEDCouplingUMesh::checkButterflyCells(std::vector& cells, double eps=1e-12) const; +MEDCouplingUMesh::computeTypes(); +MEDCouplingUMesh::convertDegeneratedCells(); +MEDCouplingUMesh::convertExtrudedPolyhedra(); +MEDCouplingUMesh::getMeshLength() const; +MEDCouplingUMesh::isFullyQuadratic() const; +MEDCouplingUMesh::isPresenceOfQuadratic() const; +MEDCouplingUMesh::simplexize(int policy); +MEDCouplingUMesh::tessellate2D(double eps); +MEDCouplingUMesh::tessellate2DCurve(double eps); + ///@ + +/*! \name Others... */ +///@{ +MEDCouplingUMesh::AggregateSortedByTypeMeshesOnSameCoords(const std::vector& ms,DataArrayInt *&szOfCellGrpOfSameType,DataArrayInt *&idInMsOfCellGrpOfSameType); - MEDCouplingUMesh::AppendExtrudedCell(const int *connBg, const int *connEnd, int nbOfNodesPerLev, bool isQuad, std::vector& ret); ++//MEDCouplingUMesh::AppendExtrudedCell(const int *connBg, const int *connEnd, int nbOfNodesPerLev, bool isQuad, std::vector& ret); +MEDCouplingUMesh::AreCellsEqual(const int *conn, const int *connI, int cell1, int cell2, int compType); +MEDCouplingUMesh::AreCellsEqual0(const int *conn, const int *connI, int cell1, int cell2); +MEDCouplingUMesh::AreCellsEqual1(const int *conn, const int *connI, int cell1, int cell2); +MEDCouplingUMesh::AreCellsEqual2(const int *conn, const int *connI, int cell1, int cell2); +MEDCouplingUMesh::AreCellsEqual3(const int *conn, const int *connI, int cell1, int cell2); +MEDCouplingUMesh::AreCellsEqual7(const int *conn, const int *connI, int cell1, int cell2); +MEDCouplingUMesh::AreCellsEqualInPool(const std::vector& candidates, int compType, const int *conn, const int *connI, DataArrayInt *result) ; - MEDCouplingUMesh::AssemblyForSplitFrom3DCurve(const std::vector& cut3DCurve, std::vector& nodesOnPlane, const int *nodal3DSurf, const int *nodalIndx3DSurf,const int *nodal3DCurve, const int *nodalIndx3DCurve,const int *desc, const int *descIndx, std::vector< std::pair >& cut3DSurf); ++//MEDCouplingUMesh::AssemblyForSplitFrom3DCurve(const std::vector& cut3DCurve, std::vector& nodesOnPlane, const int *nodal3DSurf, const int *nodalIndx3DSurf,const int *nodal3DCurve, const int *nodalIndx3DCurve,const int *desc, const int *descIndx, std::vector< std::pair >& cut3DSurf); +MEDCouplingUMesh::Build0DMeshFromCoords(DataArrayDouble *da); +MEDCouplingUMesh::BuildConvexEnvelopOf2DCellJarvis(const double *coords, const int *nodalConnBg, const int *nodalConnEnd, DataArrayInt *nodalConnecOut); - MEDCouplingUMesh::BuildIntersectEdges(const MEDCouplingUMesh *m1, const MEDCouplingUMesh *m2, const std::vector& addCoo, const std::vector< std::vector >& subDiv, std::vector< std::vector >& intersectEdge); - MEDCouplingUMesh::BuildIntersecting2DCellsFromEdges(double eps, const MEDCouplingUMesh *m1, const int *desc1, const int *descIndx1, const std::vector >& intesctEdges1, const std::vector< std::vector >& colinear2,const MEDCouplingUMesh *m2, const int *desc2, const int *descIndx2, const std::vector >& intesctEdges2,const std::vector& addCoords,std::vector& addCoordsQuadratic, std::vector& cr, std::vector& crI, std::vector& cNb1, std::vector& cNb2); ++//MEDCouplingUMesh::BuildIntersectEdges(const MEDCouplingUMesh *m1, const MEDCouplingUMesh *m2, const std::vector& addCoo, const std::vector< std::vector >& subDiv, std::vector< std::vector >& intersectEdge); ++//MEDCouplingUMesh::BuildIntersecting2DCellsFromEdges(double eps, const MEDCouplingUMesh *m1, const int *desc1, const int *descIndx1, const std::vector >& intesctEdges1, const std::vector< std::vector >& colinear2,const MEDCouplingUMesh *m2, const int *desc2, const int *descIndx2, const std::vector >& intesctEdges2,const std::vector& addCoords,std::vector& addCoordsQuadratic, std::vector& cr, std::vector& crI, std::vector& cNb1, std::vector& cNb2); +MEDCouplingUMesh::ComputeNeighborsOfCellsAdv(const DataArrayInt *desc, const DataArrayInt *descI, const DataArrayInt *revDesc, const DataArrayInt *revDescI,DataArrayInt *&neighbors, DataArrayInt *&neighborsIdx); - MEDCouplingUMesh::ComputeRangesFromTypeDistribution(const std::vector& code); ++//MEDCouplingUMesh::ComputeRangesFromTypeDistribution(const std::vector& code); +MEDCouplingUMesh::ComputeSpreadZoneGradually(const DataArrayInt *arrIn, const DataArrayInt *arrIndxIn); +MEDCouplingUMesh::ComputeSpreadZoneGraduallyFromSeed(const int *seedBg, const int *seedEnd, const DataArrayInt *arrIn, const DataArrayInt *arrIndxIn, int nbOfDepthPeeling, int& nbOfDepthPeelingPerformed); - MEDCouplingUMesh::ComputeSpreadZoneGraduallyFromSeedAlg(std::vector& fetched, const int *seedBg, const int *seedEnd, const DataArrayInt *arrIn, const DataArrayInt *arrIndxIn, int nbOfDepthPeeling, int& nbOfDepthPeelingPerformed); ++//MEDCouplingUMesh::ComputeSpreadZoneGraduallyFromSeedAlg(std::vector& fetched, const int *seedBg, const int *seedEnd, const DataArrayInt *arrIn, const DataArrayInt *arrIndxIn, int nbOfDepthPeeling, int& nbOfDepthPeelingPerformed); +MEDCouplingUMesh::ComputeVecAndPtOfFace(double eps, const double *coords, const int *begin, const int *end, double *v, double *p); - MEDCouplingUMesh::CorrectExtrudedCell(int *begin, int *end); ++//MEDCouplingUMesh::CorrectExtrudedCell(int *begin, int *end); +MEDCouplingUMesh::CorrectExtrudedStaticCell(int *begin, int *end); +MEDCouplingUMesh::ExtractFromIndexedArrays(const int *idsOfSelectBg, const int *idsOfSelectEnd, const DataArrayInt *arrIn, const DataArrayInt *arrIndxIn,DataArrayInt* &arrOut, DataArrayInt* &arrIndexOut); - MEDCouplingUMesh::FillInCompact3DMode(int spaceDim, int nbOfNodesInCell, const int *conn, const double *coo, double *zipFrmt); ++//MEDCouplingUMesh::FillInCompact3DMode(int spaceDim, int nbOfNodesInCell, const int *conn, const double *coo, double *zipFrmt); +MEDCouplingUMesh::FindCommonCellsAlg(int compType, int startCellId, const DataArrayInt *nodal, const DataArrayInt *nodalI, const DataArrayInt *revNodal, const DataArrayInt *revNodalI,DataArrayInt *& commonCellsArr, DataArrayInt *& commonCellsIArr); - MEDCouplingUMesh::IntersectDescending2DMeshes(const MEDCouplingUMesh *m1, const MEDCouplingUMesh *m2, double eps,std::vector< std::vector >& intersectEdge1, std::vector< std::vector >& colinear2, std::vector< std::vector >& subDiv2,MEDCouplingUMesh *& m1Desc, DataArrayInt *&desc1, DataArrayInt *&descIndx1, DataArrayInt *&revDesc1, DataArrayInt *&revDescIndx1,MEDCouplingUMesh *& m2Desc, DataArrayInt *&desc2, DataArrayInt *&descIndx2, DataArrayInt *&revDesc2, DataArrayInt *&revDescIndx2,std::vector& addCoo); - MEDCouplingUMesh::Is3DExtrudedCellWellOriented(const int *begin, const int *end, const double *coords); ++//MEDCouplingUMesh::IntersectDescending2DMeshes(const MEDCouplingUMesh *m1, const MEDCouplingUMesh *m2, double eps,std::vector< std::vector >& intersectEdge1, std::vector< std::vector >& colinear2, std::vector< std::vector >& subDiv2,MEDCouplingUMesh *& m1Desc, DataArrayInt *&desc1, DataArrayInt *&descIndx1, DataArrayInt *&revDesc1, DataArrayInt *&revDescIndx1,MEDCouplingUMesh *& m2Desc, DataArrayInt *&desc2, DataArrayInt *&descIndx2, DataArrayInt *&revDesc2, DataArrayInt *&revDescIndx2,std::vector& addCoo); ++//MEDCouplingUMesh::Is3DExtrudedCellWellOriented(const int *begin, const int *end, const double *coords); +MEDCouplingUMesh::Is3DExtrudedStaticCellWellOriented(const int *begin, const int *end, const double *coords); +MEDCouplingUMesh::IsPolygonWellOriented(bool isQuadratic, const double *vec, const int *begin, const int *end, const double *coords); +MEDCouplingUMesh::IsPolyhedronWellOriented(const int *begin, const int *end, const double *coords); +MEDCouplingUMesh::IsPyra5WellOriented(const int *begin, const int *end, const double *coords); +MEDCouplingUMesh::IsTetra4WellOriented(const int *begin, const int *end, const double *coords); +MEDCouplingUMesh::MEDCouplingUMesh(); +MEDCouplingUMesh::MEDCouplingUMesh(const MEDCouplingUMesh& other, bool deepCopy); - MEDCouplingUMesh::MergeUMeshesLL(std::vector& a); ++//MEDCouplingUMesh::MergeUMeshesLL(std::vector& a); +MEDCouplingUMesh::New(); - MEDCouplingUMesh::New(const char *meshName, int meshDim); ++MEDCouplingUMesh::New(const std::string& meshName, int meshDim); +MEDCouplingUMesh::RemoveIdsFromIndexedArrays(const int *idsToRemoveBg, const int *idsToRemoveEnd, DataArrayInt *arr, DataArrayInt *arrIndx, int offsetForRemoval=0); +MEDCouplingUMesh::SetPartOfIndexedArrays(const int *idsOfSelectBg, const int *idsOfSelectEnd, const DataArrayInt *arrIn, const DataArrayInt *arrIndxIn,const DataArrayInt *srcArr, const DataArrayInt *srcArrIndex,DataArrayInt* &arrOut, DataArrayInt* &arrIndexOut); +MEDCouplingUMesh::SetPartOfIndexedArrays2(int start, int end, int step, const DataArrayInt *arrIn, const DataArrayInt *arrIndxIn,const DataArrayInt *srcArr, const DataArrayInt *srcArrIndex,DataArrayInt* &arrOut, DataArrayInt* &arrIndexOut); +MEDCouplingUMesh::SetPartOfIndexedArraysSameIdx(const int *idsOfSelectBg, const int *idsOfSelectEnd, DataArrayInt *arrInOut, const DataArrayInt *arrIndxIn,const DataArrayInt *srcArr, const DataArrayInt *srcArrIndex); +MEDCouplingUMesh::SetPartOfIndexedArraysSameIdx2(int start, int end, int step, DataArrayInt *arrInOut, const DataArrayInt *arrIndxIn,const DataArrayInt *srcArr, const DataArrayInt *srcArrIndex); +MEDCouplingUMesh::SimplifyPolyhedronCell(double eps, const DataArrayDouble *coords, const int *begin, const int *end, DataArrayInt *res); +MEDCouplingUMesh::TryToCorrectPolyhedronOrientation(int *begin, int *end, const double *coords); +MEDCouplingUMesh::advancedRepr() const; - MEDCouplingUMesh::areCellsFrom2MeshEqual(const MEDCouplingUMesh *other, int cellId, double prec) const; ++//MEDCouplingUMesh::areCellsFrom2MeshEqual(const MEDCouplingUMesh *other, int cellId, double prec) const; +MEDCouplingUMesh::areCellsIncludedIn2(const MEDCouplingUMesh *other, DataArrayInt *& arr) const; - MEDCouplingUMesh::assemblyForSplitFrom3DSurf(const std::vector< std::pair >& cut3DSurf,const int *desc, const int *descIndx, DataArrayInt *nodalRes, DataArrayInt *nodalResIndx, DataArrayInt *cellIds) const; ++//MEDCouplingUMesh::assemblyForSplitFrom3DSurf(const std::vector< std::pair >& cut3DSurf,const int *desc, const int *descIndx, DataArrayInt *nodalRes, DataArrayInt *nodalResIndx, DataArrayInt *cellIds) const; +MEDCouplingUMesh::buildExtrudedMesh(const MEDCouplingUMesh *mesh1D, int policy); +MEDCouplingUMesh::buildExtrudedMeshFromThisLowLev(int nbOfNodesOf1Lev, bool isQuad) const; +MEDCouplingUMesh::buildPartOfMySelf2(int start, int end, int step, bool keepCoords=true) const; +MEDCouplingUMesh::buildPartOfMySelfKeepCoords(const int *begin, const int *end) const; +MEDCouplingUMesh::buildPartOfMySelfKeepCoords2(int start, int end, int step) const; +MEDCouplingUMesh::buildSetInstanceFromThis(int spaceDim) const; +MEDCouplingUMesh::buildSpreadZonesWithPoly() const; +MEDCouplingUMesh::buildUnionOf2DMesh() const; +MEDCouplingUMesh::buildUnionOf3DMesh() const; +MEDCouplingUMesh::buildUnstructured() const; +MEDCouplingUMesh::cellIterator(); +MEDCouplingUMesh::cellsByType(); +MEDCouplingUMesh::checkConnectivityFullyDefined() const; +MEDCouplingUMesh::checkConsecutiveCellTypes() const; +MEDCouplingUMesh::checkConsecutiveCellTypesAndOrder(const INTERP_KERNEL::NormalizedCellType *orderBg, const INTERP_KERNEL::NormalizedCellType *orderEnd) const; +MEDCouplingUMesh::checkConsecutiveCellTypesForMEDFileFrmt() const; +MEDCouplingUMesh::checkFullyDefined() const; +MEDCouplingUMesh::checkTypeConsistencyAndContig(const std::vector& code, const std::vector& idsPerType) const; +MEDCouplingUMesh::computeFetchedNodeIds() const; +MEDCouplingUMesh::computeNbOfNodesPerCell() const; +MEDCouplingUMesh::computeNeighborsOfCells(DataArrayInt *&neighbors, DataArrayInt *&neighborsIdx) const; +MEDCouplingUMesh::computeNodeIdsAlg(std::vector& nodeIdsInUse) const; +MEDCouplingUMesh::computeSkin() const; +MEDCouplingUMesh::convertCellArrayPerGeoType(const DataArrayInt *da) const; +MEDCouplingUMesh::convertLinearCellsToQuadratic(int conversionType=0); +MEDCouplingUMesh::convertLinearCellsToQuadratic1D0(DataArrayInt *&conn, DataArrayInt *&connI, DataArrayDouble *& coords, std::set& types) const; +MEDCouplingUMesh::convertLinearCellsToQuadratic2D0(DataArrayInt *&conn, DataArrayInt *&connI, DataArrayDouble *& coords, std::set& types) const; +MEDCouplingUMesh::convertLinearCellsToQuadratic2D1(DataArrayInt *&conn, DataArrayInt *&connI, DataArrayDouble *& coords, std::set& types) const; +MEDCouplingUMesh::convertLinearCellsToQuadratic2DAnd3D0(const MEDCouplingUMesh *m1D, const DataArrayInt *desc, const DataArrayInt *descI, DataArrayInt *&conn, DataArrayInt *&connI, DataArrayDouble *& coords, std::set& types) const; +MEDCouplingUMesh::convertLinearCellsToQuadratic3D0(DataArrayInt *&conn, DataArrayInt *&connI, DataArrayDouble *& coords, std::set& types) const; +MEDCouplingUMesh::convertLinearCellsToQuadratic3D1(DataArrayInt *&conn, DataArrayInt *&connI, DataArrayDouble *& coords, std::set& types) const; +MEDCouplingUMesh::convexEnvelop2D(); +MEDCouplingUMesh::cppRepr() const; +MEDCouplingUMesh::distanceToPoint(const double *ptBg, const double *ptEnd, int& cellId, int& nodeId) const; - MEDCouplingUMesh::distanceToPoint2DCurveAlg(const double *pt, const DataArrayInt *cellIds, double& ret0, int& cellId) const; - MEDCouplingUMesh::distanceToPoint3DSurfAlg(const double *pt, const DataArrayInt *cellIds, double& ret0, int& cellId) const; ++//MEDCouplingUMesh::distanceToPoint2DCurveAlg(const double *pt, const DataArrayInt *cellIds, double& ret0, int& cellId) const; ++//MEDCouplingUMesh::distanceToPoint3DSurfAlg(const double *pt, const DataArrayInt *cellIds, double& ret0, int& cellId) const; +MEDCouplingUMesh::duplicateNodes(const int *nodeIdsToDuplicateBg, const int *nodeIdsToDuplicateEnd); +MEDCouplingUMesh::duplicateNodesInConn(const int *nodeIdsToDuplicateBg, const int *nodeIdsToDuplicateEnd, int offset); +MEDCouplingUMesh::emulateMEDMEMBDC(const MEDCouplingUMesh *nM1LevMesh, DataArrayInt *desc, DataArrayInt *descIndx, DataArrayInt *&revDesc, DataArrayInt *&revDescIndx, DataArrayInt *& nM1LevMeshIds, DataArrayInt *&meshnM1Old2New) const; +MEDCouplingUMesh::explode3DMeshTo1D(DataArrayInt *desc, DataArrayInt *descIndx, DataArrayInt *revDesc, DataArrayInt *revDescIndx) const; +MEDCouplingUMesh::fillCellIdsToKeepFromNodeIds(const int *begin, const int *end, bool fullyIn, DataArrayInt *&cellIdsKeptArr) const; +MEDCouplingUMesh::fillExtCoordsUsingTranslAndAutoRotation(const MEDCouplingUMesh *mesh1D, bool isQuad) const; +MEDCouplingUMesh::fillExtCoordsUsingTranslAndAutoRotation2D(const MEDCouplingUMesh *mesh1D, bool isQuad) const; +MEDCouplingUMesh::fillExtCoordsUsingTranslAndAutoRotation3D(const MEDCouplingUMesh *mesh1D, bool isQuad) const; +MEDCouplingUMesh::fillExtCoordsUsingTranslation(const MEDCouplingUMesh *mesh1D, bool isQuad) const; +MEDCouplingUMesh::findAndCorrectBadOriented3DCells(); +MEDCouplingUMesh::findCellIdsLyingOn(const MEDCouplingUMesh& otherDimM1OnSameCoords, DataArrayInt *&cellIdsRk0, DataArrayInt *&cellIdsRk1) const; +MEDCouplingUMesh::findCellIdsOnBoundary() const; +MEDCouplingUMesh::findCommonCells(int compType, int startCellId, DataArrayInt *& commonCellsArr, DataArrayInt *& commonCellsIArr) const; +MEDCouplingUMesh::findNodesToDuplicate(const MEDCouplingUMesh& otherDimM1OnSameCoords, DataArrayInt *& nodeIdsToDuplicate,DataArrayInt *& cellIdsNeededToBeRenum, DataArrayInt *& cellIdsNotModified) const; - MEDCouplingUMesh::getAllTypes() const; ++//MEDCouplingUMesh::getAllTypes() const; +MEDCouplingUMesh::getBoundingBoxForBBTree(std::vector& bbox) const; +MEDCouplingUMesh::getDistributionOfTypes() const; +MEDCouplingUMesh::getFastAveragePlaneOfThis(double *vec, double *pos) const; - MEDCouplingUMesh::getHeapMemorySize() const; ++//MEDCouplingUMesh::getHeapMemorySize() const; +MEDCouplingUMesh::getLevArrPerCellTypes(const INTERP_KERNEL::NormalizedCellType *orderBg, const INTERP_KERNEL::NormalizedCellType *orderEnd, DataArrayInt *&nbPerType) const; +MEDCouplingUMesh::getNumberOfCellsWithType(INTERP_KERNEL::NormalizedCellType type) const; +MEDCouplingUMesh::getNumberOfNodesInCell(int cellId) const; +MEDCouplingUMesh::getQuadraticStatus() const; +MEDCouplingUMesh::getRenumArrForConsecutiveCellTypesSpec(const INTERP_KERNEL::NormalizedCellType *orderBg, const INTERP_KERNEL::NormalizedCellType *orderEnd) const; +MEDCouplingUMesh::getTinySerializationInformation(std::vector& tinyInfoD, std::vector& tinyInfo, std::vector& littleStrings) const; +MEDCouplingUMesh::getType() const { return UNSTRUCTURED; } +MEDCouplingUMesh::getVTKDataSetType() const; +MEDCouplingUMesh::giveCellsWithType(INTERP_KERNEL::NormalizedCellType type) const; +MEDCouplingUMesh::isContiguous1D() const; +MEDCouplingUMesh::isEmptyMesh(const std::vector& tinyInfo) const; +MEDCouplingUMesh::isEqualIfNotWhy(const MEDCouplingMesh *other, double prec, std::string& reason) const; +MEDCouplingUMesh::keepCellIdsByType(INTERP_KERNEL::NormalizedCellType type, const int *begin, const int *end) const; +MEDCouplingUMesh::keepSpecifiedCells(INTERP_KERNEL::NormalizedCellType type, const int *idsPerGeoTypeBg, const int *idsPerGeoTypeEnd) const; +MEDCouplingUMesh::mergeMyselfWith(const MEDCouplingMesh *other) const; +MEDCouplingUMesh::partitionBySpreadZone() const; +MEDCouplingUMesh::project1D(const double *pt, const double *v, double eps, double *res) const; +MEDCouplingUMesh::rearrange2ConsecutiveCellTypes(); +MEDCouplingUMesh::renumberCells(const int *old2NewBg, bool check=true); +MEDCouplingUMesh::reprConnectivityOfThis() const; +MEDCouplingUMesh::reprConnectivityOfThisLL(std::ostringstream& stream) const; +MEDCouplingUMesh::resizeForUnserialization(const std::vector& tinyInfo, DataArrayInt *a1, DataArrayDouble *a2, std::vector& littleStrings) const; +MEDCouplingUMesh::serialize(DataArrayInt *&a1, DataArrayDouble *&a2) const; +MEDCouplingUMesh::setPartOfMySelf(const int *cellIdsBg, const int *cellIdsEnd, const MEDCouplingUMesh& otherOnSameCoordsThanThis); +MEDCouplingUMesh::setPartOfMySelf2(int start, int end, int step, const MEDCouplingUMesh& otherOnSameCoordsThanThis); +MEDCouplingUMesh::shiftNodeNumbersInConn(int delta); +MEDCouplingUMesh::simpleRepr() const; +MEDCouplingUMesh::simplexizePlanarFace5(); +MEDCouplingUMesh::simplexizePlanarFace6(); +MEDCouplingUMesh::simplexizePol0(); +MEDCouplingUMesh::simplexizePol1(); +MEDCouplingUMesh::simplifyPolyhedra(double eps); +MEDCouplingUMesh::split3DCurveWithPlane(const double *origin, const double *vec, double eps, std::vector& cut3DCurve); +MEDCouplingUMesh::splitByType() const; +MEDCouplingUMesh::splitProfilePerType(const DataArrayInt *profile, std::vector& code, std::vector& idsInPflPerType, std::vector& idsPerType) const; +MEDCouplingUMesh::subDivide2DMesh(const int *nodeSubdived, const int *nodeIndxSubdived, const int *desc, const int *descIndex); +MEDCouplingUMesh::unserialization(const std::vector& tinyInfoD, const std::vector& tinyInfo, const DataArrayInt *a1, DataArrayDouble *a2, const std::vector& littleStrings); +MEDCouplingUMesh::updateTime() const; +MEDCouplingUMesh::writeVTKLL(std::ostream& ofs, const std::string& cellData, const std::string& pointData) const; +MEDCouplingUMesh::~MEDCouplingUMesh(); - template MEDCouplingUMesh * MEDCouplingUMesh::buildDescendingConnectivityGen(DataArrayInt *desc, DataArrayInt *descIndx, DataArrayInt *revDesc, DataArrayInt *revDescIndx, DimM1DescNbrer nbrer) const; ++//template MEDCouplingUMesh * MEDCouplingUMesh::buildDescendingConnectivityGen(DataArrayInt *desc, DataArrayInt *descIndx, DataArrayInt *revDesc, DataArrayInt *revDescIndx, DimM1DescNbrer nbrer) const; +template void MEDCouplingUMesh::getCellsContainingPointsAlg +(const double *coords, const double *pos, int nbOfPoints,double eps, std::vector& elts, + std::vector& eltsIndex) const; + - const INTERP_KERNEL::NormalizedCellType MEDCouplingUMesh::MEDMEM_ORDER[N_MEDMEM_ORDER]; - const int MEDCouplingUMesh::N_MEDMEM_ORDER=24; ++//const INTERP_KERNEL::NormalizedCellType MEDCouplingUMesh::MEDMEM_ORDER[N_MEDMEM_ORDER]; ++//const int MEDCouplingUMesh::N_MEDMEM_ORDER=24; +double MEDCouplingUMesh::EPS_FOR_POLYH_ORIENTATION; +int MEDCouplingUMesh::_mesh_dim; +std::set MEDCouplingUMesh::_types; +DataArrayInt * MEDCouplingUMesh::_nodal_connec; +DataArrayInt * MEDCouplingUMesh::_nodal_connec_index; + ///@} +} + diff --cc medtool/doc/user/doxygen/fakesources/MEDFileField.C index 4919e4a48,000000000..9e9365db6 mode 100644,000000..100644 --- a/medtool/doc/user/doxygen/fakesources/MEDFileField.C +++ b/medtool/doc/user/doxygen/fakesources/MEDFileField.C @@@ -1,106 -1,0 +1,106 @@@ +// Copyright (C) 2013-2015 CEA/DEN, EDF R&D, OPEN CASCADE +// +// 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +// +// See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com +// + +// This file contains some code used only for +// generation of documentation for inline methods. + + +namespace ParaMEDMEM // inline methods of MEDFileField1TSWithoutSDA +{ + /*! + * Returns the number of iteration where \a this field has been calculated. + * \return int - the iteration number. + */ - int MEDFileField1TSWithoutSDA::getIteration() const {} ++// int MEDFileField1TSWithoutSDA::getIteration() const {} + /*! + * Returns the order number of iteration where \a this field has been calculated. + * \return int - the order number. + */ - int MEDFileField1TSWithoutSDA::getOrder() const {} ++// int MEDFileField1TSWithoutSDA::getOrder() const {} + /*! + * Returns time, number of iteration and order number of iteration when + * \a this field has been calculated. + * \param [out] iteration - the iteration number. + * \param [out] order - the order number. + * \return double - the time value. + */ - double MEDFileField1TSWithoutSDA::getTime(int& iteration, int& order) const {} ++// double MEDFileField1TSWithoutSDA::getTime(int& iteration, int& order) const {} + /*! + * Sets time, number of iteration and order number of iteration when + * \a this field has been calculated. + * \param [in] val - the time value. + * \param [in] iteration - the iteration number. + * \param [in] order - the order number. + */ - void MEDFileField1TSWithoutSDA::setTime(int iteration, int order, double val) {} ++// void MEDFileField1TSWithoutSDA::setTime(int iteration, int order, double val) {} + /*! + * Returns units in which the time is measured. + * \return const char * - the time unit name. + */ - const std::string& MEDFileField1TSWithoutSDA::getDtUnit() const {} ++// const std::string& MEDFileField1TSWithoutSDA::getDtUnit() const {} +} + +namespace ParaMEDMEM // inline methods of MEDFileFieldGlobsReal +{ + /*! + * Returns non empty names of all used profiles. To get all profiles call getPfls(). + * \warning If a profile is used several times, its name is returned **only once**. + * To have a profile name in the result each time it is used, call + * getPflsReallyUsedMulti(). + * \return std::vector - a sequence of names of used profiles. + */ + std::vector MEDFileFieldGlobsReal::getPflsReallyUsed() const {} + /*! + * Returns non empty names of all used localizations. To get all localizations call getLocs(). + * \warning If a localization is used several times, its name is returned **only once**. + * To have a localization name in the result each time it is used, call + * getLocsReallyUsedMulti(). + * \return std::vector - a sequence of names of used localizations. + */ + std::vector MEDFileFieldGlobsReal::getLocsReallyUsed() const {} + /*! + * Returns non empty names of all used profiles as many times as they are used. + * \return std::vector - a sequence of names of used profiles. + */ + std::vector MEDFileFieldGlobsReal::getPflsReallyUsedMulti() const {} + /*! + * Returns non empty names of all used localizations as many times as they are used. + * \return std::vector - a sequence of names of used localizations. + */ + std::vector MEDFileFieldGlobsReal::getLocsReallyUsedMulti() const {} + /*! + * Replaces references to some profiles (a reference is a profile name) by references + * to other profiles. + * \param [in] mapOfModif - a sequence describing required replacements. Each element of + * this sequence is a pair whose + * - the first item is a vector of profile names to replace by the second item, + * - the second item is a profile name to replace every profile of the first item. + */ + void MEDFileFieldGlobsReal::changePflsRefsNamesGen(const std::vector< std::pair, std::string > >& mapOfModif) throw(INTERP_KERNEL::Exception) {} + /*! + * Replaces references to some localizations (a reference is a localization name) by references + * to other localizations. + * \param [in] mapOfModif - a sequence describing required replacements. Each element of + * this sequence is a pair whose + * - the first item is a vector of localization names to replace by the second item, + * - the second item is a localization name to replace every localization of the first + * item. + */ + void MEDFileFieldGlobsReal::changeLocsRefsNamesGen(const std::vector< std::pair, std::string > >& mapOfModif) throw(INTERP_KERNEL::Exception) {} +} diff --cc medtool/doc/user/doxygen/fakesources/MEDFileMesh.C index 80f85fe86,000000000..10565363b mode 100644,000000..100644 --- a/medtool/doc/user/doxygen/fakesources/MEDFileMesh.C +++ b/medtool/doc/user/doxygen/fakesources/MEDFileMesh.C @@@ -1,353 -1,0 +1,353 @@@ +// Copyright (C) 2013-2015 CEA/DEN, EDF R&D, OPEN CASCADE +// +// 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +// +// See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com +// + +// This file contains some code used only for +// * generation of documentation for inline methods, +// * groupping methods into "Basic API", "Advanced" and "Others..." sections + + +namespace ParaMEDMEM +{ + /*! + * Sets the name of \a this mesh. + * \param [in] name - the new mesh name. + */ - void MEDFileMesh::setName(const char *name) {} ++ void MEDFileMesh::setName(const std::string& name) {} + /*! + * Returns the name of \a this mesh. + * \return const char* name - the mesh name. + */ - const char *MEDFileMesh::getName() const {} ++ const std::string& MEDFileMesh::getName() const {} + /*! + * Sets the universal name of \a this mesh. The universal name uniquely identifies the mesh. + * \param [in] name - the new universal mesh name. + */ - void MEDFileMesh::setUnivName(const char *name) {} ++ void MEDFileMesh::setUnivName(const std::string& name) {} + /*! + * Returns the universal name of \a this mesh. The universal name uniquely identifies the mesh. - * \return const char * - the universal mesh name. ++ * \return const std::string& - the universal mesh name. + */ - const char *MEDFileMesh::getUnivName() const {} ++ const std::string& MEDFileMesh::getUnivName() const {} + /*! + * Sets the description of \a this mesh. + * \param [in] name - the new mesh description. + */ - void MEDFileMesh::setDescription(const char *name) {} ++ void MEDFileMesh::setDescription(const std::string& name) {} + /*! + * Returns the description of \a this mesh. + * \return const char* - the mesh description. + */ - const char *MEDFileMesh::getDescription() const {} ++ const std::string& MEDFileMesh::getDescription() const {} + /*! + * Sets the order number of iteration of \a this mesh state. + * \param [in] order - the order number. + */ + void MEDFileMesh::setOrder(int order) {} + /*! + * Returns the order number of iteration of \a this mesh state. + * \return int - the order number. + */ + int MEDFileMesh::getOrder() const {} + /*! + * Sets the number of iteration of \a this mesh state. + * \param [in] it - the iteration number. + */ + void MEDFileMesh::setIteration(int it) {} + /*! + * Returns the number of iteration of \a this mesh state. + * \return int - the iteration number. + */ + int MEDFileMesh::getIteration() const {} + /*! + * Sets the time of \a this mesh state. + * \param [in] val - the time value. + */ + void MEDFileMesh::setTimeValue(double time) {} + /*! + * Sets time, the number of iteration and the order number of iteration + * of \a this mesh state. + * \param [in] val - the time value. + * \param [in] iteration - the iteration number. + * \param [in] order - the order number. + */ + void MEDFileMesh::setTime(int dt, int it, double time) {} + /*! + * Returns time, the number of iteration and the order number of iteration + * of \a this mesh state. + * \param [out] iteration - the iteration number. + * \param [out] order - the order number. + * \return double - the time value. + */ + double MEDFileMesh::getTime(int& dt, int& it) {} + /*! + * Returns the time of \a this mesh state. + * \return double - the time value. + */ + double MEDFileMesh::getTimeValue() const {} + /*! + * Sets units in which the time is measured. + * \param [in] unit - the time unit name. + */ - void MEDFileMesh::setTimeUnit(const char *unit) {} ++ void MEDFileMesh::setTimeUnit(const std::string& unit) {} + /*! + * Returns units in which the time is measured. - * \return const char * - the time unit name. ++ * \return const std::string& - the time unit name. + */ - const char *MEDFileMesh::getTimeUnit() const {} ++ const std::string& MEDFileMesh::getTimeUnit() const {} + /*! + * Returns names and ids of all families in \a this mesh. + * \return const std::map& - a map of a family name to a family id. + */ + const std::map& MEDFileMesh::getFamilyInfo() const {} + /*! + * Returns names of all groups and families constituting them in \a this mesh. + * \return const std::map >& - + * a map of a group name to a vector of names of families constituting the group. + */ + const std::map >& MEDFileMesh::getGroupInfo() const {} + /*! + * Returns relative dimensions of mesh entities (excluding nodes) present in \a this mesh. + * \return std::vector - a sequence of the relative dimensions. + */ + std::vector MEDFileMesh::getNonEmptyLevels() const {} + /*! + * Returns relative dimensions of mesh entities (including nodes) present in \a this mesh. + * \return std::vector - a sequence of the relative dimensions. + */ + std::vector MEDFileMesh::getNonEmptyLevelsExt() const {} + /*! + * Returns number of mesh entities of a given relative dimension in \a this mesh. + * \param [in] meshDimRelToMaxExt - the relative dimension of interest. + * \return int - the number of entities. + * \throw If no mesh entities of dimension \a meshDimRelToMaxExt are available in \a this mesh. + */ + int MEDFileMesh::getSizeAtLevel(int meshDimRelToMaxExt) const throw(INTERP_KERNEL::Exception) {} + /*! + * Returns a MEDCouplingMesh of a given relative dimension. + * \param [in] meshDimRelToMax - the relative dimension of interest. + * \param [in] renum - if \c true, the returned mesh is permuted according to the + * optional numbers of mesh entities. + * \return MEDCouplingMesh * - a pointer to MEDCouplingMesh that the caller is to + * delete using decrRef() as it is no more needed. + * \throw If there are no mesh entities of \a meshDimRelToMaxExt dimension in \a this mesh. + * \throw If \a renum == \c true but permutation is impossible. + */ + MEDCouplingMesh *MEDFileMesh::getGenMeshAtLevel(int meshDimRelToMax, bool renum=false) const throw(INTERP_KERNEL::Exception) {} + /*! + * Returns the dimension on cells in \a this mesh. + * \return int - the mesh dimension. + * \throw If there are no cells in this mesh. + */ + int MEDFileMesh::getMeshDimension() const throw(INTERP_KERNEL::Exception) {} + /*! + * Returns a full textual description of \a this mesh. + * \return std::string - the string holding the mesh description. + */ + std::string MEDFileMesh::advancedRepr() const {} + /*! + * Sets the family field of a given relative dimension. + * \param [in] meshDimRelToMaxExt - the relative dimension of entities for which + * the family field is set. + * \param [in] famArr - the array of the family field. + * \throw If there are no mesh entities of \a meshDimRelToMaxExt dimension in \a this mesh. + * \throw If \a famArr has an invalid size. + */ + void MEDFileMesh::setFamilyFieldArr(int meshDimRelToMaxExt, DataArrayInt *famArr) throw(INTERP_KERNEL::Exception) {} + /*! + * Sets the optional numbers of mesh entities of a given dimension. + * \param [in] meshDimRelToMaxExt - the relative dimension of mesh entities. + * \param [in] renumArr - the array of the numbers. + * \throw If there are no mesh entities of \a meshDimRelToMaxExt dimension in \a this mesh. + * \throw If \a renumArr has an invalid size. + */ + void MEDFileMesh::setRenumFieldArr(int meshDimRelToMaxExt, DataArrayInt *renumArr) throw(INTERP_KERNEL::Exception) {} + /*! + * Returns the family field for mesh entities of a given dimension. + * \param [in] meshDimRelToMaxExt - the relative dimension of mesh entities. + * \return const DataArrayInt * - the family field. It is an array of ids of families + * each mesh entity belongs to. It can be NULL. + */ + const DataArrayInt *MEDFileMesh::getFamilyFieldAtLevel(int meshDimRelToMaxExt) const throw(INTERP_KERNEL::Exception) {} + /*! + * Returns the optional numbers of mesh entities of a given dimension. + * \param [in] meshDimRelToMaxExt - the relative dimension of mesh entities. + * \return const DataArrayInt * - the array of the entity numbers. + * \throw If there are no mesh entities of \a meshDimRelToMaxExt dimension in \a this mesh. + */ + const DataArrayInt *MEDFileMesh::getNumberFieldAtLevel(int meshDimRelToMaxExt) const throw(INTERP_KERNEL::Exception) {} + /*! + * Returns the optional numbers of mesh entities of a given dimension transformed using + * DataArrayInt::invertArrayN2O2O2N(). + * \param [in] meshDimRelToMaxExt - the relative dimension of mesh entities. + * \return const DataArrayInt * - the array of the entity numbers transformed using + * DataArrayInt::invertArrayN2O2O2N(). + * \throw If there are no mesh entities of \a meshDimRelToMaxExt dimension in \a this mesh. + */ + const DataArrayInt *MEDFileMesh::getRevNumberFieldAtLevel(int meshDimRelToMaxExt) const throw(INTERP_KERNEL::Exception) {} + /*! + * Returns ids of mesh entities contained in given families of a given dimension. + * \param [in] meshDimRelToMaxExt - a relative dimension of the mesh entities whose ids + * are required. + * \param [in] fams - the names of the families of interest. + * \param [in] renum - if \c true, the optional numbers of entities, if available, are + * returned instead of ids. + * \return DataArrayInt * - a new instance of DataArrayInt holding either ids or + * numbers, if available and required, of mesh entities of the families. The caller + * is to delete this array using decrRef() as it is no more needed. + * \throw If the family field is missing for \a meshDimRelToMaxExt. + */ + DataArrayInt *MEDFileMesh::getFamiliesArr(int meshDimRelToMaxExt, const std::vector& fams, bool renum=false) const throw(INTERP_KERNEL::Exception) {} +} + + +namespace ParaMEDMEM +{ + /*! \name Basic API */ + ///@{ + MEDFileMesh::FindOrCreateAndGiveFamilyWithId(std::map& families, int id, bool& created); - MEDFileMesh::New(const char *fileName); - MEDFileMesh::New(const char *fileName, const char *mName, int dt=-1, int it=-1); - MEDFileMesh::addFamily(const char *familyName, int id); - MEDFileMesh::addFamilyOnGrp(const char *grpName, const char *famName); ++//MEDFileMesh::New(const std::string& fileName); ++//MEDFileMesh::New(const std::string& fileName, const std::string& mName, int dt=-1, int it=-1); ++MEDFileMesh::addFamily(const std::string& familyName, int id); ++MEDFileMesh::addFamilyOnGrp(const std::string& grpName, const std::string& famName); +MEDFileMesh::advancedRepr() const = 0; +MEDFileMesh::areFamsEqual(const MEDFileMesh *other, std::string& what) const; +MEDFileMesh::areGrpsEqual(const MEDFileMesh *other, std::string& what) const; +MEDFileMesh::assignFamilyNameWithGroupName(); +MEDFileMesh::changeFamilyId(int oldId, int newId); - MEDFileMesh::changeFamilyName(const char *oldName, const char *newName); - MEDFileMesh::changeGroupName(const char *oldName, const char *newName); ++MEDFileMesh::changeFamilyName(const std::string& oldName, const std::string& newName); ++MEDFileMesh::changeGroupName(const std::string& oldName, const std::string& newName); +MEDFileMesh::copyFamGrpMapsFrom(const MEDFileMesh& other); - MEDFileMesh::createGroupOnAll(int meshDimRelToMaxExt, const char *groupName); - MEDFileMesh::existsFamily(const char *familyName) const; ++MEDFileMesh::createGroupOnAll(int meshDimRelToMaxExt, const std::string& groupName); ++MEDFileMesh::existsFamily(const std::string& familyName) const; +MEDFileMesh::existsFamily(int famId) const; - MEDFileMesh::existsGroup(const char *groupName) const; ++MEDFileMesh::existsGroup(const std::string& groupName) const; +MEDFileMesh::findOrCreateAndGiveFamilyWithId(int id, bool& created); +MEDFileMesh::getDescription() const; +MEDFileMesh::getFamiliesArr(int meshDimRelToMaxExt, const std::vector& fams, bool renum=false) const; +MEDFileMesh::getFamiliesIds(const std::vector& famNames) const; - MEDFileMesh::getFamiliesIdsOnGroup(const char *name) const; ++MEDFileMesh::getFamiliesIdsOnGroup(const std::string& name) const; +MEDFileMesh::getFamiliesNames() const; - MEDFileMesh::getFamiliesOnGroup(const char *name) const; ++MEDFileMesh::getFamiliesOnGroup(const std::string& name) const; +MEDFileMesh::getFamiliesOnGroups(const std::vector& grps) const; - MEDFileMesh::getFamilyArr(int meshDimRelToMaxExt, const char *fam, bool renum=false) const; ++MEDFileMesh::getFamilyArr(int meshDimRelToMaxExt, const std::string& fam, bool renum=false) const; +MEDFileMesh::getFamilyFieldAtLevel(int meshDimRelToMaxExt) const; - MEDFileMesh::getFamilyId(const char *name) const; ++MEDFileMesh::getFamilyId(const std::string& name) const; +MEDFileMesh::getFamilyInfo() const; +MEDFileMesh::getFamilyNameGivenId(int id) const; +MEDFileMesh::getGenMeshAtLevel(int meshDimRelToMax, bool renum=false) const; - MEDFileMesh::getGroupArr(int meshDimRelToMaxExt, const char *grp, bool renum=false) const; ++MEDFileMesh::getGroupArr(int meshDimRelToMaxExt, const std::string& grp, bool renum=false) const; +MEDFileMesh::getGroupInfo() const; +MEDFileMesh::getGroupsArr(int meshDimRelToMaxExt, const std::vector& grps, bool renum=false) const; +MEDFileMesh::getGroupsNames() const; - MEDFileMesh::getGroupsOnFamily(const char *name) const; ++MEDFileMesh::getGroupsOnFamily(const std::string& name) const; +MEDFileMesh::getIteration() const; +MEDFileMesh::getMaxFamilyId() const; +MEDFileMesh::getMeshDimension() const; +MEDFileMesh::getName() const; +MEDFileMesh::getNodeFamiliesArr(const std::vector& fams, bool renum=false) const; - MEDFileMesh::getNodeFamilyArr(const char *fam, bool renum=false) const; - MEDFileMesh::getNodeGroupArr(const char *grp, bool renum=false) const; ++MEDFileMesh::getNodeFamilyArr(const std::string& fam, bool renum=false) const; ++MEDFileMesh::getNodeGroupArr(const std::string& grp, bool renum=false) const; +MEDFileMesh::getNodeGroupsArr(const std::vector& grps, bool renum=false) const; +MEDFileMesh::getNonEmptyLevels() const = 0; +MEDFileMesh::getNonEmptyLevelsExt() const = 0; +MEDFileMesh::getNumberFieldAtLevel(int meshDimRelToMaxExt) const; +MEDFileMesh::getOrder() const; +MEDFileMesh::getRevNumberFieldAtLevel(int meshDimRelToMaxExt) const; +MEDFileMesh::getSizeAtLevel(int meshDimRelToMaxExt) const; +MEDFileMesh::getTime(int& dt, int& it); +MEDFileMesh::getTimeUnit() const; +MEDFileMesh::getTimeValue() const; +MEDFileMesh::getUnivName() const; +MEDFileMesh::isEqual(const MEDFileMesh *other, double eps, std::string& what) const; +MEDFileMesh::keepFamIdsOnlyOnLevs(const std::vector& famIds, const std::vector& levs); - MEDFileMesh::removeFamily(const char *name); - MEDFileMesh::removeGroup(const char *name); - MEDFileMesh::setDescription(const char *name); - MEDFileMesh::setFamiliesIdsOnGroup(const char *name, const std::vector& famIds); - MEDFileMesh::setFamiliesOnGroup(const char *name, const std::vector& fams); ++MEDFileMesh::removeFamily(const std::string& name); ++MEDFileMesh::removeGroup(const std::string& name); ++MEDFileMesh::setDescription(const std::string& name); ++MEDFileMesh::setFamiliesIdsOnGroup(const std::string& name, const std::vector& famIds); ++MEDFileMesh::setFamiliesOnGroup(const std::string& name, const std::vector& fams); +MEDFileMesh::setFamilyFieldArr(int meshDimRelToMaxExt, DataArrayInt *famArr); - MEDFileMesh::setFamilyId(const char *familyName, int id); ++MEDFileMesh::setFamilyId(const std::string& familyName, int id); +MEDFileMesh::setFamilyInfo(const std::map& info); +MEDFileMesh::setGroupInfo(const std::map >&info); +MEDFileMesh::setGroupsAtLevel(int meshDimRelToMaxExt, const std::vector& grps, bool renum=false); - MEDFileMesh::setGroupsOnFamily(const char *famName, const std::vector& grps); ++MEDFileMesh::setGroupsOnFamily(const std::string& famName, const std::vector& grps); +MEDFileMesh::setIteration(int it); - MEDFileMesh::setName(const char *name); ++MEDFileMesh::setName(const std::string& name); +MEDFileMesh::setOrder(int order); +MEDFileMesh::setRenumFieldArr(int meshDimRelToMaxExt, DataArrayInt *renumArr); +MEDFileMesh::setTime(int dt, int it, double time); - MEDFileMesh::setTimeUnit(const char *unit); ++MEDFileMesh::setTimeUnit(const std::string& unit); +MEDFileMesh::setTimeValue(double time); - MEDFileMesh::setUnivName(const char *name); ++MEDFileMesh::setUnivName(const std::string& name); +MEDFileMesh::simpleRepr() const; - MEDFileMesh::write(const char *fileName, int mode) const; ++MEDFileMesh::write(const std::string& fileName, int mode) const; +MEDFileMesh::write(med_idt fid) const; +///@} + +/*! \name Advanced API */ +///@{ +MEDFileMesh::clearNonDiscrAttributes() const; +///@} + +/*! \name Others... */ +///@{ - MEDFileMesh::ChangeAllGroupsContainingFamily(std::map >& groups, const char *familyNameToChange, const std::vector& newFamiliesNames); ++MEDFileMesh::ChangeAllGroupsContainingFamily(std::map >& groups, const std::string& familyNameToChange, const std::vector& newFamiliesNames); +MEDFileMesh::CreateNameNotIn(const std::string& nameTry, const std::vector& namesToAvoid); +MEDFileMesh::MEDFileMesh(); +MEDFileMesh::PutInThirdComponentOfCodeOffset(std::vector& code, int strt); +MEDFileMesh::TranslateFamilyIds(int offset, DataArrayInt *famArr, std::vector< std::vector >& famIdsPerGrp); - MEDFileMesh::addFamilyOnAllGroupsHaving(const char *famName, const char *otherFamName); ++MEDFileMesh::addFamilyOnAllGroupsHaving(const std::string& famName, const std::string& otherFamName); +MEDFileMesh::appendFamilyEntries(const DataArrayInt *famIds, const std::vector< std::vector >& fidsOfGrps, const std::vector& grpNames); - MEDFileMesh::changeAllGroupsContainingFamily(const char *familyNameToChange, const std::vector& newFamiliesNames); ++MEDFileMesh::changeAllGroupsContainingFamily(const std::string& familyNameToChange, const std::vector& newFamiliesNames); +MEDFileMesh::changeFamilyIdArr(int oldId, int newId); +MEDFileMesh::changeNames(const std::vector< std::pair >& modifTab); +MEDFileMesh::dealWithTinyInfo(const MEDCouplingMesh *m); +MEDFileMesh::deepCpy() const; +MEDFileMesh::ensureDifferentFamIdsPerLevel(); +MEDFileMesh::getAllFamiliesIdsReferenced() const; +MEDFileMesh::getFamilyRepr(std::ostream& oss) const; - MEDFileMesh::getHeapMemorySize() const; ++//MEDFileMesh::getHeapMemorySize() const; +MEDFileMesh::getMaxFamilyIdInArrays() const; +MEDFileMesh::getMinFamilyId() const; +MEDFileMesh::getMinFamilyIdInArrays() const; +MEDFileMesh::getNameFieldAtLevel(int meshDimRelToMaxExt) const; +MEDFileMesh::getNumberOfNodes() const; +MEDFileMesh::getTheMaxFamilyId() const; +MEDFileMesh::getTheMinFamilyId() const; +MEDFileMesh::normalizeFamIdsMEDFile(); +MEDFileMesh::normalizeFamIdsTrio(); - MEDFileMesh::setFamilyIdUnique(const char *familyName, int id); ++MEDFileMesh::setFamilyIdUnique(const std::string& familyName, int id); +MEDFileMesh::setNameFieldAtLevel(int meshDimRelToMaxExt, DataArrayAsciiChar *nameArr); +MEDFileMesh::shallowCpy() const; +MEDFileMesh::synchronizeTinyInfoOnLeaves() const = 0; +MEDFileMesh::unPolyze(std::vector& oldCode, std::vector& newCode, DataArrayInt *& o2nRenumCell); +MEDFileMesh::writeLL(med_idt fid) const; +int MEDFileMesh::_order; +int MEDFileMesh::_iteration; +double MEDFileMesh::_time; +std::string MEDFileMesh::_dt_unit; +std::string MEDFileMesh::_name; +std::string MEDFileMesh::_univ_name; +std::string MEDFileMesh::_desc_name; +std::map > MEDFileMesh::_groups; +std::map MEDFileMesh::_families; +static const char MEDFileMesh::DFT_FAM_NAME[]; +///@} +} + diff --cc medtool/src/INTERP_KERNEL/ExprEval/InterpKernelAsmX86.cxx index aaeeabf14,000000000..081cab633 mode 100644,000000..100644 --- a/medtool/src/INTERP_KERNEL/ExprEval/InterpKernelAsmX86.cxx +++ b/medtool/src/INTERP_KERNEL/ExprEval/InterpKernelAsmX86.cxx @@@ -1,495 -1,0 +1,499 @@@ +// Copyright (C) 2007-2015 CEA/DEN, EDF R&D +// +// 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +// +// See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com +// +// Author : Anthony Geay (CEA/DEN) + +#include "InterpKernelAsmX86.hxx" + +#include +#include +#include + +#ifdef _POSIX_MAPPED_FILES +#include +#else +#ifdef WIN32 +#include +#endif +#endif + +const char *INTERP_KERNEL::AsmX86::OPS[NB_OF_OPS]={"mov","push","pop","fld","faddp","fsubp","fmulp","fdivp","fcos","fsin","fabs","fchs","fsqrt","sub","add","ret","leave","movsd","fst"}; + +std::vector INTERP_KERNEL::AsmX86::convertIntoMachineLangage(const std::vector& asmb) const +{ + std::vector ret; + for(std::vector::const_iterator iter=asmb.begin();iter!=asmb.end();iter++) + convertOneInstructionInML(*iter,ret); + return ret; +} + +char *INTERP_KERNEL::AsmX86::copyToExecMemZone(const std::vector& ml, unsigned& offset) const +{ + char *ret=0; + int lgth=ml.size(); +#ifdef _POSIX_MAPPED_FILES ++# ifdef __APPLE__ ++ ret=(char *)mmap(0,lgth,PROT_EXEC | PROT_WRITE,MAP_ANON | MAP_PRIVATE,-1,0); ++# else + ret=(char *)mmap(0,lgth,PROT_EXEC | PROT_WRITE,MAP_ANONYMOUS | MAP_PRIVATE,-1,0); ++# endif +#else +#ifdef WIN32 + HANDLE h=CreateFileMapping(INVALID_HANDLE_VALUE,NULL,PAGE_EXECUTE_READWRITE,0,lgth,NULL); + ret=(char *)MapViewOfFile(h,FILE_MAP_EXECUTE | FILE_MAP_READ | FILE_MAP_WRITE,0,0,lgth); +#endif +#endif + if(ret) + std::copy(ml.begin(),ml.end(),ret); + return ret; +} + +void INTERP_KERNEL::AsmX86::convertOneInstructionInML(const std::string& inst, std::vector& ml) const +{ + std::string::size_type pos=inst.find_first_of(' '); + std::string op; + std::string param; + if(pos!=std::string::npos) + { + op=inst.substr(0,pos); + param=inst.substr(pos+1); + } + else + op=inst; + int id=0; + for(const char **it=OPS;it!=OPS+NB_OF_OPS;it++,id++) + { + std::string tmp(*it); + if(op==tmp) + break; + } + switch(id) + { + case 0: + convertMov(param,ml); + break; + case 1: + convertPush(param,ml); + break; + case 2: + convertPop(param,ml); + break; + case 3: + convertFld(param,ml); + break; + case 4: + convertFaddp(param,ml); + break; + case 5: + convertFsubp(param,ml); + break; + case 6: + convertFmulp(param,ml); + break; + case 7: + convertFdivp(param,ml); + break; + case 8: + convertFcos(param,ml); + break; + case 9: + convertFsin(param,ml); + break; + case 10: + convertFabs(param,ml); + break; + case 11: + convertFchs(param,ml); + break; + case 12: + convertFsqrt(param,ml); + break; + case 13: + convertSub(param,ml); + break; + case 14: + convertAdd(param,ml); + break; + case 15: + convertRet(param,ml); + break; + case 16: + convertLeave(param,ml); + break; + case 17: + convertMovsd(param,ml); + break; + case 18: + convertFst(param,ml); + break; + default: + { + std::ostringstream oss; oss << "Unrecognized op : " << op << " in assembly line : " << inst; + throw INTERP_KERNEL::Exception(oss.str().c_str()); + } + } +} + +#include + +void INTERP_KERNEL::AsmX86::convertMov(const std::string& inst, std::vector& ml) +{ + const char ASM1[]="ebp,esp"; + const unsigned char ML1[2]={0x89,0xe5}; + if(inst==ASM1) + { + ml.insert(ml.end(),ML1,ML1+sizeof(ML1)); + return ; + } + const char ASM2[]="rbp,rsp"; + const unsigned char ML2[3]={0x48,0x89,0xe5}; + if(inst==ASM2) + { + ml.insert(ml.end(),ML2,ML2+sizeof(ML2)); + return ; + } + std::string::size_type pos=inst.find_first_of(' '); + if(pos==std::string::npos) + { + std::ostringstream oss; oss << "not recognized instruction mov : " << inst; + throw INTERP_KERNEL::Exception(oss.str().c_str()); + } + std::string inst2=inst.substr(pos+1); + pos=inst2.find_first_of(','); + if(pos==std::string::npos) + { + std::ostringstream oss; oss << "not recognized instruction mov : " << inst; + throw INTERP_KERNEL::Exception(oss.str().c_str()); + } + std::string inst3=inst2.substr(0,pos); + std::string inst4=inst2.substr(pos+1); + convertMovToEsp(inst3,inst4,ml); +} + +void INTERP_KERNEL::AsmX86::convertMovToEsp(const std::string& inst1, const std::string& inst2, std::vector& ml) +{ + if(inst1[0]!='[' || inst1[inst1.length()-1]!=']') + throw INTERP_KERNEL::Exception("not recognized convertMovToEsp exp !"); + std::string inst1bis=inst1.substr(1,inst1.length()-2); + const char ASM1[]="esp"; + const unsigned char ML1[3]={0xc7,0x04,0x24}; + if(inst1bis==ASM1) + {//mov dword [esp],0x3ff3c0ca + ml.insert(ml.end(),ML1,ML1+sizeof(ML1)); + appendAddress(inst2,4,ml); + return ; + } + if(inst1bis.substr(0,3)==ASM1) + { + if(inst1bis[3]=='+') + {//mov dword [esp+4],0x3ff3c0ca + const unsigned char ML2[3]={0xc7,0x44,0x24}; + ml.insert(ml.end(),ML2,ML2+sizeof(ML2)); + std::string::size_type pos=inst1bis.find_first_of(']'); + std::string inst1_1=inst1bis.substr(4,pos-4-1); + appendAddress(inst1_1,1,ml); + appendAddress(inst2,4,ml); + return; + } + else + throw INTERP_KERNEL::Exception("Not recognized exp : mov [esp@..],..."); + } + const char ASM3[]="rsp"; + const unsigned char ML3[3]={0xc7,0x04,0x24}; + if(inst1bis==ASM3) + {//mov dword [rsp],0x3ff3c0ca + ml.insert(ml.end(),ML3,ML3+sizeof(ML3)); + appendAddress(inst2,4,ml); + return ; + } + if(inst1bis.substr(0,3)==ASM3) + { + if(inst1bis[3]=='+') + {//mov dword [rsp+4],0x3ff3c0ca + const unsigned char ML2[3]={0xc7,0x44,0x24}; + ml.insert(ml.end(),ML2,ML2+sizeof(ML2)); + std::string::size_type pos=inst1bis.find_first_of(']'); + std::string inst1_1=inst1bis.substr(4,pos-4-1); + appendAddress(inst1_1,1,ml); + appendAddress(inst2,4,ml); + return; + } + else + throw INTERP_KERNEL::Exception("Not recognized exp : mov [esp@..],..."); + } + throw INTERP_KERNEL::Exception("Not recognized exp : mov"); +} + +void INTERP_KERNEL::AsmX86::convertPush(const std::string& inst, std::vector& ml) +{ + std::string::size_type pos=inst.find_first_of(' '); + std::string inst2=inst.substr(pos+1); + const char ASM1[]="ebp"; + const unsigned char ML1[1]={0x55}; + if(inst2==ASM1) + {//push ebp + ml.insert(ml.end(),ML1,ML1+sizeof(ML1)); + return ; + } + const char ASM2[]="ebx"; + const unsigned char ML2[1]={0x53}; + if(inst2==ASM2) + {//push ebx + ml.insert(ml.end(),ML2,ML2+sizeof(ML2)); + return ; + } + const char ASM3[]="rbp"; + const unsigned char ML3[1]={0x55}; + if(inst2==ASM3) + {//push rbp + ml.insert(ml.end(),ML3,ML3+sizeof(ML3)); + return ; + } + throw INTERP_KERNEL::Exception("Unrecognized push instruction"); +} + +void INTERP_KERNEL::AsmX86::convertPop(const std::string& inst, std::vector& ml) +{ + std::string::size_type pos=inst.find_first_of(' '); + std::string inst2=inst.substr(pos+1); + const char ASM1[]="ebp"; + const unsigned char ML1[1]={0x5d}; + if(inst2==ASM1) + {//push ebp + ml.insert(ml.end(),ML1,ML1+sizeof(ML1)); + return ; + } + const char ASM2[]="ebx"; + const unsigned char ML2[1]={0x5b}; + if(inst2==ASM2) + {//push ebx + ml.insert(ml.end(),ML2,ML2+sizeof(ML2)); + return ; + } + throw INTERP_KERNEL::Exception("Unrecognized pop instruction"); +} + +void INTERP_KERNEL::AsmX86::convertFld(const std::string& inst, std::vector& ml) +{ + std::string::size_type pos=inst.find_first_of(' '); + std::string params=inst.substr(pos+1); + std::string params2=params.substr(1,params.length()-2); + if(params2.substr(0,3)=="esp") + { + const unsigned char ML1[3]={0xdd,0x04,0x24}; + if(params2.length()==3) + {//fld qword [esp] + ml.insert(ml.end(),ML1,ML1+sizeof(ML1)); + return ; + } + pos=params2.find_first_of('+'); + if(pos!=std::string::npos) + {//fld qword [esp+@] + ml.insert(ml.end(),ML1,ML1+sizeof(ML1)); + std::string params3=params2.substr(pos+1); + appendAddress(params3,1,ml); + return ; + } + throw INTERP_KERNEL::Exception("Unrecognized fld esp..."); + } + if(params2.substr(0,3)=="ebp") + { + const unsigned char ML2[2]={0xdd,0x45}; + if(params2.length()==3) + {//fld qword [ebp] + ml.insert(ml.end(),ML2,ML2+sizeof(ML2)); + ml.push_back(0); + return ; + } + pos=params2.find_first_of('+'); + if(pos!=std::string::npos) + {//fld qword [esp+@] + ml.insert(ml.end(),ML2,ML2+sizeof(ML2)); + std::string params3=params2.substr(pos+1); + appendAddress(params3,1,ml); + return ; + } + throw INTERP_KERNEL::Exception("Unrecognized fld ebp..."); + } + if(params2.substr(0,3)=="rsp") + { + const unsigned char ML2[3]={0xdd,0x04,0x24}; + ml.insert(ml.end(),ML2,ML2+sizeof(ML2));// to improve ! no fully managed ! + return ; + } + throw INTERP_KERNEL::Exception("Unrecognized fld instruction"); +} + +void INTERP_KERNEL::AsmX86::convertFaddp(const std::string& inst, std::vector& ml) +{ + const unsigned char ML1[2]={0xde,0xc1}; + ml.insert(ml.end(),ML1,ML1+sizeof(ML1)); +} + +void INTERP_KERNEL::AsmX86::convertFsubp(const std::string& inst, std::vector& ml) +{ + const unsigned char ML1[2]={0xde,0xe9}; + ml.insert(ml.end(),ML1,ML1+sizeof(ML1)); +} + +void INTERP_KERNEL::AsmX86::convertFmulp(const std::string& inst, std::vector& ml) +{ + const unsigned char ML1[2]={0xde,0xc9}; + ml.insert(ml.end(),ML1,ML1+sizeof(ML1)); +} + +void INTERP_KERNEL::AsmX86::convertFdivp(const std::string& inst, std::vector& ml) +{ + const unsigned char ML1[2]={0xde,0xf9}; + ml.insert(ml.end(),ML1,ML1+sizeof(ML1)); +} + +void INTERP_KERNEL::AsmX86::convertFcos(const std::string& inst, std::vector& ml) +{ + const unsigned char ML[2]={0xd9,0xff}; + ml.insert(ml.end(),ML,ML+sizeof(ML)); +} + +void INTERP_KERNEL::AsmX86::convertFsin(const std::string& inst, std::vector& ml) +{ + const unsigned char ML[2]={0xd9,0xfe}; + ml.insert(ml.end(),ML,ML+sizeof(ML)); +} + +void INTERP_KERNEL::AsmX86::convertFabs(const std::string& inst, std::vector& ml) +{ + const unsigned char ML[2]={0xd9,0xe1}; + ml.insert(ml.end(),ML,ML+sizeof(ML)); +} + +void INTERP_KERNEL::AsmX86::convertFchs(const std::string& inst, std::vector& ml) +{ + const unsigned char ML[2]={0xd9,0xe0}; + ml.insert(ml.end(),ML,ML+sizeof(ML)); +} + +void INTERP_KERNEL::AsmX86::convertFsqrt(const std::string& inst, std::vector& ml) +{ + const unsigned char ML[2]={0xd9,0xfa}; + ml.insert(ml.end(),ML,ML+sizeof(ML)); +} + +void INTERP_KERNEL::AsmX86::convertSub(const std::string& inst, std::vector& ml) +{ + if(inst.substr(0,4)=="esp,") + { + const unsigned char ML[2]={0x81,0xec}; + ml.insert(ml.end(),ML,ML+sizeof(ML)); + std::string inst2=inst.substr(4); + appendAddress(inst2,4,ml); + return; + } + if(inst.substr(0,4)=="rsp,") + { + const unsigned char ML[4]={0x48,0x83,0xec,0x08}; + ml.insert(ml.end(),ML,ML+sizeof(ML)); // to improve 8 statically put (last of element of ML) !!!! + return; + } + throw INTERP_KERNEL::Exception("Not recognized sub instruction."); +} + +void INTERP_KERNEL::AsmX86::convertAdd(const std::string& inst, std::vector& ml) +{ + if(inst.substr(0,4)=="esp,") + { + const unsigned char ML[2]={0x81,0xc4}; + ml.insert(ml.end(),ML,ML+sizeof(ML)); + std::string inst2=inst.substr(4); + appendAddress(inst2,4,ml); + return; + } + if(inst.substr(0,4)=="rsp,") + { + const unsigned char ML[4]={0x48,0x83,0xc4,0x08}; + ml.insert(ml.end(),ML,ML+sizeof(ML)); // to improve 8 statically put (last of element of ML) !!!! + return; + } + throw INTERP_KERNEL::Exception("Not recognized add instruction."); +} + +void INTERP_KERNEL::AsmX86::convertRet(const std::string& inst, std::vector& ml) +{ + const unsigned char ML[1]={0xc3}; + ml.insert(ml.end(),ML,ML+sizeof(ML)); +} + +void INTERP_KERNEL::AsmX86::convertLeave(const std::string& inst, std::vector& ml) +{ + const unsigned char ML[1]={0xc9}; + ml.insert(ml.end(),ML,ML+sizeof(ML)); +} + +void INTERP_KERNEL::AsmX86::convertMovsd(const std::string& inst, std::vector& ml) +{ + const char ASM1[]="[rsp],xmm0"; + const unsigned char ML1[5]={0xf2,0x0f,0x11,0x04,0x24}; + if(inst==ASM1) + { + ml.insert(ml.end(),ML1,ML1+sizeof(ML1)); + return ; + } + const char ASM2[]="xmm0,[rsp]"; + const unsigned char ML2[5]={0xf2,0x0f,0x10,0x04,0x24}; + if(inst==ASM2) + { + ml.insert(ml.end(),ML2,ML2+sizeof(ML2)); + return ; + } + std::ostringstream oss; oss << "not recognized instruction movsd : " << inst; + throw INTERP_KERNEL::Exception(oss.str().c_str()); +} + +void INTERP_KERNEL::AsmX86::convertFst(const std::string& inst, std::vector& ml) +{ + const char ASM1[]="qword [rsp]"; + const unsigned char ML1[3]={0xdd,0x14,0x24}; + if(inst==ASM1) + { + ml.insert(ml.end(),ML1,ML1+sizeof(ML1)); + return ; + } + std::ostringstream oss; oss << "not recognized instruction fst : " << inst; + throw INTERP_KERNEL::Exception(oss.str().c_str()); + //tony +} + + +void INTERP_KERNEL::AsmX86::appendAddress(const std::string& addr, int nbOfByte, std::vector& ml) +{ + int i,j; + char v; + std::istringstream iss(addr); + if(addr.length()>2) + { + if(addr[0]=='0' && addr[1]=='x') + iss >> std::hex; + } + iss >> i; + for(int k=0;k>=8; + } +} diff --cc medtool/src/INTERP_KERNEL/InterpolationOptions.hxx index 61fc7141b,000000000..dcd10d5dc mode 100644,000000..100644 --- a/medtool/src/INTERP_KERNEL/InterpolationOptions.hxx +++ b/medtool/src/INTERP_KERNEL/InterpolationOptions.hxx @@@ -1,154 -1,0 +1,154 @@@ +// Copyright (C) 2007-2015 CEA/DEN, EDF R&D +// +// 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +// +// See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com +// +// Author : Anthony Geay (CEA/DEN) + +#ifndef __INTERPOLATIONOPTIONS_HXX__ +#define __INTERPOLATIONOPTIONS_HXX__ + +#include "INTERPKERNELDefines.hxx" +#include "NormalizedUnstructuredMesh.hxx" + +#include + +namespace INTERP_KERNEL +{ + typedef enum { Triangulation, Convex, Geometric2D, PointLocator, Barycentric, BarycentricGeo2D } IntersectionType; + + /*! - * \class InterpolationOptions - * Class defining the options for all interpolation algorithms. ++ * Class defining the options for all interpolation algorithms used in the \ref remapper "remapper" and ++ * in some of the \ref para-dec "DECs". + * + * List of options, possible values and default values can be found on this page: + * \ref InterpKerIntersectors + */ + class INTERPKERNEL_EXPORT InterpolationOptions + { + private: + int _print_level ; + IntersectionType _intersection_type; + double _precision; + double _median_plane ; + bool _do_rotate ; + //! this measure is relative to the caracteristic dimension + double _bounding_box_adjustment ; + //! this measure is absolute \b not relative to the cell size + double _bounding_box_adjustment_abs ; + double _max_distance_for_3Dsurf_intersect; + double _min_dot_btw_3Dsurf_intersect; + int _orientation ; + bool _measure_abs; + SplittingPolicy _splitting_policy ; + public: + InterpolationOptions() { init(); } + int getPrintLevel() const { return _print_level; } + void setPrintLevel(int pl) { _print_level=pl; } + + IntersectionType getIntersectionType() const { return _intersection_type; } + void setIntersectionType(IntersectionType it) { _intersection_type=it; } + std::string getIntersectionTypeRepr() const; + + double getPrecision() const { return _precision; } + void setPrecision(double p) { _precision=p; } + + double getArcDetectionPrecision() const; + void setArcDetectionPrecision(double p); + + double getMedianPlane() const { return _median_plane; } + void setMedianPlane(double mp) { _median_plane=mp; } + + bool getDoRotate() const { return _do_rotate; } + void setDoRotate( bool dr) { _do_rotate = dr; } + + double getBoundingBoxAdjustment() const { return _bounding_box_adjustment; } + void setBoundingBoxAdjustment(double bba) { _bounding_box_adjustment=bba; } + + double getBoundingBoxAdjustmentAbs() const { return _bounding_box_adjustment_abs; } + void setBoundingBoxAdjustmentAbs(double bba) { _bounding_box_adjustment_abs=bba; } + + double getMaxDistance3DSurfIntersect() const { return _max_distance_for_3Dsurf_intersect; } + void setMaxDistance3DSurfIntersect(double bba) { _max_distance_for_3Dsurf_intersect=bba; } + + double getMinDotBtwPlane3DSurfIntersect() const { return _min_dot_btw_3Dsurf_intersect; } + void setMinDotBtwPlane3DSurfIntersect(double v) { _min_dot_btw_3Dsurf_intersect=v; } + + int getOrientation() const { return _orientation; } + void setOrientation(int o) { _orientation=o; } + + bool getMeasureAbsStatus() const { return _measure_abs; } + void setMeasureAbsStatus(bool newStatus) { _measure_abs=newStatus; } + + SplittingPolicy getSplittingPolicy() const { return _splitting_policy; } + void setSplittingPolicy(SplittingPolicy sp) { _splitting_policy=sp; } + std::string getSplittingPolicyRepr() const; + + std::string filterInterpolationMethod(const std::string& meth) const; + + void init(); + + bool setInterpolationOptions(long print_level, + std::string intersection_type, + double precision, + double median_plane, + bool do_rotate, + double bounding_box_adjustment, + double bounding_box_adjustment_abs, + double max_distance_for_3Dsurf_intersect, + long orientation, + bool measure_abs, + std::string splitting_policy); + void copyOptions(const InterpolationOptions & other) { *this = other; } + bool setOptionDouble(const std::string& key, double value); + bool setOptionInt(const std::string& key, int value); + bool setOptionString(const std::string& key, const std::string& value); + std::string printOptions() const; + public: + static void CheckAndSplitInterpolationMethod(const std::string& method, std::string& srcMeth, std::string& trgMeth); + private: + static const double DFT_MEDIAN_PLANE; + static const double DFT_SURF3D_ADJ_EPS; + static const double DFT_MAX_DIST_3DSURF_INTERSECT; + static const double DFT_MIN_DOT_BTW_3DSURF_INTERSECT; + public: + static const char PRECISION_STR[]; + static const char ARC_DETECTION_PRECISION_STR[]; + static const char MEDIANE_PLANE_STR[]; + static const char BOUNDING_BOX_ADJ_STR[]; + static const char BOUNDING_BOX_ADJ_ABS_STR[]; + static const char MAX_DISTANCE_3DSURF_INSECT_STR[]; + static const char MIN_DOT_BTW_3DSURF_INSECT_STR[]; + static const char PRINT_LEV_STR[]; + static const char DO_ROTATE_STR[]; + static const char ORIENTATION_STR[]; + static const char MEASURE_ABS_STR[]; + static const char INTERSEC_TYPE_STR[]; + static const char SPLITTING_POLICY_STR[]; + static const char TRIANGULATION_INTERSECT2D_STR[]; + static const char CONVEX_INTERSECT2D_STR[]; + static const char GEOMETRIC_INTERSECT2D_STR[]; + static const char POINTLOCATOR_INTERSECT_STR[]; + static const char BARYCENTRIC_INTERSECT_STR[]; + static const char BARYCENTRICGEO2D_INTERSECT_STR[]; + static const char PLANAR_SPLIT_FACE_5_STR[]; + static const char PLANAR_SPLIT_FACE_6_STR[]; + static const char GENERAL_SPLIT_24_STR[]; + static const char GENERAL_SPLIT_48_STR[]; + }; + +} +#endif diff --cc medtool/src/INTERP_KERNEL/InterpolationUtils.hxx index dd3ffef94,000000000..a96072b78 mode 100644,000000..100644 --- a/medtool/src/INTERP_KERNEL/InterpolationUtils.hxx +++ b/medtool/src/INTERP_KERNEL/InterpolationUtils.hxx @@@ -1,1110 -1,0 +1,1110 @@@ +// Copyright (C) 2007-2015 CEA/DEN, EDF R&D +// +// 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +// +// See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com +// +// Author : Anthony Geay (CEA/DEN) + +#ifndef __INTERPOLATIONUTILS_HXX__ +#define __INTERPOLATIONUTILS_HXX__ + +#include "INTERPKERNELDefines.hxx" +#include "InterpKernelException.hxx" + +#include "NormalizedUnstructuredMesh.hxx" + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +namespace INTERP_KERNEL +{ + template + class OTT//OffsetToolTrait + { + }; + + template + class OTT + { + public: + static ConnType indFC(ConnType i) { return i; } + static ConnType ind2C(ConnType i) { return i; } + static ConnType conn2C(ConnType i) { return i; } + static ConnType coo2C(ConnType i) { return i; } + }; + + template + class OTT + { + public: + static ConnType indFC(ConnType i) { return i+1; } + static ConnType ind2C(ConnType i) { return i-1; } + static ConnType conn2C(ConnType i) { return i-1; } + static ConnType coo2C(ConnType i) { return i-1; } + }; + + /*_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ */ + /* calcul la surface d'un triangle */ + /*_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ */ + + inline double Surf_Tri(const double* P_1,const double* P_2,const double* P_3) + { + double A=(P_3[1]-P_1[1])*(P_2[0]-P_1[0])-(P_2[1]-P_1[1])*(P_3[0]-P_1[0]); + double Surface = 0.5*fabs(A); + return Surface; + } + + /*_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ */ + /* fonction qui calcul le determinant */ + /* de deux vecteur(cf doc CGAL). */ + /*_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _*/ + + //fonction qui calcul le determinant des vecteurs: P3P1 et P3P2 + //(cf doc CGAL). + + inline double mon_determinant(const double* P_1, + const double* P_2, + const double* P_3) + { + double mon_det=(P_1[0]-P_3[0])*(P_2[1]-P_3[1])-(P_2[0]-P_3[0])*(P_1[1]-P_3[1]); + return mon_det; + } + + /*_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _*/ + //calcul la norme du vecteur P1P2 + + inline double norme_vecteur(const double* P_1,const double* P_2) + { + double X=P_1[0]-P_2[0]; + double Y=P_1[1]-P_2[1]; + double norme=sqrt(X*X+Y*Y); + return norme; + } + + /*_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ */ + /* calcul le cos et le sin de l'angle P1P2,P1P3 */ + /*_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ */ + + inline std::vector calcul_cos_et_sin(const double* P_1, + const double* P_2, + const double* P_3) + { + + std::vector Vect; + double P1_P2=norme_vecteur(P_1,P_2); + double P2_P3=norme_vecteur(P_2,P_3); + double P3_P1=norme_vecteur(P_3,P_1); + + double N=P1_P2*P1_P2+P3_P1*P3_P1-P2_P3*P2_P3; + double D=2.0*P1_P2*P3_P1; + double COS=N/D; + if (COS>1.0) COS=1.0; + if (COS<-1.0) COS=-1.0; + Vect.push_back(COS); + double V=mon_determinant(P_2,P_3,P_1); + double D_1=P1_P2*P3_P1; + double SIN=V/D_1; + if (SIN>1.0) SIN=1.0; + if (SIN<-1.0) SIN=-1.0; + Vect.push_back(SIN); + + return Vect; + + } + + /*! + * This method builds a quadrangle built with the first point of 'triIn' the barycenter of two edges starting or ending with + * the first point of 'triIn' and the barycenter of 'triIn'. + * + * @param triIn is a 6 doubles array in full interlace mode, that represents a triangle. + * @param quadOut is a 8 doubles array filled after the following call. + */ + template + inline void fillDualCellOfTri(const double *triIn, double *quadOut) + { + //1st point + std::copy(triIn,triIn+SPACEDIM,quadOut); + double tmp[SPACEDIM]; + std::transform(triIn,triIn+SPACEDIM,triIn+SPACEDIM,tmp,std::plus()); + //2nd point + std::transform(tmp,tmp+SPACEDIM,quadOut+SPACEDIM,std::bind2nd(std::multiplies(),0.5)); + std::transform(tmp,tmp+SPACEDIM,triIn+2*SPACEDIM,tmp,std::plus()); + //3rd point + std::transform(tmp,tmp+SPACEDIM,quadOut+2*SPACEDIM,std::bind2nd(std::multiplies(),1/3.)); + //4th point + std::transform(triIn,triIn+SPACEDIM,triIn+2*SPACEDIM,tmp,std::plus()); + std::transform(tmp,tmp+SPACEDIM,quadOut+3*SPACEDIM,std::bind2nd(std::multiplies(),0.5)); + } + + /*! + * This method builds a potentially non-convex polygon cell built with the first point of 'triIn' the barycenter of two edges starting or ending with + * the first point of 'triIn' and the barycenter of 'triIn'. + * + * @param triIn is a 6 doubles array in full interlace mode, that represents a triangle. + * @param quadOut is a 8 doubles array filled after the following call. + */ + template + inline void fillDualCellOfPolyg(const double *polygIn, int nPtsPolygonIn, double *polygOut) + { + //1st point + std::copy(polygIn,polygIn+SPACEDIM,polygOut); + std::transform(polygIn,polygIn+SPACEDIM,polygIn+SPACEDIM,polygOut+SPACEDIM,std::plus()); + //2nd point + std::transform(polygOut+SPACEDIM,polygOut+2*SPACEDIM,polygOut+SPACEDIM,std::bind2nd(std::multiplies(),0.5)); + double tmp[SPACEDIM]; + // + for(int i=0;i()); + std::transform(tmp,tmp+SPACEDIM,polygOut+(2*i+3)*SPACEDIM,std::bind2nd(std::multiplies(),0.5)); + std::transform(polygIn+(i+1)*SPACEDIM,polygIn+(i+2)*SPACEDIM,tmp,tmp,std::plus()); + std::transform(tmp,tmp+SPACEDIM,polygOut+(2*i+2)*SPACEDIM,std::bind2nd(std::multiplies(),1./3.)); + } + } + + /*_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ */ + /* calcul les coordonnees du barycentre d'un polygone */ + /* le vecteur en entree est constitue des coordonnees */ + /* des sommets du polygone */ + /*_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ */ + + inline std::vector bary_poly(const std::vector& V) + { + std::vector Bary; + long taille=V.size(); + double x=0; + double y=0; + + for(long i=0;i + bool solveSystemOfEquations(double M[nbRow][nbRow+1], double* sol) + { + const int nbCol=nbRow+1; + + // make upper triangular matrix (forward elimination) + + int iR[nbRow];// = { 0, 1, 2 }; + for ( int i = 0; i < (int) nbRow; ++i ) + iR[i] = i; + for ( int i = 0; i < (int)(nbRow-1); ++i ) // nullify nbRow-1 rows + { + // swap rows to have max value of i-th column in i-th row + double max = std::fabs( M[ iR[i] ][i] ); + for ( int r = i+1; r < (int)nbRow; ++r ) + { + double m = std::fabs( M[ iR[r] ][i] ); + if ( m > max ) + { + max = m; + std::swap( iR[r], iR[i] ); + } + } + if ( max < std::numeric_limits::min() ) + { + //sol[0]=1; sol[1]=sol[2]=sol[3]=0; + return false; // no solution + } + // make 0 below M[i][i] (actually we do not modify i-th column) + double* tUpRow = M[ iR[i] ]; + for ( int r = i+1; r < (int)nbRow; ++r ) + { + double* mRow = M[ iR[r] ]; + double coef = mRow[ i ] / tUpRow[ i ]; + for ( int c = i+1; c < nbCol; ++c ) + mRow[ c ] -= tUpRow[ c ] * coef; + } + } + double* mRow = M[ iR[nbRow-1] ]; + if ( std::fabs( mRow[ nbRow-1 ] ) < std::numeric_limits::min() ) + { + //sol[0]=1; sol[1]=sol[2]=sol[3]=0; + return false; // no solution + } + mRow[ nbRow ] /= mRow[ nbRow-1 ]; + + // calculate solution (back substitution) + + sol[ nbRow-1 ] = mRow[ nbRow ]; + + for ( int i = nbRow-2; i+1; --i ) + { + mRow = M[ iR[i] ]; + sol[ i ] = mRow[ nbRow ]; + for ( int j = nbRow-1; j > i; --j ) + sol[ i ] -= sol[j]*mRow[ j ]; + sol[ i ] /= mRow[ i ]; + } + + return true; + } + + + /*! + * \brief Solve system equation in matrix form using Gaussian elimination algorithm + * \param M - N x N+NB_OF_VARS matrix + * \param sol - vector of N solutions + * \retval bool - true if succeeded + */ + template + bool solveSystemOfEquations2(const double *matrix, double *solutions, double eps) + { + unsigned k,j; + int nr,n,m,np; + double s,g; + int mb; + // + double B[SZ*(SZ+NB_OF_RES)]; + std::copy(matrix,matrix+SZ*(SZ+NB_OF_RES),B); + // + nr=SZ+NB_OF_RES; + for(k=0;keps) + {/* Rows permutation */ + for(m=0;m(),s)); + for(j=0;j + inline void barycentric_coords(const double* triaCoords, const double* p, double* bc) + { + // matrix 2x2 + double + T11 = triaCoords[0]-triaCoords[2*SPACEDIM], T12 = triaCoords[SPACEDIM]-triaCoords[2*SPACEDIM], + T21 = triaCoords[1]-triaCoords[2*SPACEDIM+1], T22 = triaCoords[SPACEDIM+1]-triaCoords[2*SPACEDIM+1]; + // matrix determinant + double Tdet = T11*T22 - T12*T21; + if ( fabs( Tdet ) < std::numeric_limits::min() ) { + bc[0]=1; bc[1]=0; bc[2]=0; + return; + } + // matrix inverse + double t11 = T22, t12 = -T12, t21 = -T21, t22 = T11; + // vector + double r11 = p[0]-triaCoords[2*SPACEDIM], r12 = p[1]-triaCoords[2*SPACEDIM+1]; + // barycentric coordinates: mutiply matrix by vector + bc[0] = (t11 * r11 + t12 * r12)/Tdet; + bc[1] = (t21 * r11 + t22 * r12)/Tdet; + bc[2] = 1. - bc[0] - bc[1]; + } + + /*! + * Calculate barycentric coordinates of a point p with respect to triangle or tetra verices. + * This method makes 2 assumptions : + * - this is a simplex + * - spacedim == meshdim. For TRI3 and TRI6 spaceDim is expected to be equal to 2 and for TETRA4 spaceDim is expected to be equal to 3. + * If not the case (3D surf for example) a previous projection should be done before. + */ + inline void barycentric_coords(const std::vector& n, const double *p, double *bc) + { + enum { _X, _Y, _Z }; + switch(n.size()) + { + case 2: + {// SEG 2 + double delta=n[0][0]-n[1][0]; + bc[0]=fabs((*p-n[1][0])/delta); + bc[1]=fabs((*p-n[0][0])/delta); + break; + } + case 3: + { // TRIA3 + // matrix 2x2 + double + T11 = n[0][_X]-n[2][_X], T12 = n[1][_X]-n[2][_X], + T21 = n[0][_Y]-n[2][_Y], T22 = n[1][_Y]-n[2][_Y]; + // matrix determinant + double Tdet = T11*T22 - T12*T21; + if ( (std::fabs( Tdet) ) < (std::numeric_limits::min()) ) + { + bc[0]=1; bc[1]=bc[2]=0; // no solution + return; + } + // matrix inverse + double t11 = T22, t12 = -T12, t21 = -T21, t22 = T11; + // vector + double r11 = p[_X]-n[2][_X], r12 = p[_Y]-n[2][_Y]; + // barycentric coordinates: mutiply matrix by vector + bc[0] = (t11 * r11 + t12 * r12)/Tdet; + bc[1] = (t21 * r11 + t22 * r12)/Tdet; + bc[2] = 1. - bc[0] - bc[1]; + break; + } + case 4: + { // TETRA4 + // Find bc by solving system of 3 equations using Gaussian elimination algorithm + // bc1*( x1 - x4 ) + bc2*( x2 - x4 ) + bc3*( x3 - x4 ) = px - x4 + // bc1*( y1 - y4 ) + bc2*( y2 - y4 ) + bc3*( y3 - y4 ) = px - y4 + // bc1*( z1 - z4 ) + bc2*( z2 - z4 ) + bc3*( z3 - z4 ) = px - z4 + + double T[3][4]= + {{ n[0][_X]-n[3][_X], n[1][_X]-n[3][_X], n[2][_X]-n[3][_X], p[_X]-n[3][_X] }, + { n[0][_Y]-n[3][_Y], n[1][_Y]-n[3][_Y], n[2][_Y]-n[3][_Y], p[_Y]-n[3][_Y] }, + { n[0][_Z]-n[3][_Z], n[1][_Z]-n[3][_Z], n[2][_Z]-n[3][_Z], p[_Z]-n[3][_Z] }}; + + if ( !solveSystemOfEquations<3>( T, bc ) ) + bc[0]=1., bc[1] = bc[2] = bc[3] = 0; + else + bc[ 3 ] = 1. - bc[0] - bc[1] - bc[2]; + break; + } + case 6: + { + // TRIA6 + double matrix2[48]={1., 0., 0., 0., 0., 0., 0., 0., + 1., 0., 0., 0., 0., 0., 1., 0., + 1., 0., 0., 0., 0., 0., 0., 1., + 1., 0., 0., 0., 0., 0., 0.5, 0., + 1., 0., 0., 0., 0., 0., 0.5, 0.5, + 1., 0., 0., 0., 0., 0., 0.,0.5}; + for(int i=0;i<6;i++) + { + matrix2[8*i+1]=n[i][0]; + matrix2[8*i+2]=n[i][1]; + matrix2[8*i+3]=n[i][0]*n[i][0]; + matrix2[8*i+4]=n[i][0]*n[i][1]; + matrix2[8*i+5]=n[i][1]*n[i][1]; + } + double res[12]; + solveSystemOfEquations2<6,2>(matrix2,res,std::numeric_limits::min()); + double refCoo[2]; + refCoo[0]=computeTria6RefBase(res,p); + refCoo[1]=computeTria6RefBase(res+6,p); + computeWeightedCoeffsInTria6FromRefBase(refCoo,bc); + break; + } + case 10: + {//TETRA10 + double matrix2[130]={1., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., + 1., 0., 0., 0., 0., 0., 0., 0., 0., 0., 1., 0., 0., + 1., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 1., 0., + 1., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 1., + 1., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0.5, 0., 0., + 1., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0.5, 0.5, 0., + 1., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0.,0.5, 0., + 1., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0.5, + 1., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0.5, 0., 0.5, + 1., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0.5, 0.5}; + for(int i=0;i<10;i++) + { + matrix2[13*i+1]=n[i][0]; + matrix2[13*i+2]=n[i][1]; + matrix2[13*i+3]=n[i][2]; + matrix2[13*i+4]=n[i][0]*n[i][0]; + matrix2[13*i+5]=n[i][0]*n[i][1]; + matrix2[13*i+6]=n[i][0]*n[i][2]; + matrix2[13*i+7]=n[i][1]*n[i][1]; + matrix2[13*i+8]=n[i][1]*n[i][2]; + matrix2[13*i+9]=n[i][2]*n[i][2]; + } + double res[30]; + solveSystemOfEquations2<10,3>(matrix2,res,std::numeric_limits::min()); + double refCoo[3]; + refCoo[0]=computeTetra10RefBase(res,p); + refCoo[1]=computeTetra10RefBase(res+10,p); + refCoo[2]=computeTetra10RefBase(res+20,p); + computeWeightedCoeffsInTetra10FromRefBase(refCoo,bc); + break; + } + default: + throw INTERP_KERNEL::Exception("INTERP_KERNEL::barycentric_coords : unrecognized simplex !"); + } + } + + /*_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ */ + /* calcul la surface d'un polygone. */ + /*_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ */ + + inline double Surf_Poly(const std::vector& Poly) + { + + double Surface=0; + for(unsigned long i=0; i<(Poly.size())/2-2; i++) + { + double Surf=Surf_Tri( &Poly[0],&Poly[2*(i+1)],&Poly[2*(i+2)] ); + Surface=Surface + Surf ; + } + return Surface ; + } + + /*_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ */ + /* fonction qui teste si un point est dans une maille */ + /* point: P_0 */ + /* P_1, P_2, P_3 sommet des mailles */ + /*_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ */ + + inline bool point_dans_triangle(const double* P_0,const double* P_1, + const double* P_2,const double* P_3, + double eps) + { + + bool A=false; + double det_1=mon_determinant(P_1,P_3,P_0); + double det_2=mon_determinant(P_3,P_2,P_0); + double det_3=mon_determinant(P_2,P_1,P_0); + if( (det_1>=-eps && det_2>=-eps && det_3>=-eps) || (det_1<=eps && det_2<=eps && det_3<=eps) ) + { + A=true; + } + + return A; + } + + /*_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ */ + /*fonction pour verifier qu'un point n'a pas deja ete considerer dans */ + /* le vecteur et le rajouter au vecteur sinon. */ + /*_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ */ + + inline void verif_point_dans_vect(const double* P, std::vector& V, double absolute_precision ) + { + long taille=V.size(); + bool isPresent=false; + for(long i=0;i& V, double dim_caracteristic, double precision) + { + + double absolute_precision = precision*dim_caracteristic; + bool A_1=INTERP_KERNEL::point_dans_triangle(P_1,P_4,P_5,P_6,absolute_precision); + if(A_1) + verif_point_dans_vect(P_1,V,absolute_precision); + bool A_2=INTERP_KERNEL::point_dans_triangle(P_2,P_4,P_5,P_6,absolute_precision); + if(A_2) + verif_point_dans_vect(P_2,V,absolute_precision); + bool A_3=INTERP_KERNEL::point_dans_triangle(P_3,P_4,P_5,P_6,absolute_precision); + if(A_3) + verif_point_dans_vect(P_3,V,absolute_precision); + } + + + /*_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _*/ + /* calcul de l'intersection de deux segments: segments P1P2 avec P3P4 */ + /* . Si l'intersection est non nulle et si celle-ci n'est */ + /* n'est pas deja contenue dans Vect on la rajoute a Vect */ + /*_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _*/ + + inline void inters_de_segment(const double * P_1,const double * P_2, + const double * P_3,const double * P_4, + std::vector& Vect, + double dim_caracteristic, double precision) + { + // calcul du determinant de P_1P_2 et P_3P_4. + double det=(P_2[0]-P_1[0])*(P_4[1]-P_3[1])-(P_4[0]-P_3[0])*(P_2[1]-P_1[1]); + + double absolute_precision = dim_caracteristic*precision; + if(fabs(det)>absolute_precision) + { + double k_1=-((P_3[1]-P_4[1])*(P_3[0]-P_1[0])+(P_4[0]-P_3[0])*(P_3[1]-P_1[1]))/det; + + if (k_1 >= -absolute_precision && k_1 <= 1+absolute_precision) + //if( k_1 >= -precision && k_1 <= 1+precision) + { + double k_2= ((P_1[1]-P_2[1])*(P_1[0]-P_3[0])+(P_2[0]-P_1[0])*(P_1[1]-P_3[1]))/det; + + if (k_2 >= -absolute_precision && k_2 <= 1+absolute_precision) + //if( k_2 >= -precision && k_2 <= 1+precision) + { + double P_0[2]; + P_0[0]=P_1[0]+k_1*(P_2[0]-P_1[0]); + P_0[1]=P_1[1]+k_1*(P_2[1]-P_1[1]); + verif_point_dans_vect(P_0,Vect,absolute_precision); + } + } + } + } + + + + /*_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _*/ + /* calcul l'intersection de deux triangles */ + /* P_1, P_2, P_3: sommets du premier triangle */ + /* P_4, P_5, P_6: sommets du deuxi�me triangle */ + /*_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _*/ + + inline void intersec_de_triangle(const double* P_1,const double* P_2, const double* P_3, + const double* P_4,const double* P_5,const double* P_6, + std::vector& Vect, double dim_caracteristic, double precision) + { + inters_de_segment(P_1,P_2,P_4,P_5,Vect, dim_caracteristic, precision); + inters_de_segment(P_1,P_2,P_5,P_6,Vect, dim_caracteristic, precision); + inters_de_segment(P_1,P_2,P_6,P_4,Vect, dim_caracteristic, precision); + inters_de_segment(P_2,P_3,P_4,P_5,Vect, dim_caracteristic, precision); + inters_de_segment(P_2,P_3,P_5,P_6,Vect, dim_caracteristic, precision); + inters_de_segment(P_2,P_3,P_6,P_4,Vect, dim_caracteristic, precision); + inters_de_segment(P_3,P_1,P_4,P_5,Vect, dim_caracteristic, precision); + inters_de_segment(P_3,P_1,P_5,P_6,Vect, dim_caracteristic, precision); + inters_de_segment(P_3,P_1,P_6,P_4,Vect, dim_caracteristic, precision); + rajou_sommet_triangl(P_1,P_2,P_3,P_4,P_5,P_6,Vect, dim_caracteristic, precision); + rajou_sommet_triangl(P_4,P_5,P_6,P_1,P_2,P_3,Vect, dim_caracteristic, precision); + } + + /*_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _*/ + /* fonction pour verifier qu'un node maille n'a pas deja ete considerer */ + /* dans le vecteur et le rajouter au vecteur sinon. */ + /*_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _*/ + + inline void verif_maill_dans_vect(int Num, std::vector& V) + { + long taille=V.size(); + int A=0; + for(long i=0;itheta1, std::pair theta2) ++ bool operator()(std::pairtheta1, std::pair theta2) const + { + double norm1 = sqrt(theta1.first*theta1.first +theta1.second*theta1.second); + double norm2 = sqrt(theta2.first*theta2.first +theta2.second*theta2.second); + + double epsilon = 1.e-12; + + if( norm1 < epsilon || norm2 < epsilon ) + std::cout << "Warning InterpolationUtils.hxx: AngleLess : Vector with zero norm, cannot define the angle !!!! " << std::endl; + + return theta1.second*(norm2 + theta2.first) < theta2.second*(norm1 + theta1.first); + + } + }; + + + /*_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ */ + /* fonction pour reconstituer un polygone convexe a partir */ + /* d'un nuage de point. */ + /*_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ */ + + inline std::vector reconstruct_polygon(const std::vector& V) + { + + int taille((int)V.size()); + + //VB : why 6 ? + + if(taille<=6) + {return V;} + else + { + double *COS=new double[taille/2]; + double *SIN=new double[taille/2]; + //double *angle=new double[taille/2]; + std::vector Bary=bary_poly(V); + COS[0]=1.0; + SIN[0]=0.0; + //angle[0]=0.0; + for(int i=0; i Trigo=calcul_cos_et_sin(&Bary[0],&V[0],&V[2*(i+1)]); + COS[i+1]=Trigo[0]; + SIN[i+1]=Trigo[1]; + //if(SIN[i+1]>=0) + // {angle[i+1]=atan2(SIN[i+1],COS[i+1]);} + // else + // {angle[i+1]=-atan2(SIN[i+1],COS[i+1]);} + } + + //ensuite on ordonne les angles. + std::vector Pt_ordonne; + Pt_ordonne.reserve(taille); + // std::multimap Ordre; + std::multimap,int, AngleLess> CosSin; + for(int i=0;i::iterator mi; + std::multimap,int, AngleLess>::iterator micossin; + // for(mi=Ordre.begin();mi!=Ordre.end();mi++) + // { + // int j=(*mi).second; + // Pt_ordonne.push_back(V[2*j]); + // Pt_ordonne.push_back(V[2*j+1]); + // } + for(micossin=CosSin.begin();micossin!=CosSin.end();micossin++) + { + int j=(*micossin).second; + Pt_ordonne.push_back(V[2*j]); + Pt_ordonne.push_back(V[2*j+1]); + } + delete [] COS; + delete [] SIN; + // delete [] angle; + return Pt_ordonne; + } + } + + template + inline void getElemBB(double* bb, const double *coordsOfMesh, int iP, int nb_nodes) + { + bb[0]=std::numeric_limits::max(); + bb[1]=-std::numeric_limits::max(); + bb[2]=std::numeric_limits::max(); + bb[3]=-std::numeric_limits::max(); + bb[4]=std::numeric_limits::max(); + bb[5]=-std::numeric_limits::max(); + + for (int i=0; ibb[1])?x:bb[1]; + bb[2]=(ybb[3])?y:bb[3]; + bb[4]=(zbb[5])?z:bb[5]; + } + } + + /*_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _*/ + /* Computes the dot product of a and b */ + /*_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _*/ + template + inline double dotprod( const double * a, const double * b) + { + double result=0; + for(int idim = 0; idim < dim ; idim++) result += a[idim]*b[idim]; + return result; + } + /*_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _*/ + /* Computes the norm of vector v */ + /*_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _*/ + template + inline double norm(const double * v) + { + double result =0; + for(int idim =0; idim + inline double distance2( const double * a, const double * b) + { + double result =0; + for(int idim =0; idim + inline double distance2( T * a, int inda, T * b, int indb) + { + double result =0; + for(int idim =0; idim inline void crossprod( const double * A, const double * B, const double * C, double * V); + + template<> inline + void crossprod<2>( const double * A, const double * B, const double * C, double * V) + { + double AB[2]; + double AC[2]; + for(int idim =0; idim<2; idim++) AB[idim] = B[idim]-A[idim];//B-A + for(int idim =0; idim<2; idim++) AC[idim] = C[idim]-A[idim];//C-A; + + V[0]=determinant(AB,AC); + V[1]=0; + } + template<> inline + void crossprod<3>( const double * A, const double * B, const double * C, double * V) + { + double AB[3]; + double AC[3]; + for(int idim =0; idim<3; idim++) AB[idim] = B[idim]-A[idim];//B-A + for(int idim =0; idim<3; idim++) AC[idim] = C[idim]-A[idim];//C-A; + + V[0]=AB[1]*AC[2]-AB[2]*AC[1]; + V[1]=-AB[0]*AC[2]+AB[2]*AC[0]; + V[2]=AB[0]*AC[1]-AB[1]*AC[0]; + } + template<> inline + void crossprod<1>( const double * /*A*/, const double * /*B*/, const double * /*C*/, double * /*V*/) + { + // just to be able to compile + } + + /*_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _*/ + /* Checks wether point A is inside the quadrangle BCDE */ + /*_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _*/ + + template inline double check_inside(const double* A,const double* B,const double* C,const double* D, + const double* E,double* ABC, double* ADE) + { + crossprod(A,B,C,ABC); + crossprod(A,D,E,ADE); + return dotprod(ABC,ADE); + } + + + /*_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _*/ + /* Computes the geometric angle (in [0,Pi]) between two non zero vectors AB and AC */ + /*_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _*/ + template inline double angle(const double * A, const double * B, const double * C, double * n) + { + double AB[dim]; + double AC[dim]; + double orthAB[dim]; + + for(int idim =0; idim(AB); + for(int idim =0; idim(AC); + double AB_dot_AC=dotprod(AB,AC); + for(int idim =0; idim(orthAB); + + return 2*atan2(numer,denom); + } + + /*_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _*/ + /* Tells whether the frame constituted of vectors AB, AC and n is direct */ + /*_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _*/ + template inline double direct_frame(const double * A, const double * B, const double * C, double * n); + template<> inline + double direct_frame<2>(const double * A, const double * B, const double * C, double * n) + { + double AB[2]; + double AC[2]; + for(int idim =0; idim<2; idim++) AB[idim] = B[idim]-A[idim];//B-A; + for(int idim =0; idim<2; idim++) AC[idim] = C[idim]-A[idim];//C-A; + + return determinant(AB,AC)*n[0]; + } + template<> inline + double direct_frame<3>(const double * A, const double * B, const double * C, double * n) + { + double AB[3]; + double AC[3]; + for(int idim =0; idim<3; idim++) AB[idim] = B[idim]-A[idim];//B-A; + for(int idim =0; idim<3; idim++) AC[idim] = C[idim]-A[idim];//C-A; + + return determinant(AB,AC,n)>0; + } + + /*_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _*/ + /* calcul l'intersection de deux polygones COPLANAIRES */ + /* en dimension DIM (2 ou 3). Si DIM=3 l'algorithme ne considere*/ + /* que les deux premieres coordonnees de chaque point */ + /*_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _*/ + template inline void intersec_de_polygone(const double * Coords_A, const double * Coords_B, + int nb_NodesA, int nb_NodesB, + std::vector& inter, + double dim_caracteristic, double precision) + { + for(int i_A = 1; i_A3) inter=INTERP_KERNEL::reconstruct_polygon(inter); + } + + /*_ _ _ _ _ _ _ _ _ + *_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ + * fonctions qui calcule l'aire d'un polygone en dimension 2 ou 3 + *_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ */ + template inline double polygon_area(std::vector& inter) + { + double result=0.; + double area[DIM]; + + for(int i = 1; i<(int)inter.size()/DIM-1; i++) + { + INTERP_KERNEL::crossprod(&inter[0],&inter[DIM*i],&inter[DIM*(i+1)],area); + result +=0.5*norm(area); + } + return result; + } + + template inline double polygon_area(std::deque& inter) + { + double result=0.; + double area[DIM]; + + for(int i = 1; i<(int)inter.size()/DIM-1; i++) + { + INTERP_KERNEL::crossprod(&inter[0],&inter[DIM*i],&inter[DIM*(i+1)],area); + result +=0.5*norm(area); + } + return result; + } + + /*! Computes the triple product (XA^XB).XC (in 3D)*/ + inline double triple_product(const double* A, const double*B, const double*C, const double*X) + { + double XA[3]; + XA[0]=A[0]-X[0]; + XA[1]=A[1]-X[1]; + XA[2]=A[2]-X[2]; + double XB[3]; + XB[0]=B[0]-X[0]; + XB[1]=B[1]-X[1]; + XB[2]=B[2]-X[2]; + double XC[3]; + XC[0]=C[0]-X[0]; + XC[1]=C[1]-X[1]; + XC[2]=C[2]-X[2]; + + return + (XA[1]*XB[2]-XA[2]*XB[1])*XC[0]+ + (XA[2]*XB[0]-XA[0]*XB[2])*XC[1]+ + (XA[0]*XB[1]-XA[1]*XB[0])*XC[2]; + } + + /*! Subroutine of checkEqualPolygins that tests if two list of nodes (not necessarily distincts) describe the same polygon, assuming they share a comon point.*/ + /*! Indexes istart1 and istart2 designate two points P1 in L1 and P2 in L2 that have identical coordinates. Generally called with istart1=0.*/ + /*! Integer sign ( 1 or -1) indicate the direction used in going all over L2. */ + template + bool checkEqualPolygonsOneDirection(T * L1, T * L2, int size1, int size2, int istart1, int istart2, double epsilon, int sign) + { + int i1 = istart1; + int i2 = istart2; + int i1next = ( i1 + 1 ) % size1; + int i2next = ( i2 + sign +size2) % size2; + + while(true) + { + while( i1next!=istart1 && distance2(L1,i1*dim, L1,i1next*dim) < epsilon ) i1next = ( i1next + 1 ) % size1; + while( i2next!=istart2 && distance2(L2,i2*dim, L2,i2next*dim) < epsilon ) i2next = ( i2next + sign +size2 ) % size2; + + if(i1next == istart1) + { + if(i2next == istart2) + return true; + else return false; + } + else + if(i2next == istart2) + return false; + else + { + if(distance2(L1,i1next*dim, L2,i2next*dim) > epsilon ) + return false; + else + { + i1 = i1next; + i2 = i2next; + i1next = ( i1 + 1 ) % size1; + i2next = ( i2 + sign + size2 ) % size2; + } + } + } + } + + /*! Tests if two list of nodes (not necessarily distincts) describe the same polygon.*/ + /*! Existence of multiple points in the list is considered.*/ + template + bool checkEqualPolygons(T * L1, T * L2, double epsilon) + { + if(L1==NULL || L2==NULL) + { + std::cout << "Warning InterpolationUtils.hxx:checkEqualPolygonsPointer: Null pointer " << std::endl; + throw(Exception("big error: not closed polygon...")); + } + + int size1 = (*L1).size()/dim; + int size2 = (*L2).size()/dim; + int istart1 = 0; + int istart2 = 0; + + while( istart2 < size2 && distance2(L1,istart1*dim, L2,istart2*dim) > epsilon ) istart2++; + + if(istart2 == size2) + { + return (size1 == 0) && (size2 == 0); + } + else + return checkEqualPolygonsOneDirection( L1, L2, size1, size2, istart1, istart2, epsilon, 1) + || checkEqualPolygonsOneDirection( L1, L2, size1, size2, istart1, istart2, epsilon, -1); + + } +} + + +#endif diff --cc medtool/src/INTERP_KERNEL/PolygonAlgorithms.hxx index bbb49362a,000000000..5d9f9d818 mode 100644,000000..100644 --- a/medtool/src/INTERP_KERNEL/PolygonAlgorithms.hxx +++ b/medtool/src/INTERP_KERNEL/PolygonAlgorithms.hxx @@@ -1,94 -1,0 +1,94 @@@ +// Copyright (C) 2007-2015 CEA/DEN, EDF R&D +// +// 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +// +// See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com +// + +#ifndef __POLYGONALGORITHMS_HXX__ +#define __POLYGONALGORITHMS_HXX__ + +#include +#include +#include + +namespace INTERP_KERNEL +{ + template + class VertexLess + { + public: - bool operator()(const double * P_1, const double * P_2) ++ bool operator()(const double * P_1, const double * P_2) const + { + for(int idim=0; idim P_2[idim]) return false; + } + return false; + } + }; + + template + class PolygonAlgorithms + { + public: + PolygonAlgorithms(double epsilon, double precision); + std::deque intersectConvexPolygons(const double* P_1,const double* P_2, int N1, int N2); + + //Not yet tested + int convexDecomposition(const double * P, int N, std::vector< std::map< int,int > >& components, + std::vector< int >& components_index, const double epsilon); + private: + void defineIndices(int& i_loc, int& i_next, int& i_prev, + const double *& Poly1, const double *& Poly2, + int& j1, int& j1_glob, int& j2, int& j2_glob, + int& j3, int& j3_glob, int& j4, int& j4_glob, + int& i_glob, int& i_next_glob, int& i_prev_glob, + const double * P_1, const double * P_2, + int N1, int N2, int sign); + void addCrossings( const double * A, const double * B, int i , int i_next, + const double * C, const double * D, int j1, int j2, + const double * E, const double * F, int j3, int j4, + const double * G); + void addCrossing0(const double * A, const double * B, int i, int i_next, + const double * C, const double * D, int j, int j_next); + void addCrossing( double * ABCD, std::pair< int,int > i_i_next, std::pair< int,int > j_j_next); + void addNewVertex( int i, int i_glob, int i_next_glob, int i_prev_glob, const double * P); + bool intersectSegmentSegment(const double * A, const double * B, const double * C, + const double * D, const double * E, double * V); + + + //Not yet tested + void convexDecomposition(const double* P, int N, double* n, std::vector< int > subP, int NsubP, + std::vector< std::map< int,int > >& components, std::vector< int >& components_index, + int& Ncomp, int sign, const double epsilon); + void convHull(const double *P, int N, double * n, std::map< int,int >& subP, + std::map< int,int >& not_in_hull, int& NsubP, const double epsilon); + private: + std::deque< double > _Inter;/* vertices of the intersection P1^P2 */ + std::vector< std::pair< int,int > > _End_segments; /* segments containing inter final edges */ + /* status list of segments (ending point, starting point) intersected by the sweeping line */ + /* and a boolean true if the ending point is in the intersection */ + std::multimap< int, std::pair< int,bool> > _Status; + bool _is_in_intersection; + bool _terminus; + double _vdouble[DIM]; + double _epsilon; + double _precision; + }; +} + +#endif diff --cc medtool/src/MEDCoupling/MEDCouplingAMRAttribute.cxx index 0a9844669,000000000..f49b7bf9d mode 100644,000000..100644 --- a/medtool/src/MEDCoupling/MEDCouplingAMRAttribute.cxx +++ b/medtool/src/MEDCoupling/MEDCouplingAMRAttribute.cxx @@@ -1,1537 -1,0 +1,1540 @@@ +// Copyright (C) 2007-2015 CEA/DEN, EDF R&D +// +// 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +// +// See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com +// +// Author : Anthony Geay + +#include "MEDCouplingAMRAttribute.hxx" +#include "MEDCouplingFieldDouble.hxx" +#include "MEDCouplingMemArray.hxx" +#include "MEDCouplingIMesh.hxx" + +#include +#include + +using namespace ParaMEDMEM; + ++/// @cond INTERNAL +DataArrayDoubleCollection *DataArrayDoubleCollection::New(const std::vector< std::pair >& fieldNames) +{ + return new DataArrayDoubleCollection(fieldNames); +} + +DataArrayDoubleCollection *DataArrayDoubleCollection::deepCpy() const +{ + return new DataArrayDoubleCollection(*this); +} + +void DataArrayDoubleCollection::allocTuples(int nbOfTuples) +{ + std::size_t sz(_arrs.size()); + for(std::size_t i=0;ireAlloc(nbOfTuples); +} + +void DataArrayDoubleCollection::dellocTuples() +{ + std::size_t sz(_arrs.size()); + for(std::size_t i=0;ireAlloc(0); +} + +void DataArrayDoubleCollection::copyFrom(const DataArrayDoubleCollection& other) +{ + std::size_t sz(_arrs.size()); + if(sz!=other._arrs.size()) + throw INTERP_KERNEL::Exception("DataArrayDoubleCollection::copyFrom : size are not the same !"); + for(std::size_t i=0;icpyFrom(*otherArr); + } +} + +void DataArrayDoubleCollection::spillInfoOnComponents(const std::vector< std::vector >& compNames) +{ + std::size_t sz(_arrs.size()); + if(sz!=compNames.size()) + throw INTERP_KERNEL::Exception("DataArrayDoubleCollection::spillInfoOnComponents : first size of compNames has to be equal to the number of fields defined !"); + for(std::size_t i=0;i& names(compNames[i]); + _arrs[i].first->setInfoOnComponents(names); + } +} + +void DataArrayDoubleCollection::spillNatures(const std::vector& nfs) +{ + std::size_t sz(_arrs.size()); + if(sz!=nfs.size()) + throw INTERP_KERNEL::Exception("DataArrayDoubleCollection::spillNatures : first size of vector of NatureOfField has to be equal to the number of fields defined !"); + for(std::size_t i=0;i > > DataArrayDoubleCollection::getInfoOnComponents() const +{ + std::size_t sz(_arrs.size()); + std::vector< std::pair < std::string, std::vector > > ret(sz); + for(std::size_t i=0;i >(elt->getName(),elt->getInfoOnComponents()); + } + return ret; +} + +std::vector DataArrayDoubleCollection::getNatures() const +{ + std::size_t sz(_arrs.size()); + std::vector ret(sz); + for(std::size_t i=0;i DataArrayDoubleCollection::retrieveFields() const +{ + std::size_t sz(_arrs.size()); + std::vector ret(sz); + for(std::size_t i=0;i(tmp); + if(ret[i]) + ret[i]->incrRef(); + } + return ret; +} + +const DataArrayDouble *DataArrayDoubleCollection::getFieldWithName(const std::string& name) const +{ + std::vector vec; + for(std::vector< std::pair< MEDCouplingAutoRefCountObjectPtr, NatureOfField > >::const_iterator it=_arrs.begin();it!=_arrs.end();it++) + { + const DataArrayDouble *obj((*it).first); + if(obj) + { + if(obj->getName()==name) + return obj; + else + vec.push_back(obj->getName()); + } + } + std::ostringstream oss; oss << "DataArrayDoubleCollection::getFieldWithName : fieldName \"" << name << "\" does not exist in this ! Possibilities are :"; + std::copy(vec.begin(),vec.end(),std::ostream_iterator(oss," ")); + throw INTERP_KERNEL::Exception(oss.str().c_str()); +} + +DataArrayDouble *DataArrayDoubleCollection::getFieldWithName(const std::string& name) +{ + std::vector vec; + for(std::vector< std::pair< MEDCouplingAutoRefCountObjectPtr, NatureOfField > >::iterator it=_arrs.begin();it!=_arrs.end();it++) + { + DataArrayDouble *obj((*it).first); + if(obj) + { + if(obj->getName()==name) + return obj; + else + vec.push_back(obj->getName()); + } + } + std::ostringstream oss; oss << "DataArrayDoubleCollection::getFieldWithName non const : fieldName \"" << name << "\" does not exist in this ! Possibilities are :"; + std::copy(vec.begin(),vec.end(),std::ostream_iterator(oss," ")); + throw INTERP_KERNEL::Exception(oss.str().c_str()); +} + +DataArrayDouble *DataArrayDoubleCollection::at(int pos) +{ + if(pos<0 || pos>=(int)_arrs.size()) + throw INTERP_KERNEL::Exception("DataArrayDoubleCollection::at (non const) : pos must be in [0,nbOfFields) !"); + return _arrs[pos].first; +} + +const DataArrayDouble *DataArrayDoubleCollection::at(int pos) const +{ + if(pos<0 || pos>=(int)_arrs.size()) + throw INTERP_KERNEL::Exception("DataArrayDoubleCollection::at : pos must be in [0,nbOfFields) !"); + return _arrs[pos].first; +} + +int DataArrayDoubleCollection::size() const +{ + return (int)_arrs.size(); +} + +void DataArrayDoubleCollection::SynchronizeFineToCoarse(int ghostLev, const MEDCouplingCartesianAMRMeshGen *fatherOfFineMesh, int patchId, const DataArrayDoubleCollection *fine, DataArrayDoubleCollection *coarse) +{ + if(!fine || !coarse) + throw INTERP_KERNEL::Exception("DataArrayDoubleCollection::SynchronizeFineToCoarse : the input DataArrayDouble collections must be non NULL !"); + std::size_t sz(coarse->_arrs.size()); + if(fine->_arrs.size()!=sz) + throw INTERP_KERNEL::Exception("DataArrayDoubleCollection::SynchronizeFineToCoarse : the input DataArrayDouble collection must have the same size !"); + for(std::size_t i=0;i_arrs[i].second,coarse->_arrs[i].second); + fatherOfFineMesh->fillCellFieldComingFromPatchGhost(patchId,fine->_arrs[i].first,coarse->_arrs[i].first,ghostLev,IsConservativeNature(coarse->_arrs[i].second)); + } +} + +void DataArrayDoubleCollection::SynchronizeCoarseToFine(int ghostLev, const MEDCouplingCartesianAMRMeshGen *fatherOfFineMesh, int patchId, const DataArrayDoubleCollection *coarse, DataArrayDoubleCollection *fine) +{ + if(!fine || !coarse) + throw INTERP_KERNEL::Exception("DataArrayDoubleCollection::SynchronizeCoarseToFine : the input DataArrayDouble collections must be non NULL !"); + std::size_t sz(coarse->_arrs.size()); + if(fine->_arrs.size()!=sz) + throw INTERP_KERNEL::Exception("DataArrayDoubleCollection::SynchronizeCoarseToFine : the input DataArrayDouble collection must have the same size !"); + for(std::size_t i=0;i_arrs[i].second,coarse->_arrs[i].second); + fatherOfFineMesh->fillCellFieldOnPatchGhost(patchId,coarse->_arrs[i].first,fine->_arrs[i].first,ghostLev,IsConservativeNature(coarse->_arrs[i].second)); + } +} + +void DataArrayDoubleCollection::SynchronizeFineEachOther(int patchId, int ghostLev, const MEDCouplingCartesianAMRMeshGen *fatherOfFineMesh, const std::vector& children, const std::vector& fieldsOnFine) +{ + if(!fatherOfFineMesh) + throw INTERP_KERNEL::Exception("DataArrayDoubleCollection::SynchronizeFineEachOther : father is NULL !"); + std::size_t sz(children.size()); + if(fieldsOnFine.size()!=sz) + throw INTERP_KERNEL::Exception("DataArrayDoubleCollection::SynchronizeFineEachOther : sizes of vectors mismatch !"); + if(sz<=1) + return ; + std::size_t nbOfCall(fieldsOnFine[0]->_arrs.size()); + for(std::size_t i=0;igetPatchIdFromChildMesh(children[i])!=(int)i) + throw INTERP_KERNEL::Exception("DataArrayDoubleCollection::SynchronizeFineEachOther : internal error !"); + for(std::size_t i=1;i_arrs.size()) + throw INTERP_KERNEL::Exception("DataArrayDoubleCollection::SynchronizeFineEachOther : the collection of DataArrayDouble must have all the same size !"); + for(std::size_t i=0;i arrs(sz); + for(std::size_t j=0;j_arrs[i].first; + fatherOfFineMesh->fillCellFieldOnPatchOnlyGhostAdv(patchId,ghostLev,arrs); + } +} + +/*! + * This method updates \a p1dac ghost zone parts using \a p2dac (which is really const). \a p2 is in the neighborhood of \a p1 (which size is defined by \a ghostLev). + */ +void DataArrayDoubleCollection::SynchronizeGhostZoneOfOneUsingTwo(int ghostLev, const MEDCouplingCartesianAMRPatch *p1, const DataArrayDoubleCollection *p1dac, const MEDCouplingCartesianAMRPatch *p2, const DataArrayDoubleCollection *p2dac) +{ + if(!p1 || !p1dac || !p2 || !p2dac) + throw INTERP_KERNEL::Exception("DataArrayDoubleCollection::SynchronizeGhostZoneOfOneUsingTwo : input pointer must be not NULL !"); + std::size_t sz(p1dac->_arrs.size()); + if(p2dac->_arrs.size()!=sz) + throw INTERP_KERNEL::Exception("DataArrayDoubleCollection::SynchronizeGhostZoneOfOneUsingTwo : size of DataArrayDouble Collection must be the same !"); + for(std::size_t i=0;i_arrs[i].first); + DataArrayDoubleCollection::CheckSameNatures(p1dac->_arrs[i].second,p2dac->_arrs[i].second); + bool isConservative(DataArrayDoubleCollection::IsConservativeNature(p1dac->_arrs[i].second)); + MEDCouplingCartesianAMRPatch::UpdateNeighborsOfOneWithTwoMixedLev(ghostLev,p1,p2,const_cast(zeArrWhichGhostsWillBeUpdated),p2dac->_arrs[i].first,isConservative); + } +} + +void DataArrayDoubleCollection::SynchronizeCoarseToFineOnlyInGhostZone(int ghostLev, const MEDCouplingCartesianAMRMeshGen *fatherOfFineMesh, int patchId, const DataArrayDoubleCollection *coarse, DataArrayDoubleCollection *fine) +{ + if(!fine || !coarse) + throw INTERP_KERNEL::Exception("DataArrayDoubleCollection::SynchronizeCoarseToFineOnlyInGhostZone : the input DataArrayDouble collections must be non NULL !"); + std::size_t sz(coarse->_arrs.size()); + if(fine->_arrs.size()!=sz) + throw INTERP_KERNEL::Exception("DataArrayDoubleCollection::SynchronizeCoarseToFineOnlyInGhostZone : the input DataArrayDouble collection must have the same size !"); + for(std::size_t i=0;ifillCellFieldOnPatchOnlyOnGhostZone(patchId,coarse->_arrs[i].first,fine->_arrs[i].first,ghostLev); +} + +void DataArrayDoubleCollection::synchronizeMyGhostZoneUsing(int ghostLev, const DataArrayDoubleCollection& other, const MEDCouplingCartesianAMRPatch *thisp, const MEDCouplingCartesianAMRPatch *otherp, const MEDCouplingCartesianAMRMeshGen *father) const +{ + DataArrayDoubleCollection *thisNC(const_cast(this)); + std::size_t sz(_arrs.size()); + if(other._arrs.size()!=sz) + throw INTERP_KERNEL::Exception("DataArrayDoubleCollection::synchronizeMyGhostZoneUsing : sizes of collections must match !"); + for(std::size_t i=0;ifillCellFieldOnPatchOnlyOnGhostZoneWith(ghostLev,thisp,otherp,thisNC->_arrs[i].first,other._arrs[i].first); +} + +void DataArrayDoubleCollection::synchronizeMyGhostZoneUsingExt(int ghostLev, const DataArrayDoubleCollection& other, const MEDCouplingCartesianAMRPatch *thisp, const MEDCouplingCartesianAMRPatch *otherp) const +{ + DataArrayDoubleCollection *thisNC(const_cast(this)); + std::size_t sz(_arrs.size()); + if(other._arrs.size()!=sz) + throw INTERP_KERNEL::Exception("DataArrayDoubleCollection::synchronizeMyGhostZoneUsingExt : sizes of collections must match !"); + for(std::size_t i=0;i_arrs[i].first,other._arrs[i].first); +} + +DataArrayDoubleCollection::DataArrayDoubleCollection(const std::vector< std::pair >& fieldNames):_arrs(fieldNames.size()) +{ + std::size_t sz(fieldNames.size()); + std::vector names(sz); + for(std::size_t i=0;i& info(fieldNames[i]); + if(info.second<=0) + { + std::ostringstream oss; oss << "DataArrayDoubleCollection constructor : At pos #" << i << " the array with name \"" << info.first << "\" as a number of components equal to " << info.second; + oss << " It has to be >=1 !"; + throw INTERP_KERNEL::Exception(oss.str().c_str()); + } + _arrs[i].first=DataArrayDouble::New(); + _arrs[i].first->alloc(0,info.second); + _arrs[i].first->setName(info.first); + names[i]=info.second; + _arrs[i].second=ConservativeVolumic; + } + CheckDiscriminantNames(names); +} + +DataArrayDoubleCollection::DataArrayDoubleCollection(const DataArrayDoubleCollection& other):RefCountObject(other),_arrs(other._arrs.size()) +{ + std::size_t sz(other._arrs.size()); + for(std::size_t i=0;ideepCpy(); + } +} + +std::size_t DataArrayDoubleCollection::getHeapMemorySizeWithoutChildren() const +{ + std::size_t ret(sizeof(DataArrayDoubleCollection)); + ret+=_arrs.capacity()*sizeof(MEDCouplingAutoRefCountObjectPtr); + return ret; +} + +std::vector DataArrayDoubleCollection::getDirectChildrenWithNull() const +{ + std::vector ret; + for(std::vector< std::pair< MEDCouplingAutoRefCountObjectPtr, NatureOfField > >::const_iterator it=_arrs.begin();it!=_arrs.end();it++) + ret.push_back((const DataArrayDouble *)(*it).first); + return ret; +} + +void DataArrayDoubleCollection::updateTime() const +{ + for(std::vector< std::pair< MEDCouplingAutoRefCountObjectPtr, NatureOfField > >::const_iterator it=_arrs.begin();it!=_arrs.end();it++) + { + const DataArrayDouble *pt((*it).first); + if(pt) + updateTimeWith(*pt); + } +} + +void DataArrayDoubleCollection::CheckDiscriminantNames(const std::vector& names) +{ + std::set s(names.begin(),names.end()); + if(s.size()!=names.size()) + throw INTERP_KERNEL::Exception("DataArrayDoubleCollection::CheckDiscriminantNames : The names of fields must be different each other ! It is not the case !"); +} + +bool DataArrayDoubleCollection::IsConservativeNature(NatureOfField n) +{ + CheckValidNature(n); + return n==RevIntegral || n==IntegralGlobConstraint; +} + +void DataArrayDoubleCollection::CheckSameNatures(NatureOfField n1, NatureOfField n2) +{ + CheckValidNature(n1); + CheckValidNature(n2); + if(n1!=n2) + throw INTERP_KERNEL::Exception("DataArrayDoubleCollection::CheckSameNatures : natures are not the same !"); +} + +void DataArrayDoubleCollection::CheckValidNature(NatureOfField n) +{ + if(n!=ConservativeVolumic && n!=Integral && n!=IntegralGlobConstraint && n!=RevIntegral) + throw INTERP_KERNEL::Exception("DataArrayDoubleCollection::CheckValidNature : unrecognized nature !"); +} + +MEDCouplingGridCollection *MEDCouplingGridCollection::New(const std::vector& ms, const std::vector< std::pair >& fieldNames) +{ + return new MEDCouplingGridCollection(ms,fieldNames); +} + +MEDCouplingGridCollection *MEDCouplingGridCollection::deepCpy(const MEDCouplingCartesianAMRMeshGen *newGf, const MEDCouplingCartesianAMRMeshGen *oldGf) const +{ + return new MEDCouplingGridCollection(*this,newGf,oldGf); +} + +void MEDCouplingGridCollection::alloc(int ghostLev) +{ + for(std::vector< std::pair > >::iterator it=_map_of_dadc.begin();it!=_map_of_dadc.end();it++) + { + int nbTuples((*it).first->getNumberOfCellsAtCurrentLevelGhost(ghostLev)); + DataArrayDoubleCollection *dadc((*it).second); + if(dadc) + dadc->allocTuples(nbTuples); + else + throw INTERP_KERNEL::Exception("MEDCouplingGridCollection::alloc : internal error !"); + } +} + +void MEDCouplingGridCollection::dealloc() +{ + for(std::vector< std::pair > >::iterator it=_map_of_dadc.begin();it!=_map_of_dadc.end();it++) + { + DataArrayDoubleCollection *dadc((*it).second); + if(dadc) + dadc->dellocTuples(); + else + throw INTERP_KERNEL::Exception("MEDCouplingGridCollection::dealloc : internal error !"); + } +} + +void MEDCouplingGridCollection::spillInfoOnComponents(const std::vector< std::vector >& compNames) +{ + for(std::vector< std::pair > >::iterator it=_map_of_dadc.begin();it!=_map_of_dadc.end();it++) + (*it).second->spillInfoOnComponents(compNames); +} + +void MEDCouplingGridCollection::spillNatures(const std::vector& nfs) +{ + for(std::vector< std::pair > >::iterator it=_map_of_dadc.begin();it!=_map_of_dadc.end();it++) + (*it).second->spillNatures(nfs); +} + +std::vector< std::pair > > MEDCouplingGridCollection::getInfoOnComponents() const +{ + if(_map_of_dadc.empty()) + throw INTERP_KERNEL::Exception("MEDCouplingGridCollection::getInfoOnComponents : empty map !"); + const DataArrayDoubleCollection *elt(_map_of_dadc[0].second); + if(!elt) + throw INTERP_KERNEL::Exception("MEDCouplingGridCollection::getInfoOnComponents : null pointer !"); + return elt->getInfoOnComponents(); +} + +std::vector MEDCouplingGridCollection::getNatures() const +{ + if(_map_of_dadc.empty()) + throw INTERP_KERNEL::Exception("MEDCouplingGridCollection::getNatures : empty map !"); + const DataArrayDoubleCollection *elt(_map_of_dadc[0].second); + if(!elt) + throw INTERP_KERNEL::Exception("MEDCouplingGridCollection::getNatures : null pointer !"); + return elt->getNatures(); +} + +bool MEDCouplingGridCollection::presenceOf(const MEDCouplingCartesianAMRMeshGen *m, int& pos) const +{ + int ret(0); + for(std::vector< std::pair > >::const_iterator it=_map_of_dadc.begin();it!=_map_of_dadc.end();it++,ret++) + { + if((*it).first==m) + { + pos=ret; + return true; + } + } + return false; +} + +const DataArrayDoubleCollection& MEDCouplingGridCollection::getFieldsAt(int pos) const +{ + if(pos<0 || pos>(int)_map_of_dadc.size()) + throw INTERP_KERNEL::Exception("MEDCouplingGridCollection::getFieldsAt : invalid pos given in input ! Must be in [0,size) !"); + return *_map_of_dadc[pos].second; +} + +DataArrayDoubleCollection& MEDCouplingGridCollection::getFieldsAt(int pos) +{ + if(pos<0 || pos>(int)_map_of_dadc.size()) + throw INTERP_KERNEL::Exception("MEDCouplingGridCollection::getFieldsAt (non const) : invalid pos given in input ! Must be in [0,size) !"); + return *_map_of_dadc[pos].second; +} + +/*! + * This method copies for all grids intersecting themselves (between \a this and \a other), the values of fields of \a other to the intersecting + * part of fields of \a this. The fields are expected to be the same between \a other and \a this. + * This methods makes the hypothesis that \a this and \a other share two god father that are compatible each other that is to say with the same cell grid structure. + */ +void MEDCouplingGridCollection::copyOverlappedZoneFrom(int ghostLev, const MEDCouplingGridCollection& other) +{ + for(std::vector< std::pair > >::iterator it=_map_of_dadc.begin();it!=_map_of_dadc.end();it++) + { + std::vector deltaThis,deltaOther; + std::vector< std::pair > rgThis((*it).first->positionRelativeToGodFather(deltaThis)); + std::vector thisSt((*it).first->getImageMesh()->getCellGridStructure()); + std::transform(thisSt.begin(),thisSt.end(),thisSt.begin(),std::bind2nd(std::plus(),2*ghostLev)); + for(std::vector< std::pair > >::const_iterator it2=other._map_of_dadc.begin();it2!=other._map_of_dadc.end();it2++) + { + std::vector< std::pair > rgOther((*it2).first->positionRelativeToGodFather(deltaOther)); + if(MEDCouplingStructuredMesh::AreRangesIntersect(rgThis,rgOther)) + { + std::vector< std::pair > isect(MEDCouplingStructuredMesh::IntersectRanges(rgThis,rgOther)); + std::vector< std::pair > pThis,pOther; + MEDCouplingStructuredMesh::ChangeReferenceFromGlobalOfCompactFrmt(rgThis,isect,pThis,true); + MEDCouplingStructuredMesh::ChangeReferenceFromGlobalOfCompactFrmt(rgOther,isect,pOther,true); + std::vector otherSt((*it2).first->getImageMesh()->getCellGridStructure()); + MEDCouplingStructuredMesh::ApplyGhostOnCompactFrmt(pThis,ghostLev); + MEDCouplingStructuredMesh::ApplyGhostOnCompactFrmt(pOther,ghostLev); + std::transform(otherSt.begin(),otherSt.end(),otherSt.begin(),std::bind2nd(std::plus(),2*ghostLev)); + int sz((*it2).second->size()); + for(int i=0;iat(i)); + DataArrayDouble *thisArr((*it).second->at(i)); + MEDCouplingAutoRefCountObjectPtr partOfOther(MEDCouplingStructuredMesh::ExtractFieldOfDoubleFrom(otherSt,otherArr,pOther)); + MEDCouplingStructuredMesh::AssignPartOfFieldOfDoubleUsing(thisSt,thisArr,pThis,partOfOther); + } + } + } + } +} + +void MEDCouplingGridCollection::SynchronizeFineToCoarse(int ghostLev, const MEDCouplingGridCollection *fine, const MEDCouplingGridCollection *coarse) +{ + if(!fine || !coarse) + throw INTERP_KERNEL::Exception("MEDCouplingGridCollection::SynchronizeFineToCoarse : one or more input pointer is NULL !"); + const std::vector< std::pair > >& mf(fine->_map_of_dadc); + const std::vector< std::pair > >& mc(coarse->_map_of_dadc); + for(std::vector< std::pair > >::const_iterator it=mf.begin();it!=mf.end();it++) + { + const MEDCouplingCartesianAMRMeshGen *fineMesh((*it).first); + const MEDCouplingCartesianAMRMeshGen *fatherOfFineMesh(fineMesh->getFather()); + bool found(false); + for(std::vector< std::pair > >::const_iterator it0=mc.begin();it0!=mc.end() && !found;it0++) + { + if((*it0).first==fatherOfFineMesh) + { + found=true; + int patchId(fatherOfFineMesh->getPatchIdFromChildMesh(fineMesh)); + const DataArrayDoubleCollection *coarseDaCol((*it0).second); + DataArrayDoubleCollection *coarseModified(const_cast(coarseDaCol));//coarse values in DataArrayDouble will be altered + DataArrayDoubleCollection::SynchronizeFineToCoarse(ghostLev,fatherOfFineMesh,patchId,(*it).second,coarseModified); + } + } + if(!found) + throw INTERP_KERNEL::Exception("MEDCouplingGridCollection::SynchronizeFineToCoarse : a fine mesh is orphan regarding given coarse meshes !"); + } +} + +void MEDCouplingGridCollection::SynchronizeCoarseToFine(int ghostLev, const MEDCouplingGridCollection *coarse, const MEDCouplingGridCollection *fine) +{ + if(!fine || !coarse) + throw INTERP_KERNEL::Exception("MEDCouplingGridCollection::SynchronizeCoarseToFine : one or more input pointer is NULL !"); + const std::vector< std::pair > >& mf(fine->_map_of_dadc); + const std::vector< std::pair > >& mc(coarse->_map_of_dadc); + for(std::vector< std::pair > >::const_iterator it=mf.begin();it!=mf.end();it++) + { + const MEDCouplingCartesianAMRMeshGen *fineMesh((*it).first); + const MEDCouplingCartesianAMRMeshGen *fatherOfFineMesh(fineMesh->getFather()); + bool found(false); + for(std::vector< std::pair > >::const_iterator it0=mc.begin();it0!=mc.end() && !found;it0++) + { + if((*it0).first==fatherOfFineMesh) + { + found=true; + int patchId(fatherOfFineMesh->getPatchIdFromChildMesh(fineMesh)); + const DataArrayDoubleCollection *fineDaCol((*it).second); + DataArrayDoubleCollection *fineModified(const_cast(fineDaCol));//fine values in DataArrayDouble will be altered + DataArrayDoubleCollection::SynchronizeCoarseToFine(ghostLev,fatherOfFineMesh,patchId,(*it0).second,fineModified); + } + } + if(!found) + throw INTERP_KERNEL::Exception("MEDCouplingGridCollection::SynchronizeCoarseToFine : a fine mesh is orphan regarding given coarse meshes !"); + } +} + +/*! + * All the pairs in \a ps must share the same father. If not call synchronizeFineEachOtherExt instead. + * + * \sa synchronizeFineEachOtherExt + */ +void MEDCouplingGridCollection::synchronizeFineEachOther(int ghostLev, const std::vector< std::pair >& ps) const +{ + for(std::vector< std::pair >::const_iterator it=ps.begin();it!=ps.end();it++) + { + int p1,p2; + if(!presenceOf((*it).first->getMesh(),p1)) + throw INTERP_KERNEL::Exception("MEDCouplingGridCollection::synchronizeFineEachOther : internal error #1 !"); + if(!presenceOf((*it).second->getMesh(),p2)) + throw INTERP_KERNEL::Exception("MEDCouplingGridCollection::synchronizeFineEachOther : internal error #2 !"); + const DataArrayDoubleCollection& col1(getFieldsAt(p1)); + const DataArrayDoubleCollection& col2(getFieldsAt(p2)); + col1.synchronizeMyGhostZoneUsing(ghostLev,col2,(*it).first,(*it).second,(*it).first->getMesh()->getFather()); + } +} + +/*! + * This method is a generalization of synchronizeFineEachOther because elements in pairs are \b not sharing the same father but are neighbors nevertheless. + * + * \sa synchronizeFineEachOther + */ +void MEDCouplingGridCollection::synchronizeFineEachOtherExt(int ghostLev, const std::vector< std::pair >& ps) const +{ + for(std::vector< std::pair >::const_iterator it=ps.begin();it!=ps.end();it++) + { + int p1,p2; + if(!presenceOf((*it).first->getMesh(),p1)) + throw INTERP_KERNEL::Exception("MEDCouplingGridCollection::synchronizeFineEachOtherExt : internal error #1 !"); + if(!presenceOf((*it).second->getMesh(),p2)) + throw INTERP_KERNEL::Exception("MEDCouplingGridCollection::synchronizeFineEachOtherExt : internal error #2 !"); + const DataArrayDoubleCollection& col1(getFieldsAt(p1)); + const DataArrayDoubleCollection& col2(getFieldsAt(p2)); + col1.synchronizeMyGhostZoneUsingExt(ghostLev,col2,(*it).first,(*it).second); + } +} + +/*! + * The pairs returned share the same direct father. The number of returned elements must be even. + */ +std::vector< std::pair > MEDCouplingGridCollection::findNeighbors(int ghostLev) const +{ + std::vector< std::pair > ret; + std::map > m; + for(std::vector< std::pair > >::const_iterator it=_map_of_dadc.begin();it!=_map_of_dadc.end();it++) + { + const MEDCouplingCartesianAMRMeshGen *fineMesh((*it).first); + const MEDCouplingCartesianAMRMeshGen *fatherOfFineMesh(fineMesh->getFather()); + m[fatherOfFineMesh].push_back(fineMesh); + } + for(std::map >::const_iterator it0=m.begin();it0!=m.end();it0++) + { + for(std::vector::const_iterator it1=(*it0).second.begin();it1!=(*it0).second.end();it1++) + { + int patchId((*it0).first->getPatchIdFromChildMesh(*it1)); + std::vector neighs((*it0).first->getPatchIdsInTheNeighborhoodOf(patchId,ghostLev)); + const MEDCouplingCartesianAMRPatch *pRef((*it0).first->getPatch(patchId)); + for(std::vector::const_iterator it2=neighs.begin();it2!=neighs.end();it2++) + { + const MEDCouplingCartesianAMRPatch *pLoc((*it0).first->getPatch(*it2)); + ret.push_back(std::pair(pRef,pLoc)); + } + } + } + if(ret.size()%2!=0) + throw INTERP_KERNEL::Exception("MEDCouplingGridCollection::findNeighbors : something is wrong ! The number of neighbor pairs must be %2 ==0 !"); + return ret; +} + +void MEDCouplingGridCollection::SynchronizeCoarseToFineOnlyInGhostZone(int ghostLev, const MEDCouplingGridCollection *coarse, const MEDCouplingGridCollection *fine) +{ + if(!fine || !coarse) + throw INTERP_KERNEL::Exception("MEDCouplingGridCollection::SynchronizeCoarseToFineOnlyInGhostZone : one or more input pointer is NULL !"); + const std::vector< std::pair > >& mf(fine->_map_of_dadc); + const std::vector< std::pair > >& mc(coarse->_map_of_dadc); + for(std::vector< std::pair > >::const_iterator it=mf.begin();it!=mf.end();it++) + { + const MEDCouplingCartesianAMRMeshGen *fineMesh((*it).first); + const MEDCouplingCartesianAMRMeshGen *fatherOfFineMesh(fineMesh->getFather()); + bool found(false); + for(std::vector< std::pair > >::const_iterator it0=mc.begin();it0!=mc.end() && !found;it0++) + { + if((*it0).first==fatherOfFineMesh) + { + found=true; + int patchId(fatherOfFineMesh->getPatchIdFromChildMesh(fineMesh)); + const DataArrayDoubleCollection *fineDaCol((*it).second); + DataArrayDoubleCollection *fineModified(const_cast(fineDaCol));//fine values in DataArrayDouble will be altered + DataArrayDoubleCollection::SynchronizeCoarseToFineOnlyInGhostZone(ghostLev,fatherOfFineMesh,patchId,(*it0).second,fineModified); + } + } + if(!found) + throw INTERP_KERNEL::Exception("MEDCouplingGridCollection::SynchronizeCoarseToFineOnlyInGhostZone : a fine mesh is orphan regarding given coarse meshes !"); + } +} + +void MEDCouplingGridCollection::fillIfInTheProgenyOf(const std::string& fieldName, const MEDCouplingCartesianAMRMeshGen *head, std::vector& recurseArrs) const +{ + for(std::vector< std::pair > >::const_iterator it=_map_of_dadc.begin();it!=_map_of_dadc.end();it++) + { + const MEDCouplingCartesianAMRMeshGen *a((*it).first); + if(head==a || head->isObjectInTheProgeny(a)) + { + const DataArrayDoubleCollection *gc((*it).second); + recurseArrs.push_back(gc->getFieldWithName(fieldName)); + } + } +} + +MEDCouplingGridCollection::MEDCouplingGridCollection(const std::vector& ms, const std::vector< std::pair >& fieldNames):_map_of_dadc(ms.size()) +{ + std::size_t sz(ms.size()); + for(std::size_t i=0;i pos(other._map_of_dadc[i].first->getPositionRelativeTo(oldGf)); + _map_of_dadc[i].first=newGf->getMeshAtPosition(pos); + const DataArrayDoubleCollection *dac(other._map_of_dadc[i].second); + if(dac) + _map_of_dadc[i].second=dac->deepCpy(); + } +} + +std::size_t MEDCouplingGridCollection::getHeapMemorySizeWithoutChildren() const +{ + std::size_t ret(sizeof(MEDCouplingGridCollection)); + ret+=_map_of_dadc.capacity()*sizeof(std::pair >); + return ret; +} + +std::vector MEDCouplingGridCollection::getDirectChildrenWithNull() const +{ + std::vector ret; + for(std::vector< std::pair > >::const_iterator it=_map_of_dadc.begin();it!=_map_of_dadc.end();it++) + ret.push_back((const DataArrayDoubleCollection *)(*it).second); + return ret; +} + +void MEDCouplingGridCollection::updateTime() const +{ + for(std::vector< std::pair > >::const_iterator it=_map_of_dadc.begin();it!=_map_of_dadc.end();it++) + { + const MEDCouplingCartesianAMRMeshGen *a((*it).first); + if(a) + updateTimeWith(*a); + const DataArrayDoubleCollection *b((*it).second); + if(b) + updateTimeWith(*b); + } +} + ++/// @endcond ++ +MEDCouplingCartesianAMRMesh *MEDCouplingDataForGodFather::getMyGodFather() +{ + return _gf; +} + +const MEDCouplingCartesianAMRMesh *MEDCouplingDataForGodFather::getMyGodFather() const +{ + return _gf; +} + +MEDCouplingDataForGodFather::MEDCouplingDataForGodFather(MEDCouplingCartesianAMRMesh *gf):_gf(gf),_tlc(gf) +{ + if(!gf) + throw INTERP_KERNEL::Exception("MEDCouplingDataForGodFather constructor : A data has to be attached to a AMR Mesh instance !"); + gf->incrRef(); +} + +void MEDCouplingDataForGodFather::checkGodFatherFrozen() const +{ + _tlc.checkConst(); +} + +bool MEDCouplingDataForGodFather::changeGodFather(MEDCouplingCartesianAMRMesh *gf) +{ + bool ret(_tlc.keepTrackOfNewTL(gf)); + if(ret) + { + _gf=gf; + if(gf) + gf->incrRef(); + } + return ret; +} + +MEDCouplingDataForGodFather::MEDCouplingDataForGodFather(const MEDCouplingDataForGodFather& other, bool deepCpyGF):RefCountObject(other),_gf(other._gf),_tlc(other._gf) +{ + other._tlc.checkConst(); + if(deepCpyGF) + { + const MEDCouplingCartesianAMRMesh *gf(other._gf); + if(gf) + _gf=gf->deepCpy(0); + _tlc.keepTrackOfNewTL(_gf); + } +} + +/*! + * This method creates, attach to a main AMR mesh \a gf ( called god father :-) ) and returns a data linked to \a gf ready for the computation. + */ +MEDCouplingAMRAttribute *MEDCouplingAMRAttribute::New(MEDCouplingCartesianAMRMesh *gf, const std::vector< std::pair >& fieldNames, int ghostLev) +{ + return new MEDCouplingAMRAttribute(gf,fieldNames,ghostLev); +} + +MEDCouplingAMRAttribute *MEDCouplingAMRAttribute::New(MEDCouplingCartesianAMRMesh *gf, const std::vector< std::pair > >& fieldNames, int ghostLev) +{ + std::size_t sz(fieldNames.size()); + std::vector< std::pair > fieldNames2(sz); + std::vector< std::vector > compNames(sz); + for(std::size_t i=0;i ret(New(gf,fieldNames2,ghostLev)); + ret->spillInfoOnComponents(compNames); + return ret.retn(); +} + +/*! + * Assign the info on components for all DataArrayDouble instance recursively stored in \a this. + * The first dim of input \a compNames is the field id in the same order than those implicitely specified in \a fieldNames parameter of MEDCouplingAMRAttribute::New. + * The second dim of \a compNames represent the component names component per component corresponding to the field. The size of this 2nd dimension has + * to perfectly fit with those specified in MEDCouplingAMRAttribute::New. + */ +void MEDCouplingAMRAttribute::spillInfoOnComponents(const std::vector< std::vector >& compNames) +{ + _tlc.checkConst(); + for(std::vector< MEDCouplingAutoRefCountObjectPtr >::iterator it=_levs.begin();it!=_levs.end();it++) + (*it)->spillInfoOnComponents(compNames); +} + +/*! + * Assign nature for each fields in \a this. + * \param [in] nfs + */ +void MEDCouplingAMRAttribute::spillNatures(const std::vector& nfs) +{ + _tlc.checkConst(); + for(std::vector< MEDCouplingAutoRefCountObjectPtr >::iterator it=_levs.begin();it!=_levs.end();it++) + (*it)->spillNatures(nfs); +} + +MEDCouplingAMRAttribute *MEDCouplingAMRAttribute::deepCpy() const +{ + return new MEDCouplingAMRAttribute(*this,true); +} + +MEDCouplingAMRAttribute *MEDCouplingAMRAttribute::deepCpyWithoutGodFather() const +{ + return new MEDCouplingAMRAttribute(*this,false); +} + +/*! + * Returns the number of levels by \b only \b considering \a this (god father instance is considered only to see if it has not changed still last update of \a this). + * + */ +int MEDCouplingAMRAttribute::getNumberOfLevels() const +{ + checkGodFatherFrozen(); + return (int)_levs.size(); +} + +/*! + * This method returns all DataArrayDouble instances lying on the specified mesh \a mesh. + * If \a mesh is not part of the progeny of god father object given at construction of \a this an exception will be thrown. + * + * \return std::vector - DataArrayDouble instances to be deallocated by the caller (using decrRef). + * \sa retrieveFieldOn + */ +std::vector MEDCouplingAMRAttribute::retrieveFieldsOn(MEDCouplingCartesianAMRMeshGen *mesh) const +{ + for(std::vector< MEDCouplingAutoRefCountObjectPtr >::const_iterator it=_levs.begin();it!=_levs.end();it++) + { + int tmp(-1); + if((*it)->presenceOf(mesh,tmp)) + { + const DataArrayDoubleCollection& ddc((*it)->getFieldsAt(tmp)); + return ddc.retrieveFields(); + } + } + throw INTERP_KERNEL::Exception("MEDCouplingAMRAttribute::retrieveFieldsOn : the mesh specified is not in the progeny of this !"); +} + +/*! + * \sa retrieveFieldsOn + */ +const DataArrayDouble *MEDCouplingAMRAttribute::getFieldOn(MEDCouplingCartesianAMRMeshGen *mesh, const std::string& fieldName) const +{ + for(std::vector< MEDCouplingAutoRefCountObjectPtr >::const_iterator it=_levs.begin();it!=_levs.end();it++) + { + int tmp(-1); + if((*it)->presenceOf(mesh,tmp)) + { + const DataArrayDoubleCollection& ddc((*it)->getFieldsAt(tmp)); + return ddc.getFieldWithName(fieldName); + } + } + throw INTERP_KERNEL::Exception("MEDCouplingAMRAttribute::getFieldOn : the mesh specified is not in the progeny of this !"); +} + +DataArrayDouble *MEDCouplingAMRAttribute::getFieldOn(MEDCouplingCartesianAMRMeshGen *mesh, const std::string& fieldName) +{ + for(std::vector< MEDCouplingAutoRefCountObjectPtr >::iterator it=_levs.begin();it!=_levs.end();it++) + { + int tmp(-1); + if((*it)->presenceOf(mesh,tmp)) + { + DataArrayDoubleCollection& ddc((*it)->getFieldsAt(tmp)); + return ddc.getFieldWithName(fieldName); + } + } + throw INTERP_KERNEL::Exception("MEDCouplingAMRAttribute::getFieldOn non const : the mesh specified is not in the progeny of this !"); +} + +/*! + * This method returns a field on an unstructured mesh the most refined as possible without overlap. + * Ghost part are not visible here. + * + * \return MEDCouplingFieldDouble * - a field on cells that the caller has to deal with (deallocate it). + */ +MEDCouplingFieldDouble *MEDCouplingAMRAttribute::buildCellFieldOnRecurseWithoutOverlapWithoutGhost(MEDCouplingCartesianAMRMeshGen *mesh, const std::string& fieldName) const +{ + std::vector recurseArrs; + std::size_t lev(0); + for(std::vector< MEDCouplingAutoRefCountObjectPtr >::const_iterator it=_levs.begin();it!=_levs.end();it++,lev++) + { + int tmp(-1); + if((*it)->presenceOf(mesh,tmp)) + { + const DataArrayDoubleCollection& ddc((*it)->getFieldsAt(tmp)); + recurseArrs.push_back(ddc.getFieldWithName(fieldName)); + break; + } + } + lev++; + for(std::size_t i=lev;i<_levs.size();i++) + { + const MEDCouplingGridCollection *gc(_levs[i]); + gc->fillIfInTheProgenyOf(fieldName,mesh,recurseArrs); + } + return mesh->buildCellFieldOnRecurseWithoutOverlapWithoutGhost(_ghost_lev,recurseArrs); +} + +/*! + * This method builds a newly created field on cell just lying on mesh \a mesh without its eventual refinement. + * The output field also displays ghost cells. + * + * \return MEDCouplingFieldDouble * - a field on cells that the caller has to deal with (deallocate it). + * + * \sa buildCellFieldOnWithoutGhost + */ +MEDCouplingFieldDouble *MEDCouplingAMRAttribute::buildCellFieldOnWithGhost(MEDCouplingCartesianAMRMeshGen *mesh, const std::string& fieldName) const +{ + const DataArrayDouble *arr(0); + for(std::vector< MEDCouplingAutoRefCountObjectPtr >::const_iterator it=_levs.begin();it!=_levs.end();it++) + { + int tmp(-1); + if((*it)->presenceOf(mesh,tmp)) + { + const DataArrayDoubleCollection& ddc((*it)->getFieldsAt(tmp)); + arr=ddc.getFieldWithName(fieldName); + } + } + if(!arr) + throw INTERP_KERNEL::Exception("MEDCouplingAMRAttribute::buildCellFieldOnWithGhost : the mesh specified is not in the progeny of this !"); + MEDCouplingAutoRefCountObjectPtr im(mesh->getImageMesh()->buildWithGhost(_ghost_lev)); + MEDCouplingAutoRefCountObjectPtr ret(MEDCouplingFieldDouble::New(ON_CELLS)); + ret->setMesh(im); + ret->setArray(const_cast(arr)); + ret->setName(arr->getName()); + return ret.retn(); +} + +/*! + * This method builds a newly created field on cell just lying on mesh \a mesh without its eventual refinement. + * The output field does not display ghost cells. + * + * \return MEDCouplingFieldDouble * - a field on cells that the caller has to deal with (deallocate it). + * + * \sa buildCellFieldOnWithGhost + */ +MEDCouplingFieldDouble *MEDCouplingAMRAttribute::buildCellFieldOnWithoutGhost(MEDCouplingCartesianAMRMeshGen *mesh, const std::string& fieldName) const +{ + const DataArrayDouble *arr(0); + for(std::vector< MEDCouplingAutoRefCountObjectPtr >::const_iterator it=_levs.begin();it!=_levs.end();it++) + { + int tmp(-1); + if((*it)->presenceOf(mesh,tmp)) + { + const DataArrayDoubleCollection& ddc((*it)->getFieldsAt(tmp)); + arr=ddc.getFieldWithName(fieldName); + } + } + if(!arr) + throw INTERP_KERNEL::Exception("MEDCouplingAMRAttribute::buildCellFieldOnWithoutGhost : the mesh specified is not in the progeny of this !"); + // + MEDCouplingAutoRefCountObjectPtr im(mesh->getImageMesh()->buildWithGhost(_ghost_lev)); + std::vector cgs(mesh->getImageMesh()->getCellGridStructure()),cgsWG(im->getCellGridStructure()); + MEDCouplingAutoRefCountObjectPtr arr2(DataArrayDouble::New()); + arr2->alloc(mesh->getImageMesh()->getNumberOfCells(),arr->getNumberOfComponents()); + std::vector< std::pair > cgs2(MEDCouplingStructuredMesh::GetCompactFrmtFromDimensions(cgs)); + MEDCouplingStructuredMesh::ApplyGhostOnCompactFrmt(cgs2,_ghost_lev); + std::vector fakeFactors(mesh->getImageMesh()->getSpaceDimension(),1); + MEDCouplingIMesh::SpreadCoarseToFine(arr,cgsWG,arr2,cgs2,fakeFactors); + arr2->copyStringInfoFrom(*arr); + // + MEDCouplingAutoRefCountObjectPtr ret(MEDCouplingFieldDouble::New(ON_CELLS)); + ret->setMesh(mesh->getImageMesh()); + ret->setArray(arr2); + ret->setName(arr->getName()); + return ret.retn(); +} + + +std::string MEDCouplingAMRAttribute::writeVTHB(const std::string& fileName) const +{ + static const char EXT[]=".vthb"; + std::string baseName,extName,zeFileName; + MEDCouplingMesh::SplitExtension(fileName,baseName,extName); + if(extName==EXT) + zeFileName=fileName; + else + { zeFileName=baseName; zeFileName+=EXT; } + // + std::ofstream ofs(fileName.c_str()); + ofs << "\n"; + const MEDCouplingCartesianAMRMesh *gf(getMyGodFather()); + ofs << " getImageMesh()); + std::vector orig(gfm->getOrigin()); + std::vector spacing(gfm->getDXYZ()); + int dim((int)orig.size()); + std::copy(orig.begin(),orig.end(),std::ostream_iterator(ofs," ")); ofs << "\" grid_description=\""; + for(int i=0;i\n"; + // + int maxLev(gf->getMaxNumberOfLevelsRelativeToThis()),kk(0); + for(int i=0;i patches(gf->retrieveGridsAt(i)); + std::size_t sz(patches.size()); + std::vector< MEDCouplingAutoRefCountObjectPtr > patchesSafe(sz); + for(std::size_t j=0;j(ofs," ")); + ofs << "\">\n"; + if(i!=maxLev-1) + { + std::vector factors(patches[0]->getMesh()->getFactors()); + for(int k=0;k::const_iterator it=patches.begin();it!=patches.end();it++,jj++,kk++) + { + ofs << " (*it)); + const MEDCouplingCartesianAMRMeshGen *mesh((*it)->getMesh()); + if(patchCast) + { + const std::vector< std::pair >& bltr(patchCast->getBLTRRangeRelativeToGF()); + for(int pp=0;ppgetMesh()->getImageMesh()); + std::vector cgs(im->getCellGridStructure()); + for(int pp=0;pppresenceOf((*it)->getMesh(),tmp)) + { + const DataArrayDoubleCollection& ddc(_levs[i]->getFieldsAt(tmp)); + std::vector arrs(ddc.retrieveFields()); + std::size_t nbFields(arrs.size()); + std::vector< MEDCouplingAutoRefCountObjectPtr > arrsSafe(nbFields),arrs2Safe(nbFields); + std::vector< const MEDCouplingFieldDouble *> fields(nbFields); + std::vector< MEDCouplingAutoRefCountObjectPtr > fieldsSafe(nbFields); + for(std::size_t pp=0;pp im(mesh->getImageMesh()->buildWithGhost(_ghost_lev)); + std::vector cgs(mesh->getImageMesh()->getCellGridStructure()),cgsWG(im->getCellGridStructure()); + arrs2Safe[pp]=DataArrayDouble::New(); + arrs2Safe[pp]->alloc(mesh->getImageMesh()->getNumberOfCells(),arrs[pp]->getNumberOfComponents()); + std::vector< std::pair > cgs2(MEDCouplingStructuredMesh::GetCompactFrmtFromDimensions(cgs)); + MEDCouplingStructuredMesh::ApplyGhostOnCompactFrmt(cgs2,_ghost_lev); + std::vector fakeFactors(mesh->getImageMesh()->getSpaceDimension(),1); + MEDCouplingIMesh::SpreadCoarseToFine(arrs[pp],cgsWG,arrs2Safe[pp],cgs2,fakeFactors); + arrs2Safe[pp]->copyStringInfoFrom(*arrs[pp]); + // + fieldsSafe[pp]=MEDCouplingFieldDouble::New(ON_CELLS); fields[pp]=fieldsSafe[pp]; + fieldsSafe[pp]->setMesh(mesh->getImageMesh()); + fieldsSafe[pp]->setArray(arrs2Safe[pp]); + fieldsSafe[pp]->setName(arrs[pp]->getName()); + } + std::ostringstream vtiFileName; vtiFileName << baseName << "_" << kk << ".vti"; + MEDCouplingFieldDouble::WriteVTK(vtiFileName.str(),fields,true); + // + ofs << vtiFileName.str() << "\">\n"; + ofs << " \n \n"; + } + } + ofs << " \n"; + } + // + ofs << " \n"; + ofs << "\n"; + return zeFileName; +} + + /*! + * This method is useful just after a remesh after a time step computation to project values in \a this to the new + * mesh \a targetGF. + * + * This method performs a projection from \a this to a target AMR mesh \a targetGF. + * This method performs the projection by trying to transfer the finest information to \a targetGF. + * \b WARNING this method does not update the ghost zone, if any. + * The level0 of \a this god father must have the same structure than those of \a targetGF. + * + * This method makes checks that ghost size of \a this and \a targetGF are the same, and that + * the number of levels in \a this and in \a targetGF are also the same. + */ +MEDCouplingAMRAttribute *MEDCouplingAMRAttribute::projectTo(MEDCouplingCartesianAMRMesh *targetGF) const +{ + if(!targetGF) + throw INTERP_KERNEL::Exception("MEDCouplingAMRAttribute::projectTo : given other target god is NULL !"); + if(_levs.empty()) + throw INTERP_KERNEL::Exception("MEDCouplingAMRAttribute::projectTo : no levels in this !"); + const MEDCouplingGridCollection *lev0(_levs[0]); + if(!lev0) + throw INTERP_KERNEL::Exception("MEDCouplingAMRAttribute::projectTo : lev0 is NULL !"); + std::vector< std::pair < std::string, std::vector > > fieldNames(lev0->getInfoOnComponents()); + MEDCouplingAutoRefCountObjectPtr ret(MEDCouplingAMRAttribute::New(targetGF,fieldNames,_ghost_lev)); + ret->spillNatures(lev0->getNatures()); + ret->alloc(); + int nbLevs(getNumberOfLevels()); + if(targetGF->getMaxNumberOfLevelsRelativeToThis()!=nbLevs) + throw INTERP_KERNEL::Exception("MEDCouplingAMRAttribute::projectTo : number of levels of this and targetGF must be the same !"); + // first step copy level0 + if(getMyGodFather()->getImageMesh()->getCellGridStructure()!=targetGF->getImageMesh()->getCellGridStructure()) + throw INTERP_KERNEL::Exception("MEDCouplingAMRAttribute::projectTo : god father of this and target ones do not have the same structure !"); + const DataArrayDoubleCollection& col(lev0->getFieldsAt(0)); + DataArrayDoubleCollection& colTarget(ret->_levs[0]->getFieldsAt(0)); + colTarget.copyFrom(col); + // then go deeper and deeper + for(int i=1;isynchronizeCoarseToFineByOneLevel(i-1); + MEDCouplingGridCollection *targetCol(ret->_levs[i]); + if(!targetCol) + throw INTERP_KERNEL::Exception("MEDCouplingAMRAttribute::projectTo : null lev of target !"); + const MEDCouplingGridCollection *thisCol(_levs[i]); + if(!thisCol) + throw INTERP_KERNEL::Exception("MEDCouplingAMRAttribute::projectTo : null lev of this !"); + targetCol->copyOverlappedZoneFrom(_ghost_lev,*thisCol); + } + return ret.retn(); +} + +/*! + * This method synchronizes from fine to coarse direction arrays. This method makes the hypothesis that \a this has been allocated before using + * MEDCouplingAMRAttribute::alloc method. + * This method \b DOES \b NOT \b UPDATE the ghost zones (neither the fine not the coarse) + * + * \sa synchronizeFineToCoarseBetween + */ +void MEDCouplingAMRAttribute::synchronizeFineToCoarse() +{ + if(_levs.empty()) + throw INTERP_KERNEL::Exception("MEDCouplingAMRAttribute::synchronizeFineToCoarse : not any levels in this !"); + std::size_t sz(_levs.size()); + // + while(sz>1) + { + sz--; + synchronizeFineToCoarseByOneLevel((int)sz); + } +} + +/*! + * This method allows to synchronizes fields on fine patches on level \a fromLev to coarser patches at \a toLev level. + * This method operates step by step performing the synchronization the \a fromLev to \a fromLev - 1, then \a fromLev -1 to \a fromLev - 2 ... + * until reaching \a toLev level. + * This method \b DOES \b NOT \b UPDATE the ghost zones (neither the fine not the coarse). + * + * \param [in] fromLev - an existing level considered as fine so bigger than \a toLev + * \param [in] toLev - an existing level considered as the target level to reach. + * + */ +void MEDCouplingAMRAttribute::synchronizeFineToCoarseBetween(int fromLev, int toLev) +{ + int nbl(getNumberOfLevels()); + if(fromLev<0 || toLev<0 || fromLev>=nbl || toLev>=nbl) + throw INTERP_KERNEL::Exception("MEDCouplingAMRAttribute::synchronizeFineToCoarseBetween : fromLev and toLev must be >= 0 and lower than number of levels in this !"); + if(fromLev==toLev) + return ;//nothing to do + if(fromLevtoLev;i--) + synchronizeFineToCoarseByOneLevel(i); +} + +/*! + * This method synchronizes from coarse to fine arrays and fine to fine each other (if _ghost_lev is >0). This method makes the hypothesis that \a this has been allocated before using + * MEDCouplingAMRAttribute::alloc method. + * This method \b DOES \b UPDATE \b the \b ghost \b zone (contrary to synchronizeFineToCoarse method) + */ +void MEDCouplingAMRAttribute::synchronizeCoarseToFine() +{ + if(_levs.empty()) + throw INTERP_KERNEL::Exception("MEDCouplingAMRAttribute::synchronizeCoarseToFine : not any levels in this !"); + std::size_t sz(_levs.size()); + // + for(std::size_t i=0;i=nbl || toLev>=nbl) + throw INTERP_KERNEL::Exception("MEDCouplingAMRAttribute::synchronizeCoarseToFineBetween : fromLev and toLev must be >= 0 and lower than number of levels in this !"); + if(fromLev==toLev) + return ;//nothing to do + if(fromLev>toLev) + throw INTERP_KERNEL::Exception("MEDCouplingAMRAttribute::synchronizeCoarseToFineBetween : the fromLev level is greater than toLev level ! Call synchronizeFineToCoarseBetween instead !"); + for(int i=fromLev;isynchronizeFineEachOther(_ghost_lev,_neighbors[i]); + } + // 3rd - mixed level + for(std::vector< std::pair >::const_iterator it=_mixed_lev_neighbors.begin();it!=_mixed_lev_neighbors.end();it++) + { + const DataArrayDoubleCollection *firstDAC(&findCollectionAttachedTo((*it).first->getMesh())),*secondDAC(&findCollectionAttachedTo((*it).second->getMesh())); + DataArrayDoubleCollection::SynchronizeGhostZoneOfOneUsingTwo(_ghost_lev,(*it).first,firstDAC,(*it).second,secondDAC); + } + // 4th - same level but with far ancestor. + for(int i=1;isynchronizeFineEachOtherExt(_ghost_lev,_cross_lev_neighbors[i]); + } +} + +/*! + * This method works \b ONLY \b ON \b DIRECT \b SONS \b OF \a mesh. So only a part of patches at a given level is updated here. + * The ghost zone of all of these sons of \a mesh are updated using the brother patches (the patches sharing the \b SAME \a mesh). + * It is sometimes possible that a ghost zone of some sons of \a mesh are covered by a patch of same level but different father. + * For such cases, the ghost zones are \b NOT updated. If you need a more thorough (but more costly) ghost zone update use synchronizeAllGhostZonesAtASpecifiedLevel method instead. + * + * \param [in] mesh - an element in the progeny of god father in \a this, which the ghost zone of its sons will be updated each other. + * + */ +void MEDCouplingAMRAttribute::synchronizeAllGhostZonesOfDirectChidrenOf(const MEDCouplingCartesianAMRMeshGen *mesh) +{ + if(!mesh) + throw INTERP_KERNEL::Exception("MEDCouplingAMRAttribute::synchronizeAllGhostZonesOfDirectChidrenOf : input mesh is NULL !"); + int level(mesh->getAbsoluteLevelRelativeTo(_gf)),sz(getNumberOfLevels()); + if(level<0 || level>=sz-1) + throw INTERP_KERNEL::Exception("MEDCouplingAMRAttribute::synchronizeAllGhostZonesOfDirectChidrenOf : the specified level does not exist ! Must be in [0,nbOfLevelsOfThis-1) !"); + const std::vector< std::pair >& itemsToFilter(_neighbors[level+1]); + std::vector< std::pair > itemsToSync; itemsToSync.reserve(itemsToFilter.size()); + for(std::vector< std::pair >::const_iterator it=itemsToFilter.begin();it!=itemsToFilter.end();it++) + { + if((*it).first->getMesh()->getFather()==mesh && (*it).second->getMesh()->getFather()==mesh) + itemsToSync.push_back(std::pair((*it).first,(*it).second)); + } + const MEDCouplingGridCollection *curLev(_levs[level+1]); + if(!curLev) + throw INTERP_KERNEL::Exception("MEDCouplingAMRAttribute::synchronizeAllGhostZonesOfDirectChidrenOf : presence of a NULL element !"); + curLev->synchronizeFineEachOther(_ghost_lev,itemsToSync); +} + +/*! + * This method updates \b all the patches at level \a level each other without consideration of their father. + * So this method is more time consuming than synchronizeAllGhostZonesOfDirectChidrenOf. + */ +void MEDCouplingAMRAttribute::synchronizeAllGhostZonesAtASpecifiedLevel(int level) +{ + int maxLev(getNumberOfLevels()); + if(level<0 || level>=maxLev) + throw INTERP_KERNEL::Exception("MEDCouplingAMRAttribute::synchronizeAllGhostZonesAtASpecifiedLevel : the specified level must be in [0,maxLevel) !"); + if(level==0) + return ;//at level 0 only one patch -> no need to update + // 1st step - updates all patches pairs at level \a level sharing the same father + const std::vector< std::pair >& items(_neighbors[level]); + const MEDCouplingGridCollection *curLev(_levs[level]); + if(!curLev) + throw INTERP_KERNEL::Exception("MEDCouplingAMRAttribute::synchronizeAllGhostZonesAtASpecifiedLevel : presence of a NULL element !"); + curLev->synchronizeFineEachOther(_ghost_lev,items); + //2nd step - updates all patches pairs at level \a level not sharing the same father + const std::vector< std::pair >& items2(_cross_lev_neighbors[level]); + curLev->synchronizeFineEachOtherExt(_ghost_lev,items2); +} + +/*! + * This method updates ghost zones of patches at level \a level whatever their father \b using \b father \b patches \b ONLY (at level \b level - 1). + * This method is useful to propagate to the ghost zone of childhood the modification. + */ +void MEDCouplingAMRAttribute::synchronizeAllGhostZonesAtASpecifiedLevelUsingOnlyFather(int level) +{ + int maxLev(getNumberOfLevels()); + if(level<=0 || level>=maxLev) + throw INTERP_KERNEL::Exception("MEDCouplingAMRAttribute::synchronizeAllGhostZonesAtASpecifiedLevelUsingOnlyFather : the specified level must be in (0,maxLevel) !"); + const MEDCouplingGridCollection *fine(_levs[level]),*coarse(_levs[level-1]); + MEDCouplingGridCollection::SynchronizeCoarseToFineOnlyInGhostZone(_ghost_lev,coarse,fine); + //_cross_lev_neighbors is not needed. +} + +/*! + * This method allocates all DataArrayDouble instances stored recursively in \a this. + * + * \sa dealloc + */ +void MEDCouplingAMRAttribute::alloc() +{ + _tlc.resetState(); + for(std::vector< MEDCouplingAutoRefCountObjectPtr >::iterator it=_levs.begin();it!=_levs.end();it++) + { + MEDCouplingGridCollection *elt(*it); + if(elt) + elt->alloc(_ghost_lev); + else + throw INTERP_KERNEL::Exception("MEDCouplingAMRAttribute::alloc : internal error !"); + } +} + +/*! + * This method deallocates all DataArrayDouble instances stored recursively in \a this. + * \sa alloc + */ +void MEDCouplingAMRAttribute::dealloc() +{ + _tlc.checkConst(); + for(std::vector< MEDCouplingAutoRefCountObjectPtr >::iterator it=_levs.begin();it!=_levs.end();it++) + { + MEDCouplingGridCollection *elt(*it); + if(elt) + elt->dealloc(); + else + throw INTERP_KERNEL::Exception("MEDCouplingAMRAttribute::dealloc : internal error !"); + } +} + +bool MEDCouplingAMRAttribute::changeGodFather(MEDCouplingCartesianAMRMesh *gf) +{ + bool ret(MEDCouplingDataForGodFather::changeGodFather(gf)); + return ret; +} + +std::size_t MEDCouplingAMRAttribute::getHeapMemorySizeWithoutChildren() const +{ + std::size_t ret(sizeof(MEDCouplingAMRAttribute)); + ret+=_levs.capacity()*sizeof(MEDCouplingAutoRefCountObjectPtr); + return ret; +} + +std::vector MEDCouplingAMRAttribute::getDirectChildrenWithNull() const +{ + std::vector ret; + for(std::vector< MEDCouplingAutoRefCountObjectPtr >::const_iterator it=_levs.begin();it!=_levs.end();it++) + ret.push_back((const MEDCouplingGridCollection *)*it); + return ret; +} + +void MEDCouplingAMRAttribute::updateTime() const +{//tony +} + +MEDCouplingAMRAttribute::MEDCouplingAMRAttribute(MEDCouplingCartesianAMRMesh *gf, const std::vector< std::pair >& fieldNames, int ghostLev):MEDCouplingDataForGodFather(gf),_ghost_lev(ghostLev) +{ + //gf non empty, checked by constructor + int maxLev(gf->getMaxNumberOfLevelsRelativeToThis()); + _levs.resize(maxLev); + for(int i=0;i patches(gf->retrieveGridsAt(i)); + std::size_t sz(patches.size()); + std::vector< MEDCouplingAutoRefCountObjectPtr > patchesSafe(patches.size()); + for(std::size_t j=0;j ms(sz); + for(std::size_t j=0;jgetMesh(); + } + _levs[i]=MEDCouplingGridCollection::New(ms,fieldNames); + } + // updates cross levels neighbors + _neighbors.resize(_levs.size()); + _cross_lev_neighbors.resize(_levs.size()); + if(_levs.empty()) + throw INTERP_KERNEL::Exception("constructor of MEDCouplingAMRAttribute : not any levels in this !"); + std::size_t sz(_levs.size()); + for(std::size_t i=1;ifindNeighbors(_ghost_lev); + if(i!=sz-1) + { + for(std::vector< std::pair >::const_iterator it=_neighbors[i].begin();it!=_neighbors[i].end();it++) + { + MEDCouplingCartesianAMRPatch::FindNeighborsOfSubPatchesOf(_ghost_lev,(*it).first,(*it).second,_mixed_lev_neighbors); + std::vector< std::vector < std::pair > > neighs2(MEDCouplingCartesianAMRPatch::FindNeighborsOfSubPatchesOfSameLev(_ghost_lev,(*it).first,(*it).second)); + std::size_t fullLev(i+neighs2.size()); + if(fullLev>=sz) + throw INTERP_KERNEL::Exception("constructor of MEDCouplingAMRAttribute : internal error ! something is wrong in computation of cross level neighbors !"); + std::size_t ii(i+1); + for(std::vector< std::vector< std::pair > >::const_iterator it0=neighs2.begin();it0!=neighs2.end();it0++,ii++) + _cross_lev_neighbors[ii].insert(_cross_lev_neighbors[ii].end(),(*it0).begin(),(*it0).end()); + } + } + } +} + +MEDCouplingAMRAttribute::MEDCouplingAMRAttribute(const MEDCouplingAMRAttribute& other, bool deepCpyGF):MEDCouplingDataForGodFather(other,deepCpyGF),_ghost_lev(other._ghost_lev),_levs(other._levs.size()),_neighbors(other._neighbors),_mixed_lev_neighbors(other._mixed_lev_neighbors),_cross_lev_neighbors(other._cross_lev_neighbors) +{ + std::size_t sz(other._levs.size()); + for(std::size_t i=0;ideepCpy(_gf,other._gf); + } + } + //_cross_lev_neighbors(other._cross_lev_neighbors) + sz=other._neighbors.size(); + for(std::size_t i=0;i >& neigh2(other._neighbors[i]); + std::size_t sz2(neigh2.size()); + std::vector< std::pair >& neigh3(_neighbors[i]); + for(std::size_t j=0;j pp1(p1->getMesh()->getPositionRelativeTo(other._gf)),pp2(p2->getMesh()->getPositionRelativeTo(other._gf)); + neigh3[j].first=_gf->getPatchAtPosition(pp1); + neigh3[j].second=_gf->getPatchAtPosition(pp2); + } + } + // + sz=other._mixed_lev_neighbors.size(); + for(std::size_t i=0;i pp1(p1->getMesh()->getPositionRelativeTo(other._gf)),pp2(p2->getMesh()->getPositionRelativeTo(other._gf)); + _mixed_lev_neighbors[i].first=_gf->getPatchAtPosition(pp1); + _mixed_lev_neighbors[i].second=_gf->getPatchAtPosition(pp2); + } + // + sz=other._cross_lev_neighbors.size(); + for(std::size_t i=0;i >& neigh2(other._cross_lev_neighbors[i]); + std::size_t sz2(neigh2.size()); + std::vector< std::pair >& neigh3(_cross_lev_neighbors[i]); + for(std::size_t j=0;j pp1(p1->getMesh()->getPositionRelativeTo(other._gf)),pp2(p2->getMesh()->getPositionRelativeTo(other._gf)); + neigh3[j].first=_gf->getPatchAtPosition(pp1); + neigh3[j].second=_gf->getPatchAtPosition(pp2); + } + } +} + +const DataArrayDoubleCollection& MEDCouplingAMRAttribute::findCollectionAttachedTo(const MEDCouplingCartesianAMRMeshGen *m) const +{ + for(std::vector< MEDCouplingAutoRefCountObjectPtr >::const_iterator it=_levs.begin();it!=_levs.end();it++) + { + const MEDCouplingGridCollection *elt(*it); + if(elt) + { + int tmp(-1); + if(elt->presenceOf(m,tmp)) + { + return elt->getFieldsAt(tmp); + } + } + } + throw INTERP_KERNEL::Exception("MEDCouplingAMRAttribute::findCollectionAttachedTo : unable to find such part of mesh in this !"); +} + +void MEDCouplingAMRAttribute::synchronizeFineToCoarseByOneLevel(int level) +{ + int nbl(getNumberOfLevels()); + if(level<=0 || level>=nbl) + throw INTERP_KERNEL::Exception("MEDCouplingAMRAttribute::synchronizeFineToCoarseByOneLevel : the input level must be in ]0,nb_of_levels[ !"); + const MEDCouplingGridCollection *fine(_levs[level]),*coarse(_levs[level-1]); + MEDCouplingGridCollection::SynchronizeFineToCoarse(_ghost_lev,fine,coarse); +} + +void MEDCouplingAMRAttribute::synchronizeCoarseToFineByOneLevel(int level) +{ + int nbl(getNumberOfLevels()); + if(level<0 || level>=nbl-1) + throw INTERP_KERNEL::Exception("MEDCouplingAMRAttribute::synchronizeFineToCoarseByOneLevel : the input level must be in [0,nb_of_levels[ !"); + const MEDCouplingGridCollection *fine(_levs[level+1]),*coarse(_levs[level]); + MEDCouplingGridCollection::SynchronizeCoarseToFine(_ghost_lev,coarse,fine); +} diff --cc medtool/src/MEDCoupling/MEDCouplingFieldTemplate.hxx index 8b3a3c8dd,000000000..6fa402cf6 mode 100644,000000..100644 --- a/medtool/src/MEDCoupling/MEDCouplingFieldTemplate.hxx +++ b/medtool/src/MEDCoupling/MEDCouplingFieldTemplate.hxx @@@ -1,59 -1,0 +1,62 @@@ +// Copyright (C) 2007-2015 CEA/DEN, EDF R&D +// +// 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +// +// See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com +// +// Author : Anthony Geay (CEA/DEN) + +#ifndef __PARAMEDMEM_MEDCOUPLINGFIELDTEMPLATE_HXX__ +#define __PARAMEDMEM_MEDCOUPLINGFIELDTEMPLATE_HXX__ + +#include "MEDCouplingField.hxx" + +namespace ParaMEDMEM +{ + class MEDCouplingFieldDouble; + /*! - * \brief A field template can be seen as a field without array of values. ++ * \brief A field template can be seen as a field without the array of values. + * - * A field template instance aggregates a MEDCouplingMesh instance and a spatial discretization object (instance of MEDCouplingFieldDiscretization). ++ * A field template aggregates a MEDCouplingMesh and a spatial discretization object (instance of ++ * MEDCouplingFieldDiscretization). + * - * Instances of type MEDCouplingFieldTemplate are the most appropriate for preparation of matrix using MEDCouplingRemapper::prepareEx. ++ * MEDCouplingFieldTemplate is the most appropriate type for the preparation of matrix using ++ * MEDCouplingRemapper::prepareEx, since it contains the minimal information requireds to prepare ++ * the interpolation matrix. + */ + class MEDCouplingFieldTemplate : public MEDCouplingField + { + public: + MEDCOUPLING_EXPORT static MEDCouplingFieldTemplate *New(const MEDCouplingFieldDouble& f); + MEDCOUPLING_EXPORT static MEDCouplingFieldTemplate *New(TypeOfField type); + MEDCOUPLING_EXPORT std::string simpleRepr() const; + MEDCOUPLING_EXPORT std::string advancedRepr() const; + MEDCOUPLING_EXPORT void checkCoherency() const; + // + MEDCOUPLING_EXPORT void getTinySerializationIntInformation(std::vector& tinyInfo) const; + MEDCOUPLING_EXPORT void getTinySerializationDbleInformation(std::vector& tinyInfo) const; + MEDCOUPLING_EXPORT void getTinySerializationStrInformation(std::vector& tinyInfo) const; + MEDCOUPLING_EXPORT void resizeForUnserialization(const std::vector& tinyInfoI, DataArrayInt *&dataInt); + MEDCOUPLING_EXPORT void finishUnserialization(const std::vector& tinyInfoI, const std::vector& tinyInfoD, const std::vector& tinyInfoS); + MEDCOUPLING_EXPORT void serialize(DataArrayInt *&dataInt) const; + // + MEDCOUPLING_EXPORT void reprQuickOverview(std::ostream& stream) const; + private: + MEDCouplingFieldTemplate(const MEDCouplingFieldDouble& f); + MEDCouplingFieldTemplate(TypeOfField type); + }; +} + +#endif diff --cc medtool/src/MEDCoupling/MEDCouplingMesh.cxx index ea60f27de,000000000..3de265f1f mode 100644,000000..100644 --- a/medtool/src/MEDCoupling/MEDCouplingMesh.cxx +++ b/medtool/src/MEDCoupling/MEDCouplingMesh.cxx @@@ -1,760 -1,0 +1,762 @@@ +// Copyright (C) 2007-2015 CEA/DEN, EDF R&D +// +// 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +// +// See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com +// +// Author : Anthony Geay (CEA/DEN) + +#include "MEDCouplingMesh.hxx" +#include "MEDCouplingUMesh.hxx" +#include "MEDCouplingMemArray.hxx" +#include "MEDCouplingFieldDouble.hxx" +#include "MEDCouplingFieldDiscretization.hxx" +#include "MEDCouplingAutoRefCountObjectPtr.hxx" + +#include +#include +#include +#include +#include + +using namespace ParaMEDMEM; + +MEDCouplingMesh::MEDCouplingMesh():_time(0.),_iteration(-1),_order(-1) +{ +} + +MEDCouplingMesh::MEDCouplingMesh(const MEDCouplingMesh& other):RefCountObject(other),_name(other._name),_description(other._description), + _time(other._time),_iteration(other._iteration), + _order(other._order),_time_unit(other._time_unit) +{ +} + +std::size_t MEDCouplingMesh::getHeapMemorySizeWithoutChildren() const +{ + return _name.capacity()+_description.capacity()+_time_unit.capacity(); +} + +/*! + * This method is only for ParaMEDMEM in ParaFIELD constructor. + */ +bool MEDCouplingMesh::isStructured() const +{ + return getType()==CARTESIAN; +} + +bool MEDCouplingMesh::isEqualIfNotWhy(const MEDCouplingMesh *other, double prec, std::string& reason) const +{ + if(!other) + throw INTERP_KERNEL::Exception("MEDCouplingMesh::isEqualIfNotWhy : other instance is NULL !"); + std::ostringstream oss; oss.precision(15); + if(_name!=other->_name) + { + oss << "Mesh names differ : this name = \"" << _name << "\" and other name = \"" << other->_name << "\" !"; + reason=oss.str(); + return false; + } + if(_description!=other->_description) + { + oss << "Mesh descriptions differ : this description = \"" << _description << "\" and other description = \"" << other->_description << "\" !"; + reason=oss.str(); + return false; + } + if(_iteration!=other->_iteration) + { + oss << "Mesh iterations differ : this iteration = \"" << _iteration << "\" and other iteration = \"" << other->_iteration << "\" !"; + reason=oss.str(); + return false; + } + if(_order!=other->_order) + { + oss << "Mesh orders differ : this order = \"" << _order << "\" and other order = \"" << other->_order << "\" !"; + reason=oss.str(); + return false; + } + if(_time_unit!=other->_time_unit) + { + oss << "Mesh time units differ : this time unit = \"" << _time_unit << "\" and other time unit = \"" << other->_time_unit << "\" !"; + reason=oss.str(); + return false; + } + if(fabs(_time-other->_time)>=1e-12) + { + oss << "Mesh times differ : this time = \"" << _time << "\" and other time = \"" << other->_time << "\" !"; + reason=oss.str(); + return false; + } + return true; +} + +/*! + * Checks if \a this and another MEDCouplingMesh are fully equal. + * \param [in] other - an instance of MEDCouplingMesh to compare with \a this one. + * \param [in] prec - precision value used to compare node coordinates. + * \return bool - \c true if the two meshes are equal, \c false else. + */ +bool MEDCouplingMesh::isEqual(const MEDCouplingMesh *other, double prec) const +{ + std::string tmp; + return isEqualIfNotWhy(other,prec,tmp); +} + +/*! + * This method checks geo equivalence between two meshes : \a this and \a other. + * If no exception is thrown \a this and \a other are geometrically equivalent regarding \a levOfCheck level. + * This method is typically used to change the mesh of a field "safely" depending the \a levOfCheck level considered. + * + * In case of success cell \c other[i] is equal to the cell \c this[cellCor[i]]. + * In case of success node \c other->getCoords()[i] is equal to the node \c this->getCoords()[nodeCor[i]]. + * + * If \a cellCor is null (or Py_None) it means that for all #i cell in \a other is equal to cell # i in \a this. + * + * If \a nodeCor is null (or Py_None) it means that for all #i node in \a other is equal to node # i in \a this. + * + * So null (or Py_None) returned in \a cellCor and/or \a nodeCor means identity array. This is for optimization reason to avoid to build useless arrays + * for some \a levOfCheck (for example 0). + * + * **Warning a not null output does not mean that it is not identity !** + * + * \param [in] other - the mesh to be compared with \a this. + * \param [in] levOfCheck - input that specifies the level of check specified. The possible values are listed below. + * \param [in] prec - input that specifies precision for double float data used for comparison in meshes. + * \param [out] cellCor - output array not always informed (depending \a levOfCheck param) that gives the corresponding array for cells from \a other to \a this. + * \param [out] nodeCor - output array not always informed (depending \a levOfCheck param) that gives the corresponding array for nodes from \a other to \a this. + * + * Possible values for levOfCheck : + * - 0 for strict equality. This is the strongest level. \a cellCor and \a nodeCor params are never informed. + * - 10,11,12 (10+x) for less strict equality. Two meshes are compared geometrically. In case of success \a cellCor and \a nodeCor are informed. Warning ! These equivalences are CPU/Mem costly. The 3 values correspond respectively to policy used for cell comparison (see MEDCouplingUMesh::zipConnectivityTraducer to have more details) + * - 20,21,22 (20+x), for less strict equality. Two meshes are compared geometrically. The difference with the previous version is that nodes(coordinates) are expected to be the same between this and other. In case of success \a cellCor is informed. Warning ! These equivalences are CPU/Mem costly. The 3 values correspond respectively to policy used for cell comparison (see MEDCouplingUMesh::zipConnectivityTraducer to have more details) + * - 1 for fast 'equality'. This is a lazy level. Just number of cells and number of nodes are considered here and 3 cells (begin,middle,end) + * - 2 for deep 'equality' as 0 option except that no control is done on all strings in mesh. + * + * So the most strict level of check is 0 (equality). The least strict is 12. If the level of check 12 throws, the 2 meshes \a this and \a other are not similar enough + * to be compared. An interpolation using MEDCouplingRemapper class should be then used. + */ +void MEDCouplingMesh::checkGeoEquivalWith(const MEDCouplingMesh *other, int levOfCheck, double prec, + DataArrayInt *&cellCor, DataArrayInt *&nodeCor) const +{ + cellCor=0; + nodeCor=0; + if(this==other) + return ; + switch(levOfCheck) + { + case 0: + { + if(!isEqual(other,prec)) + throw INTERP_KERNEL::Exception("checkGeoFitWith : Meshes are not equal !"); + return ; + } + case 10: + case 11: + case 12: + { + checkDeepEquivalWith(other,levOfCheck-10,prec,cellCor,nodeCor); + return ; + } + case 20: + case 21: + case 22: + { + checkDeepEquivalOnSameNodesWith(other,levOfCheck-20,prec,cellCor); + return ; + } + case 1: + { + checkFastEquivalWith(other,prec); + return; + } + case 2: + { + if(!isEqualWithoutConsideringStr(other,prec)) + throw INTERP_KERNEL::Exception("checkGeoFitWith : Meshes are not equal without considering strings !"); + return ; + } + default: + throw INTERP_KERNEL::Exception("checkGeoFitWith : Invalid levOfCheck specified ! Value must be in 0,1,2,10,11 or 12."); + } +} + +/*! + * Finds cells whose all nodes are in a given array of node ids. + * \param [in] partBg - the array of node ids. + * \param [in] partEnd - end of \a partBg, i.e. a pointer to a (last+1)-th element + * of \a partBg. + * \return DataArrayInt * - a new instance of DataArrayInt holding ids of found + * cells. The caller is to delete this array using decrRef() as it is no + * more needed. + */ +DataArrayInt *MEDCouplingMesh::getCellIdsFullyIncludedInNodeIds(const int *partBg, const int *partEnd) const +{ + std::vector crest; + std::set p(partBg,partEnd); + int nbOfCells=getNumberOfCells(); + for(int i=0;i conn; + getNodeIdsOfCell(i,conn); + bool cont=true; + for(std::vector::const_iterator iter=conn.begin();iter!=conn.end() && cont;iter++) + if(p.find(*iter)==p.end()) + cont=false; + if(cont) + crest.push_back(i); + } + DataArrayInt *ret=DataArrayInt::New(); + ret->alloc((int)crest.size(),1); + std::copy(crest.begin(),crest.end(),ret->getPointer()); + return ret; +} + +/*! + * This method checks fastly that \a this and \a other are equal. All common checks are done here. + */ +void MEDCouplingMesh::checkFastEquivalWith(const MEDCouplingMesh *other, double prec) const +{ + if(!other) + throw INTERP_KERNEL::Exception("MEDCouplingMesh::checkFastEquivalWith : input mesh is null !"); + if(getMeshDimension()!=other->getMeshDimension()) + throw INTERP_KERNEL::Exception("checkFastEquivalWith : Mesh dimensions are not equal !"); + if(getSpaceDimension()!=other->getSpaceDimension()) + throw INTERP_KERNEL::Exception("checkFastEquivalWith : Space dimensions are not equal !"); + if(getNumberOfCells()!=other->getNumberOfCells()) + throw INTERP_KERNEL::Exception("checkFastEquivalWith : number of cells are not equal !"); +} + +/*! + * This method is very poor and looks only if \a this and \a other are candidate for merge of fields lying repectively on them. + */ +bool MEDCouplingMesh::areCompatibleForMerge(const MEDCouplingMesh *other) const +{ + if(!other) + throw INTERP_KERNEL::Exception("MEDCouplingMesh::areCompatibleForMerge : input mesh is null !"); + if(getMeshDimension()!=other->getMeshDimension()) + return false; + if(getSpaceDimension()!=other->getSpaceDimension()) + return false; + return true; +} + +/*! + * This method is equivalent to MEDCouplingMesh::buildPart method except that here the cell ids are specified using slice \a beginCellIds \a endCellIds and \a stepCellIds. + * \b WARNING , there is a big difference compared to MEDCouplingMesh::buildPart method. + * If the input range is equal all cells in \a this, \a this is returned ! + * + * \return a new ref to be managed by the caller. Warning this ref can be equal to \a this if input slice is exactly equal to the whole cells in the same order. + * + * \sa MEDCouplingMesh::buildPart + */ +MEDCouplingMesh *MEDCouplingMesh::buildPartRange(int beginCellIds, int endCellIds, int stepCellIds) const +{ + if(beginCellIds==0 && endCellIds==getNumberOfCells() && stepCellIds==1) + { + MEDCouplingMesh *ret(const_cast(this)); + ret->incrRef(); + return ret; + } + else + { + MEDCouplingAutoRefCountObjectPtr cellIds=DataArrayInt::Range(beginCellIds,endCellIds,stepCellIds); + return buildPart(cellIds->begin(),cellIds->end()); + } +} + +/*! + * This method is equivalent to MEDCouplingMesh::buildPartAndReduceNodes method except that here the cell ids are specified using slice \a beginCellIds \a endCellIds and \a stepCellIds. + * + * \sa MEDCouplingMesh::buildPartAndReduceNodes + */ +MEDCouplingMesh *MEDCouplingMesh::buildPartRangeAndReduceNodes(int beginCellIds, int endCellIds, int stepCellIds, int& beginOut, int& endOut, int& stepOut, DataArrayInt*& arr) const +{ + MEDCouplingAutoRefCountObjectPtr cellIds=DataArrayInt::Range(beginCellIds,endCellIds,stepCellIds); + return buildPartAndReduceNodes(cellIds->begin(),cellIds->end(),arr); +} + +/*! + * This method builds a field lying on \a this with 'nbOfComp' components. + * 'func' is a pointer that points to a function that takes 2 arrays in parameter and returns a boolean. + * The first array is a in-param of size this->getSpaceDimension and the second an out param of size 'nbOfComp'. + * The return field will have type specified by 't'. 't' is also used to determine where values of field will be + * evaluate. + * Contrary to other fillFromAnalytic methods this method requests a C++ function pointer as input. + * The 'func' is a callback that takes as first parameter an input array of size 'this->getSpaceDimension()', + * the second parameter is a pointer on a valid zone of size at least equal to 'nbOfComp' values. And too finish + * the returned value is a boolean that is equal to False in case of invalid evaluation (log(0) for example...) + * + * \param t type of field returned and specifies where the evaluation of func will be done. + * \param nbOfComp number of components of returned field. + * \param func pointer to a function that should return false if the evaluation failed. (division by 0. for example) + * \return field with counter = 1. + */ +MEDCouplingFieldDouble *MEDCouplingMesh::fillFromAnalytic(TypeOfField t, int nbOfComp, FunctionToEvaluate func) const +{ + MEDCouplingAutoRefCountObjectPtr ret=MEDCouplingFieldDouble::New(t,ONE_TIME); + ret->setMesh(this); + ret->fillFromAnalytic(nbOfComp,func); + ret->synchronizeTimeWithSupport(); + return ret.retn(); +} + +/*! + * This method copyies all tiny strings from other (name and components name). + * @throw if other and this have not same mesh type. + */ +void MEDCouplingMesh::copyTinyStringsFrom(const MEDCouplingMesh *other) +{ + if(!other) + throw INTERP_KERNEL::Exception("MEDCouplingMesh::copyTinyStringsFrom : input mesh is null !"); + _name=other->_name; + _description=other->_description; + _time_unit=other->_time_unit; +} + +/*! + * This method copies all attributes that are \b NOT arrays in this. + * All tiny attributes not usefully for state of \a this are ignored. + */ +void MEDCouplingMesh::copyTinyInfoFrom(const MEDCouplingMesh *other) +{ + _time=other->_time; + _iteration=other->_iteration; + _order=other->_order; + copyTinyStringsFrom(other); +} + +/*! + * \anchor mcmesh_fillFromAnalytic + * Creates a new MEDCouplingFieldDouble of a given type, one time, with given number of + * components, lying on \a this mesh, with contents got by applying a specified + * function to coordinates of field location points (defined by the given field type). + * For example, if \a t == ParaMEDMEM::ON_CELLS, the function is applied to cell + * barycenters.
+ * For more info on supported expressions that can be used in the function, see \ref + * MEDCouplingArrayApplyFuncExpr. The function can include arbitrary named variables + * (e.g. "x","y" or "va44") to refer to components of point coordinates. Names of + * variables are sorted in \b alphabetical \b order to associate a variable name with a + * component. For example, in the expression "2*x+z", "x" stands for the component #0 + * and "z" stands for the component #1 (\b not #2)!
+ * In a general case, a value resulting from the function evaluation is assigned to all + * components of the field. But there is a possibility to have its own expression for + * each component within one function. For this purpose, there are predefined variable + * names (IVec, JVec, KVec, LVec etc) each dedicated to a certain component (IVec, to + * the component #0 etc). A factor of such a variable is added to the + * corresponding component only.
+ * For example, \a nbOfComp == 4, \a this->getSpaceDimension() == 3, coordinates of a + * point are (1.,3.,7.), then + * - "2*x + z" produces (5.,5.,5.,5.) + * - "2*x + 0*y + z" produces (9.,9.,9.,9.) + * - "2*x*IVec + (x+z)*LVec" produces (2.,0.,0.,4.) + * - "2*y*IVec + z*KVec + x" produces (7.,1.,1.,4.) + * + * \param [in] t - the field type. It defines, apart from other things, points to + * coordinates of which the function is applied to get field values. + * \param [in] nbOfComp - the number of components in the result field. + * \param [in] func - a string defining the expression which is evaluated to get + * field values. + * \return MEDCouplingFieldDouble * - a new instance of MEDCouplingFieldDouble. The + * caller is to delete this field using decrRef() as it is no more needed. + * \throw If the nodal connectivity of cells is not defined. + * \throw If computing \a func fails. + * + * \if ENABLE_EXAMPLES + * \ref cpp_mcmesh_fillFromAnalytic "Here is a C++ example".
+ * \ref py_mcmesh_fillFromAnalytic "Here is a Python example". + * \endif + */ +MEDCouplingFieldDouble *MEDCouplingMesh::fillFromAnalytic(TypeOfField t, int nbOfComp, const std::string& func) const +{ + MEDCouplingAutoRefCountObjectPtr ret=MEDCouplingFieldDouble::New(t,ONE_TIME); + ret->setMesh(this); + ret->fillFromAnalytic(nbOfComp,func); + ret->synchronizeTimeWithSupport(); + return ret.retn(); +} + +/*! + * Creates a new MEDCouplingFieldDouble of a given type, one time, with given number of + * components, lying on \a this mesh, with contents got by applying a specified + * function to coordinates of field location points (defined by the given field type). + * For example, if \a t == ParaMEDMEM::ON_CELLS, the function is applied to cell + * barycenters. This method differs from + * \ref MEDCouplingMesh::fillFromAnalytic(TypeOfField t, int nbOfComp, const std::string& func) const "fillFromAnalytic()" + * by the way how variable + * names, used in the function, are associated with components of coordinates of field + * location points; here, a variable name corresponding to a component is retrieved from + * a corresponding node coordinates array (where it is set via + * DataArrayDouble::setInfoOnComponent()).
+ * For more info on supported expressions that can be used in the function, see \ref + * MEDCouplingArrayApplyFuncExpr.
+ * In a general case, a value resulting from the function evaluation is assigned to all + * components of a field value. But there is a possibility to have its own expression for + * each component within one function. For this purpose, there are predefined variable + * names (IVec, JVec, KVec, LVec etc) each dedicated to a certain component (IVec, to + * the component #0 etc). A factor of such a variable is added to the + * corresponding component only.
+ * For example, \a nbOfComp == 4, \a this->getSpaceDimension() == 3, names of + * spatial components are "x", "y" and "z", coordinates of a + * point are (1.,3.,7.), then + * - "2*x + z" produces (9.,9.,9.,9.) + * - "2*x*IVec + (x+z)*LVec" produces (2.,0.,0.,8.) + * - "2*y*IVec + z*KVec + x" produces (7.,1.,1.,8.) + * + * \param [in] t - the field type. It defines, apart from other things, the points to + * coordinates of which the function is applied to get field values. + * \param [in] nbOfComp - the number of components in the result field. + * \param [in] func - a string defining the expression which is evaluated to get + * field values. + * \return MEDCouplingFieldDouble * - a new instance of MEDCouplingFieldDouble. The + * caller is to delete this field using decrRef() as it is no more needed. + * \throw If the node coordinates are not defined. + * \throw If the nodal connectivity of cells is not defined. + * \throw If computing \a func fails. + * + * \if ENABLE_EXAMPLES + * \ref cpp_mcmesh_fillFromAnalytic2 "Here is a C++ example".
+ * \ref py_mcmesh_fillFromAnalytic2 "Here is a Python example". + * \endif + */ +MEDCouplingFieldDouble *MEDCouplingMesh::fillFromAnalytic2(TypeOfField t, int nbOfComp, const std::string& func) const +{ + MEDCouplingAutoRefCountObjectPtr ret=MEDCouplingFieldDouble::New(t,ONE_TIME); + ret->setMesh(this); + ret->fillFromAnalytic2(nbOfComp,func); + ret->synchronizeTimeWithSupport(); + return ret.retn(); +} + +/*! + * Creates a new MEDCouplingFieldDouble of a given type, one time, with given number of + * components, lying on \a this mesh, with contents got by applying a specified + * function to coordinates of field location points (defined by the given field type). + * For example, if \a t == ParaMEDMEM::ON_CELLS, the function is applied to cell + * barycenters. This method differs from \ref \ref mcmesh_fillFromAnalytic + * "fillFromAnalytic()" by the way how variable + * names, used in the function, are associated with components of coordinates of field + * location points; here, a component index of a variable is defined by a + * rank of the variable within the input array \a varsOrder.
+ * For more info on supported expressions that can be used in the function, see \ref + * MEDCouplingArrayApplyFuncExpr. + * In a general case, a value resulting from the function evaluation is assigned to all + * components of the field. But there is a possibility to have its own expression for + * each component within one function. For this purpose, there are predefined variable + * names (IVec, JVec, KVec, LVec etc) each dedicated to a certain component (IVec, to + * the component #0 etc). A factor of such a variable is added to the + * corresponding component only.
+ * For example, \a nbOfComp == 4, \a this->getSpaceDimension() == 3, names of + * spatial components are given in \a varsOrder: ["x", "y","z"], coordinates of a + * point are (1.,3.,7.), then + * - "2*x + z" produces (9.,9.,9.,9.) + * - "2*x*IVec + (x+z)*LVec" produces (2.,0.,0.,8.) + * - "2*y*IVec + z*KVec + x" produces (7.,1.,1.,8.) + * + * \param [in] t - the field type. It defines, apart from other things, the points to + * coordinates of which the function is applied to get field values. + * \param [in] nbOfComp - the number of components in the result field. + * \param [in] varsOrder - the vector defining names of variables used to refer to + * components of coordinates of field location points. A variable named + * varsOrder[0] refers to the component #0 etc. + * \param [in] func - a string defining the expression which is evaluated to get + * field values. + * \return MEDCouplingFieldDouble * - a new instance of MEDCouplingFieldDouble. The + * caller is to delete this field using decrRef() as it is no more needed. + * \throw If the node coordinates are not defined. + * \throw If the nodal connectivity of cells is not defined. + * \throw If computing \a func fails. + * + * \if ENABLE_EXAMPLES + * \ref cpp_mcmesh_fillFromAnalytic3 "Here is a C++ example".
+ * \ref py_mcmesh_fillFromAnalytic3 "Here is a Python example". + * \endif + */ +MEDCouplingFieldDouble *MEDCouplingMesh::fillFromAnalytic3(TypeOfField t, int nbOfComp, const std::vector& varsOrder, const std::string& func) const +{ + MEDCouplingAutoRefCountObjectPtr ret=MEDCouplingFieldDouble::New(t,ONE_TIME); + ret->setMesh(this); + ret->fillFromAnalytic3(nbOfComp,varsOrder,func); + ret->synchronizeTimeWithSupport(); + return ret.retn(); +} + +/*! + * Creates a new MEDCouplingMesh by concatenating two given meshes, if possible. + * Cells and nodes of + * the first mesh precede cells and nodes of the second mesh within the result mesh. + * The meshes must be of the same mesh type, else, an exception is thrown. The method + * MergeMeshes(), accepting a vector of input meshes, has no such a limitation. + * \param [in] mesh1 - the first mesh. + * \param [in] mesh2 - the second mesh. + * \return MEDCouplingMesh * - the result mesh. It is a new instance of + * MEDCouplingMesh. The caller is to delete this mesh using decrRef() as it + * is no more needed. + * \throw If the meshes are of different mesh type. + */ +MEDCouplingMesh *MEDCouplingMesh::MergeMeshes(const MEDCouplingMesh *mesh1, const MEDCouplingMesh *mesh2) +{ + if(!mesh1) + throw INTERP_KERNEL::Exception("MEDCouplingMesh::MergeMeshes : first parameter is an empty mesh !"); + if(!mesh2) + throw INTERP_KERNEL::Exception("MEDCouplingMesh::MergeMeshes : second parameter is an empty mesh !"); + return mesh1->mergeMyselfWith(mesh2); +} + +/*! + * Creates a new MEDCouplingMesh by concatenating all given meshes, if possible. + * Cells and nodes of + * the *i*-th mesh precede cells and nodes of the (*i*+1)-th mesh within the result mesh. + * This method performs a systematic conversion to unstructured meshes before + * performing aggregation contrary to the other MergeMeshes() + * with two parameters that works only on the same type of meshes. So here it is possible + * to mix different type of meshes. + * \param [in] meshes - a vector of meshes to concatenate. + * \return MEDCouplingMesh * - the result mesh. It is a new instance of + * MEDCouplingUMesh. The caller is to delete this mesh using decrRef() as it + * is no more needed. + * \throw If \a meshes.size() == 0. + * \throw If \a size[ *i* ] == NULL. + * \throw If the coordinates is not set in none of the meshes. + * \throw If \a meshes[ *i* ]->getMeshDimension() < 0. + * \throw If the \a meshes are of different dimension (getMeshDimension()). + */ +MEDCouplingMesh *MEDCouplingMesh::MergeMeshes(std::vector& meshes) +{ + std::vector< MEDCouplingAutoRefCountObjectPtr > ms1(meshes.size()); + std::vector< const MEDCouplingUMesh * > ms2(meshes.size()); + for(std::size_t i=0;ibuildUnstructured(); + ms1[i]=cur; ms2[i]=cur; + } + else + { + std::ostringstream oss; oss << "MEDCouplingMesh::MergeMeshes(std::vector& meshes) : mesh at pos #" << i << " of input vector of size " << meshes.size() << " is empty !"; + throw INTERP_KERNEL::Exception(oss.str().c_str()); + } + } + return MEDCouplingUMesh::MergeUMeshes(ms2); +} + +/*! + * For example if \a type is INTERP_KERNEL::NORM_TRI3 , INTERP_KERNEL::NORM_POLYGON is returned. + * If \a type is INTERP_KERNEL::NORM_HEXA8 , INTERP_KERNEL::NORM_POLYHED is returned. + * + * \param [in] type the geometric type for which the corresponding dynamic type, is asked. + * \return the corresponding dynamic type, able to store the input \a type. + * + * \throw if type is equal to \c INTERP_KERNEL::NORM_ERROR or to an unexisting geometric type. + */ +INTERP_KERNEL::NormalizedCellType MEDCouplingMesh::GetCorrespondingPolyType(INTERP_KERNEL::NormalizedCellType type) +{ + const INTERP_KERNEL::CellModel& cm=INTERP_KERNEL::CellModel::GetCellModel(type); + return cm.getCorrespondingPolyType(); +} + +/*! + * \param [in] type the geometric type for which the number of nodes consituting it, is asked. + * \return number of nodes consituting the input geometric type \a type. + * + * \throw if type is dynamic as \c INTERP_KERNEL::NORM_POLYHED , \c INTERP_KERNEL::NORM_POLYGON , \c INTERP_KERNEL::NORM_QPOLYG + * \throw if type is equal to \c INTERP_KERNEL::NORM_ERROR or to an unexisting geometric type. + */ +int MEDCouplingMesh::GetNumberOfNodesOfGeometricType(INTERP_KERNEL::NormalizedCellType type) +{ + const INTERP_KERNEL::CellModel& cm=INTERP_KERNEL::CellModel::GetCellModel(type); + if(cm.isDynamic()) + throw INTERP_KERNEL::Exception("MEDCouplingMesh::GetNumberOfNodesOfGeometricType : the input geometric type is dynamic ! Impossible to return a fixed number of nodes constituting it !"); + return (int) cm.getNumberOfNodes(); +} + +/*! + * \param [in] type the geometric type for which the status static/dynamic is asked. + * \return true for static geometric type, false for dynamic geometric type. + * + * \throw if type is equal to \c INTERP_KERNEL::NORM_ERROR or to an unexisting geometric type. + */ +bool MEDCouplingMesh::IsStaticGeometricType(INTERP_KERNEL::NormalizedCellType type) +{ + const INTERP_KERNEL::CellModel& cm=INTERP_KERNEL::CellModel::GetCellModel(type); + return !cm.isDynamic(); +} + +bool MEDCouplingMesh::IsLinearGeometricType(INTERP_KERNEL::NormalizedCellType type) +{ + const INTERP_KERNEL::CellModel& cm=INTERP_KERNEL::CellModel::GetCellModel(type); + return !cm.isQuadratic(); +} + +/*! + * \param [in] type the geometric type for which the dimension is asked. + * \return the dimension associated to the input geometric type \a type. + * + * \throw if type is equal to \c INTERP_KERNEL::NORM_ERROR or to an unexisting geometric type. + */ +int MEDCouplingMesh::GetDimensionOfGeometricType(INTERP_KERNEL::NormalizedCellType type) +{ + const INTERP_KERNEL::CellModel& cm=INTERP_KERNEL::CellModel::GetCellModel(type); + return (int) cm.getDimension(); +} + +/*! + * \param [in] type the geometric type for which the representation is asked. + * \return the string representation corresponding to the input geometric type \a type. + * + * \throw if type is equal to \c INTERP_KERNEL::NORM_ERROR or to an unexisting geometric type. + */ +const char *MEDCouplingMesh::GetReprOfGeometricType(INTERP_KERNEL::NormalizedCellType type) +{ + const INTERP_KERNEL::CellModel& cm=INTERP_KERNEL::CellModel::GetCellModel(type); + return cm.getRepr(); +} + +/*! + * Finds cells in contact with a ball (i.e. a point with precision). + * \warning This method is suitable if the caller intends to evaluate only one + * point, for more points getCellsContainingPoints() is recommended as it is + * faster. + * \param [in] pos - array of coordinates of the ball central point. + * \param [in] eps - ball radius. + * \param [in,out] elts - vector returning ids of the found cells. It is cleared + * before inserting ids. + * + * \if ENABLE_EXAMPLES + * \ref cpp_mcumesh_getCellsContainingPoint "Here is a C++ example".
+ * \ref py_mcumesh_getCellsContainingPoint "Here is a Python example". + * \endif + */ +void MEDCouplingMesh::getCellsContainingPoint(const double *pos, double eps, std::vector& elts) const +{ + int ret=getCellContainingPoint(pos,eps); + elts.push_back(ret); +} + +/*! + * Finds cells in contact with several balls (i.e. points with precision). + * This method is an extension of getCellContainingPoint() and + * getCellsContainingPoint() for the case of multiple points. + * \param [in] pos - an array of coordinates of points in full interlace mode : + * X0,Y0,Z0,X1,Y1,Z1,... Size of the array must be \a + * this->getSpaceDimension() * \a nbOfPoints + * \param [in] nbOfPoints - number of points to locate within \a this mesh. + * \param [in] eps - radius of balls (i.e. the precision). + * \param [out] elts - vector returning ids of found cells. + * \param [out] eltsIndex - an array, of length \a nbOfPoints + 1, + * dividing cell ids in \a elts into groups each referring to one + * point. Its every element (except the last one) is an index pointing to the + * first id of a group of cells. For example cells in contact with the *i*-th + * point are described by following range of indices: + * [ \a eltsIndex[ *i* ], \a eltsIndex[ *i*+1 ] ) and the cell ids are + * \a elts[ \a eltsIndex[ *i* ]], \a elts[ \a eltsIndex[ *i* ] + 1 ], ... + * Number of cells in contact with the *i*-th point is + * \a eltsIndex[ *i*+1 ] - \a eltsIndex[ *i* ]. + * + * \if ENABLE_EXAMPLES + * \ref cpp_mcumesh_getCellsContainingPoints "Here is a C++ example".
+ * \ref py_mcumesh_getCellsContainingPoints "Here is a Python example". + * \endif + */ +void MEDCouplingMesh::getCellsContainingPoints(const double *pos, int nbOfPoints, double eps, MEDCouplingAutoRefCountObjectPtr& elts, MEDCouplingAutoRefCountObjectPtr& eltsIndex) const +{ + eltsIndex=DataArrayInt::New(); elts=DataArrayInt::New(); eltsIndex->alloc(nbOfPoints+1,1); eltsIndex->setIJ(0,0,0); elts->alloc(0,1); + int *eltsIndexPtr(eltsIndex->getPointer()); + int spaceDim(getSpaceDimension()); + const double *work(pos); + for(int i=0;i=0) + { + elts->pushBackSilent(ret); + eltsIndexPtr[i+1]=eltsIndexPtr[i]+1; + } + else + eltsIndexPtr[i+1]=eltsIndexPtr[i]; + } +} + +/*! + * Writes \a this mesh into a VTK format file named as specified. + * \param [in] fileName - the name of the file to write in. If the extension is OK the fileName will be used directly. + * If extension is invalid or no extension the right extension will be appended. + * \return - the real fileName + * \throw If \a fileName is not a writable file. + * \sa getVTKFileNameOf + */ +std::string MEDCouplingMesh::writeVTK(const std::string& fileName, bool isBinary) const +{ + std::string ret(getVTKFileNameOf(fileName)); + // + std::string cda,pda; + MEDCouplingAutoRefCountObjectPtr byteArr; + if(isBinary) + { byteArr=DataArrayByte::New(); byteArr->alloc(0,1); } + writeVTKAdvanced(ret,cda,pda,byteArr); + return ret; +} + +/*! + * This method takes in input a file name \a fileName and considering the VTK extension of \a this (depending on the type of \a this) + * returns a right file name. If the input \a fileName has a valid extension the returned string is equal to \a fileName. + * + * \sa getVTKFileExtension + */ +std::string MEDCouplingMesh::getVTKFileNameOf(const std::string& fileName) const +{ + std::string ret; + std::string part0,part1; + SplitExtension(fileName,part0,part1); + std::string ext("."); ext+=getVTKFileExtension(); + if(part1==ext) + ret=fileName; + else + ret=fileName+ext; + return ret; +} + ++/// @cond INTERNAL +void MEDCouplingMesh::writeVTKAdvanced(const std::string& fileName, const std::string& cda, const std::string& pda, DataArrayByte *byteData) const +{ + std::ofstream ofs(fileName.c_str()); + ofs << "\n"; + writeVTKLL(ofs,cda,pda,byteData); + if(byteData) + { + ofs << "\n_1234"; + ofs << std::flush; ofs.close(); + std::ofstream ofs2(fileName.c_str(),std::ios_base::binary | std::ios_base::app); + ofs2.write(byteData->begin(),byteData->getNbOfElems()); ofs2 << std::flush; ofs2.close(); + std::ofstream ofs3(fileName.c_str(),std::ios_base::app); ofs3 << "\n\n\n"; ofs3.close(); + } + else + { + ofs << "\n"; + ofs.close(); + } +} + +void MEDCouplingMesh::SplitExtension(const std::string& fileName, std::string& baseName, std::string& extension) +{ + std::size_t pos(fileName.find_last_of('.')); + if(pos==std::string::npos) + { + baseName=fileName; + extension.clear(); + return ; + } + baseName=fileName.substr(0,pos); + extension=fileName.substr(pos); +} ++/// @endcond diff --cc medtool/src/MEDCoupling/MEDCouplingRefCountObject.hxx index 4eea72a52,000000000..897cdc6f7 mode 100644,000000..100644 --- a/medtool/src/MEDCoupling/MEDCouplingRefCountObject.hxx +++ b/medtool/src/MEDCoupling/MEDCouplingRefCountObject.hxx @@@ -1,106 -1,0 +1,108 @@@ +// Copyright (C) 2007-2015 CEA/DEN, EDF R&D +// +// 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +// +// See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com +// +// Author : Anthony Geay (CEA/DEN) + +#ifndef __PARAMEDMEM_MEDCOUPLINGREFCOUNTOBJECT_HXX__ +#define __PARAMEDMEM_MEDCOUPLINGREFCOUNTOBJECT_HXX__ + +#include "MEDCoupling.hxx" + +#include +#include +#include +#include + +namespace ParaMEDMEM +{ + typedef enum + { + C_DEALLOC = 2, + CPP_DEALLOC = 3 + } DeallocType; + ++ //! The various spatial discretization of a field + typedef enum + { + ON_CELLS = 0, + ON_NODES = 1, + ON_GAUSS_PT = 2, + ON_GAUSS_NE = 3, + ON_NODES_KR = 4 + } TypeOfField; + ++ //! The various temporal discretization of a field + typedef enum + { + NO_TIME = 4, + ONE_TIME = 5, + LINEAR_TIME = 6, + CONST_ON_TIME_INTERVAL = 7 + } TypeOfTimeDiscretization; + + typedef bool (*FunctionToEvaluate)(const double *pos, double *res); + + MEDCOUPLING_EXPORT const char *MEDCouplingVersionStr(); + MEDCOUPLING_EXPORT int MEDCouplingVersion(); + MEDCOUPLING_EXPORT void MEDCouplingVersionMajMinRel(int& maj, int& minor, int& releas); + MEDCOUPLING_EXPORT int MEDCouplingSizeOfVoidStar(); + MEDCOUPLING_EXPORT bool MEDCouplingByteOrder(); + MEDCOUPLING_EXPORT const char *MEDCouplingByteOrderStr(); + + class BigMemoryObject + { + public: + MEDCOUPLING_EXPORT std::size_t getHeapMemorySize() const; + MEDCOUPLING_EXPORT std::string getHeapMemorySizeStr() const; + MEDCOUPLING_EXPORT std::vector getDirectChildren() const; + MEDCOUPLING_EXPORT std::vector getAllTheProgeny() const; + MEDCOUPLING_EXPORT bool isObjectInTheProgeny(const BigMemoryObject *obj) const; + MEDCOUPLING_EXPORT static std::size_t GetHeapMemorySizeOfObjs(const std::vector& objs); + MEDCOUPLING_EXPORT virtual std::size_t getHeapMemorySizeWithoutChildren() const = 0; + MEDCOUPLING_EXPORT virtual std::vector getDirectChildrenWithNull() const = 0; + MEDCOUPLING_EXPORT virtual ~BigMemoryObject(); + private: + static std::size_t GetHeapMemoryOfSet(std::set& s1, std::set& s2); + }; + + class RefCountObjectOnly + { + protected: + MEDCOUPLING_EXPORT RefCountObjectOnly(); + MEDCOUPLING_EXPORT RefCountObjectOnly(const RefCountObjectOnly& other); + public: + MEDCOUPLING_EXPORT bool decrRef() const; + MEDCOUPLING_EXPORT void incrRef() const; + MEDCOUPLING_EXPORT int getRCValue() const; + MEDCOUPLING_EXPORT RefCountObjectOnly& operator=(const RefCountObjectOnly& other); + protected: + virtual ~RefCountObjectOnly(); + private: + mutable int _cnt; + }; + + class RefCountObject : public RefCountObjectOnly, public BigMemoryObject + { + protected: + MEDCOUPLING_EXPORT RefCountObject(); + MEDCOUPLING_EXPORT RefCountObject(const RefCountObject& other); + MEDCOUPLING_EXPORT virtual ~RefCountObject(); + }; +} + +#endif diff --cc medtool/src/MEDCoupling/MEDCouplingUMesh.cxx index d50bf73c2,000000000..81e8295b4 mode 100644,000000..100644 --- a/medtool/src/MEDCoupling/MEDCouplingUMesh.cxx +++ b/medtool/src/MEDCoupling/MEDCouplingUMesh.cxx @@@ -1,11916 -1,0 +1,11921 @@@ +// Copyright (C) 2007-2015 CEA/DEN, EDF R&D +// +// 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +// +// See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com +// +// Author : Anthony Geay (CEA/DEN) + +#include "MEDCouplingUMesh.hxx" +#include "MEDCoupling1GTUMesh.hxx" +#include "MEDCouplingMemArray.txx" +#include "MEDCouplingFieldDouble.hxx" +#include "MEDCouplingSkyLineArray.hxx" +#include "CellModel.hxx" +#include "VolSurfUser.txx" +#include "InterpolationUtils.hxx" +#include "PointLocatorAlgos.txx" +#include "BBTree.txx" +#include "BBTreeDst.txx" +#include "SplitterTetra.hxx" +#include "DiameterCalculator.hxx" +#include "DirectedBoundingBox.hxx" +#include "InterpKernelMatrixTools.hxx" +#include "InterpKernelMeshQuality.hxx" +#include "InterpKernelCellSimplify.hxx" +#include "InterpKernelGeo2DEdgeArcCircle.hxx" +#include "InterpKernelAutoPtr.hxx" +#include "InterpKernelGeo2DNode.hxx" +#include "InterpKernelGeo2DEdgeLin.hxx" +#include "InterpKernelGeo2DEdgeArcCircle.hxx" +#include "InterpKernelGeo2DQuadraticPolygon.hxx" + +#include +#include +#include +#include +#include +#include + +using namespace ParaMEDMEM; + +double MEDCouplingUMesh::EPS_FOR_POLYH_ORIENTATION=1.e-14; + ++/// @cond INTERNAL +const INTERP_KERNEL::NormalizedCellType MEDCouplingUMesh::MEDMEM_ORDER[N_MEDMEM_ORDER] = { INTERP_KERNEL::NORM_POINT1, INTERP_KERNEL::NORM_SEG2, INTERP_KERNEL::NORM_SEG3, INTERP_KERNEL::NORM_SEG4, INTERP_KERNEL::NORM_POLYL, INTERP_KERNEL::NORM_TRI3, INTERP_KERNEL::NORM_QUAD4, INTERP_KERNEL::NORM_TRI6, INTERP_KERNEL::NORM_TRI7, INTERP_KERNEL::NORM_QUAD8, INTERP_KERNEL::NORM_QUAD9, INTERP_KERNEL::NORM_POLYGON, INTERP_KERNEL::NORM_QPOLYG, INTERP_KERNEL::NORM_TETRA4, INTERP_KERNEL::NORM_PYRA5, INTERP_KERNEL::NORM_PENTA6, INTERP_KERNEL::NORM_HEXA8, INTERP_KERNEL::NORM_HEXGP12, INTERP_KERNEL::NORM_TETRA10, INTERP_KERNEL::NORM_PYRA13, INTERP_KERNEL::NORM_PENTA15, INTERP_KERNEL::NORM_HEXA20, INTERP_KERNEL::NORM_HEXA27, INTERP_KERNEL::NORM_POLYHED }; ++/// @endcond + +MEDCouplingUMesh *MEDCouplingUMesh::New() +{ + return new MEDCouplingUMesh; +} + +MEDCouplingUMesh *MEDCouplingUMesh::New(const std::string& meshName, int meshDim) +{ + MEDCouplingUMesh *ret=new MEDCouplingUMesh; + ret->setName(meshName); + ret->setMeshDimension(meshDim); + return ret; +} + +/*! + * Returns a new MEDCouplingMesh which is a full copy of \a this one. No data is shared + * between \a this and the new mesh. + * \return MEDCouplingMesh * - a new instance of MEDCouplingMesh. The caller is to + * delete this mesh using decrRef() as it is no more needed. + */ +MEDCouplingMesh *MEDCouplingUMesh::deepCpy() const +{ + return clone(true); +} + +/*! + * Returns a new MEDCouplingMesh which is a copy of \a this one. + * \param [in] recDeepCpy - if \a true, the copy is deep, else all data arrays of \a + * this mesh are shared by the new mesh. + * \return MEDCouplingMesh * - a new instance of MEDCouplingMesh. The caller is to + * delete this mesh using decrRef() as it is no more needed. + */ +MEDCouplingUMesh *MEDCouplingUMesh::clone(bool recDeepCpy) const +{ + return new MEDCouplingUMesh(*this,recDeepCpy); +} + +/*! + * This method behaves mostly like MEDCouplingUMesh::deepCpy method, except that only nodal connectivity arrays are deeply copied. + * The coordinates are shared between \a this and the returned instance. + * + * \return MEDCouplingUMesh * - A new object instance holding the copy of \a this (deep for connectivity, shallow for coordiantes) + * \sa MEDCouplingUMesh::deepCpy + */ +MEDCouplingPointSet *MEDCouplingUMesh::deepCpyConnectivityOnly() const +{ + checkConnectivityFullyDefined(); + MEDCouplingAutoRefCountObjectPtr ret=clone(false); + MEDCouplingAutoRefCountObjectPtr c(getNodalConnectivity()->deepCpy()),ci(getNodalConnectivityIndex()->deepCpy()); + ret->setConnectivity(c,ci); + return ret.retn(); +} + +void MEDCouplingUMesh::shallowCopyConnectivityFrom(const MEDCouplingPointSet *other) +{ + if(!other) + throw INTERP_KERNEL::Exception("MEDCouplingUMesh::shallowCopyConnectivityFrom : input pointer is null !"); + const MEDCouplingUMesh *otherC=dynamic_cast(other); + if(!otherC) + throw INTERP_KERNEL::Exception("MEDCouplingUMesh::shallowCopyConnectivityFrom : input pointer is not an MEDCouplingUMesh instance !"); + MEDCouplingUMesh *otherC2=const_cast(otherC);//sorry :( + setConnectivity(otherC2->getNodalConnectivity(),otherC2->getNodalConnectivityIndex(),true); +} + +std::size_t MEDCouplingUMesh::getHeapMemorySizeWithoutChildren() const +{ + std::size_t ret(MEDCouplingPointSet::getHeapMemorySizeWithoutChildren()); + return ret; +} + +std::vector MEDCouplingUMesh::getDirectChildrenWithNull() const +{ + std::vector ret(MEDCouplingPointSet::getDirectChildrenWithNull()); + ret.push_back(_nodal_connec); + ret.push_back(_nodal_connec_index); + return ret; +} + +void MEDCouplingUMesh::updateTime() const +{ + MEDCouplingPointSet::updateTime(); + if(_nodal_connec) + { + updateTimeWith(*_nodal_connec); + } + if(_nodal_connec_index) + { + updateTimeWith(*_nodal_connec_index); + } +} + +MEDCouplingUMesh::MEDCouplingUMesh():_mesh_dim(-2),_nodal_connec(0),_nodal_connec_index(0) +{ +} + +/*! + * Checks if \a this mesh is well defined. If no exception is thrown by this method, + * then \a this mesh is most probably is writable, exchangeable and available for most + * of algorithms. When a mesh is constructed from scratch, it is a good habit to call + * this method to check that all is in order with \a this mesh. + * \throw If the mesh dimension is not set. + * \throw If the coordinates array is not set (if mesh dimension != -1 ). + * \throw If \a this mesh contains elements of dimension different from the mesh dimension. + * \throw If the connectivity data array has more than one component. + * \throw If the connectivity data array has a named component. + * \throw If the connectivity index data array has more than one component. + * \throw If the connectivity index data array has a named component. + */ +void MEDCouplingUMesh::checkCoherency() const +{ + if(_mesh_dim<-1) + throw INTERP_KERNEL::Exception("No mesh dimension specified !"); + if(_mesh_dim!=-1) + MEDCouplingPointSet::checkCoherency(); + for(std::set::const_iterator iter=_types.begin();iter!=_types.end();iter++) + { + if((int)INTERP_KERNEL::CellModel::GetCellModel(*iter).getDimension()!=_mesh_dim) + { + std::ostringstream message; + message << "Mesh invalid because dimension is " << _mesh_dim << " and there is presence of cell(s) with type " << (*iter); + throw INTERP_KERNEL::Exception(message.str().c_str()); + } + } + if(_nodal_connec) + { + if(_nodal_connec->getNumberOfComponents()!=1) + throw INTERP_KERNEL::Exception("Nodal connectivity array is expected to be with number of components set to one !"); + if(_nodal_connec->getInfoOnComponent(0)!="") + throw INTERP_KERNEL::Exception("Nodal connectivity array is expected to have no info on its single component !"); + } + else + if(_mesh_dim!=-1) + throw INTERP_KERNEL::Exception("Nodal connectivity array is not defined !"); + if(_nodal_connec_index) + { + if(_nodal_connec_index->getNumberOfComponents()!=1) + throw INTERP_KERNEL::Exception("Nodal connectivity index array is expected to be with number of components set to one !"); + if(_nodal_connec_index->getInfoOnComponent(0)!="") + throw INTERP_KERNEL::Exception("Nodal connectivity index array is expected to have no info on its single component !"); + } + else + if(_mesh_dim!=-1) + throw INTERP_KERNEL::Exception("Nodal connectivity index array is not defined !"); +} + +/*! + * Checks if \a this mesh is well defined. If no exception is thrown by this method, + * then \a this mesh is most probably is writable, exchangeable and available for all + * algorithms.
In addition to the checks performed by checkCoherency(), this + * method thoroughly checks the nodal connectivity. + * \param [in] eps - a not used parameter. + * \throw If the mesh dimension is not set. + * \throw If the coordinates array is not set (if mesh dimension != -1 ). + * \throw If \a this mesh contains elements of dimension different from the mesh dimension. + * \throw If the connectivity data array has more than one component. + * \throw If the connectivity data array has a named component. + * \throw If the connectivity index data array has more than one component. + * \throw If the connectivity index data array has a named component. + * \throw If number of nodes defining an element does not correspond to the type of element. + * \throw If the nodal connectivity includes an invalid node id. + */ +void MEDCouplingUMesh::checkCoherency1(double eps) const +{ + checkCoherency(); + if(_mesh_dim==-1) + return ; + int meshDim=getMeshDimension(); + int nbOfNodes=getNumberOfNodes(); + int nbOfCells=getNumberOfCells(); + const int *ptr=_nodal_connec->getConstPointer(); + const int *ptrI=_nodal_connec_index->getConstPointer(); + for(int i=0;i=0) + { + if(nodeId>=nbOfNodes) + { + std::ostringstream oss; oss << "Cell #" << i << " is built with node #" << nodeId << " whereas there are only " << nbOfNodes << " nodes in the mesh !"; + throw INTERP_KERNEL::Exception(oss.str().c_str()); + } + } + else if(nodeId<-1) + { + std::ostringstream oss; oss << "Cell #" << i << " is built with node #" << nodeId << " in connectivity ! sounds bad !"; + throw INTERP_KERNEL::Exception(oss.str().c_str()); + } + else + { + if((INTERP_KERNEL::NormalizedCellType)(ptr[ptrI[i]])!=INTERP_KERNEL::NORM_POLYHED) + { + std::ostringstream oss; oss << "Cell #" << i << " is built with node #-1 in connectivity ! sounds bad !"; + throw INTERP_KERNEL::Exception(oss.str().c_str()); + } + } + } + } +} + + +/*! + * Checks if \a this mesh is well defined. If no exception is thrown by this method, + * then \a this mesh is most probably is writable, exchangeable and available for all + * algorithms.
This method performs the same checks as checkCoherency1() does. + * \param [in] eps - a not used parameter. + * \throw If the mesh dimension is not set. + * \throw If the coordinates array is not set (if mesh dimension != -1 ). + * \throw If \a this mesh contains elements of dimension different from the mesh dimension. + * \throw If the connectivity data array has more than one component. + * \throw If the connectivity data array has a named component. + * \throw If the connectivity index data array has more than one component. + * \throw If the connectivity index data array has a named component. + * \throw If number of nodes defining an element does not correspond to the type of element. + * \throw If the nodal connectivity includes an invalid node id. + */ +void MEDCouplingUMesh::checkCoherency2(double eps) const +{ + checkCoherency1(eps); +} + +/*! + * Sets dimension of \a this mesh. The mesh dimension in general depends on types of + * elements contained in the mesh. For more info on the mesh dimension see + * \ref MEDCouplingUMeshPage. + * \param [in] meshDim - a new mesh dimension. + * \throw If \a meshDim is invalid. A valid range is -1 <= meshDim <= 3. + */ +void MEDCouplingUMesh::setMeshDimension(int meshDim) +{ + if(meshDim<-1 || meshDim>3) + throw INTERP_KERNEL::Exception("Invalid meshDim specified ! Must be greater or equal to -1 and lower or equal to 3 !"); + _mesh_dim=meshDim; + declareAsNew(); +} + +/*! + * Allocates memory to store an estimation of the given number of cells. The closer is the estimation to the number of cells effectively inserted, + * the less will the library need to reallocate memory. If the number of cells to be inserted is not known simply put 0 to this parameter. + * If a nodal connectivity previouly existed before the call of this method, it will be reset. + * + * \param [in] nbOfCells - estimation of the number of cell \a this mesh will contain. + * + * \if ENABLE_EXAMPLES + * \ref medcouplingcppexamplesUmeshStdBuild1 "Here is a C++ example".
+ * \ref medcouplingpyexamplesUmeshStdBuild1 "Here is a Python example". + * \endif + */ +void MEDCouplingUMesh::allocateCells(int nbOfCells) +{ + if(nbOfCells<0) + throw INTERP_KERNEL::Exception("MEDCouplingUMesh::allocateCells : the input number of cells should be >= 0 !"); + if(_nodal_connec_index) + { + _nodal_connec_index->decrRef(); + } + if(_nodal_connec) + { + _nodal_connec->decrRef(); + } + _nodal_connec_index=DataArrayInt::New(); + _nodal_connec_index->reserve(nbOfCells+1); + _nodal_connec_index->pushBackSilent(0); + _nodal_connec=DataArrayInt::New(); + _nodal_connec->reserve(2*nbOfCells); + _types.clear(); + declareAsNew(); +} + +/*! + * Appends a cell to the connectivity array. For deeper understanding what is + * happening see \ref MEDCouplingUMeshNodalConnectivity. + * \param [in] type - type of cell to add. + * \param [in] size - number of nodes constituting this cell. + * \param [in] nodalConnOfCell - the connectivity of the cell to add. + * + * \if ENABLE_EXAMPLES + * \ref medcouplingcppexamplesUmeshStdBuild1 "Here is a C++ example".
+ * \ref medcouplingpyexamplesUmeshStdBuild1 "Here is a Python example". + * \endif + */ +void MEDCouplingUMesh::insertNextCell(INTERP_KERNEL::NormalizedCellType type, int size, const int *nodalConnOfCell) +{ + const INTERP_KERNEL::CellModel& cm=INTERP_KERNEL::CellModel::GetCellModel(type); + if(_nodal_connec_index==0) + throw INTERP_KERNEL::Exception("MEDCouplingUMesh::insertNextCell : nodal connectivity not set ! invoke allocateCells before calling insertNextCell !"); + if((int)cm.getDimension()==_mesh_dim) + { + if(!cm.isDynamic()) + if(size!=(int)cm.getNumberOfNodes()) + { + std::ostringstream oss; oss << "MEDCouplingUMesh::insertNextCell : Trying to push a " << cm.getRepr() << " cell with a size of " << size; + oss << " ! Expecting " << cm.getNumberOfNodes() << " !"; + throw INTERP_KERNEL::Exception(oss.str().c_str()); + } + int idx=_nodal_connec_index->back(); + int val=idx+size+1; + _nodal_connec_index->pushBackSilent(val); + _nodal_connec->writeOnPlace(idx,type,nodalConnOfCell,size); + _types.insert(type); + } + else + { + std::ostringstream oss; oss << "MEDCouplingUMesh::insertNextCell : cell type " << cm.getRepr() << " has a dimension " << cm.getDimension(); + oss << " whereas Mesh Dimension of current UMesh instance is set to " << _mesh_dim << " ! Please invoke \"setMeshDimension\" method before or invoke "; + oss << "\"MEDCouplingUMesh::New\" static method with 2 parameters name and meshDimension !"; + throw INTERP_KERNEL::Exception(oss.str().c_str()); + } +} + +/*! + * Compacts data arrays to release unused memory. This method is to be called after + * finishing cell insertion using \a this->insertNextCell(). + * + * \if ENABLE_EXAMPLES + * \ref medcouplingcppexamplesUmeshStdBuild1 "Here is a C++ example".
+ * \ref medcouplingpyexamplesUmeshStdBuild1 "Here is a Python example". + * \endif + */ +void MEDCouplingUMesh::finishInsertingCells() +{ + _nodal_connec->pack(); + _nodal_connec_index->pack(); + _nodal_connec->declareAsNew(); + _nodal_connec_index->declareAsNew(); + updateTime(); +} + +/*! + * Entry point for iteration over cells of this. Warning the returned cell iterator should be deallocated. + * Useful for python users. + */ +MEDCouplingUMeshCellIterator *MEDCouplingUMesh::cellIterator() +{ + return new MEDCouplingUMeshCellIterator(this); +} + +/*! + * Entry point for iteration over cells groups geo types per geotypes. Warning the returned cell iterator should be deallocated. + * If \a this is not so that that cells are grouped by geo types this method will throw an exception. + * In this case MEDCouplingUMesh::sortCellsInMEDFileFrmt or MEDCouplingUMesh::rearrange2ConsecutiveCellTypes methods for example can be called before invoking this method. + * Useful for python users. + */ +MEDCouplingUMeshCellByTypeEntry *MEDCouplingUMesh::cellsByType() +{ + if(!checkConsecutiveCellTypes()) + throw INTERP_KERNEL::Exception("MEDCouplingUMesh::cellsByType : this mesh is not sorted by type !"); + return new MEDCouplingUMeshCellByTypeEntry(this); +} + +/*! + * Returns a set of all cell types available in \a this mesh. + * \return std::set - the set of cell types. + * \warning this method does not throw any exception even if \a this is not defined. + * \sa MEDCouplingUMesh::getAllGeoTypesSorted + */ +std::set MEDCouplingUMesh::getAllGeoTypes() const +{ + return _types; +} + +/*! + * This method returns the sorted list of geometric types in \a this. + * Sorted means in the same order than the cells in \a this. A single entry in return vector means the maximal chunk of consecutive cells in \a this + * having the same geometric type. So a same geometric type can appear more than once if the cells are not sorted per geometric type. + * + * \throw if connectivity in \a this is not correctly defined. + * + * \sa MEDCouplingMesh::getAllGeoTypes + */ +std::vector MEDCouplingUMesh::getAllGeoTypesSorted() const +{ + std::vector ret; + checkConnectivityFullyDefined(); + int nbOfCells(getNumberOfCells()); + if(nbOfCells==0) + return ret; + if(getMeshLength()<1) + throw INTERP_KERNEL::Exception("MEDCouplingUMesh::getAllGeoTypesSorted : the connectivity in this seems invalid !"); + const int *c(_nodal_connec->begin()),*ci(_nodal_connec_index->begin()); + ret.push_back((INTERP_KERNEL::NormalizedCellType)c[*ci++]); + for(int i=1;i(other); + if(!otherC) + { + reason="mesh given in input is not castable in MEDCouplingUMesh !"; + return false; + } + if(!MEDCouplingPointSet::isEqualIfNotWhy(other,prec,reason)) + return false; + if(_mesh_dim!=otherC->_mesh_dim) + { + oss << "umesh dimension mismatch : this mesh dimension=" << _mesh_dim << " other mesh dimension=" << otherC->_mesh_dim; + reason=oss.str(); + return false; + } + if(_types!=otherC->_types) + { + oss << "umesh geometric type mismatch :\nThis geometric types are :"; + for(std::set::const_iterator iter=_types.begin();iter!=_types.end();iter++) + { const INTERP_KERNEL::CellModel& cm=INTERP_KERNEL::CellModel::GetCellModel(*iter); oss << cm.getRepr() << ", "; } + oss << "\nOther geometric types are :"; + for(std::set::const_iterator iter=otherC->_types.begin();iter!=otherC->_types.end();iter++) + { const INTERP_KERNEL::CellModel& cm=INTERP_KERNEL::CellModel::GetCellModel(*iter); oss << cm.getRepr() << ", "; } + reason=oss.str(); + return false; + } + if(_nodal_connec!=0 || otherC->_nodal_connec!=0) + if(_nodal_connec==0 || otherC->_nodal_connec==0) + { + reason="Only one UMesh between the two this and other has its nodal connectivity DataArrayInt defined !"; + return false; + } + if(_nodal_connec!=otherC->_nodal_connec) + if(!_nodal_connec->isEqualIfNotWhy(*otherC->_nodal_connec,reason)) + { + reason.insert(0,"Nodal connectivity DataArrayInt differ : "); + return false; + } + if(_nodal_connec_index!=0 || otherC->_nodal_connec_index!=0) + if(_nodal_connec_index==0 || otherC->_nodal_connec_index==0) + { + reason="Only one UMesh between the two this and other has its nodal connectivity index DataArrayInt defined !"; + return false; + } + if(_nodal_connec_index!=otherC->_nodal_connec_index) + if(!_nodal_connec_index->isEqualIfNotWhy(*otherC->_nodal_connec_index,reason)) + { + reason.insert(0,"Nodal connectivity index DataArrayInt differ : "); + return false; + } + return true; +} + +/*! + * Checks if data arrays of this mesh (node coordinates, nodal + * connectivity of cells, etc) of two meshes are same. Textual data like name etc. are + * not considered. + * \param [in] other - the mesh to compare with. + * \param [in] prec - precision value used to compare node coordinates. + * \return bool - \a true if the two meshes are same. + */ +bool MEDCouplingUMesh::isEqualWithoutConsideringStr(const MEDCouplingMesh *other, double prec) const +{ + const MEDCouplingUMesh *otherC=dynamic_cast(other); + if(!otherC) + return false; + if(!MEDCouplingPointSet::isEqualWithoutConsideringStr(other,prec)) + return false; + if(_mesh_dim!=otherC->_mesh_dim) + return false; + if(_types!=otherC->_types) + return false; + if(_nodal_connec!=0 || otherC->_nodal_connec!=0) + if(_nodal_connec==0 || otherC->_nodal_connec==0) + return false; + if(_nodal_connec!=otherC->_nodal_connec) + if(!_nodal_connec->isEqualWithoutConsideringStr(*otherC->_nodal_connec)) + return false; + if(_nodal_connec_index!=0 || otherC->_nodal_connec_index!=0) + if(_nodal_connec_index==0 || otherC->_nodal_connec_index==0) + return false; + if(_nodal_connec_index!=otherC->_nodal_connec_index) + if(!_nodal_connec_index->isEqualWithoutConsideringStr(*otherC->_nodal_connec_index)) + return false; + return true; +} + +/*! + * Checks if \a this and \a other meshes are geometrically equivalent with high + * probability, else an exception is thrown. The meshes are considered equivalent if + * (1) meshes contain the same number of nodes and the same number of elements of the + * same types (2) three cells of the two meshes (first, last and middle) are based + * on coincident nodes (with a specified precision). + * \param [in] other - the mesh to compare with. + * \param [in] prec - the precision used to compare nodes of the two meshes. + * \throw If the two meshes do not match. + */ +void MEDCouplingUMesh::checkFastEquivalWith(const MEDCouplingMesh *other, double prec) const +{ + MEDCouplingPointSet::checkFastEquivalWith(other,prec); + const MEDCouplingUMesh *otherC=dynamic_cast(other); + if(!otherC) + throw INTERP_KERNEL::Exception("MEDCouplingUMesh::checkFastEquivalWith : Two meshes are not not unstructured !"); +} + +/*! + * Returns the reverse nodal connectivity. The reverse nodal connectivity enumerates + * cells each node belongs to. + * \warning For speed reasons, this method does not check if node ids in the nodal + * connectivity correspond to the size of node coordinates array. + * \param [in,out] revNodal - an array holding ids of cells sharing each node. + * \param [in,out] revNodalIndx - an array, of length \a this->getNumberOfNodes() + 1, + * dividing cell ids in \a revNodal into groups each referring to one + * node. Its every element (except the last one) is an index pointing to the + * first id of a group of cells. For example cells sharing the node #1 are + * described by following range of indices: + * [ \a revNodalIndx[1], \a revNodalIndx[2] ) and the cell ids are + * \a revNodal[ \a revNodalIndx[1] ], \a revNodal[ \a revNodalIndx[1] + 1], ... + * Number of cells sharing the *i*-th node is + * \a revNodalIndx[ *i*+1 ] - \a revNodalIndx[ *i* ]. + * \throw If the coordinates array is not set. + * \throw If the nodal connectivity of cells is not defined. + * + * \if ENABLE_EXAMPLES + * \ref cpp_mcumesh_getReverseNodalConnectivity "Here is a C++ example".
+ * \ref py_mcumesh_getReverseNodalConnectivity "Here is a Python example". + * \endif + */ +void MEDCouplingUMesh::getReverseNodalConnectivity(DataArrayInt *revNodal, DataArrayInt *revNodalIndx) const +{ + checkFullyDefined(); + int nbOfNodes=getNumberOfNodes(); + int *revNodalIndxPtr=(int *)malloc((nbOfNodes+1)*sizeof(int)); + revNodalIndx->useArray(revNodalIndxPtr,true,C_DEALLOC,nbOfNodes+1,1); + std::fill(revNodalIndxPtr,revNodalIndxPtr+nbOfNodes+1,0); + const int *conn=_nodal_connec->getConstPointer(); + const int *connIndex=_nodal_connec_index->getConstPointer(); + int nbOfCells=getNumberOfCells(); + int nbOfEltsInRevNodal=0; + for(int eltId=0;eltId=0)//for polyhedrons + { + nbOfEltsInRevNodal++; + revNodalIndxPtr[(*iter)+1]++; + } + } + std::transform(revNodalIndxPtr+1,revNodalIndxPtr+nbOfNodes+1,revNodalIndxPtr,revNodalIndxPtr+1,std::plus()); + int *revNodalPtr=(int *)malloc((nbOfEltsInRevNodal)*sizeof(int)); + revNodal->useArray(revNodalPtr,true,C_DEALLOC,nbOfEltsInRevNodal,1); + std::fill(revNodalPtr,revNodalPtr+nbOfEltsInRevNodal,-1); + for(int eltId=0;eltId=0)//for polyhedrons + *std::find_if(revNodalPtr+revNodalIndxPtr[*iter],revNodalPtr+revNodalIndxPtr[*iter+1],std::bind2nd(std::equal_to(),-1))=eltId; + } +} + +/// @cond INTERNAL + +int MEDCouplingFastNbrer(int id, unsigned nb, const INTERP_KERNEL::CellModel& cm, bool compute, const int *conn1, const int *conn2) +{ + return id; +} + +int MEDCouplingOrientationSensitiveNbrer(int id, unsigned nb, const INTERP_KERNEL::CellModel& cm, bool compute, const int *conn1, const int *conn2) +{ + if(!compute) + return id+1; + else + { + if(cm.getOrientationStatus(nb,conn1,conn2)) + return id+1; + else + return -(id+1); + } +} + +class MinusOneSonsGenerator +{ +public: + MinusOneSonsGenerator(const INTERP_KERNEL::CellModel& cm):_cm(cm) { } + unsigned getNumberOfSons2(const int *conn, int lgth) const { return _cm.getNumberOfSons2(conn,lgth); } + unsigned fillSonCellNodalConnectivity2(int sonId, const int *nodalConn, int lgth, int *sonNodalConn, INTERP_KERNEL::NormalizedCellType& typeOfSon) const { return _cm.fillSonCellNodalConnectivity2(sonId,nodalConn,lgth,sonNodalConn,typeOfSon); } + static const int DELTA=1; +private: + const INTERP_KERNEL::CellModel& _cm; +}; + +class MinusOneSonsGeneratorBiQuadratic +{ +public: + MinusOneSonsGeneratorBiQuadratic(const INTERP_KERNEL::CellModel& cm):_cm(cm) { } + unsigned getNumberOfSons2(const int *conn, int lgth) const { return _cm.getNumberOfSons2(conn,lgth); } + unsigned fillSonCellNodalConnectivity2(int sonId, const int *nodalConn, int lgth, int *sonNodalConn, INTERP_KERNEL::NormalizedCellType& typeOfSon) const { return _cm.fillSonCellNodalConnectivity4(sonId,nodalConn,lgth,sonNodalConn,typeOfSon); } + static const int DELTA=1; +private: + const INTERP_KERNEL::CellModel& _cm; +}; + +class MinusTwoSonsGenerator +{ +public: + MinusTwoSonsGenerator(const INTERP_KERNEL::CellModel& cm):_cm(cm) { } + unsigned getNumberOfSons2(const int *conn, int lgth) const { return _cm.getNumberOfEdgesIn3D(conn,lgth); } + unsigned fillSonCellNodalConnectivity2(int sonId, const int *nodalConn, int lgth, int *sonNodalConn, INTERP_KERNEL::NormalizedCellType& typeOfSon) const { return _cm.fillSonEdgesNodalConnectivity3D(sonId,nodalConn,lgth,sonNodalConn,typeOfSon); } + static const int DELTA=2; +private: + const INTERP_KERNEL::CellModel& _cm; +}; + +/// @endcond + +/*! + * Creates a new MEDCouplingUMesh containing cells, of dimension one less than \a + * this->getMeshDimension(), that bound cells of \a this mesh. In addition arrays + * describing correspondence between cells of \a this and the result meshes are + * returned. The arrays \a desc and \a descIndx (\ref numbering-indirect) describe the descending connectivity, + * i.e. enumerate cells of the result mesh bounding each cell of \a this mesh. The + * arrays \a revDesc and \a revDescIndx (\ref numbering-indirect) describe the reverse descending connectivity, + * i.e. enumerate cells of \a this mesh bounded by each cell of the result mesh. + * \warning For speed reasons, this method does not check if node ids in the nodal + * connectivity correspond to the size of node coordinates array. + * \warning Cells of the result mesh are \b not sorted by geometric type, hence, + * to write this mesh to the MED file, its cells must be sorted using + * sortCellsInMEDFileFrmt(). + * \param [in,out] desc - the array containing cell ids of the result mesh bounding + * each cell of \a this mesh. + * \param [in,out] descIndx - the array, of length \a this->getNumberOfCells() + 1, + * dividing cell ids in \a desc into groups each referring to one + * cell of \a this mesh. Its every element (except the last one) is an index + * pointing to the first id of a group of cells. For example cells of the + * result mesh bounding the cell #1 of \a this mesh are described by following + * range of indices: + * [ \a descIndx[1], \a descIndx[2] ) and the cell ids are + * \a desc[ \a descIndx[1] ], \a desc[ \a descIndx[1] + 1], ... + * Number of cells of the result mesh sharing the *i*-th cell of \a this mesh is + * \a descIndx[ *i*+1 ] - \a descIndx[ *i* ]. + * \param [in,out] revDesc - the array containing cell ids of \a this mesh bounded + * by each cell of the result mesh. + * \param [in,out] revDescIndx - the array, of length one more than number of cells + * in the result mesh, + * dividing cell ids in \a revDesc into groups each referring to one + * cell of the result mesh the same way as \a descIndx divides \a desc. + * \return MEDCouplingUMesh * - a new instance of MEDCouplingUMesh. The caller is to + * delete this mesh using decrRef() as it is no more needed. + * \throw If the coordinates array is not set. + * \throw If the nodal connectivity of cells is node defined. + * \throw If \a desc == NULL || \a descIndx == NULL || \a revDesc == NULL || \a + * revDescIndx == NULL. + * + * \if ENABLE_EXAMPLES + * \ref cpp_mcumesh_buildDescendingConnectivity "Here is a C++ example".
+ * \ref py_mcumesh_buildDescendingConnectivity "Here is a Python example". + * \endif + * \sa buildDescendingConnectivity2() + */ +MEDCouplingUMesh *MEDCouplingUMesh::buildDescendingConnectivity(DataArrayInt *desc, DataArrayInt *descIndx, DataArrayInt *revDesc, DataArrayInt *revDescIndx) const +{ + return buildDescendingConnectivityGen(desc,descIndx,revDesc,revDescIndx,MEDCouplingFastNbrer); +} + +/*! + * \a this has to have a mesh dimension equal to 3. If it is not the case an INTERP_KERNEL::Exception will be thrown. + * This behaves exactly as MEDCouplingUMesh::buildDescendingConnectivity does except that this method compute directly the transition from mesh dimension 3 to sub edges (dimension 1) + * in one shot. That is to say that this method is equivalent to 2 successive calls to MEDCouplingUMesh::buildDescendingConnectivity. + * This method returns 4 arrays and a mesh as MEDCouplingUMesh::buildDescendingConnectivity does. + * \sa MEDCouplingUMesh::buildDescendingConnectivity + */ +MEDCouplingUMesh *MEDCouplingUMesh::explode3DMeshTo1D(DataArrayInt *desc, DataArrayInt *descIndx, DataArrayInt *revDesc, DataArrayInt *revDescIndx) const +{ + checkFullyDefined(); + if(getMeshDimension()!=3) + throw INTERP_KERNEL::Exception("MEDCouplingUMesh::explode3DMeshTo1D : This has to have a mesh dimension to 3 !"); + return buildDescendingConnectivityGen(desc,descIndx,revDesc,revDescIndx,MEDCouplingFastNbrer); +} + +/*! + * Creates a new MEDCouplingUMesh containing cells, of dimension one less than \a + * this->getMeshDimension(), that bound cells of \a this mesh. In + * addition arrays describing correspondence between cells of \a this and the result + * meshes are returned. The arrays \a desc and \a descIndx (\ref numbering-indirect) describe the descending + * connectivity, i.e. enumerate cells of the result mesh bounding each cell of \a this + * mesh. This method differs from buildDescendingConnectivity() in that apart + * from cell ids, \a desc returns mutual orientation of cells in \a this and the + * result meshes. So a positive id means that order of nodes in corresponding cells + * of two meshes is same, and a negative id means a reverse order of nodes. Since a + * cell with id #0 can't be negative, the array \a desc returns ids in FORTRAN mode, + * i.e. cell ids are one-based. + * Arrays \a revDesc and \a revDescIndx (\ref numbering-indirect) describe the reverse descending connectivity, + * i.e. enumerate cells of \a this mesh bounded by each cell of the result mesh. + * \warning For speed reasons, this method does not check if node ids in the nodal + * connectivity correspond to the size of node coordinates array. + * \warning Cells of the result mesh are \b not sorted by geometric type, hence, + * to write this mesh to the MED file, its cells must be sorted using + * sortCellsInMEDFileFrmt(). + * \param [in,out] desc - the array containing cell ids of the result mesh bounding + * each cell of \a this mesh. + * \param [in,out] descIndx - the array, of length \a this->getNumberOfCells() + 1, + * dividing cell ids in \a desc into groups each referring to one + * cell of \a this mesh. Its every element (except the last one) is an index + * pointing to the first id of a group of cells. For example cells of the + * result mesh bounding the cell #1 of \a this mesh are described by following + * range of indices: + * [ \a descIndx[1], \a descIndx[2] ) and the cell ids are + * \a desc[ \a descIndx[1] ], \a desc[ \a descIndx[1] + 1], ... + * Number of cells of the result mesh sharing the *i*-th cell of \a this mesh is + * \a descIndx[ *i*+1 ] - \a descIndx[ *i* ]. + * \param [in,out] revDesc - the array containing cell ids of \a this mesh bounded + * by each cell of the result mesh. + * \param [in,out] revDescIndx - the array, of length one more than number of cells + * in the result mesh, + * dividing cell ids in \a revDesc into groups each referring to one + * cell of the result mesh the same way as \a descIndx divides \a desc. + * \return MEDCouplingUMesh * - a new instance of MEDCouplingUMesh. This result mesh + * shares the node coordinates array with \a this mesh. The caller is to + * delete this mesh using decrRef() as it is no more needed. + * \throw If the coordinates array is not set. + * \throw If the nodal connectivity of cells is node defined. + * \throw If \a desc == NULL || \a descIndx == NULL || \a revDesc == NULL || \a + * revDescIndx == NULL. + * + * \if ENABLE_EXAMPLES + * \ref cpp_mcumesh_buildDescendingConnectivity2 "Here is a C++ example".
+ * \ref py_mcumesh_buildDescendingConnectivity2 "Here is a Python example". + * \endif + * \sa buildDescendingConnectivity() + */ +MEDCouplingUMesh *MEDCouplingUMesh::buildDescendingConnectivity2(DataArrayInt *desc, DataArrayInt *descIndx, DataArrayInt *revDesc, DataArrayInt *revDescIndx) const +{ + return buildDescendingConnectivityGen(desc,descIndx,revDesc,revDescIndx,MEDCouplingOrientationSensitiveNbrer); +} + +/*! + * \b WARNING this method do the assumption that connectivity lies on the coordinates set. + * For speed reasons no check of this will be done. This method calls + * MEDCouplingUMesh::buildDescendingConnectivity to compute the result. + * This method lists cell by cell in \b this which are its neighbors. To compute the result + * only connectivities are considered. + * The neighbor cells of cell having id 'cellId' are neighbors[neighborsIndx[cellId]:neighborsIndx[cellId+1]]. + * The format of return is hence \ref numbering-indirect. + * + * \param [out] neighbors is an array storing all the neighbors of all cells in \b this. This array is newly + * allocated and should be dealt by the caller. \b neighborsIndx 2nd output + * parameter allows to select the right part in this array (\ref numbering-indirect). The number of tuples + * is equal to the last values in \b neighborsIndx. + * \param [out] neighborsIndx is an array of size this->getNumberOfCells()+1 newly allocated and should be + * dealt by the caller. This arrays allow to use the first output parameter \b neighbors (\ref numbering-indirect). + */ +void MEDCouplingUMesh::computeNeighborsOfCells(DataArrayInt *&neighbors, DataArrayInt *&neighborsIndx) const +{ + MEDCouplingAutoRefCountObjectPtr desc=DataArrayInt::New(); + MEDCouplingAutoRefCountObjectPtr descIndx=DataArrayInt::New(); + MEDCouplingAutoRefCountObjectPtr revDesc=DataArrayInt::New(); + MEDCouplingAutoRefCountObjectPtr revDescIndx=DataArrayInt::New(); + MEDCouplingAutoRefCountObjectPtr meshDM1=buildDescendingConnectivity(desc,descIndx,revDesc,revDescIndx); + meshDM1=0; + ComputeNeighborsOfCellsAdv(desc,descIndx,revDesc,revDescIndx,neighbors,neighborsIndx); +} + +/*! + * This method is called by MEDCouplingUMesh::computeNeighborsOfCells. This methods performs the algorithm + * of MEDCouplingUMesh::computeNeighborsOfCells. + * This method is useful for users that want to reduce along a criterion the set of neighbours cell. This is + * typically the case to extract a set a neighbours, + * excluding a set of meshdim-1 cells in input descending connectivity. + * Typically \b desc, \b descIndx, \b revDesc and \b revDescIndx (\ref numbering-indirect) input params are + * the result of MEDCouplingUMesh::buildDescendingConnectivity. + * This method lists cell by cell in \b this which are its neighbors. To compute the result only connectivities + * are considered. + * The neighbor cells of cell having id 'cellId' are neighbors[neighborsIndx[cellId]:neighborsIndx[cellId+1]]. + * + * \param [in] desc descending connectivity array. + * \param [in] descIndx descending connectivity index array used to walk through \b desc (\ref numbering-indirect). + * \param [in] revDesc reverse descending connectivity array. + * \param [in] revDescIndx reverse descending connectivity index array used to walk through \b revDesc (\ref numbering-indirect). + * \param [out] neighbors is an array storing all the neighbors of all cells in \b this. This array is newly allocated and should be dealt by the caller. \b neighborsIndx 2nd output + * parameter allows to select the right part in this array. The number of tuples is equal to the last values in \b neighborsIndx. + * \param [out] neighborsIndx is an array of size this->getNumberOfCells()+1 newly allocated and should be dealt by the caller. This arrays allow to use the first output parameter \b neighbors. + */ +void MEDCouplingUMesh::ComputeNeighborsOfCellsAdv(const DataArrayInt *desc, const DataArrayInt *descIndx, const DataArrayInt *revDesc, const DataArrayInt *revDescIndx, + DataArrayInt *&neighbors, DataArrayInt *&neighborsIndx) +{ + if(!desc || !descIndx || !revDesc || !revDescIndx) + throw INTERP_KERNEL::Exception("MEDCouplingUMesh::ComputeNeighborsOfCellsAdv some input array is empty !"); + const int *descPtr=desc->getConstPointer(); + const int *descIPtr=descIndx->getConstPointer(); + const int *revDescPtr=revDesc->getConstPointer(); + const int *revDescIPtr=revDescIndx->getConstPointer(); + // + int nbCells=descIndx->getNumberOfTuples()-1; + MEDCouplingAutoRefCountObjectPtr out0=DataArrayInt::New(); + MEDCouplingAutoRefCountObjectPtr out1=DataArrayInt::New(); out1->alloc(nbCells+1,1); + int *out1Ptr=out1->getPointer(); + *out1Ptr++=0; + out0->reserve(desc->getNumberOfTuples()); + for(int i=0;i s(revDescPtr+revDescIPtr[*w1],revDescPtr+revDescIPtr[(*w1)+1]); + s.erase(i); + out0->insertAtTheEnd(s.begin(),s.end()); + } + *out1Ptr=out0->getNumberOfTuples(); + } + neighbors=out0.retn(); + neighborsIndx=out1.retn(); +} + +/*! + * \b WARNING this method do the assumption that connectivity lies on the coordinates set. + * For speed reasons no check of this will be done. This method calls + * MEDCouplingUMesh::buildDescendingConnectivity to compute the result. + * This method lists node by node in \b this which are its neighbors. To compute the result + * only connectivities are considered. + * The neighbor nodes of node having id 'nodeId' are neighbors[neighborsIndx[cellId]:neighborsIndx[cellId+1]]. + * + * \param [out] neighbors is an array storing all the neighbors of all nodes in \b this. This array + * is newly allocated and should be dealt by the caller. \b neighborsIndx 2nd output + * parameter allows to select the right part in this array (\ref numbering-indirect). + * The number of tuples is equal to the last values in \b neighborsIndx. + * \param [out] neighborsIdx is an array of size this->getNumberOfCells()+1 newly allocated and should + * be dealt by the caller. This arrays allow to use the first output parameter \b neighbors. + */ +void MEDCouplingUMesh::computeNeighborsOfNodes(DataArrayInt *&neighbors, DataArrayInt *&neighborsIdx) const +{ + checkFullyDefined(); + int mdim(getMeshDimension()),nbNodes(getNumberOfNodes()); + MEDCouplingAutoRefCountObjectPtr desc(DataArrayInt::New()),descIndx(DataArrayInt::New()),revDesc(DataArrayInt::New()),revDescIndx(DataArrayInt::New()); + MEDCouplingAutoRefCountObjectPtr mesh1D; + switch(mdim) + { + case 3: + { + mesh1D=explode3DMeshTo1D(desc,descIndx,revDesc,revDescIndx); + break; + } + case 2: + { + mesh1D=buildDescendingConnectivity(desc,descIndx,revDesc,revDescIndx); + break; + } + case 1: + { + mesh1D=const_cast(this); + mesh1D->incrRef(); + break; + } + default: + { + throw INTERP_KERNEL::Exception("MEDCouplingUMesh::computeNeighborsOfNodes : Mesh dimension supported are [3,2,1] !"); + } + } + desc=DataArrayInt::New(); descIndx=DataArrayInt::New(); revDesc=0; revDescIndx=0; + mesh1D->getReverseNodalConnectivity(desc,descIndx); + MEDCouplingAutoRefCountObjectPtr ret0(DataArrayInt::New()); + ret0->alloc(desc->getNumberOfTuples(),1); + int *r0Pt(ret0->getPointer()); + const int *c1DPtr(mesh1D->getNodalConnectivity()->begin()),*rn(desc->begin()),*rni(descIndx->begin()); + for(int i=0;i +MEDCouplingUMesh *MEDCouplingUMesh::buildDescendingConnectivityGen(DataArrayInt *desc, DataArrayInt *descIndx, DataArrayInt *revDesc, DataArrayInt *revDescIndx, DimM1DescNbrer nbrer) const +{ + if(!desc || !descIndx || !revDesc || !revDescIndx) + throw INTERP_KERNEL::Exception("MEDCouplingUMesh::buildDescendingConnectivityGen : present of a null pointer in input !"); + checkConnectivityFullyDefined(); + int nbOfCells=getNumberOfCells(); + int nbOfNodes=getNumberOfNodes(); + MEDCouplingAutoRefCountObjectPtr revNodalIndx=DataArrayInt::New(); revNodalIndx->alloc(nbOfNodes+1,1); revNodalIndx->fillWithZero(); + int *revNodalIndxPtr=revNodalIndx->getPointer(); + const int *conn=_nodal_connec->getConstPointer(); + const int *connIndex=_nodal_connec_index->getConstPointer(); + std::string name="Mesh constituent of "; name+=getName(); + MEDCouplingAutoRefCountObjectPtr ret=MEDCouplingUMesh::New(name,getMeshDimension()-SonsGenerator::DELTA); + ret->setCoords(getCoords()); + ret->allocateCells(2*nbOfCells); + descIndx->alloc(nbOfCells+1,1); + MEDCouplingAutoRefCountObjectPtr revDesc2(DataArrayInt::New()); revDesc2->reserve(2*nbOfCells); + int *descIndxPtr=descIndx->getPointer(); *descIndxPtr++=0; + for(int eltId=0;eltId tmp=new int[posP1-pos]; + for(unsigned i=0;i=0) + revNodalIndxPtr[tmp[k]+1]++; + ret->insertNextCell(cmsId,nbOfNodesSon,tmp); + revDesc2->pushBackSilent(eltId); + } + descIndxPtr[0]=descIndxPtr[-1]+(int)nbOfSons; + } + int nbOfCellsM1=ret->getNumberOfCells(); + std::transform(revNodalIndxPtr+1,revNodalIndxPtr+nbOfNodes+1,revNodalIndxPtr,revNodalIndxPtr+1,std::plus()); + MEDCouplingAutoRefCountObjectPtr revNodal=DataArrayInt::New(); revNodal->alloc(revNodalIndx->back(),1); + std::fill(revNodal->getPointer(),revNodal->getPointer()+revNodalIndx->back(),-1); + int *revNodalPtr=revNodal->getPointer(); + const int *connM1=ret->getNodalConnectivity()->getConstPointer(); + const int *connIndexM1=ret->getNodalConnectivityIndex()->getConstPointer(); + for(int eltId=0;eltId=0)//for polyhedrons + *std::find_if(revNodalPtr+revNodalIndxPtr[*iter],revNodalPtr+revNodalIndxPtr[*iter+1],std::bind2nd(std::equal_to(),-1))=eltId; + } + // + DataArrayInt *commonCells=0,*commonCellsI=0; + FindCommonCellsAlg(3,0,ret->getNodalConnectivity(),ret->getNodalConnectivityIndex(),revNodal,revNodalIndx,commonCells,commonCellsI); + MEDCouplingAutoRefCountObjectPtr commonCellsTmp(commonCells),commonCellsITmp(commonCellsI); + const int *commonCellsPtr(commonCells->getConstPointer()),*commonCellsIPtr(commonCellsI->getConstPointer()); + int newNbOfCellsM1=-1; + MEDCouplingAutoRefCountObjectPtr o2nM1=DataArrayInt::BuildOld2NewArrayFromSurjectiveFormat2(nbOfCellsM1,commonCells->begin(), + commonCellsI->begin(),commonCellsI->end(),newNbOfCellsM1); + std::vector isImpacted(nbOfCellsM1,false); + for(const int *work=commonCellsI->begin();work!=commonCellsI->end()-1;work++) + for(int work2=work[0];work2!=work[1];work2++) + isImpacted[commonCellsPtr[work2]]=true; + const int *o2nM1Ptr=o2nM1->getConstPointer(); + MEDCouplingAutoRefCountObjectPtr n2oM1=o2nM1->invertArrayO2N2N2OBis(newNbOfCellsM1); + const int *n2oM1Ptr=n2oM1->getConstPointer(); + MEDCouplingAutoRefCountObjectPtr ret2=static_cast(ret->buildPartOfMySelf(n2oM1->begin(),n2oM1->end(),true)); + ret2->copyTinyInfoFrom(this); + desc->alloc(descIndx->back(),1); + int *descPtr=desc->getPointer(); + const INTERP_KERNEL::CellModel& cmsDft=INTERP_KERNEL::CellModel::GetCellModel(INTERP_KERNEL::NORM_POINT1); + for(int i=0;ireserve(newNbOfCellsM1); + revDescIndx->alloc(newNbOfCellsM1+1,1); + int *revDescIndxPtr=revDescIndx->getPointer(); *revDescIndxPtr++=0; + const int *revDesc2Ptr=revDesc2->getConstPointer(); + for(int i=0;ipushBackSilent(revDesc2Ptr[oldCellIdM1]); + revDescIndxPtr[0]=revDescIndxPtr[-1]+1; + } + else + { + for(int j=commonCellsIPtr[0];jpushBackSilent(revDesc2Ptr[commonCellsPtr[j]]); + revDescIndxPtr[0]=revDescIndxPtr[-1]+commonCellsIPtr[1]-commonCellsIPtr[0]; + commonCellsIPtr++; + } + } + // + return ret2.retn(); +} + +struct MEDCouplingAccVisit +{ + MEDCouplingAccVisit():_new_nb_of_nodes(0) { } + int operator()(int val) { if(val!=-1) return _new_nb_of_nodes++; else return -1; } + int _new_nb_of_nodes; +}; + +/// @endcond + +/*! + * Converts specified cells to either polygons (if \a this is a 2D mesh) or + * polyhedrons (if \a this is a 3D mesh). The cells to convert are specified by an + * array of cell ids. Pay attention that after conversion all algorithms work slower + * with \a this mesh than before conversion.
If an exception is thrown during the + * conversion due presence of invalid ids in the array of cells to convert, as a + * result \a this mesh contains some already converted elements. In this case the 2D + * mesh remains valid but 3D mesh becomes \b inconsistent! + * \warning This method can significantly modify the order of geometric types in \a this, + * hence, to write this mesh to the MED file, its cells must be sorted using + * sortCellsInMEDFileFrmt(). + * \param [in] cellIdsToConvertBg - the array holding ids of cells to convert. + * \param [in] cellIdsToConvertEnd - a pointer to the last-plus-one-th element of \a + * cellIdsToConvertBg. + * \throw If the coordinates array is not set. + * \throw If the nodal connectivity of cells is node defined. + * \throw If dimension of \a this mesh is not either 2 or 3. + * + * \if ENABLE_EXAMPLES + * \ref cpp_mcumesh_convertToPolyTypes "Here is a C++ example".
+ * \ref py_mcumesh_convertToPolyTypes "Here is a Python example". + * \endif + */ +void MEDCouplingUMesh::convertToPolyTypes(const int *cellIdsToConvertBg, const int *cellIdsToConvertEnd) +{ + checkFullyDefined(); + int dim=getMeshDimension(); + if(dim<2 || dim>3) + throw INTERP_KERNEL::Exception("Invalid mesh dimension : must be 2 or 3 !"); + int nbOfCells(getNumberOfCells()); + if(dim==2) + { + const int *connIndex=_nodal_connec_index->getConstPointer(); + int *conn=_nodal_connec->getPointer(); + for(const int *iter=cellIdsToConvertBg;iter!=cellIdsToConvertEnd;iter++) + { + if(*iter>=0 && *itergetPointer()); + const int *connOld(_nodal_connec->getConstPointer()); + MEDCouplingAutoRefCountObjectPtr connNew(DataArrayInt::New()),connNewI(DataArrayInt::New()); connNew->alloc(0,1); connNewI->alloc(1,1); connNewI->setIJ(0,0,0); + std::vector toBeDone(nbOfCells,false); + for(const int *iter=cellIdsToConvertBg;iter!=cellIdsToConvertEnd;iter++) + { + if(*iter>=0 && *iterpushBackValsSilent(tmp,tmp+newLgth); + connNewI->pushBackSilent(connNewI->back()+(int)newLgth); + delete [] tmp; + } + else + { + connNew->pushBackValsSilent(connOld+pos,connOld+posP1); + connNewI->pushBackSilent(connNewI->back()+posP1-pos); + } + } + setConnectivity(connNew,connNewI,false);//false because computeTypes called just behind. + } + computeTypes(); +} + +/*! + * Converts all cells to either polygons (if \a this is a 2D mesh) or + * polyhedrons (if \a this is a 3D mesh). + * \warning As this method is purely for user-friendliness and no optimization is + * done to avoid construction of a useless vector, this method can be costly + * in memory. + * \throw If the coordinates array is not set. + * \throw If the nodal connectivity of cells is node defined. + * \throw If dimension of \a this mesh is not either 2 or 3. + */ +void MEDCouplingUMesh::convertAllToPoly() +{ + int nbOfCells=getNumberOfCells(); + std::vector cellIds(nbOfCells); + for(int i=0;i + * This method is useful to build an extruded unstructured mesh with polyhedrons as + * it releases the user from boring description of polyhedra connectivity in the valid + * format. + * \throw If \a this->getMeshDimension() != 3. + * \throw If \a this->getSpaceDimension() != 3. + * \throw If the nodal connectivity of cells is not defined. + * \throw If the coordinates array is not set. + * \throw If \a this mesh contains polyhedrons with the valid connectivity. + * \throw If \a this mesh contains polyhedrons with odd number of nodes. + * + * \if ENABLE_EXAMPLES + * \ref cpp_mcumesh_arePolyhedronsNotCorrectlyOriented "Here is a C++ example".
+ * \ref py_mcumesh_arePolyhedronsNotCorrectlyOriented "Here is a Python example". + * \endif + */ +void MEDCouplingUMesh::convertExtrudedPolyhedra() +{ + checkFullyDefined(); + if(getMeshDimension()!=3 || getSpaceDimension()!=3) + throw INTERP_KERNEL::Exception("MEDCouplingUMesh::convertExtrudedPolyhedra works on umeshes with meshdim equal to 3 and spaceDim equal to 3 too!"); + int nbOfCells=getNumberOfCells(); + MEDCouplingAutoRefCountObjectPtr newCi=DataArrayInt::New(); + newCi->alloc(nbOfCells+1,1); + int *newci=newCi->getPointer(); + const int *ci=_nodal_connec_index->getConstPointer(); + const int *c=_nodal_connec->getConstPointer(); + newci[0]=0; + for(int i=0;i newC=DataArrayInt::New(); + newC->alloc(newci[nbOfCells],1); + int *newc=newC->getPointer(); + for(int i=0;idecrRef(); _nodal_connec_index=newCi.retn(); + _nodal_connec->decrRef(); _nodal_connec=newC.retn(); +} + + +/*! + * Converts all polygons (if \a this is a 2D mesh) or polyhedrons (if \a this is a 3D + * mesh) to cells of classical types. This method is opposite to convertToPolyTypes(). + * \warning Cells of the result mesh are \b not sorted by geometric type, hence, + * to write this mesh to the MED file, its cells must be sorted using + * sortCellsInMEDFileFrmt(). + * \return \c true if at least one cell has been converted, \c false else. In the + * last case the nodal connectivity remains unchanged. + * \throw If the coordinates array is not set. + * \throw If the nodal connectivity of cells is not defined. + * \throw If \a this->getMeshDimension() < 0. + */ +bool MEDCouplingUMesh::unPolyze() +{ + checkFullyDefined(); + int mdim=getMeshDimension(); + if(mdim<0) + throw INTERP_KERNEL::Exception("MEDCouplingUMesh::unPolyze works on umeshes with meshdim equals to 0, 1 2 or 3 !"); + if(mdim<=1) + return false; + int nbOfCells=getNumberOfCells(); + if(nbOfCells<1) + return false; + int initMeshLgth=getMeshLength(); + int *conn=_nodal_connec->getPointer(); + int *index=_nodal_connec_index->getPointer(); + int posOfCurCell=0; + int newPos=0; + int lgthOfCurCell; + bool ret=false; + for(int i=0;i tmp=new int[lgthOfCurCell-1]; + std::copy(conn+posOfCurCell+1,conn+posOfCurCell+lgthOfCurCell,(int *)tmp); + newType=INTERP_KERNEL::CellSimplify::tryToUnPoly2D(cm.isQuadratic(),tmp,lgthOfCurCell-1,conn+newPos+1,newLgth); + break; + } + case 3: + { + int nbOfFaces,lgthOfPolyhConn; + INTERP_KERNEL::AutoPtr zipFullReprOfPolyh=INTERP_KERNEL::CellSimplify::getFullPolyh3DCell(type,conn+posOfCurCell+1,lgthOfCurCell-1,nbOfFaces,lgthOfPolyhConn); + newType=INTERP_KERNEL::CellSimplify::tryToUnPoly3D(zipFullReprOfPolyh,nbOfFaces,lgthOfPolyhConn,conn+newPos+1,newLgth); + break; + } + case 1: + { + newType=(lgthOfCurCell==3)?INTERP_KERNEL::NORM_SEG2:INTERP_KERNEL::NORM_POLYL; + break; + } + } + ret=ret || (newType!=type); + conn[newPos]=newType; + newPos+=newLgth+1; + posOfCurCell=index[i+1]; + index[i+1]=newPos; + } + else + { + std::copy(conn+posOfCurCell,conn+posOfCurCell+lgthOfCurCell,conn+newPos); + newPos+=lgthOfCurCell; + posOfCurCell+=lgthOfCurCell; + index[i+1]=newPos; + } + } + if(newPos!=initMeshLgth) + _nodal_connec->reAlloc(newPos); + if(ret) + computeTypes(); + return ret; +} + +/*! + * This method expects that spaceDimension is equal to 3 and meshDimension equal to 3. + * This method performs operation only on polyhedrons in \b this. If no polyhedrons exists in \b this, \b this remains unchanged. + * This method allows to merge if any coplanar 3DSurf cells that may appear in some polyhedrons cells. + * + * \param [in] eps is a relative precision that allows to establish if some 3D plane are coplanar or not. This epsilon is used to recenter around origin to have maximal + * precision. + */ +void MEDCouplingUMesh::simplifyPolyhedra(double eps) +{ + checkFullyDefined(); + if(getMeshDimension()!=3 || getSpaceDimension()!=3) + throw INTERP_KERNEL::Exception("MEDCouplingUMesh::simplifyPolyhedra : works on meshdimension 3 and spaceDimension 3 !"); + MEDCouplingAutoRefCountObjectPtr coords=getCoords()->deepCpy(); + coords->recenterForMaxPrecision(eps); + // + int nbOfCells=getNumberOfCells(); + const int *conn=_nodal_connec->getConstPointer(); + const int *index=_nodal_connec_index->getConstPointer(); + MEDCouplingAutoRefCountObjectPtr connINew=DataArrayInt::New(); + connINew->alloc(nbOfCells+1,1); + int *connINewPtr=connINew->getPointer(); *connINewPtr++=0; + MEDCouplingAutoRefCountObjectPtr connNew=DataArrayInt::New(); connNew->alloc(0,1); + bool changed=false; + for(int i=0;iinsertAtTheEnd(conn+index[i],conn+index[i+1]); + *connINewPtr=connNew->getNumberOfTuples(); + } + if(changed) + setConnectivity(connNew,connINew,false); +} + +/*! + * This method returns all node ids used in the connectivity of \b this. The data array returned has to be dealt by the caller. + * The returned node ids are sorted ascendingly. This method is close to MEDCouplingUMesh::getNodeIdsInUse except + * the format of the returned DataArrayInt instance. + * + * \return a newly allocated DataArrayInt sorted ascendingly of fetched node ids. + * \sa MEDCouplingUMesh::getNodeIdsInUse, areAllNodesFetched + */ +DataArrayInt *MEDCouplingUMesh::computeFetchedNodeIds() const +{ + checkConnectivityFullyDefined(); + int nbOfCells=getNumberOfCells(); + const int *connIndex=_nodal_connec_index->getConstPointer(); + const int *conn=_nodal_connec->getConstPointer(); + const int *maxEltPt=std::max_element(_nodal_connec->begin(),_nodal_connec->end()); + int maxElt=maxEltPt==_nodal_connec->end()?0:std::abs(*maxEltPt)+1; + std::vector retS(maxElt,false); + for(int i=0;i=0) + retS[conn[j]]=true; + int sz=0; + for(int i=0;ialloc(sz,1); + int *retPtr=ret->getPointer(); + for(int i=0;i& nodeIdsInUse) const +{ + int nbOfNodes((int)nodeIdsInUse.size()),nbOfCells(getNumberOfCells()); + const int *connIndex(_nodal_connec_index->getConstPointer()),*conn(_nodal_connec->getConstPointer()); + for(int i=0;i=0) + { + if(conn[j]getNumberOfNodes(). It holds for each node of \a this mesh either -1 + * if the node is unused or a new id else. The caller is to delete this + * array using decrRef() as it is no more needed. + * \throw If the coordinates array is not set. + * \throw If the nodal connectivity of cells is not defined. + * \throw If the nodal connectivity includes an invalid id. + * + * \if ENABLE_EXAMPLES + * \ref cpp_mcumesh_getNodeIdsInUse "Here is a C++ example".
+ * \ref py_mcumesh_getNodeIdsInUse "Here is a Python example". + * \endif + * \sa computeFetchedNodeIds, computeNodeIdsAlg() + */ +DataArrayInt *MEDCouplingUMesh::getNodeIdsInUse(int& nbrOfNodesInUse) const +{ + nbrOfNodesInUse=-1; + int nbOfNodes(getNumberOfNodes()); + MEDCouplingAutoRefCountObjectPtr ret=DataArrayInt::New(); + ret->alloc(nbOfNodes,1); + int *traducer=ret->getPointer(); + std::fill(traducer,traducer+nbOfNodes,-1); + int nbOfCells=getNumberOfCells(); + const int *connIndex=_nodal_connec_index->getConstPointer(); + const int *conn=_nodal_connec->getConstPointer(); + for(int i=0;i=0) + { + if(conn[j]getNumberOfCells() tuples and 1 component. + * For each cell in \b this the number of nodes constituting cell is computed. + * For each polyhedron cell, the sum of the number of nodes of each face constituting polyhedron cell is returned. + * So for pohyhedrons some nodes can be counted several times in the returned result. + * + * \return a newly allocated array + * \sa MEDCouplingUMesh::computeEffectiveNbOfNodesPerCell + */ +DataArrayInt *MEDCouplingUMesh::computeNbOfNodesPerCell() const +{ + checkConnectivityFullyDefined(); + int nbOfCells=getNumberOfCells(); + MEDCouplingAutoRefCountObjectPtr ret=DataArrayInt::New(); + ret->alloc(nbOfCells,1); + int *retPtr=ret->getPointer(); + const int *conn=getNodalConnectivity()->getConstPointer(); + const int *connI=getNodalConnectivityIndex()->getConstPointer(); + for(int i=0;i ret=DataArrayInt::New(); + ret->alloc(nbOfCells,1); + int *retPtr=ret->getPointer(); + const int *conn=getNodalConnectivity()->getConstPointer(); + const int *connI=getNodalConnectivityIndex()->getConstPointer(); + for(int i=0;i s(conn+connI[i]+1,conn+connI[i+1]); + if(conn[connI[i]]!=(int)INTERP_KERNEL::NORM_POLYHED) + *retPtr=(int)s.size(); + else + { + s.erase(-1); + *retPtr=(int)s.size(); + } + } + return ret.retn(); +} + +/*! + * This method returns a newly allocated array containing this->getNumberOfCells() tuples and 1 component. + * For each cell in \b this the number of faces constituting (entity of dimension this->getMeshDimension()-1) cell is computed. + * + * \return a newly allocated array + */ +DataArrayInt *MEDCouplingUMesh::computeNbOfFacesPerCell() const +{ + checkConnectivityFullyDefined(); + int nbOfCells=getNumberOfCells(); + MEDCouplingAutoRefCountObjectPtr ret=DataArrayInt::New(); + ret->alloc(nbOfCells,1); + int *retPtr=ret->getPointer(); + const int *conn=getNodalConnectivity()->getConstPointer(); + const int *connI=getNodalConnectivityIndex()->getConstPointer(); + for(int i=0;igetNumberOfNodes() before call of this method. The caller is to + * delete this array using decrRef() as it is no more needed. + * \throw If the coordinates array is not set. + * \throw If the nodal connectivity of cells is not defined. + * \throw If the nodal connectivity includes an invalid id. + * \sa areAllNodesFetched + * + * \if ENABLE_EXAMPLES + * \ref cpp_mcumesh_zipCoordsTraducer "Here is a C++ example".
+ * \ref py_mcumesh_zipCoordsTraducer "Here is a Python example". + * \endif + */ +DataArrayInt *MEDCouplingUMesh::zipCoordsTraducer() +{ + return MEDCouplingPointSet::zipCoordsTraducer(); +} + +/*! + * This method stands if 'cell1' and 'cell2' are equals regarding 'compType' policy. + * The semantic of 'compType' is specified in MEDCouplingPointSet::zipConnectivityTraducer method. + */ +int MEDCouplingUMesh::AreCellsEqual(const int *conn, const int *connI, int cell1, int cell2, int compType) +{ + switch(compType) + { + case 0: + return AreCellsEqual0(conn,connI,cell1,cell2); + case 1: + return AreCellsEqual1(conn,connI,cell1,cell2); + case 2: + return AreCellsEqual2(conn,connI,cell1,cell2); + case 3: + return AreCellsEqual3(conn,connI,cell1,cell2); + case 7: + return AreCellsEqual7(conn,connI,cell1,cell2); + } + throw INTERP_KERNEL::Exception("Unknown comparison asked ! Must be in 0,1,2,3 or 7."); +} + +/*! + * This method is the last step of the MEDCouplingPointSet::zipConnectivityTraducer with policy 0. + */ +int MEDCouplingUMesh::AreCellsEqual0(const int *conn, const int *connI, int cell1, int cell2) +{ + if(connI[cell1+1]-connI[cell1]==connI[cell2+1]-connI[cell2]) + return std::equal(conn+connI[cell1]+1,conn+connI[cell1+1],conn+connI[cell2]+1)?1:0; + return 0; +} + +/*! + * This method is the last step of the MEDCouplingPointSet::zipConnectivityTraducer with policy 1. + */ +int MEDCouplingUMesh::AreCellsEqual1(const int *conn, const int *connI, int cell1, int cell2) +{ + int sz=connI[cell1+1]-connI[cell1]; + if(sz==connI[cell2+1]-connI[cell2]) + { + if(conn[connI[cell1]]==conn[connI[cell2]]) + { + const INTERP_KERNEL::CellModel& cm=INTERP_KERNEL::CellModel::GetCellModel((INTERP_KERNEL::NormalizedCellType)conn[connI[cell1]]); + unsigned dim=cm.getDimension(); + if(dim!=3) + { + if(dim!=1) + { + int sz1=2*(sz-1); + INTERP_KERNEL::AutoPtr tmp=new int[sz1]; + int *work=std::copy(conn+connI[cell1]+1,conn+connI[cell1+1],(int *)tmp); + std::copy(conn+connI[cell1]+1,conn+connI[cell1+1],work); + work=std::search((int *)tmp,(int *)tmp+sz1,conn+connI[cell2]+1,conn+connI[cell2+1]); + return work!=tmp+sz1?1:0; + } + else + return std::equal(conn+connI[cell1]+1,conn+connI[cell1+1],conn+connI[cell2]+1)?1:0;//case of SEG2 and SEG3 + } + else + throw INTERP_KERNEL::Exception("MEDCouplingUMesh::AreCellsEqual1 : not implemented yet for meshdim == 3 !"); + } + } + return 0; +} + +/*! + * This method is the last step of the MEDCouplingPointSet::zipConnectivityTraducer with policy 2. + */ +int MEDCouplingUMesh::AreCellsEqual2(const int *conn, const int *connI, int cell1, int cell2) +{ + if(connI[cell1+1]-connI[cell1]==connI[cell2+1]-connI[cell2]) + { + if(conn[connI[cell1]]==conn[connI[cell2]]) + { + std::set s1(conn+connI[cell1]+1,conn+connI[cell1+1]); + std::set s2(conn+connI[cell2]+1,conn+connI[cell2+1]); + return s1==s2?1:0; + } + } + return 0; +} + +/*! + * This method is less restrictive than AreCellsEqual2. Here the geometric type is absolutely not taken into account ! + */ +int MEDCouplingUMesh::AreCellsEqual3(const int *conn, const int *connI, int cell1, int cell2) +{ + if(connI[cell1+1]-connI[cell1]==connI[cell2+1]-connI[cell2]) + { + std::set s1(conn+connI[cell1]+1,conn+connI[cell1+1]); + std::set s2(conn+connI[cell2]+1,conn+connI[cell2+1]); + return s1==s2?1:0; + } + return 0; +} + +/*! + * This method is the last step of the MEDCouplingPointSet::zipConnectivityTraducer with policy 7. + */ +int MEDCouplingUMesh::AreCellsEqual7(const int *conn, const int *connI, int cell1, int cell2) +{ + int sz=connI[cell1+1]-connI[cell1]; + if(sz==connI[cell2+1]-connI[cell2]) + { + if(conn[connI[cell1]]==conn[connI[cell2]]) + { + const INTERP_KERNEL::CellModel& cm=INTERP_KERNEL::CellModel::GetCellModel((INTERP_KERNEL::NormalizedCellType)conn[connI[cell1]]); + unsigned dim=cm.getDimension(); + if(dim!=3) + { + if(dim!=1) + { + int sz1=2*(sz-1); + INTERP_KERNEL::AutoPtr tmp=new int[sz1]; + int *work=std::copy(conn+connI[cell1]+1,conn+connI[cell1+1],(int *)tmp); + std::copy(conn+connI[cell1]+1,conn+connI[cell1+1],work); + work=std::search((int *)tmp,(int *)tmp+sz1,conn+connI[cell2]+1,conn+connI[cell2+1]); + if(work!=tmp+sz1) + return 1; + else + { + std::reverse_iterator it1((int *)tmp+sz1); + std::reverse_iterator it2((int *)tmp); + if(std::search(it1,it2,conn+connI[cell2]+1,conn+connI[cell2+1])!=it2) + return 2; + else + return 0; + } + + return work!=tmp+sz1?1:0; + } + else + {//case of SEG2 and SEG3 + if(std::equal(conn+connI[cell1]+1,conn+connI[cell1+1],conn+connI[cell2]+1)) + return 1; + if(!cm.isQuadratic()) + { + std::reverse_iterator it1(conn+connI[cell1+1]); + std::reverse_iterator it2(conn+connI[cell1]+1); + if(std::equal(it1,it2,conn+connI[cell2]+1)) + return 2; + return 0; + } + else + { + if(conn[connI[cell1]+1]==conn[connI[cell2]+2] && conn[connI[cell1]+2]==conn[connI[cell2]+1] && conn[connI[cell1]+3]==conn[connI[cell2]+3]) + return 2; + return 0; + } + } + } + else + throw INTERP_KERNEL::Exception("MEDCouplingUMesh::AreCellsEqual7 : not implemented yet for meshdim == 3 !"); + } + } + return 0; +} + +/*! + * This method find in candidate pool defined by 'candidates' the cells equal following the polycy 'compType'. + * If any true is returned and the results will be put at the end of 'result' output parameter. If not false is returned + * and result remains unchanged. + * The semantic of 'compType' is specified in MEDCouplingPointSet::zipConnectivityTraducer method. + * If in 'candidates' pool -1 value is considered as an empty value. + * WARNING this method returns only ONE set of result ! + */ +bool MEDCouplingUMesh::AreCellsEqualInPool(const std::vector& candidates, int compType, const int *conn, const int *connI, DataArrayInt *result) +{ + if(candidates.size()<1) + return false; + bool ret=false; + std::vector::const_iterator iter=candidates.begin(); + int start=(*iter++); + for(;iter!=candidates.end();iter++) + { + int status=AreCellsEqual(conn,connI,start,*iter,compType); + if(status!=0) + { + if(!ret) + { + result->pushBackSilent(start); + ret=true; + } + if(status==1) + result->pushBackSilent(*iter); + else + result->pushBackSilent(status==2?(*iter+1):-(*iter+1)); + } + } + return ret; +} + +/*! + * This method find cells that are equal (regarding \a compType) in \a this. The comparison is specified + * by \a compType. + * This method keeps the coordiantes of \a this. This method is time consuming. + * + * \param [in] compType input specifying the technique used to compare cells each other. + * - 0 : exactly. A cell is detected to be the same if and only if the connectivity is exactly the same without permutation and types same too. This is the strongest policy. + * - 1 : permutation same orientation. cell1 and cell2 are considered equal if the connectivity of cell2 can be deduced by those of cell1 by direct permutation (with exactly the same orientation) + * and their type equal. For 1D mesh the policy 1 is equivalent to 0. + * - 2 : nodal. cell1 and cell2 are equal if and only if cell1 and cell2 have same type and have the same nodes constituting connectivity. This is the laziest policy. This policy + * can be used for users not sensitive to orientation of cell + * \param [in] startCellId specifies the cellId starting from which the equality computation will be carried out. By default it is 0, which it means that all cells in \a this will be scanned. + * \param [out] commonCellsArr common cells ids (\ref numbering-indirect) + * \param [out] commonCellsIArr common cells ids (\ref numbering-indirect) + * \return the correspondance array old to new in a newly allocated array. + * + */ +void MEDCouplingUMesh::findCommonCells(int compType, int startCellId, DataArrayInt *& commonCellsArr, DataArrayInt *& commonCellsIArr) const +{ + MEDCouplingAutoRefCountObjectPtr revNodal=DataArrayInt::New(),revNodalI=DataArrayInt::New(); + getReverseNodalConnectivity(revNodal,revNodalI); + FindCommonCellsAlg(compType,startCellId,_nodal_connec,_nodal_connec_index,revNodal,revNodalI,commonCellsArr,commonCellsIArr); +} + +void MEDCouplingUMesh::FindCommonCellsAlg(int compType, int startCellId, const DataArrayInt *nodal, const DataArrayInt *nodalI, const DataArrayInt *revNodal, const DataArrayInt *revNodalI, + DataArrayInt *& commonCellsArr, DataArrayInt *& commonCellsIArr) +{ + MEDCouplingAutoRefCountObjectPtr commonCells=DataArrayInt::New(),commonCellsI=DataArrayInt::New(); commonCells->alloc(0,1); + int nbOfCells=nodalI->getNumberOfTuples()-1; + commonCellsI->reserve(1); commonCellsI->pushBackSilent(0); + const int *revNodalPtr=revNodal->getConstPointer(),*revNodalIPtr=revNodalI->getConstPointer(); + const int *connPtr=nodal->getConstPointer(),*connIPtr=nodalI->getConstPointer(); + std::vector isFetched(nbOfCells,false); + if(startCellId==0) + { + for(int i=0;i(),-1)); + std::vector v,v2; + if(connOfNode!=connPtr+connIPtr[i+1]) + { + const int *locRevNodal=std::find(revNodalPtr+revNodalIPtr[*connOfNode],revNodalPtr+revNodalIPtr[*connOfNode+1],i); + v2.insert(v2.end(),locRevNodal,revNodalPtr+revNodalIPtr[*connOfNode+1]); + connOfNode++; + } + for(;connOfNode!=connPtr+connIPtr[i+1] && v2.size()>1;connOfNode++) + if(*connOfNode>=0) + { + v=v2; + const int *locRevNodal=std::find(revNodalPtr+revNodalIPtr[*connOfNode],revNodalPtr+revNodalIPtr[*connOfNode+1],i); + std::vector::iterator it=std::set_intersection(v.begin(),v.end(),locRevNodal,revNodalPtr+revNodalIPtr[*connOfNode+1],v2.begin()); + v2.resize(std::distance(v2.begin(),it)); + } + if(v2.size()>1) + { + if(AreCellsEqualInPool(v2,compType,connPtr,connIPtr,commonCells)) + { + int pos=commonCellsI->back(); + commonCellsI->pushBackSilent(commonCells->getNumberOfTuples()); + for(const int *it=commonCells->begin()+pos;it!=commonCells->end();it++) + isFetched[*it]=true; + } + } + } + } + } + else + { + for(int i=startCellId;i(),-1)); + std::vector v,v2; + if(connOfNode!=connPtr+connIPtr[i+1]) + { + v2.insert(v2.end(),revNodalPtr+revNodalIPtr[*connOfNode],revNodalPtr+revNodalIPtr[*connOfNode+1]); + connOfNode++; + } + for(;connOfNode!=connPtr+connIPtr[i+1] && v2.size()>1;connOfNode++) + if(*connOfNode>=0) + { + v=v2; + std::vector::iterator it=std::set_intersection(v.begin(),v.end(),revNodalPtr+revNodalIPtr[*connOfNode],revNodalPtr+revNodalIPtr[*connOfNode+1],v2.begin()); + v2.resize(std::distance(v2.begin(),it)); + } + if(v2.size()>1) + { + if(AreCellsEqualInPool(v2,compType,connPtr,connIPtr,commonCells)) + { + int pos=commonCellsI->back(); + commonCellsI->pushBackSilent(commonCells->getNumberOfTuples()); + for(const int *it=commonCells->begin()+pos;it!=commonCells->end();it++) + isFetched[*it]=true; + } + } + } + } + } + commonCellsArr=commonCells.retn(); + commonCellsIArr=commonCellsI.retn(); +} + +/*! + * Checks if \a this mesh includes all cells of an \a other mesh, and returns an array + * giving for each cell of the \a other an id of a cell in \a this mesh. A value larger + * than \a other->getNumberOfCells() in the returned array means that there is no + * corresponding cell in \a this mesh. + * It is expected that \a this and \a other meshes share the same node coordinates + * array, if it is not so an exception is thrown. + * \param [in] other - the mesh to compare with. + * \param [in] compType - specifies a cell comparison technique. For meaning of its + * valid values [0,1,2], see zipConnectivityTraducer(). + * \param [out] arr - a new instance of DataArrayInt returning correspondence + * between cells of the two meshes. It contains \a other->getNumberOfCells() + * values. The caller is to delete this array using + * decrRef() as it is no more needed. + * \return bool - \c true if all cells of \a other mesh are present in the \a this + * mesh. + * + * \if ENABLE_EXAMPLES + * \ref cpp_mcumesh_areCellsIncludedIn "Here is a C++ example".
+ * \ref py_mcumesh_areCellsIncludedIn "Here is a Python example". + * \endif + * \sa checkDeepEquivalOnSameNodesWith() + * \sa checkGeoEquivalWith() + */ +bool MEDCouplingUMesh::areCellsIncludedIn(const MEDCouplingUMesh *other, int compType, DataArrayInt *& arr) const +{ + MEDCouplingAutoRefCountObjectPtr mesh=MergeUMeshesOnSameCoords(this,other); + int nbOfCells=getNumberOfCells(); + static const int possibleCompType[]={0,1,2}; + if(std::find(possibleCompType,possibleCompType+sizeof(possibleCompType)/sizeof(int),compType)==possibleCompType+sizeof(possibleCompType)/sizeof(int)) + { + std::ostringstream oss; oss << "MEDCouplingUMesh::areCellsIncludedIn : only following policies are possible : "; + std::copy(possibleCompType,possibleCompType+sizeof(possibleCompType)/sizeof(int),std::ostream_iterator(oss," ")); + oss << " !"; + throw INTERP_KERNEL::Exception(oss.str().c_str()); + } + MEDCouplingAutoRefCountObjectPtr o2n=mesh->zipConnectivityTraducer(compType,nbOfCells); + arr=o2n->substr(nbOfCells); + arr->setName(other->getName()); + int tmp; + if(other->getNumberOfCells()==0) + return true; + return arr->getMaxValue(tmp)getNumberOfCells()'. + * \return If \a other is fully included in 'this 'true is returned. If not false is returned. + */ +bool MEDCouplingUMesh::areCellsIncludedIn2(const MEDCouplingUMesh *other, DataArrayInt *& arr) const +{ + MEDCouplingAutoRefCountObjectPtr mesh=MergeUMeshesOnSameCoords(this,other); + DataArrayInt *commonCells=0,*commonCellsI=0; + int thisNbCells=getNumberOfCells(); + mesh->findCommonCells(7,thisNbCells,commonCells,commonCellsI); + MEDCouplingAutoRefCountObjectPtr commonCellsTmp(commonCells),commonCellsITmp(commonCellsI); + const int *commonCellsPtr=commonCells->getConstPointer(),*commonCellsIPtr=commonCellsI->getConstPointer(); + int otherNbCells=other->getNumberOfCells(); + MEDCouplingAutoRefCountObjectPtr arr2=DataArrayInt::New(); + arr2->alloc(otherNbCells,1); + arr2->fillWithZero(); + int *arr2Ptr=arr2->getPointer(); + int nbOfCommon=commonCellsI->getNumberOfTuples()-1; + for(int i=0;i0?1:-1; + int val=std::abs(commonCellsPtr[j])-1; + if(val>=thisNbCells) + arr2Ptr[val-thisNbCells]=sig*(start+1); + } + } + } + arr2->setName(other->getName()); + if(arr2->presenceOfValue(0)) + return false; + arr=arr2.retn(); + return true; +} + +MEDCouplingPointSet *MEDCouplingUMesh::mergeMyselfWithOnSameCoords(const MEDCouplingPointSet *other) const +{ + if(!other) + throw INTERP_KERNEL::Exception("MEDCouplingUMesh::mergeMyselfWithOnSameCoords : input other is null !"); + const MEDCouplingUMesh *otherC=dynamic_cast(other); + if(!otherC) + throw INTERP_KERNEL::Exception("MEDCouplingUMesh::mergeMyselfWithOnSameCoords : the input other mesh is not of type unstructured !"); + std::vector ms(2); + ms[0]=this; + ms[1]=otherC; + return MergeUMeshesOnSameCoords(ms); +} + +/*! + * Build a sub part of \b this lying or not on the same coordinates than \b this (regarding value of \b keepCoords). + * By default coordinates are kept. This method is close to MEDCouplingUMesh::buildPartOfMySelf except that here input + * cellIds is not given explicitely but by a range python like. + * + * \param start + * \param end + * \param step + * \param keepCoords that specifies if you want or not to keep coords as this or zip it (see ParaMEDMEM::MEDCouplingUMesh::zipCoords). If true zipCoords is \b NOT called, if false, zipCoords is called. + * \return a newly allocated + * + * \warning This method modifies can generate an unstructured mesh whose cells are not sorted by geometric type order. + * In view of the MED file writing, a renumbering of cells of returned unstructured mesh (using MEDCouplingUMesh::sortCellsInMEDFileFrmt) should be necessary. + */ +MEDCouplingPointSet *MEDCouplingUMesh::buildPartOfMySelf2(int start, int end, int step, bool keepCoords) const +{ + if(getMeshDimension()!=-1) + return MEDCouplingPointSet::buildPartOfMySelf2(start,end,step,keepCoords); + else + { + int newNbOfCells=DataArray::GetNumberOfItemGivenBESRelative(start,end,step,"MEDCouplingUMesh::buildPartOfMySelf2 for -1 dimension mesh "); + if(newNbOfCells!=1) + throw INTERP_KERNEL::Exception("-1D mesh has only one cell !"); + if(start!=0) + throw INTERP_KERNEL::Exception("-1D mesh has only one cell : 0 !"); + incrRef(); + return const_cast(this); + } +} + +/*! + * Creates a new MEDCouplingUMesh containing specified cells of \a this mesh. + * The result mesh shares or not the node coordinates array with \a this mesh depending + * on \a keepCoords parameter. + * \warning Cells of the result mesh can be \b not sorted by geometric type, hence, + * to write this mesh to the MED file, its cells must be sorted using + * sortCellsInMEDFileFrmt(). + * \param [in] begin - an array of cell ids to include to the new mesh. + * \param [in] end - a pointer to last-plus-one-th element of \a begin. + * \param [in] keepCoords - if \c true, the result mesh shares the node coordinates + * array of \a this mesh, else "free" nodes are removed from the result mesh + * by calling zipCoords(). + * \return MEDCouplingPointSet * - a new instance of MEDCouplingUMesh. The caller is + * to delete this mesh using decrRef() as it is no more needed. + * \throw If the coordinates array is not set. + * \throw If the nodal connectivity of cells is not defined. + * \throw If any cell id in the array \a begin is not valid. + * + * \if ENABLE_EXAMPLES + * \ref cpp_mcumesh_buildPartOfMySelf "Here is a C++ example".
+ * \ref py_mcumesh_buildPartOfMySelf "Here is a Python example". + * \endif + */ +MEDCouplingPointSet *MEDCouplingUMesh::buildPartOfMySelf(const int *begin, const int *end, bool keepCoords) const +{ + if(getMeshDimension()!=-1) + return MEDCouplingPointSet::buildPartOfMySelf(begin,end,keepCoords); + else + { + if(end-begin!=1) + throw INTERP_KERNEL::Exception("-1D mesh has only one cell !"); + if(begin[0]!=0) + throw INTERP_KERNEL::Exception("-1D mesh has only one cell : 0 !"); + incrRef(); + return const_cast(this); + } +} + +/*! + * This method operates only on nodal connectivity on \b this. Coordinates of \b this is completely ignored here. + * + * This method allows to partially modify some cells in \b this (whose list is specified by [ \b cellIdsBg, \b cellIdsEnd ) ) with cells coming in \b otherOnSameCoordsThanThis. + * Size of [ \b cellIdsBg, \b cellIdsEnd ) ) must be equal to the number of cells of otherOnSameCoordsThanThis. + * The number of cells of \b this will remain the same with this method. + * + * \param [in] cellIdsBg begin of cell ids (included) of cells in this to assign + * \param [in] cellIdsEnd end of cell ids (excluded) of cells in this to assign + * \param [in] otherOnSameCoordsThanThis an another mesh with same meshdimension than \b this with exactly the same number of cells than cell ids list in [\b cellIdsBg, \b cellIdsEnd ). + * Coordinate pointer of \b this and those of \b otherOnSameCoordsThanThis must be the same + */ +void MEDCouplingUMesh::setPartOfMySelf(const int *cellIdsBg, const int *cellIdsEnd, const MEDCouplingUMesh& otherOnSameCoordsThanThis) +{ + checkConnectivityFullyDefined(); + otherOnSameCoordsThanThis.checkConnectivityFullyDefined(); + if(getCoords()!=otherOnSameCoordsThanThis.getCoords()) + throw INTERP_KERNEL::Exception("MEDCouplingUMesh::setPartOfMySelf : coordinates pointer are not the same ! Invoke setCoords or call tryToShareSameCoords method !"); + if(getMeshDimension()!=otherOnSameCoordsThanThis.getMeshDimension()) + { + std::ostringstream oss; oss << "MEDCouplingUMesh::setPartOfMySelf : Mismatch of meshdimensions ! this is equal to " << getMeshDimension(); + oss << ", whereas other mesh dimension is set equal to " << otherOnSameCoordsThanThis.getMeshDimension() << " !"; + throw INTERP_KERNEL::Exception(oss.str().c_str()); + } + int nbOfCellsToModify=(int)std::distance(cellIdsBg,cellIdsEnd); + if(nbOfCellsToModify!=otherOnSameCoordsThanThis.getNumberOfCells()) + { + std::ostringstream oss; oss << "MEDCouplingUMesh::setPartOfMySelf : cells ids length (" << nbOfCellsToModify << ") do not match the number of cells of other mesh (" << otherOnSameCoordsThanThis.getNumberOfCells() << ") !"; + throw INTERP_KERNEL::Exception(oss.str().c_str()); + } + int nbOfCells=getNumberOfCells(); + bool easyAssign=true; + const int *connI=_nodal_connec_index->getConstPointer(); + const int *connIOther=otherOnSameCoordsThanThis._nodal_connec_index->getConstPointer(); + for(const int *it=cellIdsBg;it!=cellIdsEnd && easyAssign;it++,connIOther++) + { + if(*it>=0 && *it arrOutAuto(arrOut),arrIOutAuto(arrIOut); + setConnectivity(arrOut,arrIOut,true); + } +} + +void MEDCouplingUMesh::setPartOfMySelf2(int start, int end, int step, const MEDCouplingUMesh& otherOnSameCoordsThanThis) +{ + checkConnectivityFullyDefined(); + otherOnSameCoordsThanThis.checkConnectivityFullyDefined(); + if(getCoords()!=otherOnSameCoordsThanThis.getCoords()) + throw INTERP_KERNEL::Exception("MEDCouplingUMesh::setPartOfMySelf2 : coordinates pointer are not the same ! Invoke setCoords or call tryToShareSameCoords method !"); + if(getMeshDimension()!=otherOnSameCoordsThanThis.getMeshDimension()) + { + std::ostringstream oss; oss << "MEDCouplingUMesh::setPartOfMySelf2 : Mismatch of meshdimensions ! this is equal to " << getMeshDimension(); + oss << ", whereas other mesh dimension is set equal to " << otherOnSameCoordsThanThis.getMeshDimension() << " !"; + throw INTERP_KERNEL::Exception(oss.str().c_str()); + } + int nbOfCellsToModify=DataArray::GetNumberOfItemGivenBESRelative(start,end,step,"MEDCouplingUMesh::setPartOfMySelf2 : "); + if(nbOfCellsToModify!=otherOnSameCoordsThanThis.getNumberOfCells()) + { + std::ostringstream oss; oss << "MEDCouplingUMesh::setPartOfMySelf2 : cells ids length (" << nbOfCellsToModify << ") do not match the number of cells of other mesh (" << otherOnSameCoordsThanThis.getNumberOfCells() << ") !"; + throw INTERP_KERNEL::Exception(oss.str().c_str()); + } + int nbOfCells=getNumberOfCells(); + bool easyAssign=true; + const int *connI=_nodal_connec_index->getConstPointer(); + const int *connIOther=otherOnSameCoordsThanThis._nodal_connec_index->getConstPointer(); + int it=start; + for(int i=0;i=0 && it arrOutAuto(arrOut),arrIOutAuto(arrIOut); + setConnectivity(arrOut,arrIOut,true); + } +} + +/*! + * Keeps from \a this only cells which constituing point id are in the ids specified by [ \a begin,\a end ). + * The resulting cell ids are stored at the end of the 'cellIdsKept' parameter. + * Parameter \a fullyIn specifies if a cell that has part of its nodes in ids array is kept or not. + * If \a fullyIn is true only cells whose ids are \b fully contained in [ \a begin,\a end ) tab will be kept. + * + * \param [in] begin input start of array of node ids. + * \param [in] end input end of array of node ids. + * \param [in] fullyIn input that specifies if all node ids must be in [ \a begin,\a end ) array to consider cell to be in. + * \param [in,out] cellIdsKeptArr array where all candidate cell ids are put at the end. + */ +void MEDCouplingUMesh::fillCellIdsToKeepFromNodeIds(const int *begin, const int *end, bool fullyIn, DataArrayInt *&cellIdsKeptArr) const +{ + MEDCouplingAutoRefCountObjectPtr cellIdsKept=DataArrayInt::New(); cellIdsKept->alloc(0,1); + checkConnectivityFullyDefined(); + int tmp=-1; + int sz=getNodalConnectivity()->getMaxValue(tmp); sz=std::max(sz,0)+1; + std::vector fastFinder(sz,false); + for(const int *work=begin;work!=end;work++) + if(*work>=0 && *workgetConstPointer(); + const int *connIndex=getNodalConnectivityIndex()->getConstPointer(); + for(int i=0;i=0) + { + ref++; + if(fastFinder[*work2]) + nbOfHit++; + } + if((ref==nbOfHit && fullyIn) || (nbOfHit!=0 && !fullyIn)) + cellIdsKept->pushBackSilent(i); + } + cellIdsKeptArr=cellIdsKept.retn(); +} + +/*! + * Creates a new MEDCouplingUMesh containing cells, of dimension one less than \a + * this->getMeshDimension(), that bound some cells of \a this mesh. + * The cells of lower dimension to include to the result mesh are selected basing on + * specified node ids and the value of \a fullyIn parameter. If \a fullyIn ==\c true, a + * cell is copied if its all nodes are in the array \a begin of node ids. If \a fullyIn + * ==\c false, a cell is copied if any its node is in the array of node ids. The + * created mesh shares the node coordinates array with \a this mesh. + * \param [in] begin - the array of node ids. + * \param [in] end - a pointer to the (last+1)-th element of \a begin. + * \param [in] fullyIn - if \c true, then cells whose all nodes are in the + * array \a begin are added, else cells whose any node is in the + * array \a begin are added. + * \return MEDCouplingPointSet * - new instance of MEDCouplingUMesh. The caller is + * to delete this mesh using decrRef() as it is no more needed. + * \throw If the coordinates array is not set. + * \throw If the nodal connectivity of cells is not defined. + * \throw If any node id in \a begin is not valid. + * + * \if ENABLE_EXAMPLES + * \ref cpp_mcumesh_buildFacePartOfMySelfNode "Here is a C++ example".
+ * \ref py_mcumesh_buildFacePartOfMySelfNode "Here is a Python example". + * \endif + */ +MEDCouplingPointSet *MEDCouplingUMesh::buildFacePartOfMySelfNode(const int *begin, const int *end, bool fullyIn) const +{ + MEDCouplingAutoRefCountObjectPtr desc,descIndx,revDesc,revDescIndx; + desc=DataArrayInt::New(); descIndx=DataArrayInt::New(); revDesc=DataArrayInt::New(); revDescIndx=DataArrayInt::New(); + MEDCouplingAutoRefCountObjectPtr subMesh=buildDescendingConnectivity(desc,descIndx,revDesc,revDescIndx); + desc=0; descIndx=0; revDesc=0; revDescIndx=0; + return subMesh->buildPartOfMySelfNode(begin,end,fullyIn); +} + +/*! + * Creates a new MEDCouplingUMesh containing cells, of dimension one less than \a + * this->getMeshDimension(), which bound only one cell of \a this mesh. + * \param [in] keepCoords - if \c true, the result mesh shares the node coordinates + * array of \a this mesh, else "free" nodes are removed from the result mesh + * by calling zipCoords(). + * \return MEDCouplingPointSet * - a new instance of MEDCouplingUMesh. The caller is + * to delete this mesh using decrRef() as it is no more needed. + * \throw If the coordinates array is not set. + * \throw If the nodal connectivity of cells is not defined. + * + * \if ENABLE_EXAMPLES + * \ref cpp_mcumesh_buildBoundaryMesh "Here is a C++ example".
+ * \ref py_mcumesh_buildBoundaryMesh "Here is a Python example". + * \endif + */ +MEDCouplingPointSet *MEDCouplingUMesh::buildBoundaryMesh(bool keepCoords) const +{ + DataArrayInt *desc=DataArrayInt::New(); + DataArrayInt *descIndx=DataArrayInt::New(); + DataArrayInt *revDesc=DataArrayInt::New(); + DataArrayInt *revDescIndx=DataArrayInt::New(); + // + MEDCouplingAutoRefCountObjectPtr meshDM1=buildDescendingConnectivity(desc,descIndx,revDesc,revDescIndx); + revDesc->decrRef(); + desc->decrRef(); + descIndx->decrRef(); + int nbOfCells=meshDM1->getNumberOfCells(); + const int *revDescIndxC=revDescIndx->getConstPointer(); + std::vector boundaryCells; + for(int i=0;idecrRef(); + MEDCouplingPointSet *ret=meshDM1->buildPartOfMySelf(&boundaryCells[0],&boundaryCells[0]+boundaryCells.size(),keepCoords); + return ret; +} + +/*! + * This method returns a newly created DataArrayInt instance containing ids of cells located in boundary. + * A cell is detected to be on boundary if it contains one or more than one face having only one father. + * This method makes the assumption that \a this is fully defined (coords,connectivity). If not an exception will be thrown. + */ +DataArrayInt *MEDCouplingUMesh::findCellIdsOnBoundary() const +{ + checkFullyDefined(); + MEDCouplingAutoRefCountObjectPtr desc=DataArrayInt::New(); + MEDCouplingAutoRefCountObjectPtr descIndx=DataArrayInt::New(); + MEDCouplingAutoRefCountObjectPtr revDesc=DataArrayInt::New(); + MEDCouplingAutoRefCountObjectPtr revDescIndx=DataArrayInt::New(); + // + buildDescendingConnectivity(desc,descIndx,revDesc,revDescIndx)->decrRef(); + desc=(DataArrayInt*)0; descIndx=(DataArrayInt*)0; + // + MEDCouplingAutoRefCountObjectPtr tmp=revDescIndx->deltaShiftIndex(); + MEDCouplingAutoRefCountObjectPtr faceIds=tmp->getIdsEqual(1); tmp=(DataArrayInt*)0; + const int *revDescPtr=revDesc->getConstPointer(); + const int *revDescIndxPtr=revDescIndx->getConstPointer(); + int nbOfCells=getNumberOfCells(); + std::vector ret1(nbOfCells,false); + int sz=0; + for(const int *pt=faceIds->begin();pt!=faceIds->end();pt++) + if(!ret1[revDescPtr[revDescIndxPtr[*pt]]]) + { ret1[revDescPtr[revDescIndxPtr[*pt]]]=true; sz++; } + // + DataArrayInt *ret2=DataArrayInt::New(); + ret2->alloc(sz,1); + int *ret2Ptr=ret2->getPointer(); + sz=0; + for(std::vector::const_iterator it=ret1.begin();it!=ret1.end();it++,sz++) + if(*it) + *ret2Ptr++=sz; + ret2->setName("BoundaryCells"); + return ret2; +} + +/*! + * This method finds in \b this the cell ids that lie on mesh \b otherDimM1OnSameCoords. + * \b this and \b otherDimM1OnSameCoords have to lie on the same coordinate array pointer. The coherency of that coords array with connectivity + * of \b this and \b otherDimM1OnSameCoords is not important here because this method works only on connectivity. + * this->getMeshDimension() - 1 must be equal to otherDimM1OnSameCoords.getMeshDimension() + * + * s0 is the cell ids set in \b this lying on at least one node in the fetched nodes in \b otherDimM1OnSameCoords. + * This method also returns the cells ids set s1 which contains the cell ids in \b this for which one of the dim-1 constituent + * equals a cell in \b otherDimM1OnSameCoords. + * + * \throw if \b otherDimM1OnSameCoords is not part of constituent of \b this, or if coordinate pointer of \b this and \b otherDimM1OnSameCoords + * are not same, or if this->getMeshDimension()-1!=otherDimM1OnSameCoords.getMeshDimension() + * + * \param [in] otherDimM1OnSameCoords + * \param [out] cellIdsRk0 a newly allocated array containing the cell ids of s0 (which are cell ids of \b this) in the above algorithm. + * \param [out] cellIdsRk1 a newly allocated array containing the cell ids of s1 \b indexed into the \b cellIdsRk0 subset. To get the absolute ids of s1, simply invoke + * cellIdsRk1->transformWithIndArr(cellIdsRk0->begin(),cellIdsRk0->end()); + */ +void MEDCouplingUMesh::findCellIdsLyingOn(const MEDCouplingUMesh& otherDimM1OnSameCoords, DataArrayInt *&cellIdsRk0, DataArrayInt *&cellIdsRk1) const +{ + if(getCoords()!=otherDimM1OnSameCoords.getCoords()) + throw INTERP_KERNEL::Exception("MEDCouplingUMesh::findCellIdsLyingOn : coordinates pointer are not the same ! Use tryToShareSameCoords method !"); + checkConnectivityFullyDefined(); + otherDimM1OnSameCoords.checkConnectivityFullyDefined(); + if(getMeshDimension()-1!=otherDimM1OnSameCoords.getMeshDimension()) + throw INTERP_KERNEL::Exception("MEDCouplingUMesh::findCellIdsLyingOn : invalid mesh dimension of input mesh regarding meshdimesion of this !"); + MEDCouplingAutoRefCountObjectPtr fetchedNodeIds1=otherDimM1OnSameCoords.computeFetchedNodeIds(); + MEDCouplingAutoRefCountObjectPtr s0arr=getCellIdsLyingOnNodes(fetchedNodeIds1->begin(),fetchedNodeIds1->end(),false); + MEDCouplingAutoRefCountObjectPtr thisPart=static_cast(buildPartOfMySelf(s0arr->begin(),s0arr->end(),true)); + MEDCouplingAutoRefCountObjectPtr descThisPart=DataArrayInt::New(),descIThisPart=DataArrayInt::New(),revDescThisPart=DataArrayInt::New(),revDescIThisPart=DataArrayInt::New(); + MEDCouplingAutoRefCountObjectPtr thisPartConsti=thisPart->buildDescendingConnectivity(descThisPart,descIThisPart,revDescThisPart,revDescIThisPart); + const int *revDescThisPartPtr=revDescThisPart->getConstPointer(),*revDescIThisPartPtr=revDescIThisPart->getConstPointer(); + DataArrayInt *idsOtherInConsti=0; + bool b=thisPartConsti->areCellsIncludedIn(&otherDimM1OnSameCoords,2,idsOtherInConsti); + MEDCouplingAutoRefCountObjectPtr idsOtherInConstiAuto(idsOtherInConsti); + if(!b) + throw INTERP_KERNEL::Exception("MEDCouplingUMesh::findCellIdsLyingOn : the given mdim-1 mesh in other is not a constituent of this !"); + std::set s1; + for(const int *idOther=idsOtherInConsti->begin();idOther!=idsOtherInConsti->end();idOther++) + s1.insert(revDescThisPartPtr+revDescIThisPartPtr[*idOther],revDescThisPartPtr+revDescIThisPartPtr[*idOther+1]); + MEDCouplingAutoRefCountObjectPtr s1arr_renum1=DataArrayInt::New(); s1arr_renum1->alloc((int)s1.size(),1); std::copy(s1.begin(),s1.end(),s1arr_renum1->getPointer()); + s1arr_renum1->sort(); + cellIdsRk0=s0arr.retn(); + //cellIdsRk1=s_renum1.retn(); + cellIdsRk1=s1arr_renum1.retn(); +} + +/*! + * This method computes the skin of \b this. That is to say the consituting meshdim-1 mesh is built and only the boundary subpart is + * returned. This subpart of meshdim-1 mesh is built using meshdim-1 cells in it shared only one cell in \b this. + * + * \return a newly allocated mesh lying on the same coordinates than \b this. The caller has to deal with returned mesh. + */ +MEDCouplingUMesh *MEDCouplingUMesh::computeSkin() const +{ + MEDCouplingAutoRefCountObjectPtr desc=DataArrayInt::New(); + MEDCouplingAutoRefCountObjectPtr descIndx=DataArrayInt::New(); + MEDCouplingAutoRefCountObjectPtr revDesc=DataArrayInt::New(); + MEDCouplingAutoRefCountObjectPtr revDescIndx=DataArrayInt::New(); + // + MEDCouplingAutoRefCountObjectPtr meshDM1=buildDescendingConnectivity(desc,descIndx,revDesc,revDescIndx); + revDesc=0; desc=0; descIndx=0; + MEDCouplingAutoRefCountObjectPtr revDescIndx2=revDescIndx->deltaShiftIndex(); + MEDCouplingAutoRefCountObjectPtr part=revDescIndx2->getIdsEqual(1); + return static_cast(meshDM1->buildPartOfMySelf(part->begin(),part->end(),true)); +} + +/*! + * Finds nodes lying on the boundary of \a this mesh. + * \return DataArrayInt * - a new instance of DataArrayInt holding ids of found + * nodes. The caller is to delete this array using decrRef() as it is no + * more needed. + * \throw If the coordinates array is not set. + * \throw If the nodal connectivity of cells is node defined. + * + * \if ENABLE_EXAMPLES + * \ref cpp_mcumesh_findBoundaryNodes "Here is a C++ example".
+ * \ref py_mcumesh_findBoundaryNodes "Here is a Python example". + * \endif + */ +DataArrayInt *MEDCouplingUMesh::findBoundaryNodes() const +{ + MEDCouplingAutoRefCountObjectPtr skin=computeSkin(); + return skin->computeFetchedNodeIds(); +} + +MEDCouplingUMesh *MEDCouplingUMesh::buildUnstructured() const +{ + incrRef(); + return const_cast(this); +} + +/*! + * This method expects that \b this and \b otherDimM1OnSameCoords share the same coordinates array. + * otherDimM1OnSameCoords->getMeshDimension() is expected to be equal to this->getMeshDimension()-1. + * This method searches for nodes needed to be duplicated. These nodes are nodes fetched by \b otherDimM1OnSameCoords which are not part of the boundary of \b otherDimM1OnSameCoords. + * If a node is in the boundary of \b this \b and in the boundary of \b otherDimM1OnSameCoords this node is considerd as needed to be duplicated. + * When the set of node ids \b nodeIdsToDuplicate is computed, cell ids in \b this is searched so that their connectivity includes at least 1 node in \b nodeIdsToDuplicate. + * + * \param [in] otherDimM1OnSameCoords a mesh lying on the same coords than \b this and with a mesh dimension equal to those of \b this minus 1. WARNING this input + * parameter is altered during the call. + * \param [out] nodeIdsToDuplicate node ids needed to be duplicated following the algorithm explain above. + * \param [out] cellIdsNeededToBeRenum cell ids in \b this in which the renumber of nodes should be performed. + * \param [out] cellIdsNotModified cell ids int \b this that lies on \b otherDimM1OnSameCoords mesh whose connectivity do \b not need to be modified as it is the case for \b cellIdsNeededToBeRenum. + * + * \warning This method modifies param \b otherDimM1OnSameCoords (for speed reasons). + */ +void MEDCouplingUMesh::findNodesToDuplicate(const MEDCouplingUMesh& otherDimM1OnSameCoords, DataArrayInt *& nodeIdsToDuplicate, + DataArrayInt *& cellIdsNeededToBeRenum, DataArrayInt *& cellIdsNotModified) const +{ + typedef MEDCouplingAutoRefCountObjectPtr DAInt; + + checkFullyDefined(); + otherDimM1OnSameCoords.checkFullyDefined(); + if(getCoords()!=otherDimM1OnSameCoords.getCoords()) + throw INTERP_KERNEL::Exception("MEDCouplingUMesh::findNodesToDuplicate : meshes do not share the same coords array !"); + if(otherDimM1OnSameCoords.getMeshDimension()!=getMeshDimension()-1) + throw INTERP_KERNEL::Exception("MEDCouplingUMesh::findNodesToDuplicate : the mesh given in other parameter must have this->getMeshDimension()-1 !"); + DataArrayInt *cellIdsRk0=0,*cellIdsRk1=0; + findCellIdsLyingOn(otherDimM1OnSameCoords,cellIdsRk0,cellIdsRk1); + DAInt cellIdsRk0Auto(cellIdsRk0),cellIdsRk1Auto(cellIdsRk1); + DAInt s0=cellIdsRk1->buildComplement(cellIdsRk0->getNumberOfTuples()); + s0->transformWithIndArr(cellIdsRk0Auto->begin(),cellIdsRk0Auto->end()); + MEDCouplingAutoRefCountObjectPtr m0Part=static_cast(buildPartOfMySelf(s0->begin(),s0->end(),true)); + DAInt s1=m0Part->computeFetchedNodeIds(); + DAInt s2=otherDimM1OnSameCoords.computeFetchedNodeIds(); + DAInt s3=s2->buildSubstraction(s1); + cellIdsRk1->transformWithIndArr(cellIdsRk0Auto->begin(),cellIdsRk0Auto->end()); + // + MEDCouplingAutoRefCountObjectPtr m0Part2=static_cast(buildPartOfMySelf(cellIdsRk1->begin(),cellIdsRk1->end(),true)); + int nCells2 = m0Part2->getNumberOfCells(); + DAInt desc00=DataArrayInt::New(),descI00=DataArrayInt::New(),revDesc00=DataArrayInt::New(),revDescI00=DataArrayInt::New(); + MEDCouplingAutoRefCountObjectPtr m01=m0Part2->buildDescendingConnectivity(desc00,descI00,revDesc00,revDescI00); + // Neighbor information of the mesh without considering the crack (serves to count how many connex pieces it is made of) + DataArrayInt *tmp00=0,*tmp11=0; + MEDCouplingUMesh::ComputeNeighborsOfCellsAdv(desc00,descI00,revDesc00,revDescI00, tmp00, tmp11); + DAInt neighInit00(tmp00); + DAInt neighIInit00(tmp11); + // Neighbor information of the mesh WITH the crack (some neighbors are removed): + DataArrayInt *idsTmp=0; + bool b=m01->areCellsIncludedIn(&otherDimM1OnSameCoords,2,idsTmp); + DAInt ids(idsTmp); + if(!b) + throw INTERP_KERNEL::Exception("MEDCouplingUMesh::findNodesToDuplicate : the given mdim-1 mesh in other is not a constituent of this !"); + // In the neighbor information remove the connection between high dimension cells and its low level constituents which are part + // of the frontier given in parameter (i.e. the cells of low dimension from the group delimiting the crack): + MEDCouplingUMesh::RemoveIdsFromIndexedArrays(ids->begin(),ids->end(),desc00,descI00); + DataArrayInt *tmp0=0,*tmp1=0; + // Compute the neighbor of each cell in m0Part2, taking into account the broken link above. Two + // cells on either side of the crack (defined by the mesh of low dimension) are not neighbor anymore. + ComputeNeighborsOfCellsAdv(desc00,descI00,revDesc00,revDescI00,tmp0,tmp1); + DAInt neigh00(tmp0); + DAInt neighI00(tmp1); + + // For each initial connex part of the sub-mesh (or said differently for each independent crack): + int seed = 0, nIter = 0; + int nIterMax = nCells2+1; // Safety net for the loop + DAInt hitCells = DataArrayInt::New(); hitCells->alloc(nCells2); + hitCells->fillWithValue(-1); + DAInt cellsToModifyConn0_torenum = DataArrayInt::New(); + cellsToModifyConn0_torenum->alloc(0,1); + while (nIter < nIterMax) + { + DAInt t = hitCells->getIdsEqual(-1); + if (!t->getNumberOfTuples()) + break; + // Connex zone without the crack (to compute the next seed really) + int dnu; + DAInt connexCheck = MEDCouplingUMesh::ComputeSpreadZoneGraduallyFromSeed(&seed, &seed+1, neighInit00,neighIInit00, -1, dnu); + int cnt = 0; + for (int * ptr = connexCheck->getPointer(); cnt < connexCheck->getNumberOfTuples(); ptr++, cnt++) + hitCells->setIJ(*ptr,0,1); + // Connex zone WITH the crack (to identify cells lying on either part of the crack) + DAInt spreadZone = MEDCouplingUMesh::ComputeSpreadZoneGraduallyFromSeed(&seed, &seed+1, neigh00,neighI00, -1, dnu); + cellsToModifyConn0_torenum = DataArrayInt::Aggregate(cellsToModifyConn0_torenum, spreadZone, 0); + // Compute next seed, i.e. a cell in another connex part, which was not covered by the previous iterations + DAInt comple = cellsToModifyConn0_torenum->buildComplement(nCells2); + DAInt nonHitCells = hitCells->getIdsEqual(-1); + DAInt intersec = nonHitCells->buildIntersection(comple); + if (intersec->getNumberOfTuples()) + { seed = intersec->getIJ(0,0); } + else + { break; } + nIter++; + } + if (nIter >= nIterMax) + throw INTERP_KERNEL::Exception("MEDCouplingUMesh::findNodesToDuplicate(): internal error - too many iterations."); + + DAInt cellsToModifyConn1_torenum=cellsToModifyConn0_torenum->buildComplement(neighI00->getNumberOfTuples()-1); + cellsToModifyConn0_torenum->transformWithIndArr(cellIdsRk1->begin(),cellIdsRk1->end()); + cellsToModifyConn1_torenum->transformWithIndArr(cellIdsRk1->begin(),cellIdsRk1->end()); + // + cellIdsNeededToBeRenum=cellsToModifyConn0_torenum.retn(); + cellIdsNotModified=cellsToModifyConn1_torenum.retn(); + nodeIdsToDuplicate=s3.retn(); +} + +/*! + * This method operates a modification of the connectivity and coords in \b this. + * Every time that a node id in [ \b nodeIdsToDuplicateBg, \b nodeIdsToDuplicateEnd ) will append in nodal connectivity of \b this + * its ids will be modified to id this->getNumberOfNodes()+std::distance(nodeIdsToDuplicateBg,std::find(nodeIdsToDuplicateBg,nodeIdsToDuplicateEnd,id)). + * More explicitely the renumber array in nodes is not explicitely given in old2new to avoid to build a big array of renumbering whereas typically few node ids needs to be + * renumbered. The node id nodeIdsToDuplicateBg[0] will have id this->getNumberOfNodes()+0, node id nodeIdsToDuplicateBg[1] will have id this->getNumberOfNodes()+1, + * node id nodeIdsToDuplicateBg[2] will have id this->getNumberOfNodes()+2... + * + * As a consequence nodal connectivity array length will remain unchanged by this method, and nodal connectivity index array will remain unchanged by this method. + * + * \param [in] nodeIdsToDuplicateBg begin of node ids (included) to be duplicated in connectivity only + * \param [in] nodeIdsToDuplicateEnd end of node ids (excluded) to be duplicated in connectivity only + */ +void MEDCouplingUMesh::duplicateNodes(const int *nodeIdsToDuplicateBg, const int *nodeIdsToDuplicateEnd) +{ + int nbOfNodes=getNumberOfNodes(); + duplicateNodesInCoords(nodeIdsToDuplicateBg,nodeIdsToDuplicateEnd); + duplicateNodesInConn(nodeIdsToDuplicateBg,nodeIdsToDuplicateEnd,nbOfNodes); +} + +/*! + * This method renumbers only nodal connectivity in \a this. The renumbering is only an offset applied. So this method is a specialization of + * \a renumberNodesInConn. \b WARNING, this method does not check that the resulting node ids in the nodal connectivity is in a valid range ! + * + * \param [in] offset - specifies the offset to be applied on each element of connectivity. + * + * \sa renumberNodesInConn + */ +void MEDCouplingUMesh::renumberNodesWithOffsetInConn(int offset) +{ + checkConnectivityFullyDefined(); + int *conn(getNodalConnectivity()->getPointer()); + const int *connIndex(getNodalConnectivityIndex()->getConstPointer()); + int nbOfCells(getNumberOfCells()); + for(int i=0;i=0)//avoid polyhedron separator + { + node+=offset; + } + } + _nodal_connec->declareAsNew(); + updateTime(); +} + +/*! + * Same than renumberNodesInConn(const int *) except that here the format of old-to-new traducer is using map instead + * of array. This method is dedicated for renumbering from a big set of nodes the a tiny set of nodes which is the case during extraction + * of a big mesh. + */ +void MEDCouplingUMesh::renumberNodesInConn(const INTERP_KERNEL::HashMap& newNodeNumbersO2N) +{ + checkConnectivityFullyDefined(); + int *conn(getNodalConnectivity()->getPointer()); + const int *connIndex(getNodalConnectivityIndex()->getConstPointer()); + int nbOfCells(getNumberOfCells()); + for(int i=0;i=0)//avoid polyhedron separator + { + INTERP_KERNEL::HashMap::const_iterator it(newNodeNumbersO2N.find(node)); + if(it!=newNodeNumbersO2N.end()) + { + node=(*it).second; + } + else + { + std::ostringstream oss; oss << "MEDCouplingUMesh::renumberNodesInConn(map) : presence in connectivity for cell #" << i << " of node #" << node << " : Not in map !"; + throw INTERP_KERNEL::Exception(oss.str().c_str()); + } + } + } + _nodal_connec->declareAsNew(); + updateTime(); +} + +/*! + * Changes ids of nodes within the nodal connectivity arrays according to a permutation + * array in "Old to New" mode. The node coordinates array is \b not changed by this method. + * This method is a generalization of shiftNodeNumbersInConn(). + * \warning This method performs no check of validity of new ids. **Use it with care !** + * \param [in] newNodeNumbersO2N - a permutation array, of length \a + * this->getNumberOfNodes(), in "Old to New" mode. + * See \ref numbering for more info on renumbering modes. + * \throw If the nodal connectivity of cells is not defined. + * + * \if ENABLE_EXAMPLES + * \ref cpp_mcumesh_renumberNodesInConn "Here is a C++ example".
+ * \ref py_mcumesh_renumberNodesInConn "Here is a Python example". + * \endif + */ +void MEDCouplingUMesh::renumberNodesInConn(const int *newNodeNumbersO2N) +{ + checkConnectivityFullyDefined(); + int *conn=getNodalConnectivity()->getPointer(); + const int *connIndex=getNodalConnectivityIndex()->getConstPointer(); + int nbOfCells(getNumberOfCells()); + for(int i=0;i=0)//avoid polyhedron separator + { + node=newNodeNumbersO2N[node]; + } + } + _nodal_connec->declareAsNew(); + updateTime(); +} + +/*! + * This method renumbers nodes \b in \b connectivity \b only \b without \b any \b reference \b to \b coords. + * This method performs no check on the fact that new coordinate ids are valid. \b Use \b it \b with \b care ! + * This method is an specialization of \ref ParaMEDMEM::MEDCouplingUMesh::renumberNodesInConn "renumberNodesInConn method". + * + * \param [in] delta specifies the shift size applied to nodeId in nodal connectivity in \b this. + */ +void MEDCouplingUMesh::shiftNodeNumbersInConn(int delta) +{ + checkConnectivityFullyDefined(); + int *conn=getNodalConnectivity()->getPointer(); + const int *connIndex=getNodalConnectivityIndex()->getConstPointer(); + int nbOfCells=getNumberOfCells(); + for(int i=0;i=0)//avoid polyhedron separator + { + node+=delta; + } + } + _nodal_connec->declareAsNew(); + updateTime(); +} + +/*! + * This method operates a modification of the connectivity in \b this. + * Coordinates are \b NOT considered here and will remain unchanged by this method. this->_coords can ever been null for the needs of this method. + * Every time that a node id in [ \b nodeIdsToDuplicateBg, \b nodeIdsToDuplicateEnd ) will append in nodal connectivity of \b this + * its ids will be modified to id offset+std::distance(nodeIdsToDuplicateBg,std::find(nodeIdsToDuplicateBg,nodeIdsToDuplicateEnd,id)). + * More explicitely the renumber array in nodes is not explicitely given in old2new to avoid to build a big array of renumbering whereas typically few node ids needs to be + * renumbered. The node id nodeIdsToDuplicateBg[0] will have id offset+0, node id nodeIdsToDuplicateBg[1] will have id offset+1, + * node id nodeIdsToDuplicateBg[2] will have id offset+2... + * + * As a consequence nodal connectivity array length will remain unchanged by this method, and nodal connectivity index array will remain unchanged by this method. + * As an another consequense after the call of this method \b this can be transiently non cohrent. + * + * \param [in] nodeIdsToDuplicateBg begin of node ids (included) to be duplicated in connectivity only + * \param [in] nodeIdsToDuplicateEnd end of node ids (excluded) to be duplicated in connectivity only + * \param [in] offset the offset applied to all node ids in connectivity that are in [ \a nodeIdsToDuplicateBg, \a nodeIdsToDuplicateEnd ). + */ +void MEDCouplingUMesh::duplicateNodesInConn(const int *nodeIdsToDuplicateBg, const int *nodeIdsToDuplicateEnd, int offset) +{ + checkConnectivityFullyDefined(); + std::map m; + int val=offset; + for(const int *work=nodeIdsToDuplicateBg;work!=nodeIdsToDuplicateEnd;work++,val++) + m[*work]=val; + int *conn=getNodalConnectivity()->getPointer(); + const int *connIndex=getNodalConnectivityIndex()->getConstPointer(); + int nbOfCells=getNumberOfCells(); + for(int i=0;i=0)//avoid polyhedron separator + { + std::map::iterator it=m.find(node); + if(it!=m.end()) + node=(*it).second; + } + } + updateTime(); +} + +/*! + * This method renumbers cells of \a this using the array specified by [old2NewBg;old2NewBg+getNumberOfCells()) + * + * Contrary to MEDCouplingPointSet::renumberNodes, this method makes a permutation without any fuse of cell. + * After the call of this method the number of cells remains the same as before. + * + * If 'check' equals true the method will check that any elements in [ \a old2NewBg; \a old2NewEnd ) is unique ; if not + * an INTERP_KERNEL::Exception will be thrown. When 'check' equals true [ \a old2NewBg ; \a old2NewEnd ) is not expected to + * be strictly in [0;this->getNumberOfCells()). + * + * If 'check' equals false the method will not check the content of [ \a old2NewBg ; \a old2NewEnd ). + * To avoid any throw of SIGSEGV when 'check' equals false, the elements in [ \a old2NewBg ; \a old2NewEnd ) should be unique and + * should be contained in[0;this->getNumberOfCells()). + * + * \param [in] old2NewBg is expected to be a dynamically allocated pointer of size at least equal to this->getNumberOfCells() + * \param check + */ +void MEDCouplingUMesh::renumberCells(const int *old2NewBg, bool check) +{ + checkConnectivityFullyDefined(); + int nbCells=getNumberOfCells(); + const int *array=old2NewBg; + if(check) + array=DataArrayInt::CheckAndPreparePermutation(old2NewBg,old2NewBg+nbCells); + // + const int *conn=_nodal_connec->getConstPointer(); + const int *connI=_nodal_connec_index->getConstPointer(); + MEDCouplingAutoRefCountObjectPtr o2n=DataArrayInt::New(); o2n->useArray(array,false,C_DEALLOC,nbCells,1); + MEDCouplingAutoRefCountObjectPtr n2o=o2n->invertArrayO2N2N2O(nbCells); + const int *n2oPtr=n2o->begin(); + MEDCouplingAutoRefCountObjectPtr newConn=DataArrayInt::New(); + newConn->alloc(_nodal_connec->getNumberOfTuples(),_nodal_connec->getNumberOfComponents()); + newConn->copyStringInfoFrom(*_nodal_connec); + MEDCouplingAutoRefCountObjectPtr newConnI=DataArrayInt::New(); + newConnI->alloc(_nodal_connec_index->getNumberOfTuples(),_nodal_connec_index->getNumberOfComponents()); + newConnI->copyStringInfoFrom(*_nodal_connec_index); + // + int *newC=newConn->getPointer(); + int *newCI=newConnI->getPointer(); + int loc=0; + newCI[0]=loc; + for(int i=0;i(array)); +} + +/*! + * Finds cells whose bounding boxes intersect a given bounding box. + * \param [in] bbox - an array defining the bounding box via coordinates of its + * extremum points in "no interlace" mode, i.e. xMin, xMax, yMin, yMax, zMin, + * zMax (if in 3D). + * \param [in] eps - a factor used to increase size of the bounding box of cell + * before comparing it with \a bbox. This factor is multiplied by the maximal + * extent of the bounding box of cell to produce an addition to this bounding box. + * \return DataArrayInt * - a new instance of DataArrayInt holding ids for found + * cells. The caller is to delete this array using decrRef() as it is no more + * needed. + * \throw If the coordinates array is not set. + * \throw If the nodal connectivity of cells is not defined. + * + * \if ENABLE_EXAMPLES + * \ref cpp_mcumesh_getCellsInBoundingBox "Here is a C++ example".
+ * \ref py_mcumesh_getCellsInBoundingBox "Here is a Python example". + * \endif + */ +DataArrayInt *MEDCouplingUMesh::getCellsInBoundingBox(const double *bbox, double eps) const +{ + MEDCouplingAutoRefCountObjectPtr elems=DataArrayInt::New(); elems->alloc(0,1); + if(getMeshDimension()==-1) + { + elems->pushBackSilent(0); + return elems.retn(); + } + int dim=getSpaceDimension(); + INTERP_KERNEL::AutoPtr elem_bb=new double[2*dim]; + const int* conn = getNodalConnectivity()->getConstPointer(); + const int* conn_index= getNodalConnectivityIndex()->getConstPointer(); + const double* coords = getCoords()->getConstPointer(); + int nbOfCells=getNumberOfCells(); + for ( int ielem=0; ielem::max(); + elem_bb[i*2+1]=-std::numeric_limits::max(); + } + + for (int inode=conn_index[ielem]+1; inode=0)//avoid polyhedron separator + { + for (int idim=0; idim elem_bb[idim*2+1] ) + { + elem_bb[idim*2+1] = coords[node*dim+idim] ; + } + } + } + } + if (intersectsBoundingBox(elem_bb, bbox, dim, eps)) + elems->pushBackSilent(ielem); + } + return elems.retn(); +} + +/*! + * Given a boundary box 'bbox' returns elements 'elems' contained in this 'bbox' or touching 'bbox' (within 'eps' distance). + * Warning 'elems' is incremented during the call so if elems is not empty before call returned elements will be + * added in 'elems' parameter. + */ +DataArrayInt *MEDCouplingUMesh::getCellsInBoundingBox(const INTERP_KERNEL::DirectedBoundingBox& bbox, double eps) +{ + MEDCouplingAutoRefCountObjectPtr elems=DataArrayInt::New(); elems->alloc(0,1); + if(getMeshDimension()==-1) + { + elems->pushBackSilent(0); + return elems.retn(); + } + int dim=getSpaceDimension(); + INTERP_KERNEL::AutoPtr elem_bb=new double[2*dim]; + const int* conn = getNodalConnectivity()->getConstPointer(); + const int* conn_index= getNodalConnectivityIndex()->getConstPointer(); + const double* coords = getCoords()->getConstPointer(); + int nbOfCells=getNumberOfCells(); + for ( int ielem=0; ielem::max(); + elem_bb[i*2+1]=-std::numeric_limits::max(); + } + + for (int inode=conn_index[ielem]+1; inode=0)//avoid polyhedron separator + { + for (int idim=0; idim elem_bb[idim*2+1] ) + { + elem_bb[idim*2+1] = coords[node*dim+idim] ; + } + } + } + } + if(intersectsBoundingBox(bbox, elem_bb, dim, eps)) + elems->pushBackSilent(ielem); + } + return elems.retn(); +} + +/*! + * Returns a type of a cell by its id. + * \param [in] cellId - the id of the cell of interest. + * \return INTERP_KERNEL::NormalizedCellType - enumeration item describing the cell type. + * \throw If \a cellId is invalid. Valid range is [0, \a this->getNumberOfCells() ). + */ +INTERP_KERNEL::NormalizedCellType MEDCouplingUMesh::getTypeOfCell(int cellId) const +{ + const int *ptI=_nodal_connec_index->getConstPointer(); + const int *pt=_nodal_connec->getConstPointer(); + if(cellId>=0 && cellId<(int)_nodal_connec_index->getNbOfElems()-1) + return (INTERP_KERNEL::NormalizedCellType) pt[ptI[cellId]]; + else + { + std::ostringstream oss; oss << "MEDCouplingUMesh::getTypeOfCell : Requesting type of cell #" << cellId << " but it should be in [0," << _nodal_connec_index->getNbOfElems()-1 << ") !"; + throw INTERP_KERNEL::Exception(oss.str().c_str()); + } +} + +/*! + * This method returns a newly allocated array containing cell ids (ascendingly sorted) whose geometric type are equal to type. + * This method does not throw exception if geometric type \a type is not in \a this. + * This method throws an INTERP_KERNEL::Exception if meshdimension of \b this is not equal to those of \b type. + * The coordinates array is not considered here. + * + * \param [in] type the geometric type + * \return cell ids in this having geometric type \a type. + */ +DataArrayInt *MEDCouplingUMesh::giveCellsWithType(INTERP_KERNEL::NormalizedCellType type) const +{ + + MEDCouplingAutoRefCountObjectPtr ret=DataArrayInt::New(); + ret->alloc(0,1); + checkConnectivityFullyDefined(); + int nbCells=getNumberOfCells(); + int mdim=getMeshDimension(); + const INTERP_KERNEL::CellModel& cm=INTERP_KERNEL::CellModel::GetCellModel(type); + if(mdim!=(int)cm.getDimension()) + throw INTERP_KERNEL::Exception("MEDCouplingUMesh::giveCellsWithType : Mismatch between mesh dimension and dimension of the cell !"); + const int *ptI=_nodal_connec_index->getConstPointer(); + const int *pt=_nodal_connec->getConstPointer(); + for(int i=0;ipushBackSilent(i); + } + return ret.retn(); +} + +/*! + * Returns nb of cells having the geometric type \a type. No throw if no cells in \a this has the geometric type \a type. + */ +int MEDCouplingUMesh::getNumberOfCellsWithType(INTERP_KERNEL::NormalizedCellType type) const +{ + const int *ptI=_nodal_connec_index->getConstPointer(); + const int *pt=_nodal_connec->getConstPointer(); + int nbOfCells=getNumberOfCells(); + int ret=0; + for(int i=0;igetNumberOfCells() ). + */ +void MEDCouplingUMesh::getNodeIdsOfCell(int cellId, std::vector& conn) const +{ + const int *ptI=_nodal_connec_index->getConstPointer(); + const int *pt=_nodal_connec->getConstPointer(); + for(const int *w=pt+ptI[cellId]+1;w!=pt+ptI[cellId+1];w++) + if(*w>=0) + conn.push_back(*w); +} + +std::string MEDCouplingUMesh::simpleRepr() const +{ + static const char msg0[]="No coordinates specified !"; + std::ostringstream ret; + ret << "Unstructured mesh with name : \"" << getName() << "\"\n"; + ret << "Description of mesh : \"" << getDescription() << "\"\n"; + int tmpp1,tmpp2; + double tt=getTime(tmpp1,tmpp2); + ret << "Time attached to the mesh [unit] : " << tt << " [" << getTimeUnit() << "]\n"; + ret << "Iteration : " << tmpp1 << " Order : " << tmpp2 << "\n"; + if(_mesh_dim>=-1) + { ret << "Mesh dimension : " << _mesh_dim << "\nSpace dimension : "; } + else + { ret << " Mesh dimension has not been set or is invalid !"; } + if(_coords!=0) + { + const int spaceDim=getSpaceDimension(); + ret << spaceDim << "\nInfo attached on space dimension : "; + for(int i=0;igetInfoOnComponent(i) << "\" "; + ret << "\n"; + } + else + ret << msg0 << "\n"; + ret << "Number of nodes : "; + if(_coords!=0) + ret << getNumberOfNodes() << "\n"; + else + ret << msg0 << "\n"; + ret << "Number of cells : "; + if(_nodal_connec!=0 && _nodal_connec_index!=0) + ret << getNumberOfCells() << "\n"; + else + ret << "No connectivity specified !" << "\n"; + ret << "Cell types present : "; + for(std::set::const_iterator iter=_types.begin();iter!=_types.end();iter++) + { + const INTERP_KERNEL::CellModel& cm=INTERP_KERNEL::CellModel::GetCellModel(*iter); + ret << cm.getRepr() << " "; + } + ret << "\n"; + return ret.str(); +} + +std::string MEDCouplingUMesh::advancedRepr() const +{ + std::ostringstream ret; + ret << simpleRepr(); + ret << "\nCoordinates array : \n___________________\n\n"; + if(_coords) + _coords->reprWithoutNameStream(ret); + else + ret << "No array set !\n"; + ret << "\n\nConnectivity arrays : \n_____________________\n\n"; + reprConnectivityOfThisLL(ret); + return ret.str(); +} + +/*! + * This method returns a C++ code that is a dump of \a this. + * This method will throw if this is not fully defined. + */ +std::string MEDCouplingUMesh::cppRepr() const +{ + static const char coordsName[]="coords"; + static const char connName[]="conn"; + static const char connIName[]="connI"; + checkFullyDefined(); + std::ostringstream ret; ret << "// coordinates" << std::endl; + _coords->reprCppStream(coordsName,ret); ret << std::endl << "// connectivity" << std::endl; + _nodal_connec->reprCppStream(connName,ret); ret << std::endl; + _nodal_connec_index->reprCppStream(connIName,ret); ret << std::endl; + ret << "MEDCouplingUMesh *mesh=MEDCouplingUMesh::New(\"" << getName() << "\"," << getMeshDimension() << ");" << std::endl; + ret << "mesh->setCoords(" << coordsName << ");" << std::endl; + ret << "mesh->setConnectivity(" << connName << "," << connIName << ",true);" << std::endl; + ret << coordsName << "->decrRef(); " << connName << "->decrRef(); " << connIName << "->decrRef();" << std::endl; + return ret.str(); +} + +std::string MEDCouplingUMesh::reprConnectivityOfThis() const +{ + std::ostringstream ret; + reprConnectivityOfThisLL(ret); + return ret.str(); +} + +/*! + * This method builds a newly allocated instance (with the same name than \a this) that the caller has the responsability to deal with. + * This method returns an instance with all arrays allocated (connectivity, connectivity index, coordinates) + * but with length of these arrays set to 0. It allows to define an "empty" mesh (with nor cells nor nodes but compliant with + * some algos). + * + * This method expects that \a this has a mesh dimension set and higher or equal to 0. If not an exception will be thrown. + * This method analyzes the 3 arrays of \a this. For each the following behaviour is done : if the array is null a newly one is created + * with number of tuples set to 0, if not the array is taken as this in the returned instance. + */ +MEDCouplingUMesh *MEDCouplingUMesh::buildSetInstanceFromThis(int spaceDim) const +{ + int mdim=getMeshDimension(); + if(mdim<0) + throw INTERP_KERNEL::Exception("MEDCouplingUMesh::buildSetInstanceFromThis : invalid mesh dimension ! Should be >= 0 !"); + MEDCouplingAutoRefCountObjectPtr ret=MEDCouplingUMesh::New(getName(),mdim); + MEDCouplingAutoRefCountObjectPtr tmp1,tmp2; + bool needToCpyCT=true; + if(!_nodal_connec) + { + tmp1=DataArrayInt::New(); tmp1->alloc(0,1); + needToCpyCT=false; + } + else + { + tmp1=_nodal_connec; + tmp1->incrRef(); + } + if(!_nodal_connec_index) + { + tmp2=DataArrayInt::New(); tmp2->alloc(1,1); tmp2->setIJ(0,0,0); + needToCpyCT=false; + } + else + { + tmp2=_nodal_connec_index; + tmp2->incrRef(); + } + ret->setConnectivity(tmp1,tmp2,false); + if(needToCpyCT) + ret->_types=_types; + if(!_coords) + { + MEDCouplingAutoRefCountObjectPtr coords=DataArrayDouble::New(); coords->alloc(0,spaceDim); + ret->setCoords(coords); + } + else + ret->setCoords(_coords); + return ret.retn(); +} + +void MEDCouplingUMesh::reprConnectivityOfThisLL(std::ostringstream& stream) const +{ + if(_nodal_connec!=0 && _nodal_connec_index!=0) + { + int nbOfCells=getNumberOfCells(); + const int *c=_nodal_connec->getConstPointer(); + const int *ci=_nodal_connec_index->getConstPointer(); + for(int i=0;i(stream," ")); + stream << "\n"; + } + } + else + stream << "Connectivity not defined !\n"; +} + +int MEDCouplingUMesh::getNumberOfNodesInCell(int cellId) const +{ + const int *ptI=_nodal_connec_index->getConstPointer(); + const int *pt=_nodal_connec->getConstPointer(); + if(pt[ptI[cellId]]!=INTERP_KERNEL::NORM_POLYHED) + return ptI[cellId+1]-ptI[cellId]-1; + else + return (int)std::count_if(pt+ptI[cellId]+1,pt+ptI[cellId+1],std::bind2nd(std::not_equal_to(),-1)); +} + +/*! + * Returns types of cells of the specified part of \a this mesh. + * This method avoids computing sub-mesh explicitely to get its types. + * \param [in] begin - an array of cell ids of interest. + * \param [in] end - the end of \a begin, i.e. a pointer to its (last+1)-th element. + * \return std::set - a set of enumeration items + * describing the cell types. + * \throw If the coordinates array is not set. + * \throw If the nodal connectivity of cells is not defined. + * \sa getAllGeoTypes() + */ +std::set MEDCouplingUMesh::getTypesOfPart(const int *begin, const int *end) const +{ + checkFullyDefined(); + std::set ret; + const int *conn=_nodal_connec->getConstPointer(); + const int *connIndex=_nodal_connec_index->getConstPointer(); + for(const int *w=begin;w!=end;w++) + ret.insert((INTERP_KERNEL::NormalizedCellType)conn[connIndex[*w]]); + return ret; +} + +/*! + * Defines the nodal connectivity using given connectivity arrays in \ref numbering-indirect format. + * Optionally updates + * a set of types of cells constituting \a this mesh. + * This method is for advanced users having prepared their connectivity before. For + * more info on using this method see \ref MEDCouplingUMeshAdvBuild. + * \param [in] conn - the nodal connectivity array. + * \param [in] connIndex - the nodal connectivity index array. + * \param [in] isComputingTypes - if \c true, the set of types constituting \a this + * mesh is updated. + */ +void MEDCouplingUMesh::setConnectivity(DataArrayInt *conn, DataArrayInt *connIndex, bool isComputingTypes) +{ + DataArrayInt::SetArrayIn(conn,_nodal_connec); + DataArrayInt::SetArrayIn(connIndex,_nodal_connec_index); + if(isComputingTypes) + computeTypes(); + declareAsNew(); +} + +/*! + * Copy constructor. If 'deepCpy' is false \a this is a shallow copy of other. + * If 'deeCpy' is true all arrays (coordinates and connectivities) are deeply copied. + */ +MEDCouplingUMesh::MEDCouplingUMesh(const MEDCouplingUMesh& other, bool deepCopy):MEDCouplingPointSet(other,deepCopy),_mesh_dim(other._mesh_dim), + _nodal_connec(0),_nodal_connec_index(0), + _types(other._types) +{ + if(other._nodal_connec) + _nodal_connec=other._nodal_connec->performCpy(deepCopy); + if(other._nodal_connec_index) + _nodal_connec_index=other._nodal_connec_index->performCpy(deepCopy); +} + +MEDCouplingUMesh::~MEDCouplingUMesh() +{ + if(_nodal_connec) + _nodal_connec->decrRef(); + if(_nodal_connec_index) + _nodal_connec_index->decrRef(); +} + +/*! + * Recomputes a set of cell types of \a this mesh. For more info see + * \ref MEDCouplingUMeshNodalConnectivity. + */ +void MEDCouplingUMesh::computeTypes() +{ + ComputeAllTypesInternal(_types,_nodal_connec,_nodal_connec_index); +} + +/*! + * This method checks that all arrays are set. If yes nothing done if no an exception is thrown. + */ +void MEDCouplingUMesh::checkFullyDefined() const +{ + if(!_nodal_connec_index || !_nodal_connec || !_coords) + throw INTERP_KERNEL::Exception("Reverse nodal connectivity computation requires full connectivity and coordinates set in unstructured mesh."); +} + +/*! + * This method checks that all connectivity arrays are set. If yes nothing done if no an exception is thrown. + */ +void MEDCouplingUMesh::checkConnectivityFullyDefined() const +{ + if(!_nodal_connec_index || !_nodal_connec) + throw INTERP_KERNEL::Exception("Reverse nodal connectivity computation requires full connectivity set in unstructured mesh."); +} + +/*! + * Returns a number of cells constituting \a this mesh. + * \return int - the number of cells in \a this mesh. + * \throw If the nodal connectivity of cells is not defined. + */ +int MEDCouplingUMesh::getNumberOfCells() const +{ + if(_nodal_connec_index) + return _nodal_connec_index->getNumberOfTuples()-1; + else + if(_mesh_dim==-1) + return 1; + else + throw INTERP_KERNEL::Exception("Unable to get number of cells because no connectivity specified !"); +} + +/*! + * Returns a dimension of \a this mesh, i.e. a dimension of cells constituting \a this + * mesh. For more info see \ref meshes. + * \return int - the dimension of \a this mesh. + * \throw If the mesh dimension is not defined using setMeshDimension(). + */ +int MEDCouplingUMesh::getMeshDimension() const +{ + if(_mesh_dim<-1) + throw INTERP_KERNEL::Exception("No mesh dimension specified !"); + return _mesh_dim; +} + +/*! + * Returns a length of the nodal connectivity array. + * This method is for test reason. Normally the integer returned is not useable by + * user. For more info see \ref MEDCouplingUMeshNodalConnectivity. + * \return int - the length of the nodal connectivity array. + */ +int MEDCouplingUMesh::getMeshLength() const +{ + return _nodal_connec->getNbOfElems(); +} + +/*! + * First step of serialization process. Used by ParaMEDMEM and MEDCouplingCorba to transfert data between process. + */ +void MEDCouplingUMesh::getTinySerializationInformation(std::vector& tinyInfoD, std::vector& tinyInfo, std::vector& littleStrings) const +{ + MEDCouplingPointSet::getTinySerializationInformation(tinyInfoD,tinyInfo,littleStrings); + tinyInfo.push_back(getMeshDimension()); + tinyInfo.push_back(getNumberOfCells()); + if(_nodal_connec) + tinyInfo.push_back(getMeshLength()); + else + tinyInfo.push_back(-1); +} + +/*! + * First step of unserialization process. + */ +bool MEDCouplingUMesh::isEmptyMesh(const std::vector& tinyInfo) const +{ + return tinyInfo[6]<=0; +} + +/*! + * Second step of serialization process. + * \param tinyInfo must be equal to the result given by getTinySerializationInformation method. + * \param a1 + * \param a2 + * \param littleStrings + */ +void MEDCouplingUMesh::resizeForUnserialization(const std::vector& tinyInfo, DataArrayInt *a1, DataArrayDouble *a2, std::vector& littleStrings) const +{ + MEDCouplingPointSet::resizeForUnserialization(tinyInfo,a1,a2,littleStrings); + if(tinyInfo[5]!=-1) + a1->alloc(tinyInfo[7]+tinyInfo[6]+1,1); +} + +/*! + * Third and final step of serialization process. + */ +void MEDCouplingUMesh::serialize(DataArrayInt *&a1, DataArrayDouble *&a2) const +{ + MEDCouplingPointSet::serialize(a1,a2); + if(getMeshDimension()>-1) + { + a1=DataArrayInt::New(); + a1->alloc(getMeshLength()+getNumberOfCells()+1,1); + int *ptA1=a1->getPointer(); + const int *conn=getNodalConnectivity()->getConstPointer(); + const int *index=getNodalConnectivityIndex()->getConstPointer(); + ptA1=std::copy(index,index+getNumberOfCells()+1,ptA1); + std::copy(conn,conn+getMeshLength(),ptA1); + } + else + a1=0; +} + +/*! + * Second and final unserialization process. + * \param tinyInfo must be equal to the result given by getTinySerializationInformation method. + */ +void MEDCouplingUMesh::unserialization(const std::vector& tinyInfoD, const std::vector& tinyInfo, const DataArrayInt *a1, DataArrayDouble *a2, const std::vector& littleStrings) +{ + MEDCouplingPointSet::unserialization(tinyInfoD,tinyInfo,a1,a2,littleStrings); + setMeshDimension(tinyInfo[5]); + if(tinyInfo[7]!=-1) + { + // Connectivity + const int *recvBuffer=a1->getConstPointer(); + MEDCouplingAutoRefCountObjectPtr myConnecIndex=DataArrayInt::New(); + myConnecIndex->alloc(tinyInfo[6]+1,1); + std::copy(recvBuffer,recvBuffer+tinyInfo[6]+1,myConnecIndex->getPointer()); + MEDCouplingAutoRefCountObjectPtr myConnec=DataArrayInt::New(); + myConnec->alloc(tinyInfo[7],1); + std::copy(recvBuffer+tinyInfo[6]+1,recvBuffer+tinyInfo[6]+1+tinyInfo[7],myConnec->getPointer()); + setConnectivity(myConnec, myConnecIndex); + } +} + +/*! + * This is the low algorithm of MEDCouplingUMesh::buildPartOfMySelf2. + * CellIds are given using range specified by a start an end and step. + */ +MEDCouplingPointSet *MEDCouplingUMesh::buildPartOfMySelfKeepCoords2(int start, int end, int step) const +{ + checkFullyDefined(); + int ncell=getNumberOfCells(); + MEDCouplingAutoRefCountObjectPtr ret=MEDCouplingUMesh::New(); + ret->_mesh_dim=_mesh_dim; + ret->setCoords(_coords); + int newNbOfCells=DataArray::GetNumberOfItemGivenBESRelative(start,end,step,"MEDCouplingUMesh::buildPartOfMySelfKeepCoords2 : "); + MEDCouplingAutoRefCountObjectPtr newConnI=DataArrayInt::New(); newConnI->alloc(newNbOfCells+1,1); + int *newConnIPtr=newConnI->getPointer(); *newConnIPtr=0; + int work=start; + const int *conn=_nodal_connec->getConstPointer(); + const int *connIndex=_nodal_connec_index->getConstPointer(); + for(int i=0;i=0 && work newConn=DataArrayInt::New(); newConn->alloc(newConnIPtr[0],1); + int *newConnPtr=newConn->getPointer(); + std::set types; + work=start; + for(int i=0;isetConnectivity(newConn,newConnI,false); + ret->_types=types; + ret->copyTinyInfoFrom(this); + return ret.retn(); +} + +/*! + * This is the low algorithm of MEDCouplingUMesh::buildPartOfMySelf. + * Keeps from \a this only cells which constituing point id are in the ids specified by [ \a begin,\a end ). + * The return newly allocated mesh will share the same coordinates as \a this. + */ +MEDCouplingPointSet *MEDCouplingUMesh::buildPartOfMySelfKeepCoords(const int *begin, const int *end) const +{ + checkConnectivityFullyDefined(); + int ncell=getNumberOfCells(); + MEDCouplingAutoRefCountObjectPtr ret=MEDCouplingUMesh::New(); + ret->_mesh_dim=_mesh_dim; + ret->setCoords(_coords); + std::size_t nbOfElemsRet=std::distance(begin,end); + int *connIndexRet=(int *)malloc((nbOfElemsRet+1)*sizeof(int)); + connIndexRet[0]=0; + const int *conn=_nodal_connec->getConstPointer(); + const int *connIndex=_nodal_connec_index->getConstPointer(); + int newNbring=0; + for(const int *work=begin;work!=end;work++,newNbring++) + { + if(*work>=0 && *work types; + for(const int *work=begin;work!=end;work++) + { + types.insert((INTERP_KERNEL::NormalizedCellType)conn[connIndex[*work]]); + connRetWork=std::copy(conn+connIndex[*work],conn+connIndex[*work+1],connRetWork); + } + MEDCouplingAutoRefCountObjectPtr connRetArr=DataArrayInt::New(); + connRetArr->useArray(connRet,true,C_DEALLOC,connIndexRet[nbOfElemsRet],1); + MEDCouplingAutoRefCountObjectPtr connIndexRetArr=DataArrayInt::New(); + connIndexRetArr->useArray(connIndexRet,true,C_DEALLOC,(int)nbOfElemsRet+1,1); + ret->setConnectivity(connRetArr,connIndexRetArr,false); + ret->_types=types; + ret->copyTinyInfoFrom(this); + return ret.retn(); +} + +/*! + * Returns a new MEDCouplingFieldDouble containing volumes of cells constituting \a this + * mesh.
+ * For 1D cells, the returned field contains lengths.
+ * For 2D cells, the returned field contains areas.
+ * For 3D cells, the returned field contains volumes. + * \param [in] isAbs - if \c true, the computed cell volume does not reflect cell + * orientation, i.e. the volume is always positive. + * \return MEDCouplingFieldDouble * - a new instance of MEDCouplingFieldDouble on cells + * and one time . The caller is to delete this field using decrRef() as it is no + * more needed. + */ +MEDCouplingFieldDouble *MEDCouplingUMesh::getMeasureField(bool isAbs) const +{ + std::string name="MeasureOfMesh_"; + name+=getName(); + int nbelem=getNumberOfCells(); + MEDCouplingAutoRefCountObjectPtr field=MEDCouplingFieldDouble::New(ON_CELLS,ONE_TIME); + field->setName(name); + MEDCouplingAutoRefCountObjectPtr array=DataArrayDouble::New(); + array->alloc(nbelem,1); + double *area_vol=array->getPointer(); + field->setArray(array) ; array=0; + field->setMesh(const_cast(this)); + field->synchronizeTimeWithMesh(); + if(getMeshDimension()!=-1) + { + int ipt; + INTERP_KERNEL::NormalizedCellType type; + int dim_space=getSpaceDimension(); + const double *coords=getCoords()->getConstPointer(); + const int *connec=getNodalConnectivity()->getConstPointer(); + const int *connec_index=getNodalConnectivityIndex()->getConstPointer(); + for(int iel=0;iel(type,connec+ipt+1,connec_index[iel+1]-ipt-1,coords,dim_space); + } + if(isAbs) + std::transform(area_vol,area_vol+nbelem,area_vol,std::ptr_fun(fabs)); + } + else + { + area_vol[0]=std::numeric_limits::max(); + } + return field.retn(); +} + +/*! + * Returns a new DataArrayDouble containing volumes of specified cells of \a this + * mesh.
+ * For 1D cells, the returned array contains lengths.
+ * For 2D cells, the returned array contains areas.
+ * For 3D cells, the returned array contains volumes. + * This method avoids building explicitly a part of \a this mesh to perform the work. + * \param [in] isAbs - if \c true, the computed cell volume does not reflect cell + * orientation, i.e. the volume is always positive. + * \param [in] begin - an array of cell ids of interest. + * \param [in] end - the end of \a begin, i.e. a pointer to its (last+1)-th element. + * \return DataArrayDouble * - a new instance of DataArrayDouble. The caller is to + * delete this array using decrRef() as it is no more needed. + * + * \if ENABLE_EXAMPLES + * \ref cpp_mcumesh_getPartMeasureField "Here is a C++ example".
+ * \ref py_mcumesh_getPartMeasureField "Here is a Python example". + * \endif + * \sa getMeasureField() + */ +DataArrayDouble *MEDCouplingUMesh::getPartMeasureField(bool isAbs, const int *begin, const int *end) const +{ + std::string name="PartMeasureOfMesh_"; + name+=getName(); + int nbelem=(int)std::distance(begin,end); + MEDCouplingAutoRefCountObjectPtr array=DataArrayDouble::New(); + array->setName(name); + array->alloc(nbelem,1); + double *area_vol=array->getPointer(); + if(getMeshDimension()!=-1) + { + int ipt; + INTERP_KERNEL::NormalizedCellType type; + int dim_space=getSpaceDimension(); + const double *coords=getCoords()->getConstPointer(); + const int *connec=getNodalConnectivity()->getConstPointer(); + const int *connec_index=getNodalConnectivityIndex()->getConstPointer(); + for(const int *iel=begin;iel!=end;iel++) + { + ipt=connec_index[*iel]; + type=(INTERP_KERNEL::NormalizedCellType)connec[ipt]; + *area_vol++=INTERP_KERNEL::computeVolSurfOfCell2(type,connec+ipt+1,connec_index[*iel+1]-ipt-1,coords,dim_space); + } + if(isAbs) + std::transform(array->getPointer(),area_vol,array->getPointer(),std::ptr_fun(fabs)); + } + else + { + area_vol[0]=std::numeric_limits::max(); + } + return array.retn(); +} + +/*! + * Returns a new MEDCouplingFieldDouble containing volumes of cells of a dual mesh of + * \a this one. The returned field contains the dual cell volume for each corresponding + * node in \a this mesh. In other words, the field returns the getMeasureField() of + * the dual mesh in P1 sens of \a this.
+ * For 1D cells, the returned field contains lengths.
+ * For 2D cells, the returned field contains areas.
+ * For 3D cells, the returned field contains volumes. + * This method is useful to check "P1*" conservative interpolators. + * \param [in] isAbs - if \c true, the computed cell volume does not reflect cell + * orientation, i.e. the volume is always positive. + * \return MEDCouplingFieldDouble * - a new instance of MEDCouplingFieldDouble on + * nodes and one time. The caller is to delete this array using decrRef() as + * it is no more needed. + */ +MEDCouplingFieldDouble *MEDCouplingUMesh::getMeasureFieldOnNode(bool isAbs) const +{ + MEDCouplingAutoRefCountObjectPtr tmp=getMeasureField(isAbs); + std::string name="MeasureOnNodeOfMesh_"; + name+=getName(); + int nbNodes=getNumberOfNodes(); + MEDCouplingAutoRefCountObjectPtr ret=MEDCouplingFieldDouble::New(ON_NODES); + double cst=1./((double)getMeshDimension()+1.); + MEDCouplingAutoRefCountObjectPtr array=DataArrayDouble::New(); + array->alloc(nbNodes,1); + double *valsToFill=array->getPointer(); + std::fill(valsToFill,valsToFill+nbNodes,0.); + const double *values=tmp->getArray()->getConstPointer(); + MEDCouplingAutoRefCountObjectPtr da=DataArrayInt::New(); + MEDCouplingAutoRefCountObjectPtr daInd=DataArrayInt::New(); + getReverseNodalConnectivity(da,daInd); + const int *daPtr=da->getConstPointer(); + const int *daIPtr=daInd->getConstPointer(); + for(int i=0;isetMesh(this); + ret->setArray(array); + return ret.retn(); +} + +/*! + * Returns a new MEDCouplingFieldDouble holding normal vectors to cells of \a this + * mesh. The returned normal vectors to each cell have a norm2 equal to 1. + * The computed vectors have this->getMeshDimension()+1 components + * and are normalized. + *
\a this can be either + * - a 2D mesh in 2D or 3D space or + * - an 1D mesh in 2D space. + * + * \return MEDCouplingFieldDouble * - a new instance of MEDCouplingFieldDouble on + * cells and one time. The caller is to delete this field using decrRef() as + * it is no more needed. + * \throw If the nodal connectivity of cells is not defined. + * \throw If the coordinates array is not set. + * \throw If the mesh dimension is not set. + * \throw If the mesh and space dimension is not as specified above. + */ +MEDCouplingFieldDouble *MEDCouplingUMesh::buildOrthogonalField() const +{ + if((getMeshDimension()!=2) && (getMeshDimension()!=1 || getSpaceDimension()!=2)) + throw INTERP_KERNEL::Exception("Expected a umesh with ( meshDim == 2 spaceDim == 2 or 3 ) or ( meshDim == 1 spaceDim == 2 ) !"); + MEDCouplingAutoRefCountObjectPtr ret=MEDCouplingFieldDouble::New(ON_CELLS,ONE_TIME); + MEDCouplingAutoRefCountObjectPtr array=DataArrayDouble::New(); + int nbOfCells=getNumberOfCells(); + int nbComp=getMeshDimension()+1; + array->alloc(nbOfCells,nbComp); + double *vals=array->getPointer(); + const int *connI=_nodal_connec_index->getConstPointer(); + const int *conn=_nodal_connec->getConstPointer(); + const double *coords=_coords->getConstPointer(); + if(getMeshDimension()==2) + { + if(getSpaceDimension()==3) + { + MEDCouplingAutoRefCountObjectPtr loc=getBarycenterAndOwner(); + const double *locPtr=loc->getConstPointer(); + for(int i=0;i(locPtr+3*i,coords+3*conn[offset+1],coords+3*conn[offset+2],vals); + double n=INTERP_KERNEL::norm<3>(vals); + std::transform(vals,vals+3,vals,std::bind2nd(std::multiplies(),1./n)); + } + } + else + { + MEDCouplingAutoRefCountObjectPtr isAbs=getMeasureField(false); + const double *isAbsPtr=isAbs->getArray()->begin(); + for(int i=0;i0.?1.:-1.; } + } + } + else//meshdimension==1 + { + double tmp[2]; + for(int i=0;i()); + double n=INTERP_KERNEL::norm<2>(tmp); + std::transform(tmp,tmp+2,tmp,std::bind2nd(std::multiplies(),1./n)); + *vals++=-tmp[1]; + *vals++=tmp[0]; + } + } + ret->setArray(array); + ret->setMesh(this); + ret->synchronizeTimeWithSupport(); + return ret.retn(); +} + +/*! + * Returns a new MEDCouplingFieldDouble holding normal vectors to specified cells of + * \a this mesh. The computed vectors have this->getMeshDimension()+1 components + * and are normalized. + *
\a this can be either + * - a 2D mesh in 2D or 3D space or + * - an 1D mesh in 2D space. + * + * This method avoids building explicitly a part of \a this mesh to perform the work. + * \param [in] begin - an array of cell ids of interest. + * \param [in] end - the end of \a begin, i.e. a pointer to its (last+1)-th element. + * \return MEDCouplingFieldDouble * - a new instance of MEDCouplingFieldDouble on + * cells and one time. The caller is to delete this field using decrRef() as + * it is no more needed. + * \throw If the nodal connectivity of cells is not defined. + * \throw If the coordinates array is not set. + * \throw If the mesh dimension is not set. + * \throw If the mesh and space dimension is not as specified above. + * \sa buildOrthogonalField() + * + * \if ENABLE_EXAMPLES + * \ref cpp_mcumesh_buildPartOrthogonalField "Here is a C++ example".
+ * \ref py_mcumesh_buildPartOrthogonalField "Here is a Python example". + * \endif + */ +MEDCouplingFieldDouble *MEDCouplingUMesh::buildPartOrthogonalField(const int *begin, const int *end) const +{ + if((getMeshDimension()!=2) && (getMeshDimension()!=1 || getSpaceDimension()!=2)) + throw INTERP_KERNEL::Exception("Expected a umesh with ( meshDim == 2 spaceDim == 2 or 3 ) or ( meshDim == 1 spaceDim == 2 ) !"); + MEDCouplingAutoRefCountObjectPtr ret=MEDCouplingFieldDouble::New(ON_CELLS,ONE_TIME); + MEDCouplingAutoRefCountObjectPtr array=DataArrayDouble::New(); + std::size_t nbelems=std::distance(begin,end); + int nbComp=getMeshDimension()+1; + array->alloc((int)nbelems,nbComp); + double *vals=array->getPointer(); + const int *connI=_nodal_connec_index->getConstPointer(); + const int *conn=_nodal_connec->getConstPointer(); + const double *coords=_coords->getConstPointer(); + if(getMeshDimension()==2) + { + if(getSpaceDimension()==3) + { + MEDCouplingAutoRefCountObjectPtr loc=getPartBarycenterAndOwner(begin,end); + const double *locPtr=loc->getConstPointer(); + for(const int *i=begin;i!=end;i++,vals+=3,locPtr+=3) + { + int offset=connI[*i]; + INTERP_KERNEL::crossprod<3>(locPtr,coords+3*conn[offset+1],coords+3*conn[offset+2],vals); + double n=INTERP_KERNEL::norm<3>(vals); + std::transform(vals,vals+3,vals,std::bind2nd(std::multiplies(),1./n)); + } + } + else + { + for(std::size_t i=0;i()); + double n=INTERP_KERNEL::norm<2>(tmp); + std::transform(tmp,tmp+2,tmp,std::bind2nd(std::multiplies(),1./n)); + *vals++=-tmp[1]; + *vals++=tmp[0]; + } + } + ret->setArray(array); + ret->setMesh(this); + ret->synchronizeTimeWithSupport(); + return ret.retn(); +} + +/*! + * Returns a new MEDCouplingFieldDouble holding a direction vector for each SEG2 in \a + * this 1D mesh. The computed vectors have this->getSpaceDimension() components + * and are \b not normalized. + * \return MEDCouplingFieldDouble * - a new instance of MEDCouplingFieldDouble on + * cells and one time. The caller is to delete this field using decrRef() as + * it is no more needed. + * \throw If the nodal connectivity of cells is not defined. + * \throw If the coordinates array is not set. + * \throw If \a this->getMeshDimension() != 1. + * \throw If \a this mesh includes cells of type other than SEG2. + */ +MEDCouplingFieldDouble *MEDCouplingUMesh::buildDirectionVectorField() const +{ + if(getMeshDimension()!=1) + throw INTERP_KERNEL::Exception("Expected a umesh with meshDim == 1 for buildDirectionVectorField !"); + if(_types.size()!=1 || *(_types.begin())!=INTERP_KERNEL::NORM_SEG2) + throw INTERP_KERNEL::Exception("Expected a umesh with only NORM_SEG2 type of elements for buildDirectionVectorField !"); + MEDCouplingAutoRefCountObjectPtr ret=MEDCouplingFieldDouble::New(ON_CELLS,ONE_TIME); + MEDCouplingAutoRefCountObjectPtr array=DataArrayDouble::New(); + int nbOfCells=getNumberOfCells(); + int spaceDim=getSpaceDimension(); + array->alloc(nbOfCells,spaceDim); + double *pt=array->getPointer(); + const double *coo=getCoords()->getConstPointer(); + std::vector conn; + conn.reserve(2); + for(int i=0;i()); + } + ret->setArray(array); + ret->setMesh(this); + ret->synchronizeTimeWithSupport(); + return ret.retn(); +} + +/*! + * Creates a 2D mesh by cutting \a this 3D mesh with a plane. In addition to the mesh, + * returns a new DataArrayInt, of length equal to the number of 2D cells in the result + * mesh, holding, for each cell in the result mesh, an id of a 3D cell it comes + * from. If a result face is shared by two 3D cells, then the face in included twice in + * the result mesh. + * \param [in] origin - 3 components of a point defining location of the plane. + * \param [in] vec - 3 components of a vector normal to the plane. Vector magnitude + * must be greater than 1e-6. + * \param [in] eps - half-thickness of the plane. + * \param [out] cellIds - a new instance of DataArrayInt holding ids of 3D cells + * producing correspondent 2D cells. The caller is to delete this array + * using decrRef() as it is no more needed. + * \return MEDCouplingUMesh * - a new instance of MEDCouplingUMesh. This mesh does + * not share the node coordinates array with \a this mesh. The caller is to + * delete this mesh using decrRef() as it is no more needed. + * \throw If the coordinates array is not set. + * \throw If the nodal connectivity of cells is not defined. + * \throw If \a this->getMeshDimension() != 3 or \a this->getSpaceDimension() != 3. + * \throw If magnitude of \a vec is less than 1e-6. + * \throw If the plane does not intersect any 3D cell of \a this mesh. + * \throw If \a this includes quadratic cells. + */ +MEDCouplingUMesh *MEDCouplingUMesh::buildSlice3D(const double *origin, const double *vec, double eps, DataArrayInt *&cellIds) const +{ + checkFullyDefined(); + if(getMeshDimension()!=3 || getSpaceDimension()!=3) + throw INTERP_KERNEL::Exception("MEDCouplingUMesh::buildSlice3D works on umeshes with meshdim equal to 3 and spaceDim equal to 3 too!"); + MEDCouplingAutoRefCountObjectPtr candidates=getCellIdsCrossingPlane(origin,vec,eps); + if(candidates->empty()) + throw INTERP_KERNEL::Exception("MEDCouplingUMesh::buildSlice3D : No 3D cells in this intercepts the specified plane considering bounding boxes !"); + std::vector nodes; + DataArrayInt *cellIds1D=0; + MEDCouplingAutoRefCountObjectPtr subMesh=static_cast(buildPartOfMySelf(candidates->begin(),candidates->end(),false)); + subMesh->findNodesOnPlane(origin,vec,eps,nodes); + MEDCouplingAutoRefCountObjectPtr desc1=DataArrayInt::New(),desc2=DataArrayInt::New(); + MEDCouplingAutoRefCountObjectPtr descIndx1=DataArrayInt::New(),descIndx2=DataArrayInt::New(); + MEDCouplingAutoRefCountObjectPtr revDesc1=DataArrayInt::New(),revDesc2=DataArrayInt::New(); + MEDCouplingAutoRefCountObjectPtr revDescIndx1=DataArrayInt::New(),revDescIndx2=DataArrayInt::New(); + MEDCouplingAutoRefCountObjectPtr mDesc2=subMesh->buildDescendingConnectivity(desc2,descIndx2,revDesc2,revDescIndx2);//meshDim==2 spaceDim==3 + revDesc2=0; revDescIndx2=0; + MEDCouplingAutoRefCountObjectPtr mDesc1=mDesc2->buildDescendingConnectivity(desc1,descIndx1,revDesc1,revDescIndx1);//meshDim==1 spaceDim==3 + revDesc1=0; revDescIndx1=0; + mDesc1->fillCellIdsToKeepFromNodeIds(&nodes[0],&nodes[0]+nodes.size(),true,cellIds1D); + MEDCouplingAutoRefCountObjectPtr cellIds1DTmp(cellIds1D); + // + std::vector cut3DCurve(mDesc1->getNumberOfCells(),-2); + for(const int *it=cellIds1D->begin();it!=cellIds1D->end();it++) + cut3DCurve[*it]=-1; + mDesc1->split3DCurveWithPlane(origin,vec,eps,cut3DCurve); + std::vector< std::pair > cut3DSurf(mDesc2->getNumberOfCells()); + AssemblyForSplitFrom3DCurve(cut3DCurve,nodes,mDesc2->getNodalConnectivity()->getConstPointer(),mDesc2->getNodalConnectivityIndex()->getConstPointer(), + mDesc1->getNodalConnectivity()->getConstPointer(),mDesc1->getNodalConnectivityIndex()->getConstPointer(), + desc1->getConstPointer(),descIndx1->getConstPointer(),cut3DSurf); + MEDCouplingAutoRefCountObjectPtr conn(DataArrayInt::New()),connI(DataArrayInt::New()),cellIds2(DataArrayInt::New()); + connI->pushBackSilent(0); conn->alloc(0,1); cellIds2->alloc(0,1); + subMesh->assemblyForSplitFrom3DSurf(cut3DSurf,desc2->getConstPointer(),descIndx2->getConstPointer(),conn,connI,cellIds2); + if(cellIds2->empty()) + throw INTERP_KERNEL::Exception("MEDCouplingUMesh::buildSlice3D : No 3D cells in this intercepts the specified plane !"); + MEDCouplingAutoRefCountObjectPtr ret=MEDCouplingUMesh::New("Slice3D",2); + ret->setCoords(mDesc1->getCoords()); + ret->setConnectivity(conn,connI,true); + cellIds=candidates->selectByTupleId(cellIds2->begin(),cellIds2->end()); + return ret.retn(); +} + +/*! + * Creates an 1D mesh by cutting \a this 2D mesh in 3D space with a plane. In +addition to the mesh, returns a new DataArrayInt, of length equal to the number of 1D cells in the result mesh, holding, for each cell in the result mesh, an id of a 2D cell it comes +from. If a result segment is shared by two 2D cells, then the segment in included twice in +the result mesh. + * \param [in] origin - 3 components of a point defining location of the plane. + * \param [in] vec - 3 components of a vector normal to the plane. Vector magnitude + * must be greater than 1e-6. + * \param [in] eps - half-thickness of the plane. + * \param [out] cellIds - a new instance of DataArrayInt holding ids of faces + * producing correspondent segments. The caller is to delete this array + * using decrRef() as it is no more needed. + * \return MEDCouplingUMesh * - a new instance of MEDCouplingUMesh. This is an 1D + * mesh in 3D space. This mesh does not share the node coordinates array with + * \a this mesh. The caller is to delete this mesh using decrRef() as it is + * no more needed. + * \throw If the coordinates array is not set. + * \throw If the nodal connectivity of cells is not defined. + * \throw If \a this->getMeshDimension() != 2 or \a this->getSpaceDimension() != 3. + * \throw If magnitude of \a vec is less than 1e-6. + * \throw If the plane does not intersect any 2D cell of \a this mesh. + * \throw If \a this includes quadratic cells. + */ +MEDCouplingUMesh *MEDCouplingUMesh::buildSlice3DSurf(const double *origin, const double *vec, double eps, DataArrayInt *&cellIds) const +{ + checkFullyDefined(); + if(getMeshDimension()!=2 || getSpaceDimension()!=3) + throw INTERP_KERNEL::Exception("MEDCouplingUMesh::buildSlice3DSurf works on umeshes with meshdim equal to 2 and spaceDim equal to 3 !"); + MEDCouplingAutoRefCountObjectPtr candidates=getCellIdsCrossingPlane(origin,vec,eps); + if(candidates->empty()) + throw INTERP_KERNEL::Exception("MEDCouplingUMesh::buildSlice3DSurf : No 3D surf cells in this intercepts the specified plane considering bounding boxes !"); + std::vector nodes; + DataArrayInt *cellIds1D=0; + MEDCouplingAutoRefCountObjectPtr subMesh=static_cast(buildPartOfMySelf(candidates->begin(),candidates->end(),false)); + subMesh->findNodesOnPlane(origin,vec,eps,nodes); + MEDCouplingAutoRefCountObjectPtr desc1=DataArrayInt::New(); + MEDCouplingAutoRefCountObjectPtr descIndx1=DataArrayInt::New(); + MEDCouplingAutoRefCountObjectPtr revDesc1=DataArrayInt::New(); + MEDCouplingAutoRefCountObjectPtr revDescIndx1=DataArrayInt::New(); + MEDCouplingAutoRefCountObjectPtr mDesc1=subMesh->buildDescendingConnectivity(desc1,descIndx1,revDesc1,revDescIndx1);//meshDim==1 spaceDim==3 + mDesc1->fillCellIdsToKeepFromNodeIds(&nodes[0],&nodes[0]+nodes.size(),true,cellIds1D); + MEDCouplingAutoRefCountObjectPtr cellIds1DTmp(cellIds1D); + // + std::vector cut3DCurve(mDesc1->getNumberOfCells(),-2); + for(const int *it=cellIds1D->begin();it!=cellIds1D->end();it++) + cut3DCurve[*it]=-1; + mDesc1->split3DCurveWithPlane(origin,vec,eps,cut3DCurve); + int ncellsSub=subMesh->getNumberOfCells(); + std::vector< std::pair > cut3DSurf(ncellsSub); + AssemblyForSplitFrom3DCurve(cut3DCurve,nodes,subMesh->getNodalConnectivity()->getConstPointer(),subMesh->getNodalConnectivityIndex()->getConstPointer(), + mDesc1->getNodalConnectivity()->getConstPointer(),mDesc1->getNodalConnectivityIndex()->getConstPointer(), + desc1->getConstPointer(),descIndx1->getConstPointer(),cut3DSurf); + MEDCouplingAutoRefCountObjectPtr conn(DataArrayInt::New()),connI(DataArrayInt::New()),cellIds2(DataArrayInt::New()); connI->pushBackSilent(0); + conn->alloc(0,1); + const int *nodal=subMesh->getNodalConnectivity()->getConstPointer(); + const int *nodalI=subMesh->getNodalConnectivityIndex()->getConstPointer(); + for(int i=0;ipushBackSilent((int)INTERP_KERNEL::NORM_SEG2); conn->pushBackSilent(cut3DSurf[i].first); conn->pushBackSilent(cut3DSurf[i].second); + connI->pushBackSilent(conn->getNumberOfTuples()); + cellIds2->pushBackSilent(i); + } + else + { + int cellId3DSurf=cut3DSurf[i].second; + int offset=nodalI[cellId3DSurf]+1; + int nbOfEdges=nodalI[cellId3DSurf+1]-offset; + for(int j=0;jpushBackSilent((int)INTERP_KERNEL::NORM_SEG2); conn->pushBackSilent(nodal[offset+j]); conn->pushBackSilent(nodal[offset+(j+1)%nbOfEdges]); + connI->pushBackSilent(conn->getNumberOfTuples()); + cellIds2->pushBackSilent(cellId3DSurf); + } + } + } + } + if(cellIds2->empty()) + throw INTERP_KERNEL::Exception("MEDCouplingUMesh::buildSlice3DSurf : No 3DSurf cells in this intercepts the specified plane !"); + MEDCouplingAutoRefCountObjectPtr ret=MEDCouplingUMesh::New("Slice3DSurf",1); + ret->setCoords(mDesc1->getCoords()); + ret->setConnectivity(conn,connI,true); + cellIds=candidates->selectByTupleId(cellIds2->begin(),cellIds2->end()); + return ret.retn(); +} + +/*! + * Finds cells whose bounding boxes intersect a given plane. + * \param [in] origin - 3 components of a point defining location of the plane. + * \param [in] vec - 3 components of a vector normal to the plane. Vector magnitude + * must be greater than 1e-6. + * \param [in] eps - half-thickness of the plane. + * \return DataArrayInt * - a new instance of DataArrayInt holding ids of the found + * cells. The caller is to delete this array using decrRef() as it is no more + * needed. + * \throw If the coordinates array is not set. + * \throw If the nodal connectivity of cells is not defined. + * \throw If \a this->getSpaceDimension() != 3. + * \throw If magnitude of \a vec is less than 1e-6. + * \sa buildSlice3D() + */ +DataArrayInt *MEDCouplingUMesh::getCellIdsCrossingPlane(const double *origin, const double *vec, double eps) const +{ + checkFullyDefined(); + if(getSpaceDimension()!=3) + throw INTERP_KERNEL::Exception("MEDCouplingUMesh::buildSlice3D works on umeshes with spaceDim equal to 3 !"); + double normm=sqrt(vec[0]*vec[0]+vec[1]*vec[1]+vec[2]*vec[2]); + if(normm<1e-6) + throw INTERP_KERNEL::Exception("MEDCouplingUMesh::getCellIdsCrossingPlane : parameter 'vec' should have a norm2 greater than 1e-6 !"); + double vec2[3]; + vec2[0]=vec[1]; vec2[1]=-vec[0]; vec2[2]=0.;//vec2 is the result of cross product of vec with (0,0,1) + double angle=acos(vec[2]/normm); + MEDCouplingAutoRefCountObjectPtr cellIds; + double bbox[6]; + if(angle>eps) + { + MEDCouplingAutoRefCountObjectPtr coo=_coords->deepCpy(); + double normm2(sqrt(vec2[0]*vec2[0]+vec2[1]*vec2[1]+vec2[2]*vec2[2])); + if(normm2/normm>1e-6) + MEDCouplingPointSet::Rotate3DAlg(origin,vec2,angle,coo->getNumberOfTuples(),coo->getPointer()); + MEDCouplingAutoRefCountObjectPtr mw=clone(false);//false -> shallow copy + mw->setCoords(coo); + mw->getBoundingBox(bbox); + bbox[4]=origin[2]-eps; bbox[5]=origin[2]+eps; + cellIds=mw->getCellsInBoundingBox(bbox,eps); + } + else + { + getBoundingBox(bbox); + bbox[4]=origin[2]-eps; bbox[5]=origin[2]+eps; + cellIds=getCellsInBoundingBox(bbox,eps); + } + return cellIds.retn(); +} + +/*! + * This method checks that \a this is a contiguous mesh. The user is expected to call this method on a mesh with meshdim==1. + * If not an exception will thrown. If this is an empty mesh with no cell an exception will be thrown too. + * No consideration of coordinate is done by this method. + * A 1D mesh is said contiguous if : a cell i with nodal connectivity (k,p) the cell i+1 the nodal connectivity should be (p,m) + * If not false is returned. In case that false is returned a call to ParaMEDMEM::MEDCouplingUMesh::mergeNodes could be usefull. + */ +bool MEDCouplingUMesh::isContiguous1D() const +{ + if(getMeshDimension()!=1) + throw INTERP_KERNEL::Exception("MEDCouplingUMesh::isContiguous1D : this method has a sense only for 1D mesh !"); + int nbCells=getNumberOfCells(); + if(nbCells<1) + throw INTERP_KERNEL::Exception("MEDCouplingUMesh::isContiguous1D : this method has a sense for non empty mesh !"); + const int *connI=_nodal_connec_index->getConstPointer(); + const int *conn=_nodal_connec->getConstPointer(); + int ref=conn[connI[0]+2]; + for(int i=1;igetNumberOfCells + */ +void MEDCouplingUMesh::project1D(const double *pt, const double *v, double eps, double *res) const +{ + if(getMeshDimension()!=1) + throw INTERP_KERNEL::Exception("Expected a umesh with meshDim == 1 for project1D !"); + if(_types.size()!=1 || *(_types.begin())!=INTERP_KERNEL::NORM_SEG2) + throw INTERP_KERNEL::Exception("Expected a umesh with only NORM_SEG2 type of elements for project1D !"); + if(getSpaceDimension()!=3) + throw INTERP_KERNEL::Exception("Expected a umesh with spaceDim==3 for project1D !"); + MEDCouplingAutoRefCountObjectPtr f=buildDirectionVectorField(); + const double *fPtr=f->getArray()->getConstPointer(); + double tmp[3]; + for(int i=0;i(tmp); + n1/=INTERP_KERNEL::norm<3>(tmp1); + if(n1>eps) + throw INTERP_KERNEL::Exception("UMesh::Projection 1D failed !"); + } + const double *coo=getCoords()->getConstPointer(); + for(int i=0;i()); + std::transform(tmp,tmp+3,v,tmp,std::multiplies()); + res[i]=std::accumulate(tmp,tmp+3,0.); + } +} + +/*! + * This method computes the distance from a point \a pt to \a this and the first \a cellId in \a this corresponding to the returned distance. + * \a this is expected to be a mesh so that its space dimension is equal to its + * mesh dimension + 1. Furthermore only mesh dimension 1 and 2 are supported for the moment. + * Distance from \a ptBg to \a ptEnd is expected to be equal to the space dimension. \a this is also expected to be fully defined (connectivity and coordinates). + * + * WARNING, if there is some orphan nodes in \a this (nodes not fetched by any cells in \a this ( see MEDCouplingUMesh::zipCoords ) ) these nodes will ** not ** been taken + * into account in this method. Only cells and nodes lying on them are considered in the algorithm (even if one of these orphan nodes is closer than returned distance). + * A user that needs to consider orphan nodes should invoke DataArrayDouble::minimalDistanceTo method on the coordinates array of \a this. + * + * So this method is more accurate (so, more costly) than simply searching for the closest point in \a this. + * If only this information is enough for you simply call \c getCoords()->distanceToTuple on \a this. + * + * \param [in] ptBg the start pointer (included) of the coordinates of the point + * \param [in] ptEnd the end pointer (not included) of the coordinates of the point + * \param [out] cellId that corresponds to minimal distance. If the closer node is not linked to any cell in \a this -1 is returned. + * \return the positive value of the distance. + * \throw if distance from \a ptBg to \a ptEnd is not equal to the space dimension. An exception is also thrown if mesh dimension of \a this is not equal to space + * dimension - 1. + * \sa DataArrayDouble::distanceToTuple, MEDCouplingUMesh::distanceToPoints + */ +double MEDCouplingUMesh::distanceToPoint(const double *ptBg, const double *ptEnd, int& cellId) const +{ + int meshDim=getMeshDimension(),spaceDim=getSpaceDimension(); + if(meshDim!=spaceDim-1) + throw INTERP_KERNEL::Exception("MEDCouplingUMesh::distanceToPoint works only for spaceDim=meshDim+1 !"); + if(meshDim!=2 && meshDim!=1) + throw INTERP_KERNEL::Exception("MEDCouplingUMesh::distanceToPoint : only mesh dimension 2 and 1 are implemented !"); + checkFullyDefined(); + if((int)std::distance(ptBg,ptEnd)!=spaceDim) + { std::ostringstream oss; oss << "MEDCouplingUMesh::distanceToPoint : input point has to have dimension equal to the space dimension of this (" << spaceDim << ") !"; throw INTERP_KERNEL::Exception(oss.str().c_str()); } + DataArrayInt *ret1=0; + MEDCouplingAutoRefCountObjectPtr pts=DataArrayDouble::New(); pts->useArray(ptBg,false,C_DEALLOC,1,spaceDim); + MEDCouplingAutoRefCountObjectPtr ret0=distanceToPoints(pts,ret1); + MEDCouplingAutoRefCountObjectPtr ret1Safe(ret1); + cellId=*ret1Safe->begin(); + return *ret0->begin(); +} + +/*! + * This method computes the distance from each point of points serie \a pts (stored in a DataArrayDouble in which each tuple represents a point) + * to \a this and the first \a cellId in \a this corresponding to the returned distance. + * WARNING, if there is some orphan nodes in \a this (nodes not fetched by any cells in \a this ( see MEDCouplingUMesh::zipCoords ) ) these nodes will ** not ** been taken + * into account in this method. Only cells and nodes lying on them are considered in the algorithm (even if one of these orphan nodes is closer than returned distance). + * A user that needs to consider orphan nodes should invoke DataArrayDouble::minimalDistanceTo method on the coordinates array of \a this. + * + * \a this is expected to be a mesh so that its space dimension is equal to its + * mesh dimension + 1. Furthermore only mesh dimension 1 and 2 are supported for the moment. + * Number of components of \a pts is expected to be equal to the space dimension. \a this is also expected to be fully defined (connectivity and coordinates). + * + * So this method is more accurate (so, more costly) than simply searching for each point in \a pts the closest point in \a this. + * If only this information is enough for you simply call \c getCoords()->distanceToTuple on \a this. + * + * \param [in] pts the list of points in which each tuple represents a point + * \param [out] cellIds a newly allocated object that tells for each point in \a pts the first cell id in \a this that minimizes the distance. + * \return a newly allocated object to be dealed by the caller that tells for each point in \a pts the distance to \a this. + * \throw if number of components of \a pts is not equal to the space dimension. + * \throw if mesh dimension of \a this is not equal to space dimension - 1. + * \sa DataArrayDouble::distanceToTuple, MEDCouplingUMesh::distanceToPoint + */ +DataArrayDouble *MEDCouplingUMesh::distanceToPoints(const DataArrayDouble *pts, DataArrayInt *& cellIds) const +{ + if(!pts) + throw INTERP_KERNEL::Exception("MEDCouplingUMesh::distanceToPoints : input points pointer is NULL !"); + pts->checkAllocated(); + int meshDim=getMeshDimension(),spaceDim=getSpaceDimension(); + if(meshDim!=spaceDim-1) + throw INTERP_KERNEL::Exception("MEDCouplingUMesh::distanceToPoints works only for spaceDim=meshDim+1 !"); + if(meshDim!=2 && meshDim!=1) + throw INTERP_KERNEL::Exception("MEDCouplingUMesh::distanceToPoints : only mesh dimension 2 and 1 are implemented !"); + if(pts->getNumberOfComponents()!=spaceDim) + { + std::ostringstream oss; oss << "MEDCouplingUMesh::distanceToPoints : input pts DataArrayDouble has " << pts->getNumberOfComponents() << " components whereas it should be equal to " << spaceDim << " (mesh spaceDimension) !"; + throw INTERP_KERNEL::Exception(oss.str().c_str()); + } + checkFullyDefined(); + int nbCells=getNumberOfCells(); + if(nbCells==0) + throw INTERP_KERNEL::Exception("MEDCouplingUMesh::distanceToPoints : no cells in this !"); + int nbOfPts=pts->getNumberOfTuples(); + MEDCouplingAutoRefCountObjectPtr ret0=DataArrayDouble::New(); ret0->alloc(nbOfPts,1); + MEDCouplingAutoRefCountObjectPtr ret1=DataArrayInt::New(); ret1->alloc(nbOfPts,1); + const int *nc=_nodal_connec->begin(),*ncI=_nodal_connec_index->begin(); const double *coords=_coords->begin(); + double *ret0Ptr=ret0->getPointer(); int *ret1Ptr=ret1->getPointer(); const double *ptsPtr=pts->begin(); + MEDCouplingAutoRefCountObjectPtr bboxArr(getBoundingBoxForBBTree()); + const double *bbox(bboxArr->begin()); + switch(spaceDim) + { + case 3: + { + BBTreeDst<3> myTree(bbox,0,0,nbCells); + for(int i=0;i::max(); + std::vector elems; + myTree.getMinDistanceOfMax(ptsPtr,x); + myTree.getElemsWhoseMinDistanceToPtSmallerThan(ptsPtr,x,elems); + DistanceToPoint3DSurfAlg(ptsPtr,&elems[0],&elems[0]+elems.size(),coords,nc,ncI,*ret0Ptr,*ret1Ptr); + } + break; + } + case 2: + { + BBTreeDst<2> myTree(bbox,0,0,nbCells); + for(int i=0;i::max(); + std::vector elems; + myTree.getMinDistanceOfMax(ptsPtr,x); + myTree.getElemsWhoseMinDistanceToPtSmallerThan(ptsPtr,x,elems); + DistanceToPoint2DCurveAlg(ptsPtr,&elems[0],&elems[0]+elems.size(),coords,nc,ncI,*ret0Ptr,*ret1Ptr); + } + break; + } + default: + throw INTERP_KERNEL::Exception("MEDCouplingUMesh::distanceToPoints : only spacedim 2 and 3 supported !"); + } + cellIds=ret1.retn(); + return ret0.retn(); +} + ++/// @cond INTERNAL ++ +/*! + * \param [in] pt the start pointer (included) of the coordinates of the point + * \param [in] cellIdsBg the start pointer (included) of cellIds + * \param [in] cellIdsEnd the end pointer (excluded) of cellIds + * \param [in] nc nodal connectivity + * \param [in] ncI nodal connectivity index + * \param [in,out] ret0 the min distance between \a this and the external input point + * \param [out] cellId that corresponds to minimal distance. If the closer node is not linked to any cell in \a this -1 is returned. + * \sa MEDCouplingUMesh::distanceToPoint, MEDCouplingUMesh::distanceToPoints + */ +void MEDCouplingUMesh::DistanceToPoint3DSurfAlg(const double *pt, const int *cellIdsBg, const int *cellIdsEnd, const double *coords, const int *nc, const int *ncI, double& ret0, int& cellId) +{ + cellId=-1; + ret0=std::numeric_limits::max(); + for(const int *zeCell=cellIdsBg;zeCell!=cellIdsEnd;zeCell++) + { + switch((INTERP_KERNEL::NormalizedCellType)nc[ncI[*zeCell]]) + { + case INTERP_KERNEL::NORM_TRI3: + { + double tmp=INTERP_KERNEL::DistanceFromPtToTriInSpaceDim3(pt,coords+3*nc[ncI[*zeCell]+1],coords+3*nc[ncI[*zeCell]+2],coords+3*nc[ncI[*zeCell]+3]); + if(tmp::max(); + for(const int *zeCell=cellIdsBg;zeCell!=cellIdsEnd;zeCell++) + { + switch((INTERP_KERNEL::NormalizedCellType)nc[ncI[*zeCell]]) + { + case INTERP_KERNEL::NORM_SEG2: + { + std::size_t uselessEntry=0; + double tmp=INTERP_KERNEL::SquareDistanceFromPtToSegInSpaceDim2(pt,coords+2*nc[ncI[*zeCell]+1],coords+2*nc[ncI[*zeCell]+2],uselessEntry); + tmp=sqrt(tmp); + if(tmpgetMeshDimension() != \a this->getSpaceDimension(). + */ +int MEDCouplingUMesh::getCellContainingPoint(const double *pos, double eps) const +{ + std::vector elts; + getCellsContainingPoint(pos,eps,elts); + if(elts.empty()) + return -1; + return elts.front(); +} + +/*! + * Finds cells in contact with a ball (i.e. a point with precision). + * For speed reasons, the INTERP_KERNEL::NORM_QUAD4, INTERP_KERNEL::NORM_TRI6 and INTERP_KERNEL::NORM_QUAD8 cells are considered as convex cells to detect if a point is IN or OUT. + * If it is not the case, please change their types to INTERP_KERNEL::NORM_POLYGON or INTERP_KERNEL::NORM_QPOLYG before invoking this method. + * \warning This method is suitable if the caller intends to evaluate only one + * point, for more points getCellsContainingPoints() is recommended as it is + * faster. + * \param [in] pos - array of coordinates of the ball central point. + * \param [in] eps - ball radius. + * \param [out] elts - vector returning ids of the found cells. It is cleared + * before inserting ids. + * \throw If the coordinates array is not set. + * \throw If \a this->getMeshDimension() != \a this->getSpaceDimension(). + * + * \if ENABLE_EXAMPLES + * \ref cpp_mcumesh_getCellsContainingPoint "Here is a C++ example".
+ * \ref py_mcumesh_getCellsContainingPoint "Here is a Python example". + * \endif + */ +void MEDCouplingUMesh::getCellsContainingPoint(const double *pos, double eps, std::vector& elts) const +{ + MEDCouplingAutoRefCountObjectPtr eltsUg,eltsIndexUg; + getCellsContainingPoints(pos,1,eps,eltsUg,eltsIndexUg); + elts.clear(); elts.insert(elts.end(),eltsUg->begin(),eltsUg->end()); +} + +/// @cond INTERNAL + +namespace ParaMEDMEM +{ + template + class DummyClsMCUG + { + public: + static const int MY_SPACEDIM=SPACEDIMM; + static const int MY_MESHDIM=8; + typedef int MyConnType; + static const INTERP_KERNEL::NumberingPolicy My_numPol=INTERP_KERNEL::ALL_C_MODE; + // begin + // useless, but for windows compilation ... + const double* getCoordinatesPtr() const { return 0; } + const int* getConnectivityPtr() const { return 0; } + const int* getConnectivityIndexPtr() const { return 0; } + INTERP_KERNEL::NormalizedCellType getTypeOfElement(int) const { return (INTERP_KERNEL::NormalizedCellType)0; } + // end + }; + + INTERP_KERNEL::Edge *MEDCouplingUMeshBuildQPFromEdge2(INTERP_KERNEL::NormalizedCellType typ, const int *bg, const double *coords2D, std::map< MEDCouplingAutoRefCountObjectPtr,int>& m) + { + INTERP_KERNEL::Edge *ret(0); + MEDCouplingAutoRefCountObjectPtr n0(new INTERP_KERNEL::Node(coords2D[2*bg[0]],coords2D[2*bg[0]+1])),n1(new INTERP_KERNEL::Node(coords2D[2*bg[1]],coords2D[2*bg[1]+1])); + m[n0]=bg[0]; m[n1]=bg[1]; + switch(typ) + { + case INTERP_KERNEL::NORM_SEG2: + { + ret=new INTERP_KERNEL::EdgeLin(n0,n1); + break; + } + case INTERP_KERNEL::NORM_SEG3: + { + INTERP_KERNEL::Node *n2(new INTERP_KERNEL::Node(coords2D[2*bg[2]],coords2D[2*bg[2]+1])); m[n2]=bg[2]; + INTERP_KERNEL::EdgeLin *e1(new INTERP_KERNEL::EdgeLin(n0,n2)),*e2(new INTERP_KERNEL::EdgeLin(n2,n1)); + INTERP_KERNEL::SegSegIntersector inters(*e1,*e2); + // is the SEG3 degenerated, and thus can be reduced to a SEG2? + bool colinearity(inters.areColinears()); + delete e1; delete e2; + if(colinearity) + { ret=new INTERP_KERNEL::EdgeLin(n0,n1); } + else + { ret=new INTERP_KERNEL::EdgeArcCircle(n0,n2,n1); } + break; + } + default: + throw INTERP_KERNEL::Exception("MEDCouplingUMeshBuildQPFromEdge2 : Expecting a mesh with spaceDim==2 and meshDim==1 !"); + } + return ret; + } + + INTERP_KERNEL::Edge *MEDCouplingUMeshBuildQPFromEdge(INTERP_KERNEL::NormalizedCellType typ, std::map >& mapp2, const int *bg) + { + INTERP_KERNEL::Edge *ret=0; + switch(typ) + { + case INTERP_KERNEL::NORM_SEG2: + { + ret=new INTERP_KERNEL::EdgeLin(mapp2[bg[0]].first,mapp2[bg[1]].first); + break; + } + case INTERP_KERNEL::NORM_SEG3: + { + INTERP_KERNEL::EdgeLin *e1=new INTERP_KERNEL::EdgeLin(mapp2[bg[0]].first,mapp2[bg[2]].first); + INTERP_KERNEL::EdgeLin *e2=new INTERP_KERNEL::EdgeLin(mapp2[bg[2]].first,mapp2[bg[1]].first); + INTERP_KERNEL::SegSegIntersector inters(*e1,*e2); + // is the SEG3 degenerated, and thus can be reduced to a SEG2? + bool colinearity=inters.areColinears(); + delete e1; delete e2; + if(colinearity) + ret=new INTERP_KERNEL::EdgeLin(mapp2[bg[0]].first,mapp2[bg[1]].first); + else + ret=new INTERP_KERNEL::EdgeArcCircle(mapp2[bg[0]].first,mapp2[bg[2]].first,mapp2[bg[1]].first); + mapp2[bg[2]].second=false; + break; + } + default: + throw INTERP_KERNEL::Exception("MEDCouplingUMeshBuildQPFromEdge : Expecting a mesh with spaceDim==2 and meshDim==1 !"); + } + return ret; + } + + /*! + * This method creates a sub mesh in Geometric2D DS. The sub mesh is composed by the sub set of cells in 'candidates' taken from + * the global mesh 'mDesc'. + * The input mesh 'mDesc' must be so that mDim==1 and spaceDim==2. + * 'mapp' returns a mapping between local numbering in submesh (represented by a Node*) and the global node numbering in 'mDesc'. + */ + INTERP_KERNEL::QuadraticPolygon *MEDCouplingUMeshBuildQPFromMesh(const MEDCouplingUMesh *mDesc, const std::vector& candidates, + std::map& mapp) + { + mapp.clear(); + std::map > mapp2;//bool is for a flag specifying if node is boundary (true) or only a middle for SEG3. + const double *coo=mDesc->getCoords()->getConstPointer(); + const int *c=mDesc->getNodalConnectivity()->getConstPointer(); + const int *cI=mDesc->getNodalConnectivityIndex()->getConstPointer(); + std::set s; + for(std::vector::const_iterator it=candidates.begin();it!=candidates.end();it++) + s.insert(c+cI[*it]+1,c+cI[(*it)+1]); + for(std::set::const_iterator it2=s.begin();it2!=s.end();it2++) + { + INTERP_KERNEL::Node *n=new INTERP_KERNEL::Node(coo[2*(*it2)],coo[2*(*it2)+1]); + mapp2[*it2]=std::pair(n,true); + } + INTERP_KERNEL::QuadraticPolygon *ret=new INTERP_KERNEL::QuadraticPolygon; + for(std::vector::const_iterator it=candidates.begin();it!=candidates.end();it++) + { + INTERP_KERNEL::NormalizedCellType typ=(INTERP_KERNEL::NormalizedCellType)c[cI[*it]]; + ret->pushBack(MEDCouplingUMeshBuildQPFromEdge(typ,mapp2,c+cI[*it]+1)); + } + for(std::map >::const_iterator it2=mapp2.begin();it2!=mapp2.end();it2++) + { + if((*it2).second.second) + mapp[(*it2).second.first]=(*it2).first; + ((*it2).second.first)->decrRef(); + } + return ret; + } + + INTERP_KERNEL::Node *MEDCouplingUMeshBuildQPNode(int nodeId, const double *coo1, int offset1, const double *coo2, int offset2, const std::vector& addCoo) + { + if(nodeId>=offset2) + { + int locId=nodeId-offset2; + return new INTERP_KERNEL::Node(addCoo[2*locId],addCoo[2*locId+1]); + } + if(nodeId>=offset1) + { + int locId=nodeId-offset1; + return new INTERP_KERNEL::Node(coo2[2*locId],coo2[2*locId+1]); + } + return new INTERP_KERNEL::Node(coo1[2*nodeId],coo1[2*nodeId+1]); + } + + /** + * Construct a mapping between set of Nodes and the standart MEDCoupling connectivity format (c, cI). + */ + void MEDCouplingUMeshBuildQPFromMesh3(const double *coo1, int offset1, const double *coo2, int offset2, const std::vector& addCoo, + const int *desc1Bg, const int *desc1End, const std::vector >& intesctEdges1, + /*output*/std::map& mapp, std::map& mappRev) + { + for(const int *desc1=desc1Bg;desc1!=desc1End;desc1++) + { + int eltId1=abs(*desc1)-1; + for(std::vector::const_iterator it1=intesctEdges1[eltId1].begin();it1!=intesctEdges1[eltId1].end();it1++) + { + std::map::const_iterator it=mappRev.find(*it1); + if(it==mappRev.end()) + { + INTERP_KERNEL::Node *node=MEDCouplingUMeshBuildQPNode(*it1,coo1,offset1,coo2,offset2,addCoo); + mapp[node]=*it1; + mappRev[*it1]=node; + } + } + } + } +} + +/// @endcond + +template +void MEDCouplingUMesh::getCellsContainingPointsAlg(const double *coords, const double *pos, int nbOfPoints, + double eps, MEDCouplingAutoRefCountObjectPtr& elts, MEDCouplingAutoRefCountObjectPtr& eltsIndex) const +{ + elts=DataArrayInt::New(); eltsIndex=DataArrayInt::New(); eltsIndex->alloc(nbOfPoints+1,1); eltsIndex->setIJ(0,0,0); elts->alloc(0,1); + int *eltsIndexPtr(eltsIndex->getPointer()); + MEDCouplingAutoRefCountObjectPtr bboxArr(getBoundingBoxForBBTree(eps)); + const double *bbox(bboxArr->begin()); + int nbOfCells=getNumberOfCells(); + const int *conn=_nodal_connec->getConstPointer(); + const int *connI=_nodal_connec_index->getConstPointer(); + double bb[2*SPACEDIM]; + BBTree myTree(&bbox[0],0,0,nbOfCells,-eps); + for(int i=0;i candidates; + myTree.getIntersectingElems(bb,candidates); + for(std::vector::const_iterator iter=candidates.begin();iter!=candidates.end();iter++) + { + int sz(connI[(*iter)+1]-connI[*iter]-1); + INTERP_KERNEL::NormalizedCellType ct((INTERP_KERNEL::NormalizedCellType)conn[connI[*iter]]); + bool status(false); + if(ct!=INTERP_KERNEL::NORM_POLYGON && ct!=INTERP_KERNEL::NORM_QPOLYG) + status=INTERP_KERNEL::PointLocatorAlgos >::isElementContainsPoint(pos+i*SPACEDIM,ct,coords,conn+connI[*iter]+1,sz,eps); + else + { + if(SPACEDIM!=2) + throw INTERP_KERNEL::Exception("MEDCouplingUMesh::getCellsContainingPointsAlg : not implemented yet for POLYGON and QPOLYGON in spaceDim 3 !"); + INTERP_KERNEL::QUADRATIC_PLANAR::_precision=eps; + INTERP_KERNEL::QUADRATIC_PLANAR::_arc_detection_precision=eps; + std::vector nodes(sz); + INTERP_KERNEL::QuadraticPolygon *pol(0); + for(int j=0;jnormalizeMe(b,c); n->applySimilarity(b,c,a); + status=pol->isInOrOut2(n); + delete pol; n->decrRef(); + } + if(status) + { + eltsIndexPtr[i+1]++; + elts->pushBackSilent(*iter); + } + } + } +} +/*! + * Finds cells in contact with several balls (i.e. points with precision). + * This method is an extension of getCellContainingPoint() and + * getCellsContainingPoint() for the case of multiple points. + * For speed reasons, the INTERP_KERNEL::NORM_QUAD4, INTERP_KERNEL::NORM_TRI6 and INTERP_KERNEL::NORM_QUAD8 cells are considered as convex cells to detect if a point is IN or OUT. + * If it is not the case, please change their types to INTERP_KERNEL::NORM_POLYGON or INTERP_KERNEL::NORM_QPOLYG before invoking this method. + * \param [in] pos - an array of coordinates of points in full interlace mode : + * X0,Y0,Z0,X1,Y1,Z1,... Size of the array must be \a + * this->getSpaceDimension() * \a nbOfPoints + * \param [in] nbOfPoints - number of points to locate within \a this mesh. + * \param [in] eps - radius of balls (i.e. the precision). + * \param [out] elts - vector returning ids of found cells. + * \param [out] eltsIndex - an array, of length \a nbOfPoints + 1, + * dividing cell ids in \a elts into groups each referring to one + * point. Its every element (except the last one) is an index pointing to the + * first id of a group of cells. For example cells in contact with the *i*-th + * point are described by following range of indices: + * [ \a eltsIndex[ *i* ], \a eltsIndex[ *i*+1 ] ) and the cell ids are + * \a elts[ \a eltsIndex[ *i* ]], \a elts[ \a eltsIndex[ *i* ] + 1 ], ... + * Number of cells in contact with the *i*-th point is + * \a eltsIndex[ *i*+1 ] - \a eltsIndex[ *i* ]. + * \throw If the coordinates array is not set. + * \throw If \a this->getMeshDimension() != \a this->getSpaceDimension(). + * + * \if ENABLE_EXAMPLES + * \ref cpp_mcumesh_getCellsContainingPoints "Here is a C++ example".
+ * \ref py_mcumesh_getCellsContainingPoints "Here is a Python example". + * \endif + */ +void MEDCouplingUMesh::getCellsContainingPoints(const double *pos, int nbOfPoints, double eps, + MEDCouplingAutoRefCountObjectPtr& elts, MEDCouplingAutoRefCountObjectPtr& eltsIndex) const +{ + int spaceDim=getSpaceDimension(); + int mDim=getMeshDimension(); + if(spaceDim==3) + { + if(mDim==3) + { + const double *coords=_coords->getConstPointer(); + getCellsContainingPointsAlg<3>(coords,pos,nbOfPoints,eps,elts,eltsIndex); + } + /*else if(mDim==2) + { + + }*/ + else + throw INTERP_KERNEL::Exception("For spaceDim==3 only meshDim==3 implemented for getelementscontainingpoints !"); + } + else if(spaceDim==2) + { + if(mDim==2) + { + const double *coords=_coords->getConstPointer(); + getCellsContainingPointsAlg<2>(coords,pos,nbOfPoints,eps,elts,eltsIndex); + } + else + throw INTERP_KERNEL::Exception("For spaceDim==2 only meshDim==2 implemented for getelementscontainingpoints !"); + } + else if(spaceDim==1) + { + if(mDim==1) + { + const double *coords=_coords->getConstPointer(); + getCellsContainingPointsAlg<1>(coords,pos,nbOfPoints,eps,elts,eltsIndex); + } + else + throw INTERP_KERNEL::Exception("For spaceDim==1 only meshDim==1 implemented for getelementscontainingpoints !"); + } + else + throw INTERP_KERNEL::Exception("MEDCouplingUMesh::getCellsContainingPoints : not managed for mdim not in [1,2,3] !"); +} + +/*! + * Finds butterfly cells in \a this mesh. A 2D cell is considered to be butterfly if at + * least two its edges intersect each other anywhere except their extremities. An + * INTERP_KERNEL::NORM_NORI3 cell can \b not be butterfly. + * \param [in,out] cells - a vector returning ids of the found cells. It is not + * cleared before filling in. + * \param [in] eps - precision. + * \throw If \a this->getMeshDimension() != 2. + * \throw If \a this->getSpaceDimension() != 2 && \a this->getSpaceDimension() != 3. + */ +void MEDCouplingUMesh::checkButterflyCells(std::vector& cells, double eps) const +{ + const char msg[]="Butterfly detection work only for 2D cells with spaceDim==2 or 3!"; + if(getMeshDimension()!=2) + throw INTERP_KERNEL::Exception(msg); + int spaceDim=getSpaceDimension(); + if(spaceDim!=2 && spaceDim!=3) + throw INTERP_KERNEL::Exception(msg); + const int *conn=_nodal_connec->getConstPointer(); + const int *connI=_nodal_connec_index->getConstPointer(); + int nbOfCells=getNumberOfCells(); + std::vector cell2DinS2; + for(int i=0;igetConstPointer(); + int nbOfCells=getNumberOfCells(); + MEDCouplingAutoRefCountObjectPtr nodalConnecIndexOut=DataArrayInt::New(); + nodalConnecIndexOut->alloc(nbOfCells+1,1); + MEDCouplingAutoRefCountObjectPtr nodalConnecOut(DataArrayInt::New()); + int *workIndexOut=nodalConnecIndexOut->getPointer(); + *workIndexOut=0; + const int *nodalConnecIn=_nodal_connec->getConstPointer(); + const int *nodalConnecIndexIn=_nodal_connec_index->getConstPointer(); + std::set types; + MEDCouplingAutoRefCountObjectPtr isChanged(DataArrayInt::New()); + isChanged->alloc(0,1); + for(int i=0;igetNumberOfTuples(); + if(BuildConvexEnvelopOf2DCellJarvis(coords,nodalConnecIn+nodalConnecIndexIn[i],nodalConnecIn+nodalConnecIndexIn[i+1],nodalConnecOut)) + isChanged->pushBackSilent(i); + types.insert((INTERP_KERNEL::NormalizedCellType)nodalConnecOut->getIJ(pos,0)); + workIndexOut[1]=nodalConnecOut->getNumberOfTuples(); + } + if(isChanged->empty()) + return 0; + setConnectivity(nodalConnecOut,nodalConnecIndexOut,false); + _types=types; + return isChanged.retn(); +} + +/*! + * This method is \b NOT const because it can modify \a this. + * \a this is expected to be an unstructured mesh with meshDim==2 and spaceDim==3. If not an exception will be thrown. + * \param mesh1D is an unstructured mesh with MeshDim==1 and spaceDim==3. If not an exception will be thrown. + * \param policy specifies the type of extrusion chosen. \b 0 for translation (most simple), + * \b 1 for translation and rotation around point of 'mesh1D'. + * \return an unstructured mesh with meshDim==3 and spaceDim==3. The returned mesh has the same coords than \a this. + */ +MEDCouplingUMesh *MEDCouplingUMesh::buildExtrudedMesh(const MEDCouplingUMesh *mesh1D, int policy) +{ + checkFullyDefined(); + mesh1D->checkFullyDefined(); + if(!mesh1D->isContiguous1D()) + throw INTERP_KERNEL::Exception("buildExtrudedMesh : 1D mesh passed in parameter is not contiguous !"); + if(getSpaceDimension()!=mesh1D->getSpaceDimension()) + throw INTERP_KERNEL::Exception("Invalid call to buildExtrudedMesh this and mesh1D must have same space dimension !"); + if((getMeshDimension()!=2 || getSpaceDimension()!=3) && (getMeshDimension()!=1 || getSpaceDimension()!=2)) + throw INTERP_KERNEL::Exception("Invalid 'this' for buildExtrudedMesh method : must be (meshDim==2 and spaceDim==3) or (meshDim==1 and spaceDim==2) !"); + if(mesh1D->getMeshDimension()!=1) + throw INTERP_KERNEL::Exception("Invalid 'mesh1D' for buildExtrudedMesh method : must be meshDim==1 !"); + bool isQuad=false; + if(isPresenceOfQuadratic()) + { + if(mesh1D->isFullyQuadratic()) + isQuad=true; + else + throw INTERP_KERNEL::Exception("Invalid 2D mesh and 1D mesh because 2D mesh has quadratic cells and 1D is not fully quadratic !"); + } + int oldNbOfNodes(getNumberOfNodes()); + MEDCouplingAutoRefCountObjectPtr newCoords; + switch(policy) + { + case 0: + { + newCoords=fillExtCoordsUsingTranslation(mesh1D,isQuad); + break; + } + case 1: + { + newCoords=fillExtCoordsUsingTranslAndAutoRotation(mesh1D,isQuad); + break; + } + default: + throw INTERP_KERNEL::Exception("Not implemented extrusion policy : must be in (0) !"); + } + setCoords(newCoords); + MEDCouplingAutoRefCountObjectPtr ret(buildExtrudedMeshFromThisLowLev(oldNbOfNodes,isQuad)); + updateTime(); + return ret.retn(); +} + +/*! + * This method works on a 3D curve linear mesh that is to say (meshDim==1 and spaceDim==3). + * If it is not the case an exception will be thrown. + * This method is non const because the coordinate of \a this can be appended with some new points issued from + * intersection of plane defined by ('origin','vec'). + * This method has one in/out parameter : 'cut3DCurve'. + * Param 'cut3DCurve' is expected to be of size 'this->getNumberOfCells()'. For each i in [0,'this->getNumberOfCells()') + * if cut3DCurve[i]==-2, it means that for cell #i in \a this nothing has been detected previously. + * if cut3DCurve[i]==-1, it means that cell#i has been already detected to be fully part of plane defined by ('origin','vec'). + * This method will throw an exception if \a this contains a non linear segment. + */ +void MEDCouplingUMesh::split3DCurveWithPlane(const double *origin, const double *vec, double eps, std::vector& cut3DCurve) +{ + checkFullyDefined(); + if(getMeshDimension()!=1 || getSpaceDimension()!=3) + throw INTERP_KERNEL::Exception("MEDCouplingUMesh::split3DCurveWithPlane works on umeshes with meshdim equal to 1 and spaceDim equal to 3 !"); + int ncells=getNumberOfCells(); + int nnodes=getNumberOfNodes(); + double vec2[3],vec3[3],vec4[3]; + double normm=sqrt(vec[0]*vec[0]+vec[1]*vec[1]+vec[2]*vec[2]); + if(normm<1e-6) + throw INTERP_KERNEL::Exception("MEDCouplingUMesh::split3DCurveWithPlane : parameter 'vec' should have a norm2 greater than 1e-6 !"); + vec2[0]=vec[0]/normm; vec2[1]=vec[1]/normm; vec2[2]=vec[2]/normm; + const int *conn=_nodal_connec->getConstPointer(); + const int *connI=_nodal_connec_index->getConstPointer(); + const double *coo=_coords->getConstPointer(); + std::vector addCoo; + for(int i=0;ieps)//if colin<=eps -> current SEG2 is colinear to the input plane + { + const double *st2=coo+3*st; + vec4[0]=st2[0]-origin[0]; vec4[1]=st2[1]-origin[1]; vec4[2]=st2[2]-origin[2]; + double pos=-(vec4[0]*vec2[0]+vec4[1]*vec2[1]+vec4[2]*vec2[2])/((vec3[0]*vec2[0]+vec3[1]*vec2[1]+vec3[2]*vec2[2])); + if(pos>eps && pos<1-eps) + { + int nNode=((int)addCoo.size())/3; + vec4[0]=st2[0]+pos*vec3[0]; vec4[1]=st2[1]+pos*vec3[1]; vec4[2]=st2[2]+pos*vec3[2]; + addCoo.insert(addCoo.end(),vec4,vec4+3); + cut3DCurve[i]=nnodes+nNode; + } + } + } + } + else + throw INTERP_KERNEL::Exception("MEDCouplingUMesh::split3DCurveWithPlane : this method is only available for linear cell (NORM_SEG2) !"); + } + if(!addCoo.empty()) + { + int newNbOfNodes=nnodes+((int)addCoo.size())/3; + MEDCouplingAutoRefCountObjectPtr coo2=DataArrayDouble::New(); + coo2->alloc(newNbOfNodes,3); + double *tmp=coo2->getPointer(); + tmp=std::copy(_coords->begin(),_coords->end(),tmp); + std::copy(addCoo.begin(),addCoo.end(),tmp); + DataArrayDouble::SetArrayIn(coo2,_coords); + } +} + +/*! + * This method incarnates the policy 0 for MEDCouplingUMesh::buildExtrudedMesh method. + * \param mesh1D is the input 1D mesh used for translation computation. + * \return newCoords new coords filled by this method. + */ +DataArrayDouble *MEDCouplingUMesh::fillExtCoordsUsingTranslation(const MEDCouplingUMesh *mesh1D, bool isQuad) const +{ + int oldNbOfNodes=getNumberOfNodes(); + int nbOf1DCells=mesh1D->getNumberOfCells(); + int spaceDim=getSpaceDimension(); + DataArrayDouble *ret=DataArrayDouble::New(); + std::vector isQuads; + int nbOfLevsInVec=isQuad?2*nbOf1DCells+1:nbOf1DCells+1; + ret->alloc(oldNbOfNodes*nbOfLevsInVec,spaceDim); + double *retPtr=ret->getPointer(); + const double *coords=getCoords()->getConstPointer(); + double *work=std::copy(coords,coords+spaceDim*oldNbOfNodes,retPtr); + std::vector v; + std::vector c; + double vec[3]; + v.reserve(3); + c.reserve(6); + for(int i=0;igetNodeIdsOfCell(i,v); + c.resize(0); + mesh1D->getCoordinatesOfNode(v[isQuad?2:1],c); + mesh1D->getCoordinatesOfNode(v[0],c); + std::transform(c.begin(),c.begin()+spaceDim,c.begin()+spaceDim,vec,std::minus()); + for(int j=0;j()); + if(isQuad) + { + c.resize(0); + mesh1D->getCoordinatesOfNode(v[1],c); + mesh1D->getCoordinatesOfNode(v[0],c); + std::transform(c.begin(),c.begin()+spaceDim,c.begin()+spaceDim,vec,std::minus()); + for(int j=0;j()); + } + } + ret->copyStringInfoFrom(*getCoords()); + return ret; +} + +/*! + * This method incarnates the policy 1 for MEDCouplingUMesh::buildExtrudedMesh method. + * \param mesh1D is the input 1D mesh used for translation and automatic rotation computation. + * \return newCoords new coords filled by this method. + */ +DataArrayDouble *MEDCouplingUMesh::fillExtCoordsUsingTranslAndAutoRotation(const MEDCouplingUMesh *mesh1D, bool isQuad) const +{ + if(mesh1D->getSpaceDimension()==2) + return fillExtCoordsUsingTranslAndAutoRotation2D(mesh1D,isQuad); + if(mesh1D->getSpaceDimension()==3) + return fillExtCoordsUsingTranslAndAutoRotation3D(mesh1D,isQuad); + throw INTERP_KERNEL::Exception("Not implemented rotation and translation alg. for spacedim other than 2 and 3 !"); +} + +/*! + * This method incarnates the policy 1 for MEDCouplingUMesh::buildExtrudedMesh method. + * \param mesh1D is the input 1D mesh used for translation and automatic rotation computation. + * \return newCoords new coords filled by this method. + */ +DataArrayDouble *MEDCouplingUMesh::fillExtCoordsUsingTranslAndAutoRotation2D(const MEDCouplingUMesh *mesh1D, bool isQuad) const +{ + if(isQuad) + throw INTERP_KERNEL::Exception("MEDCouplingUMesh::fillExtCoordsUsingTranslAndAutoRotation2D : not implemented for quadratic cells !"); + int oldNbOfNodes=getNumberOfNodes(); + int nbOf1DCells=mesh1D->getNumberOfCells(); + if(nbOf1DCells<2) + throw INTERP_KERNEL::Exception("MEDCouplingUMesh::fillExtCoordsUsingTranslAndAutoRotation2D : impossible to detect any angle of rotation ! Change extrusion policy 1->0 !"); + MEDCouplingAutoRefCountObjectPtr ret=DataArrayDouble::New(); + int nbOfLevsInVec=nbOf1DCells+1; + ret->alloc(oldNbOfNodes*nbOfLevsInVec,2); + double *retPtr=ret->getPointer(); + retPtr=std::copy(getCoords()->getConstPointer(),getCoords()->getConstPointer()+getCoords()->getNbOfElems(),retPtr); + MEDCouplingAutoRefCountObjectPtr tmp=MEDCouplingUMesh::New(); + MEDCouplingAutoRefCountObjectPtr tmp2=getCoords()->deepCpy(); + tmp->setCoords(tmp2); + const double *coo1D=mesh1D->getCoords()->getConstPointer(); + const int *conn1D=mesh1D->getNodalConnectivity()->getConstPointer(); + const int *connI1D=mesh1D->getNodalConnectivityIndex()->getConstPointer(); + for(int i=1;itranslate(vec); + double tmp3[2],radius,alpha,alpha0; + const double *p0=i+1rotate(end,0,angle); + retPtr=std::copy(tmp2->getConstPointer(),tmp2->getConstPointer()+tmp2->getNbOfElems(),retPtr); + } + return ret.retn(); +} + +/*! + * This method incarnates the policy 1 for MEDCouplingUMesh::buildExtrudedMesh method. + * \param mesh1D is the input 1D mesh used for translation and automatic rotation computation. + * \return newCoords new coords filled by this method. + */ +DataArrayDouble *MEDCouplingUMesh::fillExtCoordsUsingTranslAndAutoRotation3D(const MEDCouplingUMesh *mesh1D, bool isQuad) const +{ + if(isQuad) + throw INTERP_KERNEL::Exception("MEDCouplingUMesh::fillExtCoordsUsingTranslAndAutoRotation3D : not implemented for quadratic cells !"); + int oldNbOfNodes=getNumberOfNodes(); + int nbOf1DCells=mesh1D->getNumberOfCells(); + if(nbOf1DCells<2) + throw INTERP_KERNEL::Exception("MEDCouplingUMesh::fillExtCoordsUsingTranslAndAutoRotation3D : impossible to detect any angle of rotation ! Change extrusion policy 1->0 !"); + MEDCouplingAutoRefCountObjectPtr ret=DataArrayDouble::New(); + int nbOfLevsInVec=nbOf1DCells+1; + ret->alloc(oldNbOfNodes*nbOfLevsInVec,3); + double *retPtr=ret->getPointer(); + retPtr=std::copy(getCoords()->getConstPointer(),getCoords()->getConstPointer()+getCoords()->getNbOfElems(),retPtr); + MEDCouplingAutoRefCountObjectPtr tmp=MEDCouplingUMesh::New(); + MEDCouplingAutoRefCountObjectPtr tmp2=getCoords()->deepCpy(); + tmp->setCoords(tmp2); + const double *coo1D=mesh1D->getCoords()->getConstPointer(); + const int *conn1D=mesh1D->getNodalConnectivity()->getConstPointer(); + const int *connI1D=mesh1D->getNodalConnectivityIndex()->getConstPointer(); + for(int i=1;itranslate(vec); + double tmp3[2],radius,alpha,alpha0; + const double *p0=i+11.e-7) + { + vecPlane[0]/=norm; vecPlane[1]/=norm; vecPlane[2]/=norm; + double norm2=sqrt(vecPlane[0]*vecPlane[0]+vecPlane[1]*vecPlane[1]); + double vec2[2]={vecPlane[1]/norm2,-vecPlane[0]/norm2}; + double s2=norm2; + double c2=cos(asin(s2)); + double m[3][3]={ + {vec2[0]*vec2[0]*(1-c2)+c2, vec2[0]*vec2[1]*(1-c2), vec2[1]*s2}, + {vec2[0]*vec2[1]*(1-c2), vec2[1]*vec2[1]*(1-c2)+c2, -vec2[0]*s2}, + {-vec2[1]*s2, vec2[0]*s2, c2} + }; + double p0r[3]={m[0][0]*p0[0]+m[0][1]*p0[1]+m[0][2]*p0[2], m[1][0]*p0[0]+m[1][1]*p0[1]+m[1][2]*p0[2], m[2][0]*p0[0]+m[2][1]*p0[1]+m[2][2]*p0[2]}; + double p1r[3]={m[0][0]*p1[0]+m[0][1]*p1[1]+m[0][2]*p1[2], m[1][0]*p1[0]+m[1][1]*p1[1]+m[1][2]*p1[2], m[2][0]*p1[0]+m[2][1]*p1[1]+m[2][2]*p1[2]}; + double p2r[3]={m[0][0]*p2[0]+m[0][1]*p2[1]+m[0][2]*p2[2], m[1][0]*p2[0]+m[1][1]*p2[1]+m[1][2]*p2[2], m[2][0]*p2[0]+m[2][1]*p2[1]+m[2][2]*p2[2]}; + INTERP_KERNEL::EdgeArcCircle::GetArcOfCirclePassingThru(p0r,p1r,p2r,tmp3,radius,alpha,alpha0); + double cosangle=i+1rotate(end,vecPlane,angle); + } + retPtr=std::copy(tmp2->getConstPointer(),tmp2->getConstPointer()+tmp2->getNbOfElems(),retPtr); + } + return ret.retn(); +} + +/*! + * This method is private because not easy to use for end user. This method is const contrary to + * MEDCouplingUMesh::buildExtrudedMesh method because this->_coords are expected to contain + * the coords sorted slice by slice. + * \param isQuad specifies presence of quadratic cells. + */ +MEDCouplingUMesh *MEDCouplingUMesh::buildExtrudedMeshFromThisLowLev(int nbOfNodesOf1Lev, bool isQuad) const +{ + int nbOf1DCells(getNumberOfNodes()/nbOfNodesOf1Lev-1); + int nbOf2DCells(getNumberOfCells()); + int nbOf3DCells(nbOf2DCells*nbOf1DCells); + MEDCouplingUMesh *ret(MEDCouplingUMesh::New("Extruded",getMeshDimension()+1)); + const int *conn(_nodal_connec->begin()),*connI(_nodal_connec_index->begin()); + MEDCouplingAutoRefCountObjectPtr newConn(DataArrayInt::New()),newConnI(DataArrayInt::New()); + newConnI->alloc(nbOf3DCells+1,1); + int *newConnIPtr(newConnI->getPointer()); + *newConnIPtr++=0; + std::vector newc; + for(int j=0;jalloc((int)(newc.size())*nbOf1DCells,1); + int *newConnPtr(newConn->getPointer()); + int deltaPerLev(isQuad?2*nbOfNodesOf1Lev:nbOfNodesOf1Lev); + newConnIPtr=newConnI->getPointer(); + for(int iz=0;iz(),newConnIPtr[iz*nbOf2DCells])); + const int *posOfTypeOfCell(newConnIPtr); + for(std::vector::const_iterator iter=newc.begin();iter!=newc.end();iter++,newConnPtr++) + { + int icell((int)(iter-newc.begin()));//std::distance unfortunately cannot been called here in C++98 + if(icell!=*posOfTypeOfCell) + { + if(*iter!=-1) + *newConnPtr=(*iter)+iz*deltaPerLev; + else + *newConnPtr=-1; + } + else + { + *newConnPtr=*iter; + posOfTypeOfCell++; + } + } + } + ret->setConnectivity(newConn,newConnI,true); + ret->setCoords(getCoords()); + return ret; +} + +/*! + * Checks if \a this mesh is constituted by only quadratic cells. + * \return bool - \c true if there are only quadratic cells in \a this mesh. + * \throw If the coordinates array is not set. + * \throw If the nodal connectivity of cells is not defined. + */ +bool MEDCouplingUMesh::isFullyQuadratic() const +{ + checkFullyDefined(); + bool ret=true; + int nbOfCells=getNumberOfCells(); + for(int i=0;igetConstPointer(); + for(int i=0;i newConn=DataArrayInt::New(); + MEDCouplingAutoRefCountObjectPtr newConnI=DataArrayInt::New(); + const int *icptr=_nodal_connec->getConstPointer(); + newConn->alloc(getMeshLength()-delta,1); + newConnI->alloc(nbOfCells+1,1); + int *ocptr=newConn->getPointer(); + int *ociptr=newConnI->getPointer(); + *ociptr=0; + _types.clear(); + for(int i=0;i types; + checkFullyDefined(); + MEDCouplingAutoRefCountObjectPtr ret,connSafe,connISafe; + MEDCouplingAutoRefCountObjectPtr coordsSafe; + int meshDim=getMeshDimension(); + switch(conversionType) + { + case 0: + switch(meshDim) + { + case 1: + ret=convertLinearCellsToQuadratic1D0(conn,connI,coords,types); + connSafe=conn; connISafe=connI; coordsSafe=coords; + break; + case 2: + ret=convertLinearCellsToQuadratic2D0(conn,connI,coords,types); + connSafe=conn; connISafe=connI; coordsSafe=coords; + break; + case 3: + ret=convertLinearCellsToQuadratic3D0(conn,connI,coords,types); + connSafe=conn; connISafe=connI; coordsSafe=coords; + break; + default: + throw INTERP_KERNEL::Exception("MEDCouplingUMesh::convertLinearCellsToQuadratic : conversion of type 0 mesh dimensions available are [1,2,3] !"); + } + break; + case 1: + { + switch(meshDim) + { + case 1: + ret=convertLinearCellsToQuadratic1D0(conn,connI,coords,types);//it is not a bug. In 1D policy 0 and 1 are equals + connSafe=conn; connISafe=connI; coordsSafe=coords; + break; + case 2: + ret=convertLinearCellsToQuadratic2D1(conn,connI,coords,types); + connSafe=conn; connISafe=connI; coordsSafe=coords; + break; + case 3: + ret=convertLinearCellsToQuadratic3D1(conn,connI,coords,types); + connSafe=conn; connISafe=connI; coordsSafe=coords; + break; + default: + throw INTERP_KERNEL::Exception("MEDCouplingUMesh::convertLinearCellsToQuadratic : conversion of type 1 mesh dimensions available are [1,2,3] !"); + } + break; + } + default: + throw INTERP_KERNEL::Exception("MEDCouplingUMesh::convertLinearCellsToQuadratic : conversion type available are 0 (default, the simplest) and 1 (the most complex) !"); + } + setConnectivity(connSafe,connISafe,false); + _types=types; + setCoords(coordsSafe); + return ret.retn(); +} + +#if 0 +/*! + * This method only works if \a this has spaceDimension equal to 2 and meshDimension also equal to 2. + * This method allows to modify connectivity of cells in \a this that shares some edges in \a edgeIdsToBeSplit. + * The nodes to be added in those 2D cells are defined by the pair of \a nodeIdsToAdd and \a nodeIdsIndexToAdd. + * Length of \a nodeIdsIndexToAdd is expected to equal to length of \a edgeIdsToBeSplit + 1. + * The node ids in \a nodeIdsToAdd should be valid. Those nodes have to be sorted exactly following exactly the direction of the edge. + * This method can be seen as the opposite method of colinearize2D. + * This method can be lead to create some new nodes if quadratic polygon cells have to be split. In this case the added nodes will be put at the end + * to avoid to modify the numbering of existing nodes. + * + * \param [in] nodeIdsToAdd - the list of node ids to be added (\a nodeIdsIndexToAdd array allows to walk on this array) + * \param [in] nodeIdsIndexToAdd - the entry point of \a nodeIdsToAdd to point to the corresponding nodes to be added. + * \param [in] mesh1Desc - 1st output of buildDescendingConnectivity2 on \a this. + * \param [in] desc - 2nd output of buildDescendingConnectivity2 on \a this. + * \param [in] descI - 3rd output of buildDescendingConnectivity2 on \a this. + * \param [in] revDesc - 4th output of buildDescendingConnectivity2 on \a this. + * \param [in] revDescI - 5th output of buildDescendingConnectivity2 on \a this. + * + * \sa buildDescendingConnectivity2 + */ +void MEDCouplingUMesh::splitSomeEdgesOf2DMesh(const DataArrayInt *nodeIdsToAdd, const DataArrayInt *nodeIdsIndexToAdd, const DataArrayInt *edgeIdsToBeSplit, + const MEDCouplingUMesh *mesh1Desc, const DataArrayInt *desc, const DataArrayInt *descI, const DataArrayInt *revDesc, const DataArrayInt *revDescI) +{ + if(!nodeIdsToAdd || !nodeIdsIndexToAdd || !edgeIdsToBeSplit || !mesh1Desc || !desc || !descI || !revDesc || !revDescI) + throw INTERP_KERNEL::Exception("MEDCouplingUMesh::splitSomeEdgesOf2DMesh : input pointers must be not NULL !"); + nodeIdsToAdd->checkAllocated(); nodeIdsIndexToAdd->checkAllocated(); edgeIdsToBeSplit->checkAllocated(); desc->checkAllocated(); descI->checkAllocated(); revDesc->checkAllocated(); revDescI->checkAllocated(); + if(getSpaceDimension()!=2 || getMeshDimension()!=2) + throw INTERP_KERNEL::Exception("MEDCouplingUMesh::splitSomeEdgesOf2DMesh : this must have spacedim=meshdim=2 !"); + if(mesh1Desc->getSpaceDimension()!=2 || mesh1Desc->getMeshDimension()!=1) + throw INTERP_KERNEL::Exception("MEDCouplingUMesh::splitSomeEdgesOf2DMesh : mesh1Desc must be the explosion of this with spaceDim=2 and meshDim = 1 !"); + //DataArrayInt *out0(0),*outi0(0); + //MEDCouplingUMesh::ExtractFromIndexedArrays(idsInDesc2DToBeRefined->begin(),idsInDesc2DToBeRefined->end(),dd3,dd4,out0,outi0); + //MEDCouplingAutoRefCountObjectPtr out0s(out0),outi0s(outi0); + //out0s=out0s->buildUnique(); out0s->sort(true); +} +#endif + +/*! + * Implementes \a conversionType 0 for meshes with meshDim = 1, of MEDCouplingUMesh::convertLinearCellsToQuadratic method. + * \return a newly created DataArrayInt instance that the caller should deal with containing cell ids of converted cells. + * \sa MEDCouplingUMesh::convertLinearCellsToQuadratic. + */ +DataArrayInt *MEDCouplingUMesh::convertLinearCellsToQuadratic1D0(DataArrayInt *&conn, DataArrayInt *&connI, DataArrayDouble *& coords, std::set& types) const +{ + MEDCouplingAutoRefCountObjectPtr bary=getBarycenterAndOwner(); + MEDCouplingAutoRefCountObjectPtr newConn=DataArrayInt::New(); newConn->alloc(0,1); + MEDCouplingAutoRefCountObjectPtr newConnI=DataArrayInt::New(); newConnI->alloc(1,1); newConnI->setIJ(0,0,0); + MEDCouplingAutoRefCountObjectPtr ret=DataArrayInt::New(); ret->alloc(0,1); + int nbOfCells=getNumberOfCells(); + int nbOfNodes=getNumberOfNodes(); + const int *cPtr=_nodal_connec->getConstPointer(); + const int *icPtr=_nodal_connec_index->getConstPointer(); + int lastVal=0,offset=nbOfNodes; + for(int i=0;ipushBackSilent((int)INTERP_KERNEL::NORM_SEG3); + newConn->pushBackValsSilent(cPtr+icPtr[0]+1,cPtr+icPtr[0]+3); + newConn->pushBackSilent(offset++); + lastVal+=4; + newConnI->pushBackSilent(lastVal); + ret->pushBackSilent(i); + } + else + { + types.insert(type); + lastVal+=(icPtr[1]-icPtr[0]); + newConnI->pushBackSilent(lastVal); + newConn->pushBackValsSilent(cPtr+icPtr[0],cPtr+icPtr[1]); + } + } + MEDCouplingAutoRefCountObjectPtr tmp=bary->selectByTupleIdSafe(ret->begin(),ret->end()); + coords=DataArrayDouble::Aggregate(getCoords(),tmp); conn=newConn.retn(); connI=newConnI.retn(); + return ret.retn(); +} + +DataArrayInt *MEDCouplingUMesh::convertLinearCellsToQuadratic2DAnd3D0(const MEDCouplingUMesh *m1D, const DataArrayInt *desc, const DataArrayInt *descI, DataArrayInt *&conn, DataArrayInt *&connI, DataArrayDouble *& coords, std::set& types) const +{ + MEDCouplingAutoRefCountObjectPtr newConn=DataArrayInt::New(); newConn->alloc(0,1); + MEDCouplingAutoRefCountObjectPtr newConnI=DataArrayInt::New(); newConnI->alloc(1,1); newConnI->setIJ(0,0,0); + MEDCouplingAutoRefCountObjectPtr ret=DataArrayInt::New(); ret->alloc(0,1); + // + const int *descPtr(desc->begin()),*descIPtr(descI->begin()); + DataArrayInt *conn1D=0,*conn1DI=0; + std::set types1D; + DataArrayDouble *coordsTmp=0; + MEDCouplingAutoRefCountObjectPtr ret1D=m1D->convertLinearCellsToQuadratic1D0(conn1D,conn1DI,coordsTmp,types1D); ret1D=0; + MEDCouplingAutoRefCountObjectPtr coordsTmpSafe(coordsTmp); + MEDCouplingAutoRefCountObjectPtr conn1DSafe(conn1D),conn1DISafe(conn1DI); + const int *c1DPtr=conn1D->begin(); + const int *c1DIPtr=conn1DI->begin(); + int nbOfCells=getNumberOfCells(); + const int *cPtr=_nodal_connec->getConstPointer(); + const int *icPtr=_nodal_connec_index->getConstPointer(); + int lastVal=0; + for(int i=0;ipushBackSilent(typ2); + newConn->pushBackValsSilent(cPtr+icPtr[0]+1,cPtr+icPtr[1]); + for(const int *d=descPtr+descIPtr[0];d!=descPtr+descIPtr[1];d++) + newConn->pushBackSilent(c1DPtr[c1DIPtr[*d]+3]); + lastVal+=(icPtr[1]-icPtr[0])+(descIPtr[1]-descIPtr[0]); + newConnI->pushBackSilent(lastVal); + ret->pushBackSilent(i); + } + else + { + types.insert(typ); + lastVal+=(icPtr[1]-icPtr[0]); + newConnI->pushBackSilent(lastVal); + newConn->pushBackValsSilent(cPtr+icPtr[0],cPtr+icPtr[1]); + } + } + conn=newConn.retn(); connI=newConnI.retn(); coords=coordsTmpSafe.retn(); + return ret.retn(); +} + +/*! + * Implementes \a conversionType 0 for meshes with meshDim = 2, of MEDCouplingUMesh::convertLinearCellsToQuadratic method. + * \return a newly created DataArrayInt instance that the caller should deal with containing cell ids of converted cells. + * \sa MEDCouplingUMesh::convertLinearCellsToQuadratic. + */ +DataArrayInt *MEDCouplingUMesh::convertLinearCellsToQuadratic2D0(DataArrayInt *&conn, DataArrayInt *&connI, DataArrayDouble *& coords, std::set& types) const +{ + MEDCouplingAutoRefCountObjectPtr desc(DataArrayInt::New()),descI(DataArrayInt::New()),tmp2(DataArrayInt::New()),tmp3(DataArrayInt::New()); + MEDCouplingAutoRefCountObjectPtr m1D=buildDescendingConnectivity(desc,descI,tmp2,tmp3); tmp2=0; tmp3=0; + return convertLinearCellsToQuadratic2DAnd3D0(m1D,desc,descI,conn,connI,coords,types); +} + +DataArrayInt *MEDCouplingUMesh::convertLinearCellsToQuadratic2D1(DataArrayInt *&conn, DataArrayInt *&connI, DataArrayDouble *& coords, std::set& types) const +{ + MEDCouplingAutoRefCountObjectPtr desc(DataArrayInt::New()),descI(DataArrayInt::New()),tmp2(DataArrayInt::New()),tmp3(DataArrayInt::New()); + MEDCouplingAutoRefCountObjectPtr m1D=buildDescendingConnectivity(desc,descI,tmp2,tmp3); tmp2=0; tmp3=0; + // + MEDCouplingAutoRefCountObjectPtr newConn=DataArrayInt::New(); newConn->alloc(0,1); + MEDCouplingAutoRefCountObjectPtr newConnI=DataArrayInt::New(); newConnI->alloc(1,1); newConnI->setIJ(0,0,0); + MEDCouplingAutoRefCountObjectPtr ret=DataArrayInt::New(); ret->alloc(0,1); + // + MEDCouplingAutoRefCountObjectPtr bary=getBarycenterAndOwner(); + const int *descPtr(desc->begin()),*descIPtr(descI->begin()); + DataArrayInt *conn1D=0,*conn1DI=0; + std::set types1D; + DataArrayDouble *coordsTmp=0; + MEDCouplingAutoRefCountObjectPtr ret1D=m1D->convertLinearCellsToQuadratic1D0(conn1D,conn1DI,coordsTmp,types1D); ret1D=0; + MEDCouplingAutoRefCountObjectPtr coordsTmpSafe(coordsTmp); + MEDCouplingAutoRefCountObjectPtr conn1DSafe(conn1D),conn1DISafe(conn1DI); + const int *c1DPtr=conn1D->begin(); + const int *c1DIPtr=conn1DI->begin(); + int nbOfCells=getNumberOfCells(); + const int *cPtr=_nodal_connec->getConstPointer(); + const int *icPtr=_nodal_connec_index->getConstPointer(); + int lastVal=0,offset=coordsTmpSafe->getNumberOfTuples(); + for(int i=0;ipushBackSilent(typ2); + newConn->pushBackValsSilent(cPtr+icPtr[0]+1,cPtr+icPtr[1]); + for(const int *d=descPtr+descIPtr[0];d!=descPtr+descIPtr[1];d++) + newConn->pushBackSilent(c1DPtr[c1DIPtr[*d]+3]); + newConn->pushBackSilent(offset+ret->getNumberOfTuples()); + lastVal+=(icPtr[1]-icPtr[0])+(descIPtr[1]-descIPtr[0])+1; + newConnI->pushBackSilent(lastVal); + ret->pushBackSilent(i); + } + else + { + types.insert(typ); + lastVal+=(icPtr[1]-icPtr[0]); + newConnI->pushBackSilent(lastVal); + newConn->pushBackValsSilent(cPtr+icPtr[0],cPtr+icPtr[1]); + } + } + MEDCouplingAutoRefCountObjectPtr tmp=bary->selectByTupleIdSafe(ret->begin(),ret->end()); + coords=DataArrayDouble::Aggregate(coordsTmpSafe,tmp); conn=newConn.retn(); connI=newConnI.retn(); + return ret.retn(); +} + +/*! + * Implementes \a conversionType 0 for meshes with meshDim = 3, of MEDCouplingUMesh::convertLinearCellsToQuadratic method. + * \return a newly created DataArrayInt instance that the caller should deal with containing cell ids of converted cells. + * \sa MEDCouplingUMesh::convertLinearCellsToQuadratic. + */ +DataArrayInt *MEDCouplingUMesh::convertLinearCellsToQuadratic3D0(DataArrayInt *&conn, DataArrayInt *&connI, DataArrayDouble *& coords, std::set& types) const +{ + MEDCouplingAutoRefCountObjectPtr desc(DataArrayInt::New()),descI(DataArrayInt::New()),tmp2(DataArrayInt::New()),tmp3(DataArrayInt::New()); + MEDCouplingAutoRefCountObjectPtr m1D=explode3DMeshTo1D(desc,descI,tmp2,tmp3); tmp2=0; tmp3=0; + return convertLinearCellsToQuadratic2DAnd3D0(m1D,desc,descI,conn,connI,coords,types); +} + +DataArrayInt *MEDCouplingUMesh::convertLinearCellsToQuadratic3D1(DataArrayInt *&conn, DataArrayInt *&connI, DataArrayDouble *& coords, std::set& types) const +{ + MEDCouplingAutoRefCountObjectPtr desc2(DataArrayInt::New()),desc2I(DataArrayInt::New()),tmp2(DataArrayInt::New()),tmp3(DataArrayInt::New()); + MEDCouplingAutoRefCountObjectPtr m2D=buildDescendingConnectivityGen(desc2,desc2I,tmp2,tmp3,MEDCouplingFastNbrer); tmp2=0; tmp3=0; + MEDCouplingAutoRefCountObjectPtr desc1(DataArrayInt::New()),desc1I(DataArrayInt::New()),tmp4(DataArrayInt::New()),tmp5(DataArrayInt::New()); + MEDCouplingAutoRefCountObjectPtr m1D=explode3DMeshTo1D(desc1,desc1I,tmp4,tmp5); tmp4=0; tmp5=0; + // + MEDCouplingAutoRefCountObjectPtr newConn=DataArrayInt::New(); newConn->alloc(0,1); + MEDCouplingAutoRefCountObjectPtr newConnI=DataArrayInt::New(); newConnI->alloc(1,1); newConnI->setIJ(0,0,0); + MEDCouplingAutoRefCountObjectPtr ret=DataArrayInt::New(),ret2=DataArrayInt::New(); ret->alloc(0,1); ret2->alloc(0,1); + // + MEDCouplingAutoRefCountObjectPtr bary=getBarycenterAndOwner(); + const int *descPtr(desc1->begin()),*descIPtr(desc1I->begin()),*desc2Ptr(desc2->begin()),*desc2IPtr(desc2I->begin()); + DataArrayInt *conn1D=0,*conn1DI=0,*conn2D=0,*conn2DI=0; + std::set types1D,types2D; + DataArrayDouble *coordsTmp=0,*coordsTmp2=0; + MEDCouplingAutoRefCountObjectPtr ret1D=m1D->convertLinearCellsToQuadratic1D0(conn1D,conn1DI,coordsTmp,types1D); ret1D=DataArrayInt::New(); ret1D->alloc(0,1); + MEDCouplingAutoRefCountObjectPtr conn1DSafe(conn1D),conn1DISafe(conn1DI); + MEDCouplingAutoRefCountObjectPtr coordsTmpSafe(coordsTmp); + MEDCouplingAutoRefCountObjectPtr ret2D=m2D->convertLinearCellsToQuadratic2D1(conn2D,conn2DI,coordsTmp2,types2D); ret2D=DataArrayInt::New(); ret2D->alloc(0,1); + MEDCouplingAutoRefCountObjectPtr coordsTmp2Safe(coordsTmp2); + MEDCouplingAutoRefCountObjectPtr conn2DSafe(conn2D),conn2DISafe(conn2DI); + const int *c1DPtr=conn1D->begin(),*c1DIPtr=conn1DI->begin(),*c2DPtr=conn2D->begin(),*c2DIPtr=conn2DI->begin(); + int nbOfCells=getNumberOfCells(); + const int *cPtr=_nodal_connec->getConstPointer(); + const int *icPtr=_nodal_connec_index->getConstPointer(); + int lastVal=0,offset=coordsTmpSafe->getNumberOfTuples(); + for(int i=0;ipushBackSilent(typ2); + newConn->pushBackValsSilent(cPtr+icPtr[0]+1,cPtr+icPtr[1]); + for(const int *d=descPtr+descIPtr[0];d!=descPtr+descIPtr[1];d++) + newConn->pushBackSilent(c1DPtr[c1DIPtr[*d]+3]); + for(const int *d=desc2Ptr+desc2IPtr[0];d!=desc2Ptr+desc2IPtr[1];d++) + { + int nodeId2=c2DPtr[c2DIPtr[(*d)+1]-1]; + int tmpPos=newConn->getNumberOfTuples(); + newConn->pushBackSilent(nodeId2); + ret2D->pushBackSilent(nodeId2); ret1D->pushBackSilent(tmpPos); + } + newConn->pushBackSilent(offset+ret->getNumberOfTuples()); + lastVal+=(icPtr[1]-icPtr[0])+(descIPtr[1]-descIPtr[0])+(desc2IPtr[1]-desc2IPtr[0])+1; + newConnI->pushBackSilent(lastVal); + ret->pushBackSilent(i); + } + else + { + types.insert(typ); + lastVal+=(icPtr[1]-icPtr[0]); + newConnI->pushBackSilent(lastVal); + newConn->pushBackValsSilent(cPtr+icPtr[0],cPtr+icPtr[1]); + } + } + MEDCouplingAutoRefCountObjectPtr diffRet2D=ret2D->getDifferentValues(); + MEDCouplingAutoRefCountObjectPtr o2nRet2D=diffRet2D->invertArrayN2O2O2N(coordsTmp2Safe->getNumberOfTuples()); + coordsTmp2Safe=coordsTmp2Safe->selectByTupleId(diffRet2D->begin(),diffRet2D->end()); + MEDCouplingAutoRefCountObjectPtr tmp=bary->selectByTupleIdSafe(ret->begin(),ret->end()); + std::vector v(3); v[0]=coordsTmpSafe; v[1]=coordsTmp2Safe; v[2]=tmp; + int *c=newConn->getPointer(); + const int *cI(newConnI->begin()); + for(const int *elt=ret1D->begin();elt!=ret1D->end();elt++) + c[*elt]=o2nRet2D->getIJ(c[*elt],0)+offset; + offset=coordsTmp2Safe->getNumberOfTuples(); + for(const int *elt=ret->begin();elt!=ret->end();elt++) + c[cI[(*elt)+1]-1]+=offset; + coords=DataArrayDouble::Aggregate(v); conn=newConn.retn(); connI=newConnI.retn(); + return ret.retn(); +} + +/*! + * Tessellates \a this 2D mesh by dividing not straight edges of quadratic faces, + * so that the number of cells remains the same. Quadratic faces are converted to + * polygons. This method works only for 2D meshes in + * 2D space. If no cells are quadratic (INTERP_KERNEL::NORM_QUAD8, + * INTERP_KERNEL::NORM_TRI6, INTERP_KERNEL::NORM_QPOLYG ), \a this mesh remains unchanged. + * \warning This method can lead to a huge amount of nodes if \a eps is very low. + * \param [in] eps - specifies the maximal angle (in radians) between 2 sub-edges of + * a polylinized edge constituting the input polygon. + * \throw If the coordinates array is not set. + * \throw If the nodal connectivity of cells is not defined. + * \throw If \a this->getMeshDimension() != 2. + * \throw If \a this->getSpaceDimension() != 2. + */ +void MEDCouplingUMesh::tessellate2D(double eps) +{ + checkFullyDefined(); + if(getMeshDimension()!=2 || getSpaceDimension()!=2) + throw INTERP_KERNEL::Exception("MEDCouplingUMesh::tessellate2D works on umeshes with meshdim equal to 2 and spaceDim equal to 2 too!"); + double epsa=fabs(eps); + if(epsa::min()) + throw INTERP_KERNEL::Exception("MEDCouplingUMesh::tessellate2DCurve : epsilon is null ! Please specify a higher epsilon. If too tiny it can lead to a huge amount of nodes and memory !"); + MEDCouplingAutoRefCountObjectPtr desc1=DataArrayInt::New(); + MEDCouplingAutoRefCountObjectPtr descIndx1=DataArrayInt::New(); + MEDCouplingAutoRefCountObjectPtr revDesc1=DataArrayInt::New(); + MEDCouplingAutoRefCountObjectPtr revDescIndx1=DataArrayInt::New(); + MEDCouplingAutoRefCountObjectPtr mDesc=buildDescendingConnectivity2(desc1,descIndx1,revDesc1,revDescIndx1); + revDesc1=0; revDescIndx1=0; + mDesc->tessellate2DCurve(eps); + subDivide2DMesh(mDesc->_nodal_connec->getConstPointer(),mDesc->_nodal_connec_index->getConstPointer(),desc1->getConstPointer(),descIndx1->getConstPointer()); + setCoords(mDesc->getCoords()); +} + +/*! + * Tessellates \a this 1D mesh in 2D space by dividing not straight quadratic edges. + * \warning This method can lead to a huge amount of nodes if \a eps is very low. + * \param [in] eps - specifies the maximal angle (in radian) between 2 sub-edges of + * a sub-divided edge. + * \throw If the coordinates array is not set. + * \throw If the nodal connectivity of cells is not defined. + * \throw If \a this->getMeshDimension() != 1. + * \throw If \a this->getSpaceDimension() != 2. + */ +void MEDCouplingUMesh::tessellate2DCurve(double eps) +{ + checkFullyDefined(); + if(getMeshDimension()!=1 || getSpaceDimension()!=2) + throw INTERP_KERNEL::Exception("MEDCouplingUMesh::tessellate2DCurve works on umeshes with meshdim equal to 1 and spaceDim equal to 2 too!"); + double epsa=fabs(eps); + if(epsa::min()) + throw INTERP_KERNEL::Exception("MEDCouplingUMesh::tessellate2DCurve : epsilon is null ! Please specify a higher epsilon. If too tiny it can lead to a huge amount of nodes and memory !"); + INTERP_KERNEL::QUADRATIC_PLANAR::_arc_detection_precision=1.e-10; + int nbCells=getNumberOfCells(); + int nbNodes=getNumberOfNodes(); + const int *conn=_nodal_connec->getConstPointer(); + const int *connI=_nodal_connec_index->getConstPointer(); + const double *coords=_coords->getConstPointer(); + std::vector addCoo; + std::vector newConn;//no direct DataArrayInt because interface with Geometric2D + MEDCouplingAutoRefCountObjectPtr newConnI(DataArrayInt::New()); + newConnI->alloc(nbCells+1,1); + int *newConnIPtr=newConnI->getPointer(); + *newConnIPtr=0; + int tmp1[3]; + INTERP_KERNEL::Node *tmp2[3]; + std::set types; + for(int i=0;itesselate(tmp1,nbNodes,epsa,newConn,addCoo); + types.insert((INTERP_KERNEL::NormalizedCellType)newConn[newConnIPtr[0]]); + delete eac; + newConnIPtr[1]=(int)newConn.size(); + } + else + { + types.insert(INTERP_KERNEL::NORM_SEG2); + newConn.push_back(INTERP_KERNEL::NORM_SEG2); + newConn.insert(newConn.end(),conn+connI[i]+1,conn+connI[i]+3); + newConnIPtr[1]=newConnIPtr[0]+3; + } + } + else + { + types.insert((INTERP_KERNEL::NormalizedCellType)conn[connI[i]]); + newConn.insert(newConn.end(),conn+connI[i],conn+connI[i+1]); + newConnIPtr[1]=newConnIPtr[0]+3; + } + } + if(addCoo.empty() && ((int)newConn.size())==_nodal_connec->getNumberOfTuples())//nothing happens during tessellation : no update needed + return ; + _types=types; + DataArrayInt::SetArrayIn(newConnI,_nodal_connec_index); + MEDCouplingAutoRefCountObjectPtr newConnArr=DataArrayInt::New(); + newConnArr->alloc((int)newConn.size(),1); + std::copy(newConn.begin(),newConn.end(),newConnArr->getPointer()); + DataArrayInt::SetArrayIn(newConnArr,_nodal_connec); + MEDCouplingAutoRefCountObjectPtr newCoords=DataArrayDouble::New(); + newCoords->alloc(nbNodes+((int)addCoo.size())/2,2); + double *work=std::copy(_coords->begin(),_coords->end(),newCoords->getPointer()); + std::copy(addCoo.begin(),addCoo.end(),work); + DataArrayDouble::SetArrayIn(newCoords,_coords); + updateTime(); +} + +/*! + * Divides every cell of \a this mesh into simplices (triangles in 2D and tetrahedra in 3D). + * In addition, returns an array mapping new cells to old ones.
+ * This method typically increases the number of cells in \a this mesh + * but the number of nodes remains \b unchanged. + * That's why the 3D splitting policies + * INTERP_KERNEL::GENERAL_24 and INTERP_KERNEL::GENERAL_48 are not available here. + * \param [in] policy - specifies a pattern used for splitting. + * The semantic of \a policy is: + * - 0 - to split QUAD4 by cutting it along 0-2 diagonal (for 2D mesh only). + * - 1 - to split QUAD4 by cutting it along 1-3 diagonal (for 2D mesh only). + * - INTERP_KERNEL::PLANAR_FACE_5 - to split HEXA8 into 5 TETRA4 (for 3D mesh only - see INTERP_KERNEL::SplittingPolicy for an image). + * - INTERP_KERNEL::PLANAR_FACE_6 - to split HEXA8 into 6 TETRA4 (for 3D mesh only - see INTERP_KERNEL::SplittingPolicy for an image). + * + * + * \return DataArrayInt * - a new instance of DataArrayInt holding, for each new cell, + * an id of old cell producing it. The caller is to delete this array using + * decrRef() as it is no more needed. + * + * \throw If \a policy is 0 or 1 and \a this->getMeshDimension() != 2. + * \throw If \a policy is INTERP_KERNEL::PLANAR_FACE_5 or INTERP_KERNEL::PLANAR_FACE_6 + * and \a this->getMeshDimension() != 3. + * \throw If \a policy is not one of the four discussed above. + * \throw If the nodal connectivity of cells is not defined. + * \sa MEDCouplingUMesh::tetrahedrize, MEDCoupling1SGTUMesh::sortHexa8EachOther + */ +DataArrayInt *MEDCouplingUMesh::simplexize(int policy) +{ + switch(policy) + { + case 0: + return simplexizePol0(); + case 1: + return simplexizePol1(); + case (int) INTERP_KERNEL::PLANAR_FACE_5: + return simplexizePlanarFace5(); + case (int) INTERP_KERNEL::PLANAR_FACE_6: + return simplexizePlanarFace6(); + default: + throw INTERP_KERNEL::Exception("MEDCouplingUMesh::simplexize : unrecognized policy ! Must be :\n - 0 or 1 (only available for meshdim=2) \n - PLANAR_FACE_5, PLANAR_FACE_6 (only for meshdim=3)"); + } +} + +/*! + * Checks if \a this mesh is constituted by simplex cells only. Simplex cells are: + * - 1D: INTERP_KERNEL::NORM_SEG2 + * - 2D: INTERP_KERNEL::NORM_TRI3 + * - 3D: INTERP_KERNEL::NORM_TETRA4. + * + * This method is useful for users that need to use P1 field services as + * MEDCouplingFieldDouble::getValueOn(), MEDCouplingField::buildMeasureField() etc. + * All these methods need mesh support containing only simplex cells. + * \return bool - \c true if there are only simplex cells in \a this mesh. + * \throw If the coordinates array is not set. + * \throw If the nodal connectivity of cells is not defined. + * \throw If \a this->getMeshDimension() < 1. + */ +bool MEDCouplingUMesh::areOnlySimplexCells() const +{ + checkFullyDefined(); + int mdim=getMeshDimension(); + if(mdim<1 || mdim>3) + throw INTERP_KERNEL::Exception("MEDCouplingUMesh::areOnlySimplexCells : only available with meshes having a meshdim 1, 2 or 3 !"); + int nbCells=getNumberOfCells(); + const int *conn=_nodal_connec->getConstPointer(); + const int *connI=_nodal_connec_index->getConstPointer(); + for(int i=0;i ret=DataArrayInt::New(); + int nbOfCutCells=getNumberOfCellsWithType(INTERP_KERNEL::NORM_QUAD4); + ret->alloc(nbOfCells+nbOfCutCells,1); + if(nbOfCutCells==0) { ret->iota(0); return ret.retn(); } + int *retPt=ret->getPointer(); + MEDCouplingAutoRefCountObjectPtr newConn=DataArrayInt::New(); + MEDCouplingAutoRefCountObjectPtr newConnI=DataArrayInt::New(); + newConnI->alloc(nbOfCells+nbOfCutCells+1,1); + newConn->alloc(getMeshLength()+3*nbOfCutCells,1); + int *pt=newConn->getPointer(); + int *ptI=newConnI->getPointer(); + ptI[0]=0; + const int *oldc=_nodal_connec->getConstPointer(); + const int *ci=_nodal_connec_index->getConstPointer(); + for(int i=0;idecrRef(); + _nodal_connec=newConn.retn(); + _nodal_connec_index->decrRef(); + _nodal_connec_index=newConnI.retn(); + computeTypes(); + updateTime(); + return ret.retn(); +} + +/*! + * This method implements policy 1 of virtual method ParaMEDMEM::MEDCouplingUMesh::simplexize. + */ +DataArrayInt *MEDCouplingUMesh::simplexizePol1() +{ + checkConnectivityFullyDefined(); + if(getMeshDimension()!=2) + throw INTERP_KERNEL::Exception("MEDCouplingUMesh::simplexizePol0 : this policy is only available for mesh with meshdim == 2 !"); + int nbOfCells=getNumberOfCells(); + MEDCouplingAutoRefCountObjectPtr ret=DataArrayInt::New(); + int nbOfCutCells=getNumberOfCellsWithType(INTERP_KERNEL::NORM_QUAD4); + ret->alloc(nbOfCells+nbOfCutCells,1); + if(nbOfCutCells==0) { ret->iota(0); return ret.retn(); } + int *retPt=ret->getPointer(); + MEDCouplingAutoRefCountObjectPtr newConn=DataArrayInt::New(); + MEDCouplingAutoRefCountObjectPtr newConnI=DataArrayInt::New(); + newConnI->alloc(nbOfCells+nbOfCutCells+1,1); + newConn->alloc(getMeshLength()+3*nbOfCutCells,1); + int *pt=newConn->getPointer(); + int *ptI=newConnI->getPointer(); + ptI[0]=0; + const int *oldc=_nodal_connec->getConstPointer(); + const int *ci=_nodal_connec_index->getConstPointer(); + for(int i=0;idecrRef(); + _nodal_connec=newConn.retn(); + _nodal_connec_index->decrRef(); + _nodal_connec_index=newConnI.retn(); + computeTypes(); + updateTime(); + return ret.retn(); +} + +/*! + * This method implements policy INTERP_KERNEL::PLANAR_FACE_5 of virtual method ParaMEDMEM::MEDCouplingUMesh::simplexize. + */ +DataArrayInt *MEDCouplingUMesh::simplexizePlanarFace5() +{ + checkConnectivityFullyDefined(); + if(getMeshDimension()!=3) + throw INTERP_KERNEL::Exception("MEDCouplingUMesh::simplexizePlanarFace5 : this policy is only available for mesh with meshdim == 3 !"); + int nbOfCells=getNumberOfCells(); + MEDCouplingAutoRefCountObjectPtr ret=DataArrayInt::New(); + int nbOfCutCells=getNumberOfCellsWithType(INTERP_KERNEL::NORM_HEXA8); + ret->alloc(nbOfCells+4*nbOfCutCells,1); + if(nbOfCutCells==0) { ret->iota(0); return ret.retn(); } + int *retPt=ret->getPointer(); + MEDCouplingAutoRefCountObjectPtr newConn=DataArrayInt::New(); + MEDCouplingAutoRefCountObjectPtr newConnI=DataArrayInt::New(); + newConnI->alloc(nbOfCells+4*nbOfCutCells+1,1); + newConn->alloc(getMeshLength()+16*nbOfCutCells,1);//21 + int *pt=newConn->getPointer(); + int *ptI=newConnI->getPointer(); + ptI[0]=0; + const int *oldc=_nodal_connec->getConstPointer(); + const int *ci=_nodal_connec_index->getConstPointer(); + for(int i=0;idecrRef(); + _nodal_connec=newConn.retn(); + _nodal_connec_index->decrRef(); + _nodal_connec_index=newConnI.retn(); + computeTypes(); + updateTime(); + return ret.retn(); +} + +/*! + * This method implements policy INTERP_KERNEL::PLANAR_FACE_6 of virtual method ParaMEDMEM::MEDCouplingUMesh::simplexize. + */ +DataArrayInt *MEDCouplingUMesh::simplexizePlanarFace6() +{ + checkConnectivityFullyDefined(); + if(getMeshDimension()!=3) + throw INTERP_KERNEL::Exception("MEDCouplingUMesh::simplexizePlanarFace6 : this policy is only available for mesh with meshdim == 3 !"); + int nbOfCells=getNumberOfCells(); + MEDCouplingAutoRefCountObjectPtr ret=DataArrayInt::New(); + int nbOfCutCells=getNumberOfCellsWithType(INTERP_KERNEL::NORM_HEXA8); + ret->alloc(nbOfCells+5*nbOfCutCells,1); + if(nbOfCutCells==0) { ret->iota(0); return ret.retn(); } + int *retPt=ret->getPointer(); + MEDCouplingAutoRefCountObjectPtr newConn=DataArrayInt::New(); + MEDCouplingAutoRefCountObjectPtr newConnI=DataArrayInt::New(); + newConnI->alloc(nbOfCells+5*nbOfCutCells+1,1); + newConn->alloc(getMeshLength()+21*nbOfCutCells,1); + int *pt=newConn->getPointer(); + int *ptI=newConnI->getPointer(); + ptI[0]=0; + const int *oldc=_nodal_connec->getConstPointer(); + const int *ci=_nodal_connec_index->getConstPointer(); + for(int i=0;idecrRef(); + _nodal_connec=newConn.retn(); + _nodal_connec_index->decrRef(); + _nodal_connec_index=newConnI.retn(); + computeTypes(); + updateTime(); + return ret.retn(); +} + +/*! + * This private method is used to subdivide edges of a mesh with meshdim==2. If \a this has no a meshdim equal to 2 an exception will be thrown. + * This method completly ignore coordinates. + * \param nodeSubdived is the nodal connectivity of subdivision of edges + * \param nodeIndxSubdived is the nodal connectivity index of subdivision of edges + * \param desc is descending connectivity in format specified in MEDCouplingUMesh::buildDescendingConnectivity2 + * \param descIndex is descending connectivity index in format specified in MEDCouplingUMesh::buildDescendingConnectivity2 + */ +void MEDCouplingUMesh::subDivide2DMesh(const int *nodeSubdived, const int *nodeIndxSubdived, const int *desc, const int *descIndex) +{ + checkFullyDefined(); + if(getMeshDimension()!=2) + throw INTERP_KERNEL::Exception("MEDCouplingUMesh::subDivide2DMesh : works only on umesh with meshdim==2 !"); + int nbOfCells=getNumberOfCells(); + int *connI=_nodal_connec_index->getPointer(); + int newConnLgth=0; + for(int i=0;i0; + int eedgeId=std::abs(desc[offset+nbOfEdges-1])-1; + int ref=ddirect?nodeSubdived[nodeIndxSubdived[eedgeId+1]-1]:nodeSubdived[nodeIndxSubdived[eedgeId]+1]; + for(int j=0;j0; + int edgeId=std::abs(desc[offset+j])-1; + if(!INTERP_KERNEL::CellModel::GetCellModel((INTERP_KERNEL::NormalizedCellType)nodeSubdived[nodeIndxSubdived[edgeId]]).isQuadratic()) + { + int id1=nodeSubdived[nodeIndxSubdived[edgeId]+1]; + int id2=nodeSubdived[nodeIndxSubdived[edgeId+1]-1]; + int ref2=direct?id1:id2; + if(ref==ref2) + { + int nbOfSubNodes=nodeIndxSubdived[edgeId+1]-nodeIndxSubdived[edgeId]-1; + newConnLgth+=nbOfSubNodes-1; + ref=direct?id2:id1; + } + else + { + std::ostringstream oss; oss << "MEDCouplingUMesh::subDivide2DMesh : On polygon #" << i << " edgeid #" << j << " subedges mismatch : end subedge k!=start subedge k+1 !"; + throw INTERP_KERNEL::Exception(oss.str().c_str()); + } + } + else + { + throw INTERP_KERNEL::Exception("MEDCouplingUMesh::subDivide2DMesh : this method only subdivides into linear edges !"); + } + } + newConnLgth++;//+1 is for cell type + connI[1]=newConnLgth; + } + // + MEDCouplingAutoRefCountObjectPtr newConn=DataArrayInt::New(); + newConn->alloc(newConnLgth,1); + int *work=newConn->getPointer(); + for(int i=0;i0; + int edgeId=std::abs(desc[offset+j])-1; + if(direct) + work=std::copy(nodeSubdived+nodeIndxSubdived[edgeId]+1,nodeSubdived+nodeIndxSubdived[edgeId+1]-1,work); + else + { + int nbOfSubNodes=nodeIndxSubdived[edgeId+1]-nodeIndxSubdived[edgeId]-1; + std::reverse_iterator it(nodeSubdived+nodeIndxSubdived[edgeId+1]); + work=std::copy(it,it+nbOfSubNodes-1,work); + } + } + } + DataArrayInt::SetArrayIn(newConn,_nodal_connec); + _types.clear(); + if(nbOfCells>0) + _types.insert(INTERP_KERNEL::NORM_POLYGON); +} + +/*! + * Converts degenerated 2D or 3D linear cells of \a this mesh into cells of simpler + * type. For example an INTERP_KERNEL::NORM_QUAD4 cell having only three unique nodes in + * its connectivity is transformed into an INTERP_KERNEL::NORM_TRI3 cell. This method + * does \b not perform geometrical checks and checks only nodal connectivity of cells, + * so it can be useful to call mergeNodes() before calling this method. + * \throw If \a this->getMeshDimension() <= 1. + * \throw If the coordinates array is not set. + * \throw If the nodal connectivity of cells is not defined. + */ +void MEDCouplingUMesh::convertDegeneratedCells() +{ + checkFullyDefined(); + if(getMeshDimension()<=1) + throw INTERP_KERNEL::Exception("MEDCouplingUMesh::convertDegeneratedCells works on umeshes with meshdim equals to 2 or 3 !"); + int nbOfCells=getNumberOfCells(); + if(nbOfCells<1) + return ; + int initMeshLgth=getMeshLength(); + int *conn=_nodal_connec->getPointer(); + int *index=_nodal_connec_index->getPointer(); + int posOfCurCell=0; + int newPos=0; + int lgthOfCurCell; + for(int i=0;ireAlloc(newPos); + computeTypes(); +} + +/*! + * Finds incorrectly oriented cells of this 2D mesh in 3D space. + * A cell is considered to be oriented correctly if an angle between its + * normal vector and a given vector is less than \c PI / \c 2. + * \param [in] vec - 3 components of the vector specifying the correct orientation of + * cells. + * \param [in] polyOnly - if \c true, only polygons are checked, else, all cells are + * checked. + * \param [in,out] cells - a vector returning ids of incorrectly oriented cells. It + * is not cleared before filling in. + * \throw If \a this->getMeshDimension() != 2. + * \throw If \a this->getSpaceDimension() != 3. + * + * \if ENABLE_EXAMPLES + * \ref cpp_mcumesh_are2DCellsNotCorrectlyOriented "Here is a C++ example".
+ * \ref py_mcumesh_are2DCellsNotCorrectlyOriented "Here is a Python example". + * \endif + */ +void MEDCouplingUMesh::are2DCellsNotCorrectlyOriented(const double *vec, bool polyOnly, std::vector& cells) const +{ + if(getMeshDimension()!=2 || getSpaceDimension()!=3) + throw INTERP_KERNEL::Exception("Invalid mesh to apply are2DCellsNotCorrectlyOriented on it : must be meshDim==2 and spaceDim==3 !"); + int nbOfCells=getNumberOfCells(); + const int *conn=_nodal_connec->getConstPointer(); + const int *connI=_nodal_connec_index->getConstPointer(); + const double *coordsPtr=_coords->getConstPointer(); + for(int i=0;igetMeshDimension() != 2. + * \throw If \a this->getSpaceDimension() != 3. + * + * \if ENABLE_EXAMPLES + * \ref cpp_mcumesh_are2DCellsNotCorrectlyOriented "Here is a C++ example".
+ * \ref py_mcumesh_are2DCellsNotCorrectlyOriented "Here is a Python example". + * \endif + * + * \sa changeOrientationOfCells + */ +void MEDCouplingUMesh::orientCorrectly2DCells(const double *vec, bool polyOnly) +{ + if(getMeshDimension()!=2 || getSpaceDimension()!=3) + throw INTERP_KERNEL::Exception("Invalid mesh to apply orientCorrectly2DCells on it : must be meshDim==2 and spaceDim==3 !"); + int nbOfCells(getNumberOfCells()),*conn(_nodal_connec->getPointer()); + const int *connI(_nodal_connec_index->getConstPointer()); + const double *coordsPtr(_coords->getConstPointer()); + bool isModified(false); + for(int i=0;ideclareAsNew(); + updateTime(); +} + +/*! + * This method change the orientation of cells in \a this without any consideration of coordinates. Only connectivity is impacted. + * + * \sa orientCorrectly2DCells + */ +void MEDCouplingUMesh::changeOrientationOfCells() +{ + int mdim(getMeshDimension()); + if(mdim!=2 && mdim!=1) + throw INTERP_KERNEL::Exception("Invalid mesh to apply changeOrientationOfCells on it : must be meshDim==2 or meshDim==1 !"); + int nbOfCells(getNumberOfCells()),*conn(_nodal_connec->getPointer()); + const int *connI(_nodal_connec_index->getConstPointer()); + if(mdim==2) + {//2D + for(int i=0;igetMeshDimension() != 3. + * \throw If \a this->getSpaceDimension() != 3. + * \throw If the coordinates array is not set. + * \throw If the nodal connectivity of cells is not defined. + * + * \if ENABLE_EXAMPLES + * \ref cpp_mcumesh_arePolyhedronsNotCorrectlyOriented "Here is a C++ example".
+ * \ref py_mcumesh_arePolyhedronsNotCorrectlyOriented "Here is a Python example". + * \endif + */ +void MEDCouplingUMesh::arePolyhedronsNotCorrectlyOriented(std::vector& cells) const +{ + if(getMeshDimension()!=3 || getSpaceDimension()!=3) + throw INTERP_KERNEL::Exception("Invalid mesh to apply arePolyhedronsNotCorrectlyOriented on it : must be meshDim==3 and spaceDim==3 !"); + int nbOfCells=getNumberOfCells(); + const int *conn=_nodal_connec->getConstPointer(); + const int *connI=_nodal_connec_index->getConstPointer(); + const double *coordsPtr=_coords->getConstPointer(); + for(int i=0;igetMeshDimension() != 3. + * \throw If \a this->getSpaceDimension() != 3. + * \throw If the coordinates array is not set. + * \throw If the nodal connectivity of cells is not defined. + * \throw If the reparation fails. + * + * \if ENABLE_EXAMPLES + * \ref cpp_mcumesh_arePolyhedronsNotCorrectlyOriented "Here is a C++ example".
+ * \ref py_mcumesh_arePolyhedronsNotCorrectlyOriented "Here is a Python example". + * \endif + * \sa MEDCouplingUMesh::findAndCorrectBadOriented3DCells + */ +void MEDCouplingUMesh::orientCorrectlyPolyhedrons() +{ + if(getMeshDimension()!=3 || getSpaceDimension()!=3) + throw INTERP_KERNEL::Exception("Invalid mesh to apply orientCorrectlyPolyhedrons on it : must be meshDim==3 and spaceDim==3 !"); + int nbOfCells=getNumberOfCells(); + int *conn=_nodal_connec->getPointer(); + const int *connI=_nodal_connec_index->getConstPointer(); + const double *coordsPtr=_coords->getConstPointer(); + for(int i=0;igetMeshDimension() != 3. + * \throw If \a this->getSpaceDimension() != 3. + * \throw If the coordinates array is not set. + * \throw If the nodal connectivity of cells is not defined. + * + * \if ENABLE_EXAMPLES + * \ref cpp_mcumesh_findAndCorrectBadOriented3DExtrudedCells "Here is a C++ example".
+ * \ref py_mcumesh_findAndCorrectBadOriented3DExtrudedCells "Here is a Python example". + * \endif + * \sa MEDCouplingUMesh::findAndCorrectBadOriented3DCells + */ +DataArrayInt *MEDCouplingUMesh::findAndCorrectBadOriented3DExtrudedCells() +{ + const char msg[]="check3DCellsWellOriented detection works only for 3D cells !"; + if(getMeshDimension()!=3) + throw INTERP_KERNEL::Exception(msg); + int spaceDim=getSpaceDimension(); + if(spaceDim!=3) + throw INTERP_KERNEL::Exception(msg); + // + int nbOfCells=getNumberOfCells(); + int *conn=_nodal_connec->getPointer(); + const int *connI=_nodal_connec_index->getConstPointer(); + const double *coo=getCoords()->getConstPointer(); + MEDCouplingAutoRefCountObjectPtr cells(DataArrayInt::New()); cells->alloc(0,1); + for(int i=0;ipushBackSilent(i); + } + } + } + return cells.retn(); +} + +/*! + * This method is a faster method to correct orientation of all 3D cells in \a this. + * This method works only if \a this is a 3D mesh, that is to say a mesh with mesh dimension 3 and a space dimension 3. + * This method makes the hypothesis that \a this a coherent that is to say MEDCouplingUMesh::checkCoherency2 should throw no exception. + * + * \return a newly allocated int array with one components containing cell ids renumbered to fit the convention of MED (MED file and MEDCoupling) + * \sa MEDCouplingUMesh::orientCorrectlyPolyhedrons, + */ +DataArrayInt *MEDCouplingUMesh::findAndCorrectBadOriented3DCells() +{ + if(getMeshDimension()!=3 || getSpaceDimension()!=3) + throw INTERP_KERNEL::Exception("Invalid mesh to apply findAndCorrectBadOriented3DCells on it : must be meshDim==3 and spaceDim==3 !"); + int nbOfCells=getNumberOfCells(); + int *conn=_nodal_connec->getPointer(); + const int *connI=_nodal_connec_index->getConstPointer(); + const double *coordsPtr=_coords->getConstPointer(); + MEDCouplingAutoRefCountObjectPtr ret=DataArrayInt::New(); ret->alloc(0,1); + for(int i=0;ipushBackSilent(i); + } + break; + } + case INTERP_KERNEL::NORM_PYRA5: + { + if(!IsPyra5WellOriented(conn+connI[i]+1,conn+connI[i+1],coordsPtr)) + { + std::swap(*(conn+connI[i]+2),*(conn+connI[i]+4)); + ret->pushBackSilent(i); + } + break; + } + case INTERP_KERNEL::NORM_PENTA6: + case INTERP_KERNEL::NORM_HEXA8: + case INTERP_KERNEL::NORM_HEXGP12: + { + if(!Is3DExtrudedStaticCellWellOriented(conn+connI[i]+1,conn+connI[i+1],coordsPtr)) + { + CorrectExtrudedStaticCell(conn+connI[i]+1,conn+connI[i+1]); + ret->pushBackSilent(i); + } + break; + } + case INTERP_KERNEL::NORM_POLYHED: + { + if(!IsPolyhedronWellOriented(conn+connI[i]+1,conn+connI[i+1],coordsPtr)) + { + TryToCorrectPolyhedronOrientation(conn+connI[i]+1,conn+connI[i+1],coordsPtr); + ret->pushBackSilent(i); + } + break; + } + default: + throw INTERP_KERNEL::Exception("MEDCouplingUMesh::orientCorrectly3DCells : Your mesh contains type of cell not supported yet ! send mail to anthony.geay@cea.fr to add it !"); + } + } + updateTime(); + return ret.retn(); +} + +/*! + * This method has a sense for meshes with spaceDim==3 and meshDim==2. + * If it is not the case an exception will be thrown. + * This method is fast because the first cell of \a this is used to compute the plane. + * \param vec output of size at least 3 used to store the normal vector (with norm equal to Area ) of searched plane. + * \param pos output of size at least 3 used to store a point owned of searched plane. + */ +void MEDCouplingUMesh::getFastAveragePlaneOfThis(double *vec, double *pos) const +{ + if(getMeshDimension()!=2 || getSpaceDimension()!=3) + throw INTERP_KERNEL::Exception("Invalid mesh to apply getFastAveragePlaneOfThis on it : must be meshDim==2 and spaceDim==3 !"); + const int *conn=_nodal_connec->getConstPointer(); + const int *connI=_nodal_connec_index->getConstPointer(); + const double *coordsPtr=_coords->getConstPointer(); + INTERP_KERNEL::areaVectorOfPolygon(conn+1,connI[1]-connI[0]-1,coordsPtr,vec); + std::copy(coordsPtr+3*conn[1],coordsPtr+3*conn[1]+3,pos); +} + +/*! + * Creates a new MEDCouplingFieldDouble holding Edge Ratio values of all + * cells. Currently cells of the following types are treated: + * INTERP_KERNEL::NORM_TRI3, INTERP_KERNEL::NORM_QUAD4 and INTERP_KERNEL::NORM_TETRA4. + * For a cell of other type an exception is thrown. + * Space dimension of a 2D mesh can be either 2 or 3. + * The Edge Ratio of a cell \f$t\f$ is: + * \f$\frac{|t|_\infty}{|t|_0}\f$, + * where \f$|t|_\infty\f$ and \f$|t|_0\f$ respectively denote the greatest and + * the smallest edge lengths of \f$t\f$. + * \return MEDCouplingFieldDouble * - a new instance of MEDCouplingFieldDouble on + * cells and one time, lying on \a this mesh. The caller is to delete this + * field using decrRef() as it is no more needed. + * \throw If the coordinates array is not set. + * \throw If \a this mesh contains elements of dimension different from the mesh dimension. + * \throw If the connectivity data array has more than one component. + * \throw If the connectivity data array has a named component. + * \throw If the connectivity index data array has more than one component. + * \throw If the connectivity index data array has a named component. + * \throw If \a this->getMeshDimension() is neither 2 nor 3. + * \throw If \a this->getSpaceDimension() is neither 2 nor 3. + * \throw If \a this mesh includes cells of type different from the ones enumerated above. + */ +MEDCouplingFieldDouble *MEDCouplingUMesh::getEdgeRatioField() const +{ + checkCoherency(); + int spaceDim=getSpaceDimension(); + int meshDim=getMeshDimension(); + if(spaceDim!=2 && spaceDim!=3) + throw INTERP_KERNEL::Exception("MEDCouplingUMesh::getEdgeRatioField : SpaceDimension must be equal to 2 or 3 !"); + if(meshDim!=2 && meshDim!=3) + throw INTERP_KERNEL::Exception("MEDCouplingUMesh::getEdgeRatioField : MeshDimension must be equal to 2 or 3 !"); + MEDCouplingAutoRefCountObjectPtr ret=MEDCouplingFieldDouble::New(ON_CELLS,ONE_TIME); + ret->setMesh(this); + int nbOfCells=getNumberOfCells(); + MEDCouplingAutoRefCountObjectPtr arr=DataArrayDouble::New(); + arr->alloc(nbOfCells,1); + double *pt=arr->getPointer(); + ret->setArray(arr);//In case of throw to avoid mem leaks arr will be used after decrRef. + const int *conn=_nodal_connec->getConstPointer(); + const int *connI=_nodal_connec_index->getConstPointer(); + const double *coo=_coords->getConstPointer(); + double tmp[12]; + for(int i=0;isetName("EdgeRatio"); + ret->synchronizeTimeWithSupport(); + return ret.retn(); +} + +/*! + * Creates a new MEDCouplingFieldDouble holding Aspect Ratio values of all + * cells. Currently cells of the following types are treated: + * INTERP_KERNEL::NORM_TRI3, INTERP_KERNEL::NORM_QUAD4 and INTERP_KERNEL::NORM_TETRA4. + * For a cell of other type an exception is thrown. + * Space dimension of a 2D mesh can be either 2 or 3. + * \return MEDCouplingFieldDouble * - a new instance of MEDCouplingFieldDouble on + * cells and one time, lying on \a this mesh. The caller is to delete this + * field using decrRef() as it is no more needed. + * \throw If the coordinates array is not set. + * \throw If \a this mesh contains elements of dimension different from the mesh dimension. + * \throw If the connectivity data array has more than one component. + * \throw If the connectivity data array has a named component. + * \throw If the connectivity index data array has more than one component. + * \throw If the connectivity index data array has a named component. + * \throw If \a this->getMeshDimension() is neither 2 nor 3. + * \throw If \a this->getSpaceDimension() is neither 2 nor 3. + * \throw If \a this mesh includes cells of type different from the ones enumerated above. + */ +MEDCouplingFieldDouble *MEDCouplingUMesh::getAspectRatioField() const +{ + checkCoherency(); + int spaceDim=getSpaceDimension(); + int meshDim=getMeshDimension(); + if(spaceDim!=2 && spaceDim!=3) + throw INTERP_KERNEL::Exception("MEDCouplingUMesh::getAspectRatioField : SpaceDimension must be equal to 2 or 3 !"); + if(meshDim!=2 && meshDim!=3) + throw INTERP_KERNEL::Exception("MEDCouplingUMesh::getAspectRatioField : MeshDimension must be equal to 2 or 3 !"); + MEDCouplingAutoRefCountObjectPtr ret=MEDCouplingFieldDouble::New(ON_CELLS,ONE_TIME); + ret->setMesh(this); + int nbOfCells=getNumberOfCells(); + MEDCouplingAutoRefCountObjectPtr arr=DataArrayDouble::New(); + arr->alloc(nbOfCells,1); + double *pt=arr->getPointer(); + ret->setArray(arr);//In case of throw to avoid mem leaks arr will be used after decrRef. + const int *conn=_nodal_connec->getConstPointer(); + const int *connI=_nodal_connec_index->getConstPointer(); + const double *coo=_coords->getConstPointer(); + double tmp[12]; + for(int i=0;isetName("AspectRatio"); + ret->synchronizeTimeWithSupport(); + return ret.retn(); +} + +/*! + * Creates a new MEDCouplingFieldDouble holding Warping factor values of all + * cells of \a this 2D mesh in 3D space. Currently cells of the following types are + * treated: INTERP_KERNEL::NORM_QUAD4. + * For a cell of other type an exception is thrown. + * \return MEDCouplingFieldDouble * - a new instance of MEDCouplingFieldDouble on + * cells and one time, lying on \a this mesh. The caller is to delete this + * field using decrRef() as it is no more needed. + * \throw If the coordinates array is not set. + * \throw If \a this mesh contains elements of dimension different from the mesh dimension. + * \throw If the connectivity data array has more than one component. + * \throw If the connectivity data array has a named component. + * \throw If the connectivity index data array has more than one component. + * \throw If the connectivity index data array has a named component. + * \throw If \a this->getMeshDimension() != 2. + * \throw If \a this->getSpaceDimension() != 3. + * \throw If \a this mesh includes cells of type different from the ones enumerated above. + */ +MEDCouplingFieldDouble *MEDCouplingUMesh::getWarpField() const +{ + checkCoherency(); + int spaceDim=getSpaceDimension(); + int meshDim=getMeshDimension(); + if(spaceDim!=3) + throw INTERP_KERNEL::Exception("MEDCouplingUMesh::getWarpField : SpaceDimension must be equal to 3 !"); + if(meshDim!=2) + throw INTERP_KERNEL::Exception("MEDCouplingUMesh::getWarpField : MeshDimension must be equal to 2 !"); + MEDCouplingAutoRefCountObjectPtr ret=MEDCouplingFieldDouble::New(ON_CELLS,ONE_TIME); + ret->setMesh(this); + int nbOfCells=getNumberOfCells(); + MEDCouplingAutoRefCountObjectPtr arr=DataArrayDouble::New(); + arr->alloc(nbOfCells,1); + double *pt=arr->getPointer(); + ret->setArray(arr);//In case of throw to avoid mem leaks arr will be used after decrRef. + const int *conn=_nodal_connec->getConstPointer(); + const int *connI=_nodal_connec_index->getConstPointer(); + const double *coo=_coords->getConstPointer(); + double tmp[12]; + for(int i=0;isetName("Warp"); + ret->synchronizeTimeWithSupport(); + return ret.retn(); +} + + +/*! + * Creates a new MEDCouplingFieldDouble holding Skew factor values of all + * cells of \a this 2D mesh in 3D space. Currently cells of the following types are + * treated: INTERP_KERNEL::NORM_QUAD4. + * For a cell of other type an exception is thrown. + * \return MEDCouplingFieldDouble * - a new instance of MEDCouplingFieldDouble on + * cells and one time, lying on \a this mesh. The caller is to delete this + * field using decrRef() as it is no more needed. + * \throw If the coordinates array is not set. + * \throw If \a this mesh contains elements of dimension different from the mesh dimension. + * \throw If the connectivity data array has more than one component. + * \throw If the connectivity data array has a named component. + * \throw If the connectivity index data array has more than one component. + * \throw If the connectivity index data array has a named component. + * \throw If \a this->getMeshDimension() != 2. + * \throw If \a this->getSpaceDimension() != 3. + * \throw If \a this mesh includes cells of type different from the ones enumerated above. + */ +MEDCouplingFieldDouble *MEDCouplingUMesh::getSkewField() const +{ + checkCoherency(); + int spaceDim=getSpaceDimension(); + int meshDim=getMeshDimension(); + if(spaceDim!=3) + throw INTERP_KERNEL::Exception("MEDCouplingUMesh::getSkewField : SpaceDimension must be equal to 3 !"); + if(meshDim!=2) + throw INTERP_KERNEL::Exception("MEDCouplingUMesh::getSkewField : MeshDimension must be equal to 2 !"); + MEDCouplingAutoRefCountObjectPtr ret=MEDCouplingFieldDouble::New(ON_CELLS,ONE_TIME); + ret->setMesh(this); + int nbOfCells=getNumberOfCells(); + MEDCouplingAutoRefCountObjectPtr arr=DataArrayDouble::New(); + arr->alloc(nbOfCells,1); + double *pt=arr->getPointer(); + ret->setArray(arr);//In case of throw to avoid mem leaks arr will be used after decrRef. + const int *conn=_nodal_connec->getConstPointer(); + const int *connI=_nodal_connec_index->getConstPointer(); + const double *coo=_coords->getConstPointer(); + double tmp[12]; + for(int i=0;isetName("Skew"); + ret->synchronizeTimeWithSupport(); + return ret.retn(); +} + +/*! + * Returns the cell field giving for each cell in \a this its diameter. Diameter means the max length of all possible SEG2 in the cell. + * + * \return a new instance of field containing the result. The returned instance has to be deallocated by the caller. + * + * \sa getSkewField, getWarpField, getAspectRatioField, getEdgeRatioField + */ +MEDCouplingFieldDouble *MEDCouplingUMesh::computeDiameterField() const +{ + checkCoherency(); + MEDCouplingAutoRefCountObjectPtr ret(MEDCouplingFieldDouble::New(ON_CELLS,ONE_TIME)); + ret->setMesh(this); + std::set types; + ComputeAllTypesInternal(types,_nodal_connec,_nodal_connec_index); + int spaceDim(getSpaceDimension()),nbCells(getNumberOfCells()); + MEDCouplingAutoRefCountObjectPtr arr(DataArrayDouble::New()); + arr->alloc(nbCells,1); + for(std::set::const_iterator it=types.begin();it!=types.end();it++) + { + INTERP_KERNEL::AutoCppPtr dc(INTERP_KERNEL::CellModel::GetCellModel(*it).buildInstanceOfDiameterCalulator(spaceDim)); + MEDCouplingAutoRefCountObjectPtr cellIds(giveCellsWithType(*it)); + dc->computeForListOfCellIdsUMeshFrmt(cellIds->begin(),cellIds->end(),_nodal_connec_index->begin(),_nodal_connec->begin(),getCoords()->begin(),arr->getPointer()); + } + ret->setArray(arr); + ret->setName("Diameter"); + return ret.retn(); +} + +/*! + * This method aggregate the bbox of each cell and put it into bbox parameter. + * + * \param [in] arcDetEps - a parameter specifying in case of 2D quadratic polygon cell the detection limit between linear and arc circle. (By default 1e-12) + * For all other cases this input parameter is ignored. + * \return DataArrayDouble * - newly created object (to be managed by the caller) \a this number of cells tuples and 2*spacedim components. + * + * \throw If \a this is not fully set (coordinates and connectivity). + * \throw If a cell in \a this has no valid nodeId. + * \sa MEDCouplingUMesh::getBoundingBoxForBBTreeFast, MEDCouplingUMesh::getBoundingBoxForBBTree2DQuadratic + */ +DataArrayDouble *MEDCouplingUMesh::getBoundingBoxForBBTree(double arcDetEps) const +{ + int mDim(getMeshDimension()),sDim(getSpaceDimension()); + if((mDim==3 && sDim==3) || (mDim==2 && sDim==3) || (mDim==1 && sDim==1) || ( mDim==1 && sDim==3)) // Compute refined boundary box for quadratic elements only in 2D. + return getBoundingBoxForBBTreeFast(); + if((mDim==2 && sDim==2) || (mDim==1 && sDim==2)) + { + bool presenceOfQuadratic(false); + for(std::set::const_iterator it=_types.begin();it!=_types.end();it++) + { + const INTERP_KERNEL::CellModel& cm(INTERP_KERNEL::CellModel::GetCellModel(*it)); + if(cm.isQuadratic()) + presenceOfQuadratic=true; + } + if(!presenceOfQuadratic) + return getBoundingBoxForBBTreeFast(); + if(mDim==2 && sDim==2) + return getBoundingBoxForBBTree2DQuadratic(arcDetEps); + else + return getBoundingBoxForBBTree1DQuadratic(arcDetEps); + } + throw INTERP_KERNEL::Exception("MEDCouplingUMesh::getBoundingBoxForBBTree : Managed dimensions are (mDim=1,sDim=1), (mDim=1,sDim=2), (mDim=1,sDim=3), (mDim=2,sDim=2), (mDim=2,sDim=3) and (mDim=3,sDim=3) !"); +} + +/*! + * This method aggregate the bbox of each cell only considering the nodes constituting each cell and put it into bbox parameter. + * So meshes having quadratic cells the computed bounding boxes can be invalid ! + * + * \return DataArrayDouble * - newly created object (to be managed by the caller) \a this number of cells tuples and 2*spacedim components. + * + * \throw If \a this is not fully set (coordinates and connectivity). + * \throw If a cell in \a this has no valid nodeId. + */ +DataArrayDouble *MEDCouplingUMesh::getBoundingBoxForBBTreeFast() const +{ + checkFullyDefined(); + int spaceDim(getSpaceDimension()),nbOfCells(getNumberOfCells()),nbOfNodes(getNumberOfNodes()); + MEDCouplingAutoRefCountObjectPtr ret(DataArrayDouble::New()); ret->alloc(nbOfCells,2*spaceDim); + double *bbox(ret->getPointer()); + for(int i=0;i::max(); + bbox[2*i+1]=-std::numeric_limits::max(); + } + const double *coordsPtr(_coords->getConstPointer()); + const int *conn(_nodal_connec->getConstPointer()),*connI(_nodal_connec_index->getConstPointer()); + for(int i=0;i=0 && nodeId ret(DataArrayDouble::New()); ret->alloc(nbOfCells,2*spaceDim); + double *bbox(ret->getPointer()); + const double *coords(_coords->getConstPointer()); + const int *conn(_nodal_connec->getConstPointer()),*connI(_nodal_connec_index->getConstPointer()); + for(int i=0;i nodes(sz); + INTERP_KERNEL::QuadraticPolygon *pol(0); + for(int j=0;jfillBounds(b); delete pol; + bbox[0]=b.getXMin(); bbox[1]=b.getXMax(); bbox[2]=b.getYMin(); bbox[3]=b.getYMax(); + } + return ret.retn(); +} + +/*! + * This method aggregates the bbox of each 1D cell in \a this considering the whole shape. This method is particularly + * useful for 2D meshes having quadratic cells + * because for this type of cells getBoundingBoxForBBTreeFast method may return invalid bounding boxes (since it just considers + * the two extremities of the arc of circle). + * + * \param [in] arcDetEps - a parameter specifying in case of 2D quadratic polygon cell the detection limit between linear and arc circle. (By default 1e-12) + * \return DataArrayDouble * - newly created object (to be managed by the caller) \a this number of cells tuples and 2*spacedim components. + * \throw If \a this is not fully defined. + * \throw If \a this is not a mesh with meshDimension equal to 1. + * \throw If \a this is not a mesh with spaceDimension equal to 2. + * \sa MEDCouplingUMesh::getBoundingBoxForBBTree2DQuadratic + */ +DataArrayDouble *MEDCouplingUMesh::getBoundingBoxForBBTree1DQuadratic(double arcDetEps) const +{ + checkFullyDefined(); + int spaceDim(getSpaceDimension()),mDim(getMeshDimension()),nbOfCells(getNumberOfCells()); + if(spaceDim!=2 || mDim!=1) + throw INTERP_KERNEL::Exception("MEDCouplingUMesh::getBoundingBoxForBBTree1DQuadratic : This method should be applied on mesh with mesh dimension equal to 1 and space dimension also equal to 2!"); + MEDCouplingAutoRefCountObjectPtr ret(DataArrayDouble::New()); ret->alloc(nbOfCells,2*spaceDim); + double *bbox(ret->getPointer()); + const double *coords(_coords->getConstPointer()); + const int *conn(_nodal_connec->getConstPointer()),*connI(_nodal_connec_index->getConstPointer()); + for(int i=0;i nodes(sz); + INTERP_KERNEL::Edge *edge(0); + for(int j=0;jgetBounds()); + bbox[0]=b.getXMin(); bbox[1]=b.getXMax(); bbox[2]=b.getYMin(); bbox[3]=b.getYMax(); edge->decrRef(); + } + return ret.retn(); +} + +/// @cond INTERNAL + +namespace ParaMEDMEMImpl +{ + class ConnReader + { + public: + ConnReader(const int *c, int val):_conn(c),_val(val) { } + bool operator() (const int& pos) { return _conn[pos]!=_val; } + private: + const int *_conn; + int _val; + }; + + class ConnReader2 + { + public: + ConnReader2(const int *c, int val):_conn(c),_val(val) { } + bool operator() (const int& pos) { return _conn[pos]==_val; } + private: + const int *_conn; + int _val; + }; +} + +/// @endcond + +/*! + * This method expects that \a this is sorted by types. If not an exception will be thrown. + * This method returns in the same format as code (see MEDCouplingUMesh::checkTypeConsistencyAndContig or MEDCouplingUMesh::splitProfilePerType) how + * \a this is composed in cell types. + * The returned array is of size 3*n where n is the number of different types present in \a this. + * For every k in [0,n] ret[3*k+2]==-1 because it has no sense here. + * This parameter is kept only for compatibility with other methode listed above. + */ +std::vector MEDCouplingUMesh::getDistributionOfTypes() const +{ + checkConnectivityFullyDefined(); + const int *conn=_nodal_connec->getConstPointer(); + const int *connI=_nodal_connec_index->getConstPointer(); + const int *work=connI; + int nbOfCells=getNumberOfCells(); + std::size_t n=getAllGeoTypes().size(); + std::vector ret(3*n,-1); //ret[3*k+2]==-1 because it has no sense here + std::set types; + for(std::size_t i=0;work!=connI+nbOfCells;i++) + { + INTERP_KERNEL::NormalizedCellType typ=(INTERP_KERNEL::NormalizedCellType)conn[*work]; + if(types.find(typ)!=types.end()) + { + std::ostringstream oss; oss << "MEDCouplingUMesh::getDistributionOfTypes : Type " << INTERP_KERNEL::CellModel::GetCellModel(typ).getRepr(); + oss << " is not contiguous !"; + throw INTERP_KERNEL::Exception(oss.str().c_str()); + } + types.insert(typ); + ret[3*i]=typ; + const int *work2=std::find_if(work+1,connI+nbOfCells,ParaMEDMEMImpl::ConnReader(conn,typ)); + ret[3*i+1]=(int)std::distance(work,work2); + work=work2; + } + return ret; +} + +/*! + * This method is used to check that this has contiguous cell type in same order than described in \a code. + * only for types cell, type node is not managed. + * Format of \a code is the following. \a code should be of size 3*n and non empty. If not an exception is thrown. + * foreach k in [0,n) on 3*k pos represent the geometric type and 3*k+1 number of elements of type 3*k. + * 3*k+2 refers if different from -1 the pos in 'idsPerType' to get the corresponding array. + * If 2 or more same geometric type is in \a code and exception is thrown too. + * + * This method firstly checks + * If it exists k so that 3*k geometric type is not in geometric types of this an exception will be thrown. + * If it exists k so that 3*k geometric type exists but the number of consecutive cell types does not match, + * an exception is thrown too. + * + * If all geometric types in \a code are exactly those in \a this null pointer is returned. + * If it exists a geometric type in \a this \b not in \a code \b no exception is thrown + * and a DataArrayInt instance is returned that the user has the responsability to deallocate. + */ +DataArrayInt *MEDCouplingUMesh::checkTypeConsistencyAndContig(const std::vector& code, const std::vector& idsPerType) const +{ + if(code.empty()) + throw INTERP_KERNEL::Exception("MEDCouplingUMesh::checkTypeConsistencyAndContig : code is empty, should not !"); + std::size_t sz=code.size(); + std::size_t n=sz/3; + if(sz%3!=0) + throw INTERP_KERNEL::Exception("MEDCouplingUMesh::checkTypeConsistencyAndContig : code size is NOT %3 !"); + std::vector types; + int nb=0; + bool isNoPflUsed=true; + for(std::size_t i=0;i ret=DataArrayInt::New(); + ret->alloc(nb,1); + int *retPtr=ret->getPointer(); + const int *connI=_nodal_connec_index->getConstPointer(); + const int *conn=_nodal_connec->getConstPointer(); + int nbOfCells=getNumberOfCells(); + const int *i=connI; + int kk=0; + for(std::vector::const_iterator it=types.begin();it!=types.end();it++,kk++) + { + i=std::find_if(i,connI+nbOfCells,ParaMEDMEMImpl::ConnReader2(conn,(int)(*it))); + int offset=(int)std::distance(connI,i); + const int *j=std::find_if(i+1,connI+nbOfCells,ParaMEDMEMImpl::ConnReader(conn,(int)(*it))); + int nbOfCellsOfCurType=(int)std::distance(i,j); + if(code[3*kk+2]==-1) + for(int k=0;k=0 && idInIdsPerType<(int)idsPerType.size()) + { + const DataArrayInt *zePfl=idsPerType[idInIdsPerType]; + if(zePfl) + { + zePfl->checkAllocated(); + if(zePfl->getNumberOfComponents()==1) + { + for(const int *k=zePfl->begin();k!=zePfl->end();k++,retPtr++) + { + if(*k>=0 && *k& code, std::vector& idsInPflPerType, std::vector& idsPerType) const +{ + if(!profile) + throw INTERP_KERNEL::Exception("MEDCouplingUMesh::splitProfilePerType : input profile is NULL !"); + if(profile->getNumberOfComponents()!=1) + throw INTERP_KERNEL::Exception("MEDCouplingUMesh::splitProfilePerType : input profile should have exactly one component !"); + checkConnectivityFullyDefined(); + const int *conn=_nodal_connec->getConstPointer(); + const int *connI=_nodal_connec_index->getConstPointer(); + int nbOfCells=getNumberOfCells(); + std::vector types; + std::vector typeRangeVals(1); + for(const int *i=connI;i!=connI+nbOfCells;) + { + INTERP_KERNEL::NormalizedCellType curType=(INTERP_KERNEL::NormalizedCellType)conn[*i]; + if(std::find(types.begin(),types.end(),curType)!=types.end()) + { + throw INTERP_KERNEL::Exception("MEDCouplingUMesh::splitProfilePerType : current mesh is not sorted by type !"); + } + types.push_back(curType); + i=std::find_if(i+1,connI+nbOfCells,ParaMEDMEMImpl::ConnReader(conn,(int)curType)); + typeRangeVals.push_back((int)std::distance(connI,i)); + } + // + DataArrayInt *castArr=0,*rankInsideCast=0,*castsPresent=0; + profile->splitByValueRange(&typeRangeVals[0],&typeRangeVals[0]+typeRangeVals.size(),castArr,rankInsideCast,castsPresent); + MEDCouplingAutoRefCountObjectPtr tmp0=castArr; + MEDCouplingAutoRefCountObjectPtr tmp1=rankInsideCast; + MEDCouplingAutoRefCountObjectPtr tmp2=castsPresent; + // + int nbOfCastsFinal=castsPresent->getNumberOfTuples(); + code.resize(3*nbOfCastsFinal); + std::vector< MEDCouplingAutoRefCountObjectPtr > idsInPflPerType2; + std::vector< MEDCouplingAutoRefCountObjectPtr > idsPerType2; + for(int i=0;igetIJ(i,0); + MEDCouplingAutoRefCountObjectPtr tmp3=castArr->getIdsEqual(castId); + idsInPflPerType2.push_back(tmp3); + code[3*i]=(int)types[castId]; + code[3*i+1]=tmp3->getNumberOfTuples(); + MEDCouplingAutoRefCountObjectPtr tmp4=rankInsideCast->selectByTupleId(tmp3->getConstPointer(),tmp3->getConstPointer()+tmp3->getNumberOfTuples()); + if(tmp4->getNumberOfTuples()!=typeRangeVals[castId+1]-typeRangeVals[castId] || !tmp4->isIdentity()) + { + tmp4->copyStringInfoFrom(*profile); + idsPerType2.push_back(tmp4); + code[3*i+2]=(int)idsPerType2.size()-1; + } + else + { + code[3*i+2]=-1; + } + } + std::size_t sz2=idsInPflPerType2.size(); + idsInPflPerType.resize(sz2); + for(std::size_t i=0;iincrRef(); + idsInPflPerType[i]=locDa; + } + std::size_t sz=idsPerType2.size(); + idsPerType.resize(sz); + for(std::size_t i=0;iincrRef(); + idsPerType[i]=locDa; + } +} + +/*! + * This method is here too emulate the MEDMEM behaviour on BDC (buildDescendingConnectivity). Hoping this method becomes deprecated very soon. + * This method make the assumption that \a this and 'nM1LevMesh' mesh lyies on same coords (same pointer) as MED and MEDMEM does. + * The following equality should be verified 'nM1LevMesh->getMeshDimension()==this->getMeshDimension()-1' + * This method returns 5+2 elements. 'desc', 'descIndx', 'revDesc', 'revDescIndx' and 'meshnM1' behaves exactly as ParaMEDMEM::MEDCouplingUMesh::buildDescendingConnectivity except the content as described after. The returned array specifies the n-1 mesh reordered by type as MEDMEM does. 'nM1LevMeshIds' contains the ids in returned 'meshnM1'. Finally 'meshnM1Old2New' contains numbering old2new that is to say the cell #k in coarse 'nM1LevMesh' will have the number ret[k] in returned mesh 'nM1LevMesh' MEDMEM reordered. + */ +MEDCouplingUMesh *MEDCouplingUMesh::emulateMEDMEMBDC(const MEDCouplingUMesh *nM1LevMesh, DataArrayInt *desc, DataArrayInt *descIndx, DataArrayInt *&revDesc, DataArrayInt *&revDescIndx, DataArrayInt *& nM1LevMeshIds, DataArrayInt *&meshnM1Old2New) const +{ + checkFullyDefined(); + nM1LevMesh->checkFullyDefined(); + if(getMeshDimension()-1!=nM1LevMesh->getMeshDimension()) + throw INTERP_KERNEL::Exception("MEDCouplingUMesh::emulateMEDMEMBDC : The mesh passed as first argument should have a meshDim equal to this->getMeshDimension()-1 !" ); + if(_coords!=nM1LevMesh->getCoords()) + throw INTERP_KERNEL::Exception("MEDCouplingUMesh::emulateMEDMEMBDC : 'this' and mesh in first argument should share the same coords : Use tryToShareSameCoords method !"); + MEDCouplingAutoRefCountObjectPtr tmp0=DataArrayInt::New(); + MEDCouplingAutoRefCountObjectPtr tmp1=DataArrayInt::New(); + MEDCouplingAutoRefCountObjectPtr ret1=buildDescendingConnectivity(desc,descIndx,tmp0,tmp1); + MEDCouplingAutoRefCountObjectPtr ret0=ret1->sortCellsInMEDFileFrmt(); + desc->transformWithIndArr(ret0->getConstPointer(),ret0->getConstPointer()+ret0->getNbOfElems()); + MEDCouplingAutoRefCountObjectPtr tmp=MEDCouplingUMesh::New(); + tmp->setConnectivity(tmp0,tmp1); + tmp->renumberCells(ret0->getConstPointer(),false); + revDesc=tmp->getNodalConnectivity(); + revDescIndx=tmp->getNodalConnectivityIndex(); + DataArrayInt *ret=0; + if(!ret1->areCellsIncludedIn(nM1LevMesh,2,ret)) + { + int tmp2; + ret->getMaxValue(tmp2); + ret->decrRef(); + std::ostringstream oss; oss << "MEDCouplingUMesh::emulateMEDMEMBDC : input N-1 mesh present a cell not in descending mesh ... Id of cell is " << tmp2 << " !"; + throw INTERP_KERNEL::Exception(oss.str().c_str()); + } + nM1LevMeshIds=ret; + // + revDesc->incrRef(); + revDescIndx->incrRef(); + ret1->incrRef(); + ret0->incrRef(); + meshnM1Old2New=ret0; + return ret1; +} + +/*! + * Permutes the nodal connectivity arrays so that the cells are sorted by type, which is + * necessary for writing the mesh to MED file. Additionally returns a permutation array + * in "Old to New" mode. + * \return DataArrayInt * - a new instance of DataArrayInt. The caller is to delete + * this array using decrRef() as it is no more needed. + * \throw If the nodal connectivity of cells is not defined. + */ +DataArrayInt *MEDCouplingUMesh::sortCellsInMEDFileFrmt() +{ + checkConnectivityFullyDefined(); + MEDCouplingAutoRefCountObjectPtr ret=getRenumArrForMEDFileFrmt(); + renumberCells(ret->getConstPointer(),false); + return ret.retn(); +} + +/*! + * This methods checks that cells are sorted by their types. + * This method makes asumption (no check) that connectivity is correctly set before calling. + */ +bool MEDCouplingUMesh::checkConsecutiveCellTypes() const +{ + checkFullyDefined(); + const int *conn=_nodal_connec->getConstPointer(); + const int *connI=_nodal_connec_index->getConstPointer(); + int nbOfCells=getNumberOfCells(); + std::set types; + for(const int *i=connI;i!=connI+nbOfCells;) + { + INTERP_KERNEL::NormalizedCellType curType=(INTERP_KERNEL::NormalizedCellType)conn[*i]; + if(types.find(curType)!=types.end()) + return false; + types.insert(curType); + i=std::find_if(i+1,connI+nbOfCells,ParaMEDMEMImpl::ConnReader(conn,(int)curType)); + } + return true; +} + +/*! + * This method is a specialization of MEDCouplingUMesh::checkConsecutiveCellTypesAndOrder method that is called here. + * The geometric type order is specified by MED file. + * + * \sa MEDCouplingUMesh::checkConsecutiveCellTypesAndOrder + */ +bool MEDCouplingUMesh::checkConsecutiveCellTypesForMEDFileFrmt() const +{ + return checkConsecutiveCellTypesAndOrder(MEDMEM_ORDER,MEDMEM_ORDER+N_MEDMEM_ORDER); +} + +/*! + * This method performs the same job as checkConsecutiveCellTypes except that the order of types sequence is analyzed to check + * that the order is specified in array defined by [ \a orderBg , \a orderEnd ). + * If there is some geo types in \a this \b NOT in [ \a orderBg, \a orderEnd ) it is OK (return true) if contiguous. + * If there is some geo types in [ \a orderBg, \a orderEnd ) \b NOT in \a this it is OK too (return true) if contiguous. + */ +bool MEDCouplingUMesh::checkConsecutiveCellTypesAndOrder(const INTERP_KERNEL::NormalizedCellType *orderBg, const INTERP_KERNEL::NormalizedCellType *orderEnd) const +{ + checkFullyDefined(); + const int *conn=_nodal_connec->getConstPointer(); + const int *connI=_nodal_connec_index->getConstPointer(); + int nbOfCells=getNumberOfCells(); + if(nbOfCells==0) + return true; + int lastPos=-1; + std::set sg; + for(const int *i=connI;i!=connI+nbOfCells;) + { + INTERP_KERNEL::NormalizedCellType curType=(INTERP_KERNEL::NormalizedCellType)conn[*i]; + const INTERP_KERNEL::NormalizedCellType *isTypeExists=std::find(orderBg,orderEnd,curType); + if(isTypeExists!=orderEnd) + { + int pos=(int)std::distance(orderBg,isTypeExists); + if(pos<=lastPos) + return false; + lastPos=pos; + i=std::find_if(i+1,connI+nbOfCells,ParaMEDMEMImpl::ConnReader(conn,(int)curType)); + } + else + { + if(sg.find(curType)==sg.end()) + { + i=std::find_if(i+1,connI+nbOfCells,ParaMEDMEMImpl::ConnReader(conn,(int)curType)); + sg.insert(curType); + } + else + return false; + } + } + return true; +} + +/*! + * This method returns 2 newly allocated DataArrayInt instances. The first is an array of size 'this->getNumberOfCells()' with one component, + * that tells for each cell the pos of its type in the array on type given in input parameter. The 2nd output parameter is an array with the same + * number of tuples than input type array and with one component. This 2nd output array gives type by type the number of occurence of type in 'this'. + */ +DataArrayInt *MEDCouplingUMesh::getLevArrPerCellTypes(const INTERP_KERNEL::NormalizedCellType *orderBg, const INTERP_KERNEL::NormalizedCellType *orderEnd, DataArrayInt *&nbPerType) const +{ + checkConnectivityFullyDefined(); + int nbOfCells=getNumberOfCells(); + const int *conn=_nodal_connec->getConstPointer(); + const int *connI=_nodal_connec_index->getConstPointer(); + MEDCouplingAutoRefCountObjectPtr tmpa=DataArrayInt::New(); + MEDCouplingAutoRefCountObjectPtr tmpb=DataArrayInt::New(); + tmpa->alloc(nbOfCells,1); + tmpb->alloc((int)std::distance(orderBg,orderEnd),1); + tmpb->fillWithZero(); + int *tmp=tmpa->getPointer(); + int *tmp2=tmpb->getPointer(); + for(const int *i=connI;i!=connI+nbOfCells;i++) + { + const INTERP_KERNEL::NormalizedCellType *where=std::find(orderBg,orderEnd,(INTERP_KERNEL::NormalizedCellType)conn[*i]); + if(where!=orderEnd) + { + int pos=(int)std::distance(orderBg,where); + tmp2[pos]++; + tmp[std::distance(connI,i)]=pos; + } + else + { + const INTERP_KERNEL::CellModel& cm=INTERP_KERNEL::CellModel::GetCellModel((INTERP_KERNEL::NormalizedCellType)conn[*i]); + std::ostringstream oss; oss << "MEDCouplingUMesh::getLevArrPerCellTypes : Cell #" << std::distance(connI,i); + oss << " has a type " << cm.getRepr() << " not in input array of type !"; + throw INTERP_KERNEL::Exception(oss.str().c_str()); + } + } + nbPerType=tmpb.retn(); + return tmpa.retn(); +} + +/*! + * This method behaves exactly as MEDCouplingUMesh::getRenumArrForConsecutiveCellTypesSpec but the order is those defined in MED file spec. + * + * \return a new object containing the old to new correspondance. + * + * \sa MEDCouplingUMesh::getRenumArrForConsecutiveCellTypesSpec, MEDCouplingUMesh::sortCellsInMEDFileFrmt. + */ +DataArrayInt *MEDCouplingUMesh::getRenumArrForMEDFileFrmt() const +{ + return getRenumArrForConsecutiveCellTypesSpec(MEDMEM_ORDER,MEDMEM_ORDER+N_MEDMEM_ORDER); +} + +/*! + * This method is similar to method MEDCouplingUMesh::rearrange2ConsecutiveCellTypes except that the type order is specfied by [ \a orderBg , \a orderEnd ) (as MEDCouplingUMesh::checkConsecutiveCellTypesAndOrder method) and that this method is \b const and performs \b NO permutation in \a this. + * This method returns an array of size getNumberOfCells() that gives a renumber array old2New that can be used as input of MEDCouplingMesh::renumberCells. + * The mesh after this call to MEDCouplingMesh::renumberCells will pass the test of MEDCouplingUMesh::checkConsecutiveCellTypesAndOrder with the same inputs. + * The returned array minimizes the permutations that is to say the order of cells inside same geometric type remains the same. + */ +DataArrayInt *MEDCouplingUMesh::getRenumArrForConsecutiveCellTypesSpec(const INTERP_KERNEL::NormalizedCellType *orderBg, const INTERP_KERNEL::NormalizedCellType *orderEnd) const +{ + DataArrayInt *nbPerType=0; + MEDCouplingAutoRefCountObjectPtr tmpa=getLevArrPerCellTypes(orderBg,orderEnd,nbPerType); + nbPerType->decrRef(); + return tmpa->buildPermArrPerLevel(); +} + +/*! + * This method reorganize the cells of \a this so that the cells with same geometric types are put together. + * The number of cells remains unchanged after the call of this method. + * This method tries to minimizes the number of needed permutations. So, this method behaves not exactly as + * MEDCouplingUMesh::sortCellsInMEDFileFrmt. + * + * \return the array giving the correspondance old to new. + */ +DataArrayInt *MEDCouplingUMesh::rearrange2ConsecutiveCellTypes() +{ + checkFullyDefined(); + computeTypes(); + const int *conn=_nodal_connec->getConstPointer(); + const int *connI=_nodal_connec_index->getConstPointer(); + int nbOfCells=getNumberOfCells(); + std::vector types; + for(const int *i=connI;i!=connI+nbOfCells && (types.size()!=_types.size());) + if(std::find(types.begin(),types.end(),(INTERP_KERNEL::NormalizedCellType)conn[*i])==types.end()) + { + INTERP_KERNEL::NormalizedCellType curType=(INTERP_KERNEL::NormalizedCellType)conn[*i]; + types.push_back(curType); + for(i++;i!=connI+nbOfCells && (INTERP_KERNEL::NormalizedCellType)conn[*i]==curType;i++); + } + DataArrayInt *ret=DataArrayInt::New(); + ret->alloc(nbOfCells,1); + int *retPtr=ret->getPointer(); + std::fill(retPtr,retPtr+nbOfCells,-1); + int newCellId=0; + for(std::vector::const_iterator iter=types.begin();iter!=types.end();iter++) + { + for(const int *i=connI;i!=connI+nbOfCells;i++) + if((INTERP_KERNEL::NormalizedCellType)conn[*i]==(*iter)) + retPtr[std::distance(connI,i)]=newCellId++; + } + renumberCells(retPtr,false); + return ret; +} + +/*! + * This method splits \a this into as mush as untructured meshes that consecutive set of same type cells. + * So this method has typically a sense if MEDCouplingUMesh::checkConsecutiveCellTypes has a sense. + * This method makes asumption that connectivity is correctly set before calling. + */ +std::vector MEDCouplingUMesh::splitByType() const +{ + checkConnectivityFullyDefined(); + const int *conn=_nodal_connec->getConstPointer(); + const int *connI=_nodal_connec_index->getConstPointer(); + int nbOfCells=getNumberOfCells(); + std::vector ret; + for(const int *i=connI;i!=connI+nbOfCells;) + { + INTERP_KERNEL::NormalizedCellType curType=(INTERP_KERNEL::NormalizedCellType)conn[*i]; + int beginCellId=(int)std::distance(connI,i); + i=std::find_if(i+1,connI+nbOfCells,ParaMEDMEMImpl::ConnReader(conn,(int)curType)); + int endCellId=(int)std::distance(connI,i); + int sz=endCellId-beginCellId; + int *cells=new int[sz]; + for(int j=0;j ret=MEDCoupling1GTUMesh::New(getName(),typ); + ret->setCoords(getCoords()); + MEDCoupling1SGTUMesh *retC=dynamic_cast((MEDCoupling1GTUMesh*)ret); + if(retC) + { + MEDCouplingAutoRefCountObjectPtr c=convertNodalConnectivityToStaticGeoTypeMesh(); + retC->setNodalConnectivity(c); + } + else + { + MEDCoupling1DGTUMesh *retD=dynamic_cast((MEDCoupling1GTUMesh*)ret); + if(!retD) + throw INTERP_KERNEL::Exception("MEDCouplingUMesh::convertIntoSingleGeoTypeMesh : Internal error !"); + DataArrayInt *c=0,*ci=0; + convertNodalConnectivityToDynamicGeoTypeMesh(c,ci); + MEDCouplingAutoRefCountObjectPtr cs(c),cis(ci); + retD->setNodalConnectivity(cs,cis); + } + return ret.retn(); +} + +DataArrayInt *MEDCouplingUMesh::convertNodalConnectivityToStaticGeoTypeMesh() const +{ + checkConnectivityFullyDefined(); + if(_types.size()!=1) + throw INTERP_KERNEL::Exception("MEDCouplingUMesh::convertNodalConnectivityToStaticGeoTypeMesh : current mesh does not contain exactly one geometric type !"); + INTERP_KERNEL::NormalizedCellType typ=*_types.begin(); + const INTERP_KERNEL::CellModel& cm=INTERP_KERNEL::CellModel::GetCellModel(typ); + if(cm.isDynamic()) + { + std::ostringstream oss; oss << "MEDCouplingUMesh::convertNodalConnectivityToStaticGeoTypeMesh : this contains a single geo type (" << cm.getRepr() << ") but "; + oss << "this type is dynamic ! Only static geometric type is possible for that type ! call convertNodalConnectivityToDynamicGeoTypeMesh instead !"; + throw INTERP_KERNEL::Exception(oss.str().c_str()); + } + int nbCells=getNumberOfCells(); + int typi=(int)typ; + int nbNodesPerCell=(int)cm.getNumberOfNodes(); + MEDCouplingAutoRefCountObjectPtr connOut=DataArrayInt::New(); connOut->alloc(nbCells*nbNodesPerCell,1); + int *outPtr=connOut->getPointer(); + const int *conn=_nodal_connec->begin(); + const int *connI=_nodal_connec_index->begin(); + nbNodesPerCell++; + for(int i=0;igetNumberOfTuples(); + if(lgth c(DataArrayInt::New()),ci(DataArrayInt::New()); + c->alloc(lgth-nbCells,1); ci->alloc(nbCells+1,1); + int *cp(c->getPointer()),*cip(ci->getPointer()); + const int *incp(_nodal_connec->begin()),*incip(_nodal_connec_index->begin()); + cip[0]=0; + for(int i=0;i=1) + { + if((strt>=0 && strt=0 && stop<=lgth)) + cp=std::copy(incp+strt,incp+stop,cp); + else + throw INTERP_KERNEL::Exception(msg0); + } + else + throw INTERP_KERNEL::Exception(msg0); + cip[1]=cip[0]+delta; + } + nodalConn=c.retn(); nodalConnIndex=ci.retn(); +} + +/*! + * This method takes in input a vector of MEDCouplingUMesh instances lying on the same coordinates with same mesh dimensions. + * Each mesh in \b ms must be sorted by type with the same order (typically using MEDCouplingUMesh::sortCellsInMEDFileFrmt). + * This method is particulary useful for MED file interaction. It allows to aggregate several meshes and keeping the type sorting + * and the track of the permutation by chunk of same geotype cells to retrieve it. The traditional formats old2new and new2old + * are not used here to avoid the build of big permutation array. + * + * \param [in] ms meshes with same mesh dimension lying on the same coords and sorted by type following de the same geometric type order than + * those specified in MEDCouplingUMesh::sortCellsInMEDFileFrmt method. + * \param [out] szOfCellGrpOfSameType is a newly allocated DataArrayInt instance whose number of tuples is equal to the number of chunks of same geotype + * in all meshes in \b ms. The accumulation of all values of this array is equal to the number of cells of returned mesh. + * \param [out] idInMsOfCellGrpOfSameType is a newly allocated DataArrayInt instance having the same size than \b szOfCellGrpOfSameType. This + * output array gives for each chunck of same type the corresponding mesh id in \b ms. + * \return A newly allocated unstructured mesh that is the result of the aggregation on same coords of all meshes in \b ms. This returned mesh + * is sorted by type following the geo cell types order of MEDCouplingUMesh::sortCellsInMEDFileFrmt method. + */ +MEDCouplingUMesh *MEDCouplingUMesh::AggregateSortedByTypeMeshesOnSameCoords(const std::vector& ms, + DataArrayInt *&szOfCellGrpOfSameType, + DataArrayInt *&idInMsOfCellGrpOfSameType) +{ + std::vector ms2; + for(std::vector::const_iterator it=ms.begin();it!=ms.end();it++) + if(*it) + { + (*it)->checkConnectivityFullyDefined(); + ms2.push_back(*it); + } + if(ms2.empty()) + throw INTERP_KERNEL::Exception("MEDCouplingUMesh::AggregateSortedByTypeMeshesOnSameCoords : input vector is empty !"); + const DataArrayDouble *refCoo=ms2[0]->getCoords(); + int meshDim=ms2[0]->getMeshDimension(); + std::vector m1ssm; + std::vector< MEDCouplingAutoRefCountObjectPtr > m1ssmAuto; + // + std::vector m1ssmSingle; + std::vector< MEDCouplingAutoRefCountObjectPtr > m1ssmSingleAuto; + int fake=0,rk=0; + MEDCouplingAutoRefCountObjectPtr ret1(DataArrayInt::New()),ret2(DataArrayInt::New()); + ret1->alloc(0,1); ret2->alloc(0,1); + for(std::vector::const_iterator it=ms2.begin();it!=ms2.end();it++,rk++) + { + if(meshDim!=(*it)->getMeshDimension()) + throw INTERP_KERNEL::Exception("MEDCouplingUMesh::AggregateSortedByTypeMeshesOnSameCoords : meshdims mismatch !"); + if(refCoo!=(*it)->getCoords()) + throw INTERP_KERNEL::Exception("MEDCouplingUMesh::AggregateSortedByTypeMeshesOnSameCoords : meshes are not shared by a single coordinates coords !"); + std::vector sp=(*it)->splitByType(); + std::copy(sp.begin(),sp.end(),std::back_insert_iterator< std::vector >(m1ssm)); + std::copy(sp.begin(),sp.end(),std::back_insert_iterator< std::vector > >(m1ssmAuto)); + for(std::vector::const_iterator it2=sp.begin();it2!=sp.end();it2++) + { + MEDCouplingUMesh *singleCell=static_cast((*it2)->buildPartOfMySelf(&fake,&fake+1,true)); + m1ssmSingleAuto.push_back(singleCell); + m1ssmSingle.push_back(singleCell); + ret1->pushBackSilent((*it2)->getNumberOfCells()); ret2->pushBackSilent(rk); + } + } + MEDCouplingAutoRefCountObjectPtr m1ssmSingle2=MEDCouplingUMesh::MergeUMeshesOnSameCoords(m1ssmSingle); + MEDCouplingAutoRefCountObjectPtr renum=m1ssmSingle2->sortCellsInMEDFileFrmt(); + std::vector m1ssmfinal(m1ssm.size()); + for(std::size_t i=0;igetIJ(i,0)]=m1ssm[i]; + MEDCouplingAutoRefCountObjectPtr ret0=MEDCouplingUMesh::MergeUMeshesOnSameCoords(m1ssmfinal); + szOfCellGrpOfSameType=ret1->renumber(renum->getConstPointer()); + idInMsOfCellGrpOfSameType=ret2->renumber(renum->getConstPointer()); + return ret0.retn(); +} + +/*! + * This method returns a newly created DataArrayInt instance. + * This method retrieves cell ids in [ \a begin, \a end ) that have the type \a type. + */ +DataArrayInt *MEDCouplingUMesh::keepCellIdsByType(INTERP_KERNEL::NormalizedCellType type, const int *begin, const int *end) const +{ + checkFullyDefined(); + const int *conn=_nodal_connec->getConstPointer(); + const int *connIndex=_nodal_connec_index->getConstPointer(); + MEDCouplingAutoRefCountObjectPtr ret(DataArrayInt::New()); ret->alloc(0,1); + for(const int *w=begin;w!=end;w++) + if((INTERP_KERNEL::NormalizedCellType)conn[connIndex[*w]]==type) + ret->pushBackSilent(*w); + return ret.retn(); +} + +/*! + * This method makes the assumption that da->getNumberOfTuples()getNumberOfCells(). This method makes the assumption that ids contained in 'da' + * are in [0:getNumberOfCells()) + */ +DataArrayInt *MEDCouplingUMesh::convertCellArrayPerGeoType(const DataArrayInt *da) const +{ + checkFullyDefined(); + const int *conn=_nodal_connec->getConstPointer(); + const int *connI=_nodal_connec_index->getConstPointer(); + int nbOfCells=getNumberOfCells(); + std::set types(getAllGeoTypes()); + int *tmp=new int[nbOfCells]; + for(std::set::const_iterator iter=types.begin();iter!=types.end();iter++) + { + int j=0; + for(const int *i=connI;i!=connI+nbOfCells;i++) + if((INTERP_KERNEL::NormalizedCellType)conn[*i]==(*iter)) + tmp[std::distance(connI,i)]=j++; + } + DataArrayInt *ret=DataArrayInt::New(); + ret->alloc(da->getNumberOfTuples(),da->getNumberOfComponents()); + ret->copyStringInfoFrom(*da); + int *retPtr=ret->getPointer(); + const int *daPtr=da->getConstPointer(); + int nbOfElems=da->getNbOfElems(); + for(int k=0;k code=getDistributionOfTypes(); + std::size_t nOfTypesInThis=code.size()/3; + int sz=0,szOfType=0; + for(std::size_t i=0;i=szOfType) + { + std::ostringstream oss; oss << "MEDCouplingUMesh::keepSpecifiedCells : Request on type " << type << " at place #" << std::distance(idsPerGeoTypeBg,work) << " value " << *work; + oss << ". It should be in [0," << szOfType << ") !"; + throw INTERP_KERNEL::Exception(oss.str().c_str()); + } + MEDCouplingAutoRefCountObjectPtr idsTokeep=DataArrayInt::New(); idsTokeep->alloc(sz+(int)std::distance(idsPerGeoTypeBg,idsPerGeoTypeEnd),1); + int *idsPtr=idsTokeep->getPointer(); + int offset=0; + for(std::size_t i=0;i(),offset)); + offset+=code[3*i+1]; + } + MEDCouplingAutoRefCountObjectPtr ret=static_cast(buildPartOfMySelf(idsTokeep->begin(),idsTokeep->end(),true)); + ret->copyTinyInfoFrom(this); + return ret.retn(); +} + +/*! + * This method returns a vector of size 'this->getNumberOfCells()'. + * This method retrieves for each cell in \a this if it is linear (false) or quadratic(true). + */ +std::vector MEDCouplingUMesh::getQuadraticStatus() const +{ + int ncell=getNumberOfCells(); + std::vector ret(ncell); + const int *cI=getNodalConnectivityIndex()->getConstPointer(); + const int *c=getNodalConnectivity()->getConstPointer(); + for(int i=0;igetType()!=UNSTRUCTURED) + throw INTERP_KERNEL::Exception("Merge of umesh only available with umesh each other !"); + const MEDCouplingUMesh *otherC=static_cast(other); + return MergeUMeshes(this,otherC); +} + +/*! + * Returns a new DataArrayDouble holding barycenters of all cells. The barycenter is + * computed by averaging coordinates of cell nodes, so this method is not a right + * choice for degnerated meshes (not well oriented, cells with measure close to zero). + * \return DataArrayDouble * - a new instance of DataArrayDouble, of size \a + * this->getNumberOfCells() tuples per \a this->getSpaceDimension() + * components. The caller is to delete this array using decrRef() as it is + * no more needed. + * \throw If the coordinates array is not set. + * \throw If the nodal connectivity of cells is not defined. + * \sa MEDCouplingUMesh::computeIsoBarycenterOfNodesPerCell + */ +DataArrayDouble *MEDCouplingUMesh::getBarycenterAndOwner() const +{ + MEDCouplingAutoRefCountObjectPtr ret=DataArrayDouble::New(); + int spaceDim=getSpaceDimension(); + int nbOfCells=getNumberOfCells(); + ret->alloc(nbOfCells,spaceDim); + ret->copyStringInfoFrom(*getCoords()); + double *ptToFill=ret->getPointer(); + const int *nodal=_nodal_connec->getConstPointer(); + const int *nodalI=_nodal_connec_index->getConstPointer(); + const double *coor=_coords->getConstPointer(); + for(int i=0;i(type,nodal+nodalI[i]+1,nodalI[i+1]-nodalI[i]-1,coor,spaceDim,ptToFill); + ptToFill+=spaceDim; + } + return ret.retn(); +} + +/*! + * This method computes for each cell in \a this, the location of the iso barycenter of nodes constituting + * the cell. Contrary to badly named MEDCouplingUMesh::getBarycenterAndOwner method that returns the center of inertia of the + * + * \return a newly allocated DataArrayDouble instance that the caller has to deal with. The returned + * DataArrayDouble instance will have \c this->getNumberOfCells() tuples and \c this->getSpaceDimension() components. + * + * \sa MEDCouplingUMesh::getBarycenterAndOwner + * \throw If \a this is not fully defined (coordinates and connectivity) + * \throw If there is presence in nodal connectivity in \a this of node ids not in [0, \c this->getNumberOfNodes() ) + */ +DataArrayDouble *MEDCouplingUMesh::computeIsoBarycenterOfNodesPerCell() const +{ + checkFullyDefined(); + MEDCouplingAutoRefCountObjectPtr ret=DataArrayDouble::New(); + int spaceDim=getSpaceDimension(); + int nbOfCells=getNumberOfCells(); + int nbOfNodes=getNumberOfNodes(); + ret->alloc(nbOfCells,spaceDim); + double *ptToFill=ret->getPointer(); + const int *nodal=_nodal_connec->getConstPointer(); + const int *nodalI=_nodal_connec_index->getConstPointer(); + const double *coor=_coords->getConstPointer(); + for(int i=0;i=0 && *conn()); + else + { + std::ostringstream oss; oss << "MEDCouplingUMesh::computeIsoBarycenterOfNodesPerCell : on cell #" << i << " presence of nodeId #" << *conn << " should be in [0," << nbOfNodes << ") !"; + throw INTERP_KERNEL::Exception(oss.str().c_str()); + } + } + int nbOfNodesInCell=nodalI[i+1]-nodalI[i]-1; + if(nbOfNodesInCell>0) + std::transform(ptToFill,ptToFill+spaceDim,ptToFill,std::bind2nd(std::multiplies(),1./(double)nbOfNodesInCell)); + else + { + std::ostringstream oss; oss << "MEDCouplingUMesh::computeIsoBarycenterOfNodesPerCell : on cell #" << i << " presence of cell with no nodes !"; + throw INTERP_KERNEL::Exception(oss.str().c_str()); + } + } + else + { + std::set s(nodal+nodalI[i]+1,nodal+nodalI[i+1]); + s.erase(-1); + for(std::set::const_iterator it=s.begin();it!=s.end();it++) + { + if(*it>=0 && *it()); + else + { + std::ostringstream oss; oss << "MEDCouplingUMesh::computeIsoBarycenterOfNodesPerCell : on cell polyhedron cell #" << i << " presence of nodeId #" << *it << " should be in [0," << nbOfNodes << ") !"; + throw INTERP_KERNEL::Exception(oss.str().c_str()); + } + } + if(!s.empty()) + std::transform(ptToFill,ptToFill+spaceDim,ptToFill,std::bind2nd(std::multiplies(),1./(double)s.size())); + else + { + std::ostringstream oss; oss << "MEDCouplingUMesh::computeIsoBarycenterOfNodesPerCell : on polyhedron cell #" << i << " there are no nodes !"; + throw INTERP_KERNEL::Exception(oss.str().c_str()); + } + } + } + return ret.retn(); +} + +/*! + * Returns a new DataArrayDouble holding barycenters of specified cells. The + * barycenter is computed by averaging coordinates of cell nodes. The cells to treat + * are specified via an array of cell ids. + * \warning Validity of the specified cell ids is not checked! + * Valid range is [ 0, \a this->getNumberOfCells() ). + * \param [in] begin - an array of cell ids of interest. + * \param [in] end - the end of \a begin, i.e. a pointer to its (last+1)-th element. + * \return DataArrayDouble * - a new instance of DataArrayDouble, of size ( \a + * end - \a begin ) tuples per \a this->getSpaceDimension() components. The + * caller is to delete this array using decrRef() as it is no more needed. + * \throw If the coordinates array is not set. + * \throw If the nodal connectivity of cells is not defined. + * + * \if ENABLE_EXAMPLES + * \ref cpp_mcumesh_getPartBarycenterAndOwner "Here is a C++ example".
+ * \ref py_mcumesh_getPartBarycenterAndOwner "Here is a Python example". + * \endif + */ +DataArrayDouble *MEDCouplingUMesh::getPartBarycenterAndOwner(const int *begin, const int *end) const +{ + DataArrayDouble *ret=DataArrayDouble::New(); + int spaceDim=getSpaceDimension(); + int nbOfTuple=(int)std::distance(begin,end); + ret->alloc(nbOfTuple,spaceDim); + double *ptToFill=ret->getPointer(); + double *tmp=new double[spaceDim]; + const int *nodal=_nodal_connec->getConstPointer(); + const int *nodalI=_nodal_connec_index->getConstPointer(); + const double *coor=_coords->getConstPointer(); + for(const int *w=begin;w!=end;w++) + { + INTERP_KERNEL::NormalizedCellType type=(INTERP_KERNEL::NormalizedCellType)nodal[nodalI[*w]]; + INTERP_KERNEL::computeBarycenter2(type,nodal+nodalI[*w]+1,nodalI[*w+1]-nodalI[*w]-1,coor,spaceDim,ptToFill); + ptToFill+=spaceDim; + } + delete [] tmp; + return ret; +} + +/*! + * Returns a DataArrayDouble instance giving for each cell in \a this the equation of plane given by "a*X+b*Y+c*Z+d=0". + * So the returned instance will have 4 components and \c this->getNumberOfCells() tuples. + * So this method expects that \a this has a spaceDimension equal to 3 and meshDimension equal to 2. + * The computation of the plane equation is done using each time the 3 first nodes of 2D cells. + * This method is useful to detect 2D cells in 3D space that are not coplanar. + * + * \return DataArrayDouble * - a new instance of DataArrayDouble having 4 components and a number of tuples equal to number of cells in \a this. + * \throw If spaceDim!=3 or meshDim!=2. + * \throw If connectivity of \a this is invalid. + * \throw If connectivity of a cell in \a this points to an invalid node. + */ +DataArrayDouble *MEDCouplingUMesh::computePlaneEquationOf3DFaces() const +{ + MEDCouplingAutoRefCountObjectPtr ret(DataArrayDouble::New()); + int nbOfCells(getNumberOfCells()),nbOfNodes(getNumberOfNodes()); + if(getSpaceDimension()!=3 || getMeshDimension()!=2) + throw INTERP_KERNEL::Exception("MEDCouplingUMesh::computePlaneEquationOf3DFaces : This method must be applied on a mesh having meshDimension equal 2 and a spaceDimension equal to 3 !"); + ret->alloc(nbOfCells,4); + double *retPtr(ret->getPointer()); + const int *nodal(_nodal_connec->begin()),*nodalI(_nodal_connec_index->begin()); + const double *coor(_coords->begin()); + for(int i=0;i=3) + { + for(int j=0;j<3;j++) + { + int nodeId(nodal[nodalI[0]+1+j]); + if(nodeId>=0 && nodeIdcheckAllocated(); + MEDCouplingAutoRefCountObjectPtr ret=MEDCouplingUMesh::New(da->getName(),0); + ret->setCoords(da); + int nbOfTuples=da->getNumberOfTuples(); + MEDCouplingAutoRefCountObjectPtr c=DataArrayInt::New(); + MEDCouplingAutoRefCountObjectPtr cI=DataArrayInt::New(); + c->alloc(2*nbOfTuples,1); + cI->alloc(nbOfTuples+1,1); + int *cp=c->getPointer(); + int *cip=cI->getPointer(); + *cip++=0; + for(int i=0;isetConnectivity(c,cI,true); + return ret.retn(); +} +/*! + * Creates a new MEDCouplingUMesh by concatenating two given meshes of the same dimension. + * Cells and nodes of + * the first mesh precede cells and nodes of the second mesh within the result mesh. + * \param [in] mesh1 - the first mesh. + * \param [in] mesh2 - the second mesh. + * \return MEDCouplingUMesh * - the result mesh. It is a new instance of + * MEDCouplingUMesh. The caller is to delete this mesh using decrRef() as it + * is no more needed. + * \throw If \a mesh1 == NULL or \a mesh2 == NULL. + * \throw If the coordinates array is not set in none of the meshes. + * \throw If \a mesh1->getMeshDimension() < 0 or \a mesh2->getMeshDimension() < 0. + * \throw If \a mesh1->getMeshDimension() != \a mesh2->getMeshDimension(). + */ +MEDCouplingUMesh *MEDCouplingUMesh::MergeUMeshes(const MEDCouplingUMesh *mesh1, const MEDCouplingUMesh *mesh2) +{ + std::vector tmp(2); + tmp[0]=const_cast(mesh1); tmp[1]=const_cast(mesh2); + return MergeUMeshes(tmp); +} + +/*! + * Creates a new MEDCouplingUMesh by concatenating all given meshes of the same dimension. + * Cells and nodes of + * the *i*-th mesh precede cells and nodes of the (*i*+1)-th mesh within the result mesh. + * \param [in] a - a vector of meshes (MEDCouplingUMesh) to concatenate. + * \return MEDCouplingUMesh * - the result mesh. It is a new instance of + * MEDCouplingUMesh. The caller is to delete this mesh using decrRef() as it + * is no more needed. + * \throw If \a a.size() == 0. + * \throw If \a a[ *i* ] == NULL. + * \throw If the coordinates array is not set in none of the meshes. + * \throw If \a a[ *i* ]->getMeshDimension() < 0. + * \throw If the meshes in \a a are of different dimension (getMeshDimension()). + */ +MEDCouplingUMesh *MEDCouplingUMesh::MergeUMeshes(std::vector& a) +{ + std::size_t sz=a.size(); + if(sz==0) + return MergeUMeshesLL(a); + for(std::size_t ii=0;ii > bb(sz); + std::vector< const MEDCouplingUMesh * > aa(sz); + int spaceDim=-3; + for(std::size_t i=0;igetCoords(); + if(coo) + spaceDim=coo->getNumberOfComponents(); + } + if(spaceDim==-3) + throw INTERP_KERNEL::Exception("MEDCouplingUMesh::MergeUMeshes : no spaceDim specified ! unable to perform merge !"); + for(std::size_t i=0;ibuildSetInstanceFromThis(spaceDim); + aa[i]=bb[i]; + } + return MergeUMeshesLL(aa); +} + +/// @cond INTERNAL + +MEDCouplingUMesh *MEDCouplingUMesh::MergeUMeshesLL(std::vector& a) +{ + if(a.empty()) + throw INTERP_KERNEL::Exception("MEDCouplingUMesh::MergeUMeshes : input array must be NON EMPTY !"); + std::vector::const_iterator it=a.begin(); + int meshDim=(*it)->getMeshDimension(); + int nbOfCells=(*it)->getNumberOfCells(); + int meshLgth=(*it++)->getMeshLength(); + for(;it!=a.end();it++) + { + if(meshDim!=(*it)->getMeshDimension()) + throw INTERP_KERNEL::Exception("Mesh dimensions mismatches, MergeUMeshes impossible !"); + nbOfCells+=(*it)->getNumberOfCells(); + meshLgth+=(*it)->getMeshLength(); + } + std::vector aps(a.size()); + std::copy(a.begin(),a.end(),aps.begin()); + MEDCouplingAutoRefCountObjectPtr pts=MergeNodesArray(aps); + MEDCouplingAutoRefCountObjectPtr ret=MEDCouplingUMesh::New("merge",meshDim); + ret->setCoords(pts); + MEDCouplingAutoRefCountObjectPtr c=DataArrayInt::New(); + c->alloc(meshLgth,1); + int *cPtr=c->getPointer(); + MEDCouplingAutoRefCountObjectPtr cI=DataArrayInt::New(); + cI->alloc(nbOfCells+1,1); + int *cIPtr=cI->getPointer(); + *cIPtr++=0; + int offset=0; + int offset2=0; + for(it=a.begin();it!=a.end();it++) + { + int curNbOfCell=(*it)->getNumberOfCells(); + const int *curCI=(*it)->_nodal_connec_index->getConstPointer(); + const int *curC=(*it)->_nodal_connec->getConstPointer(); + cIPtr=std::transform(curCI+1,curCI+curNbOfCell+1,cIPtr,std::bind2nd(std::plus(),offset)); + for(int j=0;jgetNumberOfNodes(); + } + // + ret->setConnectivity(c,cI,true); + return ret.retn(); +} + +/// @endcond + +/*! + * Creates a new MEDCouplingUMesh by concatenating cells of two given meshes of same + * dimension and sharing the node coordinates array. + * All cells of the first mesh precede all cells of the second mesh + * within the result mesh. + * \param [in] mesh1 - the first mesh. + * \param [in] mesh2 - the second mesh. + * \return MEDCouplingUMesh * - the result mesh. It is a new instance of + * MEDCouplingUMesh. The caller is to delete this mesh using decrRef() as it + * is no more needed. + * \throw If \a mesh1 == NULL or \a mesh2 == NULL. + * \throw If the meshes do not share the node coordinates array. + * \throw If \a mesh1->getMeshDimension() < 0 or \a mesh2->getMeshDimension() < 0. + * \throw If \a mesh1->getMeshDimension() != \a mesh2->getMeshDimension(). + */ +MEDCouplingUMesh *MEDCouplingUMesh::MergeUMeshesOnSameCoords(const MEDCouplingUMesh *mesh1, const MEDCouplingUMesh *mesh2) +{ + std::vector tmp(2); + tmp[0]=mesh1; tmp[1]=mesh2; + return MergeUMeshesOnSameCoords(tmp); +} + +/*! + * Creates a new MEDCouplingUMesh by concatenating cells of all given meshes of same + * dimension and sharing the node coordinates array. + * All cells of the *i*-th mesh precede all cells of the + * (*i*+1)-th mesh within the result mesh. + * \param [in] meshes - a vector of meshes (MEDCouplingUMesh) to concatenate. + * \return MEDCouplingUMesh * - the result mesh. It is a new instance of + * MEDCouplingUMesh. The caller is to delete this mesh using decrRef() as it + * is no more needed. + * \throw If \a a.size() == 0. + * \throw If \a a[ *i* ] == NULL. + * \throw If the meshes do not share the node coordinates array. + * \throw If \a a[ *i* ]->getMeshDimension() < 0. + * \throw If the meshes in \a a are of different dimension (getMeshDimension()). + */ +MEDCouplingUMesh *MEDCouplingUMesh::MergeUMeshesOnSameCoords(const std::vector& meshes) +{ + if(meshes.empty()) + throw INTERP_KERNEL::Exception("meshes input parameter is expected to be non empty."); + for(std::size_t ii=0;iigetCoords(); + int meshDim=meshes.front()->getMeshDimension(); + std::vector::const_iterator iter=meshes.begin(); + int meshLgth=0; + int meshIndexLgth=0; + for(;iter!=meshes.end();iter++) + { + if(coords!=(*iter)->getCoords()) + throw INTERP_KERNEL::Exception("meshes does not share the same coords ! Try using tryToShareSameCoords method !"); + if(meshDim!=(*iter)->getMeshDimension()) + throw INTERP_KERNEL::Exception("Mesh dimensions mismatches, FuseUMeshesOnSameCoords impossible !"); + meshLgth+=(*iter)->getMeshLength(); + meshIndexLgth+=(*iter)->getNumberOfCells(); + } + MEDCouplingAutoRefCountObjectPtr nodal=DataArrayInt::New(); + nodal->alloc(meshLgth,1); + int *nodalPtr=nodal->getPointer(); + MEDCouplingAutoRefCountObjectPtr nodalIndex=DataArrayInt::New(); + nodalIndex->alloc(meshIndexLgth+1,1); + int *nodalIndexPtr=nodalIndex->getPointer(); + int offset=0; + for(iter=meshes.begin();iter!=meshes.end();iter++) + { + const int *nod=(*iter)->getNodalConnectivity()->getConstPointer(); + const int *index=(*iter)->getNodalConnectivityIndex()->getConstPointer(); + int nbOfCells=(*iter)->getNumberOfCells(); + int meshLgth2=(*iter)->getMeshLength(); + nodalPtr=std::copy(nod,nod+meshLgth2,nodalPtr); + if(iter!=meshes.begin()) + nodalIndexPtr=std::transform(index+1,index+nbOfCells+1,nodalIndexPtr,std::bind2nd(std::plus(),offset)); + else + nodalIndexPtr=std::copy(index,index+nbOfCells+1,nodalIndexPtr); + offset+=meshLgth2; + } + MEDCouplingUMesh *ret=MEDCouplingUMesh::New(); + ret->setName("merge"); + ret->setMeshDimension(meshDim); + ret->setConnectivity(nodal,nodalIndex,true); + ret->setCoords(coords); + return ret; +} + +/*! + * Creates a new MEDCouplingUMesh by concatenating cells of all given meshes of same + * dimension and sharing the node coordinates array. Cells of the *i*-th mesh precede + * cells of the (*i*+1)-th mesh within the result mesh. Duplicates of cells are + * removed from \a this mesh and arrays mapping between new and old cell ids in "Old to + * New" mode are returned for each input mesh. + * \param [in] meshes - a vector of meshes (MEDCouplingUMesh) to concatenate. + * \param [in] compType - specifies a cell comparison technique. For meaning of its + * valid values [0,1,2], see zipConnectivityTraducer(). + * \param [in,out] corr - an array of DataArrayInt, of the same size as \a + * meshes. The *i*-th array describes cell ids mapping for \a meshes[ *i* ] + * mesh. The caller is to delete each of the arrays using decrRef() as it is + * no more needed. + * \return MEDCouplingUMesh * - the result mesh. It is a new instance of + * MEDCouplingUMesh. The caller is to delete this mesh using decrRef() as it + * is no more needed. + * \throw If \a meshes.size() == 0. + * \throw If \a meshes[ *i* ] == NULL. + * \throw If the meshes do not share the node coordinates array. + * \throw If \a meshes[ *i* ]->getMeshDimension() < 0. + * \throw If the \a meshes are of different dimension (getMeshDimension()). + * \throw If the nodal connectivity of cells of any of \a meshes is not defined. + * \throw If the nodal connectivity any of \a meshes includes an invalid id. + */ +MEDCouplingUMesh *MEDCouplingUMesh::FuseUMeshesOnSameCoords(const std::vector& meshes, int compType, std::vector& corr) +{ + //All checks are delegated to MergeUMeshesOnSameCoords + MEDCouplingAutoRefCountObjectPtr ret=MergeUMeshesOnSameCoords(meshes); + MEDCouplingAutoRefCountObjectPtr o2n=ret->zipConnectivityTraducer(compType); + corr.resize(meshes.size()); + std::size_t nbOfMeshes=meshes.size(); + int offset=0; + const int *o2nPtr=o2n->getConstPointer(); + for(std::size_t i=0;igetNumberOfCells(); + tmp->alloc(curNbOfCells,1); + std::copy(o2nPtr+offset,o2nPtr+offset+curNbOfCells,tmp->getPointer()); + offset+=curNbOfCells; + tmp->setName(meshes[i]->getName()); + corr[i]=tmp; + } + return ret.retn(); +} + +/*! + * Makes all given meshes share the nodal connectivity array. The common connectivity + * array is created by concatenating the connectivity arrays of all given meshes. All + * the given meshes must be of the same space dimension but dimension of cells **can + * differ**. This method is particulary useful in MEDLoader context to build a \ref + * ParaMEDMEM::MEDFileUMesh "MEDFileUMesh" instance that expects that underlying + * MEDCouplingUMesh'es of different dimension share the same nodal connectivity array. + * \param [in,out] meshes - a vector of meshes to update. + * \throw If any of \a meshes is NULL. + * \throw If the coordinates array is not set in any of \a meshes. + * \throw If the nodal connectivity of cells is not defined in any of \a meshes. + * \throw If \a meshes are of different space dimension. + */ +void MEDCouplingUMesh::PutUMeshesOnSameAggregatedCoords(const std::vector& meshes) +{ + std::size_t sz=meshes.size(); + if(sz==0 || sz==1) + return; + std::vector< const DataArrayDouble * > coords(meshes.size()); + std::vector< const DataArrayDouble * >::iterator it2=coords.begin(); + for(std::vector::const_iterator it=meshes.begin();it!=meshes.end();it++,it2++) + { + if((*it)) + { + (*it)->checkConnectivityFullyDefined(); + const DataArrayDouble *coo=(*it)->getCoords(); + if(coo) + *it2=coo; + else + { + std::ostringstream oss; oss << " MEDCouplingUMesh::PutUMeshesOnSameAggregatedCoords : Item #" << std::distance(meshes.begin(),it) << " inside the vector of length " << meshes.size(); + oss << " has no coordinate array defined !"; + throw INTERP_KERNEL::Exception(oss.str().c_str()); + } + } + else + { + std::ostringstream oss; oss << " MEDCouplingUMesh::PutUMeshesOnSameAggregatedCoords : Item #" << std::distance(meshes.begin(),it) << " inside the vector of length " << meshes.size(); + oss << " is null !"; + throw INTERP_KERNEL::Exception(oss.str().c_str()); + } + } + MEDCouplingAutoRefCountObjectPtr res=DataArrayDouble::Aggregate(coords); + std::vector::const_iterator it=meshes.begin(); + int offset=(*it)->getNumberOfNodes(); + (*it++)->setCoords(res); + for(;it!=meshes.end();it++) + { + int oldNumberOfNodes=(*it)->getNumberOfNodes(); + (*it)->setCoords(res); + (*it)->shiftNodeNumbersInConn(offset); + offset+=oldNumberOfNodes; + } +} + +/*! + * Merges nodes coincident with a given precision within all given meshes that share + * the nodal connectivity array. The given meshes **can be of different** mesh + * dimension. This method is particulary useful in MEDLoader context to build a \ref + * ParaMEDMEM::MEDFileUMesh "MEDFileUMesh" instance that expects that underlying + * MEDCouplingUMesh'es of different dimension share the same nodal connectivity array. + * \param [in,out] meshes - a vector of meshes to update. + * \param [in] eps - the precision used to detect coincident nodes (infinite norm). + * \throw If any of \a meshes is NULL. + * \throw If the \a meshes do not share the same node coordinates array. + * \throw If the nodal connectivity of cells is not defined in any of \a meshes. + */ +void MEDCouplingUMesh::MergeNodesOnUMeshesSharingSameCoords(const std::vector& meshes, double eps) +{ + if(meshes.empty()) + return ; + std::set s; + for(std::vector::const_iterator it=meshes.begin();it!=meshes.end();it++) + { + if(*it) + s.insert((*it)->getCoords()); + else + { + std::ostringstream oss; oss << "MEDCouplingUMesh::MergeNodesOnUMeshesSharingSameCoords : In input vector of unstructured meshes of size " << meshes.size() << " the element #" << std::distance(meshes.begin(),it) << " is null !"; + throw INTERP_KERNEL::Exception(oss.str().c_str()); + } + } + if(s.size()!=1) + { + std::ostringstream oss; oss << "MEDCouplingUMesh::MergeNodesOnUMeshesSharingSameCoords : In input vector of unstructured meshes of size " << meshes.size() << ", it appears that they do not share the same instance of DataArrayDouble for coordiantes ! tryToShareSameCoordsPermute method can help to reach that !"; + throw INTERP_KERNEL::Exception(oss.str().c_str()); + } + const DataArrayDouble *coo=*(s.begin()); + if(!coo) + return; + // + DataArrayInt *comm,*commI; + coo->findCommonTuples(eps,-1,comm,commI); + MEDCouplingAutoRefCountObjectPtr tmp1(comm),tmp2(commI); + int oldNbOfNodes=coo->getNumberOfTuples(); + int newNbOfNodes; + MEDCouplingAutoRefCountObjectPtr o2n=DataArrayInt::BuildOld2NewArrayFromSurjectiveFormat2(oldNbOfNodes,comm->begin(),commI->begin(),commI->end(),newNbOfNodes); + if(oldNbOfNodes==newNbOfNodes) + return ; + MEDCouplingAutoRefCountObjectPtr newCoords=coo->renumberAndReduce(o2n->getConstPointer(),newNbOfNodes); + for(std::vector::const_iterator it=meshes.begin();it!=meshes.end();it++) + { + (*it)->renumberNodesInConn(o2n->getConstPointer()); + (*it)->setCoords(newCoords); + } +} + +/*! + * This method takes in input a cell defined by its MEDcouplingUMesh connectivity [ \a connBg , \a connEnd ) and returns its extruded cell by inserting the result at the end of ret. + * \param nbOfNodesPerLev in parameter that specifies the number of nodes of one slice of global dataset + * \param isQuad specifies the policy of connectivity. + * @ret in/out parameter in which the result will be append + */ +void MEDCouplingUMesh::AppendExtrudedCell(const int *connBg, const int *connEnd, int nbOfNodesPerLev, bool isQuad, std::vector& ret) +{ + INTERP_KERNEL::NormalizedCellType flatType=(INTERP_KERNEL::NormalizedCellType)connBg[0]; + const INTERP_KERNEL::CellModel& cm=INTERP_KERNEL::CellModel::GetCellModel(flatType); + ret.push_back(cm.getExtrudedType()); + int deltaz=isQuad?2*nbOfNodesPerLev:nbOfNodesPerLev; + switch(flatType) + { + case INTERP_KERNEL::NORM_POINT1: + { + ret.push_back(connBg[1]); + ret.push_back(connBg[1]+nbOfNodesPerLev); + break; + } + case INTERP_KERNEL::NORM_SEG2: + { + int conn[4]={connBg[1],connBg[2],connBg[2]+deltaz,connBg[1]+deltaz}; + ret.insert(ret.end(),conn,conn+4); + break; + } + case INTERP_KERNEL::NORM_SEG3: + { + int conn[8]={connBg[1],connBg[3],connBg[3]+deltaz,connBg[1]+deltaz,connBg[2],connBg[3]+nbOfNodesPerLev,connBg[2]+deltaz,connBg[1]+nbOfNodesPerLev}; + ret.insert(ret.end(),conn,conn+8); + break; + } + case INTERP_KERNEL::NORM_QUAD4: + { + int conn[8]={connBg[1],connBg[2],connBg[3],connBg[4],connBg[1]+deltaz,connBg[2]+deltaz,connBg[3]+deltaz,connBg[4]+deltaz}; + ret.insert(ret.end(),conn,conn+8); + break; + } + case INTERP_KERNEL::NORM_TRI3: + { + int conn[6]={connBg[1],connBg[2],connBg[3],connBg[1]+deltaz,connBg[2]+deltaz,connBg[3]+deltaz}; + ret.insert(ret.end(),conn,conn+6); + break; + } + case INTERP_KERNEL::NORM_TRI6: + { + int conn[15]={connBg[1],connBg[2],connBg[3],connBg[1]+deltaz,connBg[2]+deltaz,connBg[3]+deltaz,connBg[4],connBg[5],connBg[6],connBg[4]+deltaz,connBg[5]+deltaz,connBg[6]+deltaz, + connBg[1]+nbOfNodesPerLev,connBg[2]+nbOfNodesPerLev,connBg[3]+nbOfNodesPerLev}; + ret.insert(ret.end(),conn,conn+15); + break; + } + case INTERP_KERNEL::NORM_QUAD8: + { + int conn[20]={ + connBg[1],connBg[2],connBg[3],connBg[4],connBg[1]+deltaz,connBg[2]+deltaz,connBg[3]+deltaz,connBg[4]+deltaz, + connBg[5],connBg[6],connBg[7],connBg[8],connBg[5]+deltaz,connBg[6]+deltaz,connBg[7]+deltaz,connBg[8]+deltaz, + connBg[1]+nbOfNodesPerLev,connBg[2]+nbOfNodesPerLev,connBg[3]+nbOfNodesPerLev,connBg[4]+nbOfNodesPerLev + }; + ret.insert(ret.end(),conn,conn+20); + break; + } + case INTERP_KERNEL::NORM_POLYGON: + { + std::back_insert_iterator< std::vector > ii(ret); + std::copy(connBg+1,connEnd,ii); + *ii++=-1; + std::reverse_iterator rConnBg(connEnd); + std::reverse_iterator rConnEnd(connBg+1); + std::transform(rConnBg,rConnEnd,ii,std::bind2nd(std::plus(),deltaz)); + std::size_t nbOfRadFaces=std::distance(connBg+1,connEnd); + for(std::size_t i=0;i0.); +} + +/*! + * The polyhedron is specfied by its connectivity nodes in [ \a begin , \a end ). + */ +bool MEDCouplingUMesh::IsPolyhedronWellOriented(const int *begin, const int *end, const double *coords) +{ + std::vector > edges; + std::size_t nbOfFaces=std::count(begin,end,-1)+1; + const int *bgFace=begin; + for(std::size_t i=0;i p1(bgFace[j],bgFace[(j+1)%nbOfEdgesInFace]); + if(std::find(edges.begin(),edges.end(),p1)!=edges.end()) + return false; + edges.push_back(p1); + } + bgFace=endFace+1; + } + return INTERP_KERNEL::calculateVolumeForPolyh2(begin,(int)std::distance(begin,end),coords)>-EPS_FOR_POLYH_ORIENTATION; +} + +/*! + * The 3D extruded static cell (PENTA6,HEXA8,HEXAGP12...) its connectivity nodes in [ \a begin , \a end ). + */ +bool MEDCouplingUMesh::Is3DExtrudedStaticCellWellOriented(const int *begin, const int *end, const double *coords) +{ + double vec0[3],vec1[3]; + std::size_t sz=std::distance(begin,end); + if(sz%2!=0) + throw INTERP_KERNEL::Exception("MEDCouplingUMesh::Is3DExtrudedStaticCellWellOriented : the length of nodal connectivity of extruded cell is not even !"); + int nbOfNodes=(int)sz/2; + INTERP_KERNEL::areaVectorOfPolygon(begin,nbOfNodes,coords,vec0); + const double *pt0=coords+3*begin[0]; + const double *pt1=coords+3*begin[nbOfNodes]; + vec1[0]=pt1[0]-pt0[0]; vec1[1]=pt1[1]-pt0[1]; vec1[2]=pt1[2]-pt0[2]; + return (vec0[0]*vec1[0]+vec0[1]*vec1[1]+vec0[2]*vec1[2])<0.; +} + +void MEDCouplingUMesh::CorrectExtrudedStaticCell(int *begin, int *end) +{ + std::size_t sz=std::distance(begin,end); + INTERP_KERNEL::AutoPtr tmp=new int[sz]; + std::size_t nbOfNodes(sz/2); + std::copy(begin,end,(int *)tmp); + for(std::size_t j=1;j(begin,4,coords,vec0); + const double *pt0=coords+3*begin[0],*pt1=coords+3*begin[4]; + return (vec0[0]*(pt1[0]-pt0[0])+vec0[1]*(pt1[1]-pt0[1])+vec0[2]*(pt1[2]-pt0[2]))<0.; +} + +/*! + * This method performs a simplyfication of a single polyedron cell. To do that each face of cell whose connectivity is defined by [ \b begin , \b end ) + * is compared with the others in order to find faces in the same plane (with approx of eps). If any, the cells are grouped together and projected to + * a 2D space. + * + * \param [in] eps is a relative precision that allows to establish if some 3D plane are coplanar or not. + * \param [in] coords the coordinates with nb of components exactly equal to 3 + * \param [in] begin begin of the nodal connectivity (geometric type included) of a single polyhedron cell + * \param [in] end end of nodal connectivity of a single polyhedron cell (excluded) + * \param [out] res the result is put at the end of the vector without any alteration of the data. + */ +void MEDCouplingUMesh::SimplifyPolyhedronCell(double eps, const DataArrayDouble *coords, const int *begin, const int *end, DataArrayInt *res) +{ + int nbFaces=std::count(begin+1,end,-1)+1; + MEDCouplingAutoRefCountObjectPtr v=DataArrayDouble::New(); v->alloc(nbFaces,3); + double *vPtr=v->getPointer(); + MEDCouplingAutoRefCountObjectPtr p=DataArrayDouble::New(); p->alloc(nbFaces,1); + double *pPtr=p->getPointer(); + const int *stFaceConn=begin+1; + for(int i=0;igetConstPointer(),stFaceConn,endFaceConn,vPtr,pPtr); + stFaceConn=endFaceConn+1; + } + pPtr=p->getPointer(); vPtr=v->getPointer(); + DataArrayInt *comm1=0,*commI1=0; + v->findCommonTuples(eps,-1,comm1,commI1); + MEDCouplingAutoRefCountObjectPtr comm1Auto(comm1),commI1Auto(commI1); + const int *comm1Ptr=comm1->getConstPointer(); + const int *commI1Ptr=commI1->getConstPointer(); + int nbOfGrps1=commI1Auto->getNumberOfTuples()-1; + res->pushBackSilent((int)INTERP_KERNEL::NORM_POLYHED); + // + MEDCouplingAutoRefCountObjectPtr mm=MEDCouplingUMesh::New("",3); + mm->setCoords(const_cast(coords)); mm->allocateCells(1); mm->insertNextCell(INTERP_KERNEL::NORM_POLYHED,(int)std::distance(begin+1,end),begin+1); + mm->finishInsertingCells(); + // + for(int i=0;i tmpgrp2=p->selectByTupleId(comm1Ptr+commI1Ptr[i],comm1Ptr+commI1Ptr[i+1]); + DataArrayInt *comm2=0,*commI2=0; + tmpgrp2->findCommonTuples(eps,-1,comm2,commI2); + MEDCouplingAutoRefCountObjectPtr comm2Auto(comm2),commI2Auto(commI2); + const int *comm2Ptr=comm2->getConstPointer(); + const int *commI2Ptr=commI2->getConstPointer(); + int nbOfGrps2=commI2Auto->getNumberOfTuples()-1; + for(int j=0;jinsertAtTheEnd(begin,end); + res->pushBackSilent(-1); + } + else + { + int pointId=comm1Ptr[commI1Ptr[i]+comm2Ptr[commI2Ptr[j]]]; + MEDCouplingAutoRefCountObjectPtr ids2=comm2->selectByTupleId2(commI2Ptr[j],commI2Ptr[j+1],1); + ids2->transformWithIndArr(comm1Ptr+commI1Ptr[i],comm1Ptr+commI1Ptr[i+1]); + DataArrayInt *tmp0=DataArrayInt::New(),*tmp1=DataArrayInt::New(),*tmp2=DataArrayInt::New(),*tmp3=DataArrayInt::New(); + MEDCouplingAutoRefCountObjectPtr mm2=mm->buildDescendingConnectivity(tmp0,tmp1,tmp2,tmp3); tmp0->decrRef(); tmp1->decrRef(); tmp2->decrRef(); tmp3->decrRef(); + MEDCouplingAutoRefCountObjectPtr mm3=static_cast(mm2->buildPartOfMySelf(ids2->begin(),ids2->end(),true)); + MEDCouplingAutoRefCountObjectPtr idsNodeTmp=mm3->zipCoordsTraducer(); + MEDCouplingAutoRefCountObjectPtr idsNode=idsNodeTmp->invertArrayO2N2N2O(mm3->getNumberOfNodes()); + const int *idsNodePtr=idsNode->getConstPointer(); + double center[3]; center[0]=pPtr[pointId]*vPtr[3*vecId]; center[1]=pPtr[pointId]*vPtr[3*vecId+1]; center[2]=pPtr[pointId]*vPtr[3*vecId+2]; + double vec[3]; vec[0]=vPtr[3*vecId+1]; vec[1]=-vPtr[3*vecId]; vec[2]=0.; + double norm=vec[0]*vec[0]+vec[1]*vec[1]+vec[2]*vec[2]; + if(std::abs(norm)>eps) + { + double angle=INTERP_KERNEL::EdgeArcCircle::SafeAsin(norm); + mm3->rotate(center,vec,angle); + } + mm3->changeSpaceDimension(2); + MEDCouplingAutoRefCountObjectPtr mm4=mm3->buildSpreadZonesWithPoly(); + const int *conn4=mm4->getNodalConnectivity()->getConstPointer(); + const int *connI4=mm4->getNodalConnectivityIndex()->getConstPointer(); + int nbOfCells=mm4->getNumberOfCells(); + for(int k=0;kpushBackSilent(idsNodePtr[*work]); + res->pushBackSilent(-1); + } + } + } + } + res->popBackSilent(); +} + +/*! + * This method computes the normalized vector of the plane and the pos of the point belonging to the plane and the line defined by the vector going + * through origin. The plane is defined by its nodal connectivity [ \b begin, \b end ). + * + * \param [in] eps below that value the dot product of 2 vectors is considered as colinears + * \param [in] coords coordinates expected to have 3 components. + * \param [in] begin start of the nodal connectivity of the face. + * \param [in] end end of the nodal connectivity (excluded) of the face. + * \param [out] v the normalized vector of size 3 + * \param [out] p the pos of plane + */ +void MEDCouplingUMesh::ComputeVecAndPtOfFace(double eps, const double *coords, const int *begin, const int *end, double *v, double *p) +{ + std::size_t nbPoints=std::distance(begin,end); + if(nbPoints<3) + throw INTERP_KERNEL::Exception("MEDCouplingUMesh::ComputeVecAndPtOfFace : < of 3 points in face ! not able to find a plane on that face !"); + double vec[3]={0.,0.,0.}; + std::size_t j=0; + bool refFound=false; + for(;jeps) + { + refFound=true; + vec[0]/=norm; vec[1]/=norm; vec[2]/=norm; + } + } + for(std::size_t i=j;ieps) + { + v[0]/=norm; v[1]/=norm; v[2]/=norm; + *p=v[0]*coords[3*begin[i]]+v[1]*coords[3*begin[i]+1]+v[2]*coords[3*begin[i]+2]; + return ; + } + } + throw INTERP_KERNEL::Exception("Not able to find a normal vector of that 3D face !"); +} + +/*! + * This method tries to obtain a well oriented polyhedron. + * If the algorithm fails, an exception will be thrown. + */ +void MEDCouplingUMesh::TryToCorrectPolyhedronOrientation(int *begin, int *end, const double *coords) +{ + std::list< std::pair > edgesOK,edgesFinished; + std::size_t nbOfFaces=std::count(begin,end,-1)+1; + std::vector isPerm(nbOfFaces,false);//field on faces False: I don't know, True : oriented + isPerm[0]=true; + int *bgFace=begin,*endFace=std::find(begin+1,end,-1); + std::size_t nbOfEdgesInFace=std::distance(bgFace,endFace); + for(std::size_t l=0;l p1(bgFace[l],bgFace[(l+1)%nbOfEdgesInFace]); edgesOK.push_back(p1); } + // + while(std::find(isPerm.begin(),isPerm.end(),false)!=isPerm.end()) + { + bgFace=begin; + std::size_t smthChanged=0; + for(std::size_t i=0;i p1(bgFace[j],bgFace[(j+1)%nbOfEdgesInFace]); + std::pair p2(p1.second,p1.first); + bool b1=std::find(edgesOK.begin(),edgesOK.end(),p1)!=edgesOK.end(); + bool b2=std::find(edgesOK.begin(),edgesOK.end(),p2)!=edgesOK.end(); + if(b1 || b2) { b=b2; isPerm[i]=true; smthChanged++; break; } + } + if(isPerm[i]) + { + if(!b) + std::reverse(bgFace+1,endFace); + for(std::size_t j=0;j p1(bgFace[j],bgFace[(j+1)%nbOfEdgesInFace]); + std::pair p2(p1.second,p1.first); + if(std::find(edgesOK.begin(),edgesOK.end(),p1)!=edgesOK.end()) + { std::ostringstream oss; oss << "Face #" << j << " of polyhedron looks bad !"; throw INTERP_KERNEL::Exception(oss.str().c_str()); } + if(std::find(edgesFinished.begin(),edgesFinished.end(),p1)!=edgesFinished.end() || std::find(edgesFinished.begin(),edgesFinished.end(),p2)!=edgesFinished.end()) + { std::ostringstream oss; oss << "Face #" << j << " of polyhedron looks bad !"; throw INTERP_KERNEL::Exception(oss.str().c_str()); } + std::list< std::pair >::iterator it=std::find(edgesOK.begin(),edgesOK.end(),p2); + if(it!=edgesOK.end()) + { + edgesOK.erase(it); + edgesFinished.push_back(p1); + } + else + edgesOK.push_back(p1); + } + } + } + bgFace=endFace+1; + } + if(smthChanged==0) + { throw INTERP_KERNEL::Exception("The polyhedron looks too bad to be repaired !"); } + } + if(!edgesOK.empty()) + { throw INTERP_KERNEL::Exception("The polyhedron looks too bad to be repaired : Some edges are shared only once !"); } + if(INTERP_KERNEL::calculateVolumeForPolyh2(begin,(int)std::distance(begin,end),coords)<-EPS_FOR_POLYH_ORIENTATION) + {//not lucky ! The first face was not correctly oriented : reorient all faces... + bgFace=begin; + for(std::size_t i=0;igetNumberOfNodes()); + const int *n2oPtr(n2o->getConstPointer()); + MEDCouplingAutoRefCountObjectPtr revNodal(DataArrayInt::New()),revNodalI(DataArrayInt::New()); + skin->getReverseNodalConnectivity(revNodal,revNodalI); + const int *revNodalPtr(revNodal->getConstPointer()),*revNodalIPtr(revNodalI->getConstPointer()); + const int *nodalPtr(skin->getNodalConnectivity()->getConstPointer()); + const int *nodalIPtr(skin->getNodalConnectivityIndex()->getConstPointer()); + MEDCouplingAutoRefCountObjectPtr ret(DataArrayInt::New()); ret->alloc(nbOfNodesExpected+1,1); + int *work(ret->getPointer()); *work++=INTERP_KERNEL::NORM_POLYGON; + if(nbOfNodesExpected<1) + return ret.retn(); + int prevCell(0),prevNode(nodalPtr[nodalIPtr[0]+1]); + *work++=n2oPtr[prevNode]; + for(int i=1;i conn(nodalPtr+nodalIPtr[prevCell]+1,nodalPtr+nodalIPtr[prevCell]+3); + conn.erase(prevNode); + if(conn.size()==1) + { + int curNode(*(conn.begin())); + *work++=n2oPtr[curNode]; + std::set shar(revNodalPtr+revNodalIPtr[curNode],revNodalPtr+revNodalIPtr[curNode+1]); + shar.erase(prevCell); + if(shar.size()==1) + { + prevCell=*(shar.begin()); + prevNode=curNode; + } + else + throw INTERP_KERNEL::Exception("MEDCouplingUMesh::buildUnionOf2DMeshLinear : presence of unexpected 2 !"); + } + else + throw INTERP_KERNEL::Exception("MEDCouplingUMesh::buildUnionOf2DMeshLinear : presence of unexpected 1 !"); + } + else + throw INTERP_KERNEL::Exception("MEDCouplingUMesh::buildUnionOf2DMeshLinear : presence of unexpected cell !"); + } + return ret.retn(); +} + +DataArrayInt *MEDCouplingUMesh::buildUnionOf2DMeshQuadratic(const MEDCouplingUMesh *skin, const DataArrayInt *n2o) const +{ + int nbOfNodesExpected(skin->getNumberOfNodes()); + int nbOfTurn(nbOfNodesExpected/2); + const int *n2oPtr(n2o->getConstPointer()); + MEDCouplingAutoRefCountObjectPtr revNodal(DataArrayInt::New()),revNodalI(DataArrayInt::New()); + skin->getReverseNodalConnectivity(revNodal,revNodalI); + const int *revNodalPtr(revNodal->getConstPointer()),*revNodalIPtr(revNodalI->getConstPointer()); + const int *nodalPtr(skin->getNodalConnectivity()->getConstPointer()); + const int *nodalIPtr(skin->getNodalConnectivityIndex()->getConstPointer()); + MEDCouplingAutoRefCountObjectPtr ret(DataArrayInt::New()); ret->alloc(nbOfNodesExpected+1,1); + int *work(ret->getPointer()); *work++=INTERP_KERNEL::NORM_QPOLYG; + if(nbOfNodesExpected<1) + return ret.retn(); + int prevCell(0),prevNode(nodalPtr[nodalIPtr[0]+1]); + *work=n2oPtr[prevNode]; work[nbOfTurn]=n2oPtr[nodalPtr[nodalIPtr[0]+3]]; work++; + for(int i=1;i conn(nodalPtr+nodalIPtr[prevCell]+1,nodalPtr+nodalIPtr[prevCell]+3); + conn.erase(prevNode); + if(conn.size()==1) + { + int curNode(*(conn.begin())); + *work=n2oPtr[curNode]; + std::set shar(revNodalPtr+revNodalIPtr[curNode],revNodalPtr+revNodalIPtr[curNode+1]); + shar.erase(prevCell); + if(shar.size()==1) + { + int curCell(*(shar.begin())); + work[nbOfTurn]=n2oPtr[nodalPtr[nodalIPtr[curCell]+3]]; + prevCell=curCell; + prevNode=curNode; + work++; + } + else + throw INTERP_KERNEL::Exception("MEDCouplingUMesh::buildUnionOf2DMeshQuadratic : presence of unexpected 2 !"); + } + else + throw INTERP_KERNEL::Exception("MEDCouplingUMesh::buildUnionOf2DMeshQuadratic : presence of unexpected 1 !"); + } + else + throw INTERP_KERNEL::Exception("MEDCouplingUMesh::buildUnionOf2DMeshQuadratic : presence of unexpected cell !"); + } + return ret.retn(); +} + +/*! + * This method makes the assumption spacedimension == meshdimension == 2. + * This method works only for linear cells. + * + * \return a newly allocated array containing the connectivity of a polygon type enum included (NORM_POLYGON in pos#0) + */ +DataArrayInt *MEDCouplingUMesh::buildUnionOf2DMesh() const +{ + if(getMeshDimension()!=2 || getSpaceDimension()!=2) + throw INTERP_KERNEL::Exception("MEDCouplingUMesh::buildUnionOf2DMesh : meshdimension, spacedimension must be equal to 2 !"); + MEDCouplingAutoRefCountObjectPtr skin(computeSkin()); + int oldNbOfNodes(skin->getNumberOfNodes()); + MEDCouplingAutoRefCountObjectPtr o2n(skin->zipCoordsTraducer()); + int nbOfNodesExpected(skin->getNumberOfNodes()); + MEDCouplingAutoRefCountObjectPtr n2o(o2n->invertArrayO2N2N2O(oldNbOfNodes)); + int nbCells(skin->getNumberOfCells()); + if(nbCells==nbOfNodesExpected) + return buildUnionOf2DMeshLinear(skin,n2o); + else if(2*nbCells==nbOfNodesExpected) + return buildUnionOf2DMeshQuadratic(skin,n2o); + else + throw INTERP_KERNEL::Exception("MEDCouplingUMesh::buildUnionOf2DMesh : the mesh 2D in input appears to be not in a single part of a 2D mesh !"); +} + +/*! + * This method makes the assumption spacedimension == meshdimension == 3. + * This method works only for linear cells. + * + * \return a newly allocated array containing the connectivity of a polygon type enum included (NORM_POLYHED in pos#0) + */ +DataArrayInt *MEDCouplingUMesh::buildUnionOf3DMesh() const +{ + if(getMeshDimension()!=3 || getSpaceDimension()!=3) + throw INTERP_KERNEL::Exception("MEDCouplingUMesh::buildUnionOf3DMesh : meshdimension, spacedimension must be equal to 2 !"); + MEDCouplingAutoRefCountObjectPtr m=computeSkin(); + const int *conn=m->getNodalConnectivity()->getConstPointer(); + const int *connI=m->getNodalConnectivityIndex()->getConstPointer(); + int nbOfCells=m->getNumberOfCells(); + MEDCouplingAutoRefCountObjectPtr ret=DataArrayInt::New(); ret->alloc(m->getNodalConnectivity()->getNumberOfTuples(),1); + int *work=ret->getPointer(); *work++=INTERP_KERNEL::NORM_POLYHED; + if(nbOfCells<1) + return ret.retn(); + work=std::copy(conn+connI[0]+1,conn+connI[1],work); + for(int i=1;igetMeshDimension(); + ParaMEDMEM::DataArrayInt* indexr=ParaMEDMEM::DataArrayInt::New(); + ParaMEDMEM::DataArrayInt* revConn=ParaMEDMEM::DataArrayInt::New(); + this->getReverseNodalConnectivity(revConn,indexr); + const int* indexr_ptr=indexr->getConstPointer(); + const int* revConn_ptr=revConn->getConstPointer(); + + const ParaMEDMEM::DataArrayInt* index; + const ParaMEDMEM::DataArrayInt* conn; + conn=this->getNodalConnectivity(); // it includes a type as the 1st element!!! + index=this->getNodalConnectivityIndex(); + int nbCells=this->getNumberOfCells(); + const int* index_ptr=index->getConstPointer(); + const int* conn_ptr=conn->getConstPointer(); + + //creating graph arcs (cell to cell relations) + //arcs are stored in terms of (index,value) notation + // 0 3 5 6 6 + // 1 2 3 2 3 3 + // means 6 arcs (0,1), (0,2), (0,3), (1,2), (1,3), (2,3) + // in present version arcs are not doubled but reflexive (1,1) arcs are present for each cell + + //warning here one node have less than or equal effective number of cell with it + //but cell could have more than effective nodes + //because other equals nodes in other domain (with other global inode) + std::vector cell2cell_index(nbCells+1,0); + std::vector cell2cell; + cell2cell.reserve(3*nbCells); + + for (int icell=0; icell counter; + for (int iconn=index_ptr[icell]+1; iconn::iterator iter=counter.find(icell2); + if (iter!=counter.end()) (iter->second)++; + else counter.insert(std::make_pair(icell2,1)); + } + } + for (std::map::const_iterator iter=counter.begin(); + iter!=counter.end(); iter++) + if (iter->second >= meshDim) + { + cell2cell_index[icell+1]++; + cell2cell.push_back(iter->first); + } + } + indexr->decrRef(); + revConn->decrRef(); + cell2cell_index[0]=0; + for (int icell=0; icell\n"; + ofs << " \n"; + ofs << " \n" << pointData << std::endl; + ofs << " \n"; + ofs << " \n" << cellData << std::endl; + ofs << " \n"; + ofs << " \n"; + if(getSpaceDimension()==3) + _coords->writeVTK(ofs,8,"Points",byteData); + else + { + MEDCouplingAutoRefCountObjectPtr coo=_coords->changeNbOfComponents(3,0.); + coo->writeVTK(ofs,8,"Points",byteData); + } + ofs << " \n"; + ofs << " \n"; + const int *cPtr=_nodal_connec->getConstPointer(); + const int *cIPtr=_nodal_connec_index->getConstPointer(); + MEDCouplingAutoRefCountObjectPtr faceoffsets=DataArrayInt::New(); faceoffsets->alloc(nbOfCells,1); + MEDCouplingAutoRefCountObjectPtr types=DataArrayInt::New(); types->alloc(nbOfCells,1); + MEDCouplingAutoRefCountObjectPtr offsets=DataArrayInt::New(); offsets->alloc(nbOfCells,1); + MEDCouplingAutoRefCountObjectPtr connectivity=DataArrayInt::New(); connectivity->alloc(_nodal_connec->getNumberOfTuples()-nbOfCells,1); + int *w1=faceoffsets->getPointer(),*w2=types->getPointer(),*w3=offsets->getPointer(),*w4=connectivity->getPointer(); + int szFaceOffsets=0,szConn=0; + for(int i=0;i c(cPtr+cIPtr[i]+1,cPtr+cIPtr[i+1]); c.erase(-1); + *w3=szConn+(int)c.size(); szConn+=(int)c.size(); + w4=std::copy(c.begin(),c.end(),w4); + } + } + types->transformWithIndArr(PARAMEDMEM2VTKTYPETRADUCER,PARAMEDMEM2VTKTYPETRADUCER+INTERP_KERNEL::NORM_MAXTYPE+1); + types->writeVTK(ofs,8,"UInt8","types",byteData); + offsets->writeVTK(ofs,8,"Int32","offsets",byteData); + if(szFaceOffsets!=0) + {//presence of Polyhedra + connectivity->reAlloc(szConn); + faceoffsets->writeVTK(ofs,8,"Int32","faceoffsets",byteData); + MEDCouplingAutoRefCountObjectPtr faces=DataArrayInt::New(); faces->alloc(szFaceOffsets,1); + w1=faces->getPointer(); + for(int i=0;iwriteVTK(ofs,8,"Int32","faces",byteData); + } + connectivity->writeVTK(ofs,8,"Int32","connectivity",byteData); + ofs << " \n"; + ofs << " \n"; + ofs << " \n"; +} + +void MEDCouplingUMesh::reprQuickOverview(std::ostream& stream) const +{ + stream << "MEDCouplingUMesh C++ instance at " << this << ". Name : \"" << getName() << "\"."; + if(_mesh_dim==-2) + { stream << " Not set !"; return ; } + stream << " Mesh dimension : " << _mesh_dim << "."; + if(_mesh_dim==-1) + return ; + if(!_coords) + { stream << " No coordinates set !"; return ; } + if(!_coords->isAllocated()) + { stream << " Coordinates set but not allocated !"; return ; } + stream << " Space dimension : " << _coords->getNumberOfComponents() << "." << std::endl; + stream << "Number of nodes : " << _coords->getNumberOfTuples() << "."; + if(!_nodal_connec_index) + { stream << std::endl << "Nodal connectivity NOT set !"; return ; } + if(!_nodal_connec_index->isAllocated()) + { stream << std::endl << "Nodal connectivity set but not allocated !"; return ; } + int lgth=_nodal_connec_index->getNumberOfTuples(); + int cpt=_nodal_connec_index->getNumberOfComponents(); + if(cpt!=1 || lgth<1) + return ; + stream << std::endl << "Number of cells : " << lgth-1 << "."; +} + +std::string MEDCouplingUMesh::getVTKDataSetType() const +{ + return std::string("UnstructuredGrid"); +} + +std::string MEDCouplingUMesh::getVTKFileExtension() const +{ + return std::string("vtu"); +} + +/*! + * Partitions the first given 2D mesh using the second given 2D mesh as a tool, and + * returns a result mesh constituted by polygons. + * Thus the final result contains all nodes from m1 plus new nodes. However it doesn't necessarily contains + * all nodes from m2. + * The meshes should be in 2D space. In + * addition, returns two arrays mapping cells of the result mesh to cells of the input + * meshes. + * \param [in] m1 - the first input mesh which is a partitioned object. The mesh must be so that each point in the space covered by \a m1 + * must be covered exactly by one entity, \b no \b more. If it is not the case, some tools are available to heal the mesh (conformize2D, mergeNodes) + * \param [in] m2 - the second input mesh which is a partition tool. The mesh must be so that each point in the space covered by \a m2 + * must be covered exactly by one entity, \b no \b more. If it is not the case, some tools are available to heal the mesh (conformize2D, mergeNodes) + * \param [in] eps - precision used to detect coincident mesh entities. + * \param [out] cellNb1 - a new instance of DataArrayInt holding for each result + * cell an id of the cell of \a m1 it comes from. The caller is to delete + * this array using decrRef() as it is no more needed. + * \param [out] cellNb2 - a new instance of DataArrayInt holding for each result + * cell an id of the cell of \a m2 it comes from. -1 value means that a + * result cell comes from a cell (or part of cell) of \a m1 not overlapped by + * any cell of \a m2. The caller is to delete this array using decrRef() as + * it is no more needed. + * \return MEDCouplingUMesh * - the result 2D mesh which is a new instance of + * MEDCouplingUMesh. The caller is to delete this mesh using decrRef() as it + * is no more needed. + * \throw If the coordinates array is not set in any of the meshes. + * \throw If the nodal connectivity of cells is not defined in any of the meshes. + * \throw If any of the meshes is not a 2D mesh in 2D space. + * + * \sa conformize2D, mergeNodes + */ +MEDCouplingUMesh *MEDCouplingUMesh::Intersect2DMeshes(const MEDCouplingUMesh *m1, const MEDCouplingUMesh *m2, + double eps, DataArrayInt *&cellNb1, DataArrayInt *&cellNb2) +{ + if(!m1 || !m2) + throw INTERP_KERNEL::Exception("MEDCouplingUMesh::Intersect2DMeshes : input meshes must be not NULL !"); + m1->checkFullyDefined(); + m2->checkFullyDefined(); + if(m1->getMeshDimension()!=2 || m1->getSpaceDimension()!=2 || m2->getMeshDimension()!=2 || m2->getSpaceDimension()!=2) + throw INTERP_KERNEL::Exception("MEDCouplingUMesh::Intersect2DMeshes works on umeshes m1 AND m2 with meshdim equal to 2 and spaceDim equal to 2 too!"); + + // Step 1: compute all edge intersections (new nodes) + std::vector< std::vector > intersectEdge1, colinear2, subDiv2; + MEDCouplingUMesh *m1Desc=0,*m2Desc=0; // descending connec. meshes + DataArrayInt *desc1=0,*descIndx1=0,*revDesc1=0,*revDescIndx1=0,*desc2=0,*descIndx2=0,*revDesc2=0,*revDescIndx2=0; + std::vector addCoo,addCoordsQuadratic; // coordinates of newly created nodes + IntersectDescending2DMeshes(m1,m2,eps,intersectEdge1,colinear2, subDiv2, + m1Desc,desc1,descIndx1,revDesc1,revDescIndx1, + addCoo, m2Desc,desc2,descIndx2,revDesc2,revDescIndx2); + revDesc1->decrRef(); revDescIndx1->decrRef(); revDesc2->decrRef(); revDescIndx2->decrRef(); + MEDCouplingAutoRefCountObjectPtr dd1(desc1),dd2(descIndx1),dd3(desc2),dd4(descIndx2); + MEDCouplingAutoRefCountObjectPtr dd5(m1Desc),dd6(m2Desc); + + // Step 2: re-order newly created nodes according to the ordering found in m2 + std::vector< std::vector > intersectEdge2; + BuildIntersectEdges(m1Desc,m2Desc,addCoo,subDiv2,intersectEdge2); + subDiv2.clear(); dd5=0; dd6=0; + + // Step 3: + std::vector cr,crI; //no DataArrayInt because interface with Geometric2D + std::vector cNb1,cNb2; //no DataArrayInt because interface with Geometric2D + BuildIntersecting2DCellsFromEdges(eps,m1,desc1->getConstPointer(),descIndx1->getConstPointer(),intersectEdge1,colinear2,m2,desc2->getConstPointer(),descIndx2->getConstPointer(),intersectEdge2,addCoo, + /* outputs -> */addCoordsQuadratic,cr,crI,cNb1,cNb2); + + // Step 4: Prepare final result: + MEDCouplingAutoRefCountObjectPtr addCooDa(DataArrayDouble::New()); + addCooDa->alloc((int)(addCoo.size())/2,2); + std::copy(addCoo.begin(),addCoo.end(),addCooDa->getPointer()); + MEDCouplingAutoRefCountObjectPtr addCoordsQuadraticDa(DataArrayDouble::New()); + addCoordsQuadraticDa->alloc((int)(addCoordsQuadratic.size())/2,2); + std::copy(addCoordsQuadratic.begin(),addCoordsQuadratic.end(),addCoordsQuadraticDa->getPointer()); + std::vector coordss(4); + coordss[0]=m1->getCoords(); coordss[1]=m2->getCoords(); coordss[2]=addCooDa; coordss[3]=addCoordsQuadraticDa; + MEDCouplingAutoRefCountObjectPtr coo(DataArrayDouble::Aggregate(coordss)); + MEDCouplingAutoRefCountObjectPtr ret(MEDCouplingUMesh::New("Intersect2D",2)); + MEDCouplingAutoRefCountObjectPtr conn(DataArrayInt::New()); conn->alloc((int)cr.size(),1); std::copy(cr.begin(),cr.end(),conn->getPointer()); + MEDCouplingAutoRefCountObjectPtr connI(DataArrayInt::New()); connI->alloc((int)crI.size(),1); std::copy(crI.begin(),crI.end(),connI->getPointer()); + MEDCouplingAutoRefCountObjectPtr c1(DataArrayInt::New()); c1->alloc((int)cNb1.size(),1); std::copy(cNb1.begin(),cNb1.end(),c1->getPointer()); + MEDCouplingAutoRefCountObjectPtr c2(DataArrayInt::New()); c2->alloc((int)cNb2.size(),1); std::copy(cNb2.begin(),cNb2.end(),c2->getPointer()); + ret->setConnectivity(conn,connI,true); + ret->setCoords(coo); + cellNb1=c1.retn(); cellNb2=c2.retn(); + return ret.retn(); +} + +/// @cond INTERNAL + +bool IsColinearOfACellOf(const std::vector< std::vector >& intersectEdge1, const std::vector& candidates, int start, int stop, int& retVal) +{ + if(candidates.empty()) + return false; + for(std::vector::const_iterator it=candidates.begin();it!=candidates.end();it++) + { + const std::vector& pool(intersectEdge1[*it]); + int tmp[2]; tmp[0]=start; tmp[1]=stop; + if(std::search(pool.begin(),pool.end(),tmp,tmp+2)!=pool.end()) + { + retVal=*it+1; + return true; + } + tmp[0]=stop; tmp[1]=start; + if(std::search(pool.begin(),pool.end(),tmp,tmp+2)!=pool.end()) + { + retVal=-*it-1; + return true; + } + } + return false; +} + +MEDCouplingUMesh *BuildMesh1DCutFrom(const MEDCouplingUMesh *mesh1D, const std::vector< std::vector >& intersectEdge2, const DataArrayDouble *coords1, const std::vector& addCoo, const std::map& mergedNodes, const std::vector< std::vector >& colinear2, const std::vector< std::vector >& intersectEdge1, + MEDCouplingAutoRefCountObjectPtr& idsInRetColinear, MEDCouplingAutoRefCountObjectPtr& idsInMesh1DForIdsInRetColinear) +{ + idsInRetColinear=DataArrayInt::New(); idsInRetColinear->alloc(0,1); + idsInMesh1DForIdsInRetColinear=DataArrayInt::New(); idsInMesh1DForIdsInRetColinear->alloc(0,1); + int nCells(mesh1D->getNumberOfCells()); + if(nCells!=(int)intersectEdge2.size()) + throw INTERP_KERNEL::Exception("BuildMesh1DCutFrom : internal error # 1 !"); + const DataArrayDouble *coo2(mesh1D->getCoords()); + const int *c(mesh1D->getNodalConnectivity()->begin()),*ci(mesh1D->getNodalConnectivityIndex()->begin()); + const double *coo2Ptr(coo2->begin()); + int offset1(coords1->getNumberOfTuples()); + int offset2(offset1+coo2->getNumberOfTuples()); + int offset3(offset2+addCoo.size()/2); + std::vector addCooQuad; + MEDCouplingAutoRefCountObjectPtr cOut(DataArrayInt::New()),ciOut(DataArrayInt::New()); cOut->alloc(0,1); ciOut->alloc(1,1); ciOut->setIJ(0,0,0); + int tmp[4],cicnt(0),kk(0); + for(int i=0;i,int> m; + INTERP_KERNEL::Edge *e(MEDCouplingUMeshBuildQPFromEdge2((INTERP_KERNEL::NormalizedCellType)c[ci[i]],c+ci[i]+1,coo2Ptr,m)); + const std::vector& subEdges(intersectEdge2[i]); + int nbSubEdge(subEdges.size()/2); + for(int j=0;j n1(MEDCouplingUMeshBuildQPNode(subEdges[2*j],coords1->begin(),offset1,coo2Ptr,offset2,addCoo)),n2(MEDCouplingUMeshBuildQPNode(subEdges[2*j+1],coords1->begin(),offset1,coo2Ptr,offset2,addCoo)); + MEDCouplingAutoRefCountObjectPtr e2(e->buildEdgeLyingOnMe(n1,n2)); + INTERP_KERNEL::Edge *e2Ptr(e2); + std::map::const_iterator itm; + if(dynamic_cast(e2Ptr)) + { + tmp[0]=INTERP_KERNEL::NORM_SEG3; + itm=mergedNodes.find(subEdges[2*j]); + tmp[1]=itm!=mergedNodes.end()?(*itm).second:subEdges[2*j]; + itm=mergedNodes.find(subEdges[2*j+1]); + tmp[2]=itm!=mergedNodes.end()?(*itm).second:subEdges[2*j+1]; + tmp[3]=offset3+(int)addCooQuad.size()/2; + double tmp2[2]; + e2->getBarycenter(tmp2); addCooQuad.insert(addCooQuad.end(),tmp2,tmp2+2); + cicnt+=4; + cOut->insertAtTheEnd(tmp,tmp+4); + ciOut->pushBackSilent(cicnt); + } + else + { + tmp[0]=INTERP_KERNEL::NORM_SEG2; + itm=mergedNodes.find(subEdges[2*j]); + tmp[1]=itm!=mergedNodes.end()?(*itm).second:subEdges[2*j]; + itm=mergedNodes.find(subEdges[2*j+1]); + tmp[2]=itm!=mergedNodes.end()?(*itm).second:subEdges[2*j+1]; + cicnt+=3; + cOut->insertAtTheEnd(tmp,tmp+3); + ciOut->pushBackSilent(cicnt); + } + int tmp00; + if(IsColinearOfACellOf(intersectEdge1,colinear2[i],tmp[1],tmp[2],tmp00)) + { + idsInRetColinear->pushBackSilent(kk); + idsInMesh1DForIdsInRetColinear->pushBackSilent(tmp00); + } + } + e->decrRef(); + } + MEDCouplingAutoRefCountObjectPtr ret(MEDCouplingUMesh::New(mesh1D->getName(),1)); + ret->setConnectivity(cOut,ciOut,true); + MEDCouplingAutoRefCountObjectPtr arr3(DataArrayDouble::New()); + arr3->useArray(&addCoo[0],false,C_DEALLOC,(int)addCoo.size()/2,2); + MEDCouplingAutoRefCountObjectPtr arr4(DataArrayDouble::New()); arr4->useArray(&addCooQuad[0],false,C_DEALLOC,(int)addCooQuad.size()/2,2); + std::vector coordss(4); + coordss[0]=coords1; coordss[1]=mesh1D->getCoords(); coordss[2]=arr3; coordss[3]=arr4; + MEDCouplingAutoRefCountObjectPtr arr(DataArrayDouble::Aggregate(coordss)); + ret->setCoords(arr); + return ret.retn(); +} + +MEDCouplingUMesh *BuildRefined2DCellLinear(const DataArrayDouble *coords, const int *descBg, const int *descEnd, const std::vector< std::vector >& intersectEdge1) +{ + std::vector allEdges; + for(const int *it2(descBg);it2!=descEnd;it2++) + { + const std::vector& edge1(intersectEdge1[std::abs(*it2)-1]); + if(*it2>0) + allEdges.insert(allEdges.end(),edge1.begin(),edge1.end()); + else + allEdges.insert(allEdges.end(),edge1.rbegin(),edge1.rend()); + } + std::size_t nb(allEdges.size()); + if(nb%2!=0) + throw INTERP_KERNEL::Exception("BuildRefined2DCellLinear : internal error 1 !"); + std::size_t nbOfEdgesOf2DCellSplit(nb/2); + MEDCouplingAutoRefCountObjectPtr ret(MEDCouplingUMesh::New("",2)); + ret->setCoords(coords); + ret->allocateCells(1); + std::vector connOut(nbOfEdgesOf2DCellSplit); + for(std::size_t kk=0;kkinsertNextCell(INTERP_KERNEL::NORM_POLYGON,connOut.size(),&connOut[0]); + return ret.retn(); +} + +MEDCouplingUMesh *BuildRefined2DCellQuadratic(const DataArrayDouble *coords, const MEDCouplingUMesh *mesh2D, int cellIdInMesh2D, const int *descBg, const int *descEnd, const std::vector< std::vector >& intersectEdge1) +{ + const int *c(mesh2D->getNodalConnectivity()->begin()),*ci(mesh2D->getNodalConnectivityIndex()->begin()); + const INTERP_KERNEL::CellModel& cm(INTERP_KERNEL::CellModel::GetCellModel((INTERP_KERNEL::NormalizedCellType)c[ci[cellIdInMesh2D]])); + std::size_t ii(0); + unsigned sz(cm.getNumberOfSons2(c+ci[cellIdInMesh2D]+1,ci[cellIdInMesh2D+1]-ci[cellIdInMesh2D]-1)); + if(sz!=std::distance(descBg,descEnd)) + throw INTERP_KERNEL::Exception("BuildRefined2DCellQuadratic : internal error 1 !"); + INTERP_KERNEL::AutoPtr tmpPtr(new int[ci[cellIdInMesh2D+1]-ci[cellIdInMesh2D]]); + std::vector allEdges,centers; + const double *coordsPtr(coords->begin()); + MEDCouplingAutoRefCountObjectPtr addCoo(DataArrayDouble::New()); addCoo->alloc(0,1); + int offset(coords->getNumberOfTuples()); + for(const int *it2(descBg);it2!=descEnd;it2++,ii++) + { + INTERP_KERNEL::NormalizedCellType typeOfSon; + cm.fillSonCellNodalConnectivity2(ii,c+ci[cellIdInMesh2D]+1,ci[cellIdInMesh2D+1]-ci[cellIdInMesh2D]-1,tmpPtr,typeOfSon); + const std::vector& edge1(intersectEdge1[std::abs(*it2)-1]); + if(*it2>0) + allEdges.insert(allEdges.end(),edge1.begin(),edge1.end()); + else + allEdges.insert(allEdges.end(),edge1.rbegin(),edge1.rend()); + if(edge1.size()==2) + centers.push_back(tmpPtr[2]);//special case where no subsplit of edge -> reuse the original center. + else + {//the current edge has been subsplit -> create corresponding centers. + std::size_t nbOfCentersToAppend(edge1.size()/2); + std::map< MEDCouplingAutoRefCountObjectPtr,int> m; + MEDCouplingAutoRefCountObjectPtr ee(MEDCouplingUMeshBuildQPFromEdge2(typeOfSon,tmpPtr,coordsPtr,m)); + std::vector::const_iterator it3(allEdges.end()-edge1.size()); + for(std::size_t k=0;kgetMiddleOfPoints(aa,bb,tmpp); + addCoo->insertAtTheEnd(tmpp,tmpp+2); + centers.push_back(offset+k); + } + } + } + std::size_t nb(allEdges.size()); + if(nb%2!=0) + throw INTERP_KERNEL::Exception("BuildRefined2DCellQuadratic : internal error 2 !"); + std::size_t nbOfEdgesOf2DCellSplit(nb/2); + MEDCouplingAutoRefCountObjectPtr ret(MEDCouplingUMesh::New("",2)); + if(addCoo->empty()) + ret->setCoords(coords); + else + { + addCoo->rearrange(2); + addCoo=DataArrayDouble::Aggregate(coords,addCoo); + ret->setCoords(addCoo); + } + ret->allocateCells(1); + std::vector connOut(nbOfEdgesOf2DCellSplit); + for(std::size_t kk=0;kkinsertNextCell(INTERP_KERNEL::NORM_QPOLYG,connOut.size(),&connOut[0]); + return ret.retn(); +} + +/*! + * This method creates a refinement of a cell in \a mesh2D. Those cell is defined by descending connectivity and the sorted subdivided nodal connectivity + * of those edges. + * + * \param [in] mesh2D - The origin 2D mesh. \b Warning \b coords are not those of \a mesh2D. But mesh2D->getCoords()==coords[:mesh2D->getNumberOfNodes()] + */ +MEDCouplingUMesh *BuildRefined2DCell(const DataArrayDouble *coords, const MEDCouplingUMesh *mesh2D, int cellIdInMesh2D, const int *descBg, const int *descEnd, const std::vector< std::vector >& intersectEdge1) +{ + const INTERP_KERNEL::CellModel& cm(INTERP_KERNEL::CellModel::GetCellModel(mesh2D->getTypeOfCell(cellIdInMesh2D))); + if(!cm.isQuadratic()) + return BuildRefined2DCellLinear(coords,descBg,descEnd,intersectEdge1); + else + return BuildRefined2DCellQuadratic(coords,mesh2D,cellIdInMesh2D,descBg,descEnd,intersectEdge1); +} + +void AddCellInMesh2D(MEDCouplingUMesh *mesh2D, const std::vector& conn, const std::vector< MEDCouplingAutoRefCountObjectPtr >& edges) +{ + bool isQuad(false); + for(std::vector< MEDCouplingAutoRefCountObjectPtr >::const_iterator it=edges.begin();it!=edges.end();it++) + { + const INTERP_KERNEL::Edge *ee(*it); + if(dynamic_cast(ee)) + isQuad=true; + } + if(!isQuad) + mesh2D->insertNextCell(INTERP_KERNEL::NORM_POLYGON,conn.size(),&conn[0]); + else + { + const double *coo(mesh2D->getCoords()->begin()); + std::size_t sz(conn.size()); + std::vector addCoo; + std::vector conn2(conn); + int offset(mesh2D->getNumberOfNodes()); + for(std::size_t i=0;igetMiddleOfPoints(coo+2*conn[i],coo+2*conn[(i+1)%sz],tmp);// tony a chier i+1 -> i + addCoo.insert(addCoo.end(),tmp,tmp+2); + conn2.push_back(offset+(int)i); + } + mesh2D->getCoords()->rearrange(1); + mesh2D->getCoords()->pushBackValsSilent(&addCoo[0],&addCoo[0]+addCoo.size()); + mesh2D->getCoords()->rearrange(2); + mesh2D->insertNextCell(INTERP_KERNEL::NORM_QPOLYG,conn2.size(),&conn2[0]); + } +} + +/*! + * \b WARNING edges in out1 coming from \a splitMesh1D are \b NOT oriented because only used for equation of curve. + * + * This method cuts in 2 parts the input 2D cell given using boundaries description (\a edge1Bis and \a edge1BisPtr) using + * a set of edges defined in \a splitMesh1D. + */ +void BuildMesh2DCutInternal2(const MEDCouplingUMesh *splitMesh1D, const std::vector& edge1Bis, const std::vector< MEDCouplingAutoRefCountObjectPtr >& edge1BisPtr, + std::vector< std::vector >& out0, std::vector< std::vector< MEDCouplingAutoRefCountObjectPtr > >& out1) +{ + std::size_t nb(edge1Bis.size()/2); + std::size_t nbOfEdgesOf2DCellSplit(nb/2); + int iEnd(splitMesh1D->getNumberOfCells()); + if(iEnd==0) + throw INTERP_KERNEL::Exception("BuildMesh2DCutInternal2 : internal error ! input 1D mesh must have at least one cell !"); + std::size_t ii,jj; + const int *cSplitPtr(splitMesh1D->getNodalConnectivity()->begin()),*ciSplitPtr(splitMesh1D->getNodalConnectivityIndex()->begin()); + for(ii=0;ii single output cell + out0.resize(1); out1.resize(1); + std::vector& connOut(out0[0]); + connOut.resize(nbOfEdgesOf2DCellSplit); + std::vector< MEDCouplingAutoRefCountObjectPtr >& edgesPtr(out1[0]); + edgesPtr.resize(nbOfEdgesOf2DCellSplit); + for(std::size_t kk=0;kk& connOutLeft(out0[0]); + std::vector& connOutRight(out0[1]);//connOutLeft should end with edge1Bis[2*ii] and connOutRight should end with edge1Bis[2*jj+1] + std::vector< MEDCouplingAutoRefCountObjectPtr >& eleft(out1[0]); + std::vector< MEDCouplingAutoRefCountObjectPtr >& eright(out1[1]); + for(std::size_t k=ii;k > ees(iEnd); + for(int ik=0;ik,int> m; + MEDCouplingAutoRefCountObjectPtr ee(MEDCouplingUMeshBuildQPFromEdge2((INTERP_KERNEL::NormalizedCellType)cSplitPtr[ciSplitPtr[ik]],cSplitPtr+ciSplitPtr[ik]+1,splitMesh1D->getCoords()->begin(),m)); + ees[ik]=ee; + } + for(int ik=iEnd-1;ik>=0;ik--) + connOutLeft.push_back(cSplitPtr[ciSplitPtr[ik]+1]); + for(std::size_t k=jj+1;k& edges, const std::vector< MEDCouplingAutoRefCountObjectPtr >& edgesPtr); +public: + std::vector _edges; + std::vector< MEDCouplingAutoRefCountObjectPtr > _edges_ptr; +}; + +CellInfo::CellInfo(const std::vector& edges, const std::vector< MEDCouplingAutoRefCountObjectPtr >& edgesPtr) +{ + std::size_t nbe(edges.size()); + std::vector edges2(2*nbe); std::vector< MEDCouplingAutoRefCountObjectPtr > edgesPtr2(2*nbe); + for(std::size_t i=0;i& mesh):_istart(istart),_iend(iend),_mesh(mesh),_left(-7),_right(-7) { } + EdgeInfo(int istart, int iend, int pos, const MEDCouplingAutoRefCountObjectPtr& edge):_istart(istart),_iend(iend),_edge(edge),_left(pos),_right(pos+1) { } + bool isInMyRange(int pos) const { return pos>=_istart && pos<_iend; } + void somethingHappendAt(int pos, const std::vector< MEDCouplingAutoRefCountObjectPtr >& newLeft, const std::vector< MEDCouplingAutoRefCountObjectPtr >& newRight); + void feedEdgeInfoAt(double eps, const MEDCouplingUMesh *mesh2D, int offset, int neighbors[2]) const; +private: + int _istart; + int _iend; + MEDCouplingAutoRefCountObjectPtr _mesh; + MEDCouplingAutoRefCountObjectPtr _edge; + int _left; + int _right; +}; + +void EdgeInfo::somethingHappendAt(int pos, const std::vector< MEDCouplingAutoRefCountObjectPtr >& newLeft, const std::vector< MEDCouplingAutoRefCountObjectPtr >& newRight) +{ + const MEDCouplingUMesh *mesh(_mesh); + if(mesh) + return ; + if(_rightpos) + { _left++; _right++; return ; } + if(_right==pos) + { + bool isLeft(std::find(newLeft.begin(),newLeft.end(),_edge)!=newLeft.end()),isRight(std::find(newRight.begin(),newRight.end(),_edge)!=newRight.end()); + if((isLeft && isRight) || (!isLeft && !isRight)) + throw INTERP_KERNEL::Exception("EdgeInfo::somethingHappendAt : internal error # 1 !"); + if(isLeft) + return ; + if(isRight) + { + _right++; + return ; + } + } + if(_left==pos) + { + bool isLeft(std::find(newLeft.begin(),newLeft.end(),_edge)!=newLeft.end()),isRight(std::find(newRight.begin(),newRight.end(),_edge)!=newRight.end()); + if((isLeft && isRight) || (!isLeft && !isRight)) + throw INTERP_KERNEL::Exception("EdgeInfo::somethingHappendAt : internal error # 2 !"); + if(isLeft) + { + _right++; + return ; + } + if(isRight) + { + _left++; + _right++; + return ; + } + } +} + +void EdgeInfo::feedEdgeInfoAt(double eps, const MEDCouplingUMesh *mesh2D, int offset, int neighbors[2]) const +{ + const MEDCouplingUMesh *mesh(_mesh); + if(!mesh) + { + neighbors[0]=offset+_left; neighbors[1]=offset+_right; + } + else + {// not fully splitting cell case + if(mesh2D->getNumberOfCells()==1) + {//little optimization. 1 cell no need to find in which cell mesh is ! + neighbors[0]=offset; neighbors[1]=offset; + return; + } + else + { + MEDCouplingAutoRefCountObjectPtr barys(mesh->getBarycenterAndOwner()); + int cellId(mesh2D->getCellContainingPoint(barys->begin(),eps)); + if(cellId==-1) + throw INTERP_KERNEL::Exception("EdgeInfo::feedEdgeInfoAt : internal error !"); + neighbors[0]=offset+cellId; neighbors[1]=offset+cellId; + } + } +} + +class VectorOfCellInfo +{ +public: + VectorOfCellInfo(const std::vector& edges, const std::vector< MEDCouplingAutoRefCountObjectPtr >& edgesPtr); + std::size_t size() const { return _pool.size(); } + int getPositionOf(double eps, const MEDCouplingUMesh *mesh) const; + void setMeshAt(int pos, const MEDCouplingAutoRefCountObjectPtr& mesh, int istart, int iend, const MEDCouplingAutoRefCountObjectPtr& mesh1DInCase, const std::vector< std::vector >& edges, const std::vector< std::vector< MEDCouplingAutoRefCountObjectPtr > >& edgePtrs); + const std::vector& getConnOf(int pos) const { return get(pos)._edges; } + const std::vector< MEDCouplingAutoRefCountObjectPtr >& getEdgePtrOf(int pos) const { return get(pos)._edges_ptr; } + MEDCouplingAutoRefCountObjectPtr getZeMesh() const { return _ze_mesh; } + void feedEdgeInfoAt(double eps, int pos, int offset, int neighbors[2]) const; +private: + int getZePosOfEdgeGivenItsGlobalId(int pos) const; + void updateEdgeInfo(int pos, const std::vector< MEDCouplingAutoRefCountObjectPtr >& newLeft, const std::vector< MEDCouplingAutoRefCountObjectPtr >& newRight); + const CellInfo& get(int pos) const; + CellInfo& get(int pos); +private: + std::vector _pool; + MEDCouplingAutoRefCountObjectPtr _ze_mesh; + std::vector _edge_info; +}; + +VectorOfCellInfo::VectorOfCellInfo(const std::vector& edges, const std::vector< MEDCouplingAutoRefCountObjectPtr >& edgesPtr):_pool(1) +{ + _pool[0]._edges=edges; + _pool[0]._edges_ptr=edgesPtr; +} + +int VectorOfCellInfo::getPositionOf(double eps, const MEDCouplingUMesh *mesh) const +{ + if(_pool.empty()) + throw INTERP_KERNEL::Exception("VectorOfCellSplitter::getPositionOf : empty !"); + if(_pool.size()==1) + return 0; + const MEDCouplingUMesh *zeMesh(_ze_mesh); + if(!zeMesh) + throw INTERP_KERNEL::Exception("VectorOfCellSplitter::getPositionOf : null aggregated mesh !"); + MEDCouplingAutoRefCountObjectPtr barys(mesh->getBarycenterAndOwner()); + return zeMesh->getCellContainingPoint(barys->begin(),eps); +} + +void VectorOfCellInfo::setMeshAt(int pos, const MEDCouplingAutoRefCountObjectPtr& mesh, int istart, int iend, const MEDCouplingAutoRefCountObjectPtr& mesh1DInCase, const std::vector< std::vector >& edges, const std::vector< std::vector< MEDCouplingAutoRefCountObjectPtr > >& edgePtrs) +{ + get(pos);//to check pos + bool isFast(pos==0 && _pool.size()==1); + std::size_t sz(edges.size()); + // dealing with edges + if(sz==1) + _edge_info.push_back(EdgeInfo(istart,iend,mesh1DInCase)); + else + _edge_info.push_back(EdgeInfo(istart,iend,pos,edgePtrs[0].back())); + // + std::vector pool(_pool.size()-1+sz); + for(int i=0;i > ms; + if(pos>0) + { + MEDCouplingAutoRefCountObjectPtr elt(static_cast(_ze_mesh->buildPartOfMySelf2(0,pos,true))); + ms.push_back(elt); + } + ms.push_back(mesh); + if(pos<_ze_mesh->getNumberOfCells()-1) + { + MEDCouplingAutoRefCountObjectPtr elt(static_cast(_ze_mesh->buildPartOfMySelf2(pos+1,_ze_mesh->getNumberOfCells(),true))); + ms.push_back(elt); + } + std::vector< const MEDCouplingUMesh *> ms2(ms.size()); + for(std::size_t j=0;j=0 !"); + int ret(0); + for(std::vector::const_iterator it=_edge_info.begin();it!=_edge_info.end();it++,ret++) + { + if((*it).isInMyRange(pos)) + return ret; + } + throw INTERP_KERNEL::Exception("VectorOfCellInfo::getZePosOfEdgeGivenItsGlobalId : invalid id !"); +} + +void VectorOfCellInfo::updateEdgeInfo(int pos, const std::vector< MEDCouplingAutoRefCountObjectPtr >& newLeft, const std::vector< MEDCouplingAutoRefCountObjectPtr >& newRight) +{ + get(pos);//to check; + if(_edge_info.empty()) + return ; + std::size_t sz(_edge_info.size()-1); + for(std::size_t i=0;i=(int)_pool.size()) + throw INTERP_KERNEL::Exception("VectorOfCellSplitter::get const : invalid pos !"); + return _pool[pos]; +} + +CellInfo& VectorOfCellInfo::get(int pos) +{ + if(pos<0 || pos>=(int)_pool.size()) + throw INTERP_KERNEL::Exception("VectorOfCellSplitter::get : invalid pos !"); + return _pool[pos]; +} + +/*! + * Given : + * - a \b closed set of edges ( \a allEdges and \a allEdgesPtr ) that defines the split descending 2D cell. + * - \a splitMesh1D a split 2D curve mesh contained into 2D cell defined above. + * + * This method returns the 2D mesh and feeds \a idsLeftRight using offset. + * + * Algorithm : \a splitMesh1D is cut into contiguous parts. Each contiguous parts will build incrementally the output 2D cells. + * + * \param [in] allEdges a list of pairs (beginNode, endNode). Linked with \a allEdgesPtr to get the equation of edge. + */ +MEDCouplingUMesh *BuildMesh2DCutInternal(double eps, const MEDCouplingUMesh *splitMesh1D, const std::vector& allEdges, const std::vector< MEDCouplingAutoRefCountObjectPtr >& allEdgesPtr, int offset, + MEDCouplingAutoRefCountObjectPtr& idsLeftRight) +{ + int nbCellsInSplitMesh1D(splitMesh1D->getNumberOfCells()); + if(nbCellsInSplitMesh1D==0) + throw INTERP_KERNEL::Exception("BuildMesh2DCutInternal : internal error ! input 1D mesh must have at least one cell !"); + const int *cSplitPtr(splitMesh1D->getNodalConnectivity()->begin()),*ciSplitPtr(splitMesh1D->getNodalConnectivityIndex()->begin()); + std::size_t nb(allEdges.size()),jj; + if(nb%2!=0) + throw INTERP_KERNEL::Exception("BuildMesh2DCutFrom : internal error 2 !"); + std::vector edge1Bis(nb*2); + std::vector< MEDCouplingAutoRefCountObjectPtr > edge1BisPtr(nb*2); + std::copy(allEdges.begin(),allEdges.end(),edge1Bis.begin()); + std::copy(allEdges.begin(),allEdges.end(),edge1Bis.begin()+nb); + std::copy(allEdgesPtr.begin(),allEdgesPtr.end(),edge1BisPtr.begin()); + std::copy(allEdgesPtr.begin(),allEdgesPtr.end(),edge1BisPtr.begin()+nb); + // + idsLeftRight=DataArrayInt::New(); idsLeftRight->alloc(nbCellsInSplitMesh1D*2); idsLeftRight->fillWithValue(-2); idsLeftRight->rearrange(2); + int *idsLeftRightPtr(idsLeftRight->getPointer()); + VectorOfCellInfo pool(edge1Bis,edge1BisPtr); + for(int iStart=0;iStart partOfSplitMesh1D(static_cast(splitMesh1D->buildPartOfMySelf2(iStart,iEnd,1,true))); + int pos(pool.getPositionOf(eps,partOfSplitMesh1D)); + // + MEDCouplingAutoRefCountObjectPtrretTmp(MEDCouplingUMesh::New("",2)); + retTmp->setCoords(splitMesh1D->getCoords()); + retTmp->allocateCells(); + + std::vector< std::vector > out0; + std::vector< std::vector< MEDCouplingAutoRefCountObjectPtr > > out1; + + BuildMesh2DCutInternal2(partOfSplitMesh1D,pool.getConnOf(pos),pool.getEdgePtrOf(pos),out0,out1); + for(std::size_t cnt=0;cnt >& intersectEdge1, int offset, + MEDCouplingAutoRefCountObjectPtr& idsLeftRight) +{ + const int *cdescPtr(mesh2DDesc->getNodalConnectivity()->begin()),*cidescPtr(mesh2DDesc->getNodalConnectivityIndex()->begin()); + // + std::vector allEdges; + std::vector< MEDCouplingAutoRefCountObjectPtr > allEdgesPtr; // for each sub edge in splitMesh2D the uncut Edge object of the original mesh2D + for(const int *it(descBg);it!=descEnd;it++) // for all edges in the descending connectivity of the 2D mesh in relative Fortran mode + { + int edgeId(std::abs(*it)-1); + std::map< MEDCouplingAutoRefCountObjectPtr,int> m; + MEDCouplingAutoRefCountObjectPtr ee(MEDCouplingUMeshBuildQPFromEdge2((INTERP_KERNEL::NormalizedCellType)cdescPtr[cidescPtr[edgeId]],cdescPtr+cidescPtr[edgeId]+1,mesh2DDesc->getCoords()->begin(),m)); + const std::vector& edge1(intersectEdge1[edgeId]); + if(*it>0) + allEdges.insert(allEdges.end(),edge1.begin(),edge1.end()); + else + allEdges.insert(allEdges.end(),edge1.rbegin(),edge1.rend()); + std::size_t sz(edge1.size()); + for(std::size_t cnt=0;cntgetCoords()->begin()); + if(std::distance(candidatesIn2DBg,candidatesIn2DEnd)==1) + return *candidatesIn2DBg; + int edgeId(std::abs(cellIdInMesh1DSplitRelative)-1); + MEDCouplingAutoRefCountObjectPtr cur1D(static_cast(mesh1DSplit->buildPartOfMySelf(&edgeId,&edgeId+1,true))); + if(cellIdInMesh1DSplitRelative<0) + cur1D->changeOrientationOfCells(); + const int *c1D(cur1D->getNodalConnectivity()->begin()); + const INTERP_KERNEL::CellModel& ref1DType(INTERP_KERNEL::CellModel::GetCellModel((INTERP_KERNEL::NormalizedCellType)c1D[0])); + for(const int *it=candidatesIn2DBg;it!=candidatesIn2DEnd;it++) + { + MEDCouplingAutoRefCountObjectPtr cur2D(static_cast(mesh2DSplit->buildPartOfMySelf(it,it+1,true))); + const int *c(cur2D->getNodalConnectivity()->begin()),*ci(cur2D->getNodalConnectivityIndex()->begin()); + const INTERP_KERNEL::CellModel &cm(INTERP_KERNEL::CellModel::GetCellModel((INTERP_KERNEL::NormalizedCellType)c[ci[0]])); + unsigned sz(cm.getNumberOfSons2(c+ci[0]+1,ci[1]-ci[0]-1)); + INTERP_KERNEL::AutoPtr tmpPtr(new int[ci[1]-ci[0]]); + for(unsigned it2=0;it2checkFullyDefined(); + mesh1D->checkFullyDefined(); + const std::vector& compNames(mesh2D->getCoords()->getInfoOnComponents()); + if(mesh2D->getMeshDimension()!=2 || mesh2D->getSpaceDimension()!=2 || mesh1D->getMeshDimension()!=1 || mesh1D->getSpaceDimension()!=2) + throw INTERP_KERNEL::Exception("MEDCouplingUMesh::Intersect2DMeshWith1DLine works with mesh2D with spacedim=meshdim=2 and mesh1D with meshdim=1 spaceDim=2 !"); + // Step 1: compute all edge intersections (new nodes) + std::vector< std::vector > intersectEdge1, colinear2, subDiv2; + std::vector addCoo,addCoordsQuadratic; // coordinates of newly created nodes + INTERP_KERNEL::QUADRATIC_PLANAR::_precision=eps; + INTERP_KERNEL::QUADRATIC_PLANAR::_arc_detection_precision=eps; + // + // Build desc connectivity + DataArrayInt *desc1(DataArrayInt::New()),*descIndx1(DataArrayInt::New()),*revDesc1(DataArrayInt::New()),*revDescIndx1(DataArrayInt::New()); + MEDCouplingAutoRefCountObjectPtr dd1(desc1),dd2(descIndx1),dd3(revDesc1),dd4(revDescIndx1); + MEDCouplingAutoRefCountObjectPtr m1Desc(mesh2D->buildDescendingConnectivity2(desc1,descIndx1,revDesc1,revDescIndx1)); + std::map mergedNodes; + Intersect1DMeshes(m1Desc,mesh1D,eps,intersectEdge1,colinear2,subDiv2,addCoo,mergedNodes); + // use mergeNodes to fix intersectEdge1 + for(std::vector< std::vector >::iterator it0=intersectEdge1.begin();it0!=intersectEdge1.end();it0++) + { + std::size_t n((*it0).size()/2); + int eltStart((*it0)[0]),eltEnd((*it0)[2*n-1]); + std::map::const_iterator it1; + it1=mergedNodes.find(eltStart); + if(it1!=mergedNodes.end()) + (*it0)[0]=(*it1).second; + it1=mergedNodes.find(eltEnd); + if(it1!=mergedNodes.end()) + (*it0)[2*n-1]=(*it1).second; + } + // + MEDCouplingAutoRefCountObjectPtr addCooDa(DataArrayDouble::New()); + addCooDa->useArray(&addCoo[0],false,C_DEALLOC,(int)addCoo.size()/2,2); + // Step 2: re-order newly created nodes according to the ordering found in m2 + std::vector< std::vector > intersectEdge2; + BuildIntersectEdges(m1Desc,mesh1D,addCoo,subDiv2,intersectEdge2); + subDiv2.clear(); + // Step 3: compute splitMesh1D + MEDCouplingAutoRefCountObjectPtr idsInRet1Colinear,idsInDescMesh2DForIdsInRetColinear; + MEDCouplingAutoRefCountObjectPtr ret2(DataArrayInt::New()); ret2->alloc(0,1); + MEDCouplingAutoRefCountObjectPtr ret1(BuildMesh1DCutFrom(mesh1D,intersectEdge2,mesh2D->getCoords(),addCoo,mergedNodes,colinear2,intersectEdge1, + idsInRet1Colinear,idsInDescMesh2DForIdsInRetColinear)); + MEDCouplingAutoRefCountObjectPtr ret3(DataArrayInt::New()); ret3->alloc(ret1->getNumberOfCells()*2,1); ret3->fillWithValue(std::numeric_limits::max()); ret3->rearrange(2); + MEDCouplingAutoRefCountObjectPtr idsInRet1NotColinear(idsInRet1Colinear->buildComplement(ret1->getNumberOfCells())); + // deal with cells in mesh2D that are not cut but only some of their edges are + MEDCouplingAutoRefCountObjectPtr idsInDesc2DToBeRefined(idsInDescMesh2DForIdsInRetColinear->deepCpy()); + idsInDesc2DToBeRefined->abs(); idsInDesc2DToBeRefined->applyLin(1,-1); + idsInDesc2DToBeRefined=idsInDesc2DToBeRefined->buildUnique(); + MEDCouplingAutoRefCountObjectPtr out0s;//ids in mesh2D that are impacted by the fact that some edges of \a mesh1D are part of the edges of those cells + if(!idsInDesc2DToBeRefined->empty()) + { + DataArrayInt *out0(0),*outi0(0); + MEDCouplingUMesh::ExtractFromIndexedArrays(idsInDesc2DToBeRefined->begin(),idsInDesc2DToBeRefined->end(),dd3,dd4,out0,outi0); + MEDCouplingAutoRefCountObjectPtr outi0s(outi0); + out0s=out0; + out0s=out0s->buildUnique(); + out0s->sort(true); + } + // + MEDCouplingAutoRefCountObjectPtr ret1NonCol(static_cast(ret1->buildPartOfMySelf(idsInRet1NotColinear->begin(),idsInRet1NotColinear->end()))); + MEDCouplingAutoRefCountObjectPtr baryRet1(ret1NonCol->getBarycenterAndOwner()); + MEDCouplingAutoRefCountObjectPtr elts,eltsIndex; + mesh2D->getCellsContainingPoints(baryRet1->begin(),baryRet1->getNumberOfTuples(),eps,elts,eltsIndex); + MEDCouplingAutoRefCountObjectPtr eltsIndex2(eltsIndex->deltaShiftIndex()); + MEDCouplingAutoRefCountObjectPtr eltsIndex3(eltsIndex2->getIdsEqual(1)); + if(eltsIndex2->count(0)+eltsIndex3->getNumberOfTuples()!=ret1NonCol->getNumberOfCells()) + throw INTERP_KERNEL::Exception("Intersect2DMeshWith1DLine : internal error 1 !"); + MEDCouplingAutoRefCountObjectPtr cellsToBeModified(elts->buildUnique()); + MEDCouplingAutoRefCountObjectPtr untouchedCells(cellsToBeModified->buildComplement(mesh2D->getNumberOfCells())); + if((DataArrayInt *)out0s) + untouchedCells=untouchedCells->buildSubstraction(out0s);//if some edges in ret1 are colinear to descending mesh of mesh2D remove cells from untouched one + std::vector< MEDCouplingAutoRefCountObjectPtr > outMesh2DSplit; + // OK all is ready to insert in ret2 mesh + if(!untouchedCells->empty()) + {// the most easy part, cells in mesh2D not impacted at all + outMesh2DSplit.push_back(static_cast(mesh2D->buildPartOfMySelf(untouchedCells->begin(),untouchedCells->end()))); + outMesh2DSplit.back()->setCoords(ret1->getCoords()); + ret2->pushBackValsSilent(untouchedCells->begin(),untouchedCells->end()); + } + if((DataArrayInt *)out0s) + {// here dealing with cells in out0s but not in cellsToBeModified + MEDCouplingAutoRefCountObjectPtr fewModifiedCells(out0s->buildSubstraction(cellsToBeModified)); + const int *rdptr(dd3->begin()),*rdiptr(dd4->begin()),*dptr(dd1->begin()),*diptr(dd2->begin()); + for(const int *it=fewModifiedCells->begin();it!=fewModifiedCells->end();it++) + { + outMesh2DSplit.push_back(BuildRefined2DCell(ret1->getCoords(),mesh2D,*it,dptr+diptr[*it],dptr+diptr[*it+1],intersectEdge1)); + ret1->setCoords(outMesh2DSplit.back()->getCoords()); + } + int offset(ret2->getNumberOfTuples()); + ret2->pushBackValsSilent(fewModifiedCells->begin(),fewModifiedCells->end()); + MEDCouplingAutoRefCountObjectPtr partOfRet3(DataArrayInt::New()); partOfRet3->alloc(2*idsInRet1Colinear->getNumberOfTuples(),1); + partOfRet3->fillWithValue(std::numeric_limits::max()); partOfRet3->rearrange(2); + int kk(0),*ret3ptr(partOfRet3->getPointer()); + for(const int *it=idsInDescMesh2DForIdsInRetColinear->begin();it!=idsInDescMesh2DForIdsInRetColinear->end();it++,kk++) + { + int faceId(std::abs(*it)-1); + for(const int *it2=rdptr+rdiptr[faceId];it2!=rdptr+rdiptr[faceId+1];it2++) + { + int tmp(fewModifiedCells->locateValue(*it2)); + if(tmp!=-1) + { + if(std::find(dptr+diptr[*it2],dptr+diptr[*it2+1],-(*it))!=dptr+diptr[*it2+1]) + ret3ptr[2*kk]=tmp+offset; + if(std::find(dptr+diptr[*it2],dptr+diptr[*it2+1],(*it))!=dptr+diptr[*it2+1]) + ret3ptr[2*kk+1]=tmp+offset; + } + else + {//the current edge is shared by a 2D cell that will be split just after + if(std::find(dptr+diptr[*it2],dptr+diptr[*it2+1],-(*it))!=dptr+diptr[*it2+1]) + ret3ptr[2*kk]=-(*it2+1); + if(std::find(dptr+diptr[*it2],dptr+diptr[*it2+1],(*it))!=dptr+diptr[*it2+1]) + ret3ptr[2*kk+1]=-(*it2+1); + } + } + } + m1Desc->setCoords(ret1->getCoords()); + ret1NonCol->setCoords(ret1->getCoords()); + ret3->setPartOfValues3(partOfRet3,idsInRet1Colinear->begin(),idsInRet1Colinear->end(),0,2,1,true); + if(!outMesh2DSplit.empty()) + { + DataArrayDouble *da(outMesh2DSplit.back()->getCoords()); + for(std::vector< MEDCouplingAutoRefCountObjectPtr >::iterator itt=outMesh2DSplit.begin();itt!=outMesh2DSplit.end();itt++) + (*itt)->setCoords(da); + } + } + cellsToBeModified=cellsToBeModified->buildUniqueNotSorted(); + for(const int *it=cellsToBeModified->begin();it!=cellsToBeModified->end();it++) + { + MEDCouplingAutoRefCountObjectPtr idsNonColPerCell(elts->getIdsEqual(*it)); + idsNonColPerCell->transformWithIndArr(eltsIndex3->begin(),eltsIndex3->end()); + MEDCouplingAutoRefCountObjectPtr idsNonColPerCell2(idsInRet1NotColinear->selectByTupleId(idsNonColPerCell->begin(),idsNonColPerCell->end())); + MEDCouplingAutoRefCountObjectPtr partOfMesh1CuttingCur2DCell(static_cast(ret1NonCol->buildPartOfMySelf(idsNonColPerCell->begin(),idsNonColPerCell->end()))); + MEDCouplingAutoRefCountObjectPtr partOfRet3; + MEDCouplingAutoRefCountObjectPtr splitOfOneCell(BuildMesh2DCutFrom(eps,*it,m1Desc,partOfMesh1CuttingCur2DCell,dd1->begin()+dd2->getIJ(*it,0),dd1->begin()+dd2->getIJ((*it)+1,0),intersectEdge1,ret2->getNumberOfTuples(),partOfRet3)); + ret3->setPartOfValues3(partOfRet3,idsNonColPerCell2->begin(),idsNonColPerCell2->end(),0,2,1,true); + outMesh2DSplit.push_back(splitOfOneCell); + for(int i=0;igetNumberOfCells();i++) + ret2->pushBackSilent(*it); + } + // + std::size_t nbOfMeshes(outMesh2DSplit.size()); + std::vector tmp(nbOfMeshes); + for(std::size_t i=0;igetCoords()->setInfoOnComponents(compNames); + MEDCouplingAutoRefCountObjectPtr ret2D(MEDCouplingUMesh::MergeUMeshesOnSameCoords(tmp)); + // To finish - filter ret3 - std::numeric_limits::max() -> -1 - negate values must be resolved. + ret3->rearrange(1); + MEDCouplingAutoRefCountObjectPtr edgesToDealWith(ret3->getIdsStrictlyNegative()); + for(const int *it=edgesToDealWith->begin();it!=edgesToDealWith->end();it++) + { + int old2DCellId(-ret3->getIJ(*it,0)-1); + MEDCouplingAutoRefCountObjectPtr candidates(ret2->getIdsEqual(old2DCellId)); + ret3->setIJ(*it,0,FindRightCandidateAmong(ret2D,candidates->begin(),candidates->end(),ret1,*it%2==0?-((*it)/2+1):(*it)/2+1,eps));// div by 2 because 2 components natively in ret3 + } + ret3->replaceOneValByInThis(std::numeric_limits::max(),-1); + ret3->rearrange(2); + // + splitMesh1D=ret1.retn(); + splitMesh2D=ret2D.retn(); + cellIdInMesh2D=ret2.retn(); + cellIdInMesh1D=ret3.retn(); +} + +/** + * Private. Third step of the partitioning algorithm (Intersect2DMeshes): reconstruct full 2D cells from the + * (newly created) nodes corresponding to the edge intersections. + * Output params: + * @param[out] cr, crI connectivity of the resulting mesh + * @param[out] cNb1, cNb2 correspondance arrays giving for the merged mesh the initial cells IDs in m1 / m2 + * TODO: describe input parameters + */ +void MEDCouplingUMesh::BuildIntersecting2DCellsFromEdges(double eps, const MEDCouplingUMesh *m1, const int *desc1, const int *descIndx1, + const std::vector >& intesctEdges1, const std::vector< std::vector >& colinear2, + const MEDCouplingUMesh *m2, const int *desc2, const int *descIndx2, const std::vector >& intesctEdges2, + const std::vector& addCoords, + std::vector& addCoordsQuadratic, std::vector& cr, std::vector& crI, std::vector& cNb1, std::vector& cNb2) +{ + static const int SPACEDIM=2; + const double *coo1(m1->getCoords()->getConstPointer()); + const int *conn1(m1->getNodalConnectivity()->getConstPointer()),*connI1(m1->getNodalConnectivityIndex()->getConstPointer()); + int offset1(m1->getNumberOfNodes()); + const double *coo2(m2->getCoords()->getConstPointer()); + const int *conn2(m2->getNodalConnectivity()->getConstPointer()),*connI2(m2->getNodalConnectivityIndex()->getConstPointer()); + int offset2(offset1+m2->getNumberOfNodes()); + int offset3(offset2+((int)addCoords.size())/2); + MEDCouplingAutoRefCountObjectPtr bbox1Arr(m1->getBoundingBoxForBBTree()),bbox2Arr(m2->getBoundingBoxForBBTree()); + const double *bbox1(bbox1Arr->begin()),*bbox2(bbox2Arr->begin()); + // Here a BBTree on 2D-cells, not on segments: + BBTree myTree(bbox2,0,0,m2->getNumberOfCells(),eps); + int ncell1(m1->getNumberOfCells()); + crI.push_back(0); + for(int i=0;i candidates2; + myTree.getIntersectingElems(bbox1+i*2*SPACEDIM,candidates2); + std::map mapp; + std::map mappRev; + INTERP_KERNEL::QuadraticPolygon pol1; + INTERP_KERNEL::NormalizedCellType typ=(INTERP_KERNEL::NormalizedCellType)conn1[connI1[i]]; + const INTERP_KERNEL::CellModel& cm=INTERP_KERNEL::CellModel::GetCellModel(typ); + // Populate mapp and mappRev with nodes from the current cell (i) from mesh1 - this also builds the Node* objects: + MEDCouplingUMeshBuildQPFromMesh3(coo1,offset1,coo2,offset2,addCoords,desc1+descIndx1[i],desc1+descIndx1[i+1],intesctEdges1,/* output */mapp,mappRev); + // pol1 is the full cell from mesh2, in QP format, with all the additional intersecting nodes. + pol1.buildFromCrudeDataArray(mappRev,cm.isQuadratic(),conn1+connI1[i]+1,coo1, + desc1+descIndx1[i],desc1+descIndx1[i+1],intesctEdges1); + // + std::set edges1;// store all edges of pol1 that are NOT consumed by intersect cells. If any after iteration over candidates2 -> a part of pol1 should appear in result + std::set edgesBoundary2;// store all edges that are on boundary of (pol2 intersect pol1) minus edges on pol1. + INTERP_KERNEL::IteratorOnComposedEdge it1(&pol1); + for(it1.first();!it1.finished();it1.next()) + edges1.insert(it1.current()->getPtr()); + // + std::map > edgesIn2ForShare; // common edges + std::vector pol2s(candidates2.size()); + int ii=0; + for(std::vector::const_iterator it2=candidates2.begin();it2!=candidates2.end();it2++,ii++) + { + INTERP_KERNEL::NormalizedCellType typ2=(INTERP_KERNEL::NormalizedCellType)conn2[connI2[*it2]]; + const INTERP_KERNEL::CellModel& cm2=INTERP_KERNEL::CellModel::GetCellModel(typ2); + // Complete mapping with elements coming from the current cell it2 in mesh2: + MEDCouplingUMeshBuildQPFromMesh3(coo1,offset1,coo2,offset2,addCoords,desc2+descIndx2[*it2],desc2+descIndx2[*it2+1],intesctEdges2,/* output */mapp,mappRev); + // pol2 is the new QP in the final merged result. + pol2s[ii].buildFromCrudeDataArray2(mappRev,cm2.isQuadratic(),conn2+connI2[*it2]+1,coo2,desc2+descIndx2[*it2],desc2+descIndx2[*it2+1],intesctEdges2, + pol1,desc1+descIndx1[i],desc1+descIndx1[i+1],intesctEdges1,colinear2, /* output */ edgesIn2ForShare); + } + ii=0; + for(std::vector::const_iterator it2=candidates2.begin();it2!=candidates2.end();it2++,ii++) + { + INTERP_KERNEL::ComposedEdge::InitLocationsWithOther(pol1,pol2s[ii]); + pol2s[ii].updateLocOfEdgeFromCrudeDataArray2(desc2+descIndx2[*it2],desc2+descIndx2[*it2+1],intesctEdges2,pol1,desc1+descIndx1[i],desc1+descIndx1[i+1],intesctEdges1,colinear2); + //MEDCouplingUMeshAssignOnLoc(pol1,pol2,desc1+descIndx1[i],desc1+descIndx1[i+1],intesctEdges1,desc2+descIndx2[*it2],desc2+descIndx2[*it2+1],intesctEdges2,colinear2); + pol1.buildPartitionsAbs(pol2s[ii],edges1,edgesBoundary2,mapp,i,*it2,offset3,addCoordsQuadratic,cr,crI,cNb1,cNb2); + } + // Deals with remaining (non-consumed) edges from m1: these are the edges that were never touched + // by m2 but that we still want to keep in the final result. + if(!edges1.empty()) + { + try + { + INTERP_KERNEL::QuadraticPolygon::ComputeResidual(pol1,edges1,edgesBoundary2,mapp,offset3,i,addCoordsQuadratic,cr,crI,cNb1,cNb2); + } + catch(INTERP_KERNEL::Exception& e) + { + std::ostringstream oss; oss << "Error when computing residual of cell #" << i << " in source/m1 mesh ! Maybe the neighbours of this cell in mesh are not well connected !\n" << "The deep reason is the following : " << e.what(); + throw INTERP_KERNEL::Exception(oss.str().c_str()); + } + } + for(std::map::const_iterator it=mappRev.begin();it!=mappRev.end();it++) + (*it).second->decrRef(); + } +} + +/** + * Provides a renumbering of the cells of this (which has to be a piecewise connected 1D line), so that + * the segments of the line are indexed in consecutive order (i.e. cells \a i and \a i+1 are neighbors). + * This doesn't modify the mesh. This method only works using nodal connectivity consideration. Coordinates of nodes are ignored here. + * The caller is to deal with the resulting DataArrayInt. + * \throw If the coordinate array is not set. + * \throw If the nodal connectivity of the cells is not defined. + * \throw If m1 is not a mesh of dimension 2, or m1 is not a mesh of dimension 1 + * \throw If m2 is not a (piecewise) line (i.e. if a point has more than 2 adjacent segments) + * + * \sa DataArrayInt::sortEachPairToMakeALinkedList + */ +DataArrayInt *MEDCouplingUMesh::orderConsecutiveCells1D() const +{ + checkFullyDefined(); + if(getMeshDimension()!=1) + throw INTERP_KERNEL::Exception("MEDCouplingUMesh::orderConsecutiveCells1D works on unstructured mesh with meshdim = 1 !"); + + // Check that this is a line (and not a more complex 1D mesh) - each point is used at most by 2 segments: + MEDCouplingAutoRefCountObjectPtr _d(DataArrayInt::New()),_dI(DataArrayInt::New()); + MEDCouplingAutoRefCountObjectPtr _rD(DataArrayInt::New()),_rDI(DataArrayInt::New()); + MEDCouplingAutoRefCountObjectPtr m_points(buildDescendingConnectivity(_d, _dI, _rD, _rDI)); + const int *d(_d->getConstPointer()), *dI(_dI->getConstPointer()); + const int *rD(_rD->getConstPointer()), *rDI(_rDI->getConstPointer()); + MEDCouplingAutoRefCountObjectPtr _dsi(_rDI->deltaShiftIndex()); + const int * dsi(_dsi->getConstPointer()); + MEDCouplingAutoRefCountObjectPtr dsii = _dsi->getIdsNotInRange(0,3); + m_points=0; + if (dsii->getNumberOfTuples()) + throw INTERP_KERNEL::Exception("MEDCouplingUMesh::orderConsecutiveCells1D only work with a mesh being a (piecewise) connected line!"); + + int nc(getNumberOfCells()); + MEDCouplingAutoRefCountObjectPtr result(DataArrayInt::New()); + result->alloc(nc,1); + + // set of edges not used so far + std::set edgeSet; + for (int i=0; i linePiece; + // fills a list of consecutive segment linked to startSeg. This can go forward or backward. + for (int direction=0;direction<2;direction++) // direction=0 --> forward, direction=1 --> backward + { + // Fill the list forward (resp. backward) from the start segment: + int activeSeg = startSeg; + int prevPointId = -20; + int ptId; + while (!edgeSet.empty()) + { + if (!(direction == 1 && prevPointId==-20)) // prevent adding twice startSeg + { + if (direction==0) + linePiece.push_back(activeSeg); + else + linePiece.push_front(activeSeg); + edgeSet.erase(activeSeg); + } + + int ptId1 = d[dI[activeSeg]], ptId2 = d[dI[activeSeg]+1]; + ptId = direction ? (ptId1 == prevPointId ? ptId2 : ptId1) : (ptId2 == prevPointId ? ptId1 : ptId2); + if (dsi[ptId] == 1) // hitting the end of the line + break; + prevPointId = ptId; + int seg1 = rD[rDI[ptId]], seg2 = rD[rDI[ptId]+1]; + activeSeg = (seg1 == activeSeg) ? seg2 : seg1; + } + } + // Done, save final piece into DA: + std::copy(linePiece.begin(), linePiece.end(), result->getPointer()+newIdx); + newIdx += linePiece.size(); + + // identify next valid start segment (one which is not consumed) + if(!edgeSet.empty()) + startSeg = *(edgeSet.begin()); + } + while (!edgeSet.empty()); + return result.retn(); +} + +/// @cond INTERNAL + +void IKGeo2DInternalMapper2(INTERP_KERNEL::Node *n, const std::map,int>& m, int forbVal0, int forbVal1, std::vector& isect) +{ + MEDCouplingAutoRefCountObjectPtr nTmp(n); nTmp->incrRef(); + std::map,int>::const_iterator it(m.find(nTmp)); + if(it==m.end()) + throw INTERP_KERNEL::Exception("Internal error in remapping !"); + int v((*it).second); + if(v==forbVal0 || v==forbVal1) + return ; + if(std::find(isect.begin(),isect.end(),v)==isect.end()) + isect.push_back(v); +} + +bool IKGeo2DInternalMapper(const INTERP_KERNEL::ComposedEdge& c, const std::map,int>& m, int forbVal0, int forbVal1, std::vector& isect) +{ + int sz(c.size()); + if(sz<=1) + return false; + bool presenceOfOn(false); + for(int i=0;igetLoc()!=INTERP_KERNEL::FULL_ON_1) + continue ; + IKGeo2DInternalMapper2(e->getStartNode(),m,forbVal0,forbVal1,isect); + IKGeo2DInternalMapper2(e->getEndNode(),m,forbVal0,forbVal1,isect); + } + return presenceOfOn; +} + +/// @endcond + +/** + * This method split some of edges of 2D cells in \a this. The edges to be split are specified in \a subNodesInSeg + * and in \a subNodesInSegI using \ref numbering-indirect storage mode. + * To do the work this method can optionally needs information about middle of subedges for quadratic cases if + * a minimal creation of new nodes is wanted. + * So this method try to reduce at most the number of new nodes. The only case that can lead this method to add + * nodes if a SEG3 is split without information of middle. + * \b WARNING : is returned value is different from 0 a call to MEDCouplingUMesh::mergeNodes is necessary to + * avoid to have a non conform mesh. + * + * \return int - the number of new nodes created (in most of cases 0). + * + * \throw If \a this is not coherent. + * \throw If \a this has not spaceDim equal to 2. + * \throw If \a this has not meshDim equal to 2. + * \throw If some subcells needed to be split are orphan. + * \sa MEDCouplingUMesh::conformize2D + */ +int MEDCouplingUMesh::split2DCells(const DataArrayInt *desc, const DataArrayInt *descI, const DataArrayInt *subNodesInSeg, const DataArrayInt *subNodesInSegI, const DataArrayInt *midOpt, const DataArrayInt *midOptI) +{ + if(!desc || !descI || !subNodesInSeg || !subNodesInSegI) + throw INTERP_KERNEL::Exception("MEDCouplingUMesh::split2DCells : the 4 first arrays must be not null !"); + desc->checkAllocated(); descI->checkAllocated(); subNodesInSeg->checkAllocated(); subNodesInSegI->checkAllocated(); + if(getSpaceDimension()!=2 || getMeshDimension()!=2) + throw INTERP_KERNEL::Exception("MEDCouplingUMesh::split2DCells : This method only works for meshes with spaceDim=2 and meshDim=2 !"); + if(midOpt==0 && midOptI==0) + { + split2DCellsLinear(desc,descI,subNodesInSeg,subNodesInSegI); + return 0; + } + else if(midOpt!=0 && midOptI!=0) + return split2DCellsQuadratic(desc,descI,subNodesInSeg,subNodesInSegI,midOpt,midOptI); + else + throw INTERP_KERNEL::Exception("MEDCouplingUMesh::split2DCells : middle parameters must be set to null for all or not null for all."); +} + +/*! + * \b WARNING this method is \b potentially \b non \b const (if returned array is empty). + * \b WARNING this method lead to have a non geometric type sorted mesh (for MED file users) ! + * This method performs a conformization of \b this. So if a edge in \a this can be split into entire edges in \a this this method + * will suppress such edges to use sub edges in \a this. So this method does not add nodes in \a this if merged edges are both linear (INTERP_KERNEL::NORM_SEG2). + * In the other cases new nodes can be created. If any are created, they will be appended at the end of the coordinates object before the invokation of this method. + * + * Whatever the returned value, this method does not alter the order of cells in \a this neither the orientation of cells. + * The modified cells, if any, are systematically declared as NORM_POLYGON or NORM_QPOLYG depending on the initial quadraticness of geometric type. + * + * This method expects that \b this has a meshDim equal 2 and spaceDim equal to 2 too. + * This method expects that all nodes in \a this are not closer than \a eps. + * If it is not the case you can invoke MEDCouplingUMesh::mergeNodes before calling this method. + * + * \param [in] eps the relative error to detect merged edges. + * \return DataArrayInt * - The list of cellIds in \a this that have been subdivided. If empty, nothing changed in \a this (as if it were a const method). The array is a newly allocated array + * that the user is expected to deal with. + * + * \throw If \a this is not coherent. + * \throw If \a this has not spaceDim equal to 2. + * \throw If \a this has not meshDim equal to 2. + * \sa MEDCouplingUMesh::mergeNodes, MEDCouplingUMesh::split2DCells + */ +DataArrayInt *MEDCouplingUMesh::conformize2D(double eps) +{ + static const int SPACEDIM=2; + checkCoherency(); + if(getSpaceDimension()!=2 || getMeshDimension()!=2) + throw INTERP_KERNEL::Exception("MEDCouplingUMesh::conformize2D : This method only works for meshes with spaceDim=2 and meshDim=2 !"); + MEDCouplingAutoRefCountObjectPtr desc1(DataArrayInt::New()),descIndx1(DataArrayInt::New()),revDesc1(DataArrayInt::New()),revDescIndx1(DataArrayInt::New()); + MEDCouplingAutoRefCountObjectPtr mDesc(buildDescendingConnectivity(desc1,descIndx1,revDesc1,revDescIndx1)); + const int *c(mDesc->getNodalConnectivity()->getConstPointer()),*ci(mDesc->getNodalConnectivityIndex()->getConstPointer()),*rd(revDesc1->getConstPointer()),*rdi(revDescIndx1->getConstPointer()); + MEDCouplingAutoRefCountObjectPtr bboxArr(mDesc->getBoundingBoxForBBTree()); + const double *bbox(bboxArr->begin()),*coords(getCoords()->begin()); + int nCell(getNumberOfCells()),nDescCell(mDesc->getNumberOfCells()); + std::vector< std::vector > intersectEdge(nDescCell),overlapEdge(nDescCell); + std::vector addCoo; + BBTree myTree(bbox,0,0,nDescCell,-eps); + INTERP_KERNEL::QUADRATIC_PLANAR::_precision=eps; + INTERP_KERNEL::QUADRATIC_PLANAR::_arc_detection_precision=eps; + for(int i=0;i candidates; + myTree.getIntersectingElems(bbox+i*2*SPACEDIM,candidates); + for(std::vector::const_iterator it=candidates.begin();it!=candidates.end();it++) + if(*it>i) + { + std::map,int> m; + INTERP_KERNEL::Edge *e1(MEDCouplingUMeshBuildQPFromEdge2((INTERP_KERNEL::NormalizedCellType)c[ci[i]],c+ci[i]+1,coords,m)), + *e2(MEDCouplingUMeshBuildQPFromEdge2((INTERP_KERNEL::NormalizedCellType)c[ci[*it]],c+ci[*it]+1,coords,m)); + INTERP_KERNEL::MergePoints merge; + INTERP_KERNEL::QuadraticPolygon c1,c2; + e1->intersectWith(e2,merge,c1,c2); + e1->decrRef(); e2->decrRef(); + if(IKGeo2DInternalMapper(c1,m,c[ci[i]+1],c[ci[i]+2],intersectEdge[i])) + overlapEdge[i].push_back(*it); + if(IKGeo2DInternalMapper(c2,m,c[ci[*it]+1],c[ci[*it]+2],intersectEdge[*it])) + overlapEdge[*it].push_back(i); + } + } + // splitting done. sort intersect point in intersectEdge. + std::vector< std::vector > middle(nDescCell); + int nbOf2DCellsToBeSplit(0); + bool middleNeedsToBeUsed(false); + std::vector cells2DToTreat(nDescCell,false); + for(int i=0;i& isect(intersectEdge[i]); + int sz((int)isect.size()); + if(sz>1) + { + std::map,int> m; + INTERP_KERNEL::Edge *e(MEDCouplingUMeshBuildQPFromEdge2((INTERP_KERNEL::NormalizedCellType)c[ci[i]],c+ci[i]+1,coords,m)); + e->sortSubNodesAbs(coords,isect); + e->decrRef(); + } + if(sz!=0) + { + int idx0(rdi[i]),idx1(rdi[i+1]); + if(idx1-idx0!=1) + throw INTERP_KERNEL::Exception("MEDCouplingUMesh::conformize2D : internal error #0 !"); + if(!cells2DToTreat[rd[idx0]]) + { + cells2DToTreat[rd[idx0]]=true; + nbOf2DCellsToBeSplit++; + } + // try to reuse at most eventual 'middle' of SEG3 + std::vector& mid(middle[i]); + mid.resize(sz+1,-1); + if((INTERP_KERNEL::NormalizedCellType)c[ci[i]]==INTERP_KERNEL::NORM_SEG3) + { + middleNeedsToBeUsed=true; + const std::vector& candidates(overlapEdge[i]); + std::vector trueCandidates; + for(std::vector::const_iterator itc=candidates.begin();itc!=candidates.end();itc++) + if((INTERP_KERNEL::NormalizedCellType)c[ci[*itc]]==INTERP_KERNEL::NORM_SEG3) + trueCandidates.push_back(*itc); + int stNode(c[ci[i]+1]),endNode(isect[0]); + for(int j=0;j::const_iterator itc=trueCandidates.begin();itc!=trueCandidates.end();itc++) + { + int tmpSt(c[ci[*itc]+1]),tmpEnd(c[ci[*itc]+2]); + if((tmpSt==stNode && tmpEnd==endNode) || (tmpSt==endNode && tmpEnd==stNode)) + { mid[j]=*itc; break; } + } + stNode=endNode; + endNode=j ret(DataArrayInt::New()),notRet(DataArrayInt::New()); ret->alloc(nbOf2DCellsToBeSplit,1); + if(nbOf2DCellsToBeSplit==0) + return ret.retn(); + // + int *retPtr(ret->getPointer()); + for(int i=0;i mSafe,nSafe,oSafe,pSafe,qSafe,rSafe; + DataArrayInt *m(0),*n(0),*o(0),*p(0),*q(0),*r(0); + MEDCouplingUMesh::ExtractFromIndexedArrays(ret->begin(),ret->end(),desc1,descIndx1,m,n); mSafe=m; nSafe=n; + DataArrayInt::PutIntoToSkylineFrmt(intersectEdge,o,p); oSafe=o; pSafe=p; + if(middleNeedsToBeUsed) + { DataArrayInt::PutIntoToSkylineFrmt(middle,q,r); qSafe=q; rSafe=r; } + MEDCouplingAutoRefCountObjectPtr modif(static_cast(buildPartOfMySelf(ret->begin(),ret->end(),true))); + int nbOfNodesCreated(modif->split2DCells(mSafe,nSafe,oSafe,pSafe,qSafe,rSafe)); + setCoords(modif->getCoords());//if nbOfNodesCreated==0 modif and this have the same coordinates pointer so this line has no effect. But for quadratic cases this line is important. + setPartOfMySelf(ret->begin(),ret->end(),*modif); + { + bool areNodesMerged; int newNbOfNodes; + if(nbOfNodesCreated!=0) + MEDCouplingAutoRefCountObjectPtr tmp(mergeNodes(eps,areNodesMerged,newNbOfNodes)); + } + return ret.retn(); +} + +/*! + * This non const method works on 2D mesh. This method scans every cell in \a this and look if each edge constituting this cell is not mergeable with neighbors edges of that cell. + * If yes, the cell is "repaired" to minimize at most its number of edges. So this method do not change the overall shape of cells in \a this (with eps precision). + * This method do not take care of shared edges between cells, so this method can lead to a non conform mesh (\a this). If a conform mesh is required you're expected + * to invoke MEDCouplingUMesh::mergeNodes and MEDCouplingUMesh::conformize2D right after this call. + * This method works on any 2D geometric types of cell (even static one). If a cell is touched its type becomes dynamic automaticaly. For 2D "repaired" quadratic cells + * new nodes for center of merged edges is are systematically created and appended at the end of the previously existing nodes. + * + * If the returned array is empty it means that nothing has changed in \a this (as if it were a const method). If the array is not empty the connectivity of \a this is modified + * using new instance, idem for coordinates. + * + * If \a this is constituted by only linear 2D cells, this method is close to the computation of the convex hull of each cells in \a this. + * + * \return DataArrayInt * - The list of cellIds in \a this that have at least one edge colinearized. + * + * \throw If \a this is not coherent. + * \throw If \a this has not spaceDim equal to 2. + * \throw If \a this has not meshDim equal to 2. + * + * \sa MEDCouplingUMesh::conformize2D, MEDCouplingUMesh::mergeNodes, MEDCouplingUMesh::convexEnvelop2D. + */ +DataArrayInt *MEDCouplingUMesh::colinearize2D(double eps) +{ + MEDCouplingAutoRefCountObjectPtr ret(DataArrayInt::New()); ret->alloc(0,1); + checkCoherency(); + if(getSpaceDimension()!=2 || getMeshDimension()!=2) + throw INTERP_KERNEL::Exception("MEDCouplingUMesh::colinearize2D : This method only works for meshes with spaceDim=2 and meshDim=2 !"); + INTERP_KERNEL::QUADRATIC_PLANAR::_arc_detection_precision=eps; + INTERP_KERNEL::QUADRATIC_PLANAR::_precision=eps; + int nbOfCells(getNumberOfCells()),nbOfNodes(getNumberOfNodes()); + const int *cptr(_nodal_connec->begin()),*ciptr(_nodal_connec_index->begin()); + MEDCouplingAutoRefCountObjectPtr newc(DataArrayInt::New()),newci(DataArrayInt::New()); newci->alloc(nbOfCells+1,1); newc->alloc(0,1); newci->setIJ(0,0,0); + MEDCouplingAutoRefCountObjectPtr appendedCoords(DataArrayDouble::New()); appendedCoords->alloc(0,1);//1 not 2 it is not a bug. + const double *coords(_coords->begin()); + int *newciptr(newci->getPointer()); + for(int i=0;ipushBackSilent(i); + newciptr[1]=newc->getNumberOfTuples(); + } + // + if(ret->empty()) + return ret.retn(); + if(!appendedCoords->empty()) + { + appendedCoords->rearrange(2); + MEDCouplingAutoRefCountObjectPtr newCoords(DataArrayDouble::Aggregate(getCoords(),appendedCoords));//treat info on components + //non const part + setCoords(newCoords); + } + //non const part + setConnectivity(newc,newci,true); + return ret.retn(); +} + +/*! + * \param [out] intersectEdge1 - for each cell in \a m1Desc returns the result of the split. The result is given using pair of int given resp start and stop. + * So for all edge \a i in \a m1Desc \a intersectEdge1[i] is of length 2*n where n is the number of sub edges. + * And for each j in [1,n) intersect[i][2*(j-1)+1]==intersect[i][2*j]. + * \param [out] subDiv2 - for each cell in \a m2Desc returns nodes that split it using convention \a m1Desc first, then \a m2Desc, then addCoo + * \param [out] colinear2 - for each cell in \a m2Desc returns the edges in \a m1Desc that are colinear to it. + * \param [out] addCoo - nodes to be append at the end + * \param [out] mergedNodes - gives all pair of nodes of \a m2Desc that have same location than some nodes in \a m1Desc. key is id in \a m2Desc offseted and value is id in \a m1Desc. + */ +void MEDCouplingUMesh::Intersect1DMeshes(const MEDCouplingUMesh *m1Desc, const MEDCouplingUMesh *m2Desc, double eps, + std::vector< std::vector >& intersectEdge1, std::vector< std::vector >& colinear2, std::vector< std::vector >& subDiv2, std::vector& addCoo, std::map& mergedNodes) +{ + static const int SPACEDIM=2; + INTERP_KERNEL::QUADRATIC_PLANAR::_precision=eps; + INTERP_KERNEL::QUADRATIC_PLANAR::_arc_detection_precision=eps; + const int *c1(m1Desc->getNodalConnectivity()->getConstPointer()),*ci1(m1Desc->getNodalConnectivityIndex()->getConstPointer()); + // Build BB tree of all edges in the tool mesh (second mesh) + MEDCouplingAutoRefCountObjectPtr bbox1Arr(m1Desc->getBoundingBoxForBBTree()),bbox2Arr(m2Desc->getBoundingBoxForBBTree()); + const double *bbox1(bbox1Arr->begin()),*bbox2(bbox2Arr->begin()); + int nDescCell1(m1Desc->getNumberOfCells()),nDescCell2(m2Desc->getNumberOfCells()); + intersectEdge1.resize(nDescCell1); + colinear2.resize(nDescCell2); + subDiv2.resize(nDescCell2); + BBTree myTree(bbox2,0,0,m2Desc->getNumberOfCells(),-eps); + + std::vector candidates1(1); + int offset1(m1Desc->getNumberOfNodes()); + int offset2(offset1+m2Desc->getNumberOfNodes()); + for(int i=0;i candidates2; // edges of mesh2 candidate for intersection + myTree.getIntersectingElems(bbox1+i*2*SPACEDIM,candidates2); + if(!candidates2.empty()) // candidates2 holds edges from the second mesh potentially intersecting current edge i in mesh1 + { + std::map map1,map2; + // pol2 is not necessarily a closed polygon: just a set of (quadratic) edges (same as candidates2) in the Geometric DS format + INTERP_KERNEL::QuadraticPolygon *pol2=MEDCouplingUMeshBuildQPFromMesh(m2Desc,candidates2,map2); + candidates1[0]=i; + INTERP_KERNEL::QuadraticPolygon *pol1=MEDCouplingUMeshBuildQPFromMesh(m1Desc,candidates1,map1); + // This following part is to avoid that some removed nodes (for example due to a merge between pol1 and pol2) are replaced by a newly created one + // This trick guarantees that Node * are discriminant (i.e. form a unique identifier) + std::set nodes; + pol1->getAllNodes(nodes); pol2->getAllNodes(nodes); + std::size_t szz(nodes.size()); + std::vector< MEDCouplingAutoRefCountObjectPtr > nodesSafe(szz); + std::set::const_iterator itt(nodes.begin()); + for(std::size_t iii=0;iiiincrRef(); nodesSafe[iii]=*itt; } + // end of protection + // Performs egde cutting: + pol1->splitAbs(*pol2,map1,map2,offset1,offset2,candidates2,intersectEdge1[i],i,colinear2,subDiv2,addCoo,mergedNodes); + delete pol2; + delete pol1; + } + else + // Copy the edge (take only the two first points, ie discard quadratic point at this stage) + intersectEdge1[i].insert(intersectEdge1[i].end(),c1+ci1[i]+1,c1+ci1[i]+3); + } +} + +/*! + * This method is private and is the first step of Partition of 2D mesh (spaceDim==2 and meshDim==2). + * It builds the descending connectivity of the two meshes, and then using a binary tree + * it computes the edge intersections. This results in new points being created : they're stored in addCoo. + * Documentation about parameters colinear2 and subDiv2 can be found in method QuadraticPolygon::splitAbs(). + */ +void MEDCouplingUMesh::IntersectDescending2DMeshes(const MEDCouplingUMesh *m1, const MEDCouplingUMesh *m2, double eps, + std::vector< std::vector >& intersectEdge1, std::vector< std::vector >& colinear2, std::vector< std::vector >& subDiv2, + MEDCouplingUMesh *& m1Desc, DataArrayInt *&desc1, DataArrayInt *&descIndx1, DataArrayInt *&revDesc1, DataArrayInt *&revDescIndx1, + std::vector& addCoo, + MEDCouplingUMesh *& m2Desc, DataArrayInt *&desc2, DataArrayInt *&descIndx2, DataArrayInt *&revDesc2, DataArrayInt *&revDescIndx2) +{ + // Build desc connectivity + desc1=DataArrayInt::New(); descIndx1=DataArrayInt::New(); revDesc1=DataArrayInt::New(); revDescIndx1=DataArrayInt::New(); + desc2=DataArrayInt::New(); + descIndx2=DataArrayInt::New(); + revDesc2=DataArrayInt::New(); + revDescIndx2=DataArrayInt::New(); + MEDCouplingAutoRefCountObjectPtr dd1(desc1),dd2(descIndx1),dd3(revDesc1),dd4(revDescIndx1); + MEDCouplingAutoRefCountObjectPtr dd5(desc2),dd6(descIndx2),dd7(revDesc2),dd8(revDescIndx2); + m1Desc=m1->buildDescendingConnectivity2(desc1,descIndx1,revDesc1,revDescIndx1); + m2Desc=m2->buildDescendingConnectivity2(desc2,descIndx2,revDesc2,revDescIndx2); + MEDCouplingAutoRefCountObjectPtr dd9(m1Desc),dd10(m2Desc); + std::map notUsedMap; + Intersect1DMeshes(m1Desc,m2Desc,eps,intersectEdge1,colinear2,subDiv2,addCoo,notUsedMap); + m1Desc->incrRef(); desc1->incrRef(); descIndx1->incrRef(); revDesc1->incrRef(); revDescIndx1->incrRef(); + m2Desc->incrRef(); desc2->incrRef(); descIndx2->incrRef(); revDesc2->incrRef(); revDescIndx2->incrRef(); +} + +/*! + * This method performs the 2nd step of Partition of 2D mesh. + * This method has 4 inputs : + * - a mesh 'm1' with meshDim==1 and a SpaceDim==2 + * - a mesh 'm2' with meshDim==1 and a SpaceDim==2 + * - subDiv of size 'm2->getNumberOfCells()' that lists for each seg cell in 'm' the splitting node ids randomly sorted. + * The aim of this method is to sort the splitting nodes, if any, and to put them in 'intersectEdge' output parameter based on edges of mesh 'm2' + * Nodes end up lying consecutively on a cutted edge. + * \param m1 is expected to be a mesh of meshDimension equal to 1 and spaceDim equal to 2. No check of that is performed by this method. + * (Only present for its coords in case of 'subDiv' shares some nodes of 'm1') + * \param m2 is expected to be a mesh of meshDimension equal to 1 and spaceDim equal to 2. No check of that is performed by this method. + * \param addCoo input parameter with additional nodes linked to intersection of the 2 meshes. + * \param[out] intersectEdge the same content as subDiv, but correclty oriented. + */ +void MEDCouplingUMesh::BuildIntersectEdges(const MEDCouplingUMesh *m1, const MEDCouplingUMesh *m2, + const std::vector& addCoo, + const std::vector< std::vector >& subDiv, std::vector< std::vector >& intersectEdge) +{ + int offset1=m1->getNumberOfNodes(); + int ncell=m2->getNumberOfCells(); + const int *c=m2->getNodalConnectivity()->getConstPointer(); + const int *cI=m2->getNodalConnectivityIndex()->getConstPointer(); + const double *coo=m2->getCoords()->getConstPointer(); + const double *cooBis=m1->getCoords()->getConstPointer(); + int offset2=offset1+m2->getNumberOfNodes(); + intersectEdge.resize(ncell); + for(int i=0;i& divs=subDiv[i]; + int nnode=cI[1]-cI[0]-1; + std::map > mapp2; + std::map mapp22; + for(int j=0;j(nn,true); + mapp22[nn]=nnid+offset1; + } + INTERP_KERNEL::Edge *e=MEDCouplingUMeshBuildQPFromEdge((INTERP_KERNEL::NormalizedCellType)c[*cI],mapp2,c+(*cI)+1); + for(std::map >::const_iterator it=mapp2.begin();it!=mapp2.end();it++) + ((*it).second.first)->decrRef(); + std::vector addNodes(divs.size()); + std::map mapp3; + for(std::size_t j=0;jsortIdsAbs(addNodes,mapp22,mapp3,intersectEdge[i]); + for(std::vector::const_iterator it=addNodes.begin();it!=addNodes.end();it++) + (*it)->decrRef(); + e->decrRef(); + } +} + +/*! + * This method is part of the Slice3D algorithm. It is the first step of assembly process, ones coordinates have been computed (by MEDCouplingUMesh::split3DCurveWithPlane method). + * This method allows to compute given the status of 3D curve cells and the descending connectivity 3DSurf->3DCurve to deduce the intersection of each 3D surf cells + * with a plane. The result will be put in 'cut3DSuf' out parameter. + * \param [in] cut3DCurve input paramter that gives for each 3DCurve cell if it owns fully to the plane or partially. + * \param [out] nodesOnPlane, returns all the nodes that are on the plane. + * \param [in] nodal3DSurf is the nodal connectivity of 3D surf mesh. + * \param [in] nodalIndx3DSurf is the nodal connectivity index of 3D surf mesh. + * \param [in] nodal3DCurve is the nodal connectivity of 3D curve mesh. + * \param [in] nodal3DIndxCurve is the nodal connectivity index of 3D curve mesh. + * \param [in] desc is the descending connectivity 3DSurf->3DCurve + * \param [in] descIndx is the descending connectivity index 3DSurf->3DCurve + * \param [out] cut3DSuf input/output param. + */ +void MEDCouplingUMesh::AssemblyForSplitFrom3DCurve(const std::vector& cut3DCurve, std::vector& nodesOnPlane, const int *nodal3DSurf, const int *nodalIndx3DSurf, + const int *nodal3DCurve, const int *nodalIndx3DCurve, + const int *desc, const int *descIndx, + std::vector< std::pair >& cut3DSurf) +{ + std::set nodesOnP(nodesOnPlane.begin(),nodesOnPlane.end()); + int nbOf3DSurfCell=(int)cut3DSurf.size(); + for(int i=0;i res; + int offset=descIndx[i]; + int nbOfSeg=descIndx[i+1]-offset; + for(int j=0;j-1) + res.push_back(status); + else + { + res.push_back(nodal3DCurve[nodalIndx3DCurve[edgeId]+1]); + res.push_back(nodal3DCurve[nodalIndx3DCurve[edgeId]+2]); + } + } + } + switch(res.size()) + { + case 2: + { + cut3DSurf[i].first=res[0]; cut3DSurf[i].second=res[1]; + break; + } + case 1: + case 0: + { + std::set s1(nodal3DSurf+nodalIndx3DSurf[i]+1,nodal3DSurf+nodalIndx3DSurf[i+1]); + std::set_intersection(nodesOnP.begin(),nodesOnP.end(),s1.begin(),s1.end(),std::back_insert_iterator< std::vector >(res)); + if(res.size()==2) + { + cut3DSurf[i].first=res[0]; cut3DSurf[i].second=res[1]; + } + else + { + cut3DSurf[i].first=-1; cut3DSurf[i].second=-1; + } + break; + } + default: + {// case when plane is on a multi colinear edge of a polyhedron + if((int)res.size()==2*nbOfSeg) + { + cut3DSurf[i].first=-2; cut3DSurf[i].second=i; + } + else + throw INTERP_KERNEL::Exception("MEDCouplingUMesh::AssemblyPointsFrom3DCurve : unexpected situation !"); + } + } + } +} + +/*! + * \a this is expected to be a mesh with spaceDim==3 and meshDim==3. If not an exception will be thrown. + * This method is part of the Slice3D algorithm. It is the second step of assembly process, ones coordinates have been computed (by MEDCouplingUMesh::split3DCurveWithPlane method). + * This method allows to compute given the result of 3D surf cells with plane and the descending connectivity 3D->3DSurf to deduce the intersection of each 3D cells + * with a plane. The result will be put in 'nodalRes' 'nodalResIndx' and 'cellIds' out parameters. + * \param cut3DSurf input paramter that gives for each 3DSurf its intersection with plane (result of MEDCouplingUMesh::AssemblyForSplitFrom3DCurve). + * \param desc is the descending connectivity 3D->3DSurf + * \param descIndx is the descending connectivity index 3D->3DSurf + */ +void MEDCouplingUMesh::assemblyForSplitFrom3DSurf(const std::vector< std::pair >& cut3DSurf, + const int *desc, const int *descIndx, + DataArrayInt *nodalRes, DataArrayInt *nodalResIndx, DataArrayInt *cellIds) const +{ + checkFullyDefined(); + if(getMeshDimension()!=3 || getSpaceDimension()!=3) + throw INTERP_KERNEL::Exception("MEDCouplingUMesh::assemblyForSplitFrom3DSurf works on umeshes with meshdim equal to 3 and spaceDim equal to 3 too!"); + const int *nodal3D=_nodal_connec->getConstPointer(); + const int *nodalIndx3D=_nodal_connec_index->getConstPointer(); + int nbOfCells=getNumberOfCells(); + for(int i=0;i > m; + int offset=descIndx[i]; + int nbOfFaces=descIndx[i+1]-offset; + int start=-1; + int end=-1; + for(int j=0;j& p=cut3DSurf[desc[offset+j]]; + if(p.first!=-1 && p.second!=-1) + { + if(p.first!=-2) + { + start=p.first; end=p.second; + m[p.first].insert(p.second); + m[p.second].insert(p.first); + } + else + { + const INTERP_KERNEL::CellModel& cm=INTERP_KERNEL::CellModel::GetCellModel((INTERP_KERNEL::NormalizedCellType)nodal3D[nodalIndx3D[i]]); + int sz=nodalIndx3D[i+1]-nodalIndx3D[i]-1; + INTERP_KERNEL::AutoPtr tmp=new int[sz]; + INTERP_KERNEL::NormalizedCellType cmsId; + unsigned nbOfNodesSon=cm.fillSonCellNodalConnectivity2(j,nodal3D+nodalIndx3D[i]+1,sz,tmp,cmsId); + start=tmp[0]; end=tmp[nbOfNodesSon-1]; + for(unsigned k=0;k conn(1,(int)INTERP_KERNEL::NORM_POLYGON); + int prev=end; + while(end!=start) + { + std::map >::const_iterator it=m.find(start); + const std::set& s=(*it).second; + std::set s2; s2.insert(prev); + std::set s3; + std::set_difference(s.begin(),s.end(),s2.begin(),s2.end(),inserter(s3,s3.begin())); + if(s3.size()==1) + { + int val=*s3.begin(); + conn.push_back(start); + prev=start; + start=val; + } + else + start=end; + } + conn.push_back(end); + if(conn.size()>3) + { + nodalRes->insertAtTheEnd(conn.begin(),conn.end()); + nodalResIndx->pushBackSilent(nodalRes->getNumberOfTuples()); + cellIds->pushBackSilent(i); + } + } +} + +/*! + * This method compute the convex hull of a single 2D cell. This method tries to conserve at maximum the given input connectivity. In particular, if the orientation of cell is not clockwise + * as in MED format norm. If definitely the result of Jarvis algorithm is not matchable with the input connectivity, the result will be copied into \b nodalConnecOut parameter and + * the geometric cell type set to INTERP_KERNEL::NORM_POLYGON. + * This method excepts that \b coords parameter is expected to be in dimension 2. [ \b nodalConnBg , \b nodalConnEnd ) is the nodal connectivity of the input + * cell (geometric cell type included at the position 0). If the meshdimension of the input cell is not equal to 2 an INTERP_KERNEL::Exception will be thrown. + * + * \return false if the input connectivity represents already the convex hull, true if the input cell needs to be reordered. + */ +bool MEDCouplingUMesh::BuildConvexEnvelopOf2DCellJarvis(const double *coords, const int *nodalConnBg, const int *nodalConnEnd, DataArrayInt *nodalConnecOut) +{ + std::size_t sz=std::distance(nodalConnBg,nodalConnEnd); + if(sz>=4) + { + const INTERP_KERNEL::CellModel& cm=INTERP_KERNEL::CellModel::GetCellModel((INTERP_KERNEL::NormalizedCellType)*nodalConnBg); + if(cm.getDimension()==2) + { + const int *node=nodalConnBg+1; + int startNode=*node++; + double refX=coords[2*startNode]; + for(;node!=nodalConnEnd;node++) + { + if(coords[2*(*node)] tmpOut; tmpOut.reserve(sz); tmpOut.push_back(startNode); + refX=1e300; + double tmp1; + double tmp2[2]; + double angle0=-M_PI/2; + // + int nextNode=-1; + int prevNode=-1; + double resRef; + double angleNext=0.; + while(nextNode!=startNode) + { + nextNode=-1; + resRef=1e300; + for(node=nodalConnBg+1;node!=nodalConnEnd;node++) + { + if(*node!=tmpOut.back() && *node!=prevNode) + { + tmp2[0]=coords[2*(*node)]-coords[2*tmpOut.back()]; tmp2[1]=coords[2*(*node)+1]-coords[2*tmpOut.back()+1]; + double angleM=INTERP_KERNEL::EdgeArcCircle::GetAbsoluteAngle(tmp2,tmp1); + double res; + if(angleM<=angle0) + res=angle0-angleM; + else + res=angle0-angleM+2.*M_PI; + if(res tmp3(2*(sz-1)); + std::vector::iterator it=std::copy(nodalConnBg+1,nodalConnEnd,tmp3.begin()); + std::copy(nodalConnBg+1,nodalConnEnd,it); + if(std::search(tmp3.begin(),tmp3.end(),tmpOut.begin(),tmpOut.end())!=tmp3.end()) + { + nodalConnecOut->insertAtTheEnd(nodalConnBg,nodalConnEnd); + return false; + } + if(std::search(tmp3.rbegin(),tmp3.rend(),tmpOut.begin(),tmpOut.end())!=tmp3.rend()) + { + nodalConnecOut->insertAtTheEnd(nodalConnBg,nodalConnEnd); + return false; + } + else + { + nodalConnecOut->pushBackSilent((int)INTERP_KERNEL::NORM_POLYGON); + nodalConnecOut->insertAtTheEnd(tmpOut.begin(),tmpOut.end()); + return true; + } + } + else + throw INTERP_KERNEL::Exception("MEDCouplingUMesh::BuildConvexEnvelopOf2DCellJarvis : invalid 2D cell connectivity !"); + } + else + throw INTERP_KERNEL::Exception("MEDCouplingUMesh::BuildConvexEnvelopOf2DCellJarvis : invalid 2D cell connectivity !"); +} + +/*! + * This method works on an input pair (\b arr, \b arrIndx) where \b arr indexes is in \b arrIndx. + * This method will not impact the size of inout parameter \b arrIndx but the size of \b arr will be modified in case of suppression. + * + * \param [in] idsToRemoveBg begin of set of ids to remove in \b arr (included) + * \param [in] idsToRemoveEnd end of set of ids to remove in \b arr (excluded) + * \param [in,out] arr array in which the remove operation will be done. + * \param [in,out] arrIndx array in the remove operation will modify + * \param [in] offsetForRemoval (by default 0) offset so that for each i in [0,arrIndx->getNumberOfTuples()-1) removal process will be performed in the following range [arr+arrIndx[i]+offsetForRemoval,arr+arr[i+1]) + * \return true if \b arr and \b arrIndx have been modified, false if not. + */ +bool MEDCouplingUMesh::RemoveIdsFromIndexedArrays(const int *idsToRemoveBg, const int *idsToRemoveEnd, DataArrayInt *arr, DataArrayInt *arrIndx, int offsetForRemoval) +{ + if(!arrIndx || !arr) + throw INTERP_KERNEL::Exception("MEDCouplingUMesh::RemoveIdsFromIndexedArrays : some input arrays are empty !"); + if(offsetForRemoval<0) + throw INTERP_KERNEL::Exception("MEDCouplingUMesh::RemoveIdsFromIndexedArrays : offsetForRemoval should be >=0 !"); + std::set s(idsToRemoveBg,idsToRemoveEnd); + int nbOfGrps=arrIndx->getNumberOfTuples()-1; + int *arrIPtr=arrIndx->getPointer(); + *arrIPtr++=0; + int previousArrI=0; + const int *arrPtr=arr->getConstPointer(); + std::vector arrOut;//no utility to switch to DataArrayInt because copy always needed + for(int i=0;ioffsetForRemoval) + { + for(const int *work=arrPtr+previousArrI+offsetForRemoval;work!=arrPtr+*arrIPtr;work++) + { + if(s.find(*work)==s.end()) + arrOut.push_back(*work); + } + } + previousArrI=*arrIPtr; + *arrIPtr=(int)arrOut.size(); + } + if(arr->getNumberOfTuples()==(int)arrOut.size()) + return false; + arr->alloc((int)arrOut.size(),1); + std::copy(arrOut.begin(),arrOut.end(),arr->getPointer()); + return true; +} + +/*! + * This method works on a pair input (\b arrIn, \b arrIndxIn) where \b arrIn indexes is in \b arrIndxIn + * (\ref numbering-indirect). + * This method returns the result of the extraction ( specified by a set of ids in [\b idsOfSelectBg , \b idsOfSelectEnd ) ). + * The selection of extraction is done standardly in new2old format. + * This method returns indexed arrays (\ref numbering-indirect) using 2 arrays (arrOut,arrIndexOut). + * + * \param [in] idsOfSelectBg begin of set of ids of the input extraction (included) + * \param [in] idsOfSelectEnd end of set of ids of the input extraction (excluded) + * \param [in] arrIn arr origin array from which the extraction will be done. + * \param [in] arrIndxIn is the input index array allowing to walk into \b arrIn + * \param [out] arrOut the resulting array + * \param [out] arrIndexOut the index array of the resulting array \b arrOut + * \sa MEDCouplingUMesh::ExtractFromIndexedArrays2 + */ +void MEDCouplingUMesh::ExtractFromIndexedArrays(const int *idsOfSelectBg, const int *idsOfSelectEnd, const DataArrayInt *arrIn, const DataArrayInt *arrIndxIn, + DataArrayInt* &arrOut, DataArrayInt* &arrIndexOut) +{ + if(!arrIn || !arrIndxIn) + throw INTERP_KERNEL::Exception("MEDCouplingUMesh::ExtractFromIndexedArrays : input pointer is NULL !"); + arrIn->checkAllocated(); arrIndxIn->checkAllocated(); + if(arrIn->getNumberOfComponents()!=1 || arrIndxIn->getNumberOfComponents()!=1) + throw INTERP_KERNEL::Exception("MEDCouplingUMesh::ExtractFromIndexedArrays : input arrays must have exactly one component !"); + std::size_t sz=std::distance(idsOfSelectBg,idsOfSelectEnd); + const int *arrInPtr=arrIn->getConstPointer(); + const int *arrIndxPtr=arrIndxIn->getConstPointer(); + int nbOfGrps=arrIndxIn->getNumberOfTuples()-1; + if(nbOfGrps<0) + throw INTERP_KERNEL::Exception("MEDCouplingUMesh::ExtractFromIndexedArrays : The format of \"arrIndxIn\" is invalid ! Its nb of tuples should be >=1 !"); + int maxSizeOfArr=arrIn->getNumberOfTuples(); + MEDCouplingAutoRefCountObjectPtr arro=DataArrayInt::New(); + MEDCouplingAutoRefCountObjectPtr arrIo=DataArrayInt::New(); + arrIo->alloc((int)(sz+1),1); + const int *idsIt=idsOfSelectBg; + int *work=arrIo->getPointer(); + *work++=0; + int lgth=0; + for(std::size_t i=0;i=0 && *idsIt=work[-1]) + *work=lgth; + else + { + std::ostringstream oss; oss << "MEDCouplingUMesh::ExtractFromIndexedArrays : id located on pos #" << i << " value is " << *idsIt << " and at this pos arrIndxIn[" << *idsIt; + oss << "+1]-arrIndxIn[" << *idsIt << "] < 0 ! The input index array is bugged !"; + throw INTERP_KERNEL::Exception(oss.str().c_str()); + } + } + arro->alloc(lgth,1); + work=arro->getPointer(); + idsIt=idsOfSelectBg; + for(std::size_t i=0;i=0 && arrIndxPtr[*idsIt+1]<=maxSizeOfArr) + work=std::copy(arrInPtr+arrIndxPtr[*idsIt],arrInPtr+arrIndxPtr[*idsIt+1],work); + else + { + std::ostringstream oss; oss << "MEDCouplingUMesh::ExtractFromIndexedArrays : id located on pos #" << i << " value is " << *idsIt << " arrIndx[" << *idsIt << "] must be >= 0 and arrIndx["; + oss << *idsIt << "+1] <= " << maxSizeOfArr << " (the size of arrIn)!"; + throw INTERP_KERNEL::Exception(oss.str().c_str()); + } + } + arrOut=arro.retn(); + arrIndexOut=arrIo.retn(); +} + +/*! + * This method works on a pair input (\b arrIn, \b arrIndxIn) where \b arrIn indexes is in \b arrIndxIn + * (\ref numbering-indirect). + * This method returns the result of the extraction ( specified by a set of ids with a slice given by \a idsOfSelectStart, \a idsOfSelectStop and \a idsOfSelectStep ). + * The selection of extraction is done standardly in new2old format. + * This method returns indexed arrays (\ref numbering-indirect) using 2 arrays (arrOut,arrIndexOut). + * + * \param [in] idsOfSelectStart begin of set of ids of the input extraction (included) + * \param [in] idsOfSelectStop end of set of ids of the input extraction (excluded) + * \param [in] idsOfSelectStep + * \param [in] arrIn arr origin array from which the extraction will be done. + * \param [in] arrIndxIn is the input index array allowing to walk into \b arrIn + * \param [out] arrOut the resulting array + * \param [out] arrIndexOut the index array of the resulting array \b arrOut + * \sa MEDCouplingUMesh::ExtractFromIndexedArrays + */ +void MEDCouplingUMesh::ExtractFromIndexedArrays2(int idsOfSelectStart, int idsOfSelectStop, int idsOfSelectStep, const DataArrayInt *arrIn, const DataArrayInt *arrIndxIn, + DataArrayInt* &arrOut, DataArrayInt* &arrIndexOut) +{ + if(!arrIn || !arrIndxIn) + throw INTERP_KERNEL::Exception("MEDCouplingUMesh::ExtractFromIndexedArrays2 : input pointer is NULL !"); + arrIn->checkAllocated(); arrIndxIn->checkAllocated(); + if(arrIn->getNumberOfComponents()!=1 || arrIndxIn->getNumberOfComponents()!=1) + throw INTERP_KERNEL::Exception("MEDCouplingUMesh::ExtractFromIndexedArrays2 : input arrays must have exactly one component !"); + int sz=DataArrayInt::GetNumberOfItemGivenBESRelative(idsOfSelectStart,idsOfSelectStop,idsOfSelectStep,"MEDCouplingUMesh::ExtractFromIndexedArrays2 : Input slice "); + const int *arrInPtr=arrIn->getConstPointer(); + const int *arrIndxPtr=arrIndxIn->getConstPointer(); + int nbOfGrps=arrIndxIn->getNumberOfTuples()-1; + if(nbOfGrps<0) + throw INTERP_KERNEL::Exception("MEDCouplingUMesh::ExtractFromIndexedArrays2 : The format of \"arrIndxIn\" is invalid ! Its nb of tuples should be >=1 !"); + int maxSizeOfArr=arrIn->getNumberOfTuples(); + MEDCouplingAutoRefCountObjectPtr arro=DataArrayInt::New(); + MEDCouplingAutoRefCountObjectPtr arrIo=DataArrayInt::New(); + arrIo->alloc((int)(sz+1),1); + int idsIt=idsOfSelectStart; + int *work=arrIo->getPointer(); + *work++=0; + int lgth=0; + for(int i=0;i=0 && idsIt=work[-1]) + *work=lgth; + else + { + std::ostringstream oss; oss << "MEDCouplingUMesh::ExtractFromIndexedArrays2 : id located on pos #" << i << " value is " << idsIt << " and at this pos arrIndxIn[" << idsIt; + oss << "+1]-arrIndxIn[" << idsIt << "] < 0 ! The input index array is bugged !"; + throw INTERP_KERNEL::Exception(oss.str().c_str()); + } + } + arro->alloc(lgth,1); + work=arro->getPointer(); + idsIt=idsOfSelectStart; + for(int i=0;i=0 && arrIndxPtr[idsIt+1]<=maxSizeOfArr) + work=std::copy(arrInPtr+arrIndxPtr[idsIt],arrInPtr+arrIndxPtr[idsIt+1],work); + else + { + std::ostringstream oss; oss << "MEDCouplingUMesh::ExtractFromIndexedArrays2 : id located on pos #" << i << " value is " << idsIt << " arrIndx[" << idsIt << "] must be >= 0 and arrIndx["; + oss << idsIt << "+1] <= " << maxSizeOfArr << " (the size of arrIn)!"; + throw INTERP_KERNEL::Exception(oss.str().c_str()); + } + } + arrOut=arro.retn(); + arrIndexOut=arrIo.retn(); +} + +/*! + * This method works on an input pair (\b arrIn, \b arrIndxIn) where \b arrIn indexes is in \b arrIndxIn. + * This method builds an output pair (\b arrOut,\b arrIndexOut) that is a copy from \b arrIn for all cell ids \b not \b in [ \b idsOfSelectBg , \b idsOfSelectEnd ) and for + * cellIds \b in [ \b idsOfSelectBg , \b idsOfSelectEnd ) a copy coming from the corresponding values in input pair (\b srcArr, \b srcArrIndex). + * This method is an generalization of MEDCouplingUMesh::SetPartOfIndexedArraysSameIdx that performs the same thing but by without building explicitely a result output arrays. + * + * \param [in] idsOfSelectBg begin of set of ids of the input extraction (included) + * \param [in] idsOfSelectEnd end of set of ids of the input extraction (excluded) + * \param [in] arrIn arr origin array from which the extraction will be done. + * \param [in] arrIndxIn is the input index array allowing to walk into \b arrIn + * \param [in] srcArr input array that will be used as source of copy for ids in [ \b idsOfSelectBg, \b idsOfSelectEnd ) + * \param [in] srcArrIndex index array of \b srcArr + * \param [out] arrOut the resulting array + * \param [out] arrIndexOut the index array of the resulting array \b arrOut + * + * \sa MEDCouplingUMesh::SetPartOfIndexedArraysSameIdx + */ +void MEDCouplingUMesh::SetPartOfIndexedArrays(const int *idsOfSelectBg, const int *idsOfSelectEnd, const DataArrayInt *arrIn, const DataArrayInt *arrIndxIn, + const DataArrayInt *srcArr, const DataArrayInt *srcArrIndex, + DataArrayInt* &arrOut, DataArrayInt* &arrIndexOut) +{ + if(arrIn==0 || arrIndxIn==0 || srcArr==0 || srcArrIndex==0) + throw INTERP_KERNEL::Exception("MEDCouplingUMesh::SetPartOfIndexedArrays : presence of null pointer in input parameter !"); + MEDCouplingAutoRefCountObjectPtr arro=DataArrayInt::New(); + MEDCouplingAutoRefCountObjectPtr arrIo=DataArrayInt::New(); + int nbOfTuples=arrIndxIn->getNumberOfTuples()-1; + std::vector v(nbOfTuples,true); + int offset=0; + const int *arrIndxInPtr=arrIndxIn->getConstPointer(); + const int *srcArrIndexPtr=srcArrIndex->getConstPointer(); + for(const int *it=idsOfSelectBg;it!=idsOfSelectEnd;it++,srcArrIndexPtr++) + { + if(*it>=0 && *itgetConstPointer(); + arrIo->alloc(nbOfTuples+1,1); + arro->alloc(arrIn->getNumberOfTuples()+offset,1); + const int *arrInPtr=arrIn->getConstPointer(); + const int *srcArrPtr=srcArr->getConstPointer(); + int *arrIoPtr=arrIo->getPointer(); *arrIoPtr++=0; + int *arroPtr=arro->getPointer(); + for(int ii=0;iigetNumberOfTuples()-1; + const int *arrIndxInPtr=arrIndxIn->getConstPointer(); + const int *srcArrIndexPtr=srcArrIndex->getConstPointer(); + int *arrInOutPtr=arrInOut->getPointer(); + const int *srcArrPtr=srcArr->getConstPointer(); + for(const int *it=idsOfSelectBg;it!=idsOfSelectEnd;it++,srcArrIndexPtr++) + { + if(*it>=0 && *itgetNumberOfTuples()-1. + * + * \param [in] arrIn arr origin array from which the extraction will be done. + * \param [in] arrIndxIn is the input index array allowing to walk into \b arrIn + * \return a newly allocated DataArray that stores all ids fetched by the gradually spread process. + * \sa MEDCouplingUMesh::ComputeSpreadZoneGraduallyFromSeed, MEDCouplingUMesh::partitionBySpreadZone + */ +DataArrayInt *MEDCouplingUMesh::ComputeSpreadZoneGradually(const DataArrayInt *arrIn, const DataArrayInt *arrIndxIn) +{ + int seed=0,nbOfDepthPeelingPerformed=0; + return ComputeSpreadZoneGraduallyFromSeed(&seed,&seed+1,arrIn,arrIndxIn,-1,nbOfDepthPeelingPerformed); +} + +/*! + * This method works on a pair input (\b arrIn, \b arrIndxIn) where \b arr indexes is in \b arrIndxIn. + * This method expects that these two input arrays come from the output of MEDCouplingUMesh::computeNeighborsOfCells method. + * This method start from id 0 that will be contained in output DataArrayInt. It searches then all neighbors of id0 regarding arrIn[arrIndxIn[0]:arrIndxIn[0+1]]. + * Then it is repeated recursively until either all ids are fetched or no more ids are reachable step by step. + * A negative value in \b arrIn means that it is ignored. + * This method is useful to see if a mesh is contiguous regarding its connectivity. If it is not the case the size of returned array is different from arrIndxIn->getNumberOfTuples()-1. + * \param [in] seedBg the begin pointer (included) of an array containing the seed of the search zone + * \param [in] seedEnd the end pointer (not included) of an array containing the seed of the search zone + * \param [in] arrIn arr origin array from which the extraction will be done. + * \param [in] arrIndxIn is the input index array allowing to walk into \b arrIn + * \param [in] nbOfDepthPeeling the max number of peels requested in search. By default -1, that is to say, no limit. + * \param [out] nbOfDepthPeelingPerformed the number of peels effectively performed. May be different from \a nbOfDepthPeeling + * \return a newly allocated DataArray that stores all ids fetched by the gradually spread process. + * \sa MEDCouplingUMesh::partitionBySpreadZone + */ +DataArrayInt *MEDCouplingUMesh::ComputeSpreadZoneGraduallyFromSeed(const int *seedBg, const int *seedEnd, const DataArrayInt *arrIn, const DataArrayInt *arrIndxIn, int nbOfDepthPeeling, int& nbOfDepthPeelingPerformed) +{ + nbOfDepthPeelingPerformed=0; + if(!arrIndxIn) + throw INTERP_KERNEL::Exception("MEDCouplingUMesh::ComputeSpreadZoneGraduallyFromSeed : arrIndxIn input pointer is NULL !"); + int nbOfTuples=arrIndxIn->getNumberOfTuples()-1; + if(nbOfTuples<=0) + { + DataArrayInt *ret=DataArrayInt::New(); ret->alloc(0,1); + return ret; + } + // + std::vector fetched(nbOfTuples,false); + return ComputeSpreadZoneGraduallyFromSeedAlg(fetched,seedBg,seedEnd,arrIn,arrIndxIn,nbOfDepthPeeling,nbOfDepthPeelingPerformed); +} + +DataArrayInt *MEDCouplingUMesh::ComputeSpreadZoneGraduallyFromSeedAlg(std::vector& fetched, const int *seedBg, const int *seedEnd, const DataArrayInt *arrIn, const DataArrayInt *arrIndxIn, int nbOfDepthPeeling, int& nbOfDepthPeelingPerformed) +{ + nbOfDepthPeelingPerformed=0; + if(!seedBg || !seedEnd || !arrIn || !arrIndxIn) + throw INTERP_KERNEL::Exception("MEDCouplingUMesh::ComputeSpreadZoneGraduallyFromSeedAlg : some input pointer is NULL !"); + int nbOfTuples=arrIndxIn->getNumberOfTuples()-1; + std::vector fetched2(nbOfTuples,false); + int i=0; + for(const int *seedElt=seedBg;seedElt!=seedEnd;seedElt++,i++) + { + if(*seedElt>=0 && *seedEltgetConstPointer(); + const int *arrIndxPtr=arrIndxIn->getConstPointer(); + int targetNbOfDepthPeeling=nbOfDepthPeeling!=-1?nbOfDepthPeeling:std::numeric_limits::max(); + std::vector idsToFetch1(seedBg,seedEnd); + std::vector idsToFetch2; + std::vector *idsToFetch=&idsToFetch1; + std::vector *idsToFetchOther=&idsToFetch2; + while(!idsToFetch->empty() && nbOfDepthPeelingPerformed::const_iterator it=idsToFetch->begin();it!=idsToFetch->end();it++) + for(const int *it2=arrInPtr+arrIndxPtr[*it];it2!=arrInPtr+arrIndxPtr[*it+1];it2++) + if(!fetched[*it2]) + { fetched[*it2]=true; fetched2[*it2]=true; idsToFetchOther->push_back(*it2); } + std::swap(idsToFetch,idsToFetchOther); + idsToFetchOther->clear(); + nbOfDepthPeelingPerformed++; + } + int lgth=(int)std::count(fetched2.begin(),fetched2.end(),true); + i=0; + MEDCouplingAutoRefCountObjectPtr ret=DataArrayInt::New(); ret->alloc(lgth,1); + int *retPtr=ret->getPointer(); + for(std::vector::const_iterator it=fetched2.begin();it!=fetched2.end();it++,i++) + if(*it) + *retPtr++=i; + return ret.retn(); +} + +/*! + * This method works on an input pair (\b arrIn, \b arrIndxIn) where \b arrIn indexes is in \b arrIndxIn. + * This method builds an output pair (\b arrOut,\b arrIndexOut) that is a copy from \b arrIn for all cell ids \b not \b in [ \b idsOfSelectBg , \b idsOfSelectEnd ) and for + * cellIds \b in [\b idsOfSelectBg, \b idsOfSelectEnd) a copy coming from the corresponding values in input pair (\b srcArr, \b srcArrIndex). + * This method is an generalization of MEDCouplingUMesh::SetPartOfIndexedArraysSameIdx that performs the same thing but by without building explicitely a result output arrays. + * + * \param [in] start begin of set of ids of the input extraction (included) + * \param [in] end end of set of ids of the input extraction (excluded) + * \param [in] step step of the set of ids in range mode. + * \param [in] arrIn arr origin array from which the extraction will be done. + * \param [in] arrIndxIn is the input index array allowing to walk into \b arrIn + * \param [in] srcArr input array that will be used as source of copy for ids in [\b idsOfSelectBg, \b idsOfSelectEnd) + * \param [in] srcArrIndex index array of \b srcArr + * \param [out] arrOut the resulting array + * \param [out] arrIndexOut the index array of the resulting array \b arrOut + * + * \sa MEDCouplingUMesh::SetPartOfIndexedArraysSameIdx MEDCouplingUMesh::SetPartOfIndexedArrays + */ +void MEDCouplingUMesh::SetPartOfIndexedArrays2(int start, int end, int step, const DataArrayInt *arrIn, const DataArrayInt *arrIndxIn, + const DataArrayInt *srcArr, const DataArrayInt *srcArrIndex, + DataArrayInt* &arrOut, DataArrayInt* &arrIndexOut) +{ + if(arrIn==0 || arrIndxIn==0 || srcArr==0 || srcArrIndex==0) + throw INTERP_KERNEL::Exception("MEDCouplingUMesh::SetPartOfIndexedArrays2 : presence of null pointer in input parameter !"); + MEDCouplingAutoRefCountObjectPtr arro=DataArrayInt::New(); + MEDCouplingAutoRefCountObjectPtr arrIo=DataArrayInt::New(); + int nbOfTuples=arrIndxIn->getNumberOfTuples()-1; + int offset=0; + const int *arrIndxInPtr=arrIndxIn->getConstPointer(); + const int *srcArrIndexPtr=srcArrIndex->getConstPointer(); + int nbOfElemsToSet=DataArray::GetNumberOfItemGivenBESRelative(start,end,step,"MEDCouplingUMesh::SetPartOfIndexedArrays2 : "); + int it=start; + for(int i=0;i=0 && itgetConstPointer(); + arrIo->alloc(nbOfTuples+1,1); + arro->alloc(arrIn->getNumberOfTuples()+offset,1); + const int *arrInPtr=arrIn->getConstPointer(); + const int *srcArrPtr=srcArr->getConstPointer(); + int *arrIoPtr=arrIo->getPointer(); *arrIoPtr++=0; + int *arroPtr=arro->getPointer(); + for(int ii=0;iigetNumberOfTuples()-1; + const int *arrIndxInPtr=arrIndxIn->getConstPointer(); + const int *srcArrIndexPtr=srcArrIndex->getConstPointer(); + int *arrInOutPtr=arrInOut->getPointer(); + const int *srcArrPtr=srcArr->getConstPointer(); + int nbOfElemsToSet=DataArray::GetNumberOfItemGivenBESRelative(start,end,step,"MEDCouplingUMesh::SetPartOfIndexedArraysSameIdx2 : "); + int it=start; + for(int i=0;i=0 && it partition=partitionBySpreadZone(); + std::vector< MEDCouplingAutoRefCountObjectPtr > partitionAuto; partitionAuto.reserve(partition.size()); + std::copy(partition.begin(),partition.end(),std::back_insert_iterator > >(partitionAuto)); + MEDCouplingAutoRefCountObjectPtr ret=MEDCouplingUMesh::New(getName(),mdim); + ret->setCoords(getCoords()); + ret->allocateCells((int)partition.size()); + // + for(std::vector::const_iterator it=partition.begin();it!=partition.end();it++) + { + MEDCouplingAutoRefCountObjectPtr tmp=static_cast(buildPartOfMySelf((*it)->begin(),(*it)->end(),true)); + MEDCouplingAutoRefCountObjectPtr cell; + switch(mdim) + { + case 2: + cell=tmp->buildUnionOf2DMesh(); + break; + case 3: + cell=tmp->buildUnionOf3DMesh(); + break; + default: + throw INTERP_KERNEL::Exception("MEDCouplingUMesh::buildSpreadZonesWithPoly : meshdimension supported are [2,3] ! Not implemented yet for others !"); + } + + ret->insertNextCell((INTERP_KERNEL::NormalizedCellType)cell->getIJSafe(0,0),cell->getNumberOfTuples()-1,cell->getConstPointer()+1); + } + // + ret->finishInsertingCells(); + return ret.retn(); +} + +/*! + * This method partitions \b this into contiguous zone. + * This method only needs a well defined connectivity. Coordinates are not considered here. + * This method returns a vector of \b newly allocated arrays that the caller has to deal with. + */ +std::vector MEDCouplingUMesh::partitionBySpreadZone() const +{ + int nbOfCellsCur=getNumberOfCells(); + std::vector ret; + if(nbOfCellsCur<=0) + return ret; + DataArrayInt *neigh=0,*neighI=0; + computeNeighborsOfCells(neigh,neighI); + MEDCouplingAutoRefCountObjectPtr neighAuto(neigh),neighIAuto(neighI); + std::vector fetchedCells(nbOfCellsCur,false); + std::vector< MEDCouplingAutoRefCountObjectPtr > ret2; + int seed=0; + while(seed >::iterator it=ret2.begin();it!=ret2.end();it++) + ret.push_back((*it).retn()); + return ret; +} + +/*! + * This method returns given a distribution of cell type (returned for example by MEDCouplingUMesh::getDistributionOfTypes method and customized after) a + * newly allocated DataArrayInt instance with 2 components ready to be interpreted as input of DataArrayInt::findRangeIdForEachTuple method. + * + * \param [in] code a code with the same format than those returned by MEDCouplingUMesh::getDistributionOfTypes except for the code[3*k+2] that should contain start id of chunck. + * \return a newly allocated DataArrayInt to be managed by the caller. + * \throw In case of \a code has not the right format (typically of size 3*n) + */ +DataArrayInt *MEDCouplingUMesh::ComputeRangesFromTypeDistribution(const std::vector& code) +{ + MEDCouplingAutoRefCountObjectPtr ret=DataArrayInt::New(); + std::size_t nb=code.size()/3; + if(code.size()%3!=0) + throw INTERP_KERNEL::Exception("MEDCouplingUMesh::ComputeRangesFromTypeDistribution : invalid input code !"); + ret->alloc((int)nb,2); + int *retPtr=ret->getPointer(); + for(std::size_t i=0;i 0, the coordinates array in returned mesh will have \a nbOfAdditionalPoints + * more tuples (nodes) than in \a this. Anyway, all the nodes in \a this (with the same order) will be in the returned mesh. + * + * \param [in] policy - the policy of splitting that must be in (PLANAR_FACE_5, PLANAR_FACE_6, GENERAL_24, GENERAL_48). The policy will be used only for INTERP_KERNEL::NORM_HEXA8 cells. + * For all other cells, the splitting policy will be ignored. See INTERP_KERNEL::SplittingPolicy for the images. + * \param [out] nbOfAdditionalPoints - number of nodes added to \c this->_coords. If > 0 a new coordinates object will be constructed result of the aggregation of the old one and the new points added. + * \param [out] n2oCells - A new instance of DataArrayInt holding, for each new cell, + * an id of old cell producing it. The caller is to delete this array using + * decrRef() as it is no more needed. + * \return MEDCoupling1SGTUMesh * - the mesh containing only INTERP_KERNEL::NORM_TETRA4 cells. + * + * \warning This method operates on each cells in this independantly ! So it can leads to non conform mesh in returned value ! If you expect to have a conform mesh in output + * the policy PLANAR_FACE_6 should be used on a mesh sorted with MEDCoupling1SGTUMesh::sortHexa8EachOther. + * + * \throw If \a this is not a 3D mesh (spaceDim==3 and meshDim==3). + * \throw If \a this is not fully constituted with linear 3D cells. + * \sa MEDCouplingUMesh::simplexize, MEDCoupling1SGTUMesh::sortHexa8EachOther + */ +MEDCoupling1SGTUMesh *MEDCouplingUMesh::tetrahedrize(int policy, DataArrayInt *& n2oCells, int& nbOfAdditionalPoints) const +{ + INTERP_KERNEL::SplittingPolicy pol((INTERP_KERNEL::SplittingPolicy)policy); + checkConnectivityFullyDefined(); + if(getMeshDimension()!=3 || getSpaceDimension()!=3) + throw INTERP_KERNEL::Exception("MEDCouplingUMesh::tetrahedrize : only available for mesh with meshdim == 3 and spacedim == 3 !"); + int nbOfCells(getNumberOfCells()),nbNodes(getNumberOfNodes()); + MEDCouplingAutoRefCountObjectPtr ret0(MEDCoupling1SGTUMesh::New(getName(),INTERP_KERNEL::NORM_TETRA4)); + MEDCouplingAutoRefCountObjectPtr ret(DataArrayInt::New()); ret->alloc(nbOfCells,1); + int *retPt(ret->getPointer()); + MEDCouplingAutoRefCountObjectPtr newConn(DataArrayInt::New()); newConn->alloc(0,1); + MEDCouplingAutoRefCountObjectPtr addPts(DataArrayDouble::New()); addPts->alloc(0,1); + const int *oldc(_nodal_connec->begin()); + const int *oldci(_nodal_connec_index->begin()); + const double *coords(_coords->begin()); + for(int i=0;i a; std::vector b; + INTERP_KERNEL::SplitIntoTetras(pol,(INTERP_KERNEL::NormalizedCellType)oldc[oldci[0]],oldc+oldci[0]+1,oldc+oldci[1],coords,a,b); + std::size_t nbOfTet(a.size()/4); *retPt=(int)nbOfTet; + const int *aa(&a[0]); + if(!b.empty()) + { + for(std::vector::iterator it=a.begin();it!=a.end();it++) + if(*it<0) + *it=(-(*(it))-1+nbNodes); + addPts->insertAtTheEnd(b.begin(),b.end()); + nbNodes+=(int)b.size()/3; + } + for(std::size_t j=0;jinsertAtTheEnd(aa,aa+4); + } + if(!addPts->empty()) + { + addPts->rearrange(3); + nbOfAdditionalPoints=addPts->getNumberOfTuples(); + addPts=DataArrayDouble::Aggregate(getCoords(),addPts); + ret0->setCoords(addPts); + } + else + { + nbOfAdditionalPoints=0; + ret0->setCoords(getCoords()); + } + ret0->setNodalConnectivity(newConn); + // + ret->computeOffsets2(); + n2oCells=ret->buildExplicitArrOfSliceOnScaledArr(0,nbOfCells,1); + return ret0.retn(); +} + +/*! + * It is the linear part of MEDCouplingUMesh::split2DCells. Here no additionnal nodes will be added in \b this. So coordinates pointer remain unchanged (is not even touch). + * + * \sa MEDCouplingUMesh::split2DCells + */ +void MEDCouplingUMesh::split2DCellsLinear(const DataArrayInt *desc, const DataArrayInt *descI, const DataArrayInt *subNodesInSeg, const DataArrayInt *subNodesInSegI) +{ + checkConnectivityFullyDefined(); + int ncells(getNumberOfCells()),lgthToReach(getMeshLength()+subNodesInSeg->getNumberOfTuples()); + MEDCouplingAutoRefCountObjectPtr c(DataArrayInt::New()); c->alloc((std::size_t)lgthToReach); + const int *subPtr(subNodesInSeg->begin()),*subIPtr(subNodesInSegI->begin()),*descPtr(desc->begin()),*descIPtr(descI->begin()),*oldConn(getNodalConnectivity()->begin()); + int *cPtr(c->getPointer()),*ciPtr(getNodalConnectivityIndex()->getPointer()); + int prevPosOfCi(ciPtr[0]); + for(int i=0;iend()!=cPtr) + throw INTERP_KERNEL::Exception("MEDCouplingUMesh::split2DCellsLinear : Some of edges to be split are orphan !"); + _nodal_connec->decrRef(); + _nodal_connec=c.retn(); _types.clear(); _types.insert(INTERP_KERNEL::NORM_POLYGON); +} + +int InternalAddPoint(const INTERP_KERNEL::Edge *e, int id, const double *coo, int startId, int endId, DataArrayDouble& addCoo, int& nodesCnter) +{ + if(id!=-1) + return id; + else + { + int ret(nodesCnter++); + double newPt[2]; + e->getMiddleOfPoints(coo+2*startId,coo+2*endId,newPt); + addCoo.insertAtTheEnd(newPt,newPt+2); + return ret; + } +} + +int InternalAddPointOriented(const INTERP_KERNEL::Edge *e, int id, const double *coo, int startId, int endId, DataArrayDouble& addCoo, int& nodesCnter) +{ + if(id!=-1) + return id; + else + { + int ret(nodesCnter++); + double newPt[2]; + e->getMiddleOfPointsOriented(coo+2*startId,coo+2*endId,newPt); + addCoo.insertAtTheEnd(newPt,newPt+2); + return ret; + } +} + + +/// @cond INTERNAL + +void EnterTheResultOf2DCellFirst(const INTERP_KERNEL::Edge *e, int start, int stp, int nbOfEdges, bool linOrArc, const double *coords, const int *connBg, int offset, DataArrayInt *newConnOfCell, DataArrayDouble *appendedCoords, std::vector& middles) +{ + int tmp[3]; + int trueStart(start>=0?start:nbOfEdges+start); + tmp[0]=linOrArc?(int)INTERP_KERNEL::NORM_QPOLYG:(int)INTERP_KERNEL::NORM_POLYGON; tmp[1]=connBg[trueStart]; tmp[2]=connBg[stp]; + newConnOfCell->insertAtTheEnd(tmp,tmp+3); + if(linOrArc) + { + if(stp-start>1) + { + int tmp2(0),tmp3(appendedCoords->getNumberOfTuples()/2); + InternalAddPointOriented(e,-1,coords,tmp[1],tmp[2],*appendedCoords,tmp2); + middles.push_back(tmp3+offset); + } + else + middles.push_back(connBg[trueStart+nbOfEdges]); + } +} + +void EnterTheResultOf2DCellMiddle(const INTERP_KERNEL::Edge *e, int start, int stp, int nbOfEdges, bool linOrArc, const double *coords, const int *connBg, int offset, DataArrayInt *newConnOfCell, DataArrayDouble *appendedCoords, std::vector& middles) +{ + int tmpSrt(newConnOfCell->back()),tmpEnd(connBg[stp]); + newConnOfCell->pushBackSilent(tmpEnd); + if(linOrArc) + { + if(stp-start>1) + { + int tmp2(0),tmp3(appendedCoords->getNumberOfTuples()/2); + InternalAddPointOriented(e,-1,coords,tmpSrt,tmpEnd,*appendedCoords,tmp2); + middles.push_back(tmp3+offset); + } + else + middles.push_back(connBg[start+nbOfEdges]); + } +} + +void EnterTheResultOf2DCellEnd(const INTERP_KERNEL::Edge *e, int start, int stp, int nbOfEdges, bool linOrArc, const double *coords, const int *connBg, int offset, DataArrayInt *newConnOfCell, DataArrayDouble *appendedCoords, std::vector& middles) +{ + // only the quadratic point to deal with: + if(linOrArc) + { + if(stp-start>1) + { + int tmpSrt(connBg[start]),tmpEnd(connBg[stp]); + int tmp2(0),tmp3(appendedCoords->getNumberOfTuples()/2); + InternalAddPointOriented(e,-1,coords,tmpSrt,tmpEnd,*appendedCoords,tmp2); + middles.push_back(tmp3+offset); + } + else + middles.push_back(connBg[start+nbOfEdges]); + } +} + +/// @endcond + +/*! + * Returns true if a colinearization has been found in the given cell. If false is returned the content pushed in \a newConnOfCell is equal to [ \a connBg , \a connEnd ) . + * \a appendedCoords is a DataArrayDouble instance with number of components equal to one (even if the items are pushed by pair). + */ +bool MEDCouplingUMesh::Colinearize2DCell(const double *coords, const int *connBg, const int *connEnd, int offset, DataArrayInt *newConnOfCell, DataArrayDouble *appendedCoords) +{ + std::size_t sz(std::distance(connBg,connEnd)); + if(sz<3)//3 because 2+1(for the cell type) and 2 is the minimal number of edges of 2D cell. + throw INTERP_KERNEL::Exception("MEDCouplingUMesh::Colinearize2DCell : the input cell has invalid format !"); + sz--; + INTERP_KERNEL::AutoPtr tmpConn(new int[sz]); + const INTERP_KERNEL::CellModel& cm(INTERP_KERNEL::CellModel::GetCellModel((INTERP_KERNEL::NormalizedCellType)connBg[0])); + unsigned nbs(cm.getNumberOfSons2(connBg+1,sz)); + unsigned nbOfHit(0); // number of fusions operated + int posBaseElt(0),posEndElt(0),nbOfTurn(0); + const unsigned int maxNbOfHit = cm.isQuadratic() ? nbs-2 : nbs-3; // a quad cell is authorized to end up with only two edges, a linear one has to keep 3 at least + INTERP_KERNEL::NormalizedCellType typeOfSon; + std::vector middles; + bool ret(false); + for(;(nbOfTurn+nbOfHit),int> m; + INTERP_KERNEL::Edge *e(MEDCouplingUMeshBuildQPFromEdge2(typeOfSon,tmpConn,coords,m)); + posEndElt = posBaseElt+1; + + // Look backward first: are the final edges of the cells colinear with the first ones? + // This initializes posBaseElt. + if(nbOfTurn==0) + { + for(unsigned i=1;iareColinears(); + if(isColinear) + { + nbOfHit++; + posBaseElt--; + ret=true; + } + delete eint; + eCand->decrRef(); + if(!isColinear) + break; + } + } + // Now move forward: + const unsigned fwdStart = (nbOfTurn == 0 ? 0 : posBaseElt); // the first element to be inspected going forward + for(unsigned j=fwdStart+1;jareColinears()); + if(isColinear) + { + nbOfHit++; + posEndElt++; + ret=true; + } + delete eint; + eCand->decrRef(); + if(!isColinear) + break; + } + //push [posBaseElt,posEndElt) in newConnOfCell using e + // The if clauses below are (volontary) not mutually exclusive: on a quad cell with 2 edges, the end of the connectivity is also its begining! + if(nbOfTurn==0) + // at the begining of the connectivity (insert type) + EnterTheResultOf2DCellFirst(e,posBaseElt,posEndElt,(int)nbs,cm.isQuadratic(),coords,connBg+1,offset,newConnOfCell,appendedCoords,middles); + else if((nbOfHit+nbOfTurn) != (nbs-1)) + // in the middle + EnterTheResultOf2DCellMiddle(e,posBaseElt,posEndElt,(int)nbs,cm.isQuadratic(),coords,connBg+1,offset,newConnOfCell,appendedCoords,middles); + if ((nbOfHit+nbOfTurn) == (nbs-1)) + // at the end (only quad points to deal with) + EnterTheResultOf2DCellEnd(e,posBaseElt,posEndElt,(int)nbs,cm.isQuadratic(),coords,connBg+1,offset,newConnOfCell,appendedCoords,middles); + posBaseElt=posEndElt; + e->decrRef(); + } + if(!middles.empty()) + newConnOfCell->insertAtTheEnd(middles.begin(),middles.end()); + return ret; +} + +/*! + * It is the quadratic part of MEDCouplingUMesh::split2DCells. Here some additionnal nodes can be added at the end of coordinates array object. + * + * \return int - the number of new nodes created. + * \sa MEDCouplingUMesh::split2DCells + */ +int MEDCouplingUMesh::split2DCellsQuadratic(const DataArrayInt *desc, const DataArrayInt *descI, const DataArrayInt *subNodesInSeg, const DataArrayInt *subNodesInSegI, const DataArrayInt *mid, const DataArrayInt *midI) +{ + checkCoherency(); + int ncells(getNumberOfCells()),lgthToReach(getMeshLength()+2*subNodesInSeg->getNumberOfTuples()),nodesCnt(getNumberOfNodes()); + MEDCouplingAutoRefCountObjectPtr c(DataArrayInt::New()); c->alloc((std::size_t)lgthToReach); + MEDCouplingAutoRefCountObjectPtr addCoo(DataArrayDouble::New()); addCoo->alloc(0,1); + const int *subPtr(subNodesInSeg->begin()),*subIPtr(subNodesInSegI->begin()),*descPtr(desc->begin()),*descIPtr(descI->begin()),*oldConn(getNodalConnectivity()->begin()); + const int *midPtr(mid->begin()),*midIPtr(midI->begin()); + const double *oldCoordsPtr(getCoords()->begin()); + int *cPtr(c->getPointer()),*ciPtr(getNodalConnectivityIndex()->getPointer()); + int prevPosOfCi(ciPtr[0]); + for(int i=0;i ns(3); + ns[0]=new INTERP_KERNEL::Node(oldCoordsPtr[2*oldConn[prevPosOfCi+1+j]],oldCoordsPtr[2*oldConn[prevPosOfCi+1+j]+1]); + ns[1]=new INTERP_KERNEL::Node(oldCoordsPtr[2*oldConn[prevPosOfCi+1+(1+j)%sz]],oldCoordsPtr[2*oldConn[prevPosOfCi+1+(1+j)%sz]+1]); + ns[2]=new INTERP_KERNEL::Node(oldCoordsPtr[2*oldConn[prevPosOfCi+1+sz+j]],oldCoordsPtr[2*oldConn[prevPosOfCi+1+sz+j]+1]); + MEDCouplingAutoRefCountObjectPtr e(INTERP_KERNEL::QuadraticPolygon::BuildArcCircleEdge(ns)); + for(int k=0;kend()!=cPtr) + throw INTERP_KERNEL::Exception("MEDCouplingUMesh::split2DCellsQuadratic : Some of edges to be split are orphan !"); + _nodal_connec->decrRef(); + _nodal_connec=c.retn(); _types.clear(); _types.insert(INTERP_KERNEL::NORM_QPOLYG); + addCoo->rearrange(2); + MEDCouplingAutoRefCountObjectPtr coo(DataArrayDouble::Aggregate(getCoords(),addCoo));//info are copied from getCoords() by using Aggregate + setCoords(coo); + return addCoo->getNumberOfTuples(); +} + +void MEDCouplingUMesh::ComputeAllTypesInternal(std::set& types, const DataArrayInt *nodalConnec, const DataArrayInt *nodalConnecIndex) +{ + if(nodalConnec && nodalConnecIndex) + { + types.clear(); + const int *conn(nodalConnec->getConstPointer()),*connIndex(nodalConnecIndex->getConstPointer()); + int nbOfElem(nodalConnecIndex->getNbOfElems()-1); + if(nbOfElem>0) + for(const int *pt=connIndex;pt!=connIndex+nbOfElem;pt++) + types.insert((INTERP_KERNEL::NormalizedCellType)conn[*pt]); + } +} + +MEDCouplingUMeshCellIterator::MEDCouplingUMeshCellIterator(MEDCouplingUMesh *mesh):_mesh(mesh),_cell(new MEDCouplingUMeshCell(mesh)), + _own_cell(true),_cell_id(-1),_nb_cell(0) +{ + if(mesh) + { + mesh->incrRef(); + _nb_cell=mesh->getNumberOfCells(); + } +} + +MEDCouplingUMeshCellIterator::~MEDCouplingUMeshCellIterator() +{ + if(_mesh) + _mesh->decrRef(); + if(_own_cell) + delete _cell; +} + +MEDCouplingUMeshCellIterator::MEDCouplingUMeshCellIterator(MEDCouplingUMesh *mesh, MEDCouplingUMeshCell *itc, int bg, int end):_mesh(mesh),_cell(itc), + _own_cell(false),_cell_id(bg-1), + _nb_cell(end) +{ + if(mesh) + mesh->incrRef(); +} + +MEDCouplingUMeshCell *MEDCouplingUMeshCellIterator::nextt() +{ + _cell_id++; + if(_cell_id<_nb_cell) + { + _cell->next(); + return _cell; + } + else + return 0; +} + +MEDCouplingUMeshCellByTypeEntry::MEDCouplingUMeshCellByTypeEntry(MEDCouplingUMesh *mesh):_mesh(mesh) +{ + if(_mesh) + _mesh->incrRef(); +} + +MEDCouplingUMeshCellByTypeIterator *MEDCouplingUMeshCellByTypeEntry::iterator() +{ + return new MEDCouplingUMeshCellByTypeIterator(_mesh); +} + +MEDCouplingUMeshCellByTypeEntry::~MEDCouplingUMeshCellByTypeEntry() +{ + if(_mesh) + _mesh->decrRef(); +} + +MEDCouplingUMeshCellEntry::MEDCouplingUMeshCellEntry(MEDCouplingUMesh *mesh, INTERP_KERNEL::NormalizedCellType type, MEDCouplingUMeshCell *itc, int bg, int end):_mesh(mesh),_type(type), + _itc(itc), + _bg(bg),_end(end) +{ + if(_mesh) + _mesh->incrRef(); +} + +MEDCouplingUMeshCellEntry::~MEDCouplingUMeshCellEntry() +{ + if(_mesh) + _mesh->decrRef(); +} + +INTERP_KERNEL::NormalizedCellType MEDCouplingUMeshCellEntry::getType() const +{ + return _type; +} + +int MEDCouplingUMeshCellEntry::getNumberOfElems() const +{ + return _end-_bg; +} + +MEDCouplingUMeshCellIterator *MEDCouplingUMeshCellEntry::iterator() +{ + return new MEDCouplingUMeshCellIterator(_mesh,_itc,_bg,_end); +} + +MEDCouplingUMeshCellByTypeIterator::MEDCouplingUMeshCellByTypeIterator(MEDCouplingUMesh *mesh):_mesh(mesh),_cell(new MEDCouplingUMeshCell(mesh)),_cell_id(0),_nb_cell(0) +{ + if(mesh) + { + mesh->incrRef(); + _nb_cell=mesh->getNumberOfCells(); + } +} + +MEDCouplingUMeshCellByTypeIterator::~MEDCouplingUMeshCellByTypeIterator() +{ + if(_mesh) + _mesh->decrRef(); + delete _cell; +} + +MEDCouplingUMeshCellEntry *MEDCouplingUMeshCellByTypeIterator::nextt() +{ + const int *c=_mesh->getNodalConnectivity()->getConstPointer(); + const int *ci=_mesh->getNodalConnectivityIndex()->getConstPointer(); + if(_cell_id<_nb_cell) + { + INTERP_KERNEL::NormalizedCellType type=(INTERP_KERNEL::NormalizedCellType)c[ci[_cell_id]]; + int nbOfElems=(int)std::distance(ci+_cell_id,std::find_if(ci+_cell_id,ci+_nb_cell,ParaMEDMEMImpl::ConnReader(c,type))); + int startId=_cell_id; + _cell_id+=nbOfElems; + return new MEDCouplingUMeshCellEntry(_mesh,type,_cell,startId,_cell_id); + } + else + return 0; +} + +MEDCouplingUMeshCell::MEDCouplingUMeshCell(MEDCouplingUMesh *mesh):_conn(0),_conn_indx(0),_conn_lgth(NOTICABLE_FIRST_VAL) +{ + if(mesh) + { + _conn=mesh->getNodalConnectivity()->getPointer(); + _conn_indx=mesh->getNodalConnectivityIndex()->getPointer(); + } +} + +void MEDCouplingUMeshCell::next() +{ + if(_conn_lgth!=NOTICABLE_FIRST_VAL) + { + _conn+=_conn_lgth; + _conn_indx++; + } + _conn_lgth=_conn_indx[1]-_conn_indx[0]; +} + +std::string MEDCouplingUMeshCell::repr() const +{ + if(_conn_lgth!=NOTICABLE_FIRST_VAL) + { + std::ostringstream oss; oss << "Cell Type " << INTERP_KERNEL::CellModel::GetCellModel((INTERP_KERNEL::NormalizedCellType)_conn[0]).getRepr(); + oss << " : "; + std::copy(_conn+1,_conn+_conn_lgth,std::ostream_iterator(oss," ")); + return oss.str(); + } + else + return std::string("MEDCouplingUMeshCell::repr : Invalid pos"); +} + +INTERP_KERNEL::NormalizedCellType MEDCouplingUMeshCell::getType() const +{ + if(_conn_lgth!=NOTICABLE_FIRST_VAL) + return (INTERP_KERNEL::NormalizedCellType)_conn[0]; + else + return INTERP_KERNEL::NORM_ERROR; +} + +const int *MEDCouplingUMeshCell::getAllConn(int& lgth) const +{ + lgth=_conn_lgth; + if(_conn_lgth!=NOTICABLE_FIRST_VAL) + return _conn; + else + return 0; +} diff --cc medtool/src/MEDCoupling_Swig/MEDCouplingExamplesTest.py index 3ebd2170d,000000000..86ee5d767 mode 100644,000000..100644 --- a/medtool/src/MEDCoupling_Swig/MEDCouplingExamplesTest.py +++ b/medtool/src/MEDCoupling_Swig/MEDCouplingExamplesTest.py @@@ -1,2343 -1,0 +1,2345 @@@ +# -*- coding: iso-8859-1 -*- +# Copyright (C) 2007-2015 CEA/DEN, EDF R&D +# +# 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +# +# See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com +# + +from MEDCoupling import * +import unittest +from math import pi, sqrt + +class MEDCouplingBasicsTest(unittest.TestCase): + + def testExample_MEDCouplingFieldDouble_WriteVTK(self): + #! [PySnippet_MEDCouplingFieldDouble_WriteVTK_1] + # mesh + coords = [0.,2.,4.] + coordsArr=DataArrayDouble(coords,3,1) + mesh=MEDCouplingCMesh() + mesh.setCoords(coordsArr,coordsArr) # mesh becomes a 2D one + + # 3 fields (lying on the same mesh!) + field1 = mesh.getMeasureField( True ) + field2 = mesh.buildOrthogonalField() + field3 = mesh.fillFromAnalytic( ON_CELLS, 2, "IVec * x + JVec * y" ) + field2.setName( "Normal" ) # name is necessary! + field3.setName( "Barycenter" ) # name is necessary! + + # WriteVTK + fileName = "testExample_MEDCouplingFieldDouble_WriteVTK" + fs = [ field1, field2, field3 ] # field series + writtenFileName=MEDCouplingFieldDouble.WriteVTK( fileName, fs ) + print "The file name with correct extension is : %s"%(writtenFileName) + #! [PySnippet_MEDCouplingFieldDouble_WriteVTK_1] + import os + os.remove( writtenFileName ) + + return + + def testExample_MEDCouplingFieldDouble_MaxFields(self): + #! [PySnippet_MEDCouplingFieldDouble_MaxFields_1] + vals1 = [0.,2., 4.,6.] # for field 1 + vals2 = [2.,0., 6.,4.] # for field 2 + valsMax = [2.,2., 6.,6.] # expected max field + valsMin = [0.,0., 4.,4.] # expected min field + + # field 1 + valsArr1=DataArrayDouble(vals1,2,2) # 2 tuples per 2 components + field1 = MEDCouplingFieldDouble( ON_NODES ) + field1.setArray( valsArr1 ) + + # field 2 + valsArr2=DataArrayDouble(vals2,2,2) # 2 tuples per 2 components + field2 = MEDCouplingFieldDouble( ON_NODES ) + field2.setArray( valsArr2 ) + + # max field + fieldMax = MEDCouplingFieldDouble.MaxFields( field1, field2 ) + self.assertTrue( fieldMax.getArray().getValues() == valsMax ) + + # min field + fieldMin = MEDCouplingFieldDouble.MinFields( field1, field2 ) + self.assertTrue( fieldMin.getArray().getValues() == valsMin ) + #! [PySnippet_MEDCouplingFieldDouble_MaxFields_1] + + def testExample_MEDCouplingFieldDouble_MergeFields(self): + #! [PySnippet_MEDCouplingFieldDouble_MergeFields_1] + # mesh 1 + coords = [0.,2.,4.] + coordsArr=DataArrayDouble(coords,3,1) + mesh1=MEDCouplingCMesh() + mesh1.setCoords(coordsArr) + # field 1 + field1 = mesh1.fillFromAnalytic( ON_CELLS, 1, "x") + + # mesh 2 and field 2 + field2 = field1.cloneWithMesh( True ) + vec = [5.] + field2.getMesh().translate(vec) # translate mesh2 + field2.applyFunc("x + 5") # "translate" field2 + + # concatenate field1 and field2 + field3 = MEDCouplingFieldDouble.MergeFields( field1, field2 ) + field4 = MEDCouplingFieldDouble.MergeFields( [ field1, field2] ) + #! [PySnippet_MEDCouplingFieldDouble_MergeFields_1] + return + + def testExample_MEDCouplingFieldDouble_substractInPlaceDM(self): + #! [PySnippet_MEDCouplingFieldDouble_substractInPlaceDM_1] + coords1=[0.,1.,2.,3.] + coords2=[2.,1.,0.,3.] #0 <==> #2 + # mesh 1 + mesh1=MEDCouplingUMesh() + coordsArr=DataArrayDouble(coords1, 4, 1) + mesh1.setCoords(coordsArr) + mesh1.setMeshDimension(0) + mesh1.allocateCells(0) + mesh1.finishInsertingCells() + # mesh 2 + mesh2=mesh1.deepCpy() + mesh2.getCoords().setValues(coords2, 4, 1) + #! [PySnippet_MEDCouplingFieldDouble_substractInPlaceDM_1] + #! [PySnippet_MEDCouplingFieldDouble_substractInPlaceDM_2] + field1 = mesh1.fillFromAnalytic(ON_NODES,1,"x") # field1 values == coords1 + field2 = mesh2.fillFromAnalytic(ON_NODES,1,"x") # field2 values == coords2 + levOfCheck = 10 # nodes can be permuted + field1.substractInPlaceDM( field2, levOfCheck, 1e-13, 0 ) # values #0 and #2 must swap + #! [PySnippet_MEDCouplingFieldDouble_substractInPlaceDM_2] + #! [PySnippet_MEDCouplingFieldDouble_substractInPlaceDM_3] + field2.applyFunc( 1, 0.0 ) # all field2 values == 0.0 + self.assertTrue( field1.isEqual( field2, 1e-13, 1e-13 )) # field1 == field2 == 0.0 + #! [PySnippet_MEDCouplingFieldDouble_substractInPlaceDM_3] + return + + def testExample_MEDCouplingFieldDouble_changeUnderlyingMesh(self): + #! [PySnippet_MEDCouplingFieldDouble_changeUnderlyingMesh_1] + coords1=[0.,1.,2.,3.] + coords2=[2.,1.,0.,3.] #0 <==> #2 + # mesh 1 + mesh1=MEDCouplingUMesh() + coordsArr=DataArrayDouble(coords1, 4, 1) + mesh1.setCoords(coordsArr) + mesh1.setMeshDimension(0) + mesh1.allocateCells(0) + mesh1.finishInsertingCells() + # mesh 2 + mesh2=mesh1.deepCpy() + mesh2.getCoords().setValues(coords2, 4, 1) + #! [PySnippet_MEDCouplingFieldDouble_changeUnderlyingMesh_1] + #! [PySnippet_MEDCouplingFieldDouble_changeUnderlyingMesh_2] + field = mesh1.fillFromAnalytic(ON_NODES,1,"x") # field values == coords1 + levOfCheck = 10 # nodes can be permuted + field.changeUnderlyingMesh( mesh2, levOfCheck, 1e-13, 0 ) # values #0 and #2 must swap + self.assertTrue( field.getArray().getValues() == coords2 ) + #! [PySnippet_MEDCouplingFieldDouble_changeUnderlyingMesh_2] + return + + def testExample_MEDCouplingFieldDouble_applyFunc_same_nb_comp(self): + #! [PySnippet_MEDCouplingFieldDouble_applyFunc_same_nb_comp_1] + v = [1.,2., 3.,4.] + array = DataArrayDouble( v, 2, 2 ) # 2 tuples per 2 components + field = MEDCouplingFieldDouble( ON_CELLS ) + field.setArray( array ) + func = "IVec * v + JVec * w*w + 10" + field.applyFunc( 2, func ) + self.assertTrue( field.getNumberOfComponents() == 2 ) # 2 components remains + #! [PySnippet_MEDCouplingFieldDouble_applyFunc_same_nb_comp_1] + #! [PySnippet_MEDCouplingFieldDouble_applyFunc_same_nb_comp_2] + v2 = field.getArray().getValues() + self.assertAlmostEqual( v2[0], 10 + v[0], 13 ) # "10 + IVec * v" + self.assertAlmostEqual( v2[1], 10 + v[1]*v[1], 13 ) # "10 + JVec * v*v" + self.assertAlmostEqual( v2[2], 10 + v[2], 13 ) # "10 + IVec * v" + self.assertAlmostEqual( v2[3], 10 + v[3]*v[3], 13 ) # "10 + JVec * v*v" + #! [PySnippet_MEDCouplingFieldDouble_applyFunc_same_nb_comp_2] + return + + def testExample_MEDCouplingFieldDouble_applyFunc3(self): + #! [PySnippet_MEDCouplingFieldDouble_applyFunc3_1] + # create a 2D vector field + values = [1.,1., 2.,1.] + array = DataArrayDouble( values, 2, 2 ) # 2 tuples per 2 components + field = MEDCouplingFieldDouble( ON_CELLS ) + field.setArray( array ) + # transform the field to a 3D vector field + func = "IVec * b + JVec * a + KVec * sqrt( a*a + b*b ) + 10" + varNames=["a","b"] # names used to refer to X and Y components + field.applyFunc3( 3, varNames, func ) # require 3 components + self.assertTrue( field.getNumberOfComponents() == 3 ) # 3 components as required + #! [PySnippet_MEDCouplingFieldDouble_applyFunc3_1] + #! [PySnippet_MEDCouplingFieldDouble_applyFunc3_2] + vec1 = field.getArray().getTuple(1) # vector #1 + a,b = values[2], values[3] # initial components of the vector #1 + self.assertAlmostEqual( vec1[0], 10 + b, 13 ) # "10 + IVec * b" + self.assertAlmostEqual( vec1[1], 10 + a, 13 ) # "10 + JVec * a" + self.assertAlmostEqual( vec1[2], 10 + sqrt(a*a+b*b), 13 ) # "10 + KVec * sqrt( a*a + b*b )" + #! [PySnippet_MEDCouplingFieldDouble_applyFunc3_2] + return + + def testExample_MEDCouplingFieldDouble_applyFunc2(self): + #! [PySnippet_MEDCouplingFieldDouble_applyFunc2_1] + # create a 2D vector field + values = [1.,1., 2.,1.] + array = DataArrayDouble( values, 2, 2 ) # 2 tuples per 2 components + array.setInfoOnComponent(0,"a") # name used to refer to X component within a function + array.setInfoOnComponent(1,"b") # name used to refer to Y component within a function + field = MEDCouplingFieldDouble( ON_CELLS ) + field.setArray( array ) + # transform the field to a 3D vector field + func = "IVec * b + JVec * a + KVec * sqrt( a*a + b*b ) + 10" + field.applyFunc2( 3, func ) # require 3 components + self.assertTrue( field.getNumberOfComponents() == 3 ) # 3 components as required + #! [PySnippet_MEDCouplingFieldDouble_applyFunc2_1] + #! [PySnippet_MEDCouplingFieldDouble_applyFunc2_2] + vec1 = field.getArray().getTuple(1) # vector #1 + a,b = values[2], values[3] # initial components of the vector #1 + self.assertAlmostEqual( vec1[0], 10 + b, 13 ) # "10 + IVec * b" + self.assertAlmostEqual( vec1[1], 10 + a, 13 ) # "10 + JVec * a" + self.assertAlmostEqual( vec1[2], 10 + sqrt(a*a+b*b), 13 ) # "10 + KVec * sqrt( a*a + b*b )" + #! [PySnippet_MEDCouplingFieldDouble_applyFunc2_2] + return + + def testExample_MEDCouplingFieldDouble_applyFunc(self): + #! [PySnippet_MEDCouplingFieldDouble_applyFunc_1] + # create a 2D vector field + values = [1.,1., 2.,1.] + array = DataArrayDouble( values, 2, 2 ) # 2 tuples per 2 components + field = MEDCouplingFieldDouble( ON_CELLS ) + field.setArray( array ) + # transform the field to a 3D vector field + func = "IVec * b + JVec * a + KVec * sqrt( a*a + b*b ) + 10" + field.applyFunc( 3, func ) # require 3 components + self.assertTrue( field.getNumberOfComponents() == 3 ) # 3 components as required + #! [PySnippet_MEDCouplingFieldDouble_applyFunc_1] + #! [PySnippet_MEDCouplingFieldDouble_applyFunc_2] + vec1 = field.getArray().getTuple(1) # vector #1 + a,b = values[2], values[3] # initial components of the vector #1 + self.assertAlmostEqual( vec1[0], 10 + b, 13 ) # "10 + IVec * b" + self.assertAlmostEqual( vec1[1], 10 + a, 13 ) # "10 + JVec * a" + self.assertAlmostEqual( vec1[2], 10 + sqrt(a*a+b*b), 13 ) # "10 + KVec * sqrt( a*a + b*b )" + #! [PySnippet_MEDCouplingFieldDouble_applyFunc_2] + return + + def testExample_MEDCouplingFieldDouble_applyFunc_val(self): + #! [PySnippet_MEDCouplingFieldDouble_applyFunc_val_1] + coords = [0.,2.,4.] + coordsArr=DataArrayDouble(coords,3,1) + mesh=MEDCouplingCMesh() + mesh.setCoords(coordsArr,coordsArr) + field = MEDCouplingFieldDouble( ON_CELLS ) + field.setMesh( mesh ) + field.fillFromAnalytic(2,"IVec * x + JVec * y") # 2 components + #! [PySnippet_MEDCouplingFieldDouble_applyFunc_val_1] + #! [PySnippet_MEDCouplingFieldDouble_applyFunc_val_2] + newValue = 7. + field.applyFunc( 3, newValue ) # 3 components are required + self.assertTrue( field.getIJ(1,0) == newValue ) # a value is as expected + self.assertTrue( field.getNumberOfComponents() == 3 ) + self.assertTrue( field.getNumberOfTuples() == mesh.getNumberOfCells() ) + #! [PySnippet_MEDCouplingFieldDouble_applyFunc_val_2] + return + + def testExample_MEDCouplingFieldDouble_fillFromAnalytic3(self): + #! [PySnippet_MEDCouplingFieldDouble_fillFromAnalytic3_1] + coords = [0.,2.,4.,6.] # 6. is not used + x=DataArrayDouble(coords[:3],3,1) + y=DataArrayDouble(coords[:2],2,1) + mesh=MEDCouplingCMesh() + mesh.setCoords(x,y) + #! [PySnippet_MEDCouplingFieldDouble_fillFromAnalytic3_1] + #! [PySnippet_MEDCouplingFieldDouble_fillFromAnalytic3_2] + field = MEDCouplingFieldDouble( ON_CELLS ) + field.setMesh( mesh ) + func = "IVec * b + JVec * a + KVec * sqrt( a*a + b*b ) + 10" + varNames=["a","b"] # names used to refer to X and Y coord components + field.fillFromAnalytic3(3,varNames,func) + #! [PySnippet_MEDCouplingFieldDouble_fillFromAnalytic3_2] + #! [PySnippet_MEDCouplingFieldDouble_fillFromAnalytic3_3] + vals1 = field.getArray().getTuple(1) # values of the cell #1 + assert len( vals1 ) == 3 # 3 components in the field + # + bc = mesh.getBarycenterAndOwner() # func is applied to barycenters of cells + bc1 = bc.getTuple(1) # coordinates of the second point + # + dist = sqrt( bc1[0]*bc1[0] + bc1[1]*bc1[1] ) # "sqrt( a*a + b*b )" + self.assertAlmostEqual( vals1[0], 10 + bc1[1], 13 ) # "10 + IVec * b" + self.assertAlmostEqual( vals1[1], 10 + bc1[0], 13 ) # "10 + JVec * a" + self.assertAlmostEqual( vals1[2], 10 + dist , 13 ) # "10 + KVec * sqrt( a*a + b*b )" + #! [PySnippet_MEDCouplingFieldDouble_fillFromAnalytic3_3] + return + + def testExample_MEDCouplingFieldDouble_fillFromAnalytic2(self): + #! [PySnippet_MEDCouplingFieldDouble_fillFromAnalytic2_1] + coords = [0.,2.,4.] + x=DataArrayDouble(coords[:3],3,1) + y=DataArrayDouble(coords[:2],2,1) + x.setInfoOnComponent(0,"a") # name used to refer to X coordinate within a function + y.setInfoOnComponent(0,"b") # name used to refer to Y coordinate within a function + mesh=MEDCouplingCMesh() + mesh.setCoords(x,y) + #! [PySnippet_MEDCouplingFieldDouble_fillFromAnalytic2_1] + #! [PySnippet_MEDCouplingFieldDouble_fillFromAnalytic2_2] + field = MEDCouplingFieldDouble( ON_CELLS ) + field.setMesh( mesh ) + func = "IVec * b + JVec * a + KVec * sqrt( a*a + b*b ) + 10" + field.fillFromAnalytic2(3,func) + #! [PySnippet_MEDCouplingFieldDouble_fillFromAnalytic2_2] + #! [PySnippet_MEDCouplingFieldDouble_fillFromAnalytic2_3] + vals1 = field.getArray().getTuple(1) # values of the cell #1 + assert len( vals1 ) == 3 # 3 components in the field + # + bc = mesh.getBarycenterAndOwner() # func is applied to barycenters of cells + bc1 = bc.getTuple(1) # coordinates of the second point + # + dist = sqrt( bc1[0]*bc1[0] + bc1[1]*bc1[1] ) # "sqrt( a*a + b*b )" + self.assertAlmostEqual( vals1[0], 10 + bc1[1], 13 ) # "10 + IVec * b" + self.assertAlmostEqual( vals1[1], 10 + bc1[0], 13 ) # "10 + JVec * a" + self.assertAlmostEqual( vals1[2], 10 + dist , 13 ) # "10 + KVec * sqrt( a*a + b*b )" + #! [PySnippet_MEDCouplingFieldDouble_fillFromAnalytic2_3] + return + + def testExample_MEDCouplingFieldDouble_fillFromAnalytic(self): + #! [PySnippet_MEDCouplingFieldDouble_fillFromAnalytic_1] + coords = [0.,2.,4.] + x=DataArrayDouble(coords[:3],3,1) + y=DataArrayDouble(coords[:2],2,1) + mesh=MEDCouplingCMesh() + mesh.setCoords(x,y) + #! [PySnippet_MEDCouplingFieldDouble_fillFromAnalytic_1] + #! [PySnippet_MEDCouplingFieldDouble_fillFromAnalytic_2] + field = MEDCouplingFieldDouble( ON_CELLS ) + field.setMesh( mesh ) + func = "IVec * b + JVec * a + KVec * sqrt( a*a + b*b ) + 10" + field.fillFromAnalytic(3,func) + #! [PySnippet_MEDCouplingFieldDouble_fillFromAnalytic_2] + #! [PySnippet_MEDCouplingFieldDouble_fillFromAnalytic_3] + vals1 = field.getArray().getTuple(1) # values of the cell #1 + assert len( vals1 ) == 3 # 3 components in the field + # + bc = mesh.getBarycenterAndOwner() # func is applied to barycenters of cells + bc1 = bc.getTuple(1) # coordinates of the second point + # + dist = sqrt( bc1[0]*bc1[0] + bc1[1]*bc1[1] ) # "sqrt( a*a + b*b )" + self.assertAlmostEqual( vals1[0], 10 + bc1[1], 13 ) # "10 + IVec * b" + self.assertAlmostEqual( vals1[1], 10 + bc1[0], 13 ) # "10 + JVec * a" + self.assertAlmostEqual( vals1[2], 10 + dist , 13 ) # "10 + KVec * sqrt( a*a + b*b )" + #! [PySnippet_MEDCouplingFieldDouble_fillFromAnalytic_3] + return + + def testExample_MEDCouplingFieldDouble_getValueOn_time(self): + #! [PySnippet_MEDCouplingFieldDouble_getValueOn_time_1] + coords = [0.,2.,4.] + coordsArr=DataArrayDouble(coords,3,1) + mesh=MEDCouplingCMesh() + mesh.setCoords(coordsArr,coordsArr) + #! [PySnippet_MEDCouplingFieldDouble_getValueOn_time_1] + #! [PySnippet_MEDCouplingFieldDouble_getValueOn_time_2] + field = MEDCouplingFieldDouble( ON_CELLS, LINEAR_TIME ) + field.setMesh( mesh ) + field.fillFromAnalytic(1,"10") # all values == 10. + field.setEndArray( field.getArray() + field.getArray() ) # all values == 20. + time1, time2 = 1.1, 22. + field.setStartTime( time1, 0, 0 ) + field.setEndTime ( time2, 0, 0 ) + #! [PySnippet_MEDCouplingFieldDouble_getValueOn_time_2] + #! [PySnippet_MEDCouplingFieldDouble_getValueOn_time_3] + pos = [ 1., 1. ] # we are in 2D space + value = field.getValueOn( pos, 0.5*( time1 + time2 )) + self.assertTrue( value[0] == 0.5*( 10. + 20.)) + #! [PySnippet_MEDCouplingFieldDouble_getValueOn_time_3] + return + + def testExample_MEDCouplingFieldDouble_getValueOnMulti(self): + #! [PySnippet_MEDCouplingFieldDouble_getValueOnMulti_1] + coords = [0.,2.,4.] + coordsArr=DataArrayDouble(coords,3,1) + mesh=MEDCouplingCMesh() + mesh.setCoords(coordsArr,coordsArr) + field = mesh.fillFromAnalytic(ON_CELLS,1,"x+y") + #! [PySnippet_MEDCouplingFieldDouble_getValueOnMulti_1] + #! [PySnippet_MEDCouplingFieldDouble_getValueOnMulti_2] + bc = mesh.getBarycenterAndOwner() # field values are located at cell barycenters + valArray = field.getValueOnMulti( bc ) + self.assertTrue( valArray.isEqual( field.getArray(), 1e-13 )) + #! [PySnippet_MEDCouplingFieldDouble_getValueOnMulti_2] + return + + def testExample_MEDCouplingFieldDouble_getValueOn(self): + #! [PySnippet_MEDCouplingFieldDouble_getValueOn_1] + coords = [0.,2.,4.] + coordsArr=DataArrayDouble(coords,3,1) + mesh=MEDCouplingCMesh() + mesh.setCoords(coordsArr,coordsArr) + field = mesh.fillFromAnalytic(ON_CELLS,1,"x+y") + #! [PySnippet_MEDCouplingFieldDouble_getValueOn_1] + #! [PySnippet_MEDCouplingFieldDouble_getValueOn_2] + bc = mesh.getBarycenterAndOwner() # field values are located at cell barycenters + vals = [] # array to collect values returned by getValueOn() + for i,tupl in enumerate( bc ): + vals.extend( field.getValueOn( tupl ) ) + self.assertTrue( vals == field.getArray().getValues() ) + #! [PySnippet_MEDCouplingFieldDouble_getValueOn_2] + return + + def testExample_MEDCouplingFieldDouble_getValueOnPos(self): + #! [PySnippet_MEDCouplingFieldDouble_getValueOnPos_1] + coords = [0.,2.,4.] + coordsArr=DataArrayDouble(coords,3,1) + mesh=MEDCouplingCMesh() + mesh.setCoords(coordsArr,coordsArr) + field = mesh.fillFromAnalytic(ON_CELLS,1,"x+y") + #! [PySnippet_MEDCouplingFieldDouble_getValueOnPos_1] + #! [PySnippet_MEDCouplingFieldDouble_getValueOnPos_2] + val11 = field.getValueOnPos( 1,1,-1) + bc = mesh.getBarycenterAndOwner() # field values are located at cell barycenters + self.assertTrue( val11[0] == bc[3,0] + bc[3,1] ) + #! [PySnippet_MEDCouplingFieldDouble_getValueOnPos_2] + return + + def testExample_MEDCouplingFieldDouble_renumberNodes(self): + #! [PySnippet_MEDCouplingFieldDouble_renumberNodes_1] + coords = [0.,2.,4.] + coordsArr=DataArrayDouble(coords,3,1) + mesh=MEDCouplingCMesh() + mesh.setCoords(coordsArr,coordsArr) + mesh=mesh.buildUnstructured() + #! [PySnippet_MEDCouplingFieldDouble_renumberNodes_1] + #! [PySnippet_MEDCouplingFieldDouble_renumberNodes_2] + field = mesh.fillFromAnalytic(ON_NODES,2,"IVec*x+JVec*y") + values = field.getArray() + nodeCoords = mesh.getCoords() + self.assertTrue( values.isEqualWithoutConsideringStr( nodeCoords, 1e-13 )) + #! [PySnippet_MEDCouplingFieldDouble_renumberNodes_2] + #! [PySnippet_MEDCouplingFieldDouble_renumberNodes_3] + renumber = [8, 7, 6, 5, 4, 3, 2, 1, 0] + field.renumberNodes(renumber,False) + mesh2 = field.getMesh() # field now refers to another mesh + values = field.getArray() + nodeCoords = mesh2.getCoords() + self.assertTrue( values.isEqualWithoutConsideringStr( nodeCoords, 1e-13 )) + #! [PySnippet_MEDCouplingFieldDouble_renumberNodes_3] + return + + + def testExample_MEDCouplingFieldDouble_renumberCells(self): + #! [PySnippet_MEDCouplingFieldDouble_renumberCells_1] + coords = [0.,2.,4.] + coordsArr=DataArrayDouble(coords,3,1) + mesh=MEDCouplingCMesh() + mesh.setCoords(coordsArr,coordsArr) + mesh=mesh.buildUnstructured() + #! [PySnippet_MEDCouplingFieldDouble_renumberCells_1] + #! [PySnippet_MEDCouplingFieldDouble_renumberCells_2] + field = mesh.fillFromAnalytic(ON_CELLS,2,"IVec*x+JVec*y") + values = field.getArray() + bc = mesh.getBarycenterAndOwner() + self.assertTrue( values.isEqualWithoutConsideringStr( bc, 1e-13 )) + #! [PySnippet_MEDCouplingFieldDouble_renumberCells_2] + #! [PySnippet_MEDCouplingFieldDouble_renumberCells_3] + renumber = [ 3, 2, 1, 0 ] + field.renumberCells(renumber,False) + mesh2 = field.getMesh() # field now refers to another mesh + values = field.getArray() + bc = mesh2.getBarycenterAndOwner() + self.assertTrue( values.isEqualWithoutConsideringStr( bc, 1e-13 )) + #! [PySnippet_MEDCouplingFieldDouble_renumberCells_3] + return + + def testExample_MEDCouplingFieldDouble_buildNewTimeReprFromThis(self): + #! [PySnippet_MEDCouplingFieldDouble_buildNewTimeReprFromThis_1] + coords = [0.,2.,4.] + coordsArr=DataArrayDouble(coords,3,1) + mesh=MEDCouplingCMesh() + mesh.setCoords(coordsArr,coordsArr) + field1 = mesh.fillFromAnalytic(ON_NODES,1,"x+y") + self.assertTrue( field1.getTimeDiscretization() == ONE_TIME ) + #! [PySnippet_MEDCouplingFieldDouble_buildNewTimeReprFromThis_1] + #! [PySnippet_MEDCouplingFieldDouble_buildNewTimeReprFromThis_2] + field2 = field1.buildNewTimeReprFromThis(NO_TIME,False) + self.assertTrue( field2.getTimeDiscretization() == NO_TIME ) + #! [PySnippet_MEDCouplingFieldDouble_buildNewTimeReprFromThis_2] + return + + def testExample_MEDCouplingMesh_fillFromAnalytic3(self): + #! [PySnippet_MEDCouplingMesh_fillFromAnalytic3_1] + coords = [0.,2.,4.,6.] # 6. is not used + x=DataArrayDouble(coords[:3],3,1) + y=DataArrayDouble(coords[:2],2,1) + mesh=MEDCouplingCMesh() + mesh.setCoords(x,y) + #! [PySnippet_MEDCouplingMesh_fillFromAnalytic3_1] + #! [PySnippet_MEDCouplingMesh_fillFromAnalytic3_2] + func = "IVec * b + JVec * a + KVec * sqrt( a*a + b*b ) + 10" + varNames=["a","b"] # names used to refer to X and Y coord components + field=mesh.fillFromAnalytic3(ON_CELLS,3,varNames,func) + #! [PySnippet_MEDCouplingMesh_fillFromAnalytic3_2] + #! [PySnippet_MEDCouplingMesh_fillFromAnalytic3_3] + vals1 = field.getArray().getTuple(1) # values of the cell #1 + assert len( vals1 ) == 3 # 3 components in the field + # + bc = mesh.getBarycenterAndOwner() # func is applied to barycenters of cells + bc1 = bc.getTuple(1) # coordinates of the second point + # + dist = sqrt( bc1[0]*bc1[0] + bc1[1]*bc1[1] ) # "sqrt( a*a + b*b )" + self.assertAlmostEqual( vals1[0], 10 + bc1[1], 13 ) # "10 + IVec * b" + self.assertAlmostEqual( vals1[1], 10 + bc1[0], 13 ) # "10 + JVec * a" + self.assertAlmostEqual( vals1[2], 10 + dist , 13 ) # "10 + KVec * sqrt( a*a + b*b )" + #! [PySnippet_MEDCouplingMesh_fillFromAnalytic3_3] + return + + def testExample_MEDCouplingMesh_fillFromAnalytic2(self): + #! [PySnippet_MEDCouplingMesh_fillFromAnalytic2_1] + coords = [0.,2.,4.,6.] # 6. is not used + x=DataArrayDouble(coords[:3],3,1) + y=DataArrayDouble(coords[:2],2,1) + x.setInfoOnComponent(0,"a") # name used to refer to X coordinate within a function + y.setInfoOnComponent(0,"b") # name used to refer to Y coordinate within a function + mesh=MEDCouplingCMesh() + mesh.setCoords(x,y) + #! [PySnippet_MEDCouplingMesh_fillFromAnalytic2_1] + #! [PySnippet_MEDCouplingMesh_fillFromAnalytic2_2] + func = "IVec * b + JVec * a + KVec * sqrt( a*a + b*b ) + 10" + field=mesh.fillFromAnalytic2(ON_CELLS,3,func) + #! [PySnippet_MEDCouplingMesh_fillFromAnalytic2_2] + #! [PySnippet_MEDCouplingMesh_fillFromAnalytic2_3] + vals1 = field.getArray().getTuple(1) # values of the cell #1 + assert len( vals1 ) == 3 # 3 components in the field + # + bc = mesh.getBarycenterAndOwner() # func is applied to barycenters of cells + bc1 = bc.getTuple(1) # coordinates of the second point + # + dist = sqrt( bc1[0]*bc1[0] + bc1[1]*bc1[1] ) # "sqrt( a*a + b*b )" + self.assertAlmostEqual( vals1[0], 10 + bc1[1], 13 ) # "10 + IVec * b" + self.assertAlmostEqual( vals1[1], 10 + bc1[0], 13 ) # "10 + JVec * a" + self.assertAlmostEqual( vals1[2], 10 + dist , 13 ) # "10 + KVec * sqrt( a*a + b*b )" + #! [PySnippet_MEDCouplingMesh_fillFromAnalytic2_3] + return + + def testExample_MEDCouplingMesh_fillFromAnalytic(self): + #! [PySnippet_MEDCouplingMesh_fillFromAnalytic_1] + coords = [0.,2.,4.,6.] # 6. is not used + x=DataArrayDouble(coords[:3],3,1) + y=DataArrayDouble(coords[:2],2,1) + mesh=MEDCouplingCMesh() + mesh.setCoords(x,y) + #! [PySnippet_MEDCouplingMesh_fillFromAnalytic_1] + #! [PySnippet_MEDCouplingMesh_fillFromAnalytic_2] + func = "IVec * b + JVec * a + KVec * sqrt( a*a + b*b ) + 10" + field=mesh.fillFromAnalytic(ON_CELLS,3,func) + #! [PySnippet_MEDCouplingMesh_fillFromAnalytic_2] + #! [PySnippet_MEDCouplingMesh_fillFromAnalytic_3] + vals1 = field.getArray().getTuple(1) # values of the cell #1 + assert len( vals1 ) == 3 # 3 components in the field + # + bc = mesh.getBarycenterAndOwner() # func is applied to barycenters of cells + bc1 = bc.getTuple(1) # coordinates of the second point + # + dist = sqrt( bc1[0]*bc1[0] + bc1[1]*bc1[1] ) # "sqrt( a*a + b*b )" + self.assertAlmostEqual( vals1[0], 10 + bc1[1], 13 ) # "10 + IVec * b" + self.assertAlmostEqual( vals1[1], 10 + bc1[0], 13 ) # "10 + JVec * a" + self.assertAlmostEqual( vals1[2], 10 + dist , 13 ) # "10 + KVec * sqrt( a*a + b*b )" + #! [PySnippet_MEDCouplingMesh_fillFromAnalytic_3] + return + + def testExample_MEDCouplingCMesh_getCoordsAt(self): + #! [PySnippet_MEDCouplingCMesh_getCoordsAt_1] + coords = [1.,2.,4.] + x=DataArrayDouble(coords,3,1) + mesh=MEDCouplingCMesh() + mesh.setCoordsAt(0,x) + x2=mesh.getCoordsAt(0) + assert coords == x2.getValues() + #! [PySnippet_MEDCouplingCMesh_getCoordsAt_1] + return + + def testExample_MEDCouplingUMesh_areCellsIncludedIn(self): + #! [PySnippet_MEDCouplingUMesh_areCellsIncludedIn_1] + mesh1=MEDCouplingUMesh() + mesh1.setMeshDimension(2) + mesh1.allocateCells(5) + conn=[0,3,4,1, 1,2,4, 4,5,2, 6,7,4,3, 7,8,5,4] + mesh1.insertNextCell(NORM_QUAD4,4,conn[0:4]) # 0 + mesh1.insertNextCell(NORM_TRI3,3, conn[4:7]) # 1 + mesh1.insertNextCell(NORM_TRI3,3, conn[7:10]) # 2 + mesh1.insertNextCell(NORM_QUAD4,4,conn[10:14]) # 3 + mesh1.insertNextCell(NORM_QUAD4,4,conn[14:18]) # 4 + mesh1.finishInsertingCells() + coords=[-0.3,-0.3, 0.2,-0.3, 0.7,-0.3, -0.3,0.2, 0.2,0.2, 0.7,0.2, -0.3,0.7, 0.2,0.7, 0.7,0.7 ] + coordsArr=DataArrayDouble(coords,9,2) + mesh1.setCoords(coordsArr) + #! [PySnippet_MEDCouplingUMesh_areCellsIncludedIn_1] + #! [PySnippet_MEDCouplingUMesh_areCellsIncludedIn_2] + cells2 = [ 4,2,0 ] + mesh2 = mesh1.buildPartOfMySelf(cells2, True ) # even cells selected + #! [PySnippet_MEDCouplingUMesh_areCellsIncludedIn_2] + #! [PySnippet_MEDCouplingUMesh_areCellsIncludedIn_3] + compType = 0 # the strongest policy + isOk, corr2to1 = mesh1.areCellsIncludedIn( mesh2, compType ) + assert isOk # a larger mesh1 includes a smaller mesh2 + assert corr2to1.getValues() == cells2 + #! [PySnippet_MEDCouplingUMesh_areCellsIncludedIn_3] + #! [PySnippet_MEDCouplingUMesh_areCellsIncludedIn_4] + isOk, corr1to2 = mesh2.areCellsIncludedIn( mesh1, compType ) + assert not isOk # the smaller mesh2 does NOT include the larger mesh1 + assert corr1to2.getValues() == [2, 3, 1, 4, 0] + #! [PySnippet_MEDCouplingUMesh_areCellsIncludedIn_4] + + def testExample_MEDCouplingUMesh_findAndCorrectBadOriented3DExtrudedCells(self): + #! [PySnippet_MEDCouplingUMesh_findAndCorrectBadOriented3DExtrudedCells_1] + # 2D coordinates of 5 base nodes + coords=[-0.3,-0.3, 0.2,-0.3, 0.7,-0.3, -0.3,0.2, 0.2,0.2] + coordsArr=DataArrayDouble(coords,5,2) + # coordinates of 5 top nodes + coordsArr2 = coordsArr.deepCpy() + # 3D coordinates of base + top nodes + coordsArr = coordsArr.changeNbOfComponents( 3, 0 ) + coordsArr2 = coordsArr2.changeNbOfComponents( 3, 1 ) + coordsArr = DataArrayDouble.Aggregate([coordsArr,coordsArr2]) + # mesh + mesh=MEDCouplingUMesh() + mesh.setCoords(coordsArr) + mesh.setMeshDimension(3) + mesh.allocateCells(2) + # connectivity of reversed HEXA8 and PENTA6 + conn=[0,1,4,3, 5,6,9,8, 1,2,4, 6,7,9] + mesh.insertNextCell(NORM_HEXA8, 8,conn[0:0+8]) + mesh.insertNextCell(NORM_PENTA6,6,conn[8:8+6]) + mesh.finishInsertingCells() + #! [PySnippet_MEDCouplingUMesh_findAndCorrectBadOriented3DExtrudedCells_1] + #! [PySnippet_MEDCouplingUMesh_findAndCorrectBadOriented3DExtrudedCells_2] + fixedCells = mesh.findAndCorrectBadOriented3DExtrudedCells() + assert len( fixedCells ) == 2 # 2 cells fixed + fixedCells = mesh.findAndCorrectBadOriented3DExtrudedCells() + assert len( fixedCells ) == 0 # no bad cells + #! [PySnippet_MEDCouplingUMesh_findAndCorrectBadOriented3DExtrudedCells_2] + return + + def testExample_MEDCouplingUMesh_arePolyhedronsNotCorrectlyOriented(self): + #! [PySnippet_MEDCouplingUMesh_arePolyhedronsNotCorrectlyOriented_1] + # 2D coordinates of 5 base nodes + coords=[-0.3,-0.3, 0.2,-0.3, 0.7,-0.3, -0.3,0.2, 0.2,0.2] + coordsArr=DataArrayDouble(coords,5,2) + # coordinates of 5 top nodes + coordsArr2 = coordsArr.deepCpy() + # 3D coordinates of base + top nodes + coordsArr = coordsArr.changeNbOfComponents( 3, 0 ) + coordsArr2 = coordsArr2.changeNbOfComponents( 3, 1 ) + coordsArr = DataArrayDouble.Aggregate([coordsArr,coordsArr2]) + # mesh + mesh=MEDCouplingUMesh() + mesh.setCoords(coordsArr) + mesh.setMeshDimension(3) + mesh.allocateCells(2) + # connectivity of a HEXA8 + a reversed PENTA6 + conn=[0,3,4,1, 5,8,9,6, 1,2,4, 6,7,9] + mesh.insertNextCell(NORM_POLYHED, 8,conn[0:0+8]) # "extruded" polyhedron + mesh.insertNextCell(NORM_POLYHED,6,conn[8:8+6]) + mesh.finishInsertingCells() + # fix connectivity of NORM_POLYHED's + mesh.convertExtrudedPolyhedra() + #! [PySnippet_MEDCouplingUMesh_arePolyhedronsNotCorrectlyOriented_1] + #! [PySnippet_MEDCouplingUMesh_arePolyhedronsNotCorrectlyOriented_2] + badCells = mesh.arePolyhedronsNotCorrectlyOriented() + assert len( badCells ) == 1 # one polyhedron is KO + # fix invalid rolyherdons + mesh.orientCorrectlyPolyhedrons() + # re-check the orientation + badCells = mesh.arePolyhedronsNotCorrectlyOriented() + assert len( badCells ) == 0 # connectivity is OK + #! [PySnippet_MEDCouplingUMesh_arePolyhedronsNotCorrectlyOriented_2] + return + + def testExample_MEDCouplingUMesh_are2DCellsNotCorrectlyOriented(self): + #! [PySnippet_MEDCouplingUMesh_are2DCellsNotCorrectlyOriented_1] + mesh=MEDCouplingUMesh() + mesh.setMeshDimension(2) + mesh.allocateCells(5) + conn=[0,3,4,1, 1,2,4, 4,5,2, 6,7,4,3, 7,8,5,4] + mesh.insertNextCell(NORM_QUAD4,4,conn[0:4]) # 0 + mesh.insertNextCell(NORM_TRI3,3, conn[4:7]) # 1 + mesh.insertNextCell(NORM_TRI3,3, conn[7:10]) # 2 + mesh.insertNextCell(NORM_QUAD4,4,conn[10:14]) # 3 + mesh.insertNextCell(NORM_QUAD4,4,conn[14:18]) # 4 + mesh.finishInsertingCells() + coords=[-0.3,-0.3, 0.2,-0.3, 0.7,-0.3, -0.3,0.2, 0.2,0.2, 0.7,0.2, -0.3,0.7, 0.2,0.7, 0.7,0.7 ] + coordsArr=DataArrayDouble(coords,9,2) + mesh.setCoords(coordsArr) + mesh.changeSpaceDimension(3) + #! [PySnippet_MEDCouplingUMesh_are2DCellsNotCorrectlyOriented_1] + #! [PySnippet_MEDCouplingUMesh_are2DCellsNotCorrectlyOriented_2] + vec = [0.,0.,-1.] + badCellIds=mesh.are2DCellsNotCorrectlyOriented( vec, False ) + assert len( badCellIds ) == 1 # one cell is reversed + # fix orientation + mesh.orientCorrectly2DCells( vec, False ) + # re-check orientation + badCellIds=mesh.are2DCellsNotCorrectlyOriented( vec, False ) + assert len( badCellIds ) == 0 # the orientation is OK + #! [PySnippet_MEDCouplingUMesh_are2DCellsNotCorrectlyOriented_2] + return + + def testExample_MEDCouplingUMesh_getCellsContainingPoints(self): + #! [PySnippet_MEDCouplingUMesh_getCellsContainingPoints_1] + mesh=MEDCouplingUMesh() + mesh.setMeshDimension(2) + mesh.allocateCells(5) + conn=[0,3,4,1, 1,2,4, 4,5,2, 6,7,4,3, 7,8,5,4] + mesh.insertNextCell(NORM_QUAD4,4,conn[0:4]) # 0 + mesh.insertNextCell(NORM_TRI3,3, conn[4:7]) # 1 + mesh.insertNextCell(NORM_TRI3,3, conn[7:10]) # 2 + mesh.insertNextCell(NORM_QUAD4,4,conn[10:14]) # 3 + mesh.insertNextCell(NORM_QUAD4,4,conn[14:18]) # 4 + mesh.finishInsertingCells() + coords=[-0.3,-0.3, 0.2,-0.3, 0.7,-0.3, -0.3,0.2, 0.2,0.2, 0.7,0.2, -0.3,0.7, 0.2,0.7, 0.7,0.7 ] + coordsArr=DataArrayDouble(coords,9,2) + mesh.setCoords(coordsArr) + #! [PySnippet_MEDCouplingUMesh_getCellsContainingPoints_1] + #! [PySnippet_MEDCouplingUMesh_getCellsContainingPoints_2] + pos = [ 10., 10, # point out of the mesh + 0.3, 0.3, # point located somewhere inside the mesh + coords[2], coords[3]] # point at the node #1 + eps = 1e-4 # ball radius + cells,cellsIndex=mesh.getCellsContainingPoints( pos, 3, eps ) + assert cells.getValues() == [4, 0, 1] + assert cellsIndex.getValues() == [0, 0, 1, 3] + #! [PySnippet_MEDCouplingUMesh_getCellsContainingPoints_2] + return + + + def testExample_MEDCouplingUMesh_getCellsContainingPoint(self): + #! [PySnippet_MEDCouplingUMesh_getCellsContainingPoint_1] + mesh=MEDCouplingUMesh() + mesh.setMeshDimension(2) + mesh.allocateCells(5) + conn=[0,3,4,1, 1,2,4, 4,5,2, 6,7,4,3, 7,8,5,4] + mesh.insertNextCell(NORM_QUAD4,4,conn[0:4]) + mesh.insertNextCell(NORM_TRI3,3, conn[4:7]) + mesh.insertNextCell(NORM_TRI3,3, conn[7:10]) + mesh.insertNextCell(NORM_QUAD4,4,conn[10:14]) + mesh.insertNextCell(NORM_QUAD4,4,conn[14:18]) + mesh.finishInsertingCells() + coords=[-0.3,-0.3, 0.2,-0.3, 0.7,-0.3, -0.3,0.2, 0.2,0.2, 0.7,0.2, -0.3,0.7, 0.2,0.7, 0.7,0.7 ] + coordsArr=DataArrayDouble(coords,9,2) + mesh.setCoords(coordsArr) + #! [PySnippet_MEDCouplingUMesh_getCellsContainingPoint_1] + #! [PySnippet_MEDCouplingUMesh_getCellsContainingPoint_2] + pos4 = coords[ 4*2 : ] # coordinates of the node #4 + eps = 1e-4 # ball radius + pos = [ pos4[0]+eps, pos4[1]-eps ] # ball center + cellIds=mesh.getCellsContainingPoint( pos, eps ) + assert len( cellIds ) == mesh.getNumberOfCells() + #! [PySnippet_MEDCouplingUMesh_getCellsContainingPoint_2] + return + + + def testExample_MEDCouplingUMesh_buildPartOrthogonalField(self): + #! [PySnippet_MEDCouplingUMesh_buildPartOrthogonalField_1] + mesh=MEDCouplingUMesh() + mesh.setMeshDimension(2) + mesh.allocateCells(5) + conn=[0,3,4,1, 1,2,4, 4,5,2, 6,7,4,3, 7,8,5,4] + mesh.insertNextCell(NORM_QUAD4,4,conn[0:4]) # 0 + mesh.insertNextCell(NORM_TRI3,3, conn[4:7]) # 1 + mesh.insertNextCell(NORM_TRI3,3, conn[7:10]) # 2 + mesh.insertNextCell(NORM_QUAD4,4,conn[10:14]) # 3 + mesh.insertNextCell(NORM_QUAD4,4,conn[14:18]) # 4 + mesh.finishInsertingCells() + coords=[-0.3,-0.3, 0.2,-0.3, 0.7,-0.3, -0.3,0.2, 0.2,0.2, 0.7,0.2, -0.3,0.7, 0.2,0.7, 0.7,0.7 ] + coordsArr=DataArrayDouble(coords,9,2) + mesh.setCoords(coordsArr) + #! [PySnippet_MEDCouplingUMesh_buildPartOrthogonalField_1] + #! [PySnippet_MEDCouplingUMesh_buildPartOrthogonalField_2] + part = DataArrayInt([1,2,3,4],4,1) # cell #0 is omitted + vecField=mesh.buildPartOrthogonalField( part ) + vecArr = vecField.getArray() + assert len( vecArr ) == len( part ) + assert vecArr.getNumberOfComponents() == 3 + #! [PySnippet_MEDCouplingUMesh_buildPartOrthogonalField_2] + return + + def testExample_MEDCouplingUMesh_getPartMeasureField(self): + #! [PySnippet_MEDCouplingUMesh_getPartMeasureField_1] + mesh=MEDCouplingUMesh() + mesh.setMeshDimension(2) + mesh.allocateCells(5) + conn=[0,3,4,1, 1,2,4, 4,5,2, 6,7,4,3, 7,8,5,4] + mesh.insertNextCell(NORM_QUAD4,4,conn[0:4]) # 0 + mesh.insertNextCell(NORM_TRI3,3, conn[4:7]) # 1 + mesh.insertNextCell(NORM_TRI3,3, conn[7:10]) # 2 + mesh.insertNextCell(NORM_QUAD4,4,conn[10:14]) # 3 + mesh.insertNextCell(NORM_QUAD4,4,conn[14:18]) # 4 + mesh.finishInsertingCells() + coords=[-0.3,-0.3, 0.2,-0.3, 0.7,-0.3, -0.3,0.2, 0.2,0.2, 0.7,0.2, -0.3,0.7, 0.2,0.7, 0.7,0.7 ] + coordsArr=DataArrayDouble(coords,9,2) + mesh.setCoords(coordsArr) + #! [PySnippet_MEDCouplingUMesh_getPartMeasureField_1] + #! [PySnippet_MEDCouplingUMesh_getPartMeasureField_2] + isAbs = True + part = DataArrayInt([1,2,3,4],4,1) # cell #0 is omitted + areaArr=mesh.getPartMeasureField( isAbs, part ) + assert areaArr[0] > 0 # orientation ignored + areaArr=mesh.getPartMeasureField( not isAbs, part ) + assert areaArr[0] < 0 # orientation considered + assert len( areaArr ) == len( part ) + #! [PySnippet_MEDCouplingUMesh_getPartMeasureField_2] + #! [PySnippet_MEDCouplingUMesh_getPartMeasureField_3] + part = DataArrayInt([1,2,3,4],4,1) # cell #0 is omitted + baryCenters = mesh.getPartBarycenterAndOwner( part ) + assert len( baryCenters ) == len( part ) + assert baryCenters.getNumberOfComponents() == mesh.getSpaceDimension() + #! [PySnippet_MEDCouplingUMesh_getPartMeasureField_3] + return + + def testExample_MEDCouplingUMesh_getCellsInBoundingBox(self): + #! [PySnippet_MEDCouplingUMesh_getCellsInBoundingBox_1] + mesh=MEDCouplingUMesh() + mesh.setMeshDimension(2) + coords=[0.,0., 0.,1., 1.,1] + coordsArr=DataArrayDouble(coords,3,2) + mesh.setCoords(coordsArr) + mesh.allocateCells(1) + conn=[0,1,2] + mesh.insertNextCell(NORM_TRI3,3,conn) + mesh.finishInsertingCells() + #! [PySnippet_MEDCouplingUMesh_getCellsInBoundingBox_1] + #! [PySnippet_MEDCouplingUMesh_getCellsInBoundingBox_2] + bbox = [1., 1., 1.001,1.001] # xMin, xMax, yMin, yMax + cellsInBox = mesh.getCellsInBoundingBox( bbox, 0.0 ) + assert cellsInBox.getValues() == [] + cellsInBox = mesh.getCellsInBoundingBox( bbox, 0.1 ) + assert cellsInBox.getValues() == [0] + #! [PySnippet_MEDCouplingUMesh_getCellsInBoundingBox_2] + + + def testExample_MEDCouplingUMesh_renumberNodesInConn(self): + #! [PySnippet_MEDCouplingUMesh_renumberNodesInConn_1] + mesh=MEDCouplingUMesh() + mesh.setMeshDimension(2) + mesh.allocateCells(1) + conn=[4,3,2,1] + mesh.insertNextCell(NORM_QUAD4,4,conn[0:4]) + mesh.finishInsertingCells() + #! [PySnippet_MEDCouplingUMesh_renumberNodesInConn_1] + #! [PySnippet_MEDCouplingUMesh_renumberNodesInConn_2] + old2newIds = [-1,3,2,1,0] + mesh.renumberNodesInConn( old2newIds ) + nodes0 = mesh.getNodeIdsOfCell( 0 ) + assert nodes0 == [0,1,2,3] + #! [PySnippet_MEDCouplingUMesh_renumberNodesInConn_2] + return + + + def testExample_MEDCouplingUMesh_renumberNodes(self): + #! [PySnippet_MEDCouplingUMesh_renumberNodes_1] + mesh=MEDCouplingUMesh() + mesh.setMeshDimension(2) + coords=[-0.3,-0.3, 0.2,-0.3, 0.7,-0.3, -0.3,0.3] + coordsArr=DataArrayDouble(coords,4,2) + mesh.setCoords(coordsArr) + mesh.allocateCells(0) + mesh.finishInsertingCells() + #! [PySnippet_MEDCouplingUMesh_renumberNodes_1] + #! [PySnippet_MEDCouplingUMesh_renumberNodes_2] + mesh.renumberNodes([ 2,1,0,-1 ], 3) + coordsArr = mesh.getCoords() # get a shorten array + assert coordsArr.getValues() == [0.7,-0.3, 0.2,-0.3, -0.3,-0.3] + #! [PySnippet_MEDCouplingUMesh_renumberNodes_2] + #! [PySnippet_MEDCouplingUMesh_renumberNodes_3] + coordsArr.setValues(coords,4,2) # restore old nodes + mesh.renumberNodes2([ 2,1,0,2 ], 3) + coordsArr = mesh.getCoords() # get a shorten array + assert coordsArr.getValues() == [0.7,-0.3, 0.2,-0.3, -0.3,0.0] + #! [PySnippet_MEDCouplingUMesh_renumberNodes_3] + return + + def testExample_MEDCouplingUMesh_findBoundaryNodes(self): + #! [PySnippet_MEDCouplingUMesh_findBoundaryNodes_1] + mesh=MEDCouplingUMesh() + mesh.setMeshDimension(2) + mesh.allocateCells(5) + conn=[0,3,4,1, 1,4,2, 4,5,2, 6,7,4,3, 7,8,5,4] + mesh.insertNextCell(NORM_QUAD4,4,conn[0:4]) + mesh.insertNextCell(NORM_TRI3,3, conn[4:7]) + mesh.insertNextCell(NORM_TRI3,3, conn[7:10]) + mesh.insertNextCell(NORM_QUAD4,4,conn[10:14]) + mesh.insertNextCell(NORM_QUAD4,4,conn[14:18]) + mesh.finishInsertingCells() + coords=[-0.3,-0.3, 0.2,-0.3, 0.7,-0.3, -0.3,0.2, 0.2,0.2, 0.7,0.2, -0.3,0.7, 0.2,0.7, 0.7,0.7 ] + coordsArr=DataArrayDouble(coords,9,2) + mesh.setCoords(coordsArr) + #! [PySnippet_MEDCouplingUMesh_findBoundaryNodes_1] + #! [PySnippet_MEDCouplingUMesh_findBoundaryNodes_2] + nodeIdsArr=mesh.findBoundaryNodes() + assert nodeIdsArr.getNumberOfTuples() == mesh.getNumberOfNodes() - 1 + #! [PySnippet_MEDCouplingUMesh_findBoundaryNodes_2] + return + + def testExample_MEDCouplingUMesh_buildBoundaryMesh(self): + #! [PySnippet_MEDCouplingUMesh_buildBoundaryMesh_1] + mesh=MEDCouplingUMesh() + mesh.setMeshDimension(2) + mesh.allocateCells(5) + conn=[0,3,4,1, 1,4,2, 4,5,2, 6,7,4,3, 7,8,5,4] + mesh.insertNextCell(NORM_QUAD4,4,conn[0:4]) + mesh.insertNextCell(NORM_TRI3,3, conn[4:7]) + mesh.insertNextCell(NORM_TRI3,3, conn[7:10]) + mesh.insertNextCell(NORM_QUAD4,4,conn[10:14]) + mesh.insertNextCell(NORM_QUAD4,4,conn[14:18]) + mesh.finishInsertingCells() + coords=[-0.3,-0.3, 0.2,-0.3, 0.7,-0.3, -0.3,0.2, 0.2,0.2, 0.7,0.2, -0.3,0.7, 0.2,0.7, 0.7,0.7 ] + coordsArr=DataArrayDouble(coords,9,2) + mesh.setCoords(coordsArr) + #! [PySnippet_MEDCouplingUMesh_buildBoundaryMesh_1] + #! [PySnippet_MEDCouplingUMesh_buildBoundaryMesh_2] + mesh1=mesh.buildBoundaryMesh(True) + mesh2=mesh.buildBoundaryMesh(False) + assert coordsArr.isEqual( mesh1.getCoords(), 1e-13 ) # same nodes + assert not coordsArr.isEqual( mesh2.getCoords(), 1e-13 ) # different nodes + #! [PySnippet_MEDCouplingUMesh_buildBoundaryMesh_2] + return + + def testExample_MEDCouplingUMesh_buildFacePartOfMySelfNode(self): + #! [PySnippet_MEDCouplingUMesh_buildFacePartOfMySelfNode_1] + mesh=MEDCouplingUMesh() + mesh.setMeshDimension(2) + mesh.allocateCells(5) + conn=[0,3,4,1, 1,4,2, 4,5,2, 6,7,4,3, 7,8,5,4] + mesh.insertNextCell(NORM_QUAD4,4,conn[0:4]) # 0 + mesh.insertNextCell(NORM_TRI3,3, conn[4:7]) # 1 + mesh.insertNextCell(NORM_TRI3,3, conn[7:10]) # 2 + mesh.insertNextCell(NORM_QUAD4,4,conn[10:14]) # 3 + mesh.insertNextCell(NORM_QUAD4,4,conn[14:18]) # 4 + mesh.finishInsertingCells() + coords=[-0.3,-0.3, 0.2,-0.3, 0.7,-0.3, -0.3,0.2, 0.2,0.2, 0.7,0.2, -0.3,0.7, 0.2,0.7, 0.7,0.7 ] + coordsArr=DataArrayDouble(coords,9,2) + mesh.setCoords(coordsArr) + #! [PySnippet_MEDCouplingUMesh_buildFacePartOfMySelfNode_1] + #! [PySnippet_MEDCouplingUMesh_buildFacePartOfMySelfNode_2] + nodeIds = mesh.getNodeIdsOfCell( 0 ) + allNodes = True + mesh1 = mesh.buildFacePartOfMySelfNode( nodeIds, allNodes ) + assert mesh1.getNumberOfCells() == 4 # 4 segments bounding QUAD4 #0 only + mesh2 = mesh.buildFacePartOfMySelfNode( nodeIds, not allNodes ) + assert mesh2.getNumberOfCells() > 4 # more segments added + #! [PySnippet_MEDCouplingUMesh_buildFacePartOfMySelfNode_2] + return + + + def testExample_MEDCouplingUMesh_buildPartOfMySelfNode(self): + #! [PySnippet_MEDCouplingUMesh_buildPartOfMySelfNode_1] + mesh=MEDCouplingUMesh() + mesh.setMeshDimension(2) + mesh.allocateCells(5) + conn=[0,3,4,1, 1,4,2, 4,5,2, 6,7,4,3, 7,8,5,4] + mesh.insertNextCell(NORM_QUAD4,4,conn[0:4]) # 0 + mesh.insertNextCell(NORM_TRI3,3, conn[4:7]) # 1 + mesh.insertNextCell(NORM_TRI3,3, conn[7:10]) # 2 + mesh.insertNextCell(NORM_QUAD4,4,conn[10:14]) # 3 + mesh.insertNextCell(NORM_QUAD4,4,conn[14:18]) # 4 + mesh.finishInsertingCells() + coords=[-0.3,-0.3, 0.2,-0.3, 0.7,-0.3, -0.3,0.2, 0.2,0.2, 0.7,0.2, -0.3,0.7, 0.2,0.7, 0.7,0.7 ] + coordsArr=DataArrayDouble(coords,9,2) + mesh.setCoords(coordsArr) + #! [PySnippet_MEDCouplingUMesh_buildPartOfMySelfNode_1] + #! [PySnippet_MEDCouplingUMesh_buildPartOfMySelfNode_2] + nodeIds = mesh.getNodeIdsOfCell( 0 ) + allNodes = True + mesh1 = mesh.buildPartOfMySelfNode( nodeIds, allNodes ) + mesh2 = mesh.buildPartOfMySelfNode( nodeIds, not allNodes ) + assert mesh1.getNumberOfCells() == 1 # cell #0 is found only + assert mesh2.getNumberOfCells() == mesh.getNumberOfCells() # all cells are found + #! [PySnippet_MEDCouplingUMesh_buildPartOfMySelfNode_2] + return + + + def testExample_MEDCouplingUMesh_getCellIdsLyingOnNodes(self): + #! [PySnippet_MEDCouplingUMesh_getCellIdsLyingOnNodes_1] + mesh=MEDCouplingUMesh() + mesh.setMeshDimension(2) + mesh.allocateCells(5) + conn=[0,3,4,1, 1,4,2, 4,5,2, 6,7,4,3, 7,8,5,4] + mesh.insertNextCell(NORM_QUAD4,4,conn[0:4]) # 0 + mesh.insertNextCell(NORM_TRI3,3, conn[4:7]) # 1 + mesh.insertNextCell(NORM_TRI3,3, conn[7:10]) # 2 + mesh.insertNextCell(NORM_QUAD4,4,conn[10:14]) # 3 + mesh.insertNextCell(NORM_QUAD4,4,conn[14:18]) # 4 + mesh.finishInsertingCells() + coords=[-0.3,-0.3, 0.2,-0.3, 0.7,-0.3, -0.3,0.2, 0.2,0.2, 0.7,0.2, -0.3,0.7, 0.2,0.7, 0.7,0.7 ] + coordsArr=DataArrayDouble(coords,9,2) + mesh.setCoords(coordsArr) + #! [PySnippet_MEDCouplingUMesh_getCellIdsLyingOnNodes_1] + #! [PySnippet_MEDCouplingUMesh_getCellIdsLyingOnNodes_2] + nodeIds = mesh.getNodeIdsOfCell( 0 ) + allNodes = True + cellIdsArr1 = mesh.getCellIdsLyingOnNodes( nodeIds, allNodes ) + cellIdsArr2 = mesh.getCellIdsLyingOnNodes( nodeIds, not allNodes ) + assert cellIdsArr1.getNumberOfTuples() == 1 # cell #0 is found only + assert cellIdsArr2.getNumberOfTuples() == mesh.getNumberOfCells() # all cells are found + #! [PySnippet_MEDCouplingUMesh_getCellIdsLyingOnNodes_2] + return + + + def testExample_MEDCouplingUMesh_getCellIdsFullyIncludedInNodeIds(self): + #! [PySnippet_MEDCouplingUMesh_getCellIdsFullyIncludedInNodeIds_1] + mesh=MEDCouplingUMesh() + mesh.setMeshDimension(2) + mesh.allocateCells(5) + conn=[0,3,4,1, 1,4,2, 4,5,2, 6,7,4,3, 7,8,5,4] + mesh.insertNextCell(NORM_QUAD4,4,conn[0:4]) + mesh.insertNextCell(NORM_TRI3,3, conn[4:7]) + mesh.insertNextCell(NORM_TRI3,3, conn[7:10]) + mesh.insertNextCell(NORM_QUAD4,4,conn[10:14]) + mesh.insertNextCell(NORM_QUAD4,4,conn[14:18]) + mesh.finishInsertingCells() + coords=[-0.3,-0.3, 0.2,-0.3, 0.7,-0.3, -0.3,0.2, 0.2,0.2, 0.7,0.2, -0.3,0.7, 0.2,0.7, 0.7,0.7 ] + coordsArr=DataArrayDouble(coords,9,2) + mesh.setCoords(coordsArr) + #! [PySnippet_MEDCouplingUMesh_getCellIdsFullyIncludedInNodeIds_1] + #! [PySnippet_MEDCouplingUMesh_getCellIdsFullyIncludedInNodeIds_2] + cellIds = [1,2] + nodeIds = mesh.getNodeIdsOfCell( cellIds[0] ) + nodeIds += mesh.getNodeIdsOfCell( cellIds[1] ) + cellIdsArr = mesh.getCellIdsFullyIncludedInNodeIds( nodeIds ) + assert cellIdsArr.getValues() == cellIds + #! [PySnippet_MEDCouplingUMesh_getCellIdsFullyIncludedInNodeIds_2] + return + + + def testExample_MEDCouplingUMesh_buildPartOfMySelf(self): + #! [PySnippet_MEDCouplingUMesh_buildPartOfMySelf_1] + mesh=MEDCouplingUMesh() + mesh.setMeshDimension(2) + mesh.allocateCells(5) + conn=[0,3,4,1, 1,4,2, 4,5,2, 6,7,4,3, 7,8,5,4] + mesh.insertNextCell(NORM_QUAD4,4,conn[0:4]) # 0 + mesh.insertNextCell(NORM_TRI3,3, conn[4:7]) # 1 + mesh.insertNextCell(NORM_TRI3,3, conn[7:10]) # 2 + mesh.insertNextCell(NORM_QUAD4,4,conn[10:14]) # 3 + mesh.insertNextCell(NORM_QUAD4,4,conn[14:18]) # 4 + mesh.finishInsertingCells() + coords=[-0.3,-0.3, 0.2,-0.3, 0.7,-0.3, -0.3,0.2, 0.2,0.2, 0.7,0.2, -0.3,0.7, 0.2,0.7, 0.7,0.7 ] + coordsArr=DataArrayDouble(coords,9,2) + mesh.setCoords(coordsArr) + #! [PySnippet_MEDCouplingUMesh_buildPartOfMySelf_1] + #! [PySnippet_MEDCouplingUMesh_buildPartOfMySelf_2] + cellIds=[1,2] + mesh2=mesh.buildPartOfMySelf(cellIds, True) + mesh3=mesh.buildPartOfMySelf(cellIds, False) + coordsArr2 = mesh2.getCoords() + assert coordsArr.isEqual( coordsArr2, 1e-13 ) # same nodes + coordsArr3 = mesh3.getCoords() + assert not coordsArr.isEqual( coordsArr3, 1e-13 ) # different nodes + assert mesh2.getNodeIdsOfCell(0) == mesh.getNodeIdsOfCell( cellIds[0]) # cell #1 was copied + assert mesh2.getNodeIdsOfCell(1) == mesh.getNodeIdsOfCell( cellIds[1]) # cell #2 was copied + #! [PySnippet_MEDCouplingUMesh_buildPartOfMySelf_2] + return + + def testExample_MEDCouplingUMesh_mergeNodes(self): + #! [PySnippet_MEDCouplingUMesh_mergeNodes_1] + mesh=MEDCouplingUMesh() + mesh.setMeshDimension(2) + mesh.allocateCells(5) + conn=[0,3,4,1, 1,4,2, 4,5,2] + mesh.insertNextCell(NORM_QUAD4,4,conn[0:4]) + mesh.insertNextCell(NORM_TRI3,3, conn[4:7]) + mesh.insertNextCell(NORM_TRI3,3, conn[7:10]) + mesh.finishInsertingCells() + coords=[0.3,-0.301, # 0 + 0.2,-0.3, # 1 + 0.3,-0.302, # 2 ~~ 0 + 1.1,0.0, # 3 + 1.1,0.0, # 4 == 3 + 0.3,-0.303]# 5 ~~ 0 + coordsArr=DataArrayDouble(coords,6,2) + mesh.setCoords(coordsArr) + #! [PySnippet_MEDCouplingUMesh_mergeNodes_1] + #! [PySnippet_MEDCouplingUMesh_mergeNodes_2] + arr,areNodesMerged,newNbOfNodes=mesh.mergeNodes(0.004) + assert arr.getValues() == [0, 1, 0, 2, 2, 0] + assert areNodesMerged + assert newNbOfNodes == 3 + #! [PySnippet_MEDCouplingUMesh_mergeNodes_2] + #! [PySnippet_MEDCouplingUMesh_mergeNodes_3] + baryCoords2 = coords[2*2:] # initial coordinates of node #2 + coordsArr = mesh.getCoords() # retrieve a new shorten coord array + self.assertNotAlmostEqual( baryCoords2[1], coordsArr.getIJ(0,1), 13 ) # Y of node #0 differs from that of baryCoords2 + # restore coordinates + coordsArr = DataArrayDouble(coords,6,2) + mesh.setCoords(coordsArr) + # call mergeNodes2() + mesh.mergeNodes2(0.004) + coordsArr = mesh.getCoords() # retrieve a new shorten coord array + self.assertAlmostEqual( baryCoords2[1], coordsArr.getIJ(0,1), 13 ) # Y of node #0 equals to that of baryCoords2 + #! [PySnippet_MEDCouplingUMesh_mergeNodes_3] + return + + def testExample_MEDCouplingUMesh_zipConnectivityTraducer(self): + #! [PySnippet_MEDCouplingUMesh_zipConnectivityTraducer_1] + mesh=MEDCouplingUMesh() + mesh.setMeshDimension(2) + mesh.allocateCells(5) + conn=[0,3,4,1, 1,4,2] + mesh.insertNextCell(NORM_QUAD4,4,conn[0:4]) # 0 + mesh.insertNextCell(NORM_TRI3,3, conn[4:7]) # 1 + mesh.insertNextCell(NORM_TRI3,3, conn[4:7]) # 2 == 1 + mesh.insertNextCell(NORM_QUAD4,4,conn[0:4]) # 3 == 0 + mesh.insertNextCell(NORM_QUAD4,4,conn[2:4]+conn[0:2]) # 4 ~~ 0 + mesh.finishInsertingCells() + coords=[-0.3,-0.3, 0.2,-0.3, 0.7,-0.3, -0.3,0.2, 0.2,0.2, 0.7,0.2, -0.3,0.7, 0.2,0.7, 0.7,0.7 ] + coordsArr=DataArrayDouble(coords,9,2) + mesh.setCoords(coordsArr) + #! [PySnippet_MEDCouplingUMesh_zipConnectivityTraducer_1] + #! [PySnippet_MEDCouplingUMesh_zipConnectivityTraducer_2] + oldNbCells = mesh.getNumberOfCells() + arr = mesh.zipConnectivityTraducer(0) + assert mesh.getNumberOfCells() == oldNbCells-2 + assert arr.getValues() == [0, 1, 1, 0, 2] + #! [PySnippet_MEDCouplingUMesh_zipConnectivityTraducer_2] + return + + def testExample_MEDCouplingUMesh_zipCoordsTraducer(self): + #! [PySnippet_MEDCouplingUMesh_zipCoordsTraducer_1] + mesh=MEDCouplingUMesh() + mesh.setMeshDimension(2) + mesh.allocateCells(5) + conn=[0,3,4,1, 1,4,2, 4,5,2, 6,7,4,3, 7,8,5,4] + mesh.insertNextCell(NORM_QUAD4,4,conn[0:4]) + mesh.insertNextCell(NORM_TRI3,3, conn[4:7]) + mesh.insertNextCell(NORM_TRI3,3, conn[7:10]) + mesh.insertNextCell(NORM_QUAD4,4,conn[10:14]) + mesh.insertNextCell(NORM_QUAD4,4,conn[14:18]) + mesh.finishInsertingCells() + coords=[-0.3,-0.3, 0.2,-0.3, 0.7,-0.3, -0.3,0.2, 0.2,0.2, 0.7,0.2, -0.3,0.7, 0.2,0.7, 0.7,0.7 ] + coordsArr=DataArrayDouble(coords,9,2) + mesh.setCoords(coordsArr) + #! [PySnippet_MEDCouplingUMesh_zipCoordsTraducer_1] + #! [PySnippet_MEDCouplingUMesh_zipCoordsTraducer_2] + cellIds=[1,2] + mesh2=mesh.buildPartOfMySelf(cellIds,True) + arr=mesh2.zipCoordsTraducer() + assert mesh2.getNumberOfNodes() == 4 # nb of nodes decreased + assert arr.getValues() == [-1,0,1,-1,2,3,-1,-1,-1] # -1 for unused nodes + #! [PySnippet_MEDCouplingUMesh_zipCoordsTraducer_2] + return + + def testExample_MEDCouplingUMesh_getNodeIdsInUse(self): + #! [PySnippet_MEDCouplingUMesh_getNodeIdsInUse_1] + mesh=MEDCouplingUMesh() + mesh.setMeshDimension(2) + mesh.allocateCells(5) + conn=[0,3,4,1, 1,4,2, 4,5,2, 6,7,4,3, 7,8,5,4] + mesh.insertNextCell(NORM_QUAD4,4,conn[0:4]) + mesh.insertNextCell(NORM_TRI3,3, conn[4:7]) + mesh.insertNextCell(NORM_TRI3,3, conn[7:10]) + mesh.insertNextCell(NORM_QUAD4,4,conn[10:14]) + mesh.insertNextCell(NORM_QUAD4,4,conn[14:18]) + mesh.finishInsertingCells() + coords=[-0.3,-0.3, 0.2,-0.3, 0.7,-0.3, -0.3,0.2, 0.2,0.2, 0.7,0.2, -0.3,0.7, 0.2,0.7, 0.7,0.7 ] + coordsArr=DataArrayDouble(coords,9,2) + mesh.setCoords(coordsArr) + #! [PySnippet_MEDCouplingUMesh_getNodeIdsInUse_1] + #! [PySnippet_MEDCouplingUMesh_getNodeIdsInUse_2] + cellIds=[1,2] + mesh2=mesh.buildPartOfMySelf(cellIds,True) + arr,newNbOfNodes=mesh2.getNodeIdsInUse() + assert arr.getValues() == [-1,0,1,-1,2,3,-1,-1,-1] + #! [PySnippet_MEDCouplingUMesh_getNodeIdsInUse_2] + #! [PySnippet_MEDCouplingUMesh_getNodeIdsInUse_3] + arr2=arr.invertArrayO2N2N2O(newNbOfNodes) + assert arr2.getValues() == [1,2,4,5] + #! [PySnippet_MEDCouplingUMesh_getNodeIdsInUse_3] + return + + def testExample_MEDCouplingUMesh_convertToPolyTypes(self): + #! [PySnippet_MEDCouplingUMesh_convertToPolyTypes_1] + mesh=MEDCouplingUMesh() + mesh.setMeshDimension(2) + mesh.allocateCells(5) + conn=[0,3,4,1, 1,4,2, 4,5,2, 6,7,4,3, 7,8,5,4] + mesh.insertNextCell(NORM_QUAD4,4,conn[0:4]) # 0 + mesh.insertNextCell(NORM_TRI3,3, conn[4:7]) # 1 + mesh.insertNextCell(NORM_TRI3,3, conn[7:10]) # 2 + mesh.insertNextCell(NORM_QUAD4,4,conn[10:14]) # 3 + mesh.insertNextCell(NORM_QUAD4,4,conn[14:18]) # 4 + mesh.finishInsertingCells() + coords=[-0.3,-0.3, 0.2,-0.3, 0.7,-0.3, -0.3,0.2, 0.2,0.2, 0.7,0.2, -0.3,0.7, 0.2,0.7, 0.7,0.7 ] + coordsArr=DataArrayDouble(coords,9,2) + mesh.setCoords(coordsArr) + #! [PySnippet_MEDCouplingUMesh_convertToPolyTypes_1] + #! [PySnippet_MEDCouplingUMesh_convertToPolyTypes_2] + cells=[1,3] + mesh.convertToPolyTypes(cells) + assert mesh.getTypeOfCell(0) == NORM_QUAD4 + assert mesh.getTypeOfCell(1) == NORM_POLYGON, mesh.getTypeOfCell(1) + assert mesh.getTypeOfCell(2) == NORM_TRI3 + assert mesh.getTypeOfCell(3) == NORM_POLYGON + #! [PySnippet_MEDCouplingUMesh_convertToPolyTypes_2] + return + + def testExample_MEDCouplingUMesh_buildDescendingConnectivity2(self): + #! [PySnippet_MEDCouplingUMesh_buildDescendingConnectivity2_1] + mesh=MEDCouplingUMesh() + mesh.setMeshDimension(2) + mesh.allocateCells(5) + conn=[0,3,4,1, 1,4,2, 4,5,2, 6,7,4,3, 7,8,5,4] + mesh.insertNextCell(NORM_QUAD4,4,conn[0:4]) # 0 + mesh.insertNextCell(NORM_TRI3,3, conn[4:7]) # 1 + mesh.insertNextCell(NORM_TRI3,3, conn[7:10]) # 2 + mesh.insertNextCell(NORM_QUAD4,4,conn[10:14]) # 3 + mesh.insertNextCell(NORM_QUAD4,4,conn[14:18]) # 4 + mesh.finishInsertingCells() + coords=[-0.3,-0.3, 0.2,-0.3, 0.7,-0.3, -0.3,0.2, 0.2,0.2, 0.7,0.2, -0.3,0.7, 0.2,0.7, 0.7,0.7 ] + coordsArr=DataArrayDouble(coords,9,2) + mesh.setCoords(coordsArr) + #! [PySnippet_MEDCouplingUMesh_buildDescendingConnectivity2_1] + #! [PySnippet_MEDCouplingUMesh_buildDescendingConnectivity2_2] + mesh2,desc,descIndx,revDesc,revDescIndx=mesh.buildDescendingConnectivity2() + assert desc.getValues() == [1,2,3,4,-3,5,6, 7,8,-5,9,10,-2,11, 12,13,-7,-10] + assert descIndx.getValues() == [0,4,7,10,14,18] + assert revDesc.getValues() == [0, 0,3, 0,1, 0, 1,2, 1, 2,4, 2, 3, 3,4, 3, 4, 4] + assert revDescIndx.getValues() == [0,1,3,5,6,8,9,11,12,13,15,16,17,18] + #! [PySnippet_MEDCouplingUMesh_buildDescendingConnectivity2_2] + #! [PySnippet_MEDCouplingUMesh_buildDescendingConnectivity2_3] + assert mesh2.getNodeIdsOfCell( 3-1 ) == [4, 1] # cell #3 in FORTRAN mode + #! [PySnippet_MEDCouplingUMesh_buildDescendingConnectivity2_3] + return + + def testExample_MEDCouplingUMesh_buildDescendingConnectivity(self): + #! [PySnippet_MEDCouplingUMesh_buildDescendingConnectivity_1] + mesh=MEDCouplingUMesh() + mesh.setMeshDimension(2) + mesh.allocateCells(5) + conn=[0,3,4,1, 1,4,2, 4,5,2, 6,7,4,3, 7,8,5,4] + mesh.insertNextCell(NORM_QUAD4,4,conn[0:4]) # 0 + mesh.insertNextCell(NORM_TRI3,3, conn[4:7]) # 1 + mesh.insertNextCell(NORM_TRI3,3, conn[7:10]) # 2 + mesh.insertNextCell(NORM_QUAD4,4,conn[10:14]) # 3 + mesh.insertNextCell(NORM_QUAD4,4,conn[14:18]) # 4 + mesh.finishInsertingCells() + coords=[-0.3,-0.3, 0.2,-0.3, 0.7,-0.3, -0.3,0.2, 0.2,0.2, 0.7,0.2, -0.3,0.7, 0.2,0.7, 0.7,0.7 ] + coordsArr=DataArrayDouble(coords,9,2) + mesh.setCoords(coordsArr) + #! [PySnippet_MEDCouplingUMesh_buildDescendingConnectivity_1] + #! [PySnippet_MEDCouplingUMesh_buildDescendingConnectivity_2] + mesh2,desc,descIndx,revDesc,revDescIndx=mesh.buildDescendingConnectivity() + assert desc.getValues() == [0,1,2,3, 2,4,5, 6,7,4, 8,9,1,10, 11,12,6,9] + assert descIndx.getValues() == [0,4,7,10,14,18] + assert revDesc.getValues() == [0, 0,3, 0,1, 0, 1,2, 1, 2,4, 2, 3, 3,4, 3, 4, 4] + assert revDescIndx.getValues() == [0,1,3,5,6,8,9,11,12,13,15,16,17,18] + #! [PySnippet_MEDCouplingUMesh_buildDescendingConnectivity_2] + return + + def testExample_MEDCouplingUMesh_getReverseNodalConnectivity(self): + #! [PySnippet_MEDCouplingUMesh_getReverseNodalConnectivity_1] + mesh=MEDCouplingUMesh() + mesh.setMeshDimension(2) + mesh.allocateCells(5) + conn=[0,3,4,1, 1,4,2, 4,5,2, 6,7,4,3, 7,8,5,4] + mesh.insertNextCell(NORM_QUAD4,4,conn[0:4]) # 0 + mesh.insertNextCell(NORM_TRI3,3, conn[4:7]) # 1 + mesh.insertNextCell(NORM_TRI3,3, conn[7:10]) # 2 + mesh.insertNextCell(NORM_QUAD4,4,conn[10:14]) # 3 + mesh.insertNextCell(NORM_QUAD4,4,conn[14:18]) # 4 + mesh.finishInsertingCells() + coords=[-0.3,-0.3, 0.2,-0.3, 0.7,-0.3, -0.3,0.2, 0.2,0.2, 0.7,0.2, -0.3,0.7, 0.2,0.7, 0.7,0.7 ] + coordsArr=DataArrayDouble(coords,9,2) + mesh.setCoords(coordsArr) + #! [PySnippet_MEDCouplingUMesh_getReverseNodalConnectivity_1] + #! [PySnippet_MEDCouplingUMesh_getReverseNodalConnectivity_2] + revNodal,revNodalIndx=mesh.getReverseNodalConnectivity() + assert revNodal.getValues() == [0,0,1,1,2,0,3,0,1,2,3,4,2,4,3,3,4,4] + assert revNodalIndx.getValues() == [0,1,3,5,7,12,14,15,17,18] + #! [PySnippet_MEDCouplingUMesh_getReverseNodalConnectivity_2] + return + + def testExample_MEDCouplingUMesh_checkDeepEquivalWith(self): + #! [PySnippet_MEDCouplingUMesh_checkDeepEquivalWith_1] + # mesh 1 + mesh1=MEDCouplingUMesh() + mesh1.setMeshDimension(2) + coords=[0.0,0.0, #0 + 1.0,0.0, #1 + 1.0,1.0, #2 + 0.0,1.0] #3 + coordsArr=DataArrayDouble(coords,4,2) + mesh1.setCoords(coordsArr) + mesh1.allocateCells(2) + mesh1.insertNextCell(NORM_TRI3,3,[0,1,2]) #0 + mesh1.insertNextCell(NORM_TRI3,3,[1,2,3]) #1 + mesh1.finishInsertingCells() + # mesh 2 + mesh2=MEDCouplingUMesh() + mesh2.setMeshDimension(2) + coords=[0.0,1.0, #0 = #3 + 0.0,0.0, #1 = #0 + 1.0,0.0, #2 = #1 + 1.0,1.001] #3 ~ #2 + coordsArr2=DataArrayDouble(coords,4,2) + mesh2.setCoords(coordsArr2) + mesh2.allocateCells(2) + mesh2.insertNextCell(NORM_TRI3,3,[2,3,0]) #0 = #1 + mesh2.insertNextCell(NORM_TRI3,3,[3,1,2]) #1 ~ #0 + mesh2.finishInsertingCells() + #! [PySnippet_MEDCouplingUMesh_checkDeepEquivalWith_1] + #! [PySnippet_MEDCouplingUMesh_checkDeepEquivalWith_2] + cellCompPol = 1 # "permuted same orientation" - policy of medium severity + cOld2New, nOld2New = mesh1.checkDeepEquivalWith( mesh2, cellCompPol, 0.002 ) + assert nOld2New.getValues() == [3, 0, 1, 2] + assert cOld2New.getValues() == [1, 0] + #! [PySnippet_MEDCouplingUMesh_checkDeepEquivalWith_2] + #! [PySnippet_MEDCouplingUMesh_checkDeepEquivalWith_3] + self.assertRaises( InterpKernelException, mesh1.checkDeepEquivalOnSameNodesWith, mesh2, cellCompPol, 0.002) + mesh2.setCoords(coordsArr) # make meshes share the same coordinates array + mesh2.allocateCells(2) + mesh2.insertNextCell(NORM_TRI3,3,[1,2,3]) #0 = #1 + mesh2.insertNextCell(NORM_TRI3,3,[1,0,2]) #1 ~ #0 + mesh2.finishInsertingCells() + cellCompPol = 2 # the weakest policy + mesh1.checkDeepEquivalOnSameNodesWith( mesh2, cellCompPol, 0 ) + #! [PySnippet_MEDCouplingUMesh_checkDeepEquivalWith_3] + return + + def testExample_MEDCouplingPointSet_scale(self): + #! [PySnippet_MEDCouplingPointSet_scale_1] + coords=[0.0,0.0, 1.0,0.0, 1.0,1.0, 0.0,1.0] # 2D coordinates of 4 nodes + coordsArr=DataArrayDouble(coords,4,2) + mesh=MEDCouplingUMesh() + mesh.setCoords(coordsArr) + initCoords = coordsArr.deepCpy() + #! [PySnippet_MEDCouplingPointSet_scale_1] + #! [PySnippet_MEDCouplingPointSet_scale_2] + center = [0.,0.] + factor = 2. + mesh.scale(center,factor) + #! [PySnippet_MEDCouplingPointSet_scale_2] + #! [PySnippet_MEDCouplingPointSet_scale_3] + coords2 = mesh.getCoords() + assert coords2.isEqualWithoutConsideringStr( initCoords, 1.0 ) + assert not coords2.isEqualWithoutConsideringStr( initCoords, 0.9 ) + #! [PySnippet_MEDCouplingPointSet_scale_3] + return + + def testExample_MEDCouplingPointSet_translate(self): + #! [PySnippet_MEDCouplingPointSet_translate_1] + coords=[0.0,0.0, 1.0,0.0, 1.0,1.0, 0.0,1.0] # 2D coordinates of 4 nodes + coordsArr=DataArrayDouble(coords,4,2) + mesh=MEDCouplingUMesh() + mesh.setCoords(coordsArr) + initCoords = coordsArr.deepCpy() + #! [PySnippet_MEDCouplingPointSet_translate_1] + #! [PySnippet_MEDCouplingPointSet_translate_2] + vector = [1.,1.] + mesh.translate(vector) + #! [PySnippet_MEDCouplingPointSet_translate_2] + #! [PySnippet_MEDCouplingPointSet_translate_3] + coords2 = mesh.getCoords() + assert coords2.isEqualWithoutConsideringStr( initCoords, 1 ) + assert not coords2.isEqualWithoutConsideringStr( initCoords, 0.9 ) + #! [PySnippet_MEDCouplingPointSet_translate_3] + return + + def testExample_MEDCouplingPointSet_rotate(self): + #! [PySnippet_MEDCouplingPointSet_rotate_1] + coords=[0.0,0.0, 0.1,0.0, 0.1,0.1, 0.0,0.1] # 2D coordinates of 4 nodes + coordsArr=DataArrayDouble(coords,4,2) + mesh=MEDCouplingUMesh() + mesh.setCoords(coordsArr) + #! [PySnippet_MEDCouplingPointSet_rotate_1] + #! [PySnippet_MEDCouplingPointSet_rotate_2] + center = [0.,0.] + mesh.rotate(center,-pi/2) + #! [PySnippet_MEDCouplingPointSet_rotate_2] + #! [PySnippet_MEDCouplingPointSet_rotate_3] + mesh.changeSpaceDimension(3) + center = [0.,0.,0.] + vector = [0.,0.,1.] + mesh.rotate(center,vector,pi/2) + #! [PySnippet_MEDCouplingPointSet_rotate_3] + #! [PySnippet_MEDCouplingPointSet_rotate_4] + mesh.changeSpaceDimension(2) + coords2 = mesh.getCoords() + for i,c in enumerate( coords ): + self.assertAlmostEqual( c, coords2.getIJ(0,i), 13 ) + #! [PySnippet_MEDCouplingPointSet_rotate_4] + return + + def testExample_MEDCouplingPointSet_getBoundingBox(self): + #! [PySnippet_MEDCouplingPointSet_getBoundingBox_1] + cc=[0.0, 0.1, 0.2, # 3D coordinates of 2 nodes + 2.0, 2.1, 2.2] + coordsArr=DataArrayDouble(cc,2,3) + mesh=MEDCouplingUMesh() + mesh.setCoords(coordsArr) + #! [PySnippet_MEDCouplingPointSet_getBoundingBox_1] + #! [PySnippet_MEDCouplingPointSet_getBoundingBox_2] + bbox=mesh.getBoundingBox() + assert bbox == [( cc[0], cc[3] ), # NOTE: list of 3 tuples is retirned! + ( cc[1], cc[4] ), + ( cc[2], cc[5] )] + #! [PySnippet_MEDCouplingPointSet_getBoundingBox_2] + + def testExample_MEDCouplingPointSet_getNodeIdsNearPoint(self): + #! [PySnippet_MEDCouplingPointSet_getNodeIdsNearPoint_1] + # 2D coordinates of 5 nodes + coords=[0.3,-0.301, # 0 + 0.2,-0.3, # 1 + 0.3,-0.302, # 2 + 1.1,0.0, # 3 + 0.3,-0.30299999999999]# 4 + coordsArr=DataArrayDouble(coords,5,2) + mesh=MEDCouplingUMesh() + mesh.setCoords(coordsArr) + #! [PySnippet_MEDCouplingPointSet_getNodeIdsNearPoint_1] + #! [PySnippet_MEDCouplingPointSet_getNodeIdsNearPoint_2] + point=[0.3, -0.3] # point close to nodes #0, #2 and #4 + ids=mesh.getNodeIdsNearPoint(point,0.003) + assert ids.getValues() == [0,2,4] + #! [PySnippet_MEDCouplingPointSet_getNodeIdsNearPoint_2] + return + + def testExample_MEDCouplingPointSet_getNodeIdsNearPoints(self): + #! [PySnippet_MEDCouplingPointSet_getNodeIdsNearPoints_1] + # 2D coordinates of 7 nodes + coords=[0.3,-0.301, # 0 + 0.2,-0.3, # 1 + 0.3,-0.302, # 2 + 1.1,0.0, # 3 + 1.1,0.0, # 4 + 1.1,0.002, # 5 + 0.3,-0.303]# 6 + coordsArr=DataArrayDouble(coords,7,2) + mesh=MEDCouplingUMesh() + mesh.setCoords(coordsArr) + #! [PySnippet_MEDCouplingPointSet_getNodeIdsNearPoints_1] + #! [PySnippet_MEDCouplingPointSet_getNodeIdsNearPoints_2] + points=[0.2,-0.301, # ~ node #1 + 0.0, 0.0, + 1.1, 0.002] # ~ nodes #3, #4 and #5 + ids,idsIndex=mesh.getNodeIdsNearPoints(points,3,0.003) + assert ids.getValues() == [1, 3, 4, 5] + assert idsIndex.getValues() == [0, 1, 1, 4] + #! [PySnippet_MEDCouplingPointSet_getNodeIdsNearPoints_2] + return + + def testExample_MEDCouplingPointSet_findCommonNodes(self): + #! [PySnippet_MEDCouplingPointSet_findCommonNodes_1] + coords=[0.3,-0.301, # 0 + 0.2,-0.3, # 1 + 0.3,-0.302, # 2 + 1.1,0.0, # 3 + 1.1,0.0, # 4 + 0.3,-0.303]# 5 + coordsArr=DataArrayDouble(coords,6,2) + mesh=MEDCouplingUMesh() + mesh.setCoords(coordsArr) + #! [PySnippet_MEDCouplingPointSet_findCommonNodes_1] + #! [PySnippet_MEDCouplingPointSet_findCommonNodes_2] + comm,commI=mesh.findCommonNodes(1e-13) + assert comm.getValues() == [3,4] + comm,commI=mesh.findCommonNodes(0.004) + assert comm.getValues() == [0,2,5,3,4] + #! [PySnippet_MEDCouplingPointSet_findCommonNodes_2] + return + + def testExample_MEDCouplingPointSet_getCoordinatesOfNode(self): + #! [PySnippet_MEDCouplingPointSet_getCoordinatesOfNode_1] + coords=[-0.3,-0.3, 0.2,-0.3, 0.7,-0.3] + coordsArr=DataArrayDouble(coords,3,2) + mesh=MEDCouplingUMesh() + mesh.setCoords(coordsArr) +#! [PySnippet_MEDCouplingPointSet_getCoordinatesOfNode_1] +#! [PySnippet_MEDCouplingPointSet_getCoordinatesOfNode_2] + nodeCoords=mesh.getCoordinatesOfNode(1) + self.assertAlmostEqual(0.2, nodeCoords[0],13) + self.assertAlmostEqual(-0.3,nodeCoords[1],13) +#! [PySnippet_MEDCouplingPointSet_getCoordinatesOfNode_2] + return + + def testExample_DataArrayInt_getTuple(self): +#! [Snippet_DataArrayInt_getTuple_1] + dv=DataArrayInt() + dv.alloc( 6, 1 ) + dv.iota(7) + dv.rearrange( 2 ) + assert dv.getTuple( 1 ) == [9,10] +#! [Snippet_DataArrayInt_getTuple_1] +#! [Snippet_DataArrayInt_getTuple_2] + for tpl in dv: + print tpl +#! [Snippet_DataArrayInt_getTuple_2] + return + + def testExample_DataArrayInt_buildPermutationArr(self): +#! [PySnippet_DataArrayInt_buildPermutationArr_1] + a=DataArrayInt() + a.setValues([4,5,6,7,8],5,1) + b=DataArrayInt() + b.setValues([5,4,8,6,7],5,1) + c=a.buildPermutationArr(b) +#! [PySnippet_DataArrayInt_buildPermutationArr_1] + self.assertEqual([1,0,4,2,3],c.getValues()) + return + + def testExample_DataArrayInt_invertArrayO2N2N2O(self): +#! [PySnippet_DataArrayInt_invertArrayO2N2N2O_1] + arr1=[2,0,4,1,5,3] + da=DataArrayInt() + da.setValues(arr1,6,1) + da2=da.invertArrayO2N2N2O(6) + expected1=[1,3,0,5,2,4] + for i in xrange(6): + self.assertEqual(expected1[i],da2.getIJ(i,0)) + pass +#! [PySnippet_DataArrayInt_invertArrayO2N2N2O_1] + return + + def testExample_DataArrayInt_invertArrayN2O2O2N(self): +#! [PySnippet_DataArrayInt_invertArrayN2O2O2N_1] + arr1=[2,0,4,1,5,3] + da=DataArrayInt() + da.setValues(arr1,6,1) + da2=da.invertArrayN2O2O2N(7) + expected1=[1,3,0,5,2,4,-1] + for i in xrange(6): + self.assertEqual(expected1[i],da2.getIJ(i,0)) + pass +#! [PySnippet_DataArrayInt_invertArrayN2O2O2N_1] + return + + + def testExample_DataArrayDouble_getIdsInRange(self): +#! [PySnippet_DataArrayDouble_getIdsInRange_1] + da=DataArrayDouble() + da.alloc( 10, 1 ) + da[ :, :] = range(10) + da2 = da.getIdsInRange( 2.5, 6 ) +#! [PySnippet_DataArrayDouble_getIdsInRange_1] + return + + def testExample_DataArrayDouble_setPartOfValues2(self): +#! [Snippet_DataArrayDouble_setPartOfValues2_1] + da=DataArrayDouble() + da.alloc( 4, 7 ) + # + dv=DataArrayDouble() + dv.alloc( 6, 1 ) + dv.iota(7) + dv.rearrange( 2 ) +#! [Snippet_DataArrayDouble_setPartOfValues2_1] +#! [Snippet_DataArrayDouble_setPartOfValues2_2] + da.fillWithZero() + da[ [0,1,2], [1,3] ] = dv +#! [Snippet_DataArrayDouble_setPartOfValues2_2] +#! [Snippet_DataArrayDouble_setPartOfValues2_3] + da.fillWithZero() + dv.rearrange( 6 ) + da[ [0,2,3], [0,2,3,4,5,6]] = dv +#! [Snippet_DataArrayDouble_setPartOfValues2_3] + return + + def testExample_DataArrayInt_setPartOfValues2(self): +#! [Snippet_DataArrayInt_setPartOfValues2_1] + da=DataArrayInt() + da.alloc( 4, 7 ) + # + dv=DataArrayInt() + dv.alloc( 6, 1 ) + dv.iota(7) + dv.rearrange( 2 ) +#! [Snippet_DataArrayInt_setPartOfValues2_1] +#! [Snippet_DataArrayInt_setPartOfValues2_2] + da.fillWithZero() + da[ [0,1,2], [1,3] ] = dv +#! [Snippet_DataArrayInt_setPartOfValues2_2] +#! [Snippet_DataArrayInt_setPartOfValues2_3] + da.fillWithZero() + dv.rearrange( 6 ) + da[ [0,2,3], [0,2,3,4,5,6]] = dv +#! [Snippet_DataArrayInt_setPartOfValues2_3] + return + + def testExample_DataArrayDouble_setPartOfValues3(self): +#! [Snippet_DataArrayDouble_setPartOfValues3_1] + da=DataArrayDouble() + da.alloc( 4, 7 ) + # + dv=DataArrayDouble() + dv.alloc( 6, 1 ) + dv.iota(7) + dv.rearrange( 2 ) +#! [Snippet_DataArrayDouble_setPartOfValues3_1] +#! [Snippet_DataArrayDouble_setPartOfValues3_2] + da.fillWithZero() + da[ 0:3, [1,3] ] = dv +#! [Snippet_DataArrayDouble_setPartOfValues3_2] +#! [Snippet_DataArrayDouble_setPartOfValues3_3] + da.fillWithZero() + dv.rearrange( 6 ) + da[ 0:4:2, [0,2,3,4,5,6]] = dv +#! [Snippet_DataArrayDouble_setPartOfValues3_3] + return + + def testExample_DataArrayInt_setPartOfValues3(self): +#! [Snippet_DataArrayInt_setPartOfValues3_1] + da=DataArrayInt() + da.alloc( 4, 7 ) + # + dv=DataArrayInt() + dv.alloc( 6, 1 ) + dv.iota(7) + dv.rearrange( 2 ) +#! [Snippet_DataArrayInt_setPartOfValues3_1] +#! [Snippet_DataArrayInt_setPartOfValues3_2] + da.fillWithZero() + da[ 0:3, [1,3] ] = dv +#! [Snippet_DataArrayInt_setPartOfValues3_2] +#! [Snippet_DataArrayInt_setPartOfValues3_3] + da.fillWithZero() + dv.rearrange( 6 ) + da[ 0:4:2, [0,2,3,4,5,6]] = dv +#! [Snippet_DataArrayInt_setPartOfValues3_3] + return + + def testExample_DataArrayDouble_setPartOfValues1(self): +#! [Snippet_DataArrayDouble_setPartOfValues1_1] + da=DataArrayDouble() + da.alloc( 4, 4 ) + da.setInfoOnComponents( ["v1","v2","v3","v4"]) + # + dv=DataArrayDouble() + dv.alloc( 4, 1 ) + dv.iota(7) + dv.rearrange( 2 ) + dv.setInfoOnComponents( ["a1","a2"]) +#! [Snippet_DataArrayDouble_setPartOfValues1_1] +#! [Snippet_DataArrayDouble_setPartOfValues1_2] + da.fillWithZero() + da.setPartOfValues1( dv, 1,3,1, 1,3,1, True ) +#! [Snippet_DataArrayDouble_setPartOfValues1_2] +#! [Snippet_DataArrayDouble_setPartOfValues1_3] + da.fillWithZero() + da.setPartOfValues1( dv, 0,4,1, 1,2,1, False ) +#! [Snippet_DataArrayDouble_setPartOfValues1_3] +#! [Snippet_DataArrayDouble_setPartOfValues1_4] + da.fillWithZero() + da.setPartOfValues1( dv, 1,2,1, 0,4,1, False ) +#! [Snippet_DataArrayDouble_setPartOfValues1_4] +#! [Snippet_DataArrayDouble_setPartOfValues1_5] + da.fillWithZero() + da.setPartOfValues1( dv, 0,3,2, 1,4,2, True ) +#! [Snippet_DataArrayDouble_setPartOfValues1_5] +#! [Snippet_DataArrayDouble_setPartOfValues1_6] + da2 = da.deepCpy() + da2.fillWithZero() + da2[ 0:3:2, 1:4:2 ] = dv + self.assertTrue( da.isEqual( da2, 1e-20 )) +#! [Snippet_DataArrayDouble_setPartOfValues1_6] + return + + def testExample_DataArrayInt_setPartOfValues1(self): +#! [Snippet_DataArrayInt_setPartOfValues1_1] + da=DataArrayInt() + da.alloc( 4, 4 ) + da.setInfoOnComponents( ["v1","v2","v3","v4"]) + # + dv=DataArrayInt() + dv.alloc( 4, 1 ) + dv.iota(7) + dv.rearrange( 2 ) + dv.setInfoOnComponents( ["a1","a2"]) +#! [Snippet_DataArrayInt_setPartOfValues1_1] +#! [Snippet_DataArrayInt_setPartOfValues1_2] + da.fillWithZero() + da.setPartOfValues1( dv, 1,3,1, 1,3,1, True ) +#! [Snippet_DataArrayInt_setPartOfValues1_2] +#! [Snippet_DataArrayInt_setPartOfValues1_3] + da.fillWithZero() + da.setPartOfValues1( dv, 0,4,1, 1,2,1, False ) +#! [Snippet_DataArrayInt_setPartOfValues1_3] +#! [Snippet_DataArrayInt_setPartOfValues1_4] + da.fillWithZero() + da.setPartOfValues1( dv, 1,2,1, 0,4,1, False ) +#! [Snippet_DataArrayInt_setPartOfValues1_4] +#! [Snippet_DataArrayInt_setPartOfValues1_5] + da.fillWithZero() + da.setPartOfValues1( dv, 0,3,2, 1,4,2, True ) +#! [Snippet_DataArrayInt_setPartOfValues1_5] +#! [Snippet_DataArrayInt_setPartOfValues1_6] + da2 = da.deepCpy() + da2.fillWithZero() + da2[ 0:3:2, 1:4:2 ] = dv + self.assertTrue( da.isEqual( da2 )) +#! [Snippet_DataArrayInt_setPartOfValues1_6] + return + + def testExample_DataArrayDouble_setPartOfValuesSimple1(self): +#! [Snippet_DataArrayDouble_setPartOfValuesSimple1_1] + da=DataArrayDouble() + da.alloc( 4, 4 ) + dv = 7 +#! [Snippet_DataArrayDouble_setPartOfValuesSimple1_1] +#! [Snippet_DataArrayDouble_setPartOfValuesSimple1_2] + da.fillWithZero() + da.setPartOfValuesSimple1( dv, 1,3,1, 1,3,1 ) +#! [Snippet_DataArrayDouble_setPartOfValuesSimple1_2] +#! [Snippet_DataArrayDouble_setPartOfValuesSimple1_3] + da.fillWithZero() + da.setPartOfValuesSimple1( dv, 0,4,1, 1,2,1 ) +#! [Snippet_DataArrayDouble_setPartOfValuesSimple1_3] +#! [Snippet_DataArrayDouble_setPartOfValuesSimple1_4] + da.fillWithZero() + da.setPartOfValuesSimple1( dv, 1,2,1, 0,4,1 ) +#! [Snippet_DataArrayDouble_setPartOfValuesSimple1_4] +#! [Snippet_DataArrayDouble_setPartOfValuesSimple1_5] + da.fillWithZero() + da.setPartOfValuesSimple1( dv, 0,3,2, 1,4,2 ) +#! [Snippet_DataArrayDouble_setPartOfValuesSimple1_5] +#! [Snippet_DataArrayDouble_setPartOfValuesSimple1_6] + da2 = da.deepCpy() + da2.fillWithZero() + da2[ 0:3:2, 1:4:2 ] = dv + self.assertTrue( da.isEqual( da2, 1e-20 )) +#! [Snippet_DataArrayDouble_setPartOfValuesSimple1_6] + return + + def testExample_DataArrayInt_setPartOfValuesSimple1(self): +#! [Snippet_DataArrayInt_setPartOfValuesSimple1_1] + da=DataArrayInt() + da.alloc( 4, 4 ) + dv = 7 +#! [Snippet_DataArrayInt_setPartOfValuesSimple1_1] +#! [Snippet_DataArrayInt_setPartOfValuesSimple1_2] + da.fillWithZero() + da.setPartOfValuesSimple1( dv, 1,3,1, 1,3,1 ) +#! [Snippet_DataArrayInt_setPartOfValuesSimple1_2] +#! [Snippet_DataArrayInt_setPartOfValuesSimple1_3] + da.fillWithZero() + da.setPartOfValuesSimple1( dv, 0,4,1, 1,2,1 ) +#! [Snippet_DataArrayInt_setPartOfValuesSimple1_3] +#! [Snippet_DataArrayInt_setPartOfValuesSimple1_4] + da.fillWithZero() + da.setPartOfValuesSimple1( dv, 1,2,1, 0,4,1 ) +#! [Snippet_DataArrayInt_setPartOfValuesSimple1_4] +#! [Snippet_DataArrayInt_setPartOfValuesSimple1_5] + da.fillWithZero() + da.setPartOfValuesSimple1( dv, 0,3,2, 1,4,2 ) +#! [Snippet_DataArrayInt_setPartOfValuesSimple1_5] +#! [Snippet_DataArrayInt_setPartOfValuesSimple1_6] + da2 = da.deepCpy() + da2.fillWithZero() + da2[ 0:3:2, 1:4:2 ] = dv + self.assertTrue( da.isEqual( da2 )) +#! [Snippet_DataArrayInt_setPartOfValuesSimple1_6] + return + + def testExample_DataArrayDouble_setPartOfValuesSimple2(self): +#! [Snippet_DataArrayDouble_setPartOfValuesSimple2_1] + da=DataArrayDouble() + da.alloc( 4, 4 ) + dv = 7 +#! [Snippet_DataArrayDouble_setPartOfValuesSimple2_1] +#! [Snippet_DataArrayDouble_setPartOfValuesSimple2_2] + da.fillWithZero() + da[[1,2], [1,2]] = dv +#! [Snippet_DataArrayDouble_setPartOfValuesSimple2_2] +#! [Snippet_DataArrayDouble_setPartOfValuesSimple2_3] + da.fillWithZero() + da[[0,1,2,3], [1]] = dv +#! [Snippet_DataArrayDouble_setPartOfValuesSimple2_3] +#! [Snippet_DataArrayDouble_setPartOfValuesSimple2_4] + da.fillWithZero() + da[[1], [0,1,2,3]] = dv +#! [Snippet_DataArrayDouble_setPartOfValuesSimple2_4] +#! [Snippet_DataArrayDouble_setPartOfValuesSimple2_5] + da.fillWithZero() + da[[0,2], [1,3]] = dv +#! [Snippet_DataArrayDouble_setPartOfValuesSimple2_5] + return + + def testExample_DataArrayInt_setPartOfValuesSimple2(self): +#! [Snippet_DataArrayInt_setPartOfValuesSimple2_1] + da=DataArrayInt() + da.alloc( 4, 4 ) + dv = 7 +#! [Snippet_DataArrayInt_setPartOfValuesSimple2_1] +#! [Snippet_DataArrayInt_setPartOfValuesSimple2_2] + da.fillWithZero() + da[[1,2], [1,2]] = dv +#! [Snippet_DataArrayInt_setPartOfValuesSimple2_2] +#! [Snippet_DataArrayInt_setPartOfValuesSimple2_3] + da.fillWithZero() + da[[0,1,2,3], [1]] = dv +#! [Snippet_DataArrayInt_setPartOfValuesSimple2_3] +#! [Snippet_DataArrayInt_setPartOfValuesSimple2_4] + da.fillWithZero() + da[[1], [0,1,2,3]] = dv +#! [Snippet_DataArrayInt_setPartOfValuesSimple2_4] +#! [Snippet_DataArrayInt_setPartOfValuesSimple2_5] + da.fillWithZero() + da[[0,2], [1,3]] = dv +#! [Snippet_DataArrayInt_setPartOfValuesSimple2_5] + return + + def testExample_DataArrayDouble_setPartOfValuesSimple3(self): +#! [Snippet_DataArrayDouble_setPartOfValuesSimple3_1] + da=DataArrayDouble() + da.alloc( 4, 4 ) + dv = 7 +#! [Snippet_DataArrayDouble_setPartOfValuesSimple3_1] +#! [Snippet_DataArrayDouble_setPartOfValuesSimple3_2] + da.fillWithZero() + da[[1,2], 1:3] = dv +#! [Snippet_DataArrayDouble_setPartOfValuesSimple3_2] +#! [Snippet_DataArrayDouble_setPartOfValuesSimple3_3] + da.fillWithZero() + da[[0,1,2,3], 1:2] = dv +#! [Snippet_DataArrayDouble_setPartOfValuesSimple3_3] +#! [Snippet_DataArrayDouble_setPartOfValuesSimple3_4] + da.fillWithZero() + da[[1], 0:4] = dv +#! [Snippet_DataArrayDouble_setPartOfValuesSimple3_4] +#! [Snippet_DataArrayDouble_setPartOfValuesSimple3_5] + da.fillWithZero() + da[[0,2], 1:4:2] = dv +#! [Snippet_DataArrayDouble_setPartOfValuesSimple3_5] + return + + def testExample_DataArrayInt_setPartOfValuesSimple3(self): +#! [Snippet_DataArrayInt_setPartOfValuesSimple3_1] + da=DataArrayInt() + da.alloc( 4, 4 ) + dv = 7 +#! [Snippet_DataArrayInt_setPartOfValuesSimple3_1] +#! [Snippet_DataArrayInt_setPartOfValuesSimple3_2] + da.fillWithZero() + da[[1,2], 1:3] = dv +#! [Snippet_DataArrayInt_setPartOfValuesSimple3_2] +#! [Snippet_DataArrayInt_setPartOfValuesSimple3_3] + da.fillWithZero() + da[[0,1,2,3], 1:2] = dv +#! [Snippet_DataArrayInt_setPartOfValuesSimple3_3] +#! [Snippet_DataArrayInt_setPartOfValuesSimple3_4] + da.fillWithZero() + da[[1], 0:4] = dv +#! [Snippet_DataArrayInt_setPartOfValuesSimple3_4] +#! [Snippet_DataArrayInt_setPartOfValuesSimple3_5] + da.fillWithZero() + da[[0,2], 1:4:2] = dv +#! [Snippet_DataArrayInt_setPartOfValuesSimple3_5] + return + + def testExample_DataArrayDouble_setSelectedComponents(self): +#! [Snippet_DataArrayDouble_setSelectedComponents1] + array1=[1.,2., 3.,4., 5.,6.] + da=DataArrayDouble(array1,3,2) + da.setInfoOnComponents( ["a1","a2"]) +#! [Snippet_DataArrayDouble_setSelectedComponents1] +#! [Snippet_DataArrayDouble_setSelectedComponents2] + dv=DataArrayDouble() + dv.alloc( 4, 4 ) + dv.fillWithZero() + dv.setInfoOnComponents( ["v1","v2","v3","v4"]) + dv2 = dv.deepCpy() + dv.setSelectedComponents( da, [1,0] ) +#! [Snippet_DataArrayDouble_setSelectedComponents2] +#! [Snippet_DataArrayDouble_setSelectedComponents3] + dv2[:3,[1,0]] = da + self.assertTrue( dv.isEqualWithoutConsideringStr( dv2, 1e-20 )) +#! [Snippet_DataArrayDouble_setSelectedComponents3] + return + + def testExample_DataArrayInt_setSelectedComponents(self): +#! [Snippet_DataArrayInt_setSelectedComponents1] + da=DataArrayInt() + array1=[1,2, 3,4, 5,6] + da.setValues(array1,3,2) + da.setInfoOnComponents( ["a1","a2"]) +#! [Snippet_DataArrayInt_setSelectedComponents1] +#! [Snippet_DataArrayInt_setSelectedComponents2] + dv=DataArrayInt() + dv.alloc( 4, 4 ) + dv.fillWithZero() + dv.setInfoOnComponents( ["v1","v2","v3","v4"]) + dv2 = dv.deepCpy() + dv.setSelectedComponents( da, [1,0] ) +#! [Snippet_DataArrayInt_setSelectedComponents2] +#! [Snippet_DataArrayInt_setSelectedComponents3] + dv2[:3,[1,0]] = da + self.assertTrue( dv.isEqualWithoutConsideringStr( dv2 )) +#! [Snippet_DataArrayInt_setSelectedComponents3] + return + + def testExample_DataArrayDouble_getDifferentValues(self): +#! [Snippet_DataArrayDouble_getDifferentValues1] + array1=[2.3,1.2,1.3,2.3,2.301,0.8] + da=DataArrayDouble(array1,6,1) + # + dv=da.getDifferentValues(2e-1) + expected2=[2.301,1.3,0.8] + self.assertEqual(3,dv.getNbOfElems()) + for i in xrange(3): + self.assertAlmostEqual(expected2[i],dv.getIJ(i,0),14) + pass +#! [Snippet_DataArrayDouble_getDifferentValues1] + return + + def testExample_DataArrayDouble_findCommonTuples1(self): +#! [PySnippet_DataArrayDouble_findCommonTuples1] + array2=[2.3,2.3, 1.2,1.2, 1.3,1.3, 2.3,2.3, 2.301,2.301, 0.8,0.8] + da=DataArrayDouble(array2,6,2) +#! [PySnippet_DataArrayDouble_findCommonTuples1] +#! [PySnippet_DataArrayDouble_findCommonTuples2] + c,cI=da.findCommonTuples(1.01e-1) + expected3=[0,3,4,1,2] + expected4=[0,3,5] + self.assertEqual(expected3,c.getValues()) + self.assertEqual(expected4,cI.getValues()) +#! [PySnippet_DataArrayDouble_findCommonTuples2] + return + + def testExampleDataArrayDoubleMeldWith(self): +#! [PySnippet_DataArrayDouble_Meld1_1] + da1=DataArrayDouble() + da1.alloc(7,2) + da2=DataArrayDouble() + da2.alloc(7,1) + # + da1.fillWithValue(7.) + da2.iota(0.) + da3=da2.applyFunc(3,"10*x*IVec+100*x*JVec+1000*x*KVec") + # + da1.setInfoOnComponent(0,"c0da1") + da1.setInfoOnComponent(1,"c1da1") + da3.setInfoOnComponent(0,"c0da3") + da3.setInfoOnComponent(1,"c1da3") + da3.setInfoOnComponent(2,"c2da3") + # + da1C=da1.deepCpy() + da1.meldWith(da3) +#! [PySnippet_DataArrayDouble_Meld1_1] + + def testExampleDataArrayIntMeldWith(self): +#! [PySnippet_DataArrayInt_Meld1_1] + da1=DataArrayInt() + da1.alloc(7,2) + da2=DataArrayInt() + da2.alloc(7,1) + # + da1.fillWithValue(7) + da2.iota(0) + # + da1.setInfoOnComponent(0,"c0da1") + da1.setInfoOnComponent(1,"c1da1") + da2.setInfoOnComponent(0,"c0da2") + # + da1.meldWith(da2) +#! [PySnippet_DataArrayInt_Meld1_1] + + def testExampleDataArrayDoubleKeepSelectedComponents1(self): +#! [SnippeDataArrayDoubleKeepSelectedComponents1_1] + arr1=[1.,2.,3.,4., # tuple 0 + 11.,12.,13.,14., # tuple 1 + 21.,22.,23.,24., # ... + 31.,32.,33.,34., + 41.,42.,43.,44.] + a1=DataArrayDouble(arr1,5,4) + a1.setInfoOnComponent(0,"a") + a1.setInfoOnComponent(1,"b") + a1.setInfoOnComponent(2,"c") + a1.setInfoOnComponent(3,"d") +#! [SnippeDataArrayDoubleKeepSelectedComponents1_1] +#! [SnippeDataArrayDoubleKeepSelectedComponents1_2] + arr2V=[1,2,1,2,0,0] + a2=a1.keepSelectedComponents(arr2V) +#! [SnippeDataArrayDoubleKeepSelectedComponents1_2] + return + + def testExampleDataArrayIntKeepSelectedComponents1(self): +#! [SnippeDataArrayIntKeepSelectedComponents1_1] + arr1=[1,2,3,4, # tuple 0 + 11,12,13,14, # tuple 1 + 21,22,23,24, # + 31,32,33,34, + 41,42,43,44] + a1=DataArrayInt() + a1.setValues(arr1,5,4) + a1.setInfoOnComponent(0,"a") + a1.setInfoOnComponent(1,"b") + a1.setInfoOnComponent(2,"c") + a1.setInfoOnComponent(3,"d") +#! [SnippeDataArrayIntKeepSelectedComponents1_1] +#! [SnippeDataArrayIntKeepSelectedComponents1_2] + arr2V=[1,2,1,2,0,0] + a2=a1.keepSelectedComponents(arr2V) +#! [SnippeDataArrayIntKeepSelectedComponents1_2] +#! [SnippeDataArrayIntKeepSelectedComponents1_3] + a3=a1[:,arr2V ] +#! [SnippeDataArrayIntKeepSelectedComponents1_3] + return + + def testExampleFieldDoubleBuildSubPart1(self): + from MEDCouplingDataForTest import MEDCouplingDataForTest +#! [PySnippetFieldDoubleBuildSubPart1_1] + mesh1=MEDCouplingDataForTest.build2DTargetMesh_1() + f1=MEDCouplingFieldDouble(ON_CELLS,ONE_TIME) + f1.setTime(2.3,5,6) + f1.setMesh(mesh1) + arr1=[3.,103.,4.,104.,5.,105.,6.,106.,7.,107.] + array=DataArrayDouble(arr1,mesh1.getNumberOfCells(),2) + f1.setArray(array) +# ! [PySnippetFieldDoubleBuildSubPart1_1] +# ! [PySnippetFieldDoubleBuildSubPart1_2] + part1=[2,1,4] + f2=f1.buildSubPart(part1) +# ! [PySnippetFieldDoubleBuildSubPart1_2] + f2.zipCoords() + self.assertEqual(3,f2.getNumberOfTuples()) + self.assertEqual(2,f2.getNumberOfComponents()) + expected1=[5.,105.,4.,104.,7.,107.] + for i in xrange(6): + self.assertAlmostEqual(f2.getIJ(0,i),expected1[i],12) + pass + self.assertEqual(3,f2.getMesh().getNumberOfCells()) + self.assertEqual(6,f2.getMesh().getNumberOfNodes()) + self.assertEqual(2,f2.getMesh().getSpaceDimension()) + self.assertEqual(2,f2.getMesh().getMeshDimension()) + m2C=f2.getMesh() + self.assertEqual(13,m2C.getMeshLength()) + expected2=[0.2, -0.3, 0.7, -0.3, 0.2, 0.2, 0.7, 0.2, 0.2, 0.7, 0.7, 0.7] + for i in xrange(12): + self.assertAlmostEqual(expected2[i],m2C.getCoords().getIJ(0,i),12) + pass + expected3=[3,2,3,1,3,0,2,1,4,4,5,3,2] + self.assertEqual(expected3,list(m2C.getNodalConnectivity().getValues())) + expected4=[0,4,8,13] + self.assertEqual(expected4,list(m2C.getNodalConnectivityIndex().getValues())) + # Test with field on nodes. +# ! [PySnippetFieldDoubleBuildSubPart1_3] + f1=MEDCouplingFieldDouble(ON_NODES,ONE_TIME) + f1.setTime(2.3,5,6) + f1.setMesh(mesh1) + arr2=[3.,103.,4.,104.,5.,105.,6.,106.,7.,107.,8.,108.,9.,109.,10.,110.,11.,111.] + array=DataArrayDouble(arr2,mesh1.getNumberOfNodes(),2) + f1.setArray(array) +# ! [PySnippetFieldDoubleBuildSubPart1_3] +# ! [PySnippetFieldDoubleBuildSubPart1_4] + part2=[1,2] + f2=f1.buildSubPart(part2) +# ! [PySnippetFieldDoubleBuildSubPart1_4] + self.assertEqual(4,f2.getNumberOfTuples()) + self.assertEqual(2,f2.getNumberOfComponents()) + expected5=[4.,104.,5.,105.,7.,107.,8.,108.] + for i in xrange(8): + self.assertAlmostEqual(f2.getIJ(0,i),expected5[i],12) + pass + self.assertEqual(2,f2.getMesh().getNumberOfCells()) + self.assertEqual(4,f2.getMesh().getNumberOfNodes()) + self.assertEqual(2,f2.getMesh().getSpaceDimension()) + self.assertEqual(2,f2.getMesh().getMeshDimension()) + m2C=f2.getMesh() + self.assertEqual(8,m2C.getMeshLength()) + for i in xrange(8):#8 is not an error + self.assertAlmostEqual(expected2[i],m2C.getCoords().getIJ(0,i),12) + pass + self.assertEqual(expected3[:4],[int(i) for i in m2C.getNodalConnectivity()][4:]) + self.assertEqual(expected3[4:8],[int(i) for i in m2C.getNodalConnectivity()][:4]) + self.assertEqual(expected4[:3],[int(i) for i in m2C.getNodalConnectivityIndex()]) + #idem previous because nodes of cell#4 are not fully present in part3 + part3=[1,2] + arrr=DataArrayInt() + arrr.setValues(part3,2,1) + f2=f1.buildSubPart(arrr) + self.assertEqual(4,f2.getNumberOfTuples()) + self.assertEqual(2,f2.getNumberOfComponents()) + for i in xrange(8): + self.assertAlmostEqual(f2.getIJ(0,i),expected5[i],12) + pass + self.assertEqual(2,f2.getMesh().getNumberOfCells()) + self.assertEqual(4,f2.getMesh().getNumberOfNodes()) + self.assertEqual(2,f2.getMesh().getSpaceDimension()) + self.assertEqual(2,f2.getMesh().getMeshDimension()) + m2C=f2.getMesh() + self.assertEqual(8,m2C.getMeshLength()) + for i in xrange(8):#8 is not an error + self.assertAlmostEqual(expected2[i],m2C.getCoords().getIJ(0,i),12) + pass + self.assertEqual(expected3[:4],[int(i) for i in m2C.getNodalConnectivity()][4:8]) + self.assertEqual(expected3[4:8],[int(i) for i in m2C.getNodalConnectivity()][:4]) + self.assertEqual(expected4[:3],m2C.getNodalConnectivityIndex().getValues()) + part4=[1,2,4] + f2=f1.buildSubPart(part4) + self.assertEqual(6,f2.getNumberOfTuples()) + self.assertEqual(2,f2.getNumberOfComponents()) + expected6=[4.,104.,5.,105.,7.,107.,8.,108.,10.,110.,11.,111.] + for i in xrange(12): + self.assertAlmostEqual(f2.getIJ(0,i),expected6[i],12) + pass + self.assertEqual(3,f2.getMesh().getNumberOfCells()) + self.assertEqual(6,f2.getMesh().getNumberOfNodes()) + self.assertEqual(2,f2.getMesh().getSpaceDimension()) + self.assertEqual(2,f2.getMesh().getMeshDimension()) + m2C=f2.getMesh() + self.assertEqual(13,m2C.getMeshLength()) + for i in xrange(12): + self.assertAlmostEqual(expected2[i],m2C.getCoords().getIJ(0,i),12) + pass + self.assertEqual(expected3[0:4],m2C.getNodalConnectivity().getValues()[4:8]) + self.assertEqual(expected3[4:8],m2C.getNodalConnectivity().getValues()[0:4]) + self.assertEqual(expected3[8:13],m2C.getNodalConnectivity().getValues()[8:13]) + self.assertEqual(expected4,m2C.getNodalConnectivityIndex().getValues()) + # previous line equivalent to + self.assertEqual(expected4,[int(i) for i in m2C.getNodalConnectivityIndex()]) + return + + def testExampleUMeshStdBuild1(self): +# ! [PySnippetUMeshStdBuild1_1] + coords=[-0.3,-0.3,0., 0.2,-0.3,0., 0.7,-0.3,0., -0.3,0.2,0., 0.2,0.2,0., + 0.7,0.2,0., -0.3,0.7,0., 0.2,0.7,0., 0.7,0.7,0. ] + nodalConnPerCell=[0,3,4,1, 1,4,2, 4,5,2, 6,7,4,3, 7,8,5,4] +# ! [PySnippetUMeshStdBuild1_1] +# ! [PySnippetUMeshStdBuild1_2] + mesh=MEDCouplingUMesh("My2DMesh",2) +# ! [PySnippetUMeshStdBuild1_2] +# ! [PySnippetUMeshStdBuild1_3] + mesh.allocateCells(5)#You can put more than 5 if you want but not less. + mesh.insertNextCell(NORM_QUAD4,nodalConnPerCell[:4]) + mesh.insertNextCell(NORM_TRI3,nodalConnPerCell[4:7]) + mesh.insertNextCell(NORM_TRI3,nodalConnPerCell[7:10]) + mesh.insertNextCell(NORM_QUAD4,nodalConnPerCell[10:14]) + mesh.insertNextCell(NORM_QUAD4,nodalConnPerCell[14:]) + mesh.finishInsertingCells() +# ! [PySnippetUMeshStdBuild1_3] +# ! [PySnippetUMeshStdBuild1_4] + coordsArr=DataArrayDouble(coords,9,3)#here coordsArr are declared to have 3 components, mesh will deduce that its spaceDim==3. + mesh.setCoords(coordsArr)#coordsArr contains 9 tuples, that is to say mesh contains 9 nodes. +# ! [PySnippetUMeshStdBuild1_4] +# ! [PySnippetUMeshStdBuild1_5] +# ! [PySnippetUMeshStdBuild1_5] + mesh.checkCoherency() + return + + def testExampleCMeshStdBuild1(self): +# ! [PySnippetCMeshStdBuild1_1] + XCoords=[-0.3,0.,0.1,0.3,0.45,0.47,0.49,1.,1.22] # 9 values along X + YCoords=[0.,0.1,0.37,0.45,0.47,0.49,1.007] # 7 values along Y + arrX=DataArrayDouble(XCoords) + arrX.setInfoOnComponent(0,"X [m]") + arrY=DataArrayDouble(YCoords) + arrY.setInfoOnComponent(0,"Y [m]") +# ! [PySnippetCMeshStdBuild1_1] +# ! [PySnippetCMeshStdBuild1_2] + mesh=MEDCouplingCMesh("My2D_CMesh") + mesh.setCoords(arrX,arrY) +# ! [PySnippetCMeshStdBuild1_2] +# ! [PySnippetCMeshStdBuild1_3] + self.assertEqual(8*6,mesh.getNumberOfCells()) + self.assertEqual(9*7,mesh.getNumberOfNodes()) + self.assertEqual(2,mesh.getSpaceDimension()) + self.assertEqual(2,mesh.getMeshDimension()) +# ! [PySnippetCMeshStdBuild1_3] + mesh=MEDCouplingCMesh("My2D_CMesh") +# ! [PySnippetCMeshStdBuild1_2bis] + mesh.setCoordsAt(0,arrX) + mesh.setCoordsAt(1,arrY) +# ! [PySnippetCMeshStdBuild1_2bis] + self.assertEqual(8*6,mesh.getNumberOfCells()) + self.assertEqual(9*7,mesh.getNumberOfNodes()) + self.assertEqual(2,mesh.getSpaceDimension()) + self.assertEqual(2,mesh.getMeshDimension()) ++# ! [PySnippetCMeshStdBuild1_4] ++# ! [PySnippetCMeshStdBuild1_4] + return + + def testExampleUMeshAdvBuild1(self): +# ! [PySnippetUMeshAdvBuild1_1] + coords=[-0.3,-0.3,0., 0.2,-0.3,0., 0.7,-0.3,0., -0.3,0.2,0., 0.2,0.2,0., + 0.7,0.2,0., -0.3,0.7,0., 0.2,0.7,0., 0.7,0.7,0. ] + nodalConnPerCell=[4,0,3,4,1, 3,1,4,2, 3,4,5,2, 4,6,7,4,3, 4,7,8,5,4] + nodalConnPerCellIndex=[0,5,9,13,18,23] +# ! [PySnippetUMeshAdvBuild1_1] +# ! [PySnippetUMeshAdvBuild1_2] + mesh=MEDCouplingUMesh("My2DMesh",2) +# ! [PySnippetUMeshAdvBuild1_2] +# ! [PySnippetUMeshAdvBuild1_3] + nodalConn=DataArrayInt(nodalConnPerCell,23,1) + nodalConnI=DataArrayInt(nodalConnPerCellIndex,6,1) + mesh.setConnectivity(nodalConn,nodalConnI,True) +# ! [PySnippetUMeshAdvBuild1_3] +# ! [PySnippetUMeshAdvBuild1_4] + coordsArr=DataArrayDouble(coords,9,3)#here coordsArr are declared to have 3 components, mesh will deduce that its spaceDim==3. + mesh.setCoords(coordsArr)#coordsArr contains 9 tuples, that is to say mesh contains 9 nodes. +# ! [PySnippetUMeshAdvBuild1_4] +# ! [PySnippetUMeshAdvBuild1_5] +# ! [PySnippetUMeshAdvBuild1_5] + mesh.checkCoherency() + return + + def testExampleDataArrayBuild1(self): +# ! [PySnippetDataArrayBuild1_0] + dataDouble=[0.,10.,20.,1.,11.,21.,2.,12.,22.,3.,13.,23.,4.,14.,24.] +# ! [PySnippetDataArrayBuild1_0] +# ! [PySnippetDataArrayBuild1_1] + arrayDouble=DataArrayDouble() + arrayDouble.setValues(dataDouble,5,3)# 5 tuples containing each 3 components +# ! [PySnippetDataArrayBuild1_1] +# ! [PySnippetDataArrayBuild1_1bis] + arrayDouble=DataArrayDouble(dataDouble,5,3) +# ! [PySnippetDataArrayBuild1_1bis] +# ! [PySnippetDataArrayBuild1_2] + dataInt=[0, 10, 20, 1, 11, 21, 2, 12, 22, 3, 13, 23, 4, 14, 24] +# ! [PySnippetDataArrayBuild1_2] +# ! [PySnippetDataArrayBuild1_3] + arrayInt=DataArrayInt() + arrayInt.setValues(dataInt,5,3)# 5 tuples containing each 3 components +# ! [PySnippetDataArrayBuild1_3] +# ! [PySnippetDataArrayBuild1_3bis] + arrayInt=DataArrayInt(dataInt,5,3) +# ! [PySnippetDataArrayBuild1_3bis] + return + + def testExampleFieldDoubleBuild1(self): + XCoords=[-0.3,0.07,0.1,0.3,0.45,0.47,0.49,1.,1.22]; arrX=DataArrayDouble(XCoords) + YCoords=[0.07,0.1,0.37,0.45,0.47,0.49,1.007]; arrY=DataArrayDouble(YCoords) + mesh=MEDCouplingCMesh("My2D_CMesh") + mesh.setCoords(arrX,arrY) +# ! [PySnippetFieldDoubleBuild1_1] + fieldOnCells=MEDCouplingFieldDouble(ON_CELLS,NO_TIME) + fieldOnCells.setName("MyTensorFieldOnCellNoTime") + fieldOnCells.setMesh(mesh) + array=DataArrayDouble() + array.alloc(fieldOnCells.getMesh().getNumberOfCells(),9) # Implicitely fieldOnCells will be a 9 components field. + array.fillWithValue(7.) + fieldOnCells.setArray(array) + # fieldOnCells is now usable + # ... +# ! [PySnippetFieldDoubleBuild1_1] +# ! [PySnippetFieldDoubleBuild1_2] + f1=mesh.fillFromAnalytic(ON_CELLS,1,"x*x+y*y*3+2.*x") # f1 is scalar + f2=mesh.fillFromAnalytic(ON_CELLS,1,"cos(x+y/x)") # f2 is scalar too + f2bis=mesh.fillFromAnalytic(ON_CELLS,2,"x*x*IVec+3*y*JVec") # f2bis is a vectors field + f3=f1+f2 # f3 scalar + f4=f3/f2 # f4 scalar + f2bis.applyFunc(1,"sqrt(x*x+y*y)") # f2bis becomes scalar + f5=f2bis*f4 # f5 scalar + pos1=[0.48,0.38] + res=f4.getValueOn(pos1) # f4 is scalar so the returned value is of size 1. + # ... +# ! [PySnippetFieldDoubleBuild1_2] +# ! [PySnippetFieldDoubleBuild1_3] +# ! [PySnippetFieldDoubleBuild1_3] + return + + def testExampleFieldDoubleBuild2(self): + XCoords=[-0.3,0.,0.1,0.3,0.45,0.47,0.49,1.,1.22]; arrX=DataArrayDouble(XCoords) + YCoords=[0.,0.1,0.37,0.45,0.47,0.49,1.007]; arrY=DataArrayDouble(YCoords) + mesh=MEDCouplingCMesh("My2D_CMesh") + mesh.setCoords(arrX,arrY) +# ! [PySnippetFieldDoubleBuild2_1] + fieldOnNodes=MEDCouplingFieldDouble(ON_NODES,NO_TIME) + fieldOnNodes.setName("MyScalarFieldOnNodeNoTime") + fieldOnNodes.setMesh(mesh) + array=DataArrayDouble() + array.alloc(fieldOnNodes.getMesh().getNumberOfNodes(),1) # Implicitely fieldOnNodes will be a 1 component field. + array.fillWithValue(7.) + fieldOnNodes.setArray(array) + # fieldOnNodes is now usable + # ... +# ! [PySnippetFieldDoubleBuild2_1] + return + + def testExampleFieldDoubleBuild3(self): + XCoords=[-0.3,0.,0.1,0.3,0.45,0.47,0.49,1.,1.22]; arrX=DataArrayDouble(XCoords) + YCoords=[0.,0.1,0.37,0.45,0.47,0.49,1.007]; arrY=DataArrayDouble(YCoords) + mesh=MEDCouplingCMesh("My2D_CMesh") + mesh.setCoords(arrX,arrY) +# ! [PySnippetFieldDoubleBuild3_1] + fieldOnCells=MEDCouplingFieldDouble(ON_CELLS,ONE_TIME) + fieldOnCells.setName("MyTensorFieldOnCellNoTime") + fieldOnCells.setTimeUnit("ms") # Time unit is ms. + fieldOnCells.setTime(4.22,2,-1) # Time attached is 4.22 ms, iteration id is 2 and order id (or sub iteration id) is -1 + fieldOnCells.setMesh(mesh) + array=DataArrayDouble() + array.alloc(fieldOnCells.getMesh().getNumberOfCells(),2) # Implicitely fieldOnCells will be a 2 components field. + array.fillWithValue(7.) + fieldOnCells.setArray(array) + # fieldOnCells is now usable + # ... +# ! [PySnippetFieldDoubleBuild3_1] + return + + def testExampleFieldDoubleBuild4(self): + XCoords=[-0.3,0.,0.1,0.3,0.45,0.47,0.49,1.,1.22]; arrX=DataArrayDouble(XCoords) + YCoords=[0.,0.1,0.37,0.45,0.47,0.49,1.007]; arrY=DataArrayDouble(YCoords) + mesh=MEDCouplingCMesh("My2D_CMesh") + mesh.setCoords(arrX,arrY) +# ! [PySnippetFieldDoubleBuild4_1] + fieldOnNodes=MEDCouplingFieldDouble(ON_NODES,CONST_ON_TIME_INTERVAL) + fieldOnNodes.setName("MyVecFieldOnNodeWithConstTime") + fieldOnNodes.setTimeUnit("ms") # Time unit is ms. + fieldOnNodes.setStartTime(4.22,2,-1) + fieldOnNodes.setEndTime(6.44,4,-1)# fieldOnNodes is defined in interval [4.22 ms,6.44 ms] + fieldOnNodes.setMesh(mesh) + array=DataArrayDouble() + array.alloc(fieldOnNodes.getMesh().getNumberOfNodes(),3) # Implicitely fieldOnNodes will be a 3 components field. + array.fillWithValue(7.) + fieldOnNodes.setArray(array) + # fieldOnNodes is now usable + # ... +# ! [PySnippetFieldDoubleBuild4_1] + return + + def testExampleDataArrayApplyFunc1(self): +# ! [PySnippetDataArrayApplyFunc1_1] + d=DataArrayDouble([1.,2.,11.,12.,21.,22.,31.,41.],4,2) + self.assertRaises(InterpKernelException,d.applyFunc,"x*y") +# ! [PySnippetDataArrayApplyFunc1_1] +# ! [PySnippetDataArrayApplyFunc1_2] + d=DataArrayDouble([1.,2.,11.,12.,21.,22.,31.,41.],4,2) + d1=d.applyFunc("smth*smth") + self.assertTrue(d1.isEqual(DataArrayDouble([1.,4.,121.,144.,441.,484.,961.,1681.],4,2),1e-12)) +# ! [PySnippetDataArrayApplyFunc1_2] +# ! [PySnippetDataArrayApplyFunc1_3] + d2=d.applyFunc(2,"smth1*IVec+2*smth2*JVec") + self.assertTrue(d2.isEqual(DataArrayDouble([1.,4.,11.,24.,21.,44.,31.,82.],4,2),1e-12)) +# ! [PySnippetDataArrayApplyFunc1_3] +# ! [PySnippetDataArrayApplyFunc1_4] + dd=DataArrayDouble([1.,4.,3.,11.,144.,13.,21.,484.,23.,31.,1024.,33.],4,3) +# ! [PySnippetDataArrayApplyFunc1_4] +# ! [PySnippetDataArrayApplyFunc1_5] + dd1=dd.applyFunc(1,"f+sqrt(g)+h") + self.assertTrue(dd1.isEqual(DataArrayDouble([6.,36.,66.,96.],4,1),1e-12)) +# ! [PySnippetDataArrayApplyFunc1_5] +# ! [PySnippetDataArrayApplyFunc1_6] + dd2=dd.applyFunc(1,"a+0.*b+c") + self.assertTrue(dd2.isEqual(DataArrayDouble([4.,24.,44.,64.],4,1),1e-12)) +# ! [PySnippetDataArrayApplyFunc1_6] +# ! [PySnippetDataArrayApplyFunc1_7] + ddd=DataArrayDouble([1.,4.,3.,11.,144.,13.,21.,484.,23.,31.,1024.,33.],4,3) + ddd.setInfoOnComponents(["Y [m]","AA [m/s]","GG [MW]"]) +# ! [PySnippetDataArrayApplyFunc1_7] +# ! [PySnippetDataArrayApplyFunc1_8] + ddd1=ddd.applyFunc2(1,"Y+GG") + self.assertTrue(ddd1.isEqual(DataArrayDouble([4.,24.,44.,64.],4,1),1e-12)) +# ! [PySnippetDataArrayApplyFunc1_8] +# ! [PySnippetDataArrayApplyFunc1_9] + ddd1=ddd.applyFunc3(1,["X","Y","Z"],"X+Z") + self.assertTrue(ddd1.isEqual(DataArrayDouble([4.,24.,44.,64.],4,1),1e-12)) +# ! [PySnippetDataArrayApplyFunc1_9] + return + + pass + +unittest.main() diff --cc medtool/src/MEDLoader/MEDFileMeshLL.cxx index cf6177beb,000000000..8fad6bf6f mode 100644,000000..100644 --- a/medtool/src/MEDLoader/MEDFileMeshLL.cxx +++ b/medtool/src/MEDLoader/MEDFileMeshLL.cxx @@@ -1,1707 -1,0 +1,1707 @@@ +// Copyright (C) 2007-2015 CEA/DEN, EDF R&D +// +// 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +// +// See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com +// +// Author : Anthony Geay (CEA/DEN) + +#include "MEDFileMeshLL.hxx" +#include "MEDFileMesh.hxx" +#include "MEDLoaderBase.hxx" +#include "MEDFileSafeCaller.txx" +#include "MEDFileMeshReadSelector.hxx" + +#include "MEDCouplingUMesh.hxx" + +#include "InterpKernelAutoPtr.hxx" +#include "CellModel.hxx" + +#include + +extern med_geometry_type typmai[MED_N_CELL_FIXED_GEO]; +extern INTERP_KERNEL::NormalizedCellType typmai2[MED_N_CELL_FIXED_GEO]; +extern med_geometry_type typmainoeud[1]; + +using namespace ParaMEDMEM; + +MEDFileMeshL2::MEDFileMeshL2():_name(MED_NAME_SIZE),_description(MED_COMMENT_SIZE),_univ_name(MED_LNAME_SIZE),_dt_unit(MED_LNAME_SIZE) +{ +} + +std::size_t MEDFileMeshL2::getHeapMemorySizeWithoutChildren() const +{ + return 0; +} + +std::vector MEDFileMeshL2::getDirectChildrenWithNull() const +{ + return std::vector(); +} + +int MEDFileMeshL2::GetMeshIdFromName(med_idt fid, const std::string& mname, ParaMEDMEM::MEDCouplingMeshType& meshType, int& dt, int& it, std::string& dtunit1) +{ + med_mesh_type type_maillage; + char maillage_description[MED_COMMENT_SIZE+1]; + char dtunit[MED_LNAME_SIZE+1]; + med_int spaceDim,dim; + char nommaa[MED_NAME_SIZE+1]; + med_int n=MEDnMesh(fid); + bool found=false; + int ret=-1; + med_sorting_type stype; + std::vector ms; + int nstep; + med_axis_type axistype; + for(int i=0;i axisname=MEDLoaderBase::buildEmptyString(naxis*MED_SNAME_SIZE); + INTERP_KERNEL::AutoPtr axisunit=MEDLoaderBase::buildEmptyString(naxis*MED_SNAME_SIZE); + MEDFILESAFECALLERRD0(MEDmeshInfo,(fid,i+1,nommaa,&spaceDim,&dim,&type_maillage,maillage_description,dtunit,&stype,&nstep,&axistype,axisname,axisunit)); + dtunit1=MEDLoaderBase::buildStringFromFortran(dtunit,sizeof(dtunit)); + std::string cur=MEDLoaderBase::buildStringFromFortran(nommaa,sizeof(nommaa)); + ms.push_back(cur); + if(cur==mname) + { + found=true; + ret=i+1; + } + } + if(!found) + { + std::ostringstream oss; + oss << "No such meshname (" << mname << ") in file ! Must be in : "; + std::copy(ms.begin(),ms.end(),std::ostream_iterator(oss,", ")); + throw INTERP_KERNEL::Exception(oss.str().c_str()); + } + switch(type_maillage) + { + case MED_UNSTRUCTURED_MESH: + meshType=UNSTRUCTURED; + break; + case MED_STRUCTURED_MESH: + { + med_grid_type gt; + MEDFILESAFECALLERRD0(MEDmeshGridTypeRd,(fid,mname.c_str(),>)); + switch(gt) + { + case MED_CARTESIAN_GRID: + meshType=CARTESIAN; + break; + case MED_CURVILINEAR_GRID: + meshType=CURVE_LINEAR; + break; + default: + throw INTERP_KERNEL::Exception("MEDFileUMeshL2::getMeshIdFromName : unrecognized structured mesh type ! Supported are :\n - cartesian\n - curve linear\n"); + } + break; + } + default: + throw INTERP_KERNEL::Exception("MEDFileUMeshL2::getMeshIdFromName : unrecognized mesh type !"); + } + med_int numdt,numit; + med_float dtt; + MEDFILESAFECALLERRD0(MEDmeshComputationStepInfo,(fid,mname.c_str(),1,&numdt,&numit,&dtt)); + dt=numdt; it=numit; + return ret; +} + +double MEDFileMeshL2::CheckMeshTimeStep(med_idt fid, const std::string& mName, int nstep, int dt, int it) +{ + bool found=false; + med_int numdt,numit; + med_float dtt; + std::vector< std::pair > p(nstep); + for(int i=0;i MEDFileMeshL2::getAxisInfoOnMesh(med_idt fid, int mId, const std::string& mName, ParaMEDMEM::MEDCouplingMeshType& meshType, int& nstep, int& Mdim) +{ + med_mesh_type type_maillage; + med_int spaceDim; + med_sorting_type stype; + med_axis_type axistype; + int naxis(MEDmeshnAxis(fid,mId)); + INTERP_KERNEL::AutoPtr nameTmp=MEDLoaderBase::buildEmptyString(MED_NAME_SIZE); + INTERP_KERNEL::AutoPtr axisname=MEDLoaderBase::buildEmptyString(naxis*MED_SNAME_SIZE); + INTERP_KERNEL::AutoPtr axisunit=MEDLoaderBase::buildEmptyString(naxis*MED_SNAME_SIZE); + INTERP_KERNEL::AutoPtr univTmp=MEDLoaderBase::buildEmptyString(MED_LNAME_SIZE); + if(MEDmeshInfo(fid,mId,nameTmp,&spaceDim,&Mdim,&type_maillage,_description.getPointer(),_dt_unit.getPointer(), + &stype,&nstep,&axistype,axisname,axisunit)!=0) + throw INTERP_KERNEL::Exception("A problem has been detected when trying to get info on mesh !"); + MEDmeshUniversalNameRd(fid,nameTmp,_univ_name.getPointer());// do not protect MEDFILESAFECALLERRD0 call : Thanks to fra.med. + switch(type_maillage) + { + case MED_UNSTRUCTURED_MESH: + meshType=UNSTRUCTURED; + break; + case MED_STRUCTURED_MESH: + { + med_grid_type gt; + MEDFILESAFECALLERRD0(MEDmeshGridTypeRd,(fid,mName.c_str(),>)); + switch(gt) + { + case MED_CARTESIAN_GRID: + meshType=CARTESIAN; + break; + case MED_CURVILINEAR_GRID: + meshType=CURVE_LINEAR; + break; + default: + throw INTERP_KERNEL::Exception("MEDFileUMeshL2::getAxisInfoOnMesh : unrecognized structured mesh type ! Supported are :\n - cartesian\n - curve linear\n"); + } + break; + } + default: + throw INTERP_KERNEL::Exception("MEDFileUMeshL2::getMeshIdFromName : unrecognized mesh type !"); + } + // + std::vector infosOnComp(naxis); + for(int i=0;i& fams, std::map >& grps, MEDFileMeshReadSelector *mrs) +{ + if(mrs && !(mrs->isCellFamilyFieldReading() || mrs->isNodeFamilyFieldReading())) + return ; + char nomfam[MED_NAME_SIZE+1]; + med_int numfam; + int nfam=MEDnFamily(fid,meshName.c_str()); + for(int i=0;i attide=new med_int[natt]; + INTERP_KERNEL::AutoPtr attval=new med_int[natt]; + INTERP_KERNEL::AutoPtr attdes=new char[MED_COMMENT_SIZE*natt+1]; + INTERP_KERNEL::AutoPtr gro=new char[MED_LNAME_SIZE*ngro+1]; + MEDfamily23Info(fid,meshName.c_str(),i+1,nomfam,attide,attval,attdes,&numfam,gro); + std::string famName=MEDLoaderBase::buildStringFromFortran(nomfam,MED_NAME_SIZE); + fams[famName]=numfam; + for(int j=0;j& fams, const std::map >& grps, int tooLongStrPol) +{ + for(std::map::const_iterator it=fams.begin();it!=fams.end();it++) + { + std::vector grpsOfFam; + for(std::map >::const_iterator it1=grps.begin();it1!=grps.end();it1++) + { + if(std::find((*it1).second.begin(),(*it1).second.end(),(*it).first)!=(*it1).second.end()) + grpsOfFam.push_back((*it1).first); + } + int ngro=grpsOfFam.size(); + INTERP_KERNEL::AutoPtr groName=MEDLoaderBase::buildEmptyString(MED_LNAME_SIZE*ngro); + int i=0; + for(std::vector::const_iterator it2=grpsOfFam.begin();it2!=grpsOfFam.end();it2++,i++) + MEDLoaderBase::safeStrCpy2((*it2).c_str(),MED_LNAME_SIZE-1,groName+i*MED_LNAME_SIZE,tooLongStrPol); + INTERP_KERNEL::AutoPtr famName=MEDLoaderBase::buildEmptyString(MED_NAME_SIZE); + MEDLoaderBase::safeStrCpy((*it).first.c_str(),MED_NAME_SIZE,famName,tooLongStrPol); + int ret=MEDfamilyCr(fid,mname.c_str(),famName,(*it).second,ngro,groName); + ret++; + } +} + +MEDFileUMeshL2::MEDFileUMeshL2() +{ +} + +std::vector MEDFileUMeshL2::loadCommonPart(med_idt fid, int mId, const std::string& mName, int dt, int it, int& Mdim) +{ + Mdim=-3; + _name.set(mName.c_str()); + int nstep; + ParaMEDMEM::MEDCouplingMeshType meshType; + std::vector ret(getAxisInfoOnMesh(fid,mId,mName.c_str(),meshType,nstep,Mdim)); + if(nstep==0) + { + Mdim=-4; + return std::vector(); + } + if(meshType!=UNSTRUCTURED) + throw INTERP_KERNEL::Exception("Invalid mesh type ! You are expected an unstructured one whereas in file it is not an unstructured !"); + _time=CheckMeshTimeStep(fid,mName,nstep,dt,it); + _iteration=dt; + _order=it; + return ret; +} + +void MEDFileUMeshL2::loadAll(med_idt fid, int mId, const std::string& mName, int dt, int it, MEDFileMeshReadSelector *mrs) +{ + int Mdim; + std::vector infosOnComp(loadCommonPart(fid,mId,mName,dt,it,Mdim)); + if(Mdim==-4) + return ; + loadConnectivity(fid,Mdim,mName,dt,it,mrs);//to improve check (dt,it) coherency + loadCoords(fid,mId,infosOnComp,mName,dt,it); +} + +void MEDFileUMeshL2::loadPart(med_idt fid, int mId, const std::string& mName, const std::vector& types, const std::vector& slicPerTyp, int dt, int it, MEDFileMeshReadSelector *mrs) +{ + int Mdim; + std::vector infosOnComp(loadCommonPart(fid,mId,mName,dt,it,Mdim)); + if(Mdim==-4) + return ; + loadPartOfConnectivity(fid,Mdim,mName,types,slicPerTyp,dt,it,mrs); + med_bool changement,transformation; + int nCoords(MEDmeshnEntity(fid,mName.c_str(),dt,it,MED_NODE,MED_NONE,MED_COORDINATE,MED_NO_CMODE,&changement,&transformation)); + std::vector fetchedNodeIds(nCoords,false); + for(std::vector< std::vector< MEDCouplingAutoRefCountObjectPtr > >::const_iterator it0=_per_type_mesh.begin();it0!=_per_type_mesh.end();it0++) + for(std::vector< MEDCouplingAutoRefCountObjectPtr >::const_iterator it1=(*it0).begin();it1!=(*it0).end();it1++) + (*it1)->getMesh()->computeNodeIdsAlg(fetchedNodeIds); + int nMin(std::distance(fetchedNodeIds.begin(),std::find(fetchedNodeIds.begin(),fetchedNodeIds.end(),true))); + int nMax(std::distance(fetchedNodeIds.rbegin(),std::find(fetchedNodeIds.rbegin(),fetchedNodeIds.rend(),true))); + nMax=nCoords-nMax; + for(std::vector< std::vector< MEDCouplingAutoRefCountObjectPtr > >::const_iterator it0=_per_type_mesh.begin();it0!=_per_type_mesh.end();it0++) + for(std::vector< MEDCouplingAutoRefCountObjectPtr >::const_iterator it1=(*it0).begin();it1!=(*it0).end();it1++) + (*it1)->getMesh()->renumberNodesWithOffsetInConn(-nMin); + loadPartCoords(fid,mId,infosOnComp,mName,dt,it,nMin,nMax); +} + +void MEDFileUMeshL2::loadConnectivity(med_idt fid, int mdim, const std::string& mName, int dt, int it, MEDFileMeshReadSelector *mrs) +{ + _per_type_mesh.resize(1); + _per_type_mesh[0].clear(); + for(int j=0;j& types, const std::vector& slicPerTyp, int dt, int it, MEDFileMeshReadSelector *mrs) +{ + std::size_t nbOfTypes(types.size()); + if(slicPerTyp.size()!=3*nbOfTypes) + throw INTERP_KERNEL::Exception("MEDFileUMeshL2::loadPartOfConnectivity : The size of slicPerTyp array is expected to be equal to 3 times size of array types !"); + std::set types2(types.begin(),types.end()); + if(types2.size()!=nbOfTypes) + throw INTERP_KERNEL::Exception("MEDFileUMeshL2::loadPartOfConnectivity : the geometric types in types array must appear once !"); + _per_type_mesh.resize(1); + _per_type_mesh[0].clear(); + for(std::size_t ii=0;ii tmp(MEDFileUMeshPerType::NewPart(fid,mName.c_str(),dt,it,mdim,types[ii],strt,stp,step,mrs)); + _per_type_mesh[0].push_back(tmp); + } + sortTypes(); +} + +void MEDFileUMeshL2::loadCoords(med_idt fid, int mId, const std::vector& infosOnComp, const std::string& mName, int dt, int it) +{ + int spaceDim((int)infosOnComp.size()); + med_bool changement,transformation; + int nCoords(MEDmeshnEntity(fid,mName.c_str(),dt,it,MED_NODE,MED_NONE,MED_COORDINATE,MED_NO_CMODE,&changement,&transformation)); + _coords=DataArrayDouble::New(); + _coords->alloc(nCoords,spaceDim); + double *coordsPtr(_coords->getPointer()); + if (nCoords) + MEDFILESAFECALLERRD0(MEDmeshNodeCoordinateRd,(fid,mName.c_str(),dt,it,MED_FULL_INTERLACE,coordsPtr)); + if(MEDmeshnEntity(fid,mName.c_str(),dt,it,MED_NODE,MED_NO_GEOTYPE,MED_FAMILY_NUMBER,MED_NODAL,&changement,&transformation)>0) + { + _fam_coords=DataArrayInt::New(); + _fam_coords->alloc(nCoords,1); + MEDFILESAFECALLERRD0(MEDmeshEntityFamilyNumberRd,(fid,mName.c_str(),dt,it,MED_NODE,MED_NO_GEOTYPE,_fam_coords->getPointer())); + } + else + _fam_coords=0; + if(MEDmeshnEntity(fid,mName.c_str(),dt,it,MED_NODE,MED_NO_GEOTYPE,MED_NUMBER,MED_NODAL,&changement,&transformation)>0) + { + _num_coords=DataArrayInt::New(); + _num_coords->alloc(nCoords,1); + MEDFILESAFECALLERRD0(MEDmeshEntityNumberRd,(fid,mName.c_str(),dt,it,MED_NODE,MED_NO_GEOTYPE,_num_coords->getPointer())); + } + else + _num_coords=0; + if(MEDmeshnEntity(fid,mName.c_str(),dt,it,MED_NODE,MED_NO_GEOTYPE,MED_NAME,MED_NODAL,&changement,&transformation)>0) + { + _name_coords=DataArrayAsciiChar::New(); + _name_coords->alloc(nCoords+1,MED_SNAME_SIZE);//not a bug to avoid the memory corruption due to last \0 at the end + MEDFILESAFECALLERRD0(MEDmeshEntityNameRd,(fid,mName.c_str(),dt,it,MED_NODE,MED_NO_GEOTYPE,_name_coords->getPointer())); + _name_coords->reAlloc(nCoords);//not a bug to avoid the memory corruption due to last \0 at the end + } + else + _name_coords=0; + for(int i=0;isetInfoOnComponent(i,infosOnComp[i]); +} + +void MEDFileUMeshL2::loadPartCoords(med_idt fid, int mId, const std::vector& infosOnComp, const std::string& mName, int dt, int it, int nMin, int nMax) +{ + med_bool changement,transformation; + int spaceDim((int)infosOnComp.size()),nCoords(MEDmeshnEntity(fid,mName.c_str(),dt,it,MED_NODE,MED_NONE,MED_COORDINATE,MED_NO_CMODE,&changement,&transformation)); + _coords=DataArrayDouble::New(); + int nbNodesToLoad(nMax-nMin); + _coords->alloc(nbNodesToLoad,spaceDim); + med_filter filter=MED_FILTER_INIT,filter2=MED_FILTER_INIT; + MEDfilterBlockOfEntityCr(fid,/*nentity*/nCoords,/*nvaluesperentity*/1,/*nconstituentpervalue*/spaceDim, + MED_ALL_CONSTITUENT,MED_FULL_INTERLACE,MED_COMPACT_STMODE,MED_NO_PROFILE, + /*start*/nMin+1,/*stride*/1,/*count*/1,/*blocksize*/nbNodesToLoad, + /*lastblocksize=useless because count=1*/0,&filter); + MEDFILESAFECALLERRD0(MEDmeshNodeCoordinateAdvancedRd,(fid,mName.c_str(),dt,it,&filter,_coords->getPointer())); + _part_coords=PartDefinition::New(nMin,nMax,1); + MEDfilterClose(&filter); + MEDfilterBlockOfEntityCr(fid,nCoords,1,1,MED_ALL_CONSTITUENT,MED_FULL_INTERLACE,MED_COMPACT_STMODE, + MED_NO_PROFILE,nMin+1,1,1,nbNodesToLoad,0,&filter2); + if(MEDmeshnEntity(fid,mName.c_str(),dt,it,MED_NODE,MED_NO_GEOTYPE,MED_FAMILY_NUMBER,MED_NODAL,&changement,&transformation)>0) + { + _fam_coords=DataArrayInt::New(); + _fam_coords->alloc(nbNodesToLoad,1); + MEDFILESAFECALLERRD0(MEDmeshEntityAttributeAdvancedRd,(fid,mName.c_str(),MED_FAMILY_NUMBER,dt,it,MED_NODE,MED_NO_GEOTYPE,&filter2,_fam_coords->getPointer())); + } + else + _fam_coords=0; + if(MEDmeshnEntity(fid,mName.c_str(),dt,it,MED_NODE,MED_NO_GEOTYPE,MED_NUMBER,MED_NODAL,&changement,&transformation)>0) + { + _num_coords=DataArrayInt::New(); + _num_coords->alloc(nbNodesToLoad,1); + MEDFILESAFECALLERRD0(MEDmeshEntityAttributeAdvancedRd,(fid,mName.c_str(),MED_NUMBER,dt,it,MED_NODE,MED_NO_GEOTYPE,&filter2,_num_coords->getPointer())); + } + else + _num_coords=0; + if(MEDmeshnEntity(fid,mName.c_str(),dt,it,MED_NODE,MED_NO_GEOTYPE,MED_NAME,MED_NODAL,&changement,&transformation)>0) + { + _name_coords=DataArrayAsciiChar::New(); + _name_coords->alloc(nbNodesToLoad+1,MED_SNAME_SIZE);//not a bug to avoid the memory corruption due to last \0 at the end + MEDFILESAFECALLERRD0(MEDmeshEntityAttributeAdvancedRd,(fid,mName.c_str(),MED_NAME,dt,it,MED_NODE,MED_NO_GEOTYPE,&filter2,_name_coords->getPointer())); + _name_coords->reAlloc(nbNodesToLoad);//not a bug to avoid the memory corruption due to last \0 at the end + } + else + _name_coords=0; + MEDfilterClose(&filter2); + _coords->setInfoOnComponents(infosOnComp); +} + +void MEDFileUMeshL2::sortTypes() +{ + std::set mdims; + std::vector< MEDCouplingAutoRefCountObjectPtr > tmp(_per_type_mesh[0]); + _per_type_mesh.clear(); + for(std::vector< MEDCouplingAutoRefCountObjectPtr >::const_iterator it=tmp.begin();it!=tmp.end();it++) + mdims.insert((*it)->getDim()); + if(mdims.empty()) + return; + int mdim=*mdims.rbegin(); + _per_type_mesh.resize(mdim+1); + for(int dim=mdim+1;dim!=0;dim--) + { + std::vector< MEDCouplingAutoRefCountObjectPtr >& elt=_per_type_mesh[mdim+1-dim]; + for(std::vector< MEDCouplingAutoRefCountObjectPtr >::const_iterator it=tmp.begin();it!=tmp.end();it++) + if((*it)->getDim()==dim-1) + elt.push_back(*it); + } + // suppression of contiguous empty levels at the end of _per_type_mesh. + int nbOfUselessLev=0; + bool isFirst=true; + for(std::vector< std::vector< MEDCouplingAutoRefCountObjectPtr > >::reverse_iterator it2=_per_type_mesh.rbegin();it2!=_per_type_mesh.rend();it2++) + { + if((*it2).empty() && isFirst) + { + nbOfUselessLev++; + } + else + isFirst=false; + } + _per_type_mesh.resize(_per_type_mesh.size()-nbOfUselessLev); +} + +void MEDFileUMeshL2::WriteCoords(med_idt fid, const std::string& mname, int dt, int it, double time, const DataArrayDouble *coords, const DataArrayInt *famCoords, const DataArrayInt *numCoords, const DataArrayAsciiChar *nameCoords) +{ + if(!coords) + return ; + MEDFILESAFECALLERWR0(MEDmeshNodeCoordinateWr,(fid,mname.c_str(),dt,it,time,MED_FULL_INTERLACE,coords->getNumberOfTuples(),coords->getConstPointer())); + if(famCoords) + MEDFILESAFECALLERWR0(MEDmeshEntityFamilyNumberWr,(fid,mname.c_str(),dt,it,MED_NODE,MED_NO_GEOTYPE,famCoords->getNumberOfTuples(),famCoords->getConstPointer())); + if(numCoords) + MEDFILESAFECALLERWR0(MEDmeshEntityNumberWr,(fid,mname.c_str(),dt,it,MED_NODE,MED_NO_GEOTYPE,numCoords->getNumberOfTuples(),numCoords->getConstPointer())); + if(nameCoords) + { + if(nameCoords->getNumberOfComponents()!=MED_SNAME_SIZE) + { + std::ostringstream oss; oss << " MEDFileUMeshL2::WriteCoords : expected a name field on nodes with number of components set to " << MED_SNAME_SIZE; + oss << " ! The array has " << nameCoords->getNumberOfComponents() << " components !"; + throw INTERP_KERNEL::Exception(oss.str().c_str()); + } + MEDFILESAFECALLERWR0(MEDmeshEntityNameWr,(fid,mname.c_str(),dt,it,MED_NODE,MED_NO_GEOTYPE,nameCoords->getNumberOfTuples(),nameCoords->getConstPointer())); + } +} + +bool MEDFileUMeshL2::isFamDefinedOnLev(int levId) const +{ + for(std::vector< MEDCouplingAutoRefCountObjectPtr >::const_iterator it=_per_type_mesh[levId].begin();it!=_per_type_mesh[levId].end();it++) + if((*it)->getFam()==0) + return false; + return true; +} + +bool MEDFileUMeshL2::isNumDefinedOnLev(int levId) const +{ + for(std::vector< MEDCouplingAutoRefCountObjectPtr >::const_iterator it=_per_type_mesh[levId].begin();it!=_per_type_mesh[levId].end();it++) + if((*it)->getNum()==0) + return false; + return true; +} + +bool MEDFileUMeshL2::isNamesDefinedOnLev(int levId) const +{ + for(std::vector< MEDCouplingAutoRefCountObjectPtr >::const_iterator it=_per_type_mesh[levId].begin();it!=_per_type_mesh[levId].end();it++) + if((*it)->getNames()==0) + return false; + return true; +} + +MEDFileCMeshL2::MEDFileCMeshL2() +{ +} + +void MEDFileCMeshL2::loadAll(med_idt fid, int mId, const std::string& mName, int dt, int it) +{ + _name.set(mName.c_str()); + int nstep; + int Mdim; + ParaMEDMEM::MEDCouplingMeshType meshType; + std::vector infosOnComp=getAxisInfoOnMesh(fid,mId,mName.c_str(),meshType,nstep,Mdim); + if(meshType!=CARTESIAN) + throw INTERP_KERNEL::Exception("Invalid mesh type ! You are expected a structured one whereas in file it is not a structured !"); + _time=CheckMeshTimeStep(fid,mName,nstep,dt,it); + _iteration=dt; + _order=it; + // + med_grid_type gridtype; + MEDFILESAFECALLERRD0(MEDmeshGridTypeRd,(fid,mName.c_str(),&gridtype)); + if(gridtype!=MED_CARTESIAN_GRID) + throw INTERP_KERNEL::Exception("Invalid structured mesh ! Expected cartesian mesh type !"); + _cmesh=MEDCouplingCMesh::New(); + for(int i=0;i da=DataArrayDouble::New(); + da->alloc(nbOfElt,1); + da->setInfoOnComponent(0,infosOnComp[i]); + MEDFILESAFECALLERRD0(MEDmeshGridIndexCoordinateRd,(fid,mName.c_str(),dt,it,i+1,da->getPointer())); + _cmesh->setCoordsAt(i,da); + } +} + +med_data_type MEDFileCMeshL2::GetDataTypeCorrespondingToSpaceId(int id) +{ + switch(id) + { + case 0: + return MED_COORDINATE_AXIS1; + case 1: + return MED_COORDINATE_AXIS2; + case 2: + return MED_COORDINATE_AXIS3; + default: + throw INTERP_KERNEL::Exception("Invalid meshdim detected in Cartesian Grid !"); + } +} + +MEDFileCLMeshL2::MEDFileCLMeshL2() +{ +} + +void MEDFileCLMeshL2::loadAll(med_idt fid, int mId, const std::string& mName, int dt, int it) +{ + _name.set(mName.c_str()); + int nstep; + int Mdim; + ParaMEDMEM::MEDCouplingMeshType meshType; + std::vector infosOnComp=getAxisInfoOnMesh(fid,mId,mName,meshType,nstep,Mdim); + if(meshType!=CURVE_LINEAR) + throw INTERP_KERNEL::Exception("Invalid mesh type ! You are expected a structured one whereas in file it is not a structured !"); + _time=CheckMeshTimeStep(fid,mName,nstep,dt,it); + _iteration=dt; + _order=it; + // + _clmesh=MEDCouplingCurveLinearMesh::New(); + INTERP_KERNEL::AutoPtr stGrid=new int[Mdim]; + MEDFILESAFECALLERRD0(MEDmeshGridStructRd,(fid,mName.c_str(),dt,it,stGrid)); + _clmesh->setNodeGridStructure(stGrid,((int *)stGrid)+Mdim); + med_bool chgt=MED_FALSE,trsf=MED_FALSE; + int nbNodes(MEDmeshnEntity(fid,mName.c_str(),dt,it,MED_NODE,MED_NONE,MED_COORDINATE,MED_NO_CMODE,&chgt,&trsf)); + MEDCouplingAutoRefCountObjectPtr da=DataArrayDouble::New(); + da->alloc(nbNodes,infosOnComp.size()); + da->setInfoOnComponents(infosOnComp); + MEDFILESAFECALLERRD0(MEDmeshNodeCoordinateRd,(fid,mName.c_str(),dt,it,MED_FULL_INTERLACE,da->getPointer())); + _clmesh->setCoords(da); +} + +MEDFileUMeshPermCompute::MEDFileUMeshPermCompute(const MEDFileUMeshSplitL1* st):_st(st),_mpt_time(0),_num_time(0) +{ +} + +/*! + * Warning it returns an instance to deallocate !!!! + */ +MEDFileUMeshPermCompute::operator MEDCouplingUMesh *() const +{ + _st->_num->updateTime(); + if((MEDCouplingUMesh *)_m==0) + { + updateTime(); + _m=static_cast(_st->_m_by_types.getUmesh()->deepCpy()); + _m->renumberCells(_st->_num->getConstPointer(),true); + return _m.retn(); + } + else + { + if(_mpt_time==_st->_m_by_types.getTimeOfThis() && _num_time==_st->_num->getTimeOfThis()) + return _m.retn(); + else + { + updateTime(); + _m=static_cast(_st->_m_by_types.getUmesh()->deepCpy()); + _m->renumberCells(_st->_num->getConstPointer(),true); + return _m.retn(); + } + } +} + +void MEDFileUMeshPermCompute::operator=(MEDCouplingUMesh *m) +{ + _m=m; +} + +void MEDFileUMeshPermCompute::updateTime() const +{ + _mpt_time=_st->_m_by_types.getTimeOfThis(); + _num_time=_st->_num->getTimeOfThis(); +} + +std::vector MEDFileUMeshPermCompute::getDirectChildrenWithNull() const +{ + std::vector ret; + ret.push_back((const MEDCouplingUMesh *)_m); + return ret; +} + +std::size_t MEDFileUMeshPermCompute::getHeapMemorySizeWithoutChildren() const +{ + return sizeof(MEDFileUMeshPermCompute); +} + +MEDFileUMeshSplitL1::MEDFileUMeshSplitL1(const MEDFileUMeshSplitL1& other):RefCountObject(other),_m_by_types(other._m_by_types),_fam(other._fam),_num(other._num),_names(other._names),_rev_num(other._rev_num),_m(this) +{ +} + +MEDFileUMeshSplitL1::MEDFileUMeshSplitL1(const MEDFileUMeshL2& l2, const std::string& mName, int id):_m(this) +{ + const std::vector< MEDCouplingAutoRefCountObjectPtr >& v=l2.getLev(id); + if(v.empty()) + return; + int sz=v.size(); + std::vector ms(sz); + std::vector fams(sz),nums(sz); + std::vector names(sz); + std::vector pds(sz); + for(int i=0;igetMesh()); + MEDCouplingAutoRefCountObjectPtr tmp2=l2.getCoords(); + elt->setCoords(tmp2); + ms[i]=elt; + pds[i]=v[i]->getPartDef(); + } + _m_by_types.assignParts(ms); + _m_by_types.assignDefParts(pds); + if(l2.isFamDefinedOnLev(id)) + { + for(int i=0;igetFam(); + if(sz!=1) + _fam=DataArrayInt::Aggregate(fams); + else + { + fams[0]->incrRef(); + _fam=const_cast(fams[0]); + } + } + if(l2.isNumDefinedOnLev(id)) + { + for(int i=0;igetNum(); + if(sz!=1) + _num=DataArrayInt::Aggregate(nums); + else + { + nums[0]->incrRef(); + _num=const_cast(nums[0]); + } + computeRevNum(); + } + if(l2.isNamesDefinedOnLev(id)) + { + for(int i=0;igetNames(); + _names=dynamic_cast(DataArrayChar::Aggregate(names)); + } +} + +MEDFileUMeshSplitL1::MEDFileUMeshSplitL1(MEDCoupling1GTUMesh *m):_m(this) +{ + std::vector< const MEDCoupling1GTUMesh * > v(1); + v[0]=m; + assignParts(v); +} + +MEDFileUMeshSplitL1::MEDFileUMeshSplitL1(MEDCouplingUMesh *m):_m(this) +{ + assignMesh(m,true); +} + +MEDFileUMeshSplitL1::MEDFileUMeshSplitL1(MEDCouplingUMesh *m, bool newOrOld):_m(this) +{ + assignMesh(m,newOrOld); +} + +void MEDFileUMeshSplitL1::setName(const std::string& name) +{ + _m_by_types.setName(name); +} + +std::size_t MEDFileUMeshSplitL1::getHeapMemorySizeWithoutChildren() const +{ + return 0; +} + +std::vector MEDFileUMeshSplitL1::getDirectChildrenWithNull() const +{ + std::vector ret; + ret.push_back(&_m_by_types); + ret.push_back(&_m); + ret.push_back((const DataArrayInt*)_fam); + ret.push_back((const DataArrayInt*)_num); + ret.push_back((const DataArrayInt*)_rev_num); + ret.push_back((const DataArrayAsciiChar*)_names); + return ret; +} + +MEDFileUMeshSplitL1 *MEDFileUMeshSplitL1::deepCpy(DataArrayDouble *coords) const +{ + MEDCouplingAutoRefCountObjectPtr ret=new MEDFileUMeshSplitL1(*this); + ret->_m_by_types=_m_by_types.deepCpy(coords); + if((const DataArrayInt *)_fam) + ret->_fam=_fam->deepCpy(); + if((const DataArrayInt *)_num) + ret->_num=_num->deepCpy(); + if((const DataArrayInt *)_rev_num) + ret->_rev_num=_rev_num->deepCpy(); + if((const DataArrayAsciiChar *)_names) + ret->_names=_names->deepCpy(); + return ret.retn(); +} + +bool MEDFileUMeshSplitL1::isEqual(const MEDFileUMeshSplitL1 *other, double eps, std::string& what) const +{ + if(!_m_by_types.isEqual(other->_m_by_types,eps,what)) + return false; + const DataArrayInt *d1=_fam; + const DataArrayInt *d2=other->_fam; + if((d1==0 && d2!=0) || (d1!=0 && d2==0)) + { + what="Presence of family arr in one sublevel and not in other!"; + return false; + } + if(d1) + if(!d1->isEqual(*d2)) + { + what="family arr at a sublevel are not deeply equal !"; + return false; + } + d1=_num; + d2=other->_num; + if((d1==0 && d2!=0) || (d1!=0 && d2==0)) + { + what="Presence of cell numbering arr in one sublevel and not in other!"; + return false; + } + if(d1) + if(!d1->isEqual(*d2)) + { + what="Numbering cell arr at a sublevel are not deeply equal !"; + return false; + } + const DataArrayAsciiChar *e1=_names; + const DataArrayAsciiChar *e2=other->_names; + if((e1==0 && e2!=0) || (e1!=0 && e2==0)) + { + what="Presence of cell names arr in one sublevel and not in other!"; + return false; + } + if(e1) + if(!e1->isEqual(*e2)) + { + what="Name cell arr at a sublevel are not deeply equal !"; + return false; + } + return true; +} + +void MEDFileUMeshSplitL1::synchronizeTinyInfo(const MEDFileMesh& master) const +{ + _m_by_types.synchronizeTinyInfo(master); +} + +void MEDFileUMeshSplitL1::clearNonDiscrAttributes() const +{ + _m_by_types.clearNonDiscrAttributes(); +} + +void MEDFileUMeshSplitL1::ClearNonDiscrAttributes(const MEDCouplingMesh *tmp) +{ + if(!tmp) + return ; + (const_cast(tmp))->setName(""); + (const_cast(tmp))->setDescription(""); + (const_cast(tmp))->setTime(0.,-1,-1); + (const_cast(tmp))->setTimeUnit(""); +} + +void MEDFileUMeshSplitL1::setCoords(DataArrayDouble *coords) +{ + _m_by_types.setCoords(coords); +} + +void MEDFileUMeshSplitL1::assignMesh(MEDCouplingUMesh *m, bool newOrOld) +{ + if(newOrOld) + { + m->incrRef(); + _m=m; + _m_by_types.assignUMesh(dynamic_cast(m->deepCpy())); + MEDCouplingAutoRefCountObjectPtr da=_m_by_types.getUmesh()->getRenumArrForConsecutiveCellTypesSpec(typmai2,typmai2+MED_N_CELL_FIXED_GEO); + if(!da->isIdentity()) + { + _num=da->invertArrayO2N2N2O(m->getNumberOfCells()); + _m.updateTime(); + computeRevNum(); + _m_by_types.getUmesh()->renumberCells(da->getConstPointer(),false); + } + } + else + { + if(!m->checkConsecutiveCellTypesAndOrder(typmai2,typmai2+MED_N_CELL_FIXED_GEO)) - throw INTERP_KERNEL::Exception("MEDFileUMeshSplitL1::assignMesh : the mode of mesh setting expects to follow the MED file numbering convention ! it is not the case !"); ++ throw INTERP_KERNEL::Exception("MEDFileUMeshSplitL1::assignMesh(): the mesh does not follow the MED file numbering convention! Invoke sortCellsInMEDFileFrmt() first!"); + m->incrRef(); + _m_by_types.assignUMesh(m); + } + assignCommonPart(); +} + +void MEDFileUMeshSplitL1::forceComputationOfParts() const +{ + _m_by_types.forceComputationOfPartsFromUMesh(); +} + +void MEDFileUMeshSplitL1::assignParts(const std::vector< const MEDCoupling1GTUMesh * >& mParts) +{ + _m_by_types.assignParts(mParts); + assignCommonPart(); +} + +MEDFileUMeshSplitL1::MEDFileUMeshSplitL1():_m(this) +{ +} + +void MEDFileUMeshSplitL1::assignCommonPart() +{ + _fam=DataArrayInt::New(); + _fam->alloc(_m_by_types.getSize(),1); + _fam->fillWithValue(0); +} + +bool MEDFileUMeshSplitL1::empty() const +{ + return _m_by_types.empty(); +} + +bool MEDFileUMeshSplitL1::presenceOfOneFams(const std::vector& ids) const +{ + const DataArrayInt *fam=_fam; + if(!fam) + return false; + return fam->presenceOfValue(ids); +} + +int MEDFileUMeshSplitL1::getMeshDimension() const +{ + return _m_by_types.getMeshDimension(); +} + +void MEDFileUMeshSplitL1::simpleRepr(std::ostream& oss) const +{ + std::vector code=_m_by_types.getDistributionOfTypes(); + int nbOfTypes=code.size()/3; + for(int i=0;i eltsToKeep=_fam->getIdsEqualList(idsBg,idsEnd); + MEDCouplingUMesh *m=(MEDCouplingUMesh *)_m_by_types.getUmesh()->buildPartOfMySelf(eltsToKeep->getConstPointer(),eltsToKeep->getConstPointer()+eltsToKeep->getNumberOfTuples(),true); + if(renum) + return renumIfNeeded(m,eltsToKeep->getConstPointer()); + return m; +} + +DataArrayInt *MEDFileUMeshSplitL1::getFamilyPartArr(const int *idsBg, const int *idsEnd, bool renum) const +{ + MEDCouplingAutoRefCountObjectPtr da=_fam->getIdsEqualList(idsBg,idsEnd); + if(renum) + return renumIfNeededArr(da); + return da.retn(); +} + +std::vector MEDFileUMeshSplitL1::getGeoTypes() const +{ + return _m_by_types.getGeoTypes(); +} + +MEDCouplingUMesh *MEDFileUMeshSplitL1::getWholeMesh(bool renum) const +{ + MEDCouplingAutoRefCountObjectPtr tmp; + if(renum && ((const DataArrayInt *)_num)) + tmp=_m; + else + { tmp=_m_by_types.getUmesh(); if(tmp) tmp->incrRef(); } + return tmp.retn(); +} + +int MEDFileUMeshSplitL1::getNumberOfCells() const +{ + return _m_by_types.getNumberOfCells(); +} + +DataArrayInt *MEDFileUMeshSplitL1::extractFamilyFieldOnGeoType(INTERP_KERNEL::NormalizedCellType gt) const +{ + const DataArrayInt *fam(_fam); + if(!fam) + return 0; + int start(0),stop(0); + _m_by_types.getStartStopOfGeoTypeWithoutComputation(gt,start,stop); + return fam->selectByTupleId2(start,stop,1); +} + +DataArrayInt *MEDFileUMeshSplitL1::extractNumberFieldOnGeoType(INTERP_KERNEL::NormalizedCellType gt) const +{ + const DataArrayInt *num(_num); + if(!num) + return 0; + int start(0),stop(0); + _m_by_types.getStartStopOfGeoTypeWithoutComputation(gt,start,stop); + return num->selectByTupleId2(start,stop,1); +} + +DataArrayInt *MEDFileUMeshSplitL1::getOrCreateAndGetFamilyField() +{ + if((DataArrayInt *)_fam) + return _fam; + int nbOfTuples=_m_by_types.getSize(); + _fam=DataArrayInt::New(); _fam->alloc(nbOfTuples,1); _fam->fillWithZero(); + return _fam; +} + +const DataArrayInt *MEDFileUMeshSplitL1::getFamilyField() const +{ + return _fam; +} + +const DataArrayInt *MEDFileUMeshSplitL1::getNumberField() const +{ + return _num; +} + +const DataArrayInt *MEDFileUMeshSplitL1::getRevNumberField() const +{ + return _rev_num; +} + +const DataArrayAsciiChar *MEDFileUMeshSplitL1::getNameField() const +{ + return _names; +} + +const PartDefinition *MEDFileUMeshSplitL1::getPartDef(INTERP_KERNEL::NormalizedCellType gt) const +{ + return _m_by_types.getPartDefOfWithoutComputation(gt); +} + +void MEDFileUMeshSplitL1::eraseFamilyField() +{ + _fam->fillWithZero(); +} + +/*! + * This method ignores _m and _m_by_types. + */ +void MEDFileUMeshSplitL1::setGroupsFromScratch(const std::vector& ms, std::map& familyIds, + std::map >& groups) +{ + std::vector< DataArrayInt * > corr; + _m=MEDCouplingUMesh::FuseUMeshesOnSameCoords(ms,0,corr); + std::vector< MEDCouplingAutoRefCountObjectPtr > corrMSafe(corr.begin(),corr.end()); + std::vector< std::vector > fidsOfGroups; + std::vector< const DataArrayInt * > corr2(corr.begin(),corr.end()); + _fam=DataArrayInt::MakePartition(corr2,((MEDCouplingUMesh *)_m)->getNumberOfCells(),fidsOfGroups); + int nbOfCells=((MEDCouplingUMesh *)_m)->getNumberOfCells(); + std::map newfams; + std::map famIdTrad; + TraduceFamilyNumber(fidsOfGroups,familyIds,famIdTrad,newfams); + int *w=_fam->getPointer(); + for(int i=0;i ms(_m_by_types.getParts()); + int start=0; + for(std::vector::const_iterator it=ms.begin();it!=ms.end();it++) + { + int nbCells=(*it)->getNumberOfCells(); + int end=start+nbCells; + MEDCouplingAutoRefCountObjectPtr fam,num; + MEDCouplingAutoRefCountObjectPtr names; + if((const DataArrayInt *)_fam) + fam=_fam->substr(start,end); + if((const DataArrayInt *)_num) + num=_num->substr(start,end); + if((const DataArrayAsciiChar *)_names) + names=static_cast(_names->substr(start,end)); + MEDFileUMeshPerType::Write(fid,mName,mdim,(*it),fam,num,names); + start=end; + } +} + +void MEDFileUMeshSplitL1::renumberNodesInConn(const int *newNodeNumbersO2N) +{ + _m_by_types.renumberNodesInConnWithoutComputation(newNodeNumbersO2N); +} + +void MEDFileUMeshSplitL1::serialize(std::vector& tinyInt, std::vector< MEDCouplingAutoRefCountObjectPtr >& bigArraysI) const +{ + bigArraysI.push_back(_fam); + bigArraysI.push_back(_num); + _m_by_types.serialize(tinyInt,bigArraysI); +} + +void MEDFileUMeshSplitL1::unserialize(const std::string& name, DataArrayDouble *coo, std::vector& tinyInt, std::vector< MEDCouplingAutoRefCountObjectPtr >& bigArraysI) +{ + _fam=bigArraysI.back(); bigArraysI.pop_back(); + _num=bigArraysI.back(); bigArraysI.pop_back(); + _m_by_types.unserialize(name,coo,tinyInt,bigArraysI); +} + +void MEDFileUMeshSplitL1::changeFamilyIdArr(int oldId, int newId) +{ + DataArrayInt *arr=_fam; + if(arr) + arr->changeValue(oldId,newId); +} + +void MEDFileUMeshSplitL1::setFamilyArr(DataArrayInt *famArr) +{ + if(!famArr) + { + _fam=0; + return ; + } + int sz(_m_by_types.getSize()); + famArr->checkNbOfTuplesAndComp(sz,1,"MEDFileUMeshSplitL1::setFamilyArr : Problem in size of Family arr ! "); + famArr->incrRef(); + _fam=famArr; +} + +DataArrayInt *MEDFileUMeshSplitL1::getFamilyField() +{ + return _fam; +} + +void MEDFileUMeshSplitL1::setRenumArr(DataArrayInt *renumArr) +{ + if(!renumArr) + { + _num=0; + _rev_num=0; + return ; + } + int sz(_m_by_types.getSize()); + renumArr->checkNbOfTuplesAndComp(sz,1,"MEDFileUMeshSplitL1::setRenumArr : Problem in size of numbering arr ! "); + renumArr->incrRef(); + _num=renumArr; + computeRevNum(); +} + +void MEDFileUMeshSplitL1::setNameArr(DataArrayAsciiChar *nameArr) +{ + if(!nameArr) + { + _names=0; + return ; + } + int sz(_m_by_types.getSize()); + nameArr->checkNbOfTuplesAndComp(sz,MED_SNAME_SIZE,"MEDFileUMeshSplitL1::setNameArr : Problem in size of name arr ! "); + nameArr->incrRef(); + _names=nameArr; +} + +MEDCouplingUMesh *MEDFileUMeshSplitL1::Renumber2(const DataArrayInt *renum, MEDCouplingUMesh *m, const int *cellIds) +{ + if(renum==0) + return m; + if(cellIds==0) + m->renumberCells(renum->getConstPointer(),true); + else + { + MEDCouplingAutoRefCountObjectPtr locnum=renum->selectByTupleId(cellIds,cellIds+m->getNumberOfCells()); + m->renumberCells(locnum->getConstPointer(),true); + } + return m; +} + +MEDFileUMeshSplitL1 *MEDFileUMeshSplitL1::Unserialize(const std::string& name, DataArrayDouble *coo, std::vector& tinyInt, std::vector< MEDCouplingAutoRefCountObjectPtr >& bigArraysI) +{ + MEDCouplingAutoRefCountObjectPtr ret(new MEDFileUMeshSplitL1); + ret->unserialize(name,coo,tinyInt,bigArraysI); + return ret.retn(); +} + +MEDCouplingUMesh *MEDFileUMeshSplitL1::renumIfNeeded(MEDCouplingUMesh *m, const int *cellIds) const +{ + return Renumber2(_num,m,cellIds); +} + +DataArrayInt *MEDFileUMeshSplitL1::Renumber(const DataArrayInt *renum, const DataArrayInt *da) +{ + if((const DataArrayInt *)renum==0) + { + da->incrRef(); + return const_cast(da); + } + return renum->selectByTupleId(da->getConstPointer(),da->getConstPointer()+da->getNumberOfTuples()); +} + +DataArrayInt *MEDFileUMeshSplitL1::renumIfNeededArr(const DataArrayInt *da) const +{ + return Renumber(_num,da); +} + +std::vector MEDFileUMeshSplitL1::GetNewFamiliesNumber(int nb, const std::map& families) +{ + int id=-1; + for(std::map::const_iterator it=families.begin();it!=families.end();it++) + id=std::max(id,(*it).second); + if(id==-1) + id=0; + std::vector ret(nb); + for(int i=1;i<=nb;i++) + ret[i]=id+i; + return ret; +} + +void MEDFileUMeshSplitL1::TraduceFamilyNumber(const std::vector< std::vector >& fidsGrps, std::map& familyIds, + std::map& famIdTrad, std::map& newfams) +{ + std::set allfids; + //tony +} + +void MEDFileUMeshSplitL1::computeRevNum() const +{ + int pos; + int maxValue=_num->getMaxValue(pos); + _rev_num=_num->invertArrayN2O2O2N(maxValue+1); +} + +//= + +MEDFileUMeshAggregateCompute::MEDFileUMeshAggregateCompute():_mp_time(0),_m_time(0) +{ +} + +void MEDFileUMeshAggregateCompute::setName(const std::string& name) +{ + if(_m_time>=_mp_time) + { + MEDCouplingUMesh *um(_m); + if(um) + um->setName(name); + } + if(_mp_time>=_m_time) + { + for(std::vector< MEDCouplingAutoRefCountObjectPtr >::iterator it=_m_parts.begin();it!=_m_parts.end();it++) + { + MEDCoupling1GTUMesh *tmp(*it); + if(tmp) + tmp->setName(name); + } + } +} + +void MEDFileUMeshAggregateCompute::assignParts(const std::vector< const MEDCoupling1GTUMesh * >& mParts) +{ + std::size_t sz(mParts.size()); + std::vector< MEDCouplingAutoRefCountObjectPtr > ret(sz); + for(std::size_t i=0;i(elt); elt->incrRef(); + } + _m_parts=ret; + _part_def.clear(); _part_def.resize(sz); + _mp_time=std::max(_mp_time,_m_time)+1; + _m=0; +} + +void MEDFileUMeshAggregateCompute::assignDefParts(const std::vector& partDefs) +{ + if(_mp_time<_m_time) + throw INTERP_KERNEL::Exception("MEDFileUMeshAggregateCompute::assignDefParts : the parts require a computation !"); + std::size_t sz(partDefs.size()); + if(_part_def.size()!=partDefs.size() || _part_def.size()!=_m_parts.size()) + throw INTERP_KERNEL::Exception("MEDFileUMeshAggregateCompute::assignDefParts : sizes of vectors of part definition mismatch !"); + for(std::size_t i=0;iincrRef(); + _part_def[i]=const_cast(elt); + } +} + +void MEDFileUMeshAggregateCompute::assignUMesh(MEDCouplingUMesh *m) +{ + _m=m; + _m_parts.clear(); + _m_time=std::max(_mp_time,_m_time)+1; +} + +MEDCouplingUMesh *MEDFileUMeshAggregateCompute::getUmesh() const +{ + if(_mp_time<=_m_time) + return _m; + std::vector< const MEDCoupling1GTUMesh *> mp(_m_parts.size()); + std::copy(_m_parts.begin(),_m_parts.end(),mp.begin()); + _m=MEDCoupling1GTUMesh::AggregateOnSameCoordsToUMesh(mp); + _m_parts.clear();//to avoid memory peak ! + _m_time=_mp_time+1;//+1 is important ! That is to say that only _m is OK not _m_parts because cleared ! + return _m; +} + +int MEDFileUMeshAggregateCompute::getNumberOfCells() const +{ + if(_mp_time<=_m_time) + return _m->getNumberOfCells(); + int ret(0); + for(std::vector< MEDCouplingAutoRefCountObjectPtr >::const_iterator it=_m_parts.begin();it!=_m_parts.end();it++) + ret+=(*it)->getNumberOfCells(); + return ret; +} + +std::vector MEDFileUMeshAggregateCompute::getGeoTypes() const +{ + if(_mp_time>=_m_time) + { + std::size_t sz(_m_parts.size()); + std::vector ret(sz); + for(std::size_t i=0;igetCellModelEnum(); + return ret; + } + else + return _m->getAllGeoTypesSorted(); +} + +std::vector MEDFileUMeshAggregateCompute::retrievePartsWithoutComputation() const +{ + if(_mp_time<_m_time) + throw INTERP_KERNEL::Exception("MEDFileUMeshAggregateCompute::getPartsWithoutComputation : the parts require a computation !"); + // + std::vector ret(_m_parts.size()); + std::size_t i(0); + for(std::vector< MEDCouplingAutoRefCountObjectPtr >::const_iterator it=_m_parts.begin();it!=_m_parts.end();it++,i++) + { + const MEDCoupling1GTUMesh *elt(*it); + ret[i]=const_cast(elt); + } + return ret; +} + +std::vector MEDFileUMeshAggregateCompute::getParts() const +{ + if(_mp_time<_m_time) + forceComputationOfPartsFromUMesh(); + return retrievePartsWithoutComputation(); +} + +MEDCoupling1GTUMesh *MEDFileUMeshAggregateCompute::retrievePartWithoutComputation(INTERP_KERNEL::NormalizedCellType gt) const +{ + std::vector v(retrievePartsWithoutComputation()); + std::size_t sz(v.size()); + for(std::size_t i=0;igetCellModelEnum()==gt) + return v[i]; + } + throw INTERP_KERNEL::Exception("MEDFileUMeshAggregateCompute::getPartWithoutComputation : the geometric type is not existing !"); +} + +void MEDFileUMeshAggregateCompute::getStartStopOfGeoTypeWithoutComputation(INTERP_KERNEL::NormalizedCellType gt, int& start, int& stop) const +{ + start=0; stop=0; + std::vector v(retrievePartsWithoutComputation()); + std::size_t sz(v.size()); + for(std::size_t i=0;igetCellModelEnum()==gt) + { + stop=start+v[i]->getNumberOfCells(); + return; + } + else + start+=v[i]->getNumberOfCells(); + } + } + throw INTERP_KERNEL::Exception("MEDFileUMeshAggregateCompute::getStartStopOfGeoTypeWithoutComputation : the geometric type is not existing !"); +} + +void MEDFileUMeshAggregateCompute::renumberNodesInConnWithoutComputation(const int *newNodeNumbersO2N) +{ + if(_mp_time>_m_time) + { + for(std::vector< MEDCouplingAutoRefCountObjectPtr >::iterator it=_m_parts.begin();it!=_m_parts.end();it++) + { + MEDCoupling1GTUMesh *m(*it); + if(m) + m->renumberNodesInConn(newNodeNumbersO2N); + } + } + else + { + MEDCouplingUMesh *m(getUmesh()); + if(!m) + return; + m->renumberNodesInConn(newNodeNumbersO2N); + } +} + +void MEDFileUMeshAggregateCompute::forceComputationOfPartsFromUMesh() const +{ + const MEDCouplingUMesh *m(_m); + if(!m) + { + if(_m_parts.empty()) + throw INTERP_KERNEL::Exception("MEDFileUMeshAggregateCompute::forceComputationOfPartsFromUMesh : null UMesh !"); + else + return ;// no needs to compte parts they are already here ! + } + std::vector ms(m->splitByType()); + std::vector< MEDCouplingAutoRefCountObjectPtr > msMSafe(ms.begin(),ms.end()); + std::size_t sz(msMSafe.size()); + _m_parts.resize(sz); + for(std::size_t i=0;igetCellModelEnum()==gt) + return _part_def[i]; + } + throw INTERP_KERNEL::Exception("MEDFileUMeshAggregateCompute::getPartDefOfWithoutComputation : The input geo type is not existing in this !"); +} + +void MEDFileUMeshAggregateCompute::serialize(std::vector& tinyInt, std::vector< MEDCouplingAutoRefCountObjectPtr >& bigArraysI) const +{ + if(_mp_time<_m_time) + throw INTERP_KERNEL::Exception("MEDFileUMeshAggregateCompute::serialize : the parts require a computation !"); + std::size_t sz(_m_parts.size()); + tinyInt.push_back((int)sz); + for(std::size_t i=0;igetCellModelEnum()); + const MEDCoupling1SGTUMesh *mesh1(dynamic_cast(mesh)); + const MEDCoupling1DGTUMesh *mesh2(dynamic_cast(mesh)); + if(mesh1) + { + DataArrayInt *elt(mesh1->getNodalConnectivity()); + if(elt) + elt->incrRef(); + MEDCouplingAutoRefCountObjectPtr elt1(elt); + bigArraysI.push_back(elt1); + } + else if(mesh2) + { + DataArrayInt *elt1(mesh2->getNodalConnectivity()),*elt2(mesh2->getNodalConnectivityIndex()); + if(elt1) + elt1->incrRef(); + if(elt2) + elt2->incrRef(); + MEDCouplingAutoRefCountObjectPtr elt11(elt1),elt22(elt2); + bigArraysI.push_back(elt11); bigArraysI.push_back(elt22); + } + else + throw INTERP_KERNEL::Exception("MEDFileUMeshAggregateCompute::serialize : unrecognized single geo type mesh !"); + const PartDefinition *pd(_part_def[i]); + if(!pd) + tinyInt.push_back(-1); + else + { + std::vector tinyTmp; + pd->serialize(tinyTmp,bigArraysI); + tinyInt.push_back((int)tinyTmp.size()); + tinyInt.insert(tinyInt.end(),tinyTmp.begin(),tinyTmp.end()); + } + } +} + +void MEDFileUMeshAggregateCompute::unserialize(const std::string& name, DataArrayDouble *coo, std::vector& tinyInt, std::vector< MEDCouplingAutoRefCountObjectPtr >& bigArraysI) +{ + int nbParts(tinyInt.back()); tinyInt.pop_back(); + _part_def.clear(); _part_def.resize(nbParts); + _m_parts.clear(); _m_parts.resize(nbParts); + for(int i=0;i mesh(MEDCoupling1GTUMesh::New(name,tp)); + mesh->setCoords(coo); + MEDCoupling1SGTUMesh *mesh1(dynamic_cast((MEDCoupling1GTUMesh *) mesh)); + MEDCoupling1DGTUMesh *mesh2(dynamic_cast((MEDCoupling1GTUMesh *) mesh)); + if(mesh1) + { + mesh1->setNodalConnectivity(bigArraysI.back()); bigArraysI.pop_back(); + } + else if(mesh2) + { + MEDCouplingAutoRefCountObjectPtr elt0,elt1; + elt0=bigArraysI.back(); bigArraysI.pop_back(); + elt1=bigArraysI.back(); bigArraysI.pop_back(); + mesh2->setNodalConnectivity(elt0,elt1); + } + else + throw INTERP_KERNEL::Exception("MEDFileUMeshAggregateCompute::unserialize : unrecognized single geo type mesh !"); + _m_parts[i]=mesh; + int pdid(tinyInt.back()); tinyInt.pop_back(); + if(pdid!=-1) + _part_def[i]=PartDefinition::Unserialize(tinyInt,bigArraysI); + _mp_time=std::max(_mp_time,_m_time)+1; + } +} + +/*! + * This method returns true if \a this is stored split by type false if stored in a merged unstructured mesh. + */ +bool MEDFileUMeshAggregateCompute::isStoredSplitByType() const +{ + return _mp_time>=_m_time; +} + +std::size_t MEDFileUMeshAggregateCompute::getTimeOfThis() const +{ + if(_mp_time>_m_time) + return getTimeOfParts(); + if(_m_time>_mp_time) + return getTimeOfUMesh(); + return std::max(getTimeOfParts(),getTimeOfUMesh()); +} + +std::size_t MEDFileUMeshAggregateCompute::getTimeOfParts() const +{ + std::size_t ret(0); + for(std::vector< MEDCouplingAutoRefCountObjectPtr >::const_iterator it=_m_parts.begin();it!=_m_parts.end();it++) + { + const MEDCoupling1GTUMesh *elt(*it); + if(!elt) + throw INTERP_KERNEL::Exception("MEDFileUMeshAggregateCompute::getTimeOfParts : null obj in parts !"); + ret=std::max(ret,elt->getTimeOfThis()); + } + if(ret==0) + throw INTERP_KERNEL::Exception("MEDFileUMeshAggregateCompute::getTimeOfParts : parts is empty !"); + return ret; +} + +std::size_t MEDFileUMeshAggregateCompute::getTimeOfUMesh() const +{ + const MEDCouplingUMesh *m(_m); + if(!m) + throw INTERP_KERNEL::Exception("MEDFileUMeshAggregateCompute::getTimeOfUMesh : unmesh is null !"); + return m->getTimeOfThis(); +} + +std::size_t MEDFileUMeshAggregateCompute::getHeapMemorySizeWithoutChildren() const +{ + std::size_t ret(_m_parts.size()*sizeof(MEDCouplingAutoRefCountObjectPtr)); + return ret; +} + +std::vector MEDFileUMeshAggregateCompute::getDirectChildrenWithNull() const +{ + std::vector ret; + for(std::vector< MEDCouplingAutoRefCountObjectPtr >::const_iterator it=_m_parts.begin();it!=_m_parts.end();it++) + ret.push_back((const MEDCoupling1GTUMesh *)*it); + ret.push_back((const MEDCouplingUMesh *)_m); + return ret; +} + +MEDFileUMeshAggregateCompute MEDFileUMeshAggregateCompute::deepCpy(DataArrayDouble *coords) const +{ + MEDFileUMeshAggregateCompute ret; + ret._m_parts.resize(_m_parts.size()); + for(std::size_t i=0;i<_m_parts.size();i++) + { + const MEDCoupling1GTUMesh *elt(_m_parts[i]); + if(elt) + { + ret._m_parts[i]=static_cast(elt->deepCpy()); + ret._m_parts[i]->setCoords(coords); + } + } + ret._mp_time=_mp_time; ret._m_time=_m_time; + if((const MEDCouplingUMesh *)_m) + { + ret._m=static_cast(_m->deepCpy()); + ret._m->setCoords(coords); + } + std::size_t sz(_part_def.size()); + ret._part_def.clear(); ret._part_def.resize(sz); + for(std::size_t i=0;ideepCpy(); + } + return ret; +} + +bool MEDFileUMeshAggregateCompute::isEqual(const MEDFileUMeshAggregateCompute& other, double eps, std::string& what) const +{ + const MEDCouplingUMesh *m1(getUmesh()); + const MEDCouplingUMesh *m2(other.getUmesh()); + if((m1==0 && m2!=0) || (m1!=0 && m2==0)) + { + what="Presence of mesh in one sublevel and not in other!"; + return false; + } + if(m1) + { + std::string what2; + if(!m1->isEqualIfNotWhy(m2,eps,what2)) + { + what=std::string("meshes at a sublevel are not deeply equal (")+what2+std::string(")!"); + return false; + } + } + std::size_t sz(_part_def.size()); + if(sz!=other._part_def.size()) + { + what=std::string("number of subdivision per geo type for part definition is not the same !"); + return false; + } + for(std::size_t i=0;iisEqual(pd1,what)); + if(!ret) + return false; + } + return true; +} + +void MEDFileUMeshAggregateCompute::clearNonDiscrAttributes() const +{ + for(std::vector< MEDCouplingAutoRefCountObjectPtr >::const_iterator it=_m_parts.begin();it!=_m_parts.end();it++) + MEDFileUMeshSplitL1::ClearNonDiscrAttributes(*it); + MEDFileUMeshSplitL1::ClearNonDiscrAttributes(_m); +} + +void MEDFileUMeshAggregateCompute::synchronizeTinyInfo(const MEDFileMesh& master) const +{ + for(std::vector< MEDCouplingAutoRefCountObjectPtr >::const_iterator it=_m_parts.begin();it!=_m_parts.end();it++) + { + const MEDCoupling1GTUMesh *tmp(*it); + if(tmp) + { + (const_cast(tmp))->setName(master.getName().c_str()); + (const_cast(tmp))->setDescription(master.getDescription().c_str()); + (const_cast(tmp))->setTime(master.getTimeValue(),master.getIteration(),master.getOrder()); + (const_cast(tmp))->setTimeUnit(master.getTimeUnit()); + } + } + const MEDCouplingUMesh *m(_m); + if(m) + { + (const_cast(m))->setName(master.getName().c_str()); + (const_cast(m))->setDescription(master.getDescription().c_str()); + (const_cast(m))->setTime(master.getTimeValue(),master.getIteration(),master.getOrder()); + (const_cast(m))->setTimeUnit(master.getTimeUnit()); + } +} + +bool MEDFileUMeshAggregateCompute::empty() const +{ + if(_mp_time<_m_time) + return ((const MEDCouplingUMesh *)_m)==0; + //else _mp_time>=_m_time) + return _m_parts.empty(); +} + +int MEDFileUMeshAggregateCompute::getMeshDimension() const +{ + if(_mp_time<_m_time) + { + const MEDCouplingUMesh *m(_m); + if(!m) + throw INTERP_KERNEL::Exception("MEDFileUMeshAggregateCompute::getMeshDimension : no umesh in this !"); + return m->getMeshDimension(); + } + else + { + if(_m_parts.empty()) + throw INTERP_KERNEL::Exception("MEDFileUMeshAggregateCompute::getMeshDimension : part mesh is empty !"); + const MEDCoupling1GTUMesh *m(_m_parts[0]); + if(!m) + throw INTERP_KERNEL::Exception("MEDFileUMeshAggregateCompute::getMeshDimension : part mesh contains null instance !"); + return m->getMeshDimension(); + } +} + +std::vector MEDFileUMeshAggregateCompute::getDistributionOfTypes() const +{ + if(_mp_time<_m_time) + { + const MEDCouplingUMesh *m(_m); + if(!m) + throw INTERP_KERNEL::Exception("MEDFileUMeshAggregateCompute::getDistributionOfTypes : no umesh in this !"); + return m->getDistributionOfTypes(); + } + else + { + std::vector ret; + for(std::vector< MEDCouplingAutoRefCountObjectPtr >::const_iterator it=_m_parts.begin();it!=_m_parts.end();it++) + { + const MEDCoupling1GTUMesh *tmp(*it); + if(!tmp) + throw INTERP_KERNEL::Exception("MEDFileUMeshAggregateCompute::getDistributionOfTypes : part mesh contains null instance !"); + std::vector ret0(tmp->getDistributionOfTypes()); + ret.insert(ret.end(),ret0.begin(),ret0.end()); + } + return ret; + } +} + +int MEDFileUMeshAggregateCompute::getSize() const +{ + if(_mp_time<_m_time) + { + const MEDCouplingUMesh *m(_m); + if(!m) + throw INTERP_KERNEL::Exception("MEDFileUMeshAggregateCompute::getSize : no umesh in this !"); + return m->getNumberOfCells(); + } + else + { + int ret=0; + for(std::vector< MEDCouplingAutoRefCountObjectPtr >::const_iterator it=_m_parts.begin();it!=_m_parts.end();it++) + { + const MEDCoupling1GTUMesh *m(*it); + if(!m) + throw INTERP_KERNEL::Exception("MEDFileUMeshAggregateCompute::getSize : part mesh contains null instance !"); + ret+=m->getNumberOfCells(); + } + return ret; + } +} + +void MEDFileUMeshAggregateCompute::setCoords(DataArrayDouble *coords) +{ + for(std::vector< MEDCouplingAutoRefCountObjectPtr >::iterator it=_m_parts.begin();it!=_m_parts.end();it++) + { + MEDCoupling1GTUMesh *tmp(*it); + if(tmp) + (*it)->setCoords(coords); + } + MEDCouplingUMesh *m(_m); + if(m) + m->setCoords(coords); +} diff --cc medtool/src/MEDLoader/SauvMedConvertor.cxx index dd2ba8961,000000000..8972744a4 mode 100644,000000..100644 --- a/medtool/src/MEDLoader/SauvMedConvertor.cxx +++ b/medtool/src/MEDLoader/SauvMedConvertor.cxx @@@ -1,3830 -1,0 +1,3831 @@@ +// Copyright (C) 2007-2015 CEA/DEN, EDF R&D +// +// 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +// +// See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com +// +// File : SauvMedConvertor.cxx +// Created : Tue Aug 16 14:43:20 2011 +// Author : Edward AGAPOV (eap) +// + +#include "SauvMedConvertor.hxx" + +#include "CellModel.hxx" +#include "MEDFileMesh.hxx" +#include "MEDFileField.hxx" +#include "MEDFileData.hxx" +#include "MEDCouplingFieldDouble.hxx" + +#include +#include +#include +#include +#include + +#include +#include +#include + +#ifdef WIN32 +#include +#else +#include +#endif + +#ifdef HAS_XDR ++#include +#include +#endif + +using namespace SauvUtilities; +using namespace ParaMEDMEM; + +namespace +{ + // for ASCII file reader + const int GIBI_MaxOutputLen = 150; // max length of a line in the sauve file + const int GIBI_BufferSize = 16184; // for buffered reading + + using namespace INTERP_KERNEL; + + const size_t MaxMedCellType = NORM_ERROR; + const size_t NbGibiCellTypes = 47; + const TCellType GibiTypeToMed[NbGibiCellTypes] = + { + /*1 */ NORM_POINT1 ,/*2 */ NORM_SEG2 ,/*3 */ NORM_SEG3 ,/*4 */ NORM_TRI3 ,/*5 */ NORM_ERROR , + /*6 */ NORM_TRI6 ,/*7 */ NORM_ERROR ,/*8 */ NORM_QUAD4 ,/*9 */ NORM_ERROR ,/*10*/ NORM_QUAD8 , + /*11*/ NORM_ERROR ,/*12*/ NORM_ERROR ,/*13*/ NORM_ERROR ,/*14*/ NORM_HEXA8 ,/*15*/ NORM_HEXA20 , + /*16*/ NORM_PENTA6 ,/*17*/ NORM_PENTA15,/*18*/ NORM_ERROR ,/*19*/ NORM_ERROR ,/*20*/ NORM_ERROR , + /*21*/ NORM_ERROR ,/*22*/ NORM_ERROR ,/*23*/ NORM_TETRA4 ,/*24*/ NORM_TETRA10,/*25*/ NORM_PYRA5 , + /*26*/ NORM_PYRA13 ,/*27*/ NORM_ERROR ,/*28*/ NORM_ERROR ,/*29*/ NORM_ERROR ,/*30*/ NORM_ERROR , + /*31*/ NORM_ERROR ,/*32*/ NORM_ERROR ,/*33*/ NORM_ERROR ,/*34*/ NORM_ERROR ,/*35*/ NORM_ERROR , + /*36*/ NORM_ERROR ,/*37*/ NORM_ERROR ,/*38*/ NORM_ERROR ,/*39*/ NORM_ERROR ,/*40*/ NORM_ERROR , + /*41*/ NORM_ERROR ,/*42*/ NORM_ERROR ,/*43*/ NORM_ERROR ,/*44*/ NORM_ERROR ,/*45*/ NORM_ERROR , + /*46*/ NORM_ERROR ,/*47*/ NORM_ERROR + }; + + //================================================================================ + /*! + * \brief Return dimension of a group + */ + //================================================================================ + + unsigned getDim( const Group* grp ) + { + return SauvUtilities::getDimension( grp->_groups.empty() ? grp->_cellType : grp->_groups[0]->_cellType ); + } + + //================================================================================ + /*! + * \brief Converts connectivity of quadratic elements + */ + //================================================================================ + + inline void ConvertQuadratic( const INTERP_KERNEL::NormalizedCellType type, + const Cell & aCell ) + { + if ( const int * conn = getGibi2MedQuadraticInterlace( type )) + { + Cell* ma = const_cast(&aCell); + std::vector< Node* > new_nodes( ma->_nodes.size() ); + for (std:: size_t i = 0; i < new_nodes.size(); ++i ) + new_nodes[ i ] = ma->_nodes[ conn[ i ]]; + ma->_nodes.swap( new_nodes ); + } + } + + //================================================================================ + /*! + * \brief Returns a vector of pairs of node indices to inverse a med volume element + */ + //================================================================================ + + void getReverseVector (const INTERP_KERNEL::NormalizedCellType type, + std::vector > & swapVec ) + { + swapVec.clear(); + + switch ( type ) + { + case NORM_TETRA4: + swapVec.resize(1); + swapVec[0] = std::make_pair( 1, 2 ); + break; + case NORM_PYRA5: + swapVec.resize(1); + swapVec[0] = std::make_pair( 1, 3 ); + break; + case NORM_PENTA6: + swapVec.resize(2); + swapVec[0] = std::make_pair( 1, 2 ); + swapVec[1] = std::make_pair( 4, 5 ); + break; + case NORM_HEXA8: + swapVec.resize(2); + swapVec[0] = std::make_pair( 1, 3 ); + swapVec[1] = std::make_pair( 5, 7 ); + break; + case NORM_TETRA10: + swapVec.resize(3); + swapVec[0] = std::make_pair( 1, 2 ); + swapVec[1] = std::make_pair( 4, 6 ); + swapVec[2] = std::make_pair( 8, 9 ); + break; + case NORM_PYRA13: + swapVec.resize(4); + swapVec[0] = std::make_pair( 1, 3 ); + swapVec[1] = std::make_pair( 5, 8 ); + swapVec[2] = std::make_pair( 6, 7 ); + swapVec[3] = std::make_pair( 10, 12 ); + break; + case NORM_PENTA15: + swapVec.resize(4); + swapVec[0] = std::make_pair( 1, 2 ); + swapVec[1] = std::make_pair( 4, 5 ); + swapVec[2] = std::make_pair( 6, 8 ); + swapVec[3] = std::make_pair( 9, 11 ); + break; + case NORM_HEXA20: + swapVec.resize(7); + swapVec[0] = std::make_pair( 1, 3 ); + swapVec[1] = std::make_pair( 5, 7 ); + swapVec[2] = std::make_pair( 8, 11 ); + swapVec[3] = std::make_pair( 9, 10 ); + swapVec[4] = std::make_pair( 12, 15 ); + swapVec[5] = std::make_pair( 13, 14 ); + swapVec[6] = std::make_pair( 17, 19 ); + break; + // case NORM_SEG3: no need to reverse edges + // swapVec.resize(1); + // swapVec[0] = std::make_pair( 1, 2 ); + // break; + case NORM_TRI6: + swapVec.resize(2); + swapVec[0] = std::make_pair( 1, 2 ); + swapVec[1] = std::make_pair( 3, 5 ); + break; + case NORM_QUAD8: + swapVec.resize(3); + swapVec[0] = std::make_pair( 1, 3 ); + swapVec[1] = std::make_pair( 4, 7 ); + swapVec[2] = std::make_pair( 5, 6 ); + break; + default:; + } + } + + //================================================================================ + /*! + * \brief Inverses element orientation using vector of indices to swap + */ + //================================================================================ + + inline void reverse(const Cell & aCell, const std::vector > & swapVec ) + { + Cell* ma = const_cast(&aCell); + for ( unsigned i = 0; i < swapVec.size(); ++i ) + std::swap( ma->_nodes[ swapVec[i].first ], + ma->_nodes[ swapVec[i].second ]); + if ( swapVec.empty() ) + ma->_reverse = true; + else + ma->_reverse = false; + } + //================================================================================ + /*! + * \brief Comparator of cells by number used for ordering cells within a med group + */ + struct TCellByIDCompare + { - bool operator () (const Cell* i1, const Cell* i2) ++ bool operator () (const Cell* i1, const Cell* i2) const + { + return i1->_number < i2->_number; + } + }; + typedef std::map< const Cell*, unsigned, TCellByIDCompare > TCellToOrderMap; + + //================================================================================ + /*! + * \brief Fill Group::_relocTable if necessary + */ + //================================================================================ + + void setRelocationTable( Group* grp, TCellToOrderMap& cell2order ) + { + if ( !grp->_isProfile ) return; + + // check if relocation table is necessary + bool isRelocated = false; + unsigned newOrder = 0; + TCellToOrderMap::iterator c2oIt = cell2order.begin(), c2oEnd = cell2order.end(); + for ( ; !isRelocated && c2oIt != c2oEnd; ++c2oIt, ++newOrder ) + isRelocated = ( c2oIt->second != newOrder ); + + if ( isRelocated ) + { + grp->_relocTable.resize( cell2order.size() ); + for ( newOrder = 0, c2oIt = cell2order.begin(); c2oIt != c2oEnd; ++c2oIt, ++newOrder ) + grp->_relocTable[ c2oIt->second ] = newOrder; + } + } +} + +namespace // define default GAUSS points +{ + typedef std::vector TDoubleVector; + typedef double* TCoordSlice; + typedef int TInt; + //--------------------------------------------------------------- + //! Shape function definitions + //--------------------------------------------------------------- + struct TShapeFun + { + TInt myDim; + TInt myNbRef; + TDoubleVector myRefCoord; + + TShapeFun(TInt theDim = 0, TInt theNbRef = 0) + :myDim(theDim),myNbRef(theNbRef),myRefCoord(theNbRef*theDim) {} + + TInt GetNbRef() const { return myNbRef; } + + TCoordSlice GetCoord(TInt theRefId) { return &myRefCoord[0] + theRefId * myDim; } + }; + //--------------------------------------------------------------- + /*! + * \brief Description of family of integration points + */ + //--------------------------------------------------------------- + struct TGaussDef + { + int myType; //!< element geometry (EGeometrieElement or med_geometrie_element) + TDoubleVector myRefCoords; //!< description of reference points + TDoubleVector myCoords; //!< coordinates of Gauss points + TDoubleVector myWeights; //!< weights, len(weights)== + + /*! + * \brief Creates definition of gauss points family + * \param geomType - element geometry (EGeometrieElement or med_geometrie_element) + * \param nbPoints - nb gauss point + * \param variant - [1-3] to choose the variant of definition + * + * Throws in case of invalid parameters + * variant == 1 refers to "Fonctions de forme et points d'integration + * des elements finis" v7.4 by J. PELLET, X. DESROCHES, 15/09/05 + * variant == 2 refers to the same doc v6.4 by J.P. LEFEBVRE, X. DESROCHES, 03/07/03 + * variant == 3 refers to the same doc v6.4, second variant for 2D elements + */ + TGaussDef(const int geomType, const int nbPoints, const int variant=1); + + int dim() const { return SauvUtilities::getDimension( NormalizedCellType( myType )); } + int nbPoints() const { return myWeights.capacity(); } + + private: + void add(const double x, const double weight); + void add(const double x, const double y, const double weight); + void add(const double x, const double y, const double z, const double weight); + void setRefCoords(const TShapeFun& aShapeFun) { myRefCoords = aShapeFun.myRefCoord; } + }; + struct TSeg2a: TShapeFun { + TSeg2a(); + }; + struct TSeg3a: TShapeFun { + TSeg3a(); + }; + struct TTria3a: TShapeFun { + TTria3a(); + }; + struct TTria6a: TShapeFun { + TTria6a(); + }; + struct TTria3b: TShapeFun { + TTria3b(); + }; + struct TTria6b: TShapeFun { + TTria6b(); + }; + struct TQuad4a: TShapeFun { + TQuad4a(); + }; + struct TQuad8a: TShapeFun { + TQuad8a(); + }; + struct TQuad4b: TShapeFun { + TQuad4b(); + }; + struct TQuad8b: TShapeFun { + TQuad8b(); + }; + struct TTetra4a: TShapeFun { + TTetra4a(); + }; + struct TTetra10a: TShapeFun { + TTetra10a(); + }; + struct TTetra4b: TShapeFun { + TTetra4b(); + }; + struct TTetra10b: TShapeFun { + TTetra10b(); + }; + struct THexa8a: TShapeFun { + THexa8a(); + }; + struct THexa20a: TShapeFun { + THexa20a(TInt theDim = 3, TInt theNbRef = 20); + }; + struct THexa27a: THexa20a { + THexa27a(); + }; + struct THexa8b: TShapeFun { + THexa8b(); + }; + struct THexa20b: TShapeFun { + THexa20b(TInt theDim = 3, TInt theNbRef = 20); + }; + struct TPenta6a: TShapeFun { + TPenta6a(); + }; + struct TPenta6b: TShapeFun { + TPenta6b(); + }; + struct TPenta15a: TShapeFun { + TPenta15a(); + }; + struct TPenta15b: TShapeFun { + TPenta15b(); + }; + struct TPyra5a: TShapeFun { + TPyra5a(); + }; + struct TPyra5b: TShapeFun { + TPyra5b(); + }; + struct TPyra13a: TShapeFun { + TPyra13a(); + }; + struct TPyra13b: TShapeFun { + TPyra13b(); + }; + + void TGaussDef::add(const double x, const double weight) + { + if ( dim() != 1 ) + THROW_IK_EXCEPTION("TGaussDef: dim() != 1"); + if ( myWeights.capacity() == myWeights.size() ) + THROW_IK_EXCEPTION("TGaussDef: Extra gauss point"); + myCoords.push_back( x ); + myWeights.push_back( weight ); + } + void TGaussDef::add(const double x, const double y, const double weight) + { + if ( dim() != 2 ) + THROW_IK_EXCEPTION("TGaussDef: dim() != 2"); + if ( myWeights.capacity() == myWeights.size() ) + THROW_IK_EXCEPTION("TGaussDef: Extra gauss point"); + myCoords.push_back( x ); + myCoords.push_back( y ); + myWeights.push_back( weight ); + } + void TGaussDef::add(const double x, const double y, const double z, const double weight) + { + if ( dim() != 3 ) + THROW_IK_EXCEPTION("TGaussDef: dim() != 3"); + if ( myWeights.capacity() == myWeights.size() ) + THROW_IK_EXCEPTION("TGaussDef: Extra gauss point"); + myCoords.push_back( x ); + myCoords.push_back( y ); + myCoords.push_back( z ); + myWeights.push_back( weight ); + } + + //--------------------------------------------------------------- + TSeg2a::TSeg2a():TShapeFun(1,2) + { + TInt aNbRef = GetNbRef(); + for(TInt aRefId = 0; aRefId < aNbRef; aRefId++){ + TCoordSlice aCoord = GetCoord(aRefId); + switch(aRefId){ + case 0: aCoord[0] = -1.0; break; + case 1: aCoord[0] = 1.0; break; + } + } + } + //--------------------------------------------------------------- + TSeg3a::TSeg3a():TShapeFun(1,3) + { + TInt aNbRef = GetNbRef(); + for(TInt aRefId = 0; aRefId < aNbRef; aRefId++){ + TCoordSlice aCoord = GetCoord(aRefId); + switch(aRefId){ + case 0: aCoord[0] = -1.0; break; + case 1: aCoord[0] = 1.0; break; + case 2: aCoord[0] = 0.0; break; + } + } + } + //--------------------------------------------------------------- + TTria3a::TTria3a(): + TShapeFun(2,3) + { + TInt aNbRef = GetNbRef(); + for(TInt aRefId = 0; aRefId < aNbRef; aRefId++){ + TCoordSlice aCoord = GetCoord(aRefId); + switch(aRefId){ + case 0: aCoord[0] = -1.0; aCoord[1] = 1.0; break; + case 1: aCoord[0] = -1.0; aCoord[1] = -1.0; break; + case 2: aCoord[0] = 1.0; aCoord[1] = -1.0; break; + } + } + } + //--------------------------------------------------------------- + TTria6a::TTria6a():TShapeFun(2,6) + { + TInt aNbRef = GetNbRef(); + for(TInt aRefId = 0; aRefId < aNbRef; aRefId++){ + TCoordSlice aCoord = GetCoord(aRefId); + switch(aRefId){ + case 0: aCoord[0] = -1.0; aCoord[1] = 1.0; break; + case 1: aCoord[0] = -1.0; aCoord[1] = -1.0; break; + case 2: aCoord[0] = 1.0; aCoord[1] = -1.0; break; + + case 3: aCoord[0] = -1.0; aCoord[1] = 1.0; break; + case 4: aCoord[0] = 0.0; aCoord[1] = -1.0; break; + case 5: aCoord[0] = 0.0; aCoord[1] = 0.0; break; + } + } + } + //--------------------------------------------------------------- + TTria3b::TTria3b(): + TShapeFun(2,3) + { + TInt aNbRef = GetNbRef(); + for(TInt aRefId = 0; aRefId < aNbRef; aRefId++){ + TCoordSlice aCoord = GetCoord(aRefId); + switch(aRefId){ + case 0: aCoord[0] = 0.0; aCoord[1] = 0.0; break; + case 1: aCoord[0] = 1.0; aCoord[1] = 0.0; break; + case 2: aCoord[0] = 0.0; aCoord[1] = 1.0; break; + } + } + } + //--------------------------------------------------------------- + TTria6b::TTria6b(): + TShapeFun(2,6) + { + TInt aNbRef = GetNbRef(); + for(TInt aRefId = 0; aRefId < aNbRef; aRefId++){ + TCoordSlice aCoord = GetCoord(aRefId); + switch(aRefId){ + case 0: aCoord[0] = 0.0; aCoord[1] = 0.0; break; + case 1: aCoord[0] = 1.0; aCoord[1] = 0.0; break; + case 2: aCoord[0] = 0.0; aCoord[1] = 1.0; break; + + case 3: aCoord[0] = 0.5; aCoord[1] = 0.0; break; + case 4: aCoord[0] = 0.5; aCoord[1] = 0.5; break; + case 5: aCoord[0] = 0.0; aCoord[1] = 0.5; break; + } + } + } + //--------------------------------------------------------------- + TQuad4a::TQuad4a(): + TShapeFun(2,4) + { + TInt aNbRef = GetNbRef(); + for(TInt aRefId = 0; aRefId < aNbRef; aRefId++){ + TCoordSlice aCoord = GetCoord(aRefId); + switch(aRefId){ + case 0: aCoord[0] = -1.0; aCoord[1] = 1.0; break; + case 1: aCoord[0] = -1.0; aCoord[1] = -1.0; break; + case 2: aCoord[0] = 1.0; aCoord[1] = -1.0; break; + case 3: aCoord[0] = 1.0; aCoord[1] = 1.0; break; + } + } + } + //--------------------------------------------------------------- + TQuad8a::TQuad8a(): + TShapeFun(2,8) + { + TInt aNbRef = GetNbRef(); + for(TInt aRefId = 0; aRefId < aNbRef; aRefId++){ + TCoordSlice aCoord = GetCoord(aRefId); + switch(aRefId){ + case 0: aCoord[0] = -1.0; aCoord[1] = 1.0; break; + case 1: aCoord[0] = -1.0; aCoord[1] = -1.0; break; + case 2: aCoord[0] = 1.0; aCoord[1] = -1.0; break; + case 3: aCoord[0] = 1.0; aCoord[1] = 1.0; break; + + case 4: aCoord[0] = -1.0; aCoord[1] = 0.0; break; + case 5: aCoord[0] = 0.0; aCoord[1] = -1.0; break; + case 6: aCoord[0] = 1.0; aCoord[1] = 0.0; break; + case 7: aCoord[0] = 0.0; aCoord[1] = 1.0; break; + } + } + } + //--------------------------------------------------------------- + TQuad4b::TQuad4b(): + TShapeFun(2,4) + { + TInt aNbRef = GetNbRef(); + for(TInt aRefId = 0; aRefId < aNbRef; aRefId++){ + TCoordSlice aCoord = GetCoord(aRefId); + switch(aRefId){ + case 0: aCoord[0] = -1.0; aCoord[1] = -1.0; break; + case 1: aCoord[0] = 1.0; aCoord[1] = -1.0; break; + case 2: aCoord[0] = 1.0; aCoord[1] = 1.0; break; + case 3: aCoord[0] = -1.0; aCoord[1] = 1.0; break; + } + } + } + //--------------------------------------------------------------- + TQuad8b::TQuad8b(): + TShapeFun(2,8) + { + TInt aNbRef = GetNbRef(); + for(TInt aRefId = 0; aRefId < aNbRef; aRefId++){ + TCoordSlice aCoord = GetCoord(aRefId); + switch(aRefId){ + case 0: aCoord[0] = -1.0; aCoord[1] = -1.0; break; + case 1: aCoord[0] = 1.0; aCoord[1] = -1.0; break; + case 2: aCoord[0] = 1.0; aCoord[1] = 1.0; break; + case 3: aCoord[0] = -1.0; aCoord[1] = 1.0; break; + + case 4: aCoord[0] = 0.0; aCoord[1] = -1.0; break; + case 5: aCoord[0] = 1.0; aCoord[1] = 0.0; break; + case 6: aCoord[0] = 0.0; aCoord[1] = 1.0; break; + case 7: aCoord[0] = -1.0; aCoord[1] = 0.0; break; + } + } + } + //--------------------------------------------------------------- + TTetra4a::TTetra4a(): + TShapeFun(3,4) + { + TInt aNbRef = GetNbRef(); + for(TInt aRefId = 0; aRefId < aNbRef; aRefId++){ + TCoordSlice aCoord = GetCoord(aRefId); + switch(aRefId){ + case 0: aCoord[0] = 0.0; aCoord[1] = 1.0; aCoord[2] = 0.0; break; + case 1: aCoord[0] = 0.0; aCoord[1] = 0.0; aCoord[2] = 1.0; break; + case 2: aCoord[0] = 0.0; aCoord[1] = 0.0; aCoord[2] = 0.0; break; + case 3: aCoord[0] = 1.0; aCoord[1] = 0.0; aCoord[2] = 0.0; break; + } + } + } + //--------------------------------------------------------------- + TTetra10a::TTetra10a(): + TShapeFun(3,10) + { + TInt aNbRef = GetNbRef(); + for(TInt aRefId = 0; aRefId < aNbRef; aRefId++){ + TCoordSlice aCoord = GetCoord(aRefId); + switch(aRefId){ + case 0: aCoord[0] = 0.0; aCoord[1] = 1.0; aCoord[2] = 0.0; break; + case 1: aCoord[0] = 0.0; aCoord[1] = 0.0; aCoord[2] = 1.0; break; + case 2: aCoord[0] = 0.0; aCoord[1] = 0.0; aCoord[2] = 0.0; break; + case 3: aCoord[0] = 1.0; aCoord[1] = 0.0; aCoord[2] = 0.0; break; + + case 4: aCoord[0] = 0.0; aCoord[1] = 0.5; aCoord[2] = 0.5; break; + case 5: aCoord[0] = 0.0; aCoord[1] = 0.0; aCoord[2] = 0.5; break; + case 6: aCoord[0] = 0.0; aCoord[1] = 0.5; aCoord[2] = 0.0; break; + + case 7: aCoord[0] = 0.5; aCoord[1] = 0.5; aCoord[2] = 0.0; break; + case 8: aCoord[0] = 0.5; aCoord[1] = 0.0; aCoord[2] = 0.5; break; + case 9: aCoord[0] = 0.5; aCoord[1] = 0.0; aCoord[2] = 0.0; break; + } + } + } + //--------------------------------------------------------------- + TTetra4b::TTetra4b(): + TShapeFun(3,4) + { + TInt aNbRef = GetNbRef(); + for(TInt aRefId = 0; aRefId < aNbRef; aRefId++){ + TCoordSlice aCoord = GetCoord(aRefId); + switch(aRefId){ + case 0: aCoord[0] = 0.0; aCoord[1] = 1.0; aCoord[2] = 0.0; break; + case 2: aCoord[0] = 0.0; aCoord[1] = 0.0; aCoord[2] = 1.0; break; + case 1: aCoord[0] = 0.0; aCoord[1] = 0.0; aCoord[2] = 0.0; break; + case 3: aCoord[0] = 1.0; aCoord[1] = 0.0; aCoord[2] = 0.0; break; + } + } + } + //--------------------------------------------------------------- + TTetra10b::TTetra10b(): + TShapeFun(3,10) + { + TInt aNbRef = GetNbRef(); + for(TInt aRefId = 0; aRefId < aNbRef; aRefId++){ + TCoordSlice aCoord = GetCoord(aRefId); + switch(aRefId){ + case 0: aCoord[0] = 0.0; aCoord[1] = 1.0; aCoord[2] = 0.0; break; + case 2: aCoord[0] = 0.0; aCoord[1] = 0.0; aCoord[2] = 1.0; break; + case 1: aCoord[0] = 0.0; aCoord[1] = 0.0; aCoord[2] = 0.0; break; + case 3: aCoord[0] = 1.0; aCoord[1] = 0.0; aCoord[2] = 0.0; break; + + case 6: aCoord[0] = 0.0; aCoord[1] = 0.5; aCoord[2] = 0.5; break; + case 5: aCoord[0] = 0.0; aCoord[1] = 0.0; aCoord[2] = 0.5; break; + case 4: aCoord[0] = 0.0; aCoord[1] = 0.5; aCoord[2] = 0.0; break; + + case 7: aCoord[0] = 0.5; aCoord[1] = 0.5; aCoord[2] = 0.0; break; + case 9: aCoord[0] = 0.5; aCoord[1] = 0.0; aCoord[2] = 0.5; break; + case 8: aCoord[0] = 0.5; aCoord[1] = 0.0; aCoord[2] = 0.0; break; + } + } + } + //--------------------------------------------------------------- + THexa8a::THexa8a(): + TShapeFun(3,8) + { + TInt aNbRef = GetNbRef(); + for(TInt aRefId = 0; aRefId < aNbRef; aRefId++){ + TCoordSlice aCoord = GetCoord(aRefId); + switch(aRefId){ + case 0: aCoord[0] = -1.0; aCoord[1] = -1.0; aCoord[2] = -1.0; break; + case 1: aCoord[0] = 1.0; aCoord[1] = -1.0; aCoord[2] = -1.0; break; + case 2: aCoord[0] = 1.0; aCoord[1] = 1.0; aCoord[2] = -1.0; break; + case 3: aCoord[0] = -1.0; aCoord[1] = 1.0; aCoord[2] = -1.0; break; + case 4: aCoord[0] = -1.0; aCoord[1] = -1.0; aCoord[2] = 1.0; break; + case 5: aCoord[0] = 1.0; aCoord[1] = -1.0; aCoord[2] = 1.0; break; + case 6: aCoord[0] = 1.0; aCoord[1] = 1.0; aCoord[2] = 1.0; break; + case 7: aCoord[0] = -1.0; aCoord[1] = 1.0; aCoord[2] = 1.0; break; + } + } + } + //--------------------------------------------------------------- + THexa20a::THexa20a(TInt theDim, TInt theNbRef): + TShapeFun(theDim,theNbRef) + { + TInt aNbRef = myRefCoord.size(); + for(TInt aRefId = 0; aRefId < aNbRef; aRefId++){ + TCoordSlice aCoord = GetCoord(aRefId); + switch(aRefId){ + case 0: aCoord[0] = -1.0; aCoord[1] = -1.0; aCoord[2] = -1.0; break; + case 1: aCoord[0] = 1.0; aCoord[1] = -1.0; aCoord[2] = -1.0; break; + case 2: aCoord[0] = 1.0; aCoord[1] = 1.0; aCoord[2] = -1.0; break; + case 3: aCoord[0] = -1.0; aCoord[1] = 1.0; aCoord[2] = -1.0; break; + case 4: aCoord[0] = -1.0; aCoord[1] = -1.0; aCoord[2] = 1.0; break; + case 5: aCoord[0] = 1.0; aCoord[1] = -1.0; aCoord[2] = 1.0; break; + case 6: aCoord[0] = 1.0; aCoord[1] = 1.0; aCoord[2] = 1.0; break; + case 7: aCoord[0] = -1.0; aCoord[1] = 1.0; aCoord[2] = 1.0; break; + + case 8: aCoord[0] = 0.0; aCoord[1] = -1.0; aCoord[2] = -1.0; break; + case 9: aCoord[0] = 1.0; aCoord[1] = 0.0; aCoord[2] = -1.0; break; + case 10: aCoord[0] = 0.0; aCoord[1] = 1.0; aCoord[2] = -1.0; break; + case 11: aCoord[0] = -1.0; aCoord[1] = 0.0; aCoord[2] = -1.0; break; + case 12: aCoord[0] = -1.0; aCoord[1] = -1.0; aCoord[2] = 0.0; break; + case 13: aCoord[0] = 1.0; aCoord[1] = -1.0; aCoord[2] = 0.0; break; + case 14: aCoord[0] = 1.0; aCoord[1] = 1.0; aCoord[2] = 0.0; break; + case 15: aCoord[0] = -1.0; aCoord[1] = 1.0; aCoord[2] = 0.0; break; + case 16: aCoord[0] = 0.0; aCoord[1] = -1.0; aCoord[2] = 1.0; break; + case 17: aCoord[0] = 1.0; aCoord[1] = 0.0; aCoord[2] = 1.0; break; + case 18: aCoord[0] = 0.0; aCoord[1] = 1.0; aCoord[2] = 1.0; break; + case 19: aCoord[0] = -1.0; aCoord[1] = 0.0; aCoord[2] = 1.0; break; + } + } + } + //--------------------------------------------------------------- + THexa27a::THexa27a(): + THexa20a(3,27) + { + TInt aNbRef = myRefCoord.size(); + for(TInt aRefId = 0; aRefId < aNbRef; aRefId++){ + TCoordSlice aCoord = GetCoord(aRefId); + switch(aRefId){ + case 20: aCoord[0] = 0.0; aCoord[1] = 0.0; aCoord[2] = -1.0; break; + case 21: aCoord[0] = 0.0; aCoord[1] = -1.0; aCoord[2] = 0.0; break; + case 22: aCoord[0] = 1.0; aCoord[1] = 0.0; aCoord[2] = 0.0; break; + case 23: aCoord[0] = 0.0; aCoord[1] = 1.0; aCoord[2] = 0.0; break; + case 24: aCoord[0] = -1.0; aCoord[1] = 0.0; aCoord[2] = 0.0; break; + case 25: aCoord[0] = 0.0; aCoord[1] = 0.0; aCoord[2] = 1.0; break; + case 26: aCoord[0] = 0.0; aCoord[1] = 0.0; aCoord[2] = 0.0; break; + } + } + } + //--------------------------------------------------------------- + THexa8b::THexa8b(): + TShapeFun(3,8) + { + TInt aNbRef = GetNbRef(); + for(TInt aRefId = 0; aRefId < aNbRef; aRefId++){ + TCoordSlice aCoord = GetCoord(aRefId); + switch(aRefId){ + case 0: aCoord[0] = -1.0; aCoord[1] = -1.0; aCoord[2] = -1.0; break; + case 3: aCoord[0] = 1.0; aCoord[1] = -1.0; aCoord[2] = -1.0; break; + case 2: aCoord[0] = 1.0; aCoord[1] = 1.0; aCoord[2] = -1.0; break; + case 1: aCoord[0] = -1.0; aCoord[1] = 1.0; aCoord[2] = -1.0; break; + case 4: aCoord[0] = -1.0; aCoord[1] = -1.0; aCoord[2] = 1.0; break; + case 7: aCoord[0] = 1.0; aCoord[1] = -1.0; aCoord[2] = 1.0; break; + case 6: aCoord[0] = 1.0; aCoord[1] = 1.0; aCoord[2] = 1.0; break; + case 5: aCoord[0] = -1.0; aCoord[1] = 1.0; aCoord[2] = 1.0; break; + } + } + } + //--------------------------------------------------------------- + THexa20b::THexa20b(TInt theDim, TInt theNbRef): + TShapeFun(theDim,theNbRef) + { + TInt aNbRef = myRefCoord.size(); + for(TInt aRefId = 0; aRefId < aNbRef; aRefId++){ + TCoordSlice aCoord = GetCoord(aRefId); + switch(aRefId){ + case 0: aCoord[0] = -1.0; aCoord[1] = -1.0; aCoord[2] = -1.0; break; + case 3: aCoord[0] = 1.0; aCoord[1] = -1.0; aCoord[2] = -1.0; break; + case 2: aCoord[0] = 1.0; aCoord[1] = 1.0; aCoord[2] = -1.0; break; + case 1: aCoord[0] = -1.0; aCoord[1] = 1.0; aCoord[2] = -1.0; break; + case 4: aCoord[0] = -1.0; aCoord[1] = -1.0; aCoord[2] = 1.0; break; + case 7: aCoord[0] = 1.0; aCoord[1] = -1.0; aCoord[2] = 1.0; break; + case 6: aCoord[0] = 1.0; aCoord[1] = 1.0; aCoord[2] = 1.0; break; + case 5: aCoord[0] = -1.0; aCoord[1] = 1.0; aCoord[2] = 1.0; break; + + case 11: aCoord[0] = 0.0; aCoord[1] = -1.0; aCoord[2] = -1.0; break; + case 10: aCoord[0] = 1.0; aCoord[1] = 0.0; aCoord[2] = -1.0; break; + case 9: aCoord[0] = 0.0; aCoord[1] = 1.0; aCoord[2] = -1.0; break; + case 8: aCoord[0] = -1.0; aCoord[1] = 0.0; aCoord[2] = -1.0; break; + case 16: aCoord[0] = -1.0; aCoord[1] = -1.0; aCoord[2] = 0.0; break; + case 19: aCoord[0] = 1.0; aCoord[1] = -1.0; aCoord[2] = 0.0; break; + case 18: aCoord[0] = 1.0; aCoord[1] = 1.0; aCoord[2] = 0.0; break; + case 17: aCoord[0] = -1.0; aCoord[1] = 1.0; aCoord[2] = 0.0; break; + case 15: aCoord[0] = 0.0; aCoord[1] = -1.0; aCoord[2] = 1.0; break; + case 14: aCoord[0] = 1.0; aCoord[1] = 0.0; aCoord[2] = 1.0; break; + case 13: aCoord[0] = 0.0; aCoord[1] = 1.0; aCoord[2] = 1.0; break; + case 12: aCoord[0] = -1.0; aCoord[1] = 0.0; aCoord[2] = 1.0; break; + } + } + } + //--------------------------------------------------------------- + TPenta6a::TPenta6a(): + TShapeFun(3,6) + { + TInt aNbRef = myRefCoord.size(); + for(TInt aRefId = 0; aRefId < aNbRef; aRefId++){ + TCoordSlice aCoord = GetCoord(aRefId); + switch(aRefId){ + case 0: aCoord[0] = -1.0; aCoord[1] = 1.0; aCoord[2] = 0.0; break; + case 1: aCoord[0] = -1.0; aCoord[1] = -0.0; aCoord[2] = 1.0; break; + case 2: aCoord[0] = -1.0; aCoord[1] = 0.0; aCoord[2] = 0.0; break; + case 3: aCoord[0] = 1.0; aCoord[1] = 1.0; aCoord[2] = 0.0; break; + case 4: aCoord[0] = 1.0; aCoord[1] = 0.0; aCoord[2] = 1.0; break; + case 5: aCoord[0] = 1.0; aCoord[1] = 0.0; aCoord[2] = 0.0; break; + } + } + } + //--------------------------------------------------------------- + TPenta6b::TPenta6b(): + TShapeFun(3,6) + { + TInt aNbRef = myRefCoord.size(); + for(TInt aRefId = 0; aRefId < aNbRef; aRefId++){ + TCoordSlice aCoord = GetCoord(aRefId); + switch(aRefId){ + case 0: aCoord[0] = -1.0; aCoord[1] = 1.0; aCoord[2] = 0.0; break; + case 2: aCoord[0] = -1.0; aCoord[1] = -0.0; aCoord[2] = 1.0; break; + case 1: aCoord[0] = -1.0; aCoord[1] = 0.0; aCoord[2] = 0.0; break; + case 3: aCoord[0] = 1.0; aCoord[1] = 1.0; aCoord[2] = 0.0; break; + case 5: aCoord[0] = 1.0; aCoord[1] = 0.0; aCoord[2] = 1.0; break; + case 4: aCoord[0] = 1.0; aCoord[1] = 0.0; aCoord[2] = 0.0; break; + } + } + } + //--------------------------------------------------------------- + TPenta15a::TPenta15a(): + TShapeFun(3,15) + { + TInt aNbRef = myRefCoord.size(); + for(TInt aRefId = 0; aRefId < aNbRef; aRefId++){ + TCoordSlice aCoord = GetCoord(aRefId); + switch(aRefId){ + case 0: aCoord[0] = -1.0; aCoord[1] = 1.0; aCoord[2] = 0.0; break; + case 1: aCoord[0] = -1.0; aCoord[1] = -0.0; aCoord[2] = 1.0; break; + case 2: aCoord[0] = -1.0; aCoord[1] = 0.0; aCoord[2] = 0.0; break; + case 3: aCoord[0] = 1.0; aCoord[1] = 1.0; aCoord[2] = 0.0; break; + case 4: aCoord[0] = 1.0; aCoord[1] = 0.0; aCoord[2] = 1.0; break; + case 5: aCoord[0] = 1.0; aCoord[1] = 0.0; aCoord[2] = 0.0; break; + + case 6: aCoord[0] = -1.0; aCoord[1] = 0.5; aCoord[2] = 0.5; break; + case 7: aCoord[0] = -1.0; aCoord[1] = 0.0; aCoord[2] = 0.5; break; + case 8: aCoord[0] = -1.0; aCoord[1] = 0.5; aCoord[2] = 0.0; break; + case 9: aCoord[0] = 0.0; aCoord[1] = 1.0; aCoord[2] = 0.0; break; + case 10: aCoord[0] = 0.0; aCoord[1] = 0.0; aCoord[2] = 1.0; break; + case 11: aCoord[0] = 0.0; aCoord[1] = 0.0; aCoord[2] = 0.0; break; + case 12: aCoord[0] = 1.0; aCoord[1] = 0.5; aCoord[2] = 0.5; break; + case 13: aCoord[0] = 1.0; aCoord[1] = 0.0; aCoord[2] = 0.5; break; + case 14: aCoord[0] = 1.0; aCoord[1] = 0.5; aCoord[2] = 0.0; break; + } + } + } + //--------------------------------------------------------------- + TPenta15b::TPenta15b(): + TShapeFun(3,15) + { + TInt aNbRef = myRefCoord.size(); + for(TInt aRefId = 0; aRefId < aNbRef; aRefId++){ + TCoordSlice aCoord = GetCoord(aRefId); + switch(aRefId){ + case 0: aCoord[0] = -1.0; aCoord[1] = 1.0; aCoord[2] = 0.0; break; + case 2: aCoord[0] = -1.0; aCoord[1] = -0.0; aCoord[2] = 1.0; break; + case 1: aCoord[0] = -1.0; aCoord[1] = 0.0; aCoord[2] = 0.0; break; + case 3: aCoord[0] = 1.0; aCoord[1] = 1.0; aCoord[2] = 0.0; break; + case 5: aCoord[0] = 1.0; aCoord[1] = 0.0; aCoord[2] = 1.0; break; + case 4: aCoord[0] = 1.0; aCoord[1] = 0.0; aCoord[2] = 0.0; break; + + case 8: aCoord[0] = -1.0; aCoord[1] = 0.5; aCoord[2] = 0.5; break; + case 7: aCoord[0] = -1.0; aCoord[1] = 0.0; aCoord[2] = 0.5; break; + case 6: aCoord[0] = -1.0; aCoord[1] = 0.5; aCoord[2] = 0.0; break; + case 12: aCoord[0] = 0.0; aCoord[1] = 1.0; aCoord[2] = 0.0; break; + case 14: aCoord[0] = 0.0; aCoord[1] = 0.0; aCoord[2] = 1.0; break; + case 13: aCoord[0] = 0.0; aCoord[1] = 0.0; aCoord[2] = 0.0; break; + case 11: aCoord[0] = 1.0; aCoord[1] = 0.5; aCoord[2] = 0.5; break; + case 10: aCoord[0] = 1.0; aCoord[1] = 0.0; aCoord[2] = 0.5; break; + case 9: aCoord[0] = 1.0; aCoord[1] = 0.5; aCoord[2] = 0.0; break; + } + } + } + //--------------------------------------------------------------- + TPyra5a::TPyra5a(): + TShapeFun(3,5) + { + TInt aNbRef = myRefCoord.size(); + for(TInt aRefId = 0; aRefId < aNbRef; aRefId++){ + TCoordSlice aCoord = GetCoord(aRefId); + switch(aRefId){ + case 0: aCoord[0] = 1.0; aCoord[1] = 0.0; aCoord[2] = 0.0; break; + case 1: aCoord[0] = 0.0; aCoord[1] = 1.0; aCoord[2] = 0.0; break; + case 2: aCoord[0] = -1.0; aCoord[1] = 0.0; aCoord[2] = 0.0; break; + case 3: aCoord[0] = 0.0; aCoord[1] = -1.0; aCoord[2] = 0.0; break; + case 4: aCoord[0] = 0.0; aCoord[1] = 0.0; aCoord[2] = 1.0; break; + } + } + } + //--------------------------------------------------------------- + TPyra5b::TPyra5b(): + TShapeFun(3,5) + { + TInt aNbRef = myRefCoord.size(); + for(TInt aRefId = 0; aRefId < aNbRef; aRefId++){ + TCoordSlice aCoord = GetCoord(aRefId); + switch(aRefId){ + case 0: aCoord[0] = 1.0; aCoord[1] = 0.0; aCoord[2] = 0.0; break; + case 3: aCoord[0] = 0.0; aCoord[1] = 1.0; aCoord[2] = 0.0; break; + case 2: aCoord[0] = -1.0; aCoord[1] = 0.0; aCoord[2] = 0.0; break; + case 1: aCoord[0] = 0.0; aCoord[1] = -1.0; aCoord[2] = 0.0; break; + case 4: aCoord[0] = 0.0; aCoord[1] = 0.0; aCoord[2] = 1.0; break; + } + } + } + //--------------------------------------------------------------- + TPyra13a::TPyra13a(): + TShapeFun(3,13) + { + TInt aNbRef = myRefCoord.size(); + for(TInt aRefId = 0; aRefId < aNbRef; aRefId++){ + TCoordSlice aCoord = GetCoord(aRefId); + switch(aRefId){ + case 0: aCoord[0] = 1.0; aCoord[1] = 0.0; aCoord[2] = 0.0; break; + case 1: aCoord[0] = 0.0; aCoord[1] = 1.0; aCoord[2] = 0.0; break; + case 2: aCoord[0] = -1.0; aCoord[1] = 0.0; aCoord[2] = 0.0; break; + case 3: aCoord[0] = 0.0; aCoord[1] = -1.0; aCoord[2] = 0.0; break; + case 4: aCoord[0] = 0.0; aCoord[1] = 0.0; aCoord[2] = 1.0; break; + + case 5: aCoord[0] = 0.5; aCoord[1] = 0.5; aCoord[2] = 0.0; break; + case 6: aCoord[0] = -0.5; aCoord[1] = 0.5; aCoord[2] = 0.0; break; + case 7: aCoord[0] = -0.5; aCoord[1] = -0.5; aCoord[2] = 0.0; break; + case 8: aCoord[0] = 0.5; aCoord[1] = -0.5; aCoord[2] = 0.0; break; + case 9: aCoord[0] = 0.5; aCoord[1] = 0.0; aCoord[2] = 0.5; break; + case 10: aCoord[0] = 0.0; aCoord[1] = 0.5; aCoord[2] = 0.5; break; + case 11: aCoord[0] = -0.5; aCoord[1] = 0.0; aCoord[2] = 0.5; break; + case 12: aCoord[0] = 0.0; aCoord[1] = -0.5; aCoord[2] = 0.5; break; + } + } + } + //--------------------------------------------------------------- + TPyra13b::TPyra13b(): + TShapeFun(3,13) + { + TInt aNbRef = myRefCoord.size(); + for(TInt aRefId = 0; aRefId < aNbRef; aRefId++){ + TCoordSlice aCoord = GetCoord(aRefId); + switch(aRefId){ + case 0: aCoord[0] = 1.0; aCoord[1] = 0.0; aCoord[2] = 0.0; break; + case 3: aCoord[0] = 0.0; aCoord[1] = 1.0; aCoord[2] = 0.0; break; + case 2: aCoord[0] = -1.0; aCoord[1] = 0.0; aCoord[2] = 0.0; break; + case 1: aCoord[0] = 0.0; aCoord[1] = -1.0; aCoord[2] = 0.0; break; + case 4: aCoord[0] = 0.0; aCoord[1] = 0.0; aCoord[2] = 1.0; break; + + case 8: aCoord[0] = 0.5; aCoord[1] = 0.5; aCoord[2] = 0.0; break; + case 7: aCoord[0] = -0.5; aCoord[1] = 0.5; aCoord[2] = 0.0; break; + case 6: aCoord[0] = -0.5; aCoord[1] = -0.5; aCoord[2] = 0.0; break; + case 5: aCoord[0] = 0.5; aCoord[1] = -0.5; aCoord[2] = 0.0; break; + case 9: aCoord[0] = 0.5; aCoord[1] = 0.0; aCoord[2] = 0.5; break; + case 12: aCoord[0] = 0.0; aCoord[1] = 0.5; aCoord[2] = 0.5; break; + case 11: aCoord[0] = -0.5; aCoord[1] = 0.0; aCoord[2] = 0.5; break; + case 10: aCoord[0] = 0.0; aCoord[1] = -0.5; aCoord[2] = 0.5; break; + } + } + } + /*! + * \brief Fill definition of gauss points family + */ + + TGaussDef::TGaussDef(const int geom, const int nbGauss, const int variant) + { + myType = geom; + myCoords .reserve( nbGauss * dim() ); + myWeights.reserve( nbGauss ); + + switch ( geom ) { + + case NORM_SEG2: + case NORM_SEG3: + if (geom == NORM_SEG2) setRefCoords( TSeg2a() ); + else setRefCoords( TSeg3a() ); + switch ( nbGauss ) { + case 1: { + add( 0.0, 2.0 ); break; + } + case 2: { + const double a = 0.577350269189626; + add( a, 1.0 ); + add( -a, 1.0 ); break; + } + case 3: { + const double a = 0.774596669241; + const double P1 = 1./1.8; + const double P2 = 1./1.125; + add( -a, P1 ); + add( 0, P2 ); + add( a, P1 ); break; + } + case 4: { + const double a = 0.339981043584856, b = 0.861136311594053; + const double P1 = 0.652145154862546, P2 = 0.347854845137454 ; + add( a, P1 ); + add( -a, P1 ); + add( b, P2 ); + add( -b, P2 ); break; + } + default: + THROW_IK_EXCEPTION("TGaussDef: Invalid nb of gauss points for SEG"< alfa + const double a = (6 + sqrt(15.))/21.; + const double b = (6 - sqrt(15.))/21.; + const double P1 = (155 + sqrt(15.))/2400.; + const double P2 = (155 - sqrt(15.))/2400.; //___ + add( -d, 1/3., 1/3., c1*9/80. );//___ + add( -d, a, a, c1*P1 ); + add( -d, 1-2*a, a, c1*P1 ); + add( -d, a, 1-2*a, c1*P1 );//___ + add( -d, b, b, c1*P2 ); + add( -d, 1-2*b, b, c1*P2 ); + add( -d, b, 1-2*b, c1*P2 );//___ + add( 0., 1/3., 1/3., c2*9/80. );//___ + add( 0., a, a, c2*P1 ); + add( 0., 1-2*a, a, c2*P1 ); + add( 0., a, 1-2*a, c2*P1 );//___ + add( 0., b, b, c2*P2 ); + add( 0., 1-2*b, b, c2*P2 ); + add( 0., b, 1-2*b, c2*P2 );//___ + add( d, 1/3., 1/3., c1*9/80. );//___ + add( d, a, a, c1*P1 ); + add( d, 1-2*a, a, c1*P1 ); + add( d, a, 1-2*a, c1*P1 );//___ + add( d, b, b, c1*P2 ); + add( d, 1-2*b, b, c1*P2 ); + add( d, b, 1-2*b, c1*P2 );//___ + break; + } + default: + THROW_IK_EXCEPTION("TGaussDef: Invalid nb of gauss points for PENTA: " < conn; + static const int hexa20 [] = {0,6,4,2, 12,18,16,14, 7,5,3,1, 19,17,15,13, 8,11,10,9}; + static const int penta15[] = {0,2,4, 9,11,13, 1,3,5, 10,12,14, 6,8,7}; + static const int pyra13 [] = {0,2,4,6, 12, 1,3,5,7, 8,9,10,11}; + static const int tetra10[] = {0,2,4, 9, 1,3,5, 6,7,8}; + static const int quad8 [] = {0,2,4,6, 1,3,5,7}; + static const int tria6 [] = {0,2,4, 1,3,5}; + static const int seg3 [] = {0,2,1}; + if ( conn.empty() ) + { + conn.resize( MaxMedCellType + 1, 0 ); + conn[ NORM_HEXA20 ] = hexa20; + conn[ NORM_PENTA15] = penta15; + conn[ NORM_PYRA13 ] = pyra13; + conn[ NORM_TETRA10] = tetra10; + conn[ NORM_SEG3 ] = seg3; + conn[ NORM_TRI6 ] = tria6; + conn[ NORM_QUAD8 ] = quad8; + } + return conn[ type ]; +} + +//================================================================================ +/*! + * \brief Avoid coping sortedNodeIDs + */ +//================================================================================ + +Cell::Cell(const Cell& ma) + : _nodes(ma._nodes), _reverse(ma._reverse), _sortedNodeIDs(0), _number(ma._number) +{ + if ( ma._sortedNodeIDs ) + { + _sortedNodeIDs = new int[ _nodes.size() ]; + std::copy( ma._sortedNodeIDs, ma._sortedNodeIDs + _nodes.size(), _sortedNodeIDs ); + } +} + +//================================================================================ +/*! + * \brief Rerturn the i-th link of face + */ +//================================================================================ + +SauvUtilities::Link Cell::link(int i) const +{ + int i2 = ( i + 1 ) % _nodes.size(); + if ( _reverse ) + return std::make_pair( _nodes[i2]->_number, _nodes[i]->_number ); + else + return std::make_pair( _nodes[i]->_number, _nodes[i2]->_number ); +} + +//================================================================================ +/*! + * \brief creates if needed and return _sortedNodeIDs + */ +//================================================================================ + +const TID* Cell::getSortedNodes() const +{ + if ( !_sortedNodeIDs ) + { + size_t l=_nodes.size(); + _sortedNodeIDs = new int[ l ]; + + for (size_t i=0; i!=l; ++i) + _sortedNodeIDs[i]=_nodes[i]->_number; + std::sort( _sortedNodeIDs, _sortedNodeIDs + l ); + } + return _sortedNodeIDs; +} + +//================================================================================ +/*! + * \brief Compare sorted ids of cell nodes + */ +//================================================================================ + +bool Cell::operator< (const Cell& ma) const +{ + if ( _nodes.size() == 1 ) + return _nodes[0] < ma._nodes[0]; + + const int* v1 = getSortedNodes(); + const int* v2 = ma.getSortedNodes(); + for ( const int* vEnd = v1 + _nodes.size(); v1 < vEnd; ++v1, ++v2 ) + if(*v1 != *v2) + return *v1 < *v2; + return false; +} + +//================================================================================ +/*! + * \brief Dump a Cell + */ +//================================================================================ + +std::ostream& SauvUtilities::operator<< (std::ostream& os, const SauvUtilities::Cell& ma) +{ + os << "cell " << ma._number << " (" << ma._nodes.size() << " nodes) : < " << ma._nodes[0]->_number; + for( size_t i=1; i!=ma._nodes.size(); ++i) + os << ", " << ma._nodes[i]->_number; +#ifdef _DEBUG_ + os << " > sortedNodes: "; + if ( ma._sortedNodeIDs ) { + os << "< "; + for( size_t i=0; i!=ma._nodes.size(); ++i) + os << ( i ? ", " : "" ) << ma._sortedNodeIDs[i]; + os << " >"; + } + else { + os << "NULL"; + } +#endif + return os; +} + +//================================================================================ +/*! + * \brief Return nb of elements in the group + */ +//================================================================================ + +int Group::size() const +{ + int sizze = 0; + if ( !_relocTable.empty() ) + sizze = _relocTable.size(); + else if ( _medGroup ) + sizze = _medGroup->getNumberOfTuples(); + else if ( !_cells.empty() ) + sizze = _cells.size(); + else + for ( size_t i = 0; i < _groups.size(); ++i ) + sizze += _groups[i]->size(); + return sizze; +} + +//================================================================================ +/*! + * \brief Conver gibi element type to med one + */ +//================================================================================ + +INTERP_KERNEL::NormalizedCellType SauvUtilities::gibi2medGeom( size_t gibiType ) +{ + if ( gibiType < 1 || gibiType > NbGibiCellTypes ) + return NORM_ERROR; + + return GibiTypeToMed[ gibiType - 1 ]; +} + +//================================================================================ +/*! + * \brief Conver med element type to gibi one + */ +//================================================================================ + +int SauvUtilities::med2gibiGeom( INTERP_KERNEL::NormalizedCellType medGeomType ) +{ + for ( unsigned int i = 0; i < NbGibiCellTypes; i++ ) + if ( GibiTypeToMed[ i ] == medGeomType ) + return i + 1; + + return -1; +} + +//================================================================================ +/*! + * \brief Remember the file name + */ +//================================================================================ + +FileReader::FileReader(const char* fileName):_fileName(fileName),_iRead(0),_nbToRead(0) +{ +} + +//================================================================================ +/*! + * \brief Constructor of ASCII sauve file reader + */ +//================================================================================ + +ASCIIReader::ASCIIReader(const char* fileName) + :FileReader(fileName), + _file(-1) +{ +} + +//================================================================================ +/*! + * \brief Return true + */ +//================================================================================ + +bool ASCIIReader::isASCII() const +{ + return true; +} + +//================================================================================ +/*! + * \brief Try to open an ASCII file + */ +//================================================================================ + +bool ASCIIReader::open() +{ +#ifdef WIN32 + _file = ::_open (_fileName.c_str(), _O_RDONLY|_O_BINARY); +#else + _file = ::open (_fileName.c_str(), O_RDONLY); +#endif + if (_file >= 0) + { + _start = new char [GIBI_BufferSize]; // working buffer beginning + //_tmpBuf = new char [GIBI_MaxOutputLen]; + _ptr = _start; + _eptr = _start; + _lineNb = 0; + } + else + { + //THROW_IK_EXCEPTION("Can't open file "<<_fileName << " fd: " << _file); + } + return (_file >= 0); +} + +//================================================================================ +/*! + * \brief Close the file + */ +//================================================================================ + +ASCIIReader::~ASCIIReader() +{ + if (_file >= 0) + { + ::close (_file); + if (_start != 0L) + { + delete [] _start; + //delete [] _tmpBuf; + _start = 0; + } + _file = -1; + } +} + +//================================================================================ +/*! + * \brief Return a next line of the file + */ +//================================================================================ + +bool ASCIIReader::getNextLine (char* & line, bool raiseOEF /*= true*/ ) +{ + if ( getLine( line )) return true; + if ( raiseOEF ) + THROW_IK_EXCEPTION("Unexpected EOF on ln "<<_lineNb); + return false; +} + +//================================================================================ +/*! + * \brief Read a next line of the file if necessary + */ +//================================================================================ + +bool ASCIIReader::getLine(char* & line) +{ + bool aResult = true; + // Check the state of the buffer; + // if there is too little left, read the next portion of data + int nBytesRest = _eptr - _ptr; + if (nBytesRest < GIBI_MaxOutputLen) + { + if (nBytesRest > 0) + { + // move the remaining portion to the buffer beginning + for ( int i = 0; i < nBytesRest; ++i ) + _start[i] = _ptr[i]; + //memcpy (_tmpBuf, _ptr, nBytesRest); + //memcpy (_start, _tmpBuf, nBytesRest); + } + else + { + nBytesRest = 0; + } + _ptr = _start; + const int nBytesRead = ::read (_file, + &_start [nBytesRest], + GIBI_BufferSize - nBytesRest); + nBytesRest += nBytesRead; + _eptr = &_start [nBytesRest]; + } + // Check the buffer for the end-of-line + char * ptr = _ptr; + while (true) + { + // Check for end-of-the-buffer, the ultimate criterion for termination + if (ptr >= _eptr) + { + if (nBytesRest <= 0) + aResult = false; + else + _eptr[-1] = '\0'; + break; + } + // seek the line-feed character + if (ptr[0] == '\n') + { + if (ptr[-1] == '\r') + ptr[-1] = '\0'; + ptr[0] = '\0'; + ++ptr; + break; + } + ++ptr; + } + // Output the result + line = _ptr; + _ptr = ptr; + _lineNb++; + + return aResult; +} + +//================================================================================ +/*! + * \brief Prepare for iterating over given nb of values + * \param nbToRead - nb of fields to read + * \param nbPosInLine - nb of fields in one line + * \param width - field width + * \param shift - shift from line beginning to the field start + */ +//================================================================================ + +void ASCIIReader::init( int nbToRead, int nbPosInLine, int width, int shift /*= 0*/ ) +{ + _nbToRead = nbToRead; + _nbPosInLine = nbPosInLine; + _width = width; + _shift = shift; + _iPos = _iRead = 0; + if ( _nbToRead ) + { + getNextLine( _curPos ); + _curPos = _curPos + _shift; + } + else + { + _curPos = 0; + } + _curLocale.clear(); +} + +//================================================================================ +/*! + * \brief Prepare for iterating over given nb of string values + */ +//================================================================================ + +void ASCIIReader::initNameReading(int nbValues, int width /*= 8*/) +{ + init( nbValues, 72 / ( width + 1 ), width, 1 ); +} + +//================================================================================ +/*! + * \brief Prepare for iterating over given nb of integer values + */ +//================================================================================ + +void ASCIIReader::initIntReading(int nbValues) +{ + init( nbValues, 10, 8 ); +} + +//================================================================================ +/*! + * \brief Prepare for iterating over given nb of real values + */ +//================================================================================ + +void ASCIIReader::initDoubleReading(int nbValues) +{ + init( nbValues, 3, 22 ); + + // Correction 2 of getDouble(): set "C" numeric locale to read numbers + // with dot decimal point separator, as it is in SAUVE files + _curLocale = setlocale(LC_NUMERIC, "C"); +} + +//================================================================================ +/*! + * \brief Return true if not all values have been read + */ +//================================================================================ + +bool ASCIIReader::more() const +{ + bool result = false; + if ( _iRead < _nbToRead) + { + if ( _curPos ) result = true; + } + return result; +} + +//================================================================================ +/*! + * \brief Go to the nex value + */ +//================================================================================ + +void ASCIIReader::next() +{ + if ( !more() ) + THROW_IK_EXCEPTION("SauvUtilities::ASCIIReader::next(): no more() values to read"); + ++_iRead; + ++_iPos; + if ( _iRead < _nbToRead ) + { + if ( _iPos >= _nbPosInLine ) + { + getNextLine( _curPos ); + _curPos = _curPos + _shift; + _iPos = 0; + } + else + { + _curPos = _curPos + _width + _shift; + } + } + else + { + _curPos = 0; + if ( !_curLocale.empty() ) + { + setlocale(LC_NUMERIC, _curLocale.c_str()); + _curLocale.clear(); + } + } +} + +//================================================================================ +/*! + * \brief Return the current integer value + */ +//================================================================================ + +int ASCIIReader::getInt() const +{ + // fix for two glued ints (issue 0021009): + // Line nb | File contents + // ------------------------------------------------------------------------------------ + // 53619905 | 1 2 6 8 + // 53619906 | SCALAIRE + // 53619907 | -63312600499 1 0 0 0 -2 0 2 + // where -63312600499 is actualy -633 and 12600499 + char hold=_curPos[_width]; + _curPos[_width] = '\0'; + int result = atoi( _curPos ); + _curPos[_width] = hold; + return result; + //return atoi(str()); +} + +//================================================================================ +/*! + * \brief Return the current float value + */ +//================================================================================ + +float ASCIIReader::getFloat() const +{ + return getDouble(); +} + +//================================================================================ +/*! + * \brief Return the current double value + */ +//================================================================================ + +double ASCIIReader::getDouble() const +{ + //std::string aStr (_curPos); + + // Correction: add missing 'E' specifier + // int aPosStart = aStr.find_first_not_of(" \t"); + // if (aPosStart < (int)aStr.length()) { + // int aPosSign = aStr.find_first_of("+-", aPosStart + 1); // pass the leading symbol, as it can be a sign + // if (aPosSign < (int)aStr.length()) { + // if (aStr[aPosSign - 1] != 'e' && aStr[aPosSign - 1] != 'E') + // aStr.insert(aPosSign, "E", 1); + // } + // } + + // Different Correction (more optimal) + // Sample: + // 0.00000000000000E+00 -2.37822406690632E+01 6.03062748797469E+01 + // 7.70000000000000-100 7.70000000000000+100 7.70000000000000+100 + //0123456789012345678901234567890123456789012345678901234567890123456789 + const size_t posE = 18; + std::string aStr (_curPos); + if ( aStr.find('E') < 0 && aStr.find('e') < 0 ) + { + if ( aStr.size() < posE+1 ) + THROW_IK_EXCEPTION("No more doubles (line #" << lineNb() << ")"); + aStr.insert( posE, "E", 1 ); + return atof(aStr.c_str()); + } + return atof( _curPos ); +} + +//================================================================================ +/*! + * \brief Return the current string value + */ +//================================================================================ + +std::string ASCIIReader::getName() const +{ + int len = _width; + while (( _curPos[len-1] == ' ' || _curPos[len-1] == 0) && len > 0 ) + len--; + return std::string( _curPos, len ); +} + +//================================================================================ +/*! + * \brief Constructor of a binary sauve file reader + */ +//================================================================================ + +XDRReader::XDRReader(const char* fileName) :FileReader(fileName), _xdrs_file(NULL) +{ +} + +//================================================================================ +/*! + * \brief Close the XDR sauve file + */ +//================================================================================ + +XDRReader::~XDRReader() +{ +#ifdef HAS_XDR + if ( _xdrs_file ) + { + xdr_destroy((XDR*)_xdrs); + free((XDR*)_xdrs); + ::fclose(_xdrs_file); + _xdrs_file = NULL; + } +#endif +} + +//================================================================================ +/*! + * \brief Return false + */ +//================================================================================ + +bool XDRReader::isASCII() const +{ + return false; +} + +//================================================================================ +/*! + * \brief Try to open an XRD file + */ +//================================================================================ + +bool XDRReader::open() +{ + bool xdr_ok = false; +#ifdef HAS_XDR +#ifdef WIN32 + if ((_xdrs_file = ::fopen(_fileName.c_str(), "rb"))) +#else + if ((_xdrs_file = ::fopen(_fileName.c_str(), "r"))) +#endif + { + _xdrs = (XDR *)malloc(sizeof(XDR)); + xdrstdio_create((XDR*)_xdrs, _xdrs_file, XDR_DECODE); + + const int maxsize = 10; + char icha[maxsize+1]; + char* icha2 = icha; + if (( xdr_ok = xdr_string((XDR*)_xdrs, &icha2, maxsize))) + { + icha[maxsize] = '\0'; + xdr_ok = (strcmp(icha, "CASTEM XDR") == 0); + } + if ( !xdr_ok ) + { + xdr_destroy((XDR*)_xdrs); + free((XDR*)_xdrs); + fclose(_xdrs_file); + _xdrs_file = NULL; + } + } +#endif + return xdr_ok; +} + +//================================================================================ +/*! + * \brief A stub + */ +//================================================================================ + +bool XDRReader::getNextLine (char* &, bool ) +{ + return true; +} + +//================================================================================ +/*! + * \brief Prepare for iterating over given nb of values + * \param nbToRead - nb of fields to read + * \param width - field width + */ +//================================================================================ + +void XDRReader::init( int nbToRead, int width/*=0*/ ) +{ + if(_iRead < _nbToRead) + { + std::cout << "_iRead, _nbToRead : " << _iRead << " " << _nbToRead << std::endl; + std::cout << "Unfinished iteration before new one !" << std::endl; + THROW_IK_EXCEPTION("SauvUtilities::XDRReader::init(): Unfinished iteration before new one !"); + } + _iRead = 0; + _nbToRead = nbToRead; + _width = width; +} + +//================================================================================ +/*! + * \brief Prepare for iterating over given nb of string values + */ +//================================================================================ + +void XDRReader::initNameReading(int nbValues, int width) +{ + init( nbValues, width ); + _xdr_kind = _xdr_kind_char; + if(nbValues*width) + { + unsigned int nels = nbValues*width; + _xdr_cvals = (char*)malloc((nels+1)*sizeof(char)); +#ifdef HAS_XDR + xdr_string((XDR*)_xdrs, &_xdr_cvals, nels); +#endif + _xdr_cvals[nels] = '\0'; + } +} + +//================================================================================ +/*! + * \brief Prepare for iterating over given nb of integer values + */ +//================================================================================ + +void XDRReader::initIntReading(int nbValues) +{ + init( nbValues ); + _xdr_kind = _xdr_kind_int; + if(nbValues) + { +#ifdef HAS_XDR + unsigned int nels = nbValues; + unsigned int actual_nels; + _xdr_ivals = (int*)malloc(nels*sizeof(int)); + xdr_array((XDR*)_xdrs, (char **)&_xdr_ivals, &actual_nels, nels, sizeof(int), (xdrproc_t)xdr_int); +#endif + } +} + +//================================================================================ +/*! + * \brief Prepare for iterating over given nb of real values + */ +//================================================================================ + +void XDRReader::initDoubleReading(int nbValues) +{ + init( nbValues ); + _xdr_kind = _xdr_kind_double; + if(nbValues) + { +#ifdef HAS_XDR + unsigned int nels = nbValues; + unsigned int actual_nels; + _xdr_dvals = (double*)malloc(nels*sizeof(double)); + xdr_array((XDR*)_xdrs, (char **)&_xdr_dvals, &actual_nels, nels, sizeof(double), (xdrproc_t)xdr_double); +#endif + } +} + +//================================================================================ +/*! + * \brief Return true if not all values have been read + */ +//================================================================================ + +bool XDRReader::more() const +{ + return _iRead < _nbToRead; +} + +//================================================================================ +/*! + * \brief Go to the nex value + */ +//================================================================================ + +void XDRReader::next() +{ + if ( !more() ) + THROW_IK_EXCEPTION("SauvUtilities::XDRReader::next(): no more() values to read"); + + ++_iRead; + if ( _iRead < _nbToRead ) + { + } + else + { + if(_xdr_kind == _xdr_kind_char) free(_xdr_cvals); + if(_xdr_kind == _xdr_kind_int) free(_xdr_ivals); + if(_xdr_kind == _xdr_kind_double) free(_xdr_dvals); + _xdr_kind = _xdr_kind_null; + } +} + +//================================================================================ +/*! + * \brief Return the current integer value + */ +//================================================================================ + +int XDRReader::getInt() const +{ + if(_iRead < _nbToRead) + { + return _xdr_ivals[_iRead]; + } + else + { + int result = 0; +#ifdef HAS_XDR + xdr_int((XDR*)_xdrs, &result); +#endif + return result; + } +} + +//================================================================================ +/*! + * \brief Return the current float value + */ +//================================================================================ + +float XDRReader::getFloat() const +{ + float result = 0; +#ifdef HAS_XDR + xdr_float((XDR*)_xdrs, &result); +#endif + return result; +} + +//================================================================================ +/*! + * \brief Return the current double value + */ +//================================================================================ + +double XDRReader::getDouble() const +{ + if(_iRead < _nbToRead) + { + return _xdr_dvals[_iRead]; + } + else + { + double result = 0; +#ifdef HAS_XDR + xdr_double((XDR*)_xdrs, &result); +#endif + return result; + } +} + +//================================================================================ +/*! + * \brief Return the current string value + */ +//================================================================================ + +std::string XDRReader::getName() const +{ + int len = _width; + char* s = _xdr_cvals + _iRead*_width; + while (( s[len-1] == ' ' || s[len-1] == 0) && len > 0 ) + len--; + return std::string( s, len ); +} + +//================================================================================ +/*! + * \brief Throw an exception if not all needed data is present + */ +//================================================================================ + +void IntermediateMED::checkDataAvailability() const +{ + if ( _spaceDim == 0 ) + THROW_IK_EXCEPTION("Wrong file format"); // it is the first record in the sauve file + + if ( _groups.empty() ) + THROW_IK_EXCEPTION("No elements have been read"); + + if ( _points.empty() || _nbNodes == 0 ) + THROW_IK_EXCEPTION("Nodes of elements are not filled"); + + if ( _coords.empty() ) + THROW_IK_EXCEPTION("Node coordinates are missing"); + + if ( _coords.size() < _nbNodes * _spaceDim ) + THROW_IK_EXCEPTION("Nodes and coordinates mismatch"); +} + +//================================================================================ +/*! + * \brief Safely adds a new Group + */ +//================================================================================ + +Group* IntermediateMED::addNewGroup(std::vector* groupsToFix) +{ + if ( _groups.size() == _groups.capacity() ) // re-allocation would occure + { + std::vector newGroups( _groups.size() ); + newGroups.push_back( Group() ); + + for ( size_t i = 0; i < _groups.size(); ++i ) + { + // avoid copying _cells + std::vector cells; + cells.swap( _groups[i]._cells ); + newGroups[i] = _groups[i]; + newGroups[i]._cells.swap( cells ); + + // correct pointers to sub-groups + for ( size_t j = 0; j < _groups[i]._groups.size(); ++j ) + { + int iG = _groups[i]._groups[j] - &_groups[0]; + newGroups[i]._groups[j] = & newGroups[ iG ]; + } + } + + // fix given groups + if ( groupsToFix ) + for ( size_t i = 0; i < groupsToFix->size(); ++i ) + if ( (*groupsToFix)[i] ) + { + int iG = (*groupsToFix)[i] - &_groups[0]; + (*groupsToFix)[i] = & newGroups[ iG ]; + } + + // fix field supports + for ( int isNode = 0; isNode < 2; ++isNode ) + { + std::vector& fields = isNode ? _nodeFields : _cellFields; + for ( size_t i = 0; i < fields.size(); ++i ) + { + if ( !fields[i] ) continue; + for ( size_t j = 0; j < fields[i]->_sub.size(); ++j ) + if ( fields[i]->_sub[j]._support ) + { + int iG = fields[i]->_sub[j]._support - &_groups[0]; + fields[i]->_sub[j]._support = & newGroups[ iG ]; + } + if ( fields[i]->_group ) + { + int iG = fields[i]->_group - &_groups[0]; + fields[i]->_group = & newGroups[ iG ]; + } + } + } + + _groups.swap( newGroups ); + } + else + { + _groups.push_back( Group() ); + } + return &_groups.back(); +} + +//================================================================================ +/*! + * \brief Makes ParaMEDMEM::MEDFileData from self + */ +//================================================================================ + +ParaMEDMEM::MEDFileData* IntermediateMED::convertInMEDFileDS() +{ + MEDCouplingAutoRefCountObjectPtr< MEDFileUMesh > mesh = makeMEDFileMesh(); + MEDCouplingAutoRefCountObjectPtr< MEDFileFields > fields = makeMEDFileFields(mesh); + + MEDCouplingAutoRefCountObjectPtr< MEDFileMeshes > meshes = MEDFileMeshes::New(); + MEDCouplingAutoRefCountObjectPtr< MEDFileData > medData = MEDFileData::New(); + meshes->pushMesh( mesh ); + medData->setMeshes( meshes ); + if ( fields ) medData->setFields( fields ); + + return medData.retn(); +} + +//================================================================================ +/*! + * \brief Creates ParaMEDMEM::MEDFileUMesh from its data + */ +//================================================================================ + +ParaMEDMEM::MEDFileUMesh* IntermediateMED::makeMEDFileMesh() +{ + // check if all needed piles are present + checkDataAvailability(); + + // set long names + setGroupLongNames(); + + // fix element orientation + if ( _spaceDim == 2 || _spaceDim == 1 ) + orientElements2D(); + else if ( _spaceDim == 3 ) + orientElements3D(); + + // process groups + decreaseHierarchicalDepthOfSubgroups(); + eraseUselessGroups(); + //detectMixDimGroups(); + + // assign IDs + _points.numberNodes(); + numberElements(); + + // make the med mesh + + MEDFileUMesh* mesh = MEDFileUMesh::New(); + + DataArrayDouble *coords = getCoords(); + setConnectivity( mesh, coords ); + setGroups( mesh ); + + coords->decrRef(); + + if ( !mesh->getName().c_str() || strlen( mesh->getName().c_str() ) == 0 ) + mesh->setName( "MESH" ); + + return mesh; +} + +//================================================================================ +/*! + * \brief Set long names to groups + */ +//================================================================================ + +void IntermediateMED::setGroupLongNames() +{ + // IMP 0020434: mapping GIBI names to MED names + // set med names to objects (mesh, fields, support, group or other) + + std::set treatedGroups; + + std::list::iterator itGIBItoMED = _listGIBItoMED_mail.begin(); + for (; itGIBItoMED != _listGIBItoMED_mail.end(); itGIBItoMED++) + { + if ( (int)_groups.size() < itGIBItoMED->gibi_id ) continue; + + SauvUtilities::Group & grp = _groups[itGIBItoMED->gibi_id - 1]; + + // if there are several names for grp then the 1st name is the name + // of grp and the rest ones are names of groups referring grp (issue 0021311) + const bool isRefName = !treatedGroups.insert( itGIBItoMED->gibi_id ).second; + if ( !isRefName ) + { + grp._name = _mapStrings[ itGIBItoMED->med_id ]; + } + else if ( !grp._refNames.empty() && grp._refNames.back().empty() ) + { + for ( unsigned i = 0; i < grp._refNames.size(); ++i ) + if ( grp._refNames[i].empty() ) + grp._refNames[i] = _mapStrings[ (*itGIBItoMED).med_id ]; + } + else + { + grp._refNames.push_back( _mapStrings[ (*itGIBItoMED).med_id ]); + } + } +} + +//================================================================================ +/*! + * \brief Set long names to fields + */ +//================================================================================ + +void IntermediateMED::setFieldLongNames(std::set< std::string >& usedNames) +{ + std::list::iterator itGIBItoMED = _listGIBItoMED_cham.begin(); + for (; itGIBItoMED != _listGIBItoMED_cham.end(); itGIBItoMED++) + { + if (itGIBItoMED->gibi_pile == PILE_FIELD) + { + _cellFields[itGIBItoMED->gibi_id - 1]->_name = _mapStrings[itGIBItoMED->med_id]; + } + else if (itGIBItoMED->gibi_pile == PILE_NODES_FIELD) + { + _nodeFields[itGIBItoMED->gibi_id - 1]->_name = _mapStrings[itGIBItoMED->med_id]; + } + } // iterate on _listGIBItoMED_cham + + for (itGIBItoMED =_listGIBItoMED_comp.begin(); itGIBItoMED != _listGIBItoMED_comp.end(); itGIBItoMED++) + { + std::string medName = _mapStrings[itGIBItoMED->med_id]; + std::string gibiName = _mapStrings[itGIBItoMED->gibi_id]; + + bool name_found = false; + for ( int isNodal = 0; isNodal < 2 && !name_found; ++isNodal ) + { + std::vector & fields = isNodal ? _nodeFields : _cellFields; + for ( size_t ifi = 0; ifi < fields.size() && !name_found; ifi++) + { + if (medName.find( fields[ifi]->_name + "." ) == 0 ) + { + std::vector& aSubDs = fields[ifi]->_sub; + int nbSub = aSubDs.size(); + for (int isu = 0; isu < nbSub; isu++) + for (int ico = 0; ico < aSubDs[isu].nbComponents(); ico++) + { + if (aSubDs[isu].compName(ico) == gibiName) + { + std::string medNameCompo = medName.substr( fields[ifi]->_name.size() + 1 ); + fields[ifi]->_sub[isu].compName(ico) = medNameCompo; + } + } + } + } + } + } // iterate on _listGIBItoMED_comp + + for ( size_t i = 0; i < _nodeFields.size() ; i++) + usedNames.insert( _nodeFields[i]->_name ); + for ( size_t i = 0; i < _cellFields.size() ; i++) + usedNames.insert( _cellFields[i]->_name ); +} + +//================================================================================ +/*! + * \brief Decrease hierarchical depth of subgroups + */ +//================================================================================ + +void IntermediateMED::decreaseHierarchicalDepthOfSubgroups() +{ + for (size_t i=0; i!=_groups.size(); ++i) + { + Group& grp = _groups[i]; + for (size_t j = 0; j < grp._groups.size(); ++j ) + { + Group & sub_grp = *grp._groups[j]; + if ( !sub_grp._groups.empty() ) + { + // replace j with its 1st subgroup + grp._groups[j] = sub_grp._groups[0]; + // push back the rest subs + grp._groups.insert( grp._groups.end(), ++sub_grp._groups.begin(), sub_grp._groups.end() ); + } + } + // remove empty sub-_groups + std::vector< Group* > newSubGroups; + newSubGroups.reserve( grp._groups.size() ); + for (size_t j = 0; j < grp._groups.size(); ++j ) + if ( !grp._groups[j]->empty() ) + newSubGroups.push_back( grp._groups[j] ); + if ( newSubGroups.size() < grp._groups.size() ) + grp._groups.swap( newSubGroups ); + } +} + +//================================================================================ +/*! + * \brief Erase _groups that won't be converted + */ +//================================================================================ + +void IntermediateMED::eraseUselessGroups() +{ + // propagate _isProfile=true to sub-groups of composite groups + // for (size_t int i=0; i!=_groups.size(); ++i) + // { + // Group* grp = _groups[i]; + // if ( grp->_isProfile && !grp->_groups.empty() ) + // for (size_t j = 0; j < grp->_groups.size(); ++j ) + // grp->_groups[j]->_isProfile=true; + // } + std::set groups2convert; + // keep not named sub-groups of field supports + for (size_t i=0; i!=_groups.size(); ++i) + { + Group& grp = _groups[i]; + if ( grp._isProfile && !grp._groups.empty() ) + groups2convert.insert( grp._groups.begin(), grp._groups.end() ); + } + + // keep named groups and their subgroups + for (size_t i=0; i!=_groups.size(); ++i) + { + Group& grp = _groups[i]; + if ( !grp._name.empty() && !grp.empty() ) + { + groups2convert.insert( &grp ); + groups2convert.insert( grp._groups.begin(), grp._groups.end() ); + } + } + // erase groups that are not in groups2convert and not _isProfile + for (size_t i=0; i!=_groups.size(); ++i) + { + Group* grp = &_groups[i]; + if ( !grp->_isProfile && !groups2convert.count( grp ) ) + { + grp->_cells.clear(); + grp->_groups.clear(); + } + } +} + +//================================================================================ +/*! + * \brief Detect _groups of mixed dimension + */ +//================================================================================ + +void IntermediateMED::detectMixDimGroups() +{ + //hasMixedCells = false; + for ( size_t i=0; i < _groups.size(); ++i ) + { + Group& grp = _groups[i]; + if ( grp._groups.size() < 2 ) + continue; + + // check if sub-groups have different dimension + unsigned dim1 = getDim( &grp ); + for ( size_t j = 1; j < grp._groups.size(); ++j ) + { + unsigned dim2 = getDim( grp._groups[j] ); + if ( dim1 != dim2 ) + { + grp._cells.clear(); + grp._groups.clear(); + if ( !grp._name.empty() ) + std::cout << "Erase a group with elements of different dim |" << grp._name << "|"<< std::endl; + break; + } + } + } +} + +//================================================================================ +/*! + * \brief Fix connectivity of elements in 2D space + */ +//================================================================================ + +void IntermediateMED::orientElements2D() +{ + std::set::const_iterator elemIt, elemEnd; + std::vector< std::pair > swapVec; + + // ------------------------------------ + // fix connectivity of quadratic edges + // ------------------------------------ + std::set& quadEdges = _cellsByType[ INTERP_KERNEL::NORM_SEG3 ]; + if ( !quadEdges.empty() ) + { + elemIt = quadEdges.begin(), elemEnd = quadEdges.end(); + for ( ; elemIt != elemEnd; ++elemIt ) + ConvertQuadratic( INTERP_KERNEL::NORM_SEG3, *elemIt ); + } + + CellsByDimIterator faceIt( *this, 2 ); + while ( const std::set * faces = faceIt.nextType() ) + { + TCellType cellType = faceIt.type(); + bool isQuadratic = getGibi2MedQuadraticInterlace( cellType ); + + getReverseVector( cellType, swapVec ); + + // ------------------------------------ + // fix connectivity of quadratic faces + // ------------------------------------ + if ( isQuadratic ) + for ( elemIt = faces->begin(), elemEnd = faces->end(); elemIt != elemEnd; elemIt++ ) + ConvertQuadratic( cellType, *elemIt ); + + // -------------------------- + // orient faces clockwise + // -------------------------- + // COMMENTED for issue 0022612 note 17739 + // int iQuad = isQuadratic ? 2 : 1; + // for ( elemIt = faces->begin(), elemEnd = faces->end(); elemIt != elemEnd; elemIt++ ) + // { + // // look for index of the most left node + // int iLeft = 0, iNode, nbNodes = elemIt->_nodes.size() / iQuad; + // double x, minX = nodeCoords( elemIt->_nodes[0] )[0]; + // for ( iNode = 1; iNode < nbNodes; ++iNode ) + // if (( x = nodeCoords( elemIt->_nodes[ iNode ])[ 0 ]) < minX ) + // minX = x, iLeft = iNode; + + // // indeces of the nodes neighboring the most left one + // int iPrev = ( iLeft - 1 < 0 ) ? nbNodes - 1 : iLeft - 1; + // int iNext = ( iLeft + 1 == nbNodes ) ? 0 : iLeft + 1; + // // find components of prev-left and left-next vectors + // double xP = nodeCoords( elemIt->_nodes[ iPrev ])[ 0 ]; + // double yP = nodeCoords( elemIt->_nodes[ iPrev ])[ 1 ]; + // double xN = nodeCoords( elemIt->_nodes[ iNext ])[ 0 ]; + // double yN = nodeCoords( elemIt->_nodes[ iNext ])[ 1 ]; + // double xL = nodeCoords( elemIt->_nodes[ iLeft ])[ 0 ]; + // double yL = nodeCoords( elemIt->_nodes[ iLeft ])[ 1 ]; + // double xPL = xL - xP, yPL = yL - yP; // components of prev-left vector + // double xLN = xN - xL, yLN = yN - yL; // components of left-next vector + // // normalise y of the vectors + // double modPL = sqrt ( xPL * xPL + yPL * yPL ); + // double modLN = sqrt ( xLN * xLN + yLN * yLN ); + // if ( modLN > std::numeric_limits::min() && + // modPL > std::numeric_limits::min() ) + // { + // yPL /= modPL; + // yLN /= modLN; + // // summary direction of neighboring links must be positive + // bool clockwise = ( yPL + yLN > 0 ); + // if ( !clockwise ) + // reverse( *elemIt, swapVec ); + // } + // } + } +} + +//================================================================================ +/*! + * \brief Fix connectivity of elements in 3D space + */ +//================================================================================ + +void IntermediateMED::orientElements3D() +{ + // set _reverse flags of faces + // COMMENTED for issue 0022612 note 17739 + //orientFaces3D(); + + // ----------------- + // fix connectivity + // ----------------- + + std::set::const_iterator elemIt, elemEnd; + std::vector< std::pair > swapVec; + + for ( int dim = 1; dim <= 3; ++dim ) + { + CellsByDimIterator cellsIt( *this, dim ); + while ( const std::set * elems = cellsIt.nextType() ) + { + TCellType cellType = cellsIt.type(); + bool isQuadratic = getGibi2MedQuadraticInterlace( cellType ); + getReverseVector( cellType, swapVec ); + + elemIt = elems->begin(), elemEnd = elems->end(); + for ( ; elemIt != elemEnd; elemIt++ ) + { + // GIBI connectivity -> MED one + if( isQuadratic ) + ConvertQuadratic( cellType, *elemIt ); + + // reverse faces + if ( elemIt->_reverse ) + reverse ( *elemIt, swapVec ); + } + } + } + + // COMMENTED for issue 0022612 note 17739 + //orientVolumes(); +} + +//================================================================================ +/*! + * \brief Orient equally (by setting _reverse flag) all connected faces in 3D space + */ +//================================================================================ + +void IntermediateMED::orientFaces3D() +{ + // fill map of links and their faces + std::set faces; + std::map fgm; + std::map > linkFacesMap; + std::map >::iterator lfIt, lfIt2; + + for (size_t i=0; i!=_groups.size(); ++i) + { + Group& grp = _groups[i]; + if ( !grp._cells.empty() && getDimension( grp._cellType ) == 2 ) + for ( size_t j = 0; j < grp._cells.size(); ++j ) + if ( faces.insert( grp._cells[j] ).second ) + { + for ( size_t k = 0; k < grp._cells[j]->_nodes.size(); ++k ) + linkFacesMap[ grp._cells[j]->link( k ) ].push_back( grp._cells[j] ); + fgm.insert( std::make_pair( grp._cells[j], &grp )); + } + } + // dump linkFacesMap + // for ( lfIt = linkFacesMap.begin(); lfIt!=linkFacesMap.end(); lfIt++) { + // cout<< "LINK: " << lfIt->first.first << "-" << lfIt->first.second << std::endl; + // std::list & fList = lfIt->second; + // std::list::iterator fIt = fList.begin(); + // for ( ; fIt != fList.end(); fIt++ ) + // cout << "\t" << **fIt << fgm[*fIt]->nom << std::endl; + // } + + // Each oriented link must appear in one face only, else a face is reversed. + + std::queue faceQueue; /* the queue contains well oriented faces + whose neighbors orientation is to be checked */ + bool manifold = true; + while ( !linkFacesMap.empty() ) + { + if ( faceQueue.empty() ) + { + assert( !linkFacesMap.begin()->second.empty() ); + faceQueue.push( linkFacesMap.begin()->second.front() ); + } + while ( !faceQueue.empty() ) + { + const Cell* face = faceQueue.front(); + faceQueue.pop(); + + // loop on links of + for ( int i = 0; i < (int)face->_nodes.size(); ++i ) + { + Link link = face->link( i ); + // find the neighbor faces + lfIt = linkFacesMap.find( link ); + int nbFaceByLink = 0; + std::list< const Cell* > ml; + if ( lfIt != linkFacesMap.end() ) + { + std::list & fList = lfIt->second; + std::list::iterator fIt = fList.begin(); + assert( fIt != fList.end() ); + for ( ; fIt != fList.end(); fIt++, nbFaceByLink++ ) + { + ml.push_back( *fIt ); + if ( *fIt != face ) // wrongly oriented neighbor face + { + const Cell* badFace = *fIt; + // reverse and remove badFace from linkFacesMap + for ( int j = 0; j < (int)badFace->_nodes.size(); ++j ) + { + Link badlink = badFace->link( j ); + if ( badlink == link ) continue; + lfIt2 = linkFacesMap.find( badlink ); + if ( lfIt2 != linkFacesMap.end() ) + { + std::list & ff = lfIt2->second; + std::list::iterator lfIt3 = find( ff.begin(), ff.end(), badFace ); + // check if badFace has been found, + // else we can't erase it + // case of degenerated face in edge + if (lfIt3 != ff.end()) + { + ff.erase( lfIt3 ); + if ( ff.empty() ) + linkFacesMap.erase( lfIt2 ); + } + } + } + badFace->_reverse = true; // reverse + //INFOS_MED( "REVERSE " << *badFace ); + faceQueue.push( badFace ); + } + } + linkFacesMap.erase( lfIt ); + } + // add good neighbors to the queue + Link revLink( link.second, link.first ); + lfIt = linkFacesMap.find( revLink ); + if ( lfIt != linkFacesMap.end() ) + { + std::list & fList = lfIt->second; + std::list::iterator fIt = fList.begin(); + for ( ; fIt != fList.end(); fIt++, nbFaceByLink++ ) + { + ml.push_back( *fIt ); + if ( *fIt != face ) + faceQueue.push( *fIt ); + } + linkFacesMap.erase( lfIt ); + } + if ( nbFaceByLink > 2 ) + { + if ( manifold ) + { + std::list::iterator ii = ml.begin(); + std::cout << nbFaceByLink << " faces by 1 link:" << std::endl; + for( ; ii!= ml.end(); ii++ ) + std::cout << "in sub-mesh <" << fgm[ *ii ]->_name << "> " << **ii << std::endl; + } + manifold = false; + } + } // loop on links of the being checked face + } // loop on the face queue + } // while ( !linkFacesMap.empty() ) + + if ( !manifold ) + std::cout << " -> Non manifold mesh, faces orientation may be incorrect" << std::endl; +} + +//================================================================================ +/*! + * \brief Orient volumes according to MED conventions: + * normal of a bottom (first) face should be outside + */ +//================================================================================ + +void IntermediateMED::orientVolumes() +{ + std::set::const_iterator elemIt, elemEnd; + std::vector< std::pair > swapVec; + + CellsByDimIterator cellsIt( *this, 3 ); + while ( const std::set * elems = cellsIt.nextType() ) + { + TCellType cellType = cellsIt.type(); + elemIt = elems->begin(), elemEnd = elems->end(); + int nbBottomNodes = 0; + switch ( cellType ) + { + case NORM_TETRA4: + case NORM_TETRA10: + case NORM_PENTA6: + case NORM_PENTA15: + nbBottomNodes = 3; break; + case NORM_PYRA5: + case NORM_PYRA13: + case NORM_HEXA8: + case NORM_HEXA20: + nbBottomNodes = 4; break; + default: continue; + } + getReverseVector( cellType, swapVec ); + + for ( ; elemIt != elemEnd; elemIt++ ) + { + // find a normal to the bottom face + const double* n[4]; + n[0] = nodeCoords( elemIt->_nodes[0]); // 3 bottom nodes + n[1] = nodeCoords( elemIt->_nodes[1]); + n[2] = nodeCoords( elemIt->_nodes[2]); + n[3] = nodeCoords( elemIt->_nodes[nbBottomNodes]); // a top node + double vec01[3]; // vector n[0]-n[1] + vec01[0] = n[1][0] - n[0][0]; + vec01[1] = n[1][1] - n[0][1]; + vec01[2] = n[1][2] - n[0][2]; + double vec02 [3]; // vector n[0]-n[2] + vec02[0] = n[2][0] - n[0][0]; + vec02[1] = n[2][1] - n[0][1]; + vec02[2] = n[2][2] - n[0][2]; + double normal [3]; // vec01 ^ vec02 + normal[0] = vec01[1] * vec02[2] - vec01[2] * vec02[1]; + normal[1] = vec01[2] * vec02[0] - vec01[0] * vec02[2]; + normal[2] = vec01[0] * vec02[1] - vec01[1] * vec02[0]; + // check if the 102 angle is convex + if ( nbBottomNodes > 3 ) + { + const double* n3 = nodeCoords( elemIt->_nodes[nbBottomNodes-1] );// last bottom node + double vec03 [3]; // vector n[0]-n3 + vec03[0] = n3[0] - n[0][0]; + vec03[1] = n3[1] - n[0][1]; + vec03[2] = n3[2] - n[0][2]; + if ( fabs( normal[0]+normal[1]+normal[2] ) <= std::numeric_limits::max() ) // vec01 || vec02 + { + normal[0] = vec01[1] * vec03[2] - vec01[2] * vec03[1]; // vec01 ^ vec03 + normal[1] = vec01[2] * vec03[0] - vec01[0] * vec03[2]; + normal[2] = vec01[0] * vec03[1] - vec01[1] * vec03[0]; + } + else + { + double vec [3]; // normal ^ vec01 + vec[0] = normal[1] * vec01[2] - normal[2] * vec01[1]; + vec[1] = normal[2] * vec01[0] - normal[0] * vec01[2]; + vec[2] = normal[0] * vec01[1] - normal[1] * vec01[0]; + double dot2 = vec[0]*vec03[0] + vec[1]*vec03[1] + vec[2]*vec03[2]; // vec*vec03 + if ( dot2 < 0 ) // concave -> reverse normal + { + normal[0] *= -1; + normal[1] *= -1; + normal[2] *= -1; + } + } + } + // direction from top to bottom + double tbDir[3]; + tbDir[0] = n[0][0] - n[3][0]; + tbDir[1] = n[0][1] - n[3][1]; + tbDir[2] = n[0][2] - n[3][2]; + + // compare 2 directions: normal and top-bottom + double dot = normal[0]*tbDir[0] + normal[1]*tbDir[1] + normal[2]*tbDir[2]; + if ( dot < 0. ) // need reverse + reverse( *elemIt, swapVec ); + + } // loop on volumes of one geometry + } // loop on 3D geometry types + +} + +//================================================================================ +/*! + * \brief Assign new IDs to nodes by skipping not used nodes and return their number + */ +//================================================================================ + +int NodeContainer::numberNodes() +{ + int id = 1; + for ( size_t i = 0; i < _nodes.size(); ++i ) + for ( size_t j = 0; j < _nodes[i].size(); ++j ) + if ( _nodes[i][j].isUsed() ) + _nodes[i][j]._number = id++; + return id-1; +} + + +//================================================================================ +/*! + * \brief Assign new IDs to elements + */ +//================================================================================ + +void IntermediateMED::numberElements() +{ + std::set::const_iterator elemIt, elemEnd; + + // numbering _cells of type NORM_POINT1 by node number + { + const std::set& points = _cellsByType[ INTERP_KERNEL::NORM_POINT1 ]; + elemIt = points.begin(), elemEnd = points.end(); + for ( ; elemIt != elemEnd; ++elemIt ) + elemIt->_number = elemIt->_nodes[0]->_number; + } + + // numbering 1D-3D _cells + for ( int dim = 1; dim <= 3; ++dim ) + { + // check if re-numeration is needed (to try to keep elem oreder as in sauve file ) + bool ok = true, renumEntity = false; + CellsByDimIterator cellsIt( *this, dim ); + int prevNbElems = 0; + while ( const std::set * typeCells = cellsIt.nextType() ) + { + TID minNumber = std::numeric_limits::max(), maxNumber = 0; + for ( elemIt = typeCells->begin(), elemEnd = typeCells->end(); elemIt!=elemEnd; ++elemIt) + { + if ( elemIt->_number < minNumber ) minNumber = elemIt->_number; + if ( elemIt->_number > maxNumber ) maxNumber = elemIt->_number; + } + TID typeSize = typeCells->size(); + if ( typeSize != maxNumber - minNumber + 1 ) + ok = false; + if ( prevNbElems != 0 ) { + if ( minNumber == 1 ) + renumEntity = true; + else if ( prevNbElems+1 != (int)minNumber ) + ok = false; + } + prevNbElems += typeSize; + } + + if ( ok && renumEntity ) // each geom type was numerated separately + { + cellsIt.init( dim ); + prevNbElems = cellsIt.nextType()->size(); // no need to renumber the first type + while ( const std::set * typeCells = cellsIt.nextType() ) + { + for ( elemIt = typeCells->begin(), elemEnd = typeCells->end(); elemIt!=elemEnd; ++elemIt) + elemIt->_number += prevNbElems; + prevNbElems += typeCells->size(); + } + } + if ( !ok ) + { + int cellID=1; + cellsIt.init( dim ); + while ( const std::set * typeCells = cellsIt.nextType() ) + for ( elemIt = typeCells->begin(), elemEnd = typeCells->end(); elemIt!=elemEnd; ++elemIt) + elemIt->_number = cellID++; + } + } +} + +//================================================================================ +/*! + * \brief Creates coord array + */ +//================================================================================ + +ParaMEDMEM::DataArrayDouble * IntermediateMED::getCoords() +{ + DataArrayDouble* coordArray = DataArrayDouble::New(); + coordArray->alloc( _nbNodes, _spaceDim ); + double * coordPrt = coordArray->getPointer(); + for ( int i = 0, nb = _points.size(); i < nb; ++i ) + { + Node* n = getNode( i+1 ); + if ( n->isUsed() ) + { + const double* nCoords = nodeCoords( n ); + std::copy( nCoords, nCoords+_spaceDim, coordPrt ); + coordPrt += _spaceDim; + } + } + return coordArray; +} + +//================================================================================ +/*! + * \brief Sets connectivity of elements to the mesh + * \param mesh - mesh to fill in + * \param coords - coordinates that must be shared by all meshes of different dim + */ +//================================================================================ + +void IntermediateMED::setConnectivity( ParaMEDMEM::MEDFileUMesh* mesh, + ParaMEDMEM::DataArrayDouble* coords ) +{ + int meshDim = 0; + + mesh->setCoords( coords ); + + std::set::const_iterator elemIt, elemEnd; + for ( int dim = 3; dim > 0; --dim ) + { + CellsByDimIterator dimCells( *this, dim ); + + int nbOfCells = 0; + while ( const std::set * cells = dimCells.nextType() ) + nbOfCells += cells->size(); + if ( nbOfCells == 0 ) + continue; + + if ( !meshDim ) meshDim = dim; + + MEDCouplingUMesh* dimMesh = MEDCouplingUMesh::New(); + dimMesh->setCoords( coords ); + dimMesh->setMeshDimension( dim ); + dimMesh->allocateCells( nbOfCells ); + + int prevNbCells = 0; + dimCells.init( dim ); + while ( const std::set * cells = dimCells.nextType() ) + { + // fill connectivity array to take into account order of elements in the sauv file + const int nbCellNodes = cells->begin()->_nodes.size(); + std::vector< TID > connectivity( cells->size() * nbCellNodes ); + int * nodalConnOfCell; + for ( elemIt = cells->begin(), elemEnd = cells->end(); elemIt != elemEnd; ++elemIt ) + { + const Cell& cell = *elemIt; + const int index = cell._number - 1 - prevNbCells; + nodalConnOfCell = &connectivity[ index * nbCellNodes ]; + if ( cell._reverse ) + for ( int i = nbCellNodes-1; i >= 0; --i ) + *nodalConnOfCell++ = cell._nodes[i]->_number - 1; + else + for ( int i = 0; i < nbCellNodes; ++i ) + *nodalConnOfCell++ = cell._nodes[i]->_number - 1; + } + prevNbCells += cells->size(); + + // fill dimMesh + TCellType cellType = dimCells.type(); + nodalConnOfCell = &connectivity[0]; + for ( size_t i = 0; i < cells->size(); ++i, nodalConnOfCell += nbCellNodes ) + dimMesh->insertNextCell( cellType, nbCellNodes, nodalConnOfCell ); + } + dimMesh->finishInsertingCells(); + mesh->setMeshAtLevel( dim - meshDim, dimMesh ); + dimMesh->decrRef(); + } +} + +//================================================================================ +/*! + * \brief Fill in the mesh with groups + * \param mesh - mesh to fill in + */ +//================================================================================ + +void IntermediateMED::setGroups( ParaMEDMEM::MEDFileUMesh* mesh ) +{ + bool isMeshNameSet = false; + const int meshDim = mesh->getMeshDimension(); + for ( int dim = 0; dim <= meshDim; ++dim ) + { + const int meshDimRelToMaxExt = ( dim == 0 ? 1 : dim - meshDim ); + + std::vector medGroups; + std::vector > refGroups; + for ( size_t i = 0; i < _groups.size(); ++i ) + { + Group& grp = _groups[i]; + if ( (int)getDim( &grp ) != dim && + grp._groups.empty() ) // to allow groups on diff dims + continue; + // convert only named groups or field supports + if ( grp.empty() || (grp._name.empty() && !grp._isProfile )) + continue; + //if ( grp._medGroup ) continue; // already converted + + // sort cells by ID and remember their initial order in the group + TCellToOrderMap cell2order; + unsigned orderInGroup = 0; + std::vector< Group* > groupVec; + if ( grp._groups.empty() ) groupVec.push_back( & grp ); + else groupVec = grp._groups; + for ( size_t iG = 0; iG < groupVec.size(); ++iG ) + { + Group* aG = groupVec[ iG ]; + if ( (int)getDim( aG ) != dim ) + continue; + for ( size_t iC = 0; iC < aG->_cells.size(); ++iC ) + cell2order.insert( cell2order.end(), std::make_pair( aG->_cells[iC], orderInGroup++ )); + } + if ( cell2order.empty() ) + continue; + bool isSelfIntersect = ( orderInGroup != cell2order.size() ); + if ( isSelfIntersect ) // self intersecting group + { + std::ostringstream msg; + msg << "Self intersecting sub-mesh: id = " << i+1 + << ", name = |" << grp._name << "|" << std::endl + << " nb unique elements = " << cell2order.size() << std::endl + << " total nb elements = " << orderInGroup; + if ( grp._isProfile ) + { + THROW_IK_EXCEPTION( msg.str() ); + } + else + { + std::cout << msg.str() << std::endl; + } + } + // create a med group + grp._medGroup = DataArrayInt::New(); + grp._medGroup->setName( grp._name.c_str() ); + grp._medGroup->alloc( cell2order.size(), /*nbOfCompo=*/1 ); + int * idsPtr = grp._medGroup->getPointer(); + TCellToOrderMap::iterator cell2orderIt, cell2orderEnd = cell2order.end(); + for ( cell2orderIt = cell2order.begin(); cell2orderIt != cell2orderEnd; ++cell2orderIt ) + *idsPtr++ = (*cell2orderIt).first->_number - 1; + + // try to set the mesh name + if ( !isMeshNameSet && + dim == meshDim && + !grp._name.empty() && + grp.size() == mesh->getSizeAtLevel( meshDimRelToMaxExt )) + { + mesh->setName( grp._name.c_str() ); + isMeshNameSet = true; + } + if ( !grp._name.empty() ) + { + medGroups.push_back( grp._medGroup ); + } + // set relocation table + setRelocationTable( &grp, cell2order ); + + // Issue 0021311. Use case: a gibi group has references (recorded in pile 1) + // and several names (pile 27) refer (pile 10) to this group. + // We create a copy of this group per each named reference + std::set uniqueNames; + uniqueNames.insert( grp._name ); + for ( unsigned iRef = 0 ; iRef < grp._refNames.size(); ++iRef ) + if ( !grp._refNames[ iRef ].empty() && + uniqueNames.insert( grp._refNames[ iRef ]).second ) // for name uniqueness (23155) + { + refGroups.push_back( grp._medGroup->deepCpy() ); + refGroups.back()->setName( grp._refNames[ iRef ].c_str() ); + medGroups.push_back( refGroups.back() ); + } + } + mesh->setGroupsAtLevel( meshDimRelToMaxExt, medGroups ); + } +} + +//================================================================================ +/*! + * \brief Return true if the group is on all elements and return its relative dimension + */ +//================================================================================ + +bool IntermediateMED::isOnAll( const Group* grp, int & dimRel ) const +{ + int dim = getDim( grp ); + + int nbElems = 0; + if ( dim == 0 ) + { + nbElems = _nbNodes; + dimRel = 0; + } + else + { + CellsByDimIterator dimCells( *this, dim ); + while ( const std::set * cells = dimCells.nextType() ) + nbElems += cells->size(); + + int meshDim = 3; + for ( ; meshDim > 0; --meshDim ) + { + dimCells.init( meshDim ); + if ( dimCells.nextType() ) + break; + } + dimRel = dim - meshDim; + } + + bool onAll = ( nbElems == grp->size() ); + return onAll; +} + +//================================================================================ +/*! + * \brief Makes fields from own data + */ +//================================================================================ + +ParaMEDMEM::MEDFileFields * IntermediateMED::makeMEDFileFields(ParaMEDMEM::MEDFileUMesh* mesh) +{ + if ( _nodeFields.empty() && _cellFields.empty() ) return 0; + + // set long names + std::set< std::string > usedFieldNames; + setFieldLongNames(usedFieldNames); + + MEDFileFields* fields = MEDFileFields::New(); + + for ( size_t i = 0; i < _nodeFields.size(); ++i ) + setFields( _nodeFields[i], fields, mesh, i+1, usedFieldNames ); + + for ( size_t i = 0; i < _cellFields.size(); ++i ) + setFields( _cellFields[i], fields, mesh, i+1, usedFieldNames ); + + return fields; +} + +//================================================================================ +/*! + * \brief Make med fields from a SauvUtilities::DoubleField + */ +//================================================================================ + +void IntermediateMED::setFields( SauvUtilities::DoubleField* fld, + ParaMEDMEM::MEDFileFields* medFields, + ParaMEDMEM::MEDFileUMesh* mesh, + const TID castemID, + std::set< std::string >& usedFieldNames) +{ + bool sameNbGauss = true; + if ( !fld || !fld->isMedCompatible( sameNbGauss )) return; + + if ( !sameNbGauss ) + fld->splitSubWithDiffNbGauss(); + + // if ( !fld->hasCommonSupport() ): + // each sub makes MEDFileFieldMultiTS + // else: + // unite several subs into a MEDCouplingFieldDouble + + const bool uniteSubs = fld->hasCommonSupport() && sameNbGauss; + if ( !uniteSubs ) + std::cout << "Castem field #" << castemID << " <" << fld->_name + << "> is incompatible with MED format, so we split it into several fields:" << std::endl; + + for ( size_t iSub = 0; iSub < fld->_sub.size(); ) + { + // set field name + if ( !uniteSubs || fld->_name.empty() ) + makeFieldNewName( usedFieldNames, fld ); + + // allocate values + DataArrayDouble * values = DataArrayDouble::New(); + values->alloc( fld->getNbTuples(iSub), fld->_sub[iSub].nbComponents() ); + + // set values + double * valPtr = values->getPointer(); + if ( uniteSubs ) + { + int nbElems = fld->_group->size(); + for ( int elemShift = 0; elemShift < nbElems && iSub < fld->_sub.size(); ) + elemShift += fld->setValues( valPtr, iSub++, elemShift ); + setTS( fld, values, medFields, mesh ); + } + else + { + fld->setValues( valPtr, iSub ); + setTS( fld, values, medFields, mesh, iSub++ ); + + std::cout << fld->_name << " with compoments"; + for ( size_t i = 0; i < (size_t)fld->_sub[iSub-1].nbComponents(); ++i ) + std::cout << " " << fld->_sub[iSub-1]._comp_names[ i ]; + std::cout << std::endl; + } + } +} + +//================================================================================ +/*! + * \brief Store value array of a field into med fields + */ +//================================================================================ + +void IntermediateMED::setTS( SauvUtilities::DoubleField* fld, + ParaMEDMEM::DataArrayDouble* values, + ParaMEDMEM::MEDFileFields* medFields, + ParaMEDMEM::MEDFileUMesh* mesh, + const int iSub) +{ + // treat a field support + const Group* support = fld->getSupport( iSub ); + int dimRel; + const bool onAll = isOnAll( support, dimRel ); + if ( !onAll && support->_name.empty() ) + { + const_cast(support)->_name += "PFL_" + fld->_name; + support->_medGroup->setName( support->_name.c_str() ); + } + + // make and fill a time-stamp + + MEDCouplingFieldDouble * timeStamp = MEDCouplingFieldDouble::New( fld->getMedType( iSub ), + fld->getMedTimeDisc() ); + timeStamp->setName( fld->_name.c_str() ); + timeStamp->setDescription( fld->_description.c_str() ); + // set the mesh + if ( onAll ) + { + MEDCouplingAutoRefCountObjectPtr + < MEDCouplingUMesh > dimMesh = mesh->getMeshAtLevel( dimRel ); + timeStamp->setMesh( dimMesh ); + } + else if ( timeStamp->getTypeOfField() == ParaMEDMEM::ON_NODES ) + { + DataArrayDouble * coo = mesh->getCoords(); + MEDCouplingAutoRefCountObjectPtr + subCoo = coo->selectByTupleId(support->_medGroup->begin(), + support->_medGroup->end()); + MEDCouplingAutoRefCountObjectPtr< MEDCouplingUMesh > nodeSubMesh = + MEDCouplingUMesh::Build0DMeshFromCoords( subCoo ); + timeStamp->setMesh( nodeSubMesh ); + } + else + { + MEDCouplingAutoRefCountObjectPtr + < MEDCouplingUMesh > dimMesh = mesh->getMeshAtLevel( dimRel ); + MEDCouplingAutoRefCountObjectPtr + subMesh = dimMesh->buildPart(support->_medGroup->begin(), + support->_medGroup->end()); + timeStamp->setMesh( subMesh); + } + // set values + for ( size_t i = 0; i < (size_t)fld->_sub[iSub].nbComponents(); ++i ) + values->setInfoOnComponent( i, fld->_sub[iSub]._comp_names[ i ].c_str() ); + timeStamp->setArray( values ); + values->decrRef(); + // set gauss points + if ( timeStamp->getTypeOfField() == ParaMEDMEM::ON_GAUSS_PT ) + { + TGaussDef gaussDef( fld->_sub[iSub]._support->_cellType, + fld->_sub[iSub].nbGauss() ); + timeStamp->setGaussLocalizationOnType( fld->_sub[iSub]._support->_cellType, + gaussDef.myRefCoords, + gaussDef.myCoords, + gaussDef.myWeights ); + } + // get a field to add the time-stamp + bool isNewMedField = false; + if ( !fld->_curMedField || fld->_name != fld->_curMedField->getName() ) + { + fld->_curMedField = MEDFileFieldMultiTS::New(); + isNewMedField = true; + } + + // set an order + const int nbTS = fld->_curMedField->getNumberOfTS(); + if ( nbTS > 0 ) + timeStamp->setOrder( nbTS ); + + // add the time-stamp + timeStamp->checkCoherency(); + if ( onAll ) + fld->_curMedField->appendFieldNoProfileSBT( timeStamp ); + else + fld->_curMedField->appendFieldProfile( timeStamp, mesh, dimRel, support->_medGroup ); + timeStamp->decrRef(); + + if ( isNewMedField ) // timeStamp must be added before this + { + medFields->pushField( fld->_curMedField ); + } +} + +//================================================================================ +/*! + * \brief Make a new unique name for a field + */ +//================================================================================ + +void IntermediateMED::makeFieldNewName(std::set< std::string >& usedNames, + SauvUtilities::DoubleField* fld ) +{ + std::string base = fld->_name; + if ( base.empty() ) + { + base = "F_"; + } + else + { + std::string::size_type pos = base.rfind('_'); + if ( pos != std::string::npos ) + base = base.substr( 0, pos+1 ); + else + base += '_'; + } + + int i = 1; + do + { + fld->_name = base + SauvUtilities::toString( i++ ); + } + while( !usedNames.insert( fld->_name ).second ); +} + +//================================================================================ +/*! + * \brief Split sub-components with different nb of gauss points into several sub-components + * \param [in,out] fld - a field to split if necessary + */ +//================================================================================ + +void DoubleField::splitSubWithDiffNbGauss() +{ + for ( size_t iSub = 0; iSub < _sub.size(); ++iSub ) + { + if ( _sub[iSub].isSameNbGauss() ) continue; + + _sub.insert( _sub.begin() + iSub + 1, 1, _Sub_data() ); + _Sub_data & subToSplit = _sub[iSub]; + _Sub_data & subNew = _sub[iSub+1]; + size_t iDiff = 1; + while ( subToSplit._nb_gauss[ 0 ] == subToSplit._nb_gauss[ iDiff ] ) + ++iDiff; + subNew._support = subToSplit._support; + subNew._comp_names.assign( subToSplit._comp_names.begin() + iDiff, + subToSplit._comp_names.end() ); + subNew._nb_gauss.assign ( subToSplit._nb_gauss.begin() + iDiff, + subToSplit._nb_gauss.end() ); + subToSplit._comp_names.resize( iDiff ); + subToSplit._nb_gauss.resize ( iDiff ); + } +} + +//================================================================================ +/*! + * \brief Return a vector ready to fill in + */ +//================================================================================ + +std::vector< double >& DoubleField::addComponent( int nb_values ) +{ + _comp_values.push_back( std::vector< double >() ); + std::vector< double >& res = _comp_values.back(); + res.resize( nb_values ); + return res; +} + +DoubleField::~DoubleField() +{ + if(_curMedField) + _curMedField->decrRef(); +} + +//================================================================================ +/*! + * \brief Returns a supporting group + */ +//================================================================================ + +const Group* DoubleField::getSupport( const int iSub ) const +{ + return _group ? _group : _sub[iSub]._support; +} + +//================================================================================ +/*! + * \brief Return true if each sub-component is a time stamp + */ +//================================================================================ + +bool DoubleField::isMultiTimeStamps() const +{ + if ( _sub.size() < 2 ) + return false; + bool sameSupports = true; + Group* grpp1 = _sub[0]._support;// grpp NOT grp because XDR under Windows defines grp... + for ( size_t i = 1; i < _sub.size() && sameSupports; ++i ) + sameSupports = ( grpp1 == _sub[i]._support ); + + return sameSupports; +} + +//================================================================================ +/*! + * \brief True if the field can be converted into the med field + */ +//================================================================================ + +bool DoubleField::isMedCompatible(bool& sameNbGauss) const +{ + for ( size_t iSub = 0; iSub < _sub.size(); ++iSub ) + { + if ( !getSupport(iSub) || !getSupport(iSub)->_medGroup ) + THROW_IK_EXCEPTION("SauvReader INTERNAL ERROR: NULL field support"); + + sameNbGauss = true; + if ( !_sub[iSub].isSameNbGauss() ) + { + std::cout << "Field <" << _name << "> : different nb of gauss points in components" << std::endl; + sameNbGauss = false; + //return false; + } + } + return true; +} + +//================================================================================ +/*! + * \brief return true if all sub-components has same components and same nbGauss + */ +//================================================================================ + +bool DoubleField::hasSameComponentsBySupport() const +{ + std::vector< _Sub_data >::const_iterator sub_data = _sub.begin(); + const _Sub_data& first_sub_data = *sub_data; + for ( ++sub_data ; sub_data != _sub.end(); ++sub_data ) + { + if ( first_sub_data._comp_names != sub_data->_comp_names ) + return false; // diff names of components + + if ( first_sub_data._nb_gauss != sub_data->_nb_gauss && + first_sub_data._support->_cellType == sub_data->_support->_cellType) + return false; // diff nb of gauss points on same cell type + } + return true; +} + +//================================================================================ +/*! + * \brief Return type of MEDCouplingFieldDouble + */ +//================================================================================ + +ParaMEDMEM::TypeOfField DoubleField::getMedType( const int iSub ) const +{ + using namespace INTERP_KERNEL; + + const Group* grp = hasCommonSupport() ? _group : _sub[iSub]._support; + if ( _sub[iSub].nbGauss() > 1 ) + { + const CellModel& cm = CellModel::GetCellModel( _sub[iSub]._support->_cellType ); + return (int) cm.getNumberOfNodes() == _sub[iSub].nbGauss() ? ON_GAUSS_NE : ON_GAUSS_PT; + } + else + { + return getDim( grp ) == 0 ? ON_NODES : ON_CELLS; + } +} + +//================================================================================ +/*! + * \brief Return TypeOfTimeDiscretization + */ +//================================================================================ + +ParaMEDMEM::TypeOfTimeDiscretization DoubleField::getMedTimeDisc() const +{ + return ONE_TIME; + // NO_TIME = 4, + // ONE_TIME = 5, + // LINEAR_TIME = 6, + // CONST_ON_TIME_INTERVAL = 7 +} + +//================================================================================ +/*! + * \brief Return nb tuples to be used to allocate DataArrayDouble + */ +//================================================================================ + +int DoubleField::getNbTuples( const int iSub ) const +{ + int nb = 0; + if ( hasCommonSupport() && !_group->_groups.empty() ) + for ( size_t i = 0; i < _group->_groups.size(); ++i ) + nb += _sub[i].nbGauss() * _sub[i]._support->size(); + else + nb = _sub[iSub].nbGauss() * getSupport(iSub)->size(); + return nb; +} + +//================================================================================ +/*! + * \brief Store values of a sub-component and return nb of elements in the iSub + */ +//================================================================================ + +int DoubleField::setValues( double * valPtr, const int iSub, const int elemShift ) const +{ + // find values for iSub + int iComp = 0; + for ( int iS = 0; iS < iSub; ++iS ) + iComp += _sub[iS].nbComponents(); + const std::vector< double > * compValues = &_comp_values[ iComp ]; + + // Set values + + const std::vector< unsigned >& relocTable = getSupport( iSub )->_relocTable; + + const int nbElems = _sub[iSub]._support->size(); + const int nbGauss = _sub[iSub].nbGauss(); + const int nbComponents = _sub[iSub].nbComponents(); + const int nbValsByElem = nbComponents * nbGauss; + + // check nb values + int nbVals = 0; + for ( iComp = 0; iComp < nbComponents; ++iComp ) + nbVals += compValues[iComp].size(); + const bool isConstField = ( nbVals == nbComponents ); // one value per component (issue 22321) + if ( !isConstField && nbVals != nbElems * nbValsByElem ) + THROW_IK_EXCEPTION("SauvMedConvertor.cxx: support size mismatches field size"); + + // compute nb values in previous subs + int valsShift = 0; + for ( int iS = iSub-1, shift = elemShift; shift > 0; --iS) + { + int nbE = _sub[iS]._support->size(); + shift -= nbE; + valsShift += nbE * _sub[iS].nbComponents() * _sub[iS].nbGauss(); + } + + if ( isConstField ) + for ( int iE = 0; iE < nbElems; ++iE ) + { + int iMed = valsShift + nbValsByElem * ( relocTable.empty() ? iE : relocTable[iE+elemShift]-elemShift ); + for ( iComp = 0; iComp < nbComponents; ++iComp ) + valPtr[ iMed + iComp ] = compValues[iComp][ 0 ]; + } + else + for ( int iE = 0; iE < nbElems; ++iE ) + { + int iMed = valsShift + nbValsByElem * ( relocTable.empty() ? iE : relocTable[iE+elemShift]-elemShift ); + for ( iComp = 0; iComp < nbComponents; ++iComp ) + for ( int iG = 0; iG < nbGauss; ++iG ) + valPtr[ iMed + iG * nbComponents + iComp ] = compValues[iComp][ iE * nbGauss + iG ]; + } + return nbElems; +} + +//================================================================================ +/*! + * \brief Destructor of IntermediateMED + */ +//================================================================================ + +IntermediateMED::~IntermediateMED() +{ + for ( size_t i = 0; i < _nodeFields.size(); ++i ) + if ( _nodeFields[i] ) + delete _nodeFields[i]; + _nodeFields.clear(); + + for ( size_t i = 0; i < _cellFields.size(); ++i ) + if ( _cellFields[i] ) + delete _cellFields[i]; + _cellFields.clear(); + + for ( size_t i = 0; i < _groups.size(); ++i ) + if ( _groups[i]._medGroup ) + _groups[i]._medGroup->decrRef(); +} + +//================================================================================ +/*! + * \brief CellsByDimIterator constructor + */ +CellsByDimIterator::CellsByDimIterator( const IntermediateMED & medi, int dimm) +{ + myImed = & medi; + init( dimm ); +} +/*! + * \brief Initialize iteration on cells of given dimention + */ +void CellsByDimIterator::init(const int dimm) +{ + myCurType = -1; + myTypeEnd = INTERP_KERNEL::NORM_HEXA20 + 1; + myDim = dimm; +} +/*! + * \brief return next set of Cell's of required dimension + */ +const std::set< Cell > * CellsByDimIterator::nextType() +{ + while ( ++myCurType < myTypeEnd ) + if ( !myImed->_cellsByType[myCurType].empty() && ( myDim < 0 || dim(false) == myDim )) + return & myImed->_cellsByType[myCurType]; + return 0; +} +/*! + * \brief return dimension of cells returned by the last or further next() + */ +int CellsByDimIterator::dim(const bool last) const +{ + int typp = myCurType; + if ( !last ) + while ( typp < myTypeEnd && myImed->_cellsByType[typp].empty() ) + ++typp; + return typp < myTypeEnd ? getDimension( TCellType( typp )) : 4; +} +// END CellsByDimIterator ======================================================== + diff --cc medtool/src/MEDLoader/Test/MEDLoaderTest.cxx index b6267238f,000000000..0eb08c206 mode 100644,000000..100644 --- a/medtool/src/MEDLoader/Test/MEDLoaderTest.cxx +++ b/medtool/src/MEDLoader/Test/MEDLoaderTest.cxx @@@ -1,1097 -1,0 +1,1494 @@@ +// Copyright (C) 2007-2015 CEA/DEN, EDF R&D +// +// 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +// +// See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com +// +// Author : Anthony Geay (CEA/DEN) + +#include "MEDLoaderTest.hxx" +#include "MEDLoader.hxx" +#include "MEDLoaderBase.hxx" +#include "MEDCouplingUMesh.hxx" +#include "MEDCouplingFieldDouble.hxx" +#include "MEDCouplingMemArray.hxx" + +#include ++#include + +using namespace ParaMEDMEM; + +void MEDLoaderTest::testMesh1DRW() +{ + MEDCouplingUMesh *mesh=build1DMesh_1(); + mesh->checkCoherency(); + MEDLoader::WriteUMesh("file1.med",mesh,true); + MEDCouplingUMesh *mesh_rw=MEDLoader::ReadUMeshFromFile("file1.med",mesh->getName().c_str(),0); + CPPUNIT_ASSERT(mesh->isEqual(mesh_rw,1e-12)); + mesh_rw->decrRef(); + mesh->decrRef(); +} + +void MEDLoaderTest::testMesh2DCurveRW() +{ + MEDCouplingUMesh *mesh=build2DCurveMesh_1(); + mesh->checkCoherency(); + MEDLoader::WriteUMesh("file2.med",mesh,true); + MEDCouplingUMesh *mesh_rw=MEDLoader::ReadUMeshFromFile("file2.med",mesh->getName().c_str(),0); + CPPUNIT_ASSERT(mesh->isEqual(mesh_rw,1e-12)); + mesh_rw->decrRef(); + mesh->decrRef(); +} + +void MEDLoaderTest::testMesh2DRW() +{ + MEDCouplingUMesh *mesh=build2DMesh_1(); + mesh->checkCoherency(); + MEDLoader::WriteUMesh("file3.med",mesh,true); + MEDCouplingUMesh *mesh_rw=MEDLoader::ReadUMeshFromFile("file3.med",mesh->getName().c_str(),0); + CPPUNIT_ASSERT(mesh->isEqual(mesh_rw,1e-12)); + mesh_rw->decrRef(); + mesh->decrRef(); +} + +void MEDLoaderTest::testMesh3DSurfRW() +{ + MEDCouplingUMesh *mesh=build3DSurfMesh_1(); + mesh->checkCoherency(); + MEDLoader::WriteUMesh("file4.med",mesh,true); + MEDCouplingUMesh *mesh_rw=MEDLoader::ReadUMeshFromFile("file4.med",mesh->getName().c_str(),0); + CPPUNIT_ASSERT(mesh->isEqual(mesh_rw,1e-12)); + mesh_rw->decrRef(); + mesh->decrRef(); +} + +void MEDLoaderTest::testMesh3DRW() +{ + MEDCouplingUMesh *mesh=build3DMesh_1(); + mesh->checkCoherency(); + MEDLoader::WriteUMesh("file5.med",mesh,true); + MEDCouplingUMesh *mesh_rw=MEDLoader::ReadUMeshFromFile("file5.med",mesh->getName().c_str(),0); + CPPUNIT_ASSERT(mesh->isEqual(mesh_rw,1e-12)); + mesh_rw->decrRef(); + mesh->decrRef(); +} + +/*! + * Most basic test : one and only one MEDCoupling field in a new file. + */ +void MEDLoaderTest::testFieldRW1() +{ + MEDCouplingFieldDouble *f1=buildVecFieldOnCells_1(); + MEDLoader::WriteField("file6.med",f1,true); + MEDCouplingFieldDouble *f2=MEDLoader::ReadFieldCell("file6.med",f1->getMesh()->getName().c_str(),0,f1->getName().c_str(),0,1); + CPPUNIT_ASSERT(f1->isEqual(f2,1e-12,1e-12)); + f1->decrRef(); + f2->decrRef(); + // + f1=buildVecFieldOnNodes_1(); + MEDLoader::WriteField("file7.med",f1,true); + f2=MEDLoader::ReadFieldNode("file7.med",f1->getMesh()->getName().c_str(),0,f1->getName().c_str(),2,3); + CPPUNIT_ASSERT(f1->isEqual(f2,1e-12,1e-12)); + // testing kind message on error of field type. + CPPUNIT_ASSERT_THROW(MEDLoader::ReadFieldCell("file7.med",f1->getMesh()->getName().c_str(),0,f1->getName().c_str(),2,3),INTERP_KERNEL::Exception); + // + f1->decrRef(); + f2->decrRef(); +} + +/*! + * Multi field writing in a same file. + */ +void MEDLoaderTest::testFieldRW2() +{ + const char fileName[]="file8.med"; + static const double VAL1=12345.67890314; + static const double VAL2=-1111111111111.; + MEDCouplingFieldDouble *f1=buildVecFieldOnCells_1(); + MEDLoader::WriteField(fileName,f1,true); + f1->setTime(10.,8,9); + double *tmp=f1->getArray()->getPointer(); + tmp[0]=VAL1; + MEDLoader::WriteFieldUsingAlreadyWrittenMesh(fileName,f1); + f1->setTime(10.14,18,19); + tmp[0]=VAL2; + MEDLoader::WriteFieldUsingAlreadyWrittenMesh(fileName,f1); + //retrieving time steps... + MEDCouplingFieldDouble *f2=MEDLoader::ReadFieldCell(fileName,f1->getMesh()->getName().c_str(),0,f1->getName().c_str(),8,9); + f1->setTime(10.,8,9); + tmp[0]=VAL1; + CPPUNIT_ASSERT(f1->isEqual(f2,1e-12,1e-12)); + f2->decrRef(); + f2=MEDLoader::ReadFieldCell(fileName,f1->getMesh()->getName().c_str(),0,f1->getName().c_str(),0,1); + MEDCouplingFieldDouble *f3=buildVecFieldOnCells_1(); + CPPUNIT_ASSERT(f3->isEqual(f2,1e-12,1e-12)); + f3->decrRef(); + f2->decrRef(); + f2=MEDLoader::ReadFieldCell(fileName,f1->getMesh()->getName().c_str(),0,f1->getName().c_str(),18,19); + f1->setTime(10.14,18,19); + tmp[0]=VAL2; + CPPUNIT_ASSERT(f1->isEqual(f2,1e-12,1e-12)); + //test of throw on invalid (dt,it) + CPPUNIT_ASSERT_THROW(MEDLoader::ReadFieldCell(fileName,f1->getMesh()->getName().c_str(),0,f1->getName().c_str(),28,19),INTERP_KERNEL::Exception); + f2->decrRef(); + f1->decrRef(); + //ON NODES + f1=buildVecFieldOnNodes_1(); + const char fileName2[]="file9.med"; + MEDLoader::WriteField(fileName2,f1,true); + f1->setTime(110.,108,109); + tmp=f1->getArray()->getPointer(); + tmp[3]=VAL1; + MEDLoader::WriteFieldUsingAlreadyWrittenMesh(fileName2,f1); + f1->setTime(210.,208,209); + tmp[3]=VAL2; + MEDLoader::WriteFieldUsingAlreadyWrittenMesh(fileName2,f1); + f2=MEDLoader::ReadFieldNode(fileName2,f1->getMesh()->getName().c_str(),0,f1->getName().c_str(),108,109); + f1->setTime(110.,108,109); + tmp[3]=VAL1; + CPPUNIT_ASSERT(f1->isEqual(f2,1e-12,1e-12)); + f2->decrRef(); + f2=MEDLoader::ReadFieldNode(fileName2,f1->getMesh()->getName().c_str(),0,f1->getName().c_str(),2,3); + f3=buildVecFieldOnNodes_1(); + CPPUNIT_ASSERT(f3->isEqual(f2,1e-12,1e-12)); + f3->decrRef(); + f2->decrRef(); + f2=MEDLoader::ReadFieldNode(fileName2,f1->getMesh()->getName().c_str(),0,f1->getName().c_str(),208,209); + f1->setTime(210.,208,209); + tmp[3]=VAL2; + CPPUNIT_ASSERT(f1->isEqual(f2,1e-12,1e-12)); + f2->decrRef(); + f1->decrRef(); +} + +/*! + * Multi field in a same file, but this field has several + */ +void MEDLoaderTest::testFieldRW3() +{ + const char fileName[]="file11.med"; + static const double VAL1=12345.67890314; + static const double VAL2=-1111111111111.; + const char name1[]="AField"; + const char name3[]="AMesh1"; + MEDCouplingFieldDouble *f1=buildVecFieldOnCells_1(); + (const_cast(f1->getMesh()))->setName(name3); + f1->setName(name1); + f1->setTime(10.,8,9); + double *tmp=f1->getArray()->getPointer(); + tmp[0]=VAL1; + MEDLoader::WriteField(fileName,f1,true); + f1->setTime(10.14,18,19); + tmp[0]=VAL2; + MEDLoader::WriteFieldUsingAlreadyWrittenMesh(fileName,f1); + f1->setTime(10.55,28,29); + tmp[0]=3*VAL1; + MEDLoader::WriteFieldUsingAlreadyWrittenMesh(fileName,f1); + f1->setTime(10.66,38,39); + tmp[0]=3*VAL2; + MEDLoader::WriteFieldUsingAlreadyWrittenMesh(fileName,f1); + f1->setTime(10.77,48,49); + tmp[0]=4*VAL2; + MEDLoader::WriteFieldUsingAlreadyWrittenMesh(fileName,f1); + //ON NODES + f1->decrRef(); + f1=buildVecFieldOnNodes_1(); + f1->setName(name1); + (const_cast(f1->getMesh()))->setName(name3); + f1->setTime(110.,8,9); + MEDLoader::WriteFieldUsingAlreadyWrittenMesh(fileName,f1); + f1->setTime(110.,108,109); + tmp=f1->getArray()->getPointer(); + tmp[3]=VAL1; + MEDLoader::WriteFieldUsingAlreadyWrittenMesh(fileName,f1); + f1->setTime(210.,208,209); + tmp[3]=VAL2; + MEDLoader::WriteFieldUsingAlreadyWrittenMesh(fileName,f1); + // + std::vector< std::pair > it1=MEDLoader::GetCellFieldIterations(fileName,name3,name1); + CPPUNIT_ASSERT_EQUAL(5,(int)it1.size()); + CPPUNIT_ASSERT_EQUAL(8,it1[0].first); CPPUNIT_ASSERT_EQUAL(9,it1[0].second); + CPPUNIT_ASSERT_EQUAL(18,it1[1].first); CPPUNIT_ASSERT_EQUAL(19,it1[1].second); + CPPUNIT_ASSERT_EQUAL(28,it1[2].first); CPPUNIT_ASSERT_EQUAL(29,it1[2].second); + CPPUNIT_ASSERT_EQUAL(38,it1[3].first); CPPUNIT_ASSERT_EQUAL(39,it1[3].second); + CPPUNIT_ASSERT_EQUAL(48,it1[4].first); CPPUNIT_ASSERT_EQUAL(49,it1[4].second); + std::vector< std::pair > it3=MEDLoader::GetNodeFieldIterations(fileName,name3,name1); + CPPUNIT_ASSERT_EQUAL(3,(int)it3.size()); + CPPUNIT_ASSERT_EQUAL(8,it3[0].first); CPPUNIT_ASSERT_EQUAL(9,it3[0].second); + CPPUNIT_ASSERT_EQUAL(108,it3[1].first); CPPUNIT_ASSERT_EQUAL(109,it3[1].second); + CPPUNIT_ASSERT_EQUAL(208,it3[2].first); CPPUNIT_ASSERT_EQUAL(209,it3[2].second); + // + f1->decrRef(); + // + f1=MEDLoader::ReadFieldCell(fileName,name3,0,name1,8,9); + CPPUNIT_ASSERT_DOUBLES_EQUAL(VAL1,f1->getArray()->getConstPointer()[0],1e-13); + f1->decrRef(); + f1=MEDLoader::ReadFieldCell(fileName,name3,0,name1,18,19); + CPPUNIT_ASSERT_DOUBLES_EQUAL(VAL2,f1->getArray()->getConstPointer()[0],1e-13); + f1->decrRef(); + f1=MEDLoader::ReadFieldCell(fileName,name3,0,name1,28,29); + CPPUNIT_ASSERT_DOUBLES_EQUAL(3*VAL1,f1->getArray()->getConstPointer()[0],1e-13); + f1->decrRef(); + f1=MEDLoader::ReadFieldCell(fileName,name3,0,name1,38,39); + CPPUNIT_ASSERT_DOUBLES_EQUAL(3*VAL2,f1->getArray()->getConstPointer()[0],1e-13); + f1->decrRef(); + f1=MEDLoader::ReadFieldCell(fileName,name3,0,name1,48,49); + CPPUNIT_ASSERT_DOUBLES_EQUAL(4*VAL2,f1->getArray()->getConstPointer()[0],1e-13); + f1->decrRef(); + // + f1=MEDLoader::ReadFieldNode(fileName,name3,0,name1,8,9); + CPPUNIT_ASSERT_DOUBLES_EQUAL(71.,f1->getArray()->getConstPointer()[3],1e-13); + f1->decrRef(); + f1=MEDLoader::ReadFieldNode(fileName,name3,0,name1,108,109); + CPPUNIT_ASSERT_DOUBLES_EQUAL(VAL1,f1->getArray()->getConstPointer()[3],1e-13); + f1->decrRef(); + f1=MEDLoader::ReadFieldNode(fileName,name3,0,name1,208,209); + CPPUNIT_ASSERT_DOUBLES_EQUAL(VAL2,f1->getArray()->getConstPointer()[3],1e-13); + f1->decrRef(); +} + +void MEDLoaderTest::testMultiMeshRW1() +{ + const char fileName[]="file10.med"; + MEDCouplingUMesh *mesh1=build3DMesh_1(); + const int part1[5]={1,2,4,13,15}; + MEDCouplingUMesh *mesh2=(MEDCouplingUMesh *)mesh1->buildPartOfMySelf(part1,part1+5,true); + mesh2->setName("mesh2"); + const int part2[4]={3,4,13,14}; + MEDCouplingUMesh *mesh3=(MEDCouplingUMesh *)mesh1->buildPartOfMySelf(part2,part2+4,true); + mesh3->setName("mesh3"); + MEDCouplingUMesh *mesh4=MEDCouplingUMesh::New(); + mesh4->setName("mesh4"); + mesh4->setMeshDimension(3); + mesh4->allocateCells(1); + int conn[4]={0,11,1,3}; + mesh4->insertNextCell(INTERP_KERNEL::NORM_TETRA4,4,conn); + mesh4->finishInsertingCells(); + mesh4->setCoords(mesh1->getCoords()); + std::vector meshes; + meshes.push_back(mesh1); + meshes.push_back(mesh2); + meshes.push_back(mesh3); + meshes.push_back(mesh4); + const char mnane[]="3DToto"; + MEDLoader::WriteUMeshesPartition(fileName,mnane,meshes,true); + // + MEDCouplingUMesh *mesh5=MEDLoader::ReadUMeshFromFile(fileName,mnane); + mesh1->setName(mnane); + const int part3[18]={0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17}; + MEDCouplingUMesh *mesh6=(MEDCouplingUMesh *)mesh5->buildPartOfMySelf(part3,part3+18,true); + mesh6->setName(mnane); + mesh5->decrRef(); + CPPUNIT_ASSERT(mesh6->isEqual(mesh1,1e-12)); + mesh6->decrRef(); + std::vector grps=MEDLoader::GetMeshGroupsNames(fileName,mnane); + CPPUNIT_ASSERT_EQUAL(4,(int)grps.size()); + CPPUNIT_ASSERT(std::find(grps.begin(),grps.end(),std::string("mesh2"))!=grps.end()); + CPPUNIT_ASSERT(std::find(grps.begin(),grps.end(),std::string("mesh3"))!=grps.end()); + CPPUNIT_ASSERT(std::find(grps.begin(),grps.end(),std::string("mesh4"))!=grps.end()); + CPPUNIT_ASSERT(std::find(grps.begin(),grps.end(),std::string("3DMesh_1"))!=grps.end()); + // + std::vector vec; + vec.push_back(std::string("mesh2")); + MEDCouplingUMesh *mesh2_2=MEDLoader::ReadUMeshFromGroups(fileName,mnane,0,vec); + CPPUNIT_ASSERT(mesh2_2->isEqual(mesh2,1e-12)); + mesh2_2->decrRef(); + vec.clear(); vec.push_back(std::string("mesh3")); + MEDCouplingUMesh *mesh3_2=MEDLoader::ReadUMeshFromGroups(fileName,mnane,0,vec); + CPPUNIT_ASSERT(mesh3_2->isEqual(mesh3,1e-12)); + mesh3_2->decrRef(); + vec.clear(); vec.push_back(std::string("mesh4")); + MEDCouplingUMesh *mesh4_2=MEDLoader::ReadUMeshFromGroups(fileName,mnane,0,vec); + CPPUNIT_ASSERT(mesh4_2->isEqual(mesh4,1e-12)); + mesh4_2->decrRef(); + vec.clear(); vec.push_back(std::string("3DMesh_1")); + MEDCouplingUMesh *mesh1_2=MEDLoader::ReadUMeshFromGroups(fileName,mnane,0,vec); + mesh1->setName("3DMesh_1"); + CPPUNIT_ASSERT(mesh1_2->isEqual(mesh1,1e-12)); + mesh1_2->decrRef(); + // + vec.clear(); vec.push_back(std::string("Family_-3")); vec.push_back(std::string("Family_-5")); + mesh2_2=MEDLoader::ReadUMeshFromFamilies(fileName,mnane,0,vec); + mesh2_2->setName("mesh2"); + CPPUNIT_ASSERT(mesh2_2->isEqual(mesh2,1e-12)); + mesh2_2->decrRef(); + // + std::vector ret=MEDLoader::GetMeshFamiliesNamesOnGroup(fileName,"3DToto","3DMesh_1"); + CPPUNIT_ASSERT_EQUAL(4,(int)ret.size()); + CPPUNIT_ASSERT(ret[0]=="Family_-2"); + CPPUNIT_ASSERT(ret[1]=="Family_-3"); + CPPUNIT_ASSERT(ret[2]=="Family_-4"); + CPPUNIT_ASSERT(ret[3]=="Family_-5"); + // + std::vector ret1=MEDLoader::GetMeshGroupsNamesOnFamily(fileName,"3DToto","Family_-3"); + CPPUNIT_ASSERT_EQUAL(2,(int)ret1.size()); + CPPUNIT_ASSERT(ret1[0]=="3DMesh_1"); + CPPUNIT_ASSERT(ret1[1]=="mesh2"); + // + mesh4->decrRef(); + mesh3->decrRef(); + mesh2->decrRef(); + mesh1->decrRef(); +} + +void MEDLoaderTest::testFieldProfilRW1() +{ + const char fileName[]="file12.med"; + MEDCouplingUMesh *mesh1=build3DMesh_1(); + bool b; + int newNbOfNodes; + DataArrayInt *da=mesh1->mergeNodes(1e-12,b,newNbOfNodes); + da->decrRef(); + MEDLoader::WriteUMesh(fileName,mesh1,true); + const int part1[5]={1,2,4,13,15}; + MEDCouplingUMesh *mesh2=(MEDCouplingUMesh *)mesh1->buildPartOfMySelf(part1,part1+5,true); + mesh2->setName(mesh1->getName().c_str());//<- important for the test + // + int nbOfCells=mesh2->getNumberOfCells(); + CPPUNIT_ASSERT_EQUAL(5,nbOfCells); + MEDCouplingFieldDouble *f1=MEDCouplingFieldDouble::New(ON_CELLS,ONE_TIME); + f1->setName("VectorFieldOnCells"); + f1->setMesh(mesh2); + DataArrayDouble *array=DataArrayDouble::New(); + array->alloc(nbOfCells,2); + f1->setArray(array); + array->decrRef(); + double *tmp=array->getPointer(); + const double arr1[10]={71.,171.,10.,110.,20.,120.,30.,130.,40.,140.}; + std::copy(arr1,arr1+10,tmp); + f1->setTime(3.14,2,7); + f1->checkCoherency(); + // + MEDLoader::WriteField(fileName,f1,false);//<- false important for the test + // + MEDCouplingFieldDouble *f2=MEDLoader::ReadFieldCell(fileName,f1->getMesh()->getName().c_str(),0,f1->getName().c_str(),2,7); + std::vector types=MEDLoader::GetTypesOfField(fileName,f1->getMesh()->getName().c_str(),f1->getName().c_str()); + CPPUNIT_ASSERT_EQUAL(1,(int)types.size()); + CPPUNIT_ASSERT(types[0]==ON_CELLS); + f2->checkCoherency(); + CPPUNIT_ASSERT(f1->isEqual(f2,1e-12,1e-12)); + // + f2->decrRef(); + f1->decrRef(); + mesh1->decrRef(); + mesh2->decrRef(); +} + +/*! + * Test MED file profiles. + */ +void MEDLoaderTest::testFieldNodeProfilRW1() +{ + const char fileName[]="file19.med"; + const char fileName2[]="file20.med"; + MEDCouplingUMesh *m=build2DMesh_1(); + int nbOfNodes=m->getNumberOfNodes(); + MEDLoader::WriteUMesh(fileName,m,true); + MEDCouplingFieldDouble *f1=MEDCouplingFieldDouble::New(ON_NODES,ONE_TIME); + f1->setName("VFieldOnNodes"); + f1->setMesh(m); + DataArrayDouble *array=DataArrayDouble::New(); + const double arr1[24]={1.,101.,2.,102.,3.,103.,4.,104.,5.,105.,6.,106.,7.,107.,8.,108.,9.,109.,10.,110.,11.,111.,12.,112.}; + array->alloc(nbOfNodes,2); + std::copy(arr1,arr1+24,array->getPointer()); + f1->setArray(array); + array->setInfoOnComponent(0,"tyty [mm]"); + array->setInfoOnComponent(1,"uiop [MW]"); + array->decrRef(); + f1->setTime(3.14,2,7); + f1->checkCoherency(); + const int arr2[2]={1,4};//node ids are 2,4,5,3,6,7 + MEDCouplingFieldDouble *f2=f1->buildSubPart(arr2,arr2+2); + (const_cast(f2->getMesh()))->setName(f1->getMesh()->getName().c_str()); + MEDLoader::WriteField(fileName,f2,false);//<- false important for the test + // + MEDCouplingFieldDouble *f3=MEDLoader::ReadFieldNode(fileName,f2->getMesh()->getName().c_str(),0,f2->getName().c_str(),2,7); + f3->checkCoherency(); + CPPUNIT_ASSERT(f3->isEqual(f2,1e-12,1e-12)); + f3->decrRef(); + // + const int arr3[6]={1,3,0,5,2,4}; + f2->renumberNodes(arr3); + MEDLoader::WriteUMesh(fileName2,m,true); + MEDLoader::WriteField(fileName2,f2,false);//<- false important for the test + f3=MEDLoader::ReadFieldNode(fileName2,f2->getMesh()->getName().c_str(),0,f2->getName().c_str(),2,7); + f3->checkCoherency(); + CPPUNIT_ASSERT(f3->isEqual(f2,1e-12,1e-12)); + f3->decrRef(); + f2->decrRef(); + // + f1->decrRef(); + m->decrRef(); +} + +void MEDLoaderTest::testFieldNodeProfilRW2() +{ + const char fileName[]="file23.med"; + MEDCouplingUMesh *mesh=build3DSurfMesh_1(); + MEDLoader::WriteUMesh(fileName,mesh,true); + // + MEDCouplingFieldDouble *f1=MEDCouplingFieldDouble::New(ON_NODES,ONE_TIME); + f1->setName("FieldMix"); + f1->setMesh(mesh); + const double arr2[24]={ + 1071.,1171.,1010.,1110.,1020.,1120.,1030.,1130.,1040.,1140.,1050.,1150., + 1060.,1160.,1070.,1170.,1080.,1180.,1090.,1190.,1091.,1191.,1092.,1192. + }; + DataArrayDouble *array=DataArrayDouble::New(); + array->alloc(12,2); + f1->setArray(array); + array->setInfoOnComponent(0,"plkj [mm]"); + array->setInfoOnComponent(1,"pqqqss [mm]"); + array->decrRef(); + double *tmp=array->getPointer(); + std::copy(arr2,arr2+24,tmp); + f1->setTime(3.17,2,7); + // + const int renumArr[12]={3,7,2,1,5,11,10,0,9,6,8,4}; + f1->renumberNodes(renumArr); + f1->checkCoherency(); + MEDLoader::WriteField(fileName,f1,false);//<- false important for the test + MEDCouplingFieldDouble *f2=MEDLoader::ReadFieldNode(fileName,f1->getMesh()->getName().c_str(),0,f1->getName().c_str(),2,7); + CPPUNIT_ASSERT(f2->isEqual(f1,1e-12,1e-12)); + // + f2->decrRef(); + mesh->decrRef(); + f1->decrRef(); +} + +void MEDLoaderTest::testFieldGaussRW1() +{ + const char fileName[]="file13.med"; + MEDCouplingFieldDouble *f1=buildVecFieldOnGauss_1(); + MEDLoader::WriteField(fileName,f1,true); + MEDCouplingFieldDouble *f2=MEDLoader::ReadField(ON_GAUSS_PT,fileName,f1->getMesh()->getName().c_str(),0,f1->getName().c_str(),1,5); + CPPUNIT_ASSERT(f1->isEqual(f2,1e-12,1e-12)); + f2->decrRef(); + f1->decrRef(); +} + +void MEDLoaderTest::testFieldGaussNERW1() +{ + const char fileName[]="file14.med"; + MEDCouplingFieldDouble *f1=buildVecFieldOnGaussNE_1(); + MEDLoader::WriteField(fileName,f1,true); + std::vector tof(MEDLoader::GetTypesOfField(fileName,"2DMesh_2","MyFieldOnGaussNE")); + CPPUNIT_ASSERT_EQUAL(1,(int)tof.size()); + CPPUNIT_ASSERT(ON_GAUSS_NE==tof[0]); + MEDCouplingFieldDouble *f2=MEDLoader::ReadField(ON_GAUSS_NE,fileName,f1->getMesh()->getName().c_str(),0,f1->getName().c_str(),1,5); + CPPUNIT_ASSERT(f1->isEqual(f2,1e-12,1e-12)); + f2->decrRef(); + f1->decrRef(); +} + +void MEDLoaderTest::testLittleStrings1() +{ + std::string s("azeeeerrrtty"); + MEDLoaderBase::zipEqualConsChar(s,3); + CPPUNIT_ASSERT(s=="azertty"); +} + +void MEDLoaderTest::testSplitIntoNameAndUnit1() +{ + std::string s(" []"); + std::string c,u; + MEDLoaderBase::splitIntoNameAndUnit(s,c,u); + CPPUNIT_ASSERT(c.empty()); + CPPUNIT_ASSERT(u.empty()); + s=" lmmm kki jjj "; + MEDLoaderBase::strip(s); + CPPUNIT_ASSERT(s=="lmmm kki jjj"); + s=" "; + MEDLoaderBase::strip(s); + CPPUNIT_ASSERT(s.empty()); + s=""; + MEDLoaderBase::strip(s); + CPPUNIT_ASSERT(s.empty()); + s=" "; + MEDLoaderBase::strip(s); + CPPUNIT_ASSERT(s.empty()); + s=" pp"; + MEDLoaderBase::strip(s); + CPPUNIT_ASSERT(s=="pp"); +} + +void MEDLoaderTest::testMesh3DSurfShuffleRW() +{ + const char fileName[]="file15.med"; + MEDCouplingUMesh *mesh=build3DSurfMesh_1(); + const int renumber1[6]={2,5,1,0,3,4}; + mesh->renumberCells(renumber1,false); + mesh->checkCoherency(); + MEDLoader::WriteUMesh(fileName,mesh,true); + MEDCouplingUMesh *mesh_rw=MEDLoader::ReadUMeshFromFile(fileName,mesh->getName().c_str(),0); + CPPUNIT_ASSERT(mesh->isEqual(mesh_rw,1e-12)); + mesh_rw->decrRef(); + mesh->decrRef(); +} + +void MEDLoaderTest::testFieldShuffleRW1() +{ + const char fileName[]="file16.med"; + MEDCouplingUMesh *mesh=build3DSurfMesh_1(); + MEDCouplingFieldDouble *f1=MEDCouplingFieldDouble::New(ON_CELLS,ONE_TIME); + f1->setName("FieldOnCellsShuffle"); + f1->setMesh(mesh); + DataArrayDouble *array=DataArrayDouble::New(); + array->alloc(6,2); + f1->setArray(array); + array->decrRef(); + double *tmp=array->getPointer(); + const double arr1[12]={71.,171.,10.,110.,20.,120.,30.,130.,40.,140.,50.,150.}; + std::copy(arr1,arr1+12,tmp); + f1->setTime(3.14,2,7); + f1->checkCoherency(); + // + const int renumber1[6]={2,1,5,0,3,4}; + f1->renumberCells(renumber1,false); + MEDLoader::WriteField(fileName,f1,true); + MEDCouplingFieldDouble *f2=MEDLoader::ReadFieldCell(fileName,mesh->getName().c_str(),0,f1->getName().c_str(),2,7); + CPPUNIT_ASSERT(f2->isEqual(f1,1e-12,1e-12)); + f2->decrRef(); + // + mesh->decrRef(); + f1->decrRef(); +} + +/*! + * Shuffle de cells but no profile. Like pointe.med + */ +void MEDLoaderTest::testMultiFieldShuffleRW1() +{ + const char fileName[]="file17.med"; + MEDCouplingUMesh *m=build3DMesh_2(); + CPPUNIT_ASSERT_EQUAL(20,m->getNumberOfCells()); + CPPUNIT_ASSERT_EQUAL(45,m->getNumberOfNodes()); + const int polys[3]={1,4,6}; + std::vector poly2(polys,polys+3); + m->convertToPolyTypes(&poly2[0],&poly2[0]+poly2.size()); + const int renum[20]={1,3,2,8,9,12,13,16,19,0,4,7,5,15,14,17,10,18,6,11}; + m->renumberCells(renum,false); + m->orientCorrectlyPolyhedrons(); + // Writing + MEDLoader::WriteUMesh(fileName,m,true); + MEDCouplingFieldDouble *f1Tmp=m->getMeasureField(false); + MEDCouplingFieldDouble *f1=f1Tmp->buildNewTimeReprFromThis(ONE_TIME,false); + f1Tmp->decrRef(); + f1->setTime(0.,1,2); + MEDCouplingFieldDouble *f_1=f1->cloneWithMesh(true); + MEDLoader::WriteFieldUsingAlreadyWrittenMesh(fileName,f1); + f1->applyFunc("2*x"); + f1->setTime(0.01,3,4); + MEDCouplingFieldDouble *f_2=f1->cloneWithMesh(true); + MEDLoader::WriteFieldUsingAlreadyWrittenMesh(fileName,f1); + f1->applyFunc("2*x/3"); + f1->setTime(0.02,5,6); + MEDCouplingFieldDouble *f_3=f1->cloneWithMesh(true); + MEDLoader::WriteFieldUsingAlreadyWrittenMesh(fileName,f1); + f1->decrRef(); + // Reading + std::vector > its; + its.push_back(std::pair(1,2)); + its.push_back(std::pair(3,4)); + its.push_back(std::pair(5,6)); + std::vector fs=MEDLoader::ReadFieldsOnSameMesh(ON_CELLS,fileName,f_1->getMesh()->getName().c_str(),0,f_1->getName().c_str(),its); + CPPUNIT_ASSERT_EQUAL(3,(int)fs.size()); + const MEDCouplingMesh *mm=fs[0]->getMesh(); + CPPUNIT_ASSERT(fs[0]->isEqual(f_1,1e-12,1e-12)); + CPPUNIT_ASSERT(fs[1]->isEqual(f_2,1e-12,1e-12)); + CPPUNIT_ASSERT(fs[2]->isEqual(f_3,1e-12,1e-12)); + CPPUNIT_ASSERT(mm==fs[1]->getMesh());// <- important for the test + CPPUNIT_ASSERT(mm==fs[2]->getMesh());// <- important for the test + for(std::vector::iterator iter=fs.begin();iter!=fs.end();iter++) + (*iter)->decrRef(); + // + f_1->decrRef(); + f_2->decrRef(); + f_3->decrRef(); + // + m->decrRef(); +} + +void MEDLoaderTest::testWriteUMeshesRW1() +{ + const char fileName[]="file18.med"; + MEDCouplingUMesh *m3d=build3DMesh_2(); + const double pt[3]={0.,0.,-0.3}; + const double vec[3]={0.,0.,1.}; + std::vector nodes; + m3d->findNodesOnPlane(pt,vec,1e-12,nodes); + MEDCouplingUMesh *m2d=(MEDCouplingUMesh *)m3d->buildFacePartOfMySelfNode(&nodes[0],&nodes[0]+nodes.size(),true); + const int renumber[5]={1,2,0,4,3}; + m2d->renumberCells(renumber,false); + m2d->setName("ExampleOfMultiDimW"); + std::vector meshes; + meshes.push_back(m2d); + meshes.push_back(m3d); + MEDLoader::WriteUMeshes(fileName,meshes,true); + MEDCouplingUMesh *m3d_bis=MEDLoader::ReadUMeshFromFile(fileName,m2d->getName().c_str(),0); + CPPUNIT_ASSERT(!m3d_bis->isEqual(m3d,1e-12)); + m3d_bis->setName(m3d->getName().c_str()); + CPPUNIT_ASSERT(m3d_bis->isEqual(m3d,1e-12)); + MEDCouplingUMesh *m2d_bis=MEDLoader::ReadUMeshFromFile(fileName,m2d->getName().c_str(),-1);//-1 for faces + CPPUNIT_ASSERT(m2d_bis->isEqual(m2d,1e-12)); + // Creation of a field on faces. + MEDCouplingFieldDouble *f1=MEDCouplingFieldDouble::New(ON_CELLS,ONE_TIME); + f1->setName("FieldOnFacesShuffle"); + f1->setMesh(m2d); + DataArrayDouble *array=DataArrayDouble::New(); + array->alloc(m2d->getNumberOfCells(),2); + array->setInfoOnComponent(0,"plkj [mm]"); + array->setInfoOnComponent(1,"pqqqss [mm]"); + f1->setArray(array); + array->decrRef(); + double *tmp=array->getPointer(); + const double arr1[10]={71.,171.,10.,110.,20.,120.,30.,130.,40.,140.}; + std::copy(arr1,arr1+10,tmp); + f1->setTime(3.14,2,7); + f1->checkCoherency(); + MEDLoader::WriteFieldUsingAlreadyWrittenMesh(fileName,f1); + MEDCouplingFieldDouble *f2=MEDLoader::ReadFieldCell(fileName,f1->getMesh()->getName().c_str(),-1,f1->getName().c_str(),2,7); + CPPUNIT_ASSERT(f2->isEqual(f1,1e-12,1e-12)); + f1->decrRef(); + f2->decrRef(); + // + m2d_bis->decrRef(); + m3d_bis->decrRef(); + m2d->decrRef(); + m3d->decrRef(); +} + +void MEDLoaderTest::testMixCellAndNodesFieldRW1() +{ + const char fileName[]="file21.med"; + MEDCouplingUMesh *mesh=build3DSurfMesh_1(); + MEDCouplingFieldDouble *f1=MEDCouplingFieldDouble::New(ON_CELLS,ONE_TIME); + f1->setName("FieldMix"); + f1->setMesh(mesh); + DataArrayDouble *array=DataArrayDouble::New(); + array->alloc(6,2); + f1->setArray(array); + array->setInfoOnComponent(0,"plkj [mm]"); + array->setInfoOnComponent(1,"pqqqss [mm]"); + array->decrRef(); + double *tmp=array->getPointer(); + const double arr1[12]={71.,171.,10.,110.,20.,120.,30.,130.,40.,140.,50.,150.}; + std::copy(arr1,arr1+12,tmp); + f1->setTime(3.14,2,7); + f1->checkCoherency(); + // + MEDCouplingFieldDouble *f2=MEDCouplingFieldDouble::New(ON_NODES,ONE_TIME); + f2->setName("FieldMix"); + f2->setMesh(mesh); + array=DataArrayDouble::New(); + array->alloc(12,2); + f2->setArray(array); + array->setInfoOnComponent(0,"plkj [mm]"); + array->setInfoOnComponent(1,"pqqqss [mm]"); + array->decrRef(); + tmp=array->getPointer(); + const double arr2[24]={ + 1071.,1171.,1010.,1110.,1020.,1120.,1030.,1130.,1040.,1140.,1050.,1150., + 1060.,1160.,1070.,1170.,1080.,1180.,1090.,1190.,1091.,1191.,1092.,1192. + }; + std::copy(arr2,arr2+24,tmp); + f2->setTime(3.14,2,7); + f2->checkCoherency(); + // + MEDLoader::WriteField(fileName,f1,true); + std::vector ts=MEDLoader::GetTypesOfField(fileName,f1->getMesh()->getName().c_str(),f1->getName().c_str()); + CPPUNIT_ASSERT_EQUAL(1,(int)ts.size()); + CPPUNIT_ASSERT_EQUAL(ON_CELLS,ts[0]); + std::vector fs=MEDLoader::GetAllFieldNamesOnMesh(fileName,f1->getMesh()->getName().c_str()); + CPPUNIT_ASSERT_EQUAL(1,(int)fs.size()); + CPPUNIT_ASSERT(fs[0]=="FieldMix"); + MEDLoader::WriteFieldUsingAlreadyWrittenMesh(fileName,f2); + fs=MEDLoader::GetAllFieldNamesOnMesh(fileName,f1->getMesh()->getName().c_str()); + CPPUNIT_ASSERT_EQUAL(1,(int)fs.size()); + CPPUNIT_ASSERT(fs[0]=="FieldMix"); + // + ts=MEDLoader::GetTypesOfField(fileName,f1->getMesh()->getName().c_str(),f1->getName().c_str()); + CPPUNIT_ASSERT_EQUAL(2,(int)ts.size()); + CPPUNIT_ASSERT_EQUAL(ON_NODES,ts[0]); + CPPUNIT_ASSERT_EQUAL(ON_CELLS,ts[1]); + // + MEDCouplingFieldDouble *f3=MEDLoader::ReadFieldNode(fileName,f1->getMesh()->getName().c_str(),0,f1->getName().c_str(),2,7); + CPPUNIT_ASSERT(f3->isEqual(f2,1e-12,1e-12)); + f3->decrRef(); + f3=MEDLoader::ReadFieldCell(fileName,f1->getMesh()->getName().c_str(),0,f1->getName().c_str(),2,7); + CPPUNIT_ASSERT(f3->isEqual(f1,1e-12,1e-12)); + f3->decrRef(); + // + f1->decrRef(); + f2->decrRef(); + mesh->decrRef(); +} + +void MEDLoaderTest::testGetAllFieldNamesRW1() +{ + const char fileName[]="file22.med"; + MEDCouplingUMesh *mesh=build2DMesh_2(); + MEDCouplingFieldDouble *f1=MEDCouplingFieldDouble::New(ON_NODES,ONE_TIME); + f1->setName("Field1"); + f1->setTime(3.44,5,6); + f1->setMesh(mesh); + f1->fillFromAnalytic(2,"x+y"); + MEDLoader::WriteField(fileName,f1,true); + f1->setTime(1002.3,7,8); + f1->fillFromAnalytic(2,"x+77.*y"); + MEDLoader::WriteFieldUsingAlreadyWrittenMesh(fileName,f1); + f1->setName("Field2"); + MEDLoader::WriteField(fileName,f1,false); + f1->setName("Field3"); + mesh->setName("2DMesh_2Bis"); + MEDLoader::WriteField(fileName,f1,false); + f1->decrRef(); + f1=MEDCouplingFieldDouble::New(ON_CELLS,ONE_TIME); + f1->setName("Field8"); + f1->setTime(8.99,7,9); + f1->setMesh(mesh); + f1->fillFromAnalytic(3,"3*x+y"); + MEDLoader::WriteField(fileName,f1,false); + f1->decrRef(); + std::vector fs=MEDLoader::GetAllFieldNames(fileName); + CPPUNIT_ASSERT_EQUAL(4,(int)fs.size()); + CPPUNIT_ASSERT(fs[0]=="Field1"); + CPPUNIT_ASSERT(fs[1]=="Field2"); + CPPUNIT_ASSERT(fs[2]=="Field3"); + CPPUNIT_ASSERT(fs[3]=="Field8"); + mesh->decrRef(); +} + ++ ++void MEDLoaderTest::testMEDLoaderRead1() ++{ ++ using namespace std; ++ using namespace INTERP_KERNEL; ++ ++ string fileName=getResourceFile("pointe.med"); ++ vector meshNames=MEDLoader::GetMeshNames(fileName.c_str()); ++ CPPUNIT_ASSERT_EQUAL(1,(int)meshNames.size()); ++ MEDCouplingUMesh *mesh=MEDLoader::ReadUMeshFromFile(fileName.c_str(),meshNames[0].c_str(),0); ++ CPPUNIT_ASSERT_EQUAL(3,mesh->getSpaceDimension()); ++ CPPUNIT_ASSERT_EQUAL(3,mesh->getMeshDimension()); ++ CPPUNIT_ASSERT_EQUAL(16,mesh->getNumberOfCells()); ++ CPPUNIT_ASSERT_EQUAL(19,mesh->getNumberOfNodes()); ++ CPPUNIT_ASSERT_EQUAL(3,(int)mesh->getAllGeoTypes().size()); ++ for(int i=0;i<12;i++) ++ CPPUNIT_ASSERT_EQUAL(NORM_TETRA4,mesh->getTypeOfCell(i)); ++ CPPUNIT_ASSERT_EQUAL(NORM_PYRA5,mesh->getTypeOfCell(12)); ++ CPPUNIT_ASSERT_EQUAL(NORM_HEXA8,mesh->getTypeOfCell(13)); ++ CPPUNIT_ASSERT_EQUAL(NORM_HEXA8,mesh->getTypeOfCell(14)); ++ CPPUNIT_ASSERT_EQUAL(NORM_PYRA5,mesh->getTypeOfCell(15)); ++ CPPUNIT_ASSERT_EQUAL((std::size_t)90,mesh->getNodalConnectivity()->getNbOfElems()); ++ CPPUNIT_ASSERT_EQUAL(701,std::accumulate(mesh->getNodalConnectivity()->getPointer(),mesh->getNodalConnectivity()->getPointer()+90,0)); ++ CPPUNIT_ASSERT_EQUAL(705,std::accumulate(mesh->getNodalConnectivityIndex()->getPointer(),mesh->getNodalConnectivityIndex()->getPointer()+17,0)); ++ CPPUNIT_ASSERT_DOUBLES_EQUAL(46.,std::accumulate(mesh->getCoords()->getPointer(),mesh->getCoords()->getPointer()+57,0),1e-12); ++ mesh->decrRef(); ++ // ++ vector families=MEDLoader::GetMeshFamiliesNames(fileName.c_str(),meshNames[0].c_str()); ++ CPPUNIT_ASSERT_EQUAL(8,(int)families.size()); ++ CPPUNIT_ASSERT(families[2]=="FAMILLE_ELEMENT_3"); ++ // ++ vector families2; ++ families2.push_back(families[2]); ++ mesh=MEDLoader::ReadUMeshFromFamilies(fileName.c_str(),meshNames[0].c_str(),0,families2); ++ CPPUNIT_ASSERT_EQUAL(3,mesh->getSpaceDimension()); ++ CPPUNIT_ASSERT_EQUAL(3,mesh->getMeshDimension()); ++ CPPUNIT_ASSERT_EQUAL(2,mesh->getNumberOfCells()); ++ CPPUNIT_ASSERT_EQUAL(19,mesh->getNumberOfNodes()); ++ CPPUNIT_ASSERT_EQUAL(2,(int)mesh->getAllGeoTypes().size()); ++ CPPUNIT_ASSERT_EQUAL(NORM_TETRA4,mesh->getTypeOfCell(0)); ++ CPPUNIT_ASSERT_EQUAL(NORM_PYRA5,mesh->getTypeOfCell(1)); ++ CPPUNIT_ASSERT_EQUAL((std::size_t)11,mesh->getNodalConnectivity()->getNbOfElems()); ++ CPPUNIT_ASSERT_EQUAL(132,std::accumulate(mesh->getNodalConnectivity()->getPointer(),mesh->getNodalConnectivity()->getPointer()+11,0)); ++ CPPUNIT_ASSERT_EQUAL(16,std::accumulate(mesh->getNodalConnectivityIndex()->getPointer(),mesh->getNodalConnectivityIndex()->getPointer()+3,0)); ++ CPPUNIT_ASSERT_DOUBLES_EQUAL(46.,std::accumulate(mesh->getCoords()->getPointer(),mesh->getCoords()->getPointer()+57,0),1e-12); ++ mesh->decrRef(); ++ // ++ vector groups=MEDLoader::GetMeshGroupsNames(fileName.c_str(),meshNames[0].c_str()); ++ CPPUNIT_ASSERT_EQUAL(5,(int)groups.size()); ++ CPPUNIT_ASSERT(groups[0]=="groupe1"); ++ CPPUNIT_ASSERT(groups[1]=="groupe2"); ++ CPPUNIT_ASSERT(groups[2]=="groupe3"); ++ CPPUNIT_ASSERT(groups[3]=="groupe4"); ++ CPPUNIT_ASSERT(groups[4]=="groupe5"); ++ vector groups2; ++ groups2.push_back(groups[0]); ++ mesh=MEDLoader::ReadUMeshFromGroups(fileName.c_str(),meshNames[0].c_str(),0,groups2); ++ CPPUNIT_ASSERT_EQUAL(3,mesh->getSpaceDimension()); ++ CPPUNIT_ASSERT_EQUAL(3,mesh->getMeshDimension()); ++ CPPUNIT_ASSERT_EQUAL(7,mesh->getNumberOfCells()); ++ CPPUNIT_ASSERT_EQUAL(19,mesh->getNumberOfNodes()); ++ CPPUNIT_ASSERT_EQUAL(2,(int)mesh->getAllGeoTypes().size()); ++ for(int i=0;i<6;i++) ++ CPPUNIT_ASSERT_EQUAL(NORM_TETRA4,mesh->getTypeOfCell(i)); ++ CPPUNIT_ASSERT_EQUAL(NORM_PYRA5,mesh->getTypeOfCell(6)); ++ CPPUNIT_ASSERT_EQUAL((std::size_t)36,mesh->getNodalConnectivity()->getNbOfElems()); ++ CPPUNIT_ASSERT_EQUAL(254,std::accumulate(mesh->getNodalConnectivity()->getPointer(),mesh->getNodalConnectivity()->getPointer()+36,0)); ++ CPPUNIT_ASSERT_EQUAL(141,std::accumulate(mesh->getNodalConnectivityIndex()->getPointer(),mesh->getNodalConnectivityIndex()->getPointer()+8,0)); ++ CPPUNIT_ASSERT_DOUBLES_EQUAL(46.,std::accumulate(mesh->getCoords()->getPointer(),mesh->getCoords()->getPointer()+57,0),1e-12); ++ mesh->decrRef(); ++ // ++ std::vector fieldsName=MEDLoader::GetCellFieldNamesOnMesh(fileName.c_str(),meshNames[0].c_str()); ++ CPPUNIT_ASSERT_EQUAL(2,(int)fieldsName.size()); ++ CPPUNIT_ASSERT(fieldsName[0]=="fieldcelldoublescalar"); ++ CPPUNIT_ASSERT(fieldsName[1]=="fieldcelldoublevector"); ++ std::vector > its0=MEDLoader::GetCellFieldIterations(fileName.c_str(),meshNames[0].c_str(),fieldsName[0].c_str()); ++ CPPUNIT_ASSERT_EQUAL(1,(int)its0.size()); ++ CPPUNIT_ASSERT_EQUAL(-1,its0[0].first); ++ CPPUNIT_ASSERT_EQUAL(-1,its0[0].second); ++ std::vector > its1=MEDLoader::GetCellFieldIterations(fileName.c_str(),meshNames[0].c_str(),fieldsName[1].c_str()); ++ CPPUNIT_ASSERT_EQUAL(1,(int)its1.size()); ++ CPPUNIT_ASSERT_EQUAL(-1,its1[0].first); ++ CPPUNIT_ASSERT_EQUAL(-1,its1[0].second); ++ // ++ MEDCouplingFieldDouble *field0=MEDLoader::ReadFieldCell(fileName.c_str(),meshNames[0].c_str(),0,fieldsName[0].c_str(),its0[0].first,its0[0].second); ++ field0->checkCoherency(); ++ CPPUNIT_ASSERT(field0->getName()==fieldsName[0]); ++ CPPUNIT_ASSERT_EQUAL(1,field0->getNumberOfComponents()); ++ CPPUNIT_ASSERT_EQUAL(16,field0->getNumberOfTuples()); ++ const double expectedValues[16]={1.,1.,1.,1.,1.,1.,1.,1.,1.,1.,1.,1.,2.,3.,3.,2.}; ++ double diffValue[16]; ++ std::transform(field0->getArray()->getPointer(),field0->getArray()->getPointer()+16,expectedValues,diffValue,std::minus()); ++ CPPUNIT_ASSERT_DOUBLES_EQUAL(0.,*std::max_element(diffValue,diffValue+16),1e-12); ++ CPPUNIT_ASSERT_DOUBLES_EQUAL(0.,*std::min_element(diffValue,diffValue+16),1e-12); ++ const MEDCouplingUMesh *constMesh=dynamic_cast(field0->getMesh()); ++ CPPUNIT_ASSERT(constMesh); ++ CPPUNIT_ASSERT_EQUAL(3,constMesh->getSpaceDimension()); ++ CPPUNIT_ASSERT_EQUAL(3,constMesh->getMeshDimension()); ++ CPPUNIT_ASSERT_EQUAL(16,constMesh->getNumberOfCells()); ++ CPPUNIT_ASSERT_EQUAL(19,constMesh->getNumberOfNodes()); ++ CPPUNIT_ASSERT_EQUAL(3,(int)constMesh->getAllGeoTypes().size()); ++ for(int i=0;i<12;i++) ++ CPPUNIT_ASSERT_EQUAL(NORM_TETRA4,constMesh->getTypeOfCell(i)); ++ CPPUNIT_ASSERT_EQUAL(NORM_PYRA5,constMesh->getTypeOfCell(12)); ++ CPPUNIT_ASSERT_EQUAL(NORM_HEXA8,constMesh->getTypeOfCell(13)); ++ CPPUNIT_ASSERT_EQUAL(NORM_HEXA8,constMesh->getTypeOfCell(14)); ++ CPPUNIT_ASSERT_EQUAL(NORM_PYRA5,constMesh->getTypeOfCell(15)); ++ CPPUNIT_ASSERT_EQUAL((std::size_t)90,constMesh->getNodalConnectivity()->getNbOfElems()); ++ CPPUNIT_ASSERT_EQUAL(701,std::accumulate(constMesh->getNodalConnectivity()->getConstPointer(),constMesh->getNodalConnectivity()->getConstPointer()+90,0)); ++ CPPUNIT_ASSERT_EQUAL(705,std::accumulate(constMesh->getNodalConnectivityIndex()->getConstPointer(),constMesh->getNodalConnectivityIndex()->getConstPointer()+17,0)); ++ CPPUNIT_ASSERT_DOUBLES_EQUAL(46.,std::accumulate(constMesh->getCoords()->getConstPointer(),constMesh->getCoords()->getConstPointer()+57,0),1e-12); ++ field0->decrRef(); ++ // ++ MEDCouplingFieldDouble *field1=MEDLoader::ReadFieldCell(fileName.c_str(),meshNames[0].c_str(),0,fieldsName[1].c_str(),its1[0].first,its1[0].second); ++ field1->checkCoherency(); ++ CPPUNIT_ASSERT(field1->getName()==fieldsName[1]); ++ CPPUNIT_ASSERT_EQUAL(3,field1->getNumberOfComponents()); ++ CPPUNIT_ASSERT_EQUAL(16,field1->getNumberOfTuples()); ++ const double expectedValues2[48]={1.,0.,1.,1.,0.,1.,1.,0.,1.,2.,1.,0.,2.,1.,0.,2.,1.,0.,3.,0.,1.,3.,0.,1.,3.,0.,1.,4.,1.,0.,4.,1.,0.,4.,1.,0.,5.,0.,0.,6.,1.,1.,6.,0.,0.,5.,1.,1.}; ++ double diffValue2[48]; ++ std::transform(field1->getArray()->getPointer(),field1->getArray()->getPointer()+48,expectedValues2,diffValue2,std::minus()); ++ CPPUNIT_ASSERT_DOUBLES_EQUAL(0.,*std::max_element(diffValue2,diffValue2+48),1e-12); ++ CPPUNIT_ASSERT_DOUBLES_EQUAL(0.,*std::min_element(diffValue2,diffValue2+48),1e-12); ++ constMesh=dynamic_cast(field1->getMesh()); ++ CPPUNIT_ASSERT(constMesh); ++ CPPUNIT_ASSERT_EQUAL(3,constMesh->getSpaceDimension()); ++ CPPUNIT_ASSERT_EQUAL(3,constMesh->getMeshDimension()); ++ CPPUNIT_ASSERT_EQUAL(16,constMesh->getNumberOfCells()); ++ CPPUNIT_ASSERT_EQUAL(19,constMesh->getNumberOfNodes()); ++ CPPUNIT_ASSERT_EQUAL(3,(int)constMesh->getAllGeoTypes().size()); ++ for(int i=0;i<12;i++) ++ CPPUNIT_ASSERT_EQUAL(NORM_TETRA4,constMesh->getTypeOfCell(i)); ++ CPPUNIT_ASSERT_EQUAL(NORM_PYRA5,constMesh->getTypeOfCell(12)); ++ CPPUNIT_ASSERT_EQUAL(NORM_HEXA8,constMesh->getTypeOfCell(13)); ++ CPPUNIT_ASSERT_EQUAL(NORM_HEXA8,constMesh->getTypeOfCell(14)); ++ CPPUNIT_ASSERT_EQUAL(NORM_PYRA5,constMesh->getTypeOfCell(15)); ++ CPPUNIT_ASSERT_EQUAL((std::size_t)90,constMesh->getNodalConnectivity()->getNbOfElems()); ++ CPPUNIT_ASSERT_EQUAL(701,std::accumulate(constMesh->getNodalConnectivity()->getConstPointer(),constMesh->getNodalConnectivity()->getConstPointer()+90,0)); ++ CPPUNIT_ASSERT_EQUAL(705,std::accumulate(constMesh->getNodalConnectivityIndex()->getConstPointer(),constMesh->getNodalConnectivityIndex()->getConstPointer()+17,0)); ++ CPPUNIT_ASSERT_DOUBLES_EQUAL(46.,std::accumulate(constMesh->getCoords()->getConstPointer(),constMesh->getCoords()->getConstPointer()+57,0),1e-12); ++ field1->decrRef(); ++ //fields on nodes ++ std::vector fieldsNameNode=MEDLoader::GetNodeFieldNamesOnMesh(fileName.c_str(),meshNames[0].c_str()); ++ CPPUNIT_ASSERT_EQUAL(2,(int)fieldsNameNode.size()); ++ CPPUNIT_ASSERT(fieldsNameNode[0]=="fieldnodedouble"); ++ CPPUNIT_ASSERT(fieldsNameNode[1]=="fieldnodeint"); ++ std::vector > its0Node=MEDLoader::GetNodeFieldIterations(fileName.c_str(),meshNames[0].c_str(),fieldsNameNode[0].c_str()); ++ CPPUNIT_ASSERT_EQUAL(3,(int)its0Node.size()); ++ CPPUNIT_ASSERT_EQUAL(-1,its0Node[0].first); ++ CPPUNIT_ASSERT_EQUAL(-1,its0Node[0].second); ++ CPPUNIT_ASSERT_EQUAL(1,its0Node[1].first); ++ CPPUNIT_ASSERT_EQUAL(-1,its0Node[1].second); ++ CPPUNIT_ASSERT_EQUAL(2,its0Node[2].first); ++ CPPUNIT_ASSERT_EQUAL(-1,its0Node[2].second); ++ MEDCouplingFieldDouble *field0Nodes=MEDLoader::ReadFieldNode(fileName.c_str(),meshNames[0].c_str(),0,fieldsNameNode[0].c_str(),its0Node[0].first,its0Node[0].second); ++ field0Nodes->checkCoherency(); ++ CPPUNIT_ASSERT(field0Nodes->getName()==fieldsNameNode[0]); ++ CPPUNIT_ASSERT_EQUAL(1,field0Nodes->getNumberOfComponents()); ++ CPPUNIT_ASSERT_EQUAL(19,field0Nodes->getNumberOfTuples()); ++ const double expectedValues3[19]={1.,1.,1.,2.,2.,2.,3.,3.,3.,4.,4.,4.,5.,5.,5.,6.,6.,6.,7.}; ++ double diffValue3[19]; ++ std::transform(field0Nodes->getArray()->getPointer(),field0Nodes->getArray()->getPointer()+19,expectedValues3,diffValue3,std::minus()); ++ CPPUNIT_ASSERT_DOUBLES_EQUAL(0.,*std::max_element(diffValue3,diffValue3+19),1e-12); ++ CPPUNIT_ASSERT_DOUBLES_EQUAL(0.,*std::min_element(diffValue3,diffValue3+19),1e-12); ++ constMesh=dynamic_cast(field0Nodes->getMesh()); ++ CPPUNIT_ASSERT(constMesh); ++ field0Nodes->decrRef(); ++ // ++ field0Nodes=MEDLoader::ReadFieldNode(fileName.c_str(),meshNames[0].c_str(),0,fieldsNameNode[0].c_str(),its0Node[2].first,its0Node[2].second); ++ field0Nodes->checkCoherency(); ++ CPPUNIT_ASSERT(field0Nodes->getName()==fieldsNameNode[0]); ++ CPPUNIT_ASSERT_EQUAL(1,field0Nodes->getNumberOfComponents()); ++ CPPUNIT_ASSERT_EQUAL(19,field0Nodes->getNumberOfTuples()); ++ const double expectedValues4[19]={1.,2.,2.,2.,3.,3.,3.,4.,4.,4.,5.,5.,5.,6.,6.,6.,7.,7.,7.}; ++ std::transform(field0Nodes->getArray()->getPointer(),field0Nodes->getArray()->getPointer()+19,expectedValues4,diffValue3,std::minus()); ++ CPPUNIT_ASSERT_DOUBLES_EQUAL(0.,*std::max_element(diffValue3,diffValue3+19),1e-12); ++ CPPUNIT_ASSERT_DOUBLES_EQUAL(0.,*std::min_element(diffValue3,diffValue3+19),1e-12); ++ constMesh=dynamic_cast(field0Nodes->getMesh()); ++ CPPUNIT_ASSERT(constMesh); ++ CPPUNIT_ASSERT_EQUAL(3,constMesh->getSpaceDimension()); ++ CPPUNIT_ASSERT_EQUAL(3,constMesh->getMeshDimension()); ++ CPPUNIT_ASSERT_EQUAL(16,constMesh->getNumberOfCells()); ++ CPPUNIT_ASSERT_EQUAL(19,constMesh->getNumberOfNodes()); ++ CPPUNIT_ASSERT_EQUAL(3,(int)constMesh->getAllGeoTypes().size()); ++ for(int i=0;i<12;i++) ++ CPPUNIT_ASSERT_EQUAL(NORM_TETRA4,constMesh->getTypeOfCell(i)); ++ CPPUNIT_ASSERT_EQUAL(NORM_PYRA5,constMesh->getTypeOfCell(12)); ++ CPPUNIT_ASSERT_EQUAL(NORM_HEXA8,constMesh->getTypeOfCell(13)); ++ CPPUNIT_ASSERT_EQUAL(NORM_HEXA8,constMesh->getTypeOfCell(14)); ++ CPPUNIT_ASSERT_EQUAL(NORM_PYRA5,constMesh->getTypeOfCell(15)); ++ CPPUNIT_ASSERT_EQUAL((std::size_t)90,constMesh->getNodalConnectivity()->getNbOfElems()); ++ CPPUNIT_ASSERT_EQUAL(701,std::accumulate(constMesh->getNodalConnectivity()->getConstPointer(),constMesh->getNodalConnectivity()->getConstPointer()+90,0)); ++ CPPUNIT_ASSERT_EQUAL(705,std::accumulate(constMesh->getNodalConnectivityIndex()->getConstPointer(),constMesh->getNodalConnectivityIndex()->getConstPointer()+17,0)); ++ CPPUNIT_ASSERT_DOUBLES_EQUAL(46.,std::accumulate(constMesh->getCoords()->getConstPointer(),constMesh->getCoords()->getConstPointer()+57,0),1e-12); ++ field0Nodes->decrRef(); ++ // ++ field0Nodes=MEDLoader::ReadFieldNode(fileName.c_str(),meshNames[0].c_str(),0,fieldsNameNode[0].c_str(),its0Node[0].first,its0Node[0].second); ++ field0Nodes->checkCoherency(); ++ CPPUNIT_ASSERT(field0Nodes->getName()==fieldsNameNode[0]); ++ CPPUNIT_ASSERT_EQUAL(1,field0Nodes->getNumberOfComponents()); ++ CPPUNIT_ASSERT_EQUAL(19,field0Nodes->getNumberOfTuples()); ++ const double expectedValues5[19]={1.,1.,1.,2.,2.,2.,3.,3.,3.,4.,4.,4.,5.,5.,5.,6.,6.,6.,7.}; ++ std::transform(field0Nodes->getArray()->getPointer(),field0Nodes->getArray()->getPointer()+19,expectedValues5,diffValue3,std::minus()); ++ CPPUNIT_ASSERT_DOUBLES_EQUAL(0.,*std::max_element(diffValue3,diffValue3+19),1e-12); ++ CPPUNIT_ASSERT_DOUBLES_EQUAL(0.,*std::min_element(diffValue3,diffValue3+19),1e-12); ++ constMesh=dynamic_cast(field0Nodes->getMesh()); ++ CPPUNIT_ASSERT(constMesh); ++ CPPUNIT_ASSERT_EQUAL(3,constMesh->getSpaceDimension()); ++ CPPUNIT_ASSERT_EQUAL(3,constMesh->getMeshDimension()); ++ CPPUNIT_ASSERT_EQUAL(16,constMesh->getNumberOfCells()); ++ CPPUNIT_ASSERT_EQUAL(19,constMesh->getNumberOfNodes()); ++ CPPUNIT_ASSERT_EQUAL(3,(int)constMesh->getAllGeoTypes().size()); ++ for(int i=0;i<12;i++) ++ CPPUNIT_ASSERT_EQUAL(NORM_TETRA4,constMesh->getTypeOfCell(i)); ++ CPPUNIT_ASSERT_EQUAL(NORM_PYRA5,constMesh->getTypeOfCell(12)); ++ CPPUNIT_ASSERT_EQUAL(NORM_HEXA8,constMesh->getTypeOfCell(13)); ++ CPPUNIT_ASSERT_EQUAL(NORM_HEXA8,constMesh->getTypeOfCell(14)); ++ CPPUNIT_ASSERT_EQUAL(NORM_PYRA5,constMesh->getTypeOfCell(15)); ++ CPPUNIT_ASSERT_EQUAL((std::size_t)90,constMesh->getNodalConnectivity()->getNbOfElems()); ++ CPPUNIT_ASSERT_EQUAL(701,std::accumulate(constMesh->getNodalConnectivity()->getConstPointer(),constMesh->getNodalConnectivity()->getConstPointer()+90,0)); ++ CPPUNIT_ASSERT_EQUAL(705,std::accumulate(constMesh->getNodalConnectivityIndex()->getConstPointer(),constMesh->getNodalConnectivityIndex()->getConstPointer()+17,0)); ++ CPPUNIT_ASSERT_DOUBLES_EQUAL(46.,std::accumulate(constMesh->getCoords()->getConstPointer(),constMesh->getCoords()->getConstPointer()+57,0),1e-12); ++ field0Nodes->decrRef(); ++} ++ ++void MEDLoaderTest::testMEDLoaderPolygonRead() ++{ ++ using namespace std; ++ using namespace INTERP_KERNEL; ++ ++ string fileName=getResourceFile("polygones.med"); ++ vector meshNames=MEDLoader::GetMeshNames(fileName.c_str()); ++ CPPUNIT_ASSERT_EQUAL(1,(int)meshNames.size()); ++ CPPUNIT_ASSERT(meshNames[0]=="Bord"); ++ MEDCouplingUMesh *mesh=MEDLoader::ReadUMeshFromFile(fileName.c_str(),meshNames[0].c_str(),0); ++ mesh->checkCoherency(); ++ CPPUNIT_ASSERT_EQUAL(3,mesh->getSpaceDimension()); ++ CPPUNIT_ASSERT_EQUAL(2,mesh->getMeshDimension()); ++ CPPUNIT_ASSERT_EQUAL(538,mesh->getNumberOfCells()); ++ CPPUNIT_ASSERT_EQUAL(579,mesh->getNumberOfNodes()); ++ CPPUNIT_ASSERT_EQUAL(2,(int)mesh->getAllGeoTypes().size()); ++ for(int i=0;i<514;i++) ++ CPPUNIT_ASSERT_EQUAL(NORM_QUAD4,mesh->getTypeOfCell(i)); ++ for(int i=514;i<538;i++) ++ CPPUNIT_ASSERT_EQUAL(NORM_POLYGON,mesh->getTypeOfCell(i)); ++ CPPUNIT_ASSERT_DOUBLES_EQUAL(0.,std::accumulate(mesh->getCoords()->getPointer(),mesh->getCoords()->getPointer()+1737,0),1e-12); ++ const double expectedVals1[12]={1.4851585216522212,-0.5,0.,1.4851585216522212,-0.4,0.,1.4851585216522212,-0.3,0., 1.5741585216522211, -0.5, 0. }; ++ double diffValue1[12]; ++ std::transform(mesh->getCoords()->getPointer(),mesh->getCoords()->getPointer()+12,expectedVals1,diffValue1,std::minus()); ++ CPPUNIT_ASSERT_DOUBLES_EQUAL(0.,*std::max_element(diffValue1,diffValue1+12),1e-12); ++ CPPUNIT_ASSERT_DOUBLES_EQUAL(0.,*std::min_element(diffValue1,diffValue1+12),1e-12); ++ CPPUNIT_ASSERT_EQUAL((std::size_t)2768,mesh->getNodalConnectivity()->getNbOfElems()); ++ CPPUNIT_ASSERT_EQUAL(651050,std::accumulate(mesh->getNodalConnectivity()->getPointer(),mesh->getNodalConnectivity()->getPointer()+2768,0)); ++ CPPUNIT_ASSERT_EQUAL(725943,std::accumulate(mesh->getNodalConnectivityIndex()->getPointer(),mesh->getNodalConnectivityIndex()->getPointer()+539,0)); ++ mesh->decrRef(); ++ // ++ std::vector fieldsName=MEDLoader::GetCellFieldNamesOnMesh(fileName.c_str(),meshNames[0].c_str()); ++ CPPUNIT_ASSERT_EQUAL(3,(int)fieldsName.size()); ++ CPPUNIT_ASSERT(fieldsName[0]=="bord_:_distorsion"); ++ CPPUNIT_ASSERT(fieldsName[1]=="bord_:_familles"); ++ CPPUNIT_ASSERT(fieldsName[2]=="bord_:_non-ortho"); ++ std::vector > its0=MEDLoader::GetCellFieldIterations(fileName.c_str(),meshNames[0].c_str(),fieldsName[0].c_str()); ++ CPPUNIT_ASSERT_EQUAL(1,(int)its0.size()); ++ MEDCouplingFieldDouble *field=MEDLoader::ReadFieldCell(fileName.c_str(),meshNames[0].c_str(),0,fieldsName[0].c_str(),its0[0].first,its0[0].second); ++ field->checkCoherency(); ++ CPPUNIT_ASSERT(field->getName()==fieldsName[0]); ++ CPPUNIT_ASSERT_EQUAL(1,field->getNumberOfComponents()); ++ CPPUNIT_ASSERT_EQUAL(538,field->getNumberOfTuples()); ++ const MEDCouplingUMesh *constMesh=dynamic_cast(field->getMesh()); ++ CPPUNIT_ASSERT(constMesh); ++ CPPUNIT_ASSERT_EQUAL(3,constMesh->getSpaceDimension()); ++ CPPUNIT_ASSERT_EQUAL(2,constMesh->getMeshDimension()); ++ CPPUNIT_ASSERT_EQUAL(538,constMesh->getNumberOfCells()); ++ CPPUNIT_ASSERT_EQUAL(579,constMesh->getNumberOfNodes()); ++ CPPUNIT_ASSERT_EQUAL(2,(int)constMesh->getAllGeoTypes().size()); ++ for(int i=0;i<514;i++) ++ CPPUNIT_ASSERT_EQUAL(NORM_QUAD4,constMesh->getTypeOfCell(i)); ++ for(int i=514;i<538;i++) ++ CPPUNIT_ASSERT_EQUAL(NORM_POLYGON,constMesh->getTypeOfCell(i)); ++ CPPUNIT_ASSERT_DOUBLES_EQUAL(0.,std::accumulate(constMesh->getCoords()->getConstPointer(),constMesh->getCoords()->getConstPointer()+1737,0),1e-12); ++ std::transform(constMesh->getCoords()->getConstPointer(),constMesh->getCoords()->getConstPointer()+12,expectedVals1,diffValue1,std::minus()); ++ CPPUNIT_ASSERT_DOUBLES_EQUAL(0.,*std::max_element(diffValue1,diffValue1+12),1e-12); ++ CPPUNIT_ASSERT_DOUBLES_EQUAL(0.,*std::min_element(diffValue1,diffValue1+12),1e-12); ++ CPPUNIT_ASSERT_EQUAL((std::size_t)2768,constMesh->getNodalConnectivity()->getNbOfElems()); ++ CPPUNIT_ASSERT_EQUAL(651050,std::accumulate(constMesh->getNodalConnectivity()->getConstPointer(),constMesh->getNodalConnectivity()->getConstPointer()+2768,0)); ++ CPPUNIT_ASSERT_EQUAL(725943,std::accumulate(constMesh->getNodalConnectivityIndex()->getConstPointer(),constMesh->getNodalConnectivityIndex()->getConstPointer()+539,0)); ++ const double *values=field->getArray()->getPointer(); ++ CPPUNIT_ASSERT_DOUBLES_EQUAL(2.87214203182918,std::accumulate(values,values+538,0.),1e-12); ++ field->decrRef(); ++} ++ ++void MEDLoaderTest::testMEDLoaderPolyhedronRead() ++{ ++ using namespace std; ++ using namespace INTERP_KERNEL; ++ ++ string fileName=getResourceFile("poly3D.med"); ++ vector meshNames=MEDLoader::GetMeshNames(fileName.c_str()); ++ CPPUNIT_ASSERT_EQUAL(1,(int)meshNames.size()); ++ CPPUNIT_ASSERT(meshNames[0]=="poly3D"); ++ MEDCouplingUMesh *mesh=MEDLoader::ReadUMeshFromFile(fileName.c_str(),meshNames[0].c_str(),0); ++ mesh->checkCoherency(); ++ CPPUNIT_ASSERT_EQUAL(3,mesh->getSpaceDimension()); ++ CPPUNIT_ASSERT_EQUAL(3,mesh->getMeshDimension()); ++ CPPUNIT_ASSERT_EQUAL(3,mesh->getNumberOfCells()); ++ CPPUNIT_ASSERT_EQUAL(19,mesh->getNumberOfNodes()); ++ CPPUNIT_ASSERT_EQUAL(2,(int)mesh->getAllGeoTypes().size()); ++ CPPUNIT_ASSERT_EQUAL(NORM_TETRA4,mesh->getTypeOfCell(0)); ++ CPPUNIT_ASSERT_EQUAL(NORM_POLYHED,mesh->getTypeOfCell(1)); ++ CPPUNIT_ASSERT_EQUAL(NORM_POLYHED,mesh->getTypeOfCell(2)); ++ CPPUNIT_ASSERT_EQUAL((std::size_t)98,mesh->getNodalConnectivity()->getNbOfElems()); ++ CPPUNIT_ASSERT_EQUAL(725,std::accumulate(mesh->getNodalConnectivity()->getPointer(),mesh->getNodalConnectivity()->getPointer()+98,0)); ++ CPPUNIT_ASSERT_DOUBLES_EQUAL(110.,std::accumulate(mesh->getCoords()->getPointer(),mesh->getCoords()->getPointer()+57,0),1e-12); ++ CPPUNIT_ASSERT_EQUAL(155,std::accumulate(mesh->getNodalConnectivityIndex()->getPointer(),mesh->getNodalConnectivityIndex()->getPointer()+4,0)); ++ mesh->decrRef(); ++ // ++ mesh=MEDLoader::ReadUMeshFromFile(fileName.c_str(),meshNames[0].c_str(),-1); ++ mesh->checkCoherency(); ++ CPPUNIT_ASSERT_EQUAL(3,mesh->getSpaceDimension()); ++ CPPUNIT_ASSERT_EQUAL(2,mesh->getMeshDimension()); ++ CPPUNIT_ASSERT_EQUAL(17,mesh->getNumberOfCells()); ++ CPPUNIT_ASSERT_EQUAL(19,mesh->getNumberOfNodes()); ++ CPPUNIT_ASSERT_EQUAL(3,(int)mesh->getAllGeoTypes().size()); ++ CPPUNIT_ASSERT_EQUAL(NORM_POLYGON,mesh->getTypeOfCell(0)); ++ CPPUNIT_ASSERT_EQUAL(NORM_QUAD4,mesh->getTypeOfCell(1)); ++ CPPUNIT_ASSERT_EQUAL(NORM_QUAD4,mesh->getTypeOfCell(2)); ++ CPPUNIT_ASSERT_EQUAL(NORM_QUAD4,mesh->getTypeOfCell(3)); ++ CPPUNIT_ASSERT_EQUAL(NORM_QUAD4,mesh->getTypeOfCell(4)); ++ CPPUNIT_ASSERT_EQUAL(NORM_QUAD4,mesh->getTypeOfCell(5)); ++ CPPUNIT_ASSERT_EQUAL(NORM_QUAD4,mesh->getTypeOfCell(6)); ++ CPPUNIT_ASSERT_EQUAL(NORM_TRI3,mesh->getTypeOfCell(7)); ++ CPPUNIT_ASSERT_EQUAL(NORM_POLYGON,mesh->getTypeOfCell(8)); ++ CPPUNIT_ASSERT_EQUAL(NORM_POLYGON,mesh->getTypeOfCell(9)); ++ CPPUNIT_ASSERT_EQUAL(NORM_QUAD4,mesh->getTypeOfCell(10)); ++ CPPUNIT_ASSERT_EQUAL(NORM_TRI3,mesh->getTypeOfCell(11)); ++ CPPUNIT_ASSERT_EQUAL(NORM_TRI3,mesh->getTypeOfCell(12)); ++ CPPUNIT_ASSERT_EQUAL(NORM_TRI3,mesh->getTypeOfCell(13)); ++ CPPUNIT_ASSERT_EQUAL(NORM_TRI3,mesh->getTypeOfCell(14)); ++ CPPUNIT_ASSERT_EQUAL(NORM_QUAD4,mesh->getTypeOfCell(15)); ++ CPPUNIT_ASSERT_EQUAL(NORM_TRI3,mesh->getTypeOfCell(16)); ++ CPPUNIT_ASSERT_DOUBLES_EQUAL(110.,std::accumulate(mesh->getCoords()->getPointer(),mesh->getCoords()->getPointer()+57,0),1e-12); ++ CPPUNIT_ASSERT_EQUAL((std::size_t)83,mesh->getNodalConnectivity()->getNbOfElems()); ++ CPPUNIT_ASSERT_EQUAL(619,std::accumulate(mesh->getNodalConnectivity()->getPointer(),mesh->getNodalConnectivity()->getPointer()+83,0)); ++ mesh->decrRef(); ++ // ++ vector families=MEDLoader::GetMeshFamiliesNames(fileName.c_str(),meshNames[0].c_str()); ++ CPPUNIT_ASSERT_EQUAL(4,(int)families.size()); ++ CPPUNIT_ASSERT(families[0]=="FAMILLE_FACE_POLYGONS3"); ++ CPPUNIT_ASSERT(families[1]=="FAMILLE_FACE_QUAD41"); ++ CPPUNIT_ASSERT(families[2]=="FAMILLE_FACE_TRIA32"); ++ CPPUNIT_ASSERT(families[3]=="FAMILLE_ZERO"); ++ vector families2; ++ families2.push_back(families[0]); ++ mesh=MEDLoader::ReadUMeshFromFamilies(fileName.c_str(),meshNames[0].c_str(),-1,families2); ++ mesh->checkCoherency(); ++ CPPUNIT_ASSERT_EQUAL(3,mesh->getSpaceDimension()); ++ CPPUNIT_ASSERT_EQUAL(2,mesh->getMeshDimension()); ++ CPPUNIT_ASSERT_EQUAL(3,mesh->getNumberOfCells()); ++ CPPUNIT_ASSERT_EQUAL(19,mesh->getNumberOfNodes()); ++ CPPUNIT_ASSERT_EQUAL(1,(int)mesh->getAllGeoTypes().size()); ++ for(int i=0;i<3;i++) ++ CPPUNIT_ASSERT_EQUAL(NORM_POLYGON,mesh->getTypeOfCell(i)); ++ CPPUNIT_ASSERT_EQUAL((std::size_t)19,mesh->getNodalConnectivity()->getNbOfElems()); ++ CPPUNIT_ASSERT_EQUAL(117,std::accumulate(mesh->getNodalConnectivity()->getPointer(),mesh->getNodalConnectivity()->getPointer()+19,0)); ++ mesh->decrRef(); ++ // ++ mesh=MEDLoader::ReadUMeshFromFamilies(fileName.c_str(),meshNames[0].c_str(),0,families2); ++ CPPUNIT_ASSERT_EQUAL(3,mesh->getSpaceDimension()); ++ CPPUNIT_ASSERT_EQUAL(0,mesh->getNumberOfCells()); ++ CPPUNIT_ASSERT_EQUAL(19,mesh->getNumberOfNodes()); ++ CPPUNIT_ASSERT_EQUAL(3,mesh->getMeshDimension()); ++ CPPUNIT_ASSERT_EQUAL(0,(int)mesh->getAllGeoTypes().size()); ++ mesh->decrRef(); ++} ++ ++std::string MEDLoaderTest::getResourceFile( const std::string& filename ) const ++{ ++ std::string resourceFile = ""; ++ ++ if ( getenv("top_srcdir") ) { ++ // we are in 'make test' step ++ resourceFile = getenv("top_srcdir"); ++ resourceFile += "/resources/"; ++ } ++ else if ( getenv("MED_ROOT_DIR") ) { ++ // use MED_ROOT_DIR env.var ++ resourceFile = getenv("MED_ROOT_DIR"); ++ resourceFile += "/share/salome/resources/med/"; ++ } ++ resourceFile += filename; ++ return resourceFile; ++} ++ ++ +MEDCouplingUMesh *MEDLoaderTest::build1DMesh_1() +{ + double coords[6]={ 0.0, 0.3, 0.75, 1.0, 1.4, 1.3 }; + int conn[9]={ 0,1, 1,2, 2,3 , 3,4,5}; + MEDCouplingUMesh *mesh=MEDCouplingUMesh::New(); + mesh->setName("1DMesh_1"); + mesh->setMeshDimension(1); + mesh->allocateCells(4); + mesh->insertNextCell(INTERP_KERNEL::NORM_SEG2,2,conn); + mesh->insertNextCell(INTERP_KERNEL::NORM_SEG2,2,conn+2); + mesh->insertNextCell(INTERP_KERNEL::NORM_SEG2,2,conn+4); + mesh->insertNextCell(INTERP_KERNEL::NORM_SEG3,3,conn+6); + mesh->finishInsertingCells(); + DataArrayDouble *myCoords=DataArrayDouble::New(); + myCoords->alloc(6,1); + myCoords->setInfoOnComponent(0,"tototototototot [m*m*m*m*m*m*m*m]"); + std::copy(coords,coords+6,myCoords->getPointer()); + mesh->setCoords(myCoords); + myCoords->decrRef(); + return mesh; +} + +MEDCouplingUMesh *MEDLoaderTest::build2DCurveMesh_1() +{ + double coords[12]={ 0.0,0.0, 0.3,0.3, 0.75,0.75, 1.0,1.0, 1.4,1.4, 1.3,1.3 }; + int conn[9]={ 0,1, 1,2, 2,3 , 3,4,5}; + MEDCouplingUMesh *mesh=MEDCouplingUMesh::New(); + mesh->setName("2DCurveMesh_1"); + mesh->setMeshDimension(1); + mesh->allocateCells(4); + mesh->insertNextCell(INTERP_KERNEL::NORM_SEG2,2,conn); + mesh->insertNextCell(INTERP_KERNEL::NORM_SEG2,2,conn+2); + mesh->insertNextCell(INTERP_KERNEL::NORM_SEG2,2,conn+4); + mesh->insertNextCell(INTERP_KERNEL::NORM_SEG3,3,conn+6); + mesh->finishInsertingCells(); + DataArrayDouble *myCoords=DataArrayDouble::New(); + myCoords->alloc(6,2); + std::copy(coords,coords+12,myCoords->getPointer()); + mesh->setCoords(myCoords); + myCoords->decrRef(); + return mesh; +} + +MEDCouplingUMesh *MEDLoaderTest::build2DMesh_1() +{ + double targetCoords[24]={-0.3,-0.3, 0.2,-0.3, 0.7,-0.3, -0.3,0.2, 0.2,0.2, 0.7,0.2, -0.3,0.7, 0.2,0.7, 0.7,0.7, -0.05,0.95, 0.2,1.2, 0.45,0.95 }; + int targetConn[24]={1,4,2, 4,5,2, 6,10,8,9,11,7, 0,3,4,1, 6,7,4,3, 7,8,5,4}; + MEDCouplingUMesh *targetMesh=MEDCouplingUMesh::New(); + targetMesh->setMeshDimension(2); + targetMesh->allocateCells(6); + targetMesh->setName("2DMesh_1"); + targetMesh->insertNextCell(INTERP_KERNEL::NORM_TRI3,3,targetConn); + targetMesh->insertNextCell(INTERP_KERNEL::NORM_TRI3,3,targetConn+3); + targetMesh->insertNextCell(INTERP_KERNEL::NORM_TRI6,6,targetConn+6); + targetMesh->insertNextCell(INTERP_KERNEL::NORM_QUAD4,4,targetConn+12); + targetMesh->insertNextCell(INTERP_KERNEL::NORM_QUAD4,4,targetConn+16); + targetMesh->insertNextCell(INTERP_KERNEL::NORM_POLYGON,4,targetConn+20); + targetMesh->finishInsertingCells(); + DataArrayDouble *myCoords=DataArrayDouble::New(); + myCoords->alloc(12,2); + myCoords->setInfoOnComponent(0,"tototototototot [m]"); + myCoords->setInfoOnComponent(1,"energie [kW]"); + std::copy(targetCoords,targetCoords+24,myCoords->getPointer()); + targetMesh->setCoords(myCoords); + myCoords->decrRef(); + return targetMesh; +} + +MEDCouplingUMesh *MEDLoaderTest::build2DMesh_2() +{ + double targetCoords[24]={ + -0.3,-0.3, 0.2,-0.3, 0.7,-0.3, -0.3,0.2, 0.2,0.2, 0.7,0.2, -0.3,0.7, 0.2,0.7, 0.7,0.7, + -0.05,0.95, 0.2,1.2, 0.45,0.95 + }; + int targetConn[24]={1,4,2, 4,5,2, 6,10,8,9,11,7, 0,3,4,1, 6,7,4,3, 7,8,5,4}; + MEDCouplingUMesh *targetMesh=MEDCouplingUMesh::New(); + targetMesh->setMeshDimension(2); + targetMesh->allocateCells(5); + targetMesh->setName("2DMesh_2"); + targetMesh->insertNextCell(INTERP_KERNEL::NORM_TRI3,3,targetConn); + targetMesh->insertNextCell(INTERP_KERNEL::NORM_TRI3,3,targetConn+3); + targetMesh->insertNextCell(INTERP_KERNEL::NORM_QUAD4,4,targetConn+12); + targetMesh->insertNextCell(INTERP_KERNEL::NORM_QUAD4,4,targetConn+16); + targetMesh->insertNextCell(INTERP_KERNEL::NORM_TRI6,6,targetConn+6); + targetMesh->finishInsertingCells(); + DataArrayDouble *myCoords=DataArrayDouble::New(); + myCoords->alloc(12,2); + myCoords->setInfoOnComponent(0,"toto [m]"); + myCoords->setInfoOnComponent(1,"energie [kW]"); + std::copy(targetCoords,targetCoords+24,myCoords->getPointer()); + targetMesh->setCoords(myCoords); + myCoords->decrRef(); + return targetMesh; +} + +MEDCouplingUMesh *MEDLoaderTest::build3DSurfMesh_1() +{ + double targetCoords[36]={ + -0.3,-0.3,-0.3, 0.2,-0.3,-0.3, 0.7,-0.3,-0.3, -0.3,0.2,-0.3, 0.2,0.2,-0.3, 0.7,0.2,-0.3, -0.3,0.7,-0.3, 0.2,0.7,-0.3, 0.7,0.7,-0.3 + ,-0.05,0.95,-0.3, 0.2,1.2,-0.3, 0.45,0.95,-0.3 + }; + int targetConn[24]={1,4,2, 4,5,2, 6,10,8,9,11,7, 0,3,4,1, 6,7,4,3, 7,8,5,4}; + MEDCouplingUMesh *targetMesh=MEDCouplingUMesh::New(); + targetMesh->setMeshDimension(2); + targetMesh->allocateCells(6); + targetMesh->setName("3DSurfMesh_1"); + targetMesh->insertNextCell(INTERP_KERNEL::NORM_TRI3,3,targetConn); + targetMesh->insertNextCell(INTERP_KERNEL::NORM_TRI3,3,targetConn+3); + targetMesh->insertNextCell(INTERP_KERNEL::NORM_QUAD4,4,targetConn+12); + targetMesh->insertNextCell(INTERP_KERNEL::NORM_QUAD4,4,targetConn+16); + targetMesh->insertNextCell(INTERP_KERNEL::NORM_TRI6,6,targetConn+6); + targetMesh->insertNextCell(INTERP_KERNEL::NORM_POLYGON,4,targetConn+20); + targetMesh->finishInsertingCells(); + DataArrayDouble *myCoords=DataArrayDouble::New(); + myCoords->alloc(12,3); + myCoords->setInfoOnComponent(0,"toto [m]"); + myCoords->setInfoOnComponent(2,"ff [km]");//component 1 is not set for test + std::copy(targetCoords,targetCoords+36,myCoords->getPointer()); + targetMesh->setCoords(myCoords); + myCoords->decrRef(); + return targetMesh; +} + +MEDCouplingUMesh *MEDLoaderTest::build3DMesh_1() +{ + double coords[180]={ + 0.,0.,0., 1.,1.,0., 1.,1.25,0., 0.,1.,0., 1.,1.5,0., 2.,0.,0., 2.,1.,0., 1.,2.,0., 0.,2.,0., 3.,1.,0., + 3.,2.,0., 0.,1.,0., 1.,3.,0., 2.,2.,0., 2.,3.,0., + 0.,0.,1., 1.,1.,1., 1.,1.25,1., 0.,1.,1., 1.,1.5,1., 2.,0.,1., 2.,1.,1., 1.,2.,1., 0.,2.,1., 3.,1.,1., + 3.,2.,1., 0.,1.,1., 1.,3.,1., 2.,2.,1., 2.,3.,1., + 0.,0.,2., 1.,1.,2., 1.,1.25,2., 0.,1.,2., 1.,1.5,2., 2.,0.,2., 2.,1.,2., 1.,2.,2., 0.,2.,2., 3.,1.,2., + 3.,2.,2., 0.,1.,2., 1.,3.,2., 2.,2.,2., 2.,3.,2., + 0.,0.,3., 1.,1.,3., 1.,1.25,3., 0.,1.,3., 1.,1.5,3., 2.,0.,3., 2.,1.,3., 1.,2.,3., 0.,2.,3., 3.,1.,3., + 3.,2.,3., 0.,1.,3., 1.,3.,3., 2.,2.,3., 2.,3.,3.}; + + int conn[354]={ + // 0 + 0,11,1,3,15,26,16,18, 1,2,4,7,13,6,-1,1,16,21,6,-1,6,21,28,13,-1,13,7,22,28,-1,7,4,19,22,-1,4,2,17,19,-1,2,1,16,17,-1,16,21,28,22,19,17, + 1,6,5,3,16,21,20,18, 13,10,9,6,28,25,24,21, + 11,8,7,4,2,1,-1,11,26,16,1,-1,1,16,17,2,-1,2,17,19,4,-1,4,19,22,7,-1,7,8,23,22,-1,8,11,26,23,-1,26,16,17,19,22,23, + 7,12,14,13,22,27,29,28, + // 1 + 15,26,16,18,30,41,31,33, 16,17,19,22,28,21,-1,16,31,36,21,-1,21,36,43,28,-1,28,22,37,43,-1,22,19,34,37,-1,19,17,32,34,-1,17,16,31,32,-1,31,36,43,37,34,32, + 16,21,20,18,31,36,35,33, 28,25,24,21,43,40,39,36, + 26,23,22,19,17,16,-1,26,41,31,16,-1,16,31,32,17,-1,17,32,34,19,-1,19,34,37,22,-1,22,23,38,37,-1,23,26,41,38,-1,41,31,32,34,37,38, + 22,27,29,28,37,42,44,43, + // 2 + 30,41,31,33,45,56,46,48, 31,32,34,37,43,36,-1,31,46,51,36,-1,36,51,58,43,-1,43,37,52,58,-1,37,34,49,52,-1,34,32,47,49,-1,32,31,46,47,-1,46,51,58,52,49,47, + 31,36,35,33,46,51,50,48, 43,40,39,36,58,55,54,51, + 41,38,37,34,32,31,-1,41,56,46,31,-1,31,46,47,32,-1,32,47,49,34,-1,34,49,52,37,-1,37,38,53,52,-1,38,41,56,53,-1,56,46,47,49,52,53, + 37,42,44,43,52,57,59,58 + }; + // + MEDCouplingUMesh *ret=MEDCouplingUMesh::New(); + ret->setName("3DMesh_1"); + ret->setMeshDimension(3); + ret->allocateCells(18); + // + ret->insertNextCell(INTERP_KERNEL::NORM_HEXA8,8,conn); + ret->insertNextCell(INTERP_KERNEL::NORM_HEXA8,8,conn+51); + ret->insertNextCell(INTERP_KERNEL::NORM_HEXA8,8,conn+59); + ret->insertNextCell(INTERP_KERNEL::NORM_HEXA8,8,conn+110); + // + ret->insertNextCell(INTERP_KERNEL::NORM_HEXA8,8,conn+118); + ret->insertNextCell(INTERP_KERNEL::NORM_HEXA8,8,conn+169); + ret->insertNextCell(INTERP_KERNEL::NORM_HEXA8,8,conn+177); + ret->insertNextCell(INTERP_KERNEL::NORM_HEXA8,8,conn+228); + // + ret->insertNextCell(INTERP_KERNEL::NORM_HEXA8,8,conn+236); + ret->insertNextCell(INTERP_KERNEL::NORM_HEXA8,8,conn+287); + ret->insertNextCell(INTERP_KERNEL::NORM_HEXA8,8,conn+295); + ret->insertNextCell(INTERP_KERNEL::NORM_HEXA8,8,conn+346); + // + ret->insertNextCell(INTERP_KERNEL::NORM_POLYHED,43,conn+8); + ret->insertNextCell(INTERP_KERNEL::NORM_POLYHED,43,conn+67); + ret->insertNextCell(INTERP_KERNEL::NORM_POLYHED,43,conn+126); + ret->insertNextCell(INTERP_KERNEL::NORM_POLYHED,43,conn+185); + ret->insertNextCell(INTERP_KERNEL::NORM_POLYHED,43,conn+244); + ret->insertNextCell(INTERP_KERNEL::NORM_POLYHED,43,conn+303); + // + ret->finishInsertingCells(); + DataArrayDouble *myCoords=DataArrayDouble::New(); + myCoords->alloc(60,3); + myCoords->setInfoOnComponent(0,"titi [m]"); + myCoords->setInfoOnComponent(1,"density power [MW/m^3]"); + myCoords->setInfoOnComponent(2,"t [kW]"); + std::copy(coords,coords+180,myCoords->getPointer()); + ret->setCoords(myCoords); + myCoords->decrRef(); + return ret; +} + +MEDCouplingUMesh *MEDLoaderTest::build3DMesh_2() +{ + MEDCouplingUMesh *m3dsurfBase=build3DSurfMesh_1(); + int numbers[5]={0,1,2,3,5}; + MEDCouplingUMesh *m3dsurf=(MEDCouplingUMesh *)m3dsurfBase->buildPartOfMySelf(numbers,numbers+5,false); + m3dsurfBase->decrRef(); + MEDCouplingUMesh *m1dBase=build1DMesh_1(); + int numbers2[4]={0,1,2,3}; + MEDCouplingUMesh *m1d=(MEDCouplingUMesh *)m1dBase->buildPartOfMySelf(numbers2,numbers2+4,false); + m1dBase->decrRef(); + m1d->changeSpaceDimension(3); + const double vec[3]={0.,1.,0.}; + const double pt[3]={0.,0.,0.}; + m1d->rotate(pt,vec,-M_PI/2.); + MEDCouplingUMesh *ret=m3dsurf->buildExtrudedMesh(m1d,0); + m1d->decrRef(); + m3dsurf->decrRef(); + return ret; +} + +MEDCouplingFieldDouble *MEDLoaderTest::buildVecFieldOnCells_1() +{ + MEDCouplingUMesh *mesh=build3DSurfMesh_1(); + int nbOfCells=mesh->getNumberOfCells(); + MEDCouplingFieldDouble *f1=MEDCouplingFieldDouble::New(ON_CELLS,ONE_TIME); + f1->setName("VectorFieldOnCells"); + f1->setMesh(mesh); + DataArrayDouble *array=DataArrayDouble::New(); + array->alloc(nbOfCells,3); + array->setInfoOnComponent(0,"power [MW/m^3]"); + array->setInfoOnComponent(1,"density [g/cm^3]"); + array->setInfoOnComponent(2,"temperature [K]"); + f1->setArray(array); + array->decrRef(); + double *tmp=array->getPointer(); + const double arr1[18]={0.,10.,20.,1.,11.,21.,2.,12.,22.,3.,13.,23.,4.,14.,24.,5.,15.,25.}; + std::copy(arr1,arr1+18,tmp); + f1->setTime(2.,0,1); + f1->checkCoherency(); + mesh->decrRef(); + return f1; +} + +MEDCouplingFieldDouble *MEDLoaderTest::buildVecFieldOnNodes_1() +{ + MEDCouplingUMesh *mesh=build3DSurfMesh_1(); + int nbOfNodes=mesh->getNumberOfNodes(); + MEDCouplingFieldDouble *f1=MEDCouplingFieldDouble::New(ON_NODES,ONE_TIME); + f1->setName("VectorFieldOnNodes"); + f1->setMesh(mesh); + DataArrayDouble *array=DataArrayDouble::New(); + array->alloc(nbOfNodes,3); + f1->setArray(array); + array->setInfoOnComponent(0,"power [MW/m^3]"); + array->setInfoOnComponent(1,"density [g/cm^3]"); + array->setInfoOnComponent(2,"temperature [K]"); + array->decrRef(); + double *tmp=array->getPointer(); + const double arr1[36]={ + 70.,80.,90.,71.,81.,91.,72.,82.,92.,73.,83.,93.,74.,84.,94.,75.,85.,95., + 1000.,10010.,10020.,1001.,10011.,10021.,1002.,10012.,10022.,1003.,10013.,10023.,1004.,10014.,10024.,1005.,10015.,10025., + }; + std::copy(arr1,arr1+36,tmp); + f1->setTime(2.12,2,3); + f1->checkCoherency(); + mesh->decrRef(); + return f1; +} + +MEDCouplingFieldDouble *MEDLoaderTest::buildVecFieldOnGauss_1() +{ + const double _a=0.446948490915965; + const double _b=0.091576213509771; + const double _p1=0.11169079483905; + const double _p2=0.0549758718227661; + const double refCoo1[6]={ 0.,0., 1.,0., 0.,1. }; + const double gsCoo1[12]={ 2*_b-1, 1-4*_b, 2*_b-1, 2.07*_b-1, 1-4*_b, + 2*_b-1, 1-4*_a, 2*_a-1, 2*_a-1, 1-4*_a, 2*_a-1, 2*_a-1 }; + const double wg1[6]={ 4*_p2, 4*_p2, 4*_p2, 4*_p1, 4*_p1, 4*_p1 }; + std::vector _refCoo1(refCoo1,refCoo1+6); + std::vector _gsCoo1(gsCoo1,gsCoo1+12); + std::vector _wg1(wg1,wg1+6); + MEDCouplingUMesh *m=build2DMesh_2(); + MEDCouplingFieldDouble *f=MEDCouplingFieldDouble::New(ON_GAUSS_PT,ONE_TIME); + f->setTime(3.14,1,5); + f->setMesh(m); + f->setGaussLocalizationOnType(INTERP_KERNEL::NORM_TRI3,_refCoo1,_gsCoo1,_wg1); + const double refCoo2[12]={-1.0,1.0, -1.0,-1.0, 1.0,-1.0, -1.0,0.0, 0.0,-1.0, 0.0,0.0 }; + std::vector _refCoo2(refCoo2,refCoo2+12); + std::vector _gsCoo2(_gsCoo1); + std::vector _wg2(_wg1); + _gsCoo2.resize(6); _wg2.resize(3); + const double refCoo3[8]={ 0.,0., 1.,0., 1.,1., 0.,1. }; + std::vector _refCoo3(refCoo3,refCoo3+8); + _gsCoo1.resize(4); _wg1.resize(2); + f->setGaussLocalizationOnType(INTERP_KERNEL::NORM_QUAD4,_refCoo3,_gsCoo1,_wg1); + f->setGaussLocalizationOnType(INTERP_KERNEL::NORM_TRI6,_refCoo2,_gsCoo2,_wg2); + DataArrayDouble *array=DataArrayDouble::New(); + array->alloc(19,2); + double *ptr=array->getPointer(); + for(int i=0;i<19*2;i++) + ptr[i]=(double)(i+7); + f->setArray(array); + f->setName("MyFirstFieldOnGaussPoint"); + array->setInfoOnComponent(0,"power [MW/m^3]"); + array->setInfoOnComponent(1,"density"); + array->decrRef(); + f->checkCoherency(); + m->decrRef(); + return f; +} + +MEDCouplingFieldDouble *MEDLoaderTest::buildVecFieldOnGaussNE_1() +{ + MEDCouplingUMesh *m=build2DMesh_2(); + MEDCouplingFieldDouble *f=MEDCouplingFieldDouble::New(ON_GAUSS_NE,ONE_TIME); + f->setTime(3.14,1,5); + f->setMesh(m); + DataArrayDouble *array=DataArrayDouble::New(); + array->alloc(20,2); + double *ptr=array->getPointer(); + for(int i=0;i<20*2;i++) + ptr[i]=(double)(i+8); + f->setArray(array); + array->setInfoOnComponent(0,"power [W]"); + array->setInfoOnComponent(1,"temperature"); + f->setName("MyFieldOnGaussNE"); + array->decrRef(); + f->checkCoherency(); + m->decrRef(); + return f; +} + ++ ++ diff --cc medtool/src/MEDLoader/Test/MEDLoaderTest.hxx index e0e842995,000000000..b42b3b3db mode 100644,000000..100644 --- a/medtool/src/MEDLoader/Test/MEDLoaderTest.hxx +++ b/medtool/src/MEDLoader/Test/MEDLoaderTest.hxx @@@ -1,95 -1,0 +1,107 @@@ +// Copyright (C) 2007-2015 CEA/DEN, EDF R&D +// +// 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +// +// See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com +// +// Author : Anthony Geay (CEA/DEN) + +#ifndef __MEDLOADERTEST_HXX__ +#define __MEDLOADERTEST_HXX__ + +#include + +namespace ParaMEDMEM +{ + class MEDCouplingUMesh; + class MEDCouplingFieldDouble; + + class MEDLoaderTest : public CppUnit::TestFixture + { + CPPUNIT_TEST_SUITE(MEDLoaderTest); + CPPUNIT_TEST( testMesh1DRW ); + CPPUNIT_TEST( testMesh2DCurveRW ); + CPPUNIT_TEST( testMesh2DRW ); + CPPUNIT_TEST( testMesh3DSurfRW ); + CPPUNIT_TEST( testMesh3DRW ); + CPPUNIT_TEST( testFieldRW1 ); + CPPUNIT_TEST( testFieldRW2 ); + CPPUNIT_TEST( testFieldRW3 ); + CPPUNIT_TEST( testMultiMeshRW1 ); + CPPUNIT_TEST( testFieldProfilRW1 ); + CPPUNIT_TEST( testFieldNodeProfilRW1 ); + CPPUNIT_TEST( testFieldNodeProfilRW2 ); + CPPUNIT_TEST( testFieldGaussRW1 ); + CPPUNIT_TEST( testFieldGaussNERW1 ); + CPPUNIT_TEST( testLittleStrings1 ); + CPPUNIT_TEST( testSplitIntoNameAndUnit1 ); + CPPUNIT_TEST( testMesh3DSurfShuffleRW ); + CPPUNIT_TEST( testFieldShuffleRW1 ); + CPPUNIT_TEST( testMultiFieldShuffleRW1 ); + CPPUNIT_TEST( testWriteUMeshesRW1 ); + CPPUNIT_TEST( testMixCellAndNodesFieldRW1 ); + CPPUNIT_TEST( testGetAllFieldNamesRW1 ); ++ ++ // Previously in ParaMEDMEM: ++ CPPUNIT_TEST(testMEDLoaderRead1); ++ CPPUNIT_TEST(testMEDLoaderPolygonRead); ++ CPPUNIT_TEST(testMEDLoaderPolyhedronRead); ++ + CPPUNIT_TEST_SUITE_END(); + public: + void testMesh1DRW(); + void testMesh2DCurveRW(); + void testMesh2DRW(); + void testMesh3DSurfRW(); + void testMesh3DRW(); + void testFieldRW1(); + void testFieldRW2(); + void testFieldRW3(); + void testMultiMeshRW1(); + void testFieldProfilRW1(); + void testFieldNodeProfilRW1(); + void testFieldNodeProfilRW2(); + void testFieldGaussRW1(); + void testFieldGaussNERW1(); + void testLittleStrings1(); + void testSplitIntoNameAndUnit1(); + void testMesh3DSurfShuffleRW(); + void testFieldShuffleRW1(); + void testMultiFieldShuffleRW1(); + void testWriteUMeshesRW1(); + void testMixCellAndNodesFieldRW1(); + void testGetAllFieldNamesRW1(); ++ ++ void testMEDLoaderRead1(); ++ void testMEDLoaderPolygonRead(); ++ void testMEDLoaderPolyhedronRead(); + private: + MEDCouplingUMesh *build1DMesh_1(); + MEDCouplingUMesh *build2DCurveMesh_1(); + MEDCouplingUMesh *build2DMesh_1(); + MEDCouplingUMesh *build2DMesh_2(); + MEDCouplingUMesh *build3DSurfMesh_1(); + MEDCouplingUMesh *build3DMesh_1(); + MEDCouplingUMesh *build3DMesh_2(); + MEDCouplingFieldDouble *buildVecFieldOnCells_1(); + MEDCouplingFieldDouble *buildVecFieldOnNodes_1(); + MEDCouplingFieldDouble *buildVecFieldOnGauss_1(); + MEDCouplingFieldDouble *buildVecFieldOnGaussNE_1(); ++ ++ std::string getResourceFile( const std::string& filename ) const; + }; +} + +#endif diff --cc medtool/src/ParaMEDMEM/BlockTopology.cxx index 8f6b4cea8,000000000..7297be21c mode 100644,000000..100644 --- a/medtool/src/ParaMEDMEM/BlockTopology.cxx +++ b/medtool/src/ParaMEDMEM/BlockTopology.cxx @@@ -1,336 -1,0 +1,345 @@@ +// Copyright (C) 2007-2015 CEA/DEN, EDF R&D +// +// 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +// +// See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com +// + +#include "BlockTopology.hxx" +#include "MEDCouplingMemArray.hxx" +#include "MEDCouplingCMesh.hxx" +#include "CommInterface.hxx" +#include "ProcessorGroup.hxx" +#include "MPIProcessorGroup.hxx" +#include "ComponentTopology.hxx" +#include "InterpKernelUtilities.hxx" + +#include +#include +#include +#include + +using namespace std; + +namespace ParaMEDMEM +{ - - //!converts a pair to a global number - std::pair BlockTopology::globalToLocal(const int global) const - { - int subdomain_id=0; - int position=global; - int size=_nb_elems; - int size_procs=_proc_group->size(); - int increment=size; - vectoraxis_position(_dimension); - vectoraxis_offset(_dimension); - for (int idim=0; idim<_dimension; idim++) - { - int axis_size=_local_array_indices[idim].size()-1; - int axis_nb_elem=_local_array_indices[idim][axis_size]; - increment=increment/axis_nb_elem; - int proc_increment = size_procs/(axis_size); - int axis_pos=position/increment; - position=position%increment; - int iaxis=1; - while (_local_array_indices[idim][iaxis]<=axis_pos) - { - subdomain_id+=proc_increment; - iaxis++; - } - axis_position[idim]=axis_pos-_local_array_indices[idim][iaxis-1]; - axis_offset[idim]=iaxis; - } - int local=0; - int local_increment=1; - for (int idim=_dimension-1; idim>=0; idim--) - { - local+=axis_position[idim]*local_increment; - local_increment*=_local_array_indices[idim][axis_offset[idim]]-_local_array_indices[idim][axis_offset[idim]-1]; - } - return make_pair(subdomain_id,local); - } - - //!converts local number to a global number - int BlockTopology::localToGlobal(const pair local) const - { - - int subdomain_id=local.first; - int global=0; - int loc=local.second; - int increment=_nb_elems; - int proc_increment=_proc_group->size(); - int local_increment=getNbLocalElements(); - for (int idim=0; idim < _dimension; idim++) - { - int axis_size=_local_array_indices[idim].size()-1; - int axis_nb_elem=_local_array_indices[idim][axis_size]; - increment=axis_nb_elem==0?0:increment/axis_nb_elem; - proc_increment = proc_increment/(axis_size); - int proc_axis=subdomain_id/proc_increment; - subdomain_id=subdomain_id%proc_increment; - int local_axis_nb_elem=_local_array_indices[idim][proc_axis+1]-_local_array_indices[idim][proc_axis]; - local_increment = (local_axis_nb_elem==0)?0:(local_increment/local_axis_nb_elem); - int iaxis=((local_increment==0)?0:(loc/local_increment))+_local_array_indices[idim][proc_axis]; - global+=increment*iaxis; - loc = (local_increment==0)?0:(loc%local_increment); - } - return global; - } - - //Retrieves the local number of elements - int BlockTopology::getNbLocalElements()const - { - int position=_proc_group->myRank(); - int nb_elem = 1; - int increment=1; - for (int i=_dimension-1; i>=0; i--) - { - increment *=_nb_procs_per_dim[i]; - int idim=position%increment; - position=position/increment; - int imin=_local_array_indices[i][idim]; - int imax=_local_array_indices[i][idim+1]; - nb_elem*=(imax-imin); - } - return nb_elem; - } ++ /*! ++ * Default ctor. ++ */ ++ BlockTopology::BlockTopology() : ++ _dimension(0), _nb_procs_per_dim(0), ++ _local_array_indices(0), _cycle_type(0), ++ _proc_group(NULL),_nb_elems(0), ++ _owns_processor_group(false) ++ {} + + /*! + * Constructor of a block topology from a grid. + * This preliminary version simply splits along the first axis + * instead of making the best choice with respect to the + * values of the different axes. + */ + BlockTopology::BlockTopology(const ProcessorGroup& group, MEDCouplingCMesh *grid): + _dimension(grid->getSpaceDimension()), _proc_group(&group), _owns_processor_group(false) + { + vector axis_length(_dimension); + _nb_elems=1; + for (int idim=0; idim <_dimension; idim++) + { + DataArrayDouble *arr=grid->getCoordsAt(idim); + axis_length[idim]=arr->getNbOfElems(); + _nb_elems*=axis_length[idim]; + } + //default splitting along 1st dimension + _local_array_indices.resize(_dimension); + _nb_procs_per_dim.resize(_dimension); + + _local_array_indices[0].resize(_proc_group->size()+1); + _local_array_indices[0][0]=0; + _nb_procs_per_dim[0]=_proc_group->size(); + + for (int i=1; i<=_proc_group->size(); i++) + { + _local_array_indices[0][i]=_local_array_indices[0][i-1]+ + axis_length[0]/_proc_group->size(); + if (i<= axis_length[0]%_proc_group->size()) + _local_array_indices[0][i]+=1; + } + for (int i=1; i<_dimension; i++) + { + _local_array_indices[i].resize(2); + _local_array_indices[i][0]=0; + _local_array_indices[i][1]=axis_length[i]; + _nb_procs_per_dim[i]=1; + } + _cycle_type.resize(_dimension); + for (int i=0; i<_dimension; i++) + _cycle_type[i]=ParaMEDMEM::Block; + } + + /*! + * Creation of a block topology by composing + * a geometrical topology and a component topology. + * This constructor is intended for creating fields + * for which the parallel distribution is made on the + * components of the field rather than on the geometrical + * partitioning of the underlying mesh. + * + */ + BlockTopology::BlockTopology(const BlockTopology& geom_topo, const ComponentTopology& comp_topo):_owns_processor_group(false) + { + // so far, the block topology can only be created if the proc group + // is either on geom_topo or on comp_topo + if (geom_topo.getProcGroup()->size()>1 && comp_topo.nbBlocks()>1) + throw INTERP_KERNEL::Exception(LOCALIZED("BlockTopology cannot yet be constructed with both complex geo and components topology")); + + if (comp_topo.nbComponents()==1) + { + *this=geom_topo; + return; + } + else + { + _dimension = geom_topo.getDimension()+1; + if (comp_topo.nbBlocks()>1) + _proc_group=comp_topo.getProcGroup(); + else + _proc_group=geom_topo.getProcGroup(); + _local_array_indices=geom_topo._local_array_indices; + vector comp_indices = *(comp_topo.getBlockIndices()); + _local_array_indices.push_back(comp_indices); + _nb_procs_per_dim=geom_topo._nb_procs_per_dim; + _nb_procs_per_dim.push_back(comp_topo.nbBlocks()); + _cycle_type=geom_topo._cycle_type; + _cycle_type.push_back(Block); + _nb_elems=geom_topo.getNbElements()*comp_topo.nbComponents(); + } + } + + /*! Constructor for creating a one-dimensional + * topology from a processor group and a local + * number of elements on each processor + * + * The function must be called only by the processors belonging + * to group \a group. Calling it from a processor not belonging + * to \a group will cause an MPI error, while calling from a subset + * of \a group will result in a deadlock. + */ + BlockTopology::BlockTopology(const ProcessorGroup& group, int nb_elem):_dimension(1),_proc_group(&group),_owns_processor_group(false) + { + int* nbelems_per_proc = new int[group.size()]; + const MPIProcessorGroup* mpi_group=dynamic_cast(_proc_group); + const MPI_Comm* comm=mpi_group->getComm(); + int nbtemp=nb_elem; + mpi_group->getCommInterface().allGather(&nbtemp, 1, MPI_INT, + nbelems_per_proc, 1, MPI_INT, + *comm); + _nb_elems=0; + + //splitting along only dimension + _local_array_indices.resize(1); + _nb_procs_per_dim.resize(1); + + _local_array_indices[0].resize(_proc_group->size()+1); + _local_array_indices[0][0]=0; + _nb_procs_per_dim[0]=_proc_group->size(); + + for (int i=1; i<=_proc_group->size(); i++) + { + _local_array_indices[0][i]=_local_array_indices[0][i-1]+ + nbelems_per_proc[i-1]; + _nb_elems+=nbelems_per_proc[i-1]; + } + _cycle_type.resize(1); + _cycle_type[0]=ParaMEDMEM::Block; + delete[] nbelems_per_proc; + } + + BlockTopology::~BlockTopology() + { + if (_owns_processor_group) + delete _proc_group; + } + ++ //!converts a pair to a global number ++ std::pair BlockTopology::globalToLocal(const int global) const ++ { ++ int subdomain_id=0; ++ int position=global; ++ int size=_nb_elems; ++ int size_procs=_proc_group->size(); ++ int increment=size; ++ vectoraxis_position(_dimension); ++ vectoraxis_offset(_dimension); ++ for (int idim=0; idim<_dimension; idim++) ++ { ++ int axis_size=_local_array_indices[idim].size()-1; ++ int axis_nb_elem=_local_array_indices[idim][axis_size]; ++ increment=increment/axis_nb_elem; ++ int proc_increment = size_procs/(axis_size); ++ int axis_pos=position/increment; ++ position=position%increment; ++ int iaxis=1; ++ while (_local_array_indices[idim][iaxis]<=axis_pos) ++ { ++ subdomain_id+=proc_increment; ++ iaxis++; ++ } ++ axis_position[idim]=axis_pos-_local_array_indices[idim][iaxis-1]; ++ axis_offset[idim]=iaxis; ++ } ++ int local=0; ++ int local_increment=1; ++ for (int idim=_dimension-1; idim>=0; idim--) ++ { ++ local+=axis_position[idim]*local_increment; ++ local_increment*=_local_array_indices[idim][axis_offset[idim]]-_local_array_indices[idim][axis_offset[idim]-1]; ++ } ++ return make_pair(subdomain_id,local); ++ } ++ ++ //!converts local number to a global number ++ int BlockTopology::localToGlobal(const pair local) const ++ { ++ ++ int subdomain_id=local.first; ++ int global=0; ++ int loc=local.second; ++ int increment=_nb_elems; ++ int proc_increment=_proc_group->size(); ++ int local_increment=getNbLocalElements(); ++ for (int idim=0; idim < _dimension; idim++) ++ { ++ int axis_size=_local_array_indices[idim].size()-1; ++ int axis_nb_elem=_local_array_indices[idim][axis_size]; ++ increment=axis_nb_elem==0?0:increment/axis_nb_elem; ++ proc_increment = proc_increment/(axis_size); ++ int proc_axis=subdomain_id/proc_increment; ++ subdomain_id=subdomain_id%proc_increment; ++ int local_axis_nb_elem=_local_array_indices[idim][proc_axis+1]-_local_array_indices[idim][proc_axis]; ++ local_increment = (local_axis_nb_elem==0)?0:(local_increment/local_axis_nb_elem); ++ int iaxis=((local_increment==0)?0:(loc/local_increment))+_local_array_indices[idim][proc_axis]; ++ global+=increment*iaxis; ++ loc = (local_increment==0)?0:(loc%local_increment); ++ } ++ return global; ++ } ++ ++ //Retrieves the local number of elements ++ int BlockTopology::getNbLocalElements()const ++ { ++ int position=_proc_group->myRank(); ++ int nb_elem = 1; ++ int increment=1; ++ for (int i=_dimension-1; i>=0; i--) ++ { ++ increment *=_nb_procs_per_dim[i]; ++ int idim=position%increment; ++ position=position/increment; ++ int imin=_local_array_indices[i][idim]; ++ int imax=_local_array_indices[i][idim+1]; ++ nb_elem*=(imax-imin); ++ } ++ return nb_elem; ++ } ++ + /*! Retrieves the min and max indices of the domain stored locally + * for each dimension. The output vector has the topology dimension + * as a size and each pair contains min and max. Indices + * range from min to max-1. + */ + std::vector > BlockTopology::getLocalArrayMinMax() const + { + vector > local_indices (_dimension); + int myrank=_proc_group->myRank(); + int increment=1; + for (int i=_dimension-1; i>=0; i--) + { + increment *=_nb_procs_per_dim[i]; + int idim=myrank%increment; + local_indices[i].first=_local_array_indices[i][idim]; + local_indices[i].second=_local_array_indices[i][idim+1]; + cout << local_indices[i].first << " "<< local_indices[i].second< buffer; + + buffer.push_back(_dimension); + buffer.push_back(_nb_elems); + for (int i=0; i<_dimension; i++) + { + buffer.push_back(_nb_procs_per_dim[i]); + buffer.push_back(_cycle_type[i]); + buffer.push_back(_local_array_indices[i].size()); + for (int j=0; j<(int)_local_array_indices[i].size(); j++) + buffer.push_back(_local_array_indices[i][j]); + } + + //serializing the comm group + int size_comm=_proc_group->size(); + buffer.push_back(size_comm); + MPIProcessorGroup world_group(_proc_group->getCommInterface()); + for (int i=0; i procs; + int size_comm=*(ptr_serializer++); + for (int i=0; i + +namespace ParaMEDMEM +{ + class ComponentTopology; + class MEDCouplingCMesh; + + typedef enum{Block,Cycle} CYCLE_TYPE; + ++ /*! ++ * \anchor BlockTopology-det ++ * ++ * A BlockTopology typically represents the split of a *structured* mesh among the processors of ++ * a common ProcessorGroup. Each processor gets a contiguous part of the cells in the mesh (a block). ++ * ++ * A BlockTopology can also be used to split a structured domain among the various components of a field. ++ * ++ * \sa ExplicitTopology ++ */ + class BlockTopology : public Topology + { + public: - BlockTopology() { } ++ BlockTopology(); + BlockTopology(const ProcessorGroup& group, MEDCouplingCMesh *grid); + BlockTopology(const BlockTopology& geom_topo, const ComponentTopology& comp_topo); + BlockTopology(const ProcessorGroup& group, int nb_elem); + virtual ~BlockTopology(); + //!Retrieves the number of elements for a given topology + int getNbElements()const { return _nb_elems; } + int getNbLocalElements() const; + const ProcessorGroup* getProcGroup()const { return _proc_group; } + std::pair globalToLocal (const int) const ; + int localToGlobal (const std::pair) const; + std::vector > getLocalArrayMinMax() const ; + int getDimension() const { return _dimension; } + void serialize(int* & serializer, int& size) const ; + void unserialize(const int* serializer, const CommInterface& comm_interface); + private: + //dimension : 2 or 3 + int _dimension; + //proc array + std::vector _nb_procs_per_dim; + //stores the offsets vector + std::vector > _local_array_indices; + //stores the cycle type (block or cyclic) + std::vector _cycle_type; + //Processor group + const ProcessorGroup* _proc_group; + //nb of elements + int _nb_elems; + bool _owns_processor_group; + }; +} + +#endif diff --cc medtool/src/ParaMEDMEM/CMakeLists.txt index a94cb3ede,000000000..cf0776595 mode 100644,000000..100644 --- a/medtool/src/ParaMEDMEM/CMakeLists.txt +++ b/medtool/src/ParaMEDMEM/CMakeLists.txt @@@ -1,71 -1,0 +1,72 @@@ +# Copyright (C) 2012-2015 CEA/DEN, EDF R&D +# +# 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +# +# See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com +# +# Author : Anthony Geay (CEA/DEN) + +ADD_DEFINITIONS(${MPI_DEFINITIONS}) + +INCLUDE_DIRECTORIES( + ${MPI_INCLUDE_DIRS} + ${CMAKE_CURRENT_SOURCE_DIR} + ${CMAKE_CURRENT_SOURCE_DIR}/../MEDCoupling + ${CMAKE_CURRENT_SOURCE_DIR}/../INTERP_KERNEL + ${CMAKE_CURRENT_SOURCE_DIR}/../INTERP_KERNEL/Bases + ${CMAKE_CURRENT_SOURCE_DIR}/../INTERP_KERNEL/Geometric2D + ${CMAKE_CURRENT_SOURCE_DIR}/../INTERP_KERNEL/ExprEval + ${CMAKE_CURRENT_SOURCE_DIR}/../INTERP_KERNEL/GaussPoints + ) + +SET(paramedmem_SOURCES + ProcessorGroup.cxx + MPIProcessorGroup.cxx + ParaMESH.cxx + ComponentTopology.cxx + MPIAccess.cxx + InterpolationMatrix.cxx + OverlapInterpolationMatrix.cxx + StructuredCoincidentDEC.cxx + ExplicitCoincidentDEC.cxx + InterpKernelDEC.cxx + ElementLocator.cxx + OverlapElementLocator.cxx + MPIAccessDEC.cxx + TimeInterpolator.cxx + LinearTimeInterpolator.cxx + DEC.cxx + DisjointDEC.cxx + OverlapDEC.cxx + ExplicitTopology.cxx + MxN_Mapping.cxx + OverlapMapping.cxx + ICoCoMEDField.cxx + ICoCoField.cxx + ParaFIELD.cxx + ParaGRID.cxx + BlockTopology.cxx ++ ExplicitMapping.cxx + ) + +ADD_LIBRARY(paramedmem SHARED ${paramedmem_SOURCES}) +TARGET_LINK_LIBRARIES(paramedmem medcoupling ${MPI_LIBRARIES}) +INSTALL(TARGETS paramedmem EXPORT ${PROJECT_NAME}TargetGroup DESTINATION ${MEDTOOL_INSTALL_LIBS}) + +FILE(GLOB paramedmem_HEADERS_HXX "${CMAKE_CURRENT_SOURCE_DIR}/*.hxx") +INSTALL(FILES ${paramedmem_HEADERS_HXX} DESTINATION ${MEDTOOL_INSTALL_HEADERS}) + +# To allow usage as SWIG dependencies: +SET(paramedmem_HEADERS_HXX PARENT_SCOPE) diff --cc medtool/src/ParaMEDMEM/CommInterface.cxx index 948f099d8,000000000..54e06e6fc mode 100644,000000..100644 --- a/medtool/src/ParaMEDMEM/CommInterface.cxx +++ b/medtool/src/ParaMEDMEM/CommInterface.cxx @@@ -1,66 -1,0 +1,66 @@@ +// Copyright (C) 2007-2015 CEA/DEN, EDF R&D +// +// 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +// +// See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com +// + +#include "CommInterface.hxx" + +namespace ParaMEDMEM +{ + /*! \anchor CommInterface-det + \class CommInterface + + The class \a CommInterface is the gateway to the MPI library. ++ It is a wrapper around all MPI calls, thus trying to abstract the rest of the code from using the direct MPI API ++ (but this is not strictly respected overall in practice ...). It is used in all ++ the \ref parallel "DEC related classes". + - It is a helper class that gathers the calls to the MPI - library that are made in the %ParaMEDMEM library. This gathering - allows easier gathering of information about the communication - in the library. - - It is typically called after the MPI_Init() call in a program. It is afterwards passed as a parameter to the constructors of %ParaMEDMEM objects so that they access the MPI library via the CommInterface. ++ It is typically instanciated after the MPI_Init() call in a program and is afterwards passed as a ++ parameter to the constructors of various \ref parallel "parallel objects" so that they access the ++ MPI library via this common interface. + + As an example, the following code excerpt initializes a processor group made of the zero processor. + + \verbatim + #include "CommInterface.hxx" + #include "ProcessorGroup.hxx" + + int main(int argc, char** argv) + { + //initialization + MPI_Init(&argc, &argv); + ParaMEDMEM::CommInterface comm_interface; + + //setting up a processor group with proc 0 + set procs; + procs.insert(0); + ParaMEDMEM::ProcessorGroup group(procs, comm_interface); + + //cleanup + MPI_Finalize(); + } + \endverbatim + */ + + CommInterface::CommInterface() + { + } + + CommInterface::~CommInterface() + { + } +} diff --cc medtool/src/ParaMEDMEM/ComponentTopology.hxx index de11e3efe,000000000..9b84607a3 mode 100644,000000..100644 --- a/medtool/src/ParaMEDMEM/ComponentTopology.hxx +++ b/medtool/src/ParaMEDMEM/ComponentTopology.hxx @@@ -1,56 -1,0 +1,64 @@@ +// Copyright (C) 2007-2015 CEA/DEN, EDF R&D +// +// 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +// +// See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com +// + +#ifndef __COMPONENTTOPOLOGY_HXX__ +#define __COMPONENTTOPOLOGY_HXX__ + +#include "Topology.hxx" + +#include + +namespace ParaMEDMEM +{ + class ProcessorGroup; + ++ /*! ++ * \anchor ComponentTopology-det ++ * ++ * The ComponentTopology can be used when building a ParaFIELD. It allows the splitting of the components ++ * of the field among different processors within a single processor group. ++ * ++ * \sa ParaFIELD::ParaFIELD(TypeOfField , TypeOfTimeDiscretization , ParaMESH* , const ComponentTopology& ) ++ */ + class ComponentTopology + { + public: + ComponentTopology(int nb_comp, ProcessorGroup* group); + ComponentTopology(int nb_comp, int nb_blocks); + ComponentTopology(int nb_comp); + ComponentTopology(); + virtual ~ComponentTopology(); + //!returns the number of MED components in the topology + int nbComponents() const { return _component_array.back(); } + //!returns the number of MED components on local processor + int nbLocalComponents() const ; + //!returns the number of the first MED component on local processor + int firstLocalComponent() const ; + //!returns the number of blocks in the topology + int nbBlocks()const {return _component_array.size()-1;} + //!returns the block structure + const std::vector* getBlockIndices() const { return &_component_array; } + const ProcessorGroup* getProcGroup()const { return _proc_group; } + private: + std::vector _component_array; + ProcessorGroup* _proc_group; + }; +} + +#endif /*COMPONENTTOPOLOGY_HXX_*/ diff --cc medtool/src/ParaMEDMEM/DEC.hxx index 1b0a8675f,000000000..6df677bbc mode 100644,000000..100644 --- a/medtool/src/ParaMEDMEM/DEC.hxx +++ b/medtool/src/ParaMEDMEM/DEC.hxx @@@ -1,43 -1,0 +1,52 @@@ +// Copyright (C) 2007-2015 CEA/DEN, EDF R&D +// +// 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +// +// See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com +// + +#ifndef __DEC_HXX__ +#define __DEC_HXX__ + +#include "MEDCouplingFieldDouble.hxx" +#include "NormalizedUnstructuredMesh.hxx" +#include "DECOptions.hxx" + +namespace ParaMEDMEM +{ + class CommInterface; ++ ++ /*! ++ * DEC stands for Data Exchange Channel. See the page \ref para-dec for more on this. ++ * ++ * This class is purely abstract. See the derivations: ++ * - \ref DisjointDEC-det "DisjointDEC" ++ * - \ref NonCoincidentDEC "NonCoincidentDEC" ++ * - \ref OverlapDEC "OverlapDEC" ++ */ + class DEC : public DECOptions + { + public: + DEC(); + void copyFrom(const DEC& other); + virtual void synchronize() = 0; + virtual void sendRecvData(bool way=true) = 0; + virtual ~DEC(); + protected: + const CommInterface* _comm_interface; + }; +} + +#endif diff --cc medtool/src/ParaMEDMEM/DECOptions.hxx index 5572ffdca,000000000..eb9271237 mode 100644,000000..100644 --- a/medtool/src/ParaMEDMEM/DECOptions.hxx +++ b/medtool/src/ParaMEDMEM/DECOptions.hxx @@@ -1,74 -1,0 +1,129 @@@ +// Copyright (C) 2007-2015 CEA/DEN, EDF R&D +// +// 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +// +// See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com +// + +#ifndef __DECOPTIONS_HXX__ +#define __DECOPTIONS_HXX__ + +#include + +namespace ParaMEDMEM +{ - //Enum describing the allToAll method used in the communication pattern ++ //! Enum describing the allToAll method used in the communication pattern + typedef enum { Native, PointToPoint } AllToAllMethod; ++ //! Enum describing the time interpolation method + typedef enum { WithoutTimeInterp, LinearTimeInterp } TimeInterpolationMethod; + ++ /*! ++ This class groups the various options accepted by all \ref para-dec "DECs" (which all inherit from %DECOptions). ++ ++ The following code excerpt shows how to set options on a %DEC : ++ ++ \code ++ InterpKernelDEC dec(source_group,target_group); ++ dec.setForcedRenormalization(true); ++ dec.attachLocalField(field); ++ dec.synchronize(); ++ if (source_group.containsMyRank()) ++ dec.sendData(); ++ else ++ dec.recvData(); ++ \endcode ++ * ++ * ++ */ + class DECOptions + { + protected: + std::string _method; + bool _asynchronous; + TimeInterpolationMethod _timeInterpolationMethod; + AllToAllMethod _allToAllMethod; + bool _forcedRenormalization; + public: + DECOptions():_method("P0"), + _asynchronous(false), + _timeInterpolationMethod(WithoutTimeInterp), + _allToAllMethod(Native), + _forcedRenormalization(false) + { + } + + DECOptions(const DECOptions& deco) + { + _method=deco._method; + _timeInterpolationMethod=deco._timeInterpolationMethod; + _asynchronous=deco._asynchronous; + _forcedRenormalization=deco._forcedRenormalization; + _allToAllMethod=deco._allToAllMethod; + } + ++ ++ /*! ++ * \sa setMethod() ++ */ + const std::string& getMethod() const { return _method; } ++ /*! ++ * Set interpolation method. Defaults to "P0". ++ */ + void setMethod(const char *m) { _method=m; } + ++ /*! ++ * \sa setTimeInterpolationMethod() ++ */ + TimeInterpolationMethod getTimeInterpolationMethod() const { return DECOptions::_timeInterpolationMethod; } ++ /*! ++ * Set time interpolation method. Default to WithoutTimeInterp. ++ */ + void setTimeInterpolationMethod(TimeInterpolationMethod it) { DECOptions::_timeInterpolationMethod=it; } + ++ /*! ++ * \sa setForcedRenormalization() ++ */ + bool getForcedRenormalization() const { return DECOptions::_forcedRenormalization; } ++ ++ /*! ++ * Force renormalization of the field after it has been received so that the total sum ++ * of the field values are the same on both the sending and the receiving side. Defaults to ++ * false. ++ */ + void setForcedRenormalization( bool dr) { DECOptions::_forcedRenormalization = dr; } + ++ ++ /*! ++ * \sa setAsynchronous() ++ */ + bool getAsynchronous() const { return DECOptions::_asynchronous; } ++ ++ /*! ++ * Switch to asynchronous data transfer mode. Default is false. ++ */ + void setAsynchronous( bool dr) { DECOptions::_asynchronous = dr; } + ++ /*! ++ * \sa setAllToAllMethod() ++ */ + AllToAllMethod getAllToAllMethod() const { return _allToAllMethod; } ++ /*! ++ * Set the broadcast method for synchronisation processes. Default to Native. ++ */ + void setAllToAllMethod(AllToAllMethod sp) { _allToAllMethod=sp; } + }; +} + +#endif diff --cc medtool/src/ParaMEDMEM/DisjointDEC.cxx index 57e67fd2c,000000000..b2ba8f795 mode 100644,000000..100644 --- a/medtool/src/ParaMEDMEM/DisjointDEC.cxx +++ b/medtool/src/ParaMEDMEM/DisjointDEC.cxx @@@ -1,403 -1,0 +1,395 @@@ +// Copyright (C) 2007-2015 CEA/DEN, EDF R&D +// +// 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +// +// See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com +// + +#include "DisjointDEC.hxx" +#include "CommInterface.hxx" +#include "Topology.hxx" +#include "BlockTopology.hxx" +#include "ComponentTopology.hxx" +#include "ParaFIELD.hxx" +#include "ParaMESH.hxx" +#include "ICoCoField.hxx" +#include "ICoCoMEDField.hxx" +#include "MPIProcessorGroup.hxx" + +#include +#include + + +namespace ParaMEDMEM +{ + + /*! + * \anchor DisjointDEC-det + * \class DisjointDEC + * - * Interface class for creation of a link between two - * processor groups for exhanging mesh or field data. - * The \c DEC is defined by attaching a field on the receiving or on the ++ * \section DisjointDEC-over Overview ++ * ++ * Abstract interface class representing a link between two ++ * processor groups for exchanging mesh or field data. The two processor groups must ++ * have a void intersection (\ref ParaMEDMEM::OverlapDEC "OverlapDEC" is to be considered otherwise). ++ * The %DEC is initialized by attaching a field on the receiving or on the + * sending side. - * On top of attaching a \c ParaMEDMEM::ParaFIELD, it is possible to - * attach a ICoCo::Field. This class is an abstract class that enables - * coupling of codes that respect the ICoCo interface \ref icoco. It has two implementations: - * one for codes that express their fields as \ref fields "MEDCoupling fields" (ICoCo::MEDField). + * - * \section dec_options DEC Options - * Options supported by \c DEC objects are ++ * The data is sent or received through calls to the (abstract) methods recvData() and sendData(). ++ * ++ * One can attach either a \c ParaMEDMEM::ParaFIELD, or a ++ * \c ICoCo::Field, or directly a \c ParaMEDMEM::MEDCouplingFieldDouble instance. ++ * See the various signatures of the method DisjointDEC::attachLocalField() ++ * ++ * The derivations of this class should be considered for practical instanciation: ++ * - \ref InterpKernelDEC-det "InterpKernelDEC" ++ * - \ref ExplicitCoincidentDEC-det "ExplicitCoincidentDEC" ++ * - \ref StructuredCoincidentDEC-det "StructuredCoincidentDEC" ++ * ++ * \section DisjointDEC-options DisjointDEC options ++ * The options supported by %DisjointDEC objects are the same that the ones supported for all ++ * DECs in general and are all inherited from the class \ref ParaMEDMEM::DECOptions "DECOptions" + * - * - * - * - *
OptionDescriptionDefault value
ForcedRenormalizationAfter receiving data, the target field is renormalized so that L2-norms of the source and target fields match. false
- - - The following code excerpt shows how to set options for an object that inherits from \c DEC : - - \code - InterpKernelDEC dec(source_group,target_group); - dec.setOptions("ForcedRenormalization",true); - dec.attachLocalField(field); - dec.synchronize(); - if (source_group.containsMyRank()) - dec.sendData(); - else - dec.recvData(); - \endcode + */ + - + DisjointDEC::DisjointDEC(ProcessorGroup& source_group, ProcessorGroup& target_group): + _local_field(0), + _source_group(&source_group), + _target_group(&target_group), + _comm_interface(0), + _owns_field(false), + _owns_groups(false), + _union_comm(MPI_COMM_NULL) + { + _union_group = source_group.fuse(target_group); + } + + DisjointDEC::DisjointDEC(const DisjointDEC& s): + DEC(s), + _local_field(0), + _union_group(0), + _source_group(0), + _target_group(0), + _comm_interface(0), + _owns_field(false), + _owns_groups(false), + _union_comm(MPI_COMM_NULL) + { + copyInstance(s); + } + + DisjointDEC & DisjointDEC::operator=(const DisjointDEC& s) + { + cleanInstance(); + copyInstance(s); + return *this; + + } + + void DisjointDEC::copyInstance(const DisjointDEC& other) + { + DEC::copyFrom(other); + if(other._target_group) + { + _target_group=other._target_group->deepCpy(); + _owns_groups=true; + } + if(other._source_group) + { + _source_group=other._source_group->deepCpy(); + _owns_groups=true; + } + if (_source_group && _target_group) + _union_group = _source_group->fuse(*_target_group); + } + + DisjointDEC::DisjointDEC(const std::set& source_ids, + const std::set& target_ids, + const MPI_Comm& world_comm): + _local_field(0), + _owns_field(false), + _owns_groups(true), + _comm_interface(0), + _union_comm(MPI_COMM_NULL) + { + ParaMEDMEM::CommInterface comm; + // Create the list of procs including source and target + std::set union_ids; // source and target ids in world_comm + union_ids.insert(source_ids.begin(),source_ids.end()); + union_ids.insert(target_ids.begin(),target_ids.end()); + if(union_ids.size()!=(source_ids.size()+target_ids.size())) - throw INTERP_KERNEL::Exception("DisjointDEC constructor : source_ids and target_ids overlap partially or fully. This type of DEC does not support it ! OverlapDEC class could be the solution !"); ++ throw INTERP_KERNEL::Exception("DisjointDEC constructor : source_ids and target_ids overlap partially or fully. This type of DEC does not support it! OverlapDEC class could be the solution!"); + int* union_ranks_world=new int[union_ids.size()]; // ranks of sources and targets in world_comm + std::copy(union_ids.begin(), union_ids.end(), union_ranks_world); + + // Create a communicator on these procs + MPI_Group union_group,world_group; + comm.commGroup(world_comm,&world_group); + comm.groupIncl(world_group,union_ids.size(),union_ranks_world,&union_group); + comm.commCreate(world_comm,union_group,&_union_comm); + delete[] union_ranks_world; + if (_union_comm==MPI_COMM_NULL) + { // This process is not in union + _source_group=0; + _target_group=0; + _union_group=0; + comm.groupFree(&union_group); + comm.groupFree(&world_group); + return; + } + + // Translate source_ids and target_ids from world_comm to union_comm + int* source_ranks_world=new int[source_ids.size()]; // ranks of sources in world_comm + std::copy(source_ids.begin(), source_ids.end(),source_ranks_world); + int* source_ranks_union=new int[source_ids.size()]; // ranks of sources in union_comm + int* target_ranks_world=new int[target_ids.size()]; // ranks of targets in world_comm + std::copy(target_ids.begin(), target_ids.end(),target_ranks_world); + int* target_ranks_union=new int[target_ids.size()]; // ranks of targets in union_comm + MPI_Group_translate_ranks(world_group,source_ids.size(),source_ranks_world,union_group,source_ranks_union); + MPI_Group_translate_ranks(world_group,target_ids.size(),target_ranks_world,union_group,target_ranks_union); + std::set source_ids_union; + for (int i=0;i<(int)source_ids.size();i++) + source_ids_union.insert(source_ranks_union[i]); + std::set target_ids_union; + for (int i=0;i<(int)target_ids.size();i++) + target_ids_union.insert(target_ranks_union[i]); + delete [] source_ranks_world; + delete [] source_ranks_union; + delete [] target_ranks_world; + delete [] target_ranks_union; + + // Create the MPIProcessorGroups + _source_group = new MPIProcessorGroup(comm,source_ids_union,_union_comm); + _target_group = new MPIProcessorGroup(comm,target_ids_union,_union_comm); + _union_group = _source_group->fuse(*_target_group); + comm.groupFree(&union_group); + comm.groupFree(&world_group); + } + + DisjointDEC::~DisjointDEC() + { + cleanInstance(); + } + + void DisjointDEC::cleanInstance() + { + if(_owns_field) + { + delete _local_field; + } + _local_field=0; + _owns_field=false; + if(_owns_groups) + { + delete _source_group; + delete _target_group; + } + _owns_groups=false; + _source_group=0; + _target_group=0; + delete _union_group; + _union_group=0; + if (_union_comm != MPI_COMM_NULL) + _comm_interface->commFree(&_union_comm); + } + + void DisjointDEC::setNature(NatureOfField nature) + { + if(_local_field) + _local_field->getField()->setNature(nature); + } + + /*! Attaches a local field to a DEC. + If the processor is on the receiving end of the DEC, the field + will be updated by a recvData() call. + Reversely, if the processor is on the sending end, the field will be read, possibly transformed, and sent appropriately to the other side. + */ + void DisjointDEC::attachLocalField(const ParaFIELD *field, bool ownPt) + { + if(!isInUnion()) + return ; + if(_owns_field) + delete _local_field; + _local_field=field; + _owns_field=ownPt; + _comm_interface=&(field->getTopology()->getProcGroup()->getCommInterface()); + compareFieldAndMethod(); + } + + /*! Attaches a local field to a DEC. The method will test whether the processor + is on the source or the target side and will associate the mesh underlying the + field to the local side. + + If the processor is on the receiving end of the DEC, the field + will be updated by a recvData() call. + Reversely, if the processor is on the sending end, the field will be read, possibly transformed, + and sent appropriately to the other side. + */ + + void DisjointDEC::attachLocalField(MEDCouplingFieldDouble *field) + { + if(!isInUnion()) + return ; + ProcessorGroup* local_group; + if (_source_group->containsMyRank()) + local_group=_source_group; + else if (_target_group->containsMyRank()) + local_group=_target_group; + else + throw INTERP_KERNEL::Exception("Invalid procgroup for field attachment to DEC"); + ParaMESH *paramesh=new ParaMESH(static_cast(const_cast(field->getMesh())),*local_group,field->getMesh()->getName()); + ParaFIELD *tmp=new ParaFIELD(field, paramesh, *local_group); + tmp->setOwnSupport(true); + attachLocalField(tmp,true); + //_comm_interface=&(local_group->getCommInterface()); + } + + /*! + Attaches a local field to a DEC. + If the processor is on the receiving end of the DEC, the field + will be updated by a recvData() call. + Reversely, if the processor is on the sending end, the field will be read, possibly transformed, and sent appropriately to the other side. + The field type is a generic ICoCo Field, so that the DEC can couple a number of different fields : + - a ICoCo::MEDField, that is created from a MEDCoupling structure + + */ + void DisjointDEC::attachLocalField(const ICoCo::MEDField *field) + { + if(!isInUnion()) + return ; + if(!field) + throw INTERP_KERNEL::Exception("DisjointDEC::attachLocalField : ICoCo::MEDField pointer is NULL !"); + attachLocalField(field->getField()); + } + + /*! + Computes the field norm over its support + on the source side and renormalizes the field on the target side + so that the norms match. + + \f[ + I_{source}=\sum_{i=1}^{n_{source}}V_{i}.|\Phi^{source}_{i}|^2, + \f] + + \f[ + I_{target}=\sum_{i=1}^{n_{target}}V_{i}.|\Phi^{target}_{i}|^2, + \f] + + \f[ + \Phi^{target}:=\Phi^{target}.\sqrt{I_{source}/I_{target}}. + \f] + + */ + void DisjointDEC::renormalizeTargetField(bool isWAbs) + { + if (_source_group->containsMyRank()) + for (int icomp=0; icomp<_local_field->getField()->getArray()->getNumberOfComponents(); icomp++) + { + double total_norm = _local_field->getVolumeIntegral(icomp+1,isWAbs); + double source_norm = total_norm; + _comm_interface->broadcast(&source_norm, 1, MPI_DOUBLE, 0,* dynamic_cast(_union_group)->getComm()); + + } + if (_target_group->containsMyRank()) + { + for (int icomp=0; icomp<_local_field->getField()->getArray()->getNumberOfComponents(); icomp++) + { + double total_norm = _local_field->getVolumeIntegral(icomp+1,isWAbs); + double source_norm=total_norm; + _comm_interface->broadcast(&source_norm, 1, MPI_DOUBLE, 0,* dynamic_cast(_union_group)->getComm()); + + if (fabs(total_norm)>1e-100) + _local_field->getField()->applyLin(source_norm/total_norm,0.0,icomp+1); + } + } + } + + bool DisjointDEC::isInSourceSide() const + { + if(!_source_group) + return false; + return _source_group->containsMyRank(); + } + + bool DisjointDEC::isInTargetSide() const + { + if(!_target_group) + return false; + return _target_group->containsMyRank(); + } + + bool DisjointDEC::isInUnion() const + { + if(!_union_group) + return false; + return _union_group->containsMyRank(); + } + + void DisjointDEC::compareFieldAndMethod() const throw(INTERP_KERNEL::Exception) + { + if (_local_field) + { + TypeOfField entity = _local_field->getField()->getTypeOfField(); + if ( getMethod() == "P0" ) + { + if ( entity != ON_CELLS ) + throw INTERP_KERNEL::Exception("Field support and interpolation method mismatch." + " For P0 interpolation, field must be on MED_CELL's"); + } + else if ( getMethod() == "P1" ) + { + if ( entity != ON_NODES ) + throw INTERP_KERNEL::Exception("Field support and interpolation method mismatch." + " For P1 interpolation, field must be on MED_NODE's"); + } + else if ( getMethod() == "P1d" ) + { + if ( entity != ON_CELLS ) + throw INTERP_KERNEL::Exception("Field support and interpolation method mismatch." + " For P1d interpolation, field must be on MED_CELL's"); + if ( _target_group->containsMyRank() ) + throw INTERP_KERNEL::Exception("Projection to P1d field not supported"); + } + else + { + throw INTERP_KERNEL::Exception("Unknown interpolation method. Possible methods: P0, P1, P1d"); + } + } + } + + /*! + If way==true, source procs call sendData() and target procs call recvData(). + if way==false, it's the other way round. + */ + void DisjointDEC::sendRecvData(bool way) + { + if(!isInUnion()) + return; + if(isInSourceSide()) + { + if(way) + sendData(); + else + recvData(); + } + else if(isInTargetSide()) + { + if(way) + recvData(); + else + sendData(); + } + } +} diff --cc medtool/src/ParaMEDMEM/DisjointDEC.hxx index aec6bb901,000000000..a4073a292 mode 100644,000000..100644 --- a/medtool/src/ParaMEDMEM/DisjointDEC.hxx +++ b/medtool/src/ParaMEDMEM/DisjointDEC.hxx @@@ -1,90 -1,0 +1,91 @@@ +// Copyright (C) 2007-2015 CEA/DEN, EDF R&D +// +// 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +// +// See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com +// + +#ifndef __DISJOINTDEC_HXX__ +#define __DISJOINTDEC_HXX__ + +#include "MEDCouplingFieldDouble.hxx" +#include "NormalizedUnstructuredMesh.hxx" +#include "DEC.hxx" + +#include +#include + +namespace ICoCo +{ + class MEDField; +} + +namespace ParaMEDMEM +{ + class ProcessorGroup; + class ParaFIELD; + + class DisjointDEC : public DEC + { + public: + DisjointDEC():_local_field(0),_union_group(0),_source_group(0),_target_group(0), - _owns_field(false),_owns_groups(false), - _comm_interface(0), _union_comm(MPI_COMM_NULL) ++ _comm_interface(0), ++ _owns_field(false),_owns_groups(false), ++ _union_comm(MPI_COMM_NULL) + { } + DisjointDEC(ProcessorGroup& source_group, ProcessorGroup& target_group); + DisjointDEC(const DisjointDEC&); + DisjointDEC &operator=(const DisjointDEC& s); + DisjointDEC(const std::set& src_ids, const std::set& trg_ids, + const MPI_Comm& world_comm=MPI_COMM_WORLD); + void setNature(NatureOfField nature); + void attachLocalField( MEDCouplingFieldDouble *field); + void attachLocalField(const ParaFIELD *field, bool ownPt=false); + void attachLocalField(const ICoCo::MEDField *field); + + virtual void prepareSourceDE() = 0; + virtual void prepareTargetDE() = 0; + virtual void recvData() = 0; + virtual void sendData() = 0; + void sendRecvData(bool way=true); + virtual void synchronize() = 0; + virtual ~DisjointDEC(); + virtual void computeProcGroup() { } + void renormalizeTargetField(bool isWAbs); + // + ProcessorGroup *getSourceGrp() const { return _source_group; } + ProcessorGroup *getTargetGrp() const { return _target_group; } + bool isInSourceSide() const; + bool isInTargetSide() const; + bool isInUnion() const; + protected: + void compareFieldAndMethod() const throw(INTERP_KERNEL::Exception); + void cleanInstance(); + void copyInstance(const DisjointDEC& other); + protected: + const ParaFIELD* _local_field; + //! Processor group representing the union of target and source processors + ProcessorGroup* _union_group; + ProcessorGroup* _source_group; + ProcessorGroup* _target_group; + + const CommInterface* _comm_interface; + bool _owns_field; + bool _owns_groups; + MPI_Comm _union_comm; + }; +} + +#endif diff --cc medtool/src/ParaMEDMEM/ElementLocator.cxx index a7fcfc28e,000000000..74e27545a mode 100644,000000..100644 --- a/medtool/src/ParaMEDMEM/ElementLocator.cxx +++ b/medtool/src/ParaMEDMEM/ElementLocator.cxx @@@ -1,718 -1,0 +1,720 @@@ +// Copyright (C) 2007-2015 CEA/DEN, EDF R&D +// +// 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +// +// See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com +// + +#include +#include "CommInterface.hxx" +#include "ElementLocator.hxx" +#include "Topology.hxx" +#include "BlockTopology.hxx" +#include "ParaFIELD.hxx" +#include "ParaMESH.hxx" +#include "ProcessorGroup.hxx" +#include "MPIProcessorGroup.hxx" +#include "MEDCouplingFieldDouble.hxx" +#include "MEDCouplingAutoRefCountObjectPtr.hxx" +#include "DirectedBoundingBox.hxx" + +#include +#include +#include + +using namespace std; + +//#define USE_DIRECTED_BB + +namespace ParaMEDMEM +{ + ElementLocator::ElementLocator(const ParaFIELD& sourceField, + const ProcessorGroup& distant_group, + const ProcessorGroup& local_group) + : _local_para_field(sourceField), + _local_cell_mesh(sourceField.getSupport()->getCellMesh()), + _local_face_mesh(sourceField.getSupport()->getFaceMesh()), + _distant_group(distant_group), + _local_group(local_group) + { + _union_group = _local_group.fuse(distant_group); + _computeBoundingBoxes(); + _comm=getCommunicator(); + } + + ElementLocator::~ElementLocator() + { + delete _union_group; + delete [] _domain_bounding_boxes; + } + + const MPI_Comm *ElementLocator::getCommunicator() const + { + MPIProcessorGroup* group=static_cast (_union_group); + return group->getComm(); + } + + NatureOfField ElementLocator::getLocalNature() const + { + return _local_para_field.getField()->getNature(); + } + - // ========================================================================== - // Procedure for exchanging mesh between a distant proc and a local processor - // param idistantrank proc id on distant group - // param distant_mesh on return , points to a local reconstruction of - // the distant mesh - // param distant_ids on return, contains a vector defining a correspondence - // between the distant ids and the ids of the local reconstruction - // ========================================================================== ++ ++ /*! Procedure for exchanging a mesh between a distant proc and a local processor ++ \param idistantrank proc id on distant group ++ \param distant_mesh on return , points to a local reconstruction of ++ the distant mesh ++ \param distant_ids on return, contains a vector defining a correspondence ++ between the distant ids and the ids of the local reconstruction ++ */ + void ElementLocator::exchangeMesh(int idistantrank, + MEDCouplingPointSet*& distant_mesh, + int*& distant_ids) + { + int rank = _union_group->translateRank(&_distant_group,idistantrank); + + if (find(_distant_proc_ids.begin(), _distant_proc_ids.end(),rank)==_distant_proc_ids.end()) + return; + + MEDCouplingAutoRefCountObjectPtr elems; +#ifdef USE_DIRECTED_BB + INTERP_KERNEL::DirectedBoundingBox dbb; + double* distant_bb = _domain_bounding_boxes+rank*dbb.dataSize(_local_cell_mesh_space_dim); + dbb.setData(distant_bb); + elems=_local_cell_mesh->getCellsInBoundingBox(dbb,getBoundingBoxAdjustment()); +#else + double* distant_bb = _domain_bounding_boxes+rank*2*_local_cell_mesh_space_dim; + elems=_local_cell_mesh->getCellsInBoundingBox(distant_bb,getBoundingBoxAdjustment()); +#endif + + DataArrayInt *distant_ids_send; + MEDCouplingPointSet *send_mesh = (MEDCouplingPointSet *)_local_para_field.getField()->buildSubMeshData(elems->begin(),elems->end(),distant_ids_send); + _exchangeMesh(send_mesh, distant_mesh, idistantrank, distant_ids_send, distant_ids); + distant_ids_send->decrRef(); + + if(send_mesh) + send_mesh->decrRef(); + } + + void ElementLocator::exchangeMethod(const std::string& sourceMeth, int idistantrank, std::string& targetMeth) + { + CommInterface comm_interface=_union_group->getCommInterface(); + MPIProcessorGroup* group=static_cast (_union_group); + const MPI_Comm* comm=(group->getComm()); + MPI_Status status; + // it must be converted to union numbering before communication + int idistRankInUnion = group->translateRank(&_distant_group,idistantrank); + char *recv_buffer=new char[4]; + std::vector send_buffer(4); + std::copy(sourceMeth.begin(),sourceMeth.end(),send_buffer.begin()); + comm_interface.sendRecv(&send_buffer[0], 4, MPI_CHAR,idistRankInUnion, 1112, + recv_buffer, 4, MPI_CHAR,idistRankInUnion, 1112, + *comm, &status); + targetMeth=recv_buffer; + delete [] recv_buffer; + } + + - // ====================== - // Compute bounding boxes - // ====================== + ++ /*! ++ Compute bounding boxes ++ */ + void ElementLocator::_computeBoundingBoxes() + { + CommInterface comm_interface =_union_group->getCommInterface(); + MPIProcessorGroup* group=static_cast (_union_group); + const MPI_Comm* comm = group->getComm(); + _local_cell_mesh_space_dim = -1; + if(_local_cell_mesh->getMeshDimension() != -1) + _local_cell_mesh_space_dim=_local_cell_mesh->getSpaceDimension(); + int *spaceDimForAll=new int[_union_group->size()]; + comm_interface.allGather(&_local_cell_mesh_space_dim, 1, MPI_INT, + spaceDimForAll,1, MPI_INT, + *comm); + _local_cell_mesh_space_dim=*std::max_element(spaceDimForAll,spaceDimForAll+_union_group->size()); + _is_m1d_corr=((*std::min_element(spaceDimForAll,spaceDimForAll+_union_group->size()))==-1); + for(int i=0;i<_union_group->size();i++) + if(spaceDimForAll[i]!=_local_cell_mesh_space_dim && spaceDimForAll[i]!=-1) + throw INTERP_KERNEL::Exception("Spacedim not matches !"); + delete [] spaceDimForAll; +#ifdef USE_DIRECTED_BB + INTERP_KERNEL::DirectedBoundingBox dbb; + int bbSize = dbb.dataSize(_local_cell_mesh_space_dim); + _domain_bounding_boxes = new double[bbSize*_union_group->size()]; + if(_local_cell_mesh->getMeshDimension() != -1) + dbb = INTERP_KERNEL::DirectedBoundingBox(_local_cell_mesh->getCoords()->getPointer(), + _local_cell_mesh->getNumberOfNodes(), + _local_cell_mesh_space_dim); + std::vector dbbData = dbb.getData(); + if ( dbbData.size() < bbSize ) dbbData.resize(bbSize,0); + double * minmax= &dbbData[0]; +#else + int bbSize = 2*_local_cell_mesh_space_dim; + _domain_bounding_boxes = new double[bbSize*_union_group->size()]; + double * minmax=new double [bbSize]; + if(_local_cell_mesh->getMeshDimension() != -1) + _local_cell_mesh->getBoundingBox(minmax); + else + for(int i=0;i<_local_cell_mesh_space_dim;i++) + { + minmax[i*2]=-std::numeric_limits::max(); + minmax[i*2+1]=std::numeric_limits::max(); + } +#endif + + comm_interface.allGather(minmax, bbSize, MPI_DOUBLE, + _domain_bounding_boxes,bbSize, MPI_DOUBLE, + *comm); + + for (int i=0; i< _distant_group.size(); i++) + { + int rank=_union_group->translateRank(&_distant_group,i); + + if (_intersectsBoundingBox(rank)) + { + _distant_proc_ids.push_back(rank); + } + } +#ifdef USE_DIRECTED_BB +#else + delete [] minmax; +#endif + } + + - // ============================================= - // Intersect Bounding Box (with a given "irank") - // ============================================= ++ ++ /*! ++ * Intersect local bounding box with a given distant bounding box on "irank" ++ */ + bool ElementLocator::_intersectsBoundingBox(int irank) + { +#ifdef USE_DIRECTED_BB + INTERP_KERNEL::DirectedBoundingBox local_dbb, distant_dbb; + local_dbb.setData( _domain_bounding_boxes+_union_group->myRank()*local_dbb.dataSize( _local_cell_mesh_space_dim )); + distant_dbb.setData( _domain_bounding_boxes+irank*distant_dbb.dataSize( _local_cell_mesh_space_dim )); + return !local_dbb.isDisjointWith( distant_dbb ); +#else + double* local_bb = _domain_bounding_boxes+_union_group->myRank()*2*_local_cell_mesh_space_dim; + double* distant_bb = _domain_bounding_boxes+irank*2*_local_cell_mesh_space_dim; + + for (int idim=0; idim < _local_cell_mesh_space_dim; idim++) + { + const double eps = 1e-12; + bool intersects = (distant_bb[idim*2]getCommInterface(); + + // First stage : exchanging sizes + // ------------------------------ + vector tinyInfoLocalD,tinyInfoDistantD(1);//not used for the moment + vector tinyInfoLocal,tinyInfoDistant; + vector tinyInfoLocalS; + //Getting tiny info of local mesh to allow the distant proc to initialize and allocate + //the transmitted mesh. + local_mesh->getTinySerializationInformation(tinyInfoLocalD,tinyInfoLocal,tinyInfoLocalS); + tinyInfoLocal.push_back(distant_ids_send->getNumberOfTuples()); + tinyInfoDistant.resize(tinyInfoLocal.size()); + std::fill(tinyInfoDistant.begin(),tinyInfoDistant.end(),0); + MPIProcessorGroup* group=static_cast (_union_group); + const MPI_Comm* comm=group->getComm(); + MPI_Status status; + + // iproc_distant is the number of proc in distant group + // it must be converted to union numbering before communication + int iprocdistant_in_union = group->translateRank(&_distant_group, + iproc_distant); + + comm_interface.sendRecv(&tinyInfoLocal[0], tinyInfoLocal.size(), MPI_INT, iprocdistant_in_union, 1112, + &tinyInfoDistant[0], tinyInfoDistant.size(), MPI_INT,iprocdistant_in_union,1112, + *comm, &status); + DataArrayInt *v1Local=0; + DataArrayDouble *v2Local=0; + DataArrayInt *v1Distant=DataArrayInt::New(); + DataArrayDouble *v2Distant=DataArrayDouble::New(); + //serialization of local mesh to send data to distant proc. + local_mesh->serialize(v1Local,v2Local); + //Building the right instance of copy of distant mesh. + MEDCouplingPointSet *distant_mesh_tmp=MEDCouplingPointSet::BuildInstanceFromMeshType((MEDCouplingMeshType)tinyInfoDistant[0]); + std::vector unusedTinyDistantSts; + distant_mesh_tmp->resizeForUnserialization(tinyInfoDistant,v1Distant,v2Distant,unusedTinyDistantSts); + int nbLocalElems=0; + int nbDistElem=0; + int *ptLocal=0; + int *ptDist=0; + if(v1Local) + { + nbLocalElems=v1Local->getNbOfElems(); + ptLocal=v1Local->getPointer(); + } + if(v1Distant) + { + nbDistElem=v1Distant->getNbOfElems(); + ptDist=v1Distant->getPointer(); + } + comm_interface.sendRecv(ptLocal, nbLocalElems, MPI_INT, + iprocdistant_in_union, 1111, + ptDist, nbDistElem, MPI_INT, + iprocdistant_in_union,1111, + *comm, &status); + nbLocalElems=0; + double *ptLocal2=0; + double *ptDist2=0; + if(v2Local) + { + nbLocalElems=v2Local->getNbOfElems(); + ptLocal2=v2Local->getPointer(); + } + nbDistElem=0; + if(v2Distant) + { + nbDistElem=v2Distant->getNbOfElems(); + ptDist2=v2Distant->getPointer(); + } + comm_interface.sendRecv(ptLocal2, nbLocalElems, MPI_DOUBLE, + iprocdistant_in_union, 1112, + ptDist2, nbDistElem, MPI_DOUBLE, + iprocdistant_in_union, 1112, + *comm, &status); + // + distant_mesh=distant_mesh_tmp; + //finish unserialization + distant_mesh->unserialization(tinyInfoDistantD,tinyInfoDistant,v1Distant,v2Distant,unusedTinyDistantSts); + // + distant_ids_recv=new int[tinyInfoDistant.back()]; + comm_interface.sendRecv(const_cast(reinterpret_cast(distant_ids_send->getConstPointer())),tinyInfoLocal.back(), MPI_INT, + iprocdistant_in_union, 1113, + distant_ids_recv,tinyInfoDistant.back(), MPI_INT, + iprocdistant_in_union,1113, + *comm, &status); + if(v1Local) + v1Local->decrRef(); + if(v2Local) + v2Local->decrRef(); + if(v1Distant) + v1Distant->decrRef(); + if(v2Distant) + v2Distant->decrRef(); + } + + /*! + * connected with ElementLocator::sendPolicyToWorkingSideL + */ + void ElementLocator::recvPolicyFromLazySideW(std::vector& policy) + { + policy.resize(_distant_proc_ids.size()); + int procId=0; + CommInterface comm; + MPI_Status status; + for(vector::const_iterator iter=_distant_proc_ids.begin();iter!=_distant_proc_ids.end();iter++,procId++) + { + int toRecv; + comm.recv((void *)&toRecv,1,MPI_INT,*iter,1120,*_comm,&status); + policy[procId]=toRecv; + } + } + + /*! + * connected with ElementLocator::recvFromWorkingSideL + */ + void ElementLocator::sendSumToLazySideW(const std::vector< std::vector >& distantLocEltIds, const std::vector< std::vector >& partialSumRelToDistantIds) + { + int procId=0; + CommInterface comm; + for(vector::const_iterator iter=_distant_proc_ids.begin();iter!=_distant_proc_ids.end();iter++,procId++) + { + const vector& eltIds=distantLocEltIds[procId]; + const vector& valued=partialSumRelToDistantIds[procId]; + int lgth=eltIds.size(); + comm.send(&lgth,1,MPI_INT,*iter,1114,*_comm); + comm.send(const_cast(reinterpret_cast(&eltIds[0])),lgth,MPI_INT,*iter,1115,*_comm); + comm.send(const_cast(reinterpret_cast(&valued[0])),lgth,MPI_DOUBLE,*iter,1116,*_comm); + } + } + + /*! + * connected with ElementLocator::sendToWorkingSideL + */ + void ElementLocator::recvSumFromLazySideW(std::vector< std::vector >& globalSumRelToDistantIds) + { + int procId=0; + CommInterface comm; + MPI_Status status; + for(vector::const_iterator iter=_distant_proc_ids.begin();iter!=_distant_proc_ids.end();iter++,procId++) + { + std::vector& vec=globalSumRelToDistantIds[procId]; + comm.recv(&vec[0],vec.size(),MPI_DOUBLE,*iter,1117,*_comm,&status); + } + } + + /*! + * connected with ElementLocator::recvLocalIdsFromWorkingSideL + */ + void ElementLocator::sendLocalIdsToLazyProcsW(const std::vector< std::vector >& distantLocEltIds) + { + int procId=0; + CommInterface comm; + for(vector::const_iterator iter=_distant_proc_ids.begin();iter!=_distant_proc_ids.end();iter++,procId++) + { + const vector& eltIds=distantLocEltIds[procId]; + int lgth=eltIds.size(); + comm.send(&lgth,1,MPI_INT,*iter,1121,*_comm); + comm.send(const_cast(reinterpret_cast(&eltIds[0])),lgth,MPI_INT,*iter,1122,*_comm); + } + } + + /*! + * connected with ElementLocator::sendGlobalIdsToWorkingSideL + */ + void ElementLocator::recvGlobalIdsFromLazyProcsW(const std::vector< std::vector >& distantLocEltIds, std::vector< std::vector >& globalIds) + { + int procId=0; + CommInterface comm; + MPI_Status status; + globalIds.resize(_distant_proc_ids.size()); + for(vector::const_iterator iter=_distant_proc_ids.begin();iter!=_distant_proc_ids.end();iter++,procId++) + { + const std::vector& vec=distantLocEltIds[procId]; + std::vector& global=globalIds[procId]; + global.resize(vec.size()); + comm.recv(&global[0],vec.size(),MPI_INT,*iter,1123,*_comm,&status); + } + } + + /*! + * connected with ElementLocator::sendCandidatesGlobalIdsToWorkingSideL + */ + void ElementLocator::recvCandidatesGlobalIdsFromLazyProcsW(std::vector< std::vector >& globalIds) + { + int procId=0; + CommInterface comm; + MPI_Status status; + globalIds.resize(_distant_proc_ids.size()); + for(vector::const_iterator iter=_distant_proc_ids.begin();iter!=_distant_proc_ids.end();iter++,procId++) + { + std::vector& global=globalIds[procId]; + int lgth; + comm.recv(&lgth,1,MPI_INT,*iter,1132,*_comm,&status); + global.resize(lgth); + comm.recv(&global[0],lgth,MPI_INT,*iter,1133,*_comm,&status); + } + } + + /*! + * connected with ElementLocator::recvSumFromWorkingSideL + */ + void ElementLocator::sendPartialSumToLazyProcsW(const std::vector& distantGlobIds, const std::vector& sum) + { + int procId=0; + CommInterface comm; + int lgth=distantGlobIds.size(); + for(vector::const_iterator iter=_distant_proc_ids.begin();iter!=_distant_proc_ids.end();iter++,procId++) + { + comm.send(&lgth,1,MPI_INT,*iter,1124,*_comm); + comm.send(const_cast(reinterpret_cast(&distantGlobIds[0])),lgth,MPI_INT,*iter,1125,*_comm); + comm.send(const_cast(reinterpret_cast(&sum[0])),lgth,MPI_DOUBLE,*iter,1126,*_comm); + } + } + + /*! + * connected with ElementLocator::recvCandidatesForAddElementsL + */ + void ElementLocator::sendCandidatesForAddElementsW(const std::vector& distantGlobIds) + { + int procId=0; + CommInterface comm; + int lgth=distantGlobIds.size(); + for(vector::const_iterator iter=_distant_proc_ids.begin();iter!=_distant_proc_ids.end();iter++,procId++) + { + comm.send(const_cast(reinterpret_cast(&lgth)),1,MPI_INT,*iter,1128,*_comm); + comm.send(const_cast(reinterpret_cast(&distantGlobIds[0])),lgth,MPI_INT,*iter,1129,*_comm); + } + } + + /*! + * connected with ElementLocator::sendAddElementsToWorkingSideL + */ + void ElementLocator::recvAddElementsFromLazyProcsW(std::vector >& elementsToAdd) + { + int procId=0; + CommInterface comm; + MPI_Status status; + int lgth=_distant_proc_ids.size(); + elementsToAdd.resize(lgth); + for(vector::const_iterator iter=_distant_proc_ids.begin();iter!=_distant_proc_ids.end();iter++,procId++) + { + int locLgth; + std::vector& eltToFeed=elementsToAdd[procId]; + comm.recv(&locLgth,1,MPI_INT,*iter,1130,*_comm,&status); + eltToFeed.resize(locLgth); + comm.recv(&eltToFeed[0],locLgth,MPI_INT,*iter,1131,*_comm,&status); + } + } + + /*! + * connected with ElementLocator::recvPolicyFromLazySideW + */ + int ElementLocator::sendPolicyToWorkingSideL() + { + CommInterface comm; + int toSend; + DataArrayInt *isCumulative=_local_para_field.returnCumulativeGlobalNumbering(); + if(isCumulative) + { + toSend=CUMULATIVE_POLICY; + isCumulative->decrRef(); + } + else + toSend=NO_POST_TREATMENT_POLICY; + for(vector::const_iterator iter=_distant_proc_ids.begin();iter!=_distant_proc_ids.end();iter++) + comm.send(&toSend,1,MPI_INT,*iter,1120,*_comm); + return toSend; + } + + /*! + * connected with ElementLocator::sendSumToLazySideW + */ + void ElementLocator::recvFromWorkingSideL() + { + _values_added.resize(_local_para_field.getField()->getNumberOfTuples()); + int procId=0; + CommInterface comm; + _ids_per_working_proc.resize(_distant_proc_ids.size()); + MPI_Status status; + for(vector::const_iterator iter=_distant_proc_ids.begin();iter!=_distant_proc_ids.end();iter++,procId++) + { + int lgth; + comm.recv(&lgth,1,MPI_INT,*iter,1114,*_comm,&status); + vector& ids=_ids_per_working_proc[procId]; + ids.resize(lgth); + vector values(lgth); + comm.recv(&ids[0],lgth,MPI_INT,*iter,1115,*_comm,&status); + comm.recv(&values[0],lgth,MPI_DOUBLE,*iter,1116,*_comm,&status); + for(int i=0;i::const_iterator iter=_distant_proc_ids.begin();iter!=_distant_proc_ids.end();iter++,procId++) + { + vector& ids=_ids_per_working_proc[procId]; + vector valsToSend(ids.size()); + vector::iterator iter3=valsToSend.begin(); + for(vector::const_iterator iter2=ids.begin();iter2!=ids.end();iter2++,iter3++) + *iter3=_values_added[*iter2]; + comm.send(&valsToSend[0],ids.size(),MPI_DOUBLE,*iter,1117,*_comm); + //ids.clear(); + } + //_ids_per_working_proc.clear(); + } + + /*! + * connected with ElementLocator::sendLocalIdsToLazyProcsW + */ + void ElementLocator::recvLocalIdsFromWorkingSideL() + { + int procId=0; + CommInterface comm; + _ids_per_working_proc.resize(_distant_proc_ids.size()); + MPI_Status status; + for(vector::const_iterator iter=_distant_proc_ids.begin();iter!=_distant_proc_ids.end();iter++,procId++) + { + int lgth; + vector& ids=_ids_per_working_proc[procId]; + comm.recv(&lgth,1,MPI_INT,*iter,1121,*_comm,&status); + ids.resize(lgth); + comm.recv(&ids[0],lgth,MPI_INT,*iter,1122,*_comm,&status); + } + } + + /*! + * connected with ElementLocator::recvGlobalIdsFromLazyProcsW + */ + void ElementLocator::sendGlobalIdsToWorkingSideL() + { + int procId=0; + CommInterface comm; + DataArrayInt *globalIds=_local_para_field.returnGlobalNumbering(); + const int *globalIdsC=globalIds->getConstPointer(); + for(vector::const_iterator iter=_distant_proc_ids.begin();iter!=_distant_proc_ids.end();iter++,procId++) + { + const vector& ids=_ids_per_working_proc[procId]; + vector valsToSend(ids.size()); + vector::iterator iter1=valsToSend.begin(); + for(vector::const_iterator iter2=ids.begin();iter2!=ids.end();iter2++,iter1++) + *iter1=globalIdsC[*iter2]; + comm.send(&valsToSend[0],ids.size(),MPI_INT,*iter,1123,*_comm); + } + if(globalIds) + globalIds->decrRef(); + } + + /*! + * connected with ElementLocator::sendPartialSumToLazyProcsW + */ + void ElementLocator::recvSumFromWorkingSideL() + { + int procId=0; + int wProcSize=_distant_proc_ids.size(); + CommInterface comm; + _ids_per_working_proc.resize(wProcSize); + _values_per_working_proc.resize(wProcSize); + MPI_Status status; + std::map sums; + for(vector::const_iterator iter=_distant_proc_ids.begin();iter!=_distant_proc_ids.end();iter++,procId++) + { + int lgth; + comm.recv(&lgth,1,MPI_INT,*iter,1124,*_comm,&status); + vector& ids=_ids_per_working_proc[procId]; + vector& vals=_values_per_working_proc[procId]; + ids.resize(lgth); + vals.resize(lgth); + comm.recv(&ids[0],lgth,MPI_INT,*iter,1125,*_comm,&status); + comm.recv(&vals[0],lgth,MPI_DOUBLE,*iter,1126,*_comm,&status); + vector::const_iterator iter1=ids.begin(); + vector::const_iterator iter2=vals.begin(); + for(;iter1!=ids.end();iter1++,iter2++) + sums[*iter1]+=*iter2; + } + //assign sum to prepare sending to working side + for(procId=0;procId& ids=_ids_per_working_proc[procId]; + vector& vals=_values_per_working_proc[procId]; + vector::const_iterator iter1=ids.begin(); + vector::iterator iter2=vals.begin(); + for(;iter1!=ids.end();iter1++,iter2++) + *iter2=sums[*iter1]; + ids.clear(); + } + } + + /*! + * Foreach working procs Wi compute and push it in _ids_per_working_proc3, + * if it exist, local id of nodes that are in interaction with an another lazy proc than this + * and that exists in this \b but with no interaction with this. + * The computation is performed here. sendAddElementsToWorkingSideL is only in charge to send + * precomputed _ids_per_working_proc3 attribute. + * connected with ElementLocator::sendCandidatesForAddElementsW + */ + void ElementLocator::recvCandidatesForAddElementsL() + { + int procId=0; + int wProcSize=_distant_proc_ids.size(); + CommInterface comm; + _ids_per_working_proc3.resize(wProcSize); + MPI_Status status; + std::map sums; + DataArrayInt *globalIds=_local_para_field.returnGlobalNumbering(); + const int *globalIdsC=globalIds->getConstPointer(); + int nbElts=globalIds->getNumberOfTuples(); + std::set globalIdsS(globalIdsC,globalIdsC+nbElts); + for(vector::const_iterator iter=_distant_proc_ids.begin();iter!=_distant_proc_ids.end();iter++,procId++) + { + const std::vector& ids0=_ids_per_working_proc[procId]; + int lgth0=ids0.size(); + std::set elts0; + for(int i=0;i ids(lgth); + comm.recv(&ids[0],lgth,MPI_INT,*iter,1129,*_comm,&status); + set ids1(ids.begin(),ids.end()); + ids.clear(); + set tmp5,tmp6; + set_intersection(globalIdsS.begin(),globalIdsS.end(),ids1.begin(),ids1.end(),inserter(tmp5,tmp5.begin())); + set_difference(tmp5.begin(),tmp5.end(),elts0.begin(),elts0.end(),inserter(tmp6,tmp6.begin())); + std::vector& ids2=_ids_per_working_proc3[procId]; + ids2.resize(tmp6.size()); + std::copy(tmp6.begin(),tmp6.end(),ids2.begin()); + //global->local + for(std::vector::iterator iter2=ids2.begin();iter2!=ids2.end();iter2++) + *iter2=std::find(globalIdsC,globalIdsC+nbElts,*iter2)-globalIdsC; + } + if(globalIds) + globalIds->decrRef(); + } + + /*! + * connected with ElementLocator::recvAddElementsFromLazyProcsW + */ + void ElementLocator::sendAddElementsToWorkingSideL() + { + int procId=0; + CommInterface comm; + for(vector::const_iterator iter=_distant_proc_ids.begin();iter!=_distant_proc_ids.end();iter++,procId++) + { + const std::vector& vals=_ids_per_working_proc3[procId]; + int size=vals.size(); + comm.send(const_cast(reinterpret_cast(&size)),1,MPI_INT,*iter,1130,*_comm); + comm.send(const_cast(reinterpret_cast(&vals[0])),size,MPI_INT,*iter,1131,*_comm); + } + } + + /*! + * This method sends to working side Wi only nodes in interaction with Wi \b and located on boundary, to reduce number. + * connected with ElementLocator::recvCandidatesGlobalIdsFromLazyProcsW + */ + void ElementLocator::sendCandidatesGlobalIdsToWorkingSideL() + { + int procId=0; + CommInterface comm; + DataArrayInt *globalIds=_local_para_field.returnGlobalNumbering(); + const int *globalIdsC=globalIds->getConstPointer(); + MEDCouplingAutoRefCountObjectPtr candidates=_local_para_field.getSupport()->getCellMesh()->findBoundaryNodes(); + for(int *iter1=candidates->getPointer();iter1!=candidates->getPointer()+candidates->getNumberOfTuples();iter1++) + (*iter1)=globalIdsC[*iter1]; + std::set candidatesS(candidates->begin(),candidates->end()); + for(vector::const_iterator iter=_distant_proc_ids.begin();iter!=_distant_proc_ids.end();iter++,procId++) + { + const vector& ids=_ids_per_working_proc[procId]; + vector valsToSend(ids.size()); + vector::iterator iter1=valsToSend.begin(); + for(vector::const_iterator iter2=ids.begin();iter2!=ids.end();iter2++,iter1++) + *iter1=globalIdsC[*iter2]; + std::set tmp2(valsToSend.begin(),valsToSend.end()); + std::vector tmp3; + set_intersection(candidatesS.begin(),candidatesS.end(),tmp2.begin(),tmp2.end(),std::back_insert_iterator< std::vector >(tmp3)); + int lgth=tmp3.size(); + comm.send(&lgth,1,MPI_INT,*iter,1132,*_comm); + comm.send(&tmp3[0],lgth,MPI_INT,*iter,1133,*_comm); + } + if(globalIds) + globalIds->decrRef(); + } +} diff --cc medtool/src/ParaMEDMEM/ElementLocator.hxx index 4853c9766,000000000..4edd27de6 mode 100644,000000..100644 --- a/medtool/src/ParaMEDMEM/ElementLocator.hxx +++ b/medtool/src/ParaMEDMEM/ElementLocator.hxx @@@ -1,109 -1,0 +1,111 @@@ +// Copyright (C) 2007-2015 CEA/DEN, EDF R&D +// +// 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +// +// See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com +// + +#ifndef __ELEMENTLOCATOR_HXX__ +#define __ELEMENTLOCATOR_HXX__ + +#include "InterpolationOptions.hxx" +#include "MEDCouplingNatureOfField.hxx" + +#include +#include +#include + +namespace ParaMEDMEM +{ + class ParaFIELD; + class ProcessorGroup; - class ParaSUPPORT; + class InterpolationMatrix; + class MEDCouplingPointSet; + class DataArrayInt; + ++ /*! Internal class, not part of the public API. Used in InterpolationMatrix. ++ * ++ */ + class ElementLocator : public INTERP_KERNEL::InterpolationOptions + { + public: + ElementLocator(const ParaFIELD& sourceField, const ProcessorGroup& distant_group, const ProcessorGroup& local_group); + + virtual ~ElementLocator(); + void exchangeMesh(int idistantrank, + MEDCouplingPointSet*& target_mesh, + int*& distant_ids); + void exchangeMethod(const std::string& sourceMeth, int idistantrank, std::string& targetMeth); + const std::vector& getDistantProcIds() const { return _distant_proc_ids; } + const MPI_Comm *getCommunicator() const; + NatureOfField getLocalNature() const; + //! This method is used to informed if there is -1D mesh on distant_group side or on local_group side. + bool isM1DCorr() const { return _is_m1d_corr; } + //Working side methods + void recvPolicyFromLazySideW(std::vector& policy); + void sendSumToLazySideW(const std::vector< std::vector >& distantLocEltIds, const std::vector< std::vector >& partialSumRelToDistantIds); + void recvSumFromLazySideW(std::vector< std::vector >& globalSumRelToDistantIds); + void sendCandidatesForAddElementsW(const std::vector& distantGlobIds); + void recvAddElementsFromLazyProcsW(std::vector >& elementsToAdd); + // + void sendLocalIdsToLazyProcsW(const std::vector< std::vector >& distantLocEltIds); + void recvGlobalIdsFromLazyProcsW(const std::vector< std::vector >& distantLocEltIds, std::vector< std::vector >& globalIds); + void recvCandidatesGlobalIdsFromLazyProcsW(std::vector< std::vector >& globalIds); + void sendPartialSumToLazyProcsW(const std::vector& distantGlobIds, const std::vector& sum); + //Lazy side methods + int sendPolicyToWorkingSideL(); + void recvFromWorkingSideL(); + void sendToWorkingSideL(); + // + void recvLocalIdsFromWorkingSideL(); + void sendGlobalIdsToWorkingSideL(); + void sendCandidatesGlobalIdsToWorkingSideL(); + // + void recvSumFromWorkingSideL(); + void recvCandidatesForAddElementsL(); + void sendAddElementsToWorkingSideL(); + private: + void _computeBoundingBoxes(); + bool _intersectsBoundingBox(int irank); + void _exchangeMesh(MEDCouplingPointSet* local_mesh, MEDCouplingPointSet*& distant_mesh, + int iproc_distant, const DataArrayInt* distant_ids_send, + int*& distant_ids_recv); + private: + const ParaFIELD& _local_para_field ; + MEDCouplingPointSet* _local_cell_mesh; + int _local_cell_mesh_space_dim; + bool _is_m1d_corr; + MEDCouplingPointSet* _local_face_mesh; + std::vector _distant_cell_meshes; + std::vector _distant_face_meshes; + double* _domain_bounding_boxes; + const ProcessorGroup& _distant_group; + const ProcessorGroup& _local_group; + ProcessorGroup* _union_group; + std::vector _distant_proc_ids; + const MPI_Comm *_comm; + //Attributes only used by lazy side + std::vector _values_added; + std::vector< std::vector > _ids_per_working_proc; + std::vector< std::vector > _ids_per_working_proc3; + std::vector< std::vector > _values_per_working_proc; + public: + static const int CUMULATIVE_POLICY=3; + static const int NO_POST_TREATMENT_POLICY=7; + }; + +} + +#endif diff --cc medtool/src/ParaMEDMEM/ExplicitCoincidentDEC.cxx index 5d30c60d4,000000000..db0396725 mode 100644,000000..100644 --- a/medtool/src/ParaMEDMEM/ExplicitCoincidentDEC.cxx +++ b/medtool/src/ParaMEDMEM/ExplicitCoincidentDEC.cxx @@@ -1,393 -1,0 +1,445 @@@ +// Copyright (C) 2007-2015 CEA/DEN, EDF R&D +// +// 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +// +// See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com +// + +#include +#include "CommInterface.hxx" +#include "Topology.hxx" +#include "BlockTopology.hxx" +#include "ComponentTopology.hxx" +#include "ParaFIELD.hxx" +#include "MPIProcessorGroup.hxx" +#include "ExplicitCoincidentDEC.hxx" +#include "ExplicitMapping.hxx" +#include "InterpKernelUtilities.hxx" + +using namespace std; + +namespace ParaMEDMEM +{ ++ + /*! - * \anchor ExplicitCoincidentDEC-det - * \class ExplicitCoincidentDEC - * - * TODO: doc - */ ++ \anchor ExplicitCoincidentDEC-det ++ \class ExplicitCoincidentDEC ++ ++ ++ This class aims at \ref interpolation "remapping fields" that have identical ++ supports (=the same underlying mesh) but different parallel topologies ++ (=different sub-domains in the mesh). It can be used to couple ++ together multi-physics codes that operate on the same domain ++ with different partitioning. ++ ++ It is very similar to what the \ref StructuredCoincidentDEC-det "StructuredCoincidentDEC" ++ does, except that it works with an arbitrary user-defined topology. ++ ++ The remapping between the two supports is based on identity of global ++ ids, instead of geometrical considerations (as it is the case for ++ \ref InterpKernelDEC-det "InterpKernelDEC"). ++ Therefore, beware that this \ref para-dec "DEC" can not be used ++ for coincident meshes if they do *not* have the exact same numbering. ++ ++ With this \ref para-dec "DEC" no projection, and no interpolation of the field data is done, contrary ++ to what happens in \ref InterpKernelDEC-det "InterpKernelDEC". It is just ++ a matter of allocating the values from one side to the other, using directly the cell ++ identifiers. ++ ++ As all the other DECs, its usage requires two phases : ++ - a setup phase during which the topologies are exchanged so that ++ the target side knows from which processors it should expect ++ the data. ++ - a send/recv phase during which the field data is actually transferred. ++ ++ This example illustrates the sending of a field with ++ the \c ExplicitCoincidentDEC : ++ \code ++ ... ++ ExplicitCoincidentDEC dec(groupA, groupB); ++ dec.attachLocalField(field); ++ dec.synchronize(); ++ if (groupA.containsMyRank()) ++ dec.recvData(); ++ else if (groupB.containsMyRank()) ++ dec.sendData(); ++ ... ++ \endcode ++ ++ Creating a ParaFIELD to be attached to the %DEC is done in exactly the same way as for ++ the other DECs, if only the partitioning of the support mesh differs. ++ In the case where the ++ fields have also different *component* topologies, creating the ParaFIELD ++ requires some more effort. See the \ref para-over "parallelism" section for more details. ++ */ ++ + + /*! Constructor + */ - ExplicitCoincidentDEC::ExplicitCoincidentDEC():_toposource(0),_topotarget(0) ++ ExplicitCoincidentDEC::ExplicitCoincidentDEC(): ++ _toposource(0),_topotarget(0), ++ _targetgroup(0), _sourcegroup(0), ++ _sendcounts(0), _recvcounts(0), ++ _senddispls(0), _recvdispls(0), ++ _recvbuffer(0), _sendbuffer(0), ++ _distant_elems(), _explicit_mapping() + { + } + + ExplicitCoincidentDEC::~ExplicitCoincidentDEC() + { + } + + /*! Synchronization process for exchanging topologies + */ + void ExplicitCoincidentDEC::synchronize() + { + if (_source_group->containsMyRank()) + { + _toposource = dynamic_cast(_local_field->getTopology()); + _sourcegroup= _toposource->getProcGroup()->createProcGroup(); + _targetgroup=_toposource->getProcGroup()->createComplementProcGroup(); + } + if (_target_group->containsMyRank()) + { + _topotarget = dynamic_cast(_local_field->getTopology()); + _sourcegroup= _topotarget->getProcGroup()->createComplementProcGroup(); + _targetgroup=_topotarget->getProcGroup()->createProcGroup(); + } + + // Exchanging + + // Transmitting source topology to target code + broadcastTopology(_toposource,_topotarget,1000); + transferMappingToSource(); + } + + /*! Creates the arrays necessary for the data transfer + * and fills the send array with the values of the + * source field + * */ + void ExplicitCoincidentDEC::prepareSourceDE() + { + //////////////////////////////////// + //Step 1 : buffer array creation + + if (!_toposource->getProcGroup()->containsMyRank()) + return; + MPIProcessorGroup* group=new MPIProcessorGroup(_sourcegroup->getCommInterface()); + + // Warning : the size of the target side is implicitly deduced + //from the size of MPI_COMM_WORLD + int target_size = _toposource->getProcGroup()->getCommInterface().worldSize()- _toposource->getProcGroup()->size() ; + + vector* target_arrays=new vector[target_size]; + + int nb_local = _toposource-> getNbLocalElements(); + + int union_size=group->size(); + + _sendcounts=new int[union_size]; + _senddispls=new int[union_size]; + _recvcounts=new int[union_size]; + _recvdispls=new int[union_size]; + + for (int i=0; i< union_size; i++) + { + _sendcounts[i]=0; + _recvcounts[i]=0; + _recvdispls[i]=0; + } + _senddispls[0]=0; + + int* counts=_explicit_mapping.getCounts(); + for (int i=0; isize(); i++) + _sendcounts[i]=counts[i]; + + for (int iproc=1; iprocsize();iproc++) + _senddispls[iproc]=_senddispls[iproc-1]+_sendcounts[iproc-1]; + + _sendbuffer = new double [nb_local * _toposource->getNbComponents()]; + + ///////////////////////////////////////////////////////////// + //Step 2 : filling the buffers with the source field values + + int* counter=new int [target_size]; + counter[0]=0; + for (int i=1; igetField()->getArray()->getPointer(); + + int* bufferindex= _explicit_mapping.getBufferIndex(); + + for (int ielem=0; ielemgetNbComponents(); + for (int icomp=0; icompgetProcGroup()->containsMyRank()) + return; + MPIProcessorGroup* group=new MPIProcessorGroup(_topotarget->getProcGroup()->getCommInterface()); + + vector < vector > source_arrays(_sourcegroup->size()); + int nb_local = _topotarget-> getNbLocalElements(); + for (int ielem=0; ielem< nb_local ; ielem++) + { + //pair source_local =_distant_elems[ielem]; + pair source_local=_explicit_mapping.getDistantNumbering(ielem); + source_arrays[source_local.first].push_back(source_local.second); + } + int union_size=group->size(); + _recvcounts=new int[union_size]; + _recvdispls=new int[union_size]; + _sendcounts=new int[union_size]; + _senddispls=new int[union_size]; + + for (int i=0; i< union_size; i++) + { + _sendcounts[i]=0; + _recvcounts[i]=0; + _recvdispls[i]=0; + } + for (int iproc=0; iproc < _sourcegroup->size(); iproc++) + { + //converts the rank in target to the rank in union communicator + int unionrank=group->translateRank(_sourcegroup,iproc); + _recvcounts[unionrank]=source_arrays[iproc].size()*_topotarget->getNbComponents(); + } + for (int i=1; igetNbComponents()]; + + } + + + /*! - * Synchronizing a topology so that all the - * group possesses it. ++ * Synchronizing a topology so that all the groups get it. + * + * \param toposend Topology that is transmitted. It is read on processes where it already exists, and it is created and filled on others. + * \param toporecv Topology which is received. + * \param tag Communication tag associated with this operation. + */ + void ExplicitCoincidentDEC::broadcastTopology(const ExplicitTopology* toposend, ExplicitTopology* toporecv, int tag) + { + MPI_Status status; + + int* serializer=0; + int size; + + MPIProcessorGroup* group=new MPIProcessorGroup(*_comm_interface); + + // The send processors serialize the send topology + // and send the buffers to the recv procs + if (toposend !=0 && toposend->getProcGroup()->containsMyRank()) + { + toposend->serialize(serializer, size); + for (int iproc=0; iproc< group->size(); iproc++) + { + int itarget=iproc; + if (!toposend->getProcGroup()->contains(itarget)) + { + _comm_interface->send(&size,1,MPI_INT, itarget,tag+itarget,*(group->getComm())); + _comm_interface->send(serializer, size, MPI_INT, itarget, tag+itarget,*(group->getComm())); + } + } + } + else + { + vector size2(group->size()); + int myworldrank=group->myRank(); + for (int iproc=0; iprocsize();iproc++) + { + int isource = iproc; + if (!toporecv->getProcGroup()->contains(isource)) + { + int nbelem; + _comm_interface->recv(&nbelem, 1, MPI_INT, isource, tag+myworldrank, *(group->getComm()), &status); + int* buffer = new int[nbelem]; + _comm_interface->recv(buffer, nbelem, MPI_INT, isource,tag+myworldrank, *(group->getComm()), &status); + + ExplicitTopology* topotemp=new ExplicitTopology(); + topotemp->unserialize(buffer, *_comm_interface); + delete[] buffer; + + for (int ielem=0; ielemgetNbLocalElements(); ielem++) + { + int global = toporecv->localToGlobal(ielem); + int sendlocal=topotemp->globalToLocal(global); + if (sendlocal!=-1) + { + size2[iproc]++; + _explicit_mapping.pushBackElem(make_pair(iproc,sendlocal)); + } + } + delete topotemp; + } + } + } + MESSAGE (" rank "<myRank()<< " broadcastTopology is over"); + } + + void ExplicitCoincidentDEC::transferMappingToSource() + { + + MPIProcessorGroup* group=new MPIProcessorGroup(*_comm_interface); + + // sending source->target mapping which is stored by target + //in _distant_elems from target to source + if (_topotarget!=0 && _topotarget->getProcGroup()->containsMyRank()) + { + int world_size = _topotarget->getProcGroup()->getCommInterface().worldSize() ; + int* nb_transfer_union=new int[world_size]; + int* dummy_recv=new int[world_size]; + for (int i=0; itranslateRank(_sourcegroup,_explicit_mapping.getDistantDomain(i)); + nb_transfer_union[unionrank]=_explicit_mapping.getNbDistantElems(i); + } + _comm_interface->allToAll(nb_transfer_union, 1, MPI_INT, dummy_recv, 1, MPI_INT, MPI_COMM_WORLD); + + int* sendbuffer= _explicit_mapping.serialize(_topotarget->getProcGroup()->myRank()); + + int* sendcounts= new int [world_size]; + int* senddispls = new int [world_size]; + for (int i=0; i< world_size; i++) + { + sendcounts[i]=2*nb_transfer_union[i]; + if (i==0) + senddispls[i]=0; + else + senddispls[i]=senddispls[i-1]+sendcounts[i-1]; + } + int* recvcounts=new int[world_size]; + int* recvdispls=new int[world_size]; + int *dummyrecv=0; + for (int i=0; i allToAllV(sendbuffer, sendcounts, senddispls, MPI_INT, dummyrecv, recvcounts, senddispls, MPI_INT, MPI_COMM_WORLD); + + } + //receiving in the source subdomains the mapping sent by targets + else + { + int world_size = _toposource->getProcGroup()->getCommInterface().worldSize() ; + int* nb_transfer_union=new int[world_size]; + int* dummy_send=new int[world_size]; + for (int i=0; iallToAll(dummy_send, 1, MPI_INT, nb_transfer_union, 1, MPI_INT, MPI_COMM_WORLD); + + int total_size=0; + for (int i=0; i< world_size; i++) + total_size+=nb_transfer_union[i]; + int nbtarget = _targetgroup->size(); + int* targetranks = new int[ nbtarget]; + for (int i=0; itranslateRank(_targetgroup,i); + int* mappingbuffer= new int [total_size*2]; + int* sendcounts= new int [world_size]; + int* senddispls = new int [world_size]; + int* recvcounts=new int[world_size]; + int* recvdispls=new int[world_size]; + for (int i=0; i< world_size; i++) + { + recvcounts[i]=2*nb_transfer_union[i]; + if (i==0) + recvdispls[i]=0; + else + recvdispls[i]=recvdispls[i-1]+recvcounts[i-1]; + } + + int *dummysend=0; + for (int i=0; i allToAllV(dummysend, sendcounts, senddispls, MPI_INT, mappingbuffer, recvcounts, recvdispls, MPI_INT, MPI_COMM_WORLD); + _explicit_mapping.unserialize(world_size,nb_transfer_union,nbtarget, targetranks, mappingbuffer); + } + } + + void ExplicitCoincidentDEC::recvData() + { + //MPI_COMM_WORLD is used instead of group because there is no + //mechanism for creating the union group yet + MESSAGE("recvData"); + + cout<<"start AllToAll"<allToAllV(_sendbuffer, _sendcounts, _senddispls, MPI_DOUBLE, + _recvbuffer, _recvcounts, _recvdispls, MPI_DOUBLE,MPI_COMM_WORLD); + cout<<"end AllToAll"<getNbLocalElements(); + double* value=new double[nb_local*_topotarget->getNbComponents()]; + + vector counters(_sourcegroup->size()); + counters[0]=0; + for (int i=0; i<_sourcegroup->size()-1; i++) + { + MPIProcessorGroup* group=new MPIProcessorGroup(*_comm_interface); + int worldrank=group->translateRank(_sourcegroup,i); + counters[i+1]=counters[i]+_recvcounts[worldrank]; + } + + for (int ielem=0; ielem distant_numbering=_explicit_mapping.getDistantNumbering(ielem); + int iproc=distant_numbering.first; + int ncomp = _topotarget->getNbComponents(); + for (int icomp=0; icomp< ncomp; icomp++) + value[ielem*ncomp+icomp]=_recvbuffer[counters[iproc]*ncomp+icomp]; + counters[iproc]++; + } + _local_field->getField()->getArray()->useArray(value,true,CPP_DEALLOC,nb_local,_topotarget->getNbComponents()); + } + + void ExplicitCoincidentDEC::sendData() + { + MESSAGE ("sendData"); + for (int i=0; i< 4; i++) + cout << _sendcounts[i]<<" "; + cout <allToAllV(_sendbuffer, _sendcounts, _senddispls, MPI_DOUBLE, + _recvbuffer, _recvcounts, _recvdispls, MPI_DOUBLE,MPI_COMM_WORLD); + } +} + diff --cc medtool/src/ParaMEDMEM/ExplicitMapping.hxx index e83d0dc97,000000000..3098b706f mode 100644,000000..100644 --- a/medtool/src/ParaMEDMEM/ExplicitMapping.hxx +++ b/medtool/src/ParaMEDMEM/ExplicitMapping.hxx @@@ -1,176 -1,0 +1,65 @@@ +// Copyright (C) 2007-2015 CEA/DEN, EDF R&D +// +// 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +// +// See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com +// + +#ifndef __EXPLICITMAPPING_HXX__ +#define __EXPLICITMAPPING_HXX__ + +#include +#include +#include + +namespace ParaMEDMEM +{ ++ /*! ++ * Internal class, not part of the public API. ++ * ++ * Used by the ExplicitCoincidentDEC. ++ */ + class ExplicitMapping + { + public: - - ExplicitMapping():_numbers(0), _domains(0), _comm_buffer(0) { } - - ~ExplicitMapping() - { - if (_domains!=0) delete[] _domains; - if (_numbers!=0) delete[] _numbers; - if (_comm_buffer!=0) delete[] _comm_buffer; - } ++ ExplicitMapping(); ++ ~ExplicitMapping(); + - void pushBackElem(std::pair idistant) - { - _mapping.push_back(idistant); - } - - void setDistantElem(int ilocal, std::pair idistant) - { - _mapping[ilocal]=idistant; - } - - int nbDistantDomains() - { - if (_distant_domains.empty()) - { - for (std::vector >::const_iterator iter= _mapping.begin(); - iter!=_mapping.end(); - iter++) - _distant_domains.insert(iter->first); - } - return _distant_domains.size(); - } ++ void pushBackElem(std::pair idistant); ++ void setDistantElem(int ilocal, std::pair idistant); ++ int nbDistantDomains(); ++ std::pair getDistantNumbering(int ielem) const; + - std::pair getDistantNumbering(int ielem)const - { - return _mapping[ielem]; - } ++ int getDistantDomain(int i); ++ int getNbDistantElems(int i); ++ int* serialize(int idproc); ++ void unserialize(int nbprocs, int* sizes,int nbtarget, int* targetrank, int* commbuffer); + - int getDistantDomain(int i) - { - if (_domains==0) - computeNumbers(); - - return _domains[i]; - } - - int getNbDistantElems(int i) - { - if (_numbers==0) - computeNumbers(); - return _numbers[i]; - } - - int* serialize(int idproc) - { - _comm_buffer=new int[_mapping.size()*2]; - std::vector offsets(_distant_domains.size()); - offsets[0]=0; - for (int i=1; i<(int)_distant_domains.size();i++) - offsets[i]=offsets[i-1]+_numbers[i-1]; - - for (int i=0; i<(int)_mapping.size(); i++) - { - int offset= offsets[_mapping[i].first]; - _comm_buffer[offset*2]=idproc; - _comm_buffer[offset*2+1]=_mapping[i].second; - offsets[_mapping[i].first]++; - } - return _comm_buffer; - } - - void unserialize(int nbprocs, int* sizes,int nbtarget, int* targetrank, int* commbuffer) - { - int total_size=0; - for (int i=0; i< nbprocs; i++) - total_size+=sizes[i]; - - _mapping.resize(total_size); - _buffer_index=new int[total_size]; - int indmap=0; - for (int i=0; i0) - { - _numbers[index]=sizes[targetrank[i]]; - _domains[index]=i; - index++; - } - } - _send_counts=new int[nbprocs]; - for (int i=0; i > _mapping; + std::set _distant_domains; + int* _numbers; + int* _domains; + int* _comm_buffer; + int* _buffer_index; + int* _send_counts; + - void computeNumbers() - { - std::map counts; - if (_numbers==0) - { - _numbers=new int[nbDistantDomains()]; - _domains=new int[nbDistantDomains()]; - for (int i=0; i<(int)_mapping.size(); i++) - { - if ( counts.find(_mapping[i].first) == counts.end()) - counts.insert(std::make_pair(_mapping[i].first,1)); - else - (counts[_mapping[i].first])++; - } - int counter=0; - for (std::map::const_iterator iter=counts.begin(); - iter!=counts.end(); - iter++) - { - _numbers[counter]=iter->second; - _domains[counter]=iter->first; - counter++; - } - } - } ++ void computeNumbers(); + }; +} + +#endif diff --cc medtool/src/ParaMEDMEM/ExplicitTopology.cxx index a624623a9,000000000..4facf53e0 mode 100644,000000..100644 --- a/medtool/src/ParaMEDMEM/ExplicitTopology.cxx +++ b/medtool/src/ParaMEDMEM/ExplicitTopology.cxx @@@ -1,109 -1,0 +1,114 @@@ +// Copyright (C) 2007-2015 CEA/DEN, EDF R&D +// +// 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +// +// See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com +// + +#include "CommInterface.hxx" +#include "ProcessorGroup.hxx" +#include "MPIProcessorGroup.hxx" +#include "ParaMESH.hxx" +#include "Topology.hxx" +#include "ExplicitTopology.hxx" +#include "BlockTopology.hxx" +#include "ComponentTopology.hxx" + +#include +#include + +using namespace std; +namespace ParaMEDMEM +{ + ++ExplicitTopology::ExplicitTopology(): ++ _proc_group(NULL), _nb_elems(0), _nb_components(0), ++ _loc2glob(NULL), _glob2loc() ++ {} ++ +ExplicitTopology::ExplicitTopology(const ParaMESH& paramesh ): +_proc_group(paramesh.getBlockTopology()->getProcGroup()), +_nb_components(1) +{ + _nb_elems=paramesh.getCellMesh()->getNumberOfCells(); + const int* global=paramesh.getGlobalNumberingCell(); + _loc2glob=new int[_nb_elems]; + + for (int i=0; i<_nb_elems; i++) + { + _loc2glob[i]=global[i]; + _glob2loc[global[i]]=i; + } +} + +ExplicitTopology::ExplicitTopology(const ExplicitTopology& topo, int nb_components) +{ + _proc_group = topo._proc_group; + _nb_elems = topo._nb_elems; + _nb_components = nb_components; + _loc2glob=new int[_nb_elems]; + for (int i=0; i<_nb_elems; i++) + { + _loc2glob[i]=topo._loc2glob[i]; + } + _glob2loc=topo._glob2loc; +} + + +ExplicitTopology::~ExplicitTopology() +{ + if (_loc2glob != 0) delete[] _loc2glob; +} + + +/*! Serializes the data contained in the Explicit Topology + * for communication purposes*/ +void ExplicitTopology::serialize(int* & serializer, int& size) const +{ + vector buffer; + + buffer.push_back(_nb_elems); + for (int i=0; i<_nb_elems; i++) + { + buffer.push_back(_loc2glob[i]); + } + + serializer=new int[buffer.size()]; + size= buffer.size(); + copy(buffer.begin(), buffer.end(), serializer); + +} +/*! Unserializes the data contained in the Explicit Topology + * after communication. Uses the same structure as the one used for serialize() + * + * */ +void ExplicitTopology::unserialize(const int* serializer,const CommInterface& comm_interface) +{ + const int* ptr_serializer=serializer; + cout << "unserialize..."< +#include +#include + +namespace ParaMEDMEM +{ + class ParaMESH; + class Topology; + class ComponentTopology; + ++ /*! ++ * \anchor ExplicitTopology-det ++ * ++ * An ExplicitTopology typically represents the split of a mesh among the processors of ++ * a common ProcessorGroup. Each processor gets a user-defined part of the cells in the mesh. ++ * \sa BlockTopology ++ */ + class ExplicitTopology : public Topology + { + public: - ExplicitTopology() { } ++ ExplicitTopology(); + ExplicitTopology( const ExplicitTopology& topo, int nbcomponents); + ExplicitTopology(const ParaMESH &mesh); + virtual ~ExplicitTopology(); + + inline int getNbElements()const; + inline int getNbLocalElements() const; + const ProcessorGroup* getProcGroup()const { return _proc_group; } + int localToGlobal (const std::pair local) const { return localToGlobal(local.second); } + inline int localToGlobal(int) const; + inline int globalToLocal(int) const; + void serialize(int* & serializer, int& size) const ; + void unserialize(const int* serializer, const CommInterface& comm_interface); + int getNbComponents() const { return _nb_components; } + private: + //Processor group + const ProcessorGroup* _proc_group; + //nb of elements + int _nb_elems; + //nb of components + int _nb_components; + //mapping local to global + int* _loc2glob; + //mapping global to local + INTERP_KERNEL::HashMap _glob2loc; + }; + + //!converts a pair to a global number + inline int ExplicitTopology::globalToLocal(const int global) const + { + return (_glob2loc.find(global))->second;; + } + + //!converts local number to a global number + int ExplicitTopology::localToGlobal(int local) const + { + return _loc2glob[local]; + } + + //!Retrieves the number of elements for a given topology + inline int ExplicitTopology::getNbElements() const + { + return _nb_elems; + } + + //Retrieves the local number of elements + inline int ExplicitTopology::getNbLocalElements()const + { + return _glob2loc.size(); + } +} + + +#endif diff --cc medtool/src/ParaMEDMEM/InterpKernelDEC.cxx index a7557e509,000000000..7f1be4b36 mode 100644,000000..100644 --- a/medtool/src/ParaMEDMEM/InterpKernelDEC.cxx +++ b/medtool/src/ParaMEDMEM/InterpKernelDEC.cxx @@@ -1,292 -1,0 +1,310 @@@ +// Copyright (C) 2007-2015 CEA/DEN, EDF R&D +// +// 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +// +// See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com +// + +#include +#include "CommInterface.hxx" +#include "Topology.hxx" +#include "BlockTopology.hxx" +#include "ComponentTopology.hxx" +#include "ParaFIELD.hxx" +#include "MPIProcessorGroup.hxx" +#include "ParaMESH.hxx" +#include "DEC.hxx" +#include "InterpolationMatrix.hxx" +#include "InterpKernelDEC.hxx" +#include "ElementLocator.hxx" + +namespace ParaMEDMEM +{ + + /*! + \anchor InterpKernelDEC-det + \class InterpKernelDEC + - \section dec-over Overview ++ \section InterpKernelDEC-over Overview + - The InterpKernelDEC enables the \ref InterpKerRemapGlobal "remapping" of fields between two parallel codes. - This remapping is based on the computation of intersection volumes between elements from code A - and elements from code B. The computation is possible for 3D meshes, 2D meshes, and 3D-surface - meshes. Dimensions must be similar for code A and code B (for instance, though it could be ++ The InterpKernelDEC enables the \ref InterpKerRemapGlobal "remapping" (or interpolation) of fields between ++ two parallel codes. ++ ++ The projection ++ methodology is based on the algorithms of %INTERP_KERNEL, that is to say, they work in a similar fashion than ++ what the \ref remapper "sequential remapper" does. The following \ref discretization "projection methods" ++ are supported: P0->P0 (the most common case), P1->P0, P0->P1. ++ ++ The computation is possible for 3D meshes, 2D meshes, and 3D-surface ++ meshes. Dimensions must be identical for code A and code B (for instance, though it could be + desirable, it is not yet possible to couple 3D surfaces with 2D surfaces). + - In the present version, only fields lying on elements are considered. ++ The name "InterpKernelDEC" comes from the fact that this class uses exactly the same algorithms ++ as the sequential remapper. Both this class and the sequential ++ \ref ParaMEDMEM::MEDCouplingRemapper "MEDCouplingRemapper" are built on top of the %INTERP_KERNEL ++ algorithms (notably the computation of the intersection volumes). ++ ++ Among the important properties inherited from the parent abstract class \ref DisjointDEC-det "DisjointDEC", ++ the two \ref MPIProcessorGroup-det "processor groups" (source and target) must have a void intersection. + - \image html NonCoincident_small.png "Example showing the transfer from a field based on a - quadrangular mesh to a triangular mesh. In a P0-P0 interpolation, to obtain the value on a triangle, - the values on quadrangles are weighted by their intersection area and summed." ++ \image html NonCoincident_small.png "Transfer of a field supported by a quadrangular mesh to a triangular mesh". + - \image latex NonCoincident_small.eps "Example showing the transfer from a field based on a quadrangular - mesh to a triangular mesh. In a P0-P0 interpolation, to obtain the value on a triangle, the values - on quadrangles are weighted by their intersection area and summed." ++ \image latex NonCoincident_small.eps "Transfer of a field supported by a quadrangular mesh to a triangular mesh" ++ ++ In the figure above we see the transfer of a field based on a quadrangular mesh to a new field supported by ++ a triangular mesh. In a P0-P0 interpolation, to obtain the value on a triangle, the values on the ++ quadrangles are weighted by their intersection area and summed. + + A typical use of InterpKernelDEC encompasses two distinct phases : + - A setup phase during which the intersection volumes are computed and the communication structures are + setup. This corresponds to calling the InterpKernelDEC::synchronize() method. - - A use phase during which the remappings are actually performed. This corresponds to the calls to ++ - A running phase during which the projections are actually performed. This corresponds to the calls to + sendData() and recvData() which actually trigger the data exchange. The data exchange are synchronous + in the current version of the library so that recvData() and sendData() calls must be synchronized + on code A and code B processor groups. + - The following code excerpt illutrates a typical use of the InterpKernelDEC class. ++ The following code excerpt illustrates a typical use of the InterpKernelDEC class. + + \code + ... + InterpKernelDEC dec(groupA, groupB); + dec.attachLocalField(field); + dec.synchronize(); + if (groupA.containsMyRank()) + dec.recvData(); + else if (groupB.containsMyRank()) + dec.sendData(); + ... + \endcode + A \ref InterpKerRemapGlobal "remapping" of the field from the source mesh to the target mesh is performed by + the function synchronise(), which computes the interpolation matrix. + + Computing the field on the receiving side can be expressed in terms of a matrix-vector product : + \f$ \phi_t=W.\phi_s\f$, with \f$ \phi_t \f$ the field on the target side and \f$ \phi_s \f$ the field + on the source side. + When remapping a 3D surface to another 3D surface, a projection phase is necessary to match elements + from both sides. Care must be taken when defining this projection to obtain a + \ref InterpKerRemapGlobal "conservative remapping". + + In the P0-P0 case, this matrix is a plain rectangular matrix with coefficients equal to the + intersection areas between triangle and quadrangles. For instance, in the above figure, the matrix + is : + + \f[ + \begin{tabular}{|cccc|} + 0.72 & 0 & 0.2 & 0 \\ + 0.46 & 0 & 0.51 & 0.03\\ + 0.42 & 0.53 & 0 & 0.05\\ + 0 & 0 & 0.92 & 0.05 \\ + \end{tabular} + \f] + - - - \section interpkerneldec_options Options - On top of \ref dec_options, options supported by %InterpKernelDEC objects are - related to the underlying Intersector class. ++ \section InterpKernelDEC-options Options ++ On top of the usual \ref ParaMEDMEM::DECOptions "DEC options", the options supported by %InterpKernelDEC objects are ++ related to the underlying \ref InterpKerIntersectors "intersector class". + All the options available in the intersector objects are - available for the %InterpKernelDEC object. The various options available for * intersectors can ++ available for the %InterpKernelDEC object. The various options available for intersectors can + be reviewed in \ref InterpKerIntersectors. + + For instance : + \verbatim + InterpKernelDEC dec(source_group, target_group); + dec.attachLocalField(field); - dec.setOptions("DoRotate",false); - dec.setOptions("Precision",1e-12); ++ dec.setDoRotate(false); ++ dec.setPrecision(1e-12); + dec.synchronize(); + \endverbatim + + \warning{ Options must be set before calling the synchronize method. } + */ + - InterpKernelDEC::InterpKernelDEC():_interpolation_matrix(0) ++ InterpKernelDEC::InterpKernelDEC(): ++ DisjointDEC(), ++ _nb_distant_points(0), _distant_coords(0), ++ _distant_locations(0), _interpolation_matrix(0) + { + } + + /*! + This constructor creates an InterpKernelDEC which has \a source_group as a working side + and \a target_group as an idle side. All the processors will actually participate, but intersection computations will be performed on the working side during the \a synchronize() phase. + The constructor must be called synchronously on all processors of both processor groups. + + \param source_group working side ProcessorGroup + \param target_group lazy side ProcessorGroup + + */ + InterpKernelDEC::InterpKernelDEC(ProcessorGroup& source_group, ProcessorGroup& target_group): - DisjointDEC(source_group, target_group),_interpolation_matrix(0) ++ DisjointDEC(source_group, target_group), ++ _nb_distant_points(0), _distant_coords(0), ++ _distant_locations(0), _interpolation_matrix(0) + { + + } + + InterpKernelDEC::InterpKernelDEC(const std::set& src_ids, const std::set& trg_ids, - const MPI_Comm& world_comm):DisjointDEC(src_ids,trg_ids,world_comm), - _interpolation_matrix(0) ++ const MPI_Comm& world_comm): ++ DisjointDEC(src_ids,trg_ids,world_comm), ++ _nb_distant_points(0), _distant_coords(0), ++ _distant_locations(0), _interpolation_matrix(0) + { + } + + InterpKernelDEC::~InterpKernelDEC() + { + if (_interpolation_matrix !=0) + delete _interpolation_matrix; + } + + /*! + \brief Synchronization process for exchanging topologies. + - This method prepares all the structures necessary for sending data from a processor group to the other. It uses the mesh underlying the fields that have been set with attachLocalField method. ++ This method prepares all the structures necessary for sending data from a processor group to the other. It uses the mesh ++ underlying the fields that have been set with attachLocalField method. + It works in four steps : - -# Bounding boxes are computed for each subdomain, ++ -# Bounding boxes are computed for each sub-domain, + -# The lazy side mesh parts that are likely to intersect the working side local processor are sent to the working side, + -# The working side calls the interpolation kernel to compute the intersection between local and imported mesh. + -# The lazy side is updated so that it knows the structure of the data that will be sent by + the working side during a \a sendData() call. + + */ + void InterpKernelDEC::synchronize() + { + if(!isInUnion()) + return ; + delete _interpolation_matrix; + _interpolation_matrix = new InterpolationMatrix (_local_field, *_source_group,*_target_group,*this,*this); + + //setting up the communication DEC on both sides + if (_source_group->containsMyRank()) + { + //locate the distant meshes + ElementLocator locator(*_local_field, *_target_group, *_source_group); + //transfering option from InterpKernelDEC to ElementLocator + locator.copyOptions(*this); + MEDCouplingPointSet* distant_mesh=0; + int* distant_ids=0; + std::string distantMeth; + for (int i=0; i<_target_group->size(); i++) + { + // int idistant_proc = (i+_source_group->myRank())%_target_group->size(); + int idistant_proc=i; + + //gathers pieces of the target meshes that can intersect the local mesh + locator.exchangeMesh(idistant_proc,distant_mesh,distant_ids); + if (distant_mesh !=0) + { + locator.exchangeMethod(_method,idistant_proc,distantMeth); + //adds the contribution of the distant mesh on the local one + int idistant_proc_in_union=_union_group->translateRank(_target_group,idistant_proc); + //std::cout <<"add contribution from proc "<myRank()<addContribution(*distant_mesh,idistant_proc_in_union,distant_ids,_method,distantMeth); + distant_mesh->decrRef(); + delete [] distant_ids; + distant_mesh=0; + distant_ids=0; + } + } + _interpolation_matrix->finishContributionW(locator); + } + + if (_target_group->containsMyRank()) + { + ElementLocator locator(*_local_field, *_source_group, *_target_group); + //transfering option from InterpKernelDEC to ElementLocator + locator.copyOptions(*this); + MEDCouplingPointSet* distant_mesh=0; + int* distant_ids=0; + for (int i=0; i<_source_group->size(); i++) + { + // int idistant_proc = (i+_target_group->myRank())%_source_group->size(); + int idistant_proc=i; + //gathers pieces of the target meshes that can intersect the local mesh + locator.exchangeMesh(idistant_proc,distant_mesh,distant_ids); + //std::cout << " Data sent from "<<_union_group->myRank()<<" to source proc "<< idistant_proc<decrRef(); + delete [] distant_ids; + distant_mesh=0; + distant_ids=0; + } + } + _interpolation_matrix->finishContributionL(locator); + } + _interpolation_matrix->prepare(); + } + + + /*! + Receives the data whether the processor is on the working side or on the lazy side. It must match a \a sendData() call on the other side. + */ + void InterpKernelDEC::recvData() + { + if (_source_group->containsMyRank()) + _interpolation_matrix->transposeMultiply(*_local_field->getField()); + else if (_target_group->containsMyRank()) + { + _interpolation_matrix->multiply(*_local_field->getField()); + if (getForcedRenormalization()) + renormalizeTargetField(getMeasureAbsStatus()); + } + } + + + /*! + Receives the data at time \a time in asynchronous mode. The value of the field + will be time-interpolated from the field values received. + \param time time at which the value is desired + */ + void InterpKernelDEC::recvData( double time ) + { + _interpolation_matrix->getAccessDEC()->setTime(time); + recvData() ; + } + + /*! + Sends the data whether the processor is on the working side or on the lazy side. + It must match a recvData() call on the other side. + */ + void InterpKernelDEC::sendData() + { + if (_source_group->containsMyRank()) + { + + _interpolation_matrix->multiply(*_local_field->getField()); + if (getForcedRenormalization()) + renormalizeTargetField(getMeasureAbsStatus()); + + } + else if (_target_group->containsMyRank()) + _interpolation_matrix->transposeMultiply(*_local_field->getField()); + } + + /*! + Sends the data available at time \a time in asynchronous mode. + \param time time at which the value is available + \param deltatime time interval between the value presently sent and the next one. + */ + void InterpKernelDEC::sendData( double time , double deltatime ) + { + _interpolation_matrix->getAccessDEC()->setTime(time,deltatime); + sendData() ; + } + +} diff --cc medtool/src/ParaMEDMEM/InterpolationMatrix.hxx index 97fc2a300,000000000..b60c9ee54 mode 100644,000000..100644 --- a/medtool/src/ParaMEDMEM/InterpolationMatrix.hxx +++ b/medtool/src/ParaMEDMEM/InterpolationMatrix.hxx @@@ -1,109 -1,0 +1,111 @@@ +// Copyright (C) 2007-2015 CEA/DEN, EDF R&D +// +// 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +// +// See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com +// + +#ifndef __INTERPOLATIONMATRIX_HXX__ +#define __INTERPOLATIONMATRIX_HXX__ + +#include "MPIAccessDEC.hxx" +#include "MxN_Mapping.hxx" +#include "InterpolationOptions.hxx" +#include "DECOptions.hxx" + +namespace ParaMEDMEM +{ + class ElementLocator; + - /**! class InterpolationMatrix ++ /*! ++ Internal class, not part of the public API. ++ + This class enables the storage of an interpolation matrix Wij mapping - source field Sj to target field Ti via Ti=Vi^(-1).Wij.Sj. ++ a source field Sj to a target field Ti via Ti=Vi^(-1).Wij.Sj. + The matrix is built and stored on the processors belonging to the source + group. + */ + class InterpolationMatrix : public INTERP_KERNEL::InterpolationOptions, + public DECOptions + { + public: + + InterpolationMatrix(const ParaMEDMEM::ParaFIELD *source_field, + const ProcessorGroup& source_group, + const ProcessorGroup& target_group, + const DECOptions& dec_opt, + const InterpolationOptions& i_opt); + + + virtual ~InterpolationMatrix(); + void addContribution(MEDCouplingPointSet& distant_support, int iproc_distant, + const int* distant_elems, const std::string& srcMeth, const std::string& targetMeth); + void finishContributionW(ElementLocator& elementLocator); + void finishContributionL(ElementLocator& elementLocator); + void multiply(MEDCouplingFieldDouble& field) const; + void transposeMultiply(MEDCouplingFieldDouble& field)const; + void prepare(); + int getNbRows() const { return _row_offsets.size(); } + MPIAccessDEC* getAccessDEC() { return _mapping.getAccessDEC(); } + private: + void computeConservVolDenoW(ElementLocator& elementLocator); + void computeIntegralDenoW(ElementLocator& elementLocator); + void computeRevIntegralDenoW(ElementLocator& elementLocator); + void computeGlobConstraintDenoW(ElementLocator& elementLocator); + void computeConservVolDenoL(ElementLocator& elementLocator); + void computeIntegralDenoL(ElementLocator& elementLocator); + void computeRevIntegralDenoL(ElementLocator& elementLocator); + + void computeLocalColSum(std::vector& res) const; + void computeLocalRowSum(const std::vector& distantProcs, std::vector >& resPerProcI, + std::vector >& resPerProcD) const; + void computeGlobalRowSum(ElementLocator& elementLocator, std::vector >& denoStrorage, std::vector >& denoStrorageInv); + void computeGlobalColSum(std::vector >& denoStrorage); + void resizeGlobalColSum(std::vector >& denoStrorage); + void fillDSFromVM(int iproc_distant, const int* distant_elems, const std::vector< std::map >& values, MEDCouplingFieldDouble *surf); + void serializeMe(std::vector< std::vector< std::map > >& data1, std::vector& data2) const; + void initialize(); + void findAdditionnalElements(ElementLocator& elementLocator, std::vector >& elementsToAdd, + const std::vector >& resPerProcI, const std::vector >& globalIdsPartial); + void addGhostElements(const std::vector& distantProcs, const std::vector >& elementsToAdd); + int mergePolicies(const std::vector& policyPartial); + void mergeRowSum(const std::vector< std::vector >& rowsPartialSumD, const std::vector< std::vector >& globalIdsPartial, + std::vector& globalIdsLazySideInteraction, std::vector& sumCorresponding); + void mergeRowSum2(const std::vector< std::vector >& globalIdsPartial, std::vector< std::vector >& rowsPartialSumD, + const std::vector& globalIdsLazySideInteraction, const std::vector& sumCorresponding); + void mergeRowSum3(const std::vector< std::vector >& globalIdsPartial, std::vector< std::vector >& rowsPartialSumD); + void mergeCoeffs(const std::vector& procsInInteraction, const std::vector< std::vector >& rowsPartialSumI, + const std::vector >& globalIdsPartial, std::vector >& denoStrorageInv); + void divideByGlobalRowSum(const std::vector& distantProcs, const std::vector >& resPerProcI, + const std::vector >& resPerProcD, std::vector >& deno); + private: + bool isSurfaceComputationNeeded(const std::string& method) const; + private: + const ParaMEDMEM::ParaFIELD *_source_field; + std::vector _row_offsets; + std::map, int > _col_offsets; + MEDCouplingPointSet *_source_support; + MxN_Mapping _mapping; + + const ProcessorGroup& _source_group; + const ProcessorGroup& _target_group; + std::vector< std::vector > _target_volume; + std::vector > > _coeffs; + std::vector > _deno_multiply; + std::vector > _deno_reverse_multiply; + }; +} + +#endif diff --cc medtool/src/ParaMEDMEM/LinearTimeInterpolator.hxx index 0128e42b2,000000000..76eca3fc7 mode 100644,000000..100644 --- a/medtool/src/ParaMEDMEM/LinearTimeInterpolator.hxx +++ b/medtool/src/ParaMEDMEM/LinearTimeInterpolator.hxx @@@ -1,47 -1,0 +1,52 @@@ +// Copyright (C) 2007-2015 CEA/DEN, EDF R&D +// +// 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +// +// See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com +// + +#ifndef __LINEARTIMEINTERPOLATOR_HXX__ +#define __LINEARTIMEINTERPOLATOR_HXX__ + +#include "TimeInterpolator.hxx" + +#include +#include + +namespace ParaMEDMEM +{ + class DEC; + ++ /*! ++ * Internal class, not part of the public API. ++ * ++ * Linear interpolation of a block of data between two given times. ++ */ + class LinearTimeInterpolator : public TimeInterpolator + { + public: + LinearTimeInterpolator( double InterpPrecision=0, int nStepBefore=1, + int nStepAfter=1 ) ; + virtual ~LinearTimeInterpolator(); + void doInterp( double time0, double time1, double time, int recvcount, + int nbuff0, int nbuff1, + int **recvbuff0, int **recvbuff1, int *result ); + void doInterp( double time0, double time1, double time, int recvcount, + int nbuff0, int nbuff1, + double **recvbuff0, double **recvbuff1, double *result ); + }; +} + +#endif diff --cc medtool/src/ParaMEDMEM/MPIAccessDEC.cxx index f8a0e1002,000000000..18184dc27 mode 100644,000000..100644 --- a/medtool/src/ParaMEDMEM/MPIAccessDEC.cxx +++ b/medtool/src/ParaMEDMEM/MPIAccessDEC.cxx @@@ -1,1057 -1,0 +1,1057 @@@ +// Copyright (C) 2007-2015 CEA/DEN, EDF R&D +// +// 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +// +// See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com +// + +#include "MPIAccessDEC.hxx" + +#include + +using namespace std; + +namespace ParaMEDMEM +{ + + /*! + This constructor creates an MPIAccessDEC which has \a source_group as a working side + and \a target_group as an idle side. + The constructor must be called synchronously on all processors of both processor groups. + + \param source_group working side ProcessorGroup + \param target_group lazy side ProcessorGroup + \param Asynchronous Communication mode (default asynchronous) + \param nStepBefore Number of Time step needed for the interpolation before current time + \param nStepAfter Number of Time step needed for the interpolation after current time + + */ + + MPIAccessDEC::MPIAccessDEC( const ProcessorGroup& source_group, + const ProcessorGroup& target_group, + bool Asynchronous ) + { + + ProcessorGroup * union_group = source_group.fuse(target_group) ; + int i ; + std::set procs; + for ( i = 0 ; i < union_group->size() ; i++ ) + { + procs.insert(i) ; + } + MPIProcessorGroup *mpilg = static_cast(const_cast(&source_group)); + _MPI_union_group = new ParaMEDMEM::MPIProcessorGroup( union_group->getCommInterface(),procs,mpilg->getWorldComm()); + delete union_group ; + _my_rank = _MPI_union_group->myRank() ; + _group_size = _MPI_union_group->size() ; + _MPI_access = new MPIAccess( _MPI_union_group ) ; + _asynchronous = Asynchronous ; + _time_messages = new vector< vector< TimeMessage > > ; + _time_messages->resize( _group_size ) ; + _out_of_time = new vector< bool > ; + _out_of_time->resize( _group_size ) ; + _data_messages_recv_count = new vector< int > ; + _data_messages_recv_count->resize( _group_size ) ; + for ( i = 0 ; i < _group_size ; i++ ) + { + (*_out_of_time)[i] = false ; + (*_data_messages_recv_count)[i] = 0 ; + } + _data_messages_type = new vector< MPI_Datatype > ; + _data_messages_type->resize( _group_size ) ; + _data_messages = new vector< vector< void * > > ; + _data_messages->resize( _group_size ) ; + _time_interpolator = NULL ; + _map_of_send_buffers = new map< int , SendBuffStruct * > ; + } + + MPIAccessDEC::~MPIAccessDEC() + { + checkFinalSent() ; + checkFinalRecv() ; + delete _MPI_union_group ; + delete _MPI_access ; + if ( _time_interpolator ) + delete _time_interpolator ; + if ( _time_messages ) + delete _time_messages ; + if ( _out_of_time ) + delete _out_of_time ; + if ( _data_messages_recv_count ) + delete _data_messages_recv_count ; + if ( _data_messages_type ) + delete _data_messages_type ; + if ( _data_messages ) + delete _data_messages ; + if ( _map_of_send_buffers ) + delete _map_of_send_buffers ; + } + + void MPIAccessDEC::setTimeInterpolator( TimeInterpolationMethod aTimeInterp , + double InterpPrecision, int nStepBefore, + int nStepAfter ) + { + if ( _time_interpolator ) + delete _time_interpolator ; + switch ( aTimeInterp ) + { + case WithoutTimeInterp : + _time_interpolator = NULL ; + _n_step_before = 0 ; + _n_step_after = 0 ; + break ; + case LinearTimeInterp : + _time_interpolator = new LinearTimeInterpolator( InterpPrecision , nStepBefore , + nStepAfter ) ; + _n_step_before = nStepBefore ; + _n_step_after = nStepAfter ; + int i ; + for ( i = 0 ; i < _group_size ; i++ ) + { + (*_time_messages)[ i ].resize( _n_step_before + _n_step_after ) ; + (*_data_messages)[ i ].resize( _n_step_before + _n_step_after ) ; + int j ; + for ( j = 0 ; j < _n_step_before + _n_step_after ; j++ ) + { + (*_time_messages)[ i ][ j ].time = -1 ; + (*_time_messages)[ i ][ j ].deltatime = -1 ; + (*_data_messages)[ i ][ j ] = NULL ; + } + } + break ; + } + } + + /*! + Send sendcount datas from sendbuf[offset] with type sendtype to target of IntraCommunicator + (Internal Protected method) + + Returns the request identifier SendRequestId + + */ + int MPIAccessDEC::send( void* sendbuf, int sendcount , int offset , + MPI_Datatype sendtype , int target , int &SendRequestId ) + { + int sts ; + if ( _asynchronous ) + { + if ( sendtype == MPI_INT ) + { + sts = _MPI_access->ISend( &((int *) sendbuf)[offset] , sendcount , sendtype , + target , SendRequestId ) ; + } + else + { + sts = _MPI_access->ISend( &((double *) sendbuf)[offset] , sendcount , sendtype , + target , SendRequestId ) ; + } + } + else + { + if ( sendtype == MPI_INT ) + { + sts = _MPI_access->send( &((int *) sendbuf)[offset] , sendcount , sendtype , + target , SendRequestId ) ; + } + else + { + sts = _MPI_access->send( &((double *) sendbuf)[offset] , sendcount , sendtype , + target , SendRequestId ) ; + } + } + return sts ; + } + + /*! + Receive recvcount datas to recvbuf[offset] with type recvtype from target of IntraCommunicator + (Internal Protected method) + + Returns the request identifier RecvRequestId + + */ + int MPIAccessDEC::recv( void* recvbuf, int recvcount , int offset , + MPI_Datatype recvtype , int target , int &RecvRequestId ) + { + int sts ; + if ( _asynchronous ) + { + if ( recvtype == MPI_INT ) + { + sts = _MPI_access->IRecv( &((int *) recvbuf)[offset] , recvcount , recvtype , + target , RecvRequestId ) ; + } + else + { + sts = _MPI_access->IRecv( &((double *) recvbuf)[offset] , recvcount , recvtype , + target , RecvRequestId ) ; + } + } + else + { + if ( recvtype == MPI_INT ) + { + sts = _MPI_access->recv( &((int *) recvbuf)[offset] , recvcount , recvtype , + target , RecvRequestId ) ; + } + else + { + sts = _MPI_access->recv( &((double *) recvbuf)[offset] , recvcount , recvtype , + target , RecvRequestId ) ; + } + } + return sts ; + } + + /*! + Send sendcount datas from sendbuf[offset] with type sendtype to target of IntraCommunicator + Receive recvcount datas to recvbuf[offset] with type recvtype from target of IntraCommunicator + (Internal Protected method) + + Returns the request identifier SendRequestId + Returns the request identifier RecvRequestId + + */ + int MPIAccessDEC::sendRecv( void* sendbuf, int sendcount , int sendoffset , + MPI_Datatype sendtype , + void* recvbuf, int recvcount , int recvoffset , + MPI_Datatype recvtype , int target , + int &SendRequestId , int &RecvRequestId ) + { + int sts ; + if ( _asynchronous ) + { + if ( sendtype == MPI_INT ) + { + if ( recvtype == MPI_INT ) + { + sts = _MPI_access->ISendRecv( &((int *) sendbuf)[sendoffset] , sendcount , + sendtype , target , SendRequestId , + &((int *) recvbuf)[recvoffset] , recvcount , + recvtype , target , RecvRequestId ) ; + } + else + { + sts = _MPI_access->ISendRecv( &((int *) sendbuf)[sendoffset] , sendcount , + sendtype , target , SendRequestId , + &((double *) recvbuf)[recvoffset] , + recvcount , recvtype , target , RecvRequestId ) ; + } + } + else + { + if ( recvtype == MPI_INT ) + { + sts = _MPI_access->ISendRecv( &((double *) sendbuf)[sendoffset] , sendcount , + sendtype , target , SendRequestId , + &((int *) recvbuf)[recvoffset] , + recvcount , recvtype , target , RecvRequestId ) ; + } + else + { + sts = _MPI_access->ISendRecv( &((double *) sendbuf)[sendoffset] , sendcount , + sendtype , target , SendRequestId , + &((double *) recvbuf)[recvoffset] , + recvcount , recvtype , target , RecvRequestId ) ; + } + } + } + else + { + if ( sendtype == MPI_INT ) + { + if ( recvtype == MPI_INT ) + { + sts = _MPI_access->sendRecv( &((int *) sendbuf)[sendoffset] , sendcount , + sendtype , target , SendRequestId , + &((int *) recvbuf)[recvoffset] , recvcount , + recvtype , target , RecvRequestId ) ; + } + else + { + sts = _MPI_access->sendRecv( &((int *) sendbuf)[sendoffset] , sendcount , + sendtype , target , SendRequestId , + &((double *) recvbuf)[recvoffset] , + recvcount , recvtype , target , RecvRequestId ) ; + } + } + else + { + if ( recvtype == MPI_INT ) + { + sts = _MPI_access->sendRecv( &((double *) sendbuf)[sendoffset] , sendcount , + sendtype , target , SendRequestId , + &((int *) recvbuf)[recvoffset] , + recvcount , recvtype , target , RecvRequestId ) ; + } + else + { + sts = _MPI_access->sendRecv( &((double *) sendbuf)[sendoffset] , sendcount , + sendtype , target , SendRequestId , + &((double *) recvbuf)[recvoffset] , + recvcount , recvtype , target , RecvRequestId ) ; + } + } + } + return sts ; + } + + /*! + Send sendcount datas from sendbuf[offset] with type sendtype to all targets of IntraCommunicator + Receive recvcount datas to recvbuf[offset] with type recvtype from all targets of IntraCommunicator + + */ + int MPIAccessDEC::allToAll( void* sendbuf, int sendcount, MPI_Datatype sendtype , + void* recvbuf, int recvcount, MPI_Datatype recvtype ) + { + if ( _time_interpolator ) + { + return allToAllTime( sendbuf, sendcount, sendtype , recvbuf, recvcount, recvtype ) ; + } + int sts ; + int target ; + int sendoffset = 0 ; + int recvoffset = 0 ; + int SendRequestId ; + int RecvRequestId ; + + //Free of SendBuffers + if ( _asynchronous ) + checkSent() ; + + //DoSend + DoRecv : SendRecv + SendBuffStruct * aSendDataStruct = NULL ; + if ( _asynchronous && sendbuf ) + { + aSendDataStruct = new SendBuffStruct ; + aSendDataStruct->SendBuffer = sendbuf ; + aSendDataStruct->Counter = 0 ; + aSendDataStruct->DataType = sendtype ; + } + for ( target = 0 ; target < _group_size ; target++ ) + { + sts = sendRecv( sendbuf , sendcount , sendoffset , sendtype , + recvbuf , recvcount , recvoffset , recvtype , + target , SendRequestId , RecvRequestId ) ; + if ( _asynchronous && sendbuf && sendcount ) + { + aSendDataStruct->Counter += 1 ; + (*_map_of_send_buffers)[ SendRequestId ] = aSendDataStruct ; + } + sendoffset += sendcount ; + recvoffset += recvcount ; + } + if ( !_asynchronous && sendbuf ) + { + if ( sendtype == MPI_INT ) + { + delete [] (int *) sendbuf ; + } + else + { + delete [] (double *) sendbuf ; + } + } + return sts ; + } + + /*! + Send sendcounts[target] datas from sendbuf[sdispls[target]] with type sendtype to all targets of IntraCommunicator + Receive recvcounts[target] datas to recvbuf[rdispls[target]] with type recvtype from all targets of IntraCommunicator + + */ + int MPIAccessDEC::allToAllv( void* sendbuf, int* sendcounts, int* sdispls, + MPI_Datatype sendtype , + void* recvbuf, int* recvcounts, int* rdispls, + MPI_Datatype recvtype ) + { + if ( _time_interpolator ) + { + return allToAllvTime( sendbuf, sendcounts, sdispls, sendtype , + recvbuf, recvcounts, rdispls, recvtype ) ; + } + int sts ; + int target ; + int SendRequestId ; + int RecvRequestId ; + + //Free of SendBuffers + if ( _asynchronous ) + { + checkSent() ; + } + + //DoSend + DoRecv : SendRecv + SendBuffStruct * aSendDataStruct = NULL ; + if ( _asynchronous && sendbuf ) + { + aSendDataStruct = new SendBuffStruct ; + aSendDataStruct->SendBuffer = sendbuf ; + aSendDataStruct->Counter = 0 ; + aSendDataStruct->DataType = sendtype ; + } + for ( target = 0 ; target < _group_size ; target++ ) + { + if ( sendcounts[target] || recvcounts[target] ) + { + sts = sendRecv( sendbuf , sendcounts[target] , sdispls[target] , sendtype , + recvbuf , recvcounts[target] , rdispls[target] , recvtype , + target , SendRequestId , RecvRequestId ) ; + if ( _asynchronous && sendbuf && sendcounts[target]) + { + aSendDataStruct->Counter += 1 ; + (*_map_of_send_buffers)[ SendRequestId ] = aSendDataStruct ; + } + } + } + if ( !_asynchronous && sendbuf ) + { + if ( sendtype == MPI_INT ) + { + delete [] (int *) sendbuf ; + } + else + { + delete [] (double *) sendbuf ; + } + } + return sts ; + } + + /* + MPIAccessDEC and the management of SendBuffers : + ================================================= + + . In the collective communications collectives we send only parts of + the same buffer to each "target". So in asynchronous mode it is + necessary that all parts are free before to delete/free the + buffer. + + . We assume that buffers are allocated with a new double[]. so a + delete [] is done. + + . The structure SendBuffStruct permit to keep the adress of the buffer + and to manage a reference counter of that buffer. It contains + also MPI_Datatype for the delete [] (double *) ... when the counter + is null. + + . The map _MapOfSendBuffers etablish the correspondance between each + RequestId given by a MPI_Access->ISend(...) and a SendBuffStruct + for each "target" of a part of the buffer. + + . All that concerns only asynchronous Send. In synchronous mode, + we delete senbuf just after the Send. + */ + + /* + MPIAccessDEC and the management of RecvBuffers : + ================================================= + + If there is no interpolation, no special action is done. + + With interpolation for each target : + ------------------------------------ + . We have _time_messages[target] which is a vector of TimesMessages. + We have 2 TimesMessages in our case with a linear interpolation. + They contain the previous time(t0)/deltatime and the last + time(t1)/deltatime. + + . We have _data_messages[target] which is a vector of DatasMessages. + We have 2 DatasMessages in our case with a linear interpolation. + They contain the previous datas at time(t0)/deltatime and at last + time(t1)/deltatime. + + . At time _t(t*) of current processus we do the interpolation of + the values of the 2 DatasMessages which are returned in the part of + recvbuf corresponding to the target with t0 < t* <= t1. + + . Because of the difference of "deltatimes" between processes, we + may have t0 < t1 < t* and there is an extrapolation. + + . The vectors _out_of_time, _DataMessagesRecvCount and _DataMessagesType + contain for each target true if t* > last t1, recvcount and + MPI_Datatype for the finalize of messages at the end. + */ + + /*! + Send a TimeMessage to all targets of IntraCommunicator + Receive the TimeMessages from targets of IntraCommunicator if necessary. + + Send sendcount datas from sendbuf[offset] with type sendtype to all targets of IntraCommunicator + Returns recvcount datas to recvbuf[offset] with type recvtype after an interpolation + with datas received from all targets of IntraCommunicator. + + */ + int MPIAccessDEC::allToAllTime( void* sendbuf, int sendcount , MPI_Datatype sendtype , + void* recvbuf, int recvcount , MPI_Datatype recvtype ) + { + int sts ; + int target ; + int sendoffset = 0 ; + int SendTimeRequestId ; + int SendDataRequestId ; + + if ( _time_interpolator == NULL ) + { + return MPI_ERR_OTHER ; + } + + //Free of SendBuffers + if ( _asynchronous ) + { + checkSent() ; + } + + //DoSend : Time + SendBuff + SendBuffStruct * aSendTimeStruct = NULL ; + SendBuffStruct * aSendDataStruct = NULL ; + if ( sendbuf && sendcount ) + { + TimeMessage * aSendTimeMessage = new TimeMessage ; + if ( _asynchronous ) + { + aSendTimeStruct = new SendBuffStruct ; + aSendTimeStruct->SendBuffer = aSendTimeMessage ; + aSendTimeStruct->Counter = 0 ; + aSendTimeStruct->DataType = _MPI_access->timeType() ; + aSendDataStruct = new SendBuffStruct ; + aSendDataStruct->SendBuffer = sendbuf ; + aSendDataStruct->Counter = 0 ; + aSendDataStruct->DataType = sendtype ; + } + aSendTimeMessage->time = _t ; + aSendTimeMessage->deltatime = _dt ; + for ( target = 0 ; target < _group_size ; target++ ) + { + sts = send( aSendTimeMessage , 1 , 0 , _MPI_access->timeType() , target , + SendTimeRequestId ) ; + sts = send( sendbuf , sendcount , sendoffset , sendtype , target , SendDataRequestId ) ; + if ( _asynchronous ) + { + aSendTimeStruct->Counter += 1 ; + (*_map_of_send_buffers)[ SendTimeRequestId ] = aSendTimeStruct ; + aSendDataStruct->Counter += 1 ; + (*_map_of_send_buffers)[ SendDataRequestId ] = aSendDataStruct ; + } + sendoffset += sendcount ; + } + if ( !_asynchronous ) + { + delete aSendTimeMessage ; + if ( sendtype == MPI_INT ) + { + delete [] (int *) sendbuf ; + } + else + { + delete [] (double *) sendbuf ; + } + } + } + + //CheckTime + DoRecv + DoInterp + if ( recvbuf && recvcount ) + { + for ( target = 0 ; target < _group_size ; target++ ) + { + int recvsize = recvcount*_MPI_access->extent( recvtype ) ; + checkTime( recvcount , recvtype , target , false ) ; + //=========================================================================== - //TODO : it is assumed actually that we have only 1 timestep before nad after ++ //TODO : it is assumed actually that we have only 1 timestep before and after + //=========================================================================== + if ( _time_interpolator && (*_time_messages)[target][0].time != -1 ) + { + if ( (*_out_of_time)[target] ) + { + cout << " =====================================================" << endl + << "Recv" << _my_rank << " <-- target " << target << " t0 " + << (*_time_messages)[target][0].time << " < t1 " + << (*_time_messages)[target][1].time << " < t* " << _t << endl + << " =====================================================" << endl ; + } + if ( recvtype == MPI_INT ) + { + _time_interpolator->doInterp( (*_time_messages)[target][0].time, + (*_time_messages)[target][1].time, _t, recvcount , + _n_step_before, _n_step_after, + (int **) &(*_data_messages)[target][0], + (int **) &(*_data_messages)[target][1], + &((int *)recvbuf)[target*recvcount] ) ; + } + else + { + _time_interpolator->doInterp( (*_time_messages)[target][0].time, + (*_time_messages)[target][1].time, _t, recvcount , + _n_step_before, _n_step_after, + (double **) &(*_data_messages)[target][0], + (double **) &(*_data_messages)[target][1], + &((double *)recvbuf)[target*recvcount] ) ; + } + } + else + { + char * buffdest = (char *) recvbuf ; + char * buffsrc = (char *) (*_data_messages)[target][1] ; + memcpy( &buffdest[target*recvsize] , buffsrc , recvsize ) ; + } + } + } + + return sts ; + } + + int MPIAccessDEC::allToAllvTime( void* sendbuf, int* sendcounts, int* sdispls, + MPI_Datatype sendtype , + void* recvbuf, int* recvcounts, int* rdispls, + MPI_Datatype recvtype ) + { + int sts ; + int target ; + int SendTimeRequestId ; + int SendDataRequestId ; + + if ( _time_interpolator == NULL ) + { + return MPI_ERR_OTHER ; + } + + //Free of SendBuffers + if ( _asynchronous ) + { + checkSent() ; + } + + /* + . DoSend : + + We create a TimeMessage (look at that structure in MPI_Access). + + If we are in asynchronous mode, we create two structures SendBuffStruct + aSendTimeStruct and aSendDataStruct that we fill. + + We fill the structure aSendTimeMessage with time/deltatime of + the current process. "deltatime" must be nul if it is the last step of + Time. + + After that for each "target", we Send the TimeMessage and the part + of sendbuf corresponding to that target. + + If we are in asynchronous mode, we increment the counter and we add + aSendTimeStruct and aSendDataStruct to _MapOfSendBuffers with the + identifiers SendTimeRequestId and SendDataRequestId returned by + MPI_Access->Send(...). + + And if we are in synchronous mode we delete the SendMessages. + */ + //DoSend : Time + SendBuff + SendBuffStruct * aSendTimeStruct = NULL ; + SendBuffStruct * aSendDataStruct = NULL ; + if ( sendbuf ) + { + TimeMessage * aSendTimeMessage = new TimeMessage ; + if ( _asynchronous ) + { + aSendTimeStruct = new SendBuffStruct ; + aSendTimeStruct->SendBuffer = aSendTimeMessage ; + aSendTimeStruct->Counter = 0 ; + aSendTimeStruct->DataType = _MPI_access->timeType() ; + aSendDataStruct = new SendBuffStruct ; + aSendDataStruct->SendBuffer = sendbuf ; + aSendDataStruct->Counter = 0 ; + aSendDataStruct->DataType = sendtype ; + } + aSendTimeMessage->time = _t ; + aSendTimeMessage->deltatime = _dt ; + for ( target = 0 ; target < _group_size ; target++ ) + { + if ( sendcounts[target] ) + { + sts = send( aSendTimeMessage , 1 , 0 , _MPI_access->timeType() , target , + SendTimeRequestId ) ; + sts = send( sendbuf , sendcounts[target] , sdispls[target] , sendtype , target , + SendDataRequestId ) ; + if ( _asynchronous ) + { + aSendTimeStruct->Counter += 1 ; + (*_map_of_send_buffers)[ SendTimeRequestId ] = aSendTimeStruct ; + aSendDataStruct->Counter += 1 ; + (*_map_of_send_buffers)[ SendDataRequestId ] = aSendDataStruct ; + } + } + } + if ( !_asynchronous ) + { + delete aSendTimeMessage ; + if ( sendtype == MPI_INT ) + { + delete [] (int *) sendbuf ; + } + else + { + delete [] (double *) sendbuf ; + } + } + } + + /* + . CheckTime + DoRecv + DoInterp + + For each target we call CheckTime + + If there is a TimeInterpolator and if the TimeMessage of the target + is not the first, we call the interpolator which return its + results in the part of the recv buffer corresponding to the "target". + + If not, there is a copy of received datas for that first step of time + in the part of the recv buffer corresponding to the "target". + */ + //CheckTime + DoRecv + DoInterp + if ( recvbuf ) + { + for ( target = 0 ; target < _group_size ; target++ ) + { + if ( recvcounts[target] ) + { + int recvsize = recvcounts[target]*_MPI_access->extent( recvtype ) ; + checkTime( recvcounts[target] , recvtype , target , false ) ; + //=========================================================================== + //TODO : it is assumed actually that we have only 1 timestep before nad after + //=========================================================================== + if ( _time_interpolator && (*_time_messages)[target][0].time != -1 ) + { + if ( (*_out_of_time)[target] ) + { + cout << " =====================================================" << endl + << "Recv" << _my_rank << " <-- target " << target << " t0 " + << (*_time_messages)[target][0].time << " < t1 " + << (*_time_messages)[target][1].time << " < t* " << _t << endl + << " =====================================================" << endl ; + } + if ( recvtype == MPI_INT ) + { + _time_interpolator->doInterp( (*_time_messages)[target][0].time, + (*_time_messages)[target][1].time, _t, + recvcounts[target] , _n_step_before, _n_step_after, + (int **) &(*_data_messages)[target][0], + (int **) &(*_data_messages)[target][1], + &((int *)recvbuf)[rdispls[target]] ) ; + } + else + { + _time_interpolator->doInterp( (*_time_messages)[target][0].time, + (*_time_messages)[target][1].time, _t, + recvcounts[target] , _n_step_before, _n_step_after, + (double **) &(*_data_messages)[target][0], + (double **) &(*_data_messages)[target][1], + &((double *)recvbuf)[rdispls[target]] ) ; + } + } + else + { + char * buffdest = (char *) recvbuf ; + char * buffsrc = (char *) (*_data_messages)[target][1] ; + memcpy( &buffdest[rdispls[target]*_MPI_access->extent( recvtype )] , buffsrc , + recvsize ) ; + } + } + } + } + + return sts ; + } + + /* + . CheckTime(recvcount , recvtype , target , UntilEnd) + + At the beginning, we read the first TimeMessage in + &(*_TimeMessages)[target][1] and the first DataMessage + in the allocated buffer (*_DataMessages)[target][1]. + + deltatime of TimesMessages must be nul if it is the last one. + + While : _t(t*) is the current time of the processus. + "while _t(t*) is greater than the time of the "target" + (*_TimeMessages)[target][1].time and + (*_TimeMessages)[target][1].deltatime is not nul", + So at the end of the while we have : + _t(t*) <= (*_TimeMessages)[target][1].time with + _t(t*) > (*_TimeMessages)[target][0].time + or we have the last TimeMessage of the "target". + + If it is the finalization of the recv of TimeMessages and + DataMessages (UntilEnd value is true), we execute the while + until (*_TimeMessages)[target][1].deltatime is nul. + + In the while : + We copy the last TimeMessage in the previoud TimeMessage and + we read a new TimeMessage + We delete the previous DataMessage. + We copy the last DataMessage pointer in the previous one. + We allocate a new last DataMessage buffer + (*_DataMessages)[target][1] and we read the corresponding + datas in that buffe. + + If the current time of the current process is greater than the + last time (*_TimeMessages)[target][1].time du target, we give + a true value to (*_OutOfTime)[target]. + (*_TimeMessages)[target][1].deltatime is nul. + */ + int MPIAccessDEC::checkTime( int recvcount , MPI_Datatype recvtype , int target , + bool UntilEnd ) + { + int sts = MPI_SUCCESS ; + int RecvTimeRequestId ; + int RecvDataRequestId ; + //Pour l'instant on cherche _time_messages[target][0] < _t <= _time_messages[target][1] + //=========================================================================== + //TODO : it is assumed actually that we have only 1 timestep before and after + // instead of _n_step_before and _n_step_after ... + //=========================================================================== + (*_data_messages_recv_count)[target] = recvcount ; + (*_data_messages_type)[target] = recvtype ; + if ( (*_time_messages)[target][1].time == -1 ) + { + (*_time_messages)[target][0] = (*_time_messages)[target][1] ; + sts = recv( &(*_time_messages)[target][1] , 1 , _MPI_access->timeType() , + target , RecvTimeRequestId ) ; + (*_data_messages)[target][0] = (*_data_messages)[target][1] ; + if ( recvtype == MPI_INT ) + { + (*_data_messages)[target][1] = new int[recvcount] ; + } + else + { + (*_data_messages)[target][1] = new double[recvcount] ; + } + sts = recv( (*_data_messages)[target][1] , recvcount , recvtype , target , + RecvDataRequestId ) ; + } + else + { + while ( ( _t > (*_time_messages)[target][1].time || UntilEnd ) && + (*_time_messages)[target][1].deltatime != 0 ) + { + (*_time_messages)[target][0] = (*_time_messages)[target][1] ; + sts = recv( &(*_time_messages)[target][1] , 1 , _MPI_access->timeType() , + target , RecvTimeRequestId ) ; + if ( UntilEnd ) + { + cout << "CheckTime" << _my_rank << " TimeMessage target " << target + << " RecvTimeRequestId " << RecvTimeRequestId << " MPITag " + << _MPI_access->recvMPITag(target) << endl ; + } + if ( recvtype == MPI_INT ) + { + delete [] (int *) (*_data_messages)[target][0] ; + } + else + { + delete [] (double *) (*_data_messages)[target][0] ; + } + (*_data_messages)[target][0] = (*_data_messages)[target][1] ; + if ( recvtype == MPI_INT ) + { + (*_data_messages)[target][1] = new int[recvcount] ; + } + else + { + (*_data_messages)[target][1] = new double[recvcount] ; + } + sts = recv( (*_data_messages)[target][1] , recvcount , recvtype , target , + RecvDataRequestId ) ; + if ( UntilEnd ) + { + cout << "CheckTime" << _my_rank << " DataMessage target " << target + << " RecvDataRequestId " << RecvDataRequestId << " MPITag " + << _MPI_access->recvMPITag(target) << endl ; + } + } + + if ( _t > (*_time_messages)[target][0].time && + _t <= (*_time_messages)[target][1].time ) + { + } + else + { + (*_out_of_time)[target] = true ; + } + } + return sts ; + } + + /* + . CheckSent() : + + call SendRequestIds of MPI_Access in order to get all + RequestIds of SendMessages of all "targets". + + For each RequestId, CheckSent call "Test" of MPI_Access in order + to know if the buffer is "free" (flag = true). If it is the + FinalCheckSent (WithWait = true), we call Wait instead of Test. + + If the buffer is "free", the counter of the structure SendBuffStruct + (from _MapOfSendBuffers) is decremented. + + If that counter is nul we delete the TimeMessage or the + SendBuffer according to the DataType. + + And we delete the structure SendBuffStruct before the suppression + (erase) of that item of _MapOfSendBuffers + */ + int MPIAccessDEC::checkSent(bool WithWait) + { + int sts = MPI_SUCCESS ; + int flag = WithWait ; + int size = _MPI_access->sendRequestIdsSize() ; + int * ArrayOfSendRequests = new int[ size ] ; + int nSendRequest = _MPI_access->sendRequestIds( size , ArrayOfSendRequests ) ; + bool SendTrace = false ; + int i ; + for ( i = 0 ; i < nSendRequest ; i++ ) + { + if ( WithWait ) + { + if (SendTrace) + { + cout << "CheckSent" << _my_rank << " " << i << "./" << nSendRequest + << " SendRequestId " << ArrayOfSendRequests[i] << " MPITarget " + << _MPI_access->MPITarget(ArrayOfSendRequests[i]) << " MPITag " + << _MPI_access->MPITag(ArrayOfSendRequests[i]) << " Wait :" << endl ; + } + sts = _MPI_access->wait( ArrayOfSendRequests[i] ) ; + } + else + { + sts = _MPI_access->test( ArrayOfSendRequests[i] , flag ) ; + } + if ( flag ) + { + _MPI_access->deleteRequest( ArrayOfSendRequests[i] ) ; + if ( SendTrace ) + { + cout << "CheckSent" << _my_rank << " " << i << "./" << nSendRequest + << " SendRequestId " << ArrayOfSendRequests[i] + << " flag " << flag + << " Counter " << (*_map_of_send_buffers)[ ArrayOfSendRequests[i] ]->Counter + << " DataType " << (*_map_of_send_buffers)[ ArrayOfSendRequests[i] ]->DataType + << endl ; + } + (*_map_of_send_buffers)[ ArrayOfSendRequests[i] ]->Counter -= 1 ; + if ( SendTrace ) + { + if ( (*_map_of_send_buffers)[ ArrayOfSendRequests[i] ]->DataType == + _MPI_access->timeType() ) + { + cout << "CheckTimeSent" << _my_rank << " Request " ; + } + else + { + cout << "CheckDataSent" << _my_rank << " Request " ; + } + cout << ArrayOfSendRequests[i] + << " _map_of_send_buffers->SendBuffer " + << (*_map_of_send_buffers)[ ArrayOfSendRequests[i] ]->SendBuffer + << " Counter " << (*_map_of_send_buffers)[ ArrayOfSendRequests[i] ]->Counter + << endl ; + } + if ( (*_map_of_send_buffers)[ ArrayOfSendRequests[i] ]->Counter == 0 ) + { + if ( SendTrace ) + { + cout << "CheckSent" << _my_rank << " SendRequestId " << ArrayOfSendRequests[i] + << " Counter " << (*_map_of_send_buffers)[ ArrayOfSendRequests[i] ]->Counter + << " flag " << flag << " SendBuffer " + << (*_map_of_send_buffers)[ ArrayOfSendRequests[i] ]->SendBuffer + << " deleted. Erase in _map_of_send_buffers :" << endl ; + } + if ( (*_map_of_send_buffers)[ ArrayOfSendRequests[i] ]->DataType == + _MPI_access->timeType() ) + { + delete (TimeMessage * ) (*_map_of_send_buffers)[ ArrayOfSendRequests[i] ]->SendBuffer ; + } + else + { + if ( (*_map_of_send_buffers)[ ArrayOfSendRequests[i] ]->DataType == MPI_INT ) + { + delete [] (int *) (*_map_of_send_buffers)[ ArrayOfSendRequests[i] ]->SendBuffer ; + } + else + { + delete [] (double *) (*_map_of_send_buffers)[ ArrayOfSendRequests[i] ]->SendBuffer ; + } + } + delete (*_map_of_send_buffers)[ ArrayOfSendRequests[i] ] ; + } + if ( SendTrace ) + { + cout << "CheckSent" << _my_rank << " Erase in _map_of_send_buffers SendRequestId " + << ArrayOfSendRequests[i] << endl ; + } + (*_map_of_send_buffers).erase( ArrayOfSendRequests[i] ) ; + } + else if ( SendTrace ) + { + cout << "CheckSent" << _my_rank << " " << i << "./" << nSendRequest + << " SendRequestId " << ArrayOfSendRequests[i] + << " flag " << flag + << " Counter " << (*_map_of_send_buffers)[ ArrayOfSendRequests[i] ]->Counter + << " DataType " << (*_map_of_send_buffers)[ ArrayOfSendRequests[i] ]->DataType + << endl ; + } + } + if ( SendTrace ) + { + _MPI_access->check() ; + } + delete [] ArrayOfSendRequests ; + return sts ; + } + + int MPIAccessDEC::checkFinalRecv() + { + int sts = MPI_SUCCESS ; + if ( _time_interpolator ) + { + int target ; + for ( target = 0 ; target < _group_size ; target++ ) + { + if ( (*_data_messages)[target][0] != NULL ) + { + sts = checkTime( (*_data_messages_recv_count)[target] , (*_data_messages_type)[target] , + target , true ) ; + if ( (*_data_messages_type)[target] == MPI_INT ) + { + delete [] (int *) (*_data_messages)[target][0] ; + } + else + { + delete [] (double *) (*_data_messages)[target][0] ; + } + (*_data_messages)[target][0] = NULL ; + if ( (*_data_messages)[target][1] != NULL ) + { + if ( (*_data_messages_type)[target] == MPI_INT ) + { + delete [] (int *) (*_data_messages)[target][1] ; + } + else + { + delete [] (double *) (*_data_messages)[target][1] ; + } + (*_data_messages)[target][1] = NULL ; + } + } + } + } + return sts ; + } + + ostream & operator<< (ostream & f ,const TimeInterpolationMethod & interpolationmethod ) + { + switch (interpolationmethod) + { + case WithoutTimeInterp : + f << " WithoutTimeInterpolation "; + break; + case LinearTimeInterp : + f << " LinearTimeInterpolation "; + break; + default : + f << " UnknownTimeInterpolation "; + break; + } + + return f; + } +} diff --cc medtool/src/ParaMEDMEM/MPIAccessDEC.hxx index e381ff61a,000000000..aba86958f mode 100644,000000..100644 --- a/medtool/src/ParaMEDMEM/MPIAccessDEC.hxx +++ b/medtool/src/ParaMEDMEM/MPIAccessDEC.hxx @@@ -1,179 -1,0 +1,184 @@@ +// Copyright (C) 2007-2015 CEA/DEN, EDF R&D +// +// 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +// +// See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com +// + +#ifndef __MPIACCESSDEC_HXX__ +#define __MPIACCESSDEC_HXX__ + +#include "MPIAccess.hxx" +#include "DEC.hxx" +#include "LinearTimeInterpolator.hxx" + +#include +#include + +namespace ParaMEDMEM +{ ++ /* ++ * Internal class, not part of the public API. ++ * ++ * Another gateway to the MPI library? ++ */ + class MPIAccessDEC + { + public: + MPIAccessDEC( const ProcessorGroup& local_group, const ProcessorGroup& distant_group, + bool Asynchronous = true ); + virtual ~MPIAccessDEC(); + MPIAccess * getMPIAccess() { return _MPI_access; } + const MPI_Comm* getComm() { return _MPI_union_group->getComm(); } + void asynchronous( bool Asynchronous = true ) { _asynchronous = Asynchronous; } + void setTimeInterpolator( TimeInterpolationMethod anInterp , double InterpPrecision=0 , + int n_step_before=1, int nStepAfter=1 ); + + void setTime( double t ) { _t = t; _dt = -1; } + void setTime( double t , double dt ) { _t = t; _dt = dt; } + bool outOfTime( int target ) { return (*_out_of_time)[target]; } + + int send( void* sendbuf, int sendcount , MPI_Datatype sendtype , int target ); + int recv( void* recvbuf, int recvcount , MPI_Datatype recvtype , int target ); + int recv( void* recvbuf, int recvcount , MPI_Datatype recvtype , int target , + int &RecvRequestId , bool Asynchronous=false ); + int sendRecv( void* sendbuf, int sendcount , MPI_Datatype sendtype , + void* recvbuf, int recvcount , MPI_Datatype recvtype , int target ); + + int allToAll( void* sendbuf, int sendcount, MPI_Datatype sendtype , + void* recvbuf, int recvcount, MPI_Datatype recvtype ); + int allToAllv( void* sendbuf, int* sendcounts, int* sdispls, MPI_Datatype sendtype , + void* recvbuf, int* recvcounts, int* rdispls, MPI_Datatype recvtype ); + + int allToAllTime( void* sendbuf, int sendcount , MPI_Datatype sendtype , + void* recvbuf, int recvcount , MPI_Datatype recvtype ); + int allToAllvTime( void* sendbuf, int* sendcounts, int* sdispls, + MPI_Datatype sendtype , + void* recvbuf, int* recvcounts, int* rdispls, + MPI_Datatype recvtype ); + int checkTime( int recvcount , MPI_Datatype recvtype , int target , bool UntilEnd ); + int checkSent(bool WithWait=false); + int checkFinalSent() { return checkSent( true ); } + int checkFinalRecv(); + protected: + int send( void* sendbuf, int sendcount , int sendoffset , MPI_Datatype sendtype , + int target, int &SendRequestId ); + int recv( void* recvbuf, int recvcount , int recvoffset , MPI_Datatype recvtype , + int target, int &RecvRequestId ); + int sendRecv( void* sendbuf, int sendcount , int sendoffset , + MPI_Datatype sendtype , + void* recvbuf, int recvcount , int recvoffset , + MPI_Datatype recvtype , int target , + int &SendRequestId ,int &RecvRequestId ); + private : + bool _asynchronous; + MPIProcessorGroup* _MPI_union_group; + + TimeInterpolator* _time_interpolator; + int _n_step_before; + int _n_step_after; + + int _my_rank; + int _group_size; + MPIAccess* _MPI_access; + + // Current time and deltatime of current process + double _t; + double _dt; + + // TimeMessages from each target _TimeMessages[target][Step] : TimeMessage + std::vector< std::vector< TimeMessage > > *_time_messages; + // Corresponding DataMessages from each target _DataMessages[target][~TimeStep] + std::vector< bool >* _out_of_time; + std::vector< int >* _data_messages_recv_count; + std::vector< MPI_Datatype >* _data_messages_type; + std::vector< std::vector< void * > >* _data_messages; + + typedef struct + { + void * SendBuffer; + int Counter; + MPI_Datatype DataType; } + SendBuffStruct; + std::map< int , SendBuffStruct * > *_map_of_send_buffers; + }; + + inline int MPIAccessDEC::send( void* sendbuf, int sendcount , MPI_Datatype sendtype , int target ) + { + int SendRequestId; + int sts; + if ( _asynchronous ) + { + sts = _MPI_access->ISend( sendbuf , sendcount , sendtype , target , + SendRequestId ); + } + else + { + sts = _MPI_access->send( sendbuf , sendcount , sendtype , target , + SendRequestId ); + if ( sts == MPI_SUCCESS ) + free( sendbuf ); + } + return sts; + } + + inline int MPIAccessDEC::recv( void* recvbuf, int recvcount , MPI_Datatype recvtype , int target ) + { + int RecvRequestId; + int sts; + if ( _asynchronous ) + sts = _MPI_access->IRecv( recvbuf , recvcount , recvtype , target , RecvRequestId ); + else + sts = _MPI_access->recv( recvbuf , recvcount , recvtype , target , RecvRequestId ); + return sts; + } + + inline int MPIAccessDEC::recv( void* recvbuf, int recvcount , MPI_Datatype recvtype , + int target , int &RecvRequestId , bool Asynchronous ) + { + int sts; + if ( Asynchronous ) + sts = _MPI_access->IRecv( recvbuf , recvcount , recvtype , target , + RecvRequestId ); + else + sts = _MPI_access->recv( recvbuf , recvcount , recvtype , target , + RecvRequestId ); + return sts; + } + + inline int MPIAccessDEC::sendRecv( void* sendbuf, int sendcount , MPI_Datatype sendtype , + void* recvbuf, int recvcount , MPI_Datatype recvtype , + int target ) + { + int SendRequestId; + int RecvRequestId; + int sts; + if ( _asynchronous ) + sts = _MPI_access->ISendRecv( sendbuf , sendcount , sendtype , target , + SendRequestId , + recvbuf , recvcount , recvtype , target , + RecvRequestId ); + else + sts = _MPI_access->sendRecv( sendbuf , sendcount , sendtype , target , + SendRequestId , + recvbuf , recvcount , recvtype , target , + RecvRequestId ); + return sts; + } + + std::ostream & operator<< (std::ostream &,const TimeInterpolationMethod &); +} + +#endif diff --cc medtool/src/ParaMEDMEM/MPIProcessorGroup.cxx index 922f20920,000000000..3bf01b69d mode 100644,000000..100644 --- a/medtool/src/ParaMEDMEM/MPIProcessorGroup.cxx +++ b/medtool/src/ParaMEDMEM/MPIProcessorGroup.cxx @@@ -1,254 -1,0 +1,257 @@@ +// Copyright (C) 2007-2015 CEA/DEN, EDF R&D +// +// 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +// +// See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com +// + +#include "ProcessorGroup.hxx" +#include "MPIProcessorGroup.hxx" +#include "CommInterface.hxx" +#include "InterpolationUtils.hxx" + +#include +#include +#include +#include "mpi.h" + +using namespace std; + + +namespace ParaMEDMEM +{ + /*! - * \anchor MPIProcessorGroup-det - * \class MPIProcessorGroup - * - * \section processor_group_overview Overview - * The MPIProcessorGroup class is used to set up processor groups that help to define - * the MPI topology of the couplings. They can be set up in various ways, the most common being - * the use of the \c MPIProcessorGroup(Comminterface, int pfirst, int plast) - * constructor. - * - * The following code excerpt creates two processor groups on respectively 3 and 2 processors. ++ \anchor MPIProcessorGroup-det ++ \class MPIProcessorGroup ++ ++ The MPIProcessorGroup class represents a set of distinct "processors" (computation nodes) ++ in a MPI code. It is used to define the MPI topology of code couplings. ++ ++ Groups can be set up in various ways, the most common being ++ the use of the \c MPIProcessorGroup(Comminterface, int pfirst, int plast) ++ constructor. ++ ++ The following code excerpt creates two processor groups on respectively 3 and 2 processors. + \verbatim + int main() + { + MPI_Init(&argc,&argv); + CommInterface comm_interface; + MPIProcessorGroup codeA_group(comm_interface, 0, 2); // groups processors 0, 1 and 2 + MPIProcessorGroup codeB_group(comm_interface, 3, 4); // groups processors 3 and 4 + + ... + } + \endverbatim + */ + + + /*! + * Creates a processor group that is based on all the - MPI_COMM_WORLD processor.This routine must be called by all processors in MPI_COMM_WORLD. ++ processors of MPI_COMM_WORLD .This routine must be called by all processors in MPI_COMM_WORLD. + \param interface CommInterface object giving access to the MPI + communication layer + */ + MPIProcessorGroup::MPIProcessorGroup(const CommInterface& interface): + ProcessorGroup(interface),_world_comm(MPI_COMM_WORLD) + { + _comm=_world_comm; + _comm_interface.commGroup(_world_comm, &_group); + int size; + _comm_interface.commSize(_world_comm,&size); + for (int i=0; i proc_ids, const MPI_Comm& world_comm): + ProcessorGroup(interface, proc_ids), _world_comm(world_comm) + { + updateMPISpecificAttributes(); + } + + + void MPIProcessorGroup::updateMPISpecificAttributes() + { + //Creation of a communicator + MPI_Group group_world; + + int size_world; + _comm_interface.commSize(_world_comm,&size_world); + int rank_world; + _comm_interface.commRank(_world_comm,&rank_world); + _comm_interface.commGroup(_world_comm, &group_world); + + int* ranks=new int[_proc_ids.size()]; + + // copying proc_ids in ranks + copy::const_iterator,int*> (_proc_ids.begin(), _proc_ids.end(), ranks); + for (int i=0; i< (int)_proc_ids.size();i++) + if (ranks[i]>size_world-1) + { + delete[] ranks; + _comm_interface.groupFree(&group_world); // MPI_Group is a C structure and won't get de-allocated automatically? + throw INTERP_KERNEL::Exception("invalid rank in set argument of MPIProcessorGroup constructor"); + } + + _comm_interface.groupIncl(group_world, _proc_ids.size(), ranks, &_group); + + _comm_interface.commCreate(_world_comm, _group, &_comm); + + // clean-up + delete[] ranks; + _comm_interface.groupFree(&group_world); // MPI_Group is a C structure and won't get de-allocated automatically? + } + + /*! Creates a processor group that is based on the processors between \a pstart and \a pend. + This routine must be called by all processors in MPI_COMM_WORLD. + + \param comm_interface CommInterface object giving access to the MPI + communication layer + \param pstart id in MPI_COMM_WORLD of the first processor in the group + \param pend id in MPI_COMM_WORLD of the last processor in the group + */ + MPIProcessorGroup::MPIProcessorGroup (const CommInterface& comm_interface, int pstart, int pend, const MPI_Comm& world_comm): ProcessorGroup(comm_interface,pstart,pend),_world_comm(world_comm) + { + //Creation of a communicator + MPI_Group group_world; + + int size_world; + _comm_interface.commSize(_world_comm,&size_world); + int rank_world; + _comm_interface.commRank(_world_comm,&rank_world); + _comm_interface.commGroup(_world_comm, &group_world); + + if (pend>size_world-1 || pend proc_ids) : - ProcessorGroup(proc_group.getCommInterface()),_world_comm(MPI_COMM_WORLD) ++ ProcessorGroup(proc_group.getCommInterface()), ++ _world_comm(MPI_COMM_WORLD), _group(MPI_GROUP_NULL), _comm(MPI_COMM_NULL) + { + cout << "MPIProcessorGroup (const ProcessorGroup& proc_group, set proc_ids)" <(group); + int local_rank; + MPI_Group_translate_ranks(targetgroup->_group, 1, &rank, _group, &local_rank); + return local_rank; + } + + /*!Creates a processor group that is the complement of the current group + inside MPI_COMM_WORLD + \return pointer to the new ProcessorGroup structure. + */ + ProcessorGroup* MPIProcessorGroup::createComplementProcGroup() const + { + set procs; + int world_size=_comm_interface.worldSize(); + for (int i=0; i::const_iterator iter=_proc_ids.begin(); iter!= _proc_ids.end(); iter++) + procs.erase(*iter); + + return new MPIProcessorGroup(_comm_interface, procs, _world_comm); + + } + + ProcessorGroup *MPIProcessorGroup::deepCpy() const + { + return new MPIProcessorGroup(*this); + } + + /*!Adding processors of group \a group to local group. + \param group group that is to be fused with current group + \return new group formed by the fusion of local group and \a group. + */ + ProcessorGroup* MPIProcessorGroup::fuse (const ProcessorGroup& group) const + { + set procs = _proc_ids; + const set& distant_proc_ids = group.getProcIDs(); + for (set::const_iterator iter=distant_proc_ids.begin(); iter!=distant_proc_ids.end(); iter++) + { + procs.insert(*iter); + } + return new MPIProcessorGroup(_comm_interface, procs, _world_comm); + } + + int MPIProcessorGroup::myRank() const + { + int rank; + MPI_Comm_rank(_comm,&rank); + return rank; + } + + ProcessorGroup* MPIProcessorGroup::createProcGroup() const + { + set procs; + for (set::const_iterator iter=_proc_ids.begin(); iter!= _proc_ids.end(); iter++) + procs.insert(*iter); + + return new MPIProcessorGroup(_comm_interface, procs, _world_comm); + + } +} diff --cc medtool/src/ParaMEDMEM/MxN_Mapping.cxx index 05ca0990e,000000000..a6a0bcba3 mode 100644,000000..100644 --- a/medtool/src/ParaMEDMEM/MxN_Mapping.cxx +++ b/medtool/src/ParaMEDMEM/MxN_Mapping.cxx @@@ -1,317 -1,0 +1,315 @@@ +// Copyright (C) 2007-2015 CEA/DEN, EDF R&D +// +// 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +// +// See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com +// + +#include "CommInterface.hxx" +#include "ProcessorGroup.hxx" +#include "MPIProcessorGroup.hxx" +#include "MPIAccessDEC.hxx" +#include "MxN_Mapping.hxx" + +using namespace std; + +namespace ParaMEDMEM +{ - MxN_Mapping::MxN_Mapping() - { - } - + + MxN_Mapping::MxN_Mapping(const ProcessorGroup& source_group, const ProcessorGroup& target_group,const DECOptions& dec_options) - : DECOptions(dec_options),_union_group(source_group.fuse(target_group)) ++ : DECOptions(dec_options), ++ _union_group(source_group.fuse(target_group)), ++ _nb_comps(0), _sending_ids(), _recv_ids() + { + _access_DEC = new MPIAccessDEC(source_group,target_group,getAsynchronous()); + _access_DEC->setTimeInterpolator(getTimeInterpolationMethod()); + _send_proc_offsets.resize(_union_group->size()+1,0); + _recv_proc_offsets.resize(_union_group->size()+1,0); + + } + + MxN_Mapping::~MxN_Mapping() + { + delete _union_group; + delete _access_DEC; + } + + + /*! + Method registering a new element for correspondence with a distant element + \param distant_proc proc rank of the distant processor (in terms of the union group) + \param distant_element id of the element on the distant processor + */ + void MxN_Mapping::addElementFromSource(int distant_proc, int distant_element) + { + _sending_ids.push_back(make_pair(distant_proc,distant_element)); + for (int i=distant_proc; i<_union_group->size(); i++) + _send_proc_offsets[i+1]++; + } + + void MxN_Mapping::initialize() + { + _sending_ids.clear(); + std::fill(_send_proc_offsets.begin(),_send_proc_offsets.end(),0); + } + + void MxN_Mapping::prepareSendRecv() + { + CommInterface comm_interface=_union_group->getCommInterface(); + // sending count pattern + int* nbsend=new int[_union_group->size()]; + int* nbrecv=new int[_union_group->size()]; + for (int i=0; i<_union_group->size(); i++) + { + nbsend[i]=_send_proc_offsets[i+1]-_send_proc_offsets[i]; + } + + MPIProcessorGroup* group = static_cast(_union_group); + const MPI_Comm* comm=group->getComm(); + comm_interface.allToAll(nbsend, 1, MPI_INT, + nbrecv, 1, MPI_INT, + *comm); + + for (int i=0; i<_union_group->size(); i++) + { + for (int j=i+1;j<_union_group->size()+1; j++) + _recv_proc_offsets[j]+=nbrecv[i]; + + } + + delete[] nbsend; + delete[] nbrecv; + + _recv_ids.resize(_recv_proc_offsets[_union_group->size()]); + int* isendbuf=0; + int* irecvbuf=0; + if (_sending_ids.size()>0) + isendbuf = new int[_sending_ids.size()]; + if (_recv_ids.size()>0) + irecvbuf = new int[_recv_ids.size()]; + int* sendcounts = new int[_union_group->size()]; + int* senddispls=new int[_union_group->size()]; + int* recvcounts=new int[_union_group->size()]; + int* recvdispls=new int[_union_group->size()]; + for (int i=0; i< _union_group->size(); i++) + { + sendcounts[i]=_send_proc_offsets[i+1]-_send_proc_offsets[i]; + senddispls[i]=_send_proc_offsets[i]; + recvcounts[i]=_recv_proc_offsets[i+1]-_recv_proc_offsets[i]; + recvdispls[i]=_recv_proc_offsets[i]; + } + vector offsets = _send_proc_offsets; + for (int i=0; i<(int)_sending_ids.size();i++) + { + int iproc = _sending_ids[i].first; + isendbuf[offsets[iproc]]=_sending_ids[i].second; + offsets[iproc]++; + } + comm_interface.allToAllV(isendbuf, sendcounts, senddispls, MPI_INT, + irecvbuf, recvcounts, recvdispls, MPI_INT, + *comm); + + for (int i=0; i< _recv_proc_offsets[_union_group->size()]; i++) + _recv_ids[i]=irecvbuf[i]; + + if (_sending_ids.size()>0) + delete[] isendbuf; + if (_recv_ids.size()>0) + delete[] irecvbuf; + delete[] sendcounts; + delete[]recvcounts; + delete[]senddispls; + delete[] recvdispls; + } + + /*! Exchanging field data between two groups of processes + * + * \param field MEDCoupling field containing the values to be sent + * + * The ids that were defined by addElementFromSource method + * are sent. + */ + void MxN_Mapping::sendRecv(double* sendfield, MEDCouplingFieldDouble& field) const + { + CommInterface comm_interface=_union_group->getCommInterface(); + const MPIProcessorGroup* group = static_cast(_union_group); + + int nbcomp=field.getArray()->getNumberOfComponents(); + double* sendbuf=0; + double* recvbuf=0; + if (_sending_ids.size() >0) + sendbuf = new double[_sending_ids.size()*nbcomp]; + if (_recv_ids.size()>0) + recvbuf = new double[_recv_ids.size()*nbcomp]; + + int* sendcounts = new int[_union_group->size()]; + int* senddispls=new int[_union_group->size()]; + int* recvcounts=new int[_union_group->size()]; + int* recvdispls=new int[_union_group->size()]; + + for (int i=0; i< _union_group->size(); i++) + { + sendcounts[i]=nbcomp*(_send_proc_offsets[i+1]-_send_proc_offsets[i]); + senddispls[i]=nbcomp*(_send_proc_offsets[i]); + recvcounts[i]=nbcomp*(_recv_proc_offsets[i+1]-_recv_proc_offsets[i]); + recvdispls[i]=nbcomp*(_recv_proc_offsets[i]); + } + //building the buffer of the elements to be sent + vector offsets = _send_proc_offsets; + + for (int i=0; i<(int)_sending_ids.size();i++) + { + int iproc = _sending_ids[i].first; + for (int icomp=0; icompgetComm(); + comm_interface.allToAllV(sendbuf, sendcounts, senddispls, MPI_DOUBLE, + recvbuf, recvcounts, recvdispls, MPI_DOUBLE, + *comm); + } + break; + case PointToPoint: + _access_DEC->allToAllv(sendbuf, sendcounts, senddispls, MPI_DOUBLE, + recvbuf, recvcounts, recvdispls, MPI_DOUBLE); + break; + } + + //setting the received values in the field + DataArrayDouble *fieldArr=field.getArray(); + double* recvptr=recvbuf; + for (int i=0; i< _recv_proc_offsets[_union_group->size()]; i++) + { + for (int icomp=0; icompgetIJ(_recv_ids[i],icomp); + fieldArr->setIJ(_recv_ids[i],icomp,temp+*recvptr); + recvptr++; + } + } + if (sendbuf!=0 && getAllToAllMethod()== Native) + delete[] sendbuf; + if (recvbuf !=0) + delete[] recvbuf; + delete[] sendcounts; + delete[] recvcounts; + delete[] senddispls; + delete[] recvdispls; + + } + + /*! Exchanging field data between two groups of processes + * + * \param field MEDCoupling field containing the values to be sent + * + * The ids that were defined by addElementFromSource method + * are sent. + */ + void MxN_Mapping::reverseSendRecv(double* recvfield, MEDCouplingFieldDouble& field) const + { + CommInterface comm_interface=_union_group->getCommInterface(); + const MPIProcessorGroup* group = static_cast(_union_group); + + int nbcomp=field.getArray()->getNumberOfComponents(); + double* sendbuf=0; + double* recvbuf=0; + if (_recv_ids.size() >0) + sendbuf = new double[_recv_ids.size()*nbcomp]; + if (_sending_ids.size()>0) + recvbuf = new double[_sending_ids.size()*nbcomp]; + + int* sendcounts = new int[_union_group->size()]; + int* senddispls=new int[_union_group->size()]; + int* recvcounts=new int[_union_group->size()]; + int* recvdispls=new int[_union_group->size()]; + + for (int i=0; i< _union_group->size(); i++) + { + sendcounts[i]=nbcomp*(_recv_proc_offsets[i+1]-_recv_proc_offsets[i]); + senddispls[i]=nbcomp*(_recv_proc_offsets[i]); + recvcounts[i]=nbcomp*(_send_proc_offsets[i+1]-_send_proc_offsets[i]); + recvdispls[i]=nbcomp*(_send_proc_offsets[i]); + } + //building the buffer of the elements to be sent + vector offsets = _recv_proc_offsets; + DataArrayDouble *fieldArr=field.getArray(); + for (int iproc=0; iproc<_union_group->size();iproc++) + for (int i=_recv_proc_offsets[iproc]; i<_recv_proc_offsets[iproc+1]; i++) + { + for (int icomp=0; icompgetIJ(_recv_ids[i],icomp); + } + + //communication phase + switch (getAllToAllMethod()) + { + case Native: + { + const MPI_Comm* comm = group->getComm(); + comm_interface.allToAllV(sendbuf, sendcounts, senddispls, MPI_DOUBLE, + recvbuf, recvcounts, recvdispls, MPI_DOUBLE, + *comm); + } + break; + case PointToPoint: + _access_DEC->allToAllv(sendbuf, sendcounts, senddispls, MPI_DOUBLE, + recvbuf, recvcounts, recvdispls, MPI_DOUBLE); + break; + } + + //setting the received values in the field + double* recvptr=recvbuf; + for (int i=0; i< _send_proc_offsets[_union_group->size()]; i++) + { + for (int icomp=0; icomp + +namespace ParaMEDMEM +{ + + class ProcessorGroup; + ++ /*! ++ * Internal class, not part of the public API. ++ * ++ * Used by InterpolationMatrix. This class manages the mapping between a given processor and part ++ * of the mesh (cell ids). ++ */ + class MxN_Mapping : public DECOptions + { + public: - MxN_Mapping(); + MxN_Mapping(const ProcessorGroup& source_group, const ProcessorGroup& target_group, const DECOptions& dec_options); + virtual ~MxN_Mapping(); + void addElementFromSource(int distant_proc, int distant_elem); + void prepareSendRecv(); + void sendRecv(MEDCouplingFieldDouble& field); + void sendRecv(double* sendfield, MEDCouplingFieldDouble& field) const ; + void reverseSendRecv(double* recvfield, MEDCouplingFieldDouble& field) const ; + + // + const std::vector >& getSendingIds() const { return _sending_ids; } + const std::vector& getSendProcsOffsets() const { return _send_proc_offsets; } + void initialize(); + + MPIAccessDEC* getAccessDEC(){ return _access_DEC; } + private : + ProcessorGroup* _union_group; + MPIAccessDEC * _access_DEC; + int _nb_comps; + std::vector > _sending_ids; + std::vector _recv_ids; + std::vector _send_proc_offsets; + std::vector _recv_proc_offsets; + }; + + std::ostream & operator<< (std::ostream &,const AllToAllMethod &); + +} + +#endif diff --cc medtool/src/ParaMEDMEM/NonCoincidentDEC.cxx index 4f44a7f54,000000000..95b9d6acd mode 100644,000000..100644 --- a/medtool/src/ParaMEDMEM/NonCoincidentDEC.cxx +++ b/medtool/src/ParaMEDMEM/NonCoincidentDEC.cxx @@@ -1,390 -1,0 +1,393 @@@ +// Copyright (C) 2007-2015 CEA/DEN, EDF R&D +// +// 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +// +// See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com +// + +#include +#include "CommInterface.hxx" +#include "Topology.hxx" +#include "BlockTopology.hxx" +#include "ComponentTopology.hxx" +#include "ParaFIELD.hxx" +#include "MPIProcessorGroup.hxx" +#include "DEC.hxx" +#include "NonCoincidentDEC.hxx" + +extern "C" { +#include +#include +#include +#include +} + +namespace ParaMEDMEM +{ + + /*! + \anchor NonCoincidentDEC-det + \class NonCoincidentDEC + - \c NonCoincidentDEC enables nonconservative remapping of fields ++ \c NonCoincidentDEC enables non-conservative remapping of fields + between two parallel codes. + The computation is possible for 3D meshes and 2D meshes. - It is not available for 3D surfaces. The computation enables fast parallel localization, and is based on a point in element search, followed ++ It is not available for 3D surfaces. ++ ++ The computation enables fast parallel localization, and is based on a point in element search, followed + by a field evaluation at the point location. Thus, it is typically - faster than the \ref InterpKernelDEC-det "InterpKernelDEC" which gives a - \ref InterpKerRemapGlobal "conservative remapping". - It is particularly true for the initialisation phase (synchronize) - which is very computationnaly intensive in \ref InterpKernelDEC-det. ++ faster than the \ref InterpKernelDEC-det "InterpKernelDEC" which uses a ++ \ref InterpKerRemapGlobal "conservative remapping" (i.e. the same algorithms of volume ++ intersection as in the \ref remapper "sequential remapper") ++ It is particularly true for the initialisation phase (synchronize() method) ++ which has a significant computation cost in \ref InterpKernelDEC-det. + - In the present version, only fields lying on elements are considered. ++ In the present version, only fields lying on elements ("P0") are considered. + The value is estimated by locating the barycenter of the target + side cell in a source cell and sending the value of this source cell + as the value of the target cell. + + \image html NonCoincident_small.png "Example showing the transfer from a field based on a quadrangular mesh to a triangular mesh. The triangle barycenters are computed and located in the quadrangles. In a P0-P0 interpolation, the value on the quadrangle is then applied to the triangles whose barycenter lies within." + + \image latex NonCoincident_small.eps "Example showing the transfer from a field based on a quadrangular mesh to a triangular mesh. The triangle barycenters are computed and located in the quadrangles. In a P0-P0 interpolation, the value on the quadrangle is then applied to the triangles whose barycenter lies within." + + A typical use of NonCoincidentDEC encompasses two distinct phases : + - A setup phase during which the intersection volumes are computed and the communication structures are setup. This corresponds to calling the NonCoincidentDEC::synchronize() method. + - A use phase during which the remappings are actually performed. This corresponds to the calls to sendData() and recvData() which actually trigger the data exchange. The data exchange are synchronous in the current version of the library so that recvData() and sendData() calls must be synchronized on code A and code B processor groups. + + The following code excerpt illutrates a typical use of the NonCoincidentDEC class. + + \code + ... + NonCoincidentDEC dec(groupA, groupB); + dec.attachLocalField(field); + dec.synchronize(); + if (groupA.containsMyRank()) + dec.recvData(); + else if (groupB.containsMyRank()) + dec.sendData(); + ... + \endcode + + Computing the field on the receiving side can be expressed in terms + of a matrix-vector product : \f$ \phi_t=W.\phi_s\f$, with \f$ \phi_t + \f$ the field on the target side and \f$ \phi_s \f$ the field on + the source side. + In the P0-P0 case, this matrix is a plain rectangular matrix with one + non-zero element per row (with value 1). For instance, in the above figure, the matrix is : + \f[ + + \begin{tabular}{|cccc|} + 1 & 0 & 0 & 0\\ + 0 & 0 & 1 & 0\\ + 1 & 0 & 0 & 0\\ + 0 & 0 & 1 & 0\\ + \end{tabular} + \f] + */ + + fvm_nodal_t* medmemMeshToFVMMesh(const MEDMEM::MESH* mesh) + { + // create an FVM structure from the paramesh structure + std::string meshName(mesh->getName());//this line avoid that mesh->getName() object killed before fvm_nodal_create read the const char *. + fvm_nodal_t * fvm_nodal = fvm_nodal_create(meshName.c_str(),mesh->getMeshDimension()); + + //loop on cell types + int nbtypes = mesh->getNumberOfTypes(MED_EN::MED_CELL); + const MED_EN::medGeometryElement* types = mesh->getTypes(MED_EN::MED_CELL); + for (int itype=0; itypegetNumberOfElements(MED_EN::MED_CELL, types[itype]); + fvm_lnum_t* conn = new fvm_lnum_t[nbelems*(types[itype]%100)]; + const int* mesh_conn =mesh->getConnectivity(MED_EN::MED_FULL_INTERLACE,MED_EN::MED_NODAL, MED_EN::MED_CELL, types[itype]); + for (int i=0; igetNumberOfNodes(); + int spacedim=mesh->getSpaceDimension(); + fvm_coord_t* coords = new fvm_coord_t[nbnodes*spacedim]; + const double* mesh_coords=mesh->getCoordinates(MED_EN::MED_FULL_INTERLACE); + for (int i=0; igetName());//this line avoid that support->getName() object killed before fvm_nodal_create read the const char *. + fvm_nodal_t * fvm_nodal = fvm_nodal_create(supportName.c_str(),1); + + const MEDMEM::MESH* mesh= support->getMesh(); + + //loop on cell types + MED_EN::medEntityMesh entity = support->getEntity(); + + int nbtypes = support->getNumberOfTypes(); + const MED_EN::medGeometryElement* types = support->getTypes(); + int ioffset=0; + const int* type_offset = support->getNumberIndex(); + + //browsing through all types + for (int itype=0; itypegetNumberOfElements(types[itype]); + + //for a partial support, defining the element numbers that are taken into + //account in the support + fvm_lnum_t* elem_numbers=0; + if (!support->isOnAllElements()) + { + elem_numbers = const_cast (support->getNumber(types[itype])); + + //creating work arrays to store list of elems for partial suports + if (itype>0) + { + fvm_lnum_t* temp = new int[nbelems]; + for (int i=0; i< nbelems; i++) + temp[i] = elem_numbers [i]-ioffset; + ioffset+=type_offset[itype]; + elem_numbers = temp; + } + } + //retrieving original mesh connectivity + fvm_lnum_t* conn = const_cast (mesh->getConnectivity(MED_EN::MED_FULL_INTERLACE,MED_EN::MED_NODAL,entity, types[itype])); + + // adding the elements to the FVM structure + fvm_nodal_append_by_transfer(fvm_nodal, nbelems, fvm_type,0,0,0,conn,elem_numbers); + + //cleaning work arrays (for partial supports) + if (!support->isOnAllElements() && itype>0) + delete[] elem_numbers; + + } + return fvm_nodal; + } + + NonCoincidentDEC::NonCoincidentDEC() + { + } + + /*! Constructor of a non coincident \ref para-dec "DEC" with + * a source group on which lies a field lying on a mesh and a + * target group on which lies a mesh. + * + * \param source_group ProcessorGroup on the source side + * \param target_group ProcessorGroup on the target side + */ + + NonCoincidentDEC::NonCoincidentDEC(ProcessorGroup& source_group, + ProcessorGroup& target_group) + :DEC(source_group, target_group) + {} + + NonCoincidentDEC::~NonCoincidentDEC() + { + } + + /*! Synchronization process. Calling this method + * synchronizes the topologies so that the target side + * gets the information which enable it to fetch the field value + * from the source side. + * A typical call is : + \verbatim + NonCoincidentDEC dec(source_group,target_group); + dec.attachLocalField(field); + dec.synchronize(); + \endverbatim + */ + void NonCoincidentDEC::synchronize() + { + + //initializing FVM parallel environment + const MPI_Comm* comm=dynamic_cast (_union_group)->getComm(); + fvm_parall_set_mpi_comm(*const_cast (comm)); + + + //setting up the communication DEC on both sides + + if (_source_group->containsMyRank()) + { + MEDMEM::MESH* mesh = _local_field->getField()->getSupport()->getMesh(); + fvm_nodal_t* source_nodal = ParaMEDMEM::medmemMeshToFVMMesh(mesh); + + int target_size = _target_group->size() ; + int start_rank= _source_group->size(); + const MPI_Comm* comm = (dynamic_cast (_union_group))->getComm(); + + _locator = fvm_locator_create(1e-6, + *comm, + target_size, + start_rank); + + fvm_locator_set_nodal(_locator, + source_nodal, + mesh->getSpaceDimension(), + 0, + NULL, + 0); + + + _nb_distant_points = fvm_locator_get_n_dist_points(_locator); + _distant_coords = fvm_locator_get_dist_coords(_locator); + _distant_locations = fvm_locator_get_dist_locations(_locator); + + } + if (_target_group->containsMyRank()) + { + MEDMEM::MESH* mesh = _local_field->getField()->getSupport()->getMesh(); + + fvm_nodal_t* target_nodal = ParaMEDMEM::medmemMeshToFVMMesh(mesh); + int source_size = _source_group->size(); + int start_rank= 0 ; + const MPI_Comm* comm = (dynamic_cast (_union_group))->getComm(); + + _locator = fvm_locator_create(1e-6, + *comm, + source_size, + start_rank); + int nbcells = mesh->getNumberOfElements(MED_EN::MED_CELL,MED_EN::MED_ALL_ELEMENTS); + const MEDMEM::SUPPORT* support=_local_field->getField()->getSupport(); + MEDMEM::FIELD* barycenter_coords = mesh->getBarycenter(support); + const double* coords = barycenter_coords->getValue(); + fvm_locator_set_nodal(_locator, + target_nodal, + mesh->getSpaceDimension(), + nbcells, + NULL, + coords); + delete barycenter_coords; + } + } + + + /*! This method is called on the target group in order to + * trigger the retrieveal of field data. It must + * be called synchronously with a sendData() call on + * the source group. + */ + void NonCoincidentDEC::recvData() + { + int nbelems = _local_field->getField()->getSupport()->getMesh()->getNumberOfElements(MED_EN::MED_CELL, MED_EN::MED_ALL_ELEMENTS); + int nbcomp = _local_field->getField()->getNumberOfComponents(); + double* values = new double [nbelems*nbcomp]; + fvm_locator_exchange_point_var(_locator, + 0, + values, + 0, + sizeof(double), + nbcomp, + 0); + _local_field->getField()->setValue(values); + if (_forced_renormalization_flag) + renormalizeTargetField(); + delete[]values; + } + + /*! This method is called on the source group in order to + * send field data. It must be called synchronously with + * a recvData() call on + * the target group. + */ + void NonCoincidentDEC::sendData() + { + const double* values=_local_field->getField()->getValue(); + int nbcomp = _local_field->getField()->getNumberOfComponents(); + double* distant_values = new double [_nb_distant_points*nbcomp]; + + //cheap interpolation : the value of the cell is transfered to the point + for (int i=0; i<_nb_distant_points; i++) + for (int j=0; j \c >. + + For a proc\#k, it is necessary to fetch info of all matrices built in + \ref ParaMEDMEMOverlapDECAlgoStep4 "Step4" where the first element in pair (i,j) + is equal to k. + + After this step, the matrix repartition is the following after a call to + ParaMEDMEM::OverlapMapping::prepare : + + - proc\#0 : (0,0),(1,0),(2,0) + - proc\#1 : (0,1),(2,1) + - proc\#2 : (1,2),(2,2) + + Tuple (2,1) computed on proc 2 is stored in proc 1 after execution of the function + "prepare". This is an example of item 0 in \ref ParaMEDMEMOverlapDECAlgoStep2 "Step2". + Tuple (0,1) computed on proc 1 is stored in proc 1 too. This is an example of item 1 in \ref ParaMEDMEMOverlapDECAlgoStep2 "Step2". + + In the end ParaMEDMEM::OverlapMapping::_proc_ids_to_send_vector_st will contain : + + - Proc\#0 : 0,1 + - Proc\#1 : 0,2 + - Proc\#2 : 0,1,2 + + In the end ParaMEDMEM::OverlapMapping::_proc_ids_to_recv_vector_st will contain : + + - Proc\#0 : 0,1,2 + - Proc\#1 : 0,2 + - Proc\#2 : 1,2 + + The method in charge to perform this is : ParaMEDMEM::OverlapMapping::prepare. +*/ + OverlapDEC::OverlapDEC(const std::set& procIds, const MPI_Comm& world_comm): + _own_group(true),_interpolation_matrix(0), + _source_field(0),_own_source_field(false), + _target_field(0),_own_target_field(false), + _comm(MPI_COMM_NULL) + { + ParaMEDMEM::CommInterface comm; + int *ranks_world=new int[procIds.size()]; // ranks of sources and targets in world_comm + std::copy(procIds.begin(),procIds.end(),ranks_world); + MPI_Group group,world_group; + comm.commGroup(world_comm,&world_group); + comm.groupIncl(world_group,procIds.size(),ranks_world,&group); + delete [] ranks_world; + comm.commCreate(world_comm,group,&_comm); + comm.groupFree(&group); + comm.groupFree(&world_group); + if(_comm==MPI_COMM_NULL) + { + _group=0; + return ; + } + std::set idsUnion; + for(std::size_t i=0;imultiply(); + } + + void OverlapDEC::recvData() + { + throw INTERP_KERNEL::Exception("Not implemented yet !!!!"); + //_interpolation_matrix->transposeMultiply(); + } + + void OverlapDEC::synchronize() + { + if(!isInGroup()) + return ; + delete _interpolation_matrix; + _interpolation_matrix=new OverlapInterpolationMatrix(_source_field,_target_field,*_group,*this,*this); + OverlapElementLocator locator(_source_field,_target_field,*_group); + locator.copyOptions(*this); + locator.exchangeMeshes(*_interpolation_matrix); + std::vector< std::pair > jobs=locator.getToDoList(); + std::string srcMeth=locator.getSourceMethod(); + std::string trgMeth=locator.getTargetMethod(); + for(std::vector< std::pair >::const_iterator it=jobs.begin();it!=jobs.end();it++) + { + const MEDCouplingPointSet *src=locator.getSourceMesh((*it).first); + const DataArrayInt *srcIds=locator.getSourceIds((*it).first); + const MEDCouplingPointSet *trg=locator.getTargetMesh((*it).second); + const DataArrayInt *trgIds=locator.getTargetIds((*it).second); + _interpolation_matrix->addContribution(src,srcIds,srcMeth,(*it).first,trg,trgIds,trgMeth,(*it).second); + } + _interpolation_matrix->prepare(locator.getProcsInInteraction()); + _interpolation_matrix->computeDeno(); + } + + void OverlapDEC::attachSourceLocalField(ParaFIELD *field, bool ownPt) + { + if(!isInGroup()) + return ; + if(_own_source_field) + delete _source_field; + _source_field=field; + _own_source_field=ownPt; + } + + void OverlapDEC::attachTargetLocalField(ParaFIELD *field, bool ownPt) + { + if(!isInGroup()) + return ; + if(_own_target_field) + delete _target_field; + _target_field=field; + _own_target_field=ownPt; + } + + bool OverlapDEC::isInGroup() const + { + if(!_group) + return false; + return _group->containsMyRank(); + } +} diff --cc medtool/src/ParaMEDMEM/OverlapDEC.hxx index 48b853ca0,000000000..b7b9b8c2f mode 100644,000000..100644 --- a/medtool/src/ParaMEDMEM/OverlapDEC.hxx +++ b/medtool/src/ParaMEDMEM/OverlapDEC.hxx @@@ -1,61 -1,0 +1,61 @@@ +// Copyright (C) 2007-2015 CEA/DEN, EDF R&D +// +// 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +// +// See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com +// +// Author : Anthony Geay (CEA/DEN) + +#ifndef __OVERLAPDEC_HXX__ +#define __OVERLAPDEC_HXX__ + +#include "DEC.hxx" +#include "InterpolationOptions.hxx" + +#include + +namespace ParaMEDMEM +{ + class OverlapInterpolationMatrix; + class ProcessorGroup; + class ParaFIELD; + + class OverlapDEC : public DEC, public INTERP_KERNEL::InterpolationOptions + { + public: + OverlapDEC(const std::set& procIds,const MPI_Comm& world_comm=MPI_COMM_WORLD); + virtual ~OverlapDEC(); + void sendRecvData(bool way=true); + void sendData(); + void recvData(); + void synchronize(); + void attachSourceLocalField(ParaFIELD *field, bool ownPt=false); + void attachTargetLocalField(ParaFIELD *field, bool ownPt=false); + ProcessorGroup *getGrp() { return _group; } + bool isInGroup() const; + private: + bool _own_group; + OverlapInterpolationMatrix* _interpolation_matrix; + ProcessorGroup *_group; - private: ++ + ParaFIELD *_source_field; + bool _own_source_field; + ParaFIELD *_target_field; + bool _own_target_field; + MPI_Comm _comm; + }; +} + +#endif diff --cc medtool/src/ParaMEDMEM/OverlapElementLocator.hxx index 13a94c821,000000000..6ce2677f2 mode 100644,000000..100644 --- a/medtool/src/ParaMEDMEM/OverlapElementLocator.hxx +++ b/medtool/src/ParaMEDMEM/OverlapElementLocator.hxx @@@ -1,92 -1,0 +1,91 @@@ +// Copyright (C) 2007-2015 CEA/DEN, EDF R&D +// +// 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +// +// See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com +// +// Author : Anthony Geay (CEA/DEN) + +#ifndef __OVERLAPELEMENTLOCATOR_HXX__ +#define __OVERLAPELEMENTLOCATOR_HXX__ + +#include "InterpolationOptions.hxx" +#include "MEDCouplingNatureOfField.hxx" +#include "MEDCouplingPointSet.hxx" +#include "MEDCouplingMemArray.hxx" +#include "MEDCouplingAutoRefCountObjectPtr.hxx" + +#include +#include +#include +#include + +namespace ParaMEDMEM +{ + class ParaFIELD; + class ProcessorGroup; - class ParaSUPPORT; + class OverlapInterpolationMatrix; + + class OverlapElementLocator : public INTERP_KERNEL::InterpolationOptions + { + public: + OverlapElementLocator(const ParaFIELD *sourceField, const ParaFIELD *targetField, const ProcessorGroup& group); + virtual ~OverlapElementLocator(); + const MPI_Comm *getCommunicator() const; + void exchangeMeshes(OverlapInterpolationMatrix& matrix); + std::vector< std::pair > getToDoList() const { return _to_do_list; } + std::vector< std::vector< int > > getProcsInInteraction() const { return _proc_pairs; } + std::string getSourceMethod() const; + std::string getTargetMethod() const; + const MEDCouplingPointSet *getSourceMesh(int procId) const; + const DataArrayInt *getSourceIds(int procId) const; + const MEDCouplingPointSet *getTargetMesh(int procId) const; + const DataArrayInt *getTargetIds(int procId) const; + private: + void computeBoundingBoxes(); + bool intersectsBoundingBox(int i, int j) const; + void sendLocalMeshTo(int procId, bool sourceOrTarget, OverlapInterpolationMatrix& matrix) const; + void receiveRemoteMesh(int procId, bool sourceOrTarget); + void sendMesh(int procId, const MEDCouplingPointSet *mesh, const DataArrayInt *idsToSend) const; + void receiveMesh(int procId, MEDCouplingPointSet* &mesh, DataArrayInt *&ids) const; + private: + const ParaFIELD *_local_source_field; + const ParaFIELD *_local_target_field; + int _local_space_dim; + MEDCouplingPointSet *_local_source_mesh; + MEDCouplingPointSet *_local_target_mesh; + std::vector _distant_cell_meshes; + std::vector _distant_face_meshes; + //! of size _group.size(). Contains for each source proc i, the ids of proc j the targets interact with. This vector is common for all procs in _group. + std::vector< std::vector< int > > _proc_pairs; + //! list of interpolations couple to be done + std::vector< std::pair > _to_do_list; + std::vector< std::pair > _procs_to_send; + std::map, MEDCouplingAutoRefCountObjectPtr< MEDCouplingPointSet > > _remote_meshes; + std::map, MEDCouplingAutoRefCountObjectPtr< DataArrayInt > > _remote_elems; + double* _domain_bounding_boxes; + const ProcessorGroup& _group; + std::vector _distant_proc_ids; + const MPI_Comm *_comm; + //Attributes only used by lazy side + //std::vector _values_added; + //std::vector< std::vector > _ids_per_working_proc; + //std::vector< std::vector > _ids_per_working_proc3; + //std::vector< std::vector > _values_per_working_proc; + }; + +} + +#endif diff --cc medtool/src/ParaMEDMEM/OverlapInterpolationMatrix.hxx index 514deb8de,000000000..2190e9add mode 100644,000000..100644 --- a/medtool/src/ParaMEDMEM/OverlapInterpolationMatrix.hxx +++ b/medtool/src/ParaMEDMEM/OverlapInterpolationMatrix.hxx @@@ -1,126 -1,0 +1,131 @@@ +// Copyright (C) 2007-2015 CEA/DEN, EDF R&D +// +// 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +// +// See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com +// +// Author : Anthony Geay (CEA/DEN) + +#ifndef __OVERLAPINTERPOLATIONMATRIX_HXX__ +#define __OVERLAPINTERPOLATIONMATRIX_HXX__ + +#include "MPIAccessDEC.hxx" +#include "OverlapMapping.hxx" +#include "InterpolationOptions.hxx" +#include "DECOptions.hxx" + +namespace ParaMEDMEM +{ + class ParaFIELD; + class MEDCouplingPointSet; + ++ /*! ++ * Internal class, not part of the public API. ++ * ++ * Similar to InterpolationMatrix, but for the OverlapDEC instead of the InterpKernelDEC. ++ */ + class OverlapInterpolationMatrix : public INTERP_KERNEL::InterpolationOptions, + public DECOptions + { + public: + + OverlapInterpolationMatrix(ParaFIELD *source_field, + ParaFIELD *target_field, + const ProcessorGroup& group, + const DECOptions& dec_opt, + const InterpolationOptions& i_opt); + + void keepTracksOfSourceIds(int procId, DataArrayInt *ids); + + void keepTracksOfTargetIds(int procId, DataArrayInt *ids); + + void addContribution(const MEDCouplingPointSet *src, const DataArrayInt *srcIds, const std::string& srcMeth, int srcProcId, + const MEDCouplingPointSet *trg, const DataArrayInt *trgIds, const std::string& trgMeth, int trgProcId); + + void prepare(const std::vector< std::vector >& procsInInteraction); + + void computeDeno(); + + void multiply(); + + void transposeMultiply(); + + virtual ~OverlapInterpolationMatrix(); +#if 0 + void addContribution(MEDCouplingPointSet& distant_support, int iproc_distant, + const int* distant_elems, const std::string& srcMeth, const std::string& targetMeth); + void finishContributionW(ElementLocator& elementLocator); + void finishContributionL(ElementLocator& elementLocator); + void multiply(MEDCouplingFieldDouble& field) const; + void transposeMultiply(MEDCouplingFieldDouble& field)const; + void prepare(); + int getNbRows() const { return _row_offsets.size(); } + MPIAccessDEC* getAccessDEC() { return _mapping.getAccessDEC(); } + private: + void computeConservVolDenoW(ElementLocator& elementLocator); + void computeIntegralDenoW(ElementLocator& elementLocator); + void computeRevIntegralDenoW(ElementLocator& elementLocator); + void computeGlobConstraintDenoW(ElementLocator& elementLocator); + void computeConservVolDenoL(ElementLocator& elementLocator); + void computeIntegralDenoL(ElementLocator& elementLocator); + void computeRevIntegralDenoL(ElementLocator& elementLocator); + + void computeLocalColSum(std::vector& res) const; + void computeLocalRowSum(const std::vector& distantProcs, std::vector >& resPerProcI, + std::vector >& resPerProcD) const; + void computeGlobalRowSum(ElementLocator& elementLocator, std::vector >& denoStrorage, std::vector >& denoStrorageInv); + void computeGlobalColSum(std::vector >& denoStrorage); + void resizeGlobalColSum(std::vector >& denoStrorage); + void fillDSFromVM(int iproc_distant, const int* distant_elems, const std::vector< std::map >& values, MEDCouplingFieldDouble *surf); + void serializeMe(std::vector< std::vector< std::map > >& data1, std::vector& data2) const; + void initialize(); + void findAdditionnalElements(ElementLocator& elementLocator, std::vector >& elementsToAdd, + const std::vector >& resPerProcI, const std::vector >& globalIdsPartial); + void addGhostElements(const std::vector& distantProcs, const std::vector >& elementsToAdd); + int mergePolicies(const std::vector& policyPartial); + void mergeRowSum(const std::vector< std::vector >& rowsPartialSumD, const std::vector< std::vector >& globalIdsPartial, + std::vector& globalIdsLazySideInteraction, std::vector& sumCorresponding); + void mergeRowSum2(const std::vector< std::vector >& globalIdsPartial, std::vector< std::vector >& rowsPartialSumD, + const std::vector& globalIdsLazySideInteraction, const std::vector& sumCorresponding); + void mergeRowSum3(const std::vector< std::vector >& globalIdsPartial, std::vector< std::vector >& rowsPartialSumD); + void mergeCoeffs(const std::vector& procsInInteraction, const std::vector< std::vector >& rowsPartialSumI, + const std::vector >& globalIdsPartial, std::vector >& denoStrorageInv); + void divideByGlobalRowSum(const std::vector& distantProcs, const std::vector >& resPerProcI, + const std::vector >& resPerProcD, std::vector >& deno); +#endif + private: + bool isSurfaceComputationNeeded(const std::string& method) const; + void fillDistributedMatrix(const std::vector< std::map >& res, + const DataArrayInt *srcIds, int srcProc, + const DataArrayInt *trgIds, int trgProc); + static void TransposeMatrix(const std::vector >& matIn, int nbColsMatIn, std::vector >& matOut); + private: + ParaMEDMEM::ParaFIELD *_source_field; + ParaMEDMEM::ParaFIELD *_target_field; + std::vector _row_offsets; + std::map, int > _col_offsets; + MEDCouplingPointSet *_source_support; + MEDCouplingPointSet *_target_support; + OverlapMapping _mapping; + + const ProcessorGroup& _group; + std::vector< std::vector > _target_volume; + std::vector > > _coeffs; + std::vector > _deno_multiply; + std::vector > _deno_reverse_multiply; + }; +} + +#endif diff --cc medtool/src/ParaMEDMEM/OverlapMapping.hxx index 952524715,000000000..cfb06b1bb mode 100644,000000..100644 --- a/medtool/src/ParaMEDMEM/OverlapMapping.hxx +++ b/medtool/src/ParaMEDMEM/OverlapMapping.hxx @@@ -1,90 -1,0 +1,97 @@@ +// Copyright (C) 2007-2015 CEA/DEN, EDF R&D +// +// 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +// +// See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com +// +// Author : Anthony Geay (CEA/DEN) + +#ifndef __OVERLAPMAPPING_HXX__ +#define __OVERLAPMAPPING_HXX__ + +#include "MEDCouplingAutoRefCountObjectPtr.hxx" + +#include +#include + +namespace ParaMEDMEM +{ + class ProcessorGroup; + class DataArrayInt; + class MEDCouplingFieldDouble; + ++ /* ++ * Internal class, not part of the public API. ++ * ++ * Used by the impl of OverlapInterpolationMatrix, plays an equivalent role than what the NxM_Mapping ++ * does for the InterpolationMatrix. ++ * ++ */ + class OverlapMapping + { + public: + OverlapMapping(const ProcessorGroup& group); + void keepTracksOfSourceIds(int procId, DataArrayInt *ids); + void keepTracksOfTargetIds(int procId, DataArrayInt *ids); + void addContributionST(const std::vector< std::map >& matrixST, const DataArrayInt *srcIds, int srcProcId, const DataArrayInt *trgIds, int trgProcId); + void prepare(const std::vector< std::vector >& procsInInteraction, int nbOfTrgElems); + void computeDenoConservativeVolumic(int nbOfTuplesTrg); + void computeDenoGlobConstraint(); + // + void multiply(const MEDCouplingFieldDouble *fieldInput, MEDCouplingFieldDouble *fieldOutput) const; + void transposeMultiply(const MEDCouplingFieldDouble *fieldInput, MEDCouplingFieldDouble *fieldOutput); + private: + void serializeMatrixStep0ST(const int *nbOfElemsSrc, int *&bigArr, int *count, int *offsets, + int *countForRecv, int *offsetsForRecv) const; + int serializeMatrixStep1ST(const int *nbOfElemsSrc, const int *recvStep0, const int *countStep0, const int *offsStep0, + int *&bigArrI, double *&bigArrD, int *count, int *offsets, + int *countForRecv, int *offsForRecv) const; + void unserializationST(int nbOfTrgElems, const int *nbOfElemsSrcPerProc, const int *bigArrRecv, const int *bigArrRecvCounts, const int *bigArrRecvOffs, + const int *bigArrRecv2, const double *bigArrDRecv2, const int *bigArrRecv2Count, const int *bigArrRecv2Offs); + void finishToFillFinalMatrixST(); + void prepareIdsToSendST(); + void updateZipSourceIdsForFuture(); + //void printTheMatrix() const; + private: + const ProcessorGroup &_group; + //! vector of ids + std::vector< MEDCouplingAutoRefCountObjectPtr > _src_ids_st2;//item #1 + std::vector< int > _src_proc_st2;//item #1 + std::vector< MEDCouplingAutoRefCountObjectPtr > _trg_ids_st2;//item #0 + std::vector< int > _trg_proc_st2;//item #0 + std::vector< int > _nb_of_src_ids_proc_st2;//item #1 + std::vector< int > _src_ids_proc_st2;//item #1 + std::vector< std::vector > _src_ids_zip_st2;//same size as _src_ids_zip_proc_st2. Sorted. specifies for each id the corresponding ids to send. This is for item0 of Step2 of main algorithm + std::vector< int > _src_ids_zip_proc_st2; + //! vector of matrixes the first entry correspond to source proc id in _source_ids_st + std::vector< std::vector< std::map > > _matrixes_st; + std::vector< std::vector > _source_ids_st; + std::vector< int > _source_proc_id_st; + std::vector< std::vector > _target_ids_st; + std::vector< int > _target_proc_id_st; + //! the matrix for matrix-vector product. The first dimension the set of target procs that interacts with local source mesh. The second dimension correspond to nb of local source ids. + std::vector< std::vector< std::map > > _the_matrix_st; + std::vector< int > _the_matrix_st_source_proc_id; + std::vector< std::vector > _the_matrix_st_source_ids; + std::vector< std::vector< std::map > > _the_deno_st; + //! this attribute stores the proc ids that wait for data from this proc ids for matrix-vector computation + std::vector< int > _proc_ids_to_send_vector_st; + std::vector< int > _proc_ids_to_recv_vector_st; + //! this attribute is of size _group.size(); for each procId in _group _source_ids_to_send_st[procId] contains tupleId to send abroad + std::vector< std::vector > _source_ids_to_send_st; + }; +} + +#endif diff --cc medtool/src/ParaMEDMEM/ParaFIELD.cxx index 9995ccae1,000000000..e8e31e4ee mode 100644,000000..100644 --- a/medtool/src/ParaMEDMEM/ParaFIELD.cxx +++ b/medtool/src/ParaMEDMEM/ParaFIELD.cxx @@@ -1,228 -1,0 +1,227 @@@ +// Copyright (C) 2007-2015 CEA/DEN, EDF R&D +// +// 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +// +// See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com +// + +#include "Topology.hxx" +#include "BlockTopology.hxx" +#include "ComponentTopology.hxx" +#include "ExplicitCoincidentDEC.hxx" +#include "StructuredCoincidentDEC.hxx" +#include "CommInterface.hxx" +#include "ProcessorGroup.hxx" +#include "MPIProcessorGroup.hxx" +#include "ParaFIELD.hxx" +#include "ParaMESH.hxx" +#include "InterpKernelUtilities.hxx" +#include "InterpolationMatrix.hxx" + +#include + +namespace ParaMEDMEM +{ + /*! + \anchor ParaFIELD-det + \class ParaFIELD + + This class encapsulates parallel fields. + - It basically encapsulates - a MEDCouplingField with extra information related to parallel ++ It gathers a \ref fields "MEDCouplingField" with some extra information related to the parallel + topology. + - It is most conveniently created by giving a pointer to a MEDCouplingField - object and a \c ProcessorGroup. ++ It is most conveniently created by giving a pointer to a MEDCouplingFieldDouble ++ object and a ProcessorGroup. + By default, a ParaFIELD object will be constructed with all field components - located on the same processors. In some specific cases, it might be necessary to scatter components over several processors. In this case, the constructor - using a ComponentTopology is required. ++ located on the same processors. In some specific cases, it might be necessary to scatter components over ++ several processors. In this case, the constructor using a ComponentTopology is required. + + */ + + /*! + - \brief Constructing a \c ParaFIELD from a \c ParaSUPPORT and a \c ComponentTopology. ++ \brief Constructing a \c ParaFIELD from a \c ParaMESH and a \c ComponentTopology. + - This constructor creates an empty field based on the ParaSUPPORT description ++ This constructor creates an empty field based on the ParaMESH description + and the partitioning of components described in \a component_topology. + It takes ownership over the \c _field object that it creates. + + Here come the three ComponentTopology constructors : + \verbatim + ComponentTopology c; // one component in the field + ComponentTopology c(6); //six components, all of them on the same processor + ComponentTopology c(6, proc_group); // six components, evenly distributed over the processors of procgroup + \endverbatim + + */ + ParaFIELD::ParaFIELD(TypeOfField type, TypeOfTimeDiscretization td, ParaMESH* para_support, const ComponentTopology& component_topology) + :_field(0), + _component_topology(component_topology),_topology(0),_own_support(false), + _support(para_support) + { + if (para_support->isStructured() || (para_support->getTopology()->getProcGroup()->size()==1 && component_topology.nbBlocks()!=1)) + { + const BlockTopology* source_topo = dynamic_cast(para_support->getTopology()); + _topology=new BlockTopology(*source_topo,component_topology); + } + else + { + if (component_topology.nbBlocks()!=1 && para_support->getTopology()->getProcGroup()->size()!=1) + throw INTERP_KERNEL::Exception(LOCALIZED("ParaFIELD constructor : Unstructured Support not taken into account with component topology yet")); + else + { + const BlockTopology* source_topo=dynamic_cast (para_support->getTopology()); + int nb_local_comp=component_topology.nbLocalComponents(); + _topology=new BlockTopology(*source_topo,nb_local_comp); + } + } + int nb_components = component_topology.nbLocalComponents(); + if (nb_components!=0) + { + _field=MEDCouplingFieldDouble::New(type,td); + _field->setMesh(_support->getCellMesh()); + DataArrayDouble *array=DataArrayDouble::New(); + array->alloc(_field->getNumberOfTuples(),nb_components); + _field->setArray(array); + array->decrRef(); + } + else return; + + _field->setName("Default ParaFIELD name"); + _field->setDescription("Default ParaFIELD description"); + } + + /*! \brief Constructor creating the ParaFIELD + from a given FIELD and a processor group. + - This constructor supposes that support underlying \a subdomain_field has no ParaSUPPORT ++ This constructor supposes that support underlying \a subdomain_field has no ParaMESH + attached and it therefore recreates one. It therefore takes ownership over _support. The component topology associated with the field is a basic one (all components on the same processor). + */ + ParaFIELD::ParaFIELD(MEDCouplingFieldDouble* subdomain_field, ParaMESH *sup, const ProcessorGroup& proc_group): + _field(subdomain_field), + _component_topology(ComponentTopology(_field->getNumberOfComponents())),_topology(0),_own_support(false), + _support(sup) + { + if(_field) + _field->incrRef(); + const BlockTopology* source_topo=dynamic_cast (_support->getTopology()); + _topology=new BlockTopology(*source_topo,_component_topology.nbLocalComponents()); + } + + ParaFIELD::~ParaFIELD() + { + if(_field) + _field->decrRef(); + if(_own_support) + delete _support; + delete _topology; + } + + void ParaFIELD::synchronizeTarget(ParaFIELD* source_field) + { + DisjointDEC* data_channel; + if (dynamic_cast(_topology)!=0) + { + data_channel=new StructuredCoincidentDEC; + } + else + { + data_channel=new ExplicitCoincidentDEC; + } + data_channel->attachLocalField(this); + data_channel->synchronize(); + data_channel->prepareTargetDE(); + data_channel->recvData(); + + delete data_channel; + } + + void ParaFIELD::synchronizeSource(ParaFIELD* target_field) + { + DisjointDEC* data_channel; + if (dynamic_cast(_topology)!=0) + { + data_channel=new StructuredCoincidentDEC; + } + else + { + data_channel=new ExplicitCoincidentDEC; + } + data_channel->attachLocalField(this); + data_channel->synchronize(); + data_channel->prepareSourceDE(); + data_channel->sendData(); + + delete data_channel; + } + + /*! + * This method returns, if it exists, an array with only one component and as many as tuples as _field has. + * This array gives for every element on which this->_field lies, its global number, if this->_field is nodal. + * For example if _field is a nodal field : returned array will be the nodal global numbers. + * The content of this method is used to inform Working side to accumulate data recieved by lazy side. + */ + DataArrayInt* ParaFIELD::returnCumulativeGlobalNumbering() const + { + if(!_field) + return 0; + TypeOfField type=_field->getTypeOfField(); + switch(type) + { + case ON_CELLS: + return 0; + case ON_NODES: + return _support->getGlobalNumberingNodeDA(); + default: + return 0; + } + } + + DataArrayInt* ParaFIELD::returnGlobalNumbering() const + { + if(!_field) + return 0; + TypeOfField type=_field->getTypeOfField(); + switch(type) + { + case ON_CELLS: + return _support->getGlobalNumberingCellDA(); + case ON_NODES: + return _support->getGlobalNumberingNodeDA(); + default: + return 0; + } + } + + int ParaFIELD::nbComponents() const + { + return _component_topology.nbComponents(); + } + + + /*! This method retrieves the integral of component \a icomp + over the all domain. */ + double ParaFIELD::getVolumeIntegral(int icomp, bool isWAbs) const + { + CommInterface comm_interface = _topology->getProcGroup()->getCommInterface(); + double integral=_field->integral(icomp,isWAbs); + double total=0.; + const MPI_Comm* comm = (dynamic_cast(_topology->getProcGroup()))->getComm(); + comm_interface.allReduce(&integral, &total, 1, MPI_DOUBLE, MPI_SUM, *comm); + + return total; + } +} diff --cc medtool/src/ParaMEDMEM/ParaFIELD.hxx index 2f5f89367,000000000..fe0a6f9d7 mode 100644,000000..100644 --- a/medtool/src/ParaMEDMEM/ParaFIELD.hxx +++ b/medtool/src/ParaMEDMEM/ParaFIELD.hxx @@@ -1,66 -1,0 +1,64 @@@ +// Copyright (C) 2007-2015 CEA/DEN, EDF R&D +// +// 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +// +// See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com +// + +#ifndef __PARAFIELD_HXX__ +#define __PARAFIELD_HXX__ + +#include "MEDCouplingRefCountObject.hxx" +#include "ComponentTopology.hxx" + +namespace ParaMEDMEM +{ + class DataArrayInt; + class ParaMESH; + class ProcessorGroup; + class MEDCouplingFieldDouble; + class ComponentTopology; + class Topology; + + class ParaFIELD + { + public: - + ParaFIELD(TypeOfField type, TypeOfTimeDiscretization td, ParaMESH* mesh, const ComponentTopology& component_topology); - - + ParaFIELD(MEDCouplingFieldDouble* field, ParaMESH *sup, const ProcessorGroup& group); - + virtual ~ParaFIELD(); ++ + void synchronizeTarget( ParaMEDMEM::ParaFIELD* source_field); + void synchronizeSource( ParaMEDMEM::ParaFIELD* target_field); + MEDCouplingFieldDouble* getField() const { return _field; } + void setOwnSupport(bool v) const { _own_support=v; } + DataArrayInt* returnCumulativeGlobalNumbering() const; + DataArrayInt* returnGlobalNumbering() const; + Topology* getTopology() const { return _topology; } + ParaMESH* getSupport() const { return _support; } + int nbComponents() const; + double getVolumeIntegral(int icomp, bool isWAbs) const; + double getL2Norm()const { return -1; } ++ + private: + MEDCouplingFieldDouble* _field; + ParaMEDMEM::ComponentTopology _component_topology; + Topology* _topology; + mutable bool _own_support; + ParaMESH* _support; + }; + +} + +#endif diff --cc medtool/src/ParaMEDMEM/ParaGRID.cxx index f45c1e7ac,000000000..8b26bd5f9 mode 100644,000000..100644 --- a/medtool/src/ParaMEDMEM/ParaGRID.cxx +++ b/medtool/src/ParaMEDMEM/ParaGRID.cxx @@@ -1,74 -1,0 +1,74 @@@ +// Copyright (C) 2007-2015 CEA/DEN, EDF R&D +// +// 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +// +// See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com +// + +#include "ParaGRID.hxx" +#include "Topology.hxx" +#include "BlockTopology.hxx" +#include "MEDCouplingMemArray.hxx" +#include "MEDCouplingCMesh.hxx" +#include "InterpKernelUtilities.hxx" + +#include + +using namespace std; + +namespace ParaMEDMEM +{ + - ParaGRID::ParaGRID(MEDCouplingCMesh* global_grid, Topology* topology) throw(INTERP_KERNEL::Exception) ++ ParaGRID::ParaGRID(MEDCouplingCMesh* global_grid, Topology* topology) throw(INTERP_KERNEL::Exception) : ++ _global_axis(), _my_domain_id(0) + { - + _block_topology = dynamic_cast(topology); + if(_block_topology==0) + throw INTERP_KERNEL::Exception(LOCALIZED("ParaGRID::ParaGRID topology must be block topology")); + + if (!_block_topology->getProcGroup()->containsMyRank()) + return; + + int dimension=_block_topology->getDimension() ; + if (dimension != global_grid->getSpaceDimension()) + throw INTERP_KERNEL::Exception(LOCALIZED("ParaGrid::ParaGrid incompatible topology")); + _grid=global_grid; + _grid->incrRef(); + /*vector > xyz_array(dimension); + vector > local_indices = _block_topology->getLocalArrayMinMax(); + vector coordinates_names; + vector coordinates_units; + for (int idim=0; idimgetCoordsAt(idim); + double *arrayC=array->getPointer(); + cout << " Indices "<< local_indices[idim].first <<" "<getName()); + coordinates_units.push_back(array->getInfoOnComponentAt(0)); + } + _grid=MEDCouplingCMesh::New(); + _grid->set(xyz_array, coordinates_names,coordinates_units); + _grid->setName(global_grid->getName()); + _grid->setDescription(global_grid->getDescription());*/ + } + + ParaGRID::~ParaGRID() + { + if(_grid) + _grid->decrRef(); + } +} diff --cc medtool/src/ParaMEDMEM/ParaGRID.hxx index 2335b9d6c,000000000..72a0109ec mode 100644,000000..100644 --- a/medtool/src/ParaMEDMEM/ParaGRID.hxx +++ b/medtool/src/ParaMEDMEM/ParaGRID.hxx @@@ -1,51 -1,0 +1,55 @@@ +// Copyright (C) 2007-2015 CEA/DEN, EDF R&D +// +// 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +// +// See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com +// + +#ifndef __PARAGRID_HXX__ +#define __PARAGRID_HXX__ + +#include "InterpolationUtils.hxx" + +#include + +namespace ParaMEDMEM +{ + class Topology; + class BlockTopology; + class MEDCouplingCMesh; + ++ /*! ++ * This class ++ * Equivalent of a ParaMESH for a structured mesh ++ */ + class ParaGRID + { + public: + ParaGRID(MEDCouplingCMesh* global_grid, Topology* topology) throw(INTERP_KERNEL::Exception); + BlockTopology * getBlockTopology() const { return _block_topology; } + virtual ~ParaGRID(); + MEDCouplingCMesh* getGrid() const { return _grid; } + private: + MEDCouplingCMesh* _grid; + // structured grid topology + ParaMEDMEM::BlockTopology* _block_topology; + // stores the x,y,z axes on the global grid + std::vector > _global_axis; + //id of the local grid + int _my_domain_id; + }; +} + +#endif diff --cc medtool/src/ParaMEDMEM/ParaMESH.cxx index a6482a554,000000000..70b1ffff7 mode 100644,000000..100644 --- a/medtool/src/ParaMEDMEM/ParaMESH.cxx +++ b/medtool/src/ParaMEDMEM/ParaMESH.cxx @@@ -1,122 -1,0 +1,122 @@@ - // Copyright (C) 2007-2015 CEA/DEN, EDF R&D +// ++// Copyright (C) 2007-2015 CEA/DEN, EDF R&D +// 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +// +// See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com +// + +#include "ParaMESH.hxx" +#include "ProcessorGroup.hxx" +#include "MPIProcessorGroup.hxx" +#include "Topology.hxx" +#include "BlockTopology.hxx" +#include "MEDCouplingMemArray.hxx" + +#include +#include + +//inclusion for the namespaces +using namespace std; + +namespace ParaMEDMEM +{ + ParaMESH::ParaMESH( MEDCouplingPointSet *subdomain_mesh, MEDCouplingPointSet *subdomain_face, + DataArrayInt *CorrespElt_local2global, DataArrayInt *CorrespFace_local2global, + DataArrayInt *CorrespNod_local2global, const ProcessorGroup& proc_group ): + _cell_mesh(subdomain_mesh), + _face_mesh(subdomain_face), + _my_domain_id(proc_group.myRank()), + _block_topology (new BlockTopology(proc_group, subdomain_mesh->getNumberOfCells())), + _explicit_topology(0), + _node_global(CorrespNod_local2global), + _face_global(CorrespFace_local2global), + _cell_global(CorrespElt_local2global) + { + if(_cell_mesh) + _cell_mesh->incrRef(); + if(_face_mesh) + _face_mesh->incrRef(); + if(CorrespElt_local2global) + CorrespElt_local2global->incrRef(); + if(CorrespFace_local2global) + CorrespFace_local2global->incrRef(); + if(CorrespNod_local2global) + CorrespNod_local2global->incrRef(); + } + + ParaMESH::ParaMESH( MEDCouplingPointSet *mesh, const ProcessorGroup& proc_group, const std::string& name): + _cell_mesh(mesh), + _face_mesh(0), + _my_domain_id(proc_group.myRank()), + _block_topology (new BlockTopology(proc_group, mesh->getNumberOfCells())), + _node_global(0), + _face_global(0) + { + if(_cell_mesh) + _cell_mesh->incrRef(); + int nb_elem=mesh->getNumberOfCells(); + _explicit_topology=new BlockTopology(proc_group,nb_elem); + int nbOfCells=mesh->getNumberOfCells(); + _cell_global = DataArrayInt::New(); + _cell_global->alloc(nbOfCells,1); + int *cellglobal=_cell_global->getPointer(); + int offset = _block_topology->localToGlobal(make_pair(_my_domain_id,0)); + for (int i=0; idecrRef(); + _node_global=nodeGlobal; + if(_node_global) + _node_global->incrRef(); + } + } + + void ParaMESH::setCellGlobal(DataArrayInt *cellGlobal) + { + if(cellGlobal!=_cell_global) + { + if(_cell_global) + _cell_global->decrRef(); + _cell_global=cellGlobal; + if(_cell_global) + _cell_global->incrRef(); + } + } + + ParaMESH::~ParaMESH() + { + if(_cell_mesh) + _cell_mesh->decrRef(); + if(_face_mesh) + _face_mesh->decrRef(); + delete _block_topology; + if(_node_global) + _node_global->decrRef(); + if(_cell_global) + _cell_global->decrRef(); + if(_face_global) + _face_global->decrRef(); + delete _explicit_topology; + } + +} diff --cc medtool/src/ParaMEDMEM/ParaMESH.hxx index 391bff5dd,000000000..06c6d754a mode 100644,000000..100644 --- a/medtool/src/ParaMEDMEM/ParaMESH.hxx +++ b/medtool/src/ParaMEDMEM/ParaMESH.hxx @@@ -1,82 -1,0 +1,93 @@@ +// Copyright (C) 2007-2015 CEA/DEN, EDF R&D +// +// 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +// +// See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com +// + +#ifndef __PARAMESH_HXX__ +#define __PARAMESH_HXX__ + +#include "MEDCouplingPointSet.hxx" +#include "ProcessorGroup.hxx" +#include "MEDCouplingMemArray.hxx" + +#include +#include + +namespace ParaMEDMEM +{ + class Topology; + class BlockTopology; + class DataArrayInt; + ++ /*! ++ * \anchor ParaMESH-det ++ * ++ * Parallel representation of an unstructured mesh. ++ * ++ * This class is very specific to the requirement of parallel code computations. ++ * Two main constructors are available: ++ * - the most simple one, taking directly a \ref meshes "MEDCoupling mesh" object ++ * - the second one (for an advanced usage), which can be used to specify an explicit topology ++ * in a parallel computation. ++ */ + class ParaMESH + { + public: ++ ParaMESH( MEDCouplingPointSet *mesh, ++ const ProcessorGroup& proc_group, const std::string& name); + ParaMESH( MEDCouplingPointSet *subdomain_mesh, + MEDCouplingPointSet *subdomain_face, + DataArrayInt *CorrespElt_local2global, + DataArrayInt *CorrespFace_local2global, + DataArrayInt *CorrespNod_local2global, + const ProcessorGroup& proc_group ) ; - ParaMESH( MEDCouplingPointSet *mesh, - const ProcessorGroup& proc_group, const std::string& name); + + virtual ~ParaMESH(); + void setNodeGlobal(DataArrayInt *nodeGlobal); + void setCellGlobal(DataArrayInt *cellGlobal); + Topology* getTopology() const { return _explicit_topology; } + bool isStructured() const { return _cell_mesh->isStructured(); } + MEDCouplingPointSet *getCellMesh() const { return _cell_mesh; } + MEDCouplingPointSet *getFaceMesh() const { return _face_mesh; } + BlockTopology* getBlockTopology() const { return _block_topology; } + + DataArrayInt* getGlobalNumberingNodeDA() const { if(_node_global) _node_global->incrRef(); return _node_global; } + DataArrayInt* getGlobalNumberingFaceDA() const { if(_face_global) _face_global->incrRef(); return _face_global; } + DataArrayInt* getGlobalNumberingCellDA() const { if(_cell_global) _cell_global->incrRef(); return _cell_global; } + const int* getGlobalNumberingNode() const { if(_node_global) return _node_global->getConstPointer(); return 0; } + const int* getGlobalNumberingFace() const { if(_face_global) return _face_global->getConstPointer(); return 0; } + const int* getGlobalNumberingCell() const { if(_cell_global) return _cell_global->getConstPointer(); return 0; } + + private: + //mesh object underlying the ParaMESH object + MEDCouplingPointSet *_cell_mesh ; + MEDCouplingPointSet *_face_mesh ; + + //id of the local grid + int _my_domain_id; + + //global topology of the cells + ParaMEDMEM::BlockTopology* _block_topology; + Topology* _explicit_topology; + // pointers to global numberings + DataArrayInt* _node_global; + DataArrayInt* _face_global; + DataArrayInt* _cell_global; + }; +} + +#endif diff --cc medtool/src/ParaMEDMEM/ProcessorGroup.hxx index 344704a9f,000000000..972219b9e mode 100644,000000..100644 --- a/medtool/src/ParaMEDMEM/ProcessorGroup.hxx +++ b/medtool/src/ParaMEDMEM/ProcessorGroup.hxx @@@ -1,60 -1,0 +1,65 @@@ +// Copyright (C) 2007-2015 CEA/DEN, EDF R&D +// +// 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +// +// See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com +// + +#ifndef __PROCESSORGROUP_HXX__ +#define __PROCESSORGROUP_HXX__ + +#include "CommInterface.hxx" + +#include + +namespace ParaMEDMEM +{ ++ /*! ++ * Abstract class defining a group of processors (computation nodes) in a parallel run of a code. ++ * ++ * See the non-abstract child \ref MPIProcessorGroup-det "MPIProcessorGroup" ++ */ + class ProcessorGroup + { + public: + + ProcessorGroup(const CommInterface& interface):_comm_interface(interface) { } + ProcessorGroup(const CommInterface& interface, std::set proc_ids): + _comm_interface(interface),_proc_ids(proc_ids) { } + ProcessorGroup (const ProcessorGroup& proc_group, std::set proc_ids): + _comm_interface(proc_group.getCommInterface()),_proc_ids(proc_ids) { } + ProcessorGroup (const ProcessorGroup& other): + _comm_interface(other.getCommInterface()),_proc_ids(other._proc_ids) { } + ProcessorGroup (const CommInterface& interface, int start, int end); + virtual ~ProcessorGroup() { } + virtual ProcessorGroup *deepCpy() const = 0; + virtual ProcessorGroup* fuse (const ProcessorGroup&) const = 0; + virtual void intersect (ProcessorGroup&) = 0; + bool contains(int rank) const { return _proc_ids.find(rank)!=_proc_ids.end(); } + virtual bool containsMyRank() const = 0; + int size() const { return _proc_ids.size(); } + const CommInterface& getCommInterface()const { return _comm_interface; } + virtual int myRank() const = 0; + virtual int translateRank(const ProcessorGroup*, int) const = 0; + virtual ProcessorGroup* createComplementProcGroup() const = 0; + virtual ProcessorGroup* createProcGroup() const = 0; + virtual const std::set& getProcIDs()const { return _proc_ids; } + protected: + const CommInterface _comm_interface; + std::set _proc_ids; + }; +} + +#endif diff --cc medtool/src/ParaMEDMEM/StructuredCoincidentDEC.cxx index 1e88a9581,000000000..9620ba135 mode 100644,000000..100644 --- a/medtool/src/ParaMEDMEM/StructuredCoincidentDEC.cxx +++ b/medtool/src/ParaMEDMEM/StructuredCoincidentDEC.cxx @@@ -1,412 -1,0 +1,419 @@@ +// Copyright (C) 2007-2015 CEA/DEN, EDF R&D +// +// 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +// +// See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com +// + +#include +#include "CommInterface.hxx" +#include "Topology.hxx" +#include "BlockTopology.hxx" +#include "ComponentTopology.hxx" +#include "ParaFIELD.hxx" +#include "MPIProcessorGroup.hxx" +#include "StructuredCoincidentDEC.hxx" +#include "InterpKernelUtilities.hxx" + +#include + +using namespace std; + +namespace ParaMEDMEM +{ + + /*! + \anchor StructuredCoincidentDEC-det + \class StructuredCoincidentDEC + - This class is meant for remapping fields that have identical - supports with different parallel topologies. It can be used to couple - together multiphysics codes that operate on the same domain - with different partitionings, which can be useful if one of ++ This class aims at \ref interpolation "remapping fields" that have identical ++ structured supports (=the same underlying mesh) but different parallel topologies ++ (=different sub-domains in the structured mesh). It can be used to couple ++ together multi-physics codes that operate on the same domain ++ with different partitioning. This can be useful for example if one of + the computation is much faster than the other. It can also be used + to couple together codes that share an interface that was generated + in the same manner (with identical global ids). - Also, this \ref para-dec can be used for fields that have component topologies, ++ Also, this \ref para-dec "DEC" can be used for fields that have component topologies, + i.e., components that are scattered over several processors. + + The remapping between the two supports is based on identity of global - ids, instead of geometrical considerations as it is the case for - \ref NonCoincidentDEC-det "NonCoincidentDEC" and \ref InterpKernelDEC-det "InterpKernelDEC". - Therefore, this \ref para-dec "DEC" must not be used - for coincident meshes that do not have the same numbering. ++ ids, instead of geometrical considerations (as it is the case for ++ \ref InterpKernelDEC-det "InterpKernelDEC"). ++ Therefore, beware that this \ref para-dec "DEC" can not be used ++ for coincident meshes if they do *not* have the exact same numbering. + - As all the other DECs, its use is made of two phases : ++ With this %DEC no projection, and no interpolation of the field data is done, contrary ++ to what happens in \ref InterpKernelDEC-det "InterpKernelDEC". It is just ++ a matter of allocating the values from one side to the other, using directly the cell ++ identifiers. ++ ++ As all the other DECs, its usage requires two phases : + - a setup phase during which the topologies are exchanged so that + the target side knows from which processors it should expect + the data. + - a send/recv phase during which the field data is actually transferred. + + This example illustrates the sending of a field with + the \c StructuredCoincidentDEC : + \code + ... + StructuredCoincidentDEC dec(groupA, groupB); + dec.attachLocalField(field); + dec.synchronize(); + if (groupA.containsMyRank()) + dec.recvData(); + else if (groupB.containsMyRank()) + dec.sendData(); + ... + \endcode + - Creating a ParaFIELD to be attached to the DEC is exactly the same as for - other DECs in the case when the remapping concerns similar meshes - that only have different partitionings. In the case when the - fields have also different component topologies, creating the ParaFIELD - requires some more effort. See the \ref para-over section for more details. ++ Creating a ParaFIELD to be attached to the %DEC is done in exactly the same way as for ++ the other DECs, if only the partitioning of the support mesh differs. ++ In the case where the ++ fields have also different *component* topologies, creating the ParaFIELD ++ requires some more effort. See the \ref para-over "parallelism" section for more details. + */ + + + StructuredCoincidentDEC::StructuredCoincidentDEC():_topo_source(0),_topo_target(0), + _send_counts(0),_recv_counts(0), + _send_displs(0),_recv_displs(0), + _recv_buffer(0),_send_buffer(0) + { + } + + + StructuredCoincidentDEC::~StructuredCoincidentDEC() + { + delete [] _send_buffer; + delete [] _recv_buffer; + delete []_send_displs; + delete [] _recv_displs; + delete [] _send_counts; + delete [] _recv_counts; + if (! _source_group->containsMyRank()) + delete _topo_source; + if(!_target_group->containsMyRank()) + delete _topo_target; + } + - StructuredCoincidentDEC::StructuredCoincidentDEC(ProcessorGroup& local_group, ProcessorGroup& distant_group):DisjointDEC(local_group,distant_group), - _topo_source(0),_topo_target(0), - _send_counts(0),_recv_counts(0), - _send_displs(0),_recv_displs(0), - _recv_buffer(0),_send_buffer(0) ++ StructuredCoincidentDEC::StructuredCoincidentDEC(ProcessorGroup& local_group, ProcessorGroup& distant_group): ++ DisjointDEC(local_group,distant_group), ++ _topo_source(0),_topo_target(0), ++ _send_counts(0),_recv_counts(0), ++ _send_displs(0),_recv_displs(0), ++ _recv_buffer(0),_send_buffer(0) + { + } + + /*! Synchronization process for exchanging topologies + */ + void StructuredCoincidentDEC::synchronizeTopology() + { + if (_source_group->containsMyRank()) + _topo_source = dynamic_cast(_local_field->getTopology()); + if (_target_group->containsMyRank()) + _topo_target = dynamic_cast(_local_field->getTopology()); + + // Transmitting source topology to target code + broadcastTopology(_topo_source,1000); + // Transmitting target topology to source code + broadcastTopology(_topo_target,2000); + if (_topo_source->getNbElements() != _topo_target->getNbElements()) + throw INTERP_KERNEL::Exception("Incompatible dimensions for target and source topologies"); + + } + + /*! Creates the arrays necessary for the data transfer + * and fills the send array with the values of the + * source field + * */ + void StructuredCoincidentDEC::prepareSourceDE() + { + //////////////////////////////////// + //Step 1 : _buffer array creation + + if (!_topo_source->getProcGroup()->containsMyRank()) + return; + MPIProcessorGroup* group=new MPIProcessorGroup(_topo_source->getProcGroup()->getCommInterface()); + + int myranksource = _topo_source->getProcGroup()->myRank(); + + vector * target_arrays=new vector[_topo_target->getProcGroup()->size()]; + + //cout<<" topotarget size"<< _topo_target->getProcGroup()->size()< getNbLocalElements(); + for (int ielem=0; ielem< nb_local ; ielem++) + { + // cout <<"source local :"<localToGlobal(make_pair(myranksource, ielem)); + // cout << "global "< target_local =_topo_target->globalToLocal(global); + // cout << "target local : "<size(); + + _send_counts=new int[union_size]; + _send_displs=new int[union_size]; + _recv_counts=new int[union_size]; + _recv_displs=new int[union_size]; + + for (int i=0; i< union_size; i++) + { + _send_counts[i]=0; + _recv_counts[i]=0; + _recv_displs[i]=0; + } + _send_displs[0]=0; + + for (int iproc=0; iproc < _topo_target->getProcGroup()->size(); iproc++) + { + //converts the rank in target to the rank in union communicator + int unionrank=group->translateRank(_topo_target->getProcGroup(),iproc); + _send_counts[unionrank]=target_arrays[iproc].size(); + } + + for (int iproc=1; iprocsize();iproc++) + _send_displs[iproc]=_send_displs[iproc-1]+_send_counts[iproc-1]; + + _send_buffer = new double [nb_local ]; + + ///////////////////////////////////////////////////////////// + //Step 2 : filling the _buffers with the source field values + + int* counter=new int [_topo_target->getProcGroup()->size()]; + counter[0]=0; + for (int i=1; i<_topo_target->getProcGroup()->size(); i++) + counter[i]=counter[i-1]+target_arrays[i-1].size(); + + + const double* value = _local_field->getField()->getArray()->getPointer(); + //cout << "Nb local " << nb_local<localToGlobal(make_pair(myranksource, ielem)); + pair target_local =_topo_target->globalToLocal(global); + //cout <<"global : "<< global<<" local :"<getProcGroup()->containsMyRank()) + return; + MPIProcessorGroup* group=new MPIProcessorGroup(_topo_source->getProcGroup()->getCommInterface()); + + int myranktarget = _topo_target->getProcGroup()->myRank(); + + vector < vector > source_arrays(_topo_source->getProcGroup()->size()); + int nb_local = _topo_target-> getNbLocalElements(); + for (int ielem=0; ielem< nb_local ; ielem++) + { + // cout <<"TS target local :"<localToGlobal(make_pair(myranktarget, ielem)); + //cout << "TS global "< source_local =_topo_source->globalToLocal(global); + // cout << "TS source local : "<size(); + _recv_counts=new int[union_size]; + _recv_displs=new int[union_size]; + _send_counts=new int[union_size]; + _send_displs=new int[union_size]; + + for (int i=0; i< union_size; i++) + { + _send_counts[i]=0; + _recv_counts[i]=0; + _recv_displs[i]=0; + } + for (int iproc=0; iproc < _topo_source->getProcGroup()->size(); iproc++) + { + //converts the rank in target to the rank in union communicator + int unionrank=group->translateRank(_topo_source->getProcGroup(),iproc); + _recv_counts[unionrank]=source_arrays[iproc].size(); + } + for (int i=1; igetProcGroup()->myRank()==0) + { + MESSAGE ("Master rank"); + topo->serialize(serializer, size); + rank_master = group->translateRank(topo->getProcGroup(),0); + MESSAGE("Master rank world number is "<size()); + for (int i=0; i< group->size(); i++) + { + if (i!= rank_master) + _comm_interface->send(&rank_master,1,MPI_INT, i,tag+i,*(group->getComm())); + } + } + else + { + MESSAGE(" rank "<myRank()<< " waiting ..."); + _comm_interface->recv(&rank_master, 1,MPI_INT, MPI_ANY_SOURCE, tag+group->myRank(), *(group->getComm()),&status); + MESSAGE(" rank "<myRank()<< "received master rank"<broadcast(&size, 1,MPI_INT,rank_master,*(group->getComm())); + + int* buffer=new int[size]; + if (topo!=0 && topo->getProcGroup()->myRank()==0) + copy(serializer, serializer+size, buffer); + _comm_interface->broadcast(buffer,size,MPI_INT,rank_master,*(group->getComm())); + + // Processors which did not possess the source topology + // unserialize it + + BlockTopology* topotemp=new BlockTopology(); + topotemp->unserialize(buffer, *_comm_interface); + + if (topo==0) + topo=topotemp; + else + delete topotemp; + + // Memory cleaning + delete[] buffer; + if (serializer!=0) + delete[] serializer; + MESSAGE (" rank "<myRank()<< " unserialize is over"); + delete group; + } + + + + void StructuredCoincidentDEC::recvData() + { + //MPI_COMM_WORLD is used instead of group because there is no + //mechanism for creating the union group yet + MESSAGE("recvData"); + for (int i=0; i< 4; i++) + cout << _recv_counts[i]<<" "; + cout <(_union_group)->getComm()); + _comm_interface->allToAllV(_send_buffer, _send_counts, _send_displs, MPI_DOUBLE, + _recv_buffer, _recv_counts, _recv_displs, MPI_DOUBLE,comm); + cout<<"end AllToAll"<getNbLocalElements(); + //double* value=new double[nb_local]; + double* value=const_cast(_local_field->getField()->getArray()->getPointer()); + + int myranktarget=_topo_target->getProcGroup()->myRank(); + vector counters(_topo_source->getProcGroup()->size()); + counters[0]=0; + for (int i=0; i<_topo_source->getProcGroup()->size()-1; i++) + { + MPIProcessorGroup* group=new MPIProcessorGroup(*_comm_interface); + int worldrank=group->translateRank(_topo_source->getProcGroup(),i); + counters[i+1]=counters[i]+_recv_counts[worldrank]; + delete group; + } + + for (int ielem=0; ielemlocalToGlobal(make_pair(myranktarget, ielem)); + pair source_local =_topo_source->globalToLocal(global); + value[ielem]=_recv_buffer[counters[source_local.first]++]; + } + + + //_local_field->getField()->setValue(value); + } + + void StructuredCoincidentDEC::sendData() + { + MESSAGE ("sendData"); + for (int i=0; i< 4; i++) + cout << _send_counts[i]<<" "; + cout <(_union_group)->getComm()); + _comm_interface->allToAllV(_send_buffer, _send_counts, _send_displs, MPI_DOUBLE, + _recv_buffer, _recv_counts, _recv_displs, MPI_DOUBLE,comm); + cout<<"end AllToAll"<containsMyRank()) + { + synchronizeTopology(); + prepareSourceDE(); + } + else if (_target_group->containsMyRank()) + { + synchronizeTopology(); + prepareTargetDE(); + } + } +} + diff --cc medtool/src/ParaMEDMEM/StructuredCoincidentDEC.hxx index 75f63b4f0,000000000..1653467b1 mode 100644,000000..100644 --- a/medtool/src/ParaMEDMEM/StructuredCoincidentDEC.hxx +++ b/medtool/src/ParaMEDMEM/StructuredCoincidentDEC.hxx @@@ -1,58 -1,0 +1,59 @@@ +// Copyright (C) 2007-2015 CEA/DEN, EDF R&D +// +// 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +// +// See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com +// + +#ifndef __STRUCTUREDCOINCIDENTDEC_HXX__ +#define __STRUCTUREDCOINCIDENTDEC_HXX__ + +#include "DisjointDEC.hxx" +#include "BlockTopology.hxx" + + +namespace ParaMEDMEM +{ + class DEC; + class BlockTopology; ++ + class StructuredCoincidentDEC : public DisjointDEC + { + public: + StructuredCoincidentDEC(); + StructuredCoincidentDEC( ProcessorGroup& source, ProcessorGroup& target); + virtual ~StructuredCoincidentDEC(); + void synchronize(); + void recvData(); + void sendData(); + void prepareSourceDE(); + void prepareTargetDE(); + + private : + void synchronizeTopology(); + void broadcastTopology(BlockTopology*&, int tag); + + BlockTopology* _topo_source; + BlockTopology* _topo_target; + int* _send_counts; + int* _recv_counts; + int* _send_displs; + int* _recv_displs; + double* _recv_buffer; + double* _send_buffer; + }; +} + +#endif diff --cc medtool/src/ParaMEDMEM/TimeInterpolator.hxx index 30df1c5e6,000000000..e284acc8e mode 100644,000000..100644 --- a/medtool/src/ParaMEDMEM/TimeInterpolator.hxx +++ b/medtool/src/ParaMEDMEM/TimeInterpolator.hxx @@@ -1,51 -1,0 +1,57 @@@ +// Copyright (C) 2007-2015 CEA/DEN, EDF R&D +// +// 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +// +// See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com +// + +#ifndef __TIMEINTERPOLATOR_HXX__ +#define __TIMEINTERPOLATOR_HXX__ + +#include "ProcessorGroup.hxx" + +#include +#include + +namespace ParaMEDMEM +{ ++ ++ /*! ++ * Internal class, not part of the public API. ++ * ++ * Abstract class for all time-related interpolation in a parallel context. ++ */ + class TimeInterpolator + { + public: + TimeInterpolator( double InterpPrecision, int nStepBefore=1, int nStepAfter=1 ); + virtual ~TimeInterpolator(); + + void setInterpParams( double InterpPrecision, int nStepBefore=1, int nStepAfter=1 ) { _interp_precision=InterpPrecision; _n_step_before=nStepBefore; _n_step_after=nStepAfter; } + void steps( int &nStepBefore, int &nStepAfter ) { nStepBefore=_n_step_before; nStepAfter=_n_step_after ; } + virtual void doInterp( double time0, double time1, double time, int recvcount , + int nbuff0, int nbuff1, + int **recvbuff0, int **recvbuff1, int *result ) = 0; + virtual void doInterp( double time0, double time1, double time, int recvcount , + int nbuff0, int nbuff1, + double **recvbuff0, double **recvbuff1, double *result ) = 0; + protected : + double _interp_precision; + int _n_step_before; + int _n_step_after; + }; +} + +#endif diff --cc medtool/src/ParaMEDMEM/Topology.hxx index 4b10f8b43,000000000..19ce03458 mode 100644,000000..100644 --- a/medtool/src/ParaMEDMEM/Topology.hxx +++ b/medtool/src/ParaMEDMEM/Topology.hxx @@@ -1,40 -1,0 +1,45 @@@ +// Copyright (C) 2007-2015 CEA/DEN, EDF R&D +// +// 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +// +// See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com +// + +#ifndef __TOPOLOGY_HXX__ +#define __TOPOLOGY_HXX__ + - #include - +namespace ParaMEDMEM +{ + class ProcessorGroup; + ++ /*! ++ * Topology of a group of processors within a processor group. Abstract class, see derivations. ++ * ++ * \sa BlockTopology ++ * \sa ExplicitTopology ++ * \sa MPIProcessorGroup ++ */ + class Topology + { + public: + Topology() { } + virtual ~Topology() { } + virtual int getNbElements() const = 0; + virtual int getNbLocalElements() const = 0; + virtual const ProcessorGroup* getProcGroup()const = 0; + }; +} + +#endif diff --cc medtool/src/ParaMEDMEMTest/CMakeLists.txt index aa4336d0d,000000000..2f2b97439 mode 100644,000000..100644 --- a/medtool/src/ParaMEDMEMTest/CMakeLists.txt +++ b/medtool/src/ParaMEDMEMTest/CMakeLists.txt @@@ -1,137 -1,0 +1,136 @@@ +# Copyright (C) 2012-2015 CEA/DEN, EDF R&D +# +# 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +# +# See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com +# + +ADD_DEFINITIONS(${MPI_DEFINITIONS} ${CPPUNIT_DEFINITIONS}) + +INCLUDE_DIRECTORIES( + ${MPI_INCLUDE_DIRS} + ${CPPUNIT_INCLUDE_DIRS} + ${CMAKE_CURRENT_SOURCE_DIR}/../ParaMEDLoader + ${CMAKE_CURRENT_SOURCE_DIR}/../ParaMEDMEM + ${CMAKE_CURRENT_SOURCE_DIR}/../MEDLoader + ${CMAKE_CURRENT_SOURCE_DIR}/../MEDCoupling + ${CMAKE_CURRENT_SOURCE_DIR}/../INTERP_KERNEL + ${CMAKE_CURRENT_SOURCE_DIR}/../INTERP_KERNEL/Bases + ) + +SET(ParaMEDMEMTest_SOURCES + ParaMEDMEMTest.cxx + ParaMEDMEMTest_MPIProcessorGroup.cxx + ParaMEDMEMTest_BlockTopology.cxx + ParaMEDMEMTest_InterpKernelDEC.cxx + ParaMEDMEMTest_StructuredCoincidentDEC.cxx - ParaMEDMEMTest_MEDLoader.cxx + ParaMEDMEMTest_ICoco.cxx + ParaMEDMEMTest_Gauthier1.cxx + ParaMEDMEMTest_FabienAPI.cxx + ParaMEDMEMTest_NonCoincidentDEC.cxx + ParaMEDMEMTest_OverlapDEC.cxx + MPIAccessDECTest.cxx + test_AllToAllDEC.cxx + test_AllToAllvDEC.cxx + test_AllToAllTimeDEC.cxx + test_AllToAllvTimeDEC.cxx + test_AllToAllvTimeDoubleDEC.cxx + MPIAccessTest.cxx + test_MPI_Access_Send_Recv.cxx + test_MPI_Access_Cyclic_Send_Recv.cxx + test_MPI_Access_SendRecv.cxx + test_MPI_Access_ISend_IRecv.cxx + test_MPI_Access_Cyclic_ISend_IRecv.cxx + test_MPI_Access_ISendRecv.cxx + test_MPI_Access_Probe.cxx + test_MPI_Access_IProbe.cxx + test_MPI_Access_Cancel.cxx + test_MPI_Access_Send_Recv_Length.cxx + test_MPI_Access_ISend_IRecv_Length.cxx + test_MPI_Access_ISend_IRecv_Length_1.cxx + test_MPI_Access_Time.cxx + test_MPI_Access_Time_0.cxx + test_MPI_Access_ISend_IRecv_BottleNeck.cxx + ) + +ADD_LIBRARY(ParaMEDMEMTest SHARED ${ParaMEDMEMTest_SOURCES}) +SET_TARGET_PROPERTIES(ParaMEDMEMTest PROPERTIES COMPILE_FLAGS "") +TARGET_LINK_LIBRARIES(ParaMEDMEMTest paramedmem paramedloader ${CPPUNIT_LIBRARIES}) +INSTALL(TARGETS ParaMEDMEMTest DESTINATION ${MEDTOOL_INSTALL_LIBS}) + +SET(TESTSParaMEDMEM) +SET(TestParaMEDMEM_SOURCES + TestParaMEDMEM.cxx + ) +SET(TESTSParaMEDMEM ${TESTSParaMEDMEM} TestParaMEDMEM) + +SET(TestMPIAccessDEC_SOURCES + TestMPIAccessDEC.cxx + ) +SET(TESTSParaMEDMEM ${TESTSParaMEDMEM} TestMPIAccessDEC) + +SET(TestMPIAccess_SOURCES + TestMPIAccess.cxx + ) +SET(TESTSParaMEDMEM ${TESTSParaMEDMEM} TestMPIAccess) + +SET(test_perf_SOURCES + test_perf.cxx + ) +SET(TESTSParaMEDMEM ${TESTSParaMEDMEM} test_perf) + +IF(MPI2_IS_OK) + SET(ParaMEDMEMTestMPI2_1_SOURCES + MPI2Connector.cxx + ParaMEDMEMTestMPI2_1.cxx + ) + SET(TESTSParaMEDMEM ${TESTSParaMEDMEM} ParaMEDMEMTestMPI2_1) + + SET(ParaMEDMEMTestMPI2_2_SOURCES + MPI2Connector.cxx + ParaMEDMEMTestMPI2_2.cxx + ) + SET(TESTSParaMEDMEM ${TESTSParaMEDMEM} ParaMEDMEMTestMPI2_2) +ENDIF(MPI2_IS_OK) + +FOREACH(bintestparamem ${TESTSParaMEDMEM}) + ADD_EXECUTABLE(${bintestparamem} ${${bintestparamem}_SOURCES}) + TARGET_LINK_LIBRARIES(${bintestparamem} ParaMEDMEMTest) +ENDFOREACH(bintestparamem ${TESTSParaMEDMEM}) + +# Now add CMake tests - test_perf, ParaMEDMEMTestMPI2_1 and ParaMEDMEMTestMPI2_2 +# are left aside, as they are too specific +# +# -- some tests require 2, 3, 4 or 5 procs -- +ADD_TEST(NAME TestParaMEDMEM_Proc2 COMMAND ${MPIEXEC} -np 2 $) +ADD_TEST(NAME TestParaMEDMEM_Proc3 COMMAND ${MPIEXEC} -np 3 $) +ADD_TEST(NAME TestParaMEDMEM_Proc4 COMMAND ${MPIEXEC} -np 4 $) +ADD_TEST(NAME TestParaMEDMEM_Proc5 COMMAND ${MPIEXEC} -np 5 $) + +ADD_TEST(NAME TestMPIAccess_Proc2 COMMAND ${MPIEXEC} -np 2 $) +ADD_TEST(NAME TestMPIAccess_Proc3 COMMAND ${MPIEXEC} -np 3 $) + +ADD_TEST(NAME TestMPIAccessDEC_Proc4 COMMAND ${MPIEXEC} -np 4 $) + +# Installation rules +INSTALL(TARGETS ${TESTSParaMEDMEM} DESTINATION ${MEDTOOL_INSTALL_BINS}) +SET(COMMON_HEADERS_HXX + MPIMainTest.hxx + MPIAccessDECTest.hxx + MPIAccessTest.hxx + ParaMEDMEMTest.hxx + MPI2Connector.hxx +) +INSTALL(FILES ${COMMON_HEADERS_HXX} DESTINATION ${MEDTOOL_INSTALL_HEADERS}) diff --cc medtool/src/ParaMEDMEMTest/ParaMEDMEMTest.hxx index a8bf2b474,000000000..b0295a08f mode 100644,000000..100644 --- a/medtool/src/ParaMEDMEMTest/ParaMEDMEMTest.hxx +++ b/medtool/src/ParaMEDMEMTest/ParaMEDMEMTest.hxx @@@ -1,188 -1,0 +1,178 @@@ +// Copyright (C) 2007-2015 CEA/DEN, EDF R&D +// +// 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +// +// See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com +// + +#ifndef _ParaMEDMEMTEST_HXX_ +#define _ParaMEDMEMTEST_HXX_ + +#include + +#include +#include +#include +#include "mpi.h" + + +class ParaMEDMEMTest : public CppUnit::TestFixture +{ + CPPUNIT_TEST_SUITE( ParaMEDMEMTest ); + CPPUNIT_TEST(testMPIProcessorGroup_constructor); + CPPUNIT_TEST(testMPIProcessorGroup_boolean); + CPPUNIT_TEST(testMPIProcessorGroup_rank); + CPPUNIT_TEST(testBlockTopology_constructor); + CPPUNIT_TEST(testBlockTopology_serialize); + CPPUNIT_TEST(testInterpKernelDEC_1D); + CPPUNIT_TEST(testInterpKernelDEC_2DCurve); + CPPUNIT_TEST(testInterpKernelDEC_2D); + CPPUNIT_TEST(testInterpKernelDEC2_2D); + CPPUNIT_TEST(testInterpKernelDEC_2DP0P1); + CPPUNIT_TEST(testInterpKernelDEC_3D); + CPPUNIT_TEST(testInterpKernelDECNonOverlapp_2D_P0P0); + CPPUNIT_TEST(testInterpKernelDECNonOverlapp_2D_P0P1P1P0); + CPPUNIT_TEST(testInterpKernelDEC2DM1D_P0P0); + CPPUNIT_TEST(testInterpKernelDECPartialProcs); + CPPUNIT_TEST(testInterpKernelDEC3DSurfEmptyBBox); + CPPUNIT_TEST(testOverlapDEC1); + + CPPUNIT_TEST(testSynchronousEqualInterpKernelWithoutInterpNativeDEC_2D); + CPPUNIT_TEST(testSynchronousEqualInterpKernelWithoutInterpDEC_2D); + CPPUNIT_TEST(testSynchronousEqualInterpKernelDEC_2D); + CPPUNIT_TEST(testSynchronousFasterSourceInterpKernelDEC_2D); + CPPUNIT_TEST(testSynchronousSlowerSourceInterpKernelDEC_2D); + CPPUNIT_TEST(testSynchronousSlowSourceInterpKernelDEC_2D); + CPPUNIT_TEST(testSynchronousFastSourceInterpKernelDEC_2D); + CPPUNIT_TEST(testAsynchronousEqualInterpKernelDEC_2D); + CPPUNIT_TEST(testAsynchronousFasterSourceInterpKernelDEC_2D); + CPPUNIT_TEST(testAsynchronousSlowerSourceInterpKernelDEC_2D); + CPPUNIT_TEST(testAsynchronousSlowSourceInterpKernelDEC_2D); + CPPUNIT_TEST(testAsynchronousFastSourceInterpKernelDEC_2D); +#ifdef MED_ENABLE_FVM + //can be added again after FVM correction for 2D + // CPPUNIT_TEST(testNonCoincidentDEC_2D); + CPPUNIT_TEST(testNonCoincidentDEC_3D); +#endif + CPPUNIT_TEST(testStructuredCoincidentDEC); + CPPUNIT_TEST(testStructuredCoincidentDEC); + CPPUNIT_TEST(testICoco1); + CPPUNIT_TEST(testGauthier1); + CPPUNIT_TEST(testGauthier2); + CPPUNIT_TEST(testGauthier3); + CPPUNIT_TEST(testGauthier4); + CPPUNIT_TEST(testFabienAPI1); + CPPUNIT_TEST(testFabienAPI2); - CPPUNIT_TEST(testMEDLoaderRead1); - CPPUNIT_TEST(testMEDLoaderPolygonRead); - CPPUNIT_TEST(testMEDLoaderPolyhedronRead); + CPPUNIT_TEST_SUITE_END(); - + +public: + + ParaMEDMEMTest():CppUnit::TestFixture(){} + ~ParaMEDMEMTest(){} + void setUp(){} + void tearDown(){} + void testMPIProcessorGroup_constructor(); + void testMPIProcessorGroup_boolean(); + void testMPIProcessorGroup_rank(); + void testBlockTopology_constructor(); + void testBlockTopology_serialize(); + void testInterpKernelDEC_1D(); + void testInterpKernelDEC_2DCurve(); + void testInterpKernelDEC_2D(); + void testInterpKernelDEC2_2D(); + void testInterpKernelDEC_2DP0P1(); + void testInterpKernelDEC_3D(); + void testInterpKernelDECNonOverlapp_2D_P0P0(); + void testInterpKernelDECNonOverlapp_2D_P0P1P1P0(); + void testInterpKernelDEC2DM1D_P0P0(); + void testInterpKernelDECPartialProcs(); + void testInterpKernelDEC3DSurfEmptyBBox(); + void testOverlapDEC1(); +#ifdef MED_ENABLE_FVM + void testNonCoincidentDEC_2D(); + void testNonCoincidentDEC_3D(); +#endif + void testStructuredCoincidentDEC(); + void testSynchronousEqualInterpKernelWithoutInterpNativeDEC_2D(); + void testSynchronousEqualInterpKernelWithoutInterpDEC_2D(); + void testSynchronousEqualInterpKernelDEC_2D(); + void testSynchronousFasterSourceInterpKernelDEC_2D(); + void testSynchronousSlowerSourceInterpKernelDEC_2D(); + void testSynchronousSlowSourceInterpKernelDEC_2D(); + void testSynchronousFastSourceInterpKernelDEC_2D(); + + void testAsynchronousEqualInterpKernelDEC_2D(); + void testAsynchronousFasterSourceInterpKernelDEC_2D(); + void testAsynchronousSlowerSourceInterpKernelDEC_2D(); + void testAsynchronousSlowSourceInterpKernelDEC_2D(); + void testAsynchronousFastSourceInterpKernelDEC_2D(); + // + void testICoco1(); + void testGauthier1(); + void testGauthier2(); + void testGauthier3(); + void testGauthier4(); + void testFabienAPI1(); + void testFabienAPI2(); - // - void testMEDLoaderRead1(); - void testMEDLoaderPolygonRead(); - void testMEDLoaderPolyhedronRead(); - void testMEDLoaderWrite1(); - void testMEDLoaderPolygonWrite(); + + std::string getResourceFile( const std::string& ); + std::string getTmpDirectory(); + std::string makeTmpFile( const std::string&, const std::string& = "" ); + +private: +#ifdef MED_ENABLE_FVM + void testNonCoincidentDEC(const std::string& filename1, + const std::string& meshname1, + const std::string& filename2, + const std::string& meshname2, + int nbprocsource, double epsilon); +#endif + void testAsynchronousInterpKernelDEC_2D(double dtA, double tmaxA, + double dtB, double tmaxB, + bool WithPointToPoint, bool Asynchronous, bool WithInterp, const char *srcMeth, const char *targetMeth); + void testInterpKernelDEC_2D_(const char *srcMeth, const char *targetMeth); + void testInterpKernelDEC2_2D_(const char *srcMeth, const char *targetMeth); + void testInterpKernelDEC_3D_(const char *srcMeth, const char *targetMeth); +}; + +// to automatically remove temporary files from disk +class ParaMEDMEMTest_TmpFilesRemover +{ +public: + ParaMEDMEMTest_TmpFilesRemover() {} + ~ParaMEDMEMTest_TmpFilesRemover(); + bool Register(const std::string theTmpFile); + +private: + std::set myTmpFiles; +}; + +/*! + * Tool to print array to stream. + */ +template +void ParaMEDMEMTest_DumpArray (std::ostream & stream, const T* array, const int length, const std::string text) +{ + stream << text << ": {"; + if (length > 0) { + stream << array[0]; + for (int i = 1; i < length; i++) { + stream << ", " << array[i]; + } + } + stream << "}" << std::endl; +} + +#endif diff --cc medtool/src/ParaMEDMEMTest/ParaMEDMEMTest_MEDLoader.cxx index f8962a780,000000000..01dc8227c mode 100644,000000..100644 --- a/medtool/src/ParaMEDMEMTest/ParaMEDMEMTest_MEDLoader.cxx +++ b/medtool/src/ParaMEDMEMTest/ParaMEDMEMTest_MEDLoader.cxx @@@ -1,399 -1,0 +1,35 @@@ +// Copyright (C) 2007-2015 CEA/DEN, EDF R&D +// +// 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +// +// See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com +// + +#include "ParaMEDMEMTest.hxx" +#include "MEDLoader.hxx" +#include "MEDCouplingUMesh.hxx" +#include "MEDCouplingFieldDouble.hxx" + +#include + +#include +#include +#include +#include + +using namespace std; +using namespace INTERP_KERNEL; +using namespace ParaMEDMEM; + - void ParaMEDMEMTest::testMEDLoaderRead1() - { - string fileName=getResourceFile("pointe.med"); - vector meshNames=MEDLoader::GetMeshNames(fileName.c_str()); - CPPUNIT_ASSERT_EQUAL(1,(int)meshNames.size()); - MEDCouplingUMesh *mesh=MEDLoader::ReadUMeshFromFile(fileName.c_str(),meshNames[0].c_str(),0); - CPPUNIT_ASSERT_EQUAL(3,mesh->getSpaceDimension()); - CPPUNIT_ASSERT_EQUAL(3,mesh->getMeshDimension()); - CPPUNIT_ASSERT_EQUAL(16,mesh->getNumberOfCells()); - CPPUNIT_ASSERT_EQUAL(19,mesh->getNumberOfNodes()); - CPPUNIT_ASSERT_EQUAL(3,(int)mesh->getAllGeoTypes().size()); - for(int i=0;i<12;i++) - CPPUNIT_ASSERT_EQUAL(NORM_TETRA4,mesh->getTypeOfCell(i)); - CPPUNIT_ASSERT_EQUAL(NORM_PYRA5,mesh->getTypeOfCell(12)); - CPPUNIT_ASSERT_EQUAL(NORM_HEXA8,mesh->getTypeOfCell(13)); - CPPUNIT_ASSERT_EQUAL(NORM_HEXA8,mesh->getTypeOfCell(14)); - CPPUNIT_ASSERT_EQUAL(NORM_PYRA5,mesh->getTypeOfCell(15)); - CPPUNIT_ASSERT_EQUAL((std::size_t)90,mesh->getNodalConnectivity()->getNbOfElems()); - CPPUNIT_ASSERT_EQUAL(701,std::accumulate(mesh->getNodalConnectivity()->getPointer(),mesh->getNodalConnectivity()->getPointer()+90,0)); - CPPUNIT_ASSERT_EQUAL(705,std::accumulate(mesh->getNodalConnectivityIndex()->getPointer(),mesh->getNodalConnectivityIndex()->getPointer()+17,0)); - CPPUNIT_ASSERT_DOUBLES_EQUAL(46.,std::accumulate(mesh->getCoords()->getPointer(),mesh->getCoords()->getPointer()+57,0),1e-12); - mesh->decrRef(); - // - vector families=MEDLoader::GetMeshFamiliesNames(fileName.c_str(),meshNames[0].c_str()); - CPPUNIT_ASSERT_EQUAL(8,(int)families.size()); - CPPUNIT_ASSERT(families[2]=="FAMILLE_ELEMENT_3"); - // - vector families2; - families2.push_back(families[2]); - mesh=MEDLoader::ReadUMeshFromFamilies(fileName.c_str(),meshNames[0].c_str(),0,families2); - CPPUNIT_ASSERT_EQUAL(3,mesh->getSpaceDimension()); - CPPUNIT_ASSERT_EQUAL(3,mesh->getMeshDimension()); - CPPUNIT_ASSERT_EQUAL(2,mesh->getNumberOfCells()); - CPPUNIT_ASSERT_EQUAL(19,mesh->getNumberOfNodes()); - CPPUNIT_ASSERT_EQUAL(2,(int)mesh->getAllGeoTypes().size()); - CPPUNIT_ASSERT_EQUAL(NORM_TETRA4,mesh->getTypeOfCell(0)); - CPPUNIT_ASSERT_EQUAL(NORM_PYRA5,mesh->getTypeOfCell(1)); - CPPUNIT_ASSERT_EQUAL((std::size_t)11,mesh->getNodalConnectivity()->getNbOfElems()); - CPPUNIT_ASSERT_EQUAL(132,std::accumulate(mesh->getNodalConnectivity()->getPointer(),mesh->getNodalConnectivity()->getPointer()+11,0)); - CPPUNIT_ASSERT_EQUAL(16,std::accumulate(mesh->getNodalConnectivityIndex()->getPointer(),mesh->getNodalConnectivityIndex()->getPointer()+3,0)); - CPPUNIT_ASSERT_DOUBLES_EQUAL(46.,std::accumulate(mesh->getCoords()->getPointer(),mesh->getCoords()->getPointer()+57,0),1e-12); - mesh->decrRef(); - // - vector groups=MEDLoader::GetMeshGroupsNames(fileName.c_str(),meshNames[0].c_str()); - CPPUNIT_ASSERT_EQUAL(5,(int)groups.size()); - CPPUNIT_ASSERT(groups[0]=="groupe1"); - CPPUNIT_ASSERT(groups[1]=="groupe2"); - CPPUNIT_ASSERT(groups[2]=="groupe3"); - CPPUNIT_ASSERT(groups[3]=="groupe4"); - CPPUNIT_ASSERT(groups[4]=="groupe5"); - vector groups2; - groups2.push_back(groups[0]); - mesh=MEDLoader::ReadUMeshFromGroups(fileName.c_str(),meshNames[0].c_str(),0,groups2); - CPPUNIT_ASSERT_EQUAL(3,mesh->getSpaceDimension()); - CPPUNIT_ASSERT_EQUAL(3,mesh->getMeshDimension()); - CPPUNIT_ASSERT_EQUAL(7,mesh->getNumberOfCells()); - CPPUNIT_ASSERT_EQUAL(19,mesh->getNumberOfNodes()); - CPPUNIT_ASSERT_EQUAL(2,(int)mesh->getAllGeoTypes().size()); - for(int i=0;i<6;i++) - CPPUNIT_ASSERT_EQUAL(NORM_TETRA4,mesh->getTypeOfCell(i)); - CPPUNIT_ASSERT_EQUAL(NORM_PYRA5,mesh->getTypeOfCell(6)); - CPPUNIT_ASSERT_EQUAL((std::size_t)36,mesh->getNodalConnectivity()->getNbOfElems()); - CPPUNIT_ASSERT_EQUAL(254,std::accumulate(mesh->getNodalConnectivity()->getPointer(),mesh->getNodalConnectivity()->getPointer()+36,0)); - CPPUNIT_ASSERT_EQUAL(141,std::accumulate(mesh->getNodalConnectivityIndex()->getPointer(),mesh->getNodalConnectivityIndex()->getPointer()+8,0)); - CPPUNIT_ASSERT_DOUBLES_EQUAL(46.,std::accumulate(mesh->getCoords()->getPointer(),mesh->getCoords()->getPointer()+57,0),1e-12); - mesh->decrRef(); - // - std::vector fieldsName=MEDLoader::GetCellFieldNamesOnMesh(fileName.c_str(),meshNames[0].c_str()); - CPPUNIT_ASSERT_EQUAL(2,(int)fieldsName.size()); - CPPUNIT_ASSERT(fieldsName[0]=="fieldcelldoublescalar"); - CPPUNIT_ASSERT(fieldsName[1]=="fieldcelldoublevector"); - std::vector > its0=MEDLoader::GetCellFieldIterations(fileName.c_str(),meshNames[0].c_str(),fieldsName[0].c_str()); - CPPUNIT_ASSERT_EQUAL(1,(int)its0.size()); - CPPUNIT_ASSERT_EQUAL(-1,its0[0].first); - CPPUNIT_ASSERT_EQUAL(-1,its0[0].second); - std::vector > its1=MEDLoader::GetCellFieldIterations(fileName.c_str(),meshNames[0].c_str(),fieldsName[1].c_str()); - CPPUNIT_ASSERT_EQUAL(1,(int)its1.size()); - CPPUNIT_ASSERT_EQUAL(-1,its1[0].first); - CPPUNIT_ASSERT_EQUAL(-1,its1[0].second); - // - MEDCouplingFieldDouble *field0=MEDLoader::ReadFieldCell(fileName.c_str(),meshNames[0].c_str(),0,fieldsName[0].c_str(),its0[0].first,its0[0].second); - field0->checkCoherency(); - CPPUNIT_ASSERT(field0->getName()==fieldsName[0]); - CPPUNIT_ASSERT_EQUAL(1,field0->getNumberOfComponents()); - CPPUNIT_ASSERT_EQUAL(16,field0->getNumberOfTuples()); - const double expectedValues[16]={1.,1.,1.,1.,1.,1.,1.,1.,1.,1.,1.,1.,2.,3.,3.,2.}; - double diffValue[16]; - std::transform(field0->getArray()->getPointer(),field0->getArray()->getPointer()+16,expectedValues,diffValue,std::minus()); - CPPUNIT_ASSERT_DOUBLES_EQUAL(0.,*std::max_element(diffValue,diffValue+16),1e-12); - CPPUNIT_ASSERT_DOUBLES_EQUAL(0.,*std::min_element(diffValue,diffValue+16),1e-12); - const MEDCouplingUMesh *constMesh=dynamic_cast(field0->getMesh()); - CPPUNIT_ASSERT(constMesh); - CPPUNIT_ASSERT_EQUAL(3,constMesh->getSpaceDimension()); - CPPUNIT_ASSERT_EQUAL(3,constMesh->getMeshDimension()); - CPPUNIT_ASSERT_EQUAL(16,constMesh->getNumberOfCells()); - CPPUNIT_ASSERT_EQUAL(19,constMesh->getNumberOfNodes()); - CPPUNIT_ASSERT_EQUAL(3,(int)constMesh->getAllGeoTypes().size()); - for(int i=0;i<12;i++) - CPPUNIT_ASSERT_EQUAL(NORM_TETRA4,constMesh->getTypeOfCell(i)); - CPPUNIT_ASSERT_EQUAL(NORM_PYRA5,constMesh->getTypeOfCell(12)); - CPPUNIT_ASSERT_EQUAL(NORM_HEXA8,constMesh->getTypeOfCell(13)); - CPPUNIT_ASSERT_EQUAL(NORM_HEXA8,constMesh->getTypeOfCell(14)); - CPPUNIT_ASSERT_EQUAL(NORM_PYRA5,constMesh->getTypeOfCell(15)); - CPPUNIT_ASSERT_EQUAL((std::size_t)90,constMesh->getNodalConnectivity()->getNbOfElems()); - CPPUNIT_ASSERT_EQUAL(701,std::accumulate(constMesh->getNodalConnectivity()->getConstPointer(),constMesh->getNodalConnectivity()->getConstPointer()+90,0)); - CPPUNIT_ASSERT_EQUAL(705,std::accumulate(constMesh->getNodalConnectivityIndex()->getConstPointer(),constMesh->getNodalConnectivityIndex()->getConstPointer()+17,0)); - CPPUNIT_ASSERT_DOUBLES_EQUAL(46.,std::accumulate(constMesh->getCoords()->getConstPointer(),constMesh->getCoords()->getConstPointer()+57,0),1e-12); - field0->decrRef(); - // - MEDCouplingFieldDouble *field1=MEDLoader::ReadFieldCell(fileName.c_str(),meshNames[0].c_str(),0,fieldsName[1].c_str(),its1[0].first,its1[0].second); - field1->checkCoherency(); - CPPUNIT_ASSERT(field1->getName()==fieldsName[1]); - CPPUNIT_ASSERT_EQUAL(3,field1->getNumberOfComponents()); - CPPUNIT_ASSERT_EQUAL(16,field1->getNumberOfTuples()); - const double expectedValues2[48]={1.,0.,1.,1.,0.,1.,1.,0.,1.,2.,1.,0.,2.,1.,0.,2.,1.,0.,3.,0.,1.,3.,0.,1.,3.,0.,1.,4.,1.,0.,4.,1.,0.,4.,1.,0.,5.,0.,0.,6.,1.,1.,6.,0.,0.,5.,1.,1.}; - double diffValue2[48]; - std::transform(field1->getArray()->getPointer(),field1->getArray()->getPointer()+48,expectedValues2,diffValue2,std::minus()); - CPPUNIT_ASSERT_DOUBLES_EQUAL(0.,*std::max_element(diffValue2,diffValue2+48),1e-12); - CPPUNIT_ASSERT_DOUBLES_EQUAL(0.,*std::min_element(diffValue2,diffValue2+48),1e-12); - constMesh=dynamic_cast(field1->getMesh()); - CPPUNIT_ASSERT(constMesh); - CPPUNIT_ASSERT_EQUAL(3,constMesh->getSpaceDimension()); - CPPUNIT_ASSERT_EQUAL(3,constMesh->getMeshDimension()); - CPPUNIT_ASSERT_EQUAL(16,constMesh->getNumberOfCells()); - CPPUNIT_ASSERT_EQUAL(19,constMesh->getNumberOfNodes()); - CPPUNIT_ASSERT_EQUAL(3,(int)constMesh->getAllGeoTypes().size()); - for(int i=0;i<12;i++) - CPPUNIT_ASSERT_EQUAL(NORM_TETRA4,constMesh->getTypeOfCell(i)); - CPPUNIT_ASSERT_EQUAL(NORM_PYRA5,constMesh->getTypeOfCell(12)); - CPPUNIT_ASSERT_EQUAL(NORM_HEXA8,constMesh->getTypeOfCell(13)); - CPPUNIT_ASSERT_EQUAL(NORM_HEXA8,constMesh->getTypeOfCell(14)); - CPPUNIT_ASSERT_EQUAL(NORM_PYRA5,constMesh->getTypeOfCell(15)); - CPPUNIT_ASSERT_EQUAL((std::size_t)90,constMesh->getNodalConnectivity()->getNbOfElems()); - CPPUNIT_ASSERT_EQUAL(701,std::accumulate(constMesh->getNodalConnectivity()->getConstPointer(),constMesh->getNodalConnectivity()->getConstPointer()+90,0)); - CPPUNIT_ASSERT_EQUAL(705,std::accumulate(constMesh->getNodalConnectivityIndex()->getConstPointer(),constMesh->getNodalConnectivityIndex()->getConstPointer()+17,0)); - CPPUNIT_ASSERT_DOUBLES_EQUAL(46.,std::accumulate(constMesh->getCoords()->getConstPointer(),constMesh->getCoords()->getConstPointer()+57,0),1e-12); - field1->decrRef(); - //fields on nodes - std::vector fieldsNameNode=MEDLoader::GetNodeFieldNamesOnMesh(fileName.c_str(),meshNames[0].c_str()); - CPPUNIT_ASSERT_EQUAL(2,(int)fieldsNameNode.size()); - CPPUNIT_ASSERT(fieldsNameNode[0]=="fieldnodedouble"); - CPPUNIT_ASSERT(fieldsNameNode[1]=="fieldnodeint"); - std::vector > its0Node=MEDLoader::GetNodeFieldIterations(fileName.c_str(),meshNames[0].c_str(),fieldsNameNode[0].c_str()); - CPPUNIT_ASSERT_EQUAL(3,(int)its0Node.size()); - CPPUNIT_ASSERT_EQUAL(-1,its0Node[0].first); - CPPUNIT_ASSERT_EQUAL(-1,its0Node[0].second); - CPPUNIT_ASSERT_EQUAL(1,its0Node[1].first); - CPPUNIT_ASSERT_EQUAL(-1,its0Node[1].second); - CPPUNIT_ASSERT_EQUAL(2,its0Node[2].first); - CPPUNIT_ASSERT_EQUAL(-1,its0Node[2].second); - MEDCouplingFieldDouble *field0Nodes=MEDLoader::ReadFieldNode(fileName.c_str(),meshNames[0].c_str(),0,fieldsNameNode[0].c_str(),its0Node[0].first,its0Node[0].second); - field0Nodes->checkCoherency(); - CPPUNIT_ASSERT(field0Nodes->getName()==fieldsNameNode[0]); - CPPUNIT_ASSERT_EQUAL(1,field0Nodes->getNumberOfComponents()); - CPPUNIT_ASSERT_EQUAL(19,field0Nodes->getNumberOfTuples()); - const double expectedValues3[19]={1.,1.,1.,2.,2.,2.,3.,3.,3.,4.,4.,4.,5.,5.,5.,6.,6.,6.,7.}; - double diffValue3[19]; - std::transform(field0Nodes->getArray()->getPointer(),field0Nodes->getArray()->getPointer()+19,expectedValues3,diffValue3,std::minus()); - CPPUNIT_ASSERT_DOUBLES_EQUAL(0.,*std::max_element(diffValue3,diffValue3+19),1e-12); - CPPUNIT_ASSERT_DOUBLES_EQUAL(0.,*std::min_element(diffValue3,diffValue3+19),1e-12); - constMesh=dynamic_cast(field0Nodes->getMesh()); - CPPUNIT_ASSERT(constMesh); - field0Nodes->decrRef(); - // - field0Nodes=MEDLoader::ReadFieldNode(fileName.c_str(),meshNames[0].c_str(),0,fieldsNameNode[0].c_str(),its0Node[2].first,its0Node[2].second); - field0Nodes->checkCoherency(); - CPPUNIT_ASSERT(field0Nodes->getName()==fieldsNameNode[0]); - CPPUNIT_ASSERT_EQUAL(1,field0Nodes->getNumberOfComponents()); - CPPUNIT_ASSERT_EQUAL(19,field0Nodes->getNumberOfTuples()); - const double expectedValues4[19]={1.,2.,2.,2.,3.,3.,3.,4.,4.,4.,5.,5.,5.,6.,6.,6.,7.,7.,7.}; - std::transform(field0Nodes->getArray()->getPointer(),field0Nodes->getArray()->getPointer()+19,expectedValues4,diffValue3,std::minus()); - CPPUNIT_ASSERT_DOUBLES_EQUAL(0.,*std::max_element(diffValue3,diffValue3+19),1e-12); - CPPUNIT_ASSERT_DOUBLES_EQUAL(0.,*std::min_element(diffValue3,diffValue3+19),1e-12); - constMesh=dynamic_cast(field0Nodes->getMesh()); - CPPUNIT_ASSERT(constMesh); - CPPUNIT_ASSERT_EQUAL(3,constMesh->getSpaceDimension()); - CPPUNIT_ASSERT_EQUAL(3,constMesh->getMeshDimension()); - CPPUNIT_ASSERT_EQUAL(16,constMesh->getNumberOfCells()); - CPPUNIT_ASSERT_EQUAL(19,constMesh->getNumberOfNodes()); - CPPUNIT_ASSERT_EQUAL(3,(int)constMesh->getAllGeoTypes().size()); - for(int i=0;i<12;i++) - CPPUNIT_ASSERT_EQUAL(NORM_TETRA4,constMesh->getTypeOfCell(i)); - CPPUNIT_ASSERT_EQUAL(NORM_PYRA5,constMesh->getTypeOfCell(12)); - CPPUNIT_ASSERT_EQUAL(NORM_HEXA8,constMesh->getTypeOfCell(13)); - CPPUNIT_ASSERT_EQUAL(NORM_HEXA8,constMesh->getTypeOfCell(14)); - CPPUNIT_ASSERT_EQUAL(NORM_PYRA5,constMesh->getTypeOfCell(15)); - CPPUNIT_ASSERT_EQUAL((std::size_t)90,constMesh->getNodalConnectivity()->getNbOfElems()); - CPPUNIT_ASSERT_EQUAL(701,std::accumulate(constMesh->getNodalConnectivity()->getConstPointer(),constMesh->getNodalConnectivity()->getConstPointer()+90,0)); - CPPUNIT_ASSERT_EQUAL(705,std::accumulate(constMesh->getNodalConnectivityIndex()->getConstPointer(),constMesh->getNodalConnectivityIndex()->getConstPointer()+17,0)); - CPPUNIT_ASSERT_DOUBLES_EQUAL(46.,std::accumulate(constMesh->getCoords()->getConstPointer(),constMesh->getCoords()->getConstPointer()+57,0),1e-12); - field0Nodes->decrRef(); - // - field0Nodes=MEDLoader::ReadFieldNode(fileName.c_str(),meshNames[0].c_str(),0,fieldsNameNode[0].c_str(),its0Node[0].first,its0Node[0].second); - field0Nodes->checkCoherency(); - CPPUNIT_ASSERT(field0Nodes->getName()==fieldsNameNode[0]); - CPPUNIT_ASSERT_EQUAL(1,field0Nodes->getNumberOfComponents()); - CPPUNIT_ASSERT_EQUAL(19,field0Nodes->getNumberOfTuples()); - const double expectedValues5[19]={1.,1.,1.,2.,2.,2.,3.,3.,3.,4.,4.,4.,5.,5.,5.,6.,6.,6.,7.}; - std::transform(field0Nodes->getArray()->getPointer(),field0Nodes->getArray()->getPointer()+19,expectedValues5,diffValue3,std::minus()); - CPPUNIT_ASSERT_DOUBLES_EQUAL(0.,*std::max_element(diffValue3,diffValue3+19),1e-12); - CPPUNIT_ASSERT_DOUBLES_EQUAL(0.,*std::min_element(diffValue3,diffValue3+19),1e-12); - constMesh=dynamic_cast(field0Nodes->getMesh()); - CPPUNIT_ASSERT(constMesh); - CPPUNIT_ASSERT_EQUAL(3,constMesh->getSpaceDimension()); - CPPUNIT_ASSERT_EQUAL(3,constMesh->getMeshDimension()); - CPPUNIT_ASSERT_EQUAL(16,constMesh->getNumberOfCells()); - CPPUNIT_ASSERT_EQUAL(19,constMesh->getNumberOfNodes()); - CPPUNIT_ASSERT_EQUAL(3,(int)constMesh->getAllGeoTypes().size()); - for(int i=0;i<12;i++) - CPPUNIT_ASSERT_EQUAL(NORM_TETRA4,constMesh->getTypeOfCell(i)); - CPPUNIT_ASSERT_EQUAL(NORM_PYRA5,constMesh->getTypeOfCell(12)); - CPPUNIT_ASSERT_EQUAL(NORM_HEXA8,constMesh->getTypeOfCell(13)); - CPPUNIT_ASSERT_EQUAL(NORM_HEXA8,constMesh->getTypeOfCell(14)); - CPPUNIT_ASSERT_EQUAL(NORM_PYRA5,constMesh->getTypeOfCell(15)); - CPPUNIT_ASSERT_EQUAL((std::size_t)90,constMesh->getNodalConnectivity()->getNbOfElems()); - CPPUNIT_ASSERT_EQUAL(701,std::accumulate(constMesh->getNodalConnectivity()->getConstPointer(),constMesh->getNodalConnectivity()->getConstPointer()+90,0)); - CPPUNIT_ASSERT_EQUAL(705,std::accumulate(constMesh->getNodalConnectivityIndex()->getConstPointer(),constMesh->getNodalConnectivityIndex()->getConstPointer()+17,0)); - CPPUNIT_ASSERT_DOUBLES_EQUAL(46.,std::accumulate(constMesh->getCoords()->getConstPointer(),constMesh->getCoords()->getConstPointer()+57,0),1e-12); - field0Nodes->decrRef(); - } - - void ParaMEDMEMTest::testMEDLoaderPolygonRead() - { - string fileName=getResourceFile("polygones.med"); - vector meshNames=MEDLoader::GetMeshNames(fileName.c_str()); - CPPUNIT_ASSERT_EQUAL(1,(int)meshNames.size()); - CPPUNIT_ASSERT(meshNames[0]=="Bord"); - MEDCouplingUMesh *mesh=MEDLoader::ReadUMeshFromFile(fileName.c_str(),meshNames[0].c_str(),0); - mesh->checkCoherency(); - CPPUNIT_ASSERT_EQUAL(3,mesh->getSpaceDimension()); - CPPUNIT_ASSERT_EQUAL(2,mesh->getMeshDimension()); - CPPUNIT_ASSERT_EQUAL(538,mesh->getNumberOfCells()); - CPPUNIT_ASSERT_EQUAL(579,mesh->getNumberOfNodes()); - CPPUNIT_ASSERT_EQUAL(2,(int)mesh->getAllGeoTypes().size()); - for(int i=0;i<514;i++) - CPPUNIT_ASSERT_EQUAL(NORM_QUAD4,mesh->getTypeOfCell(i)); - for(int i=514;i<538;i++) - CPPUNIT_ASSERT_EQUAL(NORM_POLYGON,mesh->getTypeOfCell(i)); - CPPUNIT_ASSERT_DOUBLES_EQUAL(0.,std::accumulate(mesh->getCoords()->getPointer(),mesh->getCoords()->getPointer()+1737,0),1e-12); - const double expectedVals1[12]={1.4851585216522212,-0.5,0.,1.4851585216522212,-0.4,0.,1.4851585216522212,-0.3,0., 1.5741585216522211, -0.5, 0. }; - double diffValue1[12]; - std::transform(mesh->getCoords()->getPointer(),mesh->getCoords()->getPointer()+12,expectedVals1,diffValue1,std::minus()); - CPPUNIT_ASSERT_DOUBLES_EQUAL(0.,*std::max_element(diffValue1,diffValue1+12),1e-12); - CPPUNIT_ASSERT_DOUBLES_EQUAL(0.,*std::min_element(diffValue1,diffValue1+12),1e-12); - CPPUNIT_ASSERT_EQUAL((std::size_t)2768,mesh->getNodalConnectivity()->getNbOfElems()); - CPPUNIT_ASSERT_EQUAL(651050,std::accumulate(mesh->getNodalConnectivity()->getPointer(),mesh->getNodalConnectivity()->getPointer()+2768,0)); - CPPUNIT_ASSERT_EQUAL(725943,std::accumulate(mesh->getNodalConnectivityIndex()->getPointer(),mesh->getNodalConnectivityIndex()->getPointer()+539,0)); - mesh->decrRef(); - // - std::vector fieldsName=MEDLoader::GetCellFieldNamesOnMesh(fileName.c_str(),meshNames[0].c_str()); - CPPUNIT_ASSERT_EQUAL(3,(int)fieldsName.size()); - CPPUNIT_ASSERT(fieldsName[0]=="bord_:_distorsion"); - CPPUNIT_ASSERT(fieldsName[1]=="bord_:_familles"); - CPPUNIT_ASSERT(fieldsName[2]=="bord_:_non-ortho"); - std::vector > its0=MEDLoader::GetCellFieldIterations(fileName.c_str(),meshNames[0].c_str(),fieldsName[0].c_str()); - CPPUNIT_ASSERT_EQUAL(1,(int)its0.size()); - MEDCouplingFieldDouble *field=MEDLoader::ReadFieldCell(fileName.c_str(),meshNames[0].c_str(),0,fieldsName[0].c_str(),its0[0].first,its0[0].second); - field->checkCoherency(); - CPPUNIT_ASSERT(field->getName()==fieldsName[0]); - CPPUNIT_ASSERT_EQUAL(1,field->getNumberOfComponents()); - CPPUNIT_ASSERT_EQUAL(538,field->getNumberOfTuples()); - const MEDCouplingUMesh *constMesh=dynamic_cast(field->getMesh()); - CPPUNIT_ASSERT(constMesh); - CPPUNIT_ASSERT_EQUAL(3,constMesh->getSpaceDimension()); - CPPUNIT_ASSERT_EQUAL(2,constMesh->getMeshDimension()); - CPPUNIT_ASSERT_EQUAL(538,constMesh->getNumberOfCells()); - CPPUNIT_ASSERT_EQUAL(579,constMesh->getNumberOfNodes()); - CPPUNIT_ASSERT_EQUAL(2,(int)constMesh->getAllGeoTypes().size()); - for(int i=0;i<514;i++) - CPPUNIT_ASSERT_EQUAL(NORM_QUAD4,constMesh->getTypeOfCell(i)); - for(int i=514;i<538;i++) - CPPUNIT_ASSERT_EQUAL(NORM_POLYGON,constMesh->getTypeOfCell(i)); - CPPUNIT_ASSERT_DOUBLES_EQUAL(0.,std::accumulate(constMesh->getCoords()->getConstPointer(),constMesh->getCoords()->getConstPointer()+1737,0),1e-12); - std::transform(constMesh->getCoords()->getConstPointer(),constMesh->getCoords()->getConstPointer()+12,expectedVals1,diffValue1,std::minus()); - CPPUNIT_ASSERT_DOUBLES_EQUAL(0.,*std::max_element(diffValue1,diffValue1+12),1e-12); - CPPUNIT_ASSERT_DOUBLES_EQUAL(0.,*std::min_element(diffValue1,diffValue1+12),1e-12); - CPPUNIT_ASSERT_EQUAL((std::size_t)2768,constMesh->getNodalConnectivity()->getNbOfElems()); - CPPUNIT_ASSERT_EQUAL(651050,std::accumulate(constMesh->getNodalConnectivity()->getConstPointer(),constMesh->getNodalConnectivity()->getConstPointer()+2768,0)); - CPPUNIT_ASSERT_EQUAL(725943,std::accumulate(constMesh->getNodalConnectivityIndex()->getConstPointer(),constMesh->getNodalConnectivityIndex()->getConstPointer()+539,0)); - const double *values=field->getArray()->getPointer(); - CPPUNIT_ASSERT_DOUBLES_EQUAL(2.87214203182918,std::accumulate(values,values+538,0.),1e-12); - field->decrRef(); - } - - void ParaMEDMEMTest::testMEDLoaderPolyhedronRead() - { - string fileName=getResourceFile("poly3D.med"); - vector meshNames=MEDLoader::GetMeshNames(fileName.c_str()); - CPPUNIT_ASSERT_EQUAL(1,(int)meshNames.size()); - CPPUNIT_ASSERT(meshNames[0]=="poly3D"); - MEDCouplingUMesh *mesh=MEDLoader::ReadUMeshFromFile(fileName.c_str(),meshNames[0].c_str(),0); - mesh->checkCoherency(); - CPPUNIT_ASSERT_EQUAL(3,mesh->getSpaceDimension()); - CPPUNIT_ASSERT_EQUAL(3,mesh->getMeshDimension()); - CPPUNIT_ASSERT_EQUAL(3,mesh->getNumberOfCells()); - CPPUNIT_ASSERT_EQUAL(19,mesh->getNumberOfNodes()); - CPPUNIT_ASSERT_EQUAL(2,(int)mesh->getAllGeoTypes().size()); - CPPUNIT_ASSERT_EQUAL(NORM_TETRA4,mesh->getTypeOfCell(0)); - CPPUNIT_ASSERT_EQUAL(NORM_POLYHED,mesh->getTypeOfCell(1)); - CPPUNIT_ASSERT_EQUAL(NORM_POLYHED,mesh->getTypeOfCell(2)); - CPPUNIT_ASSERT_EQUAL((std::size_t)98,mesh->getNodalConnectivity()->getNbOfElems()); - CPPUNIT_ASSERT_EQUAL(725,std::accumulate(mesh->getNodalConnectivity()->getPointer(),mesh->getNodalConnectivity()->getPointer()+98,0)); - CPPUNIT_ASSERT_DOUBLES_EQUAL(110.,std::accumulate(mesh->getCoords()->getPointer(),mesh->getCoords()->getPointer()+57,0),1e-12); - CPPUNIT_ASSERT_EQUAL(155,std::accumulate(mesh->getNodalConnectivityIndex()->getPointer(),mesh->getNodalConnectivityIndex()->getPointer()+4,0)); - mesh->decrRef(); - // - mesh=MEDLoader::ReadUMeshFromFile(fileName.c_str(),meshNames[0].c_str(),-1); - mesh->checkCoherency(); - CPPUNIT_ASSERT_EQUAL(3,mesh->getSpaceDimension()); - CPPUNIT_ASSERT_EQUAL(2,mesh->getMeshDimension()); - CPPUNIT_ASSERT_EQUAL(17,mesh->getNumberOfCells()); - CPPUNIT_ASSERT_EQUAL(19,mesh->getNumberOfNodes()); - CPPUNIT_ASSERT_EQUAL(3,(int)mesh->getAllGeoTypes().size()); - CPPUNIT_ASSERT_EQUAL(NORM_POLYGON,mesh->getTypeOfCell(0)); - CPPUNIT_ASSERT_EQUAL(NORM_QUAD4,mesh->getTypeOfCell(1)); - CPPUNIT_ASSERT_EQUAL(NORM_QUAD4,mesh->getTypeOfCell(2)); - CPPUNIT_ASSERT_EQUAL(NORM_QUAD4,mesh->getTypeOfCell(3)); - CPPUNIT_ASSERT_EQUAL(NORM_QUAD4,mesh->getTypeOfCell(4)); - CPPUNIT_ASSERT_EQUAL(NORM_QUAD4,mesh->getTypeOfCell(5)); - CPPUNIT_ASSERT_EQUAL(NORM_QUAD4,mesh->getTypeOfCell(6)); - CPPUNIT_ASSERT_EQUAL(NORM_TRI3,mesh->getTypeOfCell(7)); - CPPUNIT_ASSERT_EQUAL(NORM_POLYGON,mesh->getTypeOfCell(8)); - CPPUNIT_ASSERT_EQUAL(NORM_POLYGON,mesh->getTypeOfCell(9)); - CPPUNIT_ASSERT_EQUAL(NORM_QUAD4,mesh->getTypeOfCell(10)); - CPPUNIT_ASSERT_EQUAL(NORM_TRI3,mesh->getTypeOfCell(11)); - CPPUNIT_ASSERT_EQUAL(NORM_TRI3,mesh->getTypeOfCell(12)); - CPPUNIT_ASSERT_EQUAL(NORM_TRI3,mesh->getTypeOfCell(13)); - CPPUNIT_ASSERT_EQUAL(NORM_TRI3,mesh->getTypeOfCell(14)); - CPPUNIT_ASSERT_EQUAL(NORM_QUAD4,mesh->getTypeOfCell(15)); - CPPUNIT_ASSERT_EQUAL(NORM_TRI3,mesh->getTypeOfCell(16)); - CPPUNIT_ASSERT_DOUBLES_EQUAL(110.,std::accumulate(mesh->getCoords()->getPointer(),mesh->getCoords()->getPointer()+57,0),1e-12); - CPPUNIT_ASSERT_EQUAL((std::size_t)83,mesh->getNodalConnectivity()->getNbOfElems()); - CPPUNIT_ASSERT_EQUAL(619,std::accumulate(mesh->getNodalConnectivity()->getPointer(),mesh->getNodalConnectivity()->getPointer()+83,0)); - mesh->decrRef(); - // - vector families=MEDLoader::GetMeshFamiliesNames(fileName.c_str(),meshNames[0].c_str()); - CPPUNIT_ASSERT_EQUAL(4,(int)families.size()); - CPPUNIT_ASSERT(families[0]=="FAMILLE_FACE_POLYGONS3"); - CPPUNIT_ASSERT(families[1]=="FAMILLE_FACE_QUAD41"); - CPPUNIT_ASSERT(families[2]=="FAMILLE_FACE_TRIA32"); - CPPUNIT_ASSERT(families[3]=="FAMILLE_ZERO"); - vector families2; - families2.push_back(families[0]); - mesh=MEDLoader::ReadUMeshFromFamilies(fileName.c_str(),meshNames[0].c_str(),-1,families2); - mesh->checkCoherency(); - CPPUNIT_ASSERT_EQUAL(3,mesh->getSpaceDimension()); - CPPUNIT_ASSERT_EQUAL(2,mesh->getMeshDimension()); - CPPUNIT_ASSERT_EQUAL(3,mesh->getNumberOfCells()); - CPPUNIT_ASSERT_EQUAL(19,mesh->getNumberOfNodes()); - CPPUNIT_ASSERT_EQUAL(1,(int)mesh->getAllGeoTypes().size()); - for(int i=0;i<3;i++) - CPPUNIT_ASSERT_EQUAL(NORM_POLYGON,mesh->getTypeOfCell(i)); - CPPUNIT_ASSERT_EQUAL((std::size_t)19,mesh->getNodalConnectivity()->getNbOfElems()); - CPPUNIT_ASSERT_EQUAL(117,std::accumulate(mesh->getNodalConnectivity()->getPointer(),mesh->getNodalConnectivity()->getPointer()+19,0)); - mesh->decrRef(); - // - mesh=MEDLoader::ReadUMeshFromFamilies(fileName.c_str(),meshNames[0].c_str(),0,families2); - CPPUNIT_ASSERT_EQUAL(3,mesh->getSpaceDimension()); - CPPUNIT_ASSERT_EQUAL(0,mesh->getNumberOfCells()); - CPPUNIT_ASSERT_EQUAL(19,mesh->getNumberOfNodes()); - CPPUNIT_ASSERT_EQUAL(3,mesh->getMeshDimension()); - CPPUNIT_ASSERT_EQUAL(0,(int)mesh->getAllGeoTypes().size()); - mesh->decrRef(); - }