summaryrefslogtreecommitdiff
path: root/Dragon/src/SAL_TRAJECTORY_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_TRAJECTORY_MOD.f90
Initial commit from Polytechnique Montreal
Diffstat (limited to 'Dragon/src/SAL_TRAJECTORY_MOD.f90')
-rw-r--r--Dragon/src/SAL_TRAJECTORY_MOD.f901141
1 files changed, 1141 insertions, 0 deletions
diff --git a/Dragon/src/SAL_TRAJECTORY_MOD.f90 b/Dragon/src/SAL_TRAJECTORY_MOD.f90
new file mode 100644
index 0000000..e108fcb
--- /dev/null
+++ b/Dragon/src/SAL_TRAJECTORY_MOD.f90
@@ -0,0 +1,1141 @@
+!
+!---------------------------------------------------------------------
+!
+!Purpose:
+! Support module to compute a single track.
+!
+!Copyright:
+! Copyright (C) 2001 Ecole Polytechnique de Montreal.
+!
+!Author(s):
+! X. Warin
+!
+!---------------------------------------------------------------------
+!
+MODULE SAL_TRAJECTORY_MOD
+
+ USE PRECISION_AND_KINDS, ONLY : PDB,TWOPI,SMALL,PI
+ USE SAL_TRACKING_TYPES, ONLY : NBER,LGOK,COSINE,AX,AY,EX,EY,ALPHA,F0,AT,BT, &
+ LGTYPE,R,D0,TORIG
+ USE SAL_NUMERIC_MOD, ONLY : SALACO
+
+CONTAINS
+
+ SUBROUTINE SALTRA(DANGLT,NPERIM_MAC2,PERIM_MAC2,ISURF2_ELEM,IPAR,RPAR,PPERIM, &
+ PERIM,IBC2_ELEM,IDATA_BC2,BCDATA,PPERIM_MAC2,DIST_AXIS)
+ !
+ !---------------------------------------------------------------------
+ !
+ !Purpose:
+ ! computes intersection of trajectory (T): R=A+D*E with a mesh composed
+ ! of nodes and elements
+ !
+ ! begin
+ ! |
+ ! first entrance (LGMORE=f), get entry point
+ ! |
+ ! get boundary condition at entry point and treat it
+ ! |
+ ! if there is a left domain,do left tracking,inverse the trajectory
+ ! |
+ ! if LGGEO1=t,test if there is a left re-entry point,keep it
+ ! |
+ ! do basic tracking
+ ! |
+ ! if LGGEO1=t,test if there is a right re-entry point,keep it
+ ! |
+ ! end
+ !
+ !Parameters: input
+ ! DANGLT angle cosines
+ ! NPERIM_MAC2 number of elements composing perimeter of domain
+ ! PERIM_MAC2 elements composing perimeter of domain
+ ! ISURF2_ELEM relative 2D surf number per elem
+ ! IPAR integer geometry descriptors
+ ! RPAR REAL(PDB) geometry descriptors
+ ! PPERIM array pointer to elements in the perimeter of nodes
+ ! PERIM array of elements in perimeter of nodes
+ !
+ !Parameters: input (optional data for cyclic tracking)
+ ! IBC2_ELEM relative 2D boundary condition indices per element
+ ! IDATA_BC2 position of data per 2D boundary condition
+ ! BCDATA table of boundary condition descriptor
+ ! PPERIM_MAC2 pointer to 'perim' and 'dist_axis':
+ ! PPERIM_MAC2(1): beginning of elements on axis 1
+ ! PPERIM_MAC2(2): beginning of elements on axis 2
+ ! PPERIM_MAC2(3): beginning of elements not on axis
+ ! DIST_AXIS distance of points on this axis to the center (0,0)
+ !
+ !---------------------------------------------------------------------
+ !
+ USE SAL_GEOMETRY_TYPES, ONLY : ISPEC
+ USE SAL_TRACKING_TYPES, ONLY : NNN,NMAX2,ITRAC2,ANGTAB,ELMTAB,CNT,CNT0,NB_TOT,DNEW,DINIT, &
+ NNEW,LNEW,IERR,LGMORE,DD0,NTRACK,EPS1,EX0,EY0,LGOK,IPART,DELX, &
+ N_AXIS
+ IMPLICIT NONE
+ REAL(PDB), INTENT(IN), DIMENSION(:,:) :: DANGLT
+ INTEGER, INTENT(IN) :: NPERIM_MAC2
+ INTEGER, INTENT(IN), DIMENSION(:) :: PERIM_MAC2,PPERIM,PERIM,ISURF2_ELEM
+ INTEGER, INTENT(IN), DIMENSION(:,:) :: IPAR
+ REAL(PDB), INTENT(IN), DIMENSION(:,:) :: RPAR
+ INTEGER, INTENT(IN), DIMENSION(:), OPTIONAL :: IBC2_ELEM,IDATA_BC2,PPERIM_MAC2
+ REAL(PDB), INTENT(IN), DIMENSION(:), OPTIONAL :: DIST_AXIS
+ REAL(PDB), INTENT(IN), DIMENSION(:,:), OPTIONAL :: BCDATA
+ !***
+ INTEGER :: IOUT,LEN,P1,P2,IPHI
+ LOGICAL :: LGLEFT
+ REAL(PDB) :: RADIA
+ !***
+ ! initiate nber of sub-trajectories
+ NB_TOT=0
+ IF(ISPEC == 0) THEN
+ !* compute entry point for a basic trajectory
+ CALL SAL240_3(PERIM_MAC2,NPERIM_MAC2,IPAR,RPAR)
+ ELSE
+ EX=EX0; EY=EY0
+ LGOK=.FALSE.
+ ! initiate all elements status to untreated
+ IPART(1,:)=-1
+ ! radia of the axis
+ IF(PPERIM_MAC2(N_AXIS+1)==PPERIM_MAC2(N_AXIS)) THEN
+ RADIA=0.
+ ELSE
+ RADIA=DIST_AXIS(PPERIM_MAC2(N_AXIS+1)-1)
+ ENDIF
+ IF(DELX<RADIA) THEN
+ ! point 'DELX' is on one of the elements on the axis
+ P1=PPERIM_MAC2(N_AXIS); P2=PPERIM_MAC2(N_AXIS+1)-1
+ CALL SAL241_2(P2-P1+1,PERIM_MAC2(P1:P2),DIST_AXIS(P1:P2),IPAR)
+ LGOK=.TRUE.
+ ELSE
+ WRITE(*,*) 'PPERIM_MAC2(N_AXIS+1),PPERIM_MAC2(N_AXIS) :',PPERIM_MAC2(N_AXIS+1),PPERIM_MAC2(N_AXIS)
+ WRITE(*,*) 'DIST_AXIS(PPERIM_MAC2(N_AXIS+1)-1) :',DIST_AXIS(PPERIM_MAC2(N_AXIS+1)-1)
+ WRITE(*,*) 'DELX :',DELX
+ CALL XABORT('SALTRA: Cant find entry point')
+ ENDIF
+ ENDIF
+ DINIT=DNEW
+ !* treat boundary condition on entry point
+ CALL SAL245(ISURF2_ELEM,IPAR,RPAR,IOUT,LNEW,NNEW,DNEW,LGLEFT)
+ !* abort if there is a left domain
+ IF(LGLEFT) CALL XABORT('SALTRA: LGLEFT True')
+ !* track the basic domain
+ IF(ISPEC == 0) THEN
+ IPHI=ANGLE_TO_NUMBER(EX0,EY0,DANGLT)
+ CALL SAL240_4(PERIM,PPERIM,IPAR,RPAR,IPHI,ISURF2_ELEM,IOUT)
+ ELSE
+ CALL SAL240_4_2(DANGLT,PPERIM,PERIM,IPAR,RPAR,IDATA_BC2, &
+ BCDATA,PERIM_MAC2,PPERIM_MAC2,DIST_AXIS,IBC2_ELEM)
+ ENDIF
+ ! trajectory entered into the element joint
+ IF(IERR==0) RETURN
+ ! change DD0
+ IF(LGMORE) DD0=DNEW+1.001*EPS1
+ !* put NB_TOT, ANGTAB to ITRAC2
+ ! total length of the trajectory
+ NTRACK=CNT-(CNT0+NNN)
+ ITRAC2(CNT0+1)=NTRACK
+ ! total nber of the sub-trajectories
+ ITRAC2(CNT0+2)=NB_TOT
+ ! put ANGTAB
+ LEN=2*NB_TOT
+ IF((CNT+LEN)>=NMAX2) THEN
+ CALL XABORT('SALTRA: Buffer overflow')
+ ELSE
+ ITRAC2(CNT+1:CNT+LEN)=ANGTAB(1:LEN)
+ ITRAC2(CNT+NMAX2+1:CNT+NMAX2+LEN)=ELMTAB(1:LEN)
+ CNT=CNT+LEN
+ ENDIF
+ !
+ END SUBROUTINE SALTRA
+
+ SUBROUTINE SAL241_2(NPERIM,PERIM,DIST_AXIS,IPAR)
+ !
+ !---------------------------------------------------------------------
+ !
+ !Purpose:
+ ! compute an entry point on the axial element
+ !
+ !Parameters: input
+ ! NPERIM = number of elements on this axis
+ ! PERIM = elements on this axis in perimeter
+ ! DIST_AXIS = distance of points on this axis to the center (0,0)
+ ! IPAR = integer descriptor of elements
+ !
+ !---------------------------------------------------------------------
+ !
+ USE SAL_TRACKING_TYPES, ONLY : IPART,N_AXIS,DNEW,DELX,NNEW,LNEW,COSINE,AX, &
+ AY,HX,HY,BX,BY,EX,EY
+ INTEGER, INTENT(IN) :: NPERIM
+ INTEGER, INTENT(IN), DIMENSION(:) :: PERIM
+ REAL(PDB), INTENT(IN), DIMENSION(:) :: DIST_AXIS
+ INTEGER, INTENT(IN), DIMENSION(:,:) :: IPAR
+ INTEGER :: I,J
+ !***
+ LNEW=0
+ !* compute crossed element
+ DO I=1,NPERIM
+ IF(DELX<=DIST_AXIS(I)) THEN
+ LNEW=PERIM(I)
+ EXIT
+ ENDIF
+ ENDDO
+ IF(LNEW==0) CALL XABORT('SAL241_2: Error of distances on the axis')
+ !* get entered node
+ NNEW=IPAR(2,LNEW)
+ IF(NNEW<0) NNEW=IPAR(3,LNEW)
+ IF(NNEW<0) CALL XABORT('SAL241_2: Error of element data')
+ !* compute DNEW at entry point
+ DNEW=DELX*(EX*HX(N_AXIS)+EY*HY(N_AXIS))
+ IF(N_AXIS>2) DNEW=DNEW+BX(N_AXIS)*EX+BY(N_AXIS)*EY
+ !* compute COSINE
+ COSINE=ABS(HX(N_AXIS)*EY-HY(N_AXIS)*EX)
+ !* set all elements in this axis to be 'treated (0)'
+ ! others are 'untreated'
+ IPART(1,:)=-1
+ DO I=1,NPERIM
+ J=PERIM(I)
+ IPART(1,J)=0
+ ENDDO
+ !* initial point
+ AX=BX(N_AXIS)+DELX*HX(N_AXIS)-DNEW*EX
+ AY=BY(N_AXIS)+DELX*HY(N_AXIS)-DNEW*EY
+ !
+ END SUBROUTINE SAL241_2
+ !
+ SUBROUTINE SAL240_3(PERIM_MAC2,NPERIM_MAC2,IPAR,RPAR)
+ !
+ !---------------------------------------------------------------------
+ !
+ !Purpose:
+ ! compute entry point for a basic trajectory
+ !
+ !Parameters: input
+ ! PERIM_MAC2 elements composing perimeter of domain
+ ! NPERIM_MAC2 number of elements composing perimeter of domain
+ ! IPAR integer geometry descriptors
+ ! RPAR floating point geometry descriptors
+ !
+ !---------------------------------------------------------------------
+ !
+ USE SAL_TRACKING_TYPES, ONLY : IPART,EX0,EY0,EX,EY,DD0,LGOK,LGMORE,NBER, &
+ DNEW,NNEW,LNEW,DINIT
+ IMPLICIT NONE
+ INTEGER, INTENT(IN) :: NPERIM_MAC2
+ INTEGER, INTENT(IN), DIMENSION(:) :: PERIM_MAC2
+ REAL(PDB), INTENT(IN), DIMENSION(:,:) :: RPAR
+ INTEGER, INTENT(IN), DIMENSION(:,:) :: IPAR
+ !***
+ EX=EX0; EY=EY0
+ ! enter trajectory with vectors a and e and initial distance dd0
+ ! initiate all elements status to untreated
+ IPART(1,:)=-1
+ CALL SAL241(PERIM_MAC2,NPERIM_MAC2,IPAR,RPAR,DD0,-100,DNEW,NNEW,LNEW)
+ DINIT=DNEW
+ ! if we have sevaral entry points
+ LGMORE=NBER>3
+ !* if not succeed
+ IF(.NOT.LGOK) CALL XABORT('SAL240_3: Could not enter domain')
+ !
+ END SUBROUTINE SAL240_3
+ !
+ SUBROUTINE SAL245(ISURF2_ELEM,IPAR,RPAR,IOUT,LOLD,NOLD,DOLD,LGLEFT)
+ !
+ !---------------------------------------------------------------------
+ !
+ !Purpose:
+ ! boundary condition treatment at entry point
+ !
+ !Parameters: input
+ ! ISURF2_ELEM relative 2D surf nber per elem
+ ! IPAR integer geometry descriptors
+ ! RPAR floating point geometry descriptors
+ !
+ !Parameters: input/output
+ ! LOLD entry point
+ ! NOLD node index
+ ! DOLD distance
+ ! LGLEFT flag set to TRUE if there is a left domain
+ !
+ !Parameters: output
+ ! IOUT (to load outside surface) = 5 (left trajectory)
+ ! 6 (right trajectory)
+ !
+ !---------------------------------------------------------------------
+ !
+ USE SAL_TRACKING_TYPES, ONLY : ITRAC2,RTRAC2,CNT0,COSINE,EX,EY
+ USE SAL_GEOMETRY_TYPES, ONLY : G_BC_TYPE,ISPEC
+ IMPLICIT NONE
+ INTEGER, INTENT(IN), DIMENSION(:,:) :: IPAR
+ INTEGER, INTENT(IN), DIMENSION(:) :: ISURF2_ELEM
+ REAL(PDB), INTENT(IN), DIMENSION(:,:) :: RPAR
+ INTEGER, INTENT(INOUT) :: LOLD,NOLD
+ REAL(PDB), INTENT(INOUT) :: DOLD
+ LOGICAL, INTENT(INOUT) :: LGLEFT
+ INTEGER, INTENT(OUT) :: IOUT
+ !***
+ INTEGER :: BCIN,SURF
+ !***
+ ! initiate surface info
+ ITRAC2(CNT0+5)=0
+ ITRAC2(CNT0+6)=0
+ !* get boundary condition at entry surface
+ BCIN=IPAR(2,LOLD)
+ IF(NOLD==BCIN)BCIN=IPAR(3,LOLD)
+ ! add entry cosine anyhow (for characteristics)
+ RTRAC2(CNT0+2)=COSINE
+ LGLEFT=.FALSE.
+ IF(ISPEC == 1) RETURN
+ IF(BCIN>=G_BC_TYPE(0).OR.BCIN==G_BC_TYPE(-1).OR.BCIN==G_BC_TYPE(1))THEN
+ !* trajectory enters through vacuum:
+ ! - compute angle, trajectory-normal and store cos and sin
+ ! (inverse vector E in order to pass outgoing direction)
+ CALL SAL247_1(RPAR(:,LOLD),IPAR(:,LOLD),DOLD,RTRAC2(CNT0+3),RTRAC2(CNT0+5),-EX,-EY)
+ !* get index of the entry surface
+ SURF=ISURF2_ELEM(LOLD)
+ IF(SURF/=0) ITRAC2(CNT0+5)=SURF ! store 2D surface index
+ IOUT=6
+ ELSE
+ CALL XABORT('SAL245: Reversed direction')
+ ENDIF
+ !
+ END SUBROUTINE SAL245
+ !
+ SUBROUTINE SAL240_4(PERIM,PPERIM,IPAR,RPAR,IPHI,ISURF2_ELEM,IOUT)
+ !
+ !---------------------------------------------------------------------
+ !
+ !Purpose:
+ ! track a trajectory until leaving the domain
+ ! begin: having (nnew,dnew,lnew)
+ ! |
+ ! (1)write horizontal angle information
+ ! |
+ ! (2)compute successive crossed nodes
+ ! |
+ ! (3)boundary condition:
+ ! re-entry: get re-entry point,go to (1)
+ ! go out: compute surface number,end
+ !
+ !Parameters: input
+ ! PERIM array of elements in perimeter of nodes
+ ! PPERIM array pointer to elements in the perimeter of nodes
+ ! IPAR integer geometry descriptors
+ ! RPAR floating point geometry descriptors
+ ! IPHI angular index of the track
+ ! ISURF2_ELEM relative 2D surf number per elem
+ ! IOUT (to load outside surface) = 5 (left trajectory)
+ !
+ !---------------------------------------------------------------------
+ !
+ USE SAL_TRACKING_TYPES, ONLY : NNN,NMAX2,ITRAC2,RTRAC2,ANGTAB,ELMTAB,PRTIND,CNT, &
+ CNT0,EX,EY,LGOK,NB_TOT,NB_MAX,DNEW,NNEW,LNEW,IERR
+ USE SAL_GEOMETRY_TYPES, ONLY : G_BC_TYPE
+ IMPLICIT NONE
+ ! IN VARIABLE
+ INTEGER, INTENT(IN) :: IPHI
+ INTEGER, INTENT(IN), DIMENSION(:) :: PPERIM,PERIM
+ INTEGER, INTENT(IN), DIMENSION(:,:) :: IPAR
+ REAL(PDB), INTENT(IN), DIMENSION(:,:) :: RPAR
+ INTEGER, INTENT(IN), DIMENSION(:) :: ISURF2_ELEM
+ INTEGER, INTENT(IN) :: IOUT
+ !***
+ INTEGER :: NOLD,LOLD,P1,P2,CNT1,SURF
+ REAL(PDB) :: DOLD,LENGTH
+ LOGICAL :: LGON
+ INTEGER, PARAMETER :: FOUT =6
+ !***
+ LGON = .TRUE.
+ ! initiate counter
+ CNT1=CNT
+ EXTERIOR : DO WHILE(LGON)
+ NB_TOT=NB_TOT+1
+ IF(NB_TOT > NB_MAX) CALL XABORT('SAL240_4: NB_TOT overflow')
+ ! keep horizontal phi nber in angtab
+ IF(NB_TOT>1) CALL XABORT('SAL240_4: Angtab overflow')
+ ANGTAB(2*NB_TOT)=IPHI
+ ELMTAB(2*NB_TOT-1)=LNEW ; ELMTAB(2*NB_TOT)=0 ;
+ !
+ !* track a sub-trajectory
+ INTERIOR: DO WHILE(NNEW>0)
+ ! UPDATE DATA TO COMPUTE NEXT NODE:
+ DOLD=DNEW
+ LOLD=LNEW
+ NOLD=NNEW
+ ! crossing NODE NOLD
+ ! input: trajectory (T):R=A+D*E => A = (AX,AY), E = (EX,EY)
+ ! DOLD = D at last intersection
+ ! NOLD = NODE just entered
+ P1=PPERIM(NOLD); P2=PPERIM(NOLD+1)-1
+ CALL SAL241(PERIM(P1:P2),P2-P1+1,IPAR,RPAR,DOLD,NOLD,DNEW,NNEW,LNEW)
+ ! at return from SAL241:
+ ! DNEW = D at point exiting node
+ ! COSINE = cosine of trajectory with exiting normal
+ ! NNEW = new node entered
+ ! LNEW = element crossed when exiting node
+ ! NBER = number of intersections with perimeter
+ ! LGOK = .TRUE. if trajectory exits the node
+ IF(.NOT.LGOK) THEN
+ IERR=0
+ IF(PRTIND>0)WRITE(FOUT,'("SAL240_4 ==> couldnt exit node ",I5)') NOLD
+ RETURN
+ ENDIF
+ ! store data
+ LENGTH=DNEW-DOLD
+ ! store new length in track arrays
+ CNT=CNT+1
+ IF(CNT>=NMAX2) CALL XABORT('SAL240_4: NMAX2 overflow')
+ RTRAC2(CNT)=LENGTH
+ ITRAC2(CNT+NMAX2)=LNEW
+ ITRAC2(CNT)=NOLD
+ END DO INTERIOR
+ !
+ !* exiting motif and analyzing bc condition
+ LGON =(NNEW<G_BC_TYPE(1)).AND.(NNEW>=G_BC_TYPE(5))
+ ! STORE NBER OF REGIONS TO ANGTAB
+ ANGTAB(2*NB_TOT-1)=CNT-CNT1
+ CNT1=CNT
+ IF(LGON) THEN
+ CALL XABORT('SAL240_4: Lgon is true')
+ ELSE
+ ! compute leaving surface
+ IF(NNEW<=0)THEN
+ ! we got a surface: end of trajectory
+ ! vacuum bd condition. put a marker (surface number) to allow
+ ! psi and pss computation
+ ! store exiting surface, cosphi and sinphi
+ ! compute angle trajectory-normal
+ CALL SAL247_1(RPAR(:,LNEW),IPAR(:,LNEW),DNEW, &
+ RTRAC2(CNT0+IOUT-2),RTRAC2(CNT0+IOUT),EX,EY)
+ ! store 2D surface-cone nber
+ SURF=ISURF2_ELEM(LNEW)
+ IF(SURF/=0) ITRAC2(CNT0+IOUT)=SURF
+ ENDIF
+ ENDIF
+ !
+ ENDDO EXTERIOR
+ ! set success flag
+ IERR=1
+ !
+ END SUBROUTINE SAL240_4
+ !
+ SUBROUTINE SAL240_4_2(DANGLT,PPERIM,PERIM,IPAR,RPAR,IDATA_BC2,BCDATA, &
+ PERIM_MAC2,PPERIM_MAC2,DIST_AXIS,IBC2_ELEM)
+ !
+ !---------------------------------------------------------------------
+ !
+ !Purpose:
+ ! track a cyclic trajectory until the track length equal to the predefined
+ ! length of this trajectory
+ ! begin: having (nnew,dnew,lnew)
+ ! |
+ ! (1)write horizontal angle information
+ ! |
+ ! (2)compute successive crossed nodes
+ ! |
+ ! (3)if abs(total_length*length_inv_cycl-1)>eps1 :
+ ! yes:continue, get re-entry point,go to (1)
+ ! no: end of tracking
+ !
+ !Parameters: input
+ ! DANGLT angle cosines
+ ! PERIM array of elements in perimeter of nodes
+ ! PPERIM array pointer to elements in the perimeter of nodes
+ ! IPAR integer geometry descriptors
+ ! RPAR real geometry descriptors
+ ! IDATA_BC2 position of bc data per 2D boundary conditions
+ ! PERIM_MAC2 elements composing perimeter of domain
+ ! PPERIM_MAC2 pointer to 'PERIM' and 'DIST_AXIS':
+ ! PPERIM_MAC2(1):beginning of elements on axis 1
+ ! PPERIM_MAC2(2):beginning of elements on axis 2
+ ! PPERIM_MAC2(3):beginning of elements not on axis
+ ! DIST_AXIS distance of points on this axis to the center (0,0)
+ ! BCDATA table of bc descriptor
+ ! IBC2_ELEM relative 2D bc nber per elem
+ !
+ !Parameters: output
+ ! NB_TOT total number of sub-trajectories
+ ! ANGTAB table of {N_K,ANGLE_K} (1<K<NB_TOT)
+ ! N_K: nber of regions in kth sub-trajectory
+ ! ANGLE_K: angle nber of kth sub-trajectory
+ !
+ !---------------------------------------------------------------------
+ !
+ USE SAL_TRACKING_TYPES, ONLY : NNN,NMAX2,ITRAC2,RTRAC2,ANGTAB,ELMTAB,N_AXIS,CNT, &
+ EX,EY,AX,AY,LGOK,LENGTH_INV_CYCL,NB_TOT,NB_MAX,DNEW,NNEW,LNEW,IERR,EPS1,TORIG, &
+ N_AXIS_KEEP,IMPX
+ USE SAL_GEOMETRY_TYPES, ONLY : G_BC_TYPE
+ IMPLICIT NONE
+ ! in variable
+ !************
+ REAL(PDB), INTENT(IN), DIMENSION(:,:) :: DANGLT
+ INTEGER, INTENT(IN), DIMENSION(:) :: PPERIM,PERIM
+ INTEGER, INTENT(IN), DIMENSION(:,:) :: IPAR
+ REAL(PDB), INTENT(IN), DIMENSION(:,:) :: RPAR
+ REAL(PDB), INTENT(IN), DIMENSION(:,:) :: BCDATA
+ INTEGER, INTENT(IN), DIMENSION(:) :: PPERIM_MAC2,IBC2_ELEM
+ INTEGER, INTENT(IN), DIMENSION(:) :: PERIM_MAC2
+ REAL(PDB), INTENT(IN), DIMENSION(:),OPTIONAL :: DIST_AXIS
+ INTEGER, INTENT(IN), DIMENSION(:),OPTIONAL :: IDATA_BC2
+ ! local variable
+ INTEGER :: NOLD,LOLD,P1,P2,CNT1,IDATA,OK
+ REAL(PDB) :: DOLD,LENGTH,LENGTH_TOT
+ LOGICAL :: LGON
+ INTEGER, POINTER, DIMENSION(:) :: ITRAC3
+ REAL(PDB), POINTER, DIMENSION(:) :: RTRAC3
+ INTEGER, PARAMETER :: FOUT =6
+ !***
+ lgon=.true.
+ ! initiate counter
+ CNT1=CNT
+ LENGTH_TOT=0.
+ EXTERIOR : DO WHILE(LGON)
+ NB_TOT=NB_TOT+1
+ IF(NB_TOT > NB_MAX) CALL XABORT('SAL240_4_2: NB_TOT overflow')
+ N_AXIS_KEEP(NB_TOT)=N_AXIS
+ ! set horizontal angle index in angtab
+ ANGTAB(2*NB_TOT)=ANGLE_TO_NUMBER(EX,EY,DANGLT)
+ ELMTAB(2*NB_TOT-1)=LNEW ; ELMTAB(2*NB_TOT)=0 ;
+ TORIG(1,NB_TOT)=AX+DNEW*EX ; TORIG(2,NB_TOT)=AY+DNEW*EY ;
+ IF(IMPX > 4) WRITE(6,*) 'SAL240_4_2: beginning of track=',TORIG(:2,NB_TOT)
+ !
+ !* track a sub-trajectory
+ INTERIOR: DO WHILE(NNEW.GT.0)
+ ! update data to compute next node:
+ DOLD=DNEW
+ LOLD=LNEW
+ NOLD=NNEW
+ ! crossing node NOLD
+ ! input: trajectory (t):r=a+d*e => a = (ax,ay), e = (ex,ey)
+ ! DOLD = d at last intersection
+ ! NOLD = node just entered
+ P1=PPERIM(NOLD); P2=PPERIM(NOLD+1)-1
+ CALL SAL241(PERIM(P1:P2),P2-P1+1,IPAR,RPAR,DOLD,NOLD,DNEW,NNEW,LNEW)
+ ! at return from SAL241:
+ ! DNEW = d at point exiting node
+ ! COSINE = cosine of trajectory with exiting normal
+ ! NNEW = new node entered
+ ! LNEW = element crossed when exiting node
+ ! NBER = nber of intersections with perimeter
+ ! LGOK = .true. if trajectory exits the node
+ IF(.NOT.LGOK) THEN
+ IERR=0
+ WRITE(FOUT,'(" SAL240_4_2 ==> couldnt exit node ",I5)') NOLD
+ RETURN
+ ENDIF
+ ! store data
+ LENGTH=DNEW-DOLD
+ ! add to total length
+ LENGTH_TOT=LENGTH_TOT+LENGTH
+ CNT=CNT+1
+ IF(CNT>=NMAX2) THEN
+ ALLOCATE(ITRAC3(4*NMAX2),RTRAC3(2*NMAX2),STAT=OK)
+ IF(OK/=0) CALL XABORT('SAL240_4_2: NMAX2 overflow.')
+ RTRAC3(:NMAX2)=RTRAC2(:NMAX2)
+ ITRAC3(:2*NMAX2)=ITRAC2(:2*NMAX2)
+ DEALLOCATE(RTRAC2,ITRAC2)
+ RTRAC2=>RTRAC3
+ ITRAC2=>ITRAC3
+ NMAX2=2*NMAX2
+ ENDIF
+ RTRAC2(CNT)=LENGTH
+ ITRAC2(CNT+NMAX2)=LNEW
+ ITRAC2(CNT)=NOLD
+ ENDDO INTERIOR
+ !
+ !* exiting motif and analyzing bc condition
+ LGON=NNEW<=G_BC_TYPE(1).AND.NNEW>=G_BC_TYPE(5).AND.(ABS(LENGTH_TOT*LENGTH_INV_CYCL-1.)>EPS1)
+ ! store nber of regions to angtab
+ ANGTAB(2*NB_TOT-1)=CNT-CNT1
+ CNT1=CNT
+ IF(LGON)THEN
+ ! treat boundary condition and get new entry point
+ IF(PRESENT(IDATA_BC2).AND.PRESENT(DIST_AXIS)) THEN
+ IDATA=IDATA_BC2(IBC2_ELEM(LNEW))
+ ! treat bondary condition
+ CALL SAL247_3(BCDATA(:,IDATA))
+ ! at return from SAL247_3:
+ ! AX AY = entry point at boundary
+ ! EX EY = new direction
+ ! compute entry point
+ IF(NNEW==G_BC_TYPE(3).OR.NNEW==G_BC_TYPE(4).OR.NNEW==G_BC_TYPE(2)) THEN
+ P1=PPERIM_MAC2(N_AXIS); P2=PPERIM_MAC2(N_AXIS+1)-1
+ ! re-entry point is on the axis
+ CALL SAL241_2(P2-P1+1,PERIM_MAC2(P1:P2),DIST_AXIS(P1:P2),IPAR)
+ ENDIF
+ ELSE
+ CALL XABORT('SAL240_4_2: missing IDATA_BC2 or DIST_AXIS argument')
+ ENDIF
+ ENDIF
+ !
+ ENDDO EXTERIOR
+ ! set success flag
+ IERR=1
+ !
+ END SUBROUTINE SAL240_4_2
+ !
+ SUBROUTINE SAL247_3(BCDATA)
+ !
+ !----------------------------------------------------------------------
+ !
+ !Purpose:
+ ! Treatment of boundary conditions for the cyclic cases
+ ! side 4
+ ! side 3 ------
+ ! ---------- /\ side 3 / \ side 5
+ ! | | / \ / \
+ ! side 2 | | side 4 side 2 / \ side 3 \ /
+ ! | | / \ side 2 \ / side 6
+ ! ---------- -------- ------
+ ! side 1 side 1 side 1
+ !
+ !Parameters: input
+ ! BCDATA boundary condition descriptor
+ !
+ !----------------------------------------------------------------------
+ !
+ USE SAL_TRACKING_TYPES, ONLY : NNEW,DNEW,AX,AY,BX,BY,EX,EY,DELX,N_AXIS
+ USE SAL_GEOMETRY_TYPES, ONLY : TYPGEO,EPS,LX=>LENGTHX
+ IMPLICIT NONE
+ REAL(PDB), INTENT(IN), DIMENSION(:) :: BCDATA
+ !***
+ REAL(PDB) :: AUX,ACX,ACY,COSTHE,SINTHE,CX,CY,EX0
+ !***
+ ! boundary point:
+ AX=AX+DNEW*EX
+ AY=AY+DNEW*EY
+ CX=BCDATA(1) ; CY=BCDATA(2)
+ COSTHE=BCDATA(3)
+ SINTHE=BCDATA(4)
+ SELECT CASE(NNEW)
+ CASE(-2,-3)
+ ! translation/rotation for a segment (get displacement data)
+ ! a = displacement vector
+ ! new axis
+ SELECT CASE(TYPGEO)
+ CASE(5)
+ IF (CY<0) THEN ! end axe 2
+ N_AXIS=1
+ DELX=AX
+ ELSEIF (CY>0) THEN ! end axe 1
+ N_AXIS=3
+ DELX=AX
+ ELSEIF (CX<0) THEN ! end axe 4
+ N_AXIS=2
+ DELX=AY
+ ELSEIF (CX>0) THEN ! end axe 3
+ N_AXIS=4
+ DELX=AY
+ ENDIF
+ CASE(9)
+ IF (ABS(BCDATA(1))<EPS) THEN ! axes 1&4
+ IF (CY<0) THEN
+ N_AXIS=1
+ ELSE
+ N_AXIS=4
+ ENDIF
+ ELSEIF (CX>0) THEN
+ IF (CY>0) THEN
+ N_AXIS=5
+ ELSE
+ N_AXIS=6
+ ENDIF
+ ELSEIF (CX<0) THEN
+ IF (CY>0) THEN
+ N_AXIS=3
+ ELSE
+ N_AXIS=2
+ ENDIF
+ ENDIF
+ ACX=AX+CX ; ACY=AY+CY
+ DELX=SQRT((ACX-BX(N_AXIS))**2+(ACY-BY(N_AXIS))**2)
+ CASE(10)
+ ACX=LX-AX
+ EX0=EX
+ IF(CX>0) THEN
+ ! cx>0: axis 3
+ EX=0.5*EX+0.5*SQRT(3.)*EY
+ EY=0.5*EY-0.5*SQRT(3.)*EX0
+ N_AXIS=2
+ DELX=SQRT((AX-CX)*(AX-CX)+AY*AY)
+ ELSEIF(BCDATA(5)>0.) THEN
+ ! cx=0, angle>0: axis 2 (axis of angle pi/3)
+ EX=0.5*EX-0.5*SQRT(3.)*EY
+ EY=0.5*EY+0.5*SQRT(3.)*EX0
+ N_AXIS=3
+ DELX=SQRT(AX*AX+AY*AY)
+ ELSE
+ ! cx=0, angle=0: axis 1 (axis X)
+ EX=-EX
+ EY=-EY
+ N_AXIS=1
+ DELX=ACX
+ ENDIF
+ CASE(11)
+ ACX=AX-CX ; ACY=AY-CY
+ AUX=2._PDB*(ACX*COSTHE+ACY*SINTHE)
+ AX=AUX*COSTHE-ACX+CX
+ AY=AUX*SINTHE-ACY+CY
+ DELX=LX-SQRT((AX-CX)*(AX-CX)+(AY-CY)*(AY-CY))
+ EX0=EX
+ IF(ABS(BCDATA(5))<EPS) THEN ! exit side is on axes 1 or 3
+ EX=-0.5*EX+0.5*SQRT(3.)*EY
+ EY=-0.5*EY-0.5*SQRT(3.)*EX0
+ AX=AX+1.5*DELX
+ AY=AY+0.5*SQRT(3.)*DELX
+ IF(CY>0.) THEN
+ N_AXIS=2 ! cy>0: exit element is on axis 3 (angle=0)
+ ELSE
+ N_AXIS=4 ! cy=0: exit element is on axis 1 (angle=0)
+ ENDIF
+ ELSE ! exit side is on axes 2 or 4
+ EX=-0.5*EX-0.5*SQRT(3.)*EY
+ EY=-0.5*EY+0.5*SQRT(3.)*EX0
+ AX=AX-1.5*(LX-DELX)
+ AY=AY-0.5*SQRT(3.)*(LX-DELX)
+ IF(CX>0.) THEN
+ N_AXIS=1 ! cx>0: exit element is on axis 4 (angle>0)
+ ELSE
+ N_AXIS=3 ! cx=0: exit element is on axis 2 (angle>0)
+ ENDIF
+ ENDIF
+ CASE DEFAULT
+ CALL XABORT('SAL247_3: option not available(1)')
+ END SELECT
+ CASE(-4)
+ ! symmetry with respect an axis (get axis data)
+ ! axis: r=c+t*f (f unit vector of angle theta)
+ ACX=AX-CX ; ACY=AY-CY
+ AUX=2._PDB*(ACX*COSTHE+ACY*SINTHE)
+ AX=AUX*COSTHE-ACX+CX
+ AY=AUX*SINTHE-ACY+CY
+ AUX=2._PDB*(EX*COSTHE+EY*SINTHE)
+ EX=AUX*COSTHE-EX
+ EY=AUX*SINTHE-EY
+ SELECT CASE(TYPGEO)
+ CASE(6)
+ IF(BCDATA(5)>0.) THEN
+ ! vertical axes
+ IF(CX>0.) THEN
+ N_AXIS=4
+ ELSE
+ N_AXIS=2
+ ENDIF
+ DELX=AY
+ ELSE
+ ! horizontal axes
+ IF(CY>0.) THEN
+ N_AXIS=3
+ ELSE
+ N_AXIS=1
+ ENDIF
+ DELX=AX
+ ENDIF
+ CASE(7)
+ IF(CX>0) THEN
+ ! cx>0: axis 3 (vertical axis)
+ N_AXIS=3
+ DELX=AY
+ ELSEIF(BCDATA(5)>0.) THEN
+ ! cx=0, angle>0: axis 2 (axis of angle pi/4)
+ N_AXIS=2
+ DELX=SQRT(AX*AX+AY*AY)
+ ELSE
+ ! cx=0, angle=0: axis 1 (axis x)
+ N_AXIS=1
+ DELX=SQRT(AX*AX+AY*AY)
+ ENDIF
+ CASE(8,12)
+ IF(CX>0) THEN
+ ! cx>0: axis 3
+ N_AXIS=3
+ DELX=SQRT((AX-CX)*(AX-CX)+AY*AY)
+ ELSEIF(BCDATA(5)>0.) THEN
+ ! cx=0, angle>0: axis 2 (axis of angle pi/3 or 2*pi/3)
+ N_AXIS=2
+ DELX=SQRT(AX*AX+AY*AY)
+ ELSE
+ ! cx=0, angle=0: axis 1 (axis X)
+ N_AXIS=1
+ DELX=AX
+ ENDIF
+ CASE DEFAULT
+ CALL XABORT('SAL247_3: option not available(2)')
+ END SELECT
+ CASE DEFAULT
+ CALL XABORT('SAL247_3: option not available(3)')
+ END SELECT
+ !
+ END SUBROUTINE SAL247_3
+ !
+ INTEGER FUNCTION ANGLE_TO_NUMBER(EX,EY,DANGLT)
+ !
+ !---------------------------------------------------------------------
+ !
+ !Purpose:
+ ! search order number of a horizontal angle in the angular quadrature
+ ! formula set
+ !
+ !Parameters: input
+ ! EX angle cosine
+ ! EY angle sine
+ ! DANGLT angle cosines table
+ !
+ !---------------------------------------------------------------------
+ !
+ IMPLICIT NONE
+ REAL(PDB), INTENT(IN) :: EX,EY
+ REAL(PDB), INTENT(IN), DIMENSION(:,:) :: DANGLT
+ !***
+ INTEGER :: I,NPHI
+ REAL(PDB) :: EXREF,EYREF
+ CHARACTER(LEN=131) :: HSMG
+ !***
+ NPHI=SIZE(DANGLT,2)
+ ANGLE_TO_NUMBER=0
+ DO I=1,NPHI
+ EXREF=DANGLT(1,I) ; EYREF=DANGLT(2,I) ;
+ IF((ABS(EX-EXREF)<1.E-3).AND.(ABS(EY-EYREF)<1.E-3)) THEN
+ ANGLE_TO_NUMBER=I
+ GO TO 10
+ ELSE IF((ABS(EX-EXREF)<1.E-3).AND.(ABS(EY+EYREF)<1.E-3)) THEN
+ ANGLE_TO_NUMBER=2*NPHI-I+1
+ GO TO 10
+ ENDIF
+ ENDDO
+ WRITE(6,'(/29H ANGLE_TO_NUMBER: QUADRATURE:)')
+ DO I=1,2*NPHI
+ WRITE(6,'(1X,I5,1P,2E12.4)') I,DANGLT(:2,I)
+ ENDDO
+ WRITE(HSMG,'(47HANGLE_TO_NUMBER: UNABLE TO FIND ANGULAR COSINES,1P,2E12.4, &
+ & 26H INTO QUADRATURE SELECTED.)') EX,EY
+ CALL XABORT(HSMG)
+ 10 RETURN
+ !
+ END FUNCTION ANGLE_TO_NUMBER
+ !
+ SUBROUTINE SAL247_1(RPAR,IPAR,D,SINPHI,COSPHI,EX,EY)
+ !
+ !---------------------------------------------------------------------
+ !
+ !Purpose:
+ ! computes COSPHI and SINPHI for the intersection of the trajectory
+ ! with element LNEW of descriptors RPAR and IPAR. SINPHI is
+ ! computed with respect to directions outgoing with the trajectory
+ !
+ !Parameters: input
+ ! RPAR floating point geometry descriptors
+ ! IPAR integer geometry descriptors
+ ! D distance measured along the trajectory
+ ! EX first exiting unit vector in along trajectory
+ ! EY second exiting unit vector in along trajectory
+ !
+ !Parameters: output
+ ! SINPHI cosine at intersection
+ ! COSPHI sine at intersection
+ !
+ !---------------------------------------------------------------------
+ !
+ USE SAL_TRACKING_TYPES, ONLY : AX,AY
+ IMPLICIT NONE
+ INTEGER, INTENT(IN), DIMENSION(:) :: IPAR
+ REAL(PDB), INTENT(IN), DIMENSION(:) :: RPAR
+ REAL(PDB), INTENT(IN) :: D,EX,EY
+ REAL(PDB), INTENT(OUT) :: SINPHI,COSPHI
+ !> AX AY = components of origin of trajectory
+ !***
+ INTEGER :: TYPE
+ REAL(PDB) :: NX,NY
+ !***
+ NX=0._PDB
+ NY=0._PDB
+ TYPE=IPAR(1)
+ SELECT CASE(TYPE)
+ CASE(1)
+ ! TYPE=1=> segment (s): R=C+T*F with T in (0,1)
+ ! RPAR(1),RPAR(2) = C = (CX,CY)
+ ! RPAR(3),RPAR(4) = F = (FX,FY)
+ ! components of normal
+ NX=RPAR(4)/RPAR(5)
+ NY=-RPAR(3)/RPAR(5)
+ CASE(2,3)
+ ! TYPE=2,3=> arc of circle
+ NX=(AX+D*EX-RPAR(1))/RPAR(3)
+ NY=(AY+D*EY-RPAR(2))/RPAR(3)
+ END SELECT
+ SINPHI=NX*EY-NY*EX
+ IF((EX*NX+EY*NY)<0._PDB) SINPHI=-SINPHI
+ COSPHI=SQRT(1._PDB-SINPHI*SINPHI)
+ !
+ END SUBROUTINE SAL247_1
+ !
+ SUBROUTINE SAL241(PERIM,NPERIM,IPAR,RPAR,DOLD,NOLD,DNEW,NNEW,LNEW)
+ !
+ !---------------------------------------------------------------------
+ !
+ !Purpose:
+ ! computes intersection of trajectory (t): R=A+D*E with a perimeter
+ ! composed of the elements given in array perim
+ !
+ !Parameters: input
+ ! PERIM elements in the perimeter of a node
+ ! NPERIM number of elements in the perimeter
+ ! RPAR floating point geometry descriptors
+ ! IPAR integer geometry descriptors
+ ! DOLD value of D at current position
+ ! NOLD current entered node
+ !
+ !Parameters: output
+ ! DNEW value of D at the intersection
+ ! NNEW node index that is enter after intersection
+ ! LNEW element index that is intersected
+ !
+ !---------------------------------------------------------------------
+ !
+ USE SAL_GEOMETRY_TYPES, ONLY : NRPAR,NIPAR
+ USE SAL_TRACKING_TYPES, ONLY : NRPART,NIPART,RPART,IPART,EPS1
+ !***
+ IMPLICIT NONE
+ INTEGER, INTENT(IN), DIMENSION(:) :: PERIM
+ INTEGER, INTENT(IN), DIMENSION(:,:) :: IPAR
+ REAL(PDB), INTENT(IN), DIMENSION(:,:) :: RPAR
+ INTEGER, INTENT(IN) :: NPERIM,NOLD
+ INTEGER, INTENT(OUT) :: NNEW,LNEW
+ REAL(PDB), INTENT(IN) :: DOLD
+ REAL(PDB), INTENT(OUT) :: DNEW
+ !***
+ REAL(PDB) :: D
+ INTEGER :: I,L,INDEX,N,TYPE,NBINTE
+ ! INFTY is used to initialize search for minimum distance
+ REAL(PDB), PARAMETER :: INFTY=1.E+10
+ INTEGER, PARAMETER :: FOUT =6
+ !****
+ ! initialize distance for intersection
+ DNEW=INFTY
+ NBER=0
+ ! intersection:
+ DO I=1,NPERIM
+ L=PERIM(I)
+ ! get order nber of element in the perimeter
+ NBINTE=IPART(1,L)
+ IF(NBINTE<0)THEN
+ ! compute and store intersections
+ TYPE=IPAR(1,L)
+ IF(TYPE==1)THEN
+ ! segment
+ CALL SAL242(RPAR(:,L),IPAR(:,L),RPART(:,L),IPART(2:,L),NBINTE)
+ ELSEIF(TYPE<=3)THEN
+ ! arc of circle or circle
+ CALL SAL243(RPAR(:,L),IPAR(:,L),RPART(:,L),IPART(2:,L),NBINTE)
+ ELSE
+ CALL XABORT('SAL241: Not implemented')
+ ENDIF
+ IPART(1,L)=NBINTE
+ ENDIF
+ !
+ IF(NBINTE/=0)THEN
+ DO INDEX=1,NBINTE
+ D=RPART(INDEX,L)
+ N=IPART(1+INDEX,L)
+ ! analyzes feasability of intersection to eliminate conflicts due
+ ! to concavities and crossing of mesh points
+ IF(N/=NOLD.AND.D>(DOLD-EPS1))THEN
+ NBER=NBER+1
+ IF(D<(DNEW-EPS1))THEN
+ DNEW=D
+ COSINE=RPART(INDEX+2,L)
+ NNEW=N
+ LNEW=L
+ ELSEIF(D<(DNEW+EPS1))THEN
+ ! case of two close intersections : liquidate smaller
+ NBER=NBER-1
+ IF(D>DNEW)THEN
+ DNEW=D
+ COSINE=RPART(INDEX+2,L)
+ NNEW=N
+ LNEW=L
+ ENDIF
+ ENDIF
+ ENDIF
+ ENDDO
+ ENDIF
+ ENDDO
+ !
+ LGOK=DNEW/=INFTY
+ IF(LGOK)THEN
+ ! eliminate intersection
+ IPART(1,LNEW)=IPART(1,LNEW)-1
+ IF(IPART(1,LNEW)==1.AND.RPART(1,LNEW)==DNEW)THEN
+ ! FOR AN ELEMENT WITH TWO INTERSECTIONS, MOVE 2ND
+ ! INTERSECTION INTO FIRST IF FIRST HAS BEEN TAKEN
+ RPART(1,LNEW)=RPART(2,LNEW)
+ RPART(3,LNEW)=RPART(4,LNEW)
+ IPART(2,LNEW)=IPART(3,LNEW)
+ ENDIF
+ ELSE
+ ! print out problem
+ IF(NOLD/=-100) THEN
+ WRITE(FOUT,*)'Problem in SAL241: NOLD, DOLD, NBINTE ',NOLD,DOLD,NBINTE
+ ENDIF
+ ENDIF
+ END SUBROUTINE SAL241
+ !
+ SUBROUTINE SAL242(RPAR,IPAR,D,NODE,NBINTE)
+ !
+ !---------------------------------------------------------------------
+ !
+ !Purpose:
+ ! analysis of the intersection of the trajectory (T):R=A+D*E and
+ ! a segment
+ !
+ !Parameters: input
+ ! RPAR floating point geometry descriptors
+ ! IPAR integer geometry descriptors
+ !
+ !Parameters: output
+ ! D value of D at intersection
+ ! NODE order nber of node entered after intersection
+ ! NBINTE number of intersections
+ !
+ !---------------------------------------------------------------------
+ !
+ IMPLICIT NONE
+ INTEGER, INTENT(IN), DIMENSION(:) :: IPAR
+ INTEGER, INTENT(OUT), DIMENSION(:) :: NODE
+ INTEGER, INTENT(OUT) :: NBINTE
+ REAL(PDB), INTENT(IN), DIMENSION(:) :: RPAR
+ REAL(PDB), INTENT(OUT), DIMENSION(:) :: D
+ ! DIMENSION RPAR(*),IPAR(*),NODE(*),D(*)
+ !***
+ REAL(PDB) :: CAX,CAY,FX,FY,A,DELTAM,DELTA
+ REAL(PDB), PARAMETER :: EPS2=0.
+ !***
+ ! TYPE=1=> segment (S): R=C+T*F with T in (0,1)
+ ! RPAR(1),RPAR(2) = C = (CX,CY)
+ ! RPAR(3),RPAR(4) = F = (FX,FY)
+ ! components of vector F
+ FX=RPAR(3)
+ FY=RPAR(4)
+ ! DELTA=F X E
+ DELTA=FX*EY-FY*EX
+ IF(DELTA/=0._PDB)THEN
+ ! components of vector CA=C-A
+ CAX=RPAR(1)-AX
+ CAY=RPAR(2)-AY
+ ! A=AC X E
+ A=CAY*EX-CAX*EY
+ DELTAM=DELTA-A
+ IF(DELTAM>(-EPS2).AND.A>(-EPS2))THEN
+ ! crossing into + halfspace
+ NODE(1)=IPAR(3)
+ ELSEIF(DELTAM<=EPS2.AND.A<=EPS2)THEN
+ ! crossing into - halfspace
+ NODE(1)=IPAR(2)
+ ELSE
+ ! out-of-range crossing
+ NBINTE=0
+ RETURN
+ ENDIF
+ ! compute distance to intersection along trajectory
+ ! D = (AC X F)/DELTA
+ D(1)=(CAY*FX-CAX*FY)/DELTA
+ D(3)=ABS(DELTA)
+ NBINTE=1
+ ELSE
+ ! A/=0 => out-of-range crossing (infinity)
+ ! A==0 => trajectory coincides with segment
+ ! in any case neglect intersection
+ NBINTE=0
+ ENDIF
+ END SUBROUTINE SAL242
+ !
+ SUBROUTINE SAL243(RPAR,IPAR,D,NODE,NBINTE)
+ !
+ !---------------------------------------------------------------------
+ !
+ !Purpose:
+ ! analysis of the intersection of the trajectory (T):R=A+D*E and
+ ! a circle or arc of circle
+ !
+ !Parameters: input
+ ! RPAR floating point geometry descriptors
+ ! IPAR integer geometry descriptors
+ !
+ !Parameters: output
+ ! D value of D at intersection
+ ! NODE order nber of node entered after intersection
+ ! NBINTE number of intersections
+ !
+ !---------------------------------------------------------------------
+ !
+ IMPLICIT NONE
+ INTEGER, INTENT(IN), DIMENSION(:) :: IPAR
+ INTEGER, INTENT(OUT), DIMENSION(:) :: NODE
+ INTEGER, INTENT(OUT) :: NBINTE
+ REAL(PDB), INTENT(IN), DIMENSION(:) :: RPAR
+ REAL(PDB), INTENT(OUT), DIMENSION(:) :: D
+ ! DIMENSION RPAR(*),IPAR(*),NODE(*),D(*)
+ !***
+ INTEGER :: TYPE,I
+ REAL(PDB) :: CAX,CAY,RAD,RAD2,RHOMI2,DMIN,THETA,THETA1,THETA2, &
+ COSTHE,DELTA
+ REAL(PDB), PARAMETER :: EPS2=0._PDB
+ !***
+ ! TYPE=2,3=> arc of circle (C): R=C+R*F(THETA),
+ ! THETA in (THETA1,THETA2)
+ ! RPAR(1),RPAR(2) = C = (CX,CY)
+ ! RPAR(3) = R = RADIUS
+ ! RPAR(4),RPAR(5) = (THETA1,THETA2) in (0,2PI) with THETA1<THETA2
+ ! and THETA1<0 if arc crosses THETA=0
+ ! LGTYPE = .TRUE. => THETA1 > 0
+ ! = .FALSE. => THETA1 < 0
+ ! components of vector CA=C-A
+ CAX=RPAR(1)-AX
+ CAY=RPAR(2)-AY
+ TYPE=IPAR(1)
+ ! value of R2
+ RAD=RPAR(3)
+ RAD2=RAD**2
+ ! RHOMI2=(CA X E)**2
+ RHOMI2=(CAX*EY-CAY*EX)**2
+ IF(RAD2>=RHOMI2)THEN
+ DELTA=SQRT(RAD2-RHOMI2)
+ ! tangent point = two very close points (to avoid infinite loop)
+ if(delta==0._pdb) delta=small
+ ! DMIN=CA*E
+ DMIN=CAX*EX+CAY*EY
+ ! D(1) D(2) = min and max distances for the two intersections
+ D(1)=DMIN-DELTA
+ D(2)=DMIN+DELTA
+ D(3)=DELTA/RAD
+ D(4)=D(3)
+ IF(TYPE==2)THEN
+ ! full circle. both intersections are possible
+ NODE(1)=IPAR(2)
+ NODE(2)=IPAR(3)
+ NBINTE=2
+ ELSE
+ ! analysis for arc of circle:
+ THETA1=RPAR(4)
+ THETA2=RPAR(5)
+ NBINTE=0
+ ! compute angles for closest and farthest intersections
+ ! and check feasability
+ DO I=1,2
+ COSTHE=(D(I)*EX-CAX)/RAD
+ THETA=SALACO(COSTHE,D(I)*EY-CAY)
+ IF( (((THETA1-THETA)<EPS2).AND.((THETA-THETA2)<EPS2)).OR. &
+ ((THETA-THETA2)<(EPS2-TWOPI)) )THEN
+ NBINTE=NBINTE+1
+ IF(NBINTE/=I)D(NBINTE)=D(I)
+ NODE(NBINTE)=IPAR(I+1)
+ END IF
+ ENDDO
+ ENDIF
+ ELSE
+ NBINTE=0
+ ENDIF
+ !
+ END SUBROUTINE SAL243
+ !
+END MODULE SAL_TRAJECTORY_MOD