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-06-13 04:09:35 +05:30
use IO
use prec
use math
use mesh_base
use DAMASK_interface
use IO
use debug
use numerics
use FEsolving
use element
use discretization
use geometry_plastic_nonlocal
use HDF5_utilities
use results
implicit none
private
real ( pReal ) , public , protected :: &
mesh_unitlength !< physical length of one unit in mesh
2012-03-09 01:55:28 +05:30
2019-06-08 15:30:28 +05:30
!--------------------------------------------------------------------------------------------------
2019-06-05 23:48:19 +05:30
! public variables (DEPRECATED)
2019-06-08 15:30:28 +05:30
real ( pReal ) , dimension ( : , : , : ) , allocatable , public :: &
mesh_ipCoordinates !< IP x,y,z coordinates (after deformation!)
real ( pReal ) , dimension ( : , : ) , allocatable , public :: &
mesh_cellnode !< cell node x,y,z coordinates (after deformation! ONLY FOR MARC!!!)
!--------------------------------------------------------------------------------------------------
integer , dimension ( : , : ) , allocatable :: &
2019-10-08 20:42:53 +05:30
mesh_FEnodes
2019-06-05 23:48:19 +05:30
2019-06-08 15:30:28 +05:30
real ( pReal ) , dimension ( : , : ) , allocatable :: &
2019-06-13 11:01:45 +05:30
mesh_node , & !< node x,y,z coordinates (after deformation! ONLY FOR MARC!!!
2013-01-16 16:10:53 +05:30
mesh_node0 !< node x,y,z coordinates (initially!)
2019-06-05 23:48:19 +05:30
! --------------------------------------------------------------------------------------------------
2018-10-10 03:22:54 +05:30
2019-06-08 15:30:28 +05:30
type ( tMesh ) :: theMesh
2019-06-05 23:48:19 +05:30
2019-06-05 23:59:14 +05:30
integer :: &
mesh_Ncellnodes , & !< total number of cell nodes in mesh (including duplicates)
2019-06-05 23:48:19 +05:30
mesh_elemType , & !< Element type of the mesh (only support homogeneous meshes)
mesh_Nnodes , & !< total number of nodes in mesh
mesh_Ncells , & !< total number of cells in mesh
mesh_maxNsharedElems !< max number of CP elements sharing a node
integer , dimension ( : , : ) , allocatable :: &
2013-12-28 01:33:28 +05:30
mesh_cellnodeParent !< cellnode's parent element ID, cellnode's intra-element ID
2019-06-05 23:48:19 +05:30
integer , dimension ( : , : , : ) , allocatable :: &
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
2012-03-09 01:55:28 +05:30
2019-06-05 23:48:19 +05:30
integer , parameter :: &
2019-05-15 02:14:38 +05:30
FE_Ngeomtypes = 10 , &
FE_Ncelltypes = 4 , &
FE_maxNcellnodesPerCell = 8 , &
FE_maxNcellnodesPerCellface = 4
2013-04-15 13:43:20 +05:30
2019-06-05 23:48:19 +05:30
integer , dimension ( FE_Ncelltypes ) , parameter :: 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-10-08 13:00:32 +05:30
integer , dimension ( : ) , allocatable :: &
microstructureAt , &
homogenizationAt
2019-06-13 10:31:35 +05:30
integer :: &
2018-09-23 19:01:19 +05:30
mesh_NelemSets
2019-10-08 22:22:34 +05:30
2019-06-05 23:48:19 +05:30
character ( len = 64 ) , dimension ( : ) , allocatable :: &
2019-02-03 17:24:10 +05:30
mesh_nameElemSet
2019-06-05 23:48:19 +05:30
integer , dimension ( : , : ) , allocatable :: &
2018-09-23 18:57:51 +05:30
mesh_mapElemSet !< list of elements in elementSet
2019-06-05 23:48:19 +05:30
integer , dimension ( : , : ) , allocatable , target :: &
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-06-06 11:07:37 +05:30
integer , dimension ( : , : , : , : ) , allocatable :: &
mesh_ipNeighborhood2 !< 6 or less neighboring IPs as [element_num, IP_index, neighbor_index that points to me]
2019-06-05 23:59:14 +05:30
2019-10-08 20:56:02 +05:30
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_ipCoordinates , &
2018-09-23 21:27:48 +05:30
mesh_FEasCP
2019-01-28 19:06:44 +05:30
2019-01-28 18:23:44 +05:30
contains
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-06-13 04:09:35 +05:30
integer , intent ( in ) :: el , ip
integer , parameter :: FILEUNIT = 222
integer :: j , fileFormatVersion , elemType , &
mesh_maxNelemInSet , &
2019-06-13 10:31:35 +05:30
mesh_nElems , &
2019-06-13 04:09:35 +05:30
hypoelasticTableStyle , &
initialcondTableStyle
2019-10-08 20:56:02 +05:30
integer , dimension ( : ) , allocatable :: &
marc_matNumber !< array of material numbers for hypoelastic material (Marc only)
2019-06-13 04:09:35 +05:30
logical :: myDebug
2019-10-08 22:22:34 +05:30
real ( pReal ) , dimension ( : , : , : ) , allocatable :: &
mesh_ipArea !< area of interface to neighboring IP (initially!)
real ( pReal ) , dimension ( : , : , : , : ) , allocatable :: &
mesh_ipAreaNormal !< area normal of interface to neighboring IP (initially!)
2019-02-03 15:42:23 +05:30
2019-06-13 04:09:35 +05:30
write ( 6 , '(/,a)' ) ' <<<+- mesh init -+>>>'
2019-02-03 15:42:23 +05:30
2019-06-13 04:09:35 +05:30
mesh_unitlength = numerics_unitlength ! set physical extent of a length unit in mesh
2019-02-03 15:42:23 +05:30
2019-06-13 04:09:35 +05:30
myDebug = ( iand ( debug_level ( debug_mesh ) , debug_levelBasic ) / = 0 )
2019-02-03 15:42:23 +05:30
2019-10-08 13:00:32 +05:30
! parsing Marc input file
2019-06-13 04:09:35 +05:30
call IO_open_inputFile ( FILEUNIT , modelName )
fileFormatVersion = mesh_marc_get_fileFormat ( FILEUNIT )
call mesh_marc_get_tableStyles ( initialcondTableStyle , hypoelasticTableStyle , FILEUNIT )
2019-10-08 13:00:32 +05:30
if ( fileFormatVersion > 12 ) &
2019-10-08 20:56:02 +05:30
marc_matNumber = mesh_marc_get_matNumber ( FILEUNIT , hypoelasticTableStyle )
2019-06-13 04:09:35 +05:30
call mesh_marc_count_nodesAndElements ( mesh_nNodes , mesh_nElems , FILEUNIT )
2019-10-08 13:00:32 +05:30
call mesh_marc_count_elementSets ( mesh_NelemSets , mesh_maxNelemInSet , FILEUNIT )
2019-06-13 04:09:35 +05:30
allocate ( mesh_nameElemSet ( mesh_NelemSets ) ) ; mesh_nameElemSet = 'n/a'
allocate ( mesh_mapElemSet ( 1 + mesh_maxNelemInSet , mesh_NelemSets ) , source = 0 )
call mesh_marc_map_elementSets ( mesh_nameElemSet , mesh_mapElemSet , FILEUNIT )
2019-06-13 10:31:35 +05:30
allocate ( mesh_mapFEtoCPelem ( 2 , mesh_nElems ) , source = 0 )
2019-10-08 20:56:02 +05:30
call mesh_marc_map_elements ( hypoelasticTableStyle , mesh_nameElemSet , mesh_mapElemSet , &
mesh_nElems , fileFormatVersion , marc_matNumber , FILEUNIT )
2019-06-13 04:09:35 +05:30
allocate ( mesh_mapFEtoCPnode ( 2 , mesh_Nnodes ) , source = 0 )
call mesh_marc_map_nodes ( mesh_Nnodes , FILEUNIT ) !ToDo: don't work on global variables
2019-06-13 11:01:45 +05:30
mesh_node0 = mesh_marc_build_nodes ( mesh_Nnodes , FILEUNIT )
mesh_node = mesh_node0
2019-06-13 04:09:35 +05:30
elemType = mesh_marc_getElemType ( mesh_nElems , FILEUNIT )
if ( myDebug ) write ( 6 , '(a)' ) ' Counted CP sizes' ; flush ( 6 )
call theMesh % init ( 'mesh' , elemType , mesh_node0 )
2019-06-13 10:31:35 +05:30
call theMesh % setNelems ( mesh_nElems )
2019-06-13 04:09:35 +05:30
2019-10-08 13:00:32 +05:30
allocate ( microstructureAt ( theMesh % nElems ) , source = 0 )
allocate ( homogenizationAt ( theMesh % nElems ) , source = 0 )
2019-10-08 20:42:53 +05:30
allocate ( mesh_FEnodes ( theMesh % elem % nNodes , theMesh % nElems ) , source = 0 )
2019-02-03 15:42:23 +05:30
2019-10-08 13:00:32 +05:30
call mesh_marc_buildElements ( microstructureAt , homogenizationAt , &
mesh_nElems , theMesh % elem % nNodes , initialcondTableStyle , FILEUNIT )
2019-06-13 04:09:35 +05:30
if ( myDebug ) write ( 6 , '(a)' ) ' Built elements' ; flush ( 6 )
close ( FILEUNIT )
call mesh_build_cellconnectivity
if ( myDebug ) write ( 6 , '(a)' ) ' Built cell connectivity' ; flush ( 6 )
mesh_cellnode = mesh_build_cellnodes ( )
if ( myDebug ) write ( 6 , '(a)' ) ' Built cell nodes' ; flush ( 6 )
2019-02-03 15:42:23 +05:30
2019-06-13 04:09:35 +05:30
allocate ( mesh_ipCoordinates ( 3 , theMesh % elem % nIPs , theMesh % nElems ) , source = 0.0_pReal )
call mesh_build_ipCoordinates
if ( myDebug ) write ( 6 , '(a)' ) ' Built IP coordinates' ; flush ( 6 )
2019-10-05 23:16:08 +05:30
2019-10-08 22:22:34 +05:30
allocate ( mesh_ipArea ( theMesh % elem % nIPneighbors , theMesh % elem % nIPs , theMesh % nElems ) )
allocate ( mesh_ipAreaNormal ( 3 , theMesh % elem % nIPneighbors , theMesh % elem % nIPs , theMesh % nElems ) )
call mesh_build_ipAreas ( mesh_ipArea , mesh_ipAreaNormal )
2019-10-08 13:00:32 +05:30
if ( myDebug ) write ( 6 , '(a)' ) ' Built IP areas' ; flush ( 6 )
2019-02-03 15:42:23 +05:30
2019-06-13 04:09:35 +05:30
call IP_neighborhood2
if ( myDebug ) write ( 6 , '(a)' ) ' Built IP neighborhood' ; flush ( 6 )
2019-02-03 15:42:23 +05:30
2019-06-13 04:09:35 +05:30
if ( usePingPong . and . ( mesh_Nelems / = theMesh % nElems ) ) &
2019-10-08 13:00:32 +05:30
call IO_error ( 600 ) ! ping-pong must be disabled when having non-DAMASK elements
2019-06-13 04:09:35 +05:30
if ( debug_e < 1 . or . debug_e > theMesh % nElems ) &
2019-10-08 13:00:32 +05:30
call IO_error ( 602 , ext_msg = 'element' ) ! selected element does not exist
2019-06-13 04:09:35 +05:30
if ( debug_i < 1 . or . debug_i > theMesh % elem % nIPs ) &
2019-10-08 13:00:32 +05:30
call IO_error ( 602 , ext_msg = 'IP' ) ! selected element does not have requested IP
2019-02-02 20:27:05 +05:30
2019-06-13 04:09:35 +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...
FEsolving_execIP ( 2 , : ) = theMesh % elem % nIPs
2019-06-06 11:07:37 +05:30
2019-06-13 04:09:35 +05:30
allocate ( calcMode ( theMesh % elem % nIPs , theMesh % nElems ) )
calcMode = . false . ! pretend to have collected what first call is asking (F = I)
calcMode ( ip , mesh_FEasCP ( 'elem' , el ) ) = . true . ! first ip,el needs to be already pingponged to "calc"
2019-10-08 13:00:32 +05:30
call discretization_init ( microstructureAt , homogenizationAt , &
reshape ( mesh_ipCoordinates , [ 3 , theMesh % elem % nIPs * theMesh % nElems ] ) , &
mesh_node0 )
call geometry_plastic_nonlocal_setIPvolume ( IPvolume ( ) )
call geometry_plastic_nonlocal_setIPneighborhood ( mesh_ipNeighborhood2 )
2019-10-08 22:22:34 +05:30
call geometry_plastic_nonlocal_setIParea ( mesh_ipArea )
call geometry_plastic_nonlocal_setIPareaNormal ( mesh_ipAreaNormal )
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-06-13 04:09:35 +05:30
integer , intent ( in ) :: fileUnit
2018-01-10 21:43:25 +05:30
2019-06-13 04:09:35 +05:30
integer , allocatable , dimension ( : ) :: chunkPos
character ( len = 300 ) line
2018-01-10 21:43:25 +05:30
2019-06-13 04:09:35 +05:30
rewind ( fileUnit )
do
read ( fileUnit , '(A300)' , END = 620 ) line
chunkPos = IO_stringPos ( line )
if ( IO_lc ( IO_stringValue ( line , chunkPos , 1 ) ) == 'version' ) then
mesh_marc_get_fileFormat = IO_intValue ( line , chunkPos , 2 )
exit
endif
enddo
2018-01-10 21:43:25 +05:30
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-06-13 04:09:35 +05:30
subroutine mesh_marc_get_tableStyles ( initialcond , hypoelastic , fileUnit )
2019-05-15 02:42:32 +05:30
2019-06-13 04:09:35 +05:30
integer , intent ( out ) :: initialcond , hypoelastic
integer , intent ( in ) :: fileUnit
2018-01-10 21:43:25 +05:30
2019-06-13 04:09:35 +05:30
integer , allocatable , dimension ( : ) :: chunkPos
character ( len = 300 ) line
2009-10-12 21:31:49 +05:30
2019-06-13 04:09:35 +05:30
initialcond = 0
hypoelastic = 0
2009-10-12 21:31:49 +05:30
2019-06-13 04:09:35 +05:30
rewind ( fileUnit )
do
read ( fileUnit , '(A300)' , END = 620 ) line
chunkPos = IO_stringPos ( line )
2009-10-12 21:31:49 +05:30
2019-06-13 04:09:35 +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 )
exit
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-06-13 04:09:35 +05:30
integer , intent ( in ) :: fileUnit , tableStyle
integer , dimension ( : ) , allocatable :: mesh_marc_get_matNumber
2018-01-10 21:43:25 +05:30
2019-06-13 04:09:35 +05:30
integer , allocatable , dimension ( : ) :: chunkPos
integer :: i , j , data_blocks
character ( len = 300 ) :: line
2018-01-10 21:43:25 +05:30
2019-06-13 04:09:35 +05:30
data_blocks = 1
rewind ( fileUnit )
do
read ( fileUnit , '(A300)' , END = 620 ) line
chunkPos = IO_stringPos ( line )
if ( IO_lc ( IO_stringValue ( line , chunkPos , 1 ) ) == 'hypoelastic' ) then
read ( fileUnit , '(A300)' , END = 620 ) line
if ( len ( trim ( line ) ) / = 0 ) then
chunkPos = IO_stringPos ( line )
data_blocks = IO_intValue ( line , chunkPos , 1 )
endif
allocate ( mesh_marc_get_matNumber ( data_blocks ) , source = 0 )
do i = 1 , data_blocks ! read all data blocks
read ( fileUnit , '(A300)' , END = 620 ) line
chunkPos = IO_stringPos ( line )
mesh_marc_get_matNumber ( i ) = IO_intValue ( line , chunkPos , 1 )
2019-06-13 10:31:35 +05:30
do j = 1 , 2 + tableStyle ! read 2 or 3 remaining lines of data block
2019-06-13 04:09:35 +05:30
read ( fileUnit , '(A300)' ) line
enddo
enddo
exit
endif
enddo
2018-01-10 21:43:25 +05:30
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-06-13 04:09:35 +05:30
integer , intent ( in ) :: fileUnit
integer , intent ( out ) :: nNodes , nElems
integer , allocatable , dimension ( : ) :: chunkPos
character ( len = 300 ) :: line
2009-01-20 00:12:31 +05:30
2019-06-13 04:09:35 +05:30
nNodes = 0
nElems = 0
2009-01-20 00:12:31 +05:30
2019-06-13 04:09:35 +05:30
rewind ( fileUnit )
do
read ( fileUnit , '(A300)' , END = 620 ) line
chunkPos = IO_stringPos ( line )
2012-06-15 21:40:21 +05:30
2019-06-13 04:09:35 +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
read ( fileUnit , '(A300)' ) line
chunkPos = IO_stringPos ( line )
nNodes = IO_IntValue ( line , chunkPos , 2 )
exit ! assumes that "coordinates" comes later in file
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-06-06 16:38:10 +05:30
integer , intent ( out ) :: nElemSets , maxNelemInSet
2019-06-13 04:09:35 +05:30
integer , intent ( in ) :: fileUnit
2009-01-20 00:12:31 +05:30
2019-06-06 16:38:10 +05:30
integer , allocatable , dimension ( : ) :: chunkPos
character ( len = 300 ) :: line
2009-10-12 21:31:49 +05:30
2019-06-06 16:38:10 +05:30
nElemSets = 0
maxNelemInSet = 0
2009-01-20 00:12:31 +05:30
2019-06-06 16:38:10 +05:30
rewind ( fileUnit )
do
read ( fileUnit , '(A300)' , END = 620 ) line
chunkPos = IO_stringPos ( line )
2009-10-12 21:31:49 +05:30
2019-06-06 16:38:10 +05:30
if ( IO_lc ( IO_StringValue ( line , chunkPos , 1 ) ) == 'define' . and . &
IO_lc ( IO_StringValue ( line , chunkPos , 2 ) ) == 'element' ) then
nElemSets = nElemSets + 1
maxNelemInSet = max ( maxNelemInSet , IO_countContinuousIntValues ( fileUnit ) )
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-06-06 16:38:10 +05:30
character ( len = 64 ) , dimension ( : ) , intent ( out ) :: nameElemSet
integer , dimension ( : , : ) , intent ( out ) :: mapElemSet
2019-06-13 04:09:35 +05:30
integer , intent ( in ) :: fileUnit
2018-01-10 21:43:25 +05:30
2019-06-06 16:38:10 +05:30
integer , allocatable , dimension ( : ) :: chunkPos
character ( len = 300 ) :: line
integer :: elemSet
elemSet = 0
rewind ( fileUnit )
do
2019-06-13 10:55:26 +05:30
read ( fileUnit , '(A300)' , END = 620 ) line
2019-06-06 16:38:10 +05:30
chunkPos = IO_stringPos ( line )
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 ) )
mapElemSet ( : , elemSet ) = IO_continuousIntValues ( fileUnit , size ( mapElemSet , 1 ) - 1 , nameElemSet , mapElemSet , size ( nameElemSet ) )
endif
enddo
2018-01-10 21:43:25 +05:30
2019-06-13 10:55:26 +05:30
620 end subroutine mesh_marc_map_elementSets
2010-05-06 22:10:47 +05:30
2019-06-06 16:38:10 +05:30
2012-06-15 21:40:21 +05:30
!--------------------------------------------------------------------------------------------------
!> @brief Maps elements from FE ID to internal (consecutive) representation.
!--------------------------------------------------------------------------------------------------
2019-10-08 20:56:02 +05:30
subroutine mesh_marc_map_elements ( tableStyle , nameElemSet , mapElemSet , nElems , fileFormatVersion , matNumber , 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-10-08 20:56:02 +05:30
integer , dimension ( : ) , intent ( in ) :: matNumber
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-06-13 10:55:26 +05:30
read ( fileUnit , '(A300)' , END = 620 ) 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-06-13 10:55:26 +05:30
read ( fileUnit , '(A300)' , END = 620 ) line
2018-02-02 19:36:13 +05:30
chunkPos = IO_stringPos ( line )
2019-10-08 20:56:02 +05:30
if ( any ( matNumber == IO_intValue ( line , chunkPos , 6 ) ) ) then
2018-02-02 19:36:13 +05:30
do
2019-06-13 10:55:26 +05:30
read ( fileUnit , '(A300)' , END = 620 ) 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-06-13 10:55:26 +05:30
620 do i = 1 , contInts ( 1 )
2019-05-15 02:14:38 +05:30
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-06-16 00:12:16 +05:30
call math_sort ( mesh_mapFEtoCPelem )
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-06-13 04:09:35 +05:30
integer , intent ( in ) :: fileUnit , nNodes
2009-10-12 21:31:49 +05:30
2019-06-13 04:09:35 +05:30
integer , allocatable , dimension ( : ) :: chunkPos
character ( len = 300 ) line
2012-06-15 21:40:21 +05:30
2019-06-13 04:09:35 +05:30
integer , dimension ( nNodes ) :: node_count
integer :: i
2012-06-15 21:40:21 +05:30
2019-06-13 04:09:35 +05:30
node_count = 0
2012-06-15 21:40:21 +05:30
2019-06-13 04:09:35 +05:30
rewind ( fileUnit )
do
2019-06-13 10:55:26 +05:30
read ( fileUnit , '(A300)' , END = 620 ) line
2019-06-13 04:09:35 +05:30
chunkPos = IO_stringPos ( line )
if ( IO_lc ( IO_stringValue ( line , chunkPos , 1 ) ) == 'coordinates' ) then
read ( fileUnit , '(A300)' ) line ! skip crap line
do i = 1 , nNodes
read ( fileUnit , '(A300)' ) line
mesh_mapFEtoCPnode ( 1 , i ) = IO_fixedIntValue ( line , [ 0 , 10 ] , 1 )
mesh_mapFEtoCPnode ( 2 , i ) = i
enddo
exit
endif
enddo
2012-06-15 21:40:21 +05:30
2019-06-16 00:12:16 +05:30
620 call math_sort ( mesh_mapFEtoCPnode )
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.
!--------------------------------------------------------------------------------------------------
2019-06-13 11:01:45 +05:30
function mesh_marc_build_nodes ( nNode , fileUnit ) result ( nodes )
2009-10-12 21:31:49 +05:30
2019-06-13 11:01:45 +05:30
integer , intent ( in ) :: nNode , fileUnit
real ( pReal ) , dimension ( 3 , nNode ) :: nodes
2019-06-13 04:09:35 +05:30
integer , dimension ( 5 ) , parameter :: node_ends = [ 0 , 10 , 30 , 50 , 70 ]
integer , allocatable , dimension ( : ) :: chunkPos
character ( len = 300 ) :: line
integer :: i , j , m
2009-10-12 21:31:49 +05:30
2019-06-13 04:09:35 +05:30
rewind ( fileUnit )
do
2019-06-13 10:55:26 +05:30
read ( fileUnit , '(A300)' , END = 620 ) line
2019-06-13 04:09:35 +05:30
chunkPos = IO_stringPos ( line )
if ( IO_lc ( IO_stringValue ( line , chunkPos , 1 ) ) == 'coordinates' ) then
read ( fileUnit , '(A300)' ) line ! skip crap line
2019-06-13 11:01:45 +05:30
do i = 1 , nNode
2019-06-13 04:09:35 +05:30
read ( fileUnit , '(A300)' ) line
m = mesh_FEasCP ( 'node' , IO_fixedIntValue ( line , node_ends , 1 ) )
do j = 1 , 3
2019-06-13 11:01:45 +05:30
nodes ( j , m ) = mesh_unitlength * IO_fixedNoEFloatValue ( line , node_ends , j + 1 )
2019-06-13 04:09:35 +05:30
enddo
enddo
exit
endif
enddo
2009-10-12 21:31:49 +05:30
2019-06-13 11:01:45 +05:30
620 end function 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
!--------------------------------------------------------------------------------------------------
2019-06-06 16:38:10 +05:30
!> @brief Gets element type (and checks if the whole mesh comprises of only one type)
2012-06-15 21:40:21 +05:30
!--------------------------------------------------------------------------------------------------
2019-06-06 16:38:10 +05:30
integer function mesh_marc_getElemType ( nElem , fileUnit )
integer , intent ( in ) :: &
nElem , &
fileUnit
type ( tElement ) :: tempEl
integer , allocatable , dimension ( : ) :: chunkPos
character ( len = 300 ) :: line
integer :: i , t
t = - 1
rewind ( fileUnit )
do
2019-06-13 10:55:26 +05:30
read ( fileUnit , '(A300)' , END = 620 ) line
2019-06-06 16:38:10 +05:30
chunkPos = IO_stringPos ( line )
if ( IO_lc ( IO_stringValue ( line , chunkPos , 1 ) ) == 'connectivity' ) then
read ( fileUnit , '(A300)' ) line ! Garbage line
do i = 1 , nElem ! read all elements
read ( fileUnit , '(A300)' ) line
chunkPos = IO_stringPos ( line )
if ( t == - 1 ) then
t = mapElemtype ( IO_stringValue ( line , chunkPos , 2 ) )
call tempEl % init ( t )
mesh_marc_getElemType = t
else
if ( t / = mapElemtype ( IO_stringValue ( line , chunkPos , 2 ) ) ) call IO_error ( 191 , el = t , ip = i )
endif
call IO_skipChunks ( fileUnit , tempEl % nNodes - ( chunkPos ( 1 ) - 2 ) )
enddo
exit
endif
enddo
2009-10-12 21:31:49 +05:30
2019-10-05 20:48:21 +05:30
contains
2019-02-02 20:47:52 +05:30
2019-06-06 16:38:10 +05:30
!--------------------------------------------------------------------------------------------------
!> @brief mapping of Marc element types to internal representation
!--------------------------------------------------------------------------------------------------
integer function mapElemtype ( what )
character ( len = * ) , intent ( in ) :: what
select case ( IO_lc ( what ) )
case ( '6' )
mapElemtype = 1 ! Two-dimensional Plane Strain Triangle
case ( '155' , &
'125' , &
'128' )
mapElemtype = 2 ! Two-dimensional Plane Strain triangle (155: cubic shape function, 125/128: second order isoparametric)
case ( '11' )
mapElemtype = 3 ! Arbitrary Quadrilateral Plane-strain
case ( '27' )
mapElemtype = 4 ! Plane Strain, Eight-node Distorted Quadrilateral
case ( '54' )
mapElemtype = 5 ! Plane Strain, Eight-node Distorted Quadrilateral with reduced integration
case ( '134' )
mapElemtype = 6 ! Three-dimensional Four-node Tetrahedron
case ( '157' )
mapElemtype = 7 ! Three-dimensional, Low-order, Tetrahedron, Herrmann Formulations
case ( '127' )
mapElemtype = 8 ! Three-dimensional Ten-node Tetrahedron
case ( '136' )
mapElemtype = 9 ! Three-dimensional Arbitrarily Distorted Pentahedral
case ( '117' , &
'123' )
mapElemtype = 10 ! Three-dimensional Arbitrarily Distorted linear hexahedral with reduced integration
case ( '7' )
mapElemtype = 11 ! Three-dimensional Arbitrarily Distorted Brick
case ( '57' )
mapElemtype = 12 ! Three-dimensional Arbitrarily Distorted quad hexahedral with reduced integration
case ( '21' )
mapElemtype = 13 ! Three-dimensional Arbitrarily Distorted quadratic hexahedral
case default
call IO_error ( error_ID = 190 , ext_msg = IO_lc ( what ) )
end select
end function mapElemtype
2019-06-13 10:55:26 +05:30
620 end function mesh_marc_getElemType
2010-05-06 22:10:47 +05:30
2012-06-15 21:40:21 +05:30
!--------------------------------------------------------------------------------------------------
2019-06-06 16:38:10 +05:30
!> @brief Stores node IDs and homogenization and microstructure ID
2012-06-15 21:40:21 +05:30
!--------------------------------------------------------------------------------------------------
2019-10-08 13:00:32 +05:30
subroutine mesh_marc_buildElements ( microstructureAt , homogenizationAt , &
nElem , nNodes , initialcondTableStyle , fileUnit )
2019-05-15 02:42:32 +05:30
2019-10-08 13:00:32 +05:30
integer , dimension ( : ) , intent ( out ) :: &
microstructureAt , &
homogenizationAt
2019-06-06 16:38:10 +05:30
integer , intent ( in ) :: &
2019-06-13 10:31:35 +05:30
nElem , &
2019-10-05 20:48:21 +05:30
nNodes , & !< number of nodes per element
2019-06-06 16:38:10 +05:30
initialcondTableStyle , &
fileUnit
integer , allocatable , dimension ( : ) :: chunkPos
character ( len = 300 ) line
2019-06-13 10:31:35 +05:30
integer , dimension ( 1 + nElem ) :: contInts
2019-06-06 16:38:10 +05:30
integer :: i , j , t , sv , myVal , e , nNodesAlreadyRead
rewind ( fileUnit )
do
read ( fileUnit , '(A300)' , END = 620 ) line
chunkPos = IO_stringPos ( line )
if ( IO_lc ( IO_stringValue ( line , chunkPos , 1 ) ) == 'connectivity' ) then
read ( fileUnit , '(A300)' , END = 620 ) line ! garbage line
2019-06-13 10:31:35 +05:30
do i = 1 , nElem
2019-06-06 16:38:10 +05:30
read ( fileUnit , '(A300)' , END = 620 ) line
chunkPos = IO_stringPos ( line )
e = mesh_FEasCP ( 'elem' , IO_intValue ( line , chunkPos , 1 ) )
if ( e / = 0 ) then ! disregard non CP elems
nNodesAlreadyRead = 0
do j = 1 , chunkPos ( 1 ) - 2
2019-10-08 20:42:53 +05:30
mesh_FEnodes ( j , e ) = mesh_FEasCP ( 'node' , IO_IntValue ( line , chunkPos , j + 2 ) ) ! CP ids of nodes
2019-06-06 16:38:10 +05:30
enddo
nNodesAlreadyRead = chunkPos ( 1 ) - 2
2019-10-05 20:48:21 +05:30
do while ( nNodesAlreadyRead < nNodes ) ! read on if not all nodes in one line
2019-06-06 16:38:10 +05:30
read ( fileUnit , '(A300)' , END = 620 ) line
chunkPos = IO_stringPos ( line )
do j = 1 , chunkPos ( 1 )
2019-10-08 20:42:53 +05:30
mesh_FEnodes ( nNodesAlreadyRead + j , e ) = mesh_FEasCP ( 'node' , IO_IntValue ( line , chunkPos , j ) ) ! CP ids of nodes
2019-06-06 16:38:10 +05:30
enddo
nNodesAlreadyRead = nNodesAlreadyRead + chunkPos ( 1 )
enddo
endif
enddo
exit
endif
enddo
2015-03-25 21:36:19 +05:30
620 rewind ( fileUnit ) ! just in case "initial state" appears before "connectivity"
2019-02-02 21:54:00 +05:30
2019-06-06 16:38:10 +05:30
#if defined(DAMASK_HDF5)
call results_openJobFile
call HDF5_closeGroup ( results_addGroup ( 'geometry' ) )
2019-10-08 20:42:53 +05:30
call results_writeDataset ( 'geometry' , mesh_FEnodes , 'C' , &
2019-06-06 16:38:10 +05:30
'connectivity of the elements' , '-' )
call results_closeJobFile
#endif
2019-10-08 20:42:53 +05:30
call buildCells ( theMesh , theMesh % elem , mesh_FEnodes )
2019-06-06 16:38:10 +05:30
read ( fileUnit , '(A300)' , END = 630 ) line
do
chunkPos = IO_stringPos ( line )
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
read ( fileUnit , '(A300)' , END = 630 ) line ! read line with index of state var
chunkPos = IO_stringPos ( line )
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
read ( fileUnit , '(A300)' , END = 630 ) line ! read line with value of state var
chunkPos = IO_stringPos ( line )
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
read ( fileUnit , '(A300)' , END = 630 ) line ! read extra line
read ( fileUnit , '(A300)' , END = 630 ) line ! read extra line
endif
contInts = IO_continuousIntValues & ! get affected elements
( fileUnit , theMesh % nElems , mesh_nameElemSet , mesh_mapElemSet , mesh_NelemSets )
do i = 1 , contInts ( 1 )
e = mesh_FEasCP ( 'elem' , contInts ( 1 + i ) )
2019-10-08 13:00:32 +05:30
if ( sv == 2 ) microstructureAt ( e ) = myVal
if ( sv == 3 ) homogenizationAt ( e ) = myVal
2019-06-06 16:38:10 +05:30
enddo
if ( initialcondTableStyle == 0 ) read ( fileUnit , '(A300)' , END = 630 ) line ! ignore IP range for old table style
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_buildElements
2019-02-02 21:54:00 +05:30
2019-06-13 03:35:29 +05:30
subroutine buildCells ( thisMesh , elem , connectivity_elem )
2019-05-17 16:52:52 +05:30
2019-10-08 22:22:34 +05:30
class ( tMesh ) :: thisMesh
type ( tElement ) , intent ( in ) :: elem
2019-06-12 22:38:38 +05:30
integer , dimension ( : , : ) , intent ( in ) :: connectivity_elem
2019-10-08 22:22:34 +05:30
integer , dimension ( : ) , allocatable :: candidates_local
integer , dimension ( : , : ) , allocatable :: parentsAndWeights , candidates_global , connectivity_cell_reshape
2019-06-13 03:35:29 +05:30
integer , dimension ( : , : , : ) , allocatable :: connectivity_cell
2019-10-08 22:22:34 +05:30
2019-06-13 04:09:35 +05:30
real ( pReal ) , dimension ( : , : ) , allocatable :: nodes_new , nodes
integer :: e , n , c , p , s , i , m , j , nParentNodes , nCellNode , Nelem , candidateID
2019-06-12 22:38:38 +05:30
Nelem = thisMesh % Nelems
2019-05-17 16:52:52 +05:30
!---------------------------------------------------------------------------------------------------
! initialize global connectivity to negative local connectivity
2019-06-12 22:38:38 +05:30
allocate ( connectivity_cell ( elem % NcellNodesPerCell , elem % nIPs , Nelem ) )
connectivity_cell = - spread ( elem % cell , 3 , Nelem ) ! local cell node ID
2019-05-17 16:52:52 +05:30
!---------------------------------------------------------------------------------------------------
2019-06-12 22:38:38 +05:30
! set connectivity of cell nodes that coincide with FE nodes (defined by 1 parent node)
! and renumber local (negative) to global (positive) node ID
do e = 1 , Nelem
do c = 1 , elem % NcellNodes
realNode : if ( count ( elem % cellNodeParentNodeWeights ( : , c ) / = 0 ) == 1 ) then
2019-05-17 16:52:52 +05:30
where ( connectivity_cell ( : , : , e ) == - c )
connectivity_cell ( : , : , e ) = connectivity_elem ( c , e )
end where
endif realNode
enddo
enddo
nCellNode = thisMesh % nNodes
2019-06-12 22:38:38 +05:30
!---------------------------------------------------------------------------------------------------
! set connectivity of cell nodes that are defined by 2,...,nNodes real nodes
do nParentNodes = 2 , elem % nNodes
2019-05-17 16:52:52 +05:30
2019-06-12 22:38:38 +05:30
! get IDs of local cell nodes that are defined by the current number of parent nodes
candidates_local = [ integer :: ]
do c = 1 , elem % NcellNodes
if ( count ( elem % cellNodeParentNodeWeights ( : , c ) / = 0 ) == nParentNodes ) &
candidates_local = [ candidates_local , c ]
enddo
s = size ( candidates_local )
if ( allocated ( candidates_global ) ) deallocate ( candidates_global )
2019-06-13 10:31:35 +05:30
allocate ( candidates_global ( nParentNodes * 2 + 2 , s * Nelem ) ) ! stores parent node ID + weight together with element ID and cellnode id (local)
parentsAndWeights = reshape ( [ ( 0 , i = 1 , 2 * nParentNodes ) ] , [ nParentNodes , 2 ] ) ! (re)allocate
2019-06-12 22:38:38 +05:30
do e = 1 , Nelem
do i = 1 , size ( candidates_local )
2019-06-13 10:31:35 +05:30
candidateID = ( e - 1 ) * size ( candidates_local ) + i ! including duplicates, runs to (Nelem*size(candidates_local))
c = candidates_local ( i ) ! c is local cellnode ID for connectivity
2019-06-12 22:38:38 +05:30
p = 0
do j = 1 , size ( elem % cellNodeParentNodeWeights ( : , c ) )
if ( elem % cellNodeParentNodeWeights ( j , c ) / = 0 ) then ! real node 'j' partly defines cell node 'c'
p = p + 1
parentsAndWeights ( p , 1 : 2 ) = [ connectivity_elem ( j , e ) , elem % cellNodeParentNodeWeights ( j , c ) ]
endif
enddo
! store (and order) real node IDs and their weights together with the element number and local ID
do p = 1 , nParentNodes
m = maxloc ( parentsAndWeights ( : , 1 ) , 1 )
candidates_global ( p , candidateID ) = parentsAndWeights ( m , 1 )
candidates_global ( p + nParentNodes , candidateID ) = parentsAndWeights ( m , 2 )
candidates_global ( nParentNodes * 2 + 1 : nParentNodes * 2 + 2 , candidateID ) = [ e , c ]
2019-06-13 10:31:35 +05:30
parentsAndWeights ( m , 1 ) = - huge ( parentsAndWeights ( m , 1 ) ) ! out of the competition
2019-06-12 22:38:38 +05:30
enddo
enddo
enddo
2019-05-17 16:52:52 +05:30
2019-06-12 22:38:38 +05:30
! sort according to real node IDs + weight (from left to right)
2019-06-13 10:31:35 +05:30
call math_sort ( candidates_global , sortDim = 1 ) ! sort according to first column
2019-06-12 22:38:38 +05:30
do p = 2 , nParentNodes * 2
n = 1
do while ( n < = size ( candidates_local ) * Nelem )
j = 0
do while ( n + j < = size ( candidates_local ) * Nelem )
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 ) ) ) &
call math_sort ( candidates_global ( : , n : e ) , sortDim = p )
n = e + 1
2019-05-17 16:52:52 +05:30
enddo
2019-06-12 22:38:38 +05:30
enddo
2019-06-13 10:31:35 +05:30
i = uniqueRows ( candidates_global ( 1 : 2 * nParentNodes , : ) )
2019-06-12 22:38:38 +05:30
! calculate coordinates of cell nodes and insert their ID into the cell conectivity
2019-06-13 04:09:35 +05:30
nodes_new = reshape ( [ ( 0.0_pReal , j = 1 , 3 * i ) ] , [ 3 , i ] )
2019-06-12 22:38:38 +05:30
i = 1
n = 1
do while ( n < = size ( candidates_local ) * Nelem )
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
2019-06-13 04:09:35 +05:30
nodes_new ( : , i ) = nodes_new ( : , i ) &
+ thisMesh % node_0 ( : , parentsAndWeights ( m , 1 ) ) * real ( parentsAndWeights ( m , 2 ) , pReal )
2019-05-17 16:52:52 +05:30
enddo
2019-06-13 04:09:35 +05:30
nodes_new ( : , i ) = nodes_new ( : , i ) / real ( sum ( parentsAndWeights ( : , 2 ) ) , pReal )
2019-06-12 22:38:38 +05:30
do while ( n + j < = size ( candidates_local ) * Nelem )
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 ) ) ! still locally defined
connectivity_cell ( : , : , candidates_global ( nParentNodes * 2 + 1 , n + j ) ) = nCellNode + i ! gets current new cell node id
end where
j = j + 1
2019-05-17 16:52:52 +05:30
enddo
2019-06-12 22:38:38 +05:30
i = i + 1
n = n + j
enddo
nCellNode = nCellNode + i
2019-06-13 04:09:35 +05:30
if ( i / = 0 ) nodes = reshape ( [ nodes , nodes_new ] , [ 3 , nCellNode ] )
2019-06-13 10:31:35 +05:30
enddo
thisMesh % node_0 = nodes
mesh_cell2 = connectivity_cell
2019-06-05 00:46:18 +05:30
#if defined(DAMASK_HDF5)
2019-06-13 13:29:37 +05:30
connectivity_cell_reshape = reshape ( connectivity_cell , [ elem % NcellNodesPerCell , elem % nIPs * Nelem ] )
2019-06-13 10:31:35 +05:30
call results_openJobFile
call results_writeDataset ( 'geometry' , connectivity_cell_reshape , 'c' , &
'connectivity of the cells' , '-' )
call results_closeJobFile
2019-06-05 00:46:18 +05:30
#endif
2019-06-13 04:09:35 +05:30
2019-09-24 10:43:52 +05:30
contains
2019-06-13 10:31:35 +05:30
2019-09-24 10:43:52 +05:30
!------------------------------------------------------------------------------------------------
!> @brief count unique rows (same rows need to be stored consecutively)
!------------------------------------------------------------------------------------------------
2019-06-13 10:31:35 +05:30
pure function uniqueRows ( A ) result ( u )
integer , dimension ( : , : ) , intent ( in ) :: A !< array, rows need to be sorted
integer :: &
u , & !< # of unique rows
r , & !< row counter
d !< duplicate counter
u = 0
r = 1
do while ( r < = size ( A , 2 ) )
d = 0
do while ( r + d < = size ( A , 2 ) )
if ( any ( A ( : , r ) / = A ( : , r + d ) ) ) exit
d = d + 1
enddo
u = u + 1
r = r + d
enddo
end function uniqueRows
2019-06-13 03:35:29 +05:30
end subroutine buildCells
2019-05-17 16:52:52 +05:30
2019-06-06 11:07:37 +05:30
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.
!--------------------------------------------------------------------------------------------------
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-10-08 22:38:29 +05:30
integer , dimension ( FE_Ngeomtypes ) , parameter :: FE_NmatchingNodes = & !< number of nodes that are needed for face matching in a specific type of element geometry
int ( [ &
3 , & ! element 6 (2D 3node 1ip)
3 , & ! element 125 (2D 6node 3ip)
4 , & ! element 11 (2D 4node 4ip)
4 , & ! element 27 (2D 8node 9ip)
4 , & ! element 134 (3D 4node 1ip)
4 , & ! element 127 (3D 10node 4ip)
6 , & ! element 136 (3D 6node 6ip)
8 , & ! element 117 (3D 8node 1ip)
8 , & ! element 7 (3D 8node 8ip)
8 & ! element 21 (3D 20node 27ip)
] , pInt )
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-10-08 20:42:53 +05:30
matchingNodeID = mesh_FEnodes ( localCellnodeID , e )
2019-05-15 02:14:38 +05:30
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-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-10-08 20:42:53 +05:30
myCoords = myCoords + mesh_node ( 1 : 3 , mesh_FEnodes ( 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
end function mesh_build_cellnodes
!--------------------------------------------------------------------------------------------------
2019-10-05 23:16:08 +05:30
!> @brief Calculates IP volume.
2019-02-02 21:54:00 +05:30
!> @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.
!--------------------------------------------------------------------------------------------------
2019-10-05 23:16:08 +05:30
function IPvolume ( )
2019-05-15 02:42:32 +05:30
2019-10-05 23:16:08 +05:30
real ( pReal ) , dimension ( theMesh % elem % nIPs , theMesh % nElems ) :: IPvolume
2019-06-05 11:52:34 +05:30
integer :: e , i , c , m , f , n
2019-06-13 12:39:51 +05:30
real ( pReal ) , dimension ( size ( theMesh % elem % cellFace , 1 ) , size ( theMesh % elem % cellFace , 2 ) ) :: subvolume
2019-02-02 21:54:00 +05:30
2019-06-05 11:52:34 +05:30
c = theMesh % elem % cellType
2019-10-08 13:33:03 +05:30
m = size ( theMesh % elem % cellFace , 1 )
2019-02-02 21:54:00 +05:30
2019-10-05 23:16:08 +05:30
do e = 1 , theMesh % nElems
select case ( c )
2019-10-08 13:00:32 +05:30
case ( 1 ) ! 2D 3node
forall ( i = 1 : theMesh % elem % nIPs ) & ! loop over ips=cells in this element
2019-10-05 23:16:08 +05:30
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-10-08 13:00:32 +05:30
case ( 2 ) ! 2D 4node
forall ( i = 1 : theMesh % elem % nIPs ) & ! loop over ips=cells in this element
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
2019-10-05 23:16:08 +05:30
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-10-08 13:00:32 +05:30
case ( 3 ) ! 3D 4node
forall ( i = 1 : theMesh % elem % nIPs ) & ! loop over ips=cells in this element
2019-10-05 23:16:08 +05:30
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-10-08 13:00:32 +05:30
case ( 4 ) ! 3D 8node
do i = 1 , theMesh % elem % nIPs ! loop over ips=cells in this element
2019-10-05 23:16:08 +05:30
subvolume = 0.0_pReal
forall ( f = 1 : FE_NipNeighbors ( c ) , n = 1 : m ) &
subvolume ( n , f ) = math_volTetrahedron ( &
mesh_cellnode ( 1 : 3 , mesh_cell ( theMesh % elem % cellface ( n , f ) , i , e ) ) , &
mesh_cellnode ( 1 : 3 , mesh_cell ( theMesh % elem % cellface ( 1 + mod ( n , m ) , f ) , i , e ) ) , &
mesh_cellnode ( 1 : 3 , mesh_cell ( theMesh % elem % cellface ( 1 + mod ( n + 1 , m ) , f ) , i , e ) ) , &
mesh_ipCoordinates ( 1 : 3 , i , e ) )
2019-10-08 13:00:32 +05:30
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
2019-10-05 23:16:08 +05:30
enddo
2009-10-12 21:31:49 +05:30
2019-10-05 23:16:08 +05:30
end select
enddo
2019-02-02 21:54:00 +05:30
2019-10-05 23:16:08 +05:30
end function IPvolume
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 22:23:02 +05:30
integer , dimension ( : , : ) , allocatable :: faces
integer , dimension ( : ) , allocatable :: face
2019-06-06 11:07:37 +05:30
integer :: e , i , f , c , m , n , j , k , l , p , current , next , i2 , e2 , n2 , k2
logical :: match
allocate ( faces ( size ( theMesh % elem % cellface , 1 ) + 3 , size ( theMesh % elem % cellface , 2 ) * theMesh % elem % nIPs * theMesh % Nelems ) )
2019-06-05 04:06:25 +05:30
2019-06-06 11:07:37 +05:30
! store cell face definitions
2019-06-05 22:23:02 +05:30
f = 0
2019-06-05 11:52:34 +05:30
do e = 1 , theMesh % nElems
do i = 1 , theMesh % elem % nIPs
2019-06-05 22:23:02 +05:30
do n = 1 , theMesh % elem % nIPneighbors
f = f + 1
face = mesh_cell2 ( theMesh % elem % cellFace ( : , n ) , i , e )
2019-06-06 11:07:37 +05:30
storeSorted : do j = 1 , size ( face )
2019-06-05 22:23:02 +05:30
faces ( j , f ) = maxval ( face )
face ( maxloc ( face ) ) = - huge ( 1 )
2019-06-06 11:07:37 +05:30
enddo storeSorted
faces ( j : j + 2 , f ) = [ e , i , n ]
2019-06-05 22:23:02 +05:30
enddo
2019-06-05 11:52:34 +05:30
enddo
enddo
2019-06-05 22:23:02 +05:30
! sort ..
call math_sort ( faces , sortDim = 1 )
do p = 2 , size ( faces , 1 ) - 2
n = 1
do while ( n < = size ( faces , 2 ) )
j = 0
do while ( n + j < = size ( faces , 2 ) )
if ( faces ( p - 1 , n + j ) / = faces ( p - 1 , n ) ) exit
j = j + 1
enddo
e = n + j - 1
if ( any ( faces ( p , n : e ) / = faces ( p , n ) ) ) call math_sort ( faces ( : , n : e ) , sortDim = p )
n = e + 1
enddo
enddo
2019-06-06 11:07:37 +05:30
allocate ( mesh_ipNeighborhood2 ( 3 , theMesh % elem % nIPneighbors , theMesh % elem % nIPs , theMesh % nElems ) , source = 0 )
! find IP neighbors
f = 1
do while ( f < = size ( faces , 2 ) )
e = faces ( size ( theMesh % elem % cellface , 1 ) + 1 , f )
i = faces ( size ( theMesh % elem % cellface , 1 ) + 2 , f )
n = faces ( size ( theMesh % elem % cellface , 1 ) + 3 , f )
if ( f < size ( faces , 2 ) ) then
match = all ( faces ( 1 : size ( theMesh % elem % cellface , 1 ) , f ) == faces ( 1 : size ( theMesh % elem % cellface , 1 ) , f + 1 ) )
e2 = faces ( size ( theMesh % elem % cellface , 1 ) + 1 , f + 1 )
i2 = faces ( size ( theMesh % elem % cellface , 1 ) + 2 , f + 1 )
n2 = faces ( size ( theMesh % elem % cellface , 1 ) + 3 , f + 1 )
else
match = . false .
endif
if ( match ) then
if ( e == e2 ) then ! same element. MD: I don't think that we need this (not even for other elements)
k = theMesh % elem % IPneighbor ( n , i )
k2 = theMesh % elem % IPneighbor ( n2 , i2 )
endif
mesh_ipNeighborhood2 ( 1 : 3 , n , i , e ) = [ e2 , i2 , n2 ]
mesh_ipNeighborhood2 ( 1 : 3 , n2 , i2 , e2 ) = [ e , i , n ]
f = f + 1
endif
f = f + 1
enddo
2019-06-05 04:06:25 +05:30
end subroutine IP_neighborhood2
2012-06-15 21:40:21 +05:30
!--------------------------------------------------------------------------------------------------
2019-10-05 23:16:08 +05:30
!> @brief Calculates IP Coordinates.
! Marc however only provides nodal displacements,
2019-02-02 21:54:00 +05:30
! 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.
! !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
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-10-08 13:00:32 +05:30
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
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-10-08 22:22:34 +05:30
subroutine mesh_build_ipAreas ( ipArea , ipAreaNormal )
2010-05-06 22:10:47 +05:30
2019-10-05 21:07:14 +05:30
integer :: e , c , i , f , n , m
2019-10-08 22:22:34 +05:30
real ( pReal ) , dimension ( theMesh % elem % nIPneighbors , theMesh % elem % nIPs , theMesh % nElems ) , intent ( out ) :: ipArea
real ( pReal ) , dimension ( 3 , theMesh % elem % nIPneighbors , theMesh % elem % nIPs , theMesh % nElems ) , intent ( out ) :: ipAreaNormal
2019-01-24 14:34:43 +05:30
real ( pReal ) , dimension ( 3 , FE_maxNcellnodesPerCellface ) :: nodePos , normals
real ( pReal ) , dimension ( 3 ) :: normal
2019-10-05 21:07:14 +05:30
c = theMesh % elem % cellType
2013-04-15 13:43:20 +05:30
2019-10-08 13:00:32 +05:30
do e = 1 , theMesh % nElems ! loop over cpElems
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
2019-10-08 13:33:03 +05:30
forall ( n = 1 : size ( theMesh % elem % cellface , 1 ) ) &
2019-06-13 12:39:51 +05:30
nodePos ( 1 : 3 , n ) = mesh_cellnode ( 1 : 3 , mesh_cell ( theMesh % elem % cellface ( n , f ) , 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
2019-10-08 22:22:34 +05:30
ipArea ( f , i , e ) = norm2 ( normal )
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
2019-10-08 13:33:03 +05:30
forall ( n = 1 : size ( theMesh % elem % cellface , 1 ) ) &
2019-06-13 12:39:51 +05:30
nodePos ( 1 : 3 , n ) = mesh_cellnode ( 1 : 3 , mesh_cell ( theMesh % elem % cellface ( n , f ) , i , e ) )
2019-05-10 18:49:00 +05:30
normal = math_cross ( nodePos ( 1 : 3 , 2 ) - nodePos ( 1 : 3 , 1 ) , &
2019-09-24 10:43:52 +05:30
nodePos ( 1 : 3 , 3 ) - nodePos ( 1 : 3 , 1 ) )
2019-10-08 22:22:34 +05:30
ipArea ( f , i , e ) = norm2 ( normal )
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
2019-10-08 13:33:03 +05:30
m = size ( theMesh % elem % cellFace , 1 )
2019-05-15 02:14:38 +05:30
do i = 1 , theMesh % elem % nIPs
do f = 1 , FE_NipNeighbors ( c ) ! loop over cell faces
2019-10-08 13:33:03 +05:30
forall ( n = 1 : size ( theMesh % elem % cellface , 1 ) ) &
2019-06-13 12:39:51 +05:30
nodePos ( 1 : 3 , n ) = mesh_cellnode ( 1 : 3 , mesh_cell ( theMesh % elem % cellface ( n , f ) , i , e ) )
2019-10-08 13:33:03 +05:30
forall ( n = 1 : size ( theMesh % elem % cellface , 1 ) ) &
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 ) , &
2019-09-24 10:43:52 +05:30
nodePos ( 1 : 3 , 1 + mod ( n + 1 , m ) ) - nodePos ( 1 : 3 , n ) )
2013-04-15 13:43:20 +05:30
normal = 0.5_pReal * sum ( normals , 2 )
2019-10-08 22:22:34 +05:30
ipArea ( f , i , e ) = norm2 ( normal )
ipAreaNormal ( 1 : 3 , f , i , e ) = normal / norm2 ( normal )
2013-04-15 13:43:20 +05:30
enddo
enddo
end select
enddo
2019-10-08 13:00:32 +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
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
2019-06-16 00:12:16 +05:30
character ( len = * ) , intent ( in ) :: what
integer , intent ( in ) :: myID
integer , dimension ( : , : ) , pointer :: lookupMap
integer :: lower , upper , center
mesh_FEasCP = 0
select case ( IO_lc ( what ( 1 : 4 ) ) )
case ( 'elem' )
lookupMap = > mesh_mapFEtoCPelem
case ( 'node' )
lookupMap = > mesh_mapFEtoCPnode
case default
return
endselect
lower = 1
upper = int ( size ( lookupMap , 2 ) , pInt )
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 )
return
elseif ( lookupMap ( 1 , upper ) == myID ) then
mesh_FEasCP = lookupMap ( 2 , upper )
return
endif
binarySearch : do while ( upper - lower > 1 )
center = ( lower + upper ) / 2
if ( lookupMap ( 1 , center ) < myID ) then
lower = center
elseif ( lookupMap ( 1 , center ) > myID ) then
upper = center
else
mesh_FEasCP = lookupMap ( 2 , center )
exit
endif
enddo binarySearch
2019-02-02 21:54:00 +05:30
end function mesh_FEasCP
2012-08-16 20:25:23 +05:30
end module mesh