summaryrefslogtreecommitdiff
path: root/Dragon/src/SAL_GEOMETRY_MOD.f90
diff options
context:
space:
mode:
authorstainer_t <thomas.stainer@oecd-nea.org>2025-09-08 13:48:49 +0200
committerstainer_t <thomas.stainer@oecd-nea.org>2025-09-08 13:48:49 +0200
commit7dfcc480ba1e19bd3232349fc733caef94034292 (patch)
tree03ee104eb8846d5cc1a981d267687a729185d3f3 /Dragon/src/SAL_GEOMETRY_MOD.f90
Initial commit from Polytechnique Montreal
Diffstat (limited to 'Dragon/src/SAL_GEOMETRY_MOD.f90')
-rw-r--r--Dragon/src/SAL_GEOMETRY_MOD.f903756
1 files changed, 3756 insertions, 0 deletions
diff --git a/Dragon/src/SAL_GEOMETRY_MOD.f90 b/Dragon/src/SAL_GEOMETRY_MOD.f90
new file mode 100644
index 0000000..373c95d
--- /dev/null
+++ b/Dragon/src/SAL_GEOMETRY_MOD.f90
@@ -0,0 +1,3756 @@
+!
+!---------------------------------------------------------------------
+!
+!Purpose:
+! Support module used to create a 2D geometry.
+!
+!Copyright:
+! Copyright (C) 2001 Ecole Polytechnique de Montreal.
+!
+!Author(s):
+! X. Warin
+!
+!---------------------------------------------------------------------
+!
+MODULE SAL_GEOMETRY_MOD
+
+ USE SAL_GEOMETRY_TYPES
+ USE PRECISION_AND_KINDS, ONLY : PDB, PI,TWOPI,HALFPI
+ USE SAL_NUMERIC_MOD, ONLY : SAL141
+ USE SALGET_FUNS_MOD
+
+CONTAINS
+
+ SUBROUTINE SAL100(GG)
+ !
+ !---------------------------------------------------------------------
+ !
+ !Purpose:
+ ! perform input data and first allocation for geometry OBJECT T_G_BASIC
+ !
+ !Parameters: input/output
+ ! GG geometry basic information.
+ !
+ !---------------------------------------------------------------------
+ !
+ USE SAL_GEOMETRY_TYPES, ONLY : T_G_BASIC,TYPGEO,NBFOLD,EPS,ANGGEO, &
+ INDEX,KNDEX,PREC,ISPEC,LGSPEC
+ USE SAL_TRACKING_TYPES, ONLY : PRTIND
+ IMPLICIT NONE
+ TYPE(T_G_BASIC) :: GG
+ !*****
+ ! local variable
+ ! **************
+ INTEGER, PARAMETER :: N_DATAIN=25, N_DATARE=20
+ INTEGER, DIMENSION (N_DATAIN) :: DATAIN
+ REAL, DIMENSION (N_DATARE) :: DATARE
+ INTEGER :: OK
+ INTEGER, PARAMETER :: FOUT =6
+ !*****
+ ! TYPGEO = type of geometry:
+ ! NBFOLD = n in angle definition of rotation or symmetry geometry
+ ! NB_NODE = number of nodes
+ ! NBELEM = number of elements
+ !
+ CALL SALGET(DATAIN,6,F_GEO,FOUT0,'dimensions for geometry')
+ TYPGEO=DATAIN(1)
+ NBFOLD=DATAIN(2)
+ GG%NB_NODE=DATAIN(3)
+ GG%NB_ELEM=DATAIN(4)
+ GG%NB_MACRO=DATAIN(5)
+ GG%NB_FLUX=DATAIN(6)
+ ANGGEO=0.0D0
+ SELECT CASE(TYPGEO)
+ CASE(1)
+ IF(NBFOLD.EQ.3) THEN
+ ANGGEO=TWOPI/8.0D0 ! half diagonal symmetry case
+ ELSE
+ ANGGEO=TWOPI/NBFOLD
+ ENDIF
+ CASE(2)
+ ANGGEO=TWOPI/NBFOLD
+ CASE(5:6)
+ ANGGEO=HALFPI
+ CASE(7)
+ ANGGEO=PI*0.25
+ CASE(8:11)
+ ANGGEO=PI/3.
+ CASE(12)
+ ANGGEO=PI/6.
+ END SELECT
+ IF((PRTIND >= 1).AND.(TYPGEO.EQ.0)) THEN
+ WRITE(FOUT,*) 'SAL100: TYPGEO=',TYPGEO,' NBFOLD=',NBFOLD
+ ELSE IF(PRTIND >= 1) THEN
+ WRITE(FOUT,*) 'SAL100: TYPGEO=',TYPGEO,' NBFOLD=',NBFOLD, &
+ & ' ANGGEO=',ANGGEO,' radians'
+ ENDIF
+ LGSPEC=(TYPGEO/=0).AND.(NBFOLD==0)
+ IF(LGSPEC) THEN
+ IF(ISPEC==0) THEN
+ WRITE(*,*) 'SAL100: TYPGEO=',TYPGEO,' NBFOLD=',NBFOLD
+ CALL XABORT('SAL100: TISO option is incompatible with the surfacic file')
+ ENDIF
+ ELSE
+ IF(ISPEC==1) THEN
+ WRITE(*,*) 'SAL100: TYPGEO=',TYPGEO,' NBFOLD=',NBFOLD
+ CALL XABORT('SAL100: TSPC option is incompatible with the surfacic file')
+ ENDIF
+ ENDIF
+ !
+ !* read printing indexes for general domain data and topological deformations
+ ! INDEX = to print general domain data
+ ! KNDEX = to print motions of topological adjustment
+ ! PREC = if 0 then read RPAR & BCDATA with e20.12)
+ CALL SALGET(DATAIN,3,F_GEO,FOUT0,'index kndex prec')
+ INDEX=DATAIN(1)
+ KNDEX=DATAIN(2)
+ PREC=DATAIN(3)
+ !
+ !* read epsilons for topological deformations
+ ! EPS = if the distance of two ends of elements < eps,
+ ! they will be united to one point
+ CALL SALGET(DATARE,1,F_GEO,FOUT0,'eps')
+ EPS=DATARE(1)
+ !
+ IF(PRTIND >= 1) THEN
+ WRITE(FOUT,'(//,5X,''domain checkout:'',/, &
+ & 5X,''elements are in contact for distance < '',1P,E12.4,//)') EPS
+ ENDIF
+ !
+ ALLOCATE(GG%NUM_MERGE(GG%NB_NODE),STAT =OK)
+ IF(OK /= 0) CALL XABORT('SAL100: failure to allocate NB_NODE')
+ CALL SALGET(GG%NUM_MERGE,GG%NB_NODE,F_GEO,FOUT0,'FLUX INDEX PER NODE')
+ IF(MAXVAL(GG%NUM_MERGE) /= GG%NB_FLUX) CALL XABORT('SAL100: inconsistent NBFLUX')
+ ALLOCATE(GG%NAME_MACRO(GG%NB_MACRO),STAT =OK)
+ IF(OK /= 0) CALL XABORT('SAL100: failure to allocate NB_MACRO')
+ CALL SALGET(GG%NAME_MACRO,GG%NB_MACRO,F_GEO,FOUT0,'NAMES OF MACROS')
+ ALLOCATE(GG%NUM_MACRO(GG%NB_FLUX))
+ CALL SALGET(GG%NUM_MACRO,GG%NB_FLUX,F_GEO,FOUT0,'macro order number per flux region')
+ !* do the work (SAL100_2 is called here!):
+ CALL SAL110(GG)
+ !
+ END SUBROUTINE SAL100
+ !
+ SUBROUTINE SAL110(GG)
+ !
+ !---------------------------------------------------------------------
+ !
+ !Purpose:
+ ! constructs geometrical domain
+ !
+ !Parameters: input/output
+ ! GG geometry basic information.
+ !
+ !---------------------------------------------------------------------
+ !
+ USE SAL_GEOMETRY_TYPES, ONLY : TYPGEO,NBFOLD,NIPAR,NRPAR,ALLSUR,NANIS,IC,ISPEC,ANGGEO
+ USE SAL_TRACKING_TYPES, ONLY : PRTIND
+ !****
+ IMPLICIT NONE
+ ! in variable
+ ! ************
+ TYPE(T_G_BASIC), INTENT(INOUT) :: GG
+
+ ! local variable
+ ! ***************
+ INTEGER :: ELEM,OK,I,TYPE
+ CHARACTER(LEN=4) :: HSYM
+ REAL(PDB),PARAMETER :: CONV=PI/180._PDB
+ INTEGER, PARAMETER :: FOUT =6
+ !****
+ ! allocate node arrays
+ HSYM=' '
+ IF((TYPGEO==0).OR.((TYPGEO==6).AND.(NBFOLD==0))) THEN
+ CONTINUE
+ ELSE IF((TYPGEO==1).AND.(NBFOLD==3)) THEN
+ HSYM='QUAR'
+ ELSE IF(((TYPGEO==1).AND.(NBFOLD==8)).OR.((TYPGEO==7).AND.(NBFOLD==0))) THEN
+ HSYM='EIGH'
+ ELSE IF(((TYPGEO==1).AND.(NBFOLD==6)).OR.((TYPGEO==8).AND.(NBFOLD==0))) THEN
+ HSYM='SIXT'
+ ELSE IF(((TYPGEO==1).AND.(NBFOLD==12)).OR.((TYPGEO==12).AND.(NBFOLD==0))) THEN
+ HSYM='S30'
+ ELSE IF(((TYPGEO==1).AND.(NBFOLD==4)).OR.((TYPGEO==3).AND.(NBFOLD==0))) THEN
+ HSYM='SYME'
+ ELSE IF((TYPGEO==1).AND.(NBFOLD==2)) THEN
+ HSYM='SY1D'
+ ELSE IF(((TYPGEO==2).AND.(NBFOLD==6)).OR.((TYPGEO==10).AND.(NBFOLD==0))) THEN
+ HSYM='RA60'
+ ELSE IF((TYPGEO==5).AND.(NBFOLD==0)) THEN
+ HSYM='TRAN'
+ ELSE IF((TYPGEO==9).AND.(NBFOLD==0)) THEN
+ HSYM='TRAN'
+ ELSE IF(((TYPGEO==2).AND.(NBFOLD==3)).OR.(TYPGEO==11).AND.(NBFOLD==0)) THEN
+ HSYM='R120'
+ ELSE
+ WRITE(*,*) "TYPGEO=",TYPGEO," NBFOLD=",NBFOLD
+ CALL XABORT('SAL110: non supported type of symmetry')
+ ENDIF
+ ALLOCATE (GG%IPAR(NIPAR,GG%NB_ELEM), GG%RPAR(NRPAR,GG%NB_ELEM), STAT=OK)
+ IF(OK/=0) CALL XABORT('SAL110: not enough memory I,R')
+
+ !* read surfacic file
+ CALL SALINP(GG)
+ !
+ !* unite the ends of elements, redefine elements
+ CALL SAL128(GG%RPAR,GG%IPAR,GG%NB_ELEM)
+ !
+ IF((ISPEC==0).AND.(IC.EQ.4)) THEN
+ !* unfold domain
+ IF(HSYM=='QUAR') THEN
+ IF(PRTIND>0) WRITE(*,*) "SAL110: DIAG unfold"
+ IF(NANIS>1) CALL XABORT('SAL110: unfold unsupported with NANIS>1')
+ ANGGEO=2.0*ANGGEO
+ CALL SALFOLD_1('DIAG',GG)
+ ELSE IF(HSYM=='EIGH') THEN
+ IF(PRTIND>0) WRITE(*,*) "SAL110: DIAG + SYME unfold"
+ IF(NANIS>1) CALL XABORT('SAL110: unfold unsupported with NANIS>1')
+ ANGGEO=2.0*ANGGEO
+ CALL SALFOLD_1('DIAG',GG)
+ CALL SALFOLD_1('SYMX',GG)
+ CALL SALFOLD_1('SYMY',GG)
+ ELSE IF(HSYM=='SYME') THEN
+ IF(PRTIND>0) WRITE(*,*) "SAL110: SYME unfold"
+ IF(NANIS>1) CALL XABORT('SAL110: unfold unsupported with NANIS>1')
+ CALL SALFOLD_1('SYMX',GG)
+ CALL SALFOLD_1('SYMY',GG)
+ ELSE IF(HSYM=='SY1D') THEN
+ IF(PRTIND>0) WRITE(*,*) "SAL110: SY1D unfold"
+ IF(NANIS>1) CALL XABORT('SAL110: unfold unsupported with NANIS>1')
+ CALL SALFOLD_1('SYMX',GG)
+ ELSE IF(HSYM=='SIXT') THEN
+ IF(PRTIND>0) WRITE(*,*) "SAL110: SA60 unfold"
+ IF(NANIS>1) CALL XABORT('SAL110: unfold unsupported with NANIS>1')
+ CALL SALFOLD_1('SA60',GG)
+ CALL SALFOLD_1('SYMH',GG)
+ ELSE IF(HSYM=='S30') THEN
+ IF(PRTIND>0) WRITE(*,*) "SAL110: S30 unfold"
+ IF(NANIS>1) CALL XABORT('SAL110: unfold unsupported with NANIS>1')
+ CALL SALFOLD_1('S30 ',GG)
+ CALL SALFOLD_1('SB60',GG)
+ CALL SALFOLD_1('SYMX',GG)
+ ELSE IF(HSYM=='RA60') THEN
+ IF(PRTIND>0) WRITE(*,*) "SAL110: SR60 unfold with rotation"
+ IF(NANIS>1) CALL XABORT('SAL110: unfold unsupported with NANIS>1')
+ CALL SALFOLD_2('SR60',GG)
+ CALL SALFOLD_2('R180',GG)
+ ELSE IF(HSYM=='R120') THEN
+ IF(PRTIND>0) WRITE(*,*) "SAL110: SR120 unfold with rotation"
+ IF(NANIS>1) CALL XABORT('SAL110: unfold unsupported with NANIS>1')
+ CALL SALFOLD_2('R120',GG)
+ ELSE
+ IF(PRTIND>0) WRITE(*,*) "SAL110: no unfold"
+ ENDIF
+ IF((TYPGEO/=0).AND.(NBFOLD==0)) THEN
+ TYPGEO=6
+ ELSE
+ TYPGEO=0; NBFOLD=0
+ ENDIF
+ ENDIF
+ IF(PRTIND>0) WRITE(FOUT,*) 'SAL110: after unfolding -- NB_ELEM=',GG%NB_ELEM, &
+ & ' NB_PERIM=',GG%NBBCDA
+
+ IF(PRTIND>5) THEN
+ !* print surfacic file
+ WRITE(FOUT,'(5H--cut,75(1H-))')
+ WRITE(FOUT,'(5HBEGIN)')
+ WRITE(FOUT,'(42H* typgeo nbfold nbnode nbelem nbmacr nbreg)')
+ WRITE(FOUT,'(6I7)') TYPGEO,NBFOLD,GG%NB_NODE,GG%NB_ELEM,GG%NB_MACRO,GG%NB_NODE
+ WRITE(FOUT,'(20H* index kndex prec)')
+ WRITE(FOUT,'(4I7)') 0,0,1
+ WRITE(FOUT,'(18H* eps eps0)')
+ WRITE(FOUT,'(1P,2E18.9)') 1.0E-03,1.0E-05
+ WRITE(FOUT,'(20H* num_of_region/mesh)')
+ WRITE(FOUT,'(10I7)') (GG%NUM_MERGE(I),I=1,GG%NB_NODE)
+ WRITE(FOUT,'(13H* macro names)')
+ WRITE(FOUT,'(4(3x,a10,2x))') (GG%NAME_MACRO(I),I=1,GG%NB_MACRO)
+ WRITE(FOUT,'(35H* macro_order_index_per_flux_region)')
+ WRITE(FOUT,'(10I7)') (GG%NUM_MACRO(I),I=1,GG%NB_FLUX)
+ DO ELEM=1,GG%NB_ELEM
+ TYPE=GG%IPAR(1,ELEM)
+ WRITE(FOUT,'(7h elem =,I6)') ELEM
+ WRITE(FOUT,'(22H*type node- node+)')
+ WRITE(FOUT,'(3I6)') (GG%IPAR(I,ELEM),I=1,3)
+ WRITE(FOUT,'(63H*cx cy ex_or_R ey_or_theta1 theta2)')
+ IF(TYPE<=2) THEN
+ WRITE(FOUT,'(1P,5E18.9)') (GG%RPAR(I,ELEM),I=1,5)
+ ELSE IF(TYPE==3) THEN
+ WRITE(FOUT,'(1P,5E18.9)') (GG%RPAR(I,ELEM),I=1,3),GG%RPAR(4,ELEM)/CONV, &
+ (GG%RPAR(5,ELEM)-GG%RPAR(4,ELEM))/CONV
+ ENDIF
+ ENDDO
+ WRITE(FOUT,'(40H*defaul nbbcda allsur divsur ndivsur)')
+ WRITE(FOUT,'(1P,5I8)') GG%DEFAUL,GG%NBBCDA,ALLSUR,0,0
+ WRITE(FOUT,'(17H*albedo deltasur)')
+ WRITE(FOUT,'(1P,2E18.9)') GG%ALBEDO,0.0
+ DO ELEM=1,GG%NBBCDA
+ WRITE(FOUT,'(37H particular boundary condition number,i12)') ELEM
+ WRITE(FOUT,'(13H*type nber)')
+ WRITE(FOUT,'(1P,2I8)') GG%BCDATAREAD(ELEM)%SALTYPE,GG%BCDATAREAD(ELEM)%NBER
+ WRITE(FOUT,'(14H*elems(1,nber))')
+ WRITE(FOUT,'(1P,10I8)') (GG%BCDATAREAD(ELEM)%ELEMNB(I),I=1,GG%BCDATAREAD(ELEM)%NBER)
+ IF(GG%BCDATAREAD(ELEM)%SALTYPE==0) THEN
+ WRITE(FOUT,'(7H*albedo)')
+ WRITE(FOUT,'(1P,E18.9)') GG%BCDATAREAD(ELEM)%BCDATA(6)
+ ELSE
+ WRITE(FOUT,'(22H*cx cy angle)')
+ WRITE(FOUT,'(1P,3E18.9)') GG%BCDATAREAD(ELEM)%BCDATA(1:2),GG%BCDATAREAD(ELEM)%BCDATA(5)*180._PDB/PI
+ ENDIF
+ ENDDO
+ ENDIF
+
+ ! allocate media and element arrays
+ ALLOCATE (GG%VOL_NODE(GG%NB_NODE),GG%PPERIM_NODE(GG%NB_NODE+1),GG%IBC2_ELEM(GG%NB_ELEM), &
+ GG%ISURF2_ELEM(GG%NB_ELEM),GG%MED(GG%NB_NODE), STAT=OK)
+ IF(OK/=0) CALL XABORT('SAL110: not enough memory VOL')
+ GG%ISURF2_ELEM(:GG%NB_ELEM)=0
+
+ !* 2D boundary conditions and macro contacts:
+ ! - defines NB_BC2, NBSUR2
+ ! - defines surface strctures for each 2D macro
+ ! - defines perimeter structure for each 2D macro
+ ! - read 2D boundary conditions
+ CALL SAL130(GG)
+ !
+ !* topological check
+ CALL SAL140(GG%NB_NODE,GG%RPAR,GG%IPAR,GG%PPERIM_NODE,GG%PERIM_NODE)
+ !
+ !* volumes, surfaces, put local nbers in node, and read media:
+ CALL SAL160(GG)
+ IF(PRTIND>5) THEN
+ WRITE(FOUT,'(12H* mil(nbreg))')
+ WRITE(FOUT,'(10I7)') (GG%MED(I),I=1,GG%NB_NODE)
+ WRITE(FOUT,'(3HEND)')
+ WRITE(FOUT,'(5H--cut,75(1H-))')
+ ENDIF
+ !
+ !* printout basic domain
+ CALL SAL170(GG)
+ !
+ END SUBROUTINE SAL110
+ !
+ SUBROUTINE SALINP(GG)
+ !
+ !---------------------------------------------------------------------
+ !
+ !Purpose:
+ ! read surfacic file
+ !
+ !Parameters: input/output
+ ! GG geometry descriptor
+ !
+ !---------------------------------------------------------------------
+ !
+ USE SAL_GEOMETRY_TYPES, ONLY : ALLSUR,PREC
+ !****
+ IMPLICIT NONE
+ ! in variable
+ ! ************
+ TYPE(T_G_BASIC), INTENT(INOUT) :: GG
+ !****
+ INTEGER, PARAMETER :: N_DATAIN=25
+ INTEGER, DIMENSION (N_DATAIN) :: DATAIN
+ INTEGER :: ELEM,I,TYPE,NBER
+ INTEGER, PARAMETER, DIMENSION(0:4) :: READ_BC_LEN=(/1,1,3,3,3/)
+ INTEGER, PARAMETER :: FOUT =6
+ REAL(PDB) :: ANGLE,BCDATA_TDT(3)
+ !
+ !* read element data
+ DO ELEM=1,GG%NB_ELEM
+ CALL SAL126(GG%RPAR(:,ELEM),GG%IPAR(:,ELEM))
+ ENDDO
+ !* read
+ ! DEFAUL = default bc condition
+ ! 0 = all external surfaces are isotropically reflected
+ ! with the same ALBEDO = ALBED0
+ ! 1 = all external surfaces are reflected
+ ! NBBCDA = number of groups of bc conditions
+ !
+ CALL SALGET(DATAIN,3,F_GEO,FOUT0,'general bc data')
+ GG%DEFAUL=DATAIN(1)
+ GG%NBBCDA=DATAIN(2)
+ ALLSUR=DATAIN(3)
+ ! we can define only two default bc's
+ IF(GG%DEFAUL>4.OR.GG%DEFAUL<0) THEN
+ WRITE(FOUT,'(8H defaul=,I5)') GG%DEFAUL
+ CALL XABORT('SALINP: wrong default bc type')
+ ENDIF
+ !* read albedo : defaul bcdata
+ CALL SALGET(GG%ALBEDO,F_GEO,FOUT0,PREC,'GENERAL ALBEDO')
+ !
+ !* read detailed bcdata if required (motions)
+ LBCDIAG=.FALSE.
+ IF(GG%NBBCDA>0)THEN
+ ALLOCATE(GG%BCDATAREAD(GG%NBBCDA))
+ DO I=1,GG%NBBCDA
+ GG%BCDATAREAD(I)%BCDATA(:6)=0.0
+ CALL SALGET(DATAIN,2,F_GEO,FOUT0,'SPECIFIC BC: TYPE NBER')
+ TYPE=DATAIN(1)
+ NBER=DATAIN(2)
+ GG%BCDATAREAD(I)%SALTYPE=TYPE
+ GG%BCDATAREAD(I)%NBER=NBER
+ IF(TYPE>5.OR.TYPE<0) CALL XABORT('SALINP: wrong bc type')
+ IF(NBER>GG%NB_ELEM) CALL XABORT('SALINP: bc def exceeds nber of elements')
+ !
+ ! read order numbers of elements affected
+ ALLOCATE(GG%BCDATAREAD(I)%ELEMNB(NBER))
+ CALL SALGET(GG%BCDATAREAD(I)%ELEMNB,NBER,F_GEO,FOUT0,'BC ELEMENTS')
+ ! read bc motion
+ CALL SALGET(BCDATA_TDT,READ_BC_LEN(TYPE),F_GEO,FOUT0,PREC,'data for specific bc condition')
+ IF(READ_BC_LEN(TYPE).EQ.1) THEN
+ GG%BCDATAREAD(I)%BCDATA(1:5)=0._PDB
+ GG%BCDATAREAD(I)%BCDATA(6)=BCDATA_TDT(1)
+ ELSE
+ GG%BCDATAREAD(I)%BCDATA(1:2)=BCDATA_TDT(1:2)
+ ANGLE=BCDATA_TDT(3)*PI/180._PDB
+ GG%BCDATAREAD(I)%BCDATA(3)=COS(ANGLE)
+ GG%BCDATAREAD(I)%BCDATA(4)=SIN(ANGLE)
+ GG%BCDATAREAD(I)%BCDATA(5)=ANGLE
+ GG%BCDATAREAD(I)%BCDATA(6)=1._PDB
+ LBCDIAG=LBCDIAG.OR.((GG%BCDATAREAD(I)%BCDATA(1)==0._PDB).AND.(GG%BCDATAREAD(I)%BCDATA(2)==0._PDB) &
+ .AND.(GG%BCDATAREAD(I)%BCDATA(5)==PI/4._PDB))
+ ENDIF
+ ENDDO
+ ENDIF
+ END SUBROUTINE SALINP
+ !
+ SUBROUTINE SAL126(RPAR,IPAR)
+ !
+ !---------------------------------------------------------------------
+ !
+ !Purpose:
+ ! reads one element data
+ !
+ !Parameters: input/output
+ ! RPAR floating point geometry descriptors
+ ! IPAR integer geometry descriptors
+ !
+ !---------------------------------------------------------------------
+ !
+ !****
+ USE SAL_GEOMETRY_TYPES, ONLY : PREC,G_ELE_TYPE
+ !****
+ IMPLICIT NONE
+ ! in variable
+ INTEGER, INTENT(OUT), DIMENSION(:) :: IPAR
+ REAL(PDB), INTENT(INOUT), DIMENSION(:) :: RPAR
+ !****
+ ! local variable
+ INTEGER :: TYPE,NBER,IAUX
+ REAL(PDB) :: PHI1,PHI2,ANGMAX,DELPHI
+ !****
+ ! IPAR(1) = 1 (segment), 2 (circle), 3(arc of circle)
+ ! IPAR(2) = order nber of node in - side
+ ! IPAR(3) = order nber of node in + side
+ !
+ !* read integer element data
+ CALL SALGET(IPAR,3,F_GEO,FOUT0,'integer descriptors')
+ TYPE=IPAR(1)
+ !
+ ! ** segment:
+ ! R = C+T*F with T in (0,1)
+ ! RPAR(1~5) = CX CY FX FY F
+ !
+ ! ** arc of circle:
+ ! R = C+R*F(THETA) with
+ ! THETA in (THETA1 < THETA2)
+ ! with THETA1 in (0,360)
+ ! RPAR(1~5) = CX CY R THETA1 THETA2 (in degrees)
+ !
+ !* read real element data
+
+ IF(TYPE == G_ELE_TYPE(1)) THEN
+ NBER=4
+ ELSE IF(TYPE == G_ELE_TYPE(2)) THEN
+ NBER=3
+ ELSE IF(TYPE == G_ELE_TYPE(3)) THEN
+ NBER=5
+ ANGMAX=360._PDB
+ ELSE
+ WRITE(FOUT0,'(1X,''==> SAL126: unknown type '',I3)') TYPE
+ CALL XABORT('SAL126: unknown element type')
+ ENDIF
+
+ CALL SALGET(RPAR,NBER,F_GEO,FOUT0,PREC,'real descriptors')
+
+ IF(TYPE == G_ELE_TYPE(1)) THEN
+ ! segment: compute length
+ RPAR(5)=SQRT(RPAR(3)*RPAR(3)+RPAR(4)*RPAR(4))
+ RPAR(6)=0._PDB
+ ELSE IF(TYPE == G_ELE_TYPE(2)) THEN
+ ! full circle: set angles
+ RPAR(4)=0._PDB
+ RPAR(5)=TWOPI
+ RPAR(6)=0._PDB
+ ELSE IF((TYPE == G_ELE_TYPE(3)).OR.(TYPE == G_ELE_TYPE(4))) THEN
+ ! check angles
+ PHI1=RPAR(NBER-1)
+ DELPHI=RPAR(NBER)
+ ! order angles in increasing values:
+ IF(DELPHI>0._PDB)THEN
+ IF(DELPHI>ANGMAX)THEN
+ WRITE(FOUT0,'(1X,''==> SAL126: DELPHI = '',1P,E12.4, &
+ &'' > '',1P,E12.4,'' FOR TYPE'',I3)')DELPHI,ANGMAX,TYPE
+ CALL XABORT('SAL126: invalid value of delphi')
+ ENDIF
+ PHI2=PHI1+DELPHI
+ ELSE
+ IF(DELPHI<-ANGMAX)THEN
+ WRITE(FOUT0,'(1X,''==> SAL126: DELPHI = '',1P,E12.4, &
+ &'' < '',1P,E12.4,'' FOR TYPE'',I3)')DELPHI,-ANGMAX,TYPE
+ CALL XABORT('SAL126: invalid value of delphi')
+ ENDIF
+ PHI2=PHI1
+ PHI1=PHI1+DELPHI
+ ENDIF
+ IF(TYPE==G_ELE_TYPE(3))THEN
+ ! arc of circle: put phi1 within 0 and 360.
+ IF(PHI1>360._PDB)THEN
+ IAUX=INT(PHI1/360._PDB)
+ DELPHI=360._PDB*IAUX
+ PHI2=PHI2-DELPHI
+ PHI1=PHI1-DELPHI
+ ELSEIF(PHI1<0._PDB)THEN
+ IAUX=INT((-PHI1+1.D-7)/360._PDB)+1
+ DELPHI=360._PDB*IAUX
+ PHI2=PHI2+DELPHI
+ PHI1=PHI1+DELPHI
+ ENDIF
+ RPAR(6)=0._PDB
+ ELSE
+ CALL XABORT('SAL126: unsupported option')
+ ENDIF
+ ! convert to radians
+ RPAR(NBER-1)=PHI1*(TWOPI/360._PDB)
+ RPAR(NBER)=PHI2*(TWOPI/360._PDB)
+ ENDIF
+ !
+ END SUBROUTINE SAL126
+ !
+ SUBROUTINE SAL128(RPAR,IPAR,NB_ELEM)
+ !
+ !---------------------------------------------------------------------
+ !
+ !Purpose:
+ ! create library of ends of elements and redefine element discriptors
+ !
+ !Parameters: input/output
+ ! RPAR floating point geometry descriptors
+ ! IPAR integer geometry descriptors
+ ! NB_ELEM number of surfacic elements
+ !
+ !---------------------------------------------------------------------
+ !
+ !****
+ USE SAL_GEOMETRY_TYPES, ONLY : G_ELE_TYPE,EPS,KNDEX,TYPGEO
+ ! in variable
+ !************
+ IMPLICIT NONE
+ INTEGER, INTENT(IN), DIMENSION(:,:) :: IPAR
+ REAL(PDB), INTENT(INOUT), DIMENSION(:,:) :: RPAR
+ INTEGER , INTENT(IN) :: NB_ELEM
+ ! local variable
+ ! ***************
+ REAL(PDB), DIMENSION (:,:), ALLOCATABLE :: POINT ! coordinates of the ends of elements
+ INTEGER, DIMENSION (:,:), ALLOCATABLE :: ELEM_NEW ! point nbers of two ends of elements
+ !****
+ ! NN = total number of points
+ ! NBP = count of number of ends having the same coordinates
+ INTEGER :: TYPE,NN,ELEM,I,P,POS,I1,I2,OK
+ REAL(PDB) :: X(2),Y(2),D,DX,DY
+ REAL :: EPS2
+ LOGICAL :: LGONE
+ INTEGER, DIMENSION(NB_ELEM) :: NBP
+ INTEGER, PARAMETER :: FOUT =6
+ !****
+ ! - POINT(2,NB_ELEM) = coordinates of the ends of elements
+ ! - ELEM_NEW(2,NB_ELEM) = point nbers of two ends of elements
+ !
+ ALLOCATE(POINT(2,NB_ELEM),ELEM_NEW(2,NB_ELEM),STAT=OK)
+ IF(OK/=0) CALL XABORT('SAL100_3_1: not enough memory I,CH')
+
+ EPS2=EPS*EPS
+ IF(KNDEX/=0)WRITE(FOUT,'(//,&
+ &" reunite the ends of elements of distance less than ",E13.4)') EPS
+ !
+ !* nn counts the nber of points
+ NBP(1:NB_ELEM)=0
+ NN=0
+ DO ELEM=1,NB_ELEM
+ TYPE=IPAR(1,ELEM)
+ IF(TYPE/=G_ELE_TYPE(2)) THEN
+ DO I=1,2
+ ! get coordinates of end
+ CALL SAL141(TYPE,RPAR(:,ELEM),X(I),Y(I),I)
+ ! find if there is a defined neighbouring point
+ LGONE=.FALSE.
+ DO P=1,NN
+ DX=POINT(1,P)-X(I)
+ DY=POINT(2,P)-Y(I)
+ D=DX*DX+DY*DY
+ IF(D<EPS2) THEN
+ LGONE=.TRUE.
+ POS=P
+ EXIT
+ ENDIF
+ ENDDO
+ IF(LGONE) THEN
+ ! choose average value
+ X(I)=(X(I)+POINT(1,POS)*NBP(POS))/REAL(NBP(POS)+1)
+ Y(I)=(Y(I)+POINT(2,POS)*NBP(POS))/REAL(NBP(POS)+1)
+ ELSE
+ ! add points
+ NN=NN+1
+ IF(NN > NB_ELEM) CALL XABORT('SAL128: point overflow')
+ POS=NN
+ ENDIF
+ POINT(1,POS)=X(I)
+ POINT(2,POS)=Y(I)
+ NBP(POS)=NBP(POS)+1
+ ! define the end of element
+ ELEM_NEW(I,ELEM)=POS
+ ENDDO
+ ELSE
+ ELEM_NEW(1:2,ELEM)=0
+ ENDIF
+ ENDDO
+ !* adjust points on the axes
+ SELECT CASE(TYPGEO)
+ CASE(5:6)
+ CALL SAL128_3(NN,POINT,EPS,EPS2)
+ CASE(7)
+ CALL SAL128_4(NN,POINT,EPS,EPS2)
+ CASE(8,12)
+ CALL SAL128_5(NN,POINT,EPS,EPS2)
+ CASE(9)
+ CALL SAL128_6(NN,POINT,EPS,EPS2)
+ CASE(10)
+ CALL SAL128_7(NN,POINT,EPS,EPS2)
+ CASE(11)
+ CALL SAL128_8(NN,POINT,EPS,EPS2)
+ END SELECT
+
+ !* redefine the elements in rpar
+ IF(KNDEX/=0)WRITE(FOUT,'(/," redefine elements : ",/)')
+ DO ELEM=1,NB_ELEM
+ TYPE=IPAR(1,ELEM)
+ IF(TYPE/=G_ELE_TYPE(2)) THEN
+ I1=ELEM_NEW(1,ELEM)
+ I2=ELEM_NEW(2,ELEM)
+ CALL SAL129(POINT(1,I1),POINT(2,I1),POINT(1,I2),POINT(2,I2), &
+ TYPE,RPAR(:,ELEM),ELEM,KNDEX,FOUT)
+ ENDIF
+ ENDDO
+ !
+ DEALLOCATE(POINT,ELEM_NEW)
+ !
+ END SUBROUTINE SAL128
+ !
+ SUBROUTINE SAL128_3(NN,POINT,EPS,EPS2)
+ !
+ !---------------------------------------------------------------------
+ !
+ !Purpose:
+ ! process retangular geometry with translation or symmetry boundary condition
+ ! (TYPGEO=5,6): adjusts points on the axes, computes the lengths of the
+ ! retangle sides; in case of with translation,element lengths on the opposite
+ ! axes will be adjusted to be the same
+ !
+ !Parameters: input
+ ! NN total number of points
+ ! EPS when distance of points to axes less than EPS, displace
+ ! the points onto the axes
+ ! EPS2 variable set to EPS*EPS
+ !
+ !Parameters: input/output
+ ! POINT coordinates of points
+ !
+ !---------------------------------------------------------------------
+ !
+ USE PRECISION_AND_KINDS, ONLY : PDB
+ USE SAL_GEOMETRY_TYPES, ONLY : TYPGEO,KNDEX,LX=>LENGTHX,LY=>LENGTHY
+ !****
+ IMPLICIT NONE
+ INTEGER, INTENT(IN) :: NN
+ REAL, INTENT(IN) :: EPS,EPS2
+ REAL(PDB), INTENT(INOUT), DIMENSION(:,:) :: POINT
+ ! DIMENSION POINT(2,NN)
+ !****
+ INTEGER :: NP,NAXIS,I,J,K,M,P,IPOINT(4,NN),BP(4),IP(4)
+ LOGICAL :: LGADJUST
+ REAL(PDB) :: D,AUX,EX(4),EY(4),DIS(4),AX(4),AY(4),D_AXIS(4,NN)
+ INTEGER, PARAMETER :: FOUT =6
+ !****
+ ! flag to adjust the element lengths on the opposite axes
+ LGADJUST=TYPGEO==5
+ ! compute sides of the rectangle
+ LX=0.; LY=0.
+ DO P=1,NN
+ IF(ABS(POINT(1,P))<EPS) THEN
+ IF(LY<POINT(2,P)) LY=POINT(2,P)
+ ENDIF
+ IF(ABS(POINT(2,P))<EPS) THEN
+ IF(LX<POINT(1,P)) LX=POINT(1,P)
+ ENDIF
+ ENDDO
+ !* axis directions and their distance to (0,0)
+ NAXIS=4
+ EX(1)=1.; EY(1)=0.; DIS(1)=0.
+ EX(2)=1.; EY(2)=0.; DIS(2)=-LY
+ EX(3)=0.; EY(3)=1.; DIS(3)=0.
+ EX(4)=0.; EY(4)=1.; DIS(4)=LX
+ NP=4
+ AX(1)=0.; AY(1)=0.
+ AX(2)=0.; AY(2)=LY
+ AX(3)=LX; AY(3)=0.
+ AX(4)=LX; AY(4)=LY
+ ! beginning point of the axes
+ IF(LGADJUST) THEN
+ ! axis numbering:
+ ! M=2
+ ! ************
+ ! * *
+ ! M=3 * * M=4
+ ! ************
+ ! M=1
+ !
+ BP(1)=1; BP(2)=2; BP(3)=1; BP(4)=3
+ IP=0
+ ENDIF
+ ITER0:DO P=1,NN
+ DO I=1,NP
+ ! if it is the 4 corners of the rectangle
+ D=(POINT(1,P)-AX(I))**2+(POINT(2,P)-AY(I))**2
+ IF(D.LT.EPS2) THEN
+ ! move point to the corners
+ POINT(1,P)=AX(I) ; POINT(2,P)=AY(I)
+ IF(LGADJUST) THEN
+ ! put distance to the axis origin
+ SELECT CASE(I)
+ CASE(2)
+ ! end of axis 3,keep its distance and number
+ IP(3)=IP(3)+1
+ D_AXIS(3,IP(3))=AY(I)
+ IPOINT(3,IP(3))=P
+ CASE(3)
+ ! end of axis 1,keep its distance and number
+ IP(1)=IP(1)+1
+ D_AXIS(1,IP(1))=AX(I)
+ IPOINT(1,IP(1))=P
+ CASE(4)
+ ! end of axes 2&4,keep its distance and number
+ IP(2)=IP(2)+1
+ D_AXIS(2,IP(2))=AX(I)
+ IPOINT(2,IP(2))=P
+ IP(4)=IP(4)+1
+ D_AXIS(4,IP(4))=AY(I)
+ IPOINT(4,IP(4))=P
+ END SELECT
+ ENDIF
+ CYCLE ITER0
+ ENDIF
+ ENDDO
+ DO I=1,NAXIS
+ ! distance to the axis
+ D=POINT(1,P)*EY(I)-POINT(2,P)*EX(I)-DIS(I)
+ ! when aux>0,the point is near the half axis
+ AUX=POINT(1,P)*EX(I)+POINT(2,P)*EY(I)
+ IF(ABS(D).LT.EPS.AND.AUX>=0) THEN
+ ! move point to the axis
+ POINT(1,P)=POINT(1,P)-D*EY(I)
+ POINT(2,P)=POINT(2,P)+D*EX(I)
+ IF(LGADJUST) THEN
+ ! compute distance to the axis origin
+ D=SQRT((POINT(1,P)-AX(BP(I)))**2+(POINT(2,P)-AY(BP(I)))**2)
+ IP(I)=IP(I)+1
+ D_AXIS(I,IP(I))=D
+ IPOINT(I,IP(I))=P
+ ENDIF
+ CYCLE ITER0
+ ENDIF
+ ENDDO
+ ENDDO ITER0
+ !
+ IF(LGADJUST) THEN
+ DO I=1,NAXIS,2
+ IF(IP(I)/=IP(I+1)) &
+ CALL XABORT('SAL128_3: axial points nber not the same,axis')
+ ! sort the 'd_axis' table
+ DO J=I,I+1
+ DO P=1,IP(J)
+ DO K=P+1,IP(J)
+ IF(D_AXIS(J,P)>D_AXIS(J,K)) THEN
+ D=D_AXIS(J,P)
+ D_AXIS(J,P)=D_AXIS(J,K)
+ D_AXIS(J,K)=D
+ M=IPOINT(J,P)
+ IPOINT(J,P)=IPOINT(J,K)
+ IPOINT(J,K)=M
+ ENDIF
+ ENDDO
+ ENDDO
+ ENDDO
+ DO P=1,IP(I)
+ IF(ABS(D_AXIS(I,P)-D_AXIS(I+1,P))>EPS) THEN
+ IF(KNDEX/=0) &
+ WRITE(FOUT,'(" warning: too great axial length difference",&
+ & 2(/,2X,"axis = ",I3," point = ",I3," d = ",E13.6))')&
+ I,P,D_AXIS(I,P),I+1,P,D_AXIS(I+1,P)
+ ENDIF
+ D=(D_AXIS(I,P)+D_AXIS(I+1,P))*0.5
+ DO J=I,I+1
+ K=IPOINT(J,P)
+ POINT(1,K)=D*EX(J)+AX(BP(J))
+ POINT(2,K)=D*EY(J)+AY(BP(J))
+ ENDDO
+ ENDDO
+ ENDDO
+ ENDIF
+ !
+ END SUBROUTINE SAL128_3
+ !
+ SUBROUTINE SAL128_4(NN,POINT,EPS,EPS2)
+ !
+ !---------------------------------------------------------------------
+ !
+ !Purpose:
+ ! process a 1/8 square geometry (typgeo=7): adjusts points on the axes,
+ ! computes the square side length
+ !
+ !Parameters: input
+ ! NN total number of points
+ ! EPS when distance of points to axes less than EPS, displace
+ ! the points onto the axes
+ ! EPS2 variable set to EPS*EPS
+ !
+ !Parameters: input/output
+ ! POINT coordinates of points
+ !
+ !---------------------------------------------------------------------
+ !
+ USE PRECISION_AND_KINDS, ONLY : PDB
+ USE SAL_GEOMETRY_TYPES, ONLY : ANGGEO,KNDEX,LX=>LENGTHX,LY=>LENGTHY
+ !****
+ IMPLICIT NONE
+ INTEGER, INTENT(IN) :: NN
+ REAL, INTENT(IN) :: EPS,EPS2
+ REAL(PDB), INTENT(INOUT), DIMENSION(:,:) :: POINT
+ !****
+ INTEGER :: NP,NAXIS,I,P
+ REAL(PDB) :: D,AUX,EX(3),EY(3),DIS(3),AX(3),AY(3)
+ INTEGER, PARAMETER :: FOUT =6
+ !****
+ ! compute the square sides
+ LX=0.; LY=0.
+ DO P=1,NN
+ IF(LY<POINT(2,P)) LY=POINT(2,P)
+ IF(LX<POINT(1,P)) LX=POINT(1,P)
+ ENDDO
+ IF(KNDEX>0.AND.ABS(LY-LX)>EPS) &
+ WRITE(FOUT,'(" warning: the square sides are not the same!", &
+ & " lx = ",E12.4," ly = ",E12.4)')LX,LY
+ LX=(LX+LY)*0.5
+ LY=LX
+ !* adjust points on the axes
+ NAXIS=3
+ ! axis directions
+ EX(1)=1.; EY(1)=0.; DIS(1)=0.
+ EX(2)=COS(ANGGEO); EY(2)=SIN(ANGGEO); DIS(2)=0.
+ EX(3)=0.; EY(3)=1.; DIS(3)=LX
+ NP=3
+ ! axis ends
+ AX(1)=0.; AY(1)=0.
+ AX(2)=LX; AY(2)=0.
+ AX(3)=LX; AY(3)=LY
+ ITER0:DO P=1,NN
+ DO I=1,NP
+ D=(POINT(1,P)-AX(I))**2+(POINT(2,P)-AY(I))**2
+ IF(D.LT.EPS2) THEN
+ ! move point to the axis origin
+ POINT(1,P)=AX(I) ; POINT(2,P)=AY(I)
+ CYCLE ITER0
+ ENDIF
+ ENDDO
+ DO I=1,NAXIS
+ ! distance to the axis
+ D=POINT(1,P)*EY(I)-POINT(2,P)*EX(I)-DIS(I)
+ ! when aux>0,the point is near the half axis
+ AUX=POINT(1,P)*EX(I)+POINT(2,P)*EY(I)
+ IF(ABS(D).LT.EPS.AND.AUX>=0) THEN
+ ! move point to the axis
+ POINT(1,P)=POINT(1,P)-D*EY(I)
+ POINT(2,P)=POINT(2,P)+D*EX(I)
+ CYCLE ITER0
+ ENDIF
+ ENDDO
+ ENDDO ITER0
+ !
+ END SUBROUTINE SAL128_4
+ !
+ SUBROUTINE SAL128_5(NN,POINT,EPS,EPS2)
+ !
+ !---------------------------------------------------------------------
+ !
+ !Purpose:
+ ! process a trianglar geometry (TYPGEO=8 or 12) with specular reflection:
+ ! adjusts points on the axes, computes the triangular side length
+ !
+ !Parameters: input
+ ! NN total number of points
+ ! EPS when distance of points to axes less than EPS, displace
+ ! the points onto the axes
+ ! EPS2 variable set to EPS*EPS
+ !
+ !Parameters: input/output
+ ! POINT coordinates of points
+ !
+ !---------------------------------------------------------------------
+ !
+ USE PRECISION_AND_KINDS, ONLY : PDB
+ USE SAL_GEOMETRY_TYPES, ONLY : ANGGEO,KNDEX,LX=>LENGTHX,LY=>LENGTHY
+ !****
+ IMPLICIT NONE
+ INTEGER, INTENT(IN) :: NN
+ REAL, INTENT(IN) :: EPS,EPS2
+ REAL(PDB), INTENT(INOUT), DIMENSION(:,:) :: POINT
+ !****
+ INTEGER :: NP,NAXIS,I,P
+ REAL(PDB) :: D,AUX,EX(3),EY(3),DIS(3),AX(3),AY(3)
+ INTEGER, PARAMETER :: FOUT =6
+ !****
+ ! compute the triangular side
+ LX=0.; LY=0.
+ DO P=1,NN
+ IF(ABS(POINT(2,P))<EPS) THEN
+ IF(LX<POINT(1,P)) LX=POINT(1,P)
+ ENDIF
+ IF(LY<POINT(2,P)) LY=POINT(2,P)
+ ENDDO
+ IF(KNDEX>0.AND.ABS(LY-LX*SIN(ANGGEO))>EPS) &
+ WRITE(FOUT,'(" warning: h is different from a*sin(anggeo)!", &
+ & " a = ",E12.4," h = ",E12.4)')LX,LY
+ ! adjust h according a
+ LY=LX*SIN(ANGGEO)
+ !* adjust points on the axes
+ NAXIS=3
+ ! axis directions
+ EX(1)=1.; EY(1)=0.; DIS(1)=0.
+ EX(2)=COS(ANGGEO); EY(2)=SIN(ANGGEO); DIS(2)=0.
+ EX(3)=COS(ANGGEO*2.); EY(3)=SIN(ANGGEO*2.); DIS(3)=LY
+ NP=3
+ ! axis ends
+ AX(1)=0.; AY(1)=0.
+ AX(2)=LX; AY(2)=0.
+ AX(3)=LX*0.5; AY(3)=LY
+ ITER0:DO P=1,NN
+ DO I=1,NP
+ D=(POINT(1,P)-AX(I))**2+(POINT(2,P)-AY(I))**2
+ IF(D.LT.EPS2) THEN
+ ! move point to the axis origin
+ POINT(1,P)=AX(I) ; POINT(2,P)=AY(I)
+ CYCLE ITER0
+ ENDIF
+ ENDDO
+ DO I=1,NAXIS
+ ! distance to the axis
+ D=POINT(1,P)*EY(I)-POINT(2,P)*EX(I)-DIS(I)
+ ! when aux>0,the point is near the half axis
+ AUX=POINT(1,P)*EX(I)+POINT(2,P)*EY(I)
+ IF(ABS(D).LT.EPS.AND.AUX>=0) THEN
+ ! move point to the axis
+ POINT(1,P)=POINT(1,P)-D*EY(I)
+ POINT(2,P)=POINT(2,P)+D*EX(I)
+ CYCLE ITER0
+ ENDIF
+ ENDDO
+ ENDDO ITER0
+ !
+ END SUBROUTINE SAL128_5
+ !
+ SUBROUTINE SAL128_6(NN,POINT,EPS,EPS2)
+ !
+ !---------------------------------------------------------------------
+ !
+ !Purpose:
+ ! process a hexagonal geometry with translations on all sides (typgeo=9):
+ ! adjusts points on the axes, computes the lengths of hexagon sides;
+ ! element lengths on the opposite axes will be adjusted to be the same
+ !
+ !Parameters: input
+ ! NN total number of points
+ ! EPS when distance of points to axes less than EPS, displace
+ ! the points onto the axes
+ ! EPS2 variable set to EPS*EPS
+ !
+ !Parameters: input/output
+ ! POINT coordinates of points
+ !
+ !---------------------------------------------------------------------
+ !
+ USE PRECISION_AND_KINDS, ONLY : PDB
+ USE SAL_GEOMETRY_TYPES, ONLY : ANGGEO,KNDEX,LX=>LENGTHX,LY=>LENGTHY
+ !****
+ IMPLICIT NONE
+ INTEGER, INTENT(IN) :: NN
+ REAL, INTENT(IN) :: EPS,EPS2
+ REAL(PDB), INTENT(INOUT), DIMENSION(:,:) :: POINT
+ !****
+ INTEGER :: NP,NAXIS,I,J,K,M,P,IPOINT(6,NN),BP(6),IP(6)
+ REAL(PDB) :: D,AUX,EX(6),EY(6),DIS(6),AX(6),AY(6),D_AXIS(6,NN)
+ INTEGER, PARAMETER :: FOUT =6
+ !****
+ ! compute sides of the hexagon: LX=SIDE LENGTH,LY=LX*SIN(A)
+ LX=0.; LY=0.
+ DO P=1,NN
+ IF(ABS(POINT(2,P))<EPS) THEN
+ IF(LX<POINT(1,P)) LX=POINT(1,P)
+ ENDIF
+ IF(LY<POINT(2,P)) LY=POINT(2,P)
+ ENDDO
+ IF(KNDEX>0.AND.ABS(LY-LX*SIN(ANGGEO))>EPS) &
+ WRITE(FOUT,'(" warning: h is different from A*SIN(ANGGEO)!", &
+ & " a = ",E12.4," h = ",E12.4)')LX,LY
+ !* axis directions and their distance to (0,0)
+ NAXIS=6
+ EX(1)=1.; EY(1)=0.; DIS(1)=LY
+ EX(2)=1.; EY(2)=0.; DIS(2)=-LY
+ EX(3)=COS(ANGGEO); EY(3)=SIN(ANGGEO); DIS(3)=LY
+ EX(4)=EX(3); EY(4)=EY(3); DIS(4)=-LY
+ EX(5)=COS(2.*ANGGEO); EY(5)=SIN(2.*ANGGEO); DIS(5)=LY
+ EX(6)=EX(5); EY(6)=EY(5); DIS(6)=-LY
+ NP=6
+ AX(1)=-LX*0.5; AY(1)=-LY
+ AX(2)=LX*0.5; AY(2)=-LY
+ AX(3)=LX; AY(3)=0.
+ AX(4)=LX*0.5; AY(4)=LY
+ AX(5)=-LX*0.5; AY(5)=LY
+ AX(6)=-LX; AY(6)=0.
+ ! axis numbering:
+ ! M=2
+ ! *****
+ ! M=4 * * M=5
+ ! * * *
+ ! M=6 * * M=3
+ ! *****
+ ! M=1
+ !
+ BP(1)=1; BP(2)=5; BP(3)=2; BP(4)=6; BP(5)=3; BP(6)=1
+ IP=0
+ ITER0:DO P=1,NN
+ DO I=1,NP
+ ! if it is the 6 corners of the hexagon
+ D=(POINT(1,P)-AX(I))**2+(POINT(2,P)-AY(I))**2
+ IF(D.LT.EPS2) THEN
+ ! move point to the corner
+ POINT(1,P)=AX(I) ; POINT(2,P)=AY(I)
+ ! put distance to the axis origin
+ J=0
+ SELECT CASE(I)
+ CASE(1)
+ CYCLE ITER0
+ CASE(2)
+ ! END OF AXIS 1
+ J=1
+ CASE(3)
+ ! END OF AXIS 3
+ J=3
+ CASE(4)
+ ! END OF AXES 2&5
+ J=2
+ CASE(5)
+ ! END OF AXIS 4
+ J=4
+ CASE(6)
+ ! END OF AXIS 6
+ J=6
+ END SELECT
+ ! keep its distance and number
+10 IP(J)=IP(J)+1
+ D_AXIS(J,IP(J))=LX
+ IPOINT(J,IP(J))=P
+ IF(J==2) THEN
+ J=5
+ GOTO 10
+ ENDIF
+ CYCLE ITER0
+ ENDIF
+ ENDDO
+ DO I=1,NAXIS
+ ! distance to the axis
+ D=POINT(1,P)*EY(I)-POINT(2,P)*EX(I)-DIS(I)
+ ! when aux>0,the point is near the half axis
+ AUX=(POINT(1,P)-AX(BP(I)))*EX(I)+(POINT(2,P)-AY(BP(I)))*EY(I)
+ IF(ABS(D).LT.EPS.AND.AUX>=0) THEN
+ ! move point to the axis
+ POINT(1,P)=POINT(1,P)-D*EY(I)
+ POINT(2,P)=POINT(2,P)+D*EX(I)
+ ! compute distance to the axis origin
+ D=SQRT((POINT(1,P)-AX(BP(I)))**2+(POINT(2,P)-AY(BP(I)))**2)
+ IP(I)=IP(I)+1
+ D_AXIS(I,IP(I))=D
+ IPOINT(I,IP(I))=P
+ CYCLE ITER0
+ ENDIF
+ ENDDO
+ ENDDO ITER0
+ !
+ DO I=1,NAXIS,2
+ IF(IP(I)/=IP(I+1)) &
+ CALL XABORT('SAL128_6: axial points nber not the same,axis')
+ ! sort the 'd_axis' table
+ DO J=I,I+1
+ DO P=1,IP(J)
+ DO K=P+1,IP(J)
+ IF(D_AXIS(J,P)>D_AXIS(J,K)) THEN
+ D=D_AXIS(J,P)
+ D_AXIS(J,P)=D_AXIS(J,K)
+ D_AXIS(J,K)=D
+ M=IPOINT(J,P)
+ IPOINT(J,P)=IPOINT(J,K)
+ IPOINT(J,K)=M
+ ENDIF
+ ENDDO
+ ENDDO
+ ENDDO
+ DO P=1,IP(I)
+ IF(ABS(D_AXIS(I,P)-D_AXIS(I+1,P))>EPS) THEN
+ IF(KNDEX/=0) &
+ WRITE(FOUT,'(" warning: too great axial length difference",&
+ & 2(/,2X,"axis = ",I3," point = ",I3," d = ",E13.6))')&
+ I,P,D_AXIS(I,P),I+1,P,D_AXIS(I+1,P)
+ ENDIF
+ D=(D_AXIS(I,P)+D_AXIS(I+1,P))*0.5
+ DO J=I,I+1
+ K=IPOINT(J,P)
+ POINT(1,K)=D*EX(J)+AX(BP(J))
+ POINT(2,K)=D*EY(J)+AY(BP(J))
+ ENDDO
+ ENDDO
+ ENDDO
+ !
+ END SUBROUTINE SAL128_6
+ !
+ SUBROUTINE SAL128_7(NN,POINT,EPS,EPS2)
+ !
+ !---------------------------------------------------------------------
+ !
+ !Purpose:
+ ! process an isocel trianglar geometry (TYPGEO=10) with RA60 rotation:
+ ! adjusts points on the axes, computes the triangular side length
+ !
+ !Parameters: input
+ ! NN total number of points
+ ! EPS when distance of points to axes less than EPS, displace
+ ! the points onto the axes
+ ! EPS2 variable set to EPS*EPS
+ !
+ !Parameters: input/output
+ ! POINT coordinates of points
+ !
+ !---------------------------------------------------------------------
+ !
+ USE PRECISION_AND_KINDS, ONLY : PDB
+ USE SAL_GEOMETRY_TYPES, ONLY : ANGGEO,LX=>LENGTHX,LY=>LENGTHY
+ !****
+ IMPLICIT NONE
+ INTEGER, INTENT(IN) :: NN
+ REAL, INTENT(IN) :: EPS,EPS2
+ REAL(PDB), INTENT(INOUT), DIMENSION(:,:) :: POINT
+ !****
+ INTEGER :: NP,NAXIS,I,P
+ REAL(PDB) :: D,AUX,EX(3),EY(3),DIS(3),AX(3),AY(3)
+ INTEGER, PARAMETER :: FOUT =6
+ !****
+ ! compute the triangular side
+ LX=0.; LY=0.
+ DO P=1,NN
+ IF(ABS(POINT(2,P))<EPS) THEN
+ IF(LX<POINT(1,P)) LX=POINT(1,P)
+ ENDIF
+ IF(LY<POINT(2,P)) LY=POINT(2,P)
+ ENDDO
+ IF(KNDEX>0.AND.ABS(LY-LX*SIN(ANGGEO))>EPS) &
+ WRITE(FOUT,'(" warning: h is different from a*sin(anggeo)!", &
+ & " a = ",E12.4," h = ",E12.4)')LX,LY
+ ! adjust h according a
+ LY=LX*SIN(ANGGEO)
+ !* adjust points on the axes
+ NAXIS=3
+ ! axis directions
+ EX(1)=1.; EY(1)=0.; DIS(1)=0.
+ EX(2)=COS(ANGGEO); EY(2)=SIN(ANGGEO); DIS(2)=0.
+ EX(3)=COS(ANGGEO*2.); EY(3)=SIN(ANGGEO*2.); DIS(3)=LY
+ NP=3
+ ! axis ends
+ AX(1)=0.; AY(1)=0.
+ AX(2)=LX; AY(2)=0.
+ AX(3)=LX*0.5; AY(3)=LY
+ ITER0:DO P=1,NN
+ DO I=1,NP
+ D=(POINT(1,P)-AX(I))**2+(POINT(2,P)-AY(I))**2
+ IF(D.LT.EPS2) THEN
+ ! move point to the axis origin
+ POINT(1,P)=AX(I) ; POINT(2,P)=AY(I)
+ CYCLE ITER0
+ ENDIF
+ ENDDO
+ DO I=1,NAXIS
+ ! distance to the axis
+ D=POINT(1,P)*EY(I)-POINT(2,P)*EX(I)-DIS(I)
+ ! when aux>0,the point is near the half axis
+ AUX=POINT(1,P)*EX(I)+POINT(2,P)*EY(I)
+ IF(ABS(D).LT.EPS.AND.AUX>=0) THEN
+ ! move point to the axis
+ POINT(1,P)=POINT(1,P)-D*EY(I)
+ POINT(2,P)=POINT(2,P)+D*EX(I)
+ CYCLE ITER0
+ ENDIF
+ ENDDO
+ ENDDO ITER0
+ !
+ END SUBROUTINE SAL128_7
+ !
+ SUBROUTINE SAL128_8(NN,POINT,EPS,EPS2)
+ !
+ !---------------------------------------------------------------------
+ !
+ !Purpose:
+ ! process R120 lozenge geometry (TYPGEO=11): adjusts points on the axes,
+ ! computes the lozenge side length
+ !
+ !Parameters: input
+ ! NN total number of points
+ ! EPS when distance of points to axes less than EPS, displace
+ ! the points onto the axes
+ ! EPS2 variable set to EPS*EPS
+ !
+ !Parameters: input/output
+ ! POINT coordinates of points
+ !
+ !---------------------------------------------------------------------
+ !
+ USE PRECISION_AND_KINDS, ONLY : PDB
+ USE SAL_GEOMETRY_TYPES, ONLY : ANGGEO,LX=>LENGTHX,LY=>LENGTHY
+ !****
+ IMPLICIT NONE
+ INTEGER, INTENT(IN) :: NN
+ REAL, INTENT(IN) :: EPS,EPS2
+ REAL(PDB), INTENT(INOUT), DIMENSION(:,:) :: POINT
+ !****
+ INTEGER :: NP,NAXIS,I,P
+ REAL(PDB) :: D,AUX,EX(4),EY(4),DIS(4),AX(4),AY(4)
+ INTEGER, PARAMETER :: FOUT =6
+ !****
+ ! compute the triangular side
+ LX=0.; LY=0.
+ DO P=1,NN
+ IF(ABS(POINT(2,P))<EPS) THEN
+ IF(LX<POINT(1,P)) LX=POINT(1,P)
+ ENDIF
+ IF(LY<POINT(2,P)) LY=POINT(2,P)
+ ENDDO
+ IF(ABS(LY-LX*SIN(ANGGEO))>EPS) &
+ WRITE(FOUT,'(" warning: h is different from a*sin(anggeo)!", &
+ & " a = ",E12.4," h = ",E12.4)') LX,LY
+ ! adjust h according to base
+ LY=LX*SIN(ANGGEO)
+ !* adjust points on the axes
+ NAXIS=4
+ ! axis directions
+ EX(1)=1.; EY(1)=0.; DIS(1)=0.
+ EX(2)=1.; EY(2)=0.; DIS(2)=-LY
+ EX(3)=COS(ANGGEO); EY(3)=SIN(ANGGEO); DIS(3)=0.
+ EX(4)=COS(ANGGEO); EY(4)=SIN(ANGGEO); DIS(4)=LY
+ NP=4
+ ! axis ends
+ AX(1)=0. ; AY(1)=0.
+ AX(2)=LX*0.5; AY(2)=LY
+ AX(3)=LX ; AY(3)=0.
+ AX(4)=LX*1.5; AY(4)=LY
+ ITER0:DO P=1,NN
+ DO I=1,NP
+ D=(POINT(1,P)-AX(I))**2+(POINT(2,P)-AY(I))**2
+ IF(D.LT.EPS2) THEN
+ ! move point to the axis origin
+ POINT(1,P)=AX(I) ; POINT(2,P)=AY(I)
+ CYCLE ITER0
+ ENDIF
+ ENDDO
+ DO I=1,NAXIS
+ ! distance to the axis
+ D=POINT(1,P)*EY(I)-POINT(2,P)*EX(I)-DIS(I)
+ ! when aux>0,the point is near the half axis
+ AUX=POINT(1,P)*EX(I)+POINT(2,P)*EY(I)
+ IF(ABS(D).LT.EPS.AND.AUX>=0) THEN
+ ! move point to the axis
+ POINT(1,P)=POINT(1,P)-D*EY(I)
+ POINT(2,P)=POINT(2,P)+D*EX(I)
+ CYCLE ITER0
+ ENDIF
+ ENDDO
+ ENDDO ITER0
+ !
+ END SUBROUTINE SAL128_8
+ !
+ SUBROUTINE SAL129(X1,Y1,X2,Y2,TYPE,RPAR,II,KNDEX,FOUT)
+ !
+ !---------------------------------------------------------------------
+ !
+ !Purpose:
+ ! recompute element data by giving two ends of the element
+ !
+ !Parameters: input
+ ! X1 new position in X for the end 1
+ ! Y1 new position in Y for the end 1
+ ! X2 new position in X for the end 2
+ ! Y2 new position in Y for the end 2
+ ! TYPE type of element 1 (segment) 3 (arc of circle)
+ ! II element to be changed
+ ! KNDEX if not 0 print out data when motion>EPS
+ ! FOUT printout file
+ !
+ !Parameters: input/output
+ ! RPAR descriptors of the element
+ !
+ !---------------------------------------------------------------------
+ !
+ USE SAL_GEOMETRY_TYPES, ONLY : NRPAR,EPS,G_ELE_TYPE,G_ELE_LEN
+ USE SAL_NUMERIC_MOD, ONLY : SALACO
+ !****
+ IMPLICIT NONE
+ ! in variable
+ ! ***********
+ INTEGER, INTENT(IN) :: TYPE,KNDEX,FOUT,II
+ REAL(PDB), INTENT(IN) :: X1,Y1,X2,Y2
+ REAL(PDB), INTENT(INOUT), DIMENSION(:) :: RPAR
+ !****
+
+ ! local variable
+ ! **************
+ REAL(PDB) :: CX,CY,DELX,DELY,R,THETA,SX,SY,VX,VY,V2,DIST,MOV1,MOV2
+ INTEGER :: I
+ REAL(PDB) :: RPAR_OLD(NRPAR)
+ !****
+ ! keep old parameters:
+ RPAR_OLD(1:NRPAR)=RPAR(1:NRPAR)
+ !
+ MOV1=0._PDB; MOV2=0._PDB;
+ IF(TYPE == G_ELE_TYPE(1)) THEN
+ !* segment :
+ ! compute the motions of two ends
+ DELX=X1-RPAR(1)
+ DELY=Y1-RPAR(2)
+ MOV1=SQRT(DELX*DELX+DELY*DELY)
+ DELX=X2-(RPAR(1)+RPAR(3))
+ DELY=Y2-(RPAR(2)+RPAR(4))
+ MOV2=SQRT(DELX*DELX+DELY*DELY)
+ ! set new ends, compute direction
+ RPAR(1)=X1
+ RPAR(2)=Y1
+ RPAR(3)=X2-X1
+ RPAR(4)=Y2-Y1
+ RPAR(5)=SQRT(RPAR(3)*RPAR(3)+RPAR(4)*RPAR(4))
+ ELSE IF(TYPE == G_ELE_TYPE(3)) THEN
+ !* arc of circle :
+ ! get old radius
+ CX=RPAR(1); CY=RPAR(2)
+ ! compute the motion of two ends
+ R=RPAR(3)
+ THETA=RPAR(4)
+ DELX=CX+R*COS(THETA)-X1
+ DELY=CY+R*SIN(THETA)-Y1
+ MOV1=SQRT(DELX*DELX+DELY*DELY)
+ THETA=RPAR(5)
+ DELX=CX+R*COS(THETA)-X2
+ DELY=CY+R*SIN(THETA)-Y2
+ MOV2=SQRT(DELX*DELX+DELY*DELY)
+ ! compute new radius, new center and new angles
+ SX=X1-CX
+ SY=Y1-CY
+ ! get demi-vector from (x1,y1) to (x2,y2)
+ VX=(X2-X1)/2.0
+ VY=(Y2-Y1)/2.0
+ V2=VX*VX+VY*VY
+ ! get center closest to old center, change radius
+ ! compute new r
+ R=SQRT(V2+(SX*VY-SY*VX)**2/V2)
+ RPAR(3)=R
+ ! compute new center
+ DIST=1.0_PDB+(VX*SX+VY*SY)/V2
+ ! get new center and compute angles
+ CX=CX+VX*DIST
+ CY=CY+VY*DIST
+ RPAR(1)=CX
+ RPAR(2)=CY
+ THETA=SALACO((X1-CX)/R,Y1-CY)
+ RPAR(4)=THETA
+ THETA=SALACO((X2-CX)/R,Y2-CY)
+ RPAR(5)=THETA
+ ! if phi1 > phi2 put phi2 equal to phi2+twopi
+ IF(RPAR(4)>RPAR(5)) RPAR(5)=RPAR(5)+TWOPI
+ ENDIF
+ IF(KNDEX/=0) THEN
+ IF(MOV1>EPS.OR.MOV2>EPS) THEN
+ WRITE(FOUT,'(/," old element ",I4," : ",6(1P,E13.4))') &
+ II,(RPAR_OLD(I),I=1,G_ELE_LEN(TYPE))
+ WRITE(FOUT,'(" new element ",I4," : ",6(1P,E13.4))') &
+ II,(RPAR(I),I=1,G_ELE_LEN(TYPE))
+ ENDIF
+ ENDIF
+ !
+ END SUBROUTINE SAL129
+ !
+ SUBROUTINE SAL130(GG)
+ !
+ !---------------------------------------------------------------------
+ !
+ !Purpose:
+ ! perform domain definition and set boundary conditions
+ ! - computes node perimeters per 2d macro
+ ! - reads boundary conditions
+ ! - computes external perimeters
+ !
+ !Parameters: input/output
+ ! GG geometry descriptor
+ !
+ !---------------------------------------------------------------------
+ !
+ USE SAL_GEOMETRY_TYPES, ONLY : G_BC_TYPE,TYPGEO
+ !****
+ IMPLICIT NONE
+ ! in variable
+ ! ************
+ TYPE(T_G_BASIC), INTENT(INOUT):: GG
+ ! local variable
+ !****
+ INTEGER :: NN,OK
+ INTEGER, DIMENSION(GG%NB_ELEM*2) :: AUX_ARR
+ !****
+ !* compute node perimeters for the macro
+ CALL SAL130_2(GG%NB_ELEM,GG%NB_NODE,GG%IPAR,GG%PPERIM_NODE, &
+ GG%PERIM_NODE,AUX_ARR)
+ !
+ !* - compute number of bc's per 2D macro,
+ ! NB_BC2 counts total nber of 2D bc's
+ ! - compute IBC2_ELEM, keep relative 2D bc nber to elements
+ ! - allocation : 2D bc structures
+ ! 2D perimeter structure for a macro
+ ! - get list of elements in 2d macro perimeter
+
+ CALL SAL130_4(GG%NB_ELEM,NN,GG%IPAR,GG%IBC2_ELEM,AUX_ARR)
+
+ GG%NB_BC2=NN
+
+ ALLOCATE (GG%TYPE_BC2(NN),GG%IDATA_BC2(NN),GG%PERIM_MAC2(NN), &
+ GG%PPERIM_MAC2(7),STAT=OK)
+ IF(OK/=0) CALL XABORT('SAL130: not enough memory I,R')
+ GG%PPERIM_MAC2(:7)=0
+ GG%PERIM_MAC2(1:NN)=AUX_ARR(1:NN)
+ GG%NPERIM_MAC2=NN
+ !
+ !* read boundary conditions:
+ CALL SAL131(GG)
+ !
+ ! - define IELEM_SURF2
+ IF(GG%NB_SURF2>0) THEN
+ ! allocate
+ ALLOCATE(GG%SURF2(GG%NB_SURF2),STAT = OK)
+ IF(OK /= 0) CALL XABORT('SAL130: not enough memory I,R')
+ CALL SAL130_6(GG%NB_SURF2,GG%IBC2_SURF2,GG%PERIM_MAC2,GG%IELEM_SURF2)
+ ENDIF
+ !
+ !* construct perimeter structures for rotative or symmetrical geometry
+ SELECT CASE(TYPGEO)
+ CASE(1:2)
+ CALL SAL130_8(GG%NPERIM_MAC2,GG%PERIM_MAC2,GG%PPERIM_MAC2,GG%DIST_AXIS, &
+ GG%IBC2_ELEM,GG%TYPE_BC2,GG%IDATA_BC2,GG%BCDATA,GG%IPAR,GG%RPAR)
+ CASE(5:12)
+ CALL SAL130_10(GG%NPERIM_MAC2,GG%PERIM_MAC2,GG%PPERIM_MAC2,GG%DIST_AXIS, &
+ GG%IBC2_ELEM,GG%TYPE_BC2,GG%IDATA_BC2,GG%BCDATA,GG%IPAR,GG%RPAR)
+ END SELECT
+ !
+ END SUBROUTINE SAL130
+ !
+ SUBROUTINE SAL130_2(NB_ELEM,NB_NODE,IPAR,PPERIM,PERIM,LIST)
+ !
+ !---------------------------------------------------------------------
+ !
+ !Purpose:
+ ! compute node perimeters for one 2D macro
+ !
+ !Parameters: input
+ ! NB_ELEM number of elements
+ ! NB_NODE number of nodes
+ ! IPAR integer descriptors for elements
+ !
+ !Parameters: output
+ ! PPERIM array pointer to list of elements in perimeter per node
+ ! PERIM elements in perimeters per node
+ ! LIST temporary array
+ !
+ !---------------------------------------------------------------------
+ !
+ IMPLICIT NONE
+ INTEGER, INTENT(IN) :: NB_ELEM,NB_NODE
+ INTEGER, INTENT(IN), DIMENSION(:,:) :: IPAR
+ INTEGER, INTENT(OUT), DIMENSION(:) :: LIST
+ INTEGER, INTENT(OUT), DIMENSION(:) :: PPERIM
+ INTEGER, POINTER, DIMENSION(:) :: PERIM
+ !****
+ INTEGER :: NT,NN,NODE,ELEM,OK
+ CHARACTER(LEN=131) :: HSMG
+ !****
+ NT=0
+ PPERIM(1)=1
+ DO NODE=1,NB_NODE
+ DO ELEM=1, NB_ELEM
+ IF(IPAR(2,ELEM)==NODE.OR.IPAR(3,ELEM)==NODE) THEN
+ NT=NT+1
+ LIST(NT)=ELEM
+ ENDIF
+ ENDDO
+ NN=NT+1-PPERIM(NODE)
+ IF(NN>0) THEN
+ PPERIM(NODE+1)=NT+1
+ ELSE
+ WRITE(HSMG,'(15HSAL130_2: node=,i5,19H without perimeter.)') NODE
+ CALL XABORT(HSMG)
+ ENDIF
+ ENDDO
+ IF(NT>0) THEN
+ ALLOCATE (PERIM(NT), STAT=OK)
+ IF(OK/=0) CALL XABORT('SAL130_2: not enough memory I')
+ PERIM(1:NT)=LIST(1:NT)
+ ENDIF
+ !
+ END SUBROUTINE SAL130_2
+ !
+ SUBROUTINE SAL130_4(NB_ELEM,NB_BC,IPAR,IBC2_ELEM,LIST_BC)
+ !
+ !---------------------------------------------------------------------
+ !
+ !Purpose:
+ ! count number of bc's in a 2D macro
+ !
+ !Parameters: input
+ ! NB_ELEM number of elements
+ !
+ !Parameters: input/output
+ ! IPAR integer descriptors for elements
+ !
+ !Parameters: output
+ ! NB_BC nber of bc's
+ ! IBC2_ELEM relative 2D bc index per element
+ ! LIST_BC list of elements in boundary
+ !
+ !---------------------------------------------------------------------
+ !
+ IMPLICIT NONE
+ INTEGER, INTENT(IN) :: NB_ELEM
+ INTEGER, INTENT(OUT) :: NB_BC
+ INTEGER, INTENT(IN), DIMENSION(:,:) :: IPAR
+ INTEGER, INTENT(OUT), DIMENSION(:) :: IBC2_ELEM,LIST_BC
+ !****
+ INTEGER :: ELEM
+ !****
+ ! initiation
+ IBC2_ELEM(:)=0
+ NB_BC=0
+ DO ELEM=1, NB_ELEM
+ IF(IPAR(2,ELEM)<=0.AND.IPAR(3,ELEM)<=0) THEN
+ CALL XABORT('SAL130_4: two boundaries for element')
+ ELSE IF(IPAR(2,ELEM)<=0.OR.IPAR(3,ELEM)<=0) THEN
+ NB_BC=NB_BC+1
+ LIST_BC(NB_BC)=ELEM
+ IF(IBC2_ELEM(ELEM)/=0) CALL XABORT('SAL130_4: two surfaces to element')
+ IBC2_ELEM(ELEM)=NB_BC
+ ! set mark for the macro connection surface :
+ ENDIF
+ ENDDO
+ !
+ END SUBROUTINE SAL130_4
+ !
+ SUBROUTINE SAL130_6(NSURF,IBC2_SURF2,IELEM_BC2,IELEM_SURF2)
+ !
+ !---------------------------------------------------------------------
+ !
+ !Purpose:
+ ! get element order indices per surface
+ !
+ !Parameters: input
+ ! NSURF number of surfaces
+ ! IBC2_SURF2 2D bc order index per surface
+ ! IELEM_BC2 element order index per bc
+ !
+ !Parameters: output
+ ! IELEM_SURF2 element order index per surface
+ !
+ !---------------------------------------------------------------------
+ !
+ !****
+ USE SAL_GEOMETRY_TYPES, ONLY : G_BC_TYPE
+ !****
+ IMPLICIT NONE
+ INTEGER, INTENT(IN) :: NSURF
+ INTEGER, INTENT(IN), DIMENSION(:) :: IBC2_SURF2,IELEM_BC2
+ INTEGER, INTENT(OUT), DIMENSION(:) :: IELEM_SURF2
+ !****
+ INTEGER :: SURF,IBC,ELEM
+ !****
+ IF(NSURF > 0) THEN
+ DO SURF=1, NSURF
+ ! get relative bc order number
+ IBC=IBC2_SURF2(SURF)
+ ! get relative element
+ ELEM=IELEM_BC2(IBC)
+ ! define ielem_surf2
+ IELEM_SURF2(SURF)=ELEM
+ ENDDO
+ ENDIF
+ !
+ END SUBROUTINE SAL130_6
+ !
+ SUBROUTINE SAL130_8(NPERIM,PERIM,PPERIM,DIST_AXIS,IBC2_ELEM,TYPE_BC2,IDATA_BC2, &
+ BCDATA,IPAR,RPAR)
+ !
+ !---------------------------------------------------------------------
+ !
+ !Purpose:
+ ! calculate PERIM_MAC2,DIST_AXIS for rotative or symmetrical geometry
+ ! (TYPGEO=1 & 2)
+ !
+ !Parameters: input
+ ! NPERIM number of elements in perimeter
+ ! IBC2_ELEM 2D bc order number per element
+ ! TYPE_BC2 type of boundary conditions per 2D bc
+ ! IDATA_BC2 position in the 'bcdata' table for each 2D bc
+ ! BCDATA table of boundary conditions data
+ ! IPAR integer element descriptor table
+ ! RPAR floating point element descriptor table
+ !
+ !Parameters: input/output
+ ! PERIM list of elements in perimeter,in return it will be in following
+ ! order: (elems on axis 1)+(elems on axis 2)+(other elems)
+ !
+ !Parameters: output
+ ! PPERIM pointers to the table 'perim':
+ ! (1): first elem on axis 1 (2): first elem on axis 2
+ ! (3): first of other elems (4): NPERIM + 1
+ ! DIST_AXIS distance of points on axis to the center (0,0),in order of:
+ ! (distances of points on axis 1)+(distances of points on axis 2)
+ !
+ !---------------------------------------------------------------------
+ !
+ USE SAL_GEOMETRY_TYPES, ONLY : ANGGEO,EPS,G_BC_TYPE
+ USE SAL_NUMERIC_MOD, ONLY : SAL141
+ !****
+ IMPLICIT NONE
+ INTEGER, INTENT(IN) :: NPERIM
+ INTEGER, INTENT(IN), DIMENSION(:) :: IBC2_ELEM,TYPE_BC2,IDATA_BC2
+ INTEGER, INTENT(INOUT), DIMENSION(:) :: PERIM
+ INTEGER, INTENT(OUT), DIMENSION(:) :: PPERIM
+ REAL(PDB), POINTER, DIMENSION(:) :: DIST_AXIS
+ INTEGER, INTENT(IN), DIMENSION(:,:) :: IPAR
+ REAL(PDB), INTENT(INOUT),DIMENSION(:,:) :: RPAR
+ REAL(PDB), INTENT(IN),DIMENSION(:,:) :: BCDATA
+ !****
+ ! LIST_ELEMS = table of elements,elements on axis are in increasing order
+ ! of distance to (0,0):
+ ! 1=elements on axis 1; 2=elements on axis 2; 3=other elements
+ ! AUX_DIST = max distance of element ends to the beginnings of the axes:
+ ! 1=distances on axis 1; 2=distances on axis 2
+ INTEGER, DIMENSION(NPERIM,3) :: LIST_ELEMS
+ REAL(PDB), DIMENSION(NPERIM,2) :: AUX_DIST
+ INTEGER :: I,J,K,M,ELEM,TYPBC,IBC,IDATA,NBE(3),OK,NAXES
+ REAL(PDB) :: ANGLE,X,Y,D
+ !****
+ NAXES=2
+ !* calculate number of elements on axis 1 & 2
+ ! and their distances to the beginning of the axes
+ NBE=0
+ DO I=1,NPERIM
+ ELEM=PERIM(I)
+ IBC=IBC2_ELEM(ELEM)
+ TYPBC=TYPE_BC2(IBC)
+ IDATA=IDATA_BC2(IBC)
+ ! default is the elements not on axis
+ M=NAXES+1
+ IF(TYPBC==G_BC_TYPE(3)) THEN
+ !* rotation:
+ ANGLE=BCDATA(5,IDATA)
+ IF(ABS(ANGLE-ANGGEO)<EPS) THEN
+ ! element is on the axis 1 (angle=anggeo)
+ M=1
+ ELSEIF(ABS(ANGLE+ANGGEO)<EPS) THEN
+ ! element is on the axis 2 (angle=-anggeo)
+ M=2
+ ENDIF
+ ELSEIF(TYPBC==G_BC_TYPE(4)) THEN
+ !* symmetry:
+ ANGLE=BCDATA(5,IDATA)
+ IF(ABS(ANGLE)<EPS) THEN
+ ! element is on the axis 1 (angle=0)
+ M=1
+ ELSEIF(ABS(ANGLE-ANGGEO)<EPS) THEN
+ ! element is on the axis 2 (angle=anggeo)
+ M=2
+ ENDIF
+ ENDIF
+ NBE(M)=NBE(M)+1
+ LIST_ELEMS(NBE(M),M)=ELEM
+ IF(M/=NAXES+1) THEN
+ ! sort the element list according their distance to (0,0)
+ D=0.
+ DO K=1,2
+ CALL SAL141(IPAR(1,ELEM),RPAR(:,ELEM),X,Y,K)
+ D=MAX(D,SQRT(X*X+Y*Y))
+ ENDDO
+ AUX_DIST(NBE(M),M)=D
+ IF(NBE(M)>1) THEN
+ DO K=1,NBE(M)-1
+ IF(AUX_DIST(NBE(M),M)<AUX_DIST(K,M)) THEN
+ ! insert the last element to position k
+ D=AUX_DIST(NBE(M),M)
+ ELEM=LIST_ELEMS(NBE(M),M)
+ DO J=NBE(M),K+1,-1
+ AUX_DIST(J,M)=AUX_DIST(J-1,M)
+ LIST_ELEMS(J,M)=LIST_ELEMS(J-1,M)
+ ENDDO
+ AUX_DIST(K,M)=D
+ LIST_ELEMS(K,M)=ELEM
+ EXIT
+ ENDIF
+ ENDDO
+ ENDIF
+ ENDIF
+ ENDDO
+ ! nber of blocks in 'perim'
+ M=NAXES+1
+ !* organize elements as:
+ ! (elems on axis 1)+(elems on axis 2)+(other elems)
+ PPERIM(:)=0
+ PPERIM(1)=1
+ DO I=1,M
+ PPERIM(I+1)=PPERIM(I)+NBE(I)
+ ENDDO
+ DO I=1,M
+ PERIM(PPERIM(I):PPERIM(I+1)-1)=LIST_ELEMS(1:NBE(I),I)
+ ENDDO
+ !* allocate and set dist_axis
+ IF(PPERIM(NAXES+1)-1>0) THEN
+ ALLOCATE(DIST_AXIS(PPERIM(NAXES+1)-1),STAT=OK)
+ IF(OK.NE.0) CALL XABORT('SAL130_8: not enough memory R')
+ DO I=1,NAXES
+ DIST_AXIS(PPERIM(I):PPERIM(I+1)-1)=AUX_DIST(1:NBE(I),I)
+ ENDDO
+ ELSE
+ NULLIFY(DIST_AXIS)
+ ENDIF
+ !
+ end subroutine sal130_8
+ !
+ SUBROUTINE SAL130_10(NPERIM,PERIM,PPERIM,DIST_AXIS,IBC2_ELEM,TYPE_BC2,IDATA_BC2, &
+ BCDATA,IPAR,RPAR)
+ !
+ !---------------------------------------------------------------------
+ !
+ !Purpose:
+ ! calculate PERIM_MAC2 and DIST_AXIS for the cyclical geometries:
+ ! type 5&6: retangle with translations or symmetries on all sides
+ ! type 7 : 1/8 assembly with symmetries on all sides
+ ! type 8 : equilateral triangle with symmetries on all sides
+ ! type 9 : hexagon with translations on all sides
+ ! type 10 : hexagon with RA60 rotation
+ ! type 11 : hexagon with R120 rotation
+ ! type 12 : rectangular S30 triangle geometry
+ !
+ !Parameters: input
+ ! NPERIM number of elements in perimeter
+ ! IBC2_ELEM 2D bc order number per element
+ ! TYPE_BC2 type of boundary conditions per 2D bc
+ ! IDATA_BC2 position in the 'bcdata' table for each 2D bc
+ ! BCDATA table of boundary conditions data
+ ! IPAR integer element descriptor table
+ ! RPAR floating point element descriptor table
+ !
+ !Parameters: input/output
+ ! PERIM list of elements in perimeter,in return it will be in following
+ ! order: (elems on axis 1)+(elems on axis 2)+(other elems)
+ !
+ !Parameters: output
+ ! PPERIM pointers to the table 'perim':
+ ! DIST_AXIS distance of points on axis to the axis origin
+ !
+ !---------------------------------------------------------------------
+ !
+ USE SAL_GEOMETRY_TYPES, ONLY : TYPGEO,ANGGEO,EPS,LX=>LENGTHX,LY=>LENGTHY,G_BC_TYPE
+ USE SAL_NUMERIC_MOD, ONLY : SAL141
+ !****
+ IMPLICIT NONE
+ INTEGER, INTENT(IN) :: NPERIM
+ INTEGER, INTENT(IN), DIMENSION(:) :: IBC2_ELEM,TYPE_BC2,IDATA_BC2
+ INTEGER, INTENT(INOUT), DIMENSION(:) :: PERIM
+ INTEGER, INTENT(OUT), DIMENSION(:) :: PPERIM
+ REAL(PDB), POINTER, DIMENSION(:) :: DIST_AXIS
+ INTEGER, INTENT(IN), DIMENSION(:,:) :: IPAR
+ REAL(PDB), INTENT(INOUT),DIMENSION(:,:) :: RPAR
+ REAL(PDB), INTENT(IN),DIMENSION(:,:) :: BCDATA
+ !****
+ ! LIST_ELEMS = table of elements,elements on axis are in increasing order
+ ! of distance to axis origin:
+ ! 1=elements on axis 1; 2=elements on axis 2; ...
+ ! AUX_DIST = max distance of element ends to axis origin:
+ ! 1=distances on axis 1; 2=distances on axis 2; ...
+ INTEGER, DIMENSION(NPERIM,6) :: LIST_ELEMS
+ REAL(PDB), DIMENSION(NPERIM,6) :: AUX_DIST
+ INTEGER :: I,J,K,M,ELEM,TYPBC,IBC,IDATA,NBE(6),OK,NAXES
+ REAL(PDB) :: ANGLE,X,Y,D
+ !****
+ NAXES=0
+ IF((TYPGEO==5).OR.(TYPGEO==6).OR.(TYPGEO==11)) THEN
+ NAXES=4
+ ELSEIF((TYPGEO==7).OR.(TYPGEO==8).OR.(TYPGEO==10).OR.(TYPGEO==12)) THEN
+ NAXES=3
+ ELSEIF(TYPGEO==9) THEN
+ NAXES=6
+ ENDIF
+ !* calculate number of elements on axes,
+ ! and their distances to the origin of the axis
+ NBE=0
+
+ DO I=1,NPERIM
+ ELEM=PERIM(I)
+ IBC=IBC2_ELEM(ELEM)
+ TYPBC=TYPE_BC2(IBC)
+ IDATA=IDATA_BC2(IBC)
+ ENDDO
+ DO I=1,NPERIM
+ ELEM=PERIM(I)
+ IBC=IBC2_ELEM(ELEM)
+ TYPBC=TYPE_BC2(IBC)
+ IDATA=IDATA_BC2(IBC)
+ ANGLE=BCDATA(5,IDATA)
+ ! default is the elements not on axis
+ M=NAXES+1
+ SELECT CASE(TYPGEO)
+ CASE(5)
+ !* rectangle with translations:
+ ! axes definition:
+ ! M=3
+ ! ************
+ ! * *
+ ! M=2 * * M=4
+ ! ************
+ ! M=1
+ IF(TYPBC==G_BC_TYPE(2)) THEN
+ IF(BCDATA(2,IDATA)>0) THEN
+ M=1
+ ELSEIF(BCDATA(2,IDATA)<0) THEN
+ M=3
+ ELSEIF(BCDATA(1,IDATA)>0) THEN
+ M=2
+ ELSEIF(BCDATA(1,IDATA)<0) THEN
+ M=4
+ ENDIF
+ ELSE
+ CALL XABORT('SAL130_10: wrong boundary condition for TYPGEO=5.')
+ ENDIF
+ CASE(6)
+ !* rectangle with symmetries:
+ ! axes definition:
+ ! M=3
+ ! ************
+ ! * *
+ ! M=2 * * M=4
+ ! ************
+ ! M=1
+ IF(TYPBC==G_BC_TYPE(4)) THEN
+ IF(ABS(ANGLE)<EPS) THEN
+ IF(BCDATA(2,IDATA)>0) THEN
+ ! cy>0: element is on the axis 3 (angle=0)
+ M=3
+ ELSE
+ ! cy=0: element is on the axis 1 (angle=0)
+ M=1
+ ENDIF
+ ELSEIF(ABS(ANGLE-ANGGEO)<EPS) THEN
+ IF(BCDATA(1,IDATA)>0) THEN
+ ! cx>0: element is on the axis 4 (angle=anggeo)
+ M=4
+ ELSE
+ ! cx=0: element is on the axis 2 (angle=anggeo)
+ M=2
+ ENDIF
+ ENDIF
+ ELSE
+ CALL XABORT('SAL130_10: wrong boundary condition for TYPGEO=6.')
+ ENDIF
+ CASE(7,8,12)
+ !* triangles with symmetries:
+ ! typgeo=7 axes definition:
+ ! *
+ ! M=2 * * M=3
+ ! * *
+ ! *******
+ ! M=1
+ ! typgeo=8 axes definition:
+ ! *
+ ! M=2 * * M=3
+ ! * *
+ ! *************
+ ! M=1
+ IF(TYPBC==G_BC_TYPE(4)) THEN
+ IF(ABS(ANGLE)<EPS) THEN
+ ! element is on the axis 1 (angle=0)
+ M=1
+ ELSEIF(ABS(ANGLE-ANGGEO)<EPS) THEN
+ ! element is on the axis 2 (angle=anggeo)
+ M=2
+ ELSEIF(ABS(ANGLE-HALFPI)<EPS) THEN
+ ! typgeo=7:element is on the axis 3 (angle=pi/2)
+ M=3
+ ELSEIF(ABS(ANGLE-2.*ANGGEO)<EPS) THEN
+ ! typgeo=8:element is on the axis 3 (angle=2*anggeo)
+ M=3
+ ELSEIF(ABS(ANGLE-2.*PI/3.)<EPS) THEN
+ ! typgeo=12:element is on the axis 3 (angle=2*pi/3)
+ M=3
+ ELSE
+ CALL XABORT('SAL130_10: boundary condition data error in element for TYPGEO=7,8,12.')
+ ENDIF
+ ELSE
+ CALL XABORT('SAL130_10: wrong boundary condition for TYPGEO=7,8.')
+ ENDIF
+ CASE(9)
+ !* hexagon with translations:
+ ! axes definition:
+ ! M=4 (0,-2ly)
+ ! *****
+ ! M=3 (3/2lx,-ly) * * M=5 (-3/2lx,-ly)
+ ! * *
+ ! M=2 (3/2lx, ly) * * M=6 (-3/2lx, ly)
+ ! *****
+ ! M=1 (0, 2ly)
+ ! origins of axes:
+ ! axis 1&2: (-lx/2,-ly)
+ ! axis 3: (-lx , 0)
+ ! axis 4: (-lx/2, ly)
+ ! axis 5: ( lx , 0)
+ ! axis 6: ( lx/2,-ly)
+ IF(TYPBC==G_BC_TYPE(2)) THEN
+ IF(ABS(BCDATA(1,IDATA))<EPS) THEN
+ IF(BCDATA(2,IDATA)>0) THEN
+ M=1
+ ELSE
+ M=4
+ ENDIF
+ ELSEIF(BCDATA(1,IDATA)>0.AND.BCDATA(2,IDATA)>0) THEN
+ M=2
+ ELSEIF(BCDATA(1,IDATA)>0.AND.BCDATA(2,IDATA)<0) THEN
+ M=3
+ ELSEIF(BCDATA(1,IDATA)<0.AND.BCDATA(2,IDATA)>0) THEN
+ M=6
+ ELSEIF(BCDATA(1,IDATA)<0.AND.BCDATA(2,IDATA)<0) THEN
+ M=5
+ ENDIF
+ ELSE
+ CALL XABORT('SAL130_10: wrong boundary condition for TYPGEO=9.')
+ ENDIF
+ CASE(10)
+ !* triangles with rotations and translations:
+ ! typgeo=10 axes definition:
+ ! *
+ ! M=2 * * M=3
+ ! * *
+ ! *************
+ ! M=1
+ IF((TYPBC==G_BC_TYPE(2)).OR.(TYPBC==G_BC_TYPE(3))) THEN
+ IF(ABS(ANGLE)<EPS) THEN
+ ! element is on the axis 1 (angle=0)
+ M=1
+ ELSEIF(ABS(ANGLE-ANGGEO)<EPS) THEN
+ ! element is on the axis 2 (angle=anggeo)
+ M=2
+ ELSEIF(ABS(ANGLE-2.*ANGGEO)<EPS) THEN
+ ! element is on the axis 3 (angle=2*anggeo)
+ M=3
+ ELSE
+ CALL XABORT('SAL130_10: boundary condition data error in element for TYPGEO=10.')
+ ENDIF
+ ELSE
+ CALL XABORT('SAL130_10: wrong boundary condition for TYPGEO=10.')
+ ENDIF
+ CASE(11)
+ !* lozenge with rotations and translations:
+ ! axes definition:
+ ! M=3
+ ! ************
+ ! * *
+ ! M=2 * * M=4
+ ! ************
+ ! M=1
+ IF((TYPBC==G_BC_TYPE(2)).OR.(TYPBC==G_BC_TYPE(3))) THEN
+ IF(ABS(ANGLE)<EPS) THEN
+ IF(BCDATA(2,IDATA)>0) THEN
+ ! cy>0: element is on the axis 3 (angle=0)
+ M=3
+ ELSE
+ ! cy=0: element is on the axis 1 (angle=0)
+ M=1
+ ENDIF
+ ELSE
+ IF(BCDATA(1,IDATA)>0) THEN
+ ! cx>0: element is on the axis 4 (angle>0)
+ M=4
+ ELSE
+ ! cx=0: element is on the axis 2 (angle>0)
+ M=2
+ ENDIF
+ ENDIF
+ ELSE
+ CALL XABORT('SAL130_10: TYPGEO=11:wrong boundary condition type.')
+ ENDIF
+ CASE DEFAULT
+ CALL XABORT('SAL130_10: boundary condition not implemented.')
+ END SELECT
+ IF(M>=NAXES+1) CALL XABORT('SAL130_10: element not on axes')
+ NBE(M)=NBE(M)+1
+ LIST_ELEMS(NBE(M),M)=ELEM
+ ! sort the element list according their distance to
+ ! the origins of the axes
+ D=0.
+ SELECT CASE(TYPGEO)
+ CASE(5:6)
+ SELECT CASE(M)
+ CASE(1:2)
+ DO K=1,2
+ CALL SAL141(IPAR(1,ELEM),RPAR(:,ELEM),X,Y,K)
+ D=MAX(D,SQRT(X*X+Y*Y))
+ ENDDO
+ CASE(3)
+ DO K=1,2
+ CALL SAL141(IPAR(1,ELEM),RPAR(:,ELEM),X,Y,K)
+ D=MAX(D,X)
+ ENDDO
+ CASE(4)
+ DO K=1,2
+ CALL SAL141(IPAR(1,ELEM),RPAR(:,ELEM),X,Y,K)
+ D=MAX(D,Y)
+ ENDDO
+ END SELECT
+ CASE(7)
+ SELECT CASE(M)
+ CASE(1:2)
+ DO K=1,2
+ CALL SAL141(IPAR(1,ELEM),RPAR(:,ELEM),X,Y,K)
+ D=MAX(D,SQRT(X*X+Y*Y))
+ ENDDO
+ CASE(3)
+ DO K=1,2
+ CALL SAL141(IPAR(1,ELEM),RPAR(:,ELEM),X,Y,K)
+ D=MAX(D,Y)
+ ENDDO
+ END SELECT
+ CASE(8,10,12)
+ SELECT CASE(M)
+ CASE(1:2)
+ DO K=1,2
+ CALL SAL141(IPAR(1,ELEM),RPAR(:,ELEM),X,Y,K)
+ D=MAX(D,SQRT(X*X+Y*Y))
+ ENDDO
+ CASE(3)
+ DO K=1,2
+ CALL SAL141(IPAR(1,ELEM),RPAR(:,ELEM),X,Y,K)
+ ! axis origin is (lx,0)
+ D=MAX(D,SQRT((X-LX)*(X-LX)+Y*Y))
+ ENDDO
+ END SELECT
+ CASE(9)
+ ! origins of axes:
+ ! axis 1&2: (-lx/2,-ly)
+ ! axis 3: (-lx , 0)
+ ! axis 4: (-lx/2, ly)
+ ! axis 5: ( lx , 0)
+ ! axis 6: ( lx/2,-ly)
+ SELECT CASE(M)
+ CASE(1:2)
+ DO K=1,2
+ CALL SAL141(IPAR(1,ELEM),RPAR(:,ELEM),X,Y,K)
+ D=MAX(D,SQRT((X+LX*0.5)*(X+LX*0.5)+(Y+LY)*(Y+LY)))
+ ENDDO
+ CASE(3)
+ DO K=1,2
+ CALL SAL141(IPAR(1,ELEM),RPAR(:,ELEM),X,Y,K)
+ D=MAX(D,SQRT((X+LX)*(X+LX)+Y*Y))
+ ENDDO
+ CASE(4)
+ DO K=1,2
+ CALL SAL141(IPAR(1,ELEM),RPAR(:,ELEM),X,Y,K)
+ D=MAX(D,SQRT((X+LX*0.5)*(X+LX*0.5)+(Y-LY)*(Y-LY)))
+ ENDDO
+ CASE(5)
+ DO K=1,2
+ CALL SAL141(IPAR(1,ELEM),RPAR(:,ELEM),X,Y,K)
+ D=MAX(D,SQRT((X-LX)*(X-LX)+Y*Y))
+ ENDDO
+ CASE(6)
+ DO K=1,2
+ CALL SAL141(IPAR(1,ELEM),RPAR(:,ELEM),X,Y,K)
+ D=MAX(D,SQRT((X-LX*0.5)*(X-LX*0.5)+(Y+LY)*(Y+LY)))
+ ENDDO
+ END SELECT
+ CASE(11)
+ SELECT CASE(M)
+ CASE(1:2)
+ DO K=1,2
+ CALL SAL141(IPAR(1,ELEM),RPAR(:,ELEM),X,Y,K)
+ D=MAX(D,SQRT(X*X+Y*Y))
+ ENDDO
+ CASE(3)
+ DO K=1,2
+ CALL SAL141(IPAR(1,ELEM),RPAR(:,ELEM),X,Y,K)
+ D=MAX(D,SQRT((X-LX*0.5)*(X-LX*0.5)+(Y-LY)*(Y-LY)))
+ ENDDO
+ CASE(4)
+ DO K=1,2
+ CALL SAL141(IPAR(1,ELEM),RPAR(:,ELEM),X,Y,K)
+ D=MAX(D,SQRT((X-LX)*(X-LX)+Y*Y))
+ ENDDO
+ END SELECT
+ END SELECT
+ AUX_DIST(NBE(M),M)=D
+ IF(NBE(M)>1) THEN
+ DO K=1,NBE(M)-1
+ IF(AUX_DIST(NBE(M),M)<AUX_DIST(K,M)) THEN
+ ! insert the last element to position k
+ D=AUX_DIST(NBE(M),M)
+ ELEM=LIST_ELEMS(NBE(M),M)
+ DO J=NBE(M),K+1,-1
+ AUX_DIST(J,M)=AUX_DIST(J-1,M)
+ LIST_ELEMS(J,M)=LIST_ELEMS(J-1,M)
+ ENDDO
+ AUX_DIST(K,M)=D
+ LIST_ELEMS(K,M)=ELEM
+ EXIT
+ ENDIF
+ ENDDO
+ ENDIF
+ ENDDO
+ ! nber of blocks in 'perim'
+ M=NAXES
+ !* organize elements as: (elems on axis 1)+(elems on axis 2)+...
+ PPERIM(1)=1
+ DO I=1,M
+ PPERIM(I+1)=PPERIM(I)+NBE(I)
+ ENDDO
+ DO I=1,M
+ PERIM(PPERIM(I):PPERIM(I+1)-1)=LIST_ELEMS(1:NBE(I),I)
+ ENDDO
+ !* allocate and set dist_axis
+ IF(PPERIM(NAXES+1)-1>0) THEN
+ ALLOCATE(DIST_AXIS(PPERIM(NAXES+1)-1),STAT=OK)
+ IF(OK.NE.0) CALL XABORT('SAL130_10: not enough memory R')
+ DO I=1,NAXES
+ DIST_AXIS(PPERIM(I):PPERIM(I+1)-1)=AUX_DIST(1:NBE(I),I)
+ ENDDO
+ ELSE
+ NULLIFY(DIST_AXIS)
+ ENDIF
+ !
+ END SUBROUTINE SAL130_10
+ !
+ SUBROUTINE SAL131(GG)
+ !
+ !---------------------------------------------------------------------
+ !
+ !Purpose:
+ ! modifies GG%IPAR and constructs bcdata (modifies GG%IPAR and
+ ! constructs BCDATA)
+ !
+ !Parameters: input/output
+ ! GG geometry descriptor
+ !
+ !---------------------------------------------------------------------
+ !
+ USE SAL_GEOMETRY_TYPES, ONLY : G_BC_MAX_LEN,G_BC_LEN,G_BC_TYPE,NIPAR,EPS, &
+ ANGGEO,TYPGEO,LENGTHX,LENGTHY,ALLSUR
+ !****
+ IMPLICIT NONE
+ ! in variable
+ ! ************
+ TYPE(T_G_BASIC), INTENT(INOUT) :: GG
+ !****
+ LOGICAL :: LGBC,LGALLS
+ INTEGER :: TYPE,II,NN,NBER,I,J,ITBC,IELEM
+ REAL(PDB) :: ANGLE
+ INTEGER :: ELEM,IBC,OK,IDATA(2)
+ INTEGER, POINTER, DIMENSION(:) :: TYPE_BC2,ISURF2_ELEM,IELEM_BC2
+ !*****
+ !** TMP_BCDATA = description of motions at the boundary
+ !** IPAR = pointer to geometry descriptors
+ INTEGER, DIMENSION(GG%NB_ELEM) :: AUX_ARR
+ REAL(PDB), DIMENSION(G_BC_MAX_LEN,GG%NB_ELEM+5) :: TMP_BCDATA
+ !*****
+ !* initialization
+ IF(TYPGEO==1.OR.TYPGEO==2) IDATA(:)=0
+ !* BCDATA for surfaces of type G_BC_TYPE(-1)
+ !
+ LGALLS=ALLSUR/=0
+ ITBC=0 ! the first bc data
+ !
+ !* treat approximate boundary condictions
+ IF(LGALLS)THEN
+ ITBC=1
+ ! ALL BC'S PRODUIT SURFACES
+ IF(GG%DEFAUL==1)THEN
+ ! SPECULAR REFLEXION -> ISOTROPIC REFLEXION WITH ALBEDO=1
+ GG%DEFAUL=0 ; TMP_BCDATA(6,ITBC)=1._PDB
+ ENDIF
+ ENDIF
+ !
+ !* put default value in all bc elements:
+ CALL SAL131_2(GG%NB_ELEM,GG%DEFAUL,GG%IPAR,GG%IBC2_ELEM,GG%TYPE_BC2,GG%IDATA_BC2)
+ !
+ IF(GG%NBBCDA>0)THEN
+ ANGLE=0._PDB
+ DO I=1,GG%NBBCDA
+ ITBC=ITBC+1
+ IF(ITBC.GT.GG%NB_ELEM+5) CALL XABORT('SAL131: BCDATA overflow')
+ TMP_BCDATA(:,ITBC)=GG%BCDATAREAD(I)%BCDATA(:)
+ TYPE=GG%BCDATAREAD(I)%SALTYPE
+ SELECT CASE(TYPE)
+ CASE(1)
+ IF(LGALLS)THEN
+ ! specular reflexion -> isotropic reflexion with albedo=1
+ TYPE=0 ; TMP_BCDATA(6,ITBC)=1._PDB
+ ENDIF
+ CASE(2)
+ ANGLE=TMP_BCDATA(5,ITBC)
+ SELECT CASE(TYPGEO)
+ CASE(5)
+ ! adjust translation data according to the sides of rectangle
+ IF(TMP_BCDATA(1,ITBC)/=0) TMP_BCDATA(1,ITBC)=SIGN(LENGTHX,TMP_BCDATA(1,ITBC))
+ IF(TMP_BCDATA(2,ITBC)/=0) TMP_BCDATA(2,ITBC)=SIGN(LENGTHY,TMP_BCDATA(2,ITBC))
+ CASE(9)
+ ! adjust translation data according to the hexagonal sides
+ IF(ABS(TMP_BCDATA(1,ITBC))<EPS) THEN
+ ! axes 1 & 4
+ TMP_BCDATA(2,ITBC)=SIGN(2.*LENGTHY,TMP_BCDATA(2,ITBC))
+ ELSE
+ TMP_BCDATA(1,ITBC)=SIGN(LENGTHX*1.5,TMP_BCDATA(1,ITBC))
+ TMP_BCDATA(2,ITBC)=SIGN(LENGTHY,TMP_BCDATA(2,ITBC))
+ ENDIF
+ TMP_BCDATA(3,ITBC)=COS(ANGLE)
+ TMP_BCDATA(4,ITBC)=SIN(ANGLE)
+ TMP_BCDATA(5,ITBC)=ANGLE
+ CASE(11)
+ ! adjust translation data according to the hexagonal sides
+ IF(ABS(ANGLE)<EPS) THEN
+ IF(TMP_BCDATA(2,ITBC)>0.) THEN
+ ! cy>0 and angle=0
+ TMP_BCDATA(1,ITBC)=LENGTHX/2.0
+ TMP_BCDATA(2,ITBC)=LENGTHY
+ ELSE
+ ! cy=0 and angle=0
+ TMP_BCDATA(1,ITBC)=0.0
+ TMP_BCDATA(2,ITBC)=0.0
+ ENDIF
+ ELSE
+ IF(TMP_BCDATA(1,ITBC)>0.) THEN
+ ! cx>0 and angle=pi/3 rad
+ TMP_BCDATA(1,ITBC)=LENGTHX
+ TMP_BCDATA(2,ITBC)=0.0
+ ELSE
+ ! cx=0 and angle=pi/3 rad
+ TMP_BCDATA(1,ITBC)=0.0
+ TMP_BCDATA(2,ITBC)=0.0
+ ENDIF
+ ENDIF
+ TMP_BCDATA(3,ITBC)=COS(ANGLE)
+ TMP_BCDATA(4,ITBC)=SIN(ANGLE)
+ TMP_BCDATA(5,ITBC)=ANGLE
+ END SELECT
+ IF(LGALLS)THEN
+ ! translation -> isotropic translation with albedo=1
+ TYPE=TYPE+4
+ ! perform array shift
+ TMP_BCDATA(:,ITBC)=CSHIFT(TMP_BCDATA(:,ITBC),1)
+ ! albedo=1
+ TMP_BCDATA(6,ITBC)=1._PDB
+ ENDIF
+ CASE(3)
+ ! cases of rotation:
+ ! read angle, compute cos and sin
+ ANGLE=TMP_BCDATA(5,ITBC)
+ IF(TYPGEO==1.OR.TYPGEO==2) THEN
+ IF(ABS(ANGLE-ANGGEO)<EPS) THEN
+ ! for the axis 1:keep anggeo,cos(anggeo),sin(anggeo)
+ ANGLE=ANGGEO
+ IF(IDATA(1)==0) IDATA(1)=ITBC
+ ELSEIF(ABS(ANGLE+ANGGEO)<EPS) THEN
+ ! for the axis 2:keep -anggeo,cos(-anggeo),sin(-anggeo)
+ ANGLE=-ANGGEO
+ IF(IDATA(2)==0) IDATA(2)=ITBC
+ ELSE
+ CALL XABORT('SAL131: error in angle of rotative axis')
+ ENDIF
+ ENDIF
+ TMP_BCDATA(3,ITBC)=COS(ANGLE)
+ TMP_BCDATA(4,ITBC)=SIN(ANGLE)
+ TMP_BCDATA(5,ITBC)=ANGLE
+ IF(LGALLS)THEN
+ ! rotation -> isotropic rotation with albedo=1
+ ! axial symmetry -> isotropic axial symmetry with albedo=1
+ TYPE=TYPE+4
+ ! perform array shift
+ TMP_BCDATA(:,ITBC)=CSHIFT(TMP_BCDATA(:,ITBC),1)
+ ! albedo=1
+ TMP_BCDATA(6,ITBC)=1._PDB
+ ENDIF
+ CASE(4)
+ ! cases of specular symmetry:
+ ! read center and angle, compute cos and sin
+ ANGLE=TMP_BCDATA(5,ITBC)
+ SELECT CASE(TYPGEO)
+ CASE(1,2)
+ IF(ABS(ANGLE-0.)<EPS) THEN
+ IF(IDATA(1)==0) IDATA(1)=ITBC
+ ELSE
+ IF(IDATA(2)==0) IDATA(2)=ITBC
+ ENDIF
+ CASE(6:8)
+ ! adjust translation data according to the rectangle/triangle sides
+ IF(TMP_BCDATA(1,ITBC)/=0) TMP_BCDATA(1,ITBC)=SIGN(LENGTHX,TMP_BCDATA(1,ITBC))
+ IF(TMP_BCDATA(2,ITBC)/=0) TMP_BCDATA(2,ITBC)=SIGN(LENGTHY,TMP_BCDATA(2,ITBC))
+ END SELECT
+ TMP_BCDATA(3,ITBC)=COS(ANGLE)
+ TMP_BCDATA(4,ITBC)=SIN(ANGLE)
+ TMP_BCDATA(5,ITBC)=ANGLE
+ IF(LGALLS)THEN
+ ! rotation -> isotropic rotation with albedo=1
+ ! axial symmetry -> isotropic axial symmetry with albedo=1
+ TYPE=TYPE+4
+ ! perform array shift
+ TMP_BCDATA(:,ITBC)=CSHIFT(TMP_BCDATA(:,ITBC),1)
+ ! albedo=1
+ TMP_BCDATA(6,ITBC)=1._PDB
+ ENDIF
+ END SELECT
+ !
+ ! modify notation for boundary conditions
+ NBER=GG%BCDATAREAD(I)%NBER
+ DO J=1,NBER
+ ELEM=GG%BCDATAREAD(I)%ELEMNB(J)
+ IF(ELEM>GG%NB_ELEM.OR.ELEM<=0) CALL XABORT('SAL131: unknown bc element')
+ ! get local surface nber
+ IBC=GG%IBC2_ELEM(ELEM)
+ LGBC=GG%IPAR(2,ELEM)<=0
+ II=0
+ IF(LGBC)THEN
+ II=2
+ ELSE
+ LGBC=GG%IPAR(3,ELEM)<=0
+ IF(LGBC) II=3
+ ENDIF
+ IF(.NOT.LGBC) THEN
+ WRITE(*,*) 'elem :',ELEM
+ WRITE(*,*) 'GG%IPAR(:,ELEM) :',GG%IPAR(:,ELEM)
+ CALL XABORT('SAL131: wrong bc element')
+ ENDIF
+ ! put bc type
+ GG%IPAR(II,ELEM)=G_BC_TYPE(TYPE)
+ GG%TYPE_BC2(IBC)=G_BC_TYPE(TYPE)
+ ! put bc data position :
+ GG%IDATA_BC2(IBC)=ITBC
+ ENDDO
+ ENDDO
+ ENDIF
+ !
+ !* - set BCDATA position for surfaces of type G_BC_TYPE(-1)
+ ! - compute the nber of surfaces (type -1,0,-12,-13,-14,-15) : nbsur2
+ ! - allocate structures for the surfaces
+ ! - compute surf_mac2
+ TYPE_BC2=>GG%TYPE_BC2
+ ISURF2_ELEM=>GG%ISURF2_ELEM
+ IELEM_BC2=>GG%PERIM_MAC2
+ NN=0
+ DO IBC=1,GG%NB_BC2
+ IF(TYPE_BC2(IBC)==G_BC_TYPE(-1)) THEN
+ ! macro contact surfaces : set bcdata position to 1
+ GG%IDATA_BC2(IBC)=1
+ ENDIF
+ ! relative element nber
+ IELEM=IELEM_BC2(IBC)
+ ! count 2D surfaces number
+ IF(TYPE_BC2(IBC)==G_BC_TYPE(-1) .OR. TYPE_BC2(IBC)==G_BC_TYPE(0) .OR. &
+ TYPE_BC2(IBC)==G_BC_TYPE(1)) THEN
+ NN=NN+1
+ AUX_ARR(NN)=IBC
+ ISURF2_ELEM(IELEM)=NN
+ ELSE
+ ISURF2_ELEM(IELEM)=0
+ ENDIF
+ ENDDO
+ GG%NB_SURF2=NN
+ IF(NN>0) THEN
+ ALLOCATE (GG%IBC2_SURF2(NN),GG%IELEM_SURF2(NN),STAT=OK)
+ IF(OK/=0) CALL XABORT('SAL131: NOT ENOUGH MEMORY I,R')
+ GG%IBC2_SURF2(1:NN)=AUX_ARR(1:NN)
+ ELSE
+ NULLIFY(GG%IBC2_SURF2,GG%IELEM_SURF2)
+ ENDIF
+ !
+ !* allocate idata_axis
+ IF(TYPGEO==1.OR.TYPGEO==2) THEN
+ DO I=1,2
+ IF(IDATA(I)==0) THEN
+ ! there is no elements on this axis,add a bcdata for this axis
+ ITBC=ITBC+1
+ ANGLE=0._PDB
+ IF(TYPGEO==1) THEN
+ ! symmetry
+ IF(I==1) THEN
+ ANGLE=0._PDB
+ ELSE
+ ANGLE=ANGGEO
+ ENDIF
+ ELSEIF(TYPGEO==2) THEN
+ ! rotation
+ IF(I==1) THEN
+ ANGLE=ANGGEO
+ ELSE
+ ANGLE=-ANGGEO
+ ENDIF
+ ENDIF
+ TMP_BCDATA(1,ITBC)=0._PDB
+ TMP_BCDATA(2,ITBC)=0._PDB
+ TMP_BCDATA(3,ITBC)=COS(ANGLE)
+ TMP_BCDATA(4,ITBC)=SIN(ANGLE)
+ TMP_BCDATA(5,ITBC)=ANGLE
+ IDATA(I)=ITBC
+ ENDIF
+ ENDDO
+ ALLOCATE(GG%IDATA_AXIS(2), STAT=OK)
+ IF(OK.NE.0) CALL XABORT('SAL131: not enough memory I')
+ GG%IDATA_AXIS=IDATA
+ ENDIF
+ !* allocate bcdata
+ ALLOCATE (GG%BCDATA(G_BC_MAX_LEN,ITBC), STAT=OK)
+ IF(OK/=0) CALL XABORT('SAL131: not enough memory R')
+ GG%BCDATA(:,1:ITBC)=TMP_BCDATA(:,1:ITBC)
+ GG%NALBG=ITBC
+ !
+ END SUBROUTINE SAL131
+ !
+ SUBROUTINE SAL131_2(NB_ELEM,DEFAUL,IPAR,IBC2_ELEM,TYPE_BC2,IDATA_BC2)
+ !
+ !---------------------------------------------------------------------
+ !
+ !Purpose:
+ ! put default bc type and BCDATA to a 2D macro
+ !
+ !Parameters: input
+ ! NB_ELEM nber of elements
+ ! DEFAUL default bc type
+ ! IBC2_ELEM relative 2D bc number per element
+ !
+ !Parameters: input/output
+ ! IPAR integer descriptors for elements
+ !
+ !Parameters: input
+ ! TYPE_BC2 2D boundary condiction type
+ ! IDATA_BC2 position in bcdata par 2D bc
+ !
+ !---------------------------------------------------------------------
+ !
+ USE SAL_GEOMETRY_TYPES, ONLY : G_BC_TYPE
+ !****
+ IMPLICIT NONE
+ INTEGER, INTENT(IN) :: NB_ELEM,DEFAUL
+ INTEGER, INTENT(INOUT), DIMENSION(:,:) :: IPAR
+ INTEGER, INTENT(IN), DIMENSION(:) :: IBC2_ELEM
+ INTEGER, INTENT(OUT), DIMENSION(:) :: TYPE_BC2
+ INTEGER, INTENT(OUT), DIMENSION(:) :: IDATA_BC2
+ !****
+ INTEGER :: ELEM,II,IBC
+ LOGICAL :: LGBC
+ !****
+ ! initiation
+ TYPE_BC2=G_BC_TYPE(-1)
+ !
+ DO ELEM=1,NB_ELEM
+ LGBC=IPAR(2,ELEM)==0
+ II=0
+ IF(LGBC) THEN
+ II=2
+ IF(IPAR(3,ELEM)<=0) CALL XABORT('SAL131_2: element with 2 bc''s')
+ ELSE
+ LGBC=IPAR(3,ELEM)==0
+ IF(LGBC) II=3
+ ENDIF
+ IF(LGBC) THEN
+ ! put bc type value to ipar
+ IPAR(II,ELEM)=G_BC_TYPE(DEFAUL)
+ ! put bc type value to bc type structure
+ IBC=IBC2_ELEM(ELEM)
+ IF(IBC==0) CALL XABORT('SAL131_2: surf-element relation error')
+ IF(TYPE_BC2(IBC)/=G_BC_TYPE(-1)) CALL XABORT('SAL131_2: two elements to a surface')
+ TYPE_BC2(IBC)=G_BC_TYPE(DEFAUL)
+ ! put position of "defaul" in bcdata table (use default albedo)
+ IDATA_BC2(IBC)=0
+ ENDIF
+ ENDDO
+ !
+ END SUBROUTINE SAL131_2
+ !
+ SUBROUTINE SAL140(NB_NODE,RPAR,IPAR,PPERIM,PERIM)
+ !
+ !---------------------------------------------------------------------
+ !
+ !Purpose:
+ ! checks domain topology in a 2D macro
+ !
+ !Parameters: input
+ ! NB_NODE number of nodes in macro
+ !
+ !Parameters: input/output
+ ! RPAR floating point geometry descriptors
+ ! IPAR integer descriptors for elements
+ ! PPERIM pointer to list of elements in perimeter
+ ! PERIM list of perimeters
+ !
+ !---------------------------------------------------------------------
+ !
+ USE SAL_GEOMETRY_TYPES, ONLY : NRPAR,NIPAR
+ !****
+ IMPLICIT NONE
+ INTEGER, INTENT(IN) :: NB_NODE
+ INTEGER, INTENT(IN), DIMENSION (:) :: PPERIM
+ INTEGER, INTENT(INOUT), DIMENSION (:,:) :: IPAR
+ INTEGER, INTENT(INOUT), DIMENSION (:) :: PERIM
+ REAL(PDB), INTENT(INOUT), DIMENSION (:,:) :: RPAR
+ !****
+ INTEGER :: ELEM,NODE,ID,L,FIRST,LAST,NEXT,NLOOP, &
+ NEWEND,KEEP,IEND,I1,I2
+ REAL(PDB) :: X,Y,XNEW,YNEW,DIST
+ LOGICAL :: LGOPEN,LGON,LGERR
+ INTEGER, PARAMETER :: MXKEEP = 20
+ REAL, DIMENSION(MXKEEP) :: KEEPD
+ INTEGER, PARAMETER :: FOUT =6
+ REAL(PDB),PARAMETER :: EPS2=1.0E-7_PDB
+ !*****
+ NEXT=0
+ !* checks topology of each node
+ DO NODE=1,NB_NODE
+ I1=PPERIM(NODE)
+ ! ID counts elements in the perimeter already treated
+ ID=I1-1
+ I2=PPERIM(NODE+1)-1
+ IF(I2<I1) CALL XABORT('SAL140: node without perimeter')
+ ! mark elements in perimeter of node as untreated
+ ! (except full circle: ipar=2)
+ DO L=I1,I2
+ ELEM=PERIM(L)
+ IF(IPAR(1,ELEM)==2)THEN
+ ID=ID+1
+ IF(ID<L)THEN
+ ! move circles at beginning
+ PERIM(L)=PERIM(ID)
+ PERIM(ID)=ELEM
+ ENDIF
+ ENDIF
+ ENDDO
+ ID=ID+1
+ ! nloop counts nber of loops for node
+ NLOOP=ID-1
+ ! treat all elements in perimeter until they have been all done:
+ DO WHILE (ID<I2)
+ ! an element in the perimeter that has not been done
+ FIRST=PERIM(ID)
+ NLOOP=NLOOP+1
+ ! get first end for this element:
+ IEND=1
+ ! determine the loop defined by element last:
+ LGOPEN=.TRUE.
+ LAST=FIRST
+ DO WHILE(LGOPEN)
+ ! get coordinates x and y of end of element last
+ CALL SAL141(IPAR(1,LAST),RPAR(:,LAST),X,Y,IEND)
+ ! get next element in the perimeter in touch with
+ ! last element at its end iend
+ LGON=.TRUE.
+ L=ID+1
+ KEEP=0
+ DO WHILE(LGON.AND.L<=I2)
+ NEXT=PERIM(L)
+ ! check whether next is really 'next' to last
+ CALL SAL142(X,Y,XNEW,YNEW,IPAR(1,NEXT),RPAR(:,NEXT),NEWEND,EPS2,DIST)
+ IF(KEEP<MXKEEP)KEEP=KEEP+1
+ KEEPD(KEEP)=REAL(DIST)
+ LGON=NEWEND<0
+ IF(LGON)L=L+1
+ ENDDO
+ LGOPEN=.NOT.LGON
+ IF(LGOPEN)THEN
+ ! replace last element in order in the perimeter
+ ID=ID+1
+ IF(ID<L)THEN
+ PERIM(L)=PERIM(ID)
+ PERIM(ID)=NEXT
+ ENDIF
+ ELSE
+ LGERR=.FALSE.
+ ! try to close with first element of loop:
+ CALL SAL142(X,Y,XNEW,YNEW,IPAR(1,FIRST),RPAR(:,FIRST),NEWEND,EPS2,DIST)
+ LGOPEN=NEWEND<0
+ IF(LGOPEN)THEN
+ ! fatal error: cannot close loop for this node
+ WRITE(FOUT,'(//,''==> cannot close node '',i5, &
+ &'' AT ELEMENT'',I5,/)')NODE,LAST
+ LGERR=.TRUE.
+ ELSEIF(FIRST==LAST)THEN
+ WRITE(FOUT,'(//,''==> node '',i5,'' with '', &
+ &''isolated element'',i5,/)')NODE,LAST
+ LGERR=.TRUE.
+ ENDIF
+ IF(LGERR) CALL XABORT('SAL140: node not closed')
+ NEXT=FIRST
+ ENDIF
+ ! define last = next element and proceed
+ LAST=NEXT
+ IEND=3-NEWEND
+ ENDDO
+ ID=ID+1
+ ENDDO
+ ENDDO
+ !
+ END SUBROUTINE SAL140
+ !
+ SUBROUTINE SAL142(X,Y,XNEW,YNEW,TYPE,RPAR,IEND,EPS2,DIST)
+ !
+ !---------------------------------------------------------------------
+ !
+ !Purpose:
+ ! checks whether element is very close to point (X,Y)
+ !
+ !Parameters: input
+ ! X abscissa coordinate
+ ! Y ordinate coordinate
+ ! TYPE type of element 1 (segment), 3 (arc of circle)
+ ! EPS2 criterium for closeness
+ !
+ !Parameters: input/output
+ ! XNEW abscissa coordinate of end of element close to point
+ ! YNEW ordinate coordinate of end of element close to point
+ ! RPAR floating point geometry descriptors
+ ! IEND = 1 (beginning is close to point dist < EPS2)
+ ! 2 (end is close to point DIST < EPS2)
+ ! -1 (beginning is close to point dist > EPS2)
+ ! -2 (end is close to point DIST > EPS2)
+ ! DIST distance from end of element to point (X,Y)
+ !
+ !---------------------------------------------------------------------
+ !
+ USE SAL_GEOMETRY_TYPES, ONLY : G_ELE_TYPE
+ !****
+ IMPLICIT NONE
+ INTEGER, INTENT(IN) :: TYPE
+ INTEGER, INTENT(OUT) :: IEND
+ REAL(PDB), INTENT(IN) :: X,Y,EPS2
+ REAL(PDB), INTENT(OUT) :: XNEW,YNEW,DIST
+ REAL(PDB), INTENT(IN), DIMENSION(:) :: RPAR
+ ! DIMENSION RPAR(NRPAR)
+ !****
+ REAL(PDB) :: CX,CY,THETA,R,DIST2
+ !****
+ !* function giving distance between two points:
+ REAL(PDB) :: FUNC,X1,Y1,X2,Y2
+ FUNC(X1,Y1,X2,Y2)=(X1-X2)**2+(Y1-Y2)**2
+ !****
+ CX=RPAR(1)
+ CY=RPAR(2)
+ DIST2=0._PDB
+ IF(TYPE==G_ELE_TYPE(1))THEN
+ !* segment
+ XNEW=CX
+ YNEW=CY
+ DIST=FUNC(XNEW,YNEW,X,Y)
+ IF(DIST<=EPS2)THEN
+ IEND=1
+ RETURN
+ ELSE
+ XNEW=CX+RPAR(3)
+ YNEW=CY+RPAR(4)
+ DIST2=FUNC(XNEW,YNEW,X,Y)
+ ENDIF
+ ELSEIF(TYPE<=G_ELE_TYPE(3))THEN
+ !* arc of circle
+ R=RPAR(3)
+ THETA=RPAR(4)
+ XNEW=CX+R*COS(THETA)
+ YNEW=CY+R*SIN(THETA)
+ DIST=FUNC(XNEW,YNEW,X,Y)
+ IF(DIST<=EPS2)THEN
+ IEND=1
+ RETURN
+ ELSE
+ THETA=RPAR(5)
+ XNEW=CX+R*COS(THETA)
+ YNEW=CY+R*SIN(THETA)
+ DIST2=FUNC(XNEW,YNEW,X,Y)
+ ENDIF
+ ELSE
+ CALL XABORT('SAL142: not implemented')
+ ENDIF
+ !
+ IF(DIST2<=EPS2)THEN
+ DIST=DIST2
+ IEND=2
+ RETURN
+ ELSE
+ IF(DIST<=DIST2)THEN
+ IEND=-1
+ ELSE
+ DIST=DIST2
+ IEND=-2
+ ENDIF
+ ENDIF
+ !
+ END SUBROUTINE SAL142
+ !
+ SUBROUTINE SAL160(GG)
+ !
+ !---------------------------------------------------------------------
+ !
+ !Purpose:
+ ! analyse domain definition: 2D volumes, surfaces
+ ! - compute node volumes
+ ! - compute areas of 2d surfaces
+ ! - read medium data
+ !
+ !Parameters: input/output
+ ! GG geometry descriptor
+ !
+ !---------------------------------------------------------------------
+ !
+ USE SAL_GEOMETRY_TYPES, ONLY : G_BC_TYPE,NBMED
+ !****
+ IMPLICIT NONE
+ TYPE(T_G_BASIC), INTENT(INOUT) :: GG
+ !****
+ INTEGER :: INB,IMED
+ INTEGER, DIMENSION(GG%NB_NODE) :: DATAIN
+ !****
+ ! SUBROUTINE SAL160_2(NB_ELEM,IPAR,RPAR,VOL2,ISURF2_ELEM,NB_SURF2,SURF2)
+ IF(GG%NB_SURF2==0) THEN
+ CALL SAL160_2(GG%NB_ELEM,GG%IPAR,GG%RPAR,GG%VOL_NODE,GG%ISURF2_ELEM, &
+ GG%NB_SURF2)
+ ELSE
+ CALL SAL160_2(GG%NB_ELEM,GG%IPAR,GG%RPAR,GG%VOL_NODE,GG%ISURF2_ELEM, &
+ GG%NB_SURF2,GG%SURF2)
+ ENDIF
+ !
+ !* read medium per region
+ CALL SALGET(DATAIN,GG%NB_NODE,F_GEO,FOUT0,'media per node')
+
+ ! number of media fixed to maximum of datain
+ NBMED = MAXVAL(DATAIN(1:GG%NB_NODE))
+ !
+ !* check and define med for code regions
+ DO INB=1,GG%NB_NODE
+ IMED=DATAIN(INB)
+ IF(IMED>NBMED.OR.IMED<0)THEN
+ WRITE(*,*) 'medium : ',IMED
+ WRITE(*,*) 'inb, nbmed, nbnode : ',INB,NBMED,GG%NB_NODE
+ CALL XABORT('SAL160: wrong medium in a region')
+ ENDIF
+ GG%MED(INB)=IMED
+ ENDDO
+ !
+ END SUBROUTINE SAL160
+ !
+ SUBROUTINE SAL160_2(NB_ELEM,IPAR,RPAR,VOL2,ISURF2_ELEM,NB_SURF2,SURF2)
+ !
+ !---------------------------------------------------------------------
+ !
+ !Purpose:
+ ! compute 2D volumes and surfaces
+ ! - compute node volumes
+ ! - compute 2D surface areas
+ !
+ !Parameters: input
+ ! NB_ELEM number of elements
+ ! NB_NODE number of nodes
+ ! IPAR integer descriptors for elements
+ ! RPAR floating point descriptors for elements
+ ! ISURF2_ELEM 2D surface nber per elem
+ ! NB_SURF2 number of 2D surface
+ !
+ !Parameters: output
+ ! VOL2 2D volumes of node
+ ! SURF2 2D areas of node
+ !
+ !---------------------------------------------------------------------
+ !
+ USE PRECISION_AND_KINDS, ONLY : PDB
+ USE SAL_GEOMETRY_TYPES, ONLY : G_BC_TYPE
+ !****
+ IMPLICIT NONE
+ INTEGER, INTENT(IN) :: NB_ELEM
+ INTEGER, INTENT(IN), DIMENSION(:,:) :: IPAR
+ REAL(PDB), INTENT(IN), DIMENSION(:,:) :: RPAR
+ REAL(PDB), INTENT(OUT), DIMENSION(:) :: VOL2
+ INTEGER, INTENT(IN), DIMENSION(:) :: ISURF2_ELEM
+ INTEGER, INTENT(IN) :: NB_SURF2
+ REAL(PDB), INTENT(OUT), OPTIONAL, DIMENSION(:) :: SURF2
+ !****
+ INTEGER :: ELEM,NODEBC,NODE,ISURF
+ LOGICAL :: LGBC
+ REAL(PDB) :: AUX
+ !****
+ ! initiation
+ VOL2=0._PDB
+ IF(NB_SURF2 > 0) SURF2=0._PDB
+ DO ELEM=1,NB_ELEM
+ !* compute volume of node and add to volume of region (local)
+ CALL SAL161(IPAR(1,ELEM),RPAR(:,ELEM),AUX)
+ NODEBC=IPAR(2,ELEM)
+ LGBC=NODEBC<=0
+ IF(.NOT.LGBC) VOL2(NODEBC)=VOL2(NODEBC)+AUX
+ NODE=IPAR(3,ELEM)
+ IF(NODE>0)THEN
+ VOL2(NODE)=VOL2(NODE)-AUX
+ ELSE
+ IF(LGBC) CALL XABORT('SAL160_2: isolated element')
+ LGBC=.TRUE.
+ NODEBC=NODE
+ ENDIF
+ IF(LGBC) THEN
+ IF(NODEBC==G_BC_TYPE(-1).OR.NODEBC==G_BC_TYPE(0).OR.NODEBC==G_BC_TYPE(1))THEN
+ ! compute external surface (loaded in total order number)
+ ISURF=ISURF2_ELEM(ELEM)
+ IF(ISURF==0) CALL XABORT('SAL160_2: wrong relation of element - surf ')
+ CALL SAL162(IPAR(1,ELEM),RPAR(:,ELEM),SURF2(ISURF))
+ ENDIF
+ ENDIF
+ ENDDO
+ !
+ END SUBROUTINE SAL160_2
+ !
+ SUBROUTINE SAL161(TYPE,RPAR,VOL2)
+ !
+ !---------------------------------------------------------------------
+ !
+ !Purpose:
+ ! computes 'volume' between an element and the x axis
+ !
+ !Parameters: input
+ ! TYPE type of element
+ ! RPAR floating point descriptors for elements
+ !
+ !Parameters: output
+ ! VOL2 '2D area' between the element and the horizontal axis
+ !
+ !---------------------------------------------------------------------
+ !
+ IMPLICIT NONE
+ INTEGER, INTENT(IN) :: TYPE
+ REAL(PDB), INTENT(IN), DIMENSION (:) :: RPAR
+ REAL(PDB), INTENT(OUT) :: VOL2
+ ! DIMENSION RPAR(*)
+ !****
+ REAL(PDB) :: YC,EX,EY,R,PHI1,PHI2,COS1,COS2
+ !****
+ ! volume is added to node- and substracted from node+
+ YC=RPAR(2)
+ IF(TYPE==1)THEN
+ ! segment:
+ EX=RPAR(3)
+ EY=RPAR(4)
+ VOL2=EX*(YC+EY/2.)
+ ELSEIF(TYPE==2)THEN
+ ! whole circle
+ VOL2=PI*RPAR(3)*RPAR(3)
+ ELSEIF(TYPE==3)THEN
+ ! arc of circle:
+ R=RPAR(3)
+ PHI1=RPAR(4)
+ PHI2=RPAR(5)
+ COS1=COS(PHI1)
+ COS2=COS(PHI2)
+ VOL2=R*(YC*(COS1-COS2)+(R/2.0)*(PHI2-PHI1+ &
+ & (SIN(PHI1)*COS1-SIN(PHI2)*COS2)))
+ ELSE
+ CALL XABORT('SAL161: not implemented')
+ ENDIF
+ !
+ END SUBROUTINE SAL161
+ !
+ SUBROUTINE SAL162(TYPE,RPAR,SURF2)
+ !
+ !---------------------------------------------------------------------
+ !
+ !Purpose:
+ ! computes surface of a boundary element
+ !
+ !Parameters: input
+ ! TYPE type of element
+ ! RPAR floating point descriptors for elements
+ !
+ !Parameters: output
+ ! SURF2 '2D length' of element
+ !
+ !---------------------------------------------------------------------
+ !
+ IMPLICIT NONE
+ INTEGER, INTENT(IN) :: TYPE
+ REAL(PDB), INTENT(IN), DIMENSION (:) :: RPAR
+ REAL(PDB), INTENT(OUT) :: SURF2
+ !****
+ IF(TYPE==1)THEN
+ ! segment
+ SURF2=RPAR(5)
+ ELSEIF(TYPE<=3)THEN
+ ! arc of circle
+ SURF2=(RPAR(5)-RPAR(4))*RPAR(3)
+ ELSE
+ CALL XABORT('SAL162: not implemented')
+ ENDIF
+ !
+ END SUBROUTINE SAL162
+ !
+ SUBROUTINE SAL170(GG)
+ !
+ !---------------------------------------------------------------------
+ !
+ !Purpose:
+ ! prints out volume, surface and medium info for 2D macros
+ !
+ !Parameters: input/output
+ ! GG geometry descriptor
+ !
+ !---------------------------------------------------------------------
+ !
+ USE SAL_GEOMETRY_TYPES, ONLY : G_BC_TYPE
+ USE SAL_TRACKING_TYPES, ONLY : PRTIND
+ !****
+ IMPLICIT NONE
+ TYPE(T_G_BASIC), INTENT(INOUT) :: GG
+ INTEGER, PARAMETER :: FOUT =6
+
+ !****
+ IF(PRTIND == 1) THEN
+ WRITE(FOUT,'(//,10x,''2D geometry'',/,10X,11(''=''),//, &
+ &I8,'' regions'',/, &
+ &I8,'' external surfaces'',//)') GG%NB_NODE,GG%NB_SURF2
+ ENDIF
+ !
+ END SUBROUTINE SAL170
+ !
+ SUBROUTINE SALSYM(X1,Y1,X2,Y2,X0,Y0,X4,Y4)
+ !
+ !---------------------------------------------------------------------
+ !
+ !Purpose:
+ ! set the symmetric point (x4,y4) of (x0,y0) relative to symmetry axis
+ ! (x1,y1)->(x2,y2)
+ !
+ !Parameters: input
+ ! X1 abscissa coordinate of a point on the symmetry axis
+ ! Y1 ordinate coordinate of a point on the symmetry axis
+ ! X2 abscissa coordinate of a point on the symmetry axis
+ ! Y2 ordinate coordinate of a point on the symmetry axis
+ ! X0 abscissa coordinate of the point to mirror
+ ! Y0 ordinate coordinate of the point to mirror
+ !
+ !Parameters: output
+ ! X4 abscissa coordinate of the symmetric point
+ ! Y4 ordinate coordinate of the symmetric point
+ !
+ !---------------------------------------------------------------------
+ !
+ IMPLICIT NONE
+ REAL(PDB),INTENT(IN) :: X1,Y1,X2,Y2,X0,Y0
+ REAL(PDB),INTENT(OUT) :: X4,Y4
+
+ REAL(PDB) :: A,B,C,DEN,X3,Y3
+ A=Y2-Y1; B=X1-X2; C=X2*Y1-X1*Y2;
+ DEN=A*A+B*B;
+ IF(DEN==0._PDB) CALL XABORT('SALSYM: division by zero')
+ X3=(B*(B*X0-A*Y0)-A*C)/DEN;
+ Y3=(A*(-B*X0+A*Y0)-B*C)/DEN;
+ X4=X0+2._PDB*(X3-X0); Y4=Y0+2._PDB*(Y3-Y0);
+ END SUBROUTINE SALSYM
+ !
+ SUBROUTINE SALROT(X0,Y0,THETA,X3,Y3,X4,Y4)
+ !
+ !---------------------------------------------------------------------
+ !
+ !Purpose:
+ ! set the symmetric point (x4,y4) of (x3,y3) relative to the rotation
+ ! center (x1,y1) with angle theta.
+ !
+ !Parameters: input
+ ! X0 abscissa coordinate of the rotation center
+ ! Y0 ordinate coordinate of the rotation center
+ ! THETA rotation angle
+ ! X3 abscissa coordinate of the point to mirror
+ ! Y3 ordinate coordinate of the point to mirror
+ !
+ !Parameters: output
+ ! X4 abscissa coordinate of the symmetric point
+ ! Y4 ordinate coordinate of the symmetric point
+ !
+ !---------------------------------------------------------------------
+ !
+ IMPLICIT NONE
+ REAL(PDB),INTENT(IN) :: X0,Y0,THETA,X3,Y3
+ REAL(PDB),INTENT(OUT) :: X4,Y4
+
+ REAL(PDB) :: A,B
+ IF(THETA==0.0_PDB) THEN
+ X4=X3; Y4=Y3
+ ELSE
+ A=X3-X0; B=Y3-Y0
+ X4=X0+A*COS(THETA)-B*SIN(THETA); Y4=Y0+A*SIN(THETA)+B*COS(THETA)
+ ENDIF
+ END SUBROUTINE SALROT
+ !
+ SUBROUTINE SALFOLD_0(GG,IPASS,IB,NBBCDA,ALIGN,LFOLD,IFOLD)
+ !
+ !---------------------------------------------------------------------
+ !
+ !Purpose:
+ ! unfold the domain with reflection relative to axis AXIS_XY
+ !
+ !Parameters: input
+ ! IB actual unfolding axis
+ ! NBBCDA number of perimeters before unfolding
+ ! ALIGN unfolding axes
+ ! LFOLD identification flag to all unfolding axes
+ !
+ !Parameters: input/output
+ ! GG geometry descriptor
+ !
+ !Parameters: output
+ ! IFOLD folded element indices corresponding to unfolded ones
+ !
+ !---------------------------------------------------------------------
+ !
+ USE SAL_GEOMETRY_TYPES, ONLY : NIPAR,NRPAR,LENGTHX,LENGTHY
+ USE SAL_NUMERIC_MOD, ONLY : FINDLC,DET_ROSETTA
+ IMPLICIT NONE
+ INTEGER, INTENT(IN) :: IPASS,IB,NBBCDA
+ LOGICAL, DIMENSION(NBBCDA), INTENT(IN) :: LFOLD
+ REAL(PDB), DIMENSION(3,3,NBBCDA), INTENT(INOUT) :: ALIGN
+ TYPE(T_G_BASIC), INTENT(INOUT) :: GG
+ INTEGER, DIMENSION(:), INTENT(OUT) :: IFOLD
+ !
+ ! AXIS_XY values of AXIS_X1, AXIS_Y1, AXIS_X2 and AXIS_Y2 for the
+ ! reflecting axis
+ INTEGER :: ELEM,TYPE,OK,TMP_NB_ELEM,TMP_NBBCDA,I,J,IBC,INDBC,IAUX
+ INTEGER, DIMENSION(3) :: IPAR_TMP
+ REAL(PDB), DIMENSION(4) :: AXIS_XY
+ REAL(PDB), DIMENSION(6) :: RPAR_TMP
+ REAL(PDB),PARAMETER :: EPS=1.0E-5_PDB
+ REAL(PDB) :: X1,X2,X4,Y1,Y2,Y4,DX4,DY4,RAD,THETA1,THETA2,X1B,Y1B,X4B, &
+ Y4B,XMIN,YMIN,XMAX,YMAX,PHI1,PHI2,DELPHI,DET1,DET2
+ !
+ ! allocatable arrays
+ INTEGER, ALLOCATABLE, DIMENSION(:) :: PERIM_ELEM
+ LOGICAL, ALLOCATABLE, DIMENSION(:) :: ISPERIM
+ INTEGER, POINTER, DIMENSION(:,:) :: TMP_IPAR
+ INTEGER, ALLOCATABLE, DIMENSION(:,:) :: I2
+ REAL(PDB), ALLOCATABLE, DIMENSION(:) :: ANGLE,ALBEDO
+ REAL(PDB), POINTER, DIMENSION(:,:) :: TMP_RPAR
+ REAL(PDB), ALLOCATABLE, DIMENSION(:,:,:) :: ALIGN2
+ TYPE(T_SALBCDATA), POINTER, DIMENSION(:) :: TMP_BCDATAREAD
+ !
+ ! compute size of the unfold geometry
+ XMIN=1.E10_PDB; YMIN=1.E10_PDB; XMAX=-1.E10_PDB; YMAX=-1.E10_PDB;
+ DO ELEM=1,GG%NB_ELEM
+ TYPE=GG%IPAR(1,ELEM)
+ IF(TYPE==1) THEN
+ X1=GG%RPAR(1,ELEM); Y1=GG%RPAR(2,ELEM);
+ XMIN=MIN(XMIN,X1); YMIN=MIN(YMIN,Y1); XMAX=MAX(XMAX,X1); YMAX=MAX(YMAX,Y1);
+ X2=X1+GG%RPAR(3,ELEM); Y2=Y1+GG%RPAR(4,ELEM);
+ XMIN=MIN(XMIN,X2); YMIN=MIN(YMIN,Y2); XMAX=MAX(XMAX,X2); YMAX=MAX(YMAX,Y2);
+ ENDIF
+ ENDDO
+ LENGTHX=XMAX-XMIN; LENGTHY=YMAX-YMIN;
+ !
+ ! allocate new surfacic element containers
+ XMIN=1.E10_PDB; YMIN=1.E10_PDB; XMAX=-1.E10_PDB; YMAX=-1.E10_PDB;
+ ALLOCATE(TMP_IPAR(NIPAR,3*GG%NB_ELEM), TMP_RPAR(NRPAR,3*GG%NB_ELEM), &
+ I2(2,GG%NB_ELEM), STAT=OK)
+ IF(OK/=0) CALL XABORT('SALFOLD_0: not enough memory')
+ TMP_IPAR(:,:)=0; TMP_RPAR(:,:)=0._PDB;
+ !
+ ! loop over old elements
+ TMP_NB_ELEM=0
+ THETA1=0._PDB; THETA2=0._PDB;
+ I2(:2,:GG%NB_ELEM)=0
+ AXIS_XY(1)=ALIGN(1,1,IB) ; AXIS_XY(2)=ALIGN(1,2,IB)
+ AXIS_XY(3)=ALIGN(2,1,IB) ; AXIS_XY(4)=ALIGN(2,2,IB)
+ OUT1: DO ELEM=1,GG%NB_ELEM
+ TYPE=GG%IPAR(1,ELEM)
+ X1=GG%RPAR(1,ELEM); Y1=GG%RPAR(2,ELEM); RAD=GG%RPAR(3,ELEM)
+ IF(TYPE==1) THEN
+ XMIN=MIN(XMIN,X1); YMIN=MIN(YMIN,Y1); XMAX=MAX(XMAX,X1); YMAX=MAX(YMAX,Y1);
+ X2=X1+GG%RPAR(3,ELEM); Y2=Y1+GG%RPAR(4,ELEM)
+ ! Cycle if this element is sitting on an unfolding axe
+ DO IBC=1,NBBCDA
+ IF(.NOT.LFOLD(IBC)) CYCLE
+ IF((IPASS.EQ.1).AND.(IBC.NE.IB)) CYCLE
+ ALIGN(3,1,IBC)=X1; ALIGN(3,2,IBC)=Y1
+ DET1 = DET_ROSETTA(ALIGN(1,1,IBC),3)
+ ALIGN(3,1,IBC)=X2; ALIGN(3,2,IBC)=Y2;
+ DET2 = DET_ROSETTA(ALIGN(1,1,IBC),3)
+ IF((ABS(DET1).LE.1.0E-4).AND.(ABS(DET2).LE.1.0E-4)) CYCLE OUT1
+ ENDDO
+ !
+ CALL SALSYM(AXIS_XY(1),AXIS_XY(2),AXIS_XY(3),AXIS_XY(4),X1,Y1,X4,Y4)
+ CALL SALSYM(AXIS_XY(1),AXIS_XY(2),AXIS_XY(3),AXIS_XY(4),X2,Y2,DX4,DY4)
+ ELSE IF(TYPE==2) THEN
+ CALL SALSYM(AXIS_XY(1),AXIS_XY(2),AXIS_XY(3),AXIS_XY(4),X1,Y1,X4,Y4)
+ THETA1=0._PDB; THETA2=0._PDB;
+ ELSE IF(TYPE==3) THEN
+ CALL SALSYM(AXIS_XY(1),AXIS_XY(2),AXIS_XY(3),AXIS_XY(4),X1,Y1,X4,Y4)
+ X1B=X1+RAD*COS(GG%RPAR(4,ELEM)); Y1B=Y1+RAD*SIN(GG%RPAR(4,ELEM));
+ CALL SALSYM(AXIS_XY(1),AXIS_XY(2),AXIS_XY(3),AXIS_XY(4),X1B,Y1B,X4B,Y4B)
+ IF((ABS(X4B-X4)<EPS*ABS(RAD)).AND.(Y4B-Y4 > 0._PDB)) THEN
+ THETA1=PI/2._PDB
+ ELSE IF((ABS(X4B-X4)<EPS*ABS(RAD)).AND.(Y4B-Y4 < 0._PDB)) THEN
+ THETA1=3._PDB*PI/2._PDB
+ ELSE IF(X4B-X4 > 0._PDB) THEN
+ THETA1=ATAN((Y4B-Y4)/(X4B-X4))
+ ELSE
+ THETA1=ATAN((Y4B-Y4)/(X4B-X4))+PI
+ ENDIF
+ X1B=X1+RAD*COS(GG%RPAR(5,ELEM)); Y1B=Y1+RAD*SIN(GG%RPAR(5,ELEM));
+ CALL SALSYM(AXIS_XY(1),AXIS_XY(2),AXIS_XY(3),AXIS_XY(4),X1B,Y1B,X4B,Y4B)
+ IF((ABS(X4B-X4)<EPS*ABS(RAD)).AND.(Y4B-Y4 > 0._PDB)) THEN
+ THETA2=PI/2._PDB
+ ELSE IF((ABS(X4B-X4)<EPS*ABS(RAD)).AND.(Y4B-Y4 < 0._PDB)) THEN
+ THETA2=3._PDB*PI/2._PDB
+ ELSE IF(X4B-X4 > 0._PDB) THEN
+ THETA2=ATAN((Y4B-Y4)/(X4B-X4))
+ ELSE
+ THETA2=ATAN((Y4B-Y4)/(X4B-X4))+PI
+ ENDIF
+ ELSE
+ WRITE(*,*) " elem=",ELEM," type=",TYPE
+ CALL XABORT('SALFOLD_0: invalid type of surfacic element')
+ ENDIF
+ IPAR_TMP(:3)=0
+ RPAR_TMP(:6)=0_PDB
+ RPAR_TMP(1)=X4; RPAR_TMP(2)=Y4;
+ IPAR_TMP(1)=TYPE;
+ IF(TYPE==1) THEN
+ RPAR_TMP(3)=DX4-X4; RPAR_TMP(4)=DY4-Y4;
+ RPAR_TMP(5)=SQRT(RPAR_TMP(3)**2+RPAR_TMP(4)**2)
+ XMIN=MIN(XMIN,X4); YMIN=MIN(YMIN,Y4); XMAX=MAX(XMAX,X4); YMAX=MAX(YMAX,Y4);
+ XMIN=MIN(XMIN,DX4); YMIN=MIN(YMIN,DY4); XMAX=MAX(XMAX,DX4); YMAX=MAX(YMAX,DY4);
+ IPAR_TMP(2)=GG%IPAR(3,ELEM); IPAR_TMP(3)=GG%IPAR(2,ELEM);
+ ELSE IF((TYPE==2).OR.(TYPE==3)) THEN
+ RPAR_TMP(3)=GG%RPAR(3,ELEM) ! RADIUS
+ IF(THETA2>THETA1) THETA1=THETA1+2._PDB*PI
+ PHI1=THETA2; DELPHI=THETA1-THETA2;
+ IF(DELPHI>0._PDB)THEN
+ PHI2=PHI1+DELPHI
+ ELSE
+ PHI2=PHI1
+ PHI1=PHI1+DELPHI
+ ENDIF
+ IF(TYPE==3)THEN
+ ! arc of circle: put phi1 within 0 and 2*pi
+ IF(PHI1>2._PDB*PI)THEN
+ IAUX=INT(PHI1/(2._PDB*PI))
+ DELPHI=(2._PDB*PI)*IAUX
+ PHI1=PHI1-DELPHI ; PHI2=PHI2-DELPHI
+ ELSEIF(PHI1<0._PDB)THEN
+ IAUX=INT((-PHI1+1.D-7)/(2._PDB*PI))+1
+ DELPHI=(2._PDB*PI)*IAUX
+ PHI1=PHI1+DELPHI ; PHI2=PHI2+DELPHI
+ ENDIF
+ ENDIF
+ RPAR_TMP(4)=PHI1; RPAR_TMP(5)=PHI2; ! ANGLES
+ IPAR_TMP(2)=GG%IPAR(2,ELEM); IPAR_TMP(3)=GG%IPAR(3,ELEM)
+ ENDIF
+ RPAR_TMP(6)=0._PDB
+ IF(IPASS==2) THEN
+ ! remove identical elements at pass 2
+ DO I=1,TMP_NB_ELEM
+ IF((ABS(TMP_RPAR(1,I)-RPAR_TMP(1))<=10.0*EPS).AND. &
+ (ABS(TMP_RPAR(2,I)-RPAR_TMP(2))<=10.0*EPS).AND. &
+ (ABS(TMP_RPAR(3,I)-RPAR_TMP(3))<=10.0*EPS).AND. &
+ (ABS(TMP_RPAR(4,I)-RPAR_TMP(4))<=10.0*EPS).AND. &
+ (ABS(TMP_RPAR(5,I)-RPAR_TMP(5))<=10.0*EPS)) THEN
+ CYCLE OUT1
+ ENDIF
+ ENDDO
+ ENDIF
+ TMP_NB_ELEM=TMP_NB_ELEM+1
+ IF(TMP_NB_ELEM>3*GG%NB_ELEM) CALL XABORT('SALFOLD_0: tmp_nb_elem overflow(1)')
+ TMP_IPAR(:3,TMP_NB_ELEM)=IPAR_TMP(:3)
+ TMP_RPAR(:6,TMP_NB_ELEM)=RPAR_TMP(:6)
+ I2(2,ELEM)=TMP_NB_ELEM
+ IF(IPASS==2) THEN
+ ! remove identical elements at pass 2
+ DO I=1,TMP_NB_ELEM
+ IF((ABS(TMP_RPAR(1,I)-GG%RPAR(1,ELEM))<=10.0*EPS).AND. &
+ (ABS(TMP_RPAR(2,I)-GG%RPAR(2,ELEM))<=10.0*EPS).AND. &
+ (ABS(TMP_RPAR(3,I)-GG%RPAR(3,ELEM))<=10.0*EPS).AND. &
+ (ABS(TMP_RPAR(4,I)-GG%RPAR(4,ELEM))<=10.0*EPS).AND. &
+ (ABS(TMP_RPAR(5,I)-GG%RPAR(5,ELEM))<=10.0*EPS)) THEN
+ CYCLE OUT1
+ ENDIF
+ ENDDO
+ ENDIF
+ TMP_NB_ELEM=TMP_NB_ELEM+1
+ IF(TMP_NB_ELEM>3*GG%NB_ELEM) CALL XABORT('SALFOLD_0: tmp_nb_elem overflow(2)')
+ TMP_IPAR(:,TMP_NB_ELEM)=GG%IPAR(:,ELEM)
+ TMP_RPAR(:,TMP_NB_ELEM)=GG%RPAR(:,ELEM)
+ I2(1,ELEM)=TMP_NB_ELEM
+ ENDDO OUT1
+ DEALLOCATE(GG%IPAR,GG%RPAR)
+ DO ELEM=1,GG%NB_ELEM
+ IF(I2(1,ELEM).GT.2*GG%NB_ELEM) CALL XABORT('SALFOLD_0: IFOLD overflow')
+ IF(I2(1,ELEM).NE.0) IFOLD(I2(1,ELEM))=ELEM
+ IF(I2(2,ELEM).NE.0) IFOLD(I2(2,ELEM))=ELEM
+ ENDDO
+ GG%IPAR=>TMP_IPAR; GG%RPAR=>TMP_RPAR;
+ GG%NB_ELEM=TMP_NB_ELEM
+ !
+ ! loop over boundary conditions
+ ALLOCATE(ISPERIM(GG%NB_ELEM),ALIGN2(3,3,GG%NB_ELEM),ANGLE(GG%NB_ELEM), &
+ & ALBEDO(GG%NB_ELEM),PERIM_ELEM(GG%NB_ELEM))
+ ALIGN2(:3,3,:GG%NB_ELEM)=1.0_PDB
+ PERIM_ELEM(:GG%NB_ELEM)=0
+ ISPERIM(:GG%NB_ELEM)=.FALSE.
+ TMP_NBBCDA=0
+ DO IBC=1,GG%NBBCDA
+ DO I=1,GG%BCDATAREAD(IBC)%NBER
+ INDBC=GG%BCDATAREAD(IBC)%ELEMNB(I)
+ IF(INDBC==0) CYCLE
+ IF(I2(1,INDBC)/=0) ISPERIM(I2(1,INDBC))=.TRUE.
+ IF(I2(2,INDBC)/=0) ISPERIM(I2(2,INDBC))=.TRUE.
+ ENDDO
+ ENDDO
+ ITER0: DO ELEM=1,GG%NB_ELEM
+ IF(.NOT.ISPERIM(ELEM)) CYCLE
+ X1=GG%RPAR(1,ELEM); Y1=GG%RPAR(2,ELEM);
+ X2=X1+GG%RPAR(3,ELEM); Y2=Y1+GG%RPAR(4,ELEM);
+ DO J=1,TMP_NBBCDA
+ ALIGN2(3,1,J)=X1; ALIGN2(3,2,J)=Y1;
+ DET1 = DET_ROSETTA(ALIGN2(1,1,J),3)
+ ALIGN2(3,1,J)=X2; ALIGN2(3,2,J)=Y2;
+ DET2 = DET_ROSETTA(ALIGN2(1,1,J),3)
+ IF((ABS(DET1).LE.1.0E-4).AND.(ABS(DET2).LE.1.0E-4)) THEN
+ PERIM_ELEM(ELEM) = J
+ CYCLE ITER0
+ ENDIF
+ ENDDO
+ TMP_NBBCDA=TMP_NBBCDA+1
+ PERIM_ELEM(ELEM) = TMP_NBBCDA
+ ANGLE(TMP_NBBCDA)=ATAN((Y2-Y1)/(X2-X1))
+ IF(ABS(ANGLE(TMP_NBBCDA)).LE.1.0E-5) ANGLE(TMP_NBBCDA)=0.0
+ ALIGN2(1,1,TMP_NBBCDA)=X1; ALIGN2(1,2,TMP_NBBCDA)=Y1
+ ALIGN2(2,1,TMP_NBBCDA)=X2; ALIGN2(2,2,TMP_NBBCDA)=Y2
+ ! Recover albedo from folded geometry
+ ALBEDO(TMP_NBBCDA)=1.0
+ DO IBC=1,GG%NBBCDA
+ J = FINDLC(GG%BCDATAREAD(IBC)%ELEMNB,ELEM)
+ IF(J.EQ.1) THEN
+ ALBEDO(TMP_NBBCDA)=GG%BCDATAREAD(IBC)%BCDATA(6)
+ EXIT
+ ENDIF
+ ENDDO
+ ENDDO ITER0
+ ALLOCATE(TMP_BCDATAREAD(TMP_NBBCDA))
+ DO IBC=1,TMP_NBBCDA
+ TMP_BCDATAREAD(IBC)%NBER = COUNT(PERIM_ELEM(:GG%NB_ELEM) == IBC)
+ ALLOCATE(TMP_BCDATAREAD(IBC)%ELEMNB(TMP_BCDATAREAD(IBC)%NBER))
+ TMP_BCDATAREAD(IBC)%SALTYPE = 0
+ J=0
+ DO I=1,GG%NB_ELEM
+ IF(PERIM_ELEM(I) == IBC) THEN
+ J=J+1
+ TMP_BCDATAREAD(IBC)%ELEMNB(J) = I
+ ENDIF
+ ENDDO
+ TMP_BCDATAREAD(IBC)%BCDATA(1) = ALIGN2(1,1,IBC)
+ TMP_BCDATAREAD(IBC)%BCDATA(2) = ALIGN2(1,2,IBC)
+ TMP_BCDATAREAD(IBC)%BCDATA(3) = COS(ANGLE(IBC))
+ TMP_BCDATAREAD(IBC)%BCDATA(4) = SIN(ANGLE(IBC))
+ TMP_BCDATAREAD(IBC)%BCDATA(5) = ANGLE(IBC)
+ TMP_BCDATAREAD(IBC)%BCDATA(6) = ALBEDO(IBC)
+ ENDDO
+ DEALLOCATE(I2,PERIM_ELEM,ALBEDO,ANGLE,ALIGN2,ISPERIM)
+ DEALLOCATE(GG%BCDATAREAD)
+ GG%BCDATAREAD=>TMP_BCDATAREAD
+ GG%NBBCDA=TMP_NBBCDA
+ GG%ALBEDO=1.D0
+ END SUBROUTINE SALFOLD_0
+ !
+ SUBROUTINE SALFOLD_1(HSYM,GG)
+ !
+ !---------------------------------------------------------------------
+ !
+ !Purpose:
+ ! unfold the domain with reflection
+ !
+ !Parameters: input
+ ! HSYM: type of symmetry: 'DIAG': diagonal symmetry; 'SYMX': symmetry
+ ! relative to X axis; 'SYMY': symmetry relative to Y axis;
+ ! 'SA60': SA60 symmetry; 'S30': S30 symmetry
+ !
+ !Parameters: input/output
+ ! GG geometry descriptor
+ !
+ !---------------------------------------------------------------------
+ !
+ USE SAL_GEOMETRY_TYPES, ONLY : NIPAR,NRPAR,LENGTHX,LENGTHY
+ USE SAL_NUMERIC_MOD, ONLY : FINDLC,DET_ROSETTA
+ IMPLICIT NONE
+ CHARACTER(LEN=4),INTENT(IN) :: HSYM
+ TYPE(T_G_BASIC), INTENT(INOUT) :: GG
+ !
+ INTEGER :: ELEM,TYPE,OK,TMP_NB_ELEM,TMP_NBBCDA,I,J,IBC,INDBC,IAUX,ISYM,NSYM
+ REAL(PDB),PARAMETER :: EPS=1.0E-5_PDB
+ REAL(PDB) :: AXIS_X1(2),AXIS_X2(2),AXIS_Y1(2),AXIS_Y2(2)
+ REAL(PDB) :: X1,X2,X4,Y1,Y2,Y4,DX4,DY4,RAD,THETA1,THETA2,X1B,Y1B,X4B, &
+ Y4B,XMIN,YMIN,XMAX,YMAX,PHI1,PHI2,DELPHI,DET1,DET2
+ LOGICAL :: NOCOPY(2)
+ !
+ ! allocatable arrays
+ INTEGER, ALLOCATABLE, DIMENSION(:) :: PERIM_ELEM
+ LOGICAL, ALLOCATABLE, DIMENSION(:) :: ISPERIM
+ INTEGER, POINTER, DIMENSION(:,:) :: TMP_IPAR
+ INTEGER, ALLOCATABLE, DIMENSION(:,:) :: I2
+ REAL(PDB), ALLOCATABLE, DIMENSION(:) :: ANGLE,ALBEDO
+ REAL(PDB), POINTER, DIMENSION(:,:) :: TMP_RPAR
+ REAL(PDB), ALLOCATABLE, DIMENSION(:,:,:) :: ALIGN
+ TYPE(T_SALBCDATA), POINTER, DIMENSION(:) :: TMP_BCDATAREAD
+ !
+ ! compute size of the unfold geometry
+ XMIN=1.E10_PDB; YMIN=1.E10_PDB; XMAX=-1.E10_PDB; YMAX=-1.E10_PDB;
+ DO ELEM=1,GG%NB_ELEM
+ TYPE=GG%IPAR(1,ELEM)
+ IF(TYPE==1) THEN
+ X1=GG%RPAR(1,ELEM); Y1=GG%RPAR(2,ELEM);
+ XMIN=MIN(XMIN,X1); YMIN=MIN(YMIN,Y1); XMAX=MAX(XMAX,X1); YMAX=MAX(YMAX,Y1);
+ X2=X1+GG%RPAR(3,ELEM); Y2=Y1+GG%RPAR(4,ELEM);
+ XMIN=MIN(XMIN,X2); YMIN=MIN(YMIN,Y2); XMAX=MAX(XMAX,X2); YMAX=MAX(YMAX,Y2);
+ ENDIF
+ ENDDO
+ LENGTHX=XMAX-XMIN; LENGTHY=YMAX-YMIN;
+ !
+ NSYM=1
+ IF(HSYM=='SYMX') THEN ! define symmetry axis
+ AXIS_X1(1)=0._PDB; AXIS_X2(1)=100._PDB; AXIS_Y1(1)=0._PDB; AXIS_Y2(1)=0._PDB;
+ ELSE IF(HSYM=='SYMY') THEN
+ AXIS_X1(1)=0._PDB; AXIS_X2(1)=0._PDB; AXIS_Y1(1)=0._PDB; AXIS_Y2(1)=100._PDB;
+ ELSE IF(HSYM=='DIAG') THEN
+ AXIS_X1(1)=0._PDB; AXIS_X2(1)=100._PDB; AXIS_Y1(1)=0._PDB; AXIS_Y2(1)=100._PDB;
+ ELSE IF(HSYM=='SA60') THEN
+ ! the hexagon side is on south
+ NSYM=2
+ AXIS_X1(1)=XMIN; AXIS_Y1(1)=YMIN; AXIS_X2(1)=XMIN+0.5_PDB*LENGTHX
+ AXIS_Y2(1)=YMIN+0.5_PDB*SQRT(3._PDB)*LENGTHX
+ AXIS_X1(2)=XMIN+LENGTHX; AXIS_Y1(2)=YMIN; AXIS_X2(2)=XMIN+0.5_PDB*LENGTHX
+ AXIS_Y2(2)=YMIN+0.5_PDB*SQRT(3._PDB)*LENGTHX
+ ELSE IF(HSYM=='SB60') THEN
+ ! the hexagon side is on north-east
+ NSYM=2
+ AXIS_X1(1)=XMIN; AXIS_Y1(1)=YMIN; AXIS_X2(1)=XMIN+0.5_PDB*LENGTHX
+ AXIS_Y2(1)=YMIN+0.5_PDB*SQRT(3._PDB)*LENGTHX
+ AXIS_X1(2)=XMIN; AXIS_Y1(2)=YMIN; AXIS_X2(2)=XMIN
+ AXIS_Y2(2)=YMIN+0.5_PDB*SQRT(3._PDB)*LENGTHX
+ ELSE IF(HSYM=='S30') THEN
+ AXIS_X1(1)=XMIN; AXIS_Y1(1)=YMIN; AXIS_X2(1)=XMIN+0.75_PDB*LENGTHX
+ AXIS_Y2(1)=YMIN+0.25_PDB*SQRT(3._PDB)*LENGTHX
+ ELSE IF(HSYM=='SYMH') THEN
+ AXIS_X1(1)=XMIN ; AXIS_Y1(1)=YMIN+0.25_PDB*SQRT(3._PDB)*LENGTHX
+ AXIS_X2(1)=XMIN+LENGTHX ; AXIS_Y2(1)=AXIS_Y1(1)
+ ELSE
+ CALL XABORT('SALFOLD_1: invalid type of symmetry axis')
+ ENDIF
+ XMIN=1.E10_PDB; YMIN=1.E10_PDB; XMAX=-1.E10_PDB; YMAX=-1.E10_PDB;
+ !
+ ! allocate new surfacic element containers
+ ALLOCATE(TMP_IPAR(NIPAR,3*GG%NB_ELEM), TMP_RPAR(NRPAR,3*GG%NB_ELEM), &
+ I2(3,GG%NB_ELEM), STAT=OK)
+ IF(OK/=0) CALL XABORT('SALFOLD_1: not enough memory')
+ TMP_IPAR(:,:)=0; TMP_RPAR(:,:)=0._PDB;
+ !
+ ! loop over old elements
+ TMP_NB_ELEM=0
+ THETA1=0._PDB; THETA2=0._PDB;
+ DO ELEM=1,GG%NB_ELEM
+ I2(:,ELEM)=0
+ TYPE=GG%IPAR(1,ELEM)
+ NOCOPY(:2)=.FALSE.
+ DO ISYM=1,NSYM
+ X1=GG%RPAR(1,ELEM); Y1=GG%RPAR(2,ELEM); RAD=GG%RPAR(3,ELEM)
+ IF(TYPE==1) THEN
+ XMIN=MIN(XMIN,X1); YMIN=MIN(YMIN,Y1); XMAX=MAX(XMAX,X1); YMAX=MAX(YMAX,Y1);
+ X2=X1+GG%RPAR(3,ELEM); Y2=Y1+GG%RPAR(4,ELEM);
+ CALL SALSYM(AXIS_X1(ISYM),AXIS_Y1(ISYM),AXIS_X2(ISYM),AXIS_Y2(ISYM),X1,Y1,X4,Y4)
+ CALL SALSYM(AXIS_X1(ISYM),AXIS_Y1(ISYM),AXIS_X2(ISYM),AXIS_Y2(ISYM),X2,Y2,DX4,DY4)
+ NOCOPY(ISYM)=ABS(X1-X4)<10.0*EPS .AND. ABS(Y1-Y4)<10.0*EPS .AND. &
+ ABS(X2-DX4)<10.0*EPS .AND. ABS(Y2-DY4)<10.0*EPS
+ IF((HSYM=='SB60').AND.(ISYM==2)) THEN
+ NOCOPY(2)=(ABS(2._PDB*ABS(Y1-YMIN)-ABS(X4-X1)*SQRT(3._PDB))<10.0*EPS .AND. &
+ ABS(Y1-Y4)<10.0*EPS .AND. ABS(2._PDB*ABS(Y2-YMIN)-ABS(DX4-X2)*SQRT(3._PDB))<10.0*EPS &
+ .AND. ABS(Y2-DY4)<10.0*EPS)
+ ENDIF
+ IF(NOCOPY(ISYM)) CYCLE
+ ELSE IF(TYPE==2) THEN
+ CALL SALSYM(AXIS_X1(ISYM),AXIS_Y1(ISYM),AXIS_X2(ISYM),AXIS_Y2(ISYM),X1,Y1,X4,Y4)
+ THETA1=0._PDB; THETA2=0._PDB;
+ ELSE IF(TYPE==3) THEN
+ CALL SALSYM(AXIS_X1(ISYM),AXIS_Y1(ISYM),AXIS_X2(ISYM),AXIS_Y2(ISYM),X1,Y1,X4,Y4)
+ X1B=X1+RAD*COS(GG%RPAR(4,ELEM)); Y1B=Y1+RAD*SIN(GG%RPAR(4,ELEM));
+ CALL SALSYM(AXIS_X1(ISYM),AXIS_Y1(ISYM),AXIS_X2(ISYM),AXIS_Y2(ISYM),X1B,Y1B,X4B,Y4B)
+ IF((ABS(X4B-X4)<EPS*ABS(RAD)).AND.(Y4B-Y4 > 0._PDB)) THEN
+ THETA1=PI/2._PDB
+ ELSE IF((ABS(X4B-X4)<EPS*ABS(RAD)).AND.(Y4B-Y4 < 0._PDB)) THEN
+ THETA1=3._PDB*PI/2._PDB
+ ELSE IF(X4B-X4 > 0._PDB) THEN
+ THETA1=ATAN((Y4B-Y4)/(X4B-X4))
+ ELSE
+ THETA1=ATAN((Y4B-Y4)/(X4B-X4))+PI
+ ENDIF
+ X1B=X1+RAD*COS(GG%RPAR(5,ELEM)); Y1B=Y1+RAD*SIN(GG%RPAR(5,ELEM));
+ CALL SALSYM(AXIS_X1(ISYM),AXIS_Y1(ISYM),AXIS_X2(ISYM),AXIS_Y2(ISYM),X1B,Y1B,X4B,Y4B)
+ IF((ABS(X4B-X4)<EPS*ABS(RAD)).AND.(Y4B-Y4 > 0._PDB)) THEN
+ THETA2=PI/2._PDB
+ ELSE IF((ABS(X4B-X4)<EPS*ABS(RAD)).AND.(Y4B-Y4 < 0._PDB)) THEN
+ THETA2=3._PDB*PI/2._PDB
+ ELSE IF(X4B-X4 > 0._PDB) THEN
+ THETA2=ATAN((Y4B-Y4)/(X4B-X4))
+ ELSE
+ THETA2=ATAN((Y4B-Y4)/(X4B-X4))+PI
+ ENDIF
+ ELSE
+ WRITE(*,*) " elem=",ELEM," type=",TYPE," isym=",ISYM
+ CALL XABORT('SALFOLD_1: invalid type of surfacic element')
+ ENDIF
+ IF((TYPE==1).AND.(HSYM=='SB60').AND.(ISYM==1).AND.(ABS(Y1)<10.0*EPS).AND.(ABS(Y2)<10.0*EPS)) CYCLE
+ TMP_NB_ELEM=TMP_NB_ELEM+1
+ IF(TMP_NB_ELEM>3*GG%NB_ELEM) CALL XABORT('SALFOLD_1: tmp_nb_elem overflow(1)')
+ I2(ISYM+1,ELEM)=TMP_NB_ELEM
+ TMP_RPAR(1,TMP_NB_ELEM)=X4; TMP_RPAR(2,TMP_NB_ELEM)=Y4;
+ TMP_IPAR(1,TMP_NB_ELEM)=TYPE;
+ IF(TYPE==1) THEN
+ TMP_RPAR(3,TMP_NB_ELEM)=DX4-X4; TMP_RPAR(4,TMP_NB_ELEM)=DY4-Y4;
+ TMP_RPAR(5,TMP_NB_ELEM)=SQRT(TMP_RPAR(3,TMP_NB_ELEM)**2+TMP_RPAR(4,TMP_NB_ELEM)**2)
+ XMIN=MIN(XMIN,X4); YMIN=MIN(YMIN,Y4); XMAX=MAX(XMAX,X4); YMAX=MAX(YMAX,Y4);
+ XMIN=MIN(XMIN,DX4); YMIN=MIN(YMIN,DY4); XMAX=MAX(XMAX,DX4); YMAX=MAX(YMAX,DY4);
+ TMP_IPAR(2,TMP_NB_ELEM)=GG%IPAR(3,ELEM); TMP_IPAR(3,TMP_NB_ELEM)=GG%IPAR(2,ELEM);
+ ELSE IF((TYPE==2).OR.(TYPE==3)) THEN
+ TMP_RPAR(3,TMP_NB_ELEM)=GG%RPAR(3,ELEM) ! RADIUS
+ IF(THETA2>THETA1) THETA1=THETA1+2._PDB*PI
+ PHI1=THETA2; DELPHI=THETA1-THETA2;
+ IF(DELPHI>0._PDB)THEN
+ PHI2=PHI1+DELPHI
+ ELSE
+ PHI2=PHI1
+ PHI1=PHI1+DELPHI
+ ENDIF
+ IF(TYPE==3)THEN
+ ! arc of circle: put phi1 within 0 and 2*pi
+ IF(PHI1>2._PDB*PI)THEN
+ IAUX=INT(PHI1/(2._PDB*PI))
+ DELPHI=(2._PDB*PI)*IAUX
+ PHI1=PHI1-DELPHI ; PHI2=PHI2-DELPHI
+ ELSEIF(PHI1<0._PDB)THEN
+ IAUX=INT((-PHI1+1.D-7)/(2._PDB*PI))+1
+ DELPHI=(2._PDB*PI)*IAUX
+ PHI1=PHI1+DELPHI ; PHI2=PHI2+DELPHI
+ ENDIF
+ ENDIF
+ TMP_RPAR(4,TMP_NB_ELEM)=PHI1; TMP_RPAR(5,TMP_NB_ELEM)=PHI2; ! ANGLES
+ TMP_IPAR(2,TMP_NB_ELEM)=GG%IPAR(2,ELEM); TMP_IPAR(3,TMP_NB_ELEM)=GG%IPAR(3,ELEM)
+ ENDIF
+ TMP_RPAR(6,TMP_NB_ELEM)=0._PDB
+ ENDDO
+ IF((.NOT.NOCOPY(1)).AND.(.NOT.NOCOPY(2))) THEN
+ TMP_NB_ELEM=TMP_NB_ELEM+1
+ IF(TMP_NB_ELEM>3*GG%NB_ELEM) CALL XABORT('SALFOLD_1: tmp_nb_elem overflow(2)')
+ TMP_IPAR(:,TMP_NB_ELEM)=GG%IPAR(:,ELEM)
+ TMP_RPAR(:,TMP_NB_ELEM)=GG%RPAR(:,ELEM)
+ I2(1,ELEM)=TMP_NB_ELEM
+ ENDIF
+ ENDDO
+ DEALLOCATE(GG%IPAR,GG%RPAR)
+ GG%IPAR=>TMP_IPAR; GG%RPAR=>TMP_RPAR;
+ GG%NB_ELEM=TMP_NB_ELEM
+ !
+ ! translate the domain
+ DO ELEM=1,GG%NB_ELEM
+ GG%RPAR(1,ELEM)=GG%RPAR(1,ELEM)-XMIN
+ GG%RPAR(2,ELEM)=GG%RPAR(2,ELEM)-YMIN
+ ENDDO
+ LENGTHX=XMAX-XMIN ; LENGTHY=YMAX-YMIN ;
+ !
+ ! loop over boundary conditions
+ TMP_NBBCDA=0
+ ALLOCATE(ISPERIM(GG%NB_ELEM),ALIGN(3,3,GG%NB_ELEM),ANGLE(GG%NB_ELEM), &
+ & ALBEDO(GG%NB_ELEM),PERIM_ELEM(GG%NB_ELEM))
+ ALIGN(:3,3,:GG%NB_ELEM)=1.0_PDB
+ PERIM_ELEM(:GG%NB_ELEM)=0
+ ISPERIM(:GG%NB_ELEM)=.FALSE.
+ DO IBC=1,GG%NBBCDA
+ DO I=1,GG%BCDATAREAD(IBC)%NBER
+ INDBC=GG%BCDATAREAD(IBC)%ELEMNB(I)
+ IF(INDBC==0) CYCLE
+ DO ISYM=1,NSYM+1
+ IF(I2(ISYM,INDBC)/=0) ISPERIM(I2(ISYM,INDBC))=.TRUE.
+ ENDDO
+ ENDDO
+ ENDDO
+ ITER0: DO ELEM=1,GG%NB_ELEM
+ IF(.NOT.ISPERIM(ELEM)) CYCLE
+ X1=GG%RPAR(1,ELEM); Y1=GG%RPAR(2,ELEM);
+ X2=X1+GG%RPAR(3,ELEM); Y2=Y1+GG%RPAR(4,ELEM);
+ DO J=1,TMP_NBBCDA
+ ALIGN(3,1,J)=X1; ALIGN(3,2,J)=Y1;
+ DET1 = DET_ROSETTA(ALIGN(1,1,J),3)
+ ALIGN(3,1,J)=X2; ALIGN(3,2,J)=Y2;
+ DET2 = DET_ROSETTA(ALIGN(1,1,J),3)
+ IF((ABS(DET1).LE.1.0E-4).AND.(ABS(DET2).LE.1.0E-4)) THEN
+ PERIM_ELEM(ELEM) = J
+ CYCLE ITER0
+ ENDIF
+ ENDDO
+ TMP_NBBCDA=TMP_NBBCDA+1
+ PERIM_ELEM(ELEM) = TMP_NBBCDA
+ ANGLE(TMP_NBBCDA)=ATAN((Y2-Y1)/(X2-X1))
+ IF(ABS(ANGLE(TMP_NBBCDA)).LE.1.0E-5) ANGLE(TMP_NBBCDA)=0.0
+ ALIGN(1,1,TMP_NBBCDA)=X1; ALIGN(1,2,TMP_NBBCDA)=Y1
+ ALIGN(2,1,TMP_NBBCDA)=X2; ALIGN(2,2,TMP_NBBCDA)=Y2
+ ! Recover albedo from folded geometry
+ ALBEDO(TMP_NBBCDA)=1.0
+ DO IBC=1,GG%NBBCDA
+ J = FINDLC(GG%BCDATAREAD(IBC)%ELEMNB,ELEM)
+ IF(J.EQ.1) THEN
+ ALBEDO(TMP_NBBCDA)=GG%BCDATAREAD(IBC)%BCDATA(6)
+ EXIT
+ ENDIF
+ ENDDO
+ ENDDO ITER0
+ ALLOCATE(TMP_BCDATAREAD(TMP_NBBCDA))
+ DO IBC=1,TMP_NBBCDA
+ TMP_BCDATAREAD(IBC)%NBER = COUNT(PERIM_ELEM(:GG%NB_ELEM) == IBC)
+ ALLOCATE(TMP_BCDATAREAD(IBC)%ELEMNB(TMP_BCDATAREAD(IBC)%NBER))
+ TMP_BCDATAREAD(IBC)%SALTYPE = 0
+ J=0
+ DO I=1,GG%NB_ELEM
+ IF(PERIM_ELEM(I) == IBC) THEN
+ J=J+1
+ TMP_BCDATAREAD(IBC)%ELEMNB(J) = I
+ ENDIF
+ ENDDO
+ TMP_BCDATAREAD(IBC)%BCDATA(1) = ALIGN(1,1,IBC)
+ TMP_BCDATAREAD(IBC)%BCDATA(2) = ALIGN(1,2,IBC)
+ TMP_BCDATAREAD(IBC)%BCDATA(3) = COS(ANGLE(IBC))
+ TMP_BCDATAREAD(IBC)%BCDATA(4) = SIN(ANGLE(IBC))
+ TMP_BCDATAREAD(IBC)%BCDATA(5) = ANGLE(IBC)
+ TMP_BCDATAREAD(IBC)%BCDATA(6) = ALBEDO(IBC)
+ ENDDO
+ DEALLOCATE(I2,PERIM_ELEM,ALBEDO,ANGLE,ALIGN,ISPERIM)
+ DEALLOCATE(GG%BCDATAREAD)
+ GG%BCDATAREAD=>TMP_BCDATAREAD
+ GG%NBBCDA=TMP_NBBCDA
+ GG%ALBEDO=1.D0
+ END SUBROUTINE SALFOLD_1
+ !
+ SUBROUTINE SALFOLD_2(HSYM,GG)
+ !
+ !---------------------------------------------------------------------
+ !
+ !Purpose:
+ ! unfold the domain with rotation
+ !
+ !Parameters: input
+ ! HSYM: type of symmetry: SR60': dual 60-degree rotation; R180: 180-degree
+ ! rotation; R120: dual 120-degree rotation
+ !
+ !Parameters: input/output
+ ! GG geometry descriptor
+ !
+ !---------------------------------------------------------------------
+ !
+ USE SAL_GEOMETRY_TYPES, ONLY : NIPAR,NRPAR,LENGTHX,LENGTHY
+ IMPLICIT NONE
+ CHARACTER(LEN=4),INTENT(IN) :: HSYM
+ TYPE(T_G_BASIC), INTENT(INOUT) :: GG
+ !
+ INTEGER :: ELEM,ELEM2,TYPE,OK,TMP_NB_ELEM,ISYM,NSYM,IAUX
+ REAL(PDB) :: THROT(3),X1,X2,X4,Y1,Y2,Y4,DX4,DY4,RAD,THETA1,THETA2,X1B,Y1B,X4B, &
+ Y4B,XMIN,YMIN,XMAX,YMAX,CENTER_X,CENTER_Y,DELPHI
+ REAL(PDB),PARAMETER :: EPS=1.0E-5_PDB
+ !
+ ! allocatable arrays
+ LOGICAL, ALLOCATABLE, DIMENSION(:) :: ELEM_DUP
+ INTEGER, POINTER, DIMENSION(:,:) :: TMP_IPAR
+ INTEGER, ALLOCATABLE, DIMENSION(:,:) :: I2
+ REAL(PDB), POINTER, DIMENSION(:,:) :: TMP_RPAR
+ !
+ ! compute size of the unfold geometry
+ XMIN=1.E10_PDB; YMIN=1.E10_PDB; XMAX=-1.E10_PDB; YMAX=-1.E10_PDB;
+ DO ELEM=1,GG%NB_ELEM
+ TYPE=GG%IPAR(1,ELEM)
+ IF(TYPE==1) THEN
+ X1=GG%RPAR(1,ELEM); Y1=GG%RPAR(2,ELEM);
+ XMIN=MIN(XMIN,X1); YMIN=MIN(YMIN,Y1); XMAX=MAX(XMAX,X1); YMAX=MAX(YMAX,Y1);
+ X2=X1+GG%RPAR(3,ELEM); Y2=Y1+GG%RPAR(4,ELEM);
+ XMIN=MIN(XMIN,X2); YMIN=MIN(YMIN,Y2); XMAX=MAX(XMAX,X2); YMAX=MAX(YMAX,Y2);
+ ENDIF
+ ENDDO
+ LENGTHX=XMAX-XMIN; LENGTHY=YMAX-YMIN;
+ !
+ NSYM=0
+ IF(HSYM=='SR60') THEN ! define rotation center
+ NSYM=3
+ CENTER_X=XMIN+0.5_PDB*LENGTHX; CENTER_Y=YMIN+0.5_PDB*SQRT(3._PDB)*LENGTHX
+ THROT(1)=0.0_PDB; THROT(2)=-PI/3.0_PDB; THROT(3)=PI/3.0_PDB
+ ELSE IF(HSYM=='R180') THEN
+ NSYM=2
+ CENTER_X=XMIN+0.5_PDB*LENGTHX; CENTER_Y=YMIN+0.25_PDB*SQRT(3._PDB)*LENGTHX
+ THROT(1)=0.0_PDB; THROT(2)=PI;
+ ELSE IF(HSYM=='R120') THEN
+ NSYM=3
+ CENTER_X=XMIN+0.5_PDB*LENGTHX/1.5_PDB; CENTER_Y=YMIN+0.5_PDB*SQRT(3._PDB)*LENGTHX/1.5_PDB
+ THROT(1)=0.0_PDB; THROT(2)=-2.0_PDB*PI/3.0_PDB; THROT(3)=2.0_PDB*PI/3.0_PDB
+ ELSE
+ CALL XABORT('SALFOLD_2: invalid type of symmetry axis')
+ ENDIF
+ XMIN=1.E10_PDB; YMIN=1.E10_PDB; XMAX=-1.E10_PDB; YMAX=-1.E10_PDB;
+ !
+ ! allocate new surfacic element containers
+ ALLOCATE(I2(NSYM,GG%NB_ELEM))
+ ALLOCATE(TMP_IPAR(NIPAR,3*GG%NB_ELEM), TMP_RPAR(NRPAR,3*GG%NB_ELEM), STAT=OK)
+ IF(OK/=0) CALL XABORT('SALFOLD_2: not enough memory')
+ I2(:NSYM,:GG%NB_ELEM)=0
+ TMP_IPAR(:,:)=0; TMP_RPAR(:,:)=0._PDB;
+ !
+ ! loop over old elements
+ TMP_NB_ELEM=0
+ THETA1=0._PDB; THETA2=0._PDB;
+ DO ELEM=1,GG%NB_ELEM
+ TYPE=GG%IPAR(1,ELEM)
+ DO ISYM=1,NSYM
+ X1=GG%RPAR(1,ELEM); Y1=GG%RPAR(2,ELEM); RAD=GG%RPAR(3,ELEM)
+ IF(TYPE==1) THEN
+ XMIN=MIN(XMIN,X1); YMIN=MIN(YMIN,Y1); XMAX=MAX(XMAX,X1); YMAX=MAX(YMAX,Y1);
+ X2=X1+GG%RPAR(3,ELEM); Y2=Y1+GG%RPAR(4,ELEM);
+ CALL SALROT(CENTER_X,CENTER_Y,THROT(ISYM),X1,Y1,X4,Y4)
+ CALL SALROT(CENTER_X,CENTER_Y,THROT(ISYM),X2,Y2,DX4,DY4)
+ ELSE IF(TYPE==2) THEN
+ CALL SALROT(CENTER_X,CENTER_Y,THROT(ISYM),X1,Y1,X4,Y4)
+ THETA1=0._PDB; THETA2=0._PDB;
+ ELSE IF(TYPE==3) THEN
+ DELPHI=GG%RPAR(5,ELEM)-GG%RPAR(4,ELEM)
+ X1B=X1+RAD*COS(GG%RPAR(4,ELEM)); Y1B=Y1+RAD*SIN(GG%RPAR(4,ELEM));
+ CALL SALROT(CENTER_X,CENTER_Y,THROT(ISYM),X1,Y1,X4,Y4)
+ CALL SALROT(CENTER_X,CENTER_Y,THROT(ISYM),X1B,Y1B,X4B,Y4B)
+ IF((ABS(X4B-X4)<EPS*ABS(RAD)).AND.(Y4B-Y4 > 0._PDB)) THEN
+ THETA1=PI/2._PDB
+ ELSE IF((ABS(X4B-X4)<EPS*ABS(RAD)).AND.(Y4B-Y4 < 0._PDB)) THEN
+ THETA1=3._PDB*PI/2._PDB
+ ELSE IF(X4B-X4 > 0._PDB) THEN
+ THETA1=ATAN((Y4B-Y4)/(X4B-X4))
+ ELSE
+ THETA1=ATAN((Y4B-Y4)/(X4B-X4))+PI
+ ENDIF
+ THETA2=THETA1+DELPHI
+ ! put THETA1 within 0 and 2*pi
+ IF(THETA1>2._PDB*PI)THEN
+ IAUX=INT(THETA1/(2._PDB*PI))
+ DELPHI=(2._PDB*PI)*IAUX
+ THETA1=THETA1-DELPHI ; THETA2=THETA2-DELPHI
+ ELSEIF(THETA1<0._PDB)THEN
+ IAUX=INT((-THETA1+1.D-7)/(2._PDB*PI))+1
+ DELPHI=(2._PDB*PI)*IAUX
+ THETA1=THETA1+DELPHI ; THETA2=THETA2+DELPHI
+ ENDIF
+ ELSE
+ WRITE(*,*) " elem=",ELEM," type=",TYPE," isym=",ISYM
+ CALL XABORT('SALFOLD_2: invalid type of surfacic element')
+ ENDIF
+ TMP_NB_ELEM=TMP_NB_ELEM+1
+ IF(TMP_NB_ELEM>3*GG%NB_ELEM) CALL XABORT('SALFOLD_2: TMP_NB_ELEM overflow')
+ I2(ISYM,ELEM)=TMP_NB_ELEM
+ TMP_RPAR(1,TMP_NB_ELEM)=X4; TMP_RPAR(2,TMP_NB_ELEM)=Y4;
+ TMP_IPAR(1,TMP_NB_ELEM)=TYPE;
+ IF(TYPE==1) THEN
+ TMP_RPAR(3,TMP_NB_ELEM)=DX4-X4; TMP_RPAR(4,TMP_NB_ELEM)=DY4-Y4;
+ TMP_RPAR(5,TMP_NB_ELEM)=SQRT(TMP_RPAR(3,TMP_NB_ELEM)**2+TMP_RPAR(4,TMP_NB_ELEM)**2)
+ XMIN=MIN(XMIN,X4); YMIN=MIN(YMIN,Y4); XMAX=MAX(XMAX,X4); YMAX=MAX(YMAX,Y4);
+ XMIN=MIN(XMIN,DX4); YMIN=MIN(YMIN,DY4); XMAX=MAX(XMAX,DX4); YMAX=MAX(YMAX,DY4);
+ TMP_IPAR(2,TMP_NB_ELEM)=GG%IPAR(2,ELEM); TMP_IPAR(3,TMP_NB_ELEM)=GG%IPAR(3,ELEM)
+ ELSE IF((TYPE==2).OR.(TYPE==3)) THEN
+ TMP_RPAR(3,TMP_NB_ELEM)=GG%RPAR(3,ELEM) ! RADIUS
+ TMP_RPAR(4,TMP_NB_ELEM)=THETA1; TMP_RPAR(5,TMP_NB_ELEM)=THETA2; ! ANGLES
+ TMP_IPAR(2,TMP_NB_ELEM)=GG%IPAR(2,ELEM); TMP_IPAR(3,TMP_NB_ELEM)=GG%IPAR(3,ELEM)
+ ENDIF
+ TMP_RPAR(6,TMP_NB_ELEM)=0._PDB
+ ENDDO
+ ENDDO
+ DEALLOCATE(GG%IPAR,GG%RPAR)
+ !
+ ! eliminate duplicate elements
+ ALLOCATE(ELEM_DUP(TMP_NB_ELEM))
+ ELEM_DUP(:TMP_NB_ELEM)=.FALSE.
+ DO ELEM=1,TMP_NB_ELEM
+ TYPE=TMP_IPAR(1,ELEM)
+ IF((TYPE==1).AND.((TMP_IPAR(2,ELEM)==0).OR.(TMP_IPAR(3,ELEM)==0))) THEN
+ X4=TMP_RPAR(1,ELEM); Y4=TMP_RPAR(2,ELEM)
+ DX4=X4+TMP_RPAR(3,ELEM); DY4=Y4+TMP_RPAR(4,ELEM)
+ DO ELEM2=ELEM+1,TMP_NB_ELEM
+ IF(TMP_IPAR(1,ELEM2)/=1) CYCLE
+ X1=TMP_RPAR(1,ELEM2); Y1=TMP_RPAR(2,ELEM2)
+ X2=X1+TMP_RPAR(3,ELEM2); Y2=Y1+TMP_RPAR(4,ELEM2)
+ IF(((ABS(X1-X4)<10.0*EPS .AND. ABS(Y1-Y4)<10.0*EPS .AND. &
+ ABS(X2-DX4)<10.0*EPS .AND. ABS(Y2-DY4)<10.0*EPS)).OR. &
+ ((ABS(X1-DX4)<10.0*EPS .AND. ABS(Y1-DY4)<10.0*EPS .AND. &
+ ABS(X2-X4)<10.0*EPS .AND. ABS(Y2-Y4)<10.0*EPS))) THEN
+ ELEM_DUP(ELEM2)=.TRUE.
+ IF(TMP_IPAR(2,ELEM)==0) TMP_IPAR(2,ELEM)=MAX(TMP_IPAR(2,ELEM2),TMP_IPAR(3,ELEM2))
+ IF(TMP_IPAR(3,ELEM)==0) TMP_IPAR(3,ELEM)=MAX(TMP_IPAR(2,ELEM2),TMP_IPAR(3,ELEM2))
+ IF(TMP_IPAR(2,ELEM)==TMP_IPAR(3,ELEM)) ELEM_DUP(ELEM)=.TRUE.
+ EXIT
+ ENDIF
+ ENDDO
+ ENDIF
+ ENDDO
+ !
+ ELEM=1
+ DO WHILE(ELEM<=TMP_NB_ELEM)
+ IF(ELEM_DUP(ELEM)) THEN
+ TMP_NB_ELEM=TMP_NB_ELEM-1
+ DO ELEM2=ELEM,TMP_NB_ELEM
+ TMP_IPAR(:,ELEM2)=TMP_IPAR(:,ELEM2+1); TMP_RPAR(:,ELEM2)=TMP_RPAR(:,ELEM2+1)
+ ELEM_DUP(ELEM2)=ELEM_DUP(ELEM2+1)
+ ENDDO
+ ELSE
+ ELEM=ELEM+1
+ ENDIF
+ ENDDO
+ GG%IPAR=>TMP_IPAR; GG%RPAR=>TMP_RPAR;
+ GG%NB_ELEM=TMP_NB_ELEM
+ !
+ ! translate the domain
+ DO ELEM=1,GG%NB_ELEM
+ GG%RPAR(1,ELEM)=GG%RPAR(1,ELEM)-XMIN
+ GG%RPAR(2,ELEM)=GG%RPAR(2,ELEM)-YMIN
+ ENDDO
+ LENGTHX=XMAX-XMIN ; LENGTHY=YMAX-YMIN ;
+ GG%NBBCDA=0; GG%ALBEDO=1.D0
+ !
+ DEALLOCATE(ELEM_DUP,I2)
+ END SUBROUTINE SALFOLD_2
+END MODULE SAL_GEOMETRY_MOD