GRIDMAN
grid managment library
cut.f
Go to the documentation of this file.
1 C> @file grid2D/cut.f
2 C> Select part of 2D grid cut by polygon
3 C GRIDMAN, grid managment library. Author: Vladislav Kotov, v.kotov@fz-juelich.de
4 
5 ! Copyright (c) 2017 Forschungszentrum Juelich GmbH
6 ! Vladislav Kotov
7 !
8 ! This file is part of GRIDMAN.
9 !
10 ! GRIDMAN is free software: you can redistribute it and/or modify
11 ! it under the terms of the GNU General Public License as published by
12 ! the Free Software Foundation, either version 3 of the License, or
13 ! (at your option) any later version.
14 !
15 ! GRIDMAN is distributed in the hope that it will be useful,
16 ! but WITHOUT ANY WARRANTY; without even the implied warranty of
17 ! MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 ! GNU General Public License for more details.
19 !
20 ! You should have received a copy of the GNU General Public License
21 ! along with GRIDMAN. If not, see <http://www.gnu.org/licenses/>.
22 
23 C**********************************************************************************************
24 C> Select part of a 2D grid cut by polygon
25 C>
26 C> Take cells which lie inside or outside of a closed polygon.
27 C>
28 C> Current implementation cannot handle the case where polygon edges
29 C> intersect the grid nodes, or grid edges intersect the polygon vertices
30 C>
31 C> Normally those conditions, as well as the codition that the polygon
32 C> has no self intersections, are not checked because it may require
33 C> too long time. The checks are enforced when GRIDMAN_CHECK=.TRUE.
34 C>
35 C> If polygon segments are added to the grid, then an edge index with
36 C> indexes of the segments is added
37  SUBROUTINE gridman_grid2d_cut(CUTGRID,GRID,XP,YP,NP,LEX,IERR)
39  u gridman_dbg,gridman_check,gridman_indlist,
40  u gridman_tol
42  IMPLICIT NONE
43  INTRINSIC tiny,count,abs,maxval,minval
44 C> Resulting grid with eliminated and cut cells
45  TYPE(gridman_grid) :: CUTGRID
46 C> Initial grid
47  TYPE(gridman_grid) :: GRID
48 C> Number of points in the polygon
49  INTEGER(GRIDMAN_SP),INTENT(IN) :: NP
50 C> X-coordinates of the polygon vertices, in METER
51 C>
52 C> First and last points must be same - closed polygon
53  REAL(GRIDMAN_DP),INTENT(IN) :: XP(np)
54 C> Y-coordinates of the polygon vertices, in METER
55 C>
56 C> First and last points must be same - closed polygon
57  REAL(GRIDMAN_DP),INTENT(IN) :: YP(np)
58 C> Defines if points inside the polygon are included or excluded
59 C>
60 C> If .FALSE. then points are included
61 C> If .TRUE. then points are excluded
62  LOGICAL,INTENT(IN) :: LEX
63 C> Error code
64  INTEGER,INTENT(OUT) :: IERR
65 
66  INTERFACE
67  SUBROUTINE gridman_grid2d_polygon_trajectory(NPOL,NPEDGE,
68  s icell_pol,iedge_pol,x_pol,y_pol,indvert,indseg,
69  s xp,yp,np,grid,ierr)
71  TYPE(gridman_grid) :: GRID
72  INTEGER(GRIDMAN_SP),INTENT(OUT) :: NPOL,NPEDGE(grid%nedges)
73  INTEGER(GRIDMAN_SP),ALLOCATABLE :: ICELL_POL(:),
74  i iedge_pol(:),indseg(:)
75  REAL(GRIDMAN_DP),ALLOCATABLE :: X_POL(:),Y_POL(:)
76  INTEGER(GRIDMAN_SP),INTENT(IN) :: NP
77  INTEGER(GRIDMAN_SP),INTENT(OUT) :: INDVERT(np)
78  REAL(GRIDMAN_DP) :: XP(np),YP(np)
79  INTEGER,INTENT(OUT) :: IERR
81  END INTERFACE
82 
83 C LOCAL VARIABLES
84  LOGICAL :: LFIRST_POINT_INSIDE_POLYGON
85  LOGICAL :: LPOINT(grid%npoints),LCELL(grid%ncells)
86  INTEGER(GRIDMAN_SP) :: NPOL,NPMAX,NEMAX,NWORK,IEP,
87  i npoints,nedges,ncells,ncells0,nseg,
88  i ip,icell,icell1,iedge,iedge1,iedge0,
89  i ipoint,ipoint1,ipoint2,
90  i ie,ic,ne,n,ncount,st
91  INTEGER :: RES,IERR0,IWARN
92  INTEGER (GRIDMAN_SP) :: NPEDGE(grid%nedges),
93  i npcell(grid%NCELLS),
94  i inewcell(grid%NCELLS), !INDMAP OF CELLS, OLD->NEW
95  i inewedge(grid%NEDGES), !INDMAP OF EDGES, OLD->NEW
96  i indpoint(grid%NPOINTS), !INDMAP OF POINTS, OLD->NEW
97  i indvert(np) !INDMAP OF POLYGON VERTICES, OLD->NEW
98 ! INDVERT is at the moment not used, is calculated in GRIDMAN_GRID2D_POLYGON_TRAJECTORY
99 ! for tje case if indices of points will be added in the future
100  REAL(GRIDMAN_DP) :: X0,Y0
101 C ALLOCATABLE ARRAYS
102  REAL(GRIDMAN_DP),ALLOCATABLE :: X1(:),X2(:)
103  INTEGER(GRIDMAN_SP),ALLOCATABLE :: IOLDEDGE(:), !INDMAP OF EDGES, NEW->OLD
104  i ioldcell(:), !INDMAP OF CELLS, NEW->OLD
105  i icell_pol(:),iedge_pol(:),indseg_pol(:), !see GRIDMAN_GRID2D_POLYGON_TRAJECTORY for description
106  i cells(:,:),points(:,:) !temporary arrays for cells and points of the new grid
107  INTEGER(GRIDMAN_SP),ALLOCATABLE :: INDSEG(:,:) !INDSEG(1,:) - index of edge of the new grid,
108  !INDSEG(2,:) - index of the polygon segment
109  INTEGER(GRIDMAN_SP),ALLOCATABLE :: IPWORK(:),TPWORK(:),ICOUNT(:)
110  REAL(GRIDMAN_DP),ALLOCATABLE :: X_POL(:),Y_POL(:),DWORK(:)
111  LOGICAL,ALLOCATABLE :: LWORK(:)
112 
113  TYPE(gridman_indlist) :: CELLEDGES
114 
115 C CHECK INPUT GRID
116  IF(gridman_dbg)
117  f WRITE(gridman_unit,*) "Starting GRIDMAN_GRID2D_CUT"
118 
119  ierr=0
120 
121  IF(grid%TYPE.NE.2.OR.grid%PDIM.NE.2.OR.grid%EDIM.NE.2) THEN
122  ierr=100
123  WRITE(gridman_unit,*) "GRIDMAN_GRID2D_TRIANG: ",
124  w "grid object is not of 2D type"
125  WRITE(gridman_unit,*) " TYPE, PDIM, EDIM ",
126  w grid%TYPE,grid%PDIM,grid%EDIM
127  RETURN
128  END IF
129 
130  IF(gridman_check) THEN
131 C CHECK INPUT GRID
132  CALL gridman_grid2d_check(grid,res,ierr)
133  IF(res.NE.0.OR.ierr.GT.0) THEN
134  ierr=100
135  WRITE(gridman_unit,*) "ERROR in GRIDMAN_GRID2D_CUT: ",
136  w "incorrect input grid"
137  RETURN
138  END IF
139  END IF
140 
141 C CHECK POLYGON
142  CALL check_polygon(xp,yp,np,ierr)
143  IF(ierr.GT.0) GOTO 100
144  iwarn=ierr
145 
146 C 1. CALCULATE TRAJECTORY OF THE POLYGON
147  CALL gridman_grid2d_polygon_trajectory(npol,npedge,
148  s icell_pol,iedge_pol,
149  s x_pol,y_pol,
150  s indvert,indseg_pol,
151  s xp,yp,np,grid,ierr)
152  IF(ierr.NE.0) GOTO 100
153 
154 C 2. FIND WHICH GRID POINTS (NODES) ARE INSIDE/OUTSIDE OF THE POLYGON
155  lfirst_point_inside_polygon=.true.
156  DO ipoint=1,grid%NPOINTS
157  x0=grid%X(1,ipoint)*grid%UNIT2SI
158  y0=grid%X(2,ipoint)*grid%UNIT2SI
159  lpoint(ipoint)=point_inside_polygon(xp,yp,np,x0,y0,lex)
160  END DO
161 C NUMBER OF POINTS IN NEW GRID
162  npoints=count(lpoint(1:grid%NPOINTS))
163  npoints=npoints+npol
164 
165  IF(gridman_dbg)
166  f WRITE(gridman_unit,*) "GRIDMAN_GRID2D_CUT: NPOINTS ",npoints
167 
168 C ALLOCATE TEMPORARY ARRAYS
169  npmax=maxval(npedge)
170  CALL allocate_temporary(npoints,npol,npmax,ierr)
171  IF(ierr.GT.0) GOTO 100
172 
173 C 3. TAKE COORDINATES OF THE POINTS TO THE NEW GRID
174  npoints=npol
175  IF(npol.GT.0) THEN
176  x1(1:npol)=x_pol
177  x2(1:npol)=y_pol
178  END IF
179  indpoint=0
180  DO ipoint=1,grid%NPOINTS
181  IF(lpoint(ipoint)) THEN
182  npoints=npoints+1
183  indpoint(ipoint)=npoints
184  x1(npoints)=grid%X(1,ipoint)
185  x2(npoints)=grid%X(2,ipoint)
186  END IF
187  END DO
188 
189 C 4. BUILD ARRAY OF EDGES
190  nedges=0
191  cells=0
192  points=0
193  ioldedge=0
194  inewedge=0
195  DO iedge=1,grid%NEDGES
196 C BUILD TABLE OF POINTS FOR THE EDGE
197 C IPWORK - index of point in the array of points
198 C TPWORK - type of the point: in, out or boundary
199  CALL edge_points(ipwork,tpwork,nwork,iedge,ierr)
200  IF(ierr.GT.0) GOTO 100
201  DO iep=1,nwork-1
202  IF( (tpwork(iep).GT.0.AND.tpwork(iep+1).GE.0).OR.
203  f (tpwork(iep+1).GT.0.AND.tpwork(iep).GE.0)) THEN
204 C IF BOTH IEP AND IEP+1 ARE IN OR
205 C IF ONE POINT IS IN AND ONE ON THE BOUNDARY THEN ADD EDGE
206  nedges=nedges+1
207  cells(:,nedges)=grid%CELLS(:,iedge)
208  points(1,nedges)=ipwork(iep)
209  points(2,nedges)=ipwork(iep+1)
210  ioldedge(nedges)=iedge
211  inewedge(iedge)=nedges
212  ELSE IF( (tpwork(iep).EQ.0.AND.tpwork(iep+1).EQ.0) ) THEN
213 C IF BOTH ON THE BOUNDARY THEN TAKE MIDDLE POINT AND
214 C CHECK IF THIS POINT INSIDE THE POLYGON
215  ipoint1=ipwork(iep)
216  ipoint2=ipwork(iep+1)
217  x0=0.5*(x1(ipoint1)+x1(ipoint2))*grid%UNIT2SI
218  y0=0.5*(x2(ipoint1)+x2(ipoint2))*grid%UNIT2SI
219  IF(point_inside_polygon(xp,yp,np,x0,y0,lex)) THEN
220  nedges=nedges+1
221  cells(:,nedges)=grid%CELLS(:,iedge)
222  points(1,nedges)=ipoint1
223  points(2,nedges)=ipoint2
224  ioldedge(nedges)=iedge
225  inewedge(iedge)=nedges
226  END IF
227  END IF
228  END DO
229  END DO !DO IEDGE=1,GRID%NEDGES
230 
231  IF(gridman_dbg)
232  f WRITE(gridman_unit,*) "GRIDMAN_GRID2D_CUT: NEDGES (*) ",nedges
233 
234 C 5. ADD EDGES FORMED BY THE POLYGON SEGMENTS
235  nseg=0 !number of edges which point to the polygon segments
236  IF(npol.GT.0) THEN
237  ALLOCATE(indseg(2,npol),stat=st)
238  IF(st.NE.0) GOTO 400
239  DO ip=1,npol
240  icell=icell_pol(ip)
241  IF(icell.GT.0) THEN
242 C ADD ONLY IF THE INTERVAL OF THE TRAJECTORY
243 C INTERSECTS A CELL
244  nedges=nedges+1
245  cells(1,nedges)=icell
246  cells(2,nedges)=0
247  points(1,nedges)=ip
248  IF(ip.LT.npol) THEN
249  points(2,nedges)=ip+1
250  ELSE
251  points(2,nedges)=1
252  END IF
253  nseg=nseg+1
254  indseg(1,nseg)=nedges
255  indseg(2,nseg)=indseg_pol(ip)
256  END IF
257  END DO
258  END IF
259 
260  IF(gridman_dbg)
261  f WRITE(gridman_unit,*) "GRIDMAN_GRID2D_CUT: NEDGES ",nedges
262 
263  IF(nedges.EQ.0) GOTO 200
264 
265 C 6. INDEX MAPPING OF CELLS
266  lcell=.false.
267  DO iedge=1,nedges
268  icell=cells(1,iedge)
269  IF(icell.GT.0) lcell(icell)=.true.
270  icell=cells(2,iedge)
271  IF(icell.GT.0) lcell(icell)=.true.
272  END DO
273  ncells=0
274  inewcell=0
275  ioldcell=0
276  DO icell=1,grid%NCELLS
277  IF(lcell(icell)) THEN
278  ncells=ncells+1
279  inewcell(icell)=ncells
280  ioldcell(ncells)=icell
281  END IF
282  END DO
283 
284 C 7. TRANSLATE CELL INDICES INTO NEW INDEXING
285  npcell(1:ncells)=0 !NUMBER OF INTERSECTIONS WITH THE CELL
286  DO iedge=1,nedges
287  DO ic=1,2
288  icell=cells(ic,iedge)
289  IF(icell.GT.0) THEN
290  icell1=inewcell(icell)
291  IF(icell1.LT.1) GOTO 300
292  cells(ic,iedge)=icell1
293  iedge0=ioldedge(iedge)
294  IF(iedge0.GT.0)
295  f npcell(icell1)=npcell(icell1)+npedge(iedge0)
296  ELSEIF(icell.LT.0) THEN
297 C EDGE INDEX FOR TELEPORTATION
298  iedge1=inewedge(-icell)
299  cells(ic,iedge)=-iedge1
300  END IF
301  END DO
302  END DO
303 
304  IF(gridman_dbg)
305  f WRITE(gridman_unit,*) "GRIDMAN_GRID2D_CUT: NCELLS (*) ",ncells
306 
307 C 8. CORRECT CELL INDICES
308 C TABLE OF EDGES WHICH BELONG TO EACH CELL
309  IF(maxval(npcell).GT.2) THEN
310  CALL list_of_edges(celledges,ierr)
311  IF(ierr.GT.0) GOTO 100
312  END IF
313  ncells0=ncells
314  DO icell=1,ncells0
315 C SKIP CELLS WITH LESS THAN 2 INTERSECTIONS WHICH DO NOT REQUIRE EXTRA CORRECTION
316  IF(npcell(icell).LE.2) cycle
317 C TOTAL NUMBER OF ELEMENTS
318  ne=celledges%ILAST(icell)-celledges%IFIRST(icell)+1
319  n=0
320 C UNMARK ALL ELEMENTS
321  lwork(1:ne)=.true.
322  ic=1
323  10 CONTINUE
324 C FIND CLOUSED COUNTOUR CONSISTING OF UNMARKED ELEMENTS
325  CALL find_contour(icount,ncount,lwork,icell,ierr)
326  IF(ierr.NE.0) RETURN
327  IF(ic.GT.1) THEN
328 C IF MORE THAN ONE CONTOUR, THEN ADD NEW CELL
329  ncells=ncells+1
330  ioldcell(ncells)=ioldcell(icell)
331 C CORRECT CELL INDEX FOR ALL EDGES BELONGING TO THE CONTOUR
332  DO ie=1,ncount
333  iedge=icount(ie)
334  IF(cells(1,iedge).EQ.icell) THEN
335  cells(1,iedge)=ncells
336  ELSE
337  cells(2,iedge)=ncells
338  END IF
339  END DO
340  END IF
341  n=n+ncount
342  IF(n.LT.ne) THEN
343 C IF NOT ALL ELEMENTS OF THE CELL ARE IN THE CONTOUR,
344 C THEN REPEAT ITERATION
345  ic=ic+1
346  GOTO 10
347  END IF
348  END DO !DO ICELL=1,GRID%NCELLS
349 
350  IF(gridman_dbg)
351  f WRITE(gridman_unit,*) "GRIDMAN_GRID2D_CUT: NCELLS ",ncells
352 
353  CALL create_cutgrid(ierr)
354  IF(ierr.GT.0) GOTO 100
355 
356  CALL deallocate_temporary(ierr)
357 
358 C TO PRESERVE WARNING INDEX FROM CHECK_POLYGON
359  IF(ierr.EQ.0) ierr=iwarn
360 
361  IF(gridman_dbg)
362  f WRITE(gridman_unit,*) "GRIDMAN_GRID2D_CUT finished"
363 
364  RETURN
365 
366  100 WRITE(gridman_unit,*) "GRIDMAN_GRID2D_CUT terminated"
367  CALL deallocate_all(ierr0)
368  RETURN
369  200 ierr=100
370  WRITE(gridman_unit,*) "ERROR in GRIDMAN_GRID2D_CUT: ",
371  w "resulting grid is empty"
372  CALL deallocate_all(ierr0)
373  RETURN
374  300 ierr=400
375  WRITE(gridman_unit,*) "ERROR in GRIDMAN_GRID2D_CUT: ",
376  w "internal error"
377  WRITE(gridman_unit,*)
378  w "Cell is taken into new grid but the index is <1"
379  WRITE(gridman_unit,*) " ICELL, ICELL1 ",icell,icell1
380  CALL deallocate_all(ierr0)
381  400 WRITE(gridman_unit,*) "ERROR in GRIDMAN_GRID2D_CUT: ",
382  w "cannot allocate temporary array INDSEG"
383  WRITE(gridman_unit,*) " NPOL ",npol
384  CALL deallocate_all(ierr0)
385  RETURN
386 
387  CONTAINS
388 
389 C --------------------------------------------------------------------
390 C FIND CHAIN OF CONNECTED EDGES BELONGING TO ICELL
391 C WHICH FORM CLOSED CONTOUR
392 C TAKE ONLY EDGES WHICH WERE NOT MARGED IN LWORK AS EXCLUDED
393 C LWORK IS UPDATED
394 C --------------------------------------------------------------------
395  SUBROUTINE find_contour(ICOUNT,NCOUNT,LWORK,ICELL,IERR)
396  INTEGER(GRIDMAN_SP),INTENT(OUT) :: ICOUNT(nemax), !LIST OF EDGES IN THE CONTOUR
397  i ncount !NUMBER OF EDGES IN THE CONTOUR
398  INTEGER(GRIDMAN_SP),INTENT(IN) :: ICELL
399  LOGICAL,INTENT(INOUT) :: LWORK(nemax)
400  INTEGER,INTENT(OUT) :: IERR
401 
402  INTEGER(GRIDMAN_SP) :: IE,I,IEDGE,IPOINT,IPOINT0,IPOINT00,NMAX
403 
404  ierr=0
405 
406 C FIND FIRST EDGE WHICH WAS NOT YET EXCLUDED
407  DO ie=celledges%IFIRST(icell),celledges%ILAST(icell)
408  iedge=celledges%IND(ie)
409  i=ie-celledges%IFIRST(icell)+1
410  IF(lwork(i)) EXIT
411  END DO
412 C TAKE ONE POINT OF THIS EDGE
413  ipoint0=points(1,iedge)
414  ipoint00=ipoint0
415 
416  nmax=celledges%ILAST(icell)-celledges%IFIRST(icell)+1
417 
418  ncount=0
419  DO
420 C SCAN OVER ALL EDGES WHICH WERE NOT YET EXLCUDED
421 C LOOK FOR THE POINT WHICH IS SAME AS IPOINT0
422  DO ie=celledges%IFIRST(icell),celledges%ILAST(icell)
423  i=ie-celledges%IFIRST(icell)+1
424  IF(lwork(i)) THEN
425  iedge=celledges%IND(ie)
426  IF(iedge.LT.1) THEN
427  ierr=400
428  WRITE(gridman_unit,*) "ERROR in GRIDMAN_GRID2D_CUT: ",
429  w "intenal error"
430  WRITE(gridman_unit,*) "No IEDGE in CELLEDGES"
431  WRITE(gridman_unit,*) " ICELL, IE, IEDGE ",icell,ie,iedge
432  RETURN
433  END IF
434  ipoint=points(1,iedge)
435  IF(ipoint.EQ.ipoint0) THEN
436 C 1st POINT = IPOINT0, THEN 2nd POINT IS THE NEXT IPOINT0
437  ncount=ncount+1
438  IF(ncount.GT.nmax) GOTO 100
439  icount(ncount)=iedge
440  ipoint0=points(2,iedge)
441  lwork(i)=.false.
442  GOTO 20
443  END IF
444  ipoint=points(2,iedge)
445  IF(ipoint.EQ.ipoint0) THEN
446 C 2nd POINT = IPOINT0, THEN 1st POINT IS THE NEXT IPOINT0
447  ncount=ncount+1
448  IF(ncount.GT.nmax) GOTO 100
449  icount(ncount)=iedge
450  ipoint0=points(1,iedge)
451  lwork(i)=.false.
452  GOTO 20
453  END IF
454  END IF !IF(LWORK(I)) THEN
455  END DO
456 C NO NEXT POINT IS FOUND - AN ERROR
457  ierr=400
458  WRITE(gridman_unit,*) "ERROR in GRIDMAN_GRID2D_CUT: ",
459  w "intenal error"
460  WRITE(gridman_unit,*) "Cannot find closed contour"
461  WRITE(gridman_unit,*) " ICELL ",icell
462  RETURN
463 C IF CURRENT POINT POINT0 == VERY FIRST POINT POINT00,
464 C THEN THE CONTOUR IS CLOSED
465  20 IF(ipoint0.EQ.ipoint00) EXIT
466  END DO !DO
467 
468  RETURN
469 
470  100 ierr=400
471  WRITE(gridman_unit,*) "ERROR in GRIDMAN_GRID2D_CUT: ",
472  w "intenal error"
473  WRITE(gridman_unit,*) "Index out of range in FIND_CONTOUR"
474  WRITE(gridman_unit,*) " ICELL ",icell
475  RETURN
476 
477  END SUBROUTINE find_contour
478 
479 C --------------------------------------------------------------------
480 C CREATE TABLE (INDLIST) OF EDGES WHICH BELONG TO EACH CELL
481 C ACCORDING TO ARRAY CELLS
482 C --------------------------------------------------------------------
483  SUBROUTINE list_of_edges(CELLEDGES,IERR)
484  TYPE(gridman_indlist) :: CELLEDGES
485  INTEGER,INTENT(OUT) :: IERR
486  INTEGER(GRIDMAN_SP) :: IEDGE,IC,ICELL,L,ST,IE,NLAST
487 
488  ierr=0
489 
490 C Here memory usage can be further optimized because the list of
491 C edges is required not for all cells but only for cells
492 C with >2 intersections
493  ALLOCATE(celledges%IFIRST(ncells),
494  a celledges%ILAST(ncells),stat=st)
495  IF(st.NE.0) THEN
496  WRITE(gridman_unit,*) "ERROR in GRIDMAN_GRID2D_CUT: ",
497  w "cannot allocate temporary data structure CELLEDGES"
498  WRITE(gridman_unit,*) " NCELLS ",grid%NCELLS
499  ierr=200
500  RETURN
501  END IF
502  celledges%ILAST=0
503  l=0
504  DO iedge=1,nedges
505  DO ic=1,2
506  icell=cells(ic,iedge)
507  IF(icell.GT.0) THEN
508  celledges%ILAST(icell)=celledges%ILAST(icell)+1
509  l=l+1
510  END IF
511  END DO
512  END DO
513 C CELLEDGES%ILAST NOW IS THE NUMBER OF EDGES WHICH BELONG TO ICELL
514  nemax=maxval(celledges%ILAST)
515  celledges%N=ncells
516  celledges%L=l
517  ALLOCATE(celledges%IND(l),stat=st)
518  IF(st.NE.0) THEN
519  WRITE(gridman_unit,*) "ERROR in GRIDMAN_GRID2D_CUT: ",
520  w "cannot allocate temporary data structure CELLEDGES"
521  WRITE(gridman_unit,*) " L ",l
522  ierr=200
523  RETURN
524  END IF
525  celledges%IFIRST(1)=1
526  nlast=celledges%ILAST(1)
527  celledges%ILAST(1)=0
528  DO icell=2,celledges%N
529  celledges%IFIRST(icell)=nlast+1
530  nlast=nlast+celledges%ILAST(icell)
531  celledges%ILAST(icell)=celledges%IFIRST(icell)-1
532  END DO
533  DO iedge=1,nedges
534  DO ic=1,2
535  icell=cells(ic,iedge)
536  IF(icell.GT.0) THEN
537  celledges%ILAST(icell)=celledges%ILAST(icell)+1
538  ie=celledges%ILAST(icell)
539  celledges%IND(ie)=iedge
540  END IF
541  END DO
542  END DO
543  ALLOCATE(lwork(nemax),icount(nemax),stat=st)
544  IF(st.NE.0) THEN
545  WRITE(gridman_unit,*) "ERROR in GRIDMAN_GRID2D_CUT: ",
546  w "cannot allocate temporary arrays"
547  WRITE(gridman_unit,*) " NEMAX ",nemax
548  ierr=200
549  RETURN
550  END IF
551 
552  END SUBROUTINE list_of_edges
553 
554 C --------------------------------------------------------------------
555 C BUILD CHAIN OF POINTS WHICH REPRESENTS IEDGE
556 C --------------------------------------------------------------------
557  SUBROUTINE edge_points(IPEDGE,TPEDGE,NP,IEDGE,IERR)
558  INTEGER(GRIDMAN_SP),INTENT(OUT) :: IPEDGE(npmax+2), !INDEX OF POINT IN X1,X2
559  i !FIRST AND LAST POINTS
560  i !ARE ALWAYS EDGE ENDS
561  i tpedge(npmax+2), !TYPE OF POINT:
562  i ! 1: INSIDE POLYGON
563  i !-1: OUTSIDE POLYGON
564  i ! 0: ON THE BOUNDARY
565  i np !NUMBER OF POINTS, >=2
566  INTEGER(GRIDMAN_SP),INTENT(IN) :: IEDGE
567  INTEGER,INTENT(OUT) :: IERR
568 
569  INTEGER(GRIDMAN_SP) :: IPOINT,IP,IPOINT1,ITMP
570  REAL(GRIDMAN_DP) :: Xa,Ya,Xs,Ys,DTMP
571  LOGICAL :: LSWAP
572 
573  IF(npedge(iedge).LT.1) THEN
574 C NO INTERSECTION WITH POLYGON
575 C WHOLE EDGE IS IN OR OUT
576  DO ip=1,2
577  ipoint=grid%POINTS(ip,iedge)
578  IF(lpoint(ipoint)) THEN
579  tpedge(ip)=1
580  ELSE
581  tpedge(ip)=-1
582  END IF
583  ipedge(ip)=indpoint(ipoint)
584  END DO
585  IF(tpedge(1).NE.tpedge(2)) THEN
586  ierr=400
587  WRITE(gridman_unit,*) "ERROR in GRIDMAN_GRID2D_CUT: ",
588  w "internal error"
589  WRITE(gridman_unit,*)
590  w "If edge is not intersected by the polygon"
591  WRITE(gridman_unit,*)
592  w "then both its ends must be either inside ",
593  w "or outside the grid"
594  WRITE(gridman_unit,*) " IEDGE, TPEDGE ",iedge,tpedge(1:2)
595  END IF
596  np=2
597  ELSE !IF(NPEDGE(IEDGE).EQ.0) THEN
598 C EDGE INTERSECTS WITH POLYGON
599 C BUILD CHAINS OF INTERSECTION POINTS
600  np=1
601 C TAKE ONE END OF THE EDGE
602  ipoint=grid%POINTS(1,iedge)
603  ipoint1=indpoint(ipoint)
604  ipedge(np)=ipoint1
605  xa=grid%X(1,ipoint)
606  ya=grid%X(2,ipoint)
607  IF(lpoint(ipoint)) THEN
608  tpedge(np)=1
609  ELSE
610  tpedge(np)=-1
611  END IF
612  DO ip=1,npol !CYCLE OVER WHOLE TRAJECTORY
613  IF(iedge_pol(ip).EQ.iedge) THEN
614 C TRAJECTORY INTERSECTS IEDGE
615 C ADD INTERSECTION POIN TO IPEDGE, TPEDGE
616  np=np+1
617  ipoint1=ip
618  ipedge(np)=ipoint1
619  tpedge(np)=0
620  xs=x1(ipoint1)
621  ys=x2(ipoint1)
622 C DISTANCE BETWEEN (Xs,Ys) AND (Xa,Ya)
623  dwork(np)=(xa-xs)**2+(ya-ys)**2
624  END IF
625  END DO
626 C ADD ANOVER END OF THE EDGE
627  np=np+1
628  ipoint=grid%POINTS(2,iedge)
629  ipoint1=indpoint(ipoint)
630  ipedge(np)=ipoint1
631  IF(lpoint(ipoint)) THEN
632  tpedge(np)=1
633  ELSE
634  tpedge(np)=-1
635  END IF
636  IF(np.GT.3) THEN
637 C SORT IN INCREASING DISTANCE FROM (Xa,Ya) ORDER
638 C SIMPLE BUBBLE SORT ALGORITHM
639  10 lswap=.false.
640  DO ip=2,np-2
641  IF(dwork(ip).GT.dwork(ip+1)) THEN
642  dtmp=dwork(ip)
643  dwork(ip)=dwork(ip+1)
644  dwork(ip+1)=dtmp
645  itmp=ipedge(ip)
646  ipedge(ip)=ipedge(ip+1)
647  ipedge(ip+1)=itmp
648  itmp=tpedge(ip)
649  tpedge(ip)=tpedge(ip+1)
650  tpedge(ip+1)=itmp
651  lswap=.true.
652  END IF
653  END DO
654  IF(lswap) GOTO 10
655  END IF
656  END IF !IF(NPEDGE(IEDGE).EQ.0) THEN
657 
658  END SUBROUTINE edge_points
659 
660 C --------------------------------------------------------------------
661 C FIND IF THE POINT (X0,Y0) LIES
662 C INSIDE THE POLYGON DEFINED BY XP, YP
663 C THE RESULT IS INVERTED WHEN LEX=.TRUE,
664 C --------------------------------------------------------------------
665  FUNCTION point_inside_polygon(XP,YP,NP,X0,Y0,LEX)
667  INTEGER(GRIDMAN_SP),INTENT(IN) :: NP
668  REAL(GRIDMAN_DP),INTENT(IN) :: XP(np),YP(np),X0,Y0
669  LOGICAL,INTENT(IN) :: LEX
670  LOGICAL :: POINT_INSIDE_POLYGON
671 
672  REAL(GRIDMAN_DP),SAVE :: XMIN,XMAX,YMIN,YMAX
673 
674  IF(lfirst_point_inside_polygon) THEN
675 C FOR OPTIMIZATION
676  xmin=minval(xp)
677  xmax=maxval(xp)
678  ymin=minval(yp)
679  ymax=maxval(yp)
680  lfirst_point_inside_polygon=.false.
681  END IF
682 
683  IF(x0.GT.xmax.OR.x0.LT.xmin.OR.
684  f y0.GT.ymax.OR.y0.LT.ymin) THEN
685  IF(lex) THEN
686  point_inside_polygon=.true.
687  ELSE
688  point_inside_polygon=.false.
689  END IF
690  RETURN
691  END IF
692 
693  point_inside_polygon=gridman_point_in_polygon(xp,yp,np,x0,y0)
694  IF(lex) point_inside_polygon=.NOT.point_inside_polygon
695 
696  END FUNCTION point_inside_polygon
697 
698 C --------------------------------------------------------------------
699 C CREATE NEW GRID OBJECT OUT OF TEMPORARY ARRAYS
700 C --------------------------------------------------------------------
701  SUBROUTINE create_cutgrid(IERR)
703  INTRINSIC trim
704  INTEGER,INTENT(OUT) :: IERR
705  INTEGER(GRIDMAN_SP) :: ICELL,ICELL0,IEDGE,IEDGE0
706  INTEGER :: II,NEI
707  INTEGER (GRIDMAN_SP) :: M,IEMAP(2,nedges),ICMAP(2,ncells)
708 
709  IF(nseg.GT.0) THEN
710  nei=grid%NEDGEINDEX+1
711  ELSE
712  nei=grid%NEDGEINDEX
713  END IF
714  CALL gridman_grid_allocate(cutgrid,grid%TYPE,nedges,npoints,
715  s ncells,ierr,nei,grid%NCELLINDEX)
716  IF(ierr.NE.0) THEN
717  WRITE(gridman_unit,*) "GRIDMAN_GRID2D_CUT terminated"
718  RETURN
719  END IF
720  cutgrid%CELLS=cells(1:2,1:nedges)
721  cutgrid%POINTS(1:2,:)=points(1:2,1:nedges)
722  cutgrid%X(1,:)=x1(1:npoints)
723  cutgrid%X(2,:)=x2(1:npoints)
724  cutgrid%UNIT2SI=grid%UNIT2SI
725  cutgrid%UNITS=grid%UNITS
726  cutgrid%DESCRIPTION=trim(grid%DESCRIPTION)//
727  / " << processed by GRIDMAN_GRID2D_CUT"
728 
729 C TRANSFORM EDGE INDICES
730  DO ii=1,grid%NEDGEINDEX
731  m=0
732  DO iedge=1,nedges
733  iedge0=ioldedge(iedge)
734  IF(iedge0.GT.0) THEN
735  m=m+1
736  iemap(1,m)=iedge0
737  iemap(2,m)=iedge
738  END IF
739  END DO
740  CALL gridman_index_transform(cutgrid%EDGEINDEX(ii),
741  c grid%EDGEINDEX(ii),iemap,m,ierr)
742  IF(ierr.NE.0) THEN
743  WRITE(gridman_unit,*) "ERROR in GRIDMAN_GRID2D_CUT: ",
744  w "cannot create edge index II ",ii
745  RETURN
746  END IF
747  END DO
748 C ADD INDEX MAPPING TO THE POLYGON SEGMENTS
749  IF(nseg.GT.0) THEN
750  CALL gridman_index_allocate(cutgrid%EDGEINDEX(nei),1,nseg,ierr)
751  IF(ierr.NE.0) THEN
752  WRITE(gridman_unit,*) "ERROR in GRIDMAN_GRID2D_CUT: ",
753  w "cannot create the polygon segment index, NSEG ",nseg
754  RETURN
755  END IF
756  cutgrid%EDGEINDEX(nei)%INDEXES(0:1,1:nseg)=indseg(1:2,1:nseg)
757  cutgrid%EDGEINDEX(nei)%DESCRIPTION=
758  w 'Indices of the polygon segments'
759  cutgrid%EDGEINDEX(nei)%COLUMNS(1)='CUT_ISEG'
760  END IF
761 
762 C TRANSFORM CELL INDICES
763  DO ii=1,grid%NCELLINDEX
764  m=0
765  DO icell=1,ncells
766  icell0=ioldcell(icell)
767  IF(icell0.GT.0) THEN
768  m=m+1
769  icmap(1,m)=icell0
770  icmap(2,m)=icell
771  END IF
772  END DO
773  CALL gridman_index_transform(cutgrid%CELLINDEX(ii),
774  c grid%CELLINDEX(ii),icmap,m,ierr)
775  IF(ierr.NE.0) THEN
776  WRITE(gridman_unit,*) "ERROR in GRIDMAN_GRID2D_CUT: ",
777  w "cannot create edge index II ",ii
778  RETURN
779  END IF
780  END DO
781 
782  CALL gridman_grid2d_check(cutgrid,res,ierr)
783  IF(res.NE.0.OR.ierr.GT.0) THEN
784  ierr=400
785  WRITE(gridman_unit,*) "ERROR in GRIDMAN_GRID2D_CUT: ",
786  w "wrong resulting GRID object"
787  RETURN
788  END IF
789 
790  END SUBROUTINE create_cutgrid
791 
792 C --------------------------------------------------------------------
793 C CHECK IF THE POLYGON CAN BE USED
794 C --------------------------------------------------------------------
795  SUBROUTINE check_polygon(XP,YP,NP,IERR)
797  INTEGER(GRIDMAN_SP),INTENT(IN) :: NP
798  REAL(GRIDMAN_DP),INTENT(IN) :: XP(np),YP(np)
799  INTEGER,INTENT(OUT) :: IERR
800  INTEGER(GRIDMAN_SP) :: IP,IP1,NP1,IPOINT
801  REAL(GRIDMAN_DP) :: DX,EX,DY,EY,EPS,X1,Y1,X2,Y2,X0,Y0,
802  r x11,y11,x12,y12,x21,y21,x22,y22,xi,yi
803  ierr=0
804 
805  IF(np.LT.4) THEN
806  ierr=100
807  WRITE(gridman_unit,*) "ERROR in GRIDMAN_GRID2D_CUT: ",
808  w "polygon must have at least 3 vertices"
809  WRITE(gridman_unit,*) " NP-1 ",np-1
810  RETURN
811  END IF
812 
813  DO ip=1,np-1
814  dx=abs(xp(ip+1)-xp(ip))
815  dy=abs(yp(ip+1)-yp(ip))
816  ex=tiny(dx)*10
817  IF(dx.LT.ex.AND.dy.LT.ex) THEN
818  ierr=100
819  WRITE(gridman_unit,*) "ERROR in GRIDMAN_GRID2D_CUT: ",
820  w "duplicate points in the polygon"
821  WRITE(gridman_unit,*) " IP1, X1, Y1 ",ip,xp(ip),yp(ip)
822  WRITE(gridman_unit,*) " IP2, X2, Y2 ",
823  w ip+1,xp(ip+1),yp(ip+1)
824  RETURN
825  END IF
826  END DO
827 
828  ex=gridman_tol*(abs(xp(1))+abs(xp(np)))+tiny(dx)*10
829  dx=abs(xp(1)-xp(np))
830  ey=gridman_tol*(abs(yp(1))+abs(yp(np)))+tiny(dy)*10
831  dy=abs(yp(1)-yp(np))
832  IF(dx.GT.ex.OR.dy.GT.ey) THEN
833  ierr=100
834  WRITE(gridman_unit,*) "ERROR in GRIDMAN_GRID2D_CUT: ",
835  w "no closed polygon"
836  END IF
837 
838  IF(gridman_check) THEN
839 C TESTS WHICH REQUIRE MORE TIME
840  eps=10.*tiny(x1)
841 C 1. SELF-INTERSECTIONS OF THE POLYGONE SEGMENTS
842  np1=np-2
843  DO ip=1,np-3
844  x11=xp(ip)
845  y11=yp(ip)
846  x12=xp(ip+1)
847  y12=yp(ip+1)
848  DO ip1=ip+2,np1
849  x21=xp(ip1)
850  y21=yp(ip1)
851  x22=xp(ip1+1)
852  y22=yp(ip1+1)
853  IF(gridman_intersect2d(x11,y11,x12,y12,
854  f x21,y21,x22,y22,xi,yi)) THEN
855  ierr=100
856  WRITE(gridman_unit,*) "ERROR in GRIDMAN_GRID2D_CUT: ",
857  w "polygon have self intersection"
858  WRITE(gridman_unit,*) " IP, IP1 ",ip,ip1
859  RETURN
860  END IF
861  END DO
862  np1=np-1
863  END DO
864 C> \todo More efficient algorithm should be invented to check
865 C> for nodes on segments and vertices on edges
866 C 2. POLYGONE SEGMENTS COME TOO CLOSE TO GRID NODES
867  DO ip=1,np-1
868  x1=xp(ip)
869  y1=yp(ip)
870  x2=xp(ip+1)
871  y2=yp(ip+1)
872  DO ipoint=1,grid%NPOINTS
873  x0=grid%X(1,ipoint)*grid%UNIT2SI
874  y0=grid%X(2,ipoint)*grid%UNIT2SI
875  IF(gridman_close2interval2d(x1,y1,
876  f x2,y2,x0,y0,gridman_tol)) THEN
877  ierr=-100
878  WRITE(gridman_unit,*) "WARNING from GRIDMAN_GRID2D_CUT: ",
879  w "polygone segment comes too close to a grid node"
880  WRITE(gridman_unit,*) " IP, X1, Y1, X2, Y2 ",
881  w ip, x1, y1, x2, y2
882  WRITE(gridman_unit,*) " IPOINT, X, Y ",ipoint,x0,y0
883  END IF
884  END DO
885  END DO
886 C 3. GRID EDGES COME TOO CLOSE TO POLYGONE SEGMENTS
887  DO iedge=1,grid%NEDGES
888  ipoint=grid%POINTS(1,iedge)
889  x1=grid%X(1,ipoint)*grid%UNIT2SI
890  y1=grid%X(2,ipoint)*grid%UNIT2SI
891  ipoint=grid%POINTS(2,iedge)
892  x2=grid%X(1,ipoint)*grid%UNIT2SI
893  y2=grid%X(2,ipoint)*grid%UNIT2SI
894  DO ip=1,np-1
895  IF(gridman_close2interval2d(x1,y1,x2,y2,
896  w xp(ip),yp(ip),gridman_tol)) THEN
897  ierr=-100
898  WRITE(gridman_unit,*) "WARNING from GRIDMAN_GRID2D_CUT: ",
899  w "grid edge comes too close to a polygone vertex"
900  WRITE(gridman_unit,*) " IEDGE, X1, Y1, X2, Y2 ",
901  w iedge, x1, y1, x2, y2
902  WRITE(gridman_unit,*) " IP, X, Y ",ip,xp(ip),yp(ip)
903  END IF
904  END DO
905  END DO
906 
907  END IF !IF(GRIDMAN_CHECK) THEN
908 
909  END SUBROUTINE check_polygon
910 
911 C --------------------------------------------------------------------
912 C ALLOCATE TEMPORARY ARRAYS
913 C --------------------------------------------------------------------
914  SUBROUTINE allocate_temporary(NPOINTS,NPOL,NPMAX,IERR)
915  INTEGER(GRIDMAN_SP),INTENT(IN) :: NPOINTS,NPOL,NPMAX
916  INTEGER,INTENT(OUT) :: IERR
917  INTEGER(GRIDMAN_SP) :: NE,NC,ST
918 
919  ierr=0
920 
921  ne=grid%NEDGES+2*npol
922  nc=grid%NCELLS+npol
923 
924  IF(gridman_dbg)
925  f WRITE(gridman_unit,*)
926  w "GRIDMAN_GRID2D_CUT: NPOL, NPOINTS, NPMAX ",
927  w npol, npoints, npmax
928 
929  ALLOCATE(x1(npoints),x2(npoints),
930  a ioldedge(ne),ioldcell(nc),
931  a cells(2,ne),points(2,ne),
932  a ipwork(npmax+2),tpwork(npmax+2),dwork(npmax+2),stat=st)
933  IF(st.NE.0) THEN
934  WRITE(gridman_unit,*) "ERROR in GRIDMAN_GRID2D_CUT: ",
935  w "cannot allocate temporary arrays"
936  WRITE(gridman_unit,*) " NPOINTS, NPMAX, NPOL ",
937  w npoints, npmax, npol
938  WRITE(gridman_unit,*) " NCELLS, NEDGES ",grid%NCELLS,grid%NEDGES
939  ierr=200
940  RETURN
941  END IF
942 
943  END SUBROUTINE allocate_temporary
944 
945 C --------------------------------------------------------------------
946 C DEALLOCATE TEMPORARY ARRAYS
947 C --------------------------------------------------------------------
948  SUBROUTINE deallocate_temporary(IERR)
949  INTEGER,INTENT(OUT) :: IERR
950  INTEGER :: ST(17)
951 
952  st=0
953 
954  IF(ALLOCATED(x1)) DEALLOCATE(x1,stat=st(1))
955  IF(ALLOCATED(x2)) DEALLOCATE(x2,stat=st(2))
956  IF(ALLOCATED(ioldedge)) DEALLOCATE(ioldedge,stat=st(3))
957  IF(ALLOCATED(ioldcell)) DEALLOCATE(ioldcell,stat=st(4))
958  IF(ALLOCATED(cells)) DEALLOCATE(cells,stat=st(5))
959  IF(ALLOCATED(points)) DEALLOCATE(points,stat=st(6))
960  IF(ALLOCATED(icell_pol)) DEALLOCATE(icell_pol,stat=st(7))
961  IF(ALLOCATED(iedge_pol)) DEALLOCATE(iedge_pol,stat=st(8))
962  IF(ALLOCATED(ipwork)) DEALLOCATE(ipwork,stat=st(9))
963  IF(ALLOCATED(tpwork)) DEALLOCATE(tpwork,stat=st(10))
964  IF(ALLOCATED(icount)) DEALLOCATE(icount,stat=st(11))
965  IF(ALLOCATED(x_pol)) DEALLOCATE(x_pol,stat=st(12))
966  IF(ALLOCATED(y_pol)) DEALLOCATE(y_pol,stat=st(13))
967  IF(ALLOCATED(dwork)) DEALLOCATE(dwork,stat=st(14))
968  IF(ALLOCATED(lwork)) DEALLOCATE(lwork,stat=st(15))
969  IF(ALLOCATED(indseg)) DEALLOCATE(indseg,stat=st(16))
970 
971  CALL gridman_indlist_deallocate(celledges,st(17))
972 
973  IF(any(st.NE.0)) THEN
974  ierr=-200
975  WRITE(gridman_unit,*) "ERROR in GRIDMAN_GRID2D_CUT: ",
976  w "problems with deallocation of temporary arrays"
977  END IF
978 
979 
980  END SUBROUTINE deallocate_temporary
981 
982 C --------------------------------------------------------------------
983  SUBROUTINE deallocate_all(IERR)
984  INTEGER,INTENT(OUT) :: IERR
985  CALL deallocate_temporary(ierr)
986  CALL gridman_grid_deallocate(cutgrid,ierr)
987  END SUBROUTINE deallocate_all
988 
989  END SUBROUTINE gridman_grid2d_cut
990 
991 C****************************************************************************
992 C BUILD TRAJECTORY OF THE POLYGON ON THE GRID -
993 C FIND EDGES AND CELL INTERSECTED BY THE POYLGON
994 C auxiliary subroutine called from GRIDMAN_GRID2D_CUT
995 C****************************************************************************
996  SUBROUTINE gridman_grid2d_polygon_trajectory(NPOL,NPEDGE,
997  s icell_pol,iedge_pol,
998  s x_pol,y_pol,
999  s indvert,indseg,
1000  s xp,yp,np,
1001  s grid,ierr)
1003  u gridman_dbg,gridman_indlist
1005  IMPLICIT NONE
1006 C INPUT
1007  INTEGER(GRIDMAN_SP),INTENT(IN) :: NP !NUMBER OF POLYGON VERTICES
1008  REAL(GRIDMAN_DP) :: XP(np),YP(np) !COORDINATES OF THE POLYGON VERTICES
1009  TYPE(gridman_grid) :: GRID !GRID OBJECT
1010 C OUTPUT
1011  INTEGER(GRIDMAN_SP),INTENT(OUT) ::
1012  i npol, !NUMBER OF POINTS IN THE RESULTING TRAJECTORY
1013  i npedge(grid%NEDGES) !NUMBER OF INTERSECTIONS OF THE POLYGON WITH EACH EDGE
1014  INTEGER(GRIDMAN_SP),ALLOCATABLE ::
1015  i icell_pol(:), !INDEX OF CELL WHERE THE POINT LIES
1016  i !(OR THERE THE TRAJECTORY GOES IN)
1017  i iedge_pol(:), !INDEX OF EDGE ON WHICH THE POINT LIES
1018  i
1019  i indseg(:) !INDSEG(IP) IS THE INDEX OF THE POLYGON
1020  i !SEGMENT ON WHICH THE INTERVAL IP,IP+1 LIES
1021  INTEGER(GRIDMAN_SP),INTENT(OUT) :: INDVERT(np) !INDEX MAPPING OF THE POLYGON VERTICES
1022  i !TO THE POINTS X_POL, Y_POL (OLD->NEW)
1023  i !INDEX OF THIS VERTEX, 0 OTHERWISE
1024  REAL(GRIDMAN_DP),ALLOCATABLE :: X_POL(:),Y_POL(:) !COORDINATES OF TRAJECTORY POINTS
1025  INTEGER,INTENT(OUT) :: IERR !ERROR CODE
1026 C LOCAL
1027  INTEGER(GRIDMAN_SP) :: NWORK,IEDGE0,IEDGE1,ICELL0,ICELL1,IP,
1028  i icell_first,iedge_first,ip_first,ipol
1029  REAL(GRIDMAN_DP) :: X0,Y0,X1,Y1,X_FIRST,Y_FIRST
1030 C LOCAL, ALLOCATABLE
1031  TYPE(gridman_indlist) :: CELLS,CHAINS
1032  REAL(GRIDMAN_DP),ALLOCATABLE :: XWORK(:),YWORK(:)
1033 
1034 C CHECK INPUT GRID
1035  IF(gridman_dbg)
1036  f WRITE(gridman_unit,*)
1037  w "Starting GRIDMAN_GRID2D_POLYGON_TRAJECTORY"
1038 
1039  ierr=0
1040 
1041 C GENERATE CLOSED CHAINS OF POINTS
1042  CALL gridman_grid2d_chains(grid,chains,ierr)
1043  IF(ierr.GT.0) RETURN
1044 
1045 C GENERATE LISTS OF EDGED
1046  CALL gridman_grid_cells(cells,grid,ierr)
1047  IF(ierr.GT.0) RETURN
1048 
1049 C ALLOCATE BUFFER ARRAYS XWORK, YWORK
1050  CALL allocate_work(chains,ierr)
1051  IF(ierr.GT.0) RETURN
1052 
1053 C FIND INITIAL POINT OF THE TRAJECTORY
1054  CALL first_point(x_first,y_first,
1055  s icell_first,iedge_first,ip_first)
1056  IF(ierr.GT.0) RETURN
1057 
1058  IF(gridman_dbg) THEN
1059  WRITE(gridman_unit,*) "GRIDMAN_GRID2D_POLYGON_TRAJECTORY:"
1060  WRITE(gridman_unit,*) " ICELL_FIRST, IEDGE_FIRST, IP_FIRST ",
1061  w icell_first, iedge_first, ip_first
1062  WRITE(gridman_unit,*) " X_FIRST, Y_FIRST ", x_first,y_first
1063  END IF
1064 
1065  npedge=0
1066 
1067  IF(iedge_first.LT.0.AND.icell_first.LT.0) THEN
1068  npol=0
1069  RETURN
1070  END IF
1071 
1072 C Here instead of linked lists a primitive and old fashioned way
1073 C of dynamic memory allocation is applied.
1074 C First the trajectory is run through to calculate its length.
1075 C After that arrays are allocated, and practically same
1076 C calculations is repeated. This time to record the trajectory
1077 C in the allocated arrays
1078 
1079 C CALCULATE NUMBER OF POINTS NPOL IN THE RESULTING TRAJECTORY
1080  x0=x_first
1081  y0=y_first
1082  ip=ip_first
1083  icell0=icell_first
1084  iedge0=iedge_first
1085  npedge=0
1086  IF(iedge0.GT.0) npedge(iedge0)=npedge(iedge0)+1
1087  npol=1
1088  DO !INFINITE CYCLE
1089  CALL find_next_point(iedge1,icell1,x1,y1,iedge0,icell0,
1090  c x0,y0,xp(ip),yp(ip))
1091  IF(iedge1.LT.1.AND.icell1.LT.1) GOTO 300
1092  x0=x1
1093  y0=y1
1094  icell0=icell1
1095  iedge0=iedge1
1096  IF(iedge0.GT.0) npedge(iedge0)=npedge(iedge0)+1
1097  IF(iedge0.LT.1) THEN
1098 C IF POINT NOT ON THE EDGE THEN THIS IS THE
1099 C POLYGON VERTEX, UPDATE INDEX OF THE NEXT VERTEX
1100  ip=ip+1
1101 C IF THIS IS VERTEX NP THEN STOP THE CYCLE
1102  IF(ip.GT.np) EXIT
1103  END IF
1104  npol=npol+1
1105  IF(icell1.LT.1) THEN
1106 C TRAJECTORY HAS LEFT THE GRID, LOOK FOR THE POINT
1107 C WHERE TRAJECTORY ENTERS THE GRID AGAIN
1108  11 CONTINUE
1109  CALL find_closest_boundary(iedge1,x1,y1,iedge0,
1110  c x0,y0,xp(ip),yp(ip))
1111  IF(iedge1.GT.0) THEN
1112 C INTERSECTION FOUND, ADD NEXT POINT TO THE POLYGON
1113  x0=x1
1114  y0=y1
1115  iedge0=iedge1
1116  npedge(iedge0)=npedge(iedge0)+1
1117  icell0=grid%CELLS(1,iedge0)
1118  IF(icell0.LT.1) icell0=grid%CELLS(2,iedge0)
1119  npol=npol+1
1120  ELSE
1121 C NO INTERSECTION, SHIFT TO THE NEXT VERTEX OF THE POLYGON
1122  x0=xp(ip)
1123  y0=yp(ip)
1124  iedge0=-1
1125  icell0=0
1126  ip=ip+1
1127  IF(ip.GT.np) EXIT
1128  GOTO 11
1129  END IF !IF(IEDGE1.GT.1) THEN
1130  END IF !IF(ICELL1.LT.1) THEN
1131  END DO !INFINITE CYCLE
1132 
1133  IF(gridman_dbg)
1134  f WRITE(gridman_unit,*)
1135  w "GRIDMAN_GRID2D_POLYGON_TRAJECTORY: NPOL ",npol
1136 
1137 C ALLOCATE OUTPUT ARRAYS
1138  CALL allocate_arrays(npol,ierr)
1139  IF(ierr.GT.0) RETURN
1140 
1141 C CALCULATE TRAJECTORY
1142  indvert=0
1143  x0=x_first
1144  y0=y_first
1145  ip=ip_first
1146  icell0=icell_first
1147  iedge0=iedge_first
1148  ipol=1
1149  x_pol(ipol)=x0
1150  y_pol(ipol)=y0
1151  icell_pol(ipol)=icell0
1152  iedge_pol(ipol)=iedge0
1153  IF(iedge0.LT.0) THEN
1154  IF(ip.LT.2) GOTO 100
1155  indvert(ip-1)=ipol
1156  END IF
1157  indseg(ipol)=ip-1
1158  DO !INFINITE CYCLE
1159  CALL find_next_point(iedge1,icell1,x1,y1,iedge0,icell0,
1160  c x0,y0,xp(ip),yp(ip))
1161  IF(iedge1.LT.1.AND.icell1.LT.1) GOTO 300
1162  x0=x1
1163  y0=y1
1164  icell0=icell1
1165  iedge0=iedge1
1166  IF(iedge0.LT.1) THEN
1167 C IF POINT NOT ON THE EDGE THEN THIS IS THE
1168 C POLYGON VERTEX, UPDATE INDEX OF THE NEXT VERTEX
1169  indvert(ip)=ipol+1
1170  ip=ip+1
1171 C IF THIS IS VERTEX NP THEN STOP THE CYCLE
1172  IF(ip.GT.np) EXIT
1173  END IF
1174  ipol=ipol+1
1175  x_pol(ipol)=x0
1176  y_pol(ipol)=y0
1177  icell_pol(ipol)=icell0
1178  iedge_pol(ipol)=iedge0
1179  indseg(ipol)=ip-1
1180  IF(icell1.LT.1) THEN
1181  22 CALL find_closest_boundary(iedge1,x1,y1,iedge0,
1182  c x0,y0,xp(ip),yp(ip))
1183 C TRAJECTORY HAS LEFT THE GRID, LOOK FOR THE POINT
1184 C WHERE TRAJECTORY ENTERS THE GRID AGAIN
1185  IF(iedge1.GT.0) THEN
1186  x0=x1
1187  y0=y1
1188  iedge0=iedge1
1189  icell0=grid%CELLS(1,iedge0)
1190  IF(icell0.LT.1) icell0=grid%CELLS(2,iedge0)
1191  ipol=ipol+1
1192  x_pol(ipol)=x0
1193  y_pol(ipol)=y0
1194  icell_pol(ipol)=icell0
1195  iedge_pol(ipol)=iedge0
1196  indseg(ipol)=ip-1
1197  ELSE
1198 C NO INTERSECTION, SHIFT TO THE NEXT VERTEX OF THE POLYGON
1199  x0=xp(ip)
1200  y0=yp(ip)
1201  iedge0=-1
1202  icell0=0
1203  ip=ip+1
1204  IF(ip.GT.np) EXIT
1205  GOTO 22
1206  END IF
1207  END IF !IF(ICELL1.LT.1) THEN
1208  END DO
1209 
1210  IF(ipol.NE.npol) GOTO 200
1211 
1212  indvert(np)=indvert(1) !FIRST AND LAST POINTS OF THE CONTOUR ARE THE SAME
1213 
1214 C TRANSLATE COORDINATES FROM METER INTO UNITS OF GRID
1215  x_pol(1:npol)=x_pol(1:npol)/grid%UNIT2SI
1216  y_pol(1:npol)=y_pol(1:npol)/grid%UNIT2SI
1217 
1218  CALL deallocate_local(ierr)
1219 
1220  IF(gridman_dbg)
1221  f WRITE(gridman_unit,*)
1222  w "GRIDMAN_GRID2D_POLYGON_TRAJECTORY finished"
1223 
1224  RETURN
1225 
1226  100 WRITE(gridman_unit,*)
1227  w "ERROR in GRIDMAN_GRID2D_POLYGON_TRAJECTORY: ",
1228  w "internal error (1)"
1229  ierr=400
1230  CALL deallocate_local(ierr)
1231  RETURN
1232  200 WRITE(gridman_unit,*)
1233  w "ERROR in GRIDMAN_GRID2D_POLYGON_TRAJECTORY: ",
1234  w "internal error (2)"
1235  ierr=400
1236  CALL deallocate_local(ierr)
1237  RETURN
1238  300 WRITE(gridman_unit,*)
1239  w "ERROR in GRIDMAN_GRID2D_POLYGON_TRAJECTORY: ",
1240  w "internal error (3)"
1241  WRITE(gridman_unit,*) " IEDGE0, ICELL0 ",iedge0,icell0
1242  WRITE(gridman_unit,*) " X0, Y0 ",x0,y0
1243  WRITE(gridman_unit,*) " IEDGE1, ICELL1 ",iedge1,icell1
1244  WRITE(gridman_unit,*) " X1, Y1 ",x1,y1
1245  WRITE(gridman_unit,*) " IP ",ip
1246  WRITE(gridman_unit,*) " XP, YP ",xp(ip),yp(ip)
1247  ierr=400
1248  CALL deallocate_local(ierr)
1249  RETURN
1250 
1251  CONTAINS
1252 
1253 C --------------------------------------------------------------------
1254 C FIND FIRST POINT OF THE TRAJECTORY
1255 C --------------------------------------------------------------------
1256  SUBROUTINE first_point(X_FIRST,Y_FIRST,
1257  s icell_first,iedge_first,ip_first)
1258  REAL(GRIDMAN_DP),INTENT(OUT) :: X_FIRST, !COORDINATES
1259  s y_first
1260  INTEGER(GRIDMAN_SP),INTENT(OUT) :: ICELL_FIRST, !INDEX OF CELL
1261  s iedge_first, !INDEX OF EDGE (<0 IF INSIDE CELL)
1262  s ip_first !INDEX OF THE NEXT POLYGON VERTEX
1263 C
1264  INTEGER(GRIDMAN_SP) :: IP,ICELL1,ICELL2,ICELL0,IEDGE,IEDGE0
1265  REAL(GRIDMAN_DP) :: X0,Y0,X1,Y1
1266 
1267 C SCALING FACTORS, XP,YP ARE TRANSLATED INTO UNITS OF GRID
1268  DO ip=1,np-1
1269  CALL find_closest_edge(iedge,x1,y1,xp(ip),yp(ip),
1270  c xp(ip+1),yp(ip+1))
1271  IF(iedge.GT.0) THEN
1272  ip_first=ip
1273  EXIT
1274  END IF
1275  END DO
1276  IF(iedge.LT.1) THEN
1277  icell_first=-1
1278  iedge_first=-1
1279  RETURN
1280  END IF
1281 
1282 C NOW WE HAVE TO DECIDE WHICH POINT HAS TO BE TAKEN AS THE FIRST ONE:
1283 C VERTEX IP OF THE POLYGON OR THE INTERSECTION POINT
1284  ip=ip_first
1285  x0=xp(ip)
1286  y0=yp(ip)
1287  iedge0=iedge
1288  icell1=grid%CELLS(1,iedge)
1289  IF(icell1.GT.0) THEN
1290  IF(point_in_cell(x0,y0,icell1)) THEN
1291 C IF VERTEX IP IS IN ICELL1,
1292 C THEN THE FIRST POINT IS IP, AND FIRST CELL IS ICELL1
1293  iedge0=-1
1294  icell0=icell1
1295  ELSE
1296 C IF IP IS NOT IN ICELL1, THEN CHECK ICELL2
1297  icell2=grid%CELLS(2,iedge)
1298  IF(icell2.GT.0) THEN
1299 C IF VERTEX IP IS IN ICELL2,
1300 C THEN THE FIRST POINT IS IP, AND FIRST CELL IS ICELL2
1301  iedge0=-1
1302  icell0=icell2
1303  ELSE
1304 C OTHERWISE: ICELL2<=0, ICELL1>0, BUT IP IS NOT IN ICELL1
1305 C THUS, IP IS OUTSIE THE GRID
1306 C TAKE INTERSECTION POINT AS THE FIRST POINT,
1307 C THAT STARTS INTO ICELL1
1308  x0=x1
1309  y0=y1
1310  icell0=icell1
1311  END IF
1312  END IF
1313  ELSE
1314 C ICELL1<=0, CHECK ICELL2
1315  icell2=grid%CELLS(2,iedge)
1316  IF(icell2.GT.0) THEN
1317  icell0=icell2
1318  IF(point_in_cell(x0,y0,icell2)) THEN
1319 C VERTEX IP IS IN ICELL2
1320 C FIRST POINT IS IP AND FIRST CELL IS ICELL2
1321  iedge0=-1
1322  ELSE
1323 C OTHERWISE, ICELL1<=0, ICELL2>0, BUT IP IS NOT IN ICELL2
1324 C THUS, IP IS OUTSIDE THE GRID,
1325 C TAKE INTERSECTION POINT AS THE FIRST POINT,
1326 C THAT STARTS INTO ICELL2
1327  x0=x1
1328  y0=y1
1329  END IF
1330  ELSE
1331 C BOTH ICELL1<=0, ICELL2<=0
1332 C TAKE INTERSECTION POINT AND SET FURST CELL TO ZERO
1333  x0=x1
1334  y0=y1
1335  icell0=0
1336  END IF
1337  END IF
1338  ip_first=ip+1
1339  x_first=x0
1340  y_first=y0
1341  icell_first=icell0
1342  iedge_first=iedge0
1343 
1344  END SUBROUTINE first_point
1345 
1346 C --------------------------------------------------------------------
1347 C FIND EDGE INTERSECTED BY THE INTERVAL
1348 C [(X1,Y1),(X2,Y2)] CLOSEST TO THE POINT (X1,Y1)
1349 C --------------------------------------------------------------------
1350  SUBROUTINE find_closest_edge(IEDGE_OUT,X_OUT,Y_OUT,X1,Y1,X2,Y2)
1352  INTEGER(GRIDMAN_SP),INTENT(OUT) :: IEDGE_OUT !INDEX OF INTERESECTED EDGE,
1353 
1354  REAL(GRIDMAN_DP),INTENT(OUT) :: X_OUT,Y_OUT !COORDINATES OF THE INTERSECTION POINT
1355  REAL(GRIDMAN_DP),INTENT(IN) :: X1,Y1,X2,Y2 !COORDINATES OF THE ENDS OF THE INTERVAL
1356 
1357  REAL(GRIDMAN_DP) :: XE1,YE1,XE2,YE2,XI,YI,D,DMIN
1358  INTEGER(GRIDMAN_SP) :: IEDGE,IPOINT
1359 
1360  ierr=0
1361 
1362  dmin=(x1-x2)**2+(y1-y2)**2
1363  x_out=x2
1364  y_out=y2
1365  iedge_out=-1
1366  DO iedge=1,grid%NEDGES
1367  ipoint=grid%POINTS(1,iedge)
1368  xe1=grid%X(1,ipoint)*grid%UNIT2SI
1369  ye1=grid%X(2,ipoint)*grid%UNIT2SI
1370  ipoint=grid%POINTS(2,iedge)
1371  xe2=grid%X(1,ipoint)*grid%UNIT2SI
1372  ye2=grid%X(2,ipoint)*grid%UNIT2SI
1373  IF(gridman_intersect2d(x1,y1,x2,y2,xe1,ye1,xe2,ye2,xi,yi)) THEN
1374  d=(x1-xi)**2+(y1-yi)**2
1375  IF(d.LT.dmin) THEN
1376  dmin=d
1377  iedge_out=iedge
1378  x_out=xi
1379  y_out=yi
1380  END IF
1381  END IF
1382  END DO
1383 
1384  END SUBROUTINE find_closest_edge
1385 
1386 C --------------------------------------------------------------------
1387 C FIND BOUNDARY EDGE INTERSECTED BY A PARTICLE
1388 C STARTED FROM THE POINT (X1,Y1) TOWARDS (X2,Y2)
1389 C CLOSEST TO THE POINT (X1,Y1)
1390 C --------------------------------------------------------------------
1391  SUBROUTINE find_closest_boundary(IEDGE_OUT,X_OUT,Y_OUT,
1392  s iedge0,x1,y1,x2,y2)
1394  INTEGER(GRIDMAN_SP),INTENT(OUT) :: IEDGE_OUT !INDEX OF INTERESECTED EDGE,
1395 
1396  REAL(GRIDMAN_DP),INTENT(OUT) :: X_OUT,Y_OUT !COORDINATES OF THE INTERSECTION POINT
1397  INTEGER(GRIDMAN_SP),INTENT(IN) :: IEDGE0
1398  REAL(GRIDMAN_DP),INTENT(IN) :: X1,Y1 !COORDINATES OF THE STARTING POINT
1399  REAL(GRIDMAN_DP),INTENT(IN) :: X2,Y2 !COORDINATES OF THE TARGET POINT
1400 
1401  REAL(GRIDMAN_DP) :: XE1,YE1,XE2,YE2,XI,YI,D,DMIN,VX,VY
1402  INTEGER(GRIDMAN_SP) :: IEDGE,IPOINT,ICELL1,ICELL2
1403 
1404  ierr=0
1405 
1406  vx=x2-x1
1407  vy=y2-y1
1408  dmin=(x1-x2)**2+(y1-y2)**2
1409  x_out=x2
1410  y_out=y2
1411  iedge_out=-1
1412  DO iedge=1,grid%NEDGES
1413  IF(iedge.EQ.iedge0) cycle
1414  icell1=grid%CELLS(1,iedge)
1415  icell2=grid%CELLS(2,iedge)
1416 C SKIP EDGES WHICH ARE NOT ON THE BOUNDARY
1417  IF(icell1.GT.0.AND.icell2.GT.0) cycle
1418  ipoint=grid%POINTS(1,iedge)
1419  xe1=grid%X(1,ipoint)*grid%UNIT2SI
1420  ye1=grid%X(2,ipoint)*grid%UNIT2SI
1421  ipoint=grid%POINTS(2,iedge)
1422  xe2=grid%X(1,ipoint)*grid%UNIT2SI
1423  ye2=grid%X(2,ipoint)*grid%UNIT2SI
1424  IF(gridman_cross2d(x1,y1,vx,vy,xe1,ye1,xe2,ye2,xi,yi)) THEN
1425  d=(x1-xi)**2+(y1-yi)**2
1426  IF(d.LT.dmin) THEN
1427  dmin=d
1428  iedge_out=iedge
1429  x_out=xi
1430  y_out=yi
1431  END IF
1432  END IF
1433  END DO
1434 
1435  END SUBROUTINE find_closest_boundary
1436 
1437 C --------------------------------------------------------------------
1438 C RETURN TRUE IF POINT (X0,Y0) IS IN ICELL,
1439 C AND FALSE OTHERWISE
1440 C --------------------------------------------------------------------
1441  FUNCTION point_in_cell(X0,Y0,ICELL)
1443  REAL(GRIDMAN_DP),INTENT(IN) :: X0,Y0
1444  INTEGER(GRIDMAN_SP),INTENT(IN) :: ICELL
1445  INTEGER(GRIDMAN_SP) :: IP,IPOINT,N
1446  LOGICAL :: POINT_IN_CELL
1447 
1448  n=0
1449  DO ip=chains%IFIRST(icell),chains%ILAST(icell)
1450  ipoint=chains%IND(ip)
1451  n=n+1
1452  xwork(n)=grid%X(1,ipoint)*grid%UNIT2SI
1453  ywork(n)=grid%X(2,ipoint)*grid%UNIT2SI
1454  END DO
1455  IF( gridman_point_in_polygon(xwork,ywork,n,x0,y0) ) THEN
1456  point_in_cell=.true.
1457  ELSE
1458  point_in_cell=.false.
1459  END IF
1460 
1461  END FUNCTION point_in_cell
1462 
1463 C --------------------------------------------------------------------
1464 C FIND NEXT POINT OF THE TRAJECTORY
1465 C --------------------------------------------------------------------
1466  SUBROUTINE find_next_point(IEDGE1,ICELL1,X1,Y1,
1467  f iedge0,icell0,x0,y0,xn,yn)
1468  USE gridman_lib,ONLY:gridman_cross2d
1469 C INDEX OF THE NEXT EDGE AND CELL
1470  INTEGER(GRIDMAN_SP),INTENT(OUT) :: IEDGE1,ICELL1
1471 C COORDINATES OF THE NEXT POINT
1472  REAL(GRIDMAN_DP),INTENT(OUT) :: X1,Y1
1473 C INDEX OF THE INITIAL EDGE AND CELL
1474  INTEGER(GRIDMAN_SP),INTENT(IN) :: IEDGE0,ICELL0
1475 C COORDINATES OF THE INITIAL POINT
1476  REAL(GRIDMAN_DP),INTENT(IN) :: X0,Y0
1477 C CCORDINATES OF THE NEXT VERTEX OF THE POLYGON
1478  REAL(GRIDMAN_DP),INTENT(IN) :: XN,YN
1479  INTEGER(GRIDMAN_SP) :: IE,IEDGE,IPOINT,IMIN
1480  REAL(GRIDMAN_DP) :: VX,VY,D,DMIN,XE1,YE1,XE2,YE2,XI,YI,
1481  r xmin,ymin
1482  LOGICAL :: LERR
1483 
1484 C DIRECTION VECTOR
1485  vx=xn-x0
1486  vy=yn-y0
1487  imin=-1
1488  dmin=(xn-x0)**2+(yn-y0)**2 !DISTANCE TO THE NEXT VERTEX OF THE POLYGON
1489  lerr=.true.
1490 C CYCLE OVER ALL EDGES OF ICELL0
1491  DO ie=cells%IFIRST(icell0),cells%ILAST(icell0)
1492  iedge=cells%IND(ie)
1493  IF(iedge.EQ.iedge0) cycle
1494  ipoint=grid%POINTS(1,iedge)
1495  xe1=grid%X(1,ipoint)*grid%UNIT2SI
1496  ye1=grid%X(2,ipoint)*grid%UNIT2SI
1497  ipoint=grid%POINTS(2,iedge)
1498  xe2=grid%X(1,ipoint)*grid%UNIT2SI
1499  ye2=grid%X(2,ipoint)*grid%UNIT2SI
1500  IF(gridman_cross2d(x0,y0,vx,vy,xe1,ye1,xe2,ye2,xi,yi)) THEN
1501  d=(x0-xi)**2+(y0-yi)**2
1502  lerr=.false.
1503  IF(d.LT.dmin) THEN
1504 C LOOK FOR INTERSECTION WITH EDGES OF ICELL0 CLOSEST TO X0,Y0
1505  imin=iedge
1506  xmin=xi
1507  ymin=yi
1508  dmin=d
1509  END IF
1510  END IF
1511  END DO
1512  IF(lerr) THEN
1513 C NO INTERSECTION FOUND - ERROR
1514  iedge1=-1
1515  icell1=-1
1516  RETURN
1517  END IF
1518  IF(imin.GT.0) THEN
1519 C TAKE INTERSECTION POINT AS THE NEXT POINT
1520 C UPDATE IEDGE1, ICELL1
1521  iedge1=imin
1522  icell1=grid%CELLS(1,iedge1)
1523  IF(icell1.EQ.icell0) icell1=grid%CELLS(2,iedge1)
1524  x1=xmin
1525  y1=ymin
1526  ELSE
1527 C THEN STAY IN ICELL0, TAKE VERTEX (XN,YN) AS THE NEXT POINT
1528  iedge1=-1
1529  icell1=icell0
1530  x1=xn
1531  y1=yn
1532  END IF
1533 
1534  END SUBROUTINE find_next_point
1535 
1536 C --------------------------------------------------------------------
1537 C ALLOCATE OUTPUT ARRAYS
1538 C --------------------------------------------------------------------
1539  SUBROUTINE allocate_arrays(NPOL,IERR)
1540  INTEGER(GRIDMAN_SP),INTENT(IN) :: NPOL
1541  INTEGER,INTENT(OUT) :: IERR
1542  INTEGER :: ST
1543 
1544  ierr=0
1545 
1546  ALLOCATE(icell_pol(npol),iedge_pol(npol),indseg(npol),
1547  w x_pol(npol),y_pol(npol),stat=st)
1548  IF(st.NE.0) THEN
1549  WRITE(gridman_unit,*)
1550  w "ERROR in GRIDMAN_GRID2D_POLYGON_TRAJECTORY: ",
1551  w "cannot allocate temporary arrays"
1552  WRITE(gridman_unit,*) " NPOL ",npol
1553  ierr=200
1554  RETURN
1555  END IF
1556 
1557  END SUBROUTINE allocate_arrays
1558 
1559 C --------------------------------------------------------------------
1560 C ALLOCATE BUFFER ARRAYS XWORK, YWORK
1561 C --------------------------------------------------------------------
1562  SUBROUTINE allocate_work(CHAINS,IERR)
1563  TYPE(gridman_indlist) :: CHAINS
1564  INTEGER,INTENT(OUT) :: IERR
1565  INTEGER(GRIDMAN_SP) :: N,IC,ST
1566 C NWORK = MAXIMIM NUMBER OF POINTS IN ONE CELL
1567  nwork=0
1568  DO ic=1,chains%N
1569  n=chains%ILAST(ic)-chains%IFIRST(ic)+1
1570  IF(n.GT.nwork) nwork=n
1571  END DO
1572  ALLOCATE(xwork(nwork),ywork(nwork),stat=st)
1573  IF(st.NE.0) THEN
1574  WRITE(gridman_unit,*)
1575  w "ERROR in GRIDMAN_GRID2D_POLYGON_TRAJECTORY: ",
1576  w "cannot allocate XWORK, YWORK"
1577  WRITE(gridman_unit,*) " NWORK ", nwork
1578  ierr=200
1579  RETURN
1580  END IF
1581  END SUBROUTINE allocate_work
1582 
1583 C --------------------------------------------------------------------
1584 C DEALLOCATE TEMPORARY ARRAYS
1585 C --------------------------------------------------------------------
1586  SUBROUTINE deallocate_local(IERR)
1587  INTEGER,INTENT(OUT) :: IERR
1588  INTEGER :: ST(4),IERR0
1589 
1590  st=0
1591  IF(ALLOCATED(xwork)) DEALLOCATE(xwork,stat=st(1))
1592  IF(ALLOCATED(xwork)) DEALLOCATE(ywork,stat=st(2))
1593  CALL gridman_indlist_deallocate(chains,ierr0)
1594  IF(ierr0.NE.0) st(3)=1
1595  CALL gridman_indlist_deallocate(cells,ierr0)
1596  IF(ierr0.NE.0) st(4)=1
1597  IF(any(st.NE.0)) THEN
1598  ierr=-200
1599  WRITE(gridman_unit,*)
1600  w "ERROR in GRIDMAN_GRID2D_POLYGON_TRAJECTORY: ",
1601  w "problems with deallocation of temporary arrays"
1602  END IF
1603  END SUBROUTINE deallocate_local
1604 
1605  END SUBROUTINE gridman_grid2d_polygon_trajectory
subroutine find_closest_edge(IEDGE_OUT, X_OUT, Y_OUT, X1, Y1, X2, Y2)
Definition: cut.f:1351
logical function gridman_intersect2d(X11, Y11, X12, Y12, X21, Y21, X22, Y22, XI, YI)
Intersection of two intervals on a plane.
Definition: geom.f:167
logical function gridman_cross2d(X0, Y0, V, U, X1, Y1, X2, Y2, XI, YI)
Intersection of "particle trajectory" with an interval (2D)
Definition: geom.f:108
integer, save, public gridman_unit
Index of the standard output unit.
Definition: gridman.f:116
integer, parameter, public gridman_dp
Kind parameter for real numbers.
Definition: gridman.f:93
Explicit interfaces to GRIDMAN subroutines and functions.
Definition: gridman.f:251
subroutine gridman_grid2d_polygon_trajectory(NPOL, NPEDGE, ICELL_POL, IEDGE_POL, X_POL, Y_POL, INDVERT, INDSEG, XP, YP, NP, GRID, IERR)
Definition: cut.f:1002
subroutine check_polygon(XP, YP, NP, IERR)
Definition: cut.f:796
subroutine gridman_grid_allocate(GRID, TYPE, NEDGES, NPOINTS, NCELLS, IERR, NEDGEINDEX, NCELLINDEX)
Allocate GRIDMAN_GRID object.
Definition: grid1.f:30
subroutine gridman_grid2d_chains(GRID, CHAINS, IERR)
Find closed chain of points which form each cell.
Definition: grid2d.f:266
subroutine gridman_grid2d_cut(CUTGRID, GRID, XP, YP, NP, LEX, IERR)
Select part of a 2D grid cut by polygon.
Definition: cut.f:38
logical function gridman_close2interval2d(X1, Y1, X2, Y2, X, Y, TOL)
Find if point is close to the interval within prescribed tolerance.
Definition: geom.f:325
subroutine gridman_grid_cells(EDGES, GRID, IERR)
Create a list of edges which belong to each cell.
Definition: grid2.f:177
subroutine gridman_grid2d_check(GRID, RES, IERR)
Check correctness of the 2D grid object.
Definition: grid2d.f:37
subroutine gridman_index_transform(INDEX2, INDEX1, IMAP12, N12, IERR)
Transform indices of elements - IND(0,:)
Definition: index.f:788
subroutine gridman_indlist_deallocate(INDLIST, IERR)
Deallocate list of indices.
Definition: indlist.f:106
Data-type which describes a grid as a set of edges, methods in grid.f.
Definition: gridman.f:168
subroutine gridman_grid_deallocate(GRID, IERR)
Deallocate grid object.
Definition: grid1.f:184
subroutine gridman_index_allocate(INDEX, NINDEX, NELEMENTS, IERR)
Allocate index object.
Definition: index.f:28
logical function gridman_point_in_polygon(XP, YP, NP, X0, Y0)
Find if point lies inside a closed polygon.
Definition: geom.f:259
subroutine find_closest_boundary(IEDGE_OUT, X_OUT, Y_OUT, IEDGE0, X1, Y1, X2, Y2)
Definition: cut.f:1393
Data-type which describes lists of elements with variable number of indices for each element...
Definition: gridman.f:225
Definition of data types, global constants and variables.
Definition: gridman.f:83
integer, parameter, public gridman_sp
Kind parameter for integer numbers.
Definition: gridman.f:95