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

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

Finally working for 1D lon/lat variables from CMIP5 !!

File size: 248.7 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
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
2587!!!!!!! Variables
2588! dx,dy: spatial dimensions of the space
2589! boolmat: boolean matrix tolook for the polygons (.TRUE. based)
2590! polys: found polygons
2591! Npoly: number of polygons found
2592
2593  fname = 'polygons'
2594
2595  polys = -1
2596
2597  ! The mathematical maximum woiuld be dx*dy/4, but let's be optimistic... (sorry Jero)
2598  Nppt = dx*dy/10
2599
2600  IF (ALLOCATED(borders)) DEALLOCATE(borders)
2601  ALLOCATE(borders(Nppt,2), STAT=ierr)
2602  msg = "Problems allocating matrix 'borders'"
2603  CALL ErrMsg(msg, fname, ierr)
2604
2605  IF (ALLOCATED(paths)) DEALLOCATE(paths)
2606  ALLOCATE(paths(Nppt,Nppt,2), STAT=ierr)
2607  msg = "Problems allocating matrix 'paths'"
2608  CALL ErrMsg(msg, fname, ierr)
2609
2610  IF (ALLOCATED(Nptpaths)) DEALLOCATE(Nptpaths)
2611  ALLOCATE(Nptpaths(Nppt), STAT=ierr)
2612  msg = "Problems allocating matrix 'Nptpaths'"
2613  CALL ErrMsg(msg, fname, ierr)
2614
2615  ! Filling with the points of all the space with .TRUE.
2616  Npts = COUNT(boolmat)
2617
2618  IF (ALLOCATED(points)) DEALLOCATE(points)
2619  ALLOCATE(points(Npts,2), STAT=ierr)
2620  msg = "Problems allocating matrix 'points'"
2621  CALL ErrMsg(msg, fname, ierr)
2622
2623  ! We only want to localize that points 'inside'
2624  ip = 1
2625  DO i=1, dx
2626    DO j=1, dy
2627      IF (boolmat(i,j)) THEN
2628        points(ip,1) = i
2629        points(ip,2) = j
2630        ip = ip + 1
2631      END IF
2632    END DO
2633  END DO
2634
2635  CALL borders_matrixL(dx, dy, Nppt, boolmat, borders, isborder, isbordery)
2636  CALL paths_border(dbg, dx, dy, isborder, Nppt, borders, paths, Npath, Nptpaths)
2637
2638  Npoly = Npath
2639
2640  DO ip=1, Npath
2641    IF (ALLOCATED(vertxs)) DEALLOCATE(vertxs)
2642    ALLOCATE(vertxs(Nptpaths(ip),2))
2643    msg = "Problems allocating matrix 'vertxs'"
2644    CALL ErrMsg(msg, fname, ierr)
2645
2646    IF (ALLOCATED(isin)) DEALLOCATE(isin)
2647    ALLOCATE(isin(Npts), STAT=ierr)
2648    msg = "Problems allocating matrix 'isin'"
2649    CALL ErrMsg(msg, fname, ierr)
2650
2651    isin = .FALSE.
2652
2653    IF (dbg) PRINT *, '  path:', ip, ' N pts:', Nptpaths(ip)
2654
2655    CALL path_properties(dx, dy, boolmat, Nptpaths(ip), paths(ip,1:Nptpaths(ip),:), xtrx, xtry,       &
2656      meanpth, 'y', Nvertx, vertxs)
2657
2658    IF (dbg) THEN
2659      PRINT *, '    properties  _______'
2660      PRINT *, '    x-extremes:', xtrx
2661      PRINT *, '    y-extremes:', xtry
2662      PRINT *, '    center mean:', meanpth
2663      PRINT *, '    y-vertexs:', Nvertx,' ________'
2664      DO i=1, Nvertx
2665        PRINT *,'      ',i,':',vertxs(i,:)
2666      END DO
2667    END IF
2668 
2669    CALL gridpoints_InsidePolygon(dx, dy, isbordery, Nptpaths(ip), paths(ip,1:Nptpaths(ip),:), Nvertx,&
2670      xtrx, xtry, vertxs, Npts, points, isin)
2671
2672    ! Filling polygons
2673    DO ipp=1, Npts
2674      IF (isin(ipp)) polys(points(ipp,1),points(ipp,2)) = ip
2675    END DO
2676
2677    IF (dbg) THEN
2678      PRINT *,'  boolmat isborder isbordery polygon (',xtrx(1),',',xtry(1),')x(',xtrx(2),',',xtry(2), &
2679        ') _______'
2680      DO i=xtrx(1), xtrx(2)
2681        PRINT *,i,':',boolmat(i,xtry(1):xtry(2)), ' border ', isborder(i,xtry(1):xtry(2)),            &
2682          ' isbordery ', isbordery(i,xtry(1):xtry(2)), ' polygon ', polys(i,xtry(1):xtry(2))
2683      END DO
2684    END IF
2685
2686  END DO
2687
2688  ! Cleaning polygons matrix of not-used and paths around holes
2689  CALL clean_polygons(dx, dy, boolmat, polys, Npoly, dbg)
2690
2691  DEALLOCATE (borders) 
2692  DEALLOCATE (Nptpaths)
2693  DEALLOCATE (paths)
2694  DEALLOCATE (vertxs)
2695  DEALLOCATE (points)
2696  DEALLOCATE (isin)
2697
2698  RETURN
2699
2700END SUBROUTINE polygons
2701
2702SUBROUTINE clean_polygons(dx, dy, Lmat, pols, Npols, dbg)
2703! Subroutine to clean polygons from non-used paths, polygons only left as path since they are inner path of a hole
2704
2705  IMPLICIT NONE
2706
2707  INTEGER, INTENT(in)                                    :: dx, dy
2708  LOGICAL, DIMENSION(dx,dy), INTENT(in)                  :: Lmat
2709  INTEGER, INTENT(inout)                                 :: Npols
2710  INTEGER, DIMENSION(dx,dy), INTENT(inout)               :: pols
2711  LOGICAL, INTENT(in)                                    :: dbg
2712
2713! Local
2714  INTEGER                                                :: i,j,ip,iprm
2715  INTEGER, DIMENSION(Npols)                              :: origPol, NotPol, neigPol
2716  INTEGER                                                :: ispol, NnotPol
2717  CHARACTER(len=4)                                       :: ISa
2718
2719!!!!!!! Variables
2720! dx, dy: size of the space
2721! Lmat: original bolean matrix from which the polygons come from
2722! Npols: original number of polygons
2723! pols: polygons space
2724
2725  fname = 'clean_polygons'
2726  IF (dbg) PRINT *,"  At '" // TRIM(fname) // "' ..."
2727
2728  origPol = -1
2729
2730  ! Looking for polygons already in space
2731  NnotPol = 0
2732  DO ip=1, Npols
2733    ispol = COUNT(pols-ip == 0)
2734    IF (ispol > 0) THEN
2735      origPol(ip) = ip
2736    ELSE
2737      NnotPol = NnotPol + 1
2738      NotPol(NnotPol) = ip
2739      neigPol(NnotPol) = -1
2740    END IF
2741  END DO
2742
2743  IF (dbg) THEN
2744    PRINT *,'  It should be:', Npols, ' polygons, but already there are:', Npols - NnotPol
2745    PRINT *,'  Polygons to remove:', NotPol(1:NnotPol)
2746  END IF
2747 
2748  ! Looking for the hole border of a polygon. This is identify as such polygon point which along
2749  !   y-axis has NpolygonA, Npolygon, .FALSE.
2750  DO i=1,dx
2751    DO j=2,dy-1
2752      IF  ( (pols(i,j-1) /= pols(i,j) .AND. pols(i,j+1) == -1) .AND. (COUNT(NotPol-pols(i,j)==0)==0)  &
2753        .AND. (pols(i,j) /= -1) .AND. (pols(i,j-1) /= -1)) THEN
2754        IF (dbg) PRINT *,'  Polygon:', pols(i,j), ' to be removed at point (',i,',',j,'); j-1:',      &
2755          pols(i,j-1), ' j:', pols(i,j), ' j+1:', pols(i,j+1)
2756        NnotPol = NnotPol + 1
2757        NotPol(NnotPol) = pols(i,j)
2758        neigPol(NnotPol) = pols(i,j-1)
2759      END IF
2760    END DO
2761  END DO
2762
2763  IF (dbg) THEN
2764    PRINT *,'  It should be:', Npols, ' polygons, but already there are:', Npols - NnotPol
2765    PRINT *,'  Polygons to remove after looking for fake border-of-hole polygons _______'
2766    DO i=1, NnotPol
2767      PRINT *, '      Polygon:', NotPol(i), ' to be replaced by:', neigPol(i)
2768    END DO
2769  END IF
2770
2771  ! Removing polygons
2772  DO iprm=1, NnotPol
2773    IF (neigPol(iprm) == -1) THEN
2774      WHERE (pols == NotPol(iprm))
2775        pols = -1
2776      END WHERE
2777      IF (dbg) THEN
2778        PRINT *,'    removing polygon:', NotPol(iprm)
2779      END IF
2780    ELSE
2781      WHERE (pols == NotPol(iprm))
2782        pols = neigPol(iprm)
2783      END WHERE
2784      IF (dbg) THEN
2785        PRINT *,'       replacing polygon:', NotPol(iprm), ' by:', neigPol(iprm)
2786      END IF
2787    END IF
2788  END DO
2789
2790  ! Re-numbering (descending values)
2791  DO i = 1, NnotPol
2792    iprm = MAXVAL(NotPol(1:NnotPol))
2793    WHERE(pols > iprm)
2794      pols = pols - 1
2795    END WHERE
2796    j = Index1DArrayI(NotPol, NnotPol, iprm)
2797    NotPol(j) = -9
2798  END DO
2799
2800  Npols = Npols - NnotPol
2801
2802  RETURN
2803
2804END SUBROUTINE clean_polygons
2805
2806  SUBROUTINE path_properties(dx, dy, Lmat, Nptspth, pth, xxtrm, yxtrm, meanctr, axs, Nvrtx, vrtxs)
2807! Subroutine to determine the properties of a path:
2808!   extremes: minimum and maximum of the path along x,y axes
2809!   meancenter: center from the mean of the coordinates of the paths locations
2810!   vertexs: path point, without neighbours along a given axis
2811
2812  IMPLICIT NONE
2813
2814  INTEGER, INTENT(in)                                    :: dx, dy, Nptspth
2815  LOGICAL, DIMENSION(dx,dy), INTENT(in)                  :: Lmat
2816  INTEGER, DIMENSION(Nptspth,2), INTENT(in)              :: pth
2817  CHARACTER, INTENT(in)                                  :: axs
2818  INTEGER, DIMENSION(2), INTENT(out)                     :: meanctr, xxtrm, yxtrm
2819  INTEGER, INTENT(out)                                   :: Nvrtx
2820  INTEGER, DIMENSION(Nptspth,2), INTENT(out)             :: vrtxs
2821
2822! Local
2823  INTEGER                                                :: i, ip, jp
2824  INTEGER                                                :: neig1, neig2
2825
2826!!!!!!! Variables
2827! dx,dy: size of the space
2828! Lmat: original matrix of logical values for the path
2829! Nptspth: number of points of the path
2830! pth: path coordinates (clockwise)
2831! axs: axis of finding the vertex
2832! [x/y]xtrm: minimum and maximum coordinates of the path
2833! meanctr: center from the mean of the coordinates of the path
2834! Nvrtx: Number of vertexs of the path
2835! vrtxs: coordinates of the vertexs
2836
2837  fname = 'path_properties'
2838
2839  vrtxs = -1
2840  Nvrtx = 0
2841
2842  xxtrm = (/ MINVAL(pth(:,1)), MAXVAL(pth(:,1)) /)
2843  yxtrm = (/ MINVAL(pth(:,2)), MAXVAL(pth(:,2)) /)
2844  meanctr = (/ SUM(pth(:,1))/Nptspth, SUM(pth(:,2))/Nptspth /)
2845
2846  IF (axs == 'x' .OR. axs == 'X') THEN
2847    ! Looking vertexs along x-axis
2848    DO i=1, Nptspth
2849      ip = pth(i,1)
2850      jp = pth(i,2)
2851      neig1 = 0
2852      neig2 = 0
2853      ! W-point
2854      IF (ip == 1) THEN
2855        neig1 = -1
2856      ELSE
2857        IF (.NOT.Lmat(ip-1,jp)) neig1 = -1
2858      END IF
2859      ! E-point
2860      IF (ip == dx) THEN
2861        neig2 = -1
2862      ELSE
2863        IF (.NOT.Lmat(ip+1,jp)) neig2 = -1
2864      END IF
2865   
2866      IF (neig1 == -1 .AND. neig2 == -1) THEN
2867        Nvrtx = Nvrtx + 1
2868        vrtxs(Nvrtx,:) = (/ip,jp/)
2869      END IF
2870    END DO
2871  ELSE IF (axs == 'y' .OR. axs == 'Y') THEN
2872    ! Looking vertexs along x-axis
2873    DO i=1, Nptspth
2874      ip = pth(i,1)
2875      jp = pth(i,2)
2876
2877      neig1 = 0
2878      neig2 = 0
2879      ! S-point
2880      IF (jp == 1) THEN
2881        neig1 = -1
2882      ELSE
2883        IF (.NOT.Lmat(ip,jp-1)) neig1 = -1
2884      END IF
2885      ! N-point
2886      IF (jp == dy) THEN
2887        neig2 = -1
2888      ELSE
2889        IF (.NOT.Lmat(ip,jp+1)) neig2 = -1
2890      END IF
2891
2892      IF (neig1 == -1 .AND. neig2 == -1) THEN
2893        Nvrtx = Nvrtx + 1
2894        vrtxs(Nvrtx,:) = (/ ip, jp /)
2895      END IF
2896    END DO
2897  ELSE
2898    msg = "Axis '" // axs // "' not available" // CHAR(10) // "  Available ones: 'x', 'X', 'y, 'Y'"
2899    CALL ErrMsg(msg, fname, -1)
2900  END IF
2901
2902  RETURN
2903
2904  END SUBROUTINE path_properties
2905
2906  SUBROUTINE gridpoints_InsidePolygon(dx, dy, isbrdr, Npath, path, Nvrtx, xpathxtrm, ypathxtrm,       &
2907    vrtxs, Npts, pts, inside)
2908! Subroutine to determine if a series of grid points are inside a polygon following ray casting algorithm
2909! FROM: https://en.wikipedia.org/wiki/Point_in_polygon
2910
2911  IMPLICIT NONE
2912
2913  INTEGER, INTENT(in)                                    :: dx,dy,Npath,Nvrtx,Npts
2914  LOGICAL, DIMENSION(dx,dy), INTENT(in)                  :: isbrdr
2915  INTEGER, DIMENSION(Npath,2), INTENT(in)                :: path
2916  INTEGER, DIMENSION(2), INTENT(in)                      :: xpathxtrm, ypathxtrm
2917  INTEGER, DIMENSION(Npath,2)                            :: vrtxs
2918  INTEGER, DIMENSION(Npts,2), INTENT(in)                 :: pts
2919  LOGICAL, DIMENSION(Npts), INTENT(out)                  :: inside
2920
2921! Local
2922  INTEGER                                                :: i,j,ip,ix,iy
2923  INTEGER                                                :: Nintersecs, isvertex, ispath
2924  INTEGER                                                :: ierr
2925  LOGICAL, DIMENSION(:,:), ALLOCATABLE                   :: halo_brdr
2926  INTEGER                                                :: Nbrbrdr
2927
2928!!!!!!! Variables
2929! dx,dy: space size
2930! Npath: number of points of the path of the polygon
2931! path: path of the polygon
2932! isbrdr: boolean matrix of the space wqith .T. on polygon border
2933! Nvrtx: number of vertexs of the path
2934! [x/y]pathxtrm extremes of the path
2935! vrtxs: vertexs of the path along y-axis
2936! Npts: number of points
2937! pts: points to look for
2938! inside: vector wether point is inside or not (coincident to a border is inside)
2939
2940  fname = 'gridpoints_InsidePolygon'
2941
2942  ! Creation of a 1-grid point larger matrix to deal with points reaching the limits
2943  IF (ALLOCATED(halo_brdr)) DEALLOCATE(halo_brdr)
2944  ALLOCATE(halo_brdr(dx+2,dy+2), STAT=ierr)
2945  msg = "Problems allocating matrix 'halo_brdr'"
2946  CALL ErrMsg(msg, fname, ierr)
2947  halo_brdr = .FALSE.
2948
2949  DO i=1,dx
2950    halo_brdr(i+1,2:dy+1) = isbrdr(i,:)
2951  END DO
2952
2953  inside = .FALSE.
2954
2955  DO ip=1,Npts
2956    Nintersecs = 0
2957    ix = pts(ip,1)
2958    iy = pts(ip,2)
2959    ! Point might be outside path range...
2960    IF (ix >= xpathxtrm(1) .AND. ix <= xpathxtrm(2) .AND. iy >= ypathxtrm(1) .AND.                    &
2961      iy <= ypathxtrm(2)) THEN
2962
2963      ! It is a border point?
2964      ispath = index_list_coordsI(Npath, path, (/ix,iy/))
2965      IF (isbrdr(ix,iy) .AND. (ispath /= -1)) THEN
2966        inside(ip) = .TRUE.
2967        CYCLE
2968      END IF
2969
2970      ! Looking along y-axis
2971      ! Accounting for consecutives borders
2972      Nbrbrdr = 0
2973      DO j=MAX(1,ypathxtrm(1)-1),iy-1
2974        ! Only counting that borders that are not vertexs
2975        ispath = index_list_coordsI(Npath, path, (/ix,j/))
2976        isvertex = index_list_coordsI(Npath, vrtxs, (/ix,j/))
2977
2978        IF (halo_brdr(ix+1,j+1) .AND. (ispath /= -1) .AND. (isvertex == -1) ) Nintersecs = Nintersecs + 1
2979        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
2980          Nbrbrdr = Nbrbrdr + 1
2981        ELSE
2982          ! Will remove that consecutive borders above 2
2983          IF (Nbrbrdr /= 0) THEN
2984            Nintersecs = Nintersecs - MAX(Nbrbrdr-1, 0)
2985            Nbrbrdr = 0
2986          END IF
2987        END IF
2988      END DO
2989      IF (MOD(Nintersecs,2) /= 0) inside(ip) = .TRUE.
2990    END IF
2991
2992  END DO
2993
2994  RETURN
2995
2996END SUBROUTINE gridpoints_InsidePolygon
2997
2998SUBROUTINE look_clockwise_borders(dx,dy,Nbrdrs,brdrs,gbrdr,isbrdr,ix,iy,dbg,xf,yf,iff)
2999! Subroutine to look clock-wise for a next point within a collection of borders (limits of a region)
3000
3001  IMPLICIT NONE
3002
3003  INTEGER, INTENT(in)                                    :: dx, dy, Nbrdrs, ix, iy
3004  INTEGER, DIMENSION(Nbrdrs,2), INTENT(in)               :: brdrs
3005  LOGICAL, DIMENSION(Nbrdrs), INTENT(in)                 :: gbrdr
3006  LOGICAL, DIMENSION(dx,dy), INTENT(in)                  :: isbrdr
3007  LOGICAL, INTENT(in)                                    :: dbg
3008  INTEGER, INTENT(out)                                   :: xf, yf, iff
3009
3010! Local
3011  INTEGER                                                :: isch
3012  CHARACTER(len=2), DIMENSION(8)                         :: Lclock
3013  INTEGER, DIMENSION(8,2)                                :: spt
3014  INTEGER                                                :: iif, jjf
3015
3016!!!!!!! Variables
3017! dx, dy: 2D shape ot the space
3018! Nbrdrs: number of brdrs found in this 2D space
3019! brdrs: list of coordinates of the borders
3020! gbrdr: accounts for the use if the given border point
3021! isbrdr: accounts for the matrix of the point is a border or not
3022! ix,iy: coordinates of the point to start to find for
3023! xf,yf: coordinates of the found point
3024! iff: position of the border found within the list of borders
3025
3026  fname = 'look_clockwise_borders'
3027
3028  ! Looking clock-wise assuming that one starts from the westernmost point
3029
3030  ! Label of the search
3031  lclock = (/ 'W ', 'NW', 'N ', 'NE', 'E ', 'SE', 'S ', 'SW' /)
3032  ! Transformation to apply
3033  !spt = (/ (/-1,0/), (/-1,1/), (/0,1/), (/1,1/), (/1,0/), (/1,-1/), (/0,-1/), (/-1,-1/) /)
3034  spt(:,1) = (/ -1, -1, 0, 1, 1, 1, 0, -1 /)
3035  spt(:,2) = (/ 0, 1, 1, 1, 0, -1, -1, -1 /)
3036
3037  xf = -1
3038  yf = -1
3039  DO isch=1, 8
3040    ! clock-wise search
3041    IF (spt(isch,1) >= 0) THEN
3042      iif = MIN(dx,ix+spt(isch,1))
3043    ELSE
3044      iif = MAX(1,ix+spt(isch,1))
3045    END IF
3046    IF (spt(isch,2) >= 0) THEN
3047      jjf = MIN(dy,iy+spt(isch,2))
3048    ELSE
3049      jjf = MAX(1,iy+spt(isch,2))
3050    END IF
3051    iff = index_list_coordsI(Nbrdrs, brdrs,(/iif,jjf/))
3052    IF (iff > 0) THEN
3053      IF (dbg) PRINT *,'    ' // lclock(isch) // '-point:', iif,jjf, ':', iff, 'is',isbrdr(iif,jjf),  &
3054        'got',gbrdr(iff)
3055      IF (isbrdr(iif,jjf) .AND. .NOT.gbrdr(iff)) THEN
3056        xf = iif
3057        yf = jjf
3058        EXIT
3059      END IF
3060    END IF
3061  END DO
3062
3063  RETURN
3064
3065END SUBROUTINE look_clockwise_borders
3066
3067SUBROUTINE borders_matrixL(dx,dy,dxy,Lmat,brdrs,isbrdr,isbrdry)
3068! Subroutine to provide the borders of a logical array (interested in .TRUE.)
3069
3070  IMPLICIT NONE
3071
3072  INTEGER, INTENT(in)                                    :: dx,dy,dxy
3073  LOGICAL, DIMENSION(dx,dy), INTENT(in)                  :: Lmat
3074  INTEGER, DIMENSION(dxy,2), INTENT(out)                 :: brdrs
3075  LOGICAL, DIMENSION(dx,dy), INTENT(out)                 :: isbrdr, isbrdry
3076
3077! Local
3078  INTEGER                                                :: i,j,ib
3079
3080!!!!!!! Variables
3081! dx,dy: size of the space
3082! dxy: maximum number of border points
3083! Lmat: Matrix to look for the borders
3084! brdrs: list of coordinates of the borders
3085! isbrdr: matrix with .T./.F. wether the given matrix point is a border or not
3086! isbrdry: matrix with .T./.F. wether the given matrix point is a border or not only along y-axis
3087
3088  fname = 'borders_matrixL'
3089
3090  isbrdr = .FALSE.
3091  brdrs = -1
3092  ib = 1
3093
3094  ! Starting with the borders. If a given point is TRUE it is a path-vertex
3095  ! Along y-axis
3096  DO i=1, dx
3097    IF (Lmat(i,1) .AND. .NOT.isbrdr(i,1)) THEN
3098      brdrs(ib,1) = i
3099      brdrs(ib,2) = 1
3100      isbrdr(i,1) = .TRUE.
3101      ib=ib+1
3102    END IF
3103    IF (Lmat(i,dy) .AND. .NOT.isbrdr(i,dy)) THEN
3104      brdrs(ib,1) = i
3105      brdrs(ib,2) = dy
3106      isbrdr(i,dy) = .TRUE.
3107      ib=ib+1
3108    END IF
3109  END DO
3110  ! Along x-axis
3111  DO j=1, dy
3112    IF (Lmat(1,j) .AND. .NOT.isbrdr(1,j)) THEN
3113      brdrs(ib,1) = 1
3114      brdrs(ib,2) = j
3115      isbrdr(1,j) = .TRUE.
3116      ib=ib+1
3117     END IF
3118    IF (Lmat(dx,j) .AND. .NOT.isbrdr(dx,j)) THEN
3119      brdrs(ib,1) = dx
3120      brdrs(ib,2) = j
3121      isbrdr(dx,j) = .TRUE.
3122      ib=ib+1
3123    END IF
3124  END DO
3125
3126  isbrdry = isbrdr
3127
3128  ! Border as that when looking on x-axis points with Lmat(i) /= Lmat(i+1)
3129  DO i=1, dx-1
3130    DO j=1, dy-1
3131      IF ( Lmat(i,j) .NEQV. Lmat(i+1,j) ) THEN
3132        IF (Lmat(i,j) .AND. .NOT.isbrdr(i,j)) THEN
3133          brdrs(ib,1) = i
3134          brdrs(ib,2) = j
3135          isbrdr(i,j) = .TRUE.
3136          ib=ib+1
3137        ELSE IF (Lmat(i+1,j) .AND. .NOT.isbrdr(i+1,j)) THEN
3138          brdrs(ib,1) = i+1
3139          brdrs(ib,2) = j
3140          isbrdr(i+1,j) = .TRUE.
3141          ib=ib+1
3142        END IF
3143      END IF
3144      ! y-axis
3145      IF ( Lmat(i,j) .NEQV. Lmat(i,j+1) ) THEN
3146        IF (Lmat(i,j) .AND. .NOT.isbrdr(i,j)) THEN
3147          brdrs(ib,1) = i
3148          brdrs(ib,2) = j
3149          isbrdr(i,j) = .TRUE.
3150          isbrdry(i,j) = .TRUE.
3151          ib=ib+1
3152        ELSE IF (Lmat(i,j+1) .AND. .NOT.isbrdr(i,j+1)) THEN
3153          brdrs(ib,1) = i
3154          brdrs(ib,2) = j+1
3155          isbrdr(i,j+1) = .TRUE.
3156          isbrdry(i,j+1) = .TRUE.
3157          ib=ib+1
3158        END IF
3159      END IF
3160    END DO       
3161  END DO
3162
3163  DO i=1, dx-1
3164    DO j=1, dy-1
3165      ! y-axis
3166      IF ( Lmat(i,j) .NEQV. Lmat(i,j+1) ) THEN
3167        IF (Lmat(i,j)) THEN
3168          isbrdry(i,j) = .TRUE.
3169        ELSE IF (Lmat(i,j+1)) THEN
3170          isbrdry(i,j+1) = .TRUE.
3171        END IF
3172      END IF
3173    END DO       
3174  END DO
3175  ! only y-axis adding bands of 2 grid points
3176  DO i=1, dx-1
3177    DO j=2, dy-2
3178      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
3179        IF (Lmat(i,j)) THEN
3180          isbrdry(i,j) = .TRUE.
3181          isbrdry(i,j+1) = .TRUE.
3182        END IF
3183      END IF
3184    END DO       
3185  END DO
3186
3187  RETURN
3188
3189END SUBROUTINE borders_matrixL
3190
3191SUBROUTINE paths_border(dbg, dx, dy, isborder, Nppt, borders, paths, Npath, Nptpaths)
3192! Subroutine to search the paths of a border field.
3193
3194  IMPLICIT NONE
3195
3196  INTEGER, INTENT(in)                                    :: dx, dy, Nppt
3197  LOGICAL, INTENT(in)                                    :: dbg
3198  LOGICAL, DIMENSION(dx,dy), INTENT(in)                  :: isborder
3199  INTEGER, DIMENSION(Nppt,2), INTENT(in)                 :: borders
3200  INTEGER, DIMENSION(Nppt,Nppt,2), INTENT(out)           :: paths
3201  INTEGER, INTENT(out)                                   :: Npath
3202  INTEGER, DIMENSION(Nppt), INTENT(out)                  :: Nptpaths
3203
3204! Local
3205  INTEGER                                                :: i,j,k,ib
3206  INTEGER                                                :: ierr
3207  INTEGER                                                :: Nbrdr
3208  LOGICAL, DIMENSION(:), ALLOCATABLE                     :: gotbrdr, emptygotbrdr
3209  INTEGER                                                :: iipth, ipath, ip, Nptspath
3210  INTEGER                                                :: iib, jjb, iip, ijp, iif, jjf, iff
3211  LOGICAL                                                :: found, finishedstep
3212
3213!!!!!!! Variables
3214! dx,dy: spatial dimensions of the space
3215! Nppt: possible number of paths and points that the paths can have
3216! isborder: boolean matrix which provide the borders of the polygon
3217! borders: coordinates of the borders of the polygon
3218! paths: coordinates of each found path
3219! Npath: number of paths found
3220! Nptpaths: number of points per path
3221
3222  fname = 'paths_border'
3223
3224  ! Sarting matrix
3225  paths = -1
3226  Npath = 0
3227  Nptspath = 0
3228  Nptpaths = -1
3229
3230  ib=1
3231  finishedstep = .FALSE.
3232
3233  ! Number of border points
3234  DO ib=1, Nppt
3235    IF (borders(ib,1) == -1 ) EXIT
3236  END DO
3237  Nbrdr = ib-1
3238   
3239  IF (dbg) THEN
3240    PRINT *,'    borders _______'
3241    DO i=1,Nbrdr
3242      PRINT *,'    ',i,':',borders(i,:)
3243    END DO
3244  END IF
3245
3246  ! Matrix which keeps track if a border point has been located
3247  IF (ALLOCATED(gotbrdr)) DEALLOCATE(gotbrdr)
3248  ALLOCATE(gotbrdr(Nbrdr), STAT=ierr)
3249  msg = "Problems allocating matrix 'gotbrdr'"
3250  CALL ErrMsg(msg, fname, ierr)
3251  IF (ALLOCATED(emptygotbrdr)) DEALLOCATE(emptygotbrdr)
3252  ALLOCATE(emptygotbrdr(Nbrdr), STAT=ierr)
3253  msg = "Problems allocating matrix 'emptygotbrdr'"
3254  CALL ErrMsg(msg, fname, ierr)
3255
3256  gotbrdr = .FALSE.
3257  emptygotbrdr = .FALSE.
3258
3259  ! Starting the fun...
3260   
3261  ! Looking along the lines and when a border is found, starting from there in a clock-wise way
3262  iipth = 1
3263  ipath = 1   
3264  DO ib=1,Nbrdr
3265    iib = borders(iipth,1)
3266    jjb = borders(iipth,2)
3267    ! Starting new path
3268    newpath: IF (.NOT.gotbrdr(iipth)) THEN
3269      ip = 1
3270      Nptspath = 1
3271      paths(ipath,ip,:) = borders(iipth,:)
3272      gotbrdr(iipth) = .TRUE.
3273      ! Looking for following clock-wise search
3274      ! Not looking for W, because search starts from the W
3275      iip = iib
3276      ijp = jjb
3277      DO k=1,Nbrdr
3278        IF (dbg) PRINT *,ipath,'iip jip:', iip, ijp
3279        found = .FALSE.
3280        CALL look_clockwise_borders(dx,dy,Nppt,borders,gotbrdr,isborder,iip,ijp,.FALSE.,iif,jjf,iff)
3281        IF (iif /= -1) THEN
3282          ip=ip+1
3283          paths(ipath,ip,:) = (/ iif,jjf /)
3284          found = .TRUE.
3285          gotbrdr(iff) = .TRUE.
3286          iip = iif
3287          ijp = jjf
3288          Nptspath = Nptspath + 1         
3289        END IF
3290
3291        IF (dbg) THEN
3292          PRINT *,iib,jjb,'    end of this round path:', ipath, '_____', gotbrdr
3293          DO i=1, Nptspath
3294            PRINT *,'      ',i,':',paths(ipath,i,:)
3295          END DO
3296        END IF
3297        ! If it is not found a next point, might be because it is a non-polygon related value
3298        IF (.NOT.found) THEN
3299          IF (dbg) PRINT *,'NOT FOUND !!!', gotbrdr
3300          ! Are still there available borders? 
3301          IF (ALL(gotbrdr) .EQV. .TRUE.) THEN
3302            finishedstep = .TRUE.
3303            Npath = ipath
3304            Nptpaths(ipath) = Nptspath
3305            EXIT
3306          ELSE
3307            Nptpaths(ipath) = Nptspath
3308            ! Let's have a look if the previous points in the path have already some 'non-located' neighbourgs
3309            DO i=Nptspath,1,-1
3310              iip = paths(ipath,i,1)
3311              ijp = paths(ipath,i,2)
3312              CALL look_clockwise_borders(dx,dy,Nppt,borders,gotbrdr,isborder,iip,ijp,.FALSE., iif,   &
3313                jjf,iff)
3314              IF (iif /= -1 .AND. iff /= -1) THEN
3315                IF (dbg) PRINT *,'    re-take path from point:', iif,',',jjf,' n-path:', iff
3316                found = .TRUE.
3317                iipth = index_list_coordsI(Nppt, borders, (/iip,ijp/))
3318                EXIT
3319              END IF
3320            END DO
3321            IF (.NOT.found) THEN
3322              ! Looking for the next available border point for the new path
3323              DO i=1,Nbrdr
3324                IF (.NOT.gotbrdr(i)) THEN
3325                  iipth = i
3326                  EXIT
3327                END IF
3328              END DO
3329              IF (dbg) PRINT *,'  Looking for next path starting at:', iipth, ' point:',              &
3330                borders(iipth,:)
3331              ipath=ipath+1
3332              EXIT
3333            END IF
3334          END IF
3335        ELSE
3336          IF (dbg) PRINT *,'  looking for next point...'
3337        END IF
3338        IF (finishedstep) EXIT
3339      END DO
3340    END IF newpath
3341  END DO
3342  Npath = ipath
3343  Nptpaths(ipath) = Nptspath
3344   
3345  DEALLOCATE (gotbrdr)
3346  DEALLOCATE (emptygotbrdr)
3347
3348  RETURN
3349
3350END SUBROUTINE paths_border
3351
3352SUBROUTINE rand_sample(Nvals, Nsample, sample)
3353! Subroutine to randomly sample a range of indices
3354
3355  IMPLICIT NONE
3356
3357  INTEGER, INTENT(in)                                    :: Nvals, Nsample
3358  INTEGER, DIMENSION(Nsample), INTENT(out)               :: sample
3359
3360! Local
3361  INTEGER                                                :: i, ind, jmax
3362  REAL, DIMENSION(Nsample)                               :: randv
3363  CHARACTER(len=50)                                      :: fname
3364  LOGICAL                                                :: found
3365  LOGICAL, DIMENSION(Nvals)                              :: issampled
3366  CHARACTER(len=256)                                     :: msg
3367  CHARACTER(len=10)                                      :: IS1, IS2
3368
3369!!!!!!! Variables
3370! Nvals: number of values
3371! Nsamples: number of samples
3372! sample: samnple
3373  fname = 'rand_sample'
3374
3375  IF (Nsample > Nvals) THEN
3376    WRITE(IS1,'(I10)')Nvals
3377    WRITE(IS2,'(I10)')Nsample
3378    msg = 'Sampling of ' // TRIM(IS1) // ' is too big for ' // TRIM(IS1) // 'values'
3379    CALL ErrMsg(msg, fname, -1)
3380  END IF
3381
3382  ! Generation of random numbers always the same series during the whole program!
3383  CALL RANDOM_NUMBER(randv)
3384
3385  ! Making sure that we do not repeat any value
3386  issampled = .FALSE.
3387
3388  DO i=1, Nsample
3389    ! Generation of the index from the random numbers
3390    ind = MAX(INT(randv(i)*Nvals), 1)
3391
3392    IF (.NOT.issampled(ind)) THEN
3393      sample(i) = ind
3394      issampled(ind) = .TRUE.
3395    ELSE
3396      ! Looking around the given index
3397      !PRINT *,' Index :', ind, ' already sampled!', issampled(ind)
3398      found = .FALSE.
3399      DO jmax=1, Nvals
3400        ind = MIN(ind+jmax, Nvals)
3401        IF (.NOT.issampled(ind)) THEN
3402          sample(i) = ind
3403          issampled(ind) = .TRUE.
3404          found = .TRUE.
3405          EXIT
3406        END IF
3407        ind = MAX(1, ind-jmax)
3408        IF (.NOT.issampled(ind)) THEN
3409          sample(i) = ind
3410          issampled(ind) = .TRUE.
3411          found = .TRUE.
3412          EXIT
3413        END IF
3414      END DO
3415      IF (.NOT.found) THEN
3416        msg = 'sampling could not be finished due to absence of available value!!'
3417        CALL ErrMsg(msg, fname, -1)
3418      END IF
3419    END IF
3420
3421  END DO
3422
3423  RETURN
3424
3425END SUBROUTINE rand_sample
3426
3427SUBROUTINE PrintQuantilesR_K(Nvals, vals, Nquants, qtvs, bspc)
3428! Subroutine to print the quantiles of values REAL(r_k)
3429
3430  IMPLICIT NONE
3431
3432  INTEGER, INTENT(in)                                    :: Nvals, Nquants
3433  REAL(r_k), DIMENSION(Nvals), INTENT(in)                :: vals
3434  REAL(r_k), DIMENSION(Nquants), INTENT(in)              :: qtvs
3435  CHARACTER(len=1000), OPTIONAL                          :: bspc
3436
3437! Local
3438  INTEGER                                                :: iq
3439  LOGICAL, DIMENSION(Nvals)                              :: search1, search2, search
3440  CHARACTER(len=6)                                       :: RS1
3441  CHARACTER(len=50)                                      :: fname
3442  CHARACTER(len=1000)                                    :: bspcS
3443
3444!!!!!!! Variables
3445! vals: series of values
3446! qtvs: values of the quantiles
3447! bspc: base quantity of spaces
3448
3449  fname = 'PrintQuantilesR_K'
3450
3451  IF (PRESENT(bspc)) THEN
3452    bspcS = bspc
3453  ELSE
3454    bspcS = '      '
3455  END IF
3456
3457  DO iq=1, Nquants-1
3458
3459    WHERE (vals >= qtvs(iq))
3460      search1 = .TRUE.
3461    ELSEWHERE
3462      search1 = .FALSE.
3463    END WHERE
3464
3465    WHERE (vals < qtvs(iq+1))
3466      search2 = .TRUE.
3467    ELSEWHERE
3468      search2 = .FALSE.
3469    END WHERE
3470
3471    WHERE (search1 .AND. search2)
3472      search = .TRUE.
3473    ELSEWHERE
3474      search = .FALSE.
3475    END WHERE
3476
3477    WRITE(RS1, '(F6.2)')(iq)*100./(Nquants-1)
3478    PRINT *, TRIM(bspcS) // '[',iq,']', TRIM(RS1) // ' %:', qtvs(iq), 'N:', COUNT(search)
3479
3480  END DO
3481
3482  RETURN
3483
3484END SUBROUTINE PrintQuantilesR_K
3485
3486   INTEGER FUNCTION FindMinimumR_K(x, dsize, Startv, Endv)
3487! Function returns the location of the minimum in the section between Start and End.
3488
3489      IMPLICIT NONE
3490
3491      INTEGER, INTENT(in)                                :: dsize
3492      REAL(r_k), DIMENSION(dsize), INTENT(in)            :: x
3493      INTEGER, INTENT(in)                                :: Startv, Endv
3494
3495! Local
3496      REAL(r_k)                                          :: Minimum
3497      INTEGER                                            :: Location
3498      INTEGER                                            :: i
3499
3500      Minimum  = x(Startv)                               ! assume the first is the min
3501      Location = Startv                                  ! record its position
3502      DO i = Startv+1, Endv                              ! start with next elements
3503         IF (x(i) < Minimum) THEN                        !   if x(i) less than the min?
3504            Minimum  = x(i)                              !      Yes, a new minimum found
3505            Location = i                                 !      record its position
3506         END IF
3507      END DO
3508
3509      FindMinimumR_K = Location                          ! return the position
3510
3511   END FUNCTION  FindMinimumR_K
3512
3513   SUBROUTINE SwapR_K(a, b)
3514! Subroutine swaps the values of its two formal arguments.
3515
3516      IMPLICIT NONE
3517
3518      REAL(r_k), INTENT(INOUT)                           :: a, b
3519! Local
3520      REAL(r_k)                                          :: Temp
3521
3522      Temp = a
3523      a    = b
3524      b    = Temp
3525
3526   END SUBROUTINE  SwapR_K
3527
3528   SUBROUTINE  SortR_K(x, Nx)
3529! Subroutine receives an array x() r_K and sorts it into ascending order.
3530
3531      IMPLICIT NONE
3532
3533      INTEGER, INTENT(IN)                                :: Nx
3534      REAL(r_k), DIMENSION(Nx), INTENT(INOUT)            :: x
3535
3536! Local
3537      INTEGER                                            :: i
3538      INTEGER                                            :: Location
3539
3540      DO i = 1, Nx-1                                     ! except for the last
3541         Location = FindMinimumR_K(x, Nx-i+1, i, Nx)     ! find min from this to last
3542         CALL  SwapR_K(x(i), x(Location))                ! swap this and the minimum
3543      END DO
3544
3545   END SUBROUTINE  SortR_K
3546
3547SUBROUTINE quantilesR_K(Nvals, vals, Nquants, quants)
3548! Subroutine to provide the quantiles of a given set of values of type real 'r_k'
3549
3550  IMPLICIT NONE
3551
3552  INTEGER, INTENT(in)                                    :: Nvals, Nquants
3553  REAL(r_k), DIMENSION(Nvals), INTENT(in)                :: vals
3554  REAL(r_k), DIMENSION(Nquants), INTENT(out)             :: quants
3555
3556! Local
3557  INTEGER                                                :: i
3558  REAL(r_k)                                              :: minv, maxv
3559  REAL(r_k), DIMENSION(Nvals)                            :: sortedvals
3560
3561!!!!!!! Variables
3562! Nvals: number of values
3563! Rk: kind of real of the values
3564! vals: values
3565! Nquants: number of quants
3566! quants: values at which the quantile start
3567
3568  minv = MINVAL(vals)
3569  maxv = MAXVAL(vals)
3570
3571  sortedvals = vals
3572  ! Using from: http://www.cs.mtu.edu/~shene/COURSES/cs201/NOTES/chap08/sorting.f90
3573  CALL SortR_K(sortedvals, Nvals)
3574
3575  quants(1) = minv
3576  DO i=2, Nquants
3577    quants(i) = sortedvals(INT((i-1)*Nvals/Nquants))
3578  END DO
3579
3580END SUBROUTINE quantilesR_K
3581
3582
3583SUBROUTINE StatsR_K(Nvals, vals, minv, maxv, mean, mean2, stdev)
3584! Subroutine to provide the minmum, maximum, mean, the quadratic mean, and the standard deviation of a
3585!   series of r_k numbers
3586
3587  IMPLICIT NONE
3588
3589  INTEGER, INTENT(in)                                    :: Nvals
3590  REAL(r_k), DIMENSION(Nvals), INTENT(in)                :: vals
3591  REAL(r_k), INTENT(out)                                 :: minv, maxv, mean, mean2, stdev
3592
3593!!!!!!! Variables
3594! Nvals: number of values
3595! vals: values
3596! minv: minimum value of values
3597! maxv: maximum value of values
3598! mean: mean value of values
3599! mean2: quadratic mean value of values
3600! stdev: standard deviation of values
3601
3602  minv = MINVAL(vals)
3603  maxv = MAXVAL(vals)
3604
3605  mean=SUM(vals)
3606  mean2=SUM(vals*vals)
3607
3608  mean=mean/Nvals
3609  mean2=mean2/Nvals
3610
3611  stdev=SQRT(mean2 - mean*mean)
3612
3613  RETURN
3614
3615END SUBROUTINE StatsR_k
3616
3617  SUBROUTINE NcountR(values, d1, Ndiffvals, counts)
3618! Subroutine to count real values
3619
3620    IMPLICIT NONE
3621
3622    INTEGER, INTENT(in)                                  :: d1
3623    REAL(r_k), DIMENSION(d1), INTENT(in)                 :: values
3624    INTEGER, INTENT(out)                                 :: Ndiffvals
3625    REAL(r_k), DIMENSION(d1,2), INTENT(out)              :: counts
3626! Local
3627    INTEGER                                              :: i, ival
3628    REAL(r_k), DIMENSION(d1)                             :: diffv
3629
3630!!!!!!! Variables
3631! values: values to count
3632! counts: counts of time for each value
3633   
3634    fname = 'NcountR'
3635
3636    counts = -1.
3637
3638    counts(1,1) = values(1)
3639    counts(1,2) = 1
3640    Ndiffvals = 1
3641    DO i=2,d1
3642      diffv(1:Ndiffvals) = counts(1:Ndiffvals,1) - values(i)
3643      IF (ANY(diffv(1:Ndiffvals) == 0)) THEN
3644        ival = Index1DArrayR(counts(1:Ndiffvals,1), Ndiffvals, values(i))
3645        counts(ival,2) = counts(ival,2) + 1
3646      ELSE
3647        Ndiffvals = Ndiffvals + 1
3648        counts(Ndiffvals,1) = values(i)
3649        counts(Ndiffvals,2) = 1
3650      END IF
3651    END DO
3652
3653  END SUBROUTINE NcountR
3654
3655  SUBROUTINE runmean_F1D(d1, values, Nmean, headertail, runmean)
3656! Subroutine fo computing the running mean of a given set of float 1D values
3657
3658  IMPLICIT NONE
3659
3660  INTEGER, INTENT(in)                                    :: d1, Nmean
3661  REAL(r_k), DIMENSION(d1), INTENT(in)                   :: values
3662  CHARACTER(len=*), INTENT(in)                           :: headertail
3663  REAL(r_k), DIMENSION(d1), INTENT(out)                  :: runmean
3664 
3665! Local
3666  INTEGER                                                :: i, j, Nmean2
3667  CHARACTER(len=5)                                       :: NmeanS
3668
3669!!!!!!! Variables
3670! values: values to compute the running mean
3671! Nmean: number of odd points to use for the running mean
3672! headertail: How to proceed for the grid points at the beginning of the values which are not
3673!   encompassed by the Nmean
3674!   'miss': set as missing values (1.d20)
3675!   'original': keep the original values
3676!   'progressfill': mean the values as a progressive running filter (e.g. for Nmean=5):
3677!     runmean[values(1)] = values(1)
3678!     runmean[values(2)] = MEAN(values(1:3))
3679!     runmean[values(3)] = MEAN(values(1:5))
3680!     runmean[values(4)] = MEAN(values(2:6))
3681!     (...)
3682!     runmean[values(d1-2)] = MEAN(values(d1-5:d1))
3683!     runmean[values(d1-1)] = MEAN(values(d1-2:d1))
3684!     runmean[values(d1)] = MEAN(values(dd1))
3685!   'zero': set as zero values
3686! runmean: runnig mean values
3687
3688  fname = 'runmean_F1D'
3689
3690  IF (MOD(Nmean,2) == 0) THEN
3691    WRITE(NmeanS,'(I5)')Nmean
3692    msg="Nmean has to be odd!! value provided: "// NmeanS
3693    CALL ErrMsg(msg, fname, -1)
3694  END IF
3695  Nmean2 = Nmean/2
3696 
3697  SELECT CASE (TRIM(headertail))
3698    CASE ('missing')
3699      runmean = fillval64
3700    CASE ('original')
3701      runmean = values
3702    CASE ('progressfill')
3703      DO i=1, Nmean2
3704        runmean(i) = SUM(values(1:2*(i-1)+1))/(2*(i-1)+1)
3705      END DO
3706      runmean(d1) = values(d1)
3707      DO i=2, Nmean2
3708        j = d1-(2*(i-1))
3709        runmean(d1-(i-1)) = SUM(values(j:d1))/(2*(i-1)+1)
3710      END DO
3711    CASE ('zero')
3712      runmean = zeroRK
3713    CASE DEFAULT
3714      msg = "'" // TRIM(headertail) // "' not available !!" //CHAR(44) // "  available ones: " //     &
3715        "'missing', 'original', 'progressfill', 'zero'"
3716      CALL ErrMsg(msg, fname, -1)
3717  END SELECT
3718
3719  DO i= 1+Nmean2, d1 - Nmean2
3720    runmean(i) = SUM(values(i-Nmean2:i+Nmean2))/Nmean
3721  END DO
3722
3723  END SUBROUTINE runmean_F1D
3724
3725  SUBROUTINE percentiles_R_K2D(values, axisS, Npercen, d1, d2, percentiles)
3726  ! Subroutine to compute the percentiles of a 2D R_K array along given set of axis
3727
3728    IMPLICIT NONE
3729 
3730    INTEGER, INTENT(in)                                    :: d1, d2, Npercen
3731    REAL(r_k), DIMENSION(d1,d2), INTENT(in)                :: values
3732    CHARACTER(LEN=*), INTENT(in)                           :: axisS
3733    REAL(r_k), DIMENSION(d1, d2, Npercen), INTENT(out)     :: percentiles
3734
3735    ! Local
3736    INTEGER                                                :: i
3737    INTEGER                                                :: Lstring, LaxisS, iichar
3738    CHARACTER(LEN=1000)                                    :: splitaxis
3739    INTEGER, DIMENSION(1)                                  :: axis1
3740    CHARACTER(LEN=200), DIMENSION(2)                       :: axis2S
3741    INTEGER, DIMENSION(2)                                  :: axis2
3742    CHARACTER(LEN=1)                                       :: Naxs
3743
3744!!!!!!! Variables
3745! d1,d2: length of the 2D dimensions
3746! values: values to use to compute the percentiles
3747! axisS: ':' separated list of axis to use to compute the percentiles ('all' for all axes)
3748! Npercen: number of percentiles
3749! percentiles: percentiles of the daata
3750
3751    fname = 'percentiles_R_K2D'
3752
3753    LaxisS = LEN_TRIM(axisS)
3754    iichar = numberTimes(axisS(1:LaxisS), ':')
3755
3756    splitaxis = ''
3757    splitaxis(1:LaxisS) = axisS(1:LaxisS)
3758    percentiles = 0.
3759
3760    IF (iichar == 0) THEN
3761      READ(axisS,'(I1)')axis1(1)
3762    ELSE IF (iichar == 1) THEN
3763      CALL split(splitaxis, ':', 2, axis2S)
3764    ELSE
3765      WRITE(Naxs,'(A1)')iichar
3766      msg = "' rank 2 values can not compute percentiles using " // Naxs // "' number of axis !!"
3767      CALL ErrMsg(msg, fname, -1)
3768    END IF
3769
3770    IF (TRIM(axisS) == 'all') iichar = 2
3771 
3772    IF (iichar == 0) THEN
3773      ! Might be a better way, but today I can't think it !!
3774      IF (axis1(1) == 1) THEN
3775        DO i=1, d2
3776          CALL quantilesR_K(d1, values(:,i), Npercen, percentiles(1,i,:))
3777        END DO
3778      ELSE IF (axis1(1) == 2) THEN
3779        DO i=1, d1
3780          CALL quantilesR_K(d2, values(i,:), Npercen, percentiles(i,1,:))
3781        END DO
3782      ELSE
3783        WRITE(Naxs,'(A1)')axis1(1)
3784        msg = "' rank 2 values can not compute percentiles using axis " // Naxs // "' !!"
3785        CALL ErrMsg(msg, fname, -1)
3786      END IF
3787    ELSE
3788      CALL quantilesR_K(d1*d2, RESHAPE(values, (/d1*d2/)), Npercen, percentiles(1,1,:))
3789    END IF
3790
3791  END SUBROUTINE percentiles_R_K2D
3792
3793  SUBROUTINE percentiles_R_K3D(values, axisS, Npercen, d1, d2, d3, percentiles)
3794  ! Subroutine to compute the percentiles of a 3D R_K array along given set of axis
3795
3796    IMPLICIT NONE
3797 
3798    INTEGER, INTENT(in)                                    :: d1, d2, d3, Npercen
3799    REAL(r_k), DIMENSION(d1,d2,d3), INTENT(in)             :: values
3800    CHARACTER(LEN=*), INTENT(in)                           :: axisS
3801    REAL(r_k), DIMENSION(d1, d2, d3, Npercen), INTENT(out) :: percentiles
3802
3803    ! Local
3804    INTEGER                                                :: i, j
3805    INTEGER                                                :: Lstring, LaxisS, iichar
3806    CHARACTER(LEN=1000)                                    :: splitaxis
3807    INTEGER, DIMENSION(1)                                  :: axis1
3808    CHARACTER(LEN=200), DIMENSION(2)                       :: axis2S
3809    INTEGER, DIMENSION(2)                                  :: axis2
3810    CHARACTER(LEN=200), DIMENSION(3)                       :: axis3S
3811    INTEGER, DIMENSION(3)                                  :: axis3
3812    CHARACTER(LEN=1)                                       :: Naxs1, Naxs2
3813
3814!!!!!!! Variables
3815! d1,d2: length of the 2D dimensions
3816! values: values to use to compute the percentiles
3817! axisS: ':' separated list of axis to use to compute the percentiles ('all' for all axes)
3818! Npercen: number of percentiles
3819! percentiles: percentiles of the daata
3820
3821    fname = 'percentiles_R_K3D'
3822
3823    LaxisS = LEN_TRIM(axisS)
3824    iichar = numberTimes(axisS(1:LaxisS), ':')
3825
3826    splitaxis = ''
3827    splitaxis(1:LaxisS) = axisS(1:LaxisS)
3828
3829    percentiles = 0.
3830
3831    IF (iichar == 0) THEN
3832      READ(axisS,'(I1)')axis1(1)
3833    ELSE IF (iichar == 1) THEN
3834      CALL split(splitaxis, ':', 2, axis2S)
3835      DO i=1,2
3836        READ(axis2S(i), '(I1)')axis2(i)
3837      END DO
3838    ELSE IF (iichar == 2) THEN
3839      CALL split(splitaxis, ':', 3, axis3S)
3840    ELSE
3841      READ(Naxs1,'(A1)')iichar
3842      msg = "' rank 3 values can not compute percentiles using " // Naxs1 // "' number of axis !!"
3843      CALL ErrMsg(msg, fname, -1)
3844    END IF
3845
3846    IF (TRIM(axisS) == 'all') iichar = 3
3847 
3848    IF (iichar == 0) THEN
3849      ! Might be a better way, but today I can't think it !!
3850      IF (axis1(1) == 1) THEN
3851        DO i=1, d2
3852          DO j=1, d3
3853            CALL quantilesR_K(d1, values(:,i,j), Npercen, percentiles(1,i,j,:))
3854          END DO
3855        END DO
3856      ELSE IF (axis1(1) == 2) THEN
3857        DO i=1, d1
3858          DO j=1, d3
3859            CALL quantilesR_K(d2, values(i,:,j), Npercen, percentiles(i,1,j,:))
3860          END DO
3861        END DO
3862      ELSE IF (axis1(1) == 3) THEN
3863        DO i=1, d1
3864          DO j=1, d2
3865            CALL quantilesR_K(d3, values(i,j,:), Npercen, percentiles(i,j,1,:))
3866          END DO
3867        END DO
3868      ELSE
3869        WRITE(Naxs1,'(A1)')axis1(1)
3870        msg = "' rank 3 values can not compute percentiles using axis " // Naxs1 // "' !!"
3871        CALL ErrMsg(msg, fname, -1)
3872      END IF
3873    ELSE IF (iichar == 1) THEN
3874      ! Might be a better way, but today I can't think it !!
3875      IF (axis2(1) == 1 .AND. axis2(2) == 2) THEN
3876        DO i=1, d3
3877          CALL quantilesR_K(d1*d2, RESHAPE(values(:,:,i), (/d1*d2/)), Npercen, percentiles(1,1,i,:))
3878        END DO
3879      ELSE IF (axis2(1) == 1 .AND. axis2(2) == 3) THEN
3880        DO i=1, d2
3881          CALL quantilesR_K(d1*d3, RESHAPE(values(:,i,:), (/d1*d3/)), Npercen, percentiles(1,i,1,:))
3882        END DO
3883      ELSE IF (axis2(1) == 2 .AND. axis2(2) == 3) THEN
3884        DO i=1, d1
3885          CALL quantilesR_K(d2*d3, RESHAPE(values(i,:,:), (/d2*d3/)), Npercen, percentiles(i,1,1,:))
3886        END DO
3887      ELSE
3888        WRITE(Naxs1,'(A1)')axis2(1)
3889        WRITE(Naxs2,'(A1)')axis2(2)
3890        msg="' rank 3 values can not compute percentiles using axis "//Naxs1// ', ' // Naxs2 // "' !!"
3891        CALL ErrMsg(msg, fname, -1)
3892      END IF
3893    ELSE
3894      CALL quantilesR_K(d1*d2*d3, RESHAPE(values, (/d1*d2*d3/)), Npercen, percentiles(1,1,1,:))
3895    END IF
3896
3897  END SUBROUTINE percentiles_R_K3D
3898
3899  SUBROUTINE percentiles_R_K4D(values, axisS, Npercen, d1, d2, d3, d4, percentiles)
3900  ! Subroutine to compute the percentiles of a 4D R_K array along given set of axis
3901
3902    IMPLICIT NONE
3903 
3904    INTEGER, INTENT(in)                                    :: d1, d2, d3, d4, Npercen
3905    REAL(r_k), DIMENSION(d1,d2,d3,d4), INTENT(in)          :: values
3906    CHARACTER(LEN=*), INTENT(in)                           :: axisS
3907    REAL(r_k), DIMENSION(d1,d2,d3,d4,Npercen), INTENT(out) :: percentiles
3908
3909    ! Local
3910    INTEGER                                                :: i, j, k
3911    INTEGER                                                :: Lstring, LaxisS, iichar
3912    CHARACTER(LEN=1000)                                    :: splitaxis
3913    INTEGER, DIMENSION(1)                                  :: axis1
3914    CHARACTER(LEN=200), DIMENSION(2)                       :: axis2S
3915    INTEGER, DIMENSION(2)                                  :: axis2
3916    CHARACTER(LEN=200), DIMENSION(3)                       :: axis3S
3917    INTEGER, DIMENSION(3)                                  :: axis3
3918    CHARACTER(LEN=200), DIMENSION(4)                       :: axis4S
3919    CHARACTER(LEN=1)                                       :: Naxs1, Naxs2, Naxs3
3920
3921!!!!!!! Variables
3922! d1,d2: length of the 2D dimensions
3923! values: values to use to compute the percentiles
3924! axisS: ':' separated list of axis to use to compute the percentiles ('all' for all axes)
3925! Npercen: number of percentiles
3926! percentiles: percentiles of the daata
3927
3928    fname = 'percentiles_R_K3D'
3929
3930    LaxisS = LEN_TRIM(axisS)
3931    iichar = numberTimes(axisS(1:LaxisS), ':')
3932
3933    splitaxis = ''
3934    splitaxis(1:LaxisS) = axisS(1:LaxisS)
3935
3936    percentiles = 0.
3937
3938    PRINT *,'iichar:', iichar, axisS(1:LaxisS)
3939
3940    IF (iichar == 0) THEN
3941      READ(axisS,'(I1)')axis1(1)
3942    ELSE IF (iichar == 1) THEN
3943      CALL split(splitaxis, ':', 2, axis2S)
3944      DO i=1,2
3945        READ(axis2S(i), '(I1)')axis2(i)
3946      END DO
3947    ELSE IF (iichar == 2) THEN
3948      CALL split(splitaxis, ':', 3, axis3S)
3949      DO i=1,3
3950        READ(axis3S(i), '(I1)')axis3(i)
3951      END DO
3952    ELSE IF (iichar == 3) THEN
3953      CALL split(splitaxis, ':', 4, axis4S)
3954    ELSE
3955      READ(Naxs1,'(A1)')iichar
3956      msg = "' rank 4 values can not compute percentiles using " // Naxs1 // "' number of axis !!"
3957      CALL ErrMsg(msg, fname, -1)
3958    END IF
3959
3960    IF (TRIM(axisS) == 'all') iichar = 4
3961 
3962    IF (iichar == 0) THEN
3963      ! Might be a better way, but today I can't think it !!
3964      IF (axis1(1) == 1) THEN
3965        DO i=1, d2
3966          DO j=1, d3
3967            DO k=1, d4
3968              CALL quantilesR_K(d1, values(:,i,j,k), Npercen, percentiles(1,i,j,k,:))
3969            END DO
3970          END DO
3971        END DO
3972      ELSE IF (axis1(1) == 2) THEN
3973        DO i=1, d1
3974          DO j=1, d3
3975            DO k=1, d4
3976              CALL quantilesR_K(d2, values(i,:,j,k), Npercen, percentiles(i,1,j,k,:))
3977            END DO
3978          END DO
3979        END DO
3980      ELSE IF (axis1(1) == 3) THEN
3981        DO i=1, d1
3982          DO j=1, d2
3983            DO k=1, d4
3984              CALL quantilesR_K(d3, values(i,j,:,k), Npercen, percentiles(i,j,1,k,:))
3985            END DO
3986          END DO
3987        END DO
3988      ELSE IF (axis1(1) == 4) THEN
3989        DO i=1, d1
3990          DO j=1, d2
3991            DO k=1, d3
3992              CALL quantilesR_K(d4, values(i,j,k,:), Npercen, percentiles(i,j,k,1,:))
3993            END DO
3994          END DO
3995        END DO
3996      ELSE
3997        WRITE(Naxs1,'(A1)')axis1(1)
3998        msg = "' rank 3 values can not compute percentiles using axis " // Naxs1 // "' !!"
3999        CALL ErrMsg(msg, fname, -1)
4000      END IF
4001    ELSE IF (iichar == 1) THEN
4002      ! Might be a better way, but today I can't think it !!
4003      IF (axis2(1) == 1 .AND. axis2(2) == 2) THEN
4004        DO i=1, d3
4005          DO j=1, d4
4006            CALL quantilesR_K(d1*d2, RESHAPE(values(:,:,i,j), (/d1*d2/)), Npercen,                    &
4007              percentiles(1,1,i,j,:))
4008          END DO
4009        END DO
4010      ELSE IF (axis2(1) == 1 .AND. axis2(2) == 3) THEN
4011        DO i=1, d2
4012          DO j=1, d4
4013            CALL quantilesR_K(d1*d3, RESHAPE(values(:,i,:,j), (/d1*d3/)), Npercen,                    &
4014              percentiles(1,i,1,j,:))
4015          END DO
4016        END DO
4017      ELSE IF (axis2(1) == 1 .AND. axis2(2) == 4) THEN
4018        DO i=1, d2
4019          DO j=1, d3
4020            CALL quantilesR_K(d1*d4, RESHAPE(values(:,i,j,:), (/d1*d4/)), Npercen,                    &
4021              percentiles(1,i,j,1,:))
4022          END DO
4023        END DO
4024      ELSE IF (axis2(1) == 2 .AND. axis2(2) == 3) THEN
4025        DO i=1, d1
4026          DO j=1, d4
4027            CALL quantilesR_K(d2*d3, RESHAPE(values(i,:,:,j), (/d2*d3/)), Npercen,                    &
4028              percentiles(i,1,1,j,:))
4029          END DO
4030        END DO
4031      ELSE IF (axis2(1) == 2 .AND. axis2(2) == 4) THEN
4032        DO i=1, d1
4033          DO j=1, d3
4034            CALL quantilesR_K(d2*d4, RESHAPE(values(i,:,j,:), (/d2*d4/)), Npercen,                    &
4035              percentiles(i,1,j,1,:))
4036          END DO
4037        END DO
4038      ELSE IF (axis2(1) == 3 .AND. axis2(2) == 4) THEN
4039        DO i=1, d1
4040          DO j=1, d2
4041            CALL quantilesR_K(d3*d4, RESHAPE(values(i,j,:,:), (/d3*d4/)), Npercen,                    &
4042              percentiles(i,j,1,1,:))
4043          END DO
4044        END DO
4045      ELSE
4046        WRITE(Naxs1,'(A1)')axis2(1)
4047        WRITE(Naxs2,'(A1)')axis2(2)
4048        msg="' rank 4 values can not compute percentiles using axis "//Naxs1// ', ' // Naxs2 // "' !!"
4049        CALL ErrMsg(msg, fname, -1)
4050      END IF
4051    ELSE IF (iichar == 2) THEN
4052      IF (axis2(1) == 1 .AND. axis2(2) == 2 .AND. axis3(3) == 3) THEN
4053        DO i=1, d4
4054          CALL quantilesR_K(d1*d2*d3, RESHAPE(values(:,:,:,i), (/d1*d2*d3/)), Npercen,                &
4055            percentiles(1,1,1,i,:))
4056        END DO
4057      ELSE IF (axis2(1) == 1 .AND. axis2(2) == 2 .AND. axis3(3) == 4) THEN
4058        DO i=1, d3
4059          CALL quantilesR_K(d1*d2*d4, RESHAPE(values(:,:,i,:), (/d1*d2*d4/)), Npercen,                &
4060            percentiles(1,1,i,1,:))
4061        END DO
4062      ELSE IF (axis2(1) == 1 .AND. axis2(2) == 3 .AND. axis3(3) == 4) THEN
4063        DO i=1, d2
4064          CALL quantilesR_K(d1*d3*d4, RESHAPE(values(:,i,:,:), (/d1*d3*d4/)), Npercen,                &
4065            percentiles(1,i,1,1,:))
4066        END DO
4067      ELSE IF (axis2(1) == 2 .AND. axis2(2) == 3 .AND. axis3(3) == 4) THEN
4068        DO i=1, d1
4069          CALL quantilesR_K(d2*d3*d4, RESHAPE(values(i,:,:,:), (/d2*d3*d4/)), Npercen,                &
4070            percentiles(i,1,1,1,:))
4071        END DO
4072      ELSE
4073        WRITE(Naxs1,'(A1)')axis3(1)
4074        WRITE(Naxs2,'(A1)')axis3(2)
4075        WRITE(Naxs3,'(A1)')axis3(2)
4076        msg="' rank 4 values can not compute percentiles using axis "// Naxs1 // ', ' // Naxs2 //     &
4077          ', ' // Naxs3 //"' !!"
4078        CALL ErrMsg(msg, fname, -1)
4079      END IF
4080    ELSE
4081      CALL quantilesR_K(d1*d2*d3*d4, RESHAPE(values, (/d1*d2*d3*d4/)), Npercen, percentiles(1,1,1,1,:))
4082    END IF
4083
4084  END SUBROUTINE percentiles_R_K4D
4085
4086  REAL(r_k) FUNCTION distanceRK(pointA, pointB)
4087  ! Function to provide the distance between two points
4088
4089    IMPLICIT NONE
4090
4091    REAL(r_k), DIMENSION(2), INTENT(in)                  :: pointA, pointB
4092
4093!!!!!!! Variables
4094! pointA, B: couple of points to compute the distance between them
4095
4096    fname = 'distanceRK'
4097
4098    distanceRK = SQRT( (pointB(1)-pointA(1))**2 + (pointB(2)-pointA(2))**2 )
4099
4100  END FUNCTION distanceRK
4101
4102  REAL(r_k) FUNCTION shoelace_area_polygon(Nvertex, poly)
4103  ! Computing the area of a polygon using sholace formula
4104  ! FROM: https://en.wikipedia.org/wiki/Shoelace_formula
4105
4106    IMPLICIT NONE
4107
4108      INTEGER, INTENT(in)                                :: Nvertex
4109      REAL(r_k), DIMENSION(Nvertex,2), INTENT(in)        :: poly
4110
4111! Local
4112      INTEGER                                            :: i
4113      REAL(r_k)                                          :: areapos, areaneg
4114
4115!!!!!!! Variables
4116! Nvertex: number of vertices of the polygon
4117! poly: coordinates of the vertex of the polygon (sorted)
4118
4119    fname = 'shoelace_area_polygon'
4120
4121    areapos = 0.
4122    areaneg = 0.
4123
4124    DO i=1, Nvertex-1
4125      areapos = areapos + poly(i,1)*poly(i+1,2)
4126      areaneg = areaneg + poly(i+1,1)*poly(i,2)
4127    END DO
4128
4129    areapos = areapos + poly(Nvertex,1)*poly(1,2)
4130    areaneg = areaneg + poly(1,1)*poly(Nvertex,2)
4131
4132    shoelace_area_polygon = 0.5*(areapos - areaneg)
4133
4134  END FUNCTION shoelace_area_polygon
4135
4136  SUBROUTINE intersection_2Dlines(lineA, lineB, intersect, ptintersect)
4137  ! Subroutine to provide the intersection point between two lines on the plane using Cramer's method
4138
4139    IMPLICIT NONE
4140
4141    REAL(r_k), DIMENSION(2,2), INTENT(in)                  :: lineA, lineB
4142    LOGICAL, INTENT(out)                                   :: intersect
4143    REAL(r_k), DIMENSION(2), INTENT(out)                   :: ptintersect
4144
4145! Local
4146    REAL(r_k), DIMENSION(2)                                :: segmentA, segmentB
4147    REAL(r_k)                                              :: a11, a12, a21, a22, z1, z2
4148    REAL(r_k)                                              :: det, detX, detY
4149    LOGICAL                                                :: axisAx, axisBx, axisAy, axisBy
4150
4151!!!!!!! Variables
4152! lineA: couple of coordinates for the line A
4153! lineB: couple of coordinates for the line B
4154! intersect: whether two lines intersect
4155! ptintersect: point of intersection [(0,0) if they do not intersect]
4156
4157    fname = 'intersection_2Dlines'
4158
4159    axisAx = .FALSE.
4160    axisAy = .FALSE.
4161    axisBx = .FALSE.
4162    axisBy = .FALSE.
4163    ! Setting segment parameters y = A + B*x
4164    IF (lineA(2,1) /= lineA(1,1)) THEN
4165      segmentA(2) = (lineA(2,2)-lineA(1,2))/(lineA(2,1)-lineA(1,1))
4166      ! This might be to ask too much... ?
4167      !IF ( (lineA(1,1)*segmentA(2) - lineA(1,2)) /= (lineA(2,1)*segmentA(2) - lineA(2,2)) ) THEN
4168      !  PRINT *,'A = y1 - x2*B = ', lineA(1,2) - lineA(1,1)*segmentA(2)
4169      !  PRINT *,'A = y2 - x2*B = ', lineA(2,2) - lineA(2,1)*segmentA(2)
4170      !  msg = 'Wrong calculation of parameter A, for lineA'
4171      !  CALL ErrMSg(msg, fname, -1)
4172      !END IF
4173      segmentA(1) = lineA(1,2) - lineA(1,1)*segmentA(2)
4174      a11 = segmentA(2)
4175      a12 = -oneRK
4176      z1 = -segmentA(1)
4177      IF (lineA(2,2) == lineA(1,2)) axisAx = .TRUE.
4178    ELSE
4179      ! lineA || y-axis
4180      axisAy = .TRUE.
4181    END IF
4182
4183    IF (lineB(2,1) /= lineB(1,1)) THEN
4184      segmentB(2) = (lineB(2,2)-lineB(1,2))/(lineB(2,1)-lineB(1,1))
4185      ! This might be to ask too much... ?
4186      !IF ( (lineB(1,1)*segmentB(2) - lineB(1,2)) /= (lineB(2,1)*segmentB(2) - lineB(2,2)) ) THEN
4187      !  PRINT *,'A = x1*B -y1 = ', lineB(1,1)*segmentB(2) - lineB(1,2)
4188      !  PRINT *,'A = x2*B -y2 = ', lineB(2,1)*segmentB(2) - lineB(2,2)
4189      !  msg = 'Wrong calculation of parameter A, for lineB'
4190      !  CALL ErrMSg(msg, fname, -1)
4191      !END IF
4192      segmentB(1) = lineB(1,2) - lineB(1,1)*segmentB(2)
4193      a21 = segmentB(2)
4194      a22 = -oneRK
4195      z2 = -segmentB(1)
4196      IF (lineB(2,2) == lineB(1,2)) axisBx = .TRUE.
4197    ELSE
4198      ! lineB || y-axis
4199      axisBy = .TRUE.
4200    END IF
4201    ! Cramer's method
4202    ! a11 = B1; a12 = -1
4203    ! a21 = B2; a22 = -1
4204    ! z1 = -A1
4205    ! z2 = -A2
4206    ! (a11 a12)(x) (z1)
4207    ! (a21 a22)(y) (z2)
4208    ! -------- ------ ----- ---- --- -- -
4209    ! det = (a11*a22-a12*a21)
4210    ! detX = (z1*a22-z2*a21)
4211    ! detY = (a11*z1-a12*z2)
4212    ! ptintercept = (detX/det, detY/det)
4213
4214    ! Cases when some of the lines are parallel to any given axis
4215!    PRINT *,'          axisAx', axisAx, 'axisAy', axisAy, 'axisBx', axisBx, 'axisBy', axisBy
4216    IF (axisAx .OR. axisAy .OR. axisBx .OR. axisBy) THEN
4217      IF (axisAx) THEN
4218        IF (axisBy) THEN
4219          intersect = .TRUE.
4220          ptintersect(1) = lineB(1,1)
4221          ptintersect(2) = lineA(1,2)
4222        ELSE
4223          intersect = .TRUE.
4224          ptintersect(1) = (lineA(1,2)-segmentB(1))/segmentB(2)
4225          ptintersect(2) = lineA(1,2)
4226        END IF
4227      END IF
4228      IF (axisAy) THEN
4229        IF (axisBy) THEN
4230          intersect = .TRUE.
4231          ptintersect(1) = lineA(1,1)
4232          ptintersect(2) = lineB(1,2)
4233        ELSE
4234          intersect = .TRUE.
4235          ptintersect(1) = lineA(1,1)
4236          ptintersect(2) = segmentB(1) + lineA(1,1)*segmentB(2)
4237        END IF
4238      END IF
4239      IF (axisBx) THEN
4240        IF (axisAy) THEN
4241          intersect = .TRUE.
4242          ptintersect(1) = lineA(1,1)
4243          ptintersect(2) = lineB(1,2)
4244        ELSE
4245          intersect = .TRUE.
4246          ptintersect(1) = (lineB(1,2)-segmentA(1))/segmentA(2)
4247          ptintersect(2) = lineB(1,2)
4248        END IF
4249      END IF
4250      IF (axisBy) THEN
4251        IF (axisAx) THEN
4252          intersect = .TRUE.
4253          ptintersect(1) = lineB(1,1)
4254          ptintersect(2) = lineA(1,2)
4255        ELSE
4256          intersect = .TRUE.
4257          ptintersect(1) = lineB(1,1)
4258          ptintersect(2) = segmentA(1) + lineB(1,1)*segmentA(2)
4259        END IF
4260      END IF
4261    ELSE
4262      det = (a11*a22-a12*a21)
4263      ! Parallel lines !
4264      IF (det == zeroRK) THEN
4265        intersect = .FALSE.
4266        ptintersect = zeroRK
4267      ELSE
4268        intersect = .TRUE.
4269        detX = (z1*a22-z2*a12)
4270        detY = (a11*z2-a21*z1)
4271
4272        ptintersect(1) = detX/det
4273        ptintersect(2) = detY/det
4274      END IF
4275    END IF
4276
4277  END SUBROUTINE intersection_2Dlines
4278
4279!refs:
4280!https://www.mathopenref.com/heronsformula.html
4281!https://math.stackexchange.com/questions/1406340/intersect-area-of-two-polygons-in-cartesian-plan
4282!http://www.cap-lore.com/MathPhys/IP/
4283!http://www.cap-lore.com/MathPhys/IP/IL.html
4284!https://www.element84.com/blog/determining-the-winding-of-a-polygon-given-as-a-set-of-ordered-points
4285!https://stackoverflow.com/questions/1165647/how-to-determine-if-a-list-of-polygon-points-are-in-clockwise-order
4286!https://en.wikipedia.org/wiki/Shoelace_formula
4287!https://en.wikipedia.org/wiki/Winding_number
4288!https://en.wikipedia.org/wiki/Simple_polygon
4289!https://en.wikipedia.org/wiki/Polygon#Properties
4290!https://en.wikipedia.org/wiki/Convex_polygon
4291!https://en.wikipedia.org/wiki/Jordan_curve_theorem
4292!https://www.sangakoo.com/ca/temes/metode-de-cramer
4293!https://www.geogebra.org/m/pw4QHFYT
4294
4295  SUBROUTINE intersectfaces(faceA, faceB, intersect, intersectpt)
4296  ! Subroutine to provide if two faces of two polygons intersect
4297  ! AFTER: http://www.cap-lore.com/MathPhys/IP/IL.html
4298  !   A: faceA(1,:)
4299  !   B: faceA(2,:)
4300  !   C: faceB(1,:)
4301  !   D: faceB(2,:)
4302
4303    IMPLICIT NONE
4304
4305    REAL(r_k), DIMENSION(2,2), INTENT(in)                :: faceA, faceB
4306    INTEGER, INTENT(out)                                 :: intersect
4307    REAL(r_k), DIMENSION(2), INTENT(out)                 :: intersectpt
4308
4309! Local
4310    REAL(r_k)                                            :: Axmin, Aymin, Axmax, Aymax
4311    REAL(r_k)                                            :: Bxmin, Bymin, Bxmax, Bymax
4312    REAL(r_k)                                            :: areaABD, areaACD, areaBDC, areaDAB
4313    REAL(r_k), DIMENSION(3,2)                            :: triangle
4314    LOGICAL                                              :: Lintersect
4315
4316!!!!!!! Variables
4317! faceA/B: coordinates of faces A and B to determine if they intersect
4318! intersect: integer to say if they intersect (0, no-intersect, +/-1 intersect)
4319! intersectpt: point where faces intersect [(0,0) otherwise]
4320
4321    fname = 'intersectfaces'
4322
4323!    PRINT *,'     ' // TRIM(fname) // ' ________'
4324!    PRINT *,'            faceA:', faceA(1,:), ';',faceA(2,:)
4325!    PRINT *,'            faceB:', faceB(1,:), ';',faceB(2,:)
4326
4327    Axmin = MINVAL(faceA(:,1))
4328    Axmax = MAXVAL(faceA(:,1))
4329    Aymin = MINVAL(faceA(:,2))
4330    Aymax = MAXVAL(faceA(:,2))
4331    Bxmin = MINVAL(faceB(:,1))
4332    Bxmax = MAXVAL(faceB(:,1))
4333    Bymin = MINVAL(faceB(:,2))
4334    Bymax = MAXVAL(faceB(:,2))
4335
4336    ! No intersection
4337    IF ( (Axmax <= Bxmin) .OR. (Axmin >= Bxmax) .OR. (Aymax <= Bymin) .OR. (Aymin >= Bymax) ) THEN
4338      intersect = 0
4339      intersectpt = zeroRK
4340    ELSE
4341      ! Triangle ABD
4342      triangle(1,:) = faceA(1,:)
4343      triangle(2,:) = faceA(2,:)
4344      triangle(3,:) = faceB(2,:)
4345      areaABD = shoelace_area_polygon(3, triangle)
4346 
4347      ! Triangle ACD
4348      triangle(1,:) = faceA(1,:)
4349      triangle(2,:) = faceB(1,:)
4350      triangle(3,:) = faceB(2,:)
4351      areaACD = shoelace_area_polygon(3, triangle)
4352
4353      ! Triangle BDC
4354      triangle(1,:) = faceA(2,:)
4355      triangle(2,:) = faceB(2,:)
4356      triangle(3,:) = faceB(1,:)
4357      areaBDC = shoelace_area_polygon(3, triangle)
4358
4359      ! Triangle DAB
4360      triangle(1,:) = faceB(2,:)
4361      triangle(2,:) = faceA(1,:)
4362      triangle(3,:) = faceA(2,:)
4363      areaDAB = shoelace_area_polygon(3, triangle)
4364
4365      IF (areaABD>zeroRK .AND. areaACD>zeroRK .AND. areaBDC>zeroRK .AND. areaDAB>zeroRK) THEN
4366        intersect = INT(ABS(areaABD)/areaABD)
4367        CALL intersection_2Dlines(faceA, faceB, Lintersect, intersectpt)
4368      ELSE IF (areaABD<zeroRK .AND. areaACD<zeroRK .AND. areaBDC<zeroRK .AND. areaDAB<zeroRK) THEN
4369        intersect = INT(ABS(areaABD)/areaABD)
4370        CALL intersection_2Dlines(faceA, faceB, Lintersect, intersectpt)
4371      ELSE
4372        intersect = 0
4373        intersectpt = zeroRK
4374      END IF
4375!      PRINT *,'     intersect faces: areaABD',areaABD, 'areaACD', areaACD, 'areaBDC',areaBDC, 'areaDAB',areaDAB, 'prod', &
4376!        areaABD*areaACD*areaBDC*areaDAB, 'L:', areaABD*areaACD*areaBDC*areaDAB > zeroRK, 'I', intersect
4377
4378    END IF
4379
4380  END SUBROUTINE intersectfaces
4381
4382  LOGICAL FUNCTION poly_has_point(Nvertex, polygon, point)
4383  ! Function to determine if a polygon has already a given point as one of its vertex
4384
4385    IMPLICIT NONE
4386
4387    INTEGER, INTENT(in)                                  :: Nvertex
4388    REAL(r_k), DIMENSION(Nvertex,2), INTENT(in)          :: polygon
4389    REAL(r_k), DIMENSION(2), INTENT(in)                  :: point
4390
4391! Local
4392    INTEGER                                              :: iv
4393    REAL(r_k), DIMENSION(2)                              :: diff
4394
4395!!!!!!! Vertrex
4396! Nvertex: number of vertexs of the polygon
4397! polygon: vertexs of the polygon
4398! point: point to look for its ownership into the polygon
4399
4400    fname = 'poly_has_point'
4401
4402    poly_has_point = .FALSE.
4403    DO iv=1, Nvertex
4404      diff = polygon(iv,:)-point
4405      IF ( (diff(1) == zeroRK) .AND. (diff(2) == zeroRK)) THEN
4406        poly_has_point = .TRUE.
4407        EXIT
4408      END IF
4409    END DO
4410
4411  END FUNCTION poly_has_point
4412
4413  SUBROUTINE join_polygon(NvertexA, NvertexB, NvertexAB, polyA, polyB, Ncoinvertex, coinpoly)
4414  ! Subroutine to join two polygons
4415  ! AFTER: http://www.cap-lore.com/MathPhys/IP/ and http://www.cap-lore.com/MathPhys/IP/IL.html
4416
4417    IMPLICIT NONE
4418
4419    INTEGER, INTENT(in)                                  :: NvertexA, NvertexB, NvertexAB
4420    REAL(r_k), DIMENSION(NvertexA,2), INTENT(in)         :: polyA
4421    REAL(r_k), DIMENSION(NvertexB,2), INTENT(in)         :: polyB
4422    INTEGER, INTENT(out)                                 :: Ncoinvertex
4423    REAL(r_k), DIMENSION(NvertexAB,2), INTENT(out)        :: coinpoly
4424
4425! Local
4426    INTEGER                                              :: iA, iB, icoin, ii
4427    REAL(r_k), DIMENSION(2,2)                            :: face1, face2
4428    INTEGER                                              :: intersct
4429    REAL(r_k), DIMENSION(2)                              :: ptintersct
4430
4431
4432!!!!!!! variables
4433! NvertexA: number of vertexs polygon A
4434! NvertexB: number of vertexs polygon B
4435! polyA: pairs of coordinates for the polygon A (clockwise)
4436! polyB: pairs of coordinates for the polygon B (clockwise)
4437! Ncoinvertex: number of vertexes for the coincident polygon
4438! coinpoly: pairs of coordinates for the coincident polygon (clockwise)
4439
4440    fname = 'join_polygon'
4441
4442    icoin = 0
4443    coinpoly = 0.
4444
4445    ! First, include that vertex which do not lay within any polygon
4446    DO iA=1, NvertexA
4447      !PRINT *, '  iA:', iA, ':', polyA(iA,:), point_inside(polyA(iA,:), NvertexB, polyB)
4448      IF (.NOT. point_inside(polyA(iA,:), NvertexB, polyB)) THEN
4449        icoin = icoin + 1
4450        coinpoly(icoin,:) = polyA(iA,:)
4451      END IF
4452    END DO
4453
4454    DO iB=1, NvertexB
4455      !PRINT *, '  iB:', iB, ':', polyB(iB,:), point_inside(polyB(iB,:), NvertexA, polyA)
4456      IF (.NOT. point_inside(polyB(iB,:), NvertexA, polyA)) THEN
4457        icoin = icoin + 1
4458        coinpoly(icoin,:) = polyB(iB,:)
4459      END IF
4460    END DO
4461
4462    DO iA=1, NvertexA
4463      ! Getting couple of vertexs from polyA and polyB
4464      IF (iA /= NvertexA) THEN
4465        face1(1,:) = polyA(iA,:)
4466        face1(2,:) = polyA(iA+1,:)
4467      ELSE
4468        face1(1,:) = polyA(iA,:)
4469        face1(2,:) = polyA(1,:)
4470      END IF
4471      DO iB=1, NvertexB
4472        IF (iB /= NvertexB) THEN
4473          face2(1,:) = polyB(iB,:)
4474          face2(2,:) = polyB(iB+1,:)
4475        ELSE
4476          face2(1,:) = polyB(iB,:)
4477          face2(2,:) = polyB(1,:)
4478        END IF
4479       
4480        ! Compute areas of the four possible triangles. Introduce the coincident vertexs not included
4481        CALL intersectfaces(face1, face2, intersct, ptintersct)
4482        !PRINT *,iA,':',face1(1,:),';',face1(2,:), '=', iB, face2(1,:),';',face2(2,:), '<>', intersct,':', ptintersct
4483        IF (intersct == 1) THEN
4484          IF (.NOT.poly_has_point(icoin,coinpoly(1:icoin,:),ptintersct) ) THEN
4485            icoin = icoin + 1
4486            coinpoly(icoin,:) = ptintersct
4487          END IF
4488        ELSE IF (intersct == -1) THEN
4489          IF (.NOT.poly_has_point(icoin,coinpoly(1:icoin,:),ptintersct) ) THEN
4490            icoin = icoin + 1
4491            coinpoly(icoin,:) = ptintersct
4492          END IF
4493        END IF
4494
4495      END DO
4496    END DO
4497    Ncoinvertex = icoin
4498
4499  END SUBROUTINE join_polygon
4500
4501  SUBROUTINE sort_polygon(Nvertex, polygon, sense, Nnewvertex, newpoly)
4502  ! Subroutine to sort a polygon using its center as average of the coordinates and remove duplicates
4503  !    Should be used the centroid instead, but by now let do it simple
4504  !    https://en.wikipedia.org/wiki/Centroid
4505
4506
4507    IMPLICIT NONE
4508
4509    INTEGER, INTENT(in)                                  :: Nvertex, sense
4510    REAL(r_k), DIMENSION(Nvertex,2), INTENT(in)          :: polygon
4511    INTEGER, INTENT(out)                                 :: Nnewvertex
4512    REAL(r_k), DIMENSION(Nvertex,2), INTENT(out)         :: newpoly
4513
4514! Local
4515    INTEGER                                              :: iv, j
4516    REAL(r_k)                                            :: vang
4517    REAL(r_k), DIMENSION(2)                              :: center
4518    REAL(r_k), DIMENSION(Nvertex)                        :: angles
4519    REAL(r_k), DIMENSION(Nvertex,2)                      :: sortpoly
4520
4521!!!!!!! Variables
4522! Nvertex: number of vertices
4523! polygon: coordinates of the vertices of the polygon
4524! sense: sens of sorting thepolygon (1: clockwise, -1: anti-clockwise)
4525! sortpoly: sorted polygon
4526! Nnewvertex: number of vertices new polygon
4527! newpoly: sorted and duplicate removed polygon
4528
4529    fname = 'sort_polygon'
4530
4531    ! To be substituted by centroid calculation (which requires already sorted vetexs...)
4532    center(1) = SUM(polygon(:,1))/Nvertex
4533    center(2) = SUM(polygon(:,2))/Nvertex
4534
4535    DO iv=1, Nvertex
4536      angles(iv) = ATAN2(polygon(iv,2)-center(2),polygon(iv,1)-center(1))
4537    END DO
4538    CALL sortR_K(angles, Nvertex)
4539
4540    sortpoly = zeroRK
4541    DO iv=1, Nvertex
4542      DO j=1, Nvertex
4543        vang = ATAN2(polygon(j,2)-center(2), polygon(j,1)-center(1))
4544        IF (angles(iv) == vang) THEN
4545          IF (sense == -1) THEN
4546            sortpoly(iv,:) = polygon(j,:)
4547          ELSE
4548            sortpoly(Nvertex-iv+1,:) = polygon(j,:)
4549          END IF
4550          EXIT
4551        END IF
4552      END DO
4553    END DO
4554
4555    newpoly(1,:) = sortpoly(1,:)
4556    j = 1
4557    DO iv=2, Nvertex
4558      IF (.NOT.poly_has_point(j,newpoly(1:j,:),sortpoly(iv,:)) ) THEN
4559        j = j+1
4560        newpoly(j,:) = sortpoly(iv,:)
4561      END IF
4562    END DO
4563    Nnewvertex = j
4564
4565  END SUBROUTINE sort_polygon
4566
4567  LOGICAL FUNCTION point_inside(point, Nvertex, polygon)
4568  ! Function to determine if a given point is inside a polygon providing its sorted vertices
4569  ! FROM: https://en.wikipedia.org/wiki/Point_in_polygon
4570
4571    IMPLICIT NONE
4572
4573    REAL(r_k), DIMENSION(2), INTENT(in)                  :: point
4574    INTEGER, INTENT(in)                                  :: Nvertex
4575    REAL(r_k), DIMENSION(Nvertex,2), INTENT(in)          :: polygon
4576
4577    ! Local
4578    INTEGER                                              :: iv, Nintersect
4579    INTEGER                                              :: cross
4580    REAL(r_k)                                            :: xmin
4581    REAL(r_k), DIMENSION(2)                              :: crosspoint
4582    REAL(r_k), DIMENSION(2,2)                            :: face1, face2
4583    REAL(r_k), DIMENSION(Nvertex)                        :: abovebelow
4584
4585!!!!!!! Variables
4586! point: point to look for
4587! Nvertrex: number of vertices of a polygon
4588! polygon: vertices of a polygon
4589
4590    fname = 'point_inside'
4591
4592    xmin = MINVAL(polygon(:,1))
4593
4594    ! Looking for the intersection with the ray
4595    Nintersect = 0
4596    face1(1,:) = (/ xmin-0.5, point(2) /)
4597    face1(2,:) = (/ point(1), point(2) /)
4598
4599    DO iv = 1, Nvertex
4600      IF (iv /= Nvertex) THEN
4601        face2(1,:) = polygon(iv,:)
4602        face2(2,:) = polygon(iv+1,:)
4603      ELSE
4604        face2(1,:) = polygon(iv,:)
4605        face2(2,:) = polygon(1,:)
4606      END IF
4607      CALL intersectfaces(face1, face2, cross, crosspoint)
4608      IF (cross /= 0) THEN
4609        Nintersect = Nintersect + 1
4610        abovebelow(Nintersect) = iv
4611      END IF
4612    END DO
4613
4614    IF (MOD(Nintersect,2) == 0) THEN
4615      point_inside = .FALSE.
4616    ELSE
4617      point_inside = .TRUE.
4618    END IF
4619
4620  END FUNCTION point_inside
4621
4622  LOGICAL FUNCTION point_in_face(pt, Nvertex, poly)
4623  ! Function to determine if a given point is on a face of a polygon
4624
4625    IMPLICIT NONE
4626
4627    REAL(r_k), DIMENSION(2), INTENT(in)                  :: pt
4628    INTEGER, INTENT(in)                                  :: Nvertex
4629    REAL(r_k), DIMENSION(Nvertex,2), INTENT(in)          :: poly
4630! Local
4631    INTEGER                                              :: iv
4632    REAL(r_k)                                            :: ix, ex, iy, ey, tmpv
4633    REAL(r_k)                                            :: dx, dy, A, B
4634
4635!!!!!!! Variables
4636! pt: point to look for
4637! Nvertex: Number of vertices of the polygon
4638! poly: polygon
4639    fname = 'point_in_face'
4640
4641    point_in_face = .FALSE.
4642    DO iv=1, Nvertex
4643      IF (iv < Nvertex) THEN
4644        ix = poly(iv,1)
4645        ex = poly(iv+1,1)
4646        iy = poly(iv,2)
4647        ey = poly(iv+1,2)
4648      ELSE
4649        ix = poly(iv,1)
4650        ex = poly(1,1)
4651        iy = poly(iv,2)
4652        ey = poly(1,2)
4653      END IF   
4654      dx = ex - ix
4655      dy = ey - iy
4656
4657      IF (dx == zeroRK) THEN
4658        IF (pt(1) == ix) THEN
4659          IF ( (iy < ey) .AND. (pt(2) >= iy) .AND. pt(2) <= ey) THEN
4660            point_in_face = .TRUE.
4661            EXIT
4662          ELSE IF ( (iy > ey) .AND. (pt(2) >= ey) .AND. pt(2) <= iy) THEN
4663            point_in_face = .TRUE.
4664            EXIT
4665          END IF
4666        END IF
4667      ELSE
4668        IF (dy == zeroRK) THEN
4669          IF (pt(2) == iy) THEN
4670            IF ((ix < ex) .AND. (pt(1) >= ix) .AND. pt(1) <= ex) THEN
4671              point_in_face = .TRUE.
4672              EXIT           
4673            ELSE IF ((ix > ex) .AND. (pt(1) >= ex) .AND. pt(1) <= ix) THEN
4674              point_in_face = .TRUE.
4675              EXIT
4676            END IF
4677          END IF
4678        ELSE
4679          A = iy
4680          B = (ey-iy)/(ex-ix)
4681          IF (A+B*(pt(1)-ix) == pt(2)) THEN
4682            point_in_face = .TRUE.
4683            EXIT
4684          END IF
4685        END IF
4686      END IF
4687    END DO
4688
4689  END FUNCTION point_in_face
4690
4691  SUBROUTINE coincident_polygon(NvertexA, NvertexB, NvertexAB, polyA, polyB, Ncoinvertex, coinpoly)
4692  ! Subroutine to provide the intersection polygon between two polygons
4693  ! AFTER: http://www.cap-lore.com/MathPhys/IP/ and http://www.cap-lore.com/MathPhys/IP/IL.html
4694
4695    IMPLICIT NONE
4696
4697    INTEGER, INTENT(in)                                  :: NvertexA, NvertexB, NvertexAB
4698    REAL(r_k), DIMENSION(NvertexA,2), INTENT(in)         :: polyA
4699    REAL(r_k), DIMENSION(NvertexB,2), INTENT(in)         :: polyB
4700    INTEGER, INTENT(out)                                 :: Ncoinvertex
4701    REAL(r_k), DIMENSION(NvertexAB,2), INTENT(out)       :: coinpoly
4702
4703! Local
4704    INTEGER                                              :: iA, iB, icoin, ii
4705    REAL(r_k), DIMENSION(2,2)                            :: face1, face2
4706    INTEGER                                              :: intersct
4707    REAL(r_k), DIMENSION(2)                              :: ptintersct
4708
4709!!!!!!! variables
4710! NvertexA: number of vertexs polygon A
4711! NvertexB: number of vertexs polygon B
4712! polyA: pairs of coordinates for the polygon A (clockwise)
4713! polyB: pairs of coordinates for the polygon B (clockwise)
4714! Ncoinvertex: number of vertexes for the coincident polygon
4715! coinpoly: pairs of coordinates for the coincident polygon (clockwise)
4716
4717    fname = 'coincident_polygon'
4718
4719    icoin = 0
4720    coinpoly = 0.
4721    ! First, include that vertex which lay within any polygon
4722    DO iA=1, NvertexA
4723      IF (point_inside(polyA(iA,:), NvertexB, polyB)) THEN
4724        icoin = icoin + 1
4725        coinpoly(icoin,:) = polyA(iA,:)
4726      END IF
4727      IF (point_in_face(polyA(iA,:), NvertexB, polyB)) THEN
4728        icoin = icoin + 1
4729        coinpoly(icoin,:) = polyA(iA,:)
4730      END IF
4731    END DO
4732
4733    DO iB=1, NvertexB
4734      IF (point_inside(polyB(iB,:), NvertexA, polyA)) THEN
4735        icoin = icoin + 1
4736        coinpoly(icoin,:) = polyB(iB,:)
4737      END IF
4738      IF (point_in_face(polyB(iB,:), NvertexA, polyA)) THEN
4739        icoin = icoin + 1
4740        coinpoly(icoin,:) = polyB(iB,:)
4741      END IF
4742    END DO
4743
4744    ! Look interesections
4745    DO iA=1, NvertexA
4746      ! Getting couple of vertexs from polyA and polyB
4747      IF (iA /= NvertexA) THEN
4748        face1(1,:) = polyA(iA,:)
4749        face1(2,:) = polyA(iA+1,:)
4750      ELSE
4751        face1(1,:) = polyA(iA,:)
4752        face1(2,:) = polyA(1,:)
4753      END IF
4754      DO iB=1, NvertexB
4755        IF (iB /= NvertexB) THEN
4756          face2(1,:) = polyB(iB,:)
4757          face2(2,:) = polyB(iB+1,:)
4758        ELSE
4759          face2(1,:) = polyB(iB,:)
4760          face2(2,:) = polyB(1,:)
4761        END IF
4762       
4763        ! Compute areas of the four possible triangles. Introduce the coincident vertexs not included
4764        CALL intersectfaces(face1, face2, intersct, ptintersct)
4765        !PRINT *,iA,':',face1(1,:),';',face1(2,:), '=', iB, face2(1,:),';',face2(2,:), '<>', intersct,':', ptintersct
4766        IF ((intersct /= 0) .AND. (.NOT.poly_has_point(icoin,coinpoly(1:icoin,:),ptintersct)) ) THEN
4767          icoin = icoin + 1
4768          coinpoly(icoin,:) = ptintersct
4769        END IF
4770
4771      END DO
4772    END DO
4773    Ncoinvertex = icoin
4774
4775  END SUBROUTINE coincident_polygon
4776
4777  SUBROUTINE grid_within_polygon(NvertexA, polygonA, dx, dy, dxy, xCvals, yCvals, Nvertexmax, xBvals, &
4778    yBvals, Ngridsin, gridsin)
4779  ! Subroutine to determine which grid cells from a matrix lay inside a polygon
4780
4781    IMPLICIT NONE
4782
4783    INTEGER, INTENT(in)                                  :: NvertexA, dx, dy, dxy, Nvertexmax
4784    REAL(r_k), DIMENSION(NvertexA,2), INTENT(in)         :: polygonA
4785    REAL(r_k), DIMENSION(dx,dy), INTENT(in)              :: xCvals, yCvals
4786    REAL(r_k), DIMENSION(dx,dy,Nvertexmax), INTENT(in)   :: xBvals, yBvals
4787    INTEGER, INTENT(out)                                 :: Ngridsin
4788    INTEGER, DIMENSION(dxy,2), INTENT(out)               :: gridsin
4789
4790! Local
4791    INTEGER                                              :: ix, iy, iv
4792    REAL(r_k), DIMENSION(2)                              :: centergrid, vertex
4793    LOGICAL, DIMENSION(dx,dy)                            :: within
4794
4795!!!!!!! Variables
4796! NvertexA: Number of vertices of the polygin to find the grids
4797! polygonA: ordered vertices of the polygon
4798! dx, dy: shape of the matrix with the grid points
4799! xCvals, yCvals: coordinates of the center of the grid cells
4800! Nvertexmax: Maximum number of vertices of the grid cells
4801! xBvals, yBvals: coordinates of th vertices of the grid cells (-99999 for no vertex)
4802! Ngridsin: number of grids with some extension within the polygon
4803! gridsin: grids within the polygin
4804! percentages: percentages of area of each of the grids within the polygon
4805
4806    fname = 'spacepercen_within_reg'
4807
4808    Ngridsin = 0
4809    gridsin = 0
4810    within = .FALSE.
4811    DO ix = 1, dx
4812      DO iy = 1, dy
4813        IF (.NOT.within(ix,iy)) THEN
4814          centergrid = (/ xCvals(ix,iy), yCvals(ix,iy) /)
4815          ! By grid center
4816          IF (point_inside(centergrid, NvertexA, polygonA)) THEN
4817            Ngridsin = Ngridsin + 1
4818            ! Getting coordinates
4819            gridsin(Ngridsin,1) = ix
4820            gridsin(Ngridsin,2) = iy
4821            within(ix,iy) = .TRUE.
4822            CYCLE
4823          END IF
4824
4825          ! Getting grid vertices
4826          DO iv=1, Nvertexmax
4827            IF (.NOT.within(ix,iy)) THEN
4828              IF (xBvals(ix,iy,iv) /= fillvalI) THEN
4829                vertex = (/ xBvals(ix,iy,iv), yBvals(ix,iy,iv) /)
4830                IF (point_inside(vertex, NvertexA, polygonA)) THEN
4831                  Ngridsin = Ngridsin + 1
4832                  ! Getting coordinates
4833                  gridsin(Ngridsin,1) = ix
4834                  gridsin(Ngridsin,2) = iy
4835                  within(ix,iy) = .TRUE.
4836                  CYCLE
4837                END IF
4838              END IF
4839            END IF
4840          END DO
4841
4842        END IF
4843      END DO
4844    END DO
4845
4846  END SUBROUTINE grid_within_polygon
4847
4848  SUBROUTINE spacepercen_within_reg(NvertexA, polygonA, dx, dy, Nvertexmax, xBvals, yBvals,           &
4849    Ngridsin, gridsin, strict, percentages)
4850  ! Subroutine to compute the percentage of a series of grid cells which are encompassed by a polygon
4851  ! NOTE: Assuming coordinates on the plane with rectilinar, distance preserved and perpendicular x
4852  !   and y axes.
4853
4854    IMPLICIT NONE
4855
4856    INTEGER, INTENT(in)                                  :: NvertexA, dx, dy, Nvertexmax
4857    REAL(r_k), DIMENSION(NvertexA,2), INTENT(in)         :: polygonA
4858    REAL(r_k), DIMENSION(dx,dy,Nvertexmax), INTENT(in)   :: xBvals, yBvals
4859    INTEGER, INTENT(in)                                  :: Ngridsin
4860    INTEGER, DIMENSION(Ngridsin,2), INTENT(in)           :: gridsin
4861    LOGICAL, INTENT(in)                                  :: strict
4862    REAL(r_k), DIMENSION(Ngridsin), INTENT(out)          :: percentages
4863
4864! Local
4865   INTEGER                                               :: ig, iv, ix, iy
4866   INTEGER                                               :: Nvertex, NvertexAgrid, Ncoin, Nsort
4867   CHARACTER(len=20)                                     :: DS
4868   REAL(r_k)                                             :: areapoly, areagpoly, totarea, totpercent
4869   REAL(r_k), ALLOCATABLE, DIMENSION(:,:)                :: vertexgrid, icoinpoly, coinpoly,          &
4870     sortpoly, poly
4871
4872!!!!!!! Variables
4873! NvertexA: Number of vertices of the polygin to find the grids
4874! polygonA: ordered vertices of the polygon
4875! dx, dy: shape of the matrix with the grid points
4876! xCvals, yCvals: coordinates of the center of the grid cells
4877! Nvertexmax: Maximum number of vertices of the grid cells
4878! xBvals, yBvals: coordinates of th vertices of the grid cells (-99999 for no vertex)
4879! Ngridsin: number of grids with some extension within the polygon
4880! gridsin: grids within the polygon
4881! strict: give an error if the area of the polygon is not fully covered
4882! percentages: percentages of area of each of the grids within the polygon
4883
4884    fname = 'spacepercen_within_reg'
4885
4886    percentages = zeroRK
4887    totpercent = zeroRK
4888    totarea = zeroRK
4889
4890    areapoly = shoelace_area_polygon(NvertexA, polygonA)
4891
4892    DO ig = 1, Ngridsin
4893      ix = gridsin(ig,1)
4894      iy = gridsin(ig,2)
4895
4896      ! Getting grid vertices
4897      Nvertex = 0
4898      DO iv=1, Nvertexmax
4899        IF (xBvals(ix,iy,iv) /= fillvalI) THEN
4900          Nvertex = Nvertex + 1
4901        END IF
4902      END DO
4903      IF (ALLOCATED(vertexgrid)) DEALLOCATE(vertexgrid)
4904      ALLOCATE(vertexgrid(Nvertex,2))
4905      vertexgrid(:,1) = xBvals(ix,iy,1:Nvertex)
4906      vertexgrid(:,2) = yBvals(ix,iy,1:Nvertex)
4907
4908      ! Getting common vertices
4909      NvertexAgrid = NvertexA*Nvertex*2
4910      IF (ALLOCATED(icoinpoly)) DEALLOCATE(icoinpoly)
4911      ALLOCATE(icoinpoly(NvertexAgrid,2))
4912      CALL coincident_polygon(NvertexA, Nvertex, NvertexAgrid, polygonA, vertexgrid, Ncoin, icoinpoly)
4913
4914      IF (ALLOCATED(coinpoly)) DEALLOCATE(coinpoly)
4915      ALLOCATE(coinpoly(Ncoin,2))
4916      DO iv=1, Ncoin
4917        coinpoly(iv,:) = icoinpoly(iv,:)
4918      END DO
4919
4920      IF (ALLOCATED(sortpoly)) DEALLOCATE(sortpoly)
4921      ALLOCATE(sortpoly(Ncoin,2))
4922      CALL sort_polygon(Ncoin, coinpoly, 1, Nsort, sortpoly)
4923
4924      IF (ALLOCATED(poly)) DEALLOCATE(poly)
4925      ALLOCATE(poly(Nsort,2))
4926      DO iv=1, Nsort
4927        poly(iv,:) = sortpoly(iv,:)
4928      END DO
4929
4930      areagpoly = shoelace_area_polygon(Nsort, poly)
4931      IF (INT(LOG10(EPSILON(totpercent))) < 12) THEN
4932        totarea = totarea + ABS(areagpoly)
4933        percentages(ig) = ABS(areagpoly / areapoly)
4934! f2py does not like it!
4935!      ELSE
4936!        totarea = totarea + DABS(areagpoly)
4937!        percentages(ig) = DABS(areagpoly / areapoly)
4938      END IF
4939      totpercent = totpercent + percentages(ig)
4940    END DO
4941
4942    IF (INT(LOG10(EPSILON(totpercent))) < 12) THEN
4943      IF (strict .AND. ABS(totpercent - oneRK) > epsilonRK) THEN
4944        PRINT *, 'totarea:', totarea, ' area polygon:', areapoly
4945        PRINT *, 'totpercent:', totpercent, ' oneRK:', oneRK, ' diff:', totpercent - oneRK
4946        WRITE(DS,'(F20.8)')ABS(totpercent - oneRK)
4947        msg = 'sum of all grid space percentages does not cover (' // TRIM(DS) // ') all polygon'
4948        CALL ErrMsg(msg, fname, -1)
4949      END IF
4950    ELSE
4951! f2py does not like it!
4952!      IF (strict .AND. ABS(totpercent - oneRK) > epsilonRK) THEN
4953!        PRINT *, 'totarea:', totarea, ' area polygon:', areapoly
4954!        PRINT *, 'totpercent:', totpercent, ' oneRK:', oneRK, ' diff:', totpercent - oneRK
4955!        WRITE(DS,'(F20.16)')ABS(totpercent - oneRK)
4956!        msg = 'sum of all grid space percentages does not cover (' // TRIM(DS) // ') all polygon'
4957!        CALL ErrMsg(msg, fname, -1)
4958!      END IF
4959    END IF
4960
4961    IF (ALLOCATED(vertexgrid)) DEALLOCATE(vertexgrid)
4962    IF (ALLOCATED(icoinpoly)) DEALLOCATE(icoinpoly)
4963    IF (ALLOCATED(coinpoly)) DEALLOCATE(coinpoly)
4964    IF (ALLOCATED(sortpoly)) DEALLOCATE(sortpoly)
4965    IF (ALLOCATED(poly)) DEALLOCATE(poly)
4966
4967  END SUBROUTINE spacepercen_within_reg
4968
4969  SUBROUTINE grid_spacepercen_within_reg(NvertexA, polygonA, dx, dy, Nvertexmax, xBvals, yBvals,      &
4970    Ngridsin, gridsin, strict, gridspace, percentages)
4971  ! Subroutine to compute the percentage of grid space of a series of grid cells which are encompassed
4972  !   by a polygon
4973  ! NOTE: Assuming coordinates on the plane with rectilinar, distance preserved and perpendicular x
4974  !   and y axes.
4975
4976    IMPLICIT NONE
4977
4978    INTEGER, INTENT(in)                                  :: NvertexA, dx, dy, Nvertexmax
4979    REAL(r_k), DIMENSION(NvertexA,2), INTENT(in)         :: polygonA
4980    REAL(r_k), DIMENSION(dx,dy,Nvertexmax), INTENT(in)   :: xBvals, yBvals
4981    INTEGER, INTENT(in)                                  :: Ngridsin
4982    INTEGER, DIMENSION(Ngridsin,2), INTENT(in)           :: gridsin
4983    LOGICAL, INTENT(in)                                  :: strict
4984    REAL(r_k), DIMENSION(Ngridsin), INTENT(out)          :: gridspace, percentages
4985
4986! Local
4987   INTEGER                                               :: ig, iv, ix, iy
4988   INTEGER                                               :: Nvertex, NvertexAgrid, Ncoin, Nsort
4989   CHARACTER(len=20)                                     :: DS
4990   REAL(r_k)                                             :: areapoly, areagpoly
4991   REAL(r_k), ALLOCATABLE, DIMENSION(:,:)                :: vertexgrid, icoinpoly, coinpoly,          &
4992     sortpoly, poly
4993
4994!!!!!!! Variables
4995! NvertexA: Number of vertices of the polygon to find the grids
4996! polygonA: ordered vertices of the polygon
4997! dx, dy: shape of the matrix with the grid points
4998! xCvals, yCvals: coordinates of the center of the grid cells
4999! Nvertexmax: Maximum number of vertices of the grid cells
5000! xBvals, yBvals: coordinates of th vertices of the grid cells (-99999 for no vertex)
5001! Ngridsin: number of grids with some extension within the polygon
5002! gridsin: grids within the polygon
5003! strict: give an error if the area of the polygon is not fully covered
5004! gridspace: area of each of the grids
5005! percentages: percentages of grid area of each of the grids within the polygon
5006
5007    fname = 'grid_spacepercen_within_reg'
5008
5009    gridspace = zeroRK
5010    percentages = zeroRK
5011
5012    DO ig = 1, Ngridsin
5013      ix = gridsin(ig,1)
5014      iy = gridsin(ig,2)
5015
5016     ! Getting grid vertices
5017      Nvertex = 0
5018      DO iv=1, Nvertexmax
5019        IF (xBvals(ix,iy,iv) /= fillvalI) THEN
5020          Nvertex = Nvertex + 1
5021        END IF
5022      END DO
5023      IF (ALLOCATED(vertexgrid)) DEALLOCATE(vertexgrid)
5024      ALLOCATE(vertexgrid(Nvertex,2))
5025      vertexgrid(:,1) = xBvals(ix,iy,1:Nvertex)
5026      vertexgrid(:,2) = yBvals(ix,iy,1:Nvertex)
5027      areapoly = shoelace_area_polygon(Nvertex, vertexgrid)
5028
5029      ! Getting common vertices
5030      NvertexAgrid = NvertexA*Nvertex*2
5031      IF (ALLOCATED(icoinpoly)) DEALLOCATE(icoinpoly)
5032      ALLOCATE(icoinpoly(NvertexAgrid,2))
5033      CALL coincident_polygon(NvertexA, Nvertex, NvertexAgrid, polygonA, vertexgrid, Ncoin, icoinpoly)
5034
5035      IF (ALLOCATED(coinpoly)) DEALLOCATE(coinpoly)
5036      ALLOCATE(coinpoly(Ncoin,2))
5037      DO iv=1, Ncoin
5038        coinpoly(iv,:) = icoinpoly(iv,:)
5039      END DO
5040
5041      IF (ALLOCATED(sortpoly)) DEALLOCATE(sortpoly)
5042      ALLOCATE(sortpoly(Ncoin,2))
5043      CALL sort_polygon(Ncoin, coinpoly, 1, Nsort, sortpoly)
5044
5045      IF (ALLOCATED(poly)) DEALLOCATE(poly)
5046      ALLOCATE(poly(Nsort,2))
5047      DO iv=1, Nsort
5048        poly(iv,:) = sortpoly(iv,:)
5049      END DO
5050
5051      areagpoly = shoelace_area_polygon(Nsort, poly)
5052      gridspace(ig) = ABS(areapoly)
5053      percentages(ig) = ABS(areagpoly / areapoly)
5054    END DO
5055
5056    IF (ALLOCATED(vertexgrid)) DEALLOCATE(vertexgrid)
5057    IF (ALLOCATED(icoinpoly)) DEALLOCATE(icoinpoly)
5058    IF (ALLOCATED(coinpoly)) DEALLOCATE(coinpoly)
5059    IF (ALLOCATED(sortpoly)) DEALLOCATE(sortpoly)
5060    IF (ALLOCATED(poly)) DEALLOCATE(poly)
5061
5062  END SUBROUTINE grid_spacepercen_within_reg
5063
5064  SUBROUTINE grid_spacepercen_within_reg_providing_polys(NvertexA, polygonA, dx, dy, Nvertexmax,      &
5065    xBvals, yBvals, Ngridsin, gridsin, strict, Nmaxver2, Ncoinpoly, ccoinpoly, gridspace, percentages)
5066  ! Subroutine to compute the percentage of grid space of a series of grid cells which are encompassed
5067  !   by a polygon providing coordinates of the resultant polygons
5068  ! NOTE: Assuming coordinates on the plane with rectilinar, distance preserved and perpendicular x
5069  !   and y axes.
5070
5071    IMPLICIT NONE
5072
5073    INTEGER, INTENT(in)                                  :: NvertexA, dx, dy, Nvertexmax, Nmaxver2
5074    REAL(r_k), DIMENSION(NvertexA,2), INTENT(in)         :: polygonA
5075    REAL(r_k), DIMENSION(dx,dy,Nvertexmax), INTENT(in)   :: xBvals, yBvals
5076    INTEGER, INTENT(in)                                  :: Ngridsin
5077    INTEGER, DIMENSION(Ngridsin,2), INTENT(in)           :: gridsin
5078    LOGICAL, INTENT(in)                                  :: strict
5079    INTEGER, DIMENSION(Ngridsin), INTENT(out)            :: Ncoinpoly
5080    REAL(r_k), DIMENSION(Ngridsin,Nmaxver2,2),                                                        &
5081      INTENT(out)                                        :: ccoinpoly
5082    REAL(r_k), DIMENSION(Ngridsin), INTENT(out)          :: gridspace, percentages
5083
5084! Local
5085   INTEGER                                               :: ig, iv, ix, iy
5086   INTEGER                                               :: Nvertex, NvertexAgrid, Ncoin, Nsort
5087   CHARACTER(len=20)                                     :: DS
5088   REAL(r_k)                                             :: areapoly, areagpoly
5089   REAL(r_k), ALLOCATABLE, DIMENSION(:,:)                :: vertexgrid, icoinpoly, coinpoly,          &
5090     sortpoly, poly
5091
5092!!!!!!! Variables
5093! NvertexA: Number of vertices of the polygon to find the grids
5094! polygonA: ordered vertices of the polygon
5095! dx, dy: shape of the matrix with the grid points
5096! xCvals, yCvals: coordinates of the center of the grid cells
5097! Nvertexmax: Maximum number of vertices of the grid cells
5098! xBvals, yBvals: coordinates of th vertices of the grid cells (-99999 for no vertex)
5099! Ngridsin: number of grids with some extension within the polygon
5100! gridsin: grids within the polygon
5101! strict: give an error if the area of the polygon is not fully covered
5102! Nmaxver2: maximum possible number of vertices of the coincident polygon
5103! Ncoinpoly: number of vertices of the coincident polygon
5104! coinpoly: coordinates of the vertices of the coincident polygon
5105! gridspace: area of each of the grids
5106! percentages: percentages of grid area of each of the grids within the polygon
5107
5108    fname = 'grid_spacepercen_within_reg_providing_polys'
5109
5110    gridspace = zeroRK
5111    percentages = zeroRK
5112
5113    DO ig = 1, Ngridsin
5114      ix = gridsin(ig,1)
5115      iy = gridsin(ig,2)
5116
5117     ! Getting grid vertices
5118      Nvertex = 0
5119      DO iv=1, Nvertexmax
5120        IF (xBvals(ix,iy,iv) /= fillvalI) THEN
5121          Nvertex = Nvertex + 1
5122        END IF
5123      END DO
5124      IF (ALLOCATED(vertexgrid)) DEALLOCATE(vertexgrid)
5125      ALLOCATE(vertexgrid(Nvertex,2))
5126      vertexgrid(:,1) = xBvals(ix,iy,1:Nvertex)
5127      vertexgrid(:,2) = yBvals(ix,iy,1:Nvertex)
5128      areapoly = shoelace_area_polygon(Nvertex, vertexgrid)
5129
5130      ! Getting common vertices
5131      NvertexAgrid = NvertexA*Nvertex*2
5132      IF (ALLOCATED(icoinpoly)) DEALLOCATE(icoinpoly)
5133      ALLOCATE(icoinpoly(NvertexAgrid,2))
5134      CALL coincident_polygon(NvertexA, Nvertex, NvertexAgrid, polygonA, vertexgrid, Ncoin, icoinpoly)
5135
5136      IF (ALLOCATED(coinpoly)) DEALLOCATE(coinpoly)
5137      ALLOCATE(coinpoly(Ncoin,2))
5138      DO iv=1, Ncoin
5139        coinpoly(iv,:) = icoinpoly(iv,:)
5140      END DO
5141
5142      IF (ALLOCATED(sortpoly)) DEALLOCATE(sortpoly)
5143      ALLOCATE(sortpoly(Ncoin,2))
5144      CALL sort_polygon(Ncoin, coinpoly, 1, Nsort, sortpoly)
5145
5146      IF (ALLOCATED(poly)) DEALLOCATE(poly)
5147      ALLOCATE(poly(Nsort,2))
5148      DO iv=1, Nsort
5149        poly(iv,:) = sortpoly(iv,:)
5150      END DO
5151
5152      areagpoly = shoelace_area_polygon(Nsort, poly)
5153      Ncoinpoly(ig)= Nsort
5154      ccoinpoly(ig,:,:) = poly(:,:)
5155      gridspace(ig) = ABS(areapoly)
5156      percentages(ig) = ABS(areagpoly / areapoly)
5157    END DO
5158
5159    IF (ALLOCATED(vertexgrid)) DEALLOCATE(vertexgrid)
5160    IF (ALLOCATED(icoinpoly)) DEALLOCATE(icoinpoly)
5161    IF (ALLOCATED(coinpoly)) DEALLOCATE(coinpoly)
5162    IF (ALLOCATED(sortpoly)) DEALLOCATE(sortpoly)
5163    IF (ALLOCATED(poly)) DEALLOCATE(poly)
5164
5165  END SUBROUTINE grid_spacepercen_within_reg_providing_polys
5166
5167  SUBROUTINE spacepercen(xCAvals, yCAvals, xBAvals, yBAvals, xCBvals, yCBvals, xBBvals, yBBvals,      &
5168    dxA, dyA, NAvertexmax, dxB, dyB, dxyB, NBvertexmax, strict, Ngridsin, gridsin, areas, percentages)
5169  ! Subroutine to compute the space-percentages of a series of grid cells (B) into another series of
5170  !   grid-cells (A)
5171  ! NOTE: Assuming coordinates on the plane with rectilinar, distance preserved and perpendicular x
5172  !   and y axes.
5173
5174    IMPLICIT NONE
5175
5176    INTEGER, INTENT(in)                                  :: dxA, dyA, NAvertexmax
5177    INTEGER, INTENT(in)                                  :: dxB, dyB, NBvertexmax, dxyB
5178    REAL(r_k), DIMENSION(dxA,dyA), INTENT(in)            :: xCAvals, yCAvals
5179    REAL(r_k), DIMENSION(dxB,dyB), INTENT(in)            :: xCBvals, yCBvals
5180    REAL(r_k), DIMENSION(dxA,dyA,NAvertexmax), INTENT(in):: xBAvals, yBAvals
5181    REAL(r_k), DIMENSION(dxB,dyB,NBvertexmax), INTENT(in):: xBBvals, yBBvals
5182    LOGICAL, INTENT(in)                                  :: strict
5183    INTEGER, DIMENSION(dxA,dyA), INTENT(out)             :: Ngridsin
5184    INTEGER, DIMENSION(dxA,dyA,dxyB,2), INTENT(out)      :: gridsin
5185    REAL(r_k), DIMENSION(dxA,dyA), INTENT(out)           :: areas
5186    REAL(r_k), DIMENSION(dxA,dyA,dxyB), INTENT(out)      :: percentages
5187
5188! Local
5189   INTEGER                                               :: iv, ix, iy
5190   INTEGER                                               :: Nvertex
5191   INTEGER, ALLOCATABLE, DIMENSION(:,:)                  :: poinsin
5192   CHARACTER(len=20)                                     :: IS
5193   REAL(r_k), ALLOCATABLE, DIMENSION(:,:)                :: vertexgrid
5194
5195!!!!!!! Variables
5196! dxA, dyA: shape of the matrix with the grid points A
5197! xCAvals, yCAvals: coordinates of the center of the grid cells A
5198! NAvertexmax: Maximum number of vertices of the grid cells A
5199! xBAvals, yBAvals: coordinates of th vertices of the grid cells A (-99999 for no vertex)
5200! dxB, dyB: shape of the matrix with the grid points B
5201! xCBvals, yCBvals: coordinates of the center of the grid cells B
5202! NBvertexmax: Maximum number of vertices of the grid cells B
5203! xBBvals, yBBvals: coordinates of th vertices of the grid cells B (-99999 for no vertex)
5204! strict: give an error if the area of the polygon is not fully covered
5205! Ngridsin: number of grids from grid B with some extension within the grid cell A
5206! gridsin: indices of B grids within the grids of A
5207! areas: areas of the polygons
5208! percentages: percentages of area of cells B of each of the grids within the grid cell A
5209
5210    fname = 'spacepercen'
5211
5212    DO ix = 1, dxA
5213      DO iy = 1, dyA
5214
5215        ! Getting grid vertices
5216        Nvertex = 0
5217        DO iv=1, NAvertexmax
5218          IF (xBAvals(ix,iy,iv) /= fillval64) THEN
5219           Nvertex = Nvertex + 1
5220          END IF
5221        END DO
5222        IF (ALLOCATED(vertexgrid)) DEALLOCATE(vertexgrid)
5223        ALLOCATE(vertexgrid(Nvertex,2))
5224        vertexgrid(:,1) = xBAvals(ix,iy,1:Nvertex)
5225        vertexgrid(:,2) = yBAvals(ix,iy,1:Nvertex)
5226 
5227        CALL grid_within_polygon(Nvertex, vertexgrid, dxB, dyB, dxB*dyB, xCBvals, yCBvals,            &
5228          NBvertexmax, xBBvals, yBBvals, Ngridsin(ix,iy), gridsin(ix,iy,:,:))
5229   
5230        IF (ALLOCATED(poinsin)) DEALLOCATE(poinsin)
5231        ALLOCATE(poinsin(Ngridsin(ix,iy),2))
5232
5233        DO iv=1, Ngridsin(ix,iy)
5234          poinsin(iv,1) = gridsin(ix,iy,iv,1)
5235          poinsin(iv,2) = gridsin(ix,iy,iv,2)
5236        END DO
5237
5238        areas(ix,iy) = shoelace_area_polygon(Nvertex, vertexgrid)
5239        CALL spacepercen_within_reg(Nvertex, vertexgrid, dxB, dyB, NBvertexmax, xBBvals, yBBvals,     &
5240          Ngridsin(ix,iy), poinsin, strict, percentages(ix,iy,:))
5241
5242      END DO
5243    END DO
5244
5245    IF (ALLOCATED(vertexgrid)) DEALLOCATE(vertexgrid)
5246    IF (ALLOCATED(poinsin)) DEALLOCATE(poinsin)
5247
5248  END SUBROUTINE spacepercen
5249
5250  SUBROUTINE grid_spacepercen(xCAvals, yCAvals, xBAvals, yBAvals, xCBvals, yCBvals, xBBvals, yBBvals, &
5251    dxA, dyA, NAvertexmax, dxB, dyB, dxyB, NBvertexmax, strict, Ngridsin, gridsin,  areas2D, areas,   &
5252    percentages)
5253  ! Subroutine to compute the space-percentages of a series of grid cells (B) which lay inside another
5254  !   series of grid-cells (A) porviding coincident polygons
5255  ! NOTE: Assuming coordinates on the plane with rectilinar, distance preserved and perpendicular x
5256  !   and y axes.
5257
5258    IMPLICIT NONE
5259
5260    INTEGER, INTENT(in)                                  :: dxA, dyA, NAvertexmax
5261    INTEGER, INTENT(in)                                  :: dxB, dyB, NBvertexmax, dxyB
5262    REAL(r_k), DIMENSION(dxA,dyA), INTENT(in)            :: xCAvals, yCAvals
5263    REAL(r_k), DIMENSION(dxB,dyB), INTENT(in)            :: xCBvals, yCBvals
5264    REAL(r_k), DIMENSION(dxA,dyA,NAvertexmax), INTENT(in):: xBAvals, yBAvals
5265    REAL(r_k), DIMENSION(dxB,dyB,NBvertexmax), INTENT(in):: xBBvals, yBBvals
5266    LOGICAL, INTENT(in)                                  :: strict
5267    INTEGER, DIMENSION(dxA,dyA), INTENT(out)             :: Ngridsin
5268    INTEGER, DIMENSION(dxA,dyA,dxyB,2), INTENT(out)      :: gridsin
5269    REAL(r_k), DIMENSION(dxB,dyB), INTENT(out)           :: areas2D
5270    REAL(r_k), DIMENSION(dxA,dyA,dxyB), INTENT(out)      :: areas,percentages
5271
5272! Local
5273   INTEGER                                               :: iv, ix, iy
5274   INTEGER                                               :: Nvertex, Nptin
5275   INTEGER, ALLOCATABLE, DIMENSION(:,:)                  :: poinsin
5276   CHARACTER(len=20)                                     :: IS
5277   REAL(r_k), ALLOCATABLE, DIMENSION(:,:)                :: vertexgrid
5278
5279!!!!!!! Variables
5280! dxA, dyA: shape of the matrix with the grid points A
5281! xCAvals, yCAvals: coordinates of the center of the grid cells A
5282! NAvertexmax: Maximum number of vertices of the grid cells A
5283! xBAvals, yBAvals: coordinates of th vertices of the grid cells A (-99999 for no vertex)
5284! dxB, dyB: shape of the matrix with the grid points B
5285! xCBvals, yCBvals: coordinates of the center of the grid cells B
5286! NBvertexmax: Maximum number of vertices of the grid cells B
5287! xBBvals, yBBvals: coordinates of th vertices of the grid cells B (-99999 for no vertex)
5288! strict: give an error if the area of the polygon is not fully covered
5289! Ngridsin: number of grids from grid B with some extension within the grid cell A
5290! gridsin: indices of B grids within the grids of A
5291! areas2D: areas of the grids as 2D matrix in the original shape
5292! areas: areas of cells B of each of the grids inside the grid cell A
5293! percentages: percentages of area of cells B of each of the grids inside the grid cell A
5294
5295    fname = 'grid_spacepercen'
5296
5297    areas2D = zeroRK
5298    areas = zeroRK
5299    percentages = zeroRK
5300
5301    DO ix = 1, dxA
5302      DO iy = 1, dyA
5303
5304        ! Getting grid vertices
5305        Nvertex = 0
5306        DO iv=1, NAvertexmax
5307          IF (xBAvals(ix,iy,iv) /= fillval64) THEN
5308           Nvertex = Nvertex + 1
5309          END IF
5310        END DO
5311        IF (ALLOCATED(vertexgrid)) DEALLOCATE(vertexgrid)
5312        ALLOCATE(vertexgrid(Nvertex,2))
5313        vertexgrid(:,1) = xBAvals(ix,iy,1:Nvertex)
5314        vertexgrid(:,2) = yBAvals(ix,iy,1:Nvertex)
5315 
5316        CALL grid_within_polygon(Nvertex, vertexgrid, dxB, dyB, dxB*dyB, xCBvals, yCBvals,            &
5317          NBvertexmax, xBBvals, yBBvals, Ngridsin(ix,iy), gridsin(ix,iy,1:dxyB,:))
5318   
5319        IF (ALLOCATED(poinsin)) DEALLOCATE(poinsin)
5320        ALLOCATE(poinsin(Ngridsin(ix,iy),2))
5321
5322        DO iv=1, Ngridsin(ix,iy)
5323          poinsin(iv,1) = gridsin(ix,iy,iv,1)
5324          poinsin(iv,2) = gridsin(ix,iy,iv,2)
5325        END DO
5326
5327        Nptin = Ngridsin(ix,iy)
5328        CALL grid_spacepercen_within_reg(Nvertex, vertexgrid, dxB, dyB, NBvertexmax, xBBvals,        &
5329          yBBvals, Ngridsin(ix,iy), poinsin, strict, areas(ix,iy,1:Nptin), percentages(ix,iy,1:Nptin))
5330
5331        ! Filling areas
5332        DO iv = 1, Ngridsin(ix,iy)
5333          IF (areas2D(poinsin(iv,1), poinsin(iv,2)) == zeroRK) THEN
5334            areas2D(poinsin(iv,1), poinsin(iv,2)) = areas(ix,iy,iv)
5335          END IF
5336        END DO
5337
5338      END DO
5339    END DO
5340
5341    IF (ALLOCATED(vertexgrid)) DEALLOCATE(vertexgrid)
5342    IF (ALLOCATED(poinsin)) DEALLOCATE(poinsin)
5343
5344  END SUBROUTINE grid_spacepercen
5345
5346  SUBROUTINE grid_spacepercen_providing_polys(xCAvals, yCAvals, xBAvals, yBAvals, xCBvals, yCBvals,   &
5347    xBBvals, yBBvals, dxA, dyA, NAvertexmax, dxB, dyB, dxyB, NBvertexmax, strict, Nmaxvercoin,        &
5348    Nvercoinpolys, vercoinpolys, Ngridsin, gridsin,  areas, percentages)
5349  ! Subroutine to compute the space-percentages of a series of grid cells (B) which lay inside another
5350  !   series of grid-cells (A) providing coincident polygons
5351  ! NOTE: Assuming coordinates on the plane with rectilinar, distance preserved and perpendicular x
5352  !   and y axes.
5353
5354    IMPLICIT NONE
5355
5356    INTEGER, INTENT(in)                                  :: dxA, dyA, NAvertexmax
5357    INTEGER, INTENT(in)                                  :: dxB, dyB, NBvertexmax, dxyB
5358    INTEGER, INTENT(in)                                  :: Nmaxvercoin
5359    REAL(r_k), DIMENSION(dxA,dyA), INTENT(in)            :: xCAvals, yCAvals
5360    REAL(r_k), DIMENSION(dxB,dyB), INTENT(in)            :: xCBvals, yCBvals
5361    REAL(r_k), DIMENSION(dxA,dyA,NAvertexmax), INTENT(in):: xBAvals, yBAvals
5362    REAL(r_k), DIMENSION(dxB,dyB,NBvertexmax), INTENT(in):: xBBvals, yBBvals
5363    LOGICAL, INTENT(in)                                  :: strict
5364    INTEGER, DIMENSION(dxA,dyA,dxyB,Nmaxvercoin),                                                     &
5365      INTENT(out)                                        :: Nvercoinpolys
5366    REAL(r_k), DIMENSION(dxA,dyA,dxyB,Nmaxvercoin,2),                                                 &
5367      INTENT(out)                                        :: vercoinpolys
5368    INTEGER, DIMENSION(dxA,dyA), INTENT(out)             :: Ngridsin
5369    INTEGER, DIMENSION(dxA,dyA,dxyB,2), INTENT(out)      :: gridsin
5370    REAL(r_k), DIMENSION(dxB,dyB), INTENT(out)           :: areas
5371    REAL(r_k), DIMENSION(dxA,dyA,dxyB), INTENT(out)      :: percentages
5372
5373! Local
5374   INTEGER                                               :: iv, ix, iy
5375   INTEGER                                               :: Nvertex
5376   INTEGER, ALLOCATABLE, DIMENSION(:,:)                  :: poinsin
5377   CHARACTER(len=20)                                     :: IS
5378   REAL(r_k), ALLOCATABLE, DIMENSION(:)                  :: pareas
5379   REAL(r_k), ALLOCATABLE, DIMENSION(:,:)                :: vertexgrid
5380
5381!!!!!!! Variables
5382! dxA, dyA: shape of the matrix with the grid points A
5383! xCAvals, yCAvals: coordinates of the center of the grid cells A
5384! NAvertexmax: Maximum number of vertices of the grid cells A
5385! xBAvals, yBAvals: coordinates of th vertices of the grid cells A (-99999 for no vertex)
5386! dxB, dyB: shape of the matrix with the grid points B
5387! xCBvals, yCBvals: coordinates of the center of the grid cells B
5388! NBvertexmax: Maximum number of vertices of the grid cells B
5389! xBBvals, yBBvals: coordinates of th vertices of the grid cells B (-99999 for no vertex)
5390! strict: give an error if the area of the polygon is not fully covered
5391! Nvercoinpolys: number of vertices of the coincident polygon of each grid
5392! coinpolys: of vertices of the coincident polygon of each grid
5393! Ngridsin: number of grids from grid B with some extension within the grid cell A
5394! gridsin: indices of B grids within the grids of A
5395! areas: areas of the grids
5396! percentages: percentages of area of cells B of each of the grids inside the grid cell A
5397
5398    fname = 'grid_spacepercen_providing_polys'
5399
5400    areas = zeroRK
5401
5402    DO ix = 1, dxA
5403      DO iy = 1, dyA
5404
5405        ! Getting grid vertices
5406        Nvertex = 0
5407        DO iv=1, NAvertexmax
5408          IF (xBAvals(ix,iy,iv) /= fillval64) THEN
5409           Nvertex = Nvertex + 1
5410          END IF
5411        END DO
5412        IF (ALLOCATED(vertexgrid)) DEALLOCATE(vertexgrid)
5413        ALLOCATE(vertexgrid(Nvertex,2))
5414        vertexgrid(:,1) = xBAvals(ix,iy,1:Nvertex)
5415        vertexgrid(:,2) = yBAvals(ix,iy,1:Nvertex)
5416 
5417        CALL grid_within_polygon(Nvertex, vertexgrid, dxB, dyB, dxB*dyB, xCBvals, yCBvals,            &
5418          NBvertexmax, xBBvals, yBBvals, Ngridsin(ix,iy), gridsin(ix,iy,:,:))
5419   
5420        IF (ALLOCATED(poinsin)) DEALLOCATE(poinsin)
5421        ALLOCATE(poinsin(Ngridsin(ix,iy),2))
5422        IF (ALLOCATED(pareas)) DEALLOCATE(pareas)
5423        ALLOCATE(pareas(Ngridsin(ix,iy)))
5424
5425        DO iv=1, Ngridsin(ix,iy)
5426          poinsin(iv,1) = gridsin(ix,iy,iv,1)
5427          poinsin(iv,2) = gridsin(ix,iy,iv,2)
5428        END DO
5429
5430        CALL grid_spacepercen_within_reg_providing_polys(Nvertex, vertexgrid, dxB, dyB, NBvertexmax, &
5431          xBBvals, yBBvals, Ngridsin(ix,iy), poinsin, strict, Nmaxvercoin, Nvercoinpolys(ix,iy,:,:), &
5432          vercoinpolys(ix,iy,:,:,:), pareas, percentages(ix,iy,:))
5433
5434        ! Filling areas
5435        DO iv = 1, Ngridsin(ix,iy)
5436          IF (areas(poinsin(iv,1), poinsin(iv,2)) == zeroRK) THEN
5437            areas(poinsin(iv,1), poinsin(iv,2)) = pareas(iv)
5438          END IF
5439        END DO
5440
5441      END DO
5442    END DO
5443
5444    IF (ALLOCATED(vertexgrid)) DEALLOCATE(vertexgrid)
5445    IF (ALLOCATED(pareas)) DEALLOCATE(pareas)
5446    IF (ALLOCATED(poinsin)) DEALLOCATE(poinsin)
5447
5448  END SUBROUTINE grid_spacepercen_providing_polys
5449
5450  SUBROUTINE unique_matrixRK2D(dx, dy, dxy, matrix2D, Nunique, unique)
5451  ! Subroutine to provide the unique values within a 2D RK matrix
5452
5453    IMPLICIT NONE
5454
5455    INTEGER, INTENT(in)                                  :: dx, dy, dxy
5456    REAL(r_k), DIMENSION(dx,dy), INTENT(in)              :: matrix2D
5457    INTEGER, INTENT(out)                                 :: Nunique
5458    REAL(r_k), DIMENSION(dxy), INTENT(out)               :: unique
5459
5460! Local
5461    INTEGER                                              :: ix, iy, iu, minvalv
5462    LOGICAL                                              :: single
5463    REAL(r_k), ALLOCATABLE, DIMENSION(:)                 :: uniques
5464
5465
5466!!!!!!! Variables
5467! dx, dy: dimensions of the matrix
5468! dxy: dx*dy, maximum possible amount of different values
5469! matrix2D: matgrix of values
5470! Nunique: amount of unique values
5471! unique: sorted from minimum to maximum vector with the unique values
5472
5473    fname = 'unique_matrixRK2D'
5474
5475    minvalv = MINVAL(matrix2D)
5476
5477    Nunique = 1
5478    unique(1) = minvalv
5479    DO ix= 1, dx
5480      DO iy= 1, dy
5481        single = .TRUE.
5482        DO iu = 1, Nunique
5483          IF (matrix2D(ix,iy) == unique(iu)) THEN
5484            single = .FALSE.
5485            EXIT
5486          END IF
5487        END DO
5488        IF (single) THEN
5489          Nunique = Nunique + 1
5490          unique(Nunique) = matrix2D(ix,iy)
5491        END IF
5492      END DO
5493    END DO
5494    IF (ALLOCATED(uniques)) DEALLOCATE(uniques)
5495    ALLOCATE(uniques(Nunique))
5496    uniques(1:Nunique) = unique(1:Nunique)
5497   
5498    CALL sortR_K(uniques(1:Nunique), Nunique)
5499    unique(1:Nunique) = uniques(1:Nunique)
5500
5501  END SUBROUTINE unique_matrixRK2D
5502
5503  SUBROUTINE spaceweightstats(varin, Ngridsin, gridsin, percentages, stats, varout, dxA, dyA, dxB,    &
5504    dyB, maxNgridsin, Lstats)
5505  ! Subroutine to compute an spatial statistics value from a matrix B into a matrix A using weights
5506
5507    IMPLICIT NONE
5508
5509    INTEGER, INTENT(in)                                  :: dxA, dyA, dxB, dyB, maxNgridsin, Lstats
5510    CHARACTER(len=*), INTENT(in)                         :: stats
5511    INTEGER, DIMENSION(dxA,dyA), INTENT(in)              :: Ngridsin
5512    INTEGER, DIMENSION(dxA,dyA,maxNgridsin,2), INTENT(in):: gridsin
5513    REAL(r_k), DIMENSION(dxB,dyB), INTENT(in)            :: varin
5514    REAL(r_k), DIMENSION(dxA,dyA,maxNgridsin), INTENT(in):: percentages
5515    REAL(r_k), DIMENSION(dxA,dyA,Lstats), INTENT(out)    :: varout
5516
5517! Local
5518    INTEGER                                              :: ix, iy, iv, ic, iu, ii, jj
5519    INTEGER                                              :: Ncounts
5520    CHARACTER(len=3)                                     :: val1S, val2S
5521    CHARACTER(len=30)                                    :: val3S
5522    REAL(r_k)                                            :: val1, val2
5523    REAL(r_k), DIMENSION(Lstats)                         :: icounts
5524
5525!!!!!!! Variables
5526! dxA, dyA: length of dimensions of matrix A
5527! dxB, dyB: length of dimensions of matrix B
5528! maxNgridsin: maximum number of grid points from B to be used to compute into a grid of matrix A
5529! Lstats: length of the dimension of the statistics
5530! varin: variable from matrix B to be used
5531! Ngridsin: number of grids from matrix B for each grid of matrix A
5532! gridsin: coordinates of grids of matrix B for each grid of matrix A
5533! percentages: weights as percentages of space of grid in matrix A covered by grid of matrix B
5534! stats: name of the spatial statistics to compute inside each grid of matrix A using values from
5535!     matrix B. Avaialbe ones:
5536!   'min': minimum value
5537!   'max': maximum value
5538!   'mean': space weighted mean value
5539!   'mean2': space weighted quadratic mean value
5540!   'stddev': space weighted standard deviation value
5541!   'count': percentage of the space of matrix A covered by each different value of matrix B
5542! varout: output statistical variable
5543
5544    fname = 'spaceweightstats'
5545
5546    ! Let's be efficvient?
5547    statn: SELECT CASE(TRIM(stats))
5548      CASE('min')
5549        varout = fillVal64
5550        DO ix=1, dxA
5551          DO iy=1, dyA
5552            DO iv=1, Ngridsin(ix,iy)
5553              ii = gridsin(ix,iy,iv,1)
5554              jj = gridsin(ix,iy,iv,2)
5555              IF (varin(ii,jj) < varout(ix,iy,Lstats)) varout(ix,iy,1) = varin(ii,jj)
5556            END DO
5557          END DO
5558        END DO
5559      CASE('max')
5560        varout = -fillVal64
5561        DO ix=1, dxA
5562          DO iy=1, dyA
5563            DO iv=1, Ngridsin(ix,iy)
5564              ii = gridsin(ix,iy,iv,1)
5565              jj = gridsin(ix,iy,iv,2)
5566              IF (varin(ii,jj) > varout(ix,iy,Lstats)) varout(ix,iy,1) = varin(ii,jj)
5567            END DO
5568          END DO
5569        END DO
5570      CASE('mean')
5571        varout = zeroRK
5572        DO ix=1, dxA
5573          DO iy=1, dyA
5574            DO iv=1, Ngridsin(ix,iy)
5575              ii = gridsin(ix,iy,iv,1)
5576              jj = gridsin(ix,iy,iv,2)
5577              varout(ix,iy,1) = varout(ix,iy,1) + varin(ii,jj)*percentages(ix,iy,iv)
5578            END DO
5579          END DO
5580        END DO
5581      CASE('mean2')
5582        varout = zeroRK
5583        DO ix=1, dxA
5584          DO iy=1, dyA
5585            DO iv=1, Ngridsin(ix,iy)
5586              ii = gridsin(ix,iy,iv,1)
5587              jj = gridsin(ix,iy,iv,2)
5588              varout(ix,iy,1) = varout(ix,iy,1) + percentages(ix,iy,iv)*(varin(ii,jj))**2
5589            END DO
5590            varout(ix,iy,1) = varout(ix,iy,1) / Ngridsin(ix,iy)
5591          END DO
5592        END DO
5593      CASE('stddev')
5594        varout = zeroRK
5595        DO ix=1, dxA
5596          DO iy=1, dyA
5597            val1 = zeroRK
5598            val2 = zeroRK
5599            DO iv=1, Ngridsin(ix,iy)
5600              ii = gridsin(ix,iy,iv,1)
5601              jj = gridsin(ix,iy,iv,2)
5602              val1 = val1 + varin(ii,jj)*percentages(ix,iy,iv)
5603              val2 = val2 + percentages(ix,iy,iv)*(varin(ii,jj))**2
5604            END DO
5605            varout(ix,iy,1) = SQRT(val2 - val1**2)
5606          END DO
5607        END DO
5608      CASE('count')
5609        CALL unique_matrixRK2D(dxB, dyB, dxB*dyB, varin, Ncounts, icounts)
5610        IF (Lstats /= Ncounts) THEN
5611          PRINT *,'  ' // TRIM(fname) // 'provided:', Lstats
5612          PRINT *,'  ' // TRIM(fname) // 'found:', Ncounts, ' :', icounts
5613          WRITE(val1S,'(I3)')Lstats
5614          WRITE(val2S,'(I3)')Ncounts
5615          msg = "for 'count' different amount of passed categories: " // TRIM(val1S) //               &
5616            ' and found ' // TRIM(val2S)
5617          CALL ErrMsg(msg, fname, -1)
5618        END IF
5619        varout = zeroRK
5620        DO ix=1, dxA
5621          DO iy=1, dyA
5622            DO iv=1, Ngridsin(ix,iy)
5623              ii = gridsin(ix,iy,iv,1)
5624              jj = gridsin(ix,iy,iv,2)
5625              ic = Index1DArrayR_K(icounts, Ncounts, varin(ii,jj))
5626              IF (ic == -1) THEN
5627                WRITE(val3S,'(f30.20)')varin(ii,jj)
5628                msg = "value '" // val3S // "' for 'count' not found"
5629                CALL ErrMSg(msg, fname, -1)
5630              ELSE
5631                varout(ix,iy,ic) = varout(ix,iy,ic) + percentages(ix,iy,iv)
5632              END IF
5633            END DO
5634          END DO
5635        END DO
5636      CASE DEFAULT
5637        msg = "statisitcs '" // TRIM(stats) // "' not ready !!" // CHAR(44) // " available ones: " // &
5638          "'min', 'max', 'mean', 'mean2', 'stddev', 'count'"
5639        CALL ErrMsg(msg, fname, -1)
5640    END SELECT statn
5641
5642  END SUBROUTINE spaceweightstats
5643
5644  SUBROUTINE multi_spaceweightstats_in1DRKno_slc3v3(varin, idv, Ngridsin, gridsin, percentages,       &
5645    varout, di1, ds1, ds2, ds3, maxNgridsin)
5646  ! Subroutine to compute an spatial statistics value from a 1D RK matrix without running one into a
5647  !   matrix of 3-variables slices of rank 3 using spatial weights
5648
5649    IMPLICIT NONE
5650
5651    INTEGER, INTENT(in)                                  :: di1, idv, ds1, ds2, ds3
5652    INTEGER, INTENT(in)                                  :: maxNgridsin
5653    INTEGER, DIMENSION(ds1,ds2,ds3), INTENT(in)          :: Ngridsin
5654    INTEGER, DIMENSION(ds1,ds2,ds3,maxNgridsin,2),                                                    &
5655      INTENT(in)                                         :: gridsin
5656    REAL(r_k), DIMENSION(di1), INTENT(in)                :: varin
5657    REAL(r_k), INTENT(in),                                                                            &
5658      DIMENSION(ds1,ds2,ds3,maxNgridsin)                 :: percentages
5659    REAL(r_k), DIMENSION(ds1,ds2,ds3,7), INTENT(out)     :: varout
5660
5661! Local
5662    INTEGER                                              :: i1, i2, i3, s1, s2, s3, iv
5663    INTEGER                                              :: ii3, ss1, ss2, ss3
5664    INTEGER                                              :: Ncounts, Nin
5665    INTEGER, DIMENSION(1)                                :: dmaxvarin
5666    CHARACTER(len=3)                                     :: val1S, val2S
5667    CHARACTER(len=30)                                    :: val3S
5668    REAL(r_k)                                            :: minv, maxv, meanv, mean2v, stdv, medv
5669    REAL(r_k), DIMENSION(:), ALLOCATABLE                 :: pin
5670    INTEGER, DIMENSION(:,:), ALLOCATABLE                 :: gin
5671    REAL(r_k), DIMENSION(:), ALLOCATABLE                 :: svin
5672    REAL(r_k), DIMENSION(:), ALLOCATABLE                 :: vin
5673
5674!!!!!!! Variables
5675! di1: length of dimensions of the 1D matrix of values
5676! ds[1-3]: length of dimensions of matrix with the slices
5677! maxNgridsin: maximum number of grid points from the 3D matrix in any slice
5678! varin: 1D RK variable to be used
5679! idv: which dimension of the sliced grids coincide with the dimension of 1D varin
5680! Ngridsin: number of grids from 3D RK matrix for each slice
5681! gridsin: coordinates of grids of the 3D RK matrix B to matrix of slices
5682! percentages: weights as percentages of space of 3D RK matrix for each slice
5683!!!!!
5684! Available spatial statistics to compute inside each slice using values from 3D RK matrix
5685!   'min': minimum value
5686!   'max': maximum value
5687!   'mean': space weighted mean value
5688!   'mean2': space weighted quadratic mean value
5689!   'stddev': space weighted standard deviation value
5690!   'median': median value
5691!   'count': percentage of the space of matrix A covered by each different value of matrix B
5692! varout: output statistical variable
5693
5694    fname = 'multi_spaceweightstats_in1DRKno_slc3v3'
5695
5696    varout = fillval64
5697
5698    ss1 = 8 + 1
5699    ss2 = 5 + 1
5700    ss3 = 3 + 1
5701    ii3 = 1 + 1
5702
5703    dmaxvarin = UBOUND(varin)
5704
5705    ! Let's be efficient?
5706    varout = fillVal64
5707    DO s1 =1, ds1
5708      DO s2 =1, ds2
5709        DO s3 =1, ds3
5710          Nin = Ngridsin(s1,s2,s3)
5711          ! Computing along d3
5712          IF (Nin > 1) THEN
5713            IF (ALLOCATED(gin)) DEALLOCATE(gin)
5714            ALLOCATE(gin(Nin,2))
5715            IF (ALLOCATED(pin)) DEALLOCATE(pin)
5716            ALLOCATE(pin(Nin))
5717            IF (ALLOCATED(vin)) DEALLOCATE(vin)
5718            ALLOCATE(vin(Nin))
5719            IF (ALLOCATED(svin)) DEALLOCATE(svin)
5720            ALLOCATE(svin(Nin))
5721            gin = gridsin(s1,s2,s3,1:Nin,:)
5722            pin = percentages(s1,s2,s3,1:Nin)
5723
5724            ! Getting the values
5725            DO iv=1, Nin
5726              i1 = gin(iv,idv)
5727              vin(iv) = varin(i1)
5728            END DO
5729            minv = fillVal64
5730            maxv = -fillVal64
5731            meanv = zeroRK
5732            mean2v = zeroRK
5733            stdv = zeroRK
5734            minv = MINVAL(vin)
5735            maxv = MAXVAL(vin)
5736            meanv = SUM(vin*pin)
5737            mean2v = SUM(vin**2*pin)
5738            DO iv=1,Nin
5739              stdv = stdv + ( (meanv - vin(iv))*pin(iv) )**2
5740            END DO
5741            stdv = SQRT(stdv)
5742            svin = vin(:)
5743            CALL SortR_K(svin, Nin)
5744            medv = svin(INT(Nin/2))
5745            varout(s1,s2,s3,1) = minv
5746            varout(s1,s2,s3,2) = maxv
5747            varout(s1,s2,s3,3) = meanv
5748            varout(s1,s2,s3,4) = mean2v
5749            varout(s1,s2,s3,5) = stdv
5750            varout(s1,s2,s3,6) = medv
5751            varout(s1,s2,s3,7) = Nin*1.
5752          ELSE
5753            i1 = gridsin(s1,s2,s3,1,idv)
5754            IF (i1 > 0 .AND. i1 <= dmaxvarin(1)) THEN
5755              varout(s1,s2,s3,1) = varin(i1)
5756              varout(s1,s2,s3,2) = varin(i1)
5757              varout(s1,s2,s3,3) = varin(i1)
5758              varout(s1,s2,s3,4) = varin(i1)*varin(i1)
5759              varout(s1,s2,s3,5) = zeroRK
5760              varout(s1,s2,s3,6) = varin(i1)
5761              varout(s1,s2,s3,7) = Nin*1.
5762            END IF
5763          END IF
5764        END DO
5765      END DO
5766    END DO
5767
5768    IF (ALLOCATED(gin)) DEALLOCATE(gin)
5769    IF (ALLOCATED(pin)) DEALLOCATE(pin)
5770    IF (ALLOCATED(vin)) DEALLOCATE(vin)
5771    IF (ALLOCATED(svin)) DEALLOCATE(svin)
5772   
5773    RETURN
5774
5775  END SUBROUTINE multi_spaceweightstats_in1DRKno_slc3v3
5776
5777  SUBROUTINE multi_spaceweightstats_in2DRKno_slc3v3(varin, Ngridsin, gridsin, percentages, varout,     &
5778    di1, di2, ds1, ds2, ds3, maxNgridsin)
5779  ! Subroutine to compute an spatial statistics value from a 2D RK matrix without running one into a
5780  !   matrix of 3-variables slices of rank 3 using spatial weights
5781
5782    IMPLICIT NONE
5783
5784    INTEGER, INTENT(in)                                  :: di1, di2, ds1, ds2, ds3
5785    INTEGER, INTENT(in)                                  :: maxNgridsin
5786    INTEGER, DIMENSION(ds1,ds2,ds3), INTENT(in)          :: Ngridsin
5787    INTEGER, DIMENSION(ds1,ds2,ds3,maxNgridsin,2),                                                    &
5788      INTENT(in)                                         :: gridsin
5789    REAL(r_k), DIMENSION(di1,di2), INTENT(in)            :: varin
5790    REAL(r_k), INTENT(in),                                                                            &
5791      DIMENSION(ds1,ds2,ds3,maxNgridsin)                 :: percentages
5792    REAL(r_k), DIMENSION(ds1,ds2,ds3,7), INTENT(out)     :: varout
5793
5794! Local
5795    INTEGER                                              :: i1, i2, i3, s1, s2, s3, iv
5796    INTEGER                                              :: ii3, ss1, ss2, ss3
5797    INTEGER                                              :: Ncounts, Nin
5798    CHARACTER(len=3)                                     :: val1S, val2S
5799    CHARACTER(len=30)                                    :: val3S
5800    REAL(r_k)                                            :: minv, maxv, meanv, mean2v, stdv, medv
5801    REAL(r_k), DIMENSION(:), ALLOCATABLE                 :: pin
5802    INTEGER, DIMENSION(:,:), ALLOCATABLE                 :: gin
5803    REAL(r_k), DIMENSION(:), ALLOCATABLE                 :: svin
5804    REAL(r_k), DIMENSION(:), ALLOCATABLE                 :: vin
5805
5806!!!!!!! Variables
5807! di1, di2: length of dimensions of the 2D matrix of values
5808! ds[1-3]: length of dimensions of matrix with the slices
5809! maxNgridsin: maximum number of grid points from the 3D matrix in any slice
5810! varin: 2D RK variable to be used
5811! Ngridsin: number of grids from 3D RK matrix for each slice
5812! gridsin: coordinates of grids of the 3D RK matrix B to matrix of slices
5813! percentages: weights as percentages of space of 3D RK matrix for each slice
5814!!!!!
5815! Available spatial statistics to compute inside each slice using values from 3D RK matrix
5816!   'min': minimum value
5817!   'max': maximum value
5818!   'mean': space weighted mean value
5819!   'mean2': space weighted quadratic mean value
5820!   'stddev': space weighted standard deviation value
5821!   'median': median value
5822!   'count': percentage of the space of matrix A covered by each different value of matrix B
5823! varout: output statistical variable
5824
5825    fname = 'multi_spaceweightstats_in2DRKno_slc3v3'
5826
5827    varout = fillval64
5828
5829    ss1 = 8 + 1
5830    ss2 = 5 + 1
5831    ss3 = 3 + 1
5832    ii3 = 1 + 1
5833
5834    ! Let's be efficient?
5835    varout = fillVal64
5836    DO s1 =1, ds1
5837      DO s2 =1, ds2
5838        DO s3 =1, ds3
5839          Nin = Ngridsin(s1,s2,s3)
5840          ! Computing along d3
5841          IF (Nin > 1) THEN
5842            IF (ALLOCATED(gin)) DEALLOCATE(gin)
5843            ALLOCATE(gin(Nin,2))
5844            IF (ALLOCATED(pin)) DEALLOCATE(pin)
5845            ALLOCATE(pin(Nin))
5846            IF (ALLOCATED(vin)) DEALLOCATE(vin)
5847            ALLOCATE(vin(Nin))
5848            IF (ALLOCATED(svin)) DEALLOCATE(svin)
5849            ALLOCATE(svin(Nin))
5850            gin = gridsin(s1,s2,s3,1:Nin,:)
5851            pin = percentages(s1,s2,s3,1:Nin)
5852
5853            ! Getting the values
5854            DO iv=1, Nin
5855              i1 = gin(iv,1)
5856              i2 = gin(iv,2)
5857              vin(iv) = varin(i1,i2)
5858            END DO
5859            minv = fillVal64
5860            maxv = -fillVal64
5861            meanv = zeroRK
5862            mean2v = zeroRK
5863            stdv = zeroRK
5864            minv = MINVAL(vin)
5865            maxv = MAXVAL(vin)
5866            meanv = SUM(vin*pin)
5867            mean2v = SUM(vin**2*pin)
5868            DO iv=1,Nin
5869              stdv = stdv + ( (meanv - vin(iv))*pin(iv) )**2
5870            END DO
5871            stdv = SQRT(stdv)
5872            svin = vin(:)
5873            CALL SortR_K(svin, Nin)
5874            medv = svin(INT(Nin/2))
5875            varout(s1,s2,s3,1) = minv
5876            varout(s1,s2,s3,2) = maxv
5877            varout(s1,s2,s3,3) = meanv
5878            varout(s1,s2,s3,4) = mean2v
5879            varout(s1,s2,s3,5) = stdv
5880            varout(s1,s2,s3,6) = medv
5881            varout(s1,s2,s3,7) = Nin*1.
5882          ELSE
5883            i1 = gridsin(s1,s2,s3,1,1)
5884            i2 = gridsin(s1,s2,s3,1,2)
5885            varout(s1,s2,s3,1) = varin(i1,i2)
5886            varout(s1,s2,s3,2) = varin(i1,i2)
5887            varout(s1,s2,s3,3) = varin(i1,i2)
5888            varout(s1,s2,s3,4) = varin(i1,i2)*varin(i1,i2)
5889            varout(s1,s2,s3,5) = zeroRK
5890            varout(s1,s2,s3,6) = varin(i1,i2)
5891            varout(s1,s2,s3,7) = Nin*1.
5892          END IF
5893        END DO
5894      END DO
5895    END DO
5896
5897    IF (ALLOCATED(gin)) DEALLOCATE(gin)
5898    IF (ALLOCATED(pin)) DEALLOCATE(pin)
5899    IF (ALLOCATED(vin)) DEALLOCATE(vin)
5900    IF (ALLOCATED(svin)) DEALLOCATE(svin)
5901   
5902    RETURN
5903
5904  END SUBROUTINE multi_spaceweightstats_in2DRKno_slc3v3
5905
5906  SUBROUTINE multi_spaceweightstats_in3DRK3_slc3v3(varin, Ngridsin, gridsin, percentages, varout,     &
5907    di1, di2, di3, ds1, ds2, ds3, maxNgridsin)
5908  ! Subroutine to compute an spatial statistics value from a 3D RK matrix using 3rd dimension as
5909  !   running one into a matrix of 3-variables slices of rank 3 using spatial weights
5910
5911    IMPLICIT NONE
5912
5913    INTEGER, INTENT(in)                                  :: di1, di2, di3, ds1, ds2, ds3
5914    INTEGER, INTENT(in)                                  :: maxNgridsin
5915    INTEGER, DIMENSION(ds1,ds2,ds3), INTENT(in)          :: Ngridsin
5916    INTEGER, DIMENSION(ds1,ds2,ds3,maxNgridsin,2),                                                    &
5917      INTENT(in)                                         :: gridsin
5918    REAL(r_k), DIMENSION(di1,di2,di3), INTENT(in)        :: varin
5919    REAL(r_k), INTENT(in),                                                                            &
5920      DIMENSION(ds1,ds2,ds3,maxNgridsin)                 :: percentages
5921    REAL(r_k), DIMENSION(ds1,ds2,ds3,di3,7), INTENT(out) :: varout
5922
5923! Local
5924    INTEGER                                              :: i1, i2, i3, s1, s2, s3, iv
5925    INTEGER                                              :: ii3, ss1, ss2, ss3
5926    INTEGER                                              :: Ncounts, Nin
5927    CHARACTER(len=3)                                     :: val1S, val2S
5928    CHARACTER(len=30)                                    :: val3S
5929    REAL(r_k)                                            :: minv, maxv, meanv, mean2v, stdv, medv
5930    REAL(r_k), DIMENSION(:), ALLOCATABLE                 :: pin
5931    INTEGER, DIMENSION(:,:), ALLOCATABLE                 :: gin
5932    REAL(r_k), DIMENSION(:), ALLOCATABLE                 :: svin
5933    REAL(r_k), DIMENSION(:,:), ALLOCATABLE               :: vin
5934
5935!!!!!!! Variables
5936! di1, di2, di3: length of dimensions of the 3D matrix of values
5937! ds[1-3]: length of dimensions of matrix with the slices
5938! maxNgridsin: maximum number of grid points from the 3D matrix in any slice
5939! varin: 3D RK variable to be used
5940! Ngridsin: number of grids from 3D RK matrix for each slice
5941! gridsin: coordinates of grids of the 3D RK matrix B to matrix of slices
5942! percentages: weights as percentages of space of 3D RK matrix for each slice
5943!!!!!
5944! Available spatial statistics to compute inside each slice using values from 3D RK matrix
5945!   'min': minimum value
5946!   'max': maximum value
5947!   'mean': space weighted mean value
5948!   'mean2': space weighted quadratic mean value
5949!   'stddev': space weighted standard deviation value
5950!   'median': median value
5951!   'count': percentage of the space of matrix A covered by each different value of matrix B
5952! varout: output statistical variable
5953
5954    fname = 'multi_spaceweightstats_in3DRK3_slc3v3'
5955
5956    varout = fillval64
5957
5958    ss1 = 8 + 1
5959    ss2 = 5 + 1
5960    ss3 = 3 + 1
5961    ii3 = 1 + 1
5962
5963    ! Let's be efficient?
5964    varout = fillVal64
5965    DO s1 =1, ds1
5966      DO s2 =1, ds2
5967        DO s3 =1, ds3
5968          Nin = Ngridsin(s1,s2,s3)
5969          ! Computing along d3
5970          IF (Nin > 1) THEN
5971            IF (ALLOCATED(gin)) DEALLOCATE(gin)
5972            ALLOCATE(gin(Nin,2))
5973            IF (ALLOCATED(pin)) DEALLOCATE(pin)
5974            ALLOCATE(pin(Nin))
5975            IF (ALLOCATED(vin)) DEALLOCATE(vin)
5976            ALLOCATE(vin(Nin,di3))
5977            IF (ALLOCATED(svin)) DEALLOCATE(svin)
5978            ALLOCATE(svin(Nin))
5979            gin = gridsin(s1,s2,s3,1:Nin,:)
5980            pin = percentages(s1,s2,s3,1:Nin)
5981
5982            ! Getting the values
5983            DO iv=1, Nin
5984              i1 = gin(iv,1)
5985              i2 = gin(iv,2)
5986              vin(iv,:) = varin(i1,i2,:)
5987            END DO
5988            DO i3=1, di3
5989              minv = fillVal64
5990              maxv = -fillVal64
5991              meanv = zeroRK
5992              mean2v = zeroRK
5993              stdv = zeroRK
5994              minv = MINVAL(vin(:,i3))
5995              maxv = MAXVAL(vin(:,i3))
5996              meanv = SUM(vin(:,i3)*pin)
5997              mean2v = SUM(vin(:,i3)**2*pin)
5998              DO iv=1,Nin
5999                stdv = stdv + ( (meanv - vin(iv,i3))*pin(iv) )**2
6000              END DO
6001              stdv = SQRT(stdv)
6002              svin = vin(:,i3)
6003              CALL SortR_K(svin, Nin)
6004              medv = svin(INT(Nin/2))
6005              varout(s1,s2,s3,i3,1) = minv
6006              varout(s1,s2,s3,i3,2) = maxv
6007              varout(s1,s2,s3,i3,3) = meanv
6008              varout(s1,s2,s3,i3,4) = mean2v
6009              varout(s1,s2,s3,i3,5) = stdv
6010              varout(s1,s2,s3,i3,6) = medv
6011              varout(s1,s2,s3,i3,7) = Nin*1.
6012            END DO
6013          ELSE
6014            i1 = gridsin(s1,s2,s3,1,1)
6015            i2 = gridsin(s1,s2,s3,1,2)
6016            varout(s1,s2,s3,:,1) = varin(i1,i2,:)
6017            varout(s1,s2,s3,:,2) = varin(i1,i2,:)
6018            varout(s1,s2,s3,:,3) = varin(i1,i2,:)
6019            varout(s1,s2,s3,:,4) = varin(i1,i2,:)*varin(i1,i2,:)
6020            varout(s1,s2,s3,:,5) = zeroRK
6021            varout(s1,s2,s3,:,6) = varin(i1,i2,:)
6022            varout(s1,s2,s3,:,7) = Nin*1.
6023          END IF
6024        END DO
6025      END DO
6026    END DO
6027
6028    IF (ALLOCATED(gin)) DEALLOCATE(gin)
6029    IF (ALLOCATED(pin)) DEALLOCATE(pin)
6030    IF (ALLOCATED(vin)) DEALLOCATE(vin)
6031    IF (ALLOCATED(svin)) DEALLOCATE(svin)
6032   
6033    RETURN
6034
6035  END SUBROUTINE multi_spaceweightstats_in3DRK3_slc3v3
6036
6037  SUBROUTINE multi_spaceweightstats_in3DRK3_slc3v4(varin, Ngridsin, gridsin, percentages, varout,     &
6038    di1, di2, di3, ds1, ds2, ds3, ds4, maxNgridsin)
6039  ! Subroutine to compute an spatial statistics value from a 3D RK matrix using 3rd dimension as
6040  !   running one into a matrix of 3-variables slices of rank 4 using spatial weights
6041
6042    IMPLICIT NONE
6043
6044    INTEGER, INTENT(in)                                  :: di1, di2, di3, ds1, ds2, ds3, ds4
6045    INTEGER, INTENT(in)                                  :: maxNgridsin
6046    INTEGER, DIMENSION(ds1,ds2,ds3,ds4), INTENT(in)      :: Ngridsin
6047    INTEGER, INTENT(in),                                                                              &
6048      DIMENSION(ds1,ds2,ds3,ds4,maxNgridsin,2)           :: gridsin
6049    REAL(r_k), DIMENSION(di1,di2,di3), INTENT(in)        :: varin
6050    REAL(r_k), INTENT(in),                                                                            &
6051      DIMENSION(ds1,ds2,ds3,ds4,maxNgridsin)             :: percentages
6052    REAL(r_k), DIMENSION(ds1,ds2,ds3,ds4,di3,7),                                                      &
6053      INTENT(out)                                        :: varout
6054
6055! Local
6056    INTEGER                                              :: i1, i2, i3, s1, s2, s3, s4, iv
6057    INTEGER                                              :: Ncounts, Nin
6058    CHARACTER(len=3)                                     :: val1S, val2S
6059    CHARACTER(len=30)                                    :: val3S
6060    REAL(r_k)                                            :: minv, maxv, meanv, mean2v, stdv, medv
6061    REAL(r_k), DIMENSION(:), ALLOCATABLE                 :: pin
6062    INTEGER, DIMENSION(:,:), ALLOCATABLE                 :: gin
6063    REAL(r_k), DIMENSION(:), ALLOCATABLE                 :: svin
6064    REAL(r_k), DIMENSION(:,:), ALLOCATABLE               :: vin
6065
6066!!!!!!! Variables
6067! di1, di2, di3: length of dimensions of the 3D matrix of values
6068! ds[1-4]: length of dimensions of matrix with the slices
6069! maxNgridsin: maximum number of grid points from the 3D matrix in any slice
6070! varin: 3D RK variable to be used
6071! Ngridsin: number of grids from 3D RK matrix for each slice
6072! gridsin: coordinates of grids of the 3D RK matrix B to matrix of slices
6073! percentages: weights as percentages of space of 3D RK matrix for each slice
6074!!!!!
6075! Available spatial statistics to compute inside each slice using values from 3D RK matrix
6076!   'min': minimum value
6077!   'max': maximum value
6078!   'mean': space weighted mean value
6079!   'mean2': space weighted quadratic mean value
6080!   'stddev': space weighted standard deviation value
6081!   'median': median value
6082!   'count': percentage of the space of matrix A covered by each different value of matrix B
6083! varout: output statistical variable
6084
6085    fname = 'multi_spaceweightstats_in3DRK3_slc3v4'
6086
6087    varout = fillval64
6088
6089    ! Let's be efficient?
6090    varout = fillVal64
6091    DO s1 =1, ds1
6092      DO s2 =1, ds2
6093        DO s3 =1, ds3
6094          DO s4 =1, ds4
6095            Nin = Ngridsin(s1,s2,s3,s4)
6096            IF (Nin > 1) THEN
6097              IF (ALLOCATED(gin)) DEALLOCATE(gin)
6098              ALLOCATE(gin(Nin,2))
6099              IF (ALLOCATED(pin)) DEALLOCATE(pin)
6100              ALLOCATE(pin(Nin))
6101              IF (ALLOCATED(vin)) DEALLOCATE(vin)
6102              ALLOCATE(vin(Nin,di3))
6103              IF (ALLOCATED(svin)) DEALLOCATE(svin)
6104              ALLOCATE(svin(Nin))
6105              gin = gridsin(s1,s2,s3,s4,1:Nin,:)
6106              pin = percentages(s1,s2,s3,s4,1:Nin)
6107
6108              ! Getting the values
6109              DO iv=1, Nin
6110                i1 = gin(iv,1)
6111                i2 = gin(iv,2)
6112                vin(iv,:) = varin(i1,i2,:)
6113              END DO
6114              ! Computing along d3
6115              DO i3=1, di3
6116                minv = fillVal64
6117                maxv = -fillVal64
6118                meanv = zeroRK
6119                mean2v = zeroRK
6120                stdv = zeroRK
6121
6122                minv = MINVAL(vin(:,i3))
6123                maxv = MAXVAL(vin(:,i3))
6124                meanv = SUM(vin(:,i3)*pin)
6125                mean2v = SUM(vin(:,i3)**2*pin) 
6126                DO iv=1,Nin
6127                  stdv = stdv + ( (meanv - vin(iv,i3))*pin(iv) )**2
6128                END DO
6129                stdv = SQRT(stdv)
6130                svin = vin(:,i3)
6131                CALL SortR_K(svin, Nin)
6132                medv = svin(INT(Nin/2))
6133                varout(s1,s2,s3,s4,i3,1) = minv
6134                varout(s1,s2,s3,s4,i3,2) = maxv
6135                varout(s1,s2,s3,s4,i3,3) = meanv
6136                varout(s1,s2,s3,s4,i3,4) = mean2v
6137                varout(s1,s2,s3,s4,i3,5) = stdv
6138                varout(s1,s2,s3,s4,i3,6) = medv
6139                varout(s1,s2,s3,s4,i3,7) = Nin*1.
6140              END DO
6141            ELSE
6142                i1 = gridsin(s1,s2,s3,s4,1,1)
6143                i2 = gridsin(s1,s2,s3,s4,1,2)
6144                varout(s1,s2,s3,s4,:,1) = varin(i1,i2,:)
6145                varout(s1,s2,s3,s4,:,2) = varin(i1,i2,:)
6146                varout(s1,s2,s3,s4,:,3) = varin(i1,i2,:)
6147                varout(s1,s2,s3,s4,:,4) = varin(i1,i2,:)*varin(i1,i2,:)
6148                varout(s1,s2,s3,s4,:,5) = zeroRK
6149                varout(s1,s2,s3,s4,:,6) = varin(i1,i2,:)
6150                varout(s1,s2,s3,s4,:,7) = Nin*1.
6151            END IF
6152          END DO
6153        END DO
6154      END DO
6155    END DO
6156
6157    IF (ALLOCATED(gin)) DEALLOCATE(gin)
6158    IF (ALLOCATED(pin)) DEALLOCATE(pin)
6159    IF (ALLOCATED(vin)) DEALLOCATE(vin)
6160    IF (ALLOCATED(svin)) DEALLOCATE(svin)
6161   
6162    RETURN
6163
6164  END SUBROUTINE multi_spaceweightstats_in3DRK3_slc3v4
6165
6166  SUBROUTINE multi_index_mat2DI(d1, d2, d12, mat, value, Nindices, indices)
6167  ! Subroutine to provide the indices of the different locations of a value inside a 2D integer matrix
6168
6169    IMPLICIT NONE
6170
6171    INTEGER, INTENT(in)                                  :: d1, d2, d12
6172    INTEGER, DIMENSION(d1,d2), INTENT(in)                :: mat
6173    INTEGER,INTENT(in)                                   :: value
6174    INTEGER, INTENT(out)                                 :: Nindices
6175    INTEGER, DIMENSION(2,d12), INTENT(out)               :: indices
6176
6177! Local
6178    INTEGER                                              :: i,j
6179    INTEGER                                              :: Ncounts1D, icount1D
6180    INTEGER, DIMENSION(d2)                               :: diffmat1D
6181
6182    !!!!!!! Variables
6183    ! d1, d2: shape of the 2D matrix
6184    ! mat: 2D matrix
6185    ! value: value to be looking for
6186    ! Nindices: number of times value found within matrix
6187    ! indices: indices of the found values
6188
6189    fname = 'multi_index_mat2DI'
6190
6191    Nindices = 0
6192    indices = 0
6193    DO i=1, d1
6194      diffmat1D = mat(i,:) - value
6195      IF (ANY(diffmat1D == 0)) THEN
6196        Ncounts1D = COUNT(diffmat1D == 0)
6197        icount1D = 0
6198        DO j=1, d2
6199          IF (diffmat1D(j) == 0) THEN
6200            Nindices = Nindices + 1
6201            indices(1,Nindices) = i
6202            indices(2,Nindices) = j
6203            icount1D = icount1D + 1
6204            IF (icount1D == Ncounts1D) EXIT
6205          END IF
6206        END DO
6207      END IF
6208    END DO
6209
6210  END SUBROUTINE multi_index_mat2DI
6211
6212  SUBROUTINE multi_index_mat3DI(d1, d2, d3, d123, mat, value, Nindices, indices)
6213  ! Subroutine to provide the indices of the different locations of a value inside a 3D integer matrix
6214
6215    IMPLICIT NONE
6216
6217    INTEGER, INTENT(in)                                  :: d1, d2, d3, d123
6218    INTEGER, DIMENSION(d1,d2,d3), INTENT(in)             :: mat
6219    INTEGER, INTENT(in)                                  :: value
6220    INTEGER, INTENT(out)                                 :: Nindices
6221    INTEGER, DIMENSION(3,d123), INTENT(out)              :: indices
6222
6223! Local
6224    INTEGER                                              :: i,j,k
6225    INTEGER                                              :: Ncounts1D, icount1D
6226    INTEGER                                              :: Ncounts2D, icount2D
6227    INTEGER, DIMENSION(d2,d3)                            :: diffmat2D
6228    INTEGER, DIMENSION(d3)                               :: diffmat1D
6229
6230    !!!!!!! Variables
6231    ! d1, d2, d3: shape of the 3D matrix
6232    ! mat: 3D matrix
6233    ! value: value to be looking for
6234    ! Nindices: number of times value found within matrix
6235    ! indices: indices of the found values
6236
6237    fname = 'multi_index_mat3DI'
6238
6239    Nindices = 0
6240    indices = 0
6241    DO i=1, d1
6242      diffmat2D = mat(i,:,:) - value
6243      IF (ANY(diffmat2D == 0)) THEN
6244        Ncounts2D = COUNT(diffmat2D == 0)
6245        icount2D = 0
6246        DO j=1, d2
6247          diffmat1D = mat(i,j,:) - value
6248          IF (ANY(diffmat1D == 0)) THEN
6249            Ncounts1D = COUNT(diffmat1D == 0)
6250            icount1D = 0
6251            DO k=1, d3
6252              IF (diffmat1D(k) == 0) THEN
6253                Nindices = Nindices + 1
6254                indices(1,Nindices) = i
6255                indices(2,Nindices) = j
6256                indices(3,Nindices) = k
6257                icount1D = icount1D + 1
6258                IF (icount1D == Ncounts1D) EXIT
6259              END IF
6260            END DO
6261            icount2D = icount2D + icount1D
6262            IF (icount2D == Ncounts2D) EXIT
6263          END IF
6264        END DO
6265      END IF
6266    END DO
6267
6268  END SUBROUTINE multi_index_mat3DI
6269
6270  SUBROUTINE multi_index_mat4DI(d1, d2, d3, d4, d1234, mat, value, Nindices, indices)
6271  ! Subroutine to provide the indices of the different locations of a value inside a 4D integer matrix
6272
6273    IMPLICIT NONE
6274
6275    INTEGER, INTENT(in)                                  :: d1, d2, d3, d4, d1234
6276    INTEGER, DIMENSION(d1,d2,d3,d4), INTENT(in)          :: mat
6277    INTEGER, INTENT(in)                                  :: value
6278    INTEGER, INTENT(out)                                 :: Nindices
6279    INTEGER, DIMENSION(4,d1234), INTENT(out)             :: indices
6280
6281! Local
6282    INTEGER                                              :: i,j,k,l
6283    INTEGER                                              :: Ncounts1D, icount1D
6284    INTEGER                                              :: Ncounts2D, icount2D
6285    INTEGER                                              :: Ncounts3D, icount3D
6286    INTEGER, DIMENSION(d2,d3,d4)                         :: diffmat3D
6287    INTEGER, DIMENSION(d3,d4)                            :: diffmat2D
6288    INTEGER, DIMENSION(d4)                               :: diffmat1D
6289
6290    !!!!!!! Variables
6291    ! d1, d2, d3, d4: shape of the 4D matrix
6292    ! mat: 4D matrix
6293    ! value: value to be looking for
6294    ! Nindices: number of times value found within matrix
6295    ! indices: indices of the found values
6296
6297    fname = 'multi_index_mat4DI'
6298
6299    Nindices = 0
6300    indices = 0
6301    DO i=1, d1
6302      diffmat3D = mat(i,:,:,:) - value
6303      IF (ANY(diffmat3D == 0)) THEN
6304        Ncounts3D = COUNT(diffmat3D == 0)
6305        icount3D = 0
6306        DO j=1, d2
6307          diffmat2D = mat(i,j,:,:) - value
6308          IF (ANY(diffmat2D == 0)) THEN
6309            Ncounts2D = COUNT(diffmat2D == 0)
6310            icount2D = 0
6311            DO k=1, d3
6312              diffmat1D = mat(i,j,k,:) - value
6313              IF (ANY(diffmat1D == 0)) THEN
6314                Ncounts1D = COUNT(diffmat1D == 0)
6315                icount1D = 0
6316                DO l=1, d4
6317                  IF (diffmat1D(l) == 0) THEN
6318                    Nindices = Nindices + 1
6319                    indices(1,Nindices) = i
6320                    indices(2,Nindices) = j
6321                    indices(3,Nindices) = k
6322                    indices(4,Nindices) = l
6323                    icount1D = icount1D + 1
6324                    IF (icount1D == Ncounts1D) EXIT
6325                  END IF
6326                END DO
6327              icount2D = icount2D + icount1D
6328              IF (icount2D == Ncounts2D) EXIT
6329              END IF
6330            END DO
6331            icount3D = icount3D + icount1D
6332            IF (icount3D == Ncounts3D) EXIT
6333          END IF
6334        END DO
6335      END IF
6336    END DO
6337
6338  END SUBROUTINE multi_index_mat4DI
6339
6340  SUBROUTINE multi_index_mat2DRK(d1, d2, d12, mat, value, Nindices, indices)
6341  ! Subroutine to provide the indices of the different locations of a value inside a 2D RK matrix
6342
6343    IMPLICIT NONE
6344
6345    INTEGER, INTENT(in)                                  :: d1, d2, d12
6346    REAL(r_k), DIMENSION(d1,d2), INTENT(in)              :: mat
6347    REAL(r_k),INTENT(in)                                 :: value
6348    INTEGER, INTENT(out)                                 :: Nindices
6349    INTEGER, DIMENSION(2,d12), INTENT(out)               :: indices
6350
6351! Local
6352    INTEGER                                              :: i,j
6353    INTEGER                                              :: Ncounts1D, icount1D
6354    REAL(r_k), DIMENSION(d2)                             :: diffmat1D
6355
6356    !!!!!!! Variables
6357    ! d1, d2: shape of the 2D matrix
6358    ! mat: 2D matrix
6359    ! value: value to be looking for
6360    ! Nindices: number of times value found within matrix
6361    ! indices: indices of the found values
6362
6363    fname = 'multi_index_mat2DRK'
6364
6365    Nindices = 0
6366    indices = 0
6367    DO i=1, d1
6368      diffmat1D = mat(i,:) - value
6369      IF (ANY(diffmat1D == zeroRK)) THEN
6370        Ncounts1D = COUNT(diffmat1D == zeroRK)
6371        icount1D = 0
6372        DO j=1, d2
6373          IF (diffmat1D(j) == zeroRK) THEN
6374            Nindices = Nindices + 1
6375            indices(1,Nindices) = i
6376            indices(2,Nindices) = j
6377            icount1D = icount1D + 1
6378            IF (icount1D == Ncounts1D) EXIT
6379          END IF
6380        END DO
6381      END IF
6382    END DO
6383
6384  END SUBROUTINE multi_index_mat2DRK
6385
6386  SUBROUTINE multi_index_mat3DRK(d1, d2, d3, d123, mat, value, Nindices, indices)
6387  ! Subroutine to provide the indices of the different locations of a value inside a 3D RK matrix
6388
6389    IMPLICIT NONE
6390
6391    INTEGER, INTENT(in)                                  :: d1, d2, d3, d123
6392    REAL(r_k), DIMENSION(d1,d2,d3), INTENT(in)           :: mat
6393    REAL(r_k),INTENT(in)                                 :: value
6394    INTEGER, INTENT(out)                                 :: Nindices
6395    INTEGER, DIMENSION(3,d123), INTENT(out)              :: indices
6396
6397! Local
6398    INTEGER                                              :: i,j,k
6399    INTEGER                                              :: Ncounts1D, icount1D
6400    INTEGER                                              :: Ncounts2D, icount2D
6401    REAL(r_k), DIMENSION(d2,d3)                          :: diffmat2D
6402    REAL(r_k), DIMENSION(d3)                             :: diffmat1D
6403
6404    !!!!!!! Variables
6405    ! d1, d2, d3: shape of the 3D matrix
6406    ! mat: 3D matrix
6407    ! value: value to be looking for
6408    ! Nindices: number of times value found within matrix
6409    ! indices: indices of the found values
6410
6411    fname = 'multi_index_mat3DRK'
6412
6413    Nindices = 0
6414    indices = 0
6415    DO i=1, d1
6416      diffmat2D = mat(i,:,:) - value
6417      IF (ANY(diffmat2D == zeroRK)) THEN
6418        Ncounts2D = COUNT(diffmat2D == zeroRK)
6419        icount2D = 0
6420        DO j=1, d2
6421          diffmat1D = mat(i,j,:) - value
6422          IF (ANY(diffmat1D == zeroRK)) THEN
6423            Ncounts1D = COUNT(diffmat1D == zeroRK)
6424            icount1D = 0
6425            DO k=1, d3
6426              IF (diffmat1D(k) == zeroRK) THEN
6427                Nindices = Nindices + 1
6428                indices(1,Nindices) = i
6429                indices(2,Nindices) = j
6430                indices(3,Nindices) = k
6431                icount1D = icount1D + 1
6432                IF (icount1D == Ncounts1D) EXIT
6433              END IF
6434            END DO
6435            icount2D = icount2D + icount1D
6436            IF (icount2D == Ncounts2D) EXIT
6437          END IF
6438        END DO
6439      END IF
6440    END DO
6441
6442  END SUBROUTINE multi_index_mat3DRK
6443
6444  SUBROUTINE multi_index_mat4DRK(d1, d2, d3, d4, d1234, mat, value, Nindices, indices)
6445  ! Subroutine to provide the indices of the different locations of a value inside a 4D RK matrix
6446
6447    IMPLICIT NONE
6448
6449    INTEGER, INTENT(in)                                  :: d1, d2, d3, d4, d1234
6450    REAL(r_k), DIMENSION(d1,d2,d3,d4), INTENT(in)        :: mat
6451    REAL(r_k),INTENT(in)                                 :: value
6452    INTEGER, INTENT(out)                                 :: Nindices
6453    INTEGER, DIMENSION(4,d1234), INTENT(out)             :: indices
6454
6455! Local
6456    INTEGER                                              :: i,j,k,l
6457    INTEGER                                              :: Ncounts1D, icount1D
6458    INTEGER                                              :: Ncounts2D, icount2D
6459    INTEGER                                              :: Ncounts3D, icount3D
6460    REAL(r_k), DIMENSION(d2,d3,d4)                       :: diffmat3D
6461    REAL(r_k), DIMENSION(d3,d4)                          :: diffmat2D
6462    REAL(r_k), DIMENSION(d4)                             :: diffmat1D
6463
6464    !!!!!!! Variables
6465    ! d1, d2, d3, d4: shape of the 4D matrix
6466    ! mat: 4D matrix
6467    ! value: value to be looking for
6468    ! Nindices: number of times value found within matrix
6469    ! indices: indices of the found values
6470
6471    fname = 'multi_index_mat4DRK'
6472
6473    Nindices = 0
6474    indices = 0
6475    DO i=1, d1
6476      diffmat3D = mat(i,:,:,:) - value
6477      IF (ANY(diffmat3D == zeroRK)) THEN
6478        Ncounts3D = COUNT(diffmat3D == zeroRK)
6479        icount3D = 0
6480        DO j=1, d2
6481          diffmat2D = mat(i,j,:,:) - value
6482          IF (ANY(diffmat2D == zeroRK)) THEN
6483            Ncounts2D = COUNT(diffmat2D == zeroRK)
6484            icount2D = 0
6485            DO k=1, d3
6486              diffmat1D = mat(i,j,k,:) - value
6487              IF (ANY(diffmat1D == zeroRK)) THEN
6488                Ncounts1D = COUNT(diffmat1D == zeroRK)
6489                icount1D = 0
6490                DO l=1, d4
6491                  IF (diffmat1D(l) == zeroRK) THEN
6492                    Nindices = Nindices + 1
6493                    indices(1,Nindices) = i
6494                    indices(2,Nindices) = j
6495                    indices(3,Nindices) = k
6496                    indices(4,Nindices) = l
6497                    icount1D = icount1D + 1
6498                    IF (icount1D == Ncounts1D) EXIT
6499                  END IF
6500                END DO
6501              icount2D = icount2D + icount1D
6502              IF (icount2D == Ncounts2D) EXIT
6503              END IF
6504            END DO
6505            icount3D = icount3D + icount1D
6506            IF (icount3D == Ncounts3D) EXIT
6507          END IF
6508        END DO
6509      END IF
6510    END DO
6511
6512  END SUBROUTINE multi_index_mat4DRK
6513
6514  SUBROUTINE coincident_list_2Dcoords(NpointsA, pointsA, NpointsB, pointsB, Npoints, points, inpA,    &
6515    inpB)
6516  ! Subroutine to determine which 2D points of an A list are also found in a B list
6517
6518    IMPLICIT NONE
6519
6520    INTEGER, INTENT(in)                                  :: NpointsA, NpointsB
6521    INTEGER, DIMENSION(NpointsA,2), INTENT(in)           :: pointsA
6522    INTEGER, DIMENSION(NpointsB,2), INTENT(in)           :: pointsB
6523    INTEGER, INTENT(out)                                 :: Npoints
6524    INTEGER, DIMENSION(NpointsA,2), INTENT(out)          :: points
6525    INTEGER, DIMENSION(NpointsA), INTENT(out)            :: inpA, inpB
6526
6527    ! Local
6528    INTEGER                                              :: iA, iB
6529
6530!!!!!!! Variables
6531! NpointsA: Number of points of the list A
6532! pointsA: points of the list A
6533! NpointsB: Number of points of the list B
6534! pointsB: points of the list B
6535! Npoints: Number of coincident points
6536! points: coincident points
6537! inpA: coincident points list A
6538! inpB: coincident points list B
6539
6540
6541    fname = 'coincident_list_2Dcoords'
6542
6543    Npoints = 0
6544    points = 0
6545    inpA = 0
6546    inpB = 0
6547
6548    DO iA = 1, NpointsA
6549      DO iB = 1, NpointsB
6550        IF ( (pointsA(iA,1) == pointsB(iB,1)) .AND. (pointsA(iA,2) == pointsB(iB,2)) ) THEN
6551          Npoints = Npoints + 1
6552          points(Npoints,1) = pointsA(iA,1)
6553          points(Npoints,2) = pointsA(iA,2)
6554          inpA(Npoints) = iA
6555          inpB(Npoints) = iB
6556          EXIT
6557        END IF
6558
6559      END DO
6560    END DO
6561
6562  END SUBROUTINE coincident_list_2Dcoords
6563
6564  SUBROUTINE coincident_gridsin2D_old(dxA, dyA, dxyA, NpointsA, pointsA, dxB, dyB, dxyB, NpointsB,    &
6565    pointsB, Npoints, points, inpointsA, inpointsB)
6566  ! Subroutine to determine which lists of 2D gridsin points of an A list are also found in a B list
6567
6568    IMPLICIT NONE
6569
6570    INTEGER, INTENT(in)                                  :: dxA, dyA, dxyA
6571    INTEGER, INTENT(in)                                  :: dxB, dyB, dxyB
6572    INTEGER, DIMENSION(dxA, dyA), INTENT(in)             :: NpointsA
6573    INTEGER, DIMENSION(dxB, dyB), INTENT(in)             :: NpointsB
6574    INTEGER, DIMENSION(dxA, dyA, dxyA, 2), INTENT(in)    :: pointsA
6575    INTEGER, DIMENSION(dxB, dyB, dxyB, 2), INTENT(in)    :: pointsB
6576    INTEGER, DIMENSION(dxA, dyA, dxB, dyB), INTENT(out)  :: Npoints
6577    INTEGER, DIMENSION(dxA, dyA, dxB, dyB, dxyA, 2),                                                  &
6578      INTENT(out)                                        :: points
6579    INTEGER, DIMENSION(dxA, dyA, dxB, dyB, dxyA),                                                     &
6580      INTENT(out)                                        :: inpointsA
6581    INTEGER, DIMENSION(dxA, dyA, dxB, dyB, dxyA),                                                     &
6582      INTENT(out)                                        :: inpointsB
6583
6584    ! Local
6585    INTEGER                                              :: ixA, iyA, ixB, iyB, iv, ii
6586    INTEGER                                              :: NA, NB
6587    INTEGER, DIMENSION(dxyA)                             :: ptsA, ptsB
6588    INTEGER, DIMENSION(dxyA, 2)                          :: pts
6589
6590
6591!!!!!!! Variables
6592! dxA, dyA: 2D shape of the list A
6593! NpointsA: 2D Number of points of the list A
6594! pointsA: points of the list A
6595! dxB, dyB: 2D shape of the list B
6596! NpointsB: 2D Number of points of the list B
6597! pointsB: points of the list B
6598! Npoints: Number of coincident points
6599! points: coincident points
6600! inpointsA: coincident points list A
6601! inpointsB: coincident points list B
6602
6603    fname = 'coincident_gridsin2D_old'
6604
6605    Npoints = 0
6606    points = 0
6607    inpointsA = 0
6608    inpointsB = 0
6609
6610    DO ixA=1, dxA
6611      DO iyA=1, dyA
6612        NA = NpointsA(ixA,iyA)
6613        DO ixB=1, dxB
6614          DO iyB=1, dyB
6615            NB = NpointsB(ixB,iyB)
6616            pts = -1
6617            CALL coincident_list_2Dcoords(NA, pointsA(ixA,iyA,1:NA,:), NB, pointsB(ixB,iyB,1:NB,:),   &
6618              Npoints(ixA,iyA,ixB,iyB), pts(1:NA,:), ptsA, ptsB)
6619            DO iv = 1, Npoints(ixA,iyA,ixB,iyB)
6620              points(ixA,iyA,ixB,iyB,iv,1) = pts(iv,1)
6621              points(ixA,iyA,ixB,iyB,iv,2) = pts(iv,2)
6622              inpointsA(ixA,iyA,ixB,iyB,iv) = ptsA(iv)
6623              inpointsB(ixA,iyA,ixB,iyB,iv) = ptsB(iv)
6624            END DO
6625          END DO
6626        END DO
6627      END DO
6628    END DO
6629
6630  END SUBROUTINE coincident_gridsin2D_old
6631
6632  SUBROUTINE coincident_gridsin2D(dxA, dyA, dxyA, NpointsA, pointsA, dxB, dyB, dxyB, NpointsB,        &
6633    pointsB, Npoints, points, inpointsA, inpointsB)
6634  ! Subroutine to determine which lists of 2D gridsin points of an A list are also found in a B list
6635
6636    IMPLICIT NONE
6637
6638    INTEGER, INTENT(in)                                  :: dxA, dyA, dxyA
6639    INTEGER, INTENT(in)                                  :: dxB, dyB, dxyB
6640    INTEGER, DIMENSION(dxA, dyA), INTENT(in)             :: NpointsA
6641    INTEGER, DIMENSION(dxB, dyB), INTENT(in)             :: NpointsB
6642    INTEGER, DIMENSION(dxA, dyA, dxyA, 2), INTENT(in)    :: pointsA
6643    INTEGER, DIMENSION(dxB, dyB, dxyB, 2), INTENT(in)    :: pointsB
6644    INTEGER, DIMENSION(dxA, dyA, dxB, dyB), INTENT(out)  :: Npoints
6645    INTEGER, DIMENSION(dxA, dyA, dxB, dyB, dxyA, 2),                                                  &
6646      INTENT(out)                                        :: points
6647    INTEGER, DIMENSION(dxA, dyA, dxB, dyB, dxyA),                                                     &
6648      INTENT(out)                                        :: inpointsA
6649    INTEGER, DIMENSION(dxA, dyA, dxB, dyB, dxyA),                                                     &
6650      INTENT(out)                                        :: inpointsB
6651
6652    ! Local
6653    INTEGER                                              :: ixA, iyA, ixB, iyB, iv, iv1, iv2
6654    INTEGER                                              :: NA, NB
6655    INTEGER, DIMENSION(dxyA)                             :: ptsA, ptsB
6656    INTEGER, DIMENSION(dxyA, 2)                          :: pts
6657
6658
6659!!!!!!! Variables
6660! dxA, dyA: 2D shape of the list A
6661! NpointsA: 2D Number of points of the list A
6662! pointsA: points of the list A
6663! dxB, dyB: 2D shape of the list B
6664! NpointsB: 2D Number of points of the list B
6665! pointsB: points of the list B
6666! Npoints: Number of coincident points
6667! points: coincident points
6668! inpointsA: coincident points list A
6669! inpointsB: coincident points list B
6670
6671    fname = 'coincident_gridsin2D'
6672
6673    Npoints = 0
6674    points = 0
6675    inpointsA = 0
6676    inpointsB = 0
6677
6678    DO ixA=1, dxA
6679      DO iyA=1, dyA
6680        NA = NpointsA(ixA,iyA)
6681        DO ixB=1, dxB
6682          DO iyB=1, dyB
6683            NB = NpointsB(ixB,iyB)
6684            iv = 0
6685            DO iv1=1, NA
6686              DO iv2=1, NB
6687                IF ( (pointsA(ixA,iyA,iv1,1) == pointsB(ixB,iyB,iv2,1)) .AND.                         &
6688                  (pointsA(ixA,iyA,iv1,2) == pointsB(ixB,iyB,iv2,2)) ) THEN
6689                  iv = iv + 1
6690                  points(ixA,iyA,ixB,iyB,iv,1) = pointsA(ixA,iyA,iv1,1)
6691                  points(ixA,iyA,ixB,iyB,iv,2) = pointsA(ixA,iyA,iv1,2)
6692                  inpointsA(ixA,iyA,ixB,iyB,iv) = iv1
6693                  inpointsB(ixA,iyA,ixB,iyB,iv) = iv2
6694                END IF
6695              END DO
6696            END DO
6697            Npoints(ixA,iyA,ixB,iyB) = iv
6698          END DO
6699        END DO
6700      END DO
6701    END DO   
6702
6703  END SUBROUTINE coincident_gridsin2D
6704
6705END MODULE module_scientific
Note: See TracBrowser for help on using the repository browser.