source: lmdz_wrf/trunk/tools/module_scientific.f90 @ 2341

Last change on this file since 2341 was 2341, checked in by lfita, 6 years ago

Working version of 'range_faces' with homogenization of 'range'

File size: 250.3 KB
Line 
1MODULE module_scientific
2! Module of the scientific function/subroutines
3 
4!!!!!!! Functions & subroutines
5! all_polygons_properties: Subroutine to determine the properties of all polygons in a 2D field:
6! borders_matrixL: Subroutine to provide the borders of a logical array (interested in .TRUE.)
7! coincidence_all_polys: Subtourine to determine which is the coincident polygon when a boolean polygon is provided
8!   to a map of integer polygons
9! coincidence_all_polys_area: Subtourine to determine which is the coincident polygon when a boolean polygon is provided
10!   to a map of integer polygons filtrered by a minimal area
11! coincidence_poly: Subtourine to determine which is the coincident polygon when a boolean polygon is provided
12!   to a map of integer polygons
13! coincidence_poly_area: Subtourine to determine which is the coincident polygon when a boolean polygon is provided
14!   to a map of integer polygons filtrered by a minimal area
15! coincident_gridsin2D: Subroutine to determine which lists of 2D gridsin points of an A list are also found in a B list
16! coincident_list_2Dcoords: Subroutine to determine which 2D points of an A list are also found in a B list
17! clean_polygons: Subroutine to clean polygons from non-used paths, polygons only left as path since they are inner path of a hole
18! coincident_polygon: Subroutine to provide the intersection polygon between two polygons
19! distanceRK: Function to provide the distance between two points
20! FindMinimumR_K*: Function returns the location of the minimum in the section between Start and End.
21! fill3DI_2Dvec: Subroutine to fill a 3D integer matrix from a series of indices from a 2D matrix
22! fill3DR_2Dvec: Subroutine to fill a 3D float matrix from a series of indices from a 2D matrix
23! grid_within_polygon: Subroutine to determine which grid cells from a matrix lay inside a polygon
24! grid_spacepercen: Subroutine to compute the space-percentages of a series of grid cells (B) which lay inside another
25!   series of grid-cells (A)
26! grid_spacepercen_providing_polys: Subroutine to compute the space-percentages of a series of grid cells (B) which lay inside another
27!   series of grid-cells (A) providing coincident polygons
28! grid_spacepercen_within_reg: Subroutine to compute the percentage of grid space of a series of grid cells which are encompassed
29!   by a polygon
30! grid_spacepercen_within_reg_providing_polys: Subroutine to compute the percentage of grid space of a series of grid
31!   cells which are encompassed by a polygon providing coordinates of the resultant polygons
32! gridpoints_InsidePolygon: Subroutine to determine if a series of grid points are inside a polygon
33!   following ray casting algorithm
34! Heron_area_triangle: Subroutine to compute area of a triangle using Heron's formula
35! intersectfaces: Subroutine to provide if two faces of two polygons intersect
36! intersection_2Dlines: Subroutine to provide the intersection point between two lines on the plane using Cramer's method
37! join_polygon: Subroutine to join two polygons
38! look_clockwise_borders: Subroutine to look clock-wise for a next point within a collection of borders
39!   (limits of a region)
40! multi_index_mat2DI: Subroutine to provide the indices of the different locations of a value inside a 2D integer matrix
41! multi_index_mat3DI: Subroutine to provide the indices of the different locations of a value inside a 3D integer matrix
42! multi_index_mat4DI: Subroutine to provide the indices of the different locations of a value inside a 4D integer matrix
43! multi_index_mat2DRK: Subroutine to provide the indices of the different locations of a value inside a 2D RK matrix
44! multi_index_mat3DRK: Subroutine to provide the indices of the different locations of a value inside a 3D RK matrix
45! multi_index_mat4DRK: Subroutine to provide the indices of the different locations of a value inside a 4D RK matrix
46! multi_spaceweightstats_in1DRKno_slc3v3: Subroutine to compute an spatial statistics value from a 1D RK matrix without
47!   running one into a matrix of 3-variables slices of rank 3 using spatial weights
48! multi_spaceweightstats_in2DRKno_slc3v3: Subroutine to compute an spatial statistics value from a 2D RK matrix without
49!   running one into a matrix of 3-variables slices of rank 3 using spatial weights
50! multi_spaceweightstats_in3DRK3_slc3v3: Subroutine to compute an spatial statistics value from a 3D RK matrix using
51!   3rd dimension as running one into a matrix of 3-variables slices of rank 3 using spatial weights
52! multi_spaceweightstats_in3DRK3_slc3v4: Subroutine to compute an spatial statistics value from a 3D RK matrix using
53!   3rd dimension as running one into a matrix of 3-variables slices of rank 4 using spatial weights
54! NcountR: Subroutine to count real values
55! paths_border: Subroutine to search the paths of a border field.
56! path_properties: Subroutine to determine the properties of a path
57! percentiles_R_K*D: Subroutine to compute the percentiles of a *D R_K array along given set of axis
58! point_in_face: Function to determine if a given point is on a face of a polygon
59! point_inside: Function to determine if a given point is inside a polygon providing its sorted vertices
60! poly_has_point: Function to determine if a polygon has already a given point as one of its vertex
61! polygon_properties: Subroutine to determine the properties of a polygon (as .TRUE. matrix)
62! polygons: Subroutine to search the polygons of a border field. FORTRAN based. 1st = 1!
63! polygons_t: Subroutine to search the polygons of a temporal series of boolean fields. FORTRAN based. 1st = 1!
64! poly_overlap_tracks: Subroutine to determine tracks of a series of consecutive 2D field with polygons using
65!   maximum overlaping/coincidence
66! PrintQuantilesR_K: Subroutine to print the quantiles of values REAL(r_k)
67! poly_overlap_tracks_area: Subroutine to determine tracks of a series of consecutive 2D field with polygons using
68!   maximum overlaping/coincidence filtrered by a minimal area
69! poly_overlap_tracks_area_ascii: Subroutine to determine tracks of a series of consecutive 2D field with polygons using maximum
70!   overlaping/coincidence filtrered by a minimal area writting theoutput on an ASCII file (memory limitations)
71! quantilesR_K: Subroutine to provide the quantiles of a given set of values of type real 'r_k'
72! rand_sample: Subroutine to randomly sample a range of indices
73! read_finaltrack_ascii: Subroutine to read the final trajectories from an ASCII file
74! read_overlap_single_track_ascii: Subroutine to read the values for a given trajectory
75! read_overlap_polys_ascii: Subroutine to read from an ASCII file the associated polygons at a given time-step
76! read_overlap_tracks_ascii: Subroutine to write to an ASCII the polygons associated to a trajectory at a given time step
77! reconstruct_matrix: Subroutine to reconstruct a 2D matrix from a pair of syncronized vectors with the positions on x
78!   and y coordinates
79! runmean_F1D: Subroutine fo computing the running mean of a given set of float 1D values
80! shoelace_area_polygon: Computing the area of a polygon using sholace formula
81! sort_polygon: Subroutine to sort a polygon using its center as average of the coordinates and remove duplicates
82! SortR_K*: Subroutine receives an array x() r_K and sorts it into ascending order.
83! spacepercen: Subroutine to compute the space-percentages of a series of grid cells (B) into another series of grid-cells (A)
84! spaceweightstats: Subroutine to compute an spatial statistics value from a matrix B into a matrix A using weights
85! StatsR_K: Subroutine to provide the minmum, maximum, mean, the quadratic mean, and the standard deviation of a
86!   series of r_k numbers
87! SwapR_K*: Subroutine swaps the values of its two formal arguments.
88! unique_matrixRK2D: Subroutine to provide the unique values within a 2D RK matrix
89! write_finaltrack_ascii: Subroutine to read the final trajectories into an ASCII file
90! write_overlap_polys_ascii: Subroutine to write to an ASCII file the associated polygons at a given time-step
91! write_overlap_tracks_ascii: Subroutine to write to an ASCII the polygons associated to a trajectory at a given time step
92
93!!! *Functions/Subroutines to sort values adpated. The method used is usually referred to as "selection" method.
94! from: http://www.cs.mtu.edu/~shene/COURSES/cs201/NOTES/chap08/sorting.f90
95
96  USE module_definitions
97  USE module_generic
98
99  CONTAINS
100
101  SUBROUTINE fill3DI_2Dvec(matind, inmat, id1, id2, od1, od2, od3, outmat)
102! Subroutine to fill a 3D integer matrix from a series of indices from a 2D matrix
103
104    IMPLICIT NONE
105
106    INTEGER, INTENT(in)                                  :: id1, id2, od1, od2, od3
107    INTEGER, DIMENSION(id1,id2), INTENT(in)              :: inmat
108    INTEGER, DIMENSION(od1,od2), INTENT(in)              :: matind
109    INTEGER, DIMENSION(od1,od2,od3), INTENT(out)         :: outmat
110
111! Local
112    INTEGER                                              :: i, j
113
114!!!!!!! Variables
115! matind: equivalence on the 2D space of the location in inmat
116! inmat: values of the input matrix (1Dvec, time)
117! id1/2: dimensions of the input matrix
118! od1/3: dimensions of the output matrix
119! outmat: output matrix
120! NOTE: id2 == od3
121
122    fname = 'fill3DR_2Dvec'
123
124    DO i=1, od1
125      DO j=1, od2
126        IF (matind(i,j) /= -1) THEN
127          outmat(i,j,:) = inmat(matind(i,j),:)
128        ELSE
129          outmat(i,j,:) = fillvalI
130        END IF
131      END DO
132    END DO
133
134  END SUBROUTINE fill3DI_2Dvec
135
136  SUBROUTINE fill3DR_2Dvec(matind, inmat, id1, id2, od1, od2, od3, outmat)
137! Subroutine to fill a 3D float matrix from a series of indices from a 2D matrix
138
139    IMPLICIT NONE
140
141    INTEGER, INTENT(in)                                  :: id1, id2, od1, od2, od3
142    REAL(r_k), DIMENSION(id1,id2), INTENT(in)            :: inmat
143    INTEGER, DIMENSION(od1,od2), INTENT(in)              :: matind
144    REAL(r_k), DIMENSION(od1,od2,od3), INTENT(out)       :: outmat
145
146! Local
147    INTEGER                                              :: i, j
148
149!!!!!!! Variables
150! matind: equivalence on the 2D space of the location in inmat
151! inmat: values of the input matrix (1Dvec, time)
152! id1/2: dimensions of the input matrix
153! od1/3: dimensions of the output matrix
154! outmat: output matrix
155! NOTE: id2 == od3
156
157    fname = 'fill3DR_2Dvec'
158
159    DO i=1, od1
160      DO j=1, od2
161        IF (matind(i,j) /= -1) THEN
162          outmat(i,j,:) = inmat(matind(i,j),:)
163        ELSE
164          outmat(i,j,:) = fillval64
165        END IF
166      END DO
167    END DO
168
169  END SUBROUTINE fill3DR_2Dvec
170
171  SUBROUTINE reconstruct_matrix(vectorXpos, vectorYpos, dvec, Xmin, Xmax, Ymin, Ymax, dmatx, dmaty,   &
172    matProj, maxdiff, matind, matX, matY, matdiff)
173! Subroutine to reconstruct a 2D matrix from a pair of syncronized vectors with the positions on x
174!   and y coordinates
175
176    IMPLICIT NONE
177
178    INTEGER, INTENT(in)                                  :: dvec, dmatx, dmaty
179    REAL(r_k), DIMENSION(dvec), INTENT(in)               :: vectorXpos, vectorYpos
180    REAL(r_k), INTENT(in)                                :: Xmin, Xmax, Ymin, Ymax, maxdiff
181    CHARACTER(len=50), INTENT(in)                        :: matPRoj
182    INTEGER, DIMENSION(dmatx, dmaty), INTENT(out)        :: matind
183    REAL(r_k), DIMENSION(dmatx, dmaty), INTENT(out)      :: matX, matY, matdiff
184
185! Local
186    INTEGER                                              :: i,j,iv, idiff, jdiff
187    REAL(r_k)                                            :: ddx, ddy, Xpos, Ypos, mindiff
188    REAL(r_k), DIMENSION(dmatx,dmaty)                    :: diff
189    REAL(r_k)                                            :: nXpos, xXpos, nYpos, xYpos
190    INTEGER, DIMENSION(2)                                :: mindiffloc
191    CHARACTER(LEN=50)                                    :: RSa, RSb
192
193!!!!!!! Variables
194! vectorXpos, vectorYpos: syncronized vectors with the x,y coordinates from which the matrix will be reconstructed
195! dvec: quantitiy of coordinates to use
196! Xmin,Xmax,Ymin,Ymax: Location range of the matrix to be reconstructed
197! maxdiff: Authorized maximum distance between matrix location and vector location
198! dmatx, dmaty: Size in grid points of the matrix to be reconstructed
199! matProj: Assumed projection of the values of the matrix
200!   'latlon': regular lat/lon projection
201! matind: matrix with the correspondant indiced from the vector of positions
202! matX, matY: matrix with the coordinates of the elements of the matrix
203! matdiff: matrix with the differences at each grid point
204
205    fname = 'reconstruct_matrix'
206
207    matind = -oneRK
208    matdiff = -oneRK
209
210    nXpos = MINVAL(vectorXpos)
211    xXpos = MAXVAL(vectorXpos)
212    nYpos = MINVAL(vectorYpos)
213    xYpos = MAXVAL(vectorYpos)
214    PRINT *, 'Limits of the positions to localize in a matrix: longitudes:', nXpos,  &
215     ' ,',xXpos, ' latitudes:', nYpos, ' ,', xYpos
216
217    Projection: SELECT CASE(TRIM(matProj))
218
219    CASE('latlon')
220      ! Resolution along matrix axes
221      ddx = (Xmax - Xmin)/(dmatx-1)
222      ddy = (Ymax - Ymin)/(dmaty-1)
223
224      ! Filling matrix positions
225      DO i=1,dmatx
226        Xpos = Xmin + ddx*(i-1)
227        DO j=1,dmaty
228          Ypos = Ymin + ddy*(j-1)
229          matX(i,j) = Xpos
230          matY(i,j) = Ypos
231        END DO
232      END DO
233
234    CASE DEFAULT
235      msg = "Projection of matrix '" // TRIM(matProj) // "' not ready " // CHAR(10) //                &
236        "  Available ones: 'latlon'"
237      CALL ErrMsg(msg, fname, -1)
238    END SELECT Projection
239
240    ! Let's do it properly...
241    DO iv=1,dvec
242      diff = SQRT((matX - vectorXpos(iv))**2 + (matY - vectorYpos(iv))**2)
243      mindiffloc = MINLOC(diff)
244      mindiff = MINVAL(diff)
245      IF (mindiff > maxdiff) THEN
246        PRINT *,'  vectorXpos:', vectorXpos(iv), 'vectorYpos:', vectorYpos(iv)
247        !PRINT *,'  Xpos:', Xpos, 'Ypos:', Ypos
248        WRITE(RSa, '(f20.10)')mindiff
249        WRITE(RSb, '(f20.10)')maxdiff
250        msg = 'Difference: ' // TRIM(RSa) // ' overpasses the maximum authorized distance: ' //   &
251          TRIM(RSb)
252        CALL ErrMsg(msg, fname, -1)
253      ELSE
254        i = mindiffloc(1)
255        j = mindiffloc(2)
256        matind(i,j) = iv
257        matdiff(i,j) = mindiff
258      END IF
259    END DO
260
261    RETURN
262
263  END SUBROUTINE reconstruct_matrix
264
265  SUBROUTINE read_finaltrack_ascii(funit, dt, itrack, ftrack)
266! Subroutine to read the final trajectories from an ASCII file
267
268    IMPLICIT NONE
269
270    INTEGER, INTENT(in)                                  :: funit, dt, itrack
271    REAL(r_k), DIMENSION(5,dt), INTENT(out)              :: ftrack
272
273! Local
274    INTEGER                                              :: i, j, it
275    LOGICAL                                              :: found
276
277!!!!!!! Variables
278! funit: unit where to write the trajectory
279! dt: number of time-steps
280! itrack: trajectory to read the values
281! ftrack: values of the trajectory
282
283    fname = 'read_finaltrack_ascii'
284
285    ftrack = 0.
286   
287    REWIND(funit)
288
289    it = 1
290    DO WHILE (.NOT.found)
291
292      READ(funit,10)ftrack(1,1), Str1, ((ftrack(i,j),Str1,i=2,5),Str1,j=1,dt)
293      IF (INT(ftrack(1,1)) == itrack) THEN
294        ftrack(1,2:dt) = ftrack(1,1)
295        found = .TRUE.
296      END IF
297
298      ! Just in case
299      IF (it >= dt) found = .TRUE.
300
301    END DO
302
303    RETURN
304
305 10 FORMAT(I10000000,1x,A1,1x,10000000(4(F20.10,A1),A1))
306
307  END SUBROUTINE read_finaltrack_ascii
308
309  SUBROUTINE write_finaltrack_ascii(funit, dt, ftrack)
310! Subroutine to write the final trajectories into an ASCII file
311
312    IMPLICIT NONE
313
314    INTEGER, INTENT(in)                                  :: funit, dt
315    REAL(r_k), DIMENSION(5,dt), INTENT(in)               :: ftrack
316
317! Local
318    INTEGER                                              :: i, j
319
320!!!!!!! Variables
321! funit: unit where to write the trajectory
322! dt: number of time-steps
323! ftrack: values of the trajectory
324
325    fname = 'write_finaltrack_ascii'
326    WRITE(funit,10)INT(ftrack(1,1)), ';', ((ftrack(i,j), ',', i=2,5), ':', j=1,dt)
327
328    RETURN
329
330 10 FORMAT(I10,1x,A1,1x,10000000(4(F20.10,A1),A1))
331
332  END SUBROUTINE write_finaltrack_ascii
333
334  SUBROUTINE read_overlap_single_track_ascii(funit, dt, Nxp, Nxtr, itrack, strack)
335! Subroutine to read the values for a given trajectory
336
337    IMPLICIT NONE
338
339    INTEGER, INTENT(in)                                  :: funit, dt, Nxp, Nxtr, itrack
340    REAL(r_k), DIMENSION(5,Nxp,dt), INTENT(out)          :: strack
341
342! Local
343    INTEGER                                              :: i,j,k,l
344    INTEGER                                              :: read_it, itt, it, Ntrcks
345    INTEGER, DIMENSION(Nxp)                              :: Npindep
346    LOGICAL                                              :: looking
347    REAL(r_k), DIMENSION(5,Nxp,Nxtr)                     :: trcks
348
349!!!!!!! Variables
350! funit: unit from where retrieve the values of the trajectory
351! dt: time-dimension
352! Nxp: maximum allowed number of polygons per time-step
353! Nxp: maximum allowed number of trajectories
354! itrack: trajectory Id to look for
355! strack: Values for the given trajectory
356
357    fname = 'read_overlap_single_track_ascii'
358
359    strack = 0.
360
361    REWIND(funit)
362
363    looking = .TRUE.
364    itt = 0
365    it = 1
366    DO WHILE (looking)
367      READ(funit,5,END=100)Str10, read_it
368
369      READ(funit,*)Ntrcks
370      DO i=1, Ntrcks
371        READ(funit,10)l, Str1, Npindep(i), Str1, ((trcks(k,j,i),Str1,k=1,5),Str1,j=1,Npindep(i))
372      END DO
373
374      ! There is the desired trajectory at this time-step?
375      IF (ANY(INT(trcks(1,1,:)) == itrack)) THEN
376        itt = itt + 1
377        DO i=1, Ntrcks
378          IF (INT(trcks(1,1,i)) == itrack) THEN
379            DO j=1, Npindep(i)
380              strack(:,j,it) = trcks(:,j,i)
381            END DO
382          END IF
383        END DO
384      ELSE
385        ! It trajectory has already been initialized this is the end
386        IF (itt > 0) looking = .FALSE.
387      END IF
388
389      ! Just in case... ;)
390      IF (read_it >= dt) looking = .FALSE.
391      it = it + 1
392
393      IF (it > dt) looking = .FALSE.
394
395    END DO
396
397 100 CONTINUE
398
399    RETURN
400
401  5 FORMAT(A10,1x,I4)
402 10 FORMAT(I4,1x,A1,I4,1x,A1,1x,1000000(5(F20.10,A1),A1))
403
404  END SUBROUTINE read_overlap_single_track_ascii
405
406  SUBROUTINE read_overlap_tracks_ascii(funit, tstep, Nxp, Ntrcks, trcks)
407! Subroutine to write to an ASCII the polygons associated to a trajectory at a given time step
408
409    IMPLICIT NONE
410
411    INTEGER, INTENT(in)                                  :: funit, tstep, Nxp
412    INTEGER, INTENT(out)                                 :: Ntrcks
413    REAL(r_k), DIMENSION(5,Nxp,Nxp), INTENT(out)         :: trcks
414
415! Local
416    INTEGER                                              :: i, j, k, l, Npindep
417    INTEGER                                              :: read_it
418
419!!!!!!! Variables
420! funit: unit where to write the file
421! tstep: time-step to write the trajectories
422! Nxp: maximum number of polygons per time-step
423! Nrtcks: Number of trajectories of the given time-step
424! trcks: trajectories
425
426    fname = 'read_overlap_tracks_ascii'
427
428    Ntrcks = 0
429    trcks = 0
430
431    READ(funit,5)Str10, read_it
432
433    IF (read_it /= tstep) THEN
434      WRITE(numSa,'(I4)')read_it
435      WRITE(numSb,'(I4)')tstep
436      msg = 'File time-step;' // TRIM(numSa) // ' does not coincide with the one from program:' //    &
437        TRIM(numSb)
438    END IF
439
440    READ(funit,*)Ntrcks
441    DO i=1, Ntrcks
442      READ(funit,10)l, Str1, Npindep, Str1, ((trcks(k,j,i),Str1,k=1,5),Str1,j=1,Npindep)
443    END DO
444
445    RETURN
446
447  5 FORMAT(A10,1x,I4)
448 10 FORMAT(I4,1x,A1,I4,1x,A1,1x,1000000(5(F20.10,A1),A1))
449
450  END SUBROUTINE read_overlap_tracks_ascii
451
452  SUBROUTINE write_overlap_tracks_ascii(funit, tstep, Nxp, Ntrcks, trcks)
453! Subroutine to write to an ASCII the polygons associated to a trajectory at a given time step
454
455    IMPLICIT NONE
456
457    INTEGER, INTENT(in)                                  :: funit, tstep, Nxp, Ntrcks
458    REAL(r_k), DIMENSION(5,Nxp,Ntrcks)                   :: trcks
459
460! Local
461    INTEGER                                              :: i, j, k, ii, Npindep, Nrealtracks
462
463!!!!!!! Variables
464! funit: unit where to write the file
465! tstep: time-step to write the trajectories
466! Nxp: maximum number of polygons per time-step
467! Nrtcks: Number of trajectories of the given time-step
468! trcks: trajectories
469
470    fname = 'write_overlap_tracks_ascii'
471
472    WRITE(funit,5)'time-step:', tstep
473
474    ! Looking for the non-zero trajectories
475    Nrealtracks = 0
476    DO i=1, Ntrcks
477      Npindep = COUNT(trcks(2,:,i) /= zeroRK)
478      IF (Npindep /= 0) Nrealtracks = Nrealtracks + 1
479    END DO
480    WRITE(funit,*)Nrealtracks
481
482    ! Only writting the trajectories with values
483    ii = 1
484    DO i=1, Ntrcks
485      Npindep = COUNT(trcks(2,:,i) /= zeroRK)
486      IF (Npindep /= 0) THEN
487        WRITE(funit,10)ii,';', Npindep, ';', ((trcks(k,j,i),',',k=1,5),':',j=1,Npindep)
488        ii = ii + 1
489      END IF
490    END DO
491
492    RETURN
493
494  5 FORMAT(A10,1x,I4)
495 10 FORMAT(I4,1x,A1,I4,1x,A1,1x,1000000(5(F20.10,A1),A1))
496
497  END SUBROUTINE write_overlap_tracks_ascii
498
499  SUBROUTINE read_overlap_polys_ascii(funit, tstep, Nxp, Nindep, SpIndep, NpIndep, pIndep)
500! Subroutine to read from an ASCII file the associated polygons at a given time-step
501
502    IMPLICIT NONE
503
504    INTEGER, INTENT(in)                                  :: funit, tstep, Nxp
505    INTEGER, INTENT(out)                                 :: Nindep
506    INTEGER, DIMENSION(Nxp), INTENT(out)                 :: SpIndep, NpIndep
507    INTEGER, DIMENSION(Nxp,Nxp), INTENT(out)             :: pIndep
508
509! Local
510    INTEGER                                              :: i, j, k
511    INTEGER                                              :: read_it
512
513!!!!!!! Variables
514! funit: unit associated to the file
515! tstep: time-step of the values
516! Nxp: allowed maximum numbe of polygons per time-step
517! Nindpe: Number of independent polygons at this time-step
518! SpIndep: Associated polygon to the independent one from the previous time-step
519! NpIndep: Number of associated polygons to the independent time-step
520! pIndep: polygons associated to a given independent polygon
521
522    fname = 'read_overlap_polys_ascii'
523
524    Nindep = 0
525    SpIndep = 0
526    NpIndep = 0
527
528    READ(funit,5)Str10, read_it
529
530    IF (read_it /= tstep) THEN
531      WRITE(numSa,'(I4)')read_it
532      WRITE(numSb,'(I4)')tstep
533      msg = 'File time-step;' // TRIM(numSa) // ' does not coincide with the one from program:' //    &
534        TRIM(numSb)
535    END IF
536
537    READ(funit,*)Nindep
538    DO i=1, Nindep
539      READ(funit,10) k, Str1, SpIndep(i), Str1, NpIndep(i), Str1, (pIndep(i,j), Str1, j=1,NpIndep(i))
540    END DO
541
542    RETURN
543
544  5 FORMAT(A10,1x,I4)
545 10 FORMAT(I4,1x,A1,1x,I4,1x,A1,1x,I4,A1,1x,100000(I4,A1))
546
547  END SUBROUTINE read_overlap_polys_ascii
548
549  SUBROUTINE write_overlap_polys_ascii(funit, tstep, Nxp, Nindep, SpIndep, NpIndep, pIndep)
550! Subroutine to write into an ASCII file the associated polygons at a given time-step
551
552    IMPLICIT NONE
553
554    INTEGER, INTENT(in)                                  :: funit, tstep, Nxp, Nindep
555    INTEGER, DIMENSION(Nindep), INTENT(in)               :: SpIndep, NpIndep
556    INTEGER, DIMENSION(Nindep,Nxp), INTENT(in)           :: pIndep
557
558! Local
559    INTEGER                                              :: i, j
560
561!!!!!!! Variables
562! funit: unit associated to the file
563! tstep: time-step of the values
564! Nxp: allowed maximum numbe of polygons per time-step
565! Nindpe: Number of independent polygons at this time-step
566! SpIndep: Associated polygon to the independent one from the previous time-step
567! NpIndep: Number of associated polygons to the independent time-step
568! pIndep: polygons associated to a given independent polygon
569
570    fname = 'write_overlap_polys_ascii'
571
572    WRITE(funit,5)'time-step:', tstep
573    WRITE(funit,*)Nindep, ' ! Number of independent polygons'
574    DO i=1, Nindep
575      WRITE(funit,10) i, ';', SpIndep(i), ';', NpIndep(i), ':', (pIndep(i,j), ',', j=1,NpIndep(i))
576    END DO
577
578    RETURN
579
580  5 FORMAT(A10,1x,I4)
581 10 FORMAT(I4,1x,A1,1x,I4,1x,A1,1x,I4,A1,1x,100000(I4,A1))
582
583  END SUBROUTINE write_overlap_polys_ascii
584
585  SUBROUTINE poly_overlap_tracks_area_ascii(dbg, compute, dx, dy, dt, minarea, inNallpolys, allpolys, &
586    ctrpolys, areapolys, Nmaxpoly, Nmaxtracks, methodmulti)
587! Subroutine to determine tracks of a series of consecutive 2D field with polygons using maximum
588!   overlaping/coincidence filtrered by a minimal area writting theoutput on an ASCII file (memory limitations)
589
590    IMPLICIT NONE
591
592    LOGICAL, INTENT(in)                                  :: dbg
593    CHARACTER(LEN=*), INTENT(in)                         :: compute, methodmulti
594    INTEGER, INTENT(in)                                  :: dx, dy, dt, Nmaxpoly, Nmaxtracks
595    INTEGER, DIMENSION(dt), INTENT(in)                   :: inNallpolys
596    INTEGER, DIMENSION(dx,dy,dt), INTENT(in)             :: allpolys
597    REAL(r_k), INTENT(in)                                :: minarea
598    REAL(r_k), DIMENSION(2,Nmaxpoly,dt), INTENT(in)      :: ctrpolys
599    REAL(r_k), DIMENSION(Nmaxpoly,dt), INTENT(in)        :: areapolys
600
601! Local
602    INTEGER                                              :: i, j, ip, it, iip, itt, iit
603    INTEGER                                              :: fprevunit, ftrackunit, ftrunit, ierr, ios
604    LOGICAL                                              :: file_exist, dooverlap, dotracks, doftracks
605    REAL(r_k), DIMENSION(Nmaxpoly)                       :: Aprevpolys, Acurrpolys
606    REAL(r_k), DIMENSION(2,Nmaxpoly)                     :: Cprevpolys, Ccurrpolys
607    INTEGER, DIMENSION(dx,dy)                            :: meetpolys, searchpolys
608    INTEGER, DIMENSION(Nmaxpoly)                         :: coincidencies
609    INTEGER, DIMENSION(Nmaxpoly)                         :: prevID, currID
610    REAL(r_k), DIMENSION(5,Nmaxpoly,Nmaxtracks,2)        :: tracks
611    REAL(r_k), DIMENSION(5,dt)                           :: finaltracks
612    INTEGER, DIMENSION(:), ALLOCATABLE                   :: coins
613    INTEGER, DIMENSION(:,:), ALLOCATABLE                 :: coinsNpts
614    INTEGER                                              :: Nmeet, Nsearch, Nindep
615    INTEGER, DIMENSION(2)                                :: Nindeppolys, Npolystime
616    CHARACTER(len=5)                                     :: NcoinS
617    INTEGER, DIMENSION(Nmaxpoly,Nmaxpoly,2)              :: polysIndep
618    INTEGER, DIMENSION(Nmaxpoly,2)                       :: NpolysIndep
619    INTEGER, DIMENSION(Nmaxpoly,2)                       :: SpolysIndep
620    INTEGER                                              :: iindep, iiprev
621    INTEGER                                              :: Nprev, NNprev, Ntprev
622    LOGICAL                                              :: Indeppolychained
623    INTEGER                                              :: itrack, ictrack
624    INTEGER                                              :: ixp, iyp, ttrack
625    INTEGER, DIMENSION(2)                                :: Ntracks
626    INTEGER                                              :: idtrack, maxtrack
627    REAL(r_k), DIMENSION(5,Nmaxpoly,dt)                  :: singletrack
628    REAL(r_k)                                            :: totArea, dist, mindist, maxarea, areai
629
630!!!!!!! Variables
631! dx,dy,dt: space/time dimensions
632! compute: how to copmute
633!   'scratch': everything from the beginning
634!   'continue': skipt that parts which already have the ascii file written
635! inNallpolys: Vector with the original number of polygons at each time-step
636! allpolys: Series of 2D field with the polygons
637! minarea: minimal area (in same units as areapolys) to perform the tracking
638! ctrpolys: center of the polygons
639! areapolys: area of the polygons
640! Nmaxpoly: Maximum possible number of polygons
641! Nmaxtracks: maximum number of tracks
642! methodmulti: methodology to follow when multiple polygons are given for the same track
643!   'mean': get coordinates from the areal-weighted mean of the centers of the given polygons and their areas
644!   'largest': get the coorindates of the largest polygon
645!   'closest': get the coordinates of the closest polygon
646
647    fname = 'poly_overlap_tracks_area_ascii'
648
649    IF (dbg) PRINT *,TRIM(fname)
650
651    SELECT CASE (TRIM(compute))
652      CASE ('scratch')
653        dooverlap = .TRUE.
654        dotracks = .TRUE.
655        doftracks = .TRUE.
656      CASE ('continue')
657        INQUIRE(file='polygons_overlap.dat', exist=file_exist)
658        IF (.NOT.file_exist) THEN
659          dooverlap = .TRUE.
660        ELSE
661          IF (dbg) THEN
662            PRINT *, TRIM(warnmsg)
663            PRINT *,"  "//TRIM(fname) // ": File 'polygons_overlap.dat' already exists, skipping it !!"
664          END IF
665          dooverlap = .FALSE.
666        END IF
667        INQUIRE(file='trajectories_overlap.dat', exist=file_exist)
668        IF (.NOT.file_exist) THEN
669          dotracks = .TRUE.
670        ELSE
671          IF (dbg) THEN
672            PRINT *, TRIM(warnmsg)
673            PRINT *, "  " // TRIM(fname) // ": File 'trajectories_overlap.dat' already exists, " //   &
674              "skipping it !!"
675          END IF
676          dotracks = .FALSE.
677        END IF
678        INQUIRE(file='trajectories.dat', exist=file_exist)
679        IF (.NOT.file_exist) THEN
680          doftracks = .TRUE.
681        ELSE
682          IF (dbg) THEN
683            PRINT *, TRIM(warnmsg)
684            PRINT *,"  "//TRIM(fname) // ": File 'trajectories.dat' already exists, skipping it !!"
685          END IF
686          doftracks = .FALSE.
687        END IF
688    CASE DEFAULT
689      msg = "compute case: '" // TRIM(compute) // "' not ready !!"
690      CALL ErrMsg(msg, fname, -1)
691    END SELECT
692
693    ! Checking multi-polygon methodology
694    IF ( (TRIM(methodmulti) /= 'mean') .AND. (TRIM(methodmulti) /= 'largest') .AND.                   &
695      (TRIM(methodmulti) /= 'closest')) THEN
696      msg= "methodology for multiple-polygons: '"//TRIM(methodmulti)//"' not ready" // NEW_LINE('a')//&
697        " available ones: 'mean', 'largest', 'closest'"
698      CALL ErrMsg(msg, fname, -1)
699    END IF
700
701    IF (dooverlap) THEN
702      ! ASCII file for all the polygons and their previous associated one
703      fprevunit = freeunit()
704      OPEN(fprevunit, file='polygons_overlap.dat', status='new', form='formatted', iostat=ios)
705      msg = "Problems opening file: 'polygons_overlap.dat'"
706      IF (ios == 17) PRINT *,"  Careful: 'polygons_overlap.dat' already exists!!"
707      CALL ErrMsg(msg, fname, ios)
708
709      ! Number of independent polygons by time step
710      Nindeppolys = 0
711      ! Number of polygons attached to each independent polygons by time step
712      NpolysIndep = 0
713      ! ID of searching polygon attached to each independent polygons by time step
714      SpolysIndep = 0
715      ! ID of polygons attached to each independent polygons by time step
716      polysIndep = 0
717      ! ID of polygons from previous time-step
718      prevID = 0
719      ! ID of polygons from current time-step
720      currID = 0
721
722      ! First time-step all are independent polygons
723      it = 1
724      Nmeet = inNallpolys(it)
725      Nindeppolys(it) = Nmeet
726      ip = 0
727      meetpolys = allpolys(:,:,it)
728      DO i=1, Nmeet
729        IF (areapolys(i,it) >= minarea) THEN
730          ip = ip + 1
731          SpolysIndep(ip,it) = i
732          currID(ip) = i
733          Acurrpolys(ip) = areapolys(i,it)
734          Ccurrpolys(1,ip) = ctrpolys(1,i,it)
735          Ccurrpolys(2,ip) = ctrpolys(2,i,it)
736          NpolysIndep(ip,it) = 1
737          polysIndep(ip,1,it) = i
738        ELSE
739          WHERE (meetpolys == i)
740            meetpolys = 0
741          END WHERE
742        END IF
743      END DO
744      Nindeppolys(1) = ip
745      Npolystime(1) = ip
746 
747      ! Starting step
748      it = 0
749      IF (dbg) THEN
750        PRINT *,'  time step:',it+1,' number to look polygons:', Nmeet,' searching polygons:',0
751        PRINT *,'    number of independent polygons:', Nindeppolys(it+1)
752        PRINT *,'    indep_polygon prev_step_polygon Nassociated_polygons curr_ass_polygons _______'
753        DO i=1, Nindeppolys(it+1)
754          PRINT *,i, SpolysIndep(i,it+1), NpolysIndep(i,it+1), ':',                                     &
755            polysIndep(i,1:NpolysIndep(i,it+1),it+1)
756        END DO
757      END IF
758      ! Writting to the ASCII file Independent polygons and their associated
759      CALL write_overlap_polys_ascii(fprevunit,it+1, Nmaxpoly, Nindeppolys(it+1),                       &
760        SpolysIndep(1:Nindeppolys(it+1),it+1), NpolysIndep(1:Nindeppolys(it+1),it+1),                   &
761        polysIndep(1:Nindeppolys(it+1),:,it+1))
762
763      it = 1
764      ! Looking for the coincidencies at each time step
765      DO iit=1, dt-1
766        ! Number of times that a polygon has a coincidence
767        coincidencies = 0
768 
769        ! Preparing for next time-step
770        searchpolys = meetpolys
771        prevID = 0
772        prevID = currID
773        Aprevpolys = Acurrpolys
774        Cprevpolys = Ccurrpolys
775
776        Nmeet = inNallpolys(iit+1)
777        meetpolys = allpolys(:,:,iit+1)
778        ip = 0
779        DO i=1, Nmeet
780          IF (areapolys(i,iit+1) >= minarea) THEN
781            ip = ip + 1
782            currID(ip) = i
783            Acurrpolys(ip) = areapolys(i,iit+1)
784            Acurrpolys(ip) = areapolys(i,iit+1)
785            Ccurrpolys(1,ip) = ctrpolys(1,i,iit+1)
786            Ccurrpolys(2,ip) = ctrpolys(2,i,iit+1)
787          ELSE
788            WHERE (meetpolys == i)
789              meetpolys = 0
790            END WHERE
791          END IF
792        END DO
793        Nindeppolys(it+1) = ip
794        Npolystime(it+1) = ip
795
796        ! Looking throughout the independent polygons
797        Nmeet = Nindeppolys(it+1)
798        !Nsearch = Nindeppolys(it)
799        ! Previous space might have more polygons that their number of independent ones
800        Nsearch = Npolystime(it)
801
802        IF (ALLOCATED(coins)) DEALLOCATE(coins)
803        ALLOCATE(coins(Nmeet), STAT=ierr)
804        msg="Problems allocating 'coins'"
805        CALL ErrMsg(msg,fname,ierr)
806
807        IF (ALLOCATED(coinsNpts)) DEALLOCATE(coinsNpts)
808        ALLOCATE(coinsNpts(Nmeet, Nsearch), STAT=ierr)
809        msg="Problems allocating 'coinsNpts'"
810        CALL ErrMsg(msg,fname,ierr)
811
812        CALL coincidence_all_polys_area(dbg, dx, dy, Nmeet, currID, meetpolys, Ccurrpolys(:,1:Nmeet),   &
813          Nsearch, prevID, searchpolys, Cprevpolys(:,1:Nsearch), Aprevpolys(1:Nsearch), coins,          &
814          coinsNpts)
815
816        ! Counting the number of times that a polygon has a coincidency
817        IF (dbg) THEN
818          PRINT *,'  Coincidencies for the given time-step:', iit+1,' _______'
819          DO i=1, Nmeet
820            PRINT *,currID(i), coins(i),' N search pts:', coinsNpts(i,:)
821          END DO
822        END IF
823
824        ! Looking for the same equivalencies
825        Nindep = 0
826        DO i=1, Nmeet
827          IF (coins(i) == -1) THEN
828            Nindep = Nindep + 1
829            SpolysIndep(Nindep,it+1) = -1
830            NpolysIndep(Nindep,it+1) = NpolysIndep(Nindep,it+1) + 1
831            polysIndep(Nindep,NpolysIndep(Nindep,it+1),it+1) = currID(i)
832          ELSE IF (coins(i) == -9) THEN
833            WRITE(NcoinS,'(I5)')coins(i)
834            msg="coins= "//TRIM(NcoinS)//" This is an error. One should have always only one " //      &
835              "coincidence of polygon"
836            CALL ErrMsg(msg, fname, -1)
837          ELSE
838            ! Looking for coincidences with previous independent polygons
839            DO ip=1, Nsearch
840              ! Looking into the polygons associated
841              NNprev = NpolysIndep(ip,it)
842              DO j=1, NNprev
843                IF (coins(i) == polysIndep(ip,j,it)) THEN
844                  ! Which index corresponds to this coincidence?
845                  iindep = Index1DArrayI(SpolysIndep(1:Nindep,it+1), Nindep, coins(i))
846                  IF (iindep == -1) THEN
847                    Nindep = Nindep + 1
848                    SpolysIndep(Nindep,it+1) = coins(i)
849                  END IF
850                  iindep = Index1DArrayI(SpolysIndep(1:Nindep,it+1), Nindep, coins(i))
851                  IF (iindep < 0) THEN
852                    PRINT *,'    Looking for:', coins(i)
853                    PRINT *,'    Within:', SpolysIndep(1:Nindep,it+1)
854                    PRINT *,'    Might content:', polysIndep(ip,1:NNprev,it)
855                    PRINT *,'    From an initial list:', coins(1:Nmeet)
856                    msg = 'Wrong index! There must be an index here'
857                    CALL ErrMsg(msg,fname,iindep)
858                  END IF
859                  coincidencies(ip) = coincidencies(ip) + 1
860                  NpolysIndep(iindep,it+1) = NpolysIndep(iindep,it+1) + 1
861                  polysIndep(iindep,NpolysIndep(iindep,it+1),it+1) = currID(i)
862                  EXIT
863                END IF
864              END DO
865            END DO
866          END IF
867        END DO
868        Nindeppolys(it+1) = Nindep
869
870        IF (dbg) THEN
871          PRINT *,'  time step:',iit+1,' number to look polygons:', Nmeet,' searching polygons:',Nsearch
872          PRINT *,'    number of independent polygons:', Nindeppolys(it+1)
873          PRINT *,'    indep_polygon prev_step_polygon Nassociated_polygons curr_ass_polygons _______'
874          DO i=1, Nindeppolys(it+1)
875            PRINT *,i, SpolysIndep(i,it+1), NpolysIndep(i,it+1), ':',                                   &
876              polysIndep(i,1:NpolysIndep(i,it+1),it+1)
877          END DO
878        END IF
879
880        ! Writting to the ASCII file Independent polygons and their associated
881        CALL write_overlap_polys_ascii(fprevunit, iit+1, Nmaxpoly, Nindeppolys(it+1),                   &
882          SpolysIndep(1:Nindeppolys(it+1),it+1), NpolysIndep(1:Nindeppolys(it+1),it+1),                 &
883          polysIndep(1:Nindeppolys(it+1),:,it+1))
884        ! Preparing for the next time-step
885        SpolysIndep(:,it) = 0
886        NpolysIndep(:,it) = 0
887        polysIndep(:,:,it) = 0
888        Nindeppolys(it) = Nindeppolys(it+1)
889        SpolysIndep(1:Nindeppolys(it),it) = SpolysIndep(1:Nindeppolys(it+1),it+1)
890        NpolysIndep(1:Nindeppolys(it),it) = NpolysIndep(1:Nindeppolys(it+1),it+1)
891        Npolystime(it) = Npolystime(it+1)
892
893        DO ip=1, Nindeppolys(it)
894          polysIndep(ip,1,it) = polysIndep(ip,1,it+1)
895          polysIndep(ip,2,it) = polysIndep(ip,2,it+1)
896        END DO
897        SpolysIndep(:,it+1) = 0
898        NpolysIndep(:,it+1) = 0
899        polysIndep(:,:,it+1) = 0
900
901      END DO
902      CLOSE(fprevunit)
903      IF (dbg) PRINT *,"  Succesful writting of ASCII chain of polygons 'polygons_overlap.dat' !!"
904    END IF
905    ! ASCII file for all the polygons and their previous associated one
906    fprevunit = freeunit()
907    OPEN(fprevunit, file='polygons_overlap.dat', status='old', form='formatted', iostat=ios)
908    msg = "Problems opening file: 'polygons_overlap.dat'"
909    CALL ErrMsg(msg, fname, ios)
910
911    it = 1
912    IF (dbg) THEN
913      PRINT *,  'Coincidencies to connect _______'
914      DO iit=1, dt
915        ! Reading from the ASCII file Independent polygons and their associated
916        CALL read_overlap_polys_ascii(fprevunit, iit, Nmaxpoly, Nindeppolys(it), SpolysIndep(:,it),   &
917          NpolysIndep(:,it), polysIndep(:,:,it))
918        PRINT *,'  it:', iit, ' Nindep:', Nindeppolys(it)
919        PRINT '(4x,3(A6,1x))','Nindep', 'PrevID', 'IDs'
920        DO ip=1, Nindeppolys(it)
921          PRINT '(4x,I6,A1,I6,A1,100(I6))', ip, ',', SpolysIndep(ip,it), ':',                         &
922            polysIndep(ip,1:NpolysIndep(ip,it),it)
923        END DO
924      END DO
925    END IF
926
927    REWIND(fprevunit)
928
929    ! Trajectories
930    ! It should be done following the number of 'independent' polygons
931    ! One would concatenate that independent polygons which share IDs from one step to another
932    IF (dotracks) THEN
933
934      ! ASCII file for the trajectories
935      ftrackunit = freeunit()
936      OPEN(ftrackunit, file='trajectories_overlap.dat', status='new', form='formatted', iostat=ios)
937      msg = "Problems opening file: 'trajectories_overlap.dat'"
938      IF (ios == 17) PRINT *,"  Careful: 'trajectories_overlap.dat' already exists!!"
939      CALL ErrMsg(msg,fname,ios)
940
941      ! First time-step. Take all polygons
942      itrack = 0
943      tracks = zeroRK
944      Ntracks = 0
945      it = 1
946      iit = 1
947      CALL read_overlap_polys_ascii(fprevunit, iit, Nmaxpoly, Nindeppolys(it), SpolysIndep(:,it),       &
948        NpolysIndep(:,it), polysIndep(:,:,it))
949
950      DO ip=1, Nindeppolys(1)
951        itrack = itrack + 1
952        tracks(1,1,itrack,1) = itrack*1.
953        tracks(2,1,itrack,1) = SpolysIndep(ip,1)
954        tracks(3,1,itrack,1) = ctrpolys(1,ip,1)
955        tracks(4,1,itrack,1) = ctrpolys(2,ip,1)
956        tracks(5,1,itrack,1) = 1
957        Ntracks(1) = Ntracks(1) + 1
958      END DO
959
960      ! Writting first time-step trajectories to the intermediate file
961      CALL write_overlap_tracks_ascii(ftrackunit,iit,Nmaxpoly, Ntracks(it), tracks(:,:,1:Ntracks(it),it))
962
963      ! Looping allover already assigned tracks
964      it = 2
965      maxtrack = Ntracks(1)
966      timesteps: DO iit=2, dt
967        CALL read_overlap_polys_ascii(fprevunit, iit, Nmaxpoly, Nindeppolys(it), SpolysIndep(:,it),     &
968          NpolysIndep(:,it), polysIndep(:,:,it))
969        IF (dbg) PRINT *,'track-timestep:', iit, 'N indep polys:', Nindeppolys(it)
970        ! Indep polygons current time-step
971        current_poly: DO i=1, Nindeppolys(it)
972          IF (dbg) PRINT *,'  curent poly:', i, 'Prev poly:', SpolysIndep(i,it), ' N ass. polygons:',   &
973            NpolysIndep(i,it), 'ass. poly:', polysIndep(i,1:NpolysIndep(i,it),it)
974          Indeppolychained = .FALSE.
975
976          ! Number of tracks previous time-step
977          ! Looping overall
978          it1_tracks: DO itt=1, Ntracks(it-1)
979            itrack = tracks(1,1,itt,it-1)
980            ! Number polygons ID assigned
981            Ntprev = COUNT(tracks(2,:,itt,it-1) /= 0)
982            IF (dbg) PRINT *,itt,'  track:', itrack, 'assigned:', tracks(2,1:Ntprev,itt,it-1)
983
984            ! Looking for coincidencies
985            DO iip=1, Ntprev
986              IF (tracks(2,iip,itt,it-1) == SpolysIndep(i,it)) THEN
987                Indeppolychained = .TRUE.
988                IF (dbg) PRINT *,'    coincidence found by polygon:', tracks(2,iip,itt,it-1)
989                EXIT
990              END IF
991            END DO
992            IF (Indeppolychained) THEN
993              Ntracks(it) = Ntracks(it) + 1
994              ictrack = Ntracks(it)
995              ! Assigning all the IDs to the next step of the track
996              DO iip=1, NpolysIndep(i,it)
997                iiprev = polysIndep(i,iip,it)
998                tracks(1,iip,ictrack,it) = itrack
999                tracks(2,iip,ictrack,it) = iiprev
1000                tracks(3,iip,ictrack,it) = ctrpolys(1,iiprev,iit)
1001                tracks(4,iip,ictrack,it) = ctrpolys(2,iiprev,iit)
1002                tracks(5,iip,ictrack,it) = iit
1003              END DO
1004              EXIT
1005            END IF
1006            IF (Indeppolychained) EXIT
1007          END DO it1_tracks
1008
1009          ! Creation of a new track
1010          IF (.NOT.Indeppolychained) THEN
1011            Ntracks(it) = Ntracks(it) + 1
1012            ictrack = Ntracks(it)
1013            ! ID of new track
1014            maxtrack = maxtrack + 1
1015            IF (dbg) PRINT *,'  New track!', maxtrack
1016
1017            ! Assigning all the IDs to the next step of the track
1018            DO j=1, NpolysIndep(i,it)
1019              iiprev = polysIndep(i,j,it)
1020              tracks(1,j,ictrack,it) = maxtrack
1021              tracks(2,j,ictrack,it) = iiprev
1022              tracks(3,j,ictrack,it) = ctrpolys(1,iiprev,iit)
1023              tracks(4,j,ictrack,it) = ctrpolys(2,iiprev,iit)
1024              tracks(5,j,ictrack,it) = iit
1025            END DO
1026          END IF
1027
1028        END DO current_poly
1029
1030        IF (dbg) THEN
1031          PRINT *,'  At this time-step:', iit, ' N trajectories:', Ntracks(it)
1032          DO i=1, Ntracks(it)
1033            Nprev = COUNT(INT(tracks(2,:,i,it)) /= 0)
1034            PRINT *,i ,'ID tracks:', tracks(1,1,i,it), 'ID polygon:', tracks(2,1:Nprev,i,it)
1035          END DO
1036        END IF
1037
1038        CALL write_overlap_tracks_ascii(ftrackunit,iit,Nmaxpoly,Ntracks(it),tracks(:,:,1:Ntracks(it),it))
1039        ! Re-initializing for the next time-step
1040        tracks(:,:,:,it-1) = zeroRK
1041        Ntracks(it-1) = Ntracks(it)
1042        tracks(:,:,1:Ntracks(it-1),it-1) = tracks(:,:,1:Ntracks(it),it)
1043        Ntracks(it) = 0
1044        tracks(:,:,:,it) = zeroRK
1045
1046      END DO timesteps
1047      CLOSE(ftrackunit)
1048      IF (dbg) PRINT *,"  Succesful writting of ASCII chain of polygons 'trajectories_overlap.dat' !!"
1049      CLOSE(fprevunit)
1050    END IF
1051
1052    ! Summarizing trajectories
1053    ! When multiple polygons are available, the mean of their central positions determines the position
1054
1055    IF (doftracks) THEN
1056      ! ASCII file for the trajectories
1057      ftrackunit = freeunit()
1058      OPEN(ftrackunit, file='trajectories_overlap.dat', status='old', form='formatted', iostat=ios)
1059      msg = "Problems opening file: 'trajectories_overlap.dat'"
1060      CALL ErrMsg(msg,fname,ios)
1061
1062      ! ASCII file for the final trajectories
1063      ftrunit = freeunit()
1064      OPEN(ftrunit, file='trajectories.dat', status='new', form='formatted', iostat=ios)
1065      msg = "Problems opening file: 'trajectories.dat'"
1066      IF (ios == 17) PRINT *,"  Careful: 'trajectories.dat' already exists!!"
1067      CALL ErrMsg(msg,fname,ios)
1068
1069      finaltracks = zeroRK
1070
1071      DO itt=1, Nmaxtracks
1072        CALL read_overlap_single_track_ascii(ftrackunit, dt, Nmaxpoly, Nmaxtracks, itt, singletrack)
1073
1074        ! It might reach the las trajectory
1075        IF (ALL(singletrack == zeroRK)) EXIT
1076
1077        itrack = INT(MAXVAL(singletrack(1,1,:)))
1078        IF (dbg) THEN
1079          PRINT *,'  Trajectory:', itt, '_______', itrack
1080          DO it=1, dt
1081            IF (singletrack(2,1,it) /= zeroRK) THEN
1082              j = COUNT(singletrack(2,:,it) /= zeroRK)
1083              PRINT *,it,':',(singletrack(3,i,it),',',singletrack(4,i,it),' ; ',i=1,j)
1084            END IF
1085          END DO
1086        END IF
1087
1088        finaltracks = zeroRK
1089        finaltracks(1,:) = itrack*oneRK
1090        DO it =1, dt     
1091          Nprev = COUNT(INT(singletrack(2,:,it)) /= zeroRK)
1092          IF (Nprev /= 0) THEN
1093            finaltracks(5,it) = it*oneRK
1094            IF (TRIM(methodmulti) == 'largest') THEN
1095              maxarea = -10.*oneRK
1096              DO ip=1, Nprev
1097                IF (areapolys(singletrack(2,ip,it),it) > maxarea) THEN
1098                  maxarea = areapolys(singletrack(2,ip,it),it)
1099                  i = ip
1100                END IF
1101              END DO
1102              IF (dbg) THEN
1103                PRINT *,'  Determine the trajectory coordinates to the largest polygon:', i,          &
1104                  ' area:', maxarea
1105              END IF
1106              finaltracks(2,it) = singletrack(2,i,it)*oneRK
1107              finaltracks(3,it) = singletrack(3,i,it)
1108              finaltracks(4,it) = singletrack(4,i,it)
1109            ELSE IF (TRIM(methodmulti) == 'closest') THEN
1110              IF (it > 1) THEN
1111                mindist = 10000000.*oneRK
1112                DO ip=1, Nprev
1113                  dist = SQRT((singletrack(3,ip,it)-finaltracks(3,it-1))**2 +                         &
1114                    (singletrack(4,ip,it)-finaltracks(4,it-1))**2 )
1115                  IF (dist < mindist) THEN
1116                    mindist = dist
1117                    i = ip
1118                  END IF
1119                END DO
1120                finaltracks(2,it) = singletrack(3,i,it)*oneRK
1121                finaltracks(3,it) = singletrack(3,i,it)
1122                finaltracks(4,it) = singletrack(4,i,it)
1123                IF (dbg) THEN
1124                  PRINT *,'  Determine the trajectory coordinates to the closest previous polygon:',i,&
1125                    ' distance:', mindist
1126                END IF
1127              ELSE
1128                maxarea = -10.*oneRK
1129                DO ip=1, Nprev
1130                  IF (areapolys(singletrack(2,ip,it),it) > maxarea) THEN
1131                    maxarea = areapolys(singletrack(2,ip,it),it)
1132                    i = ip
1133                  END IF
1134                END DO
1135                IF (dbg) THEN
1136                  PRINT *, '  Determine the trajectory coordinates to the largest polygon:', i,        &
1137                    ' area:', maxarea, ' at the first time-step then to the closest'
1138                END IF
1139                finaltracks(2,it) = i*oneRK
1140                finaltracks(3,it) = singletrack(3,i,it)
1141                finaltracks(4,it) = singletrack(4,i,it)             
1142              END IF
1143            ELSE
1144              totArea = zeroRK
1145              finaltracks(2,it) = -oneRK
1146              finaltracks(3,it) = zeroRK
1147              finaltracks(4,it) = zeroRK
1148              DO ip=1, Nprev
1149                areai = areapolys(singletrack(2,ip,it),it)
1150                totArea = totArea + areai
1151                finaltracks(3,it) = finaltracks(3,it) + singletrack(3,ip,it)*areai
1152                finaltracks(4,it) = finaltracks(4,it) + singletrack(4,ip,it)*areai
1153              END DO
1154              finaltracks(3,it) = finaltracks(3,it)/totArea
1155              finaltracks(4,it) = finaltracks(4,it)/totArea
1156              IF (dbg) THEN
1157                PRINT *,'  Determine the trajectory coordinates to the area-averaged polygon ' //     &
1158                  ' total area:', totArea
1159              END IF
1160
1161            END IF
1162
1163          END IF
1164        END DO
1165        ! Writting the final track into the ASCII file
1166        CALL write_finaltrack_ascii(ftrunit, dt, finaltracks)
1167
1168      END DO
1169      CLOSE(ftrackunit)
1170      IF (dbg) PRINT *,"  Succesful writting of ASCII trajectories 'trajectories.dat' !!"
1171      CLOSE(ftrunit)
1172    END IF
1173
1174    IF (ALLOCATED(coins)) DEALLOCATE(coins)
1175    IF (ALLOCATED(coinsNpts)) DEALLOCATE(coinsNpts)
1176
1177    RETURN
1178
1179  END SUBROUTINE poly_overlap_tracks_area_ascii
1180
1181  SUBROUTINE poly_overlap_tracks_area(dbg, dx, dy, dt, minarea, inNallpolys, allpolys, ctrpolys,      &
1182    areapolys, Nmaxpoly, Nmaxtracks, tracks, finaltracks)
1183! Subroutine to determine tracks of a series of consecutive 2D field with polygons using maximum
1184!   overlaping/coincidence filtrered by a minimal area
1185
1186    IMPLICIT NONE
1187
1188    LOGICAL, INTENT(in)                                  :: dbg
1189    INTEGER, INTENT(in)                                  :: dx, dy, dt, Nmaxpoly, Nmaxtracks
1190    INTEGER, DIMENSION(dt), INTENT(in)                   :: inNallpolys
1191    INTEGER, DIMENSION(dx,dy,dt), INTENT(in)             :: allpolys
1192    REAL(r_k), INTENT(in)                                :: minarea
1193    REAL(r_k), DIMENSION(2,Nmaxpoly,dt), INTENT(in)      :: ctrpolys
1194    REAL(r_k), DIMENSION(Nmaxpoly,dt), INTENT(in)        :: areapolys
1195    REAL(r_k), DIMENSION(5,Nmaxpoly,Nmaxtracks,dt),                                                   &
1196      INTENT(out)                                        :: tracks
1197    REAL(r_k), DIMENSION(4,Nmaxtracks,dt), INTENT(out)   :: finaltracks
1198
1199! Local
1200    INTEGER                                              :: i, j, ip, it, iip, itt
1201    INTEGER                                              :: ierr
1202    REAL(r_k), DIMENSION(Nmaxpoly)                       :: Aprevpolys, Acurrpolys
1203    REAL(r_k), DIMENSION(2,Nmaxpoly)                     :: Cprevpolys, Ccurrpolys
1204    INTEGER, DIMENSION(dt)                               :: Nallpolys
1205    INTEGER, DIMENSION(dx,dy)                            :: meetpolys, searchpolys
1206    INTEGER, DIMENSION(Nmaxpoly)                         :: coincidencies
1207    INTEGER, DIMENSION(Nmaxpoly)                         :: prevID, currID
1208    INTEGER, DIMENSION(:), ALLOCATABLE                   :: coins
1209    INTEGER, DIMENSION(:,:), ALLOCATABLE                 :: coinsNpts
1210    INTEGER                                              :: Nmeet, Nsearch, Nindep
1211    INTEGER, DIMENSION(dt)                               :: Nindeppolys
1212    CHARACTER(len=5)                                     :: NcoinS
1213    INTEGER, DIMENSION(Nmaxpoly,Nmaxpoly,dt)             :: polysIndep
1214    INTEGER, DIMENSION(Nmaxpoly,dt)                      :: NpolysIndep
1215    INTEGER, DIMENSION(Nmaxpoly,dt)                      :: SpolysIndep
1216    INTEGER                                              :: iindep, iiprev
1217    INTEGER                                              :: Nprev, NNprev, Ntprev
1218    LOGICAL                                              :: Indeppolychained
1219    INTEGER                                              :: itrack, ictrack
1220    REAL(r_k)                                            :: ixp, iyp
1221    INTEGER                                              :: ttrack
1222    INTEGER, DIMENSION(dt)                               :: Ntracks
1223    INTEGER                                              :: idtrack, maxtrack
1224
1225!!!!!!! Variables
1226! dx,dy,dt: space/time dimensions
1227! Nallpolys: Vector with the number of polygons at each time-step
1228! allpolys: Series of 2D field with the polygons
1229! minarea: minimal area (in same units as areapolys) to perform the tracking
1230! ctrpolys: center of the polygons
1231! areapolys: area of the polygons
1232! Nmaxpoly: Maximum possible number of polygons
1233! Nmaxtracks: maximum number of tracks
1234! tracks: series of consecutive polygons
1235! trackperiod: period of the track in time-steps
1236
1237    fname = 'poly_overlap_tracks_area'
1238
1239    IF (dbg) PRINT *,TRIM(fname)
1240
1241    ! Number of independent polygons by time step
1242    Nindeppolys = 0
1243    ! Number of polygons attached to each independent polygons by time step
1244    NpolysIndep = 0
1245    ! ID of searching polygon attached to each independent polygons by time step
1246    SpolysIndep = 0
1247    ! ID of polygons attached to each independent polygons by time step
1248    polysIndep = 0
1249    ! ID of polygons from previous time-step
1250    prevID = 0
1251    ! ID of polygons from current time-step
1252    currID = 0
1253
1254    ! First time-step all are independent polygons
1255    it = 1
1256    Nmeet = inNallpolys(it)
1257    Nindeppolys(it) = Nmeet
1258    ip = 0
1259    meetpolys = allpolys(:,:,it)
1260    DO i=1, Nmeet
1261      IF (areapolys(i,it) >= minarea) THEN
1262        ip = ip + 1
1263        SpolysIndep(ip,it) = i
1264        currID(ip) = i
1265        Acurrpolys(ip) = areapolys(i,it)
1266        Ccurrpolys(1,ip) = ctrpolys(1,i,it)
1267        Ccurrpolys(2,ip) = ctrpolys(2,i,it)
1268        NpolysIndep(ip,it) = 1
1269        polysIndep(ip,1,it) = i
1270      ELSE
1271        WHERE (meetpolys == i)
1272          meetpolys = 0
1273        END WHERE
1274      END IF
1275    END DO
1276    Nallpolys(1) = ip
1277    Nindeppolys(1) = ip
1278
1279    ! Starting step
1280    it = 0
1281    IF (dbg) THEN
1282      PRINT *,'  time step:',it+1,' number to look polygons:', Nmeet,' searching polygons:',0
1283      PRINT *,'    number of independent polygons:', Nindeppolys(it+1)
1284      PRINT *,'    indep_polygon prev_step_polygon Nassociated_polygons curr_ass_polygons _______'
1285      DO i=1, Nindeppolys(it+1)
1286        PRINT *,i, SpolysIndep(i,it+1), NpolysIndep(i,it+1), ':',                                     &
1287          polysIndep(i,1:NpolysIndep(i,it+1),it+1)
1288      END DO
1289    END IF
1290
1291    ! Looking for the coincidencies at each time step
1292    DO it=1, dt-1
1293      ! Number of times that a polygon has a coincidence
1294      coincidencies = 0
1295
1296      Nmeet = inNallpolys(it+1)
1297      searchpolys = meetpolys
1298      meetpolys = allpolys(:,:,it+1)
1299      prevID = 0
1300      prevID = currID
1301      Aprevpolys = Acurrpolys
1302      Cprevpolys = Ccurrpolys
1303      ip = 0
1304
1305      DO i=1, Nmeet
1306        IF (areapolys(i,it+1) >= minarea) THEN
1307          ip = ip + 1
1308          currID(ip) = i
1309          Acurrpolys(ip) = areapolys(i,it+1)
1310          Acurrpolys(ip) = areapolys(i,it+1)
1311          Ccurrpolys(1,ip) = ctrpolys(1,i,it+1)
1312          Ccurrpolys(2,ip) = ctrpolys(2,i,it+1)
1313        ELSE
1314          WHERE (meetpolys == i)
1315            meetpolys = 0
1316          END WHERE
1317        END IF
1318      END DO
1319      Nallpolys(it+1) = ip
1320      Nindeppolys(it+1) = ip
1321
1322      Nmeet = Nallpolys(it+1)
1323      ! Looking throughout the independent polygons
1324      Nsearch = Nindeppolys(it)
1325
1326      IF (ALLOCATED(coins)) DEALLOCATE(coins)
1327      ALLOCATE(coins(Nmeet), STAT=ierr)
1328      msg="Problems allocating 'coins'"
1329      CALL ErrMsg(msg,fname,ierr)
1330
1331      IF (ALLOCATED(coinsNpts)) DEALLOCATE(coinsNpts)
1332      ALLOCATE(coinsNpts(Nmeet, Nsearch), STAT=ierr)
1333      msg="Problems allocating 'coinsNpts'"
1334      CALL ErrMsg(msg,fname,ierr)
1335
1336      CALL coincidence_all_polys_area(dbg, dx,dy, Nmeet, currID, meetpolys, Acurrpolys(1:Nmeet),      &
1337        Nsearch, prevID, searchpolys, Cprevpolys(:,1:Nsearch), Aprevpolys(1:Nsearch), coins,          &
1338        coinsNpts)
1339
1340      ! Counting the number of times that a polygon has a coincidency
1341      IF (dbg) THEN
1342        PRINT *,'  Coincidencies for the given time-step:', it+1,' _______'
1343        DO i=1, Nmeet
1344          PRINT *,currID(i), coins(i),' N search pts:', coinsNpts(i,:)
1345        END DO
1346      END IF
1347
1348      ! Looking for the same equivalencies
1349      Nindep = 0
1350      DO i=1, Nmeet
1351        IF (coins(i) == -1) THEN
1352          Nindep = Nindep + 1
1353          SpolysIndep(Nindep,it+1) = -1
1354          NpolysIndep(Nindep,it+1) = NpolysIndep(Nindep,it+1) + 1
1355          polysIndep(Nindep,NpolysIndep(Nindep,it+1),it+1) = currID(i)
1356        ELSE IF (coins(i) == -9) THEN
1357          WRITE(NcoinS,'(I5)')coins(i)
1358          msg="coins= "//TRIM(NcoinS)//" This is an error. One should have always only one " //      &
1359            "coincidence of polygon"
1360          CALL ErrMsg(msg, fname, -1)
1361        ELSE
1362          ! Looking for coincidences with previous independent polygons
1363          DO ip=1, Nsearch
1364            ! Looking into the polygons associated
1365            NNprev = NpolysIndep(ip,it)
1366            DO j=1, NNprev
1367              IF (coins(i) == polysIndep(ip,j,it)) THEN
1368                ! Which index corresponds to this coincidence?
1369                iindep = Index1DArrayI(SpolysIndep(1:Nindep,it+1), Nindep, coins(i))
1370                IF (iindep == -1) THEN
1371                  Nindep = Nindep + 1
1372                  SpolysIndep(Nindep,it+1) = coins(i)
1373                END IF
1374                iindep = Index1DArrayI(SpolysIndep(1:Nindep,it+1), Nindep, coins(i))
1375                IF (iindep < 0) THEN
1376                  PRINT *,'    Looking for:', coins(i)
1377                  PRINT *,'    Within:', SpolysIndep(1:Nindep,it+1)
1378                  PRINT *,'    Might content:', polysIndep(ip,1:NNprev,it)
1379                  PRINT *,'    From an initial list:', coins(1:Nmeet)
1380                  msg = 'Wrong index! There must be an index here'
1381                  CALL ErrMsg(msg,fname,iindep)
1382                END IF
1383                coincidencies(ip) = coincidencies(ip) + 1
1384                NpolysIndep(iindep,it+1) = NpolysIndep(iindep,it+1) + 1
1385                polysIndep(iindep,NpolysIndep(iindep,it+1),it+1) = currID(i)
1386                EXIT
1387              END IF
1388            END DO
1389          END DO
1390        END IF
1391      END DO
1392      Nindeppolys(it+1) = Nindep
1393
1394      IF (dbg) THEN
1395        PRINT *,'  time step:',it+1,' number to look polygons:', Nmeet,' searching polygons:',Nsearch
1396        PRINT *,'    number of independent polygons:', Nindeppolys(it+1)
1397        PRINT *,'    indep_polygon prev_step_polygon Nassociated_polygons curr_ass_polygons _______'
1398        DO i=1, Nindeppolys(it+1)
1399          PRINT *,i, SpolysIndep(i,it+1), NpolysIndep(i,it+1), ':',                                   &
1400            polysIndep(i,1:NpolysIndep(i,it+1),it+1)
1401        END DO
1402      END IF
1403    END DO
1404
1405    IF (dbg) THEN
1406      PRINT *,  'Coincidencies to connect _______'
1407      DO it=1, dt
1408        PRINT *,'  it:', it, ' Nindep:', Nindeppolys(it)
1409        PRINT '(4x,3(A6,1x))','Nindep', 'PrevID', 'IDs'
1410        DO ip=1, Nindeppolys(it)
1411          PRINT '(4x,I6,A1,I6,A1,100(I6))', ip, ',', SpolysIndep(ip,it), ':',                         &
1412            polysIndep(ip,1:NpolysIndep(ip,it),it)
1413        END DO
1414      END DO
1415
1416    END IF
1417
1418    ! Trajectories
1419    ! It should be done following the number of 'independent' polygons
1420    ! One would concatenate that independent polygons which share IDs from one step to another
1421
1422    ! First time-step. Take all polygons
1423    itrack = 0
1424    tracks = 0.
1425    Ntracks = 0
1426    DO ip=1, Nindeppolys(1)
1427      itrack = itrack + 1
1428      tracks(1,1,itrack,1) = itrack*1.
1429      tracks(2,1,itrack,1) = SpolysIndep(ip,1)
1430      tracks(3,1,itrack,1) = ctrpolys(1,ip,1)
1431      tracks(4,1,itrack,1) = ctrpolys(2,ip,1)
1432      tracks(5,1,itrack,1) = 1
1433      Ntracks(1) = Ntracks(1) + 1
1434    END DO
1435
1436    ! Looping allover already assigned tracks
1437    timesteps: DO it=2, dt
1438      IF (dbg) PRINT *,'track-timestep:', it, 'N indep polys:', Nindeppolys(it)
1439      ! Indep polygons current time-step
1440      current_poly: DO i=1, Nindeppolys(it)
1441        IF (dbg) PRINT *,'  curent poly:', i, 'Prev poly:', SpolysIndep(i,it), ' N ass. polygons:',   &
1442          NpolysIndep(i,it), 'ass. poly:', polysIndep(i,1:NpolysIndep(i,it),it)
1443        Indeppolychained = .FALSE.
1444
1445        ! Number of tracks previous time-step
1446        ! Looping overall
1447        it1_tracks: DO itt=1, Ntracks(it-1)
1448          itrack = tracks(1,1,itt,it-1)
1449          ! Number polygons ID assigned
1450          Ntprev = COUNT(tracks(2,:,itt,it-1) /= 0)
1451          IF (dbg) PRINT *,itt,'  track:', itrack, 'assigned:', tracks(2,1:Ntprev,itt,it-1)
1452
1453          ! Looking for coincidencies
1454          DO iip=1, Ntprev
1455            IF (tracks(2,iip,itt,it-1) == SpolysIndep(i,it)) THEN
1456              Indeppolychained = .TRUE.
1457              IF (dbg) PRINT *,'    coincidence found by polygon:', tracks(2,iip,itt,it-1)
1458              EXIT
1459            END IF
1460          END DO
1461          IF (Indeppolychained) THEN
1462            Ntracks(it) = Ntracks(it) + 1
1463            ictrack = Ntracks(it)
1464            ! Assigning all the IDs to the next step of the track
1465            DO iip=1, NpolysIndep(i,it)
1466              iiprev = polysIndep(i,iip,it)
1467              tracks(1,iip,ictrack,it) = itrack
1468              tracks(2,iip,ictrack,it) = iiprev
1469              ixp = ctrpolys(1,iiprev,it)
1470              iyp = ctrpolys(2,iiprev,it)
1471              tracks(3,iip,ictrack,it) = ixp
1472              tracks(4,iip,ictrack,it) = iyp
1473              tracks(5,iip,ictrack,it) = it
1474            END DO
1475            EXIT
1476          END IF
1477          IF (Indeppolychained) EXIT
1478        END DO it1_tracks
1479
1480        ! Creation of a new track
1481        IF (.NOT.Indeppolychained) THEN
1482          Ntracks(it) = Ntracks(it) + 1
1483          ictrack = Ntracks(it)
1484          ! ID of new track
1485          maxtrack = INT(MAXVAL(tracks(1,:,:,:)*1.))
1486          IF (dbg) PRINT *,'  New track!', maxtrack+1
1487
1488          ! Assigning all the IDs to the next step of the track
1489          DO j=1, NpolysIndep(i,it)
1490            iiprev = polysIndep(i,j,it)
1491            tracks(1,j,ictrack,it) = maxtrack+1
1492            tracks(2,j,ictrack,it) = iiprev
1493            ixp = ctrpolys(1,iiprev,it)
1494            iyp = ctrpolys(2,iiprev,it)
1495            tracks(3,j,ictrack,it) = ixp
1496            tracks(4,j,ictrack,it) = iyp
1497            tracks(5,j,ictrack,it) = it
1498          END DO
1499        END IF
1500
1501      END DO current_poly
1502
1503      IF (dbg) THEN
1504        PRINT *,'  At this time-step:', it, ' N trajectories:', Ntracks(it)
1505        DO i=1, Ntracks(it)
1506          Nprev = COUNT(INT(tracks(2,:,i,it)) /= 0)
1507          PRINT *,i ,'ID tracks:', tracks(1,1,i,it), 'ID polygon:', tracks(2,1:Nprev,i,it)
1508        END DO
1509      END IF
1510
1511    END DO timesteps
1512
1513    ! Summarizing trajectories
1514    ! When multiple polygons are available, the mean of their central positions determines the position
1515
1516    finaltracks = 0.
1517    maxtrack = MAXVAL(tracks(1,:,:,:))
1518
1519    DO it=1, dt
1520      DO itt=1, Ntracks(it)
1521        itrack = INT(tracks(1,1,itt,it))
1522        Nprev = COUNT(INT(tracks(2,:,itt,it)) /= 0)
1523        finaltracks(1,itrack,it) = itrack*1.
1524        finaltracks(2,itrack,it) = SUM(tracks(3,:,itt,it))/Nprev*1.
1525        finaltracks(3,itrack,it) = SUM(tracks(4,:,itt,it))/Nprev*1.
1526        finaltracks(4,itrack,it) = it*1.
1527      END DO
1528    END DO
1529
1530    DEALLOCATE(coins)
1531    DEALLOCATE(coinsNpts)
1532
1533    RETURN
1534
1535  END SUBROUTINE poly_overlap_tracks_area
1536
1537  SUBROUTINE coincidence_all_polys_area(dbg, dx, dy, Nallpoly, IDallpoly, allpoly, icpolys, Npoly, &
1538    IDpolys, polys, cpolys, apolys, polycoins, coinNptss)
1539! Subtourine to determine which is the coincident polygon when a boolean polygon is provided to a map of integer polygons
1540!   In case of multiple coincidencies, the closest and then the largest is taken filtrered by a minimal area
1541!   Here the difference is that the index does not coincide with its ID
1542
1543    IMPLICIT NONE
1544
1545    LOGICAL, INTENT(in)                                  :: dbg
1546    INTEGER, INTENT(in)                                  :: dx, dy, Nallpoly, Npoly
1547    INTEGER, DIMENSION(dx,dy), INTENT(in)                :: allpoly, polys
1548    INTEGER, DIMENSION(Nallpoly), INTENT(in)             :: IDallpoly
1549    INTEGER, DIMENSION(Npoly), INTENT(in)                :: IDpolys
1550    REAL(r_k), DIMENSION(2,Nallpoly), INTENT(in)         :: icpolys
1551    REAL(r_k), DIMENSION(2,Npoly), INTENT(in)            :: cpolys
1552    REAL(r_k), DIMENSION(Npoly), INTENT(in)              :: apolys
1553    INTEGER, DIMENSION(Nallpoly), INTENT(out)            :: polycoins
1554    INTEGER, DIMENSION(Nallpoly,Npoly), INTENT(out)      :: coinNptss
1555
1556! Local
1557    INTEGER                                              :: i, j, ip
1558    INTEGER                                              :: maxcorr
1559    INTEGER                                              :: Nmaxcorr
1560    LOGICAL, DIMENSION(dx,dy)                            :: boolpoly
1561    INTEGER                                              :: maxcoin
1562    REAL                                                 :: dist, maxcoindist, maxcoinarea
1563    INTEGER, DIMENSION(Npoly)                            :: IDcoins
1564
1565!!!!!!! Variables
1566! dx,dy: dimension of the space
1567! Nallpoly: Number of polygons to find coincidence
1568! allpoly: space with the polygons to meet
1569! IDallpoly: ID of the polygon to find coincidence
1570! icpolys: center of the polygons to look for the coincidence
1571! Npoly: number of polygons on the 2D space
1572! polys: 2D field of polygons identified by their integer number (0 for no polygon)
1573! IDpolys: ID of the polygon to search for coincidences
1574! cpolys: center of the polygons
1575! apolys: area of the polygons
1576! polycoins: coincident polyogn
1577!          -1: no-coincidence
1578!   1 < Npoly: single coincidence with a given polygon
1579!          -9: coincidence with more than one polygon
1580! coinNptss: number of points coincident with each polygon
1581
1582    fname = 'coincidence_all_polys_area'
1583    IF (dbg) PRINT *,TRIM(fname)
1584
1585    DO ip=1, Nallpoly
1586      boolpoly = allpoly == IDallpoly(ip)
1587      CALL coincidence_poly_area(dbg, dx, dy, boolpoly, Npoly, polys, polycoins(ip), IDcoins,         &
1588        coinNptss(ip,:))
1589      IF (dbg) PRINT *,'  polygon', IDallpoly(ip), ' coincidence with:', polycoins(ip), 'IDpolys:', IDpolys(1:Npoly)
1590
1591      ! Coincidence with more than one polygon
1592      IF (polycoins(ip) == -9) THEN
1593        maxcoindist = -10.
1594        maxcoinarea = -10.
1595        maxcoin = MAXVAL(coinNptss(ip,:))
1596        DO j=1, Npoly
1597          IF (coinNptss(ip,j) == maxcoin) THEN
1598            dist = SQRT( (icpolys(1,ip)*1.-cpolys(1,j)*1.)**2 + (icpolys(2,ip)*1.-cpolys(2,j)*1.)**2 )
1599            IF ( dist > maxcoindist) THEN
1600              maxcoindist = dist
1601              maxcoinarea = apolys(j)
1602              polycoins(ip) = IDcoins(j)
1603            ELSE IF ( dist == maxcoindist) THEN
1604              IF (apolys(j) > maxcoinarea) THEN
1605                polycoins(ip) = IDcoins(j)
1606                maxcoinarea = apolys(j)
1607              END IF
1608            END IF
1609          END IF
1610        END DO
1611      END IF
1612    END DO
1613
1614    RETURN
1615
1616  END SUBROUTINE coincidence_all_polys_area
1617
1618  SUBROUTINE coincidence_poly_area(dbg, dx, dy, poly, Npoly, polys, polycoin, IDpoly, coinNpts)
1619! Subtourine to determine which is the coincident polygon when a boolean polygon is provided to a map of integer polygons
1620!   Here the difference is that the index does not coincide with its ID
1621
1622    IMPLICIT NONE
1623
1624    LOGICAL, INTENT(in)                                  :: dbg
1625    INTEGER, INTENT(in)                                  :: dx, dy, Npoly
1626    LOGICAL, DIMENSION(dx,dy), INTENT(in)                :: poly
1627    INTEGER, DIMENSION(dx,dy), INTENT(in)                :: polys
1628    INTEGER, INTENT(out)                                 :: polycoin
1629    INTEGER, DIMENSION(Npoly), INTENT(out)               :: IDpoly, coinNpts
1630
1631! Local
1632    INTEGER                                              :: i, j, ip
1633    INTEGER                                              :: maxcorr
1634    INTEGER                                              :: Nmaxcorr
1635! Lluis
1636    INTEGER                                              :: Ndiffvals
1637    INTEGER, DIMENSION(:), ALLOCATABLE                   :: diffvals
1638
1639!!!!!!! Variables
1640! dx,dy: dimension of the space
1641! poly: bolean polygon to meet
1642! Npoly: number of polygons on the 2D space
1643! polys: 2D field of polygons identified by their integer number (0 for no polygon)
1644! polycoin: coincident polyogn
1645!          -1: no-coincidence
1646!   1 < Npoly: single coincidence with a given polygon
1647!          -9: coincidence with more than one polygon
1648! IDpoly: ID of the found polygon
1649! coinNpts: number of points coincident with each polygon
1650
1651    fname = 'coincidence_poly_area'
1652    IF (dbg) PRINT *,TRIM(fname)
1653
1654    IF (dbg) THEN
1655      PRINT *,'  Boolean polygon to search coincidences ...'
1656      DO i=1,dx
1657        PRINT *,poly(i,:)
1658      END DO
1659
1660      PRINT *,'  2D polygons space ...'
1661      DO i=1,dx
1662        PRINT '(1000(I7,1x))',polys(i,:)
1663      END DO
1664    END IF
1665
1666    IF (ALLOCATED(diffvals)) DEALLOCATE(diffvals)
1667    ALLOCATE(diffvals(dx*dy))
1668
1669    ! Checking for consistency on number of polygons and real content (except 0 value)
1670    CALL Nvalues_2DArrayI(dx, dy, dx*dy, polys, Ndiffvals, diffvals)
1671    IF (Ndiffvals -1 /= Npoly) THEN
1672      PRINT *,TRIM(emsg)
1673      PRINT *,'    number of different values:', Ndiffvals-1, ' theoretical Npoly:', Npoly
1674      PRINT *,'    Different values:', diffvals(1:Ndiffvals)
1675      msg = 'Number of different values and Npoly must coincide'
1676      CALL ErrMsg(msg, fname, -1)
1677    END IF
1678
1679    ! Looking for coincient points for the polygon
1680    coinNpts = 0
1681    IDpoly = 0
1682    ip = 0
1683    DO i=1,dx
1684      DO j=1,dy
1685        IF (poly(i,j) .AND. polys(i,j) .NE. 0) THEN
1686          IF (.NOT.ANY(IDpoly == polys(i,j))) THEN
1687            ip = ip + 1
1688            IDpoly(ip) = polys(i,j)
1689          ELSE
1690            ip = Index1DarrayI(IDpoly, Npoly, polys(i,j))
1691          END IF
1692          coinNpts(ip) = coinNpts(ip) + 1
1693        END IF
1694      END DO
1695    END DO
1696
1697    maxcorr = 0
1698    maxcorr = INT(MAXVAL(coinNpts*1.))
1699
1700    IF (dbg) PRINT *,'  Maximum coincidence:', maxcorr
1701    IF (maxcorr == 0) THEN
1702      polycoin = -1
1703    ELSE
1704      Nmaxcorr = 0
1705      DO ip=1, Npoly
1706        IF (coinNpts(ip) == maxcorr) THEN
1707          Nmaxcorr = Nmaxcorr+1
1708          polycoin = IDpoly(ip)
1709        END IF
1710      END DO
1711      IF (Nmaxcorr > 1) polycoin = -9
1712    END IF
1713
1714    IF (dbg) THEN
1715      PRINT *,'  Coincidences for each polygon _______', Npoly
1716      DO ip=1, Npoly
1717        PRINT *,'  ',ip, ' ID:', IDpoly(ip),': ', coinNpts(ip)
1718      END DO
1719    END IF
1720
1721    RETURN
1722
1723END SUBROUTINE coincidence_poly_area
1724
1725  SUBROUTINE poly_overlap_tracks(dbg, dx, dy, dt, minarea, Nallpolys, allpolys, ctrpolys,        &
1726    areapolys, Nmaxpoly, Nmaxtracks, tracks, finaltracks)
1727! Subroutine to determine tracks of a series of consecutive 2D field with polygons using maximum overlaping/coincidence
1728
1729    IMPLICIT NONE
1730
1731    LOGICAL, INTENT(in)                                  :: dbg
1732    INTEGER, INTENT(in)                                  :: dx, dy, dt, Nmaxpoly, Nmaxtracks
1733    INTEGER, DIMENSION(dt), INTENT(in)                   :: Nallpolys
1734    INTEGER, DIMENSION(dx,dy,dt), INTENT(in)             :: allpolys
1735    REAL(r_k), INTENT(in)                                :: minarea
1736    REAL(r_k), DIMENSION(2,Nmaxpoly,dt), INTENT(in)      :: ctrpolys
1737    REAL(r_k), DIMENSION(Nmaxpoly,dt), INTENT(in)        :: areapolys
1738    REAL(r_k), DIMENSION(5,Nmaxpoly,Nmaxtracks,dt),                                                   &
1739      INTENT(out)                                        :: tracks
1740    REAL(r_k), DIMENSION(4,Nmaxtracks,dt), INTENT(out)   :: finaltracks
1741
1742! Local
1743    INTEGER                                              :: i, j, ip, it, iip, itt
1744    INTEGER                                              :: ierr
1745    INTEGER, DIMENSION(Nmaxpoly,dt)                      :: coincidencies, NOcoincidencies
1746    INTEGER, DIMENSION(:), ALLOCATABLE                   :: coins
1747    INTEGER, DIMENSION(:,:), ALLOCATABLE                 :: coinsNpts
1748    INTEGER, DIMENSION(Nmaxpoly,dt)                      :: polycoincidencies
1749    INTEGER, DIMENSION(Nmaxpoly,Nmaxpoly,dt)             :: coincidenciesNpts
1750    INTEGER                                              :: Nmeet, Nsearch, Nindep
1751    INTEGER, DIMENSION(dt)                               :: Nindeppolys
1752    CHARACTER(len=5)                                     :: NcoinS
1753    INTEGER, DIMENSION(Nmaxpoly,Nmaxpoly,dt)             :: polysIndep
1754    INTEGER, DIMENSION(Nmaxpoly,dt)                      :: NpolysIndep
1755    INTEGER, DIMENSION(Nmaxpoly,dt)                      :: SpolysIndep
1756    INTEGER                                              :: iindep, iiprev
1757    INTEGER                                              :: Nprev, NNprev, Ntprev
1758    LOGICAL                                              :: Indeppolychained
1759    INTEGER                                              :: itrack, ictrack
1760    INTEGER                                              :: ixp, iyp, ttrack
1761    INTEGER, DIMENSION(dt)                               :: Ntracks
1762    INTEGER                                              :: idtrack, maxtrack
1763
1764!!!!!!! Variables
1765! dx,dy,dt: space/time dimensions
1766! Nallpolys: Vector with the number of polygons at each time-step
1767! allpolys: Series of 2D field with the polygons
1768! minarea: minimal area (in same units as areapolys) to perform the tracking
1769! ctrpolys: center of the polygons
1770! areapolys: area of the polygons
1771! Nmaxpoly: Maximum possible number of polygons
1772! Nmaxtracks: maximum number of tracks
1773! tracks: series of consecutive polygons
1774! trackperiod: period of the track in time-steps
1775
1776    fname = 'poly_overlap_tracks'
1777
1778    IF (dbg) PRINT *,TRIM(fname)
1779
1780    polycoincidencies = fillvalI
1781    coincidenciesNpts = fillvalI
1782    ! Number of times that a polygon has a coincidence
1783    coincidencies = 0
1784    ! Polygons without a coincidence
1785    NOcoincidencies = 0
1786    ! Number of independent polygons by time step
1787    Nindeppolys = 0
1788    ! Number of polygons attached to each independent polygons by time step
1789    NpolysIndep = 0
1790    ! ID of searching polygon attached to each independent polygons by time step
1791    SpolysIndep = 0
1792    ! ID of polygons attached to each independent polygons by time step
1793    polysIndep = 0
1794
1795    ! First time-step all are independent polygons
1796    it = 1
1797    Nmeet = Nallpolys(it)
1798    Nindeppolys(it) = Nmeet
1799    DO i=1, Nmeet
1800      SpolysIndep(i,it) = i
1801      NpolysIndep(1:Nmeet,it) = 1
1802      polysIndep(1,i,it) = i
1803    END DO
1804
1805    ! Looking for the coincidencies at each time step
1806    DO it=1, dt-1
1807      Nmeet = Nallpolys(it+1)
1808      Nsearch = Nallpolys(it)
1809
1810      IF (ALLOCATED(coins)) DEALLOCATE(coins)
1811      ALLOCATE(coins(Nmeet), STAT=ierr)
1812      msg="Problems allocating 'coins'"
1813      CALL ErrMsg(msg,fname,ierr)
1814
1815      IF (ALLOCATED(coinsNpts)) DEALLOCATE(coinsNpts)
1816      ALLOCATE(coinsNpts(Nmeet, Nsearch), STAT=ierr)
1817      msg="Problems allocating 'coinsNpts'"
1818      CALL ErrMsg(msg,fname,ierr)
1819
1820      CALL coincidence_all_polys(dbg, dx, dy, Nmeet, allpolys(:,:,it+1), ctrpolys(:,1:Nmeet,it+1),    &
1821        Nsearch, allpolys(:,:,it), ctrpolys(:,1:Nsearch,it), areapolys(1:Nsearch,it), coins, coinsNpts)
1822
1823      polycoincidencies(1:Nmeet,it+1) = coins
1824      coincidenciesNpts(1:Nmeet,1:Nsearch,it+1) = coinsNpts
1825
1826      ! Counting the number of times that a polygon has a coincidency
1827      IF (dbg) THEN
1828        PRINT *,'  Coincidencies for the given time-step:', it+1,' _______'
1829        DO i=1, Nmeet
1830          PRINT *,coins(i),' N search pts:', coinsNpts(i,:)
1831        END DO
1832      END IF
1833
1834      Nindep = 0
1835      DO i=1, Nmeet
1836        IF (coins(i) == -1) THEN
1837          Nindep = Nindep + 1
1838          NOcoincidencies(i,it+1) = 1
1839          SpolysIndep(Nindep,it+1) = -1
1840          NpolysIndep(Nindep,it+1) = NpolysIndep(Nindep,it+1) + 1
1841          polysIndep(Nindep,NpolysIndep(Nindep,it+1),it+1) = i
1842        ELSE IF (coins(i) == -9) THEN
1843          WRITE(NcoinS,'(I5)')coins(i)
1844          msg="coins= "//TRIM(NcoinS)//" This is an error. One should have always only one " //      &
1845            "coincidence of polygon"
1846          CALL ErrMsg(msg, fname, -1)
1847        ELSE
1848          DO ip=1, Nsearch
1849            IF (coins(i) == ip) THEN
1850              IF (coincidencies(ip,it+1) == 0) THEN
1851                Nindep = Nindep + 1
1852                SpolysIndep(Nindep,it+1) = ip
1853              END IF
1854              coincidencies(ip,it+1) = coincidencies(ip,it+1) + 1
1855              DO iindep=1, Nindep
1856                IF (SpolysIndep(iindep,it+1) == coins(i)) THEN
1857                  NpolysIndep(iindep,it+1) = NpolysIndep(iindep,it+1) + 1
1858                  polysIndep(iindep,NpolysIndep(iindep,it+1),it+1) = i
1859                END IF
1860              END DO
1861            END IF
1862          END DO
1863        END IF
1864      END DO
1865      Nindeppolys(it+1) = Nindep
1866
1867      IF (dbg) THEN
1868        PRINT *,'  time step:',it+1,' number to look polygons:', Nmeet,' searching polygons:',Nsearch
1869        PRINT *,'    number of independent polygons:', Nindeppolys(it+1)
1870        PRINT *,'    indep_polygon prev_step_polygon Nassociated_polygons curr_ass_polygons _______'
1871        DO i=1, Nindeppolys(it+1)
1872          PRINT *,i, SpolysIndep(i,it+1), NpolysIndep(i,it+1), ':',                                   &
1873            polysIndep(i,1:NpolysIndep(i,it+1),it+1)
1874        END DO
1875      END IF
1876    END DO
1877
1878    IF (dbg) THEN
1879      PRINT *,  'Coincidencies to connect _______'
1880      DO it=1, dt
1881        PRINT *,'  it:', it, ' Nindep:', Nindeppolys(it)
1882        PRINT '(4x,3(A6,1x))','Nindep', 'PrevID', 'IDs'
1883        DO ip=1, Nindeppolys(it)
1884          PRINT '(4x,I6,A1,I6,A1,100(I6))', ip, ',', SpolysIndep(ip,it), ':',                         &
1885            polysIndep(ip,1:NpolysIndep(ip,it),it)
1886        END DO
1887      END DO
1888
1889    END IF
1890
1891    ! Trajectories
1892    ! It should be done following the number of 'independent' polygons
1893    ! One would concatenate that independent polygons which share IDs from one step to another
1894
1895    ! First time-step. Take all polygons
1896    itrack = 0
1897    tracks = 0.
1898    Ntracks = 0
1899    DO ip=1, Nindeppolys(1)
1900      itrack = itrack + 1
1901      tracks(1,1,itrack,1) = itrack*1.
1902      tracks(2,1,itrack,1) = SpolysIndep(ip,1)
1903      tracks(3,1,itrack,1) = ctrpolys(1,ip,1)
1904      tracks(4,1,itrack,1) = ctrpolys(2,ip,1)
1905      tracks(5,1,itrack,1) = 1
1906      Ntracks(1) = Ntracks(1) + 1
1907    END DO
1908
1909    ! Looping allover already assigned tracks
1910    timesteps: DO it=2, dt
1911      IF (dbg) PRINT *,'timestep:', it, 'N indep polys:', Nindeppolys(it)
1912      ! Indep polygons current time-step
1913      current_poly: DO i=1, Nindeppolys(it)
1914        IF (dbg) PRINT *,'  curent poly:', i, 'Prev poly:', SpolysIndep(i,it), ' N ass. polygons:',   &
1915          NpolysIndep(i,it), 'ass. poly:', polysIndep(i,1:NpolysIndep(i,it),it)
1916        Indeppolychained = .FALSE.
1917
1918        ! Number of tracks previous time-step
1919        ! Looping overall
1920        it1_tracks: DO itt=1, Ntracks(it-1)
1921          itrack = tracks(1,1,itt,it-1)
1922          ! Number polygons ID assigned
1923          Ntprev = COUNT(tracks(2,:,itt,it-1) /= 0)
1924          IF (dbg) PRINT *,itt,'  track:', itrack, 'assigned:', tracks(2,1:Ntprev,itt,it-1)
1925
1926          ! Looking for coincidencies
1927          DO iip=1, Ntprev
1928            IF (tracks(2,iip,itt,it-1) == SpolysIndep(i,it)) THEN
1929              Indeppolychained = .TRUE.
1930              IF (dbg) PRINT *,'    coincidence found by polygon:', tracks(2,iip,itt,it-1)
1931              EXIT
1932            END IF
1933          END DO
1934          IF (Indeppolychained) THEN
1935            Ntracks(it) = Ntracks(it) + 1
1936            ictrack = Ntracks(it)
1937            ! Assigning all the IDs to the next step of the track
1938            DO iip=1, NpolysIndep(i,it)
1939              iiprev = polysIndep(i,iip,it)
1940              tracks(1,iip,ictrack,it) = itrack
1941              tracks(2,iip,ictrack,it) = iiprev
1942              ixp = ctrpolys(1,iiprev,it)
1943              iyp = ctrpolys(2,iiprev,it)
1944              tracks(3,iip,ictrack,it) = ixp
1945              tracks(4,iip,ictrack,it) = iyp
1946              tracks(5,iip,ictrack,it) = it
1947            END DO
1948            EXIT
1949          END IF
1950        END DO it1_tracks
1951
1952        ! Creation of a new track
1953        IF (.NOT.Indeppolychained) THEN
1954          Ntracks(it) = Ntracks(it) + 1
1955          ictrack = Ntracks(it)
1956          ! ID of new track
1957          maxtrack = INT(MAXVAL(tracks(1,:,:,:)*1.))
1958          IF (dbg) PRINT *,'  New track!', maxtrack+1
1959
1960          ! Assigning all the IDs to the next step of the track
1961          DO j=1, NpolysIndep(i,it)
1962            iiprev = polysIndep(i,j,it)
1963            tracks(1,j,ictrack,it) = maxtrack+1
1964            tracks(2,j,ictrack,it) = iiprev
1965            ixp = ctrpolys(1,iiprev,it)
1966            iyp = ctrpolys(2,iiprev,it)
1967            tracks(3,j,ictrack,it) = ixp
1968            tracks(4,j,ictrack,it) = iyp
1969            tracks(5,j,ictrack,it) = it
1970          END DO
1971        END IF
1972
1973      END DO current_poly
1974
1975      IF (dbg) THEN
1976        PRINT *,'  At this time-step:', it, ' N trajectories:', Ntracks(it)
1977        DO i=1, Ntracks(it)
1978          Nprev = COUNT(INT(tracks(2,:,i,it)) /= 0)
1979          PRINT *,i,'tracks:', tracks(2,1:Nprev,i,it)
1980        END DO
1981      END IF
1982
1983    END DO timesteps
1984
1985    ! Summarizing trajectories
1986    ! When multiple polygons are available, the mean of their central positions determines the position
1987
1988    finaltracks = 0.
1989    maxtrack = MAXVAL(tracks(1,:,:,:))
1990
1991    DO it=1, dt
1992      DO itt=1, Ntracks(it)
1993        itrack = INT(tracks(1,1,itt,it))
1994        Nprev = COUNT(INT(tracks(2,:,itt,it)) /= 0)
1995        PRINT *,'it:', it,'itrack:', itrack, 'Nprev:', Nprev
1996        finaltracks(1,itrack,it) = itrack*1.
1997        finaltracks(2,itrack,it) = SUM(tracks(3,:,itt,it))/Nprev
1998        finaltracks(3,itrack,it) = SUM(tracks(4,:,itt,it))/Nprev
1999        finaltracks(4,itrack,it) = it*1.
2000        PRINT *,'  finaltrack:', finaltracks(:,itrack,it)
2001      END DO
2002    END DO
2003
2004    RETURN
2005
2006  END SUBROUTINE poly_overlap_tracks
2007
2008  SUBROUTINE coincidence_all_polys(dbg, dx, dy, Nallpoly, allpoly, icpolys, Npoly, polys, cpolys,     &
2009    apolys, polycoins, coinNptss)
2010! Subtourine to determine which is the coincident polygon when a boolean polygon is provided to a map of integer polygons
2011!   In case of multiple coincidencies, the closest and then the largest is taken
2012
2013    IMPLICIT NONE
2014
2015    LOGICAL, INTENT(in)                                  :: dbg
2016    INTEGER, INTENT(in)                                  :: dx, dy, Nallpoly, Npoly
2017    INTEGER, DIMENSION(dx,dy), INTENT(in)                :: allpoly, polys
2018    REAL(r_k), DIMENSION(2,Nallpoly), INTENT(in)         :: icpolys
2019    REAL(r_k), DIMENSION(2,Npoly), INTENT(in)            :: cpolys
2020    REAL(r_k), DIMENSION(Npoly), INTENT(in)              :: apolys
2021    INTEGER, DIMENSION(Nallpoly), INTENT(out)            :: polycoins
2022    INTEGER, DIMENSION(Nallpoly,Npoly), INTENT(out)      :: coinNptss
2023
2024! Local
2025    INTEGER                                              :: i, j, ip
2026    INTEGER                                              :: maxcorr
2027    INTEGER                                              :: Nmaxcorr
2028    LOGICAL, DIMENSION(dx,dy)                            :: boolpoly
2029    INTEGER                                              :: maxcoin
2030    REAL                                                 :: dist, maxcoindist, maxcoinarea
2031
2032!!!!!!! Variables
2033! dx,dy: dimension of the space
2034! Nallpoly: Number of polygons to find coincidence
2035! allpoly: space with the polygons to meet
2036! icpolys: center of the polygons to look for the coincidence
2037! Npoly: number of polygons on the 2D space
2038! polys: 2D field of polygons identified by their integer number (0 for no polygon)
2039! cpolys: center of the polygons
2040! apolys: area of the polygons
2041! polycoins: coincident polyogn
2042!          -1: no-coincidence
2043!   1 < Npoly: single coincidence with a given polygon
2044!          -9: coincidence with more than one polygon
2045! coinNptss: number of points coincident with each polygon
2046
2047    fname = 'coincidence_all_polys'
2048    IF (dbg) PRINT *,TRIM(fname)
2049
2050    DO ip=1, Nallpoly
2051      boolpoly = allpoly == ip
2052      CALL coincidence_poly(dbg, dx, dy, boolpoly, Npoly, polys, polycoins(ip), coinNptss(ip,:))
2053      IF (dbg) PRINT *,'  polygon', ip, ' coincidence with:', polycoins(ip)
2054
2055      ! Coincidence with more than one polygon
2056      IF (polycoins(ip) == -9) THEN
2057        maxcoindist = -10.
2058        maxcoinarea = -10.
2059        maxcoin = MAXVAL(coinNptss(ip,:))
2060        DO j=1, Npoly
2061          IF (coinNptss(ip,j) == maxcoin) THEN
2062            dist = SQRT( (icpolys(1,ip)*1.-cpolys(1,j)*1.)**2 + (icpolys(2,ip)*1.-cpolys(2,j)*1.)**2 )
2063            IF ( dist > maxcoindist) THEN
2064              maxcoindist = dist
2065              maxcoinarea = apolys(j)
2066              polycoins(ip) = j
2067            ELSE IF ( dist == maxcoindist) THEN
2068              IF (apolys(j) > maxcoinarea) THEN
2069                polycoins(ip) = j
2070                maxcoinarea = apolys(j)
2071              END IF
2072            END IF
2073          END IF
2074        END DO
2075      END IF
2076    END DO
2077
2078    RETURN
2079
2080  END SUBROUTINE coincidence_all_polys
2081
2082  SUBROUTINE coincidence_poly(dbg, dx, dy, poly, Npoly, polys, polycoin, coinNpts)
2083! Subtourine to determine which is the coincident polygon when a boolean polygon is provided to a map of integer polygons
2084
2085    IMPLICIT NONE
2086
2087    LOGICAL, INTENT(in)                                  :: dbg
2088    INTEGER, INTENT(in)                                  :: dx, dy, Npoly
2089    LOGICAL, DIMENSION(dx,dy), INTENT(in)                :: poly
2090    INTEGER, DIMENSION(dx,dy), INTENT(in)                :: polys
2091    INTEGER, INTENT(out)                                 :: polycoin
2092    INTEGER, DIMENSION(Npoly), INTENT(out)               :: coinNpts
2093
2094! Local
2095    INTEGER                                              :: i, j, ip
2096    INTEGER                                              :: maxcorr
2097    INTEGER                                              :: Nmaxcorr
2098
2099!!!!!!! Variables
2100! dx,dy: dimension of the space
2101! poly: bolean polygon to meet
2102! Npoly: number of polygons on the 2D space
2103! polys: 2D field of polygons identified by their integer number (0 for no polygon)
2104! polycoin: coincident polyogn
2105!          -1: no-coincidence
2106!   1 < Npoly: single coincidence with a given polygon
2107!          -9: coincidence with more than one polygon
2108! coinNpts: number of points coincident with each polygon
2109
2110    fname = 'coincidence_poly'
2111    IF (dbg) PRINT *,TRIM(fname)
2112
2113    IF (dbg) THEN
2114      PRINT *,'  Boolean polygon to search coincidences ...'
2115      DO i=1,dx
2116        PRINT *,poly(i,:)
2117      END DO
2118
2119      PRINT *,'  2D polygons space ...'
2120      DO i=1,dx
2121        PRINT '(1000(I7,1x))',polys(i,:)
2122      END DO
2123    END IF
2124
2125    ! Looking for coincient points for the polygon
2126    coinNpts = 0
2127    DO i=1,dx
2128      DO j=1,dy
2129        IF (poly(i,j) .AND. polys(i,j) .NE. 0) coinNpts(polys(i,j)) = coinNpts(polys(i,j)) + 1
2130      END DO
2131    END DO
2132
2133    maxcorr = 0
2134    maxcorr = INT(MAXVAL(coinNpts*1.))
2135
2136    IF (dbg) PRINT *,'  Maximum coincidence:', maxcorr
2137    IF (maxcorr == 0) THEN
2138      polycoin = -1
2139    ELSE
2140      Nmaxcorr = 0
2141      DO ip=1, Npoly
2142        IF (coinNpts(ip) == maxcorr) THEN
2143          Nmaxcorr=Nmaxcorr+1
2144          polycoin = ip
2145        END IF
2146      END DO
2147      IF (Nmaxcorr > 1) polycoin = -9
2148    END IF
2149
2150    IF (dbg) THEN
2151      PRINT *,'  Coincidences for each polygon _______'
2152      DO ip=1, Npoly
2153        PRINT *,'  ', ip,': ', coinNpts(ip)
2154      END DO
2155    END IF
2156
2157    RETURN
2158
2159END SUBROUTINE coincidence_poly
2160
2161  SUBROUTINE all_polygons_properties(dbg, dx, dy, Npoly, polys, lon, lat, values, xres, yres, projN,  &
2162    Npolyptss, xxtrms, yxtrms, meanctrs, meanwctrs, areas, nvals, xvals, mvals, m2vals, stdvals,      &
2163    Nquant, quants, nvcoords, xvcoords, meanvnctrs, meanvxctrs)
2164! Subroutine to determine the properties of all polygons in a 2D field:
2165!   Number of grid points
2166!   grid-point coordinates of the minimum and maximum of the path along x,y axes
2167!   grid coordinates of center from the mean of the coordinates of the poygon locations
2168!   lon, lat center from the area weighted mean of the coordinates of the polygon locations
2169!   area of the polygon (km2)
2170!   minimum and maximum of the values within the polygon
2171!   mean of the values within the polygon
2172!   quadratic mean of the values within the polygon
2173!   standard deviation of the values within the polygon
2174!   number of quantiles
2175!   quantiles of the values within the polygon
2176!   grid coordinates of the minimum, maximum value within the polygon
2177!   lon, lat coordinates of the area center weighted and also by distance to the lowest or highest values of the polygon
2178
2179  IMPLICIT NONE
2180
2181  LOGICAL, INTENT(in)                                    :: dbg
2182  INTEGER, INTENT(in)                                    :: dx, dy, Npoly, Nquant
2183  INTEGER, DIMENSION(dx,dy), INTENT(in)                  :: polys
2184  REAL(r_k), DIMENSION(dx,dy), INTENT(in)                :: lon, lat, values
2185  REAL(r_k), INTENT(in)                                  :: xres, yres
2186  CHARACTER(len=1000), INTENT(in)                        :: projN
2187  INTEGER, DIMENSION(Npoly), INTENT(out)                 :: Npolyptss
2188  INTEGER, DIMENSION(Npoly,2), INTENT(out)               :: xxtrms, yxtrms, meanctrs
2189  REAL(r_k), DIMENSION(Npoly), INTENT(out)               :: areas
2190  REAL(r_k), DIMENSION(Npoly), INTENT(out)               :: nvals, xvals, mvals, m2vals, stdvals
2191  REAL(r_k), DIMENSION(Npoly, Nquant), INTENT(out)       :: quants
2192  INTEGER, DIMENSION(Npoly,2), INTENT(out)               :: nvcoords, xvcoords
2193  REAL(r_k), DIMENSION(Npoly,2), INTENT(out)             :: meanwctrs, meanvnctrs, meanvxctrs
2194
2195! Local
2196  INTEGER                                                :: ip
2197  LOGICAL, DIMENSION(dx,dy)                              :: boolpoly
2198
2199!!!!!!! Variables
2200! dx,dy: size of the space
2201! Npoly: number of polygons
2202! polys: polygon matrix with all polygons (as integer number per polygon)
2203! lon, lat: geographical coordinates of the grid-points of the matrix
2204! values: values of the 2D field to use
2205! [x/y]res resolution along the x and y axis
2206! projN: name of the projection
2207!   'ctsarea': Constant Area
2208!   'lon/lat': for regular longitude-latitude
2209!   'nadir-sat,[lonNADIR],[latNADIR]': for satellite data with the resolution given at nadir (lonNADIR, latNADIR)
2210! Npolyptss: number of points of the polygons
2211! [x/y]xtrms: grid-point coordinates of minimum and maximum coordinates of the polygons
2212! meanctrs: center from the mean of the coordinates of the polygons
2213! meanwctrs: lon, lat coordinates of the center from the spatial-weighted mean of the polygons
2214! areas: area of the polygons [km]
2215! [n/x]vals: minimum and maximum of the values within the polygons
2216! mvals: mean of the values within the polygons
2217! m2vals: quadratic mean of the values within the polygons
2218! stdvals: standard deviation of the values within the polygons
2219! Nquant: number of quantiles
2220! quants: quantiles of the values within the polygons
2221! [n/x]vcoords: grid coordinates of the minimum/maximum of the values within the polygons
2222! meanv[n/x]ctrs: lon, lat coordinates of the area center weighted and also by distance to the lowest or highest values of the polygons
2223
2224  fname = 'all_polygons_properties'
2225
2226  ! Initializing matrices
2227  Npolyptss = -1
2228  xxtrms = fillval64
2229  yxtrms = fillval64
2230  meanctrs = fillval64
2231  meanwctrs = fillval64
2232  areas = fillval64
2233  nvals = fillvalI
2234  xvals = fillval64
2235  mvals = fillval64
2236  m2vals = fillval64
2237  stdvals = fillval64
2238  quants = fillval64
2239  nvcoords = fillvalI
2240  xvcoords = fillvalI
2241  meanvnctrs = fillval64
2242  meanvxctrs = fillval64
2243
2244  DO ip=1, Npoly
2245    boolpoly = polys == ip
2246    CALL polygon_properties(dbg, dx, dy, boolpoly, lon, lat, values, xres, yres, projN, Npolyptss(ip),&
2247      xxtrms(ip,:), yxtrms(ip,:), meanctrs(ip,:), meanwctrs(ip,:), areas(ip), nvals(ip), xvals(ip),   &
2248      mvals(ip), m2vals(ip), stdvals(ip), Nquant, quants(ip,:), nvcoords(ip,:), xvcoords(ip,:),       &
2249      meanvnctrs(ip,:), meanvxctrs(ip,:))
2250  END DO
2251
2252  RETURN
2253
2254  END SUBROUTINE all_polygons_properties
2255
2256  SUBROUTINE polygon_properties(dbg, dx, dy, poly, lon, lat, values, xres, yres, projN, Npolypts,     &
2257    xxtrm, yxtrm, meanctr, meanwctr, area, nval, xval, mval, m2val, stdval, Nquant, quant, nvcoord,   &
2258    xvcoord, meanvnctr, meanvxctr)
2259! Subroutine to determine the properties of a polygon (as .TRUE. matrix)
2260!   Number of grid points
2261!   grid-point coordinates of the minimum and maximum of the path along x,y axes
2262!   grid coordinates of center from the mean of the coordinates of the poygon locations
2263!   lon, lat center from the area weighted mean of the coordinates of the polygon locations
2264!   area of the polygon (km2)
2265!   minimum and maximum of the values within the polygon
2266!   mean of the values within the polygon
2267!   quadratic mean of the values within the polygon
2268!   standard deviation of the values within the polygon
2269!   number of quantiles
2270!   quantiles of the values within the polygon
2271!   grid coordinates of the minimum, maximum value within the polygon
2272!   lon, lat coordinates of the area center weighted and also by distance to the lowest or highest values of the polygon
2273
2274  IMPLICIT NONE
2275
2276  LOGICAL, INTENT(in)                                    :: dbg
2277  INTEGER, INTENT(in)                                    :: dx, dy, Nquant
2278  LOGICAL, DIMENSION(dx,dy), INTENT(in)                  :: poly
2279  REAL(r_k), DIMENSION(dx,dy), INTENT(in)                :: lon, lat, values
2280  REAL(r_k), INTENT(in)                                  :: xres, yres
2281  CHARACTER(len=1000), INTENT(in)                        :: projN
2282  INTEGER, INTENT(out)                                   :: Npolypts
2283  INTEGER, DIMENSION(2), INTENT(out)                     :: xxtrm, yxtrm, meanctr
2284  INTEGER, DIMENSION(2), INTENT(out)                     :: nvcoord, xvcoord
2285  REAL(r_k), DIMENSION(2), INTENT(out)                   :: meanwctr, meanvnctr, meanvxctr
2286  REAL(r_k), INTENT(out)                                 :: area
2287  REAL(r_k), INTENT(out)                                 :: nval, xval, mval, m2val, stdval
2288  REAL(r_k), DIMENSION(Nquant), INTENT(out)              :: quant
2289
2290! Local
2291  INTEGER                                                :: i, j, ip
2292  INTEGER                                                :: ierr
2293  INTEGER, DIMENSION(:,:), ALLOCATABLE                   :: polypts
2294  REAL(r_k), DIMENSION(:), ALLOCATABLE                   :: polyvals, distvn, distvx
2295  REAL(r_k)                                              :: lonNADIR, latNADIR
2296  REAL(r_k)                                              :: sumRESx, sumRESy
2297  REAL(r_k), DIMENSION(dx,dy)                            :: xcorr, ycorr
2298  CHARACTER(len=200), DIMENSION(3)                       :: satSvals
2299  CHARACTER(len=50)                                      :: projS
2300  REAL(r_k)                                              :: sumDISTnlon, sumDISTnlat, sumDISTxlon,   &
2301    sumDISTxlat
2302
2303!!!!!!! Variables
2304! dx,dy: size of the space
2305! poly: polygon matrix (boolean)
2306! lon, lat: geographical coordinates of the grid-points of the matrix
2307! values: values of the 2D field to use
2308! [x/y]res resolution along the x and y axis
2309! projN: name of the projection
2310!   'ctsarea': Constant Area
2311!   'lon/lat': for regular longitude-latitude
2312!   'nadir-sat,[lonNADIR],[latNADIR]': for satellite data with the resolution given at nadir (lonNADIR, latNADIR)
2313! Npolypts: number of points of the polygon
2314! [x/y]xtrm: grid-point coordinates of minimum and maximum coordinates of the polygon
2315! meanctr: center from the mean of the coordinates of the polygon
2316! meanwctr: lon, lat coordinates of the center from the spatial-weighted mean of the polygon
2317! area: area of the polygon [km]
2318! [n/x]val: minimum and maximum of the values within the polygon
2319! mval: mean of the values within the polygon
2320! m2val: quadratic mean of the values within the polygon
2321! stdval: standard deviation of the values within the polygon
2322! Nquant: number of quantiles
2323! quant: quantiles of the values within the polygon
2324! [n/x]vcoord: grid coordinates of the minimum/maximum of the values within the polygon
2325! meanv[n/x]ctr: lon, lat coordinates of the area center weighted and also by distance to the lowest or highest values of the polygon
2326
2327  fname = 'polygon_properties'
2328
2329  IF (dbg) PRINT *,"  '" // TRIM(fname) // "' ..."
2330
2331  ! Getting grid-point coordinates of the polygon
2332  Npolypts = COUNT(poly)
2333
2334  IF (ALLOCATED(polypts)) DEALLOCATE(polypts)
2335  ALLOCATE(polypts(Npolypts,2), STAT=ierr)
2336  msg = "Problems allocating 'polypts'"
2337  CALL ErrMsg(msg, fname, ierr)
2338
2339  IF (ALLOCATED(polyvals)) DEALLOCATE(polyvals)
2340  ALLOCATE(polyvals(Npolypts), STAT=ierr)
2341  msg = "Problems allocating 'polyvals'"
2342  CALL ErrMsg(msg, fname, ierr)
2343
2344  IF (ALLOCATED(distvn)) DEALLOCATE(distvn)
2345  ALLOCATE(distvn(Npolypts), STAT=ierr)
2346  msg = "Problems allocating 'distvn'"
2347  CALL ErrMsg(msg, fname, ierr)
2348
2349  IF (ALLOCATED(distvx)) DEALLOCATE(distvx)
2350  ALLOCATE(distvx(Npolypts), STAT=ierr)
2351  msg = "Problems allocating 'distvx'"
2352  CALL ErrMsg(msg, fname, ierr)
2353
2354  IF (projN(1:7) == 'lon/lat') THEN
2355    projS = projN
2356  ELSE IF (projN(1:7) == 'ctsarea') THEN
2357    projS = projN
2358  ELSE IF (projN(1:9) == 'nadir-sat') THEN
2359    projS = 'nadir-sat'
2360    CALL split(projN, ',', 3, satSvals)
2361    READ(satSvals(2),'(F200.100)')lonNadir
2362    READ(satSvals(3),'(F200.100)')latNadir
2363    IF (dbg) PRINT *,"  'nadir-geostationary-satellite' based projection of data with nadir " //      &
2364      "location at:", lonNadir, latNadir
2365  ELSE
2366    msg = "Projection '" // TRIM(projN) // "' not ready" // CHAR(10) // " available ones: " //        &
2367       "'ctsarea', 'lon/lat', 'nadir-sat'"
2368    CALL ErrMsg(msg,fname,-1)
2369  END IF
2370
2371  area = 0.
2372  sumRESx = 0.
2373  sumRESy = 0.
2374  meanwctr = 0.
2375  meanvnctr = 0.
2376  meanvxctr = 0.
2377  xcorr = 0.
2378  ycorr = 0.
2379
2380  nval = fillval64
2381  xval = -fillval64
2382
2383  ip = 1
2384  DO i=1,dx
2385    DO j=1,dy
2386      IF (poly(i,j)) THEN
2387        polypts(ip,1) = i
2388        polypts(ip,2) = j
2389        polyvals(ip) = values(i,j)
2390        SELECT CASE (TRIM(projS))
2391          CASE ('ctsarea')
2392            ! Constant Area
2393            xcorr(i,j) = 1.
2394            ycorr(i,j) = 1.
2395          CASE ('lon/lat')
2396            ! Area as fixed yres and sinus-lat varying for xres
2397!            IF (KIND(xcorr(i,j)) == KIND(1.d0)) THEN
2398!              xcorr(i,j) = DABS(DSIN(lon(i,j)*DegRad))
2399!            ELSE
2400              xcorr(i,j) = ABS(SIN(lon(i,j)*DegRad))
2401!            END IF
2402            ycorr(i,j) = 1.
2403          CASE ('nadir-sat')
2404            ! Area from nadir resolution and degrading as we get far from satellite's nadir
2405            ! GOES-E: 0 N, 75 W
2406!            IF (KIND(xcorr(i,j)) == KIND(1.d0)) THEN
2407!              xcorr(i,j) = DABS(DSIN(lon(i,j)*DegRad))
2408!            ELSE
2409              xcorr(i,j) = ABS(SIN(lon(i,j)*DegRad))
2410!            END IF
2411            ycorr(i,j) = 1.
2412        END SELECT
2413        area = area + xres*xcorr(i,j)*yres*ycorr(i,j)
2414        meanwctr(1) = meanwctr(1) + lon(i,j)*xres*xcorr(i,j)
2415        meanwctr(2) = meanwctr(2) + lat(i,j)*yres*ycorr(i,j)
2416        IF (nval > values(i,j)) THEN
2417          nvcoord(1) = i
2418          nvcoord(2) = j
2419          nval = values(i,j)
2420        END IF
2421        IF (xval < values(i,j)) THEN
2422          xvcoord(1) = i
2423          xvcoord(2) = j
2424          xval = values(i,j)
2425        END IF
2426        ip = ip + 1
2427      END IF
2428    END DO
2429  END DO
2430
2431  IF (dbg) THEN
2432    PRINT *,'  grid_coord lon lat value _______ '
2433    DO ip=1, Npolypts
2434      PRINT *, polypts(ip,:), ';', lon(polypts(ip,1),polypts(ip,2)), lat(polypts(ip,1),polypts(ip,2)),&
2435         ':', polyvals(ip)
2436    END DO
2437  END IF
2438
2439  sumRESx = xres*SUM(xcorr)
2440  sumRESy = yres*SUM(ycorr)
2441
2442  xxtrm = (/ MINVAL(polypts(:,1)), MAXVAL(polypts(:,1)) /)
2443  yxtrm = (/ MINVAL(polypts(:,2)), MAXVAL(polypts(:,2)) /)
2444  meanctr = (/ SUM(polypts(:,1))/Npolypts, SUM(polypts(:,2))/Npolypts /)
2445  meanwctr = (/ meanwctr(1)/sumRESx, meanwctr(2)/sumRESy /)
2446
2447  IF (dbg) THEN
2448    PRINT *,'  mean grid center: ', meanctr, ' weighted mean center: ', meanwctr
2449  END IF
2450
2451  ! Statistics of the values within the polygon
2452  CALL StatsR_K(Npolypts, polyvals, nval, xval, mval, m2val, stdval)
2453
2454  IF (dbg) THEN
2455    PRINT *,'    minimum value: ', nval, ' maximum:', xval, ' mean:', mval
2456    PRINT *,'    coor. minimum: ', nvcoord
2457    PRINT *,'    coor. maximum: ', xvcoord
2458  END IF
2459
2460  ! Mean center weighted to minimum and maximum values
2461!  IF (KIND(polyvals(1)) == KIND(1.d0)) THEN
2462!    distvn = DABS(polyvals - nval)
2463!    distvx = DABS(polyvals - xval)
2464!  ELSE
2465    distvn = ABS(polyvals - nval)
2466    distvx = ABS(polyvals - xval)
2467!  END IF
2468
2469  meanvnctr = 0.
2470  meanvxctr = 0.
2471  sumDISTnlon = 0.
2472  sumDISTnlat = 0.
2473  sumDISTxlon = 0.
2474  sumDISTxlat = 0.
2475
2476  ip = 1
2477  DO i=1,dx
2478    DO j=1,dy
2479      IF (poly(i,j)) THEN
2480        meanvnctr(1) = meanvnctr(1)+lon(i,j)*distvn(ip)*xres*xcorr(i,j)
2481        meanvnctr(2) = meanvnctr(2)+lat(i,j)*distvn(ip)*yres*ycorr(i,j)
2482
2483        meanvxctr(1) = meanvxctr(1)+lon(i,j)*distvx(ip)*xres*xcorr(i,j)     
2484        meanvxctr(2) = meanvxctr(2)+lat(i,j)*distvx(ip)*yres*ycorr(i,j)
2485
2486        sumDISTnlon = sumDISTnlon + distvn(ip)*xres*xcorr(i,j)
2487        sumDISTnlat = sumDISTnlat + distvn(ip)*yres*ycorr(i,j)
2488        sumDISTxlon = sumDISTxlon + distvx(ip)*xres*xcorr(i,j)
2489        sumDISTxlat = sumDISTxlat + distvx(ip)*yres*ycorr(i,j)
2490
2491        ip = ip + 1
2492      END IF
2493    END DO
2494  END DO
2495
2496  meanvnctr = (/ meanvnctr(1)/sumDISTnlon, meanvnctr(2)/sumDISTnlat /)
2497  meanvxctr = (/ meanvxctr(1)/sumDISTxlon, meanvxctr(2)/sumDISTxlat /)
2498
2499  IF (dbg) THEN
2500    PRINT *,'  mean center to minimum: ', meanvnctr, ' to maximum: ', meanvxctr
2501  END IF
2502
2503  ! Quantiles of the values within the polygon
2504  quant = -9999.d0
2505  IF (Npolypts > Nquant) THEN
2506    CALL quantilesR_K(Npolypts, polyvals, Nquant, quant)
2507  ELSE
2508    CALL SortR_K(polyvals, Npolypts)
2509  END IF
2510
2511  DEALLOCATE (polypts)
2512  DEALLOCATE (polyvals)
2513
2514  RETURN
2515
2516  END SUBROUTINE polygon_properties
2517
2518SUBROUTINE polygons_t(dbg, dx, dy, dt, boolmatt, polys, Npoly)
2519! Subroutine to search the polygons of a temporal series of boolean fields. FORTRAN based. 1st = 1!
2520
2521  IMPLICIT NONE
2522
2523  INTEGER, INTENT(in)                                    :: dx, dy, dt
2524  LOGICAL, DIMENSION(dx,dy,dt), INTENT(in)               :: boolmatt
2525  LOGICAL, INTENT(in)                                    :: dbg
2526  INTEGER, DIMENSION(dt), INTENT(out)                    :: Npoly
2527  INTEGER, DIMENSION(dx,dy,dt), INTENT(out)              :: polys
2528
2529! Local
2530  INTEGER                                                :: i,it
2531
2532!!!!!!! Variables
2533! dx,dy: spatial dimensions of the space
2534! boolmatt: boolean matrix tolook for the polygons (.TRUE. based)
2535! polys: found polygons
2536! Npoly: number of polygons found
2537
2538  fname = 'polygons'
2539
2540  IF (dbg) PRINT *,TRIM(fname)
2541
2542  polys = -1
2543  Npoly = 0
2544
2545  DO it=1,dt
2546    IF (ANY(boolmatt(:,:,it))) THEN
2547      IF (dbg) THEN
2548        PRINT *,'  it:', it, ' num. TRUE:', COUNT(boolmatt(:,:,it)), 'bool _______'
2549        DO i=1,dx
2550          PRINT *,boolmatt(i,:,it)
2551        END DO
2552      END IF
2553      CALL polygons(dbg, dx, dy, boolmatt(:,:,it), polys(:,:,it), Npoly(it))
2554    ELSE
2555      IF (dbg) THEN
2556        PRINT *,'  it:', it, " without '.TRUE.' values skipiing it!!"
2557      END IF
2558    END IF
2559  END DO
2560
2561END SUBROUTINE polygons_t
2562
2563SUBROUTINE polygons(dbg, dx, dy, boolmat, polys, Npoly)
2564! Subroutine to search the polygons of a boolean field. FORTRAN based. 1st = 1!
2565
2566  IMPLICIT NONE
2567
2568  INTEGER, INTENT(in)                                    :: dx, dy
2569  LOGICAL, DIMENSION(dx,dy), INTENT(in)                  :: boolmat
2570  LOGICAL, INTENT(in)                                    :: dbg
2571  INTEGER, INTENT(out)                                   :: Npoly
2572  INTEGER, DIMENSION(dx,dy), INTENT(out)                 :: polys
2573
2574! Local
2575  INTEGER                                                :: i, j, ip, ipp, Nppt
2576  INTEGER                                                :: ierr
2577  INTEGER, DIMENSION(:,:), ALLOCATABLE                   :: borders
2578  LOGICAL, DIMENSION(dx,dy)                              :: isborder, isbordery, borderp
2579  INTEGER, DIMENSION(:,:,:), ALLOCATABLE                 :: paths
2580  INTEGER                                                :: Npath
2581  INTEGER, DIMENSION(:), ALLOCATABLE                     :: Nptpaths
2582  INTEGER, DIMENSION(2)                                  :: xtrx, xtry, meanpth
2583  INTEGER                                                :: Nvertx, Npts
2584  INTEGER, DIMENSION(:,:), ALLOCATABLE                   :: vertxs, points
2585  LOGICAL, DIMENSION(:), ALLOCATABLE                     :: isin
2586  CHARACTER(len=1000)                                    :: boundsS
2587
2588!!!!!!! Variables
2589! dx,dy: spatial dimensions of the space
2590! boolmat: boolean matrix tolook for the polygons (.TRUE. based)
2591! polys: found polygons
2592! Npoly: number of polygons found
2593
2594  fname = 'polygons'
2595
2596  polys = -1
2597
2598  ! The mathematical maximum woiuld be dx*dy/4, but let's be optimistic... (sorry Jero)
2599  Nppt = dx*dy/100
2600
2601  IF (ALLOCATED(borders)) DEALLOCATE(borders)
2602  ALLOCATE(borders(Nppt,2), STAT=ierr)
2603  msg = "Problems allocating matrix 'borders'"
2604  CALL ErrMsg(msg, fname, ierr)
2605
2606  IF (ALLOCATED(paths)) DEALLOCATE(paths)
2607  ALLOCATE(paths(Nppt,Nppt,2), STAT=ierr)
2608  boundsS = vectorI_S(3, (/Nppt, Nppt, 2/))
2609  msg = "Problems allocating matrix 'paths' shape: " // TRIM(boundsS) // " try to reduce Nppt " //    &
2610    "and recompile"
2611  CALL ErrMsg(msg, fname, ierr)
2612
2613  IF (ALLOCATED(Nptpaths)) DEALLOCATE(Nptpaths)
2614  ALLOCATE(Nptpaths(Nppt), STAT=ierr)
2615  msg = "Problems allocating matrix 'Nptpaths'"
2616  CALL ErrMsg(msg, fname, ierr)
2617
2618  ! Filling with the points of all the space with .TRUE.
2619  Npts = COUNT(boolmat)
2620  PRINT * ,'Lluis Npts:', Npts, 'Nppt:', Nppt
2621
2622  IF (ALLOCATED(points)) DEALLOCATE(points)
2623  ALLOCATE(points(Npts,2), STAT=ierr)
2624  msg = "Problems allocating matrix 'points'"
2625  CALL ErrMsg(msg, fname, ierr)
2626
2627  ! We only want to localize that points 'inside'
2628  ip = 1
2629  DO i=1, dx
2630    DO j=1, dy
2631      IF (boolmat(i,j)) THEN
2632        points(ip,1) = i
2633        points(ip,2) = j
2634        ip = ip + 1
2635      END IF
2636    END DO
2637  END DO
2638
2639  CALL borders_matrixL(dbg, dx, dy, Nppt, boolmat, borders, isborder, isbordery)
2640  CALL paths_border(dbg, dx, dy, isborder, Nppt, borders, paths, Npath, Nptpaths)
2641
2642  Npoly = Npath
2643
2644  DO ip=1, Npath
2645    IF (ALLOCATED(vertxs)) DEALLOCATE(vertxs)
2646    ALLOCATE(vertxs(Nptpaths(ip),2))
2647    msg = "Problems allocating matrix 'vertxs'"
2648    CALL ErrMsg(msg, fname, ierr)
2649
2650    IF (ALLOCATED(isin)) DEALLOCATE(isin)
2651    ALLOCATE(isin(Npts), STAT=ierr)
2652    msg = "Problems allocating matrix 'isin'"
2653    CALL ErrMsg(msg, fname, ierr)
2654
2655    isin = .FALSE.
2656
2657    IF (dbg) THEN
2658      PRINT *, '  path:', ip, ' N pts:', Nptpaths(ip)
2659      DO j=1, Nptpaths(ip)
2660        PRINT *, '      ',j,':',paths(ip,j,:)
2661      END DO
2662    END IF
2663
2664    borderp = .FALSE.
2665    DO j=1,Nptpaths(ip)
2666      borderp(paths(ip,j,1),paths(ip,j,2)) = .TRUE.
2667    END DO
2668
2669    CALL path_properties(dx, dy, boolmat, Nptpaths(ip), paths(ip,1:Nptpaths(ip),:), xtrx, xtry,       &
2670      meanpth, 'y', Nvertx, vertxs)
2671
2672    IF (dbg) THEN
2673      PRINT *, '    properties  _______'
2674      PRINT *, '    x-extremes:', xtrx
2675      PRINT *, '    y-extremes:', xtry
2676      PRINT *, '    center mean:', meanpth
2677      PRINT *, '    y-vertexs:', Nvertx,' ________'
2678      DO i=1, Nvertx
2679        PRINT *,'      ',i,':',vertxs(i,:)
2680      END DO
2681    END IF
2682 
2683    CALL gridpoints_InsidePolygon(dbg, dx, dy, isbordery, Nptpaths(ip), paths(ip,1:Nptpaths(ip),:),   &
2684      Nvertx, xtrx, xtry, vertxs, Npts, points, isin)
2685
2686    ! Filling polygons
2687    DO ipp=1, Npts
2688      IF (isin(ipp)) polys(points(ipp,1),points(ipp,2)) = ip
2689    END DO
2690
2691    IF (dbg) THEN
2692      PRINT *,'  boolmat isborder isbordery polygon (',xtrx(1),',',xtry(1),')x(',xtrx(2),',',xtry(2), &
2693        ') _______'
2694      DO i=xtrx(1), xtrx(2)
2695        PRINT *,i,':',boolmat(i,xtry(1):xtry(2)), ' border ', isborder(i,xtry(1):xtry(2)),            &
2696          ' isbordery ', isbordery(i,xtry(1):xtry(2)), ' polygon ', polys(i,xtry(1):xtry(2))
2697      END DO
2698    END IF
2699
2700  END DO
2701
2702  ! Cleaning polygons matrix of not-used and paths around holes
2703  CALL clean_polygons(dx, dy, boolmat, polys, Npoly, dbg)
2704
2705  IF (ALLOCATED(borders)) DEALLOCATE (borders)
2706  IF (ALLOCATED(Nptpaths)) DEALLOCATE (Nptpaths)
2707  IF (ALLOCATED(paths)) DEALLOCATE (paths)
2708  IF (ALLOCATED(vertxs)) DEALLOCATE (vertxs)
2709  IF (ALLOCATED(points)) DEALLOCATE (points)
2710  IF (ALLOCATED(isin)) DEALLOCATE (isin)
2711
2712  RETURN
2713
2714END SUBROUTINE polygons
2715
2716SUBROUTINE clean_polygons(dx, dy, Lmat, pols, Npols, dbg)
2717! Subroutine to clean polygons from non-used paths, polygons only left as path since they are inner path of a hole
2718
2719  IMPLICIT NONE
2720
2721  INTEGER, INTENT(in)                                    :: dx, dy
2722  LOGICAL, DIMENSION(dx,dy), INTENT(in)                  :: Lmat
2723  INTEGER, INTENT(inout)                                 :: Npols
2724  INTEGER, DIMENSION(dx,dy), INTENT(inout)               :: pols
2725  LOGICAL, INTENT(in)                                    :: dbg
2726
2727! Local
2728  INTEGER                                                :: i,j,ip,iprm
2729  INTEGER, DIMENSION(Npols)                              :: origPol, NotPol, neigPol
2730  INTEGER                                                :: ispol, NnotPol
2731  CHARACTER(len=4)                                       :: ISa
2732
2733!!!!!!! Variables
2734! dx, dy: size of the space
2735! Lmat: original bolean matrix from which the polygons come from
2736! Npols: original number of polygons
2737! pols: polygons space
2738
2739  fname = 'clean_polygons'
2740  IF (dbg) PRINT *,"  At '" // TRIM(fname) // "' ..."
2741
2742  origPol = -1
2743
2744  ! Looking for polygons already in space
2745  NnotPol = 0
2746  DO ip=1, Npols
2747    ispol = COUNT(pols-ip == 0)
2748    IF (ispol > 0) THEN
2749      origPol(ip) = ip
2750    ELSE
2751      NnotPol = NnotPol + 1
2752      NotPol(NnotPol) = ip
2753      neigPol(NnotPol) = -1
2754    END IF
2755  END DO
2756
2757  IF (NnotPol == Npols) THEN
2758    PRINT *,'  ' // TRIM(fname) // ": avoiding to remove all polygons !!"
2759    NnotPol = 0
2760  END IF
2761
2762  IF (dbg) THEN
2763    PRINT *,'  It should be:', Npols, ' polygons, but already there are:', Npols - NnotPol
2764    PRINT *,'  Polygons to remove:', NotPol(1:NnotPol)
2765  END IF
2766 
2767  ! Looking for the hole border of a polygon. This is identify as such polygon point which along
2768  !   y-axis has NpolygonA, Npolygon, .FALSE.
2769  DO i=1,dx
2770    DO j=2,dy-1
2771      IF  ( (pols(i,j-1) /= pols(i,j) .AND. pols(i,j+1) == -1) .AND. (COUNT(NotPol-pols(i,j)==0)==0)  &
2772        .AND. (pols(i,j) /= -1) .AND. (pols(i,j-1) /= -1)) THEN
2773        IF (dbg) PRINT *,'  Polygon:', pols(i,j), ' to be removed at point (',i,',',j,'); j-1:',      &
2774          pols(i,j-1), ' j:', pols(i,j), ' j+1:', pols(i,j+1)
2775        NnotPol = NnotPol + 1
2776        NotPol(NnotPol) = pols(i,j)
2777        neigPol(NnotPol) = pols(i,j-1)
2778      END IF
2779    END DO
2780  END DO
2781
2782  IF (dbg) THEN
2783    PRINT *,'  It should be:', Npols, ' polygons, but already there are:', Npols - NnotPol
2784    PRINT *,'  Polygons to remove after looking for fake border-of-hole polygons _______'
2785    DO i=1, NnotPol
2786      PRINT *, '      Polygon:', NotPol(i), ' to be replaced by:', neigPol(i)
2787    END DO
2788  END IF
2789
2790  ! Removing polygons
2791  DO iprm=1, NnotPol
2792    IF (neigPol(iprm) == -1) THEN
2793      WHERE (pols == NotPol(iprm))
2794        pols = -1
2795      END WHERE
2796      IF (dbg) THEN
2797        PRINT *,'    removing polygon:', NotPol(iprm)
2798      END IF
2799    ELSE
2800      WHERE (pols == NotPol(iprm))
2801        pols = neigPol(iprm)
2802      END WHERE
2803      IF (dbg) THEN
2804        PRINT *,'       replacing polygon:', NotPol(iprm), ' by:', neigPol(iprm)
2805      END IF
2806    END IF
2807  END DO
2808
2809  ! Re-numbering (descending values)
2810  DO i = 1, NnotPol
2811    iprm = MAXVAL(NotPol(1:NnotPol))
2812    WHERE(pols > iprm)
2813      pols = pols - 1
2814    END WHERE
2815    j = Index1DArrayI(NotPol, NnotPol, iprm)
2816    NotPol(j) = -9
2817  END DO
2818
2819  Npols = Npols - NnotPol
2820
2821  RETURN
2822
2823END SUBROUTINE clean_polygons
2824
2825  SUBROUTINE path_properties(dx, dy, Lmat, Nptspth, pth, xxtrm, yxtrm, meanctr, axs, Nvrtx, vrtxs)
2826! Subroutine to determine the properties of a path:
2827!   extremes: minimum and maximum of the path along x,y axes
2828!   meancenter: center from the mean of the coordinates of the paths locations
2829!   vertexs: path point, without neighbours along a given axis
2830
2831  IMPLICIT NONE
2832
2833  INTEGER, INTENT(in)                                    :: dx, dy, Nptspth
2834  LOGICAL, DIMENSION(dx,dy), INTENT(in)                  :: Lmat
2835  INTEGER, DIMENSION(Nptspth,2), INTENT(in)              :: pth
2836  CHARACTER, INTENT(in)                                  :: axs
2837  INTEGER, DIMENSION(2), INTENT(out)                     :: meanctr, xxtrm, yxtrm
2838  INTEGER, INTENT(out)                                   :: Nvrtx
2839  INTEGER, DIMENSION(Nptspth,2), INTENT(out)             :: vrtxs
2840
2841! Local
2842  INTEGER                                                :: i, ip, jp
2843  INTEGER                                                :: neig1, neig2
2844
2845!!!!!!! Variables
2846! dx,dy: size of the space
2847! Lmat: original matrix of logical values for the path
2848! Nptspth: number of points of the path
2849! pth: path coordinates (clockwise)
2850! axs: axis of finding the vertex
2851! [x/y]xtrm: minimum and maximum coordinates of the path
2852! meanctr: center from the mean of the coordinates of the path
2853! Nvrtx: Number of vertexs of the path
2854! vrtxs: coordinates of the vertexs
2855
2856  fname = 'path_properties'
2857
2858  vrtxs = -1
2859  Nvrtx = 0
2860
2861  xxtrm = (/ MINVAL(pth(:,1)), MAXVAL(pth(:,1)) /)
2862  yxtrm = (/ MINVAL(pth(:,2)), MAXVAL(pth(:,2)) /)
2863  meanctr = (/ SUM(pth(:,1))/Nptspth, SUM(pth(:,2))/Nptspth /)
2864
2865  IF (axs == 'x' .OR. axs == 'X') THEN
2866    ! Looking vertexs along x-axis
2867    DO i=1, Nptspth
2868      ip = pth(i,1)
2869      jp = pth(i,2)
2870      neig1 = 0
2871      neig2 = 0
2872      ! W-point
2873      IF (ip == 1) THEN
2874        neig1 = -1
2875      ELSE
2876        IF (.NOT.Lmat(ip-1,jp)) neig1 = -1
2877      END IF
2878      ! E-point
2879      IF (ip == dx) THEN
2880        neig2 = -1
2881      ELSE
2882        IF (.NOT.Lmat(ip+1,jp)) neig2 = -1
2883      END IF
2884   
2885      IF (neig1 == -1 .AND. neig2 == -1) THEN
2886        Nvrtx = Nvrtx + 1
2887        vrtxs(Nvrtx,:) = (/ip,jp/)
2888      END IF
2889    END DO
2890  ELSE IF (axs == 'y' .OR. axs == 'Y') THEN
2891    ! Looking vertexs along x-axis
2892    DO i=1, Nptspth
2893      ip = pth(i,1)
2894      jp = pth(i,2)
2895
2896      neig1 = 0
2897      neig2 = 0
2898      ! S-point
2899      IF (jp == 1) THEN
2900        neig1 = -1
2901      ELSE
2902        IF (.NOT.Lmat(ip,jp-1)) neig1 = -1
2903      END IF
2904      ! N-point
2905      IF (jp == dy) THEN
2906        neig2 = -1
2907      ELSE
2908        IF (.NOT.Lmat(ip,jp+1)) neig2 = -1
2909      END IF
2910
2911      IF (neig1 == -1 .AND. neig2 == -1) THEN
2912        Nvrtx = Nvrtx + 1
2913        vrtxs(Nvrtx,:) = (/ ip, jp /)
2914      END IF
2915    END DO
2916  ELSE
2917    msg = "Axis '" // axs // "' not available" // CHAR(10) // "  Available ones: 'x', 'X', 'y, 'Y'"
2918    CALL ErrMsg(msg, fname, -1)
2919  END IF
2920
2921  RETURN
2922
2923  END SUBROUTINE path_properties
2924
2925  SUBROUTINE gridpoints_InsidePolygon(dbg, dx, dy, isbrdr, Npath, path, Nvrtx, xpathxtrm, ypathxtrm,  &
2926    vrtxs, Npts, pts, inside)
2927! Subroutine to determine if a series of grid points are inside a polygon following ray casting algorithm
2928! FROM: https://en.wikipedia.org/wiki/Point_in_polygon
2929
2930  IMPLICIT NONE
2931
2932  INTEGER, INTENT(in)                                    :: dx,dy,Npath,Nvrtx,Npts
2933  LOGICAL, INTENT(in)                                    :: dbg
2934  LOGICAL, DIMENSION(dx,dy), INTENT(in)                  :: isbrdr
2935  INTEGER, DIMENSION(Npath,2), INTENT(in)                :: path
2936  INTEGER, DIMENSION(2), INTENT(in)                      :: xpathxtrm, ypathxtrm
2937  INTEGER, DIMENSION(Npath,2)                            :: vrtxs
2938  INTEGER, DIMENSION(Npts,2), INTENT(in)                 :: pts
2939  LOGICAL, DIMENSION(Npts), INTENT(out)                  :: inside
2940
2941! Local
2942  INTEGER                                                :: i,j,ip,ix,iy
2943  INTEGER                                                :: Nintersecs, isvertex, ispath
2944  INTEGER                                                :: ierr
2945  LOGICAL, DIMENSION(:,:), ALLOCATABLE                   :: halo_brdr
2946  INTEGER                                                :: Nbrbrdr
2947
2948!!!!!!! Variables
2949! dx,dy: space size
2950! Npath: number of points of the path of the polygon
2951! path: path of the polygon
2952! isbrdr: boolean matrix of the space wqith .T. on polygon border
2953! Nvrtx: number of vertexs of the path
2954! [x/y]pathxtrm extremes of the path
2955! vrtxs: vertexs of the path along y-axis
2956! Npts: number of points
2957! pts: points to look for
2958! inside: vector wether point is inside or not (coincident to a border is inside)
2959
2960  fname = 'gridpoints_InsidePolygon'
2961
2962  ! Creation of a 1-grid point larger matrix to deal with points reaching the limits
2963  IF (ALLOCATED(halo_brdr)) DEALLOCATE(halo_brdr)
2964  ALLOCATE(halo_brdr(dx+2,dy+2), STAT=ierr)
2965  msg = "Problems allocating matrix 'halo_brdr'"
2966  CALL ErrMsg(msg, fname, ierr)
2967  halo_brdr = .FALSE.
2968
2969  IF (dbg) PRINT *,'Border _______'
2970  DO i=1,dx
2971    halo_brdr(i+1,2:dy+1) = isbrdr(i,:)
2972    IF (dbg) PRINT *,isbrdr(i,:)
2973  END DO
2974
2975  inside = .FALSE.
2976
2977  DO ip=1,Npts
2978    Nintersecs = 0
2979    ix = pts(ip,1)
2980    iy = pts(ip,2)
2981    ! Point might be outside path range...
2982    IF (ix >= xpathxtrm(1) .AND. ix <= xpathxtrm(2) .AND. iy >= ypathxtrm(1) .AND.                    &
2983      iy <= ypathxtrm(2)) THEN
2984
2985      ! It is a border point?
2986      ispath = index_list_coordsI(Npath, path, (/ix,iy/))
2987      IF (isbrdr(ix,iy) .AND. (ispath /= -1)) THEN
2988        inside(ip) = .TRUE.
2989        CYCLE
2990      END IF
2991
2992      ! Looking along y-axis
2993      ! Accounting for consecutives borders
2994      Nbrbrdr = 0
2995      DO j=MAX(1,ypathxtrm(1)-1),iy-1
2996        ! Only counting that borders that are not vertexs
2997        ispath = index_list_coordsI(Npath, path, (/ix,j/))
2998        isvertex = index_list_coordsI(Npath, vrtxs, (/ix,j/))
2999
3000        IF (halo_brdr(ix+1,j+1) .AND. (ispath /= -1) .AND. (isvertex == -1) ) Nintersecs = Nintersecs + 1
3001        IF (halo_brdr(ix+1,j+1) .AND. (ispath /= -1) .AND. (halo_brdr(ix+1,j+1) .EQV. halo_brdr(ix+1,j+2))) THEN
3002          Nbrbrdr = Nbrbrdr + 1
3003          IF (dbg) PRINT *,'    ',Nbrbrdr,' Consec brdrs:', halo_brdr(ix+1,j+1), halo_brdr(ix+1,j+2), &
3004             '(', ix,j,';', ix,j+1,')', isbrdr(ix,j), isbrdr(ix,j+1)
3005        ELSE
3006          ! Will remove that consecutive borders above 2
3007          IF (Nbrbrdr /= 0) THEN
3008            IF (dbg) PRINT *, ix,',',iy,';', Nintersecs, '  amount of consecutive borders:', Nbrbrdr, &
3009              ' removing:', MAX(Nbrbrdr-1, 0)
3010            Nintersecs = Nintersecs - MAX(Nbrbrdr-1, 0)
3011            Nbrbrdr = 0
3012          END IF
3013        END IF
3014      END DO
3015      IF (MOD(Nintersecs,2) /= 0) inside(ip) = .TRUE.
3016      IF (dbg) PRINT *,ip,'    point:', ix, iy, 'isbrdr:', isbrdr(ix,1:iy-1), 'y-ray:', halo_brdr(ix+1,1:iy), 'inside:', inside(ip)
3017    END IF
3018
3019  END DO
3020
3021  RETURN
3022
3023END SUBROUTINE gridpoints_InsidePolygon
3024
3025SUBROUTINE look_clockwise_borders(dx,dy,Nbrdrs,brdrs,gbrdr,isbrdr,ix,iy,dbg,xf,yf,iff)
3026! Subroutine to look clock-wise for a next point within a collection of borders (limits of a region)
3027
3028  IMPLICIT NONE
3029
3030  INTEGER, INTENT(in)                                    :: dx, dy, Nbrdrs, ix, iy
3031  INTEGER, DIMENSION(Nbrdrs,2), INTENT(in)               :: brdrs
3032  LOGICAL, DIMENSION(Nbrdrs), INTENT(in)                 :: gbrdr
3033  LOGICAL, DIMENSION(dx,dy), INTENT(in)                  :: isbrdr
3034  LOGICAL, INTENT(in)                                    :: dbg
3035  INTEGER, INTENT(out)                                   :: xf, yf, iff
3036
3037! Local
3038  INTEGER                                                :: isch
3039  CHARACTER(len=2), DIMENSION(8)                         :: Lclock
3040  INTEGER, DIMENSION(8,2)                                :: spt
3041  INTEGER                                                :: iif, jjf
3042
3043!!!!!!! Variables
3044! dx, dy: 2D shape ot the space
3045! Nbrdrs: number of brdrs found in this 2D space
3046! brdrs: list of coordinates of the borders
3047! gbrdr: accounts for the use if the given border point
3048! isbrdr: accounts for the matrix of the point is a border or not
3049! ix,iy: coordinates of the point to start to find for
3050! xf,yf: coordinates of the found point
3051! iff: position of the border found within the list of borders
3052
3053  fname = 'look_clockwise_borders'
3054
3055  ! Looking clock-wise assuming that one starts from the westernmost point
3056
3057  ! Label of the search
3058  lclock = (/ 'W ', 'NW', 'N ', 'NE', 'E ', 'SE', 'S ', 'SW' /)
3059  ! Transformation to apply
3060  !spt = (/ (/-1,0/), (/-1,1/), (/0,1/), (/1,1/), (/1,0/), (/1,-1/), (/0,-1/), (/-1,-1/) /)
3061  spt(:,1) = (/ -1, -1, 0, 1, 1, 1, 0, -1 /)
3062  spt(:,2) = (/ 0, 1, 1, 1, 0, -1, -1, -1 /)
3063
3064  xf = -1
3065  yf = -1
3066  DO isch=1, 8
3067    ! clock-wise search
3068    IF (spt(isch,1) >= 0) THEN
3069      iif = MIN(dx,ix+spt(isch,1))
3070    ELSE
3071      iif = MAX(1,ix+spt(isch,1))
3072    END IF
3073    IF (spt(isch,2) >= 0) THEN
3074      jjf = MIN(dy,iy+spt(isch,2))
3075    ELSE
3076      jjf = MAX(1,iy+spt(isch,2))
3077    END IF
3078    iff = index_list_coordsI(Nbrdrs, brdrs,(/iif,jjf/))
3079    IF (iff > 0) THEN
3080      IF (dbg) PRINT *,'    ' // lclock(isch) // '-point:', iif,jjf, ':', iff, 'is',isbrdr(iif,jjf),  &
3081        'got',gbrdr(iff)
3082      IF (isbrdr(iif,jjf) .AND. .NOT.gbrdr(iff)) THEN
3083        xf = iif
3084        yf = jjf
3085        EXIT
3086      END IF
3087    END IF
3088  END DO
3089
3090  RETURN
3091
3092END SUBROUTINE look_clockwise_borders
3093
3094SUBROUTINE borders_matrixL(dbg,dx,dy,dxy,Lmat,brdrs,isbrdr,isbrdry)
3095! Subroutine to provide the borders of a logical array (interested in .TRUE.)
3096
3097  IMPLICIT NONE
3098
3099  INTEGER, INTENT(in)                                    :: dx,dy,dxy
3100  LOGICAL, INTENT(in)                                    :: dbg
3101  LOGICAL, DIMENSION(dx,dy), INTENT(in)                  :: Lmat
3102  INTEGER, DIMENSION(dxy,2), INTENT(out)                 :: brdrs
3103  LOGICAL, DIMENSION(dx,dy), INTENT(out)                 :: isbrdr, isbrdry
3104
3105! Local
3106  INTEGER                                                :: i,j,ib
3107
3108!!!!!!! Variables
3109! dx,dy: size of the space
3110! dxy: maximum number of border points
3111! Lmat: Matrix to look for the borders
3112! brdrs: list of coordinates of the borders
3113! isbrdr: matrix with .T./.F. wether the given matrix point is a border or not
3114! isbrdry: matrix with .T./.F. wether the given matrix point is a border or not only along y-axis
3115
3116  fname = 'borders_matrixL'
3117
3118  isbrdr = .FALSE.
3119  brdrs = -1
3120  ib = 1
3121
3122  ! Starting with the borders. If a given point is TRUE it is a path-vertex
3123  ! Along y-axis
3124  DO i=1, dx
3125    IF (Lmat(i,1) .AND. .NOT.isbrdr(i,1)) THEN
3126      brdrs(ib,1) = i
3127      brdrs(ib,2) = 1
3128      isbrdr(i,1) = .TRUE.
3129      ib=ib+1
3130    END IF
3131    IF (Lmat(i,dy) .AND. .NOT.isbrdr(i,dy)) THEN
3132      brdrs(ib,1) = i
3133      brdrs(ib,2) = dy
3134      isbrdr(i,dy) = .TRUE.
3135      ib=ib+1
3136    END IF
3137  END DO
3138  ! Along x-axis
3139  DO j=1, dy
3140    IF (Lmat(1,j) .AND. .NOT.isbrdr(1,j)) THEN
3141      brdrs(ib,1) = 1
3142      brdrs(ib,2) = j
3143      isbrdr(1,j) = .TRUE.
3144      ib=ib+1
3145     END IF
3146    IF (Lmat(dx,j) .AND. .NOT.isbrdr(dx,j)) THEN
3147      brdrs(ib,1) = dx
3148      brdrs(ib,2) = j
3149      isbrdr(dx,j) = .TRUE.
3150      ib=ib+1
3151    END IF
3152  END DO
3153
3154  isbrdry = isbrdr
3155
3156  ! Border as that when looking on x-axis points with Lmat(i) /= Lmat(i+1)
3157  DO i=1, dx-1
3158    DO j=1, dy-1
3159      IF ( Lmat(i,j) .NEQV. Lmat(i+1,j) ) THEN
3160        IF (Lmat(i,j) .AND. .NOT.isbrdr(i,j)) THEN
3161          brdrs(ib,1) = i
3162          brdrs(ib,2) = j
3163          isbrdr(i,j) = .TRUE.
3164          ib=ib+1
3165        ELSE IF (Lmat(i+1,j) .AND. .NOT.isbrdr(i+1,j)) THEN
3166          brdrs(ib,1) = i+1
3167          brdrs(ib,2) = j
3168          isbrdr(i+1,j) = .TRUE.
3169          ib=ib+1
3170        END IF
3171      END IF
3172      ! y-axis
3173      IF ( Lmat(i,j) .NEQV. Lmat(i,j+1) ) THEN
3174        IF (Lmat(i,j) .AND. .NOT.isbrdr(i,j)) THEN
3175          brdrs(ib,1) = i
3176          brdrs(ib,2) = j
3177          isbrdr(i,j) = .TRUE.
3178          isbrdry(i,j) = .TRUE.
3179          ib=ib+1
3180        ELSE IF (Lmat(i,j+1) .AND. .NOT.isbrdr(i,j+1)) THEN
3181          brdrs(ib,1) = i
3182          brdrs(ib,2) = j+1
3183          isbrdr(i,j+1) = .TRUE.
3184          isbrdry(i,j+1) = .TRUE.
3185          ib=ib+1
3186        END IF
3187      END IF
3188    END DO       
3189  END DO
3190
3191  DO i=1, dx-1
3192    DO j=1, dy-1
3193      ! y-axis
3194      IF ( Lmat(i,j) .NEQV. Lmat(i,j+1) ) THEN
3195        IF (Lmat(i,j)) THEN
3196          isbrdry(i,j) = .TRUE.
3197        ELSE IF (Lmat(i,j+1)) THEN
3198          isbrdry(i,j+1) = .TRUE.
3199        END IF
3200      END IF
3201    END DO       
3202  END DO
3203  ! only y-axis adding bands of 2 grid points
3204  DO i=1, dx-1
3205    DO j=2, dy-2
3206      IF ( (Lmat(i,j) .EQV. Lmat(i,j+1)) .AND. (Lmat(i,j).NEQV.Lmat(i,j-1)) .AND. (Lmat(i,j).NEQV.Lmat(i,j+2)) ) THEN
3207        IF (Lmat(i,j)) THEN
3208          isbrdry(i,j) = .TRUE.
3209          isbrdry(i,j+1) = .TRUE.
3210        END IF
3211      END IF
3212    END DO       
3213  END DO
3214
3215  IF (dbg) THEN
3216    PRINT *,' BORDERS _______ x y'
3217    DO i=1,dx
3218      PRINT *,isbrdr(i,:), '       ', isbrdry(i,:)
3219    END DO
3220  END IF
3221
3222  RETURN
3223
3224END SUBROUTINE borders_matrixL
3225
3226SUBROUTINE paths_border(dbg, dx, dy, isborder, Nppt, borders, paths, Npath, Nptpaths)
3227! Subroutine to search the paths of a border field.
3228
3229  IMPLICIT NONE
3230
3231  INTEGER, INTENT(in)                                    :: dx, dy, Nppt
3232  LOGICAL, INTENT(in)                                    :: dbg
3233  LOGICAL, DIMENSION(dx,dy), INTENT(in)                  :: isborder
3234  INTEGER, DIMENSION(Nppt,2), INTENT(in)                 :: borders
3235  INTEGER, DIMENSION(Nppt,Nppt,2), INTENT(out)           :: paths
3236  INTEGER, INTENT(out)                                   :: Npath
3237  INTEGER, DIMENSION(Nppt), INTENT(out)                  :: Nptpaths
3238
3239! Local
3240  INTEGER                                                :: i,j,k,ib
3241  INTEGER                                                :: ierr
3242  INTEGER                                                :: Nbrdr
3243  LOGICAL, DIMENSION(:), ALLOCATABLE                     :: gotbrdr, emptygotbrdr
3244  INTEGER                                                :: iipth, ipath, ip, Nptspath
3245  INTEGER                                                :: iib, jjb, iip, ijp, iif, jjf, iff
3246  LOGICAL                                                :: found, finishedstep
3247
3248!!!!!!! Variables
3249! dx,dy: spatial dimensions of the space
3250! Nppt: possible number of paths and points that the paths can have
3251! isborder: boolean matrix which provide the borders of the polygon
3252! borders: coordinates of the borders of the polygon
3253! paths: coordinates of each found path
3254! Npath: number of paths found
3255! Nptpaths: number of points per path
3256
3257  fname = 'paths_border'
3258
3259  IF (dbg) PRINT *, TRIM(fname) // ' ...'
3260
3261  ! Sarting matrix
3262  paths = -1
3263  Npath = 0
3264  Nptspath = 0
3265  Nptpaths = -1
3266
3267  ib=1
3268  finishedstep = .FALSE.
3269
3270  ! Number of border points
3271  DO ib=1, Nppt
3272    IF (borders(ib,1) == -1 ) EXIT
3273  END DO
3274  Nbrdr = ib-1
3275   
3276  IF (dbg) THEN
3277    PRINT *,'  isborder ______'
3278    DO i=1,dx
3279      PRINT *,isborder(i,:)
3280    END DO
3281
3282    PRINT *,'    borders _______'
3283    DO i=1,Nbrdr
3284      PRINT *,'    ',i,':',borders(i,:)
3285    END DO
3286  END IF
3287
3288  ! Matrix which keeps track if a border point has been located
3289  IF (ALLOCATED(gotbrdr)) DEALLOCATE(gotbrdr)
3290  ALLOCATE(gotbrdr(Nbrdr), STAT=ierr)
3291  msg = "Problems allocating matrix 'gotbrdr'"
3292  CALL ErrMsg(msg, fname, ierr)
3293  IF (ALLOCATED(emptygotbrdr)) DEALLOCATE(emptygotbrdr)
3294  ALLOCATE(emptygotbrdr(Nbrdr), STAT=ierr)
3295  msg = "Problems allocating matrix 'emptygotbrdr'"
3296  CALL ErrMsg(msg, fname, ierr)
3297
3298  gotbrdr = .FALSE.
3299  emptygotbrdr = .FALSE.
3300
3301  ! Starting the fun...
3302   
3303  ! Looking along the lines and when a border is found, starting from there in a clock-wise way
3304  iipth = 1
3305  ipath = 1   
3306  DO ib=1,Nbrdr
3307    iib = borders(iipth,1)
3308    jjb = borders(iipth,2)
3309    ! Starting new path
3310    newpath: IF (.NOT.gotbrdr(iipth)) THEN
3311      ip = 1
3312      Nptspath = 1
3313      paths(ipath,ip,:) = borders(iipth,:)
3314      gotbrdr(iipth) = .TRUE.
3315      ! Looking for following clock-wise search
3316      ! Not looking for W, because search starts from the W
3317      iip = iib
3318      ijp = jjb
3319      DO k=1,Nbrdr
3320        IF (dbg) PRINT *,ipath,'iip jip:', iip, ijp
3321        found = .FALSE.
3322        CALL look_clockwise_borders(dx,dy,Nppt,borders,gotbrdr,isborder,iip,ijp,dbg,iif,jjf,iff)
3323        IF (iif /= -1) THEN
3324          ip=ip+1
3325          paths(ipath,ip,:) = (/ iif,jjf /)
3326          found = .TRUE.
3327          gotbrdr(iff) = .TRUE.
3328          iip = iif
3329          ijp = jjf
3330          Nptspath = Nptspath + 1         
3331        END IF
3332
3333        IF (dbg) THEN
3334          PRINT *,iib,jjb,'    end of this round path:', ipath, '_____', gotbrdr
3335          DO i=1, Nptspath
3336            PRINT *,'      ',i,':',paths(ipath,i,:)
3337          END DO
3338        END IF
3339        ! If it is not found a next point, might be because it is a non-polygon related value
3340        IF (.NOT.found) THEN
3341          IF (dbg) PRINT *,'NOT FOUND !!!', gotbrdr
3342          ! Are still there available borders? 
3343          IF (ALL(gotbrdr) .EQV. .TRUE.) THEN
3344            finishedstep = .TRUE.
3345            Npath = ipath
3346            Nptpaths(ipath) = Nptspath
3347            EXIT
3348          ELSE
3349            Nptpaths(ipath) = Nptspath
3350            ! Let's have a look if the previous points in the path have already some 'non-located' neighbourgs
3351            DO i=Nptspath,1,-1
3352              iip = paths(ipath,i,1)
3353              ijp = paths(ipath,i,2)
3354              CALL look_clockwise_borders(dx,dy,Nppt,borders, gotbrdr, isborder,iip, ijp, dbg, iif,   &
3355                jjf,iff)
3356              IF (iif /= -1 .AND. iff /= -1) THEN
3357                IF (dbg) PRINT *,'    re-take path from point:', iif,',',jjf,' n-path:', iff
3358                found = .TRUE.
3359                iipth = index_list_coordsI(Nppt, borders, (/iip,ijp/))
3360                EXIT
3361              END IF
3362            END DO
3363            IF (.NOT.found) THEN
3364              ! Looking for the next available border point for the new path
3365              DO i=1,Nbrdr
3366                IF (.NOT.gotbrdr(i)) THEN
3367                  iipth = i
3368                  EXIT
3369                END IF
3370              END DO
3371              IF (dbg) PRINT *,'  Looking for next path starting at:', iipth, ' point:',              &
3372                borders(iipth,:)
3373              ipath=ipath+1
3374              EXIT
3375            END IF
3376          END IF
3377        ELSE
3378          IF (dbg) PRINT *,'  looking for next point...'
3379        END IF
3380        IF (finishedstep) EXIT
3381      END DO
3382    END IF newpath
3383  END DO
3384  Npath = ipath
3385  Nptpaths(ipath) = Nptspath
3386   
3387  DEALLOCATE (gotbrdr)
3388  DEALLOCATE (emptygotbrdr)
3389
3390  RETURN
3391
3392END SUBROUTINE paths_border
3393
3394SUBROUTINE rand_sample(Nvals, Nsample, sample)
3395! Subroutine to randomly sample a range of indices
3396
3397  IMPLICIT NONE
3398
3399  INTEGER, INTENT(in)                                    :: Nvals, Nsample
3400  INTEGER, DIMENSION(Nsample), INTENT(out)               :: sample
3401
3402! Local
3403  INTEGER                                                :: i, ind, jmax
3404  REAL, DIMENSION(Nsample)                               :: randv
3405  CHARACTER(len=50)                                      :: fname
3406  LOGICAL                                                :: found
3407  LOGICAL, DIMENSION(Nvals)                              :: issampled
3408  CHARACTER(len=256)                                     :: msg
3409  CHARACTER(len=10)                                      :: IS1, IS2
3410
3411!!!!!!! Variables
3412! Nvals: number of values
3413! Nsamples: number of samples
3414! sample: samnple
3415  fname = 'rand_sample'
3416
3417  IF (Nsample > Nvals) THEN
3418    WRITE(IS1,'(I10)')Nvals
3419    WRITE(IS2,'(I10)')Nsample
3420    msg = 'Sampling of ' // TRIM(IS1) // ' is too big for ' // TRIM(IS1) // 'values'
3421    CALL ErrMsg(msg, fname, -1)
3422  END IF
3423
3424  ! Generation of random numbers always the same series during the whole program!
3425  CALL RANDOM_NUMBER(randv)
3426
3427  ! Making sure that we do not repeat any value
3428  issampled = .FALSE.
3429
3430  DO i=1, Nsample
3431    ! Generation of the index from the random numbers
3432    ind = MAX(INT(randv(i)*Nvals), 1)
3433
3434    IF (.NOT.issampled(ind)) THEN
3435      sample(i) = ind
3436      issampled(ind) = .TRUE.
3437    ELSE
3438      ! Looking around the given index
3439      !PRINT *,' Index :', ind, ' already sampled!', issampled(ind)
3440      found = .FALSE.
3441      DO jmax=1, Nvals
3442        ind = MIN(ind+jmax, Nvals)
3443        IF (.NOT.issampled(ind)) THEN
3444          sample(i) = ind
3445          issampled(ind) = .TRUE.
3446          found = .TRUE.
3447          EXIT
3448        END IF
3449        ind = MAX(1, ind-jmax)
3450        IF (.NOT.issampled(ind)) THEN
3451          sample(i) = ind
3452          issampled(ind) = .TRUE.
3453          found = .TRUE.
3454          EXIT
3455        END IF
3456      END DO
3457      IF (.NOT.found) THEN
3458        msg = 'sampling could not be finished due to absence of available value!!'
3459        CALL ErrMsg(msg, fname, -1)
3460      END IF
3461    END IF
3462
3463  END DO
3464
3465  RETURN
3466
3467END SUBROUTINE rand_sample
3468
3469SUBROUTINE PrintQuantilesR_K(Nvals, vals, Nquants, qtvs, bspc)
3470! Subroutine to print the quantiles of values REAL(r_k)
3471
3472  IMPLICIT NONE
3473
3474  INTEGER, INTENT(in)                                    :: Nvals, Nquants
3475  REAL(r_k), DIMENSION(Nvals), INTENT(in)                :: vals
3476  REAL(r_k), DIMENSION(Nquants), INTENT(in)              :: qtvs
3477  CHARACTER(len=1000), OPTIONAL                          :: bspc
3478
3479! Local
3480  INTEGER                                                :: iq
3481  LOGICAL, DIMENSION(Nvals)                              :: search1, search2, search
3482  CHARACTER(len=6)                                       :: RS1
3483  CHARACTER(len=50)                                      :: fname
3484  CHARACTER(len=1000)                                    :: bspcS
3485
3486!!!!!!! Variables
3487! vals: series of values
3488! qtvs: values of the quantiles
3489! bspc: base quantity of spaces
3490
3491  fname = 'PrintQuantilesR_K'
3492
3493  IF (PRESENT(bspc)) THEN
3494    bspcS = bspc
3495  ELSE
3496    bspcS = '      '
3497  END IF
3498
3499  DO iq=1, Nquants-1
3500
3501    WHERE (vals >= qtvs(iq))
3502      search1 = .TRUE.
3503    ELSEWHERE
3504      search1 = .FALSE.
3505    END WHERE
3506
3507    WHERE (vals < qtvs(iq+1))
3508      search2 = .TRUE.
3509    ELSEWHERE
3510      search2 = .FALSE.
3511    END WHERE
3512
3513    WHERE (search1 .AND. search2)
3514      search = .TRUE.
3515    ELSEWHERE
3516      search = .FALSE.
3517    END WHERE
3518
3519    WRITE(RS1, '(F6.2)')(iq)*100./(Nquants-1)
3520    PRINT *, TRIM(bspcS) // '[',iq,']', TRIM(RS1) // ' %:', qtvs(iq), 'N:', COUNT(search)
3521
3522  END DO
3523
3524  RETURN
3525
3526END SUBROUTINE PrintQuantilesR_K
3527
3528   INTEGER FUNCTION FindMinimumR_K(x, dsize, Startv, Endv)
3529! Function returns the location of the minimum in the section between Start and End.
3530
3531      IMPLICIT NONE
3532
3533      INTEGER, INTENT(in)                                :: dsize
3534      REAL(r_k), DIMENSION(dsize), INTENT(in)            :: x
3535      INTEGER, INTENT(in)                                :: Startv, Endv
3536
3537! Local
3538      REAL(r_k)                                          :: Minimum
3539      INTEGER                                            :: Location
3540      INTEGER                                            :: i
3541
3542      Minimum  = x(Startv)                               ! assume the first is the min
3543      Location = Startv                                  ! record its position
3544      DO i = Startv+1, Endv                              ! start with next elements
3545         IF (x(i) < Minimum) THEN                        !   if x(i) less than the min?
3546            Minimum  = x(i)                              !      Yes, a new minimum found
3547            Location = i                                 !      record its position
3548         END IF
3549      END DO
3550
3551      FindMinimumR_K = Location                          ! return the position
3552
3553   END FUNCTION  FindMinimumR_K
3554
3555   SUBROUTINE SwapR_K(a, b)
3556! Subroutine swaps the values of its two formal arguments.
3557
3558      IMPLICIT NONE
3559
3560      REAL(r_k), INTENT(INOUT)                           :: a, b
3561! Local
3562      REAL(r_k)                                          :: Temp
3563
3564      Temp = a
3565      a    = b
3566      b    = Temp
3567
3568   END SUBROUTINE  SwapR_K
3569
3570   SUBROUTINE  SortR_K(x, Nx)
3571! Subroutine receives an array x() r_K and sorts it into ascending order.
3572
3573      IMPLICIT NONE
3574
3575      INTEGER, INTENT(IN)                                :: Nx
3576      REAL(r_k), DIMENSION(Nx), INTENT(INOUT)            :: x
3577
3578! Local
3579      INTEGER                                            :: i
3580      INTEGER                                            :: Location
3581
3582      DO i = 1, Nx-1                                     ! except for the last
3583         Location = FindMinimumR_K(x, Nx-i+1, i, Nx)     ! find min from this to last
3584         CALL  SwapR_K(x(i), x(Location))                ! swap this and the minimum
3585      END DO
3586
3587   END SUBROUTINE  SortR_K
3588
3589SUBROUTINE quantilesR_K(Nvals, vals, Nquants, quants)
3590! Subroutine to provide the quantiles of a given set of values of type real 'r_k'
3591
3592  IMPLICIT NONE
3593
3594  INTEGER, INTENT(in)                                    :: Nvals, Nquants
3595  REAL(r_k), DIMENSION(Nvals), INTENT(in)                :: vals
3596  REAL(r_k), DIMENSION(Nquants), INTENT(out)             :: quants
3597
3598! Local
3599  INTEGER                                                :: i
3600  REAL(r_k)                                              :: minv, maxv
3601  REAL(r_k), DIMENSION(Nvals)                            :: sortedvals
3602
3603!!!!!!! Variables
3604! Nvals: number of values
3605! Rk: kind of real of the values
3606! vals: values
3607! Nquants: number of quants
3608! quants: values at which the quantile start
3609
3610  minv = MINVAL(vals)
3611  maxv = MAXVAL(vals)
3612
3613  sortedvals = vals
3614  ! Using from: http://www.cs.mtu.edu/~shene/COURSES/cs201/NOTES/chap08/sorting.f90
3615  CALL SortR_K(sortedvals, Nvals)
3616
3617  quants(1) = minv
3618  DO i=2, Nquants
3619    quants(i) = sortedvals(INT((i-1)*Nvals/Nquants))
3620  END DO
3621
3622END SUBROUTINE quantilesR_K
3623
3624
3625SUBROUTINE StatsR_K(Nvals, vals, minv, maxv, mean, mean2, stdev)
3626! Subroutine to provide the minmum, maximum, mean, the quadratic mean, and the standard deviation of a
3627!   series of r_k numbers
3628
3629  IMPLICIT NONE
3630
3631  INTEGER, INTENT(in)                                    :: Nvals
3632  REAL(r_k), DIMENSION(Nvals), INTENT(in)                :: vals
3633  REAL(r_k), INTENT(out)                                 :: minv, maxv, mean, mean2, stdev
3634
3635!!!!!!! Variables
3636! Nvals: number of values
3637! vals: values
3638! minv: minimum value of values
3639! maxv: maximum value of values
3640! mean: mean value of values
3641! mean2: quadratic mean value of values
3642! stdev: standard deviation of values
3643
3644  minv = MINVAL(vals)
3645  maxv = MAXVAL(vals)
3646
3647  mean=SUM(vals)
3648  mean2=SUM(vals*vals)
3649
3650  mean=mean/Nvals
3651  mean2=mean2/Nvals
3652
3653  stdev=SQRT(mean2 - mean*mean)
3654
3655  RETURN
3656
3657END SUBROUTINE StatsR_k
3658
3659  SUBROUTINE NcountR(values, d1, Ndiffvals, counts)
3660! Subroutine to count real values
3661
3662    IMPLICIT NONE
3663
3664    INTEGER, INTENT(in)                                  :: d1
3665    REAL(r_k), DIMENSION(d1), INTENT(in)                 :: values
3666    INTEGER, INTENT(out)                                 :: Ndiffvals
3667    REAL(r_k), DIMENSION(d1,2), INTENT(out)              :: counts
3668! Local
3669    INTEGER                                              :: i, ival
3670    REAL(r_k), DIMENSION(d1)                             :: diffv
3671
3672!!!!!!! Variables
3673! values: values to count
3674! counts: counts of time for each value
3675   
3676    fname = 'NcountR'
3677
3678    counts = -1.
3679
3680    counts(1,1) = values(1)
3681    counts(1,2) = 1
3682    Ndiffvals = 1
3683    DO i=2,d1
3684      diffv(1:Ndiffvals) = counts(1:Ndiffvals,1) - values(i)
3685      IF (ANY(diffv(1:Ndiffvals) == 0)) THEN
3686        ival = Index1DArrayR(counts(1:Ndiffvals,1), Ndiffvals, values(i))
3687        counts(ival,2) = counts(ival,2) + 1
3688      ELSE
3689        Ndiffvals = Ndiffvals + 1
3690        counts(Ndiffvals,1) = values(i)
3691        counts(Ndiffvals,2) = 1
3692      END IF
3693    END DO
3694
3695  END SUBROUTINE NcountR
3696
3697  SUBROUTINE runmean_F1D(d1, values, Nmean, headertail, runmean)
3698! Subroutine fo computing the running mean of a given set of float 1D values
3699
3700  IMPLICIT NONE
3701
3702  INTEGER, INTENT(in)                                    :: d1, Nmean
3703  REAL(r_k), DIMENSION(d1), INTENT(in)                   :: values
3704  CHARACTER(len=*), INTENT(in)                           :: headertail
3705  REAL(r_k), DIMENSION(d1), INTENT(out)                  :: runmean
3706 
3707! Local
3708  INTEGER                                                :: i, j, Nmean2
3709  CHARACTER(len=5)                                       :: NmeanS
3710
3711!!!!!!! Variables
3712! values: values to compute the running mean
3713! Nmean: number of odd points to use for the running mean
3714! headertail: How to proceed for the grid points at the beginning of the values which are not
3715!   encompassed by the Nmean
3716!   'miss': set as missing values (1.d20)
3717!   'original': keep the original values
3718!   'progressfill': mean the values as a progressive running filter (e.g. for Nmean=5):
3719!     runmean[values(1)] = values(1)
3720!     runmean[values(2)] = MEAN(values(1:3))
3721!     runmean[values(3)] = MEAN(values(1:5))
3722!     runmean[values(4)] = MEAN(values(2:6))
3723!     (...)
3724!     runmean[values(d1-2)] = MEAN(values(d1-5:d1))
3725!     runmean[values(d1-1)] = MEAN(values(d1-2:d1))
3726!     runmean[values(d1)] = MEAN(values(dd1))
3727!   'zero': set as zero values
3728! runmean: runnig mean values
3729
3730  fname = 'runmean_F1D'
3731
3732  IF (MOD(Nmean,2) == 0) THEN
3733    WRITE(NmeanS,'(I5)')Nmean
3734    msg="Nmean has to be odd!! value provided: "// NmeanS
3735    CALL ErrMsg(msg, fname, -1)
3736  END IF
3737  Nmean2 = Nmean/2
3738 
3739  SELECT CASE (TRIM(headertail))
3740    CASE ('missing')
3741      runmean = fillval64
3742    CASE ('original')
3743      runmean = values
3744    CASE ('progressfill')
3745      DO i=1, Nmean2
3746        runmean(i) = SUM(values(1:2*(i-1)+1))/(2*(i-1)+1)
3747      END DO
3748      runmean(d1) = values(d1)
3749      DO i=2, Nmean2
3750        j = d1-(2*(i-1))
3751        runmean(d1-(i-1)) = SUM(values(j:d1))/(2*(i-1)+1)
3752      END DO
3753    CASE ('zero')
3754      runmean = zeroRK
3755    CASE DEFAULT
3756      msg = "'" // TRIM(headertail) // "' not available !!" //CHAR(44) // "  available ones: " //     &
3757        "'missing', 'original', 'progressfill', 'zero'"
3758      CALL ErrMsg(msg, fname, -1)
3759  END SELECT
3760
3761  DO i= 1+Nmean2, d1 - Nmean2
3762    runmean(i) = SUM(values(i-Nmean2:i+Nmean2))/Nmean
3763  END DO
3764
3765  END SUBROUTINE runmean_F1D
3766
3767  SUBROUTINE percentiles_R_K2D(values, axisS, Npercen, d1, d2, percentiles)
3768  ! Subroutine to compute the percentiles of a 2D R_K array along given set of axis
3769
3770    IMPLICIT NONE
3771 
3772    INTEGER, INTENT(in)                                    :: d1, d2, Npercen
3773    REAL(r_k), DIMENSION(d1,d2), INTENT(in)                :: values
3774    CHARACTER(LEN=*), INTENT(in)                           :: axisS
3775    REAL(r_k), DIMENSION(d1, d2, Npercen), INTENT(out)     :: percentiles
3776
3777    ! Local
3778    INTEGER                                                :: i
3779    INTEGER                                                :: Lstring, LaxisS, iichar
3780    CHARACTER(LEN=1000)                                    :: splitaxis
3781    INTEGER, DIMENSION(1)                                  :: axis1
3782    CHARACTER(LEN=200), DIMENSION(2)                       :: axis2S
3783    INTEGER, DIMENSION(2)                                  :: axis2
3784    CHARACTER(LEN=1)                                       :: Naxs
3785
3786!!!!!!! Variables
3787! d1,d2: length of the 2D dimensions
3788! values: values to use to compute the percentiles
3789! axisS: ':' separated list of axis to use to compute the percentiles ('all' for all axes)
3790! Npercen: number of percentiles
3791! percentiles: percentiles of the daata
3792
3793    fname = 'percentiles_R_K2D'
3794
3795    LaxisS = LEN_TRIM(axisS)
3796    iichar = numberTimes(axisS(1:LaxisS), ':')
3797
3798    splitaxis = ''
3799    splitaxis(1:LaxisS) = axisS(1:LaxisS)
3800    percentiles = 0.
3801
3802    IF (iichar == 0) THEN
3803      READ(axisS,'(I1)')axis1(1)
3804    ELSE IF (iichar == 1) THEN
3805      CALL split(splitaxis, ':', 2, axis2S)
3806    ELSE
3807      WRITE(Naxs,'(A1)')iichar
3808      msg = "' rank 2 values can not compute percentiles using " // Naxs // "' number of axis !!"
3809      CALL ErrMsg(msg, fname, -1)
3810    END IF
3811
3812    IF (TRIM(axisS) == 'all') iichar = 2
3813 
3814    IF (iichar == 0) THEN
3815      ! Might be a better way, but today I can't think it !!
3816      IF (axis1(1) == 1) THEN
3817        DO i=1, d2
3818          CALL quantilesR_K(d1, values(:,i), Npercen, percentiles(1,i,:))
3819        END DO
3820      ELSE IF (axis1(1) == 2) THEN
3821        DO i=1, d1
3822          CALL quantilesR_K(d2, values(i,:), Npercen, percentiles(i,1,:))
3823        END DO
3824      ELSE
3825        WRITE(Naxs,'(A1)')axis1(1)
3826        msg = "' rank 2 values can not compute percentiles using axis " // Naxs // "' !!"
3827        CALL ErrMsg(msg, fname, -1)
3828      END IF
3829    ELSE
3830      CALL quantilesR_K(d1*d2, RESHAPE(values, (/d1*d2/)), Npercen, percentiles(1,1,:))
3831    END IF
3832
3833  END SUBROUTINE percentiles_R_K2D
3834
3835  SUBROUTINE percentiles_R_K3D(values, axisS, Npercen, d1, d2, d3, percentiles)
3836  ! Subroutine to compute the percentiles of a 3D R_K array along given set of axis
3837
3838    IMPLICIT NONE
3839 
3840    INTEGER, INTENT(in)                                    :: d1, d2, d3, Npercen
3841    REAL(r_k), DIMENSION(d1,d2,d3), INTENT(in)             :: values
3842    CHARACTER(LEN=*), INTENT(in)                           :: axisS
3843    REAL(r_k), DIMENSION(d1, d2, d3, Npercen), INTENT(out) :: percentiles
3844
3845    ! Local
3846    INTEGER                                                :: i, j
3847    INTEGER                                                :: Lstring, LaxisS, iichar
3848    CHARACTER(LEN=1000)                                    :: splitaxis
3849    INTEGER, DIMENSION(1)                                  :: axis1
3850    CHARACTER(LEN=200), DIMENSION(2)                       :: axis2S
3851    INTEGER, DIMENSION(2)                                  :: axis2
3852    CHARACTER(LEN=200), DIMENSION(3)                       :: axis3S
3853    INTEGER, DIMENSION(3)                                  :: axis3
3854    CHARACTER(LEN=1)                                       :: Naxs1, Naxs2
3855
3856!!!!!!! Variables
3857! d1,d2: length of the 2D dimensions
3858! values: values to use to compute the percentiles
3859! axisS: ':' separated list of axis to use to compute the percentiles ('all' for all axes)
3860! Npercen: number of percentiles
3861! percentiles: percentiles of the daata
3862
3863    fname = 'percentiles_R_K3D'
3864
3865    LaxisS = LEN_TRIM(axisS)
3866    iichar = numberTimes(axisS(1:LaxisS), ':')
3867
3868    splitaxis = ''
3869    splitaxis(1:LaxisS) = axisS(1:LaxisS)
3870
3871    percentiles = 0.
3872
3873    IF (iichar == 0) THEN
3874      READ(axisS,'(I1)')axis1(1)
3875    ELSE IF (iichar == 1) THEN
3876      CALL split(splitaxis, ':', 2, axis2S)
3877      DO i=1,2
3878        READ(axis2S(i), '(I1)')axis2(i)
3879      END DO
3880    ELSE IF (iichar == 2) THEN
3881      CALL split(splitaxis, ':', 3, axis3S)
3882    ELSE
3883      READ(Naxs1,'(A1)')iichar
3884      msg = "' rank 3 values can not compute percentiles using " // Naxs1 // "' number of axis !!"
3885      CALL ErrMsg(msg, fname, -1)
3886    END IF
3887
3888    IF (TRIM(axisS) == 'all') iichar = 3
3889 
3890    IF (iichar == 0) THEN
3891      ! Might be a better way, but today I can't think it !!
3892      IF (axis1(1) == 1) THEN
3893        DO i=1, d2
3894          DO j=1, d3
3895            CALL quantilesR_K(d1, values(:,i,j), Npercen, percentiles(1,i,j,:))
3896          END DO
3897        END DO
3898      ELSE IF (axis1(1) == 2) THEN
3899        DO i=1, d1
3900          DO j=1, d3
3901            CALL quantilesR_K(d2, values(i,:,j), Npercen, percentiles(i,1,j,:))
3902          END DO
3903        END DO
3904      ELSE IF (axis1(1) == 3) THEN
3905        DO i=1, d1
3906          DO j=1, d2
3907            CALL quantilesR_K(d3, values(i,j,:), Npercen, percentiles(i,j,1,:))
3908          END DO
3909        END DO
3910      ELSE
3911        WRITE(Naxs1,'(A1)')axis1(1)
3912        msg = "' rank 3 values can not compute percentiles using axis " // Naxs1 // "' !!"
3913        CALL ErrMsg(msg, fname, -1)
3914      END IF
3915    ELSE IF (iichar == 1) THEN
3916      ! Might be a better way, but today I can't think it !!
3917      IF (axis2(1) == 1 .AND. axis2(2) == 2) THEN
3918        DO i=1, d3
3919          CALL quantilesR_K(d1*d2, RESHAPE(values(:,:,i), (/d1*d2/)), Npercen, percentiles(1,1,i,:))
3920        END DO
3921      ELSE IF (axis2(1) == 1 .AND. axis2(2) == 3) THEN
3922        DO i=1, d2
3923          CALL quantilesR_K(d1*d3, RESHAPE(values(:,i,:), (/d1*d3/)), Npercen, percentiles(1,i,1,:))
3924        END DO
3925      ELSE IF (axis2(1) == 2 .AND. axis2(2) == 3) THEN
3926        DO i=1, d1
3927          CALL quantilesR_K(d2*d3, RESHAPE(values(i,:,:), (/d2*d3/)), Npercen, percentiles(i,1,1,:))
3928        END DO
3929      ELSE
3930        WRITE(Naxs1,'(A1)')axis2(1)
3931        WRITE(Naxs2,'(A1)')axis2(2)
3932        msg="' rank 3 values can not compute percentiles using axis "//Naxs1// ', ' // Naxs2 // "' !!"
3933        CALL ErrMsg(msg, fname, -1)
3934      END IF
3935    ELSE
3936      CALL quantilesR_K(d1*d2*d3, RESHAPE(values, (/d1*d2*d3/)), Npercen, percentiles(1,1,1,:))
3937    END IF
3938
3939  END SUBROUTINE percentiles_R_K3D
3940
3941  SUBROUTINE percentiles_R_K4D(values, axisS, Npercen, d1, d2, d3, d4, percentiles)
3942  ! Subroutine to compute the percentiles of a 4D R_K array along given set of axis
3943
3944    IMPLICIT NONE
3945 
3946    INTEGER, INTENT(in)                                    :: d1, d2, d3, d4, Npercen
3947    REAL(r_k), DIMENSION(d1,d2,d3,d4), INTENT(in)          :: values
3948    CHARACTER(LEN=*), INTENT(in)                           :: axisS
3949    REAL(r_k), DIMENSION(d1,d2,d3,d4,Npercen), INTENT(out) :: percentiles
3950
3951    ! Local
3952    INTEGER                                                :: i, j, k
3953    INTEGER                                                :: Lstring, LaxisS, iichar
3954    CHARACTER(LEN=1000)                                    :: splitaxis
3955    INTEGER, DIMENSION(1)                                  :: axis1
3956    CHARACTER(LEN=200), DIMENSION(2)                       :: axis2S
3957    INTEGER, DIMENSION(2)                                  :: axis2
3958    CHARACTER(LEN=200), DIMENSION(3)                       :: axis3S
3959    INTEGER, DIMENSION(3)                                  :: axis3
3960    CHARACTER(LEN=200), DIMENSION(4)                       :: axis4S
3961    CHARACTER(LEN=1)                                       :: Naxs1, Naxs2, Naxs3
3962
3963!!!!!!! Variables
3964! d1,d2: length of the 2D dimensions
3965! values: values to use to compute the percentiles
3966! axisS: ':' separated list of axis to use to compute the percentiles ('all' for all axes)
3967! Npercen: number of percentiles
3968! percentiles: percentiles of the daata
3969
3970    fname = 'percentiles_R_K3D'
3971
3972    LaxisS = LEN_TRIM(axisS)
3973    iichar = numberTimes(axisS(1:LaxisS), ':')
3974
3975    splitaxis = ''
3976    splitaxis(1:LaxisS) = axisS(1:LaxisS)
3977
3978    percentiles = 0.
3979
3980    PRINT *,'iichar:', iichar, axisS(1:LaxisS)
3981
3982    IF (iichar == 0) THEN
3983      READ(axisS,'(I1)')axis1(1)
3984    ELSE IF (iichar == 1) THEN
3985      CALL split(splitaxis, ':', 2, axis2S)
3986      DO i=1,2
3987        READ(axis2S(i), '(I1)')axis2(i)
3988      END DO
3989    ELSE IF (iichar == 2) THEN
3990      CALL split(splitaxis, ':', 3, axis3S)
3991      DO i=1,3
3992        READ(axis3S(i), '(I1)')axis3(i)
3993      END DO
3994    ELSE IF (iichar == 3) THEN
3995      CALL split(splitaxis, ':', 4, axis4S)
3996    ELSE
3997      READ(Naxs1,'(A1)')iichar
3998      msg = "' rank 4 values can not compute percentiles using " // Naxs1 // "' number of axis !!"
3999      CALL ErrMsg(msg, fname, -1)
4000    END IF
4001
4002    IF (TRIM(axisS) == 'all') iichar = 4
4003 
4004    IF (iichar == 0) THEN
4005      ! Might be a better way, but today I can't think it !!
4006      IF (axis1(1) == 1) THEN
4007        DO i=1, d2
4008          DO j=1, d3
4009            DO k=1, d4
4010              CALL quantilesR_K(d1, values(:,i,j,k), Npercen, percentiles(1,i,j,k,:))
4011            END DO
4012          END DO
4013        END DO
4014      ELSE IF (axis1(1) == 2) THEN
4015        DO i=1, d1
4016          DO j=1, d3
4017            DO k=1, d4
4018              CALL quantilesR_K(d2, values(i,:,j,k), Npercen, percentiles(i,1,j,k,:))
4019            END DO
4020          END DO
4021        END DO
4022      ELSE IF (axis1(1) == 3) THEN
4023        DO i=1, d1
4024          DO j=1, d2
4025            DO k=1, d4
4026              CALL quantilesR_K(d3, values(i,j,:,k), Npercen, percentiles(i,j,1,k,:))
4027            END DO
4028          END DO
4029        END DO
4030      ELSE IF (axis1(1) == 4) THEN
4031        DO i=1, d1
4032          DO j=1, d2
4033            DO k=1, d3
4034              CALL quantilesR_K(d4, values(i,j,k,:), Npercen, percentiles(i,j,k,1,:))
4035            END DO
4036          END DO
4037        END DO
4038      ELSE
4039        WRITE(Naxs1,'(A1)')axis1(1)
4040        msg = "' rank 3 values can not compute percentiles using axis " // Naxs1 // "' !!"
4041        CALL ErrMsg(msg, fname, -1)
4042      END IF
4043    ELSE IF (iichar == 1) THEN
4044      ! Might be a better way, but today I can't think it !!
4045      IF (axis2(1) == 1 .AND. axis2(2) == 2) THEN
4046        DO i=1, d3
4047          DO j=1, d4
4048            CALL quantilesR_K(d1*d2, RESHAPE(values(:,:,i,j), (/d1*d2/)), Npercen,                    &
4049              percentiles(1,1,i,j,:))
4050          END DO
4051        END DO
4052      ELSE IF (axis2(1) == 1 .AND. axis2(2) == 3) THEN
4053        DO i=1, d2
4054          DO j=1, d4
4055            CALL quantilesR_K(d1*d3, RESHAPE(values(:,i,:,j), (/d1*d3/)), Npercen,                    &
4056              percentiles(1,i,1,j,:))
4057          END DO
4058        END DO
4059      ELSE IF (axis2(1) == 1 .AND. axis2(2) == 4) THEN
4060        DO i=1, d2
4061          DO j=1, d3
4062            CALL quantilesR_K(d1*d4, RESHAPE(values(:,i,j,:), (/d1*d4/)), Npercen,                    &
4063              percentiles(1,i,j,1,:))
4064          END DO
4065        END DO
4066      ELSE IF (axis2(1) == 2 .AND. axis2(2) == 3) THEN
4067        DO i=1, d1
4068          DO j=1, d4
4069            CALL quantilesR_K(d2*d3, RESHAPE(values(i,:,:,j), (/d2*d3/)), Npercen,                    &
4070              percentiles(i,1,1,j,:))
4071          END DO
4072        END DO
4073      ELSE IF (axis2(1) == 2 .AND. axis2(2) == 4) THEN
4074        DO i=1, d1
4075          DO j=1, d3
4076            CALL quantilesR_K(d2*d4, RESHAPE(values(i,:,j,:), (/d2*d4/)), Npercen,                    &
4077              percentiles(i,1,j,1,:))
4078          END DO
4079        END DO
4080      ELSE IF (axis2(1) == 3 .AND. axis2(2) == 4) THEN
4081        DO i=1, d1
4082          DO j=1, d2
4083            CALL quantilesR_K(d3*d4, RESHAPE(values(i,j,:,:), (/d3*d4/)), Npercen,                    &
4084              percentiles(i,j,1,1,:))
4085          END DO
4086        END DO
4087      ELSE
4088        WRITE(Naxs1,'(A1)')axis2(1)
4089        WRITE(Naxs2,'(A1)')axis2(2)
4090        msg="' rank 4 values can not compute percentiles using axis "//Naxs1// ', ' // Naxs2 // "' !!"
4091        CALL ErrMsg(msg, fname, -1)
4092      END IF
4093    ELSE IF (iichar == 2) THEN
4094      IF (axis2(1) == 1 .AND. axis2(2) == 2 .AND. axis3(3) == 3) THEN
4095        DO i=1, d4
4096          CALL quantilesR_K(d1*d2*d3, RESHAPE(values(:,:,:,i), (/d1*d2*d3/)), Npercen,                &
4097            percentiles(1,1,1,i,:))
4098        END DO
4099      ELSE IF (axis2(1) == 1 .AND. axis2(2) == 2 .AND. axis3(3) == 4) THEN
4100        DO i=1, d3
4101          CALL quantilesR_K(d1*d2*d4, RESHAPE(values(:,:,i,:), (/d1*d2*d4/)), Npercen,                &
4102            percentiles(1,1,i,1,:))
4103        END DO
4104      ELSE IF (axis2(1) == 1 .AND. axis2(2) == 3 .AND. axis3(3) == 4) THEN
4105        DO i=1, d2
4106          CALL quantilesR_K(d1*d3*d4, RESHAPE(values(:,i,:,:), (/d1*d3*d4/)), Npercen,                &
4107            percentiles(1,i,1,1,:))
4108        END DO
4109      ELSE IF (axis2(1) == 2 .AND. axis2(2) == 3 .AND. axis3(3) == 4) THEN
4110        DO i=1, d1
4111          CALL quantilesR_K(d2*d3*d4, RESHAPE(values(i,:,:,:), (/d2*d3*d4/)), Npercen,                &
4112            percentiles(i,1,1,1,:))
4113        END DO
4114      ELSE
4115        WRITE(Naxs1,'(A1)')axis3(1)
4116        WRITE(Naxs2,'(A1)')axis3(2)
4117        WRITE(Naxs3,'(A1)')axis3(2)
4118        msg="' rank 4 values can not compute percentiles using axis "// Naxs1 // ', ' // Naxs2 //     &
4119          ', ' // Naxs3 //"' !!"
4120        CALL ErrMsg(msg, fname, -1)
4121      END IF
4122    ELSE
4123      CALL quantilesR_K(d1*d2*d3*d4, RESHAPE(values, (/d1*d2*d3*d4/)), Npercen, percentiles(1,1,1,1,:))
4124    END IF
4125
4126  END SUBROUTINE percentiles_R_K4D
4127
4128  REAL(r_k) FUNCTION distanceRK(pointA, pointB)
4129  ! Function to provide the distance between two points
4130
4131    IMPLICIT NONE
4132
4133    REAL(r_k), DIMENSION(2), INTENT(in)                  :: pointA, pointB
4134
4135!!!!!!! Variables
4136! pointA, B: couple of points to compute the distance between them
4137
4138    fname = 'distanceRK'
4139
4140    distanceRK = SQRT( (pointB(1)-pointA(1))**2 + (pointB(2)-pointA(2))**2 )
4141
4142  END FUNCTION distanceRK
4143
4144  REAL(r_k) FUNCTION shoelace_area_polygon(Nvertex, poly)
4145  ! Computing the area of a polygon using sholace formula
4146  ! FROM: https://en.wikipedia.org/wiki/Shoelace_formula
4147
4148    IMPLICIT NONE
4149
4150      INTEGER, INTENT(in)                                :: Nvertex
4151      REAL(r_k), DIMENSION(Nvertex,2), INTENT(in)        :: poly
4152
4153! Local
4154      INTEGER                                            :: i
4155      REAL(r_k)                                          :: areapos, areaneg
4156
4157!!!!!!! Variables
4158! Nvertex: number of vertices of the polygon
4159! poly: coordinates of the vertex of the polygon (sorted)
4160
4161    fname = 'shoelace_area_polygon'
4162
4163    areapos = 0.
4164    areaneg = 0.
4165
4166    DO i=1, Nvertex-1
4167      areapos = areapos + poly(i,1)*poly(i+1,2)
4168      areaneg = areaneg + poly(i+1,1)*poly(i,2)
4169    END DO
4170
4171    areapos = areapos + poly(Nvertex,1)*poly(1,2)
4172    areaneg = areaneg + poly(1,1)*poly(Nvertex,2)
4173
4174    shoelace_area_polygon = 0.5*(areapos - areaneg)
4175
4176  END FUNCTION shoelace_area_polygon
4177
4178  SUBROUTINE intersection_2Dlines(lineA, lineB, intersect, ptintersect)
4179  ! Subroutine to provide the intersection point between two lines on the plane using Cramer's method
4180
4181    IMPLICIT NONE
4182
4183    REAL(r_k), DIMENSION(2,2), INTENT(in)                  :: lineA, lineB
4184    LOGICAL, INTENT(out)                                   :: intersect
4185    REAL(r_k), DIMENSION(2), INTENT(out)                   :: ptintersect
4186
4187! Local
4188    REAL(r_k), DIMENSION(2)                                :: segmentA, segmentB
4189    REAL(r_k)                                              :: a11, a12, a21, a22, z1, z2
4190    REAL(r_k)                                              :: det, detX, detY
4191    LOGICAL                                                :: axisAx, axisBx, axisAy, axisBy
4192
4193!!!!!!! Variables
4194! lineA: couple of coordinates for the line A
4195! lineB: couple of coordinates for the line B
4196! intersect: whether two lines intersect
4197! ptintersect: point of intersection [(0,0) if they do not intersect]
4198
4199    fname = 'intersection_2Dlines'
4200
4201    axisAx = .FALSE.
4202    axisAy = .FALSE.
4203    axisBx = .FALSE.
4204    axisBy = .FALSE.
4205    ! Setting segment parameters y = A + B*x
4206    IF (lineA(2,1) /= lineA(1,1)) THEN
4207      segmentA(2) = (lineA(2,2)-lineA(1,2))/(lineA(2,1)-lineA(1,1))
4208      ! This might be to ask too much... ?
4209      !IF ( (lineA(1,1)*segmentA(2) - lineA(1,2)) /= (lineA(2,1)*segmentA(2) - lineA(2,2)) ) THEN
4210      !  PRINT *,'A = y1 - x2*B = ', lineA(1,2) - lineA(1,1)*segmentA(2)
4211      !  PRINT *,'A = y2 - x2*B = ', lineA(2,2) - lineA(2,1)*segmentA(2)
4212      !  msg = 'Wrong calculation of parameter A, for lineA'
4213      !  CALL ErrMSg(msg, fname, -1)
4214      !END IF
4215      segmentA(1) = lineA(1,2) - lineA(1,1)*segmentA(2)
4216      a11 = segmentA(2)
4217      a12 = -oneRK
4218      z1 = -segmentA(1)
4219      IF (lineA(2,2) == lineA(1,2)) axisAx = .TRUE.
4220    ELSE
4221      ! lineA || y-axis
4222      axisAy = .TRUE.
4223    END IF
4224
4225    IF (lineB(2,1) /= lineB(1,1)) THEN
4226      segmentB(2) = (lineB(2,2)-lineB(1,2))/(lineB(2,1)-lineB(1,1))
4227      ! This might be to ask too much... ?
4228      !IF ( (lineB(1,1)*segmentB(2) - lineB(1,2)) /= (lineB(2,1)*segmentB(2) - lineB(2,2)) ) THEN
4229      !  PRINT *,'A = x1*B -y1 = ', lineB(1,1)*segmentB(2) - lineB(1,2)
4230      !  PRINT *,'A = x2*B -y2 = ', lineB(2,1)*segmentB(2) - lineB(2,2)
4231      !  msg = 'Wrong calculation of parameter A, for lineB'
4232      !  CALL ErrMSg(msg, fname, -1)
4233      !END IF
4234      segmentB(1) = lineB(1,2) - lineB(1,1)*segmentB(2)
4235      a21 = segmentB(2)
4236      a22 = -oneRK
4237      z2 = -segmentB(1)
4238      IF (lineB(2,2) == lineB(1,2)) axisBx = .TRUE.
4239    ELSE
4240      ! lineB || y-axis
4241      axisBy = .TRUE.
4242    END IF
4243    ! Cramer's method
4244    ! a11 = B1; a12 = -1
4245    ! a21 = B2; a22 = -1
4246    ! z1 = -A1
4247    ! z2 = -A2
4248    ! (a11 a12)(x) (z1)
4249    ! (a21 a22)(y) (z2)
4250    ! -------- ------ ----- ---- --- -- -
4251    ! det = (a11*a22-a12*a21)
4252    ! detX = (z1*a22-z2*a21)
4253    ! detY = (a11*z1-a12*z2)
4254    ! ptintercept = (detX/det, detY/det)
4255
4256    ! Cases when some of the lines are parallel to any given axis
4257!    PRINT *,'          axisAx', axisAx, 'axisAy', axisAy, 'axisBx', axisBx, 'axisBy', axisBy
4258    IF (axisAx .OR. axisAy .OR. axisBx .OR. axisBy) THEN
4259      IF (axisAx) THEN
4260        IF (axisBy) THEN
4261          intersect = .TRUE.
4262          ptintersect(1) = lineB(1,1)
4263          ptintersect(2) = lineA(1,2)
4264        ELSE
4265          intersect = .TRUE.
4266          ptintersect(1) = (lineA(1,2)-segmentB(1))/segmentB(2)
4267          ptintersect(2) = lineA(1,2)
4268        END IF
4269      END IF
4270      IF (axisAy) THEN
4271        IF (axisBy) THEN
4272          intersect = .TRUE.
4273          ptintersect(1) = lineA(1,1)
4274          ptintersect(2) = lineB(1,2)
4275        ELSE
4276          intersect = .TRUE.
4277          ptintersect(1) = lineA(1,1)
4278          ptintersect(2) = segmentB(1) + lineA(1,1)*segmentB(2)
4279        END IF
4280      END IF
4281      IF (axisBx) THEN
4282        IF (axisAy) THEN
4283          intersect = .TRUE.
4284          ptintersect(1) = lineA(1,1)
4285          ptintersect(2) = lineB(1,2)
4286        ELSE
4287          intersect = .TRUE.
4288          ptintersect(1) = (lineB(1,2)-segmentA(1))/segmentA(2)
4289          ptintersect(2) = lineB(1,2)
4290        END IF
4291      END IF
4292      IF (axisBy) THEN
4293        IF (axisAx) THEN
4294          intersect = .TRUE.
4295          ptintersect(1) = lineB(1,1)
4296          ptintersect(2) = lineA(1,2)
4297        ELSE
4298          intersect = .TRUE.
4299          ptintersect(1) = lineB(1,1)
4300          ptintersect(2) = segmentA(1) + lineB(1,1)*segmentA(2)
4301        END IF
4302      END IF
4303    ELSE
4304      det = (a11*a22-a12*a21)
4305      ! Parallel lines !
4306      IF (det == zeroRK) THEN
4307        intersect = .FALSE.
4308        ptintersect = zeroRK
4309      ELSE
4310        intersect = .TRUE.
4311        detX = (z1*a22-z2*a12)
4312        detY = (a11*z2-a21*z1)
4313
4314        ptintersect(1) = detX/det
4315        ptintersect(2) = detY/det
4316      END IF
4317    END IF
4318
4319  END SUBROUTINE intersection_2Dlines
4320
4321!refs:
4322!https://www.mathopenref.com/heronsformula.html
4323!https://math.stackexchange.com/questions/1406340/intersect-area-of-two-polygons-in-cartesian-plan
4324!http://www.cap-lore.com/MathPhys/IP/
4325!http://www.cap-lore.com/MathPhys/IP/IL.html
4326!https://www.element84.com/blog/determining-the-winding-of-a-polygon-given-as-a-set-of-ordered-points
4327!https://stackoverflow.com/questions/1165647/how-to-determine-if-a-list-of-polygon-points-are-in-clockwise-order
4328!https://en.wikipedia.org/wiki/Shoelace_formula
4329!https://en.wikipedia.org/wiki/Winding_number
4330!https://en.wikipedia.org/wiki/Simple_polygon
4331!https://en.wikipedia.org/wiki/Polygon#Properties
4332!https://en.wikipedia.org/wiki/Convex_polygon
4333!https://en.wikipedia.org/wiki/Jordan_curve_theorem
4334!https://www.sangakoo.com/ca/temes/metode-de-cramer
4335!https://www.geogebra.org/m/pw4QHFYT
4336
4337  SUBROUTINE intersectfaces(faceA, faceB, intersect, intersectpt)
4338  ! Subroutine to provide if two faces of two polygons intersect
4339  ! AFTER: http://www.cap-lore.com/MathPhys/IP/IL.html
4340  !   A: faceA(1,:)
4341  !   B: faceA(2,:)
4342  !   C: faceB(1,:)
4343  !   D: faceB(2,:)
4344
4345    IMPLICIT NONE
4346
4347    REAL(r_k), DIMENSION(2,2), INTENT(in)                :: faceA, faceB
4348    INTEGER, INTENT(out)                                 :: intersect
4349    REAL(r_k), DIMENSION(2), INTENT(out)                 :: intersectpt
4350
4351! Local
4352    REAL(r_k)                                            :: Axmin, Aymin, Axmax, Aymax
4353    REAL(r_k)                                            :: Bxmin, Bymin, Bxmax, Bymax
4354    REAL(r_k)                                            :: areaABD, areaACD, areaBDC, areaDAB
4355    REAL(r_k), DIMENSION(3,2)                            :: triangle
4356    LOGICAL                                              :: Lintersect
4357
4358!!!!!!! Variables
4359! faceA/B: coordinates of faces A and B to determine if they intersect
4360! intersect: integer to say if they intersect (0, no-intersect, +/-1 intersect)
4361! intersectpt: point where faces intersect [(0,0) otherwise]
4362
4363    fname = 'intersectfaces'
4364
4365!    PRINT *,'     ' // TRIM(fname) // ' ________'
4366!    PRINT *,'            faceA:', faceA(1,:), ';',faceA(2,:)
4367!    PRINT *,'            faceB:', faceB(1,:), ';',faceB(2,:)
4368
4369    Axmin = MINVAL(faceA(:,1))
4370    Axmax = MAXVAL(faceA(:,1))
4371    Aymin = MINVAL(faceA(:,2))
4372    Aymax = MAXVAL(faceA(:,2))
4373    Bxmin = MINVAL(faceB(:,1))
4374    Bxmax = MAXVAL(faceB(:,1))
4375    Bymin = MINVAL(faceB(:,2))
4376    Bymax = MAXVAL(faceB(:,2))
4377
4378    ! No intersection
4379    IF ( (Axmax <= Bxmin) .OR. (Axmin >= Bxmax) .OR. (Aymax <= Bymin) .OR. (Aymin >= Bymax) ) THEN
4380      intersect = 0
4381      intersectpt = zeroRK
4382    ELSE
4383      ! Triangle ABD
4384      triangle(1,:) = faceA(1,:)
4385      triangle(2,:) = faceA(2,:)
4386      triangle(3,:) = faceB(2,:)
4387      areaABD = shoelace_area_polygon(3, triangle)
4388 
4389      ! Triangle ACD
4390      triangle(1,:) = faceA(1,:)
4391      triangle(2,:) = faceB(1,:)
4392      triangle(3,:) = faceB(2,:)
4393      areaACD = shoelace_area_polygon(3, triangle)
4394
4395      ! Triangle BDC
4396      triangle(1,:) = faceA(2,:)
4397      triangle(2,:) = faceB(2,:)
4398      triangle(3,:) = faceB(1,:)
4399      areaBDC = shoelace_area_polygon(3, triangle)
4400
4401      ! Triangle DAB
4402      triangle(1,:) = faceB(2,:)
4403      triangle(2,:) = faceA(1,:)
4404      triangle(3,:) = faceA(2,:)
4405      areaDAB = shoelace_area_polygon(3, triangle)
4406
4407      IF (areaABD>zeroRK .AND. areaACD>zeroRK .AND. areaBDC>zeroRK .AND. areaDAB>zeroRK) THEN
4408        intersect = INT(ABS(areaABD)/areaABD)
4409        CALL intersection_2Dlines(faceA, faceB, Lintersect, intersectpt)
4410      ELSE IF (areaABD<zeroRK .AND. areaACD<zeroRK .AND. areaBDC<zeroRK .AND. areaDAB<zeroRK) THEN
4411        intersect = INT(ABS(areaABD)/areaABD)
4412        CALL intersection_2Dlines(faceA, faceB, Lintersect, intersectpt)
4413      ELSE
4414        intersect = 0
4415        intersectpt = zeroRK
4416      END IF
4417!      PRINT *,'     intersect faces: areaABD',areaABD, 'areaACD', areaACD, 'areaBDC',areaBDC, 'areaDAB',areaDAB, 'prod', &
4418!        areaABD*areaACD*areaBDC*areaDAB, 'L:', areaABD*areaACD*areaBDC*areaDAB > zeroRK, 'I', intersect
4419
4420    END IF
4421
4422  END SUBROUTINE intersectfaces
4423
4424  LOGICAL FUNCTION poly_has_point(Nvertex, polygon, point)
4425  ! Function to determine if a polygon has already a given point as one of its vertex
4426
4427    IMPLICIT NONE
4428
4429    INTEGER, INTENT(in)                                  :: Nvertex
4430    REAL(r_k), DIMENSION(Nvertex,2), INTENT(in)          :: polygon
4431    REAL(r_k), DIMENSION(2), INTENT(in)                  :: point
4432
4433! Local
4434    INTEGER                                              :: iv
4435    REAL(r_k), DIMENSION(2)                              :: diff
4436
4437!!!!!!! Vertrex
4438! Nvertex: number of vertexs of the polygon
4439! polygon: vertexs of the polygon
4440! point: point to look for its ownership into the polygon
4441
4442    fname = 'poly_has_point'
4443
4444    poly_has_point = .FALSE.
4445    DO iv=1, Nvertex
4446      diff = polygon(iv,:)-point
4447      IF ( (diff(1) == zeroRK) .AND. (diff(2) == zeroRK)) THEN
4448        poly_has_point = .TRUE.
4449        EXIT
4450      END IF
4451    END DO
4452
4453  END FUNCTION poly_has_point
4454
4455  SUBROUTINE join_polygon(NvertexA, NvertexB, NvertexAB, polyA, polyB, Ncoinvertex, coinpoly)
4456  ! Subroutine to join two polygons
4457  ! AFTER: http://www.cap-lore.com/MathPhys/IP/ and http://www.cap-lore.com/MathPhys/IP/IL.html
4458
4459    IMPLICIT NONE
4460
4461    INTEGER, INTENT(in)                                  :: NvertexA, NvertexB, NvertexAB
4462    REAL(r_k), DIMENSION(NvertexA,2), INTENT(in)         :: polyA
4463    REAL(r_k), DIMENSION(NvertexB,2), INTENT(in)         :: polyB
4464    INTEGER, INTENT(out)                                 :: Ncoinvertex
4465    REAL(r_k), DIMENSION(NvertexAB,2), INTENT(out)        :: coinpoly
4466
4467! Local
4468    INTEGER                                              :: iA, iB, icoin, ii
4469    REAL(r_k), DIMENSION(2,2)                            :: face1, face2
4470    INTEGER                                              :: intersct
4471    REAL(r_k), DIMENSION(2)                              :: ptintersct
4472
4473
4474!!!!!!! variables
4475! NvertexA: number of vertexs polygon A
4476! NvertexB: number of vertexs polygon B
4477! polyA: pairs of coordinates for the polygon A (clockwise)
4478! polyB: pairs of coordinates for the polygon B (clockwise)
4479! Ncoinvertex: number of vertexes for the coincident polygon
4480! coinpoly: pairs of coordinates for the coincident polygon (clockwise)
4481
4482    fname = 'join_polygon'
4483
4484    icoin = 0
4485    coinpoly = 0.
4486
4487    ! First, include that vertex which do not lay within any polygon
4488    DO iA=1, NvertexA
4489      !PRINT *, '  iA:', iA, ':', polyA(iA,:), point_inside(polyA(iA,:), NvertexB, polyB)
4490      IF (.NOT. point_inside(polyA(iA,:), NvertexB, polyB)) THEN
4491        icoin = icoin + 1
4492        coinpoly(icoin,:) = polyA(iA,:)
4493      END IF
4494    END DO
4495
4496    DO iB=1, NvertexB
4497      !PRINT *, '  iB:', iB, ':', polyB(iB,:), point_inside(polyB(iB,:), NvertexA, polyA)
4498      IF (.NOT. point_inside(polyB(iB,:), NvertexA, polyA)) THEN
4499        icoin = icoin + 1
4500        coinpoly(icoin,:) = polyB(iB,:)
4501      END IF
4502    END DO
4503
4504    DO iA=1, NvertexA
4505      ! Getting couple of vertexs from polyA and polyB
4506      IF (iA /= NvertexA) THEN
4507        face1(1,:) = polyA(iA,:)
4508        face1(2,:) = polyA(iA+1,:)
4509      ELSE
4510        face1(1,:) = polyA(iA,:)
4511        face1(2,:) = polyA(1,:)
4512      END IF
4513      DO iB=1, NvertexB
4514        IF (iB /= NvertexB) THEN
4515          face2(1,:) = polyB(iB,:)
4516          face2(2,:) = polyB(iB+1,:)
4517        ELSE
4518          face2(1,:) = polyB(iB,:)
4519          face2(2,:) = polyB(1,:)
4520        END IF
4521       
4522        ! Compute areas of the four possible triangles. Introduce the coincident vertexs not included
4523        CALL intersectfaces(face1, face2, intersct, ptintersct)
4524        !PRINT *,iA,':',face1(1,:),';',face1(2,:), '=', iB, face2(1,:),';',face2(2,:), '<>', intersct,':', ptintersct
4525        IF (intersct == 1) THEN
4526          IF (.NOT.poly_has_point(icoin,coinpoly(1:icoin,:),ptintersct) ) THEN
4527            icoin = icoin + 1
4528            coinpoly(icoin,:) = ptintersct
4529          END IF
4530        ELSE IF (intersct == -1) THEN
4531          IF (.NOT.poly_has_point(icoin,coinpoly(1:icoin,:),ptintersct) ) THEN
4532            icoin = icoin + 1
4533            coinpoly(icoin,:) = ptintersct
4534          END IF
4535        END IF
4536
4537      END DO
4538    END DO
4539    Ncoinvertex = icoin
4540
4541  END SUBROUTINE join_polygon
4542
4543  SUBROUTINE sort_polygon(Nvertex, polygon, sense, Nnewvertex, newpoly)
4544  ! Subroutine to sort a polygon using its center as average of the coordinates and remove duplicates
4545  !    Should be used the centroid instead, but by now let do it simple
4546  !    https://en.wikipedia.org/wiki/Centroid
4547
4548
4549    IMPLICIT NONE
4550
4551    INTEGER, INTENT(in)                                  :: Nvertex, sense
4552    REAL(r_k), DIMENSION(Nvertex,2), INTENT(in)          :: polygon
4553    INTEGER, INTENT(out)                                 :: Nnewvertex
4554    REAL(r_k), DIMENSION(Nvertex,2), INTENT(out)         :: newpoly
4555
4556! Local
4557    INTEGER                                              :: iv, j
4558    REAL(r_k)                                            :: vang
4559    REAL(r_k), DIMENSION(2)                              :: center
4560    REAL(r_k), DIMENSION(Nvertex)                        :: angles
4561    REAL(r_k), DIMENSION(Nvertex,2)                      :: sortpoly
4562
4563!!!!!!! Variables
4564! Nvertex: number of vertices
4565! polygon: coordinates of the vertices of the polygon
4566! sense: sens of sorting thepolygon (1: clockwise, -1: anti-clockwise)
4567! sortpoly: sorted polygon
4568! Nnewvertex: number of vertices new polygon
4569! newpoly: sorted and duplicate removed polygon
4570
4571    fname = 'sort_polygon'
4572
4573    ! To be substituted by centroid calculation (which requires already sorted vetexs...)
4574    center(1) = SUM(polygon(:,1))/Nvertex
4575    center(2) = SUM(polygon(:,2))/Nvertex
4576
4577    DO iv=1, Nvertex
4578      angles(iv) = ATAN2(polygon(iv,2)-center(2),polygon(iv,1)-center(1))
4579    END DO
4580    CALL sortR_K(angles, Nvertex)
4581
4582    sortpoly = zeroRK
4583    DO iv=1, Nvertex
4584      DO j=1, Nvertex
4585        vang = ATAN2(polygon(j,2)-center(2), polygon(j,1)-center(1))
4586        IF (angles(iv) == vang) THEN
4587          IF (sense == -1) THEN
4588            sortpoly(iv,:) = polygon(j,:)
4589          ELSE
4590            sortpoly(Nvertex-iv+1,:) = polygon(j,:)
4591          END IF
4592          EXIT
4593        END IF
4594      END DO
4595    END DO
4596
4597    newpoly(1,:) = sortpoly(1,:)
4598    j = 1
4599    DO iv=2, Nvertex
4600      IF (.NOT.poly_has_point(j,newpoly(1:j,:),sortpoly(iv,:)) ) THEN
4601        j = j+1
4602        newpoly(j,:) = sortpoly(iv,:)
4603      END IF
4604    END DO
4605    Nnewvertex = j
4606
4607  END SUBROUTINE sort_polygon
4608
4609  LOGICAL FUNCTION point_inside(point, Nvertex, polygon)
4610  ! Function to determine if a given point is inside a polygon providing its sorted vertices
4611  ! FROM: https://en.wikipedia.org/wiki/Point_in_polygon
4612
4613    IMPLICIT NONE
4614
4615    REAL(r_k), DIMENSION(2), INTENT(in)                  :: point
4616    INTEGER, INTENT(in)                                  :: Nvertex
4617    REAL(r_k), DIMENSION(Nvertex,2), INTENT(in)          :: polygon
4618
4619    ! Local
4620    INTEGER                                              :: iv, Nintersect
4621    INTEGER                                              :: cross
4622    REAL(r_k)                                            :: xmin
4623    REAL(r_k), DIMENSION(2)                              :: crosspoint
4624    REAL(r_k), DIMENSION(2,2)                            :: face1, face2
4625    REAL(r_k), DIMENSION(Nvertex)                        :: abovebelow
4626
4627!!!!!!! Variables
4628! point: point to look for
4629! Nvertrex: number of vertices of a polygon
4630! polygon: vertices of a polygon
4631
4632    fname = 'point_inside'
4633
4634    xmin = MINVAL(polygon(:,1))
4635
4636    ! Looking for the intersection with the ray
4637    Nintersect = 0
4638    face1(1,:) = (/ xmin-0.5, point(2) /)
4639    face1(2,:) = (/ point(1), point(2) /)
4640
4641    DO iv = 1, Nvertex
4642      IF (iv /= Nvertex) THEN
4643        face2(1,:) = polygon(iv,:)
4644        face2(2,:) = polygon(iv+1,:)
4645      ELSE
4646        face2(1,:) = polygon(iv,:)
4647        face2(2,:) = polygon(1,:)
4648      END IF
4649      CALL intersectfaces(face1, face2, cross, crosspoint)
4650      IF (cross /= 0) THEN
4651        Nintersect = Nintersect + 1
4652        abovebelow(Nintersect) = iv
4653      END IF
4654    END DO
4655
4656    IF (MOD(Nintersect,2) == 0) THEN
4657      point_inside = .FALSE.
4658    ELSE
4659      point_inside = .TRUE.
4660    END IF
4661
4662  END FUNCTION point_inside
4663
4664  LOGICAL FUNCTION point_in_face(pt, Nvertex, poly)
4665  ! Function to determine if a given point is on a face of a polygon
4666
4667    IMPLICIT NONE
4668
4669    REAL(r_k), DIMENSION(2), INTENT(in)                  :: pt
4670    INTEGER, INTENT(in)                                  :: Nvertex
4671    REAL(r_k), DIMENSION(Nvertex,2), INTENT(in)          :: poly
4672! Local
4673    INTEGER                                              :: iv
4674    REAL(r_k)                                            :: ix, ex, iy, ey, tmpv
4675    REAL(r_k)                                            :: dx, dy, A, B
4676
4677!!!!!!! Variables
4678! pt: point to look for
4679! Nvertex: Number of vertices of the polygon
4680! poly: polygon
4681    fname = 'point_in_face'
4682
4683    point_in_face = .FALSE.
4684    DO iv=1, Nvertex
4685      IF (iv < Nvertex) THEN
4686        ix = poly(iv,1)
4687        ex = poly(iv+1,1)
4688        iy = poly(iv,2)
4689        ey = poly(iv+1,2)
4690      ELSE
4691        ix = poly(iv,1)
4692        ex = poly(1,1)
4693        iy = poly(iv,2)
4694        ey = poly(1,2)
4695      END IF   
4696      dx = ex - ix
4697      dy = ey - iy
4698
4699      IF (dx == zeroRK) THEN
4700        IF (pt(1) == ix) THEN
4701          IF ( (iy < ey) .AND. (pt(2) >= iy) .AND. pt(2) <= ey) THEN
4702            point_in_face = .TRUE.
4703            EXIT
4704          ELSE IF ( (iy > ey) .AND. (pt(2) >= ey) .AND. pt(2) <= iy) THEN
4705            point_in_face = .TRUE.
4706            EXIT
4707          END IF
4708        END IF
4709      ELSE
4710        IF (dy == zeroRK) THEN
4711          IF (pt(2) == iy) THEN
4712            IF ((ix < ex) .AND. (pt(1) >= ix) .AND. pt(1) <= ex) THEN
4713              point_in_face = .TRUE.
4714              EXIT           
4715            ELSE IF ((ix > ex) .AND. (pt(1) >= ex) .AND. pt(1) <= ix) THEN
4716              point_in_face = .TRUE.
4717              EXIT
4718            END IF
4719          END IF
4720        ELSE
4721          A = iy
4722          B = (ey-iy)/(ex-ix)
4723          IF (A+B*(pt(1)-ix) == pt(2)) THEN
4724            point_in_face = .TRUE.
4725            EXIT
4726          END IF
4727        END IF
4728      END IF
4729    END DO
4730
4731  END FUNCTION point_in_face
4732
4733  SUBROUTINE coincident_polygon(NvertexA, NvertexB, NvertexAB, polyA, polyB, Ncoinvertex, coinpoly)
4734  ! Subroutine to provide the intersection polygon between two polygons
4735  ! AFTER: http://www.cap-lore.com/MathPhys/IP/ and http://www.cap-lore.com/MathPhys/IP/IL.html
4736
4737    IMPLICIT NONE
4738
4739    INTEGER, INTENT(in)                                  :: NvertexA, NvertexB, NvertexAB
4740    REAL(r_k), DIMENSION(NvertexA,2), INTENT(in)         :: polyA
4741    REAL(r_k), DIMENSION(NvertexB,2), INTENT(in)         :: polyB
4742    INTEGER, INTENT(out)                                 :: Ncoinvertex
4743    REAL(r_k), DIMENSION(NvertexAB,2), INTENT(out)       :: coinpoly
4744
4745! Local
4746    INTEGER                                              :: iA, iB, icoin, ii
4747    REAL(r_k), DIMENSION(2,2)                            :: face1, face2
4748    INTEGER                                              :: intersct
4749    REAL(r_k), DIMENSION(2)                              :: ptintersct
4750
4751!!!!!!! variables
4752! NvertexA: number of vertexs polygon A
4753! NvertexB: number of vertexs polygon B
4754! polyA: pairs of coordinates for the polygon A (clockwise)
4755! polyB: pairs of coordinates for the polygon B (clockwise)
4756! Ncoinvertex: number of vertexes for the coincident polygon
4757! coinpoly: pairs of coordinates for the coincident polygon (clockwise)
4758
4759    fname = 'coincident_polygon'
4760
4761    icoin = 0
4762    coinpoly = 0.
4763    ! First, include that vertex which lay within any polygon
4764    DO iA=1, NvertexA
4765      IF (point_inside(polyA(iA,:), NvertexB, polyB)) THEN
4766        icoin = icoin + 1
4767        coinpoly(icoin,:) = polyA(iA,:)
4768      END IF
4769      IF (point_in_face(polyA(iA,:), NvertexB, polyB)) THEN
4770        icoin = icoin + 1
4771        coinpoly(icoin,:) = polyA(iA,:)
4772      END IF
4773    END DO
4774
4775    DO iB=1, NvertexB
4776      IF (point_inside(polyB(iB,:), NvertexA, polyA)) THEN
4777        icoin = icoin + 1
4778        coinpoly(icoin,:) = polyB(iB,:)
4779      END IF
4780      IF (point_in_face(polyB(iB,:), NvertexA, polyA)) THEN
4781        icoin = icoin + 1
4782        coinpoly(icoin,:) = polyB(iB,:)
4783      END IF
4784    END DO
4785
4786    ! Look interesections
4787    DO iA=1, NvertexA
4788      ! Getting couple of vertexs from polyA and polyB
4789      IF (iA /= NvertexA) THEN
4790        face1(1,:) = polyA(iA,:)
4791        face1(2,:) = polyA(iA+1,:)
4792      ELSE
4793        face1(1,:) = polyA(iA,:)
4794        face1(2,:) = polyA(1,:)
4795      END IF
4796      DO iB=1, NvertexB
4797        IF (iB /= NvertexB) THEN
4798          face2(1,:) = polyB(iB,:)
4799          face2(2,:) = polyB(iB+1,:)
4800        ELSE
4801          face2(1,:) = polyB(iB,:)
4802          face2(2,:) = polyB(1,:)
4803        END IF
4804       
4805        ! Compute areas of the four possible triangles. Introduce the coincident vertexs not included
4806        CALL intersectfaces(face1, face2, intersct, ptintersct)
4807        !PRINT *,iA,':',face1(1,:),';',face1(2,:), '=', iB, face2(1,:),';',face2(2,:), '<>', intersct,':', ptintersct
4808        IF ((intersct /= 0) .AND. (.NOT.poly_has_point(icoin,coinpoly(1:icoin,:),ptintersct)) ) THEN
4809          icoin = icoin + 1
4810          coinpoly(icoin,:) = ptintersct
4811        END IF
4812
4813      END DO
4814    END DO
4815    Ncoinvertex = icoin
4816
4817  END SUBROUTINE coincident_polygon
4818
4819  SUBROUTINE grid_within_polygon(NvertexA, polygonA, dx, dy, dxy, xCvals, yCvals, Nvertexmax, xBvals, &
4820    yBvals, Ngridsin, gridsin)
4821  ! Subroutine to determine which grid cells from a matrix lay inside a polygon
4822
4823    IMPLICIT NONE
4824
4825    INTEGER, INTENT(in)                                  :: NvertexA, dx, dy, dxy, Nvertexmax
4826    REAL(r_k), DIMENSION(NvertexA,2), INTENT(in)         :: polygonA
4827    REAL(r_k), DIMENSION(dx,dy), INTENT(in)              :: xCvals, yCvals
4828    REAL(r_k), DIMENSION(dx,dy,Nvertexmax), INTENT(in)   :: xBvals, yBvals
4829    INTEGER, INTENT(out)                                 :: Ngridsin
4830    INTEGER, DIMENSION(dxy,2), INTENT(out)               :: gridsin
4831
4832! Local
4833    INTEGER                                              :: ix, iy, iv
4834    REAL(r_k), DIMENSION(2)                              :: centergrid, vertex
4835    LOGICAL, DIMENSION(dx,dy)                            :: within
4836
4837!!!!!!! Variables
4838! NvertexA: Number of vertices of the polygin to find the grids
4839! polygonA: ordered vertices of the polygon
4840! dx, dy: shape of the matrix with the grid points
4841! xCvals, yCvals: coordinates of the center of the grid cells
4842! Nvertexmax: Maximum number of vertices of the grid cells
4843! xBvals, yBvals: coordinates of th vertices of the grid cells (-99999 for no vertex)
4844! Ngridsin: number of grids with some extension within the polygon
4845! gridsin: grids within the polygin
4846! percentages: percentages of area of each of the grids within the polygon
4847
4848    fname = 'spacepercen_within_reg'
4849
4850    Ngridsin = 0
4851    gridsin = 0
4852    within = .FALSE.
4853    DO ix = 1, dx
4854      DO iy = 1, dy
4855        IF (.NOT.within(ix,iy)) THEN
4856          centergrid = (/ xCvals(ix,iy), yCvals(ix,iy) /)
4857          ! By grid center
4858          IF (point_inside(centergrid, NvertexA, polygonA)) THEN
4859            Ngridsin = Ngridsin + 1
4860            ! Getting coordinates
4861            gridsin(Ngridsin,1) = ix
4862            gridsin(Ngridsin,2) = iy
4863            within(ix,iy) = .TRUE.
4864            CYCLE
4865          END IF
4866
4867          ! Getting grid vertices
4868          DO iv=1, Nvertexmax
4869            IF (.NOT.within(ix,iy)) THEN
4870              IF (xBvals(ix,iy,iv) /= fillvalI) THEN
4871                vertex = (/ xBvals(ix,iy,iv), yBvals(ix,iy,iv) /)
4872                IF (point_inside(vertex, NvertexA, polygonA)) THEN
4873                  Ngridsin = Ngridsin + 1
4874                  ! Getting coordinates
4875                  gridsin(Ngridsin,1) = ix
4876                  gridsin(Ngridsin,2) = iy
4877                  within(ix,iy) = .TRUE.
4878                  CYCLE
4879                END IF
4880              END IF
4881            END IF
4882          END DO
4883
4884        END IF
4885      END DO
4886    END DO
4887
4888  END SUBROUTINE grid_within_polygon
4889
4890  SUBROUTINE spacepercen_within_reg(NvertexA, polygonA, dx, dy, Nvertexmax, xBvals, yBvals,           &
4891    Ngridsin, gridsin, strict, percentages)
4892  ! Subroutine to compute the percentage of a series of grid cells which are encompassed by a polygon
4893  ! NOTE: Assuming coordinates on the plane with rectilinar, distance preserved and perpendicular x
4894  !   and y axes.
4895
4896    IMPLICIT NONE
4897
4898    INTEGER, INTENT(in)                                  :: NvertexA, dx, dy, Nvertexmax
4899    REAL(r_k), DIMENSION(NvertexA,2), INTENT(in)         :: polygonA
4900    REAL(r_k), DIMENSION(dx,dy,Nvertexmax), INTENT(in)   :: xBvals, yBvals
4901    INTEGER, INTENT(in)                                  :: Ngridsin
4902    INTEGER, DIMENSION(Ngridsin,2), INTENT(in)           :: gridsin
4903    LOGICAL, INTENT(in)                                  :: strict
4904    REAL(r_k), DIMENSION(Ngridsin), INTENT(out)          :: percentages
4905
4906! Local
4907   INTEGER                                               :: ig, iv, ix, iy
4908   INTEGER                                               :: Nvertex, NvertexAgrid, Ncoin, Nsort
4909   CHARACTER(len=20)                                     :: DS
4910   REAL(r_k)                                             :: areapoly, areagpoly, totarea, totpercent
4911   REAL(r_k), ALLOCATABLE, DIMENSION(:,:)                :: vertexgrid, icoinpoly, coinpoly,          &
4912     sortpoly, poly
4913
4914!!!!!!! Variables
4915! NvertexA: Number of vertices of the polygin to find the grids
4916! polygonA: ordered vertices of the polygon
4917! dx, dy: shape of the matrix with the grid points
4918! xCvals, yCvals: coordinates of the center of the grid cells
4919! Nvertexmax: Maximum number of vertices of the grid cells
4920! xBvals, yBvals: coordinates of th vertices of the grid cells (-99999 for no vertex)
4921! Ngridsin: number of grids with some extension within the polygon
4922! gridsin: grids within the polygon
4923! strict: give an error if the area of the polygon is not fully covered
4924! percentages: percentages of area of each of the grids within the polygon
4925
4926    fname = 'spacepercen_within_reg'
4927
4928    percentages = zeroRK
4929    totpercent = zeroRK
4930    totarea = zeroRK
4931
4932    areapoly = shoelace_area_polygon(NvertexA, polygonA)
4933
4934    DO ig = 1, Ngridsin
4935      ix = gridsin(ig,1)
4936      iy = gridsin(ig,2)
4937
4938      ! Getting grid vertices
4939      Nvertex = 0
4940      DO iv=1, Nvertexmax
4941        IF (xBvals(ix,iy,iv) /= fillvalI) THEN
4942          Nvertex = Nvertex + 1
4943        END IF
4944      END DO
4945      IF (ALLOCATED(vertexgrid)) DEALLOCATE(vertexgrid)
4946      ALLOCATE(vertexgrid(Nvertex,2))
4947      vertexgrid(:,1) = xBvals(ix,iy,1:Nvertex)
4948      vertexgrid(:,2) = yBvals(ix,iy,1:Nvertex)
4949
4950      ! Getting common vertices
4951      NvertexAgrid = NvertexA*Nvertex*2
4952      IF (ALLOCATED(icoinpoly)) DEALLOCATE(icoinpoly)
4953      ALLOCATE(icoinpoly(NvertexAgrid,2))
4954      CALL coincident_polygon(NvertexA, Nvertex, NvertexAgrid, polygonA, vertexgrid, Ncoin, icoinpoly)
4955
4956      IF (ALLOCATED(coinpoly)) DEALLOCATE(coinpoly)
4957      ALLOCATE(coinpoly(Ncoin,2))
4958      DO iv=1, Ncoin
4959        coinpoly(iv,:) = icoinpoly(iv,:)
4960      END DO
4961
4962      IF (ALLOCATED(sortpoly)) DEALLOCATE(sortpoly)
4963      ALLOCATE(sortpoly(Ncoin,2))
4964      CALL sort_polygon(Ncoin, coinpoly, 1, Nsort, sortpoly)
4965
4966      IF (ALLOCATED(poly)) DEALLOCATE(poly)
4967      ALLOCATE(poly(Nsort,2))
4968      DO iv=1, Nsort
4969        poly(iv,:) = sortpoly(iv,:)
4970      END DO
4971
4972      areagpoly = shoelace_area_polygon(Nsort, poly)
4973      IF (INT(LOG10(EPSILON(totpercent))) < 12) THEN
4974        totarea = totarea + ABS(areagpoly)
4975        percentages(ig) = ABS(areagpoly / areapoly)
4976! f2py does not like it!
4977!      ELSE
4978!        totarea = totarea + DABS(areagpoly)
4979!        percentages(ig) = DABS(areagpoly / areapoly)
4980      END IF
4981      totpercent = totpercent + percentages(ig)
4982    END DO
4983
4984    IF (INT(LOG10(EPSILON(totpercent))) < 12) THEN
4985      IF (strict .AND. ABS(totpercent - oneRK) > epsilonRK) THEN
4986        PRINT *, 'totarea:', totarea, ' area polygon:', areapoly
4987        PRINT *, 'totpercent:', totpercent, ' oneRK:', oneRK, ' diff:', totpercent - oneRK
4988        WRITE(DS,'(F20.8)')ABS(totpercent - oneRK)
4989        msg = 'sum of all grid space percentages does not cover (' // TRIM(DS) // ') all polygon'
4990        CALL ErrMsg(msg, fname, -1)
4991      END IF
4992    ELSE
4993! f2py does not like it!
4994!      IF (strict .AND. ABS(totpercent - oneRK) > epsilonRK) THEN
4995!        PRINT *, 'totarea:', totarea, ' area polygon:', areapoly
4996!        PRINT *, 'totpercent:', totpercent, ' oneRK:', oneRK, ' diff:', totpercent - oneRK
4997!        WRITE(DS,'(F20.16)')ABS(totpercent - oneRK)
4998!        msg = 'sum of all grid space percentages does not cover (' // TRIM(DS) // ') all polygon'
4999!        CALL ErrMsg(msg, fname, -1)
5000!      END IF
5001    END IF
5002
5003    IF (ALLOCATED(vertexgrid)) DEALLOCATE(vertexgrid)
5004    IF (ALLOCATED(icoinpoly)) DEALLOCATE(icoinpoly)
5005    IF (ALLOCATED(coinpoly)) DEALLOCATE(coinpoly)
5006    IF (ALLOCATED(sortpoly)) DEALLOCATE(sortpoly)
5007    IF (ALLOCATED(poly)) DEALLOCATE(poly)
5008
5009  END SUBROUTINE spacepercen_within_reg
5010
5011  SUBROUTINE grid_spacepercen_within_reg(NvertexA, polygonA, dx, dy, Nvertexmax, xBvals, yBvals,      &
5012    Ngridsin, gridsin, strict, gridspace, percentages)
5013  ! Subroutine to compute the percentage of grid space of a series of grid cells which are encompassed
5014  !   by a polygon
5015  ! NOTE: Assuming coordinates on the plane with rectilinar, distance preserved and perpendicular x
5016  !   and y axes.
5017
5018    IMPLICIT NONE
5019
5020    INTEGER, INTENT(in)                                  :: NvertexA, dx, dy, Nvertexmax
5021    REAL(r_k), DIMENSION(NvertexA,2), INTENT(in)         :: polygonA
5022    REAL(r_k), DIMENSION(dx,dy,Nvertexmax), INTENT(in)   :: xBvals, yBvals
5023    INTEGER, INTENT(in)                                  :: Ngridsin
5024    INTEGER, DIMENSION(Ngridsin,2), INTENT(in)           :: gridsin
5025    LOGICAL, INTENT(in)                                  :: strict
5026    REAL(r_k), DIMENSION(Ngridsin), INTENT(out)          :: gridspace, percentages
5027
5028! Local
5029   INTEGER                                               :: ig, iv, ix, iy
5030   INTEGER                                               :: Nvertex, NvertexAgrid, Ncoin, Nsort
5031   CHARACTER(len=20)                                     :: DS
5032   REAL(r_k)                                             :: areapoly, areagpoly
5033   REAL(r_k), ALLOCATABLE, DIMENSION(:,:)                :: vertexgrid, icoinpoly, coinpoly,          &
5034     sortpoly, poly
5035
5036!!!!!!! Variables
5037! NvertexA: Number of vertices of the polygon to find the grids
5038! polygonA: ordered vertices of the polygon
5039! dx, dy: shape of the matrix with the grid points
5040! xCvals, yCvals: coordinates of the center of the grid cells
5041! Nvertexmax: Maximum number of vertices of the grid cells
5042! xBvals, yBvals: coordinates of th vertices of the grid cells (-99999 for no vertex)
5043! Ngridsin: number of grids with some extension within the polygon
5044! gridsin: grids within the polygon
5045! strict: give an error if the area of the polygon is not fully covered
5046! gridspace: area of each of the grids
5047! percentages: percentages of grid area of each of the grids within the polygon
5048
5049    fname = 'grid_spacepercen_within_reg'
5050
5051    gridspace = zeroRK
5052    percentages = zeroRK
5053
5054    DO ig = 1, Ngridsin
5055      ix = gridsin(ig,1)
5056      iy = gridsin(ig,2)
5057
5058     ! Getting grid vertices
5059      Nvertex = 0
5060      DO iv=1, Nvertexmax
5061        IF (xBvals(ix,iy,iv) /= fillvalI) THEN
5062          Nvertex = Nvertex + 1
5063        END IF
5064      END DO
5065      IF (ALLOCATED(vertexgrid)) DEALLOCATE(vertexgrid)
5066      ALLOCATE(vertexgrid(Nvertex,2))
5067      vertexgrid(:,1) = xBvals(ix,iy,1:Nvertex)
5068      vertexgrid(:,2) = yBvals(ix,iy,1:Nvertex)
5069      areapoly = shoelace_area_polygon(Nvertex, vertexgrid)
5070
5071      ! Getting common vertices
5072      NvertexAgrid = NvertexA*Nvertex*2
5073      IF (ALLOCATED(icoinpoly)) DEALLOCATE(icoinpoly)
5074      ALLOCATE(icoinpoly(NvertexAgrid,2))
5075      CALL coincident_polygon(NvertexA, Nvertex, NvertexAgrid, polygonA, vertexgrid, Ncoin, icoinpoly)
5076
5077      IF (ALLOCATED(coinpoly)) DEALLOCATE(coinpoly)
5078      ALLOCATE(coinpoly(Ncoin,2))
5079      DO iv=1, Ncoin
5080        coinpoly(iv,:) = icoinpoly(iv,:)
5081      END DO
5082
5083      IF (ALLOCATED(sortpoly)) DEALLOCATE(sortpoly)
5084      ALLOCATE(sortpoly(Ncoin,2))
5085      CALL sort_polygon(Ncoin, coinpoly, 1, Nsort, sortpoly)
5086
5087      IF (ALLOCATED(poly)) DEALLOCATE(poly)
5088      ALLOCATE(poly(Nsort,2))
5089      DO iv=1, Nsort
5090        poly(iv,:) = sortpoly(iv,:)
5091      END DO
5092
5093      areagpoly = shoelace_area_polygon(Nsort, poly)
5094      gridspace(ig) = ABS(areapoly)
5095      percentages(ig) = ABS(areagpoly / areapoly)
5096    END DO
5097
5098    IF (ALLOCATED(vertexgrid)) DEALLOCATE(vertexgrid)
5099    IF (ALLOCATED(icoinpoly)) DEALLOCATE(icoinpoly)
5100    IF (ALLOCATED(coinpoly)) DEALLOCATE(coinpoly)
5101    IF (ALLOCATED(sortpoly)) DEALLOCATE(sortpoly)
5102    IF (ALLOCATED(poly)) DEALLOCATE(poly)
5103
5104  END SUBROUTINE grid_spacepercen_within_reg
5105
5106  SUBROUTINE grid_spacepercen_within_reg_providing_polys(NvertexA, polygonA, dx, dy, Nvertexmax,      &
5107    xBvals, yBvals, Ngridsin, gridsin, strict, Nmaxver2, Ncoinpoly, ccoinpoly, gridspace, percentages)
5108  ! Subroutine to compute the percentage of grid space of a series of grid cells which are encompassed
5109  !   by a polygon providing coordinates of the resultant polygons
5110  ! NOTE: Assuming coordinates on the plane with rectilinar, distance preserved and perpendicular x
5111  !   and y axes.
5112
5113    IMPLICIT NONE
5114
5115    INTEGER, INTENT(in)                                  :: NvertexA, dx, dy, Nvertexmax, Nmaxver2
5116    REAL(r_k), DIMENSION(NvertexA,2), INTENT(in)         :: polygonA
5117    REAL(r_k), DIMENSION(dx,dy,Nvertexmax), INTENT(in)   :: xBvals, yBvals
5118    INTEGER, INTENT(in)                                  :: Ngridsin
5119    INTEGER, DIMENSION(Ngridsin,2), INTENT(in)           :: gridsin
5120    LOGICAL, INTENT(in)                                  :: strict
5121    INTEGER, DIMENSION(Ngridsin), INTENT(out)            :: Ncoinpoly
5122    REAL(r_k), DIMENSION(Ngridsin,Nmaxver2,2),                                                        &
5123      INTENT(out)                                        :: ccoinpoly
5124    REAL(r_k), DIMENSION(Ngridsin), INTENT(out)          :: gridspace, percentages
5125
5126! Local
5127   INTEGER                                               :: ig, iv, ix, iy
5128   INTEGER                                               :: Nvertex, NvertexAgrid, Ncoin, Nsort
5129   CHARACTER(len=20)                                     :: DS
5130   REAL(r_k)                                             :: areapoly, areagpoly
5131   REAL(r_k), ALLOCATABLE, DIMENSION(:,:)                :: vertexgrid, icoinpoly, coinpoly,          &
5132     sortpoly, poly
5133
5134!!!!!!! Variables
5135! NvertexA: Number of vertices of the polygon to find the grids
5136! polygonA: ordered vertices of the polygon
5137! dx, dy: shape of the matrix with the grid points
5138! xCvals, yCvals: coordinates of the center of the grid cells
5139! Nvertexmax: Maximum number of vertices of the grid cells
5140! xBvals, yBvals: coordinates of th vertices of the grid cells (-99999 for no vertex)
5141! Ngridsin: number of grids with some extension within the polygon
5142! gridsin: grids within the polygon
5143! strict: give an error if the area of the polygon is not fully covered
5144! Nmaxver2: maximum possible number of vertices of the coincident polygon
5145! Ncoinpoly: number of vertices of the coincident polygon
5146! coinpoly: coordinates of the vertices of the coincident polygon
5147! gridspace: area of each of the grids
5148! percentages: percentages of grid area of each of the grids within the polygon
5149
5150    fname = 'grid_spacepercen_within_reg_providing_polys'
5151
5152    gridspace = zeroRK
5153    percentages = zeroRK
5154
5155    DO ig = 1, Ngridsin
5156      ix = gridsin(ig,1)
5157      iy = gridsin(ig,2)
5158
5159     ! Getting grid vertices
5160      Nvertex = 0
5161      DO iv=1, Nvertexmax
5162        IF (xBvals(ix,iy,iv) /= fillvalI) THEN
5163          Nvertex = Nvertex + 1
5164        END IF
5165      END DO
5166      IF (ALLOCATED(vertexgrid)) DEALLOCATE(vertexgrid)
5167      ALLOCATE(vertexgrid(Nvertex,2))
5168      vertexgrid(:,1) = xBvals(ix,iy,1:Nvertex)
5169      vertexgrid(:,2) = yBvals(ix,iy,1:Nvertex)
5170      areapoly = shoelace_area_polygon(Nvertex, vertexgrid)
5171
5172      ! Getting common vertices
5173      NvertexAgrid = NvertexA*Nvertex*2
5174      IF (ALLOCATED(icoinpoly)) DEALLOCATE(icoinpoly)
5175      ALLOCATE(icoinpoly(NvertexAgrid,2))
5176      CALL coincident_polygon(NvertexA, Nvertex, NvertexAgrid, polygonA, vertexgrid, Ncoin, icoinpoly)
5177
5178      IF (ALLOCATED(coinpoly)) DEALLOCATE(coinpoly)
5179      ALLOCATE(coinpoly(Ncoin,2))
5180      DO iv=1, Ncoin
5181        coinpoly(iv,:) = icoinpoly(iv,:)
5182      END DO
5183
5184      IF (ALLOCATED(sortpoly)) DEALLOCATE(sortpoly)
5185      ALLOCATE(sortpoly(Ncoin,2))
5186      CALL sort_polygon(Ncoin, coinpoly, 1, Nsort, sortpoly)
5187
5188      IF (ALLOCATED(poly)) DEALLOCATE(poly)
5189      ALLOCATE(poly(Nsort,2))
5190      DO iv=1, Nsort
5191        poly(iv,:) = sortpoly(iv,:)
5192      END DO
5193
5194      areagpoly = shoelace_area_polygon(Nsort, poly)
5195      Ncoinpoly(ig)= Nsort
5196      ccoinpoly(ig,:,:) = poly(:,:)
5197      gridspace(ig) = ABS(areapoly)
5198      percentages(ig) = ABS(areagpoly / areapoly)
5199    END DO
5200
5201    IF (ALLOCATED(vertexgrid)) DEALLOCATE(vertexgrid)
5202    IF (ALLOCATED(icoinpoly)) DEALLOCATE(icoinpoly)
5203    IF (ALLOCATED(coinpoly)) DEALLOCATE(coinpoly)
5204    IF (ALLOCATED(sortpoly)) DEALLOCATE(sortpoly)
5205    IF (ALLOCATED(poly)) DEALLOCATE(poly)
5206
5207  END SUBROUTINE grid_spacepercen_within_reg_providing_polys
5208
5209  SUBROUTINE spacepercen(xCAvals, yCAvals, xBAvals, yBAvals, xCBvals, yCBvals, xBBvals, yBBvals,      &
5210    dxA, dyA, NAvertexmax, dxB, dyB, dxyB, NBvertexmax, strict, Ngridsin, gridsin, areas, percentages)
5211  ! Subroutine to compute the space-percentages of a series of grid cells (B) into another series of
5212  !   grid-cells (A)
5213  ! NOTE: Assuming coordinates on the plane with rectilinar, distance preserved and perpendicular x
5214  !   and y axes.
5215
5216    IMPLICIT NONE
5217
5218    INTEGER, INTENT(in)                                  :: dxA, dyA, NAvertexmax
5219    INTEGER, INTENT(in)                                  :: dxB, dyB, NBvertexmax, dxyB
5220    REAL(r_k), DIMENSION(dxA,dyA), INTENT(in)            :: xCAvals, yCAvals
5221    REAL(r_k), DIMENSION(dxB,dyB), INTENT(in)            :: xCBvals, yCBvals
5222    REAL(r_k), DIMENSION(dxA,dyA,NAvertexmax), INTENT(in):: xBAvals, yBAvals
5223    REAL(r_k), DIMENSION(dxB,dyB,NBvertexmax), INTENT(in):: xBBvals, yBBvals
5224    LOGICAL, INTENT(in)                                  :: strict
5225    INTEGER, DIMENSION(dxA,dyA), INTENT(out)             :: Ngridsin
5226    INTEGER, DIMENSION(dxA,dyA,dxyB,2), INTENT(out)      :: gridsin
5227    REAL(r_k), DIMENSION(dxA,dyA), INTENT(out)           :: areas
5228    REAL(r_k), DIMENSION(dxA,dyA,dxyB), INTENT(out)      :: percentages
5229
5230! Local
5231   INTEGER                                               :: iv, ix, iy
5232   INTEGER                                               :: Nvertex
5233   INTEGER, ALLOCATABLE, DIMENSION(:,:)                  :: poinsin
5234   CHARACTER(len=20)                                     :: IS
5235   REAL(r_k), ALLOCATABLE, DIMENSION(:,:)                :: vertexgrid
5236
5237!!!!!!! Variables
5238! dxA, dyA: shape of the matrix with the grid points A
5239! xCAvals, yCAvals: coordinates of the center of the grid cells A
5240! NAvertexmax: Maximum number of vertices of the grid cells A
5241! xBAvals, yBAvals: coordinates of th vertices of the grid cells A (-99999 for no vertex)
5242! dxB, dyB: shape of the matrix with the grid points B
5243! xCBvals, yCBvals: coordinates of the center of the grid cells B
5244! NBvertexmax: Maximum number of vertices of the grid cells B
5245! xBBvals, yBBvals: coordinates of th vertices of the grid cells B (-99999 for no vertex)
5246! strict: give an error if the area of the polygon is not fully covered
5247! Ngridsin: number of grids from grid B with some extension within the grid cell A
5248! gridsin: indices of B grids within the grids of A
5249! areas: areas of the polygons
5250! percentages: percentages of area of cells B of each of the grids within the grid cell A
5251
5252    fname = 'spacepercen'
5253
5254    DO ix = 1, dxA
5255      DO iy = 1, dyA
5256
5257        ! Getting grid vertices
5258        Nvertex = 0
5259        DO iv=1, NAvertexmax
5260          IF (xBAvals(ix,iy,iv) /= fillval64) THEN
5261           Nvertex = Nvertex + 1
5262          END IF
5263        END DO
5264        IF (ALLOCATED(vertexgrid)) DEALLOCATE(vertexgrid)
5265        ALLOCATE(vertexgrid(Nvertex,2))
5266        vertexgrid(:,1) = xBAvals(ix,iy,1:Nvertex)
5267        vertexgrid(:,2) = yBAvals(ix,iy,1:Nvertex)
5268 
5269        CALL grid_within_polygon(Nvertex, vertexgrid, dxB, dyB, dxB*dyB, xCBvals, yCBvals,            &
5270          NBvertexmax, xBBvals, yBBvals, Ngridsin(ix,iy), gridsin(ix,iy,:,:))
5271   
5272        IF (ALLOCATED(poinsin)) DEALLOCATE(poinsin)
5273        ALLOCATE(poinsin(Ngridsin(ix,iy),2))
5274
5275        DO iv=1, Ngridsin(ix,iy)
5276          poinsin(iv,1) = gridsin(ix,iy,iv,1)
5277          poinsin(iv,2) = gridsin(ix,iy,iv,2)
5278        END DO
5279
5280        areas(ix,iy) = shoelace_area_polygon(Nvertex, vertexgrid)
5281        CALL spacepercen_within_reg(Nvertex, vertexgrid, dxB, dyB, NBvertexmax, xBBvals, yBBvals,     &
5282          Ngridsin(ix,iy), poinsin, strict, percentages(ix,iy,:))
5283
5284      END DO
5285    END DO
5286
5287    IF (ALLOCATED(vertexgrid)) DEALLOCATE(vertexgrid)
5288    IF (ALLOCATED(poinsin)) DEALLOCATE(poinsin)
5289
5290  END SUBROUTINE spacepercen
5291
5292  SUBROUTINE grid_spacepercen(xCAvals, yCAvals, xBAvals, yBAvals, xCBvals, yCBvals, xBBvals, yBBvals, &
5293    dxA, dyA, NAvertexmax, dxB, dyB, dxyB, NBvertexmax, strict, Ngridsin, gridsin,  areas2D, areas,   &
5294    percentages)
5295  ! Subroutine to compute the space-percentages of a series of grid cells (B) which lay inside another
5296  !   series of grid-cells (A) porviding coincident polygons
5297  ! NOTE: Assuming coordinates on the plane with rectilinar, distance preserved and perpendicular x
5298  !   and y axes.
5299
5300    IMPLICIT NONE
5301
5302    INTEGER, INTENT(in)                                  :: dxA, dyA, NAvertexmax
5303    INTEGER, INTENT(in)                                  :: dxB, dyB, NBvertexmax, dxyB
5304    REAL(r_k), DIMENSION(dxA,dyA), INTENT(in)            :: xCAvals, yCAvals
5305    REAL(r_k), DIMENSION(dxB,dyB), INTENT(in)            :: xCBvals, yCBvals
5306    REAL(r_k), DIMENSION(dxA,dyA,NAvertexmax), INTENT(in):: xBAvals, yBAvals
5307    REAL(r_k), DIMENSION(dxB,dyB,NBvertexmax), INTENT(in):: xBBvals, yBBvals
5308    LOGICAL, INTENT(in)                                  :: strict
5309    INTEGER, DIMENSION(dxA,dyA), INTENT(out)             :: Ngridsin
5310    INTEGER, DIMENSION(dxA,dyA,dxyB,2), INTENT(out)      :: gridsin
5311    REAL(r_k), DIMENSION(dxB,dyB), INTENT(out)           :: areas2D
5312    REAL(r_k), DIMENSION(dxA,dyA,dxyB), INTENT(out)      :: areas,percentages
5313
5314! Local
5315   INTEGER                                               :: iv, ix, iy
5316   INTEGER                                               :: Nvertex, Nptin
5317   INTEGER, ALLOCATABLE, DIMENSION(:,:)                  :: poinsin
5318   CHARACTER(len=20)                                     :: IS
5319   REAL(r_k), ALLOCATABLE, DIMENSION(:,:)                :: vertexgrid
5320
5321!!!!!!! Variables
5322! dxA, dyA: shape of the matrix with the grid points A
5323! xCAvals, yCAvals: coordinates of the center of the grid cells A
5324! NAvertexmax: Maximum number of vertices of the grid cells A
5325! xBAvals, yBAvals: coordinates of th vertices of the grid cells A (-99999 for no vertex)
5326! dxB, dyB: shape of the matrix with the grid points B
5327! xCBvals, yCBvals: coordinates of the center of the grid cells B
5328! NBvertexmax: Maximum number of vertices of the grid cells B
5329! xBBvals, yBBvals: coordinates of th vertices of the grid cells B (-99999 for no vertex)
5330! strict: give an error if the area of the polygon is not fully covered
5331! Ngridsin: number of grids from grid B with some extension within the grid cell A
5332! gridsin: indices of B grids within the grids of A
5333! areas2D: areas of the grids as 2D matrix in the original shape
5334! areas: areas of cells B of each of the grids inside the grid cell A
5335! percentages: percentages of area of cells B of each of the grids inside the grid cell A
5336
5337    fname = 'grid_spacepercen'
5338
5339    areas2D = zeroRK
5340    areas = zeroRK
5341    percentages = zeroRK
5342
5343    DO ix = 1, dxA
5344      DO iy = 1, dyA
5345
5346        ! Getting grid vertices
5347        Nvertex = 0
5348        DO iv=1, NAvertexmax
5349          IF (xBAvals(ix,iy,iv) /= fillval64) THEN
5350           Nvertex = Nvertex + 1
5351          END IF
5352        END DO
5353        IF (ALLOCATED(vertexgrid)) DEALLOCATE(vertexgrid)
5354        ALLOCATE(vertexgrid(Nvertex,2))
5355        vertexgrid(:,1) = xBAvals(ix,iy,1:Nvertex)
5356        vertexgrid(:,2) = yBAvals(ix,iy,1:Nvertex)
5357 
5358        CALL grid_within_polygon(Nvertex, vertexgrid, dxB, dyB, dxB*dyB, xCBvals, yCBvals,            &
5359          NBvertexmax, xBBvals, yBBvals, Ngridsin(ix,iy), gridsin(ix,iy,1:dxyB,:))
5360   
5361        IF (ALLOCATED(poinsin)) DEALLOCATE(poinsin)
5362        ALLOCATE(poinsin(Ngridsin(ix,iy),2))
5363
5364        DO iv=1, Ngridsin(ix,iy)
5365          poinsin(iv,1) = gridsin(ix,iy,iv,1)
5366          poinsin(iv,2) = gridsin(ix,iy,iv,2)
5367        END DO
5368
5369        Nptin = Ngridsin(ix,iy)
5370        CALL grid_spacepercen_within_reg(Nvertex, vertexgrid, dxB, dyB, NBvertexmax, xBBvals,        &
5371          yBBvals, Ngridsin(ix,iy), poinsin, strict, areas(ix,iy,1:Nptin), percentages(ix,iy,1:Nptin))
5372
5373        ! Filling areas
5374        DO iv = 1, Ngridsin(ix,iy)
5375          IF (areas2D(poinsin(iv,1), poinsin(iv,2)) == zeroRK) THEN
5376            areas2D(poinsin(iv,1), poinsin(iv,2)) = areas(ix,iy,iv)
5377          END IF
5378        END DO
5379
5380      END DO
5381    END DO
5382
5383    IF (ALLOCATED(vertexgrid)) DEALLOCATE(vertexgrid)
5384    IF (ALLOCATED(poinsin)) DEALLOCATE(poinsin)
5385
5386  END SUBROUTINE grid_spacepercen
5387
5388  SUBROUTINE grid_spacepercen_providing_polys(xCAvals, yCAvals, xBAvals, yBAvals, xCBvals, yCBvals,   &
5389    xBBvals, yBBvals, dxA, dyA, NAvertexmax, dxB, dyB, dxyB, NBvertexmax, strict, Nmaxvercoin,        &
5390    Nvercoinpolys, vercoinpolys, Ngridsin, gridsin,  areas, percentages)
5391  ! Subroutine to compute the space-percentages of a series of grid cells (B) which lay inside another
5392  !   series of grid-cells (A) providing coincident polygons
5393  ! NOTE: Assuming coordinates on the plane with rectilinar, distance preserved and perpendicular x
5394  !   and y axes.
5395
5396    IMPLICIT NONE
5397
5398    INTEGER, INTENT(in)                                  :: dxA, dyA, NAvertexmax
5399    INTEGER, INTENT(in)                                  :: dxB, dyB, NBvertexmax, dxyB
5400    INTEGER, INTENT(in)                                  :: Nmaxvercoin
5401    REAL(r_k), DIMENSION(dxA,dyA), INTENT(in)            :: xCAvals, yCAvals
5402    REAL(r_k), DIMENSION(dxB,dyB), INTENT(in)            :: xCBvals, yCBvals
5403    REAL(r_k), DIMENSION(dxA,dyA,NAvertexmax), INTENT(in):: xBAvals, yBAvals
5404    REAL(r_k), DIMENSION(dxB,dyB,NBvertexmax), INTENT(in):: xBBvals, yBBvals
5405    LOGICAL, INTENT(in)                                  :: strict
5406    INTEGER, DIMENSION(dxA,dyA,dxyB,Nmaxvercoin),                                                     &
5407      INTENT(out)                                        :: Nvercoinpolys
5408    REAL(r_k), DIMENSION(dxA,dyA,dxyB,Nmaxvercoin,2),                                                 &
5409      INTENT(out)                                        :: vercoinpolys
5410    INTEGER, DIMENSION(dxA,dyA), INTENT(out)             :: Ngridsin
5411    INTEGER, DIMENSION(dxA,dyA,dxyB,2), INTENT(out)      :: gridsin
5412    REAL(r_k), DIMENSION(dxB,dyB), INTENT(out)           :: areas
5413    REAL(r_k), DIMENSION(dxA,dyA,dxyB), INTENT(out)      :: percentages
5414
5415! Local
5416   INTEGER                                               :: iv, ix, iy
5417   INTEGER                                               :: Nvertex
5418   INTEGER, ALLOCATABLE, DIMENSION(:,:)                  :: poinsin
5419   CHARACTER(len=20)                                     :: IS
5420   REAL(r_k), ALLOCATABLE, DIMENSION(:)                  :: pareas
5421   REAL(r_k), ALLOCATABLE, DIMENSION(:,:)                :: vertexgrid
5422
5423!!!!!!! Variables
5424! dxA, dyA: shape of the matrix with the grid points A
5425! xCAvals, yCAvals: coordinates of the center of the grid cells A
5426! NAvertexmax: Maximum number of vertices of the grid cells A
5427! xBAvals, yBAvals: coordinates of th vertices of the grid cells A (-99999 for no vertex)
5428! dxB, dyB: shape of the matrix with the grid points B
5429! xCBvals, yCBvals: coordinates of the center of the grid cells B
5430! NBvertexmax: Maximum number of vertices of the grid cells B
5431! xBBvals, yBBvals: coordinates of th vertices of the grid cells B (-99999 for no vertex)
5432! strict: give an error if the area of the polygon is not fully covered
5433! Nvercoinpolys: number of vertices of the coincident polygon of each grid
5434! coinpolys: of vertices of the coincident polygon of each grid
5435! Ngridsin: number of grids from grid B with some extension within the grid cell A
5436! gridsin: indices of B grids within the grids of A
5437! areas: areas of the grids
5438! percentages: percentages of area of cells B of each of the grids inside the grid cell A
5439
5440    fname = 'grid_spacepercen_providing_polys'
5441
5442    areas = zeroRK
5443
5444    DO ix = 1, dxA
5445      DO iy = 1, dyA
5446
5447        ! Getting grid vertices
5448        Nvertex = 0
5449        DO iv=1, NAvertexmax
5450          IF (xBAvals(ix,iy,iv) /= fillval64) THEN
5451           Nvertex = Nvertex + 1
5452          END IF
5453        END DO
5454        IF (ALLOCATED(vertexgrid)) DEALLOCATE(vertexgrid)
5455        ALLOCATE(vertexgrid(Nvertex,2))
5456        vertexgrid(:,1) = xBAvals(ix,iy,1:Nvertex)
5457        vertexgrid(:,2) = yBAvals(ix,iy,1:Nvertex)
5458 
5459        CALL grid_within_polygon(Nvertex, vertexgrid, dxB, dyB, dxB*dyB, xCBvals, yCBvals,            &
5460          NBvertexmax, xBBvals, yBBvals, Ngridsin(ix,iy), gridsin(ix,iy,:,:))
5461   
5462        IF (ALLOCATED(poinsin)) DEALLOCATE(poinsin)
5463        ALLOCATE(poinsin(Ngridsin(ix,iy),2))
5464        IF (ALLOCATED(pareas)) DEALLOCATE(pareas)
5465        ALLOCATE(pareas(Ngridsin(ix,iy)))
5466
5467        DO iv=1, Ngridsin(ix,iy)
5468          poinsin(iv,1) = gridsin(ix,iy,iv,1)
5469          poinsin(iv,2) = gridsin(ix,iy,iv,2)
5470        END DO
5471
5472        CALL grid_spacepercen_within_reg_providing_polys(Nvertex, vertexgrid, dxB, dyB, NBvertexmax, &
5473          xBBvals, yBBvals, Ngridsin(ix,iy), poinsin, strict, Nmaxvercoin, Nvercoinpolys(ix,iy,:,:), &
5474          vercoinpolys(ix,iy,:,:,:), pareas, percentages(ix,iy,:))
5475
5476        ! Filling areas
5477        DO iv = 1, Ngridsin(ix,iy)
5478          IF (areas(poinsin(iv,1), poinsin(iv,2)) == zeroRK) THEN
5479            areas(poinsin(iv,1), poinsin(iv,2)) = pareas(iv)
5480          END IF
5481        END DO
5482
5483      END DO
5484    END DO
5485
5486    IF (ALLOCATED(vertexgrid)) DEALLOCATE(vertexgrid)
5487    IF (ALLOCATED(pareas)) DEALLOCATE(pareas)
5488    IF (ALLOCATED(poinsin)) DEALLOCATE(poinsin)
5489
5490  END SUBROUTINE grid_spacepercen_providing_polys
5491
5492  SUBROUTINE unique_matrixRK2D(dx, dy, dxy, matrix2D, Nunique, unique)
5493  ! Subroutine to provide the unique values within a 2D RK matrix
5494
5495    IMPLICIT NONE
5496
5497    INTEGER, INTENT(in)                                  :: dx, dy, dxy
5498    REAL(r_k), DIMENSION(dx,dy), INTENT(in)              :: matrix2D
5499    INTEGER, INTENT(out)                                 :: Nunique
5500    REAL(r_k), DIMENSION(dxy), INTENT(out)               :: unique
5501
5502! Local
5503    INTEGER                                              :: ix, iy, iu, minvalv
5504    LOGICAL                                              :: single
5505    REAL(r_k), ALLOCATABLE, DIMENSION(:)                 :: uniques
5506
5507
5508!!!!!!! Variables
5509! dx, dy: dimensions of the matrix
5510! dxy: dx*dy, maximum possible amount of different values
5511! matrix2D: matgrix of values
5512! Nunique: amount of unique values
5513! unique: sorted from minimum to maximum vector with the unique values
5514
5515    fname = 'unique_matrixRK2D'
5516
5517    minvalv = MINVAL(matrix2D)
5518
5519    Nunique = 1
5520    unique(1) = minvalv
5521    DO ix= 1, dx
5522      DO iy= 1, dy
5523        single = .TRUE.
5524        DO iu = 1, Nunique
5525          IF (matrix2D(ix,iy) == unique(iu)) THEN
5526            single = .FALSE.
5527            EXIT
5528          END IF
5529        END DO
5530        IF (single) THEN
5531          Nunique = Nunique + 1
5532          unique(Nunique) = matrix2D(ix,iy)
5533        END IF
5534      END DO
5535    END DO
5536    IF (ALLOCATED(uniques)) DEALLOCATE(uniques)
5537    ALLOCATE(uniques(Nunique))
5538    uniques(1:Nunique) = unique(1:Nunique)
5539   
5540    CALL sortR_K(uniques(1:Nunique), Nunique)
5541    unique(1:Nunique) = uniques(1:Nunique)
5542
5543  END SUBROUTINE unique_matrixRK2D
5544
5545  SUBROUTINE spaceweightstats(varin, Ngridsin, gridsin, percentages, stats, varout, dxA, dyA, dxB,    &
5546    dyB, maxNgridsin, Lstats)
5547  ! Subroutine to compute an spatial statistics value from a matrix B into a matrix A using weights
5548
5549    IMPLICIT NONE
5550
5551    INTEGER, INTENT(in)                                  :: dxA, dyA, dxB, dyB, maxNgridsin, Lstats
5552    CHARACTER(len=*), INTENT(in)                         :: stats
5553    INTEGER, DIMENSION(dxA,dyA), INTENT(in)              :: Ngridsin
5554    INTEGER, DIMENSION(dxA,dyA,maxNgridsin,2), INTENT(in):: gridsin
5555    REAL(r_k), DIMENSION(dxB,dyB), INTENT(in)            :: varin
5556    REAL(r_k), DIMENSION(dxA,dyA,maxNgridsin), INTENT(in):: percentages
5557    REAL(r_k), DIMENSION(dxA,dyA,Lstats), INTENT(out)    :: varout
5558
5559! Local
5560    INTEGER                                              :: ix, iy, iv, ic, iu, ii, jj
5561    INTEGER                                              :: Ncounts
5562    CHARACTER(len=3)                                     :: val1S, val2S
5563    CHARACTER(len=30)                                    :: val3S
5564    REAL(r_k)                                            :: val1, val2
5565    REAL(r_k), DIMENSION(Lstats)                         :: icounts
5566
5567!!!!!!! Variables
5568! dxA, dyA: length of dimensions of matrix A
5569! dxB, dyB: length of dimensions of matrix B
5570! maxNgridsin: maximum number of grid points from B to be used to compute into a grid of matrix A
5571! Lstats: length of the dimension of the statistics
5572! varin: variable from matrix B to be used
5573! Ngridsin: number of grids from matrix B for each grid of matrix A
5574! gridsin: coordinates of grids of matrix B for each grid of matrix A
5575! percentages: weights as percentages of space of grid in matrix A covered by grid of matrix B
5576! stats: name of the spatial statistics to compute inside each grid of matrix A using values from
5577!     matrix B. Avaialbe ones:
5578!   'min': minimum value
5579!   'max': maximum value
5580!   'mean': space weighted mean value
5581!   'mean2': space weighted quadratic mean value
5582!   'stddev': space weighted standard deviation value
5583!   'count': percentage of the space of matrix A covered by each different value of matrix B
5584! varout: output statistical variable
5585
5586    fname = 'spaceweightstats'
5587
5588    ! Let's be efficvient?
5589    statn: SELECT CASE(TRIM(stats))
5590      CASE('min')
5591        varout = fillVal64
5592        DO ix=1, dxA
5593          DO iy=1, dyA
5594            DO iv=1, Ngridsin(ix,iy)
5595              ii = gridsin(ix,iy,iv,1)
5596              jj = gridsin(ix,iy,iv,2)
5597              IF (varin(ii,jj) < varout(ix,iy,Lstats)) varout(ix,iy,1) = varin(ii,jj)
5598            END DO
5599          END DO
5600        END DO
5601      CASE('max')
5602        varout = -fillVal64
5603        DO ix=1, dxA
5604          DO iy=1, dyA
5605            DO iv=1, Ngridsin(ix,iy)
5606              ii = gridsin(ix,iy,iv,1)
5607              jj = gridsin(ix,iy,iv,2)
5608              IF (varin(ii,jj) > varout(ix,iy,Lstats)) varout(ix,iy,1) = varin(ii,jj)
5609            END DO
5610          END DO
5611        END DO
5612      CASE('mean')
5613        varout = zeroRK
5614        DO ix=1, dxA
5615          DO iy=1, dyA
5616            DO iv=1, Ngridsin(ix,iy)
5617              ii = gridsin(ix,iy,iv,1)
5618              jj = gridsin(ix,iy,iv,2)
5619              varout(ix,iy,1) = varout(ix,iy,1) + varin(ii,jj)*percentages(ix,iy,iv)
5620            END DO
5621          END DO
5622        END DO
5623      CASE('mean2')
5624        varout = zeroRK
5625        DO ix=1, dxA
5626          DO iy=1, dyA
5627            DO iv=1, Ngridsin(ix,iy)
5628              ii = gridsin(ix,iy,iv,1)
5629              jj = gridsin(ix,iy,iv,2)
5630              varout(ix,iy,1) = varout(ix,iy,1) + percentages(ix,iy,iv)*(varin(ii,jj))**2
5631            END DO
5632            varout(ix,iy,1) = varout(ix,iy,1) / Ngridsin(ix,iy)
5633          END DO
5634        END DO
5635      CASE('stddev')
5636        varout = zeroRK
5637        DO ix=1, dxA
5638          DO iy=1, dyA
5639            val1 = zeroRK
5640            val2 = zeroRK
5641            DO iv=1, Ngridsin(ix,iy)
5642              ii = gridsin(ix,iy,iv,1)
5643              jj = gridsin(ix,iy,iv,2)
5644              val1 = val1 + varin(ii,jj)*percentages(ix,iy,iv)
5645              val2 = val2 + percentages(ix,iy,iv)*(varin(ii,jj))**2
5646            END DO
5647            varout(ix,iy,1) = SQRT(val2 - val1**2)
5648          END DO
5649        END DO
5650      CASE('count')
5651        CALL unique_matrixRK2D(dxB, dyB, dxB*dyB, varin, Ncounts, icounts)
5652        IF (Lstats /= Ncounts) THEN
5653          PRINT *,'  ' // TRIM(fname) // 'provided:', Lstats
5654          PRINT *,'  ' // TRIM(fname) // 'found:', Ncounts, ' :', icounts
5655          WRITE(val1S,'(I3)')Lstats
5656          WRITE(val2S,'(I3)')Ncounts
5657          msg = "for 'count' different amount of passed categories: " // TRIM(val1S) //               &
5658            ' and found ' // TRIM(val2S)
5659          CALL ErrMsg(msg, fname, -1)
5660        END IF
5661        varout = zeroRK
5662        DO ix=1, dxA
5663          DO iy=1, dyA
5664            DO iv=1, Ngridsin(ix,iy)
5665              ii = gridsin(ix,iy,iv,1)
5666              jj = gridsin(ix,iy,iv,2)
5667              ic = Index1DArrayR_K(icounts, Ncounts, varin(ii,jj))
5668              IF (ic == -1) THEN
5669                WRITE(val3S,'(f30.20)')varin(ii,jj)
5670                msg = "value '" // val3S // "' for 'count' not found"
5671                CALL ErrMSg(msg, fname, -1)
5672              ELSE
5673                varout(ix,iy,ic) = varout(ix,iy,ic) + percentages(ix,iy,iv)
5674              END IF
5675            END DO
5676          END DO
5677        END DO
5678      CASE DEFAULT
5679        msg = "statisitcs '" // TRIM(stats) // "' not ready !!" // CHAR(44) // " available ones: " // &
5680          "'min', 'max', 'mean', 'mean2', 'stddev', 'count'"
5681        CALL ErrMsg(msg, fname, -1)
5682    END SELECT statn
5683
5684  END SUBROUTINE spaceweightstats
5685
5686  SUBROUTINE multi_spaceweightstats_in1DRKno_slc3v3(varin, idv, Ngridsin, gridsin, percentages,       &
5687    varout, di1, ds1, ds2, ds3, maxNgridsin)
5688  ! Subroutine to compute an spatial statistics value from a 1D RK matrix without running one into a
5689  !   matrix of 3-variables slices of rank 3 using spatial weights
5690
5691    IMPLICIT NONE
5692
5693    INTEGER, INTENT(in)                                  :: di1, idv, ds1, ds2, ds3
5694    INTEGER, INTENT(in)                                  :: maxNgridsin
5695    INTEGER, DIMENSION(ds1,ds2,ds3), INTENT(in)          :: Ngridsin
5696    INTEGER, DIMENSION(ds1,ds2,ds3,maxNgridsin,2),                                                    &
5697      INTENT(in)                                         :: gridsin
5698    REAL(r_k), DIMENSION(di1), INTENT(in)                :: varin
5699    REAL(r_k), INTENT(in),                                                                            &
5700      DIMENSION(ds1,ds2,ds3,maxNgridsin)                 :: percentages
5701    REAL(r_k), DIMENSION(ds1,ds2,ds3,7), INTENT(out)     :: varout
5702
5703! Local
5704    INTEGER                                              :: i1, i2, i3, s1, s2, s3, iv
5705    INTEGER                                              :: ii3, ss1, ss2, ss3
5706    INTEGER                                              :: Ncounts, Nin
5707    INTEGER, DIMENSION(1)                                :: dmaxvarin
5708    CHARACTER(len=3)                                     :: val1S, val2S
5709    CHARACTER(len=30)                                    :: val3S
5710    REAL(r_k)                                            :: minv, maxv, meanv, mean2v, stdv, medv
5711    REAL(r_k), DIMENSION(:), ALLOCATABLE                 :: pin
5712    INTEGER, DIMENSION(:,:), ALLOCATABLE                 :: gin
5713    REAL(r_k), DIMENSION(:), ALLOCATABLE                 :: svin
5714    REAL(r_k), DIMENSION(:), ALLOCATABLE                 :: vin
5715
5716!!!!!!! Variables
5717! di1: length of dimensions of the 1D matrix of values
5718! ds[1-3]: length of dimensions of matrix with the slices
5719! maxNgridsin: maximum number of grid points from the 3D matrix in any slice
5720! varin: 1D RK variable to be used
5721! idv: which dimension of the sliced grids coincide with the dimension of 1D varin
5722! Ngridsin: number of grids from 3D RK matrix for each slice
5723! gridsin: coordinates of grids of the 3D RK matrix B to matrix of slices
5724! percentages: weights as percentages of space of 3D RK matrix for each slice
5725!!!!!
5726! Available spatial statistics to compute inside each slice using values from 3D RK matrix
5727!   'min': minimum value
5728!   'max': maximum value
5729!   'mean': space weighted mean value
5730!   'mean2': space weighted quadratic mean value
5731!   'stddev': space weighted standard deviation value
5732!   'median': median value
5733!   'count': percentage of the space of matrix A covered by each different value of matrix B
5734! varout: output statistical variable
5735
5736    fname = 'multi_spaceweightstats_in1DRKno_slc3v3'
5737
5738    varout = fillval64
5739
5740    ss1 = 8 + 1
5741    ss2 = 5 + 1
5742    ss3 = 3 + 1
5743    ii3 = 1 + 1
5744
5745    dmaxvarin = UBOUND(varin)
5746
5747    ! Let's be efficient?
5748    varout = fillVal64
5749    DO s1 =1, ds1
5750      DO s2 =1, ds2
5751        DO s3 =1, ds3
5752          Nin = Ngridsin(s1,s2,s3)
5753          ! Computing along d3
5754          IF (Nin > 1) THEN
5755            IF (ALLOCATED(gin)) DEALLOCATE(gin)
5756            ALLOCATE(gin(Nin,2))
5757            IF (ALLOCATED(pin)) DEALLOCATE(pin)
5758            ALLOCATE(pin(Nin))
5759            IF (ALLOCATED(vin)) DEALLOCATE(vin)
5760            ALLOCATE(vin(Nin))
5761            IF (ALLOCATED(svin)) DEALLOCATE(svin)
5762            ALLOCATE(svin(Nin))
5763            gin = gridsin(s1,s2,s3,1:Nin,:)
5764            pin = percentages(s1,s2,s3,1:Nin)
5765
5766            ! Getting the values
5767            DO iv=1, Nin
5768              i1 = gin(iv,idv)
5769              vin(iv) = varin(i1)
5770            END DO
5771            minv = fillVal64
5772            maxv = -fillVal64
5773            meanv = zeroRK
5774            mean2v = zeroRK
5775            stdv = zeroRK
5776            minv = MINVAL(vin)
5777            maxv = MAXVAL(vin)
5778            meanv = SUM(vin*pin)
5779            mean2v = SUM(vin**2*pin)
5780            DO iv=1,Nin
5781              stdv = stdv + ( (meanv - vin(iv))*pin(iv) )**2
5782            END DO
5783            stdv = SQRT(stdv)
5784            svin = vin(:)
5785            CALL SortR_K(svin, Nin)
5786            medv = svin(INT(Nin/2))
5787            varout(s1,s2,s3,1) = minv
5788            varout(s1,s2,s3,2) = maxv
5789            varout(s1,s2,s3,3) = meanv
5790            varout(s1,s2,s3,4) = mean2v
5791            varout(s1,s2,s3,5) = stdv
5792            varout(s1,s2,s3,6) = medv
5793            varout(s1,s2,s3,7) = Nin*1.
5794          ELSE
5795            i1 = gridsin(s1,s2,s3,1,idv)
5796            IF (i1 > 0 .AND. i1 <= dmaxvarin(1)) THEN
5797              varout(s1,s2,s3,1) = varin(i1)
5798              varout(s1,s2,s3,2) = varin(i1)
5799              varout(s1,s2,s3,3) = varin(i1)
5800              varout(s1,s2,s3,4) = varin(i1)*varin(i1)
5801              varout(s1,s2,s3,5) = zeroRK
5802              varout(s1,s2,s3,6) = varin(i1)
5803              varout(s1,s2,s3,7) = Nin*1.
5804            END IF
5805          END IF
5806        END DO
5807      END DO
5808    END DO
5809
5810    IF (ALLOCATED(gin)) DEALLOCATE(gin)
5811    IF (ALLOCATED(pin)) DEALLOCATE(pin)
5812    IF (ALLOCATED(vin)) DEALLOCATE(vin)
5813    IF (ALLOCATED(svin)) DEALLOCATE(svin)
5814   
5815    RETURN
5816
5817  END SUBROUTINE multi_spaceweightstats_in1DRKno_slc3v3
5818
5819  SUBROUTINE multi_spaceweightstats_in2DRKno_slc3v3(varin, Ngridsin, gridsin, percentages, varout,     &
5820    di1, di2, ds1, ds2, ds3, maxNgridsin)
5821  ! Subroutine to compute an spatial statistics value from a 2D RK matrix without running one into a
5822  !   matrix of 3-variables slices of rank 3 using spatial weights
5823
5824    IMPLICIT NONE
5825
5826    INTEGER, INTENT(in)                                  :: di1, di2, ds1, ds2, ds3
5827    INTEGER, INTENT(in)                                  :: maxNgridsin
5828    INTEGER, DIMENSION(ds1,ds2,ds3), INTENT(in)          :: Ngridsin
5829    INTEGER, DIMENSION(ds1,ds2,ds3,maxNgridsin,2),                                                    &
5830      INTENT(in)                                         :: gridsin
5831    REAL(r_k), DIMENSION(di1,di2), INTENT(in)            :: varin
5832    REAL(r_k), INTENT(in),                                                                            &
5833      DIMENSION(ds1,ds2,ds3,maxNgridsin)                 :: percentages
5834    REAL(r_k), DIMENSION(ds1,ds2,ds3,7), INTENT(out)     :: varout
5835
5836! Local
5837    INTEGER                                              :: i1, i2, i3, s1, s2, s3, iv
5838    INTEGER                                              :: ii3, ss1, ss2, ss3
5839    INTEGER                                              :: Ncounts, Nin
5840    CHARACTER(len=3)                                     :: val1S, val2S
5841    CHARACTER(len=30)                                    :: val3S
5842    REAL(r_k)                                            :: minv, maxv, meanv, mean2v, stdv, medv
5843    REAL(r_k), DIMENSION(:), ALLOCATABLE                 :: pin
5844    INTEGER, DIMENSION(:,:), ALLOCATABLE                 :: gin
5845    REAL(r_k), DIMENSION(:), ALLOCATABLE                 :: svin
5846    REAL(r_k), DIMENSION(:), ALLOCATABLE                 :: vin
5847
5848!!!!!!! Variables
5849! di1, di2: length of dimensions of the 2D matrix of values
5850! ds[1-3]: length of dimensions of matrix with the slices
5851! maxNgridsin: maximum number of grid points from the 3D matrix in any slice
5852! varin: 2D RK variable to be used
5853! Ngridsin: number of grids from 3D RK matrix for each slice
5854! gridsin: coordinates of grids of the 3D RK matrix B to matrix of slices
5855! percentages: weights as percentages of space of 3D RK matrix for each slice
5856!!!!!
5857! Available spatial statistics to compute inside each slice using values from 3D RK matrix
5858!   'min': minimum value
5859!   'max': maximum value
5860!   'mean': space weighted mean value
5861!   'mean2': space weighted quadratic mean value
5862!   'stddev': space weighted standard deviation value
5863!   'median': median value
5864!   'count': percentage of the space of matrix A covered by each different value of matrix B
5865! varout: output statistical variable
5866
5867    fname = 'multi_spaceweightstats_in2DRKno_slc3v3'
5868
5869    varout = fillval64
5870
5871    ss1 = 8 + 1
5872    ss2 = 5 + 1
5873    ss3 = 3 + 1
5874    ii3 = 1 + 1
5875
5876    ! Let's be efficient?
5877    varout = fillVal64
5878    DO s1 =1, ds1
5879      DO s2 =1, ds2
5880        DO s3 =1, ds3
5881          Nin = Ngridsin(s1,s2,s3)
5882          ! Computing along d3
5883          IF (Nin > 1) THEN
5884            IF (ALLOCATED(gin)) DEALLOCATE(gin)
5885            ALLOCATE(gin(Nin,2))
5886            IF (ALLOCATED(pin)) DEALLOCATE(pin)
5887            ALLOCATE(pin(Nin))
5888            IF (ALLOCATED(vin)) DEALLOCATE(vin)
5889            ALLOCATE(vin(Nin))
5890            IF (ALLOCATED(svin)) DEALLOCATE(svin)
5891            ALLOCATE(svin(Nin))
5892            gin = gridsin(s1,s2,s3,1:Nin,:)
5893            pin = percentages(s1,s2,s3,1:Nin)
5894
5895            ! Getting the values
5896            DO iv=1, Nin
5897              i1 = gin(iv,1)
5898              i2 = gin(iv,2)
5899              vin(iv) = varin(i1,i2)
5900            END DO
5901            minv = fillVal64
5902            maxv = -fillVal64
5903            meanv = zeroRK
5904            mean2v = zeroRK
5905            stdv = zeroRK
5906            minv = MINVAL(vin)
5907            maxv = MAXVAL(vin)
5908            meanv = SUM(vin*pin)
5909            mean2v = SUM(vin**2*pin)
5910            DO iv=1,Nin
5911              stdv = stdv + ( (meanv - vin(iv))*pin(iv) )**2
5912            END DO
5913            stdv = SQRT(stdv)
5914            svin = vin(:)
5915            CALL SortR_K(svin, Nin)
5916            medv = svin(INT(Nin/2))
5917            varout(s1,s2,s3,1) = minv
5918            varout(s1,s2,s3,2) = maxv
5919            varout(s1,s2,s3,3) = meanv
5920            varout(s1,s2,s3,4) = mean2v
5921            varout(s1,s2,s3,5) = stdv
5922            varout(s1,s2,s3,6) = medv
5923            varout(s1,s2,s3,7) = Nin*1.
5924          ELSE
5925            i1 = gridsin(s1,s2,s3,1,1)
5926            i2 = gridsin(s1,s2,s3,1,2)
5927            varout(s1,s2,s3,1) = varin(i1,i2)
5928            varout(s1,s2,s3,2) = varin(i1,i2)
5929            varout(s1,s2,s3,3) = varin(i1,i2)
5930            varout(s1,s2,s3,4) = varin(i1,i2)*varin(i1,i2)
5931            varout(s1,s2,s3,5) = zeroRK
5932            varout(s1,s2,s3,6) = varin(i1,i2)
5933            varout(s1,s2,s3,7) = Nin*1.
5934          END IF
5935        END DO
5936      END DO
5937    END DO
5938
5939    IF (ALLOCATED(gin)) DEALLOCATE(gin)
5940    IF (ALLOCATED(pin)) DEALLOCATE(pin)
5941    IF (ALLOCATED(vin)) DEALLOCATE(vin)
5942    IF (ALLOCATED(svin)) DEALLOCATE(svin)
5943   
5944    RETURN
5945
5946  END SUBROUTINE multi_spaceweightstats_in2DRKno_slc3v3
5947
5948  SUBROUTINE multi_spaceweightstats_in3DRK3_slc3v3(varin, Ngridsin, gridsin, percentages, varout,     &
5949    di1, di2, di3, ds1, ds2, ds3, maxNgridsin)
5950  ! Subroutine to compute an spatial statistics value from a 3D RK matrix using 3rd dimension as
5951  !   running one into a matrix of 3-variables slices of rank 3 using spatial weights
5952
5953    IMPLICIT NONE
5954
5955    INTEGER, INTENT(in)                                  :: di1, di2, di3, ds1, ds2, ds3
5956    INTEGER, INTENT(in)                                  :: maxNgridsin
5957    INTEGER, DIMENSION(ds1,ds2,ds3), INTENT(in)          :: Ngridsin
5958    INTEGER, DIMENSION(ds1,ds2,ds3,maxNgridsin,2),                                                    &
5959      INTENT(in)                                         :: gridsin
5960    REAL(r_k), DIMENSION(di1,di2,di3), INTENT(in)        :: varin
5961    REAL(r_k), INTENT(in),                                                                            &
5962      DIMENSION(ds1,ds2,ds3,maxNgridsin)                 :: percentages
5963    REAL(r_k), DIMENSION(ds1,ds2,ds3,di3,7), INTENT(out) :: varout
5964
5965! Local
5966    INTEGER                                              :: i1, i2, i3, s1, s2, s3, iv
5967    INTEGER                                              :: ii3, ss1, ss2, ss3
5968    INTEGER                                              :: Ncounts, Nin
5969    CHARACTER(len=3)                                     :: val1S, val2S
5970    CHARACTER(len=30)                                    :: val3S
5971    REAL(r_k)                                            :: minv, maxv, meanv, mean2v, stdv, medv
5972    REAL(r_k), DIMENSION(:), ALLOCATABLE                 :: pin
5973    INTEGER, DIMENSION(:,:), ALLOCATABLE                 :: gin
5974    REAL(r_k), DIMENSION(:), ALLOCATABLE                 :: svin
5975    REAL(r_k), DIMENSION(:,:), ALLOCATABLE               :: vin
5976
5977!!!!!!! Variables
5978! di1, di2, di3: length of dimensions of the 3D matrix of values
5979! ds[1-3]: length of dimensions of matrix with the slices
5980! maxNgridsin: maximum number of grid points from the 3D matrix in any slice
5981! varin: 3D RK variable to be used
5982! Ngridsin: number of grids from 3D RK matrix for each slice
5983! gridsin: coordinates of grids of the 3D RK matrix B to matrix of slices
5984! percentages: weights as percentages of space of 3D RK matrix for each slice
5985!!!!!
5986! Available spatial statistics to compute inside each slice using values from 3D RK matrix
5987!   'min': minimum value
5988!   'max': maximum value
5989!   'mean': space weighted mean value
5990!   'mean2': space weighted quadratic mean value
5991!   'stddev': space weighted standard deviation value
5992!   'median': median value
5993!   'count': percentage of the space of matrix A covered by each different value of matrix B
5994! varout: output statistical variable
5995
5996    fname = 'multi_spaceweightstats_in3DRK3_slc3v3'
5997
5998    varout = fillval64
5999
6000    ss1 = 8 + 1
6001    ss2 = 5 + 1
6002    ss3 = 3 + 1
6003    ii3 = 1 + 1
6004
6005    ! Let's be efficient?
6006    varout = fillVal64
6007    DO s1 =1, ds1
6008      DO s2 =1, ds2
6009        DO s3 =1, ds3
6010          Nin = Ngridsin(s1,s2,s3)
6011          ! Computing along d3
6012          IF (Nin > 1) THEN
6013            IF (ALLOCATED(gin)) DEALLOCATE(gin)
6014            ALLOCATE(gin(Nin,2))
6015            IF (ALLOCATED(pin)) DEALLOCATE(pin)
6016            ALLOCATE(pin(Nin))
6017            IF (ALLOCATED(vin)) DEALLOCATE(vin)
6018            ALLOCATE(vin(Nin,di3))
6019            IF (ALLOCATED(svin)) DEALLOCATE(svin)
6020            ALLOCATE(svin(Nin))
6021            gin = gridsin(s1,s2,s3,1:Nin,:)
6022            pin = percentages(s1,s2,s3,1:Nin)
6023
6024            ! Getting the values
6025            DO iv=1, Nin
6026              i1 = gin(iv,1)
6027              i2 = gin(iv,2)
6028              vin(iv,:) = varin(i1,i2,:)
6029            END DO
6030            DO i3=1, di3
6031              minv = fillVal64
6032              maxv = -fillVal64
6033              meanv = zeroRK
6034              mean2v = zeroRK
6035              stdv = zeroRK
6036              minv = MINVAL(vin(:,i3))
6037              maxv = MAXVAL(vin(:,i3))
6038              meanv = SUM(vin(:,i3)*pin)
6039              mean2v = SUM(vin(:,i3)**2*pin)
6040              DO iv=1,Nin
6041                stdv = stdv + ( (meanv - vin(iv,i3))*pin(iv) )**2
6042              END DO
6043              stdv = SQRT(stdv)
6044              svin = vin(:,i3)
6045              CALL SortR_K(svin, Nin)
6046              medv = svin(INT(Nin/2))
6047              varout(s1,s2,s3,i3,1) = minv
6048              varout(s1,s2,s3,i3,2) = maxv
6049              varout(s1,s2,s3,i3,3) = meanv
6050              varout(s1,s2,s3,i3,4) = mean2v
6051              varout(s1,s2,s3,i3,5) = stdv
6052              varout(s1,s2,s3,i3,6) = medv
6053              varout(s1,s2,s3,i3,7) = Nin*1.
6054            END DO
6055          ELSE
6056            i1 = gridsin(s1,s2,s3,1,1)
6057            i2 = gridsin(s1,s2,s3,1,2)
6058            varout(s1,s2,s3,:,1) = varin(i1,i2,:)
6059            varout(s1,s2,s3,:,2) = varin(i1,i2,:)
6060            varout(s1,s2,s3,:,3) = varin(i1,i2,:)
6061            varout(s1,s2,s3,:,4) = varin(i1,i2,:)*varin(i1,i2,:)
6062            varout(s1,s2,s3,:,5) = zeroRK
6063            varout(s1,s2,s3,:,6) = varin(i1,i2,:)
6064            varout(s1,s2,s3,:,7) = Nin*1.
6065          END IF
6066        END DO
6067      END DO
6068    END DO
6069
6070    IF (ALLOCATED(gin)) DEALLOCATE(gin)
6071    IF (ALLOCATED(pin)) DEALLOCATE(pin)
6072    IF (ALLOCATED(vin)) DEALLOCATE(vin)
6073    IF (ALLOCATED(svin)) DEALLOCATE(svin)
6074   
6075    RETURN
6076
6077  END SUBROUTINE multi_spaceweightstats_in3DRK3_slc3v3
6078
6079  SUBROUTINE multi_spaceweightstats_in3DRK3_slc3v4(varin, Ngridsin, gridsin, percentages, varout,     &
6080    di1, di2, di3, ds1, ds2, ds3, ds4, maxNgridsin)
6081  ! Subroutine to compute an spatial statistics value from a 3D RK matrix using 3rd dimension as
6082  !   running one into a matrix of 3-variables slices of rank 4 using spatial weights
6083
6084    IMPLICIT NONE
6085
6086    INTEGER, INTENT(in)                                  :: di1, di2, di3, ds1, ds2, ds3, ds4
6087    INTEGER, INTENT(in)                                  :: maxNgridsin
6088    INTEGER, DIMENSION(ds1,ds2,ds3,ds4), INTENT(in)      :: Ngridsin
6089    INTEGER, INTENT(in),                                                                              &
6090      DIMENSION(ds1,ds2,ds3,ds4,maxNgridsin,2)           :: gridsin
6091    REAL(r_k), DIMENSION(di1,di2,di3), INTENT(in)        :: varin
6092    REAL(r_k), INTENT(in),                                                                            &
6093      DIMENSION(ds1,ds2,ds3,ds4,maxNgridsin)             :: percentages
6094    REAL(r_k), DIMENSION(ds1,ds2,ds3,ds4,di3,7),                                                      &
6095      INTENT(out)                                        :: varout
6096
6097! Local
6098    INTEGER                                              :: i1, i2, i3, s1, s2, s3, s4, iv
6099    INTEGER                                              :: Ncounts, Nin
6100    CHARACTER(len=3)                                     :: val1S, val2S
6101    CHARACTER(len=30)                                    :: val3S
6102    REAL(r_k)                                            :: minv, maxv, meanv, mean2v, stdv, medv
6103    REAL(r_k), DIMENSION(:), ALLOCATABLE                 :: pin
6104    INTEGER, DIMENSION(:,:), ALLOCATABLE                 :: gin
6105    REAL(r_k), DIMENSION(:), ALLOCATABLE                 :: svin
6106    REAL(r_k), DIMENSION(:,:), ALLOCATABLE               :: vin
6107
6108!!!!!!! Variables
6109! di1, di2, di3: length of dimensions of the 3D matrix of values
6110! ds[1-4]: length of dimensions of matrix with the slices
6111! maxNgridsin: maximum number of grid points from the 3D matrix in any slice
6112! varin: 3D RK variable to be used
6113! Ngridsin: number of grids from 3D RK matrix for each slice
6114! gridsin: coordinates of grids of the 3D RK matrix B to matrix of slices
6115! percentages: weights as percentages of space of 3D RK matrix for each slice
6116!!!!!
6117! Available spatial statistics to compute inside each slice using values from 3D RK matrix
6118!   'min': minimum value
6119!   'max': maximum value
6120!   'mean': space weighted mean value
6121!   'mean2': space weighted quadratic mean value
6122!   'stddev': space weighted standard deviation value
6123!   'median': median value
6124!   'count': percentage of the space of matrix A covered by each different value of matrix B
6125! varout: output statistical variable
6126
6127    fname = 'multi_spaceweightstats_in3DRK3_slc3v4'
6128
6129    varout = fillval64
6130
6131    ! Let's be efficient?
6132    varout = fillVal64
6133    DO s1 =1, ds1
6134      DO s2 =1, ds2
6135        DO s3 =1, ds3
6136          DO s4 =1, ds4
6137            Nin = Ngridsin(s1,s2,s3,s4)
6138            IF (Nin > 1) THEN
6139              IF (ALLOCATED(gin)) DEALLOCATE(gin)
6140              ALLOCATE(gin(Nin,2))
6141              IF (ALLOCATED(pin)) DEALLOCATE(pin)
6142              ALLOCATE(pin(Nin))
6143              IF (ALLOCATED(vin)) DEALLOCATE(vin)
6144              ALLOCATE(vin(Nin,di3))
6145              IF (ALLOCATED(svin)) DEALLOCATE(svin)
6146              ALLOCATE(svin(Nin))
6147              gin = gridsin(s1,s2,s3,s4,1:Nin,:)
6148              pin = percentages(s1,s2,s3,s4,1:Nin)
6149
6150              ! Getting the values
6151              DO iv=1, Nin
6152                i1 = gin(iv,1)
6153                i2 = gin(iv,2)
6154                vin(iv,:) = varin(i1,i2,:)
6155              END DO
6156              ! Computing along d3
6157              DO i3=1, di3
6158                minv = fillVal64
6159                maxv = -fillVal64
6160                meanv = zeroRK
6161                mean2v = zeroRK
6162                stdv = zeroRK
6163
6164                minv = MINVAL(vin(:,i3))
6165                maxv = MAXVAL(vin(:,i3))
6166                meanv = SUM(vin(:,i3)*pin)
6167                mean2v = SUM(vin(:,i3)**2*pin) 
6168                DO iv=1,Nin
6169                  stdv = stdv + ( (meanv - vin(iv,i3))*pin(iv) )**2
6170                END DO
6171                stdv = SQRT(stdv)
6172                svin = vin(:,i3)
6173                CALL SortR_K(svin, Nin)
6174                medv = svin(INT(Nin/2))
6175                varout(s1,s2,s3,s4,i3,1) = minv
6176                varout(s1,s2,s3,s4,i3,2) = maxv
6177                varout(s1,s2,s3,s4,i3,3) = meanv
6178                varout(s1,s2,s3,s4,i3,4) = mean2v
6179                varout(s1,s2,s3,s4,i3,5) = stdv
6180                varout(s1,s2,s3,s4,i3,6) = medv
6181                varout(s1,s2,s3,s4,i3,7) = Nin*1.
6182              END DO
6183            ELSE
6184                i1 = gridsin(s1,s2,s3,s4,1,1)
6185                i2 = gridsin(s1,s2,s3,s4,1,2)
6186                varout(s1,s2,s3,s4,:,1) = varin(i1,i2,:)
6187                varout(s1,s2,s3,s4,:,2) = varin(i1,i2,:)
6188                varout(s1,s2,s3,s4,:,3) = varin(i1,i2,:)
6189                varout(s1,s2,s3,s4,:,4) = varin(i1,i2,:)*varin(i1,i2,:)
6190                varout(s1,s2,s3,s4,:,5) = zeroRK
6191                varout(s1,s2,s3,s4,:,6) = varin(i1,i2,:)
6192                varout(s1,s2,s3,s4,:,7) = Nin*1.
6193            END IF
6194          END DO
6195        END DO
6196      END DO
6197    END DO
6198
6199    IF (ALLOCATED(gin)) DEALLOCATE(gin)
6200    IF (ALLOCATED(pin)) DEALLOCATE(pin)
6201    IF (ALLOCATED(vin)) DEALLOCATE(vin)
6202    IF (ALLOCATED(svin)) DEALLOCATE(svin)
6203   
6204    RETURN
6205
6206  END SUBROUTINE multi_spaceweightstats_in3DRK3_slc3v4
6207
6208  SUBROUTINE multi_index_mat2DI(d1, d2, d12, mat, value, Nindices, indices)
6209  ! Subroutine to provide the indices of the different locations of a value inside a 2D integer matrix
6210
6211    IMPLICIT NONE
6212
6213    INTEGER, INTENT(in)                                  :: d1, d2, d12
6214    INTEGER, DIMENSION(d1,d2), INTENT(in)                :: mat
6215    INTEGER,INTENT(in)                                   :: value
6216    INTEGER, INTENT(out)                                 :: Nindices
6217    INTEGER, DIMENSION(2,d12), INTENT(out)               :: indices
6218
6219! Local
6220    INTEGER                                              :: i,j
6221    INTEGER                                              :: Ncounts1D, icount1D
6222    INTEGER, DIMENSION(d2)                               :: diffmat1D
6223
6224    !!!!!!! Variables
6225    ! d1, d2: shape of the 2D matrix
6226    ! mat: 2D matrix
6227    ! value: value to be looking for
6228    ! Nindices: number of times value found within matrix
6229    ! indices: indices of the found values
6230
6231    fname = 'multi_index_mat2DI'
6232
6233    Nindices = 0
6234    indices = 0
6235    DO i=1, d1
6236      diffmat1D = mat(i,:) - value
6237      IF (ANY(diffmat1D == 0)) THEN
6238        Ncounts1D = COUNT(diffmat1D == 0)
6239        icount1D = 0
6240        DO j=1, d2
6241          IF (diffmat1D(j) == 0) THEN
6242            Nindices = Nindices + 1
6243            indices(1,Nindices) = i
6244            indices(2,Nindices) = j
6245            icount1D = icount1D + 1
6246            IF (icount1D == Ncounts1D) EXIT
6247          END IF
6248        END DO
6249      END IF
6250    END DO
6251
6252  END SUBROUTINE multi_index_mat2DI
6253
6254  SUBROUTINE multi_index_mat3DI(d1, d2, d3, d123, mat, value, Nindices, indices)
6255  ! Subroutine to provide the indices of the different locations of a value inside a 3D integer matrix
6256
6257    IMPLICIT NONE
6258
6259    INTEGER, INTENT(in)                                  :: d1, d2, d3, d123
6260    INTEGER, DIMENSION(d1,d2,d3), INTENT(in)             :: mat
6261    INTEGER, INTENT(in)                                  :: value
6262    INTEGER, INTENT(out)                                 :: Nindices
6263    INTEGER, DIMENSION(3,d123), INTENT(out)              :: indices
6264
6265! Local
6266    INTEGER                                              :: i,j,k
6267    INTEGER                                              :: Ncounts1D, icount1D
6268    INTEGER                                              :: Ncounts2D, icount2D
6269    INTEGER, DIMENSION(d2,d3)                            :: diffmat2D
6270    INTEGER, DIMENSION(d3)                               :: diffmat1D
6271
6272    !!!!!!! Variables
6273    ! d1, d2, d3: shape of the 3D matrix
6274    ! mat: 3D matrix
6275    ! value: value to be looking for
6276    ! Nindices: number of times value found within matrix
6277    ! indices: indices of the found values
6278
6279    fname = 'multi_index_mat3DI'
6280
6281    Nindices = 0
6282    indices = 0
6283    DO i=1, d1
6284      diffmat2D = mat(i,:,:) - value
6285      IF (ANY(diffmat2D == 0)) THEN
6286        Ncounts2D = COUNT(diffmat2D == 0)
6287        icount2D = 0
6288        DO j=1, d2
6289          diffmat1D = mat(i,j,:) - value
6290          IF (ANY(diffmat1D == 0)) THEN
6291            Ncounts1D = COUNT(diffmat1D == 0)
6292            icount1D = 0
6293            DO k=1, d3
6294              IF (diffmat1D(k) == 0) THEN
6295                Nindices = Nindices + 1
6296                indices(1,Nindices) = i
6297                indices(2,Nindices) = j
6298                indices(3,Nindices) = k
6299                icount1D = icount1D + 1
6300                IF (icount1D == Ncounts1D) EXIT
6301              END IF
6302            END DO
6303            icount2D = icount2D + icount1D
6304            IF (icount2D == Ncounts2D) EXIT
6305          END IF
6306        END DO
6307      END IF
6308    END DO
6309
6310  END SUBROUTINE multi_index_mat3DI
6311
6312  SUBROUTINE multi_index_mat4DI(d1, d2, d3, d4, d1234, mat, value, Nindices, indices)
6313  ! Subroutine to provide the indices of the different locations of a value inside a 4D integer matrix
6314
6315    IMPLICIT NONE
6316
6317    INTEGER, INTENT(in)                                  :: d1, d2, d3, d4, d1234
6318    INTEGER, DIMENSION(d1,d2,d3,d4), INTENT(in)          :: mat
6319    INTEGER, INTENT(in)                                  :: value
6320    INTEGER, INTENT(out)                                 :: Nindices
6321    INTEGER, DIMENSION(4,d1234), INTENT(out)             :: indices
6322
6323! Local
6324    INTEGER                                              :: i,j,k,l
6325    INTEGER                                              :: Ncounts1D, icount1D
6326    INTEGER                                              :: Ncounts2D, icount2D
6327    INTEGER                                              :: Ncounts3D, icount3D
6328    INTEGER, DIMENSION(d2,d3,d4)                         :: diffmat3D
6329    INTEGER, DIMENSION(d3,d4)                            :: diffmat2D
6330    INTEGER, DIMENSION(d4)                               :: diffmat1D
6331
6332    !!!!!!! Variables
6333    ! d1, d2, d3, d4: shape of the 4D matrix
6334    ! mat: 4D matrix
6335    ! value: value to be looking for
6336    ! Nindices: number of times value found within matrix
6337    ! indices: indices of the found values
6338
6339    fname = 'multi_index_mat4DI'
6340
6341    Nindices = 0
6342    indices = 0
6343    DO i=1, d1
6344      diffmat3D = mat(i,:,:,:) - value
6345      IF (ANY(diffmat3D == 0)) THEN
6346        Ncounts3D = COUNT(diffmat3D == 0)
6347        icount3D = 0
6348        DO j=1, d2
6349          diffmat2D = mat(i,j,:,:) - value
6350          IF (ANY(diffmat2D == 0)) THEN
6351            Ncounts2D = COUNT(diffmat2D == 0)
6352            icount2D = 0
6353            DO k=1, d3
6354              diffmat1D = mat(i,j,k,:) - value
6355              IF (ANY(diffmat1D == 0)) THEN
6356                Ncounts1D = COUNT(diffmat1D == 0)
6357                icount1D = 0
6358                DO l=1, d4
6359                  IF (diffmat1D(l) == 0) THEN
6360                    Nindices = Nindices + 1
6361                    indices(1,Nindices) = i
6362                    indices(2,Nindices) = j
6363                    indices(3,Nindices) = k
6364                    indices(4,Nindices) = l
6365                    icount1D = icount1D + 1
6366                    IF (icount1D == Ncounts1D) EXIT
6367                  END IF
6368                END DO
6369              icount2D = icount2D + icount1D
6370              IF (icount2D == Ncounts2D) EXIT
6371              END IF
6372            END DO
6373            icount3D = icount3D + icount1D
6374            IF (icount3D == Ncounts3D) EXIT
6375          END IF
6376        END DO
6377      END IF
6378    END DO
6379
6380  END SUBROUTINE multi_index_mat4DI
6381
6382  SUBROUTINE multi_index_mat2DRK(d1, d2, d12, mat, value, Nindices, indices)
6383  ! Subroutine to provide the indices of the different locations of a value inside a 2D RK matrix
6384
6385    IMPLICIT NONE
6386
6387    INTEGER, INTENT(in)                                  :: d1, d2, d12
6388    REAL(r_k), DIMENSION(d1,d2), INTENT(in)              :: mat
6389    REAL(r_k),INTENT(in)                                 :: value
6390    INTEGER, INTENT(out)                                 :: Nindices
6391    INTEGER, DIMENSION(2,d12), INTENT(out)               :: indices
6392
6393! Local
6394    INTEGER                                              :: i,j
6395    INTEGER                                              :: Ncounts1D, icount1D
6396    REAL(r_k), DIMENSION(d2)                             :: diffmat1D
6397
6398    !!!!!!! Variables
6399    ! d1, d2: shape of the 2D matrix
6400    ! mat: 2D matrix
6401    ! value: value to be looking for
6402    ! Nindices: number of times value found within matrix
6403    ! indices: indices of the found values
6404
6405    fname = 'multi_index_mat2DRK'
6406
6407    Nindices = 0
6408    indices = 0
6409    DO i=1, d1
6410      diffmat1D = mat(i,:) - value
6411      IF (ANY(diffmat1D == zeroRK)) THEN
6412        Ncounts1D = COUNT(diffmat1D == zeroRK)
6413        icount1D = 0
6414        DO j=1, d2
6415          IF (diffmat1D(j) == zeroRK) THEN
6416            Nindices = Nindices + 1
6417            indices(1,Nindices) = i
6418            indices(2,Nindices) = j
6419            icount1D = icount1D + 1
6420            IF (icount1D == Ncounts1D) EXIT
6421          END IF
6422        END DO
6423      END IF
6424    END DO
6425
6426  END SUBROUTINE multi_index_mat2DRK
6427
6428  SUBROUTINE multi_index_mat3DRK(d1, d2, d3, d123, mat, value, Nindices, indices)
6429  ! Subroutine to provide the indices of the different locations of a value inside a 3D RK matrix
6430
6431    IMPLICIT NONE
6432
6433    INTEGER, INTENT(in)                                  :: d1, d2, d3, d123
6434    REAL(r_k), DIMENSION(d1,d2,d3), INTENT(in)           :: mat
6435    REAL(r_k),INTENT(in)                                 :: value
6436    INTEGER, INTENT(out)                                 :: Nindices
6437    INTEGER, DIMENSION(3,d123), INTENT(out)              :: indices
6438
6439! Local
6440    INTEGER                                              :: i,j,k
6441    INTEGER                                              :: Ncounts1D, icount1D
6442    INTEGER                                              :: Ncounts2D, icount2D
6443    REAL(r_k), DIMENSION(d2,d3)                          :: diffmat2D
6444    REAL(r_k), DIMENSION(d3)                             :: diffmat1D
6445
6446    !!!!!!! Variables
6447    ! d1, d2, d3: shape of the 3D matrix
6448    ! mat: 3D matrix
6449    ! value: value to be looking for
6450    ! Nindices: number of times value found within matrix
6451    ! indices: indices of the found values
6452
6453    fname = 'multi_index_mat3DRK'
6454
6455    Nindices = 0
6456    indices = 0
6457    DO i=1, d1
6458      diffmat2D = mat(i,:,:) - value
6459      IF (ANY(diffmat2D == zeroRK)) THEN
6460        Ncounts2D = COUNT(diffmat2D == zeroRK)
6461        icount2D = 0
6462        DO j=1, d2
6463          diffmat1D = mat(i,j,:) - value
6464          IF (ANY(diffmat1D == zeroRK)) THEN
6465            Ncounts1D = COUNT(diffmat1D == zeroRK)
6466            icount1D = 0
6467            DO k=1, d3
6468              IF (diffmat1D(k) == zeroRK) THEN
6469                Nindices = Nindices + 1
6470                indices(1,Nindices) = i
6471                indices(2,Nindices) = j
6472                indices(3,Nindices) = k
6473                icount1D = icount1D + 1
6474                IF (icount1D == Ncounts1D) EXIT
6475              END IF
6476            END DO
6477            icount2D = icount2D + icount1D
6478            IF (icount2D == Ncounts2D) EXIT
6479          END IF
6480        END DO
6481      END IF
6482    END DO
6483
6484  END SUBROUTINE multi_index_mat3DRK
6485
6486  SUBROUTINE multi_index_mat4DRK(d1, d2, d3, d4, d1234, mat, value, Nindices, indices)
6487  ! Subroutine to provide the indices of the different locations of a value inside a 4D RK matrix
6488
6489    IMPLICIT NONE
6490
6491    INTEGER, INTENT(in)                                  :: d1, d2, d3, d4, d1234
6492    REAL(r_k), DIMENSION(d1,d2,d3,d4), INTENT(in)        :: mat
6493    REAL(r_k),INTENT(in)                                 :: value
6494    INTEGER, INTENT(out)                                 :: Nindices
6495    INTEGER, DIMENSION(4,d1234), INTENT(out)             :: indices
6496
6497! Local
6498    INTEGER                                              :: i,j,k,l
6499    INTEGER                                              :: Ncounts1D, icount1D
6500    INTEGER                                              :: Ncounts2D, icount2D
6501    INTEGER                                              :: Ncounts3D, icount3D
6502    REAL(r_k), DIMENSION(d2,d3,d4)                       :: diffmat3D
6503    REAL(r_k), DIMENSION(d3,d4)                          :: diffmat2D
6504    REAL(r_k), DIMENSION(d4)                             :: diffmat1D
6505
6506    !!!!!!! Variables
6507    ! d1, d2, d3, d4: shape of the 4D matrix
6508    ! mat: 4D matrix
6509    ! value: value to be looking for
6510    ! Nindices: number of times value found within matrix
6511    ! indices: indices of the found values
6512
6513    fname = 'multi_index_mat4DRK'
6514
6515    Nindices = 0
6516    indices = 0
6517    DO i=1, d1
6518      diffmat3D = mat(i,:,:,:) - value
6519      IF (ANY(diffmat3D == zeroRK)) THEN
6520        Ncounts3D = COUNT(diffmat3D == zeroRK)
6521        icount3D = 0
6522        DO j=1, d2
6523          diffmat2D = mat(i,j,:,:) - value
6524          IF (ANY(diffmat2D == zeroRK)) THEN
6525            Ncounts2D = COUNT(diffmat2D == zeroRK)
6526            icount2D = 0
6527            DO k=1, d3
6528              diffmat1D = mat(i,j,k,:) - value
6529              IF (ANY(diffmat1D == zeroRK)) THEN
6530                Ncounts1D = COUNT(diffmat1D == zeroRK)
6531                icount1D = 0
6532                DO l=1, d4
6533                  IF (diffmat1D(l) == zeroRK) THEN
6534                    Nindices = Nindices + 1
6535                    indices(1,Nindices) = i
6536                    indices(2,Nindices) = j
6537                    indices(3,Nindices) = k
6538                    indices(4,Nindices) = l
6539                    icount1D = icount1D + 1
6540                    IF (icount1D == Ncounts1D) EXIT
6541                  END IF
6542                END DO
6543              icount2D = icount2D + icount1D
6544              IF (icount2D == Ncounts2D) EXIT
6545              END IF
6546            END DO
6547            icount3D = icount3D + icount1D
6548            IF (icount3D == Ncounts3D) EXIT
6549          END IF
6550        END DO
6551      END IF
6552    END DO
6553
6554  END SUBROUTINE multi_index_mat4DRK
6555
6556  SUBROUTINE coincident_list_2Dcoords(NpointsA, pointsA, NpointsB, pointsB, Npoints, points, inpA,    &
6557    inpB)
6558  ! Subroutine to determine which 2D points of an A list are also found in a B list
6559
6560    IMPLICIT NONE
6561
6562    INTEGER, INTENT(in)                                  :: NpointsA, NpointsB
6563    INTEGER, DIMENSION(NpointsA,2), INTENT(in)           :: pointsA
6564    INTEGER, DIMENSION(NpointsB,2), INTENT(in)           :: pointsB
6565    INTEGER, INTENT(out)                                 :: Npoints
6566    INTEGER, DIMENSION(NpointsA,2), INTENT(out)          :: points
6567    INTEGER, DIMENSION(NpointsA), INTENT(out)            :: inpA, inpB
6568
6569    ! Local
6570    INTEGER                                              :: iA, iB
6571
6572!!!!!!! Variables
6573! NpointsA: Number of points of the list A
6574! pointsA: points of the list A
6575! NpointsB: Number of points of the list B
6576! pointsB: points of the list B
6577! Npoints: Number of coincident points
6578! points: coincident points
6579! inpA: coincident points list A
6580! inpB: coincident points list B
6581
6582
6583    fname = 'coincident_list_2Dcoords'
6584
6585    Npoints = 0
6586    points = 0
6587    inpA = 0
6588    inpB = 0
6589
6590    DO iA = 1, NpointsA
6591      DO iB = 1, NpointsB
6592        IF ( (pointsA(iA,1) == pointsB(iB,1)) .AND. (pointsA(iA,2) == pointsB(iB,2)) ) THEN
6593          Npoints = Npoints + 1
6594          points(Npoints,1) = pointsA(iA,1)
6595          points(Npoints,2) = pointsA(iA,2)
6596          inpA(Npoints) = iA
6597          inpB(Npoints) = iB
6598          EXIT
6599        END IF
6600
6601      END DO
6602    END DO
6603
6604  END SUBROUTINE coincident_list_2Dcoords
6605
6606  SUBROUTINE coincident_gridsin2D_old(dxA, dyA, dxyA, NpointsA, pointsA, dxB, dyB, dxyB, NpointsB,    &
6607    pointsB, Npoints, points, inpointsA, inpointsB)
6608  ! Subroutine to determine which lists of 2D gridsin points of an A list are also found in a B list
6609
6610    IMPLICIT NONE
6611
6612    INTEGER, INTENT(in)                                  :: dxA, dyA, dxyA
6613    INTEGER, INTENT(in)                                  :: dxB, dyB, dxyB
6614    INTEGER, DIMENSION(dxA, dyA), INTENT(in)             :: NpointsA
6615    INTEGER, DIMENSION(dxB, dyB), INTENT(in)             :: NpointsB
6616    INTEGER, DIMENSION(dxA, dyA, dxyA, 2), INTENT(in)    :: pointsA
6617    INTEGER, DIMENSION(dxB, dyB, dxyB, 2), INTENT(in)    :: pointsB
6618    INTEGER, DIMENSION(dxA, dyA, dxB, dyB), INTENT(out)  :: Npoints
6619    INTEGER, DIMENSION(dxA, dyA, dxB, dyB, dxyA, 2),                                                  &
6620      INTENT(out)                                        :: points
6621    INTEGER, DIMENSION(dxA, dyA, dxB, dyB, dxyA),                                                     &
6622      INTENT(out)                                        :: inpointsA
6623    INTEGER, DIMENSION(dxA, dyA, dxB, dyB, dxyA),                                                     &
6624      INTENT(out)                                        :: inpointsB
6625
6626    ! Local
6627    INTEGER                                              :: ixA, iyA, ixB, iyB, iv, ii
6628    INTEGER                                              :: NA, NB
6629    INTEGER, DIMENSION(dxyA)                             :: ptsA, ptsB
6630    INTEGER, DIMENSION(dxyA, 2)                          :: pts
6631
6632
6633!!!!!!! Variables
6634! dxA, dyA: 2D shape of the list A
6635! NpointsA: 2D Number of points of the list A
6636! pointsA: points of the list A
6637! dxB, dyB: 2D shape of the list B
6638! NpointsB: 2D Number of points of the list B
6639! pointsB: points of the list B
6640! Npoints: Number of coincident points
6641! points: coincident points
6642! inpointsA: coincident points list A
6643! inpointsB: coincident points list B
6644
6645    fname = 'coincident_gridsin2D_old'
6646
6647    Npoints = 0
6648    points = 0
6649    inpointsA = 0
6650    inpointsB = 0
6651
6652    DO ixA=1, dxA
6653      DO iyA=1, dyA
6654        NA = NpointsA(ixA,iyA)
6655        DO ixB=1, dxB
6656          DO iyB=1, dyB
6657            NB = NpointsB(ixB,iyB)
6658            pts = -1
6659            CALL coincident_list_2Dcoords(NA, pointsA(ixA,iyA,1:NA,:), NB, pointsB(ixB,iyB,1:NB,:),   &
6660              Npoints(ixA,iyA,ixB,iyB), pts(1:NA,:), ptsA, ptsB)
6661            DO iv = 1, Npoints(ixA,iyA,ixB,iyB)
6662              points(ixA,iyA,ixB,iyB,iv,1) = pts(iv,1)
6663              points(ixA,iyA,ixB,iyB,iv,2) = pts(iv,2)
6664              inpointsA(ixA,iyA,ixB,iyB,iv) = ptsA(iv)
6665              inpointsB(ixA,iyA,ixB,iyB,iv) = ptsB(iv)
6666            END DO
6667          END DO
6668        END DO
6669      END DO
6670    END DO
6671
6672  END SUBROUTINE coincident_gridsin2D_old
6673
6674  SUBROUTINE coincident_gridsin2D(dxA, dyA, dxyA, NpointsA, pointsA, dxB, dyB, dxyB, NpointsB,        &
6675    pointsB, Npoints, points, inpointsA, inpointsB)
6676  ! Subroutine to determine which lists of 2D gridsin points of an A list are also found in a B list
6677
6678    IMPLICIT NONE
6679
6680    INTEGER, INTENT(in)                                  :: dxA, dyA, dxyA
6681    INTEGER, INTENT(in)                                  :: dxB, dyB, dxyB
6682    INTEGER, DIMENSION(dxA, dyA), INTENT(in)             :: NpointsA
6683    INTEGER, DIMENSION(dxB, dyB), INTENT(in)             :: NpointsB
6684    INTEGER, DIMENSION(dxA, dyA, dxyA, 2), INTENT(in)    :: pointsA
6685    INTEGER, DIMENSION(dxB, dyB, dxyB, 2), INTENT(in)    :: pointsB
6686    INTEGER, DIMENSION(dxA, dyA, dxB, dyB), INTENT(out)  :: Npoints
6687    INTEGER, DIMENSION(dxA, dyA, dxB, dyB, dxyA, 2),                                                  &
6688      INTENT(out)                                        :: points
6689    INTEGER, DIMENSION(dxA, dyA, dxB, dyB, dxyA),                                                     &
6690      INTENT(out)                                        :: inpointsA
6691    INTEGER, DIMENSION(dxA, dyA, dxB, dyB, dxyA),                                                     &
6692      INTENT(out)                                        :: inpointsB
6693
6694    ! Local
6695    INTEGER                                              :: ixA, iyA, ixB, iyB, iv, iv1, iv2
6696    INTEGER                                              :: NA, NB
6697    INTEGER, DIMENSION(dxyA)                             :: ptsA, ptsB
6698    INTEGER, DIMENSION(dxyA, 2)                          :: pts
6699
6700
6701!!!!!!! Variables
6702! dxA, dyA: 2D shape of the list A
6703! NpointsA: 2D Number of points of the list A
6704! pointsA: points of the list A
6705! dxB, dyB: 2D shape of the list B
6706! NpointsB: 2D Number of points of the list B
6707! pointsB: points of the list B
6708! Npoints: Number of coincident points
6709! points: coincident points
6710! inpointsA: coincident points list A
6711! inpointsB: coincident points list B
6712
6713    fname = 'coincident_gridsin2D'
6714
6715    Npoints = 0
6716    points = 0
6717    inpointsA = 0
6718    inpointsB = 0
6719
6720    DO ixA=1, dxA
6721      DO iyA=1, dyA
6722        NA = NpointsA(ixA,iyA)
6723        DO ixB=1, dxB
6724          DO iyB=1, dyB
6725            NB = NpointsB(ixB,iyB)
6726            iv = 0
6727            DO iv1=1, NA
6728              DO iv2=1, NB
6729                IF ( (pointsA(ixA,iyA,iv1,1) == pointsB(ixB,iyB,iv2,1)) .AND.                         &
6730                  (pointsA(ixA,iyA,iv1,2) == pointsB(ixB,iyB,iv2,2)) ) THEN
6731                  iv = iv + 1
6732                  points(ixA,iyA,ixB,iyB,iv,1) = pointsA(ixA,iyA,iv1,1)
6733                  points(ixA,iyA,ixB,iyB,iv,2) = pointsA(ixA,iyA,iv1,2)
6734                  inpointsA(ixA,iyA,ixB,iyB,iv) = iv1
6735                  inpointsB(ixA,iyA,ixB,iyB,iv) = iv2
6736                END IF
6737              END DO
6738            END DO
6739            Npoints(ixA,iyA,ixB,iyB) = iv
6740          END DO
6741        END DO
6742      END DO
6743    END DO   
6744
6745  END SUBROUTINE coincident_gridsin2D
6746
6747END MODULE module_scientific
Note: See TracBrowser for help on using the repository browser.