2012-06-15 21:40:21 +05:30
!--------------------------------------------------------------------------------------------------
2013-04-18 22:10:49 +05:30
!> @author Franz Roters, Max-Planck-Institut für Eisenforschung GmbH
!> @author Philip Eisenlohr, Max-Planck-Institut für Eisenforschung GmbH
!> @author Christoph Koords, Max-Planck-Institut für Eisenforschung GmbH
!> @author Martin Diehl, Max-Planck-Institut für Eisenforschung GmbH
2019-01-28 19:06:44 +05:30
!> @brief Sets up the mesh for the solver MSC.Marc
2012-06-15 21:40:21 +05:30
!--------------------------------------------------------------------------------------------------
2014-04-29 23:20:59 +05:30
module mesh
2019-05-17 16:13:42 +05:30
use IO
2019-05-15 02:42:32 +05:30
use prec
2019-05-17 16:52:52 +05:30
use math
2019-01-28 18:23:44 +05:30
use mesh_base
2019-06-04 22:43:01 +05:30
use DAMASK_interface
use IO
use debug
use numerics
use FEsolving
use element
2019-06-04 23:36:08 +05:30
#if defined(DAMASK_HDF5)
use HDF5_utilities
use results
#endif
2012-08-06 18:13:05 +05:30
2007-03-21 21:48:33 +05:30
implicit none
2012-03-09 01:55:28 +05:30
private
2019-05-19 02:27:51 +05:30
integer , public , protected :: &
mesh_Ncellnodes !< total number of cell nodes in mesh (including duplicates)
integer :: &
2018-09-24 00:23:35 +05:30
mesh_elemType , & !< Element type of the mesh (only support homogeneous meshes)
2012-06-15 21:40:21 +05:30
mesh_Nnodes , & !< total number of nodes in mesh
2013-04-18 22:10:49 +05:30
mesh_Ncells , & !< total number of cells in mesh
2018-09-23 21:07:57 +05:30
mesh_maxNsharedElems !< max number of CP elements sharing a node
2012-03-09 01:55:28 +05:30
2019-05-15 02:14:38 +05:30
integer , dimension ( : , : ) , allocatable , public , protected :: &
2018-09-23 23:28:43 +05:30
mesh_element , & !DEPRECATED
2012-06-15 21:40:21 +05:30
mesh_sharedElem , & !< entryCount and list of elements containing node
mesh_nodeTwins !< node twins are surface nodes that lie exactly on opposite sides of the mesh (surfaces nodes with equal coordinate values in two dimensions)
2018-01-10 21:43:25 +05:30
2019-05-15 02:14:38 +05:30
integer , dimension ( : , : , : , : ) , allocatable , public , protected :: &
2012-10-24 19:33:02 +05:30
mesh_ipNeighborhood !< 6 or less neighboring IPs as [element_num, IP_index, neighbor_index that points to me]
2012-03-09 01:55:28 +05:30
2013-05-07 18:36:29 +05:30
real ( pReal ) , public , protected :: &
mesh_unitlength !< physical length of one unit in mesh
2012-03-09 01:55:28 +05:30
real ( pReal ) , dimension ( : , : ) , allocatable , public :: &
2013-04-22 00:18:59 +05:30
mesh_node , & !< node x,y,z coordinates (after deformation! ONLY FOR MARC!!!)
mesh_cellnode !< cell node x,y,z coordinates (after deformation! ONLY FOR MARC!!!)
2018-01-10 21:43:25 +05:30
2013-01-16 16:10:53 +05:30
real ( pReal ) , dimension ( : , : ) , allocatable , public , protected :: &
mesh_ipVolume , & !< volume associated with IP (initially!)
mesh_node0 !< node x,y,z coordinates (initially!)
real ( pReal ) , dimension ( : , : , : ) , allocatable , public , protected :: &
2013-01-31 21:58:08 +05:30
mesh_ipArea !< area of interface to neighboring IP (initially!)
2018-01-10 21:43:25 +05:30
2013-01-16 16:10:53 +05:30
real ( pReal ) , dimension ( : , : , : ) , allocatable , public :: &
mesh_ipCoordinates !< IP x,y,z coordinates (after deformation!)
2018-01-10 21:43:25 +05:30
real ( pReal ) , dimension ( : , : , : , : ) , allocatable , public , protected :: &
2012-06-15 21:40:21 +05:30
mesh_ipAreaNormal !< area normal of interface to neighboring IP (initially!)
2018-01-10 21:43:25 +05:30
2013-01-16 16:10:53 +05:30
logical , dimension ( 3 ) , public , protected :: mesh_periodicSurface !< flag indicating periodic outer surfaces (used for fluxes)
2013-02-28 02:11:14 +05:30
2018-10-10 03:22:54 +05:30
2019-05-15 02:14:38 +05:30
integer , dimension ( : , : ) , allocatable , private :: &
2013-12-28 01:33:28 +05:30
mesh_cellnodeParent !< cellnode's parent element ID, cellnode's intra-element ID
2019-05-15 02:14:38 +05:30
integer , dimension ( : , : , : ) , allocatable , private :: &
2019-06-05 01:32:54 +05:30
mesh_cell2 , & !< cell connectivity for each element,ip/cell
2013-04-22 00:18:59 +05:30
mesh_cell !< cell connectivity for each element,ip/cell
2013-04-15 13:43:20 +05:30
2019-05-15 02:14:38 +05:30
integer , dimension ( : , : , : ) , allocatable , private :: &
2013-04-15 13:43:20 +05:30
FE_cellface !< list of intra-cell cell node IDs that constitute the cell faces of a specific type of cell
2018-01-10 21:43:25 +05:30
2012-06-15 21:40:21 +05:30
! These definitions should actually reside in the FE-solver specific part (different for MARC/ABAQUS)
2007-03-22 20:18:58 +05:30
! Hence, I suggest to prefix with "FE_"
2012-03-09 01:55:28 +05:30
2019-05-15 02:14:38 +05:30
integer , parameter , public :: &
FE_Nelemtypes = 13 , &
FE_Ngeomtypes = 10 , &
FE_Ncelltypes = 4 , &
FE_maxNipNeighbors = 6 , &
FE_maxmaxNnodesAtIP = 8 , & !< max number of (equivalent) nodes attached to an IP
FE_maxNmatchingNodesPerFace = 4 , &
FE_maxNfaces = 6 , &
FE_maxNcellnodes = 64 , &
FE_maxNcellnodesPerCell = 8 , &
FE_maxNcellfaces = 6 , &
FE_maxNcellnodesPerCellface = 4
integer , dimension ( FE_Ngeomtypes ) , parameter , private :: FE_NmatchingNodes = & !< number of nodes that are needed for face matching in a specific type of element geometry
2012-11-16 04:15:20 +05:30
int ( [ &
3 , & ! element 6 (2D 3node 1ip)
2013-04-15 13:43:20 +05:30
3 , & ! element 125 (2D 6node 3ip)
2012-11-16 04:15:20 +05:30
4 , & ! element 11 (2D 4node 4ip)
4 , & ! element 27 (2D 8node 9ip)
4 , & ! element 134 (3D 4node 1ip)
2013-04-15 13:43:20 +05:30
4 , & ! element 127 (3D 10node 4ip)
2012-11-16 04:15:20 +05:30
6 , & ! element 136 (3D 6node 6ip)
2013-04-15 13:43:20 +05:30
8 , & ! element 117 (3D 8node 1ip)
8 , & ! element 7 (3D 8node 8ip)
8 & ! element 21 (3D 20node 27ip)
2012-11-16 04:15:20 +05:30
] , pInt )
2019-05-15 02:14:38 +05:30
integer , dimension ( FE_maxNfaces , FE_Ngeomtypes ) , parameter , private :: &
2013-04-15 13:43:20 +05:30
FE_NmatchingNodesPerFace = & !< number of matching nodes per face in a specific type of element geometry
2012-11-16 04:15:20 +05:30
reshape ( int ( [ &
2013-04-15 13:43:20 +05:30
2 , 2 , 2 , 0 , 0 , 0 , & ! element 6 (2D 3node 1ip)
2012-11-16 04:15:20 +05:30
2 , 2 , 2 , 0 , 0 , 0 , & ! element 125 (2D 6node 3ip)
2 , 2 , 2 , 2 , 0 , 0 , & ! element 11 (2D 4node 4ip)
2 , 2 , 2 , 2 , 0 , 0 , & ! element 27 (2D 8node 9ip)
3 , 3 , 3 , 3 , 0 , 0 , & ! element 134 (3D 4node 1ip)
3 , 3 , 3 , 3 , 0 , 0 , & ! element 127 (3D 10node 4ip)
3 , 4 , 4 , 4 , 3 , 0 , & ! element 136 (3D 6node 6ip)
4 , 4 , 4 , 4 , 4 , 4 , & ! element 117 (3D 8node 1ip)
4 , 4 , 4 , 4 , 4 , 4 , & ! element 7 (3D 8node 8ip)
4 , 4 , 4 , 4 , 4 , 4 & ! element 21 (3D 20node 27ip)
2018-01-10 21:43:25 +05:30
] , pInt ) , [ FE_maxNipNeighbors , FE_Ngeomtypes ] )
2012-11-16 04:15:20 +05:30
2019-05-15 02:14:38 +05:30
integer , dimension ( FE_maxNmatchingNodesPerFace , FE_maxNfaces , FE_Ngeomtypes ) , &
2013-04-15 13:43:20 +05:30
parameter , private :: FE_face = & !< List of node indices on each face of a specific type of element geometry
2012-02-16 00:28:38 +05:30
reshape ( int ( [ &
2012-11-16 04:15:20 +05:30
1 , 2 , 0 , 0 , & ! element 6 (2D 3node 1ip)
2 , 3 , 0 , 0 , &
3 , 1 , 0 , 0 , &
2007-04-25 13:03:24 +05:30
0 , 0 , 0 , 0 , &
2007-10-12 19:18:29 +05:30
0 , 0 , 0 , 0 , &
2012-11-16 04:15:20 +05:30
0 , 0 , 0 , 0 , &
1 , 2 , 0 , 0 , & ! element 125 (2D 6node 3ip)
2 , 3 , 0 , 0 , &
3 , 1 , 0 , 0 , &
0 , 0 , 0 , 0 , &
0 , 0 , 0 , 0 , &
0 , 0 , 0 , 0 , &
1 , 2 , 0 , 0 , & ! element 11 (2D 4node 4ip)
2007-10-12 19:18:29 +05:30
2 , 3 , 0 , 0 , &
3 , 4 , 0 , 0 , &
4 , 1 , 0 , 0 , &
0 , 0 , 0 , 0 , &
0 , 0 , 0 , 0 , &
2012-11-16 04:15:20 +05:30
1 , 2 , 0 , 0 , & ! element 27 (2D 8node 9ip)
2009-04-02 18:30:51 +05:30
2 , 3 , 0 , 0 , &
3 , 4 , 0 , 0 , &
4 , 1 , 0 , 0 , &
2007-10-12 19:18:29 +05:30
0 , 0 , 0 , 0 , &
2008-06-17 14:41:54 +05:30
0 , 0 , 0 , 0 , &
2012-11-16 04:15:20 +05:30
1 , 2 , 3 , 0 , & ! element 134 (3D 4node 1ip)
2008-06-17 14:41:54 +05:30
1 , 4 , 2 , 0 , &
2 , 3 , 4 , 0 , &
1 , 3 , 4 , 0 , &
0 , 0 , 0 , 0 , &
0 , 0 , 0 , 0 , &
2012-11-16 04:15:20 +05:30
1 , 2 , 3 , 0 , & ! element 127 (3D 10node 4ip)
1 , 4 , 2 , 0 , &
2 , 4 , 3 , 0 , &
1 , 3 , 4 , 0 , &
0 , 0 , 0 , 0 , &
0 , 0 , 0 , 0 , &
1 , 2 , 3 , 0 , & ! element 136 (3D 6node 6ip)
2008-06-17 14:41:54 +05:30
1 , 4 , 5 , 2 , &
2 , 5 , 6 , 3 , &
1 , 3 , 6 , 4 , &
4 , 6 , 5 , 0 , &
2009-04-02 18:30:51 +05:30
0 , 0 , 0 , 0 , &
2012-11-16 04:15:20 +05:30
1 , 2 , 3 , 4 , & ! element 117 (3D 8node 1ip)
2009-04-02 18:30:51 +05:30
2 , 1 , 5 , 6 , &
3 , 2 , 6 , 7 , &
4 , 3 , 7 , 8 , &
4 , 1 , 5 , 8 , &
2010-05-10 20:24:59 +05:30
8 , 7 , 6 , 5 , &
2012-11-16 04:15:20 +05:30
1 , 2 , 3 , 4 , & ! element 7 (3D 8node 8ip)
2010-05-10 20:24:59 +05:30
2 , 1 , 5 , 6 , &
3 , 2 , 6 , 7 , &
4 , 3 , 7 , 8 , &
4 , 1 , 5 , 8 , &
2010-08-17 04:23:24 +05:30
8 , 7 , 6 , 5 , &
2012-11-16 04:15:20 +05:30
1 , 2 , 3 , 4 , & ! element 21 (3D 20node 27ip)
2010-08-17 04:23:24 +05:30
2 , 1 , 5 , 6 , &
3 , 2 , 6 , 7 , &
4 , 3 , 7 , 8 , &
4 , 1 , 5 , 8 , &
2012-11-16 04:15:20 +05:30
8 , 7 , 6 , 5 &
2013-04-15 13:43:20 +05:30
] , pInt ) , [ FE_maxNmatchingNodesPerFace , FE_maxNfaces , FE_Ngeomtypes ] )
2019-05-15 02:14:38 +05:30
integer , dimension ( FE_Ncelltypes ) , parameter , private :: FE_NcellnodesPerCellface = & !< number of cell nodes per cell face in a specific cell type
2013-04-15 13:43:20 +05:30
int ( [ &
2 , & ! (2D 3node)
2 , & ! (2D 4node)
3 , & ! (3D 4node)
4 & ! (3D 8node)
] , pInt )
2019-05-15 02:14:38 +05:30
integer , dimension ( FE_Ncelltypes ) , parameter , private :: FE_NipNeighbors = & !< number of ip neighbors / cell faces in a specific cell type
2013-04-15 13:43:20 +05:30
int ( [ &
3 , & ! (2D 3node)
4 , & ! (2D 4node)
4 , & ! (3D 4node)
6 & ! (3D 8node)
] , pInt )
2019-05-15 02:14:38 +05:30
integer , private :: &
2018-09-23 20:35:01 +05:30
mesh_Nelems , & !< total number of elements in mesh (including non-DAMASK elements)
2018-09-23 19:01:19 +05:30
mesh_NelemSets
2018-09-23 18:57:51 +05:30
character ( len = 64 ) , dimension ( : ) , allocatable , private :: &
2019-02-03 17:24:10 +05:30
mesh_nameElemSet
2019-05-15 02:14:38 +05:30
integer , dimension ( : , : ) , allocatable , private :: &
2018-09-23 18:57:51 +05:30
mesh_mapElemSet !< list of elements in elementSet
2019-05-15 02:14:38 +05:30
integer , dimension ( : , : ) , allocatable , target , private :: &
2018-09-23 18:57:51 +05:30
mesh_mapFEtoCPelem , & !< [sorted FEid, corresponding CPid]
mesh_mapFEtoCPnode !< [sorted FEid, corresponding CPid]
2019-01-24 14:34:43 +05:30
2019-05-15 02:14:38 +05:30
integer , private :: &
2018-09-23 18:57:51 +05:30
hypoelasticTableStyle , & !< Table style (Marc only)
initialcondTableStyle !< Table style (Marc only)
2019-05-15 02:14:38 +05:30
integer , dimension ( : ) , allocatable , private :: &
2018-09-23 18:57:51 +05:30
Marc_matNumber !< array of material numbers for hypoelastic material (Marc only)
2013-04-22 00:18:59 +05:30
2013-04-18 22:10:49 +05:30
public :: &
mesh_init , &
2013-04-22 00:18:59 +05:30
mesh_build_cellnodes , &
2013-04-18 22:10:49 +05:30
mesh_build_ipVolumes , &
mesh_build_ipCoordinates , &
2018-09-23 21:27:48 +05:30
mesh_FEasCP
2019-01-24 14:34:43 +05:30
2012-06-15 21:40:21 +05:30
private :: &
2018-09-23 21:27:48 +05:30
mesh_build_cellconnectivity , &
mesh_build_ipAreas , &
FE_mapElemtype , &
mesh_build_FEdata , &
mesh_build_nodeTwins , &
mesh_build_sharedElems , &
mesh_build_ipNeighborhood , &
2018-01-10 21:43:25 +05:30
mesh_marc_get_fileFormat , &
2013-04-18 22:10:49 +05:30
mesh_marc_get_tableStyles , &
2018-01-10 21:43:25 +05:30
mesh_marc_get_matNumber , &
2013-04-18 22:10:49 +05:30
mesh_marc_count_nodesAndElements , &
mesh_marc_count_elementSets , &
mesh_marc_map_elementSets , &
mesh_marc_map_Elements , &
2018-01-10 21:43:25 +05:30
mesh_marc_map_nodes , &
2013-04-18 22:10:49 +05:30
mesh_marc_build_nodes , &
2018-09-23 21:27:48 +05:30
mesh_marc_build_elements
2013-04-18 22:10:49 +05:30
2019-01-28 18:23:44 +05:30
type , public , extends ( tMesh ) :: tMesh_marc
2019-02-01 16:54:23 +05:30
contains
procedure , pass ( self ) :: tMesh_marc_init
generic , public :: init = > tMesh_marc_init
2019-01-28 18:23:44 +05:30
end type tMesh_marc
type ( tMesh_marc ) , public , protected :: theMesh
2019-01-28 19:06:44 +05:30
2019-01-28 18:23:44 +05:30
contains
2019-02-01 16:54:23 +05:30
subroutine tMesh_marc_init ( self , elemType , nodes )
2019-05-15 02:42:32 +05:30
2019-01-28 18:23:44 +05:30
class ( tMesh_marc ) :: self
2019-02-01 16:54:23 +05:30
real ( pReal ) , dimension ( : , : ) , intent ( in ) :: nodes
2019-05-15 02:14:38 +05:30
integer , intent ( in ) :: elemType
2019-02-01 16:54:23 +05:30
call self % tMesh % init ( 'mesh' , elemType , nodes )
2019-01-28 18:23:44 +05:30
end subroutine tMesh_marc_init
2009-01-20 00:12:31 +05:30
2012-06-15 21:40:21 +05:30
!--------------------------------------------------------------------------------------------------
!> @brief initializes the mesh by calling all necessary private routines the mesh module
!! Order and routines strongly depend on type of solver
!--------------------------------------------------------------------------------------------------
2013-02-05 18:57:37 +05:30
subroutine mesh_init ( ip , el )
2018-01-10 21:43:25 +05:30
2019-05-15 02:14:38 +05:30
integer , intent ( in ) :: el , ip
2019-02-03 15:42:23 +05:30
2019-05-15 02:14:38 +05:30
integer , parameter :: FILEUNIT = 222
integer :: j , fileFormatVersion , elemType
integer :: &
2019-02-03 21:10:15 +05:30
mesh_maxNelemInSet , &
mesh_NcpElems
2014-12-19 00:11:02 +05:30
logical :: myDebug
2018-01-10 21:43:25 +05:30
2016-06-29 20:29:22 +05:30
write ( 6 , '(/,a)' ) ' <<<+- mesh init -+>>>'
2019-02-02 20:27:05 +05:30
2013-05-07 18:36:29 +05:30
mesh_unitlength = numerics_unitlength ! set physical extent of a length unit in mesh
2018-01-10 21:43:25 +05:30
2019-05-15 02:14:38 +05:30
myDebug = ( iand ( debug_level ( debug_mesh ) , debug_levelBasic ) / = 0 )
2013-05-07 18:36:29 +05:30
2013-12-11 22:19:20 +05:30
call IO_open_inputFile ( FILEUNIT , modelName ) ! parse info from input file...
2014-12-19 00:11:02 +05:30
if ( myDebug ) write ( 6 , '(a)' ) ' Opened input file' ; flush ( 6 )
2019-02-03 15:42:23 +05:30
2019-06-05 16:27:08 +05:30
fileFormatVersion = mesh_marc_get_fileFormat ( FILEUNIT )
2019-02-03 15:42:23 +05:30
fileFormatVersion = MarcVersion
2018-01-10 21:43:25 +05:30
if ( myDebug ) write ( 6 , '(a)' ) ' Got input file format' ; flush ( 6 )
2019-02-03 15:42:23 +05:30
call mesh_marc_get_tableStyles ( initialcondTableStyle , hypoelasticTableStyle , FILEUNIT )
2014-12-19 00:11:02 +05:30
if ( myDebug ) write ( 6 , '(a)' ) ' Got table styles' ; flush ( 6 )
2019-02-03 15:42:23 +05:30
if ( fileFormatVersion > 12 ) then
Marc_matNumber = mesh_marc_get_matNumber ( FILEUNIT , hypoelasticTableStyle )
2018-01-10 21:43:25 +05:30
if ( myDebug ) write ( 6 , '(a)' ) ' Got hypoleastic material number' ; flush ( 6 )
2018-01-11 21:41:03 +05:30
endif
2019-02-03 15:42:23 +05:30
call mesh_marc_count_nodesAndElements ( mesh_nNodes , mesh_nElems , FILEUNIT )
2014-12-19 00:11:02 +05:30
if ( myDebug ) write ( 6 , '(a)' ) ' Counted nodes/elements' ; flush ( 6 )
2019-02-03 15:42:23 +05:30
call mesh_marc_count_elementSets ( mesh_NelemSets , mesh_maxNelemInSet , FILEUNIT )
2014-12-19 00:11:02 +05:30
if ( myDebug ) write ( 6 , '(a)' ) ' Counted element sets' ; flush ( 6 )
2019-02-03 15:42:23 +05:30
allocate ( mesh_nameElemSet ( mesh_NelemSets ) ) ; mesh_nameElemSet = 'n/a'
2019-05-15 02:14:38 +05:30
allocate ( mesh_mapElemSet ( 1 + mesh_maxNelemInSet , mesh_NelemSets ) , source = 0 )
2019-02-03 16:58:04 +05:30
call mesh_marc_map_elementSets ( mesh_nameElemSet , mesh_mapElemSet , FILEUNIT )
2014-12-19 00:11:02 +05:30
if ( myDebug ) write ( 6 , '(a)' ) ' Mapped element sets' ; flush ( 6 )
2019-02-03 15:42:23 +05:30
2019-02-04 23:19:30 +05:30
mesh_NcpElems = mesh_nElems
2014-12-19 00:11:02 +05:30
if ( myDebug ) write ( 6 , '(a)' ) ' Counted CP elements' ; flush ( 6 )
2019-02-03 15:42:23 +05:30
2019-05-15 02:14:38 +05:30
allocate ( mesh_mapFEtoCPelem ( 2 , mesh_NcpElems ) , source = 0 )
2019-06-05 16:27:08 +05:30
call mesh_marc_map_elements ( hypoelasticTableStyle , mesh_nameElemSet , mesh_mapElemSet , mesh_NcpElems , fileFormatVersion , FILEUNIT )
2014-12-19 00:11:02 +05:30
if ( myDebug ) write ( 6 , '(a)' ) ' Mapped elements' ; flush ( 6 )
2019-02-03 15:42:23 +05:30
2019-05-15 02:14:38 +05:30
allocate ( mesh_mapFEtoCPnode ( 2 , mesh_Nnodes ) , source = 0 )
2019-02-03 21:10:15 +05:30
call mesh_marc_map_nodes ( mesh_Nnodes , FILEUNIT ) !ToDo: don't work on global variables
2014-12-19 00:11:02 +05:30
if ( myDebug ) write ( 6 , '(a)' ) ' Mapped nodes' ; flush ( 6 )
2019-02-03 15:42:23 +05:30
2019-02-03 21:10:15 +05:30
call mesh_marc_build_nodes ( FILEUNIT ) !ToDo: don't work on global variables
2019-02-03 16:58:04 +05:30
mesh_node = mesh_node0
2014-12-19 00:11:02 +05:30
if ( myDebug ) write ( 6 , '(a)' ) ' Built nodes' ; flush ( 6 )
2019-02-03 15:42:23 +05:30
elemType = mesh_marc_count_cpSizes ( FILEUNIT )
2014-12-19 00:11:02 +05:30
if ( myDebug ) write ( 6 , '(a)' ) ' Counted CP sizes' ; flush ( 6 )
2019-02-03 15:42:23 +05:30
call theMesh % init ( elemType , mesh_node0 )
call theMesh % setNelems ( mesh_NcpElems )
2013-12-11 22:19:20 +05:30
call mesh_marc_build_elements ( FILEUNIT )
2014-12-19 00:11:02 +05:30
if ( myDebug ) write ( 6 , '(a)' ) ' Built elements' ; flush ( 6 )
2019-02-02 20:27:05 +05:30
close ( FILEUNIT )
2019-02-03 01:15:19 +05:30
call mesh_build_FEdata ! get properties of the different types of elements
2013-04-22 00:18:59 +05:30
call mesh_build_cellconnectivity
2014-12-19 00:11:02 +05:30
if ( myDebug ) write ( 6 , '(a)' ) ' Built cell connectivity' ; flush ( 6 )
2019-05-19 02:40:40 +05:30
mesh_cellnode = mesh_build_cellnodes ( )
2014-12-19 00:11:02 +05:30
if ( myDebug ) write ( 6 , '(a)' ) ' Built cell nodes' ; flush ( 6 )
2019-06-05 04:06:25 +05:30
allocate ( mesh_ipCoordinates ( 3 , theMesh % elem % nIPs , theMesh % nElems ) , source = 0.0_pReal )
2012-03-09 01:55:28 +05:30
call mesh_build_ipCoordinates
2014-12-19 00:11:02 +05:30
if ( myDebug ) write ( 6 , '(a)' ) ' Built IP coordinates' ; flush ( 6 )
2012-03-09 01:55:28 +05:30
call mesh_build_ipVolumes
2014-12-19 00:11:02 +05:30
if ( myDebug ) write ( 6 , '(a)' ) ' Built IP volumes' ; flush ( 6 )
2012-03-09 01:55:28 +05:30
call mesh_build_ipAreas
2014-12-19 00:11:02 +05:30
if ( myDebug ) write ( 6 , '(a)' ) ' Built IP areas' ; flush ( 6 )
2019-02-02 20:27:05 +05:30
2015-11-26 02:25:17 +05:30
2012-03-09 01:55:28 +05:30
call mesh_build_nodeTwins
2014-12-19 00:11:02 +05:30
if ( myDebug ) write ( 6 , '(a)' ) ' Built node twins' ; flush ( 6 )
2012-03-09 01:55:28 +05:30
call mesh_build_sharedElems
2014-12-19 00:11:02 +05:30
if ( myDebug ) write ( 6 , '(a)' ) ' Built shared elements' ; flush ( 6 )
2012-03-09 01:55:28 +05:30
call mesh_build_ipNeighborhood
2019-06-05 11:52:34 +05:30
call IP_neighborhood2
2015-11-26 02:25:17 +05:30
if ( myDebug ) write ( 6 , '(a)' ) ' Built IP neighborhood' ; flush ( 6 )
2012-02-13 23:11:27 +05:30
2019-02-03 21:10:15 +05:30
if ( usePingPong . and . ( mesh_Nelems / = theMesh % nElems ) ) &
2019-05-15 02:14:38 +05:30
call IO_error ( 600 ) ! ping-pong must be disabled when having non-DAMASK elements
2019-02-03 21:10:15 +05:30
if ( debug_e < 1 . or . debug_e > theMesh % nElems ) &
2019-05-15 02:14:38 +05:30
call IO_error ( 602 , ext_msg = 'element' ) ! selected element does not exist
2019-02-03 21:10:15 +05:30
if ( debug_i < 1 . or . debug_i > theMesh % elem % nIPs ) &
2019-05-15 02:14:38 +05:30
call IO_error ( 602 , ext_msg = 'IP' ) ! selected element does not have requested IP
2018-01-10 21:43:25 +05:30
2019-05-15 02:14:38 +05:30
FEsolving_execElem = [ 1 , theMesh % nElems ] ! parallel loop bounds set to comprise all DAMASK elements
allocate ( FEsolving_execIP ( 2 , theMesh % nElems ) , source = 1 ) ! parallel loop bounds set to comprise from first IP...
2019-02-03 21:10:15 +05:30
FEsolving_execIP ( 2 , : ) = theMesh % elem % nIPs
2018-01-10 21:43:25 +05:30
2019-02-03 21:10:15 +05:30
allocate ( calcMode ( theMesh % elem % nIPs , theMesh % nElems ) )
2012-06-15 21:40:21 +05:30
calcMode = . false . ! pretend to have collected what first call is asking (F = I)
2013-02-05 18:57:37 +05:30
calcMode ( ip , mesh_FEasCP ( 'elem' , el ) ) = . true . ! first ip,el needs to be already pingponged to "calc"
2013-04-19 18:11:06 +05:30
2019-03-10 15:06:50 +05:30
theMesh % homogenizationAt = mesh_element ( 3 , : )
theMesh % microstructureAt = mesh_element ( 4 , : )
2019-02-02 20:27:05 +05:30
2012-03-09 01:55:28 +05:30
end subroutine mesh_init
2009-01-20 00:12:31 +05:30
2014-04-04 20:10:30 +05:30
2012-06-15 21:40:21 +05:30
!--------------------------------------------------------------------------------------------------
2019-02-03 15:42:23 +05:30
!> @brief Figures out version of Marc input file format
2018-01-10 21:43:25 +05:30
!--------------------------------------------------------------------------------------------------
2019-05-15 02:14:38 +05:30
integer function mesh_marc_get_fileFormat ( fileUnit )
2019-05-15 02:42:32 +05:30
2019-05-15 02:14:38 +05:30
integer , intent ( in ) :: fileUnit
2018-01-10 21:43:25 +05:30
2019-05-15 02:14:38 +05:30
integer , allocatable , dimension ( : ) :: chunkPos
2018-01-10 21:43:25 +05:30
character ( len = 300 ) line
rewind ( fileUnit )
do
2019-02-02 20:47:52 +05:30
read ( fileUnit , '(A300)' , END = 620 ) line
2018-01-10 21:43:25 +05:30
chunkPos = IO_stringPos ( line )
2019-02-02 21:54:00 +05:30
2019-05-15 02:14:38 +05:30
if ( IO_lc ( IO_stringValue ( line , chunkPos , 1 ) ) == 'version' ) then
mesh_marc_get_fileFormat = IO_intValue ( line , chunkPos , 2 )
2018-01-10 21:43:25 +05:30
exit
endif
enddo
2019-02-03 15:42:23 +05:30
620 end function mesh_marc_get_fileFormat
2018-01-10 21:43:25 +05:30
2018-01-11 21:41:03 +05:30
2018-01-10 21:43:25 +05:30
!--------------------------------------------------------------------------------------------------
2019-02-03 15:42:23 +05:30
!> @brief Figures out table styles for initial cond and hypoelastic
2012-06-15 21:40:21 +05:30
!--------------------------------------------------------------------------------------------------
2019-02-03 15:42:23 +05:30
subroutine mesh_marc_get_tableStyles ( initialcond , hypoelastic , fileUnit )
2019-05-15 02:42:32 +05:30
2019-05-15 02:14:38 +05:30
integer , intent ( out ) :: initialcond , hypoelastic
integer , intent ( in ) :: fileUnit
2018-01-10 21:43:25 +05:30
2019-05-15 02:14:38 +05:30
integer , allocatable , dimension ( : ) :: chunkPos
2009-10-12 21:31:49 +05:30
character ( len = 300 ) line
2019-05-15 02:14:38 +05:30
initialcond = 0
hypoelastic = 0
2009-10-12 21:31:49 +05:30
2013-12-11 22:19:20 +05:30
rewind ( fileUnit )
2018-01-10 21:43:25 +05:30
do
2019-02-02 20:47:52 +05:30
read ( fileUnit , '(A300)' , END = 620 ) line
2015-08-28 13:08:48 +05:30
chunkPos = IO_stringPos ( line )
2009-10-12 21:31:49 +05:30
2019-05-15 02:14:38 +05:30
if ( IO_lc ( IO_stringValue ( line , chunkPos , 1 ) ) == 'table' . and . chunkPos ( 1 ) > 5 ) then
initialcond = IO_intValue ( line , chunkPos , 4 )
hypoelastic = IO_intValue ( line , chunkPos , 5 )
2007-09-28 20:26:26 +05:30
exit
2009-06-15 18:41:21 +05:30
endif
enddo
2009-10-12 21:31:49 +05:30
2012-06-15 21:40:21 +05:30
620 end subroutine mesh_marc_get_tableStyles
2009-04-03 12:33:25 +05:30
2019-02-03 15:42:23 +05:30
2018-01-10 21:43:25 +05:30
!--------------------------------------------------------------------------------------------------
2019-02-03 16:58:04 +05:30
!> @brief Figures out material number of hypoelastic material
2018-01-10 21:43:25 +05:30
!--------------------------------------------------------------------------------------------------
2019-02-03 15:42:23 +05:30
function mesh_marc_get_matNumber ( fileUnit , tableStyle )
2019-05-15 02:42:32 +05:30
2019-05-17 16:13:42 +05:30
integer , intent ( in ) :: fileUnit , tableStyle
2019-05-15 02:14:38 +05:30
integer , dimension ( : ) , allocatable :: mesh_marc_get_matNumber
2018-01-10 21:43:25 +05:30
2019-05-15 02:14:38 +05:30
integer , allocatable , dimension ( : ) :: chunkPos
integer :: i , j , data_blocks
2019-05-17 16:13:42 +05:30
character ( len = 300 ) :: line
2018-01-10 21:43:25 +05:30
2019-05-15 02:14:38 +05:30
data_blocks = 1
2019-05-17 16:13:42 +05:30
rewind ( fileUnit )
2018-01-10 21:43:25 +05:30
do
2019-02-02 20:47:52 +05:30
read ( fileUnit , '(A300)' , END = 620 ) line
2018-01-10 21:43:25 +05:30
chunkPos = IO_stringPos ( line )
2019-02-02 21:54:00 +05:30
2019-05-15 02:14:38 +05:30
if ( IO_lc ( IO_stringValue ( line , chunkPos , 1 ) ) == 'hypoelastic' ) then
2019-02-02 21:54:00 +05:30
read ( fileUnit , '(A300)' , END = 620 ) line
2019-05-15 02:14:38 +05:30
if ( len ( trim ( line ) ) / = 0 ) then
2018-01-11 21:41:03 +05:30
chunkPos = IO_stringPos ( line )
2019-05-15 02:14:38 +05:30
data_blocks = IO_intValue ( line , chunkPos , 1 )
2018-02-02 19:36:13 +05:30
endif
2019-05-15 02:14:38 +05:30
allocate ( mesh_marc_get_matNumber ( data_blocks ) , source = 0 )
do i = 1 , data_blocks ! read all data blocks
2019-02-02 21:54:00 +05:30
read ( fileUnit , '(A300)' , END = 620 ) line
2018-01-11 21:41:03 +05:30
chunkPos = IO_stringPos ( line )
2019-05-15 02:14:38 +05:30
mesh_marc_get_matNumber ( i ) = IO_intValue ( line , chunkPos , 1 )
do j = 1_pint , 2 + tableStyle ! read 2 or 3 remaining lines of data block
2019-02-02 21:54:00 +05:30
read ( fileUnit , '(A300)' ) line
2018-01-11 21:41:03 +05:30
enddo
2018-01-10 21:43:25 +05:30
enddo
exit
endif
enddo
2019-02-03 15:42:23 +05:30
620 end function mesh_marc_get_matNumber
2018-01-10 21:43:25 +05:30
2012-06-15 21:40:21 +05:30
!--------------------------------------------------------------------------------------------------
2019-02-03 17:24:10 +05:30
!> @brief Count overall number of nodes and elements
2012-06-15 21:40:21 +05:30
!--------------------------------------------------------------------------------------------------
2019-02-03 15:42:23 +05:30
subroutine mesh_marc_count_nodesAndElements ( nNodes , nElems , fileUnit )
2019-05-15 02:42:32 +05:30
2019-05-15 02:14:38 +05:30
integer , intent ( in ) :: fileUnit
integer , intent ( out ) :: nNodes , nElems
2019-02-03 15:42:23 +05:30
2019-05-15 02:14:38 +05:30
integer , allocatable , dimension ( : ) :: chunkPos
2019-05-17 16:13:42 +05:30
character ( len = 300 ) :: line
2009-01-20 00:12:31 +05:30
2019-05-15 02:14:38 +05:30
nNodes = 0
nElems = 0
2009-01-20 00:12:31 +05:30
2013-12-11 22:19:20 +05:30
rewind ( fileUnit )
2018-01-10 21:43:25 +05:30
do
2019-02-02 20:47:52 +05:30
read ( fileUnit , '(A300)' , END = 620 ) line
2015-08-28 13:08:48 +05:30
chunkPos = IO_stringPos ( line )
2012-06-15 21:40:21 +05:30
2019-05-15 02:14:38 +05:30
if ( IO_lc ( IO_StringValue ( line , chunkPos , 1 ) ) == 'sizing' ) &
nElems = IO_IntValue ( line , chunkPos , 3 )
if ( IO_lc ( IO_StringValue ( line , chunkPos , 1 ) ) == 'coordinates' ) then
2019-02-02 21:54:00 +05:30
read ( fileUnit , '(A300)' ) line
2015-08-28 13:08:48 +05:30
chunkPos = IO_stringPos ( line )
2019-05-15 02:14:38 +05:30
nNodes = IO_IntValue ( line , chunkPos , 2 )
2019-02-03 15:42:23 +05:30
exit ! assumes that "coordinates" comes later in file
2009-06-15 18:41:21 +05:30
endif
enddo
2009-01-20 00:12:31 +05:30
2012-06-15 21:40:21 +05:30
620 end subroutine mesh_marc_count_nodesAndElements
!--------------------------------------------------------------------------------------------------
2019-02-03 15:42:23 +05:30
!> @brief Count overall number of element sets in mesh.
2012-06-15 21:40:21 +05:30
!--------------------------------------------------------------------------------------------------
2019-05-17 16:13:42 +05:30
subroutine mesh_marc_count_elementSets ( nElemSets , maxNelemInSet , fileUnit )
2019-05-15 02:42:32 +05:30
2019-05-17 16:13:42 +05:30
integer , intent ( in ) :: fileUnit
2019-05-15 02:14:38 +05:30
integer , intent ( out ) :: nElemSets , maxNelemInSet
2009-01-20 00:12:31 +05:30
2019-05-15 02:14:38 +05:30
integer , allocatable , dimension ( : ) :: chunkPos
2019-02-03 15:42:23 +05:30
character ( len = 300 ) :: line
2009-10-12 21:31:49 +05:30
2019-05-15 02:14:38 +05:30
nElemSets = 0
maxNelemInSet = 0
2009-01-20 00:12:31 +05:30
2013-12-11 22:19:20 +05:30
rewind ( fileUnit )
2018-01-10 21:43:25 +05:30
do
2019-02-02 20:47:52 +05:30
read ( fileUnit , '(A300)' , END = 620 ) line
2015-08-28 13:08:48 +05:30
chunkPos = IO_stringPos ( line )
2009-10-12 21:31:49 +05:30
2019-05-15 02:14:38 +05:30
if ( IO_lc ( IO_StringValue ( line , chunkPos , 1 ) ) == 'define' . and . &
IO_lc ( IO_StringValue ( line , chunkPos , 2 ) ) == 'element' ) then
nElemSets = nElemSets + 1
2019-02-03 15:42:23 +05:30
maxNelemInSet = max ( maxNelemInSet , IO_countContinuousIntValues ( fileUnit ) )
2009-06-15 18:41:21 +05:30
endif
enddo
2009-01-20 00:12:31 +05:30
2012-03-09 01:55:28 +05:30
620 end subroutine mesh_marc_count_elementSets
2007-04-25 13:03:24 +05:30
2009-01-20 00:12:31 +05:30
2019-02-03 15:42:23 +05:30
!--------------------------------------------------------------------------------------------------
!> @brief map element sets
!--------------------------------------------------------------------------------------------------
2019-02-03 16:58:04 +05:30
subroutine mesh_marc_map_elementSets ( nameElemSet , mapElemSet , fileUnit )
2019-05-15 02:42:32 +05:30
2019-05-17 16:13:42 +05:30
integer , intent ( in ) :: fileUnit
character ( len = 64 ) , dimension ( : ) , intent ( out ) :: nameElemSet
integer , dimension ( : , : ) , intent ( out ) :: mapElemSet
2018-01-10 21:43:25 +05:30
2019-05-15 02:14:38 +05:30
integer , allocatable , dimension ( : ) :: chunkPos
2012-03-09 01:55:28 +05:30
character ( len = 300 ) :: line
2019-05-15 02:14:38 +05:30
integer :: elemSet
2019-02-03 15:42:23 +05:30
2019-05-15 02:14:38 +05:30
elemSet = 0
2009-01-20 00:12:31 +05:30
2013-12-11 22:19:20 +05:30
rewind ( fileUnit )
2012-06-15 21:40:21 +05:30
do
2019-02-02 20:47:52 +05:30
read ( fileUnit , '(A300)' , END = 640 ) line
2015-08-28 13:08:48 +05:30
chunkPos = IO_stringPos ( line )
2019-05-15 02:14:38 +05:30
if ( ( IO_lc ( IO_stringValue ( line , chunkPos , 1 ) ) == 'define' ) . and . &
( IO_lc ( IO_stringValue ( line , chunkPos , 2 ) ) == 'element' ) ) then
elemSet = elemSet + 1
nameElemSet ( elemSet ) = trim ( IO_stringValue ( line , chunkPos , 4 ) )
2019-02-03 16:58:04 +05:30
mapElemSet ( : , elemSet ) = IO_continuousIntValues ( fileUnit , size ( mapElemSet , 1 ) - 1 , nameElemSet , mapElemSet , size ( nameElemSet ) )
2012-06-15 21:40:21 +05:30
endif
2009-06-15 18:41:21 +05:30
enddo
2018-01-10 21:43:25 +05:30
2012-06-15 21:40:21 +05:30
640 end subroutine mesh_marc_map_elementSets
2010-05-06 22:10:47 +05:30
2012-06-15 21:40:21 +05:30
!--------------------------------------------------------------------------------------------------
!> @brief Maps elements from FE ID to internal (consecutive) representation.
!--------------------------------------------------------------------------------------------------
2019-06-05 16:27:08 +05:30
subroutine mesh_marc_map_elements ( tableStyle , nameElemSet , mapElemSet , nElems , fileFormatVersion , fileUnit )
2019-05-15 02:42:32 +05:30
2019-06-05 16:27:08 +05:30
integer , intent ( in ) :: fileUnit , tableStyle , nElems , fileFormatVersion
2019-02-03 17:24:10 +05:30
character ( len = 64 ) , intent ( in ) , dimension ( : ) :: nameElemSet
2019-05-15 02:14:38 +05:30
integer , dimension ( : , : ) , intent ( in ) :: &
2019-02-03 17:24:10 +05:30
mapElemSet
2012-06-15 21:40:21 +05:30
2019-05-15 02:14:38 +05:30
integer , allocatable , dimension ( : ) :: chunkPos
2018-02-02 19:36:13 +05:30
character ( len = 300 ) :: line , &
tmp
2012-06-15 21:40:21 +05:30
2019-05-15 02:14:38 +05:30
integer , dimension ( 1 + nElems ) :: contInts
integer :: i , cpElem
2012-06-15 21:40:21 +05:30
2019-05-15 02:14:38 +05:30
cpElem = 0
contInts = 0
2013-12-11 22:19:20 +05:30
rewind ( fileUnit )
2012-06-15 21:40:21 +05:30
do
2019-02-02 20:47:52 +05:30
read ( fileUnit , '(A300)' , END = 660 ) line
2015-08-28 13:08:48 +05:30
chunkPos = IO_stringPos ( line )
2019-06-05 16:27:08 +05:30
if ( fileFormatVersion < 13 ) then ! Marc 2016 or earlier
2019-05-15 02:14:38 +05:30
if ( IO_lc ( IO_stringValue ( line , chunkPos , 1 ) ) == 'hypoelastic' ) then
2019-05-17 16:13:42 +05:30
do i = 1 , 3 + TableStyle ! skip three (or four if new table style!) lines
2019-02-02 21:54:00 +05:30
read ( fileUnit , '(A300)' ) line
2018-02-02 19:36:13 +05:30
enddo
2019-02-03 21:10:15 +05:30
contInts = IO_continuousIntValues ( fileUnit , nElems , nameElemSet , &
2019-02-03 17:24:10 +05:30
mapElemSet , size ( nameElemSet ) )
2018-02-02 19:36:13 +05:30
exit
endif
2019-02-03 15:42:23 +05:30
else ! Marc2017 and later
2019-05-15 02:14:38 +05:30
if ( IO_lc ( IO_stringValue ( line , chunkPos , 1 ) ) == 'connectivity' ) then
2019-02-02 20:47:52 +05:30
read ( fileUnit , '(A300)' , END = 660 ) line
2018-02-02 19:36:13 +05:30
chunkPos = IO_stringPos ( line )
2019-05-15 02:14:38 +05:30
if ( any ( Marc_matNumber == IO_intValue ( line , chunkPos , 6 ) ) ) then
2018-02-02 19:36:13 +05:30
do
2019-02-02 20:47:52 +05:30
read ( fileUnit , '(A300)' , END = 660 ) line
2018-02-02 19:36:13 +05:30
chunkPos = IO_stringPos ( line )
2019-05-15 02:14:38 +05:30
tmp = IO_lc ( IO_stringValue ( line , chunkPos , 1 ) )
2019-02-03 15:42:23 +05:30
if ( verify ( trim ( tmp ) , "0123456789" ) / = 0 ) then ! found keyword
2018-02-02 19:36:13 +05:30
exit
else
2019-05-15 02:14:38 +05:30
contInts ( 1 ) = contInts ( 1 ) + 1
2018-02-02 19:36:13 +05:30
read ( tmp , * ) contInts ( contInts ( 1 ) + 1 )
endif
enddo
endif
endif
endif
enddo
2019-05-15 02:14:38 +05:30
660 do i = 1 , contInts ( 1 )
cpElem = cpElem + 1
mesh_mapFEtoCPelem ( 1 , cpElem ) = contInts ( 1 + i )
2018-02-02 19:36:13 +05:30
mesh_mapFEtoCPelem ( 2 , cpElem ) = cpElem
enddo
2019-05-15 02:14:38 +05:30
call math_sort ( mesh_mapFEtoCPelem , 1 , int ( size ( mesh_mapFEtoCPelem , 2 ) , pInt ) ) ! should be mesh_NcpElems
2009-01-20 00:12:31 +05:30
2012-06-15 21:40:21 +05:30
end subroutine mesh_marc_map_elements
2009-10-12 21:31:49 +05:30
2012-06-15 21:40:21 +05:30
!--------------------------------------------------------------------------------------------------
!> @brief Maps node from FE ID to internal (consecutive) representation.
!--------------------------------------------------------------------------------------------------
2019-02-03 21:10:15 +05:30
subroutine mesh_marc_map_nodes ( nNodes , fileUnit )
2012-06-15 21:40:21 +05:30
2019-05-10 18:33:54 +05:30
use math , only : math_sort
2012-03-09 01:55:28 +05:30
use IO , only : IO_lc , &
IO_stringValue , &
IO_stringPos , &
2012-06-15 21:40:21 +05:30
IO_fixedIntValue
2018-01-10 21:43:25 +05:30
2019-05-15 02:42:32 +05:30
2019-05-15 02:14:38 +05:30
integer , intent ( in ) :: fileUnit , nNodes
2009-10-12 21:31:49 +05:30
2019-05-15 02:14:38 +05:30
integer , allocatable , dimension ( : ) :: chunkPos
2012-06-15 21:40:21 +05:30
character ( len = 300 ) line
2019-05-15 02:14:38 +05:30
integer , dimension ( nNodes ) :: node_count
integer :: i
2012-06-15 21:40:21 +05:30
2019-05-15 02:14:38 +05:30
node_count = 0
2012-06-15 21:40:21 +05:30
2013-12-11 22:19:20 +05:30
rewind ( fileUnit )
2009-10-12 21:31:49 +05:30
do
2019-02-02 20:47:52 +05:30
read ( fileUnit , '(A300)' , END = 650 ) line
2015-08-28 13:08:48 +05:30
chunkPos = IO_stringPos ( line )
2019-05-15 02:14:38 +05:30
if ( IO_lc ( IO_stringValue ( line , chunkPos , 1 ) ) == 'coordinates' ) then
2019-02-03 15:42:23 +05:30
read ( fileUnit , '(A300)' ) line ! skip crap line
2019-05-15 02:14:38 +05:30
do i = 1 , nNodes
2019-02-02 21:54:00 +05:30
read ( fileUnit , '(A300)' ) line
2019-05-15 02:14:38 +05:30
mesh_mapFEtoCPnode ( 1 , i ) = IO_fixedIntValue ( line , [ 0 , 10 ] , 1 )
mesh_mapFEtoCPnode ( 2 , i ) = i
2012-06-15 21:40:21 +05:30
enddo
exit
2009-10-12 21:31:49 +05:30
endif
enddo
2012-06-15 21:40:21 +05:30
2019-05-15 02:14:38 +05:30
650 call math_sort ( mesh_mapFEtoCPnode , 1 , int ( size ( mesh_mapFEtoCPnode , 2 ) , pInt ) )
2018-01-10 21:43:25 +05:30
2012-06-15 21:40:21 +05:30
end subroutine mesh_marc_map_nodes
2009-10-12 21:31:49 +05:30
2012-06-15 21:40:21 +05:30
!--------------------------------------------------------------------------------------------------
!> @brief store x,y,z coordinates of all nodes in mesh.
!--------------------------------------------------------------------------------------------------
2013-12-11 22:19:20 +05:30
subroutine mesh_marc_build_nodes ( fileUnit )
2009-10-12 21:31:49 +05:30
2019-05-15 02:14:38 +05:30
integer , intent ( in ) :: fileUnit
2009-10-12 21:31:49 +05:30
2019-05-15 02:14:38 +05:30
integer , dimension ( 5 ) , parameter :: node_ends = int ( [ 0 , 10 , 30 , 50 , 70 ] , pInt )
integer , allocatable , dimension ( : ) :: chunkPos
2012-03-09 01:55:28 +05:30
character ( len = 300 ) :: line
2019-05-15 02:14:38 +05:30
integer :: i , j , m
2009-10-12 21:31:49 +05:30
2018-09-23 20:56:13 +05:30
allocate ( mesh_node0 ( 3 , mesh_Nnodes ) , source = 0.0_pReal )
2009-10-12 21:31:49 +05:30
2013-12-11 22:19:20 +05:30
rewind ( fileUnit )
2009-10-12 21:31:49 +05:30
do
2019-02-02 20:47:52 +05:30
read ( fileUnit , '(A300)' , END = 670 ) line
2015-08-28 13:08:48 +05:30
chunkPos = IO_stringPos ( line )
2019-05-15 02:14:38 +05:30
if ( IO_lc ( IO_stringValue ( line , chunkPos , 1 ) ) == 'coordinates' ) then
2019-02-03 15:42:23 +05:30
read ( fileUnit , '(A300)' ) line ! skip crap line
2019-05-15 02:14:38 +05:30
do i = 1 , mesh_Nnodes
2019-02-02 21:54:00 +05:30
read ( fileUnit , '(A300)' ) line
2019-05-15 02:14:38 +05:30
m = mesh_FEasCP ( 'node' , IO_fixedIntValue ( line , node_ends , 1 ) )
do j = 1 , 3
mesh_node0 ( j , m ) = mesh_unitlength * IO_fixedNoEFloatValue ( line , node_ends , j + 1 )
2013-02-07 14:22:47 +05:30
enddo
2012-06-15 21:40:21 +05:30
enddo
exit
2009-10-12 21:31:49 +05:30
endif
enddo
2012-06-15 21:40:21 +05:30
670 mesh_node = mesh_node0
2009-10-12 21:31:49 +05:30
2012-06-15 21:40:21 +05:30
end subroutine mesh_marc_build_nodes
2009-10-12 21:31:49 +05:30
2012-03-09 01:55:28 +05:30
2012-06-15 21:40:21 +05:30
!--------------------------------------------------------------------------------------------------
2013-04-15 13:43:20 +05:30
!> @brief Gets maximum count of nodes, IPs, IP neighbors, and cellnodes among cpElements.
2018-01-10 21:43:25 +05:30
!! Sets global values 'mesh_maxNnodes', 'mesh_maxNips', 'mesh_maxNipNeighbors',
2014-12-15 17:21:32 +05:30
!! and 'mesh_maxNcellnodes'
2012-06-15 21:40:21 +05:30
!--------------------------------------------------------------------------------------------------
2019-05-15 02:14:38 +05:30
integer function mesh_marc_count_cpSizes ( fileUnit )
2018-01-10 21:43:25 +05:30
2019-05-15 02:14:38 +05:30
integer , intent ( in ) :: fileUnit
2018-01-10 21:43:25 +05:30
2019-02-04 23:19:30 +05:30
type ( tElement ) :: tempEl
2019-05-15 02:14:38 +05:30
integer , allocatable , dimension ( : ) :: chunkPos
2012-06-15 21:40:21 +05:30
character ( len = 300 ) :: line
2019-05-15 02:14:38 +05:30
integer :: i , t , g , e , c
2009-10-12 21:31:49 +05:30
2019-05-15 02:14:38 +05:30
t = - 1
2019-02-02 20:47:52 +05:30
2013-12-11 22:19:20 +05:30
rewind ( fileUnit )
2012-06-15 21:40:21 +05:30
do
2019-02-02 20:47:52 +05:30
read ( fileUnit , '(A300)' , END = 630 ) line
2015-08-28 13:08:48 +05:30
chunkPos = IO_stringPos ( line )
2019-05-15 02:14:38 +05:30
if ( IO_lc ( IO_stringValue ( line , chunkPos , 1 ) ) == 'connectivity' ) then
2019-02-03 15:42:23 +05:30
read ( fileUnit , '(A300)' ) line ! Garbage line
2019-05-15 02:14:38 +05:30
do i = 1 , mesh_Nelems ! read all elements
2019-02-02 21:54:00 +05:30
read ( fileUnit , '(A300)' ) line
2018-01-10 21:43:25 +05:30
chunkPos = IO_stringPos ( line ) ! limit to id and type
2019-05-15 02:14:38 +05:30
if ( t == - 1 ) then
t = FE_mapElemtype ( IO_stringValue ( line , chunkPos , 2 ) )
2019-02-04 23:19:30 +05:30
call tempEl % init ( t )
2019-02-03 15:42:23 +05:30
mesh_marc_count_cpSizes = t
2019-02-04 23:19:30 +05:30
else
2019-05-15 02:14:38 +05:30
if ( t / = FE_mapElemtype ( IO_stringValue ( line , chunkPos , 2 ) ) ) call IO_error ( 0 ) !ToDo: error message
2012-06-15 21:40:21 +05:30
endif
2019-05-15 02:14:38 +05:30
call IO_skipChunks ( fileUnit , tempEl % nNodes - ( chunkPos ( 1 ) - 2 ) )
2009-10-12 21:31:49 +05:30
enddo
2012-06-15 21:40:21 +05:30
exit
2009-10-12 21:31:49 +05:30
endif
enddo
2018-01-10 21:43:25 +05:30
2019-02-03 15:42:23 +05:30
630 end function mesh_marc_count_cpSizes
2010-05-06 22:10:47 +05:30
2012-06-15 21:40:21 +05:30
!--------------------------------------------------------------------------------------------------
2014-12-15 17:21:32 +05:30
!> @brief Store FEid, type, mat, tex, and node list per element.
2012-06-15 21:40:21 +05:30
!! Allocates global array 'mesh_element'
!--------------------------------------------------------------------------------------------------
2013-12-11 22:19:20 +05:30
subroutine mesh_marc_build_elements ( fileUnit )
2019-05-15 02:42:32 +05:30
2019-05-15 02:14:38 +05:30
integer , intent ( in ) :: fileUnit
2009-10-12 21:31:49 +05:30
2019-05-15 02:14:38 +05:30
integer , allocatable , dimension ( : ) :: chunkPos
2009-10-12 21:31:49 +05:30
character ( len = 300 ) line
2019-05-15 02:14:38 +05:30
integer , dimension ( 1 + theMesh % nElems ) :: contInts
integer :: i , j , t , sv , myVal , e , nNodesAlreadyRead
2009-10-12 21:31:49 +05:30
2019-05-15 02:14:38 +05:30
allocate ( mesh_element ( 4 + theMesh % elem % nNodes , theMesh % nElems ) , source = 0 )
mesh_elemType = - 1
2009-10-12 21:31:49 +05:30
2013-12-11 22:19:20 +05:30
rewind ( fileUnit )
2009-10-12 21:31:49 +05:30
do
2019-02-02 20:47:52 +05:30
read ( fileUnit , '(A300)' , END = 620 ) line
2015-08-31 22:00:04 +05:30
chunkPos = IO_stringPos ( line )
2019-05-15 02:14:38 +05:30
if ( IO_lc ( IO_stringValue ( line , chunkPos , 1 ) ) == 'connectivity' ) then
2019-02-02 20:47:52 +05:30
read ( fileUnit , '(A300)' , END = 620 ) line ! garbage line
2019-05-15 02:14:38 +05:30
do i = 1 , mesh_Nelems
2019-02-02 20:47:52 +05:30
read ( fileUnit , '(A300)' , END = 620 ) line
2015-08-28 13:08:48 +05:30
chunkPos = IO_stringPos ( line )
2019-05-15 02:14:38 +05:30
e = mesh_FEasCP ( 'elem' , IO_intValue ( line , chunkPos , 1 ) )
if ( e / = 0 ) then ! disregard non CP elems
mesh_element ( 1 , e ) = - 1 ! DEPRECATED
t = FE_mapElemtype ( IO_StringValue ( line , chunkPos , 2 ) ) ! elem type
if ( mesh_elemType / = t . and . mesh_elemType / = - 1 ) &
2018-09-23 18:49:47 +05:30
call IO_error ( 191 , el = t , ip = mesh_elemType )
mesh_elemType = t
2012-11-16 04:15:20 +05:30
mesh_element ( 2 , e ) = t
2019-05-15 02:14:38 +05:30
nNodesAlreadyRead = 0
do j = 1 , chunkPos ( 1 ) - 2
mesh_element ( 4 + j , e ) = mesh_FEasCP ( 'node' , IO_IntValue ( line , chunkPos , j + 2 ) ) ! CP ids of nodes
2018-01-10 21:43:25 +05:30
enddo
2019-05-15 02:14:38 +05:30
nNodesAlreadyRead = chunkPos ( 1 ) - 2
2019-02-03 21:10:15 +05:30
do while ( nNodesAlreadyRead < theMesh % elem % nNodes ) ! read on if not all nodes in one line
2019-02-02 20:47:52 +05:30
read ( fileUnit , '(A300)' , END = 620 ) line
2015-08-28 13:08:48 +05:30
chunkPos = IO_stringPos ( line )
2019-05-15 02:14:38 +05:30
do j = 1 , chunkPos ( 1 )
mesh_element ( 4 + nNodesAlreadyRead + j , e ) &
2015-08-28 13:08:48 +05:30
= mesh_FEasCP ( 'node' , IO_IntValue ( line , chunkPos , j ) ) ! CP ids of nodes
2013-04-15 13:43:20 +05:30
enddo
2015-08-28 13:08:48 +05:30
nNodesAlreadyRead = nNodesAlreadyRead + chunkPos ( 1 )
2013-04-15 13:43:20 +05:30
enddo
2012-06-15 21:40:21 +05:30
endif
2009-10-12 21:31:49 +05:30
enddo
exit
endif
enddo
2015-03-25 21:36:19 +05:30
620 rewind ( fileUnit ) ! just in case "initial state" appears before "connectivity"
2019-06-05 00:46:18 +05:30
call calcCells ( theMesh , mesh_element ( 5 : , : ) )
2019-02-16 14:54:12 +05:30
read ( fileUnit , '(A300)' , END = 630 ) line
do
2015-08-31 22:00:04 +05:30
chunkPos = IO_stringPos ( line )
2019-05-15 02:14:38 +05:30
if ( ( IO_lc ( IO_stringValue ( line , chunkPos , 1 ) ) == 'initial' ) . and . &
( IO_lc ( IO_stringValue ( line , chunkPos , 2 ) ) == 'state' ) ) then
if ( initialcondTableStyle == 2 ) read ( fileUnit , '(A300)' , END = 630 ) line ! read extra line for new style
2019-02-02 20:47:52 +05:30
read ( fileUnit , '(A300)' , END = 630 ) line ! read line with index of state var
2015-08-31 22:00:04 +05:30
chunkPos = IO_stringPos ( line )
2019-05-15 02:14:38 +05:30
sv = IO_IntValue ( line , chunkPos , 1 ) ! figure state variable index
if ( ( sv == 2 ) . or . ( sv == 3 ) ) then ! only state vars 2 and 3 of interest
2019-02-16 14:54:12 +05:30
read ( fileUnit , '(A300)' , END = 630 ) line ! read line with value of state var
2015-08-31 22:00:04 +05:30
chunkPos = IO_stringPos ( line )
2019-05-15 02:14:38 +05:30
do while ( scan ( IO_stringValue ( line , chunkPos , 1 ) , '+-' , back = . true . ) > 1 ) ! is noEfloat value?
myVal = nint ( IO_fixedNoEFloatValue ( line , [ 0 , 20 ] , 1 ) , pInt ) ! state var's value
if ( initialcondTableStyle == 2 ) then
2019-02-02 20:47:52 +05:30
read ( fileUnit , '(A300)' , END = 630 ) line ! read extra line
read ( fileUnit , '(A300)' , END = 630 ) line ! read extra line
2012-06-15 21:40:21 +05:30
endif
2015-03-25 21:36:19 +05:30
contInts = IO_continuousIntValues & ! get affected elements
2019-02-03 21:10:15 +05:30
( fileUnit , theMesh % nElems , mesh_nameElemSet , mesh_mapElemSet , mesh_NelemSets )
2019-05-15 02:14:38 +05:30
do i = 1 , contInts ( 1 )
e = mesh_FEasCP ( 'elem' , contInts ( 1 + i ) )
mesh_element ( 1 + sv , e ) = myVal
2012-06-15 21:40:21 +05:30
enddo
2019-05-15 02:14:38 +05:30
if ( initialcondTableStyle == 0 ) read ( fileUnit , '(A300)' , END = 630 ) line ! ignore IP range for old table style
2019-02-02 21:54:00 +05:30
read ( fileUnit , '(A300)' , END = 630 ) line
chunkPos = IO_stringPos ( line )
enddo
endif
else
read ( fileUnit , '(A300)' , END = 630 ) line
endif
enddo
630 end subroutine mesh_marc_build_elements
2019-05-17 16:52:52 +05:30
subroutine calcCells ( thisMesh , connectivity_elem )
class ( tMesh ) :: thisMesh
integer ( pInt ) , dimension ( : , : ) , intent ( inout ) :: connectivity_elem
integer ( pInt ) , dimension ( : , : ) , allocatable :: con_elem , temp , con , parentsAndWeights , candidates_global
integer ( pInt ) , dimension ( : ) , allocatable :: l , nodes , candidates_local
integer ( pInt ) , dimension ( : , : , : ) , allocatable :: con_cell , connectivity_cell
2019-06-05 00:46:18 +05:30
integer ( pInt ) , dimension ( : , : ) , allocatable :: sorted , test , connectivity_cell_reshape
2019-05-17 16:52:52 +05:30
real ( pReal ) , dimension ( : , : ) , allocatable :: coordinates , nodes5
integer ( pInt ) :: e , n , c , p , s , u , i , m , j , nParentNodes , nCellNode , ierr
2019-06-05 00:46:18 +05:30
#if defined(DAMASK_HDF5)
call results_openJobFile
call HDF5_closeGroup ( results_addGroup ( 'geometry' ) )
call results_writeDataset ( 'geometry' , connectivity_elem , 'connectivity_element' , &
'connectivity of the elements' , '-' )
#endif
2019-05-17 16:52:52 +05:30
!---------------------------------------------------------------------------------------------------
! initialize global connectivity to negative local connectivity
allocate ( connectivity_cell ( thisMesh % elem % NcellNodesPerCell , thisMesh % elem % nIPs , thisMesh % Nelems ) )
connectivity_cell = - spread ( thisMesh % elem % cell , 3 , thisMesh % Nelems ) ! local cell node ID
!---------------------------------------------------------------------------------------------------
! set connectivity of cell nodes that conincide with FE nodes (defined by 1 parent node)
! change to global node ID
do e = 1 , thisMesh % Nelems
do c = 1 , thisMesh % elem % NcellNodes
realNode : if ( count ( thisMesh % elem % cellNodeParentNodeWeights ( : , c ) / = 0_pInt ) == 1_pInt ) then
where ( connectivity_cell ( : , : , e ) == - c )
connectivity_cell ( : , : , e ) = connectivity_elem ( c , e )
end where
endif realNode
enddo
enddo
nCellNode = thisMesh % nNodes
do nParentNodes = 2 , thisMesh % elem % nNodes
! get IDs of local cell nodes that are defined by the current number of parent nodes
candidates_local = [ integer ( pInt ) :: ]
do c = 1 , thisMesh % elem % NcellNodes
if ( count ( thisMesh % elem % cellNodeParentNodeWeights ( : , c ) / = 0_pInt ) == nParentNodes ) &
candidates_local = [ candidates_local , c ]
enddo
s = size ( candidates_local )
if ( allocated ( candidates_global ) ) deallocate ( candidates_global )
allocate ( candidates_global ( nParentNodes * 2_pInt + 2_pInt , s * thisMesh % Nelems ) )
parentsAndWeights = reshape ( [ ( 0_pInt , i = 1_pInt , 2_pInt * nParentNodes ) ] , [ nParentNodes , 2 ] )
do e = 1_pInt , thisMesh % Nelems
do i = 1_pInt , s
c = candidates_local ( i )
m = 0_pInt
do p = 1_pInt , size ( thisMesh % elem % cellNodeParentNodeWeights ( : , c ) )
if ( thisMesh % elem % cellNodeParentNodeWeights ( p , c ) / = 0_pInt ) then ! real node 'c' partly defines cell node 'n'
m = m + 1_pInt
parentsAndWeights ( m , 1 : 2 ) = [ connectivity_elem ( p , e ) , thisMesh % elem % cellNodeParentNodeWeights ( p , c ) ]
endif
enddo
! store (and order) real nodes and their weights together with the element number and local ID
do p = 1_pInt , nParentNodes
m = maxloc ( parentsAndWeights ( : , 1 ) , 1 )
candidates_global ( p , ( e - 1 ) * s + i ) = parentsAndWeights ( m , 1 )
parentsAndWeights ( m , 1 ) = - huge ( i ) ! out of the competition
candidates_global ( p + nParentNodes , ( e - 1 ) * s + i ) = parentsAndWeights ( m , 2 )
candidates_global ( nParentNodes * 2 + 1 : nParentNodes * 2 + 2 , ( e - 1 ) * s + i ) = [ e , c ]
enddo
enddo
enddo
! sort according to real node IDs (from left to right)
call math_sort ( candidates_global , sortDim = 1 )
do p = 2 , nParentNodes - 1
n = 1
do while ( n < = s * thisMesh % Nelems )
j = 0
do while ( n + j < = s * thisMesh % Nelems )
if ( candidates_global ( p - 1 , n + j ) / = candidates_global ( p - 1 , n ) ) exit
j = j + 1
enddo
e = n + j - 1
if ( any ( candidates_global ( p , n : e ) / = candidates_global ( p , n ) ) ) then
call math_sort ( candidates_global ( : , n : e ) , sortDim = p )
endif
n = e + 1
enddo
enddo
! find duplicates (trivial for sorted IDs)
i = 0
n = 1
do while ( n < = s * thisMesh % Nelems )
j = 0
do while ( n + j < = s * thisMesh % Nelems )
if ( any ( candidates_global ( 1 : 2 * nParentNodes , n + j ) / = candidates_global ( 1 : 2 * nParentNodes , n ) ) ) exit
j = j + 1
enddo
i = i + 1
n = n + j
enddo
p = i ! ToDo: Hack
! calculate coordinates of cell nodes and insert their ID into the cell conectivity
coordinates = reshape ( [ ( 0.0_pReal , i = 1 , 3 * s * thisMesh % Nelems ) ] , [ 3 , i ] )
i = 0
n = 1
do while ( n < = s * thisMesh % Nelems )
j = 0
parentsAndWeights ( : , 1 ) = candidates_global ( 1 : nParentNodes , n + j )
parentsAndWeights ( : , 2 ) = candidates_global ( nParentNodes + 1 : nParentNodes * 2 , n + j )
e = candidates_global ( nParentNodes * 2 + 1 , n + j )
c = candidates_global ( nParentNodes * 2 + 2 , n + j )
do m = 1 , nParentNodes
coordinates ( : , i + 1 ) = coordinates ( : , i + 1 ) &
+ thisMesh % node_0 ( : , parentsAndWeights ( m , 1 ) ) * real ( parentsAndWeights ( m , 2 ) , pReal )
enddo
coordinates ( : , i + 1 ) = coordinates ( : , i + 1 ) / real ( sum ( parentsAndWeights ( : , 2 ) ) , pReal )
do while ( n + j < = s * thisMesh % Nelems )
if ( any ( candidates_global ( 1 : 2 * nParentNodes , n + j ) / = candidates_global ( 1 : 2 * nParentNodes , n ) ) ) exit
where ( connectivity_cell ( : , : , candidates_global ( nParentNodes * 2 + 1 , n + j ) ) == - candidates_global ( nParentNodes * 2 + 2 , n + j ) )
connectivity_cell ( : , : , candidates_global ( nParentNodes * 2 + 1 , n + j ) ) = i + 1 + nCellNode
end where
j = j + 1
enddo
i = i + 1
n = n + j
enddo
nCellNode = nCellNode + p
if ( p / = 0 ) nodes5 = reshape ( [ nodes5 , coordinates ] , [ 3 , nCellNode ] )
enddo
thisMesh % node_0 = nodes5
2019-06-05 01:32:54 +05:30
mesh_cell2 = connectivity_cell
2019-06-05 00:46:18 +05:30
connectivity_cell_reshape = reshape ( connectivity_cell , [ thisMesh % elem % NcellNodesPerCell , thisMesh % elem % nIPs * thisMesh % Nelems ] )
#if defined(DAMASK_HDF5)
call results_writeDataset ( 'geometry' , connectivity_cell_reshape , 'connectivity_cell' , &
'connectivity of the cells' , '-' )
call results_closeJobFile
#endif
2019-05-17 16:52:52 +05:30
end subroutine calcCells
2019-02-02 21:54:00 +05:30
!--------------------------------------------------------------------------------------------------
!> @brief Split CP elements into cells.
!> @details Build a mapping between cells and the corresponding cell nodes ('mesh_cell').
!> Cell nodes that are also matching nodes are unique in the list of cell nodes,
!> all others (currently) might be stored more than once.
!> Also allocates the 'mesh_node' array.
!--------------------------------------------------------------------------------------------------
subroutine mesh_build_cellconnectivity
2019-05-15 02:14:38 +05:30
integer , dimension ( : ) , allocatable :: &
2019-02-02 21:54:00 +05:30
matchingNode2cellnode
2019-05-15 02:14:38 +05:30
integer , dimension ( : , : ) , allocatable :: &
2019-02-02 21:54:00 +05:30
cellnodeParent
2019-05-15 02:14:38 +05:30
integer , dimension ( theMesh % elem % Ncellnodes ) :: &
2019-02-02 21:54:00 +05:30
localCellnode2globalCellnode
2019-05-15 02:14:38 +05:30
integer :: &
2019-02-03 01:15:19 +05:30
e , n , i , &
2019-02-02 21:54:00 +05:30
matchingNodeID , &
localCellnodeID
2019-05-15 02:14:38 +05:30
allocate ( mesh_cell ( FE_maxNcellnodesPerCell , theMesh % elem % nIPs , theMesh % nElems ) , source = 0 )
allocate ( matchingNode2cellnode ( theMesh % nNodes ) , source = 0 )
allocate ( cellnodeParent ( 2 , theMesh % elem % Ncellnodes * theMesh % nElems ) , source = 0 )
2019-02-03 01:15:19 +05:30
mesh_Ncells = theMesh % nElems * theMesh % elem % nIPs
2019-02-02 21:54:00 +05:30
!--------------------------------------------------------------------------------------------------
! Count cell nodes (including duplicates) and generate cell connectivity list
2019-05-15 02:14:38 +05:30
mesh_Ncellnodes = 0
2019-02-03 01:15:19 +05:30
2019-05-15 02:14:38 +05:30
do e = 1 , theMesh % nElems
localCellnode2globalCellnode = 0
do i = 1 , theMesh % elem % nIPs
do n = 1 , theMesh % elem % NcellnodesPerCell
2019-02-03 01:15:19 +05:30
localCellnodeID = theMesh % elem % cell ( n , i )
if ( localCellnodeID < = FE_NmatchingNodes ( theMesh % elem % geomType ) ) then ! this cell node is a matching node
2019-05-15 02:14:38 +05:30
matchingNodeID = mesh_element ( 4 + localCellnodeID , e )
if ( matchingNode2cellnode ( matchingNodeID ) == 0 ) then ! if this matching node does not yet exist in the glbal cell node list ...
mesh_Ncellnodes = mesh_Ncellnodes + 1 ! ... count it as cell node ...
2019-02-02 21:54:00 +05:30
matchingNode2cellnode ( matchingNodeID ) = mesh_Ncellnodes ! ... and remember its global ID
2019-05-15 02:14:38 +05:30
cellnodeParent ( 1 , mesh_Ncellnodes ) = e ! ... and where it belongs to
cellnodeParent ( 2 , mesh_Ncellnodes ) = localCellnodeID
2019-02-02 21:54:00 +05:30
endif
mesh_cell ( n , i , e ) = matchingNode2cellnode ( matchingNodeID )
else ! this cell node is no matching node
2019-05-15 02:14:38 +05:30
if ( localCellnode2globalCellnode ( localCellnodeID ) == 0 ) then ! if this local cell node does not yet exist in the global cell node list ...
mesh_Ncellnodes = mesh_Ncellnodes + 1 ! ... count it as cell node ...
2019-02-02 21:54:00 +05:30
localCellnode2globalCellnode ( localCellnodeID ) = mesh_Ncellnodes ! ... and remember its global ID ...
2019-05-15 02:14:38 +05:30
cellnodeParent ( 1 , mesh_Ncellnodes ) = e ! ... and it belongs to
cellnodeParent ( 2 , mesh_Ncellnodes ) = localCellnodeID
2019-02-02 21:54:00 +05:30
endif
mesh_cell ( n , i , e ) = localCellnode2globalCellnode ( localCellnodeID )
endif
enddo
enddo
enddo
2019-05-15 02:14:38 +05:30
allocate ( mesh_cellnodeParent ( 2 , mesh_Ncellnodes ) )
allocate ( mesh_cellnode ( 3 , mesh_Ncellnodes ) )
2019-02-03 01:15:19 +05:30
2019-05-15 02:14:38 +05:30
forall ( n = 1 : mesh_Ncellnodes )
2019-02-02 21:54:00 +05:30
mesh_cellnodeParent ( 1 , n ) = cellnodeParent ( 1 , n )
mesh_cellnodeParent ( 2 , n ) = cellnodeParent ( 2 , n )
endforall
end subroutine mesh_build_cellconnectivity
!--------------------------------------------------------------------------------------------------
!> @brief Calculate position of cellnodes from the given position of nodes
!> Build list of cellnodes' coordinates.
!> Cellnode coordinates are calculated from a weighted sum of node coordinates.
!--------------------------------------------------------------------------------------------------
2019-05-19 02:40:40 +05:30
function mesh_build_cellnodes ( )
2019-02-02 21:54:00 +05:30
2019-05-15 02:42:32 +05:30
2019-05-19 02:40:40 +05:30
real ( pReal ) , dimension ( 3 , mesh_Ncellnodes ) :: mesh_build_cellnodes
2019-02-02 21:54:00 +05:30
2019-05-15 02:14:38 +05:30
integer :: &
2019-02-03 01:15:19 +05:30
e , n , m , &
2019-02-02 21:54:00 +05:30
localCellnodeID
real ( pReal ) , dimension ( 3 ) :: &
myCoords
mesh_build_cellnodes = 0.0_pReal
2019-02-03 01:15:19 +05:30
!$OMP PARALLEL DO PRIVATE(e,localCellnodeID,myCoords)
2019-05-19 02:40:40 +05:30
do n = 1 , mesh_Ncellnodes ! loop over cell nodes
2019-02-02 21:54:00 +05:30
e = mesh_cellnodeParent ( 1 , n )
localCellnodeID = mesh_cellnodeParent ( 2 , n )
myCoords = 0.0_pReal
2019-05-15 02:14:38 +05:30
do m = 1 , theMesh % elem % nNodes
2019-05-19 02:40:40 +05:30
myCoords = myCoords + mesh_node ( 1 : 3 , mesh_element ( 4 + m , e ) ) &
2019-02-03 01:15:19 +05:30
* theMesh % elem % cellNodeParentNodeWeights ( m , localCellnodeID )
2019-02-02 21:54:00 +05:30
enddo
2019-02-03 01:15:19 +05:30
mesh_build_cellnodes ( 1 : 3 , n ) = myCoords / sum ( theMesh % elem % cellNodeParentNodeWeights ( : , localCellnodeID ) )
2019-02-02 21:54:00 +05:30
enddo
!$OMP END PARALLEL DO
end function mesh_build_cellnodes
!--------------------------------------------------------------------------------------------------
!> @brief Calculates IP volume. Allocates global array 'mesh_ipVolume'
!> @details The IP volume is calculated differently depending on the cell type.
!> 2D cells assume an element depth of one in order to calculate the volume.
!> For the hexahedral cell we subdivide the cell into subvolumes of pyramidal
!> shape with a cell face as basis and the central ip at the tip. This subvolume is
!> calculated as an average of four tetrahedals with three corners on the cell face
!> and one corner at the central ip.
!--------------------------------------------------------------------------------------------------
subroutine mesh_build_ipVolumes
2019-05-15 02:42:32 +05:30
2019-06-05 11:52:34 +05:30
integer :: e , i , c , m , f , n
real ( pReal ) , dimension ( FE_maxNcellnodesPerCellface , FE_maxNcellfaces ) :: subvolume
2019-02-02 21:54:00 +05:30
2019-02-03 21:10:15 +05:30
allocate ( mesh_ipVolume ( theMesh % elem % nIPs , theMesh % nElems ) , source = 0.0_pReal )
2019-06-05 11:52:34 +05:30
c = theMesh % elem % cellType
m = FE_NcellnodesPerCellface ( c )
2019-02-02 21:54:00 +05:30
2019-06-05 11:52:34 +05:30
!$OMP PARALLEL DO PRIVATE(f,n,subvolume)
do e = 1 , theMesh % nElems
2019-02-02 21:54:00 +05:30
select case ( c )
2019-05-15 02:14:38 +05:30
case ( 1 ) ! 2D 3node
forall ( i = 1 : theMesh % elem % nIPs ) & ! loop over ips=cells in this element
2019-06-05 01:32:54 +05:30
mesh_ipVolume ( i , e ) = math_areaTriangle ( theMesh % node_0 ( 1 : 3 , mesh_cell2 ( 1 , i , e ) ) , &
theMesh % node_0 ( 1 : 3 , mesh_cell2 ( 2 , i , e ) ) , &
theMesh % node_0 ( 1 : 3 , mesh_cell2 ( 3 , i , e ) ) )
2019-02-02 21:54:00 +05:30
2019-05-15 02:14:38 +05:30
case ( 2 ) ! 2D 4node
forall ( i = 1 : theMesh % elem % nIPs ) & ! loop over ips=cells in this element
2019-06-05 01:32:54 +05:30
mesh_ipVolume ( i , e ) = math_areaTriangle ( theMesh % node_0 ( 1 : 3 , mesh_cell2 ( 1 , i , e ) ) , & ! here we assume a planar shape, so division in two triangles suffices
theMesh % node_0 ( 1 : 3 , mesh_cell2 ( 2 , i , e ) ) , &
theMesh % node_0 ( 1 : 3 , mesh_cell2 ( 3 , i , e ) ) ) &
+ math_areaTriangle ( theMesh % node_0 ( 1 : 3 , mesh_cell2 ( 3 , i , e ) ) , &
theMesh % node_0 ( 1 : 3 , mesh_cell2 ( 4 , i , e ) ) , &
theMesh % node_0 ( 1 : 3 , mesh_cell2 ( 1 , i , e ) ) )
2019-02-02 21:54:00 +05:30
2019-05-15 02:14:38 +05:30
case ( 3 ) ! 3D 4node
forall ( i = 1 : theMesh % elem % nIPs ) & ! loop over ips=cells in this element
2019-06-05 01:32:54 +05:30
mesh_ipVolume ( i , e ) = math_volTetrahedron ( theMesh % node_0 ( 1 : 3 , mesh_cell2 ( 1 , i , e ) ) , &
theMesh % node_0 ( 1 : 3 , mesh_cell2 ( 2 , i , e ) ) , &
theMesh % node_0 ( 1 : 3 , mesh_cell2 ( 3 , i , e ) ) , &
theMesh % node_0 ( 1 : 3 , mesh_cell2 ( 4 , i , e ) ) )
2019-02-02 21:54:00 +05:30
2019-05-15 02:14:38 +05:30
case ( 4 ) ! 3D 8node
do i = 1 , theMesh % elem % nIPs ! loop over ips=cells in this element
2019-02-02 21:54:00 +05:30
subvolume = 0.0_pReal
2019-06-05 11:52:34 +05:30
forall ( f = 1 : FE_NipNeighbors ( c ) , n = 1 : m ) &
2019-02-02 21:54:00 +05:30
subvolume ( n , f ) = math_volTetrahedron ( &
mesh_cellnode ( 1 : 3 , mesh_cell ( FE_cellface ( n , f , c ) , i , e ) ) , &
mesh_cellnode ( 1 : 3 , mesh_cell ( FE_cellface ( 1 + mod ( n , m ) , f , c ) , i , e ) ) , &
mesh_cellnode ( 1 : 3 , mesh_cell ( FE_cellface ( 1 + mod ( n + 1 , m ) , f , c ) , i , e ) ) , &
mesh_ipCoordinates ( 1 : 3 , i , e ) )
mesh_ipVolume ( i , e ) = 0.5_pReal * sum ( subvolume ) ! each subvolume is based on four tetrahedrons, altough the face consists of only two triangles -> averaging factor two
enddo
2009-10-12 21:31:49 +05:30
2019-02-02 21:54:00 +05:30
end select
enddo
!$OMP END PARALLEL DO
end subroutine mesh_build_ipVolumes
2009-10-12 21:31:49 +05:30
2019-01-24 14:34:43 +05:30
2019-06-05 04:06:25 +05:30
subroutine IP_neighborhood2
2019-06-05 11:52:34 +05:30
integer , dimension ( : , : , : , : , : , : ) , allocatable :: faces
2019-06-05 16:27:08 +05:30
integer , dimension ( : ) , allocatable :: cellnodes
integer :: e , i , f , c , m , n , j , k , l
2019-06-05 11:52:34 +05:30
allocate ( faces ( size ( theMesh % elem % cellface , 1 ) , size ( theMesh % elem % cellface , 2 ) , theMesh % elem % nIPs , theMesh % Nelems , 1 , 1 ) )
2019-06-05 16:27:08 +05:30
print * , 'faces' , shape ( faces )
print * , 'cell2' , shape ( mesh_cell2 )
2019-06-05 11:52:34 +05:30
!allocate(connectivity_cell(thisMesh%elem%NcellNodesPerCell,thisMesh%elem%nIPs,thisMesh%Nelems))
2019-06-05 16:27:08 +05:30
allocate ( cellnodes ( theMesh % elem % NcellnodesPerCell ) )
2019-06-05 04:06:25 +05:30
2019-06-05 11:52:34 +05:30
c = theMesh % elem % cellType
m = FE_NcellnodesPerCellface ( c )
n = FE_NipNeighbors ( c )
f = size ( theMesh % elem % cellface , 2 )
2019-06-05 16:27:08 +05:30
do i = 1 , theMesh % elem % nIPs
do n = 1 , theMesh % elem % nIPneighbors
write ( 6 , * ) theMesh % elem % cell ( theMesh % elem % cellFace ( : , n ) , i )
write ( 6 , * ) ''
enddo
enddo
2019-06-05 11:52:34 +05:30
do e = 1 , theMesh % nElems
do i = 1 , theMesh % elem % nIPs
2019-06-05 16:27:08 +05:30
!print*, 'e',e,'i',i
!print*, mesh_cell2(:,i,e)
!print*, ''
!do n = 1, FE_NipNeighbors(c)
! print*, theMesh%elem%cell(:,n)
!enddo
2019-06-05 11:52:34 +05:30
enddo
enddo
2019-06-05 04:06:25 +05:30
end subroutine IP_neighborhood2
2012-06-15 21:40:21 +05:30
!--------------------------------------------------------------------------------------------------
2019-02-02 21:54:00 +05:30
!> @brief Calculates IP Coordinates. Allocates global array 'mesh_ipCoordinates'
! Called by all solvers in mesh_init in order to initialize the ip coordinates.
! Later on the current ip coordinates are directly prvided by the spectral solver and by Abaqus,
! so no need to use this subroutine anymore; Marc however only provides nodal displacements,
! so in this case the ip coordinates are always calculated on the basis of this subroutine.
! !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
! FOR THE MOMENT THIS SUBROUTINE ACTUALLY CALCULATES THE CELL CENTER AND NOT THE IP COORDINATES,
! AS THE IP IS NOT (ALWAYS) LOCATED IN THE CENTER OF THE IP VOLUME.
! HAS TO BE CHANGED IN A LATER VERSION.
! !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
2012-06-15 21:40:21 +05:30
!--------------------------------------------------------------------------------------------------
2019-02-02 21:54:00 +05:30
subroutine mesh_build_ipCoordinates
2018-01-10 21:43:25 +05:30
2019-06-05 04:06:25 +05:30
integer :: e , i , n
real ( pReal ) , dimension ( 3 ) :: myCoords
2018-01-10 21:43:25 +05:30
2019-06-05 04:06:25 +05:30
!$OMP PARALLEL DO PRIVATE(myCoords)
2019-06-05 11:52:34 +05:30
do e = 1 , theMesh % nElems
2019-06-05 04:06:25 +05:30
do i = 1 , theMesh % elem % nIPs
myCoords = 0.0_pReal
do n = 1 , theMesh % elem % nCellnodesPerCell
myCoords = myCoords + mesh_cellnode ( 1 : 3 , mesh_cell2 ( n , i , e ) )
enddo
mesh_ipCoordinates ( 1 : 3 , i , e ) = myCoords / real ( theMesh % elem % nCellnodesPerCell , pReal )
enddo
enddo
!$OMP END PARALLEL DO
2018-01-10 21:43:25 +05:30
2019-02-02 21:54:00 +05:30
end subroutine mesh_build_ipCoordinates
2009-10-12 21:31:49 +05:30
2019-02-02 21:54:00 +05:30
2013-04-18 22:10:49 +05:30
!--------------------------------------------------------------------------------------------------
2019-01-24 14:34:43 +05:30
!> @brief calculation of IP interface areas, allocate globals '_ipArea', and '_ipAreaNormal'
2013-04-18 22:10:49 +05:30
!--------------------------------------------------------------------------------------------------
2019-01-24 14:34:43 +05:30
subroutine mesh_build_ipAreas
2010-05-06 22:10:47 +05:30
2019-05-15 02:14:38 +05:30
integer :: e , t , g , c , i , f , n , m
2019-01-24 14:34:43 +05:30
real ( pReal ) , dimension ( 3 , FE_maxNcellnodesPerCellface ) :: nodePos , normals
real ( pReal ) , dimension ( 3 ) :: normal
2010-05-06 22:10:47 +05:30
2019-02-03 21:10:15 +05:30
allocate ( mesh_ipArea ( theMesh % elem % nIPneighbors , theMesh % elem % nIPs , theMesh % nElems ) , source = 0.0_pReal )
2019-05-15 02:14:38 +05:30
allocate ( mesh_ipAreaNormal ( 3 , theMesh % elem % nIPneighbors , theMesh % elem % nIPs , theMesh % nElems ) , source = 0.0_pReal )
2013-04-15 13:43:20 +05:30
!$OMP PARALLEL DO PRIVATE(t,g,c,nodePos,normal,normals)
2019-05-15 02:14:38 +05:30
do e = 1 , theMesh % nElems ! loop over cpElems
t = mesh_element ( 2 , e ) ! get element type
2019-02-03 21:10:15 +05:30
g = theMesh % elem % geomType
c = theMesh % elem % cellType
2013-04-15 13:43:20 +05:30
select case ( c )
2019-05-15 02:14:38 +05:30
case ( 1 , 2 ) ! 2D 3 or 4 node
do i = 1 , theMesh % elem % nIPs
do f = 1 , FE_NipNeighbors ( c ) ! loop over cell faces
forall ( n = 1 : FE_NcellnodesPerCellface ( c ) ) &
2013-04-22 00:18:59 +05:30
nodePos ( 1 : 3 , n ) = mesh_cellnode ( 1 : 3 , mesh_cell ( FE_cellface ( n , f , c ) , i , e ) )
2013-04-15 13:43:20 +05:30
normal ( 1 ) = nodePos ( 2 , 2 ) - nodePos ( 2 , 1 ) ! x_normal = y_connectingVector
normal ( 2 ) = - ( nodePos ( 1 , 2 ) - nodePos ( 1 , 1 ) ) ! y_normal = -x_connectingVector
normal ( 3 ) = 0.0_pReal
2016-01-10 19:04:26 +05:30
mesh_ipArea ( f , i , e ) = norm2 ( normal )
mesh_ipAreaNormal ( 1 : 3 , f , i , e ) = normal / norm2 ( normal ) ! ensure unit length of area normal
2013-04-15 13:43:20 +05:30
enddo
2013-04-09 23:37:30 +05:30
enddo
2013-04-15 13:43:20 +05:30
2019-05-15 02:14:38 +05:30
case ( 3 ) ! 3D 4node
do i = 1 , theMesh % elem % nIPs
do f = 1 , FE_NipNeighbors ( c ) ! loop over cell faces
forall ( n = 1 : FE_NcellnodesPerCellface ( c ) ) &
2013-04-22 00:18:59 +05:30
nodePos ( 1 : 3 , n ) = mesh_cellnode ( 1 : 3 , mesh_cell ( FE_cellface ( n , f , c ) , i , e ) )
2019-05-10 18:49:00 +05:30
normal = math_cross ( nodePos ( 1 : 3 , 2 ) - nodePos ( 1 : 3 , 1 ) , &
2013-04-15 13:43:20 +05:30
nodePos ( 1 : 3 , 3 ) - nodePos ( 1 : 3 , 1 ) )
2016-01-10 19:04:26 +05:30
mesh_ipArea ( f , i , e ) = norm2 ( normal )
mesh_ipAreaNormal ( 1 : 3 , f , i , e ) = normal / norm2 ( normal ) ! ensure unit length of area normal
2013-04-15 13:43:20 +05:30
enddo
2013-04-09 23:37:30 +05:30
enddo
2013-02-05 18:57:37 +05:30
2019-05-15 02:14:38 +05:30
case ( 4 ) ! 3D 8node
2018-01-10 21:43:25 +05:30
! for this cell type we get the normal of the quadrilateral face as an average of
2013-04-15 13:43:20 +05:30
! four normals of triangular subfaces; since the face consists only of two triangles,
2018-01-10 21:43:25 +05:30
! the sum has to be divided by two; this whole prcedure tries to compensate for
! probable non-planar cell surfaces
2013-04-15 13:43:20 +05:30
m = FE_NcellnodesPerCellface ( c )
2019-05-15 02:14:38 +05:30
do i = 1 , theMesh % elem % nIPs
do f = 1 , FE_NipNeighbors ( c ) ! loop over cell faces
forall ( n = 1 : FE_NcellnodesPerCellface ( c ) ) &
2013-04-22 00:18:59 +05:30
nodePos ( 1 : 3 , n ) = mesh_cellnode ( 1 : 3 , mesh_cell ( FE_cellface ( n , f , c ) , i , e ) )
2019-05-15 02:14:38 +05:30
forall ( n = 1 : FE_NcellnodesPerCellface ( c ) ) &
2013-04-15 13:43:20 +05:30
normals ( 1 : 3 , n ) = 0.5_pReal &
2019-05-10 18:49:00 +05:30
* math_cross ( nodePos ( 1 : 3 , 1 + mod ( n , m ) ) - nodePos ( 1 : 3 , n ) , &
2013-04-15 13:43:20 +05:30
nodePos ( 1 : 3 , 1 + mod ( n + 1 , m ) ) - nodePos ( 1 : 3 , n ) )
normal = 0.5_pReal * sum ( normals , 2 )
2016-01-10 19:04:26 +05:30
mesh_ipArea ( f , i , e ) = norm2 ( normal )
mesh_ipAreaNormal ( 1 : 3 , f , i , e ) = normal / norm2 ( normal )
2013-04-15 13:43:20 +05:30
enddo
enddo
end select
enddo
!$OMP END PARALLEL DO
2018-01-10 21:43:25 +05:30
2015-04-11 17:17:33 +05:30
end subroutine mesh_build_ipAreas
2018-01-10 21:43:25 +05:30
2019-01-24 14:34:43 +05:30
2013-04-18 22:10:49 +05:30
!--------------------------------------------------------------------------------------------------
!> @brief assignment of twin nodes for each cp node, allocate globals '_nodeTwins'
!--------------------------------------------------------------------------------------------------
2012-06-15 21:40:21 +05:30
subroutine mesh_build_nodeTwins
2019-05-15 02:42:32 +05:30
2019-05-15 02:14:38 +05:30
integer dir , & ! direction of periodicity
2013-04-19 18:11:06 +05:30
node , &
minimumNode , &
maximumNode , &
n1 , &
n2
2019-05-15 02:14:38 +05:30
integer , dimension ( mesh_Nnodes + 1 ) :: minimumNodes , maximumNodes ! list of surface nodes (minimum and maximum coordinate value) with first entry giving the number of nodes
2015-03-25 21:36:19 +05:30
real ( pReal ) minCoord , maxCoord , & ! extreme positions in one dimension
tolerance ! tolerance below which positions are assumed identical
real ( pReal ) , dimension ( 3 ) :: distance ! distance between two nodes in all three coordinates
2013-04-19 18:11:06 +05:30
logical , dimension ( mesh_Nnodes ) :: unpaired
2018-01-10 21:43:25 +05:30
2013-04-19 18:11:06 +05:30
allocate ( mesh_nodeTwins ( 3 , mesh_Nnodes ) )
2019-05-15 02:14:38 +05:30
mesh_nodeTwins = 0
2018-01-10 21:43:25 +05:30
2013-04-19 18:11:06 +05:30
tolerance = 0.001_pReal * minval ( mesh_ipVolume ) ** 0.333_pReal
2018-01-10 21:43:25 +05:30
2019-05-15 02:14:38 +05:30
do dir = 1 , 3 ! check periodicity in directions of x,y,z
2015-03-25 21:36:19 +05:30
if ( mesh_periodicSurface ( dir ) ) then ! only if periodicity is requested
2018-01-10 21:43:25 +05:30
!*** find out which nodes sit on the surface
2013-04-19 18:11:06 +05:30
!*** and have a minimum or maximum position in this dimension
2018-01-10 21:43:25 +05:30
2019-05-15 02:14:38 +05:30
minimumNodes = 0
maximumNodes = 0
2013-04-19 18:11:06 +05:30
minCoord = minval ( mesh_node0 ( dir , : ) )
maxCoord = maxval ( mesh_node0 ( dir , : ) )
2019-05-15 02:14:38 +05:30
do node = 1 , mesh_Nnodes ! loop through all nodes and find surface nodes
2013-04-19 18:11:06 +05:30
if ( abs ( mesh_node0 ( dir , node ) - minCoord ) < = tolerance ) then
2019-05-15 02:14:38 +05:30
minimumNodes ( 1 ) = minimumNodes ( 1 ) + 1
minimumNodes ( minimumNodes ( 1 ) + 1 ) = node
2013-04-19 18:11:06 +05:30
elseif ( abs ( mesh_node0 ( dir , node ) - maxCoord ) < = tolerance ) then
2019-05-15 02:14:38 +05:30
maximumNodes ( 1 ) = maximumNodes ( 1 ) + 1
maximumNodes ( maximumNodes ( 1 ) + 1 ) = node
2013-04-19 18:11:06 +05:30
endif
enddo
2018-01-10 21:43:25 +05:30
2013-04-19 18:11:06 +05:30
!*** find the corresponding node on the other side with the same position in this dimension
2018-01-10 21:43:25 +05:30
2013-04-19 18:11:06 +05:30
unpaired = . true .
2019-05-15 02:14:38 +05:30
do n1 = 1 , minimumNodes ( 1 )
minimumNode = minimumNodes ( n1 + 1 )
2013-04-19 18:11:06 +05:30
if ( unpaired ( minimumNode ) ) then
2019-05-15 02:14:38 +05:30
do n2 = 1 , maximumNodes ( 1 )
maximumNode = maximumNodes ( n2 + 1 )
2013-04-19 18:11:06 +05:30
distance = abs ( mesh_node0 ( : , minimumNode ) - mesh_node0 ( : , maximumNode ) )
2015-03-25 21:36:19 +05:30
if ( sum ( distance ) - distance ( dir ) < = tolerance ) then ! minimum possible distance (within tolerance)
2013-04-19 18:11:06 +05:30
mesh_nodeTwins ( dir , minimumNode ) = maximumNode
mesh_nodeTwins ( dir , maximumNode ) = minimumNode
2015-03-25 21:36:19 +05:30
unpaired ( maximumNode ) = . false . ! remember this node, we don't have to look for his partner again
2013-04-19 18:11:06 +05:30
exit
endif
enddo
endif
enddo
2018-01-10 21:43:25 +05:30
2013-04-19 18:11:06 +05:30
endif
enddo
2018-01-10 21:43:25 +05:30
2012-06-15 21:40:21 +05:30
end subroutine mesh_build_nodeTwins
2013-04-18 22:10:49 +05:30
!--------------------------------------------------------------------------------------------------
2018-01-10 21:43:25 +05:30
!> @brief get maximum count of shared elements among cpElements and build list of elements shared
2013-04-18 22:10:49 +05:30
!! by each node in mesh. Allocate globals '_maxNsharedElems' and '_sharedElem'
!--------------------------------------------------------------------------------------------------
2012-06-15 21:40:21 +05:30
subroutine mesh_build_sharedElems
2019-05-15 02:42:32 +05:30
2013-04-19 18:11:06 +05:30
integer ( pint ) e , & ! element index
g , & ! element type
node , & ! CP node index
2018-01-10 21:43:25 +05:30
n , & ! node index per element
myDim , & ! dimension index
2013-04-19 18:11:06 +05:30
nodeTwin ! node twin in the specified dimension
2019-05-15 02:14:38 +05:30
integer , dimension ( mesh_Nnodes ) :: node_count
integer , dimension ( : ) , allocatable :: node_seen
2018-01-10 21:43:25 +05:30
2013-04-19 18:11:06 +05:30
allocate ( node_seen ( maxval ( FE_NmatchingNodes ) ) )
2018-01-10 21:43:25 +05:30
2019-05-15 02:14:38 +05:30
node_count = 0
2018-01-10 21:43:25 +05:30
2019-05-15 02:14:38 +05:30
do e = 1 , theMesh % nElems
2019-02-03 21:10:15 +05:30
g = theMesh % elem % geomType
2019-05-15 02:14:38 +05:30
node_seen = 0 ! reset node duplicates
do n = 1 , FE_NmatchingNodes ( g ) ! check each node of element
2013-04-22 00:18:59 +05:30
node = mesh_element ( 4 + n , e )
2013-04-19 18:11:06 +05:30
if ( all ( node_seen / = node ) ) then
2019-05-15 02:14:38 +05:30
node_count ( node ) = node_count ( node ) + 1 ! if FE node not yet encountered -> count it
do myDim = 1 , 3 ! check in each dimension...
2013-04-19 18:11:06 +05:30
nodeTwin = mesh_nodeTwins ( myDim , node )
2019-05-15 02:14:38 +05:30
if ( nodeTwin > 0 ) & ! if I am a twin of some node...
node_count ( nodeTwin ) = node_count ( nodeTwin ) + 1 ! -> count me again for the twin node
2013-04-19 18:11:06 +05:30
enddo
endif
node_seen ( n ) = node ! remember this node to be counted already
enddo
enddo
2018-01-10 21:43:25 +05:30
2013-04-19 18:11:06 +05:30
mesh_maxNsharedElems = int ( maxval ( node_count ) , pInt ) ! most shared node
2018-01-10 21:43:25 +05:30
2019-05-15 02:14:38 +05:30
allocate ( mesh_sharedElem ( 1 + mesh_maxNsharedElems , mesh_Nnodes ) , source = 0 )
2018-01-10 21:43:25 +05:30
2019-05-15 02:14:38 +05:30
do e = 1 , theMesh % nElems
2019-02-03 21:10:15 +05:30
g = theMesh % elem % geomType
2019-05-15 02:14:38 +05:30
node_seen = 0
do n = 1 , FE_NmatchingNodes ( g )
node = mesh_element ( 4 + n , e )
2013-04-19 18:11:06 +05:30
if ( all ( node_seen / = node ) ) then
2019-05-15 02:14:38 +05:30
mesh_sharedElem ( 1 , node ) = mesh_sharedElem ( 1 , node ) + 1 ! count for each node the connected elements
mesh_sharedElem ( mesh_sharedElem ( 1 , node ) + 1 , node ) = e ! store the respective element id
do myDim = 1 , 3 ! check in each dimension...
2013-04-19 18:11:06 +05:30
nodeTwin = mesh_nodeTwins ( myDim , node )
2019-05-15 02:14:38 +05:30
if ( nodeTwin > 0 ) then ! if i am a twin of some node...
mesh_sharedElem ( 1 , nodeTwin ) = mesh_sharedElem ( 1 , nodeTwin ) + 1 ! ...count me again for the twin
2013-04-19 18:11:06 +05:30
mesh_sharedElem ( mesh_sharedElem ( 1 , nodeTwin ) + 1 , nodeTwin ) = e ! store the respective element id
endif
enddo
endif
node_seen ( n ) = node
enddo
enddo
2018-01-10 21:43:25 +05:30
2012-03-09 01:55:28 +05:30
end subroutine mesh_build_sharedElems
2009-10-12 21:31:49 +05:30
2013-04-18 22:10:49 +05:30
!--------------------------------------------------------------------------------------------------
2013-12-28 01:33:28 +05:30
!> @brief build up of IP neighborhood, allocate globals '_ipNeighborhood'
2013-04-18 22:10:49 +05:30
!--------------------------------------------------------------------------------------------------
2012-03-09 01:55:28 +05:30
subroutine mesh_build_ipNeighborhood
2018-01-10 21:43:25 +05:30
2019-05-15 02:14:38 +05:30
integer :: myElem , & ! my CP element index
2013-04-19 18:11:06 +05:30
myIP , &
myType , & ! my element type
myFace , &
neighbor , & ! neighor index
2018-01-10 21:43:25 +05:30
neighboringIPkey , & ! positive integer indicating the neighboring IP (for intra-element) and negative integer indicating the face towards neighbor (for neighboring element)
2013-04-19 18:11:06 +05:30
candidateIP , &
neighboringType , & ! element type of neighbor
NlinkedNodes , & ! number of linked nodes
twin_of_linkedNode , & ! node twin of a specific linkedNode
NmatchingNodes , & ! number of matching nodes
dir , & ! direction of periodicity
matchingElem , & ! CP elem number of matching element
matchingFace , & ! face ID of matching element
a , anchor , &
2018-01-10 21:43:25 +05:30
neighboringIP , &
2013-04-19 18:11:06 +05:30
neighboringElem , &
pointingToMe
2019-05-15 02:14:38 +05:30
integer , dimension ( FE_maxmaxNnodesAtIP ) :: &
linkedNodes = 0 , &
2013-04-19 18:11:06 +05:30
matchingNodes
logical checkTwins
2018-01-10 21:43:25 +05:30
2019-02-03 21:10:15 +05:30
allocate ( mesh_ipNeighborhood ( 3 , theMesh % elem % nIPneighbors , theMesh % elem % nIPs , theMesh % nElems ) )
2019-05-15 02:14:38 +05:30
mesh_ipNeighborhood = 0
2018-01-10 21:43:25 +05:30
2019-05-15 02:14:38 +05:30
do myElem = 1 , theMesh % nElems ! loop over cpElems
2019-02-03 21:10:15 +05:30
myType = theMesh % elem % geomType
2019-05-15 02:14:38 +05:30
do myIP = 1 , theMesh % elem % nIPs
2018-01-10 21:43:25 +05:30
2019-05-15 02:14:38 +05:30
do neighbor = 1 , FE_NipNeighbors ( theMesh % elem % cellType ) ! loop over neighbors of IP
2019-02-03 21:10:15 +05:30
neighboringIPkey = theMesh % elem % IPneighbor ( neighbor , myIP )
2018-01-10 21:43:25 +05:30
2013-04-19 18:11:06 +05:30
!*** if the key is positive, the neighbor is inside the element
!*** that means, we have already found our neighboring IP
2018-01-10 21:43:25 +05:30
2019-05-15 02:14:38 +05:30
if ( neighboringIPkey > 0 ) then
2013-04-19 18:11:06 +05:30
mesh_ipNeighborhood ( 1 , neighbor , myIP , myElem ) = myElem
mesh_ipNeighborhood ( 2 , neighbor , myIP , myElem ) = neighboringIPkey
2018-01-10 21:43:25 +05:30
2013-04-19 18:11:06 +05:30
!*** if the key is negative, the neighbor resides in a neighboring element
!*** that means, we have to look through the face indicated by the key and see which element is behind that face
2018-01-10 21:43:25 +05:30
2019-05-15 02:14:38 +05:30
elseif ( neighboringIPkey < 0 ) then ! neighboring element's IP
2013-04-19 18:11:06 +05:30
myFace = - neighboringIPkey
call mesh_faceMatch ( myElem , myFace , matchingElem , matchingFace ) ! get face and CP elem id of face match
2019-05-15 02:14:38 +05:30
if ( matchingElem > 0 ) then ! found match?
2019-02-03 21:10:15 +05:30
neighboringType = theMesh % elem % geomType
2018-01-10 21:43:25 +05:30
2013-04-19 18:11:06 +05:30
!*** trivial solution if neighbor has only one IP
2018-01-10 21:43:25 +05:30
2019-05-15 02:14:38 +05:30
if ( theMesh % elem % nIPs == 1 ) then
2013-04-19 18:11:06 +05:30
mesh_ipNeighborhood ( 1 , neighbor , myIP , myElem ) = matchingElem
2019-05-15 02:14:38 +05:30
mesh_ipNeighborhood ( 2 , neighbor , myIP , myElem ) = 1
2013-04-19 18:11:06 +05:30
cycle
endif
2018-01-10 21:43:25 +05:30
2013-04-19 18:11:06 +05:30
!*** find those nodes which build the link to the neighbor
2018-01-10 21:43:25 +05:30
2019-05-15 02:14:38 +05:30
NlinkedNodes = 0
linkedNodes = 0
do a = 1 , theMesh % elem % maxNnodeAtIP
2019-02-03 21:10:15 +05:30
anchor = theMesh % elem % NnodeAtIP ( a , myIP )
2019-05-15 02:14:38 +05:30
if ( anchor / = 0 ) then ! valid anchor node
2013-04-19 18:11:06 +05:30
if ( any ( FE_face ( : , myFace , myType ) == anchor ) ) then ! ip anchor sits on face?
2019-05-15 02:14:38 +05:30
NlinkedNodes = NlinkedNodes + 1
linkedNodes ( NlinkedNodes ) = mesh_element ( 4 + anchor , myElem ) ! CP id of anchor node
2013-04-19 18:11:06 +05:30
else ! something went wrong with the linkage, since not all anchors sit on my face
2019-05-15 02:14:38 +05:30
NlinkedNodes = 0
linkedNodes = 0
2013-04-19 18:11:06 +05:30
exit
endif
endif
enddo
2018-01-10 21:43:25 +05:30
2013-04-19 18:11:06 +05:30
!*** loop through the ips of my neighbor
!*** and try to find an ip with matching nodes
!*** also try to match with node twins
2018-01-10 21:43:25 +05:30
2019-05-15 02:14:38 +05:30
checkCandidateIP : do candidateIP = 1 , theMesh % elem % nIPs
NmatchingNodes = 0
matchingNodes = 0
do a = 1 , theMesh % elem % maxNnodeAtIP
2019-02-03 21:10:15 +05:30
anchor = theMesh % elem % NnodeAtIP ( a , candidateIP )
2019-05-15 02:14:38 +05:30
if ( anchor / = 0 ) then ! valid anchor node
2013-04-19 18:11:06 +05:30
if ( any ( FE_face ( : , matchingFace , neighboringType ) == anchor ) ) then ! sits on matching face?
2019-05-15 02:14:38 +05:30
NmatchingNodes = NmatchingNodes + 1
2013-04-22 00:18:59 +05:30
matchingNodes ( NmatchingNodes ) = mesh_element ( 4 + anchor , matchingElem ) ! CP id of neighbor's anchor node
2013-04-19 18:11:06 +05:30
else ! no matching, because not all nodes sit on the matching face
2019-05-15 02:14:38 +05:30
NmatchingNodes = 0
matchingNodes = 0
2013-04-19 18:11:06 +05:30
exit
endif
endif
enddo
2018-01-10 21:43:25 +05:30
2013-04-19 18:11:06 +05:30
if ( NmatchingNodes / = NlinkedNodes ) & ! this ip has wrong count of anchors on face
cycle checkCandidateIP
2018-01-10 21:43:25 +05:30
2013-04-19 18:11:06 +05:30
!*** check "normal" nodes whether they match or not
2018-01-10 21:43:25 +05:30
2013-04-19 18:11:06 +05:30
checkTwins = . false .
2019-05-15 02:14:38 +05:30
do a = 1 , NlinkedNodes
2013-04-19 18:11:06 +05:30
if ( all ( matchingNodes / = linkedNodes ( a ) ) ) then ! this linkedNode does not match any matchingNode
checkTwins = . true .
exit ! no need to search further
endif
enddo
2018-01-10 21:43:25 +05:30
2013-04-19 18:11:06 +05:30
!*** if no match found, then also check node twins
2018-01-10 21:43:25 +05:30
2013-04-19 18:11:06 +05:30
if ( checkTwins ) then
dir = int ( maxloc ( abs ( mesh_ipAreaNormal ( 1 : 3 , neighbor , myIP , myElem ) ) , 1 ) , pInt ) ! check for twins only in direction of the surface normal
2019-05-15 02:14:38 +05:30
do a = 1 , NlinkedNodes
2013-04-19 18:11:06 +05:30
twin_of_linkedNode = mesh_nodeTwins ( dir , linkedNodes ( a ) )
2019-05-15 02:14:38 +05:30
if ( twin_of_linkedNode == 0 . or . & ! twin of linkedNode does not exist...
2013-04-19 18:11:06 +05:30
all ( matchingNodes / = twin_of_linkedNode ) ) then ! ... or it does not match any matchingNode
cycle checkCandidateIP ! ... then check next candidateIP
endif
enddo
endif
2018-01-10 21:43:25 +05:30
2013-04-19 18:11:06 +05:30
!*** we found a match !!!
2018-01-10 21:43:25 +05:30
2013-04-19 18:11:06 +05:30
mesh_ipNeighborhood ( 1 , neighbor , myIP , myElem ) = matchingElem
mesh_ipNeighborhood ( 2 , neighbor , myIP , myElem ) = candidateIP
2018-01-10 21:43:25 +05:30
exit checkCandidateIP
2013-04-19 18:11:06 +05:30
enddo checkCandidateIP
endif ! end of valid external matching
endif ! end of internal/external matching
enddo
enddo
enddo
2019-05-15 02:14:38 +05:30
do myElem = 1 , theMesh % nElems ! loop over cpElems
2019-02-03 21:10:15 +05:30
myType = theMesh % elem % geomType
2019-05-15 02:14:38 +05:30
do myIP = 1 , theMesh % elem % nIPs
do neighbor = 1 , FE_NipNeighbors ( theMesh % elem % cellType ) ! loop over neighbors of IP
2013-04-19 18:11:06 +05:30
neighboringElem = mesh_ipNeighborhood ( 1 , neighbor , myIP , myElem )
neighboringIP = mesh_ipNeighborhood ( 2 , neighbor , myIP , myElem )
2019-05-15 02:14:38 +05:30
if ( neighboringElem > 0 . and . neighboringIP > 0 ) then ! if neighbor exists ...
2019-02-03 21:10:15 +05:30
neighboringType = theMesh % elem % geomType
2019-05-15 02:14:38 +05:30
do pointingToMe = 1 , FE_NipNeighbors ( theMesh % elem % cellType ) ! find neighboring index that points from my neighbor to myself
2013-04-19 18:11:06 +05:30
if ( myElem == mesh_ipNeighborhood ( 1 , pointingToMe , neighboringIP , neighboringElem ) &
. and . myIP == mesh_ipNeighborhood ( 2 , pointingToMe , neighboringIP , neighboringElem ) ) then ! possible candidate
if ( math_mul3x3 ( mesh_ipAreaNormal ( 1 : 3 , neighbor , myIP , myElem ) , &
mesh_ipAreaNormal ( 1 : 3 , pointingToMe , neighboringIP , neighboringElem ) ) < 0.0_pReal ) then ! area normals have opposite orientation (we have to check that because of special case for single element with two ips and periodicity. In this case the neighbor is identical in two different directions.)
mesh_ipNeighborhood ( 3 , neighbor , myIP , myElem ) = pointingToMe ! found match
exit ! so no need to search further
endif
endif
enddo
endif
enddo
enddo
enddo
2019-02-02 21:54:00 +05:30
contains
!--------------------------------------------------------------------------------------------------
2013-04-18 22:10:49 +05:30
!> @brief find face-matching element of same type
!--------------------------------------------------------------------------------------------------
2012-06-15 21:40:21 +05:30
subroutine mesh_faceMatch ( elem , face , matchingElem , matchingFace )
2012-05-08 20:27:06 +05:30
2019-05-15 02:14:38 +05:30
integer , intent ( out ) :: matchingElem , & ! matching CP element ID
2018-01-10 21:43:25 +05:30
matchingFace ! matching face ID
2019-05-15 02:14:38 +05:30
integer , intent ( in ) :: face , & ! face ID
2013-04-22 00:18:59 +05:30
elem ! CP elem ID
2019-05-15 02:14:38 +05:30
integer , dimension ( FE_NmatchingNodesPerFace ( face , theMesh % elem % geomType ) ) :: &
2012-06-15 21:40:21 +05:30
myFaceNodes ! global node ids on my face
2019-05-15 02:14:38 +05:30
integer :: myType , &
2012-06-15 21:40:21 +05:30
candidateType , &
candidateElem , &
candidateFace , &
candidateFaceNode , &
minNsharedElems , &
NsharedElems , &
2019-05-15 02:14:38 +05:30
lonelyNode = 0 , &
2012-06-15 21:40:21 +05:30
i , &
n , &
dir ! periodicity direction
2019-05-15 02:14:38 +05:30
integer , dimension ( : ) , allocatable :: element_seen
2012-06-15 21:40:21 +05:30
logical checkTwins
2012-04-24 22:32:27 +05:30
2019-05-15 02:14:38 +05:30
matchingElem = 0
matchingFace = 0
minNsharedElems = mesh_maxNsharedElems + 1 ! init to worst case
2019-02-03 21:10:15 +05:30
myType = theMesh % elem % geomType
2012-05-08 20:27:06 +05:30
2019-05-15 02:14:38 +05:30
do n = 1 , FE_NmatchingNodesPerFace ( face , myType ) ! loop over nodes on face
myFaceNodes ( n ) = mesh_element ( 4 + FE_face ( n , face , myType ) , elem ) ! CP id of face node
NsharedElems = mesh_sharedElem ( 1 , myFaceNodes ( n ) ) ! figure # shared elements for this node
2012-06-15 21:40:21 +05:30
if ( NsharedElems < minNsharedElems ) then
minNsharedElems = NsharedElems ! remember min # shared elems
lonelyNode = n ! remember most lonely node
endif
enddo
2012-05-08 20:27:06 +05:30
2012-06-15 21:40:21 +05:30
allocate ( element_seen ( minNsharedElems ) )
2019-05-15 02:14:38 +05:30
element_seen = 0
2012-05-08 20:27:06 +05:30
2019-05-15 02:14:38 +05:30
checkCandidate : do i = 1 , minNsharedElems ! iterate over lonelyNode's shared elements
candidateElem = mesh_sharedElem ( 1 + i , myFaceNodes ( lonelyNode ) ) ! present candidate elem
2012-06-15 21:40:21 +05:30
if ( all ( element_seen / = candidateElem ) ) then ! element seen for the first time?
element_seen ( i ) = candidateElem
2019-02-03 21:10:15 +05:30
candidateType = theMesh % elem % geomType
2019-05-15 02:14:38 +05:30
checkCandidateFace : do candidateFace = 1 , FE_maxNipNeighbors ! check each face of candidate
2013-04-15 13:43:20 +05:30
if ( FE_NmatchingNodesPerFace ( candidateFace , candidateType ) &
/ = FE_NmatchingNodesPerFace ( face , myType ) & ! incompatible face
2012-11-16 04:15:20 +05:30
. or . ( candidateElem == elem . and . candidateFace == face ) ) then ! this is my face
2012-06-15 21:40:21 +05:30
cycle checkCandidateFace
endif
checkTwins = . false .
2019-05-15 02:14:38 +05:30
do n = 1 , FE_NmatchingNodesPerFace ( candidateFace , candidateType ) ! loop through nodes on face
candidateFaceNode = mesh_element ( 4 + FE_face ( n , candidateFace , candidateType ) , candidateElem )
2013-04-15 13:43:20 +05:30
if ( all ( myFaceNodes / = candidateFaceNode ) ) then ! candidate node does not match any of my face nodes
checkTwins = . true . ! perhaps the twin nodes do match
2012-06-15 21:40:21 +05:30
exit
endif
enddo
if ( checkTwins ) then
2019-05-15 02:14:38 +05:30
checkCandidateFaceTwins : do dir = 1 , 3
do n = 1 , FE_NmatchingNodesPerFace ( candidateFace , candidateType ) ! loop through nodes on face
2013-04-22 00:18:59 +05:30
candidateFaceNode = mesh_element ( 4 + FE_face ( n , candidateFace , candidateType ) , candidateElem )
2013-04-15 13:43:20 +05:30
if ( all ( myFaceNodes / = mesh_nodeTwins ( dir , candidateFaceNode ) ) ) then ! node twin does not match either
2019-05-15 02:14:38 +05:30
if ( dir == 3 ) then
2012-06-15 21:40:21 +05:30
cycle checkCandidateFace
else
2013-04-15 13:43:20 +05:30
cycle checkCandidateFaceTwins ! try twins in next dimension
2012-06-15 21:40:21 +05:30
endif
endif
enddo
exit checkCandidateFaceTwins
enddo checkCandidateFaceTwins
endif
matchingFace = candidateFace
matchingElem = candidateElem
2013-04-15 13:43:20 +05:30
exit checkCandidate ! found my matching candidate
2012-06-15 21:40:21 +05:30
enddo checkCandidateFace
endif
enddo checkCandidate
2012-05-08 20:27:06 +05:30
2012-06-15 21:40:21 +05:30
end subroutine mesh_faceMatch
2012-05-08 20:27:06 +05:30
2019-02-02 21:54:00 +05:30
end subroutine mesh_build_ipNeighborhood
!--------------------------------------------------------------------------------------------------
!> @brief mapping of FE element types to internal representation
!--------------------------------------------------------------------------------------------------
2019-05-15 02:14:38 +05:30
integer function FE_mapElemtype ( what )
2019-02-02 21:54:00 +05:30
character ( len = * ) , intent ( in ) :: what
select case ( IO_lc ( what ) )
case ( '6' )
2019-05-15 02:14:38 +05:30
FE_mapElemtype = 1 ! Two-dimensional Plane Strain Triangle
2019-02-02 21:54:00 +05:30
case ( '155' , &
'125' , &
'128' )
2019-05-15 02:14:38 +05:30
FE_mapElemtype = 2 ! Two-dimensional Plane Strain triangle (155: cubic shape function, 125/128: second order isoparametric)
2019-02-02 21:54:00 +05:30
case ( '11' )
2019-05-15 02:14:38 +05:30
FE_mapElemtype = 3 ! Arbitrary Quadrilateral Plane-strain
2019-02-02 21:54:00 +05:30
case ( '27' )
2019-05-15 02:14:38 +05:30
FE_mapElemtype = 4 ! Plane Strain, Eight-node Distorted Quadrilateral
2019-02-02 21:54:00 +05:30
case ( '54' )
2019-05-15 02:14:38 +05:30
FE_mapElemtype = 5 ! Plane Strain, Eight-node Distorted Quadrilateral with reduced integration
2019-02-02 21:54:00 +05:30
case ( '134' )
2019-05-15 02:14:38 +05:30
FE_mapElemtype = 6 ! Three-dimensional Four-node Tetrahedron
2019-02-02 21:54:00 +05:30
case ( '157' )
2019-05-15 02:14:38 +05:30
FE_mapElemtype = 7 ! Three-dimensional, Low-order, Tetrahedron, Herrmann Formulations
2019-02-02 21:54:00 +05:30
case ( '127' )
2019-05-15 02:14:38 +05:30
FE_mapElemtype = 8 ! Three-dimensional Ten-node Tetrahedron
2019-02-02 21:54:00 +05:30
case ( '136' )
2019-05-15 02:14:38 +05:30
FE_mapElemtype = 9 ! Three-dimensional Arbitrarily Distorted Pentahedral
2019-02-02 21:54:00 +05:30
case ( '117' , &
'123' )
2019-05-15 02:14:38 +05:30
FE_mapElemtype = 10 ! Three-dimensional Arbitrarily Distorted linear hexahedral with reduced integration
2019-02-02 21:54:00 +05:30
case ( '7' )
2019-05-15 02:14:38 +05:30
FE_mapElemtype = 11 ! Three-dimensional Arbitrarily Distorted Brick
2019-02-02 21:54:00 +05:30
case ( '57' )
2019-05-15 02:14:38 +05:30
FE_mapElemtype = 12 ! Three-dimensional Arbitrarily Distorted quad hexahedral with reduced integration
2019-02-02 21:54:00 +05:30
case ( '21' )
2019-05-15 02:14:38 +05:30
FE_mapElemtype = 13 ! Three-dimensional Arbitrarily Distorted quadratic hexahedral
2019-02-02 21:54:00 +05:30
case default
2019-05-15 02:14:38 +05:30
call IO_error ( error_ID = 190 , ext_msg = IO_lc ( what ) )
2019-02-02 21:54:00 +05:30
end select
end function FE_mapElemtype
2012-04-10 20:45:46 +05:30
2013-04-15 13:43:20 +05:30
!--------------------------------------------------------------------------------------------------
!> @brief get properties of different types of finite elements
2019-02-03 21:10:15 +05:30
!> @details assign globals FE_cellface
2013-04-15 13:43:20 +05:30
!--------------------------------------------------------------------------------------------------
2012-06-15 21:40:21 +05:30
subroutine mesh_build_FEdata
2019-05-15 02:42:32 +05:30
2019-05-15 02:14:38 +05:30
integer :: me
allocate ( FE_cellface ( FE_maxNcellnodesPerCellface , FE_maxNcellfaces , FE_Ncelltypes ) , source = 0 )
2013-04-15 13:43:20 +05:30
! *** FE_cellface ***
2019-05-15 02:14:38 +05:30
me = 0
2013-04-15 13:43:20 +05:30
2019-05-15 02:14:38 +05:30
me = me + 1
2013-04-18 22:10:49 +05:30
FE_cellface ( 1 : FE_NcellnodesPerCellface ( me ) , 1 : FE_NipNeighbors ( me ) , me ) = & ! 2D 3node, VTK_TRIANGLE (5)
2012-06-15 21:40:21 +05:30
reshape ( int ( [ &
2013-04-15 13:43:20 +05:30
2 , 3 , &
3 , 1 , &
1 , 2 &
] , pInt ) , [ FE_NcellnodesPerCellface ( me ) , FE_NipNeighbors ( me ) ] )
2012-06-15 21:40:21 +05:30
2019-05-15 02:14:38 +05:30
me = me + 1
2013-04-18 22:10:49 +05:30
FE_cellface ( 1 : FE_NcellnodesPerCellface ( me ) , 1 : FE_NipNeighbors ( me ) , me ) = & ! 2D 4node, VTK_QUAD (9)
2012-11-16 04:15:20 +05:30
reshape ( int ( [ &
2013-04-15 13:43:20 +05:30
2 , 3 , &
4 , 1 , &
3 , 4 , &
1 , 2 &
] , pInt ) , [ FE_NcellnodesPerCellface ( me ) , FE_NipNeighbors ( me ) ] )
2012-11-16 04:15:20 +05:30
2019-05-15 02:14:38 +05:30
me = me + 1
2013-04-18 22:10:49 +05:30
FE_cellface ( 1 : FE_NcellnodesPerCellface ( me ) , 1 : FE_NipNeighbors ( me ) , me ) = & ! 3D 4node, VTK_TETRA (10)
2012-11-16 04:15:20 +05:30
reshape ( int ( [ &
2013-04-15 13:43:20 +05:30
1 , 3 , 2 , &
1 , 2 , 4 , &
2 , 3 , 4 , &
1 , 4 , 3 &
] , pInt ) , [ FE_NcellnodesPerCellface ( me ) , FE_NipNeighbors ( me ) ] )
2012-11-16 04:15:20 +05:30
2019-05-15 02:14:38 +05:30
me = me + 1
2013-04-18 22:10:49 +05:30
FE_cellface ( 1 : FE_NcellnodesPerCellface ( me ) , 1 : FE_NipNeighbors ( me ) , me ) = & ! 3D 8node, VTK_HEXAHEDRON (12)
2012-06-15 21:40:21 +05:30
reshape ( int ( [ &
2013-04-15 13:43:20 +05:30
2 , 3 , 7 , 6 , &
4 , 1 , 5 , 8 , &
3 , 4 , 8 , 7 , &
1 , 2 , 6 , 5 , &
5 , 6 , 7 , 8 , &
1 , 4 , 3 , 2 &
] , pInt ) , [ FE_NcellnodesPerCellface ( me ) , FE_NipNeighbors ( me ) ] )
2012-06-15 21:40:21 +05:30
end subroutine mesh_build_FEdata
2019-02-02 21:54:00 +05:30
!--------------------------------------------------------------------------------------------------
!> @brief Gives the FE to CP ID mapping by binary search through lookup array
!! valid questions (what) are 'elem', 'node'
!--------------------------------------------------------------------------------------------------
2019-05-15 02:14:38 +05:30
integer function mesh_FEasCP ( what , myID )
2019-02-02 21:54:00 +05:30
character ( len = * ) , intent ( in ) :: what
2019-05-15 02:14:38 +05:30
integer , intent ( in ) :: myID
2019-02-02 21:54:00 +05:30
2019-05-15 02:14:38 +05:30
integer , dimension ( : , : ) , pointer :: lookupMap
integer :: lower , upper , center
2019-02-02 21:54:00 +05:30
2019-05-15 02:14:38 +05:30
mesh_FEasCP = 0
2019-02-02 21:54:00 +05:30
select case ( IO_lc ( what ( 1 : 4 ) ) )
case ( 'elem' )
lookupMap = > mesh_mapFEtoCPelem
case ( 'node' )
lookupMap = > mesh_mapFEtoCPnode
case default
return
endselect
2019-05-15 02:14:38 +05:30
lower = 1
upper = int ( size ( lookupMap , 2 ) , pInt )
2019-02-02 21:54:00 +05:30
2019-05-15 02:14:38 +05:30
if ( lookupMap ( 1 , lower ) == myID ) then ! check at bounds QUESTION is it valid to extend bounds by 1 and just do binary search w/o init check at bounds?
mesh_FEasCP = lookupMap ( 2 , lower )
2019-02-02 21:54:00 +05:30
return
2019-05-15 02:14:38 +05:30
elseif ( lookupMap ( 1 , upper ) == myID ) then
mesh_FEasCP = lookupMap ( 2 , upper )
2019-02-02 21:54:00 +05:30
return
endif
2019-05-15 02:14:38 +05:30
binarySearch : do while ( upper - lower > 1 )
center = ( lower + upper ) / 2
if ( lookupMap ( 1 , center ) < myID ) then
2019-02-02 21:54:00 +05:30
lower = center
2019-05-15 02:14:38 +05:30
elseif ( lookupMap ( 1 , center ) > myID ) then
2019-02-02 21:54:00 +05:30
upper = center
else
2019-05-15 02:14:38 +05:30
mesh_FEasCP = lookupMap ( 2 , center )
2019-02-02 21:54:00 +05:30
exit
endif
enddo binarySearch
end function mesh_FEasCP
2012-08-16 20:25:23 +05:30
end module mesh