SABER
tools_stripack.F90
Go to the documentation of this file.
1 # 1 "/Users/miesch/JEDI/code/working_copy/public/fv3-bundle/saber/src/saber/external/tools_stripack.fypp"
2 # 1 "/Users/miesch/JEDI/code/working_copy/public/fv3-bundle/saber/src/saber/external/../instrumentation.fypp" 1
3 # 1 "/Users/miesch/JEDI/code/working_copy/public/fv3-bundle/saber/src/saber/external/../subr_list.fypp" 1
4 !----------------------------------------------------------------------
5 ! Header: subr_list
6 !> Subroutines/functions list
7 ! Author: Benjamin Menetrier
8 ! Licensing: this code is distributed under the CeCILL-C license
9 ! Copyright 2015-... UCAR, CERFACS, METEO-FRANCE and IRIT
10 !----------------------------------------------------------------------
11 
12 # 726 "/Users/miesch/JEDI/code/working_copy/public/fv3-bundle/saber/src/saber/external/../subr_list.fypp"
13 # 2 "/Users/miesch/JEDI/code/working_copy/public/fv3-bundle/saber/src/saber/external/../instrumentation.fypp" 2
14 !----------------------------------------------------------------------
15 ! Header: instrumentation
16 !> Instrumentation functions
17 ! Author: Benjamin Menetrier
18 ! Licensing: this code is distributed under the CeCILL-C license
19 ! Copyright 2015-... UCAR, CERFACS, METEO-FRANCE and IRIT
20 !----------------------------------------------------------------------
21 
22 # 112 "/Users/miesch/JEDI/code/working_copy/public/fv3-bundle/saber/src/saber/external/../instrumentation.fypp"
23 # 2 "/Users/miesch/JEDI/code/working_copy/public/fv3-bundle/saber/src/saber/external/tools_stripack.fypp" 2
24 !----------------------------------------------------------------------
25 ! Module: tools_stripack
26 !> STRIPACK routines
27 ! Source: https://people.sc.fsu.edu/~jburkardt/f_src/stripack/stripack.html
28 ! Author: Robert Renka
29 ! Original licensing: none
30 ! Modified by Benjamin Menetrier for BUMP
31 ! Licensing: this code is distributed under the CeCILL-C license
32 ! Copyright 2015-... UCAR, CERFACS, METEO-FRANCE and IRIT
33 !----------------------------------------------------------------------
35 
36 use tools_const, only: zero,one,four,hundred,pi
37 use tools_kinds, only: kind_real
38 use tools_repro, only: eq,inf,sup,supeq,small
39 use type_mpl, only: mpl_type
40 
41 
42 implicit none
43 
44 interface addnod
45  module procedure stripack_addnod
46 end interface
47 interface area
48  module procedure stripack_area
49 end interface
50 interface bdyadd
51  module procedure stripack_bdyadd
52 end interface
53 interface bnodes
54  module procedure stripack_bnodes
55 end interface
56 interface covsph
57  module procedure stripack_covsph
58 end interface
59 interface det
60  module procedure stripack_det
61 end interface
62 interface insert
63  module procedure stripack_insert
64 end interface
65 interface intadd
66  module procedure stripack_intadd
67 end interface
68 interface jrand
69  module procedure stripack_jrand
70 end interface
71 interface left
72  module procedure stripack_left
73 end interface
74 interface lstptr
75  module procedure stripack_lstptr
76 end interface
77 interface swap
78  module procedure stripack_swap
79 end interface
80 interface swptst
81  module procedure stripack_swptst
82 end interface
83 interface trfind
84  module procedure stripack_trfind
85 end interface
86 interface trmesh
87  module procedure stripack_trmesh
88 end interface
89 
90 private
91 public :: area,bnodes,trfind,trmesh
92 
93 contains
94 
95 !----------------------------------------------------------------------
96 ! Subroutine: stripack_addnod
97 !> Add a node to a triangulation
98 !----------------------------------------------------------------------
99 subroutine stripack_addnod(mpl,nst,k,x,y,z,list,lptr,lend,lnew)
100 
101 implicit none
102 
103 ! Passed variables
104 type(mpl_type),intent(inout) :: mpl !< MPI data
105 integer,intent(in) :: nst !< Index of a node at which TRFIND, begins its search.Search time depends on the proximity of this node to K. If NST<1, the search is begun at node K-1.
106 integer,intent(in) :: k !< Nodal index (index for X, Y, Z, and LEND) of the new node to be added. 4<=K.
107 real(kind_real),intent(in) :: x(k) !< X-coordinates of the nodes
108 real(kind_real),intent(in) :: y(k) !< Y-coordinates of the nodes
109 real(kind_real),intent(in) :: z(k) !< Z-coordinates of the nodes
110 integer,intent(inout) :: list(*) !< On input, the data structure associated with the triangulation of nodes 1 to K-1. On output, the data has been updated to include node K. The array lengths are assumed to be large enough to add node K. Refer to TRMESH.
111 integer,intent(inout) :: lptr(*) !< cf. list
112 integer,intent(inout) :: lend(k) !< cf. list
113 integer,intent(inout) :: lnew !< cf. list
114 
115 ! Local variables
116 integer :: i1,i2,i3,in1,io1,io2,ist,kk,km1,l,lp,lpf,lpo1,lpo1s
117 real(kind_real) :: b1,b2,b3,p(3)
118 logical :: output
119 
120 ! Set name
121 
122 
123 ! Probe in
124 
125 
126 ! Initialization
127 kk = k
128 if (kk<4) call mpl%abort('stripack_addnod','K<4')
129 km1 = kk-1
130 ist = nst
131 if (ist<1) ist = km1
132 p(1) = x(kk)
133 p(2) = y(kk)
134 p(3) = z(kk)
135 
136 ! Find a triangle (I1,I2,I3) containing K or the rightmost (I1) and leftmost (I2) visible boundary nodes as viewed from node K.
137 call trfind(ist,p,km1,x,y,z,list,lptr,lend,b1,b2,b3,i1,i2,i3)
138 
139 ! Test for colinear or duplicate nodes.
140 if (i1==0) call mpl%abort('stripack_addnod','colinear points')
141 if (i3/=0) then
142  l = i1
143  if (eq(p(1),x(l)).and.eq(p(2),y(l)).and.eq(p(3),z(l))) call mpl%abort('stripack_addnod','colinear or duplicate nodes')
144  l = i2
145  if (eq(p(1),x(l)).and.eq(p(2),y(l)).and.eq(p(3),z(l))) call mpl%abort('stripack_addnod','colinear or duplicate nodes')
146  l = i3
147  if (eq(p(1),x(l)).and.eq(p(2),y(l)).and.eq(p(3),z(l))) call mpl%abort('stripack_addnod','colinear or duplicate nodes')
148  call intadd(kk,i1,i2,i3,list,lptr,lend,lnew)
149 else
150  if (i1/=i2) then
151  call bdyadd(kk,i1,i2,list,lptr,lend,lnew)
152  else
153  call covsph(kk,i1,list,lptr,lend,lnew)
154  end if
155 end if
156 
157 ! Initialize variables for optimization of the triangulation.
158 lp = lend(kk)
159 lpf = lptr(lp)
160 io2 = list(lpf)
161 lpo1 = lptr(lpf)
162 io1 = abs(list(lpo1))
163 
164 ! Begin loop: find the node opposite K.
165 do
166  call lstptr(lend(io1),io2,list,lptr,lp)
167  if (0<=list(lp)) then
168  lp = lptr(lp)
169  in1 = abs(list(lp))
170 
171  ! Swap test: if a swap occurs,two new arcs are opposite K and must be tested.
172  lpo1s = lpo1
173  call swptst(in1,kk,io1,io2,x,y,z,output)
174  if (.not.output) then
175  if ((lpo1==lpf).or.(list(lpo1)<0)) exit
176  io2 = io1
177  lpo1 = lptr(lpo1)
178  io1 = abs(list(lpo1))
179  cycle
180  end if
181  call swap(in1,kk,io1,io2,list,lptr,lend,lpo1)
182 
183  ! A swap is not possible because KK and IN1 are already adjacent. This error in SWPTST only occurs in the neutral case and when there are nearly duplicate nodes.
184  if (lpo1/=0) then
185  io1 = in1
186  cycle
187  end if
188  lpo1 = lpo1s
189  end if
190 
191  ! No swap occurred. Test for termination and reset IO2 and IO1.
192  if ((lpo1==lpf).or.(list(lpo1)<0)) exit
193  io2 = io1
194  lpo1 = lptr(lpo1)
195  io1 = abs(list(lpo1))
196 end do
197 
198 ! Probe out
199 
200 
201 end subroutine stripack_addnod
202 
203 !----------------------------------------------------------------------
204 ! Subroutine: stripack_area
205 !> Compute the area of a spherical triangle
206 !----------------------------------------------------------------------
207 subroutine stripack_area(v1,v2,v3,area)
208 
209 implicit none
210 
211 ! Passed variables
212 real(kind_real),intent(in) :: v1(3) !< First point cartesian coordinates
213 real(kind_real),intent(in) :: v2(3) !< Second point cartesian coordinates
214 real(kind_real),intent(in) :: v3(3) !< Third point cartesian coordinates
215 real(kind_real),intent(out) :: area !< Area on the unit sphere
216 
217 ! Local variables
218 real(kind_real) :: a1,a2,a3,ca1,ca2,ca3,s12,s23,s31
219 real(kind_real) :: dv1(3),dv2(3),dv3(3),u12(3),u23(3),u31(3)
220 
221 ! Set name
222 
223 
224 ! Probe in
225 
226 
227 ! Initialization
228 dv1 = v1
229 dv2 = v2
230 dv3 = v3
231 
232 ! Compute cross products Uij = Vi X Vj
233 u12(1) = dv1(2)*dv2(3)-dv1(3)*dv2(2)
234 u12(2) = dv1(3)*dv2(1)-dv1(1)*dv2(3)
235 u12(3) = dv1(1)*dv2(2)-dv1(2)*dv2(1)
236 u23(1) = dv2(2)*dv3(3)-dv2(3)*dv3(2)
237 u23(2) = dv2(3)*dv3(1)-dv2(1)*dv3(3)
238 u23(3) = dv2(1)*dv3(2)-dv2(2)*dv3(1)
239 u31(1) = dv3(2)*dv1(3)-dv3(3)*dv1(2)
240 u31(2) = dv3(3)*dv1(1)-dv3(1)*dv1(3)
241 u31(3) = dv3(1)*dv1(2)-dv3(2)*dv1(1)
242 
243 ! Normalize Uij to unit vectors
244 s12 = dot_product(u12,u12)
245 s23 = dot_product(u23,u23)
246 s31 = dot_product(u31,u31)
247 
248 ! Test for a degenerate triangle associated with collinear vertices
249 if ((.not.(abs(s12)>zero)).or.(.not.(abs(s23)>zero)).or.(.not.(abs(s31)>zero))) then
250  area = zero
251 else
252  s12 = sqrt(s12)
253  s23 = sqrt(s23)
254  s31 = sqrt(s31)
255  u12 = u12/s12
256  u23 = u23/s23
257  u31 = u31/s31
258 
259  ! Compute interior angles Ai as the dihedral angles between planes
260  ca1 = -dot_product(u12,u31)
261  ca2 = -dot_product(u23,u12)
262  ca3 = -dot_product(u31,u23)
263  ca1 = max(ca1,-one)
264  ca1 = min(ca1,+one)
265  ca2 = max(ca2,-one)
266  ca2 = min(ca2,+one)
267  ca3 = max(ca3,-one)
268  ca3 = min(ca3,+one)
269  a1 = acos(ca1)
270  a2 = acos(ca2)
271  a3 = acos(ca3)
272 
273  ! Compute area = a1 + a2 + a3 - pi
274  area = a1+a2+a3-pi
275  if (area<zero) area = zero
276 end if
277 
278 ! Probe out
279 
280 
281 end subroutine stripack_area
282 
283 
284 !----------------------------------------------------------------------
285 ! Subroutine: stripack_bdyadd
286 !> Add a boundary node to a triangulation
287 !----------------------------------------------------------------------
288 subroutine stripack_bdyadd(kk,i1,i2,list,lptr,lend,lnew)
289 
290 implicit none
291 
292 ! Passed variable
293 integer,intent(in) :: kk !< Index of a node to be connected to the sequence of all visible boundary nodes. 1<=KK and KK must not be equal to I1 or I2.
294 integer,intent(in) :: i1 !< First (rightmost as viewed from KK) boundary node in the triangulation that is visible from node KK (the line segment KK-I1 intersects no arcs.
295 integer,intent(in) :: i2 !< Last (leftmost) boundary node that is visible from node KK. I1 and I2 may be determined by TRFIND.
296 integer,intent(inout) :: list(*) !< Triangulation data structure created by TRMESH. Nodes I1 and I2 must be included in the triangulation. On output, the data structure is updated with the addition of node KK. Node KK is connected to I1, I2, and all boundary nodes in between.
297 integer,intent(inout) :: lptr(*) !< cf. list
298 integer,intent(inout) :: lend(*) !< cf. list
299 integer,intent(inout) :: lnew !< cf. list
300 
301 ! Local variables
302 integer :: k,lp,lsav,n1,n2,next,nsav
303 
304 ! Set name
305 
306 
307 ! Probe in
308 
309 
310 ! Initialization
311 k = kk
312 n1 = i1
313 n2 = i2
314 
315 ! Add K as the last neighbor of N1.
316 lp = lend(n1)
317 lsav = lptr(lp)
318 lptr(lp) = lnew
319 list(lnew) = -k
320 lptr(lnew) = lsav
321 lend(n1) = lnew
322 lnew = lnew+1
323 next = -list(lp)
324 list(lp) = next
325 nsav = next
326 
327 ! Loop on the remaining boundary nodes between N1 and N2, adding K as the first neighbor.
328 do
329  lp = lend(next)
330  call insert(k,lp,list,lptr,lnew)
331  if (next==n2) exit
332  next = -list(lp)
333  list(lp) = next
334 end do
335 
336 ! Add the boundary nodes between N1 and N2 as neighbors of node K.
337 lsav = lnew
338 list(lnew) = n1
339 lptr(lnew) = lnew+1
340 lnew = lnew+1
341 next = nsav
342 do
343  if (next==n2) exit
344  list(lnew) = next
345  lptr(lnew) = lnew+1
346  lnew = lnew+1
347  lp = lend(next)
348  next = list(lp)
349 end do
350 list(lnew) = -n2
351 lptr(lnew) = lsav
352 lend(k) = lnew
353 lnew = lnew+1
354 
355 ! Probe out
356 
357 
358 end subroutine stripack_bdyadd
359 
360 !----------------------------------------------------------------------
361 ! Subroutine: stripack_bnodes
362 !> Return the boundary nodes of a triangulation
363 !----------------------------------------------------------------------
364 subroutine stripack_bnodes(n,list,lptr,lend,nodes,nb)
365 
366 implicit none
367 
368 ! Passed variables
369 integer,intent(in) :: n !< Number of nodes in the triangulation. 3 <= N.
370 integer,intent(in) :: list(6*(n-2)) !< The data structure defining the triangulation, created by TRMESH.
371 integer,intent(in) :: lptr(6*(n-2)) !< cf. list
372 integer,intent(in) :: lend(n) !< cf. list
373 integer,intent(out) :: nodes(n) !< Ordered sequence of NB boundary node indexes in the range 1 to N.
374 integer,intent(out) :: nb !< Number of boundary nodes.
375 
376 ! Local variables
377 integer :: i,k,lp,n0,na,nn,nst,nt
378 
379 ! Set name
380 
381 
382 ! Initialization
383 nn = n
384 
385 ! Search for a boundary node
386 nst = 0
387 do i = 1, nn
388  lp = lend(i)
389  if (list(lp)<0) then
390  nst = i
391  exit
392  end if
393 end do
394 
395 ! The triangulation contains no boundary nodes
396 if (nst==0) then
397  nb = 0
398  na = 3*(nn-2)
399  nt = 2*(nn-2)
400 
401  return
402 end if
403 
404 ! NST is the first boundary node encountered
405 ! Initialize for traversal of the boundary
406 nodes(1) = nst
407 k = 1
408 n0 = nst
409 
410 ! Traverse the boundary in counterclockwise order
411 do
412  lp = lend(n0)
413  lp = lptr(lp)
414  n0 = list(lp)
415  if (n0==nst) then
416  exit
417  end if
418  k = k+1
419  nodes(k) = n0
420 end do
421 
422 ! Store the counts
423 nb = k
424 nt = 2*n-nb-2
425 na = nt+n-1
426 
427 ! Probe out
428 
429 
430 end subroutine stripack_bnodes
431 
432 !----------------------------------------------------------------------
433 ! Subroutine: stripack_covsph
434 !> Connect an exterior node to boundary nodes, covering the sphere
435 !----------------------------------------------------------------------
436 subroutine stripack_covsph(kk,n0,list,lptr,lend,lnew)
437 
438 implicit none
439 
440 ! Passed variables
441 integer,intent(in) :: kk !< Index of the node to be connected to the set of all boundary nodes. 4<=KK.
442 integer,intent(in) :: n0 !< Index of a boundary node (in the range 1 to KK-1). N0 may be determined by TRFIND.
443 integer,intent(inout) :: list(*) !< Triangulation data structure created by TRMESH. Node N0 must be included in the triangulation. On output, updated with the addition of node KK as the last entry. The updated triangulation contains no boundary nodes.
444 integer,intent(inout) :: lptr(*) !< cf. list
445 integer,intent(inout) :: lend(*) !< cf. list
446 integer,intent(inout) :: lnew !< cf. list
447 
448 ! Local variables
449 integer :: k,lp,lsav,next,nst
450 
451 ! Set name
452 
453 
454 ! Probe in
455 
456 
457 ! Initialization
458 k = kk
459 nst = n0
460 
461 ! Traverse the boundary in clockwise order, inserting K as the first neighbor of each boundary node, and converting the boundary node to an interior node.
462 next = nst
463 do
464  lp = lend(next)
465  call insert(k,lp,list,lptr,lnew)
466  next = -list(lp)
467  list(lp) = next
468  if (next==nst) exit
469 end do
470 
471 ! Traverse the boundary again, adding each node to K's adjacency list.
472 lsav = lnew
473 do
474  lp = lend(next)
475  list(lnew) = next
476  lptr(lnew) = lnew+1
477  lnew = lnew+1
478  next = list(lp)
479  if (next==nst) exit
480 end do
481 lptr(lnew-1) = lsav
482 lend(k) = lnew-1
483 
484 ! Probe out
485 
486 
487 end subroutine stripack_covsph
488 
489 !----------------------------------------------------------------------
490 ! Subroutine: stripack_det
491 !> Compute 3D determinant
492 !----------------------------------------------------------------------
493 subroutine stripack_det(x1,y1,z1,x2,y2,z2,x0,y0,z0,output)
494 
495 implicit none
496 
497 ! Passed variables
498 real(kind_real),intent(in) :: x1 !< X-coordinate, term 1
499 real(kind_real),intent(in) :: y1 !< Y-coordinate, term 1
500 real(kind_real),intent(in) :: z1 !< Z-coordinate, term 1
501 real(kind_real),intent(in) :: x2 !< X-coordinate, term 2
502 real(kind_real),intent(in) :: y2 !< Y-coordinate, term 2
503 real(kind_real),intent(in) :: z2 !< Z-coordinate, term 2
504 real(kind_real),intent(in) :: x0 !< X-coordinate, term 0
505 real(kind_real),intent(in) :: y0 !< Y-coordinate, term 0
506 real(kind_real),intent(in) :: z0 !< Z-coordinate, term 0
507 real(kind_real),intent(out) :: output !< Determinant
508 
509 ! Local variables
510 real(kind_real) :: t1,t2,t3
511 
512 ! Set name
513 
514 
515 ! Probe in
516 
517 
518 ! Compute determinant terms
519 t1 = x0*(y1*z2-y2*z1)
520 t2 = y0*(x1*z2-x2*z1)
521 t3 = z0*(x1*y2-x2*y1)
522 
523 ! Determinant
524 output = t1-t2+t3
525 
526 ! Indistinguishability threshold for cross-platform reproducibility
527 if (small(output,t1).or.small(output,t2).or.small(output,t3)) output = zero
528 
529 ! Probe out
530 
531 
532 end subroutine stripack_det
533 
534 !----------------------------------------------------------------------
535 ! Subroutine: stripack_insert
536 !> Insert K as a neighbor of N1
537 !----------------------------------------------------------------------
538 subroutine stripack_insert(k,lp,list,lptr,lnew)
539 
540 implicit none
541 
542 ! Passed variables
543 integer,intent(in) :: k !< Index of the node to be inserted.
544 integer,intent(in) :: lp !< LIST pointer of N2 as a neighbor of N1.
545 integer,intent(inout) :: list(*) !< Triangulation data structure created by TRMESH. On output, updated with the addition of node K.
546 integer,intent(inout) :: lptr(*) !< cf. list
547 integer,intent(inout) :: lnew !< cf. list
548 
549 ! Local variables
550 integer :: lsav
551 
552 ! Set name
553 
554 
555 ! Probe in
556 
557 
558 lsav = lptr(lp)
559 lptr(lp) = lnew
560 list(lnew) = k
561 lptr(lnew) = lsav
562 lnew = lnew+1
563 
564 ! Probe out
565 
566 
567 end subroutine stripack_insert
568 
569 !----------------------------------------------------------------------
570 ! Subroutine: stripack_intadd
571 !> Add an interior node to a triangulation
572 !----------------------------------------------------------------------
573 subroutine stripack_intadd(kk,i1,i2,i3,list,lptr,lend,lnew)
574 
575 implicit none
576 
577 ! Passed variables
578 integer,intent(in) :: kk !< Index of the node to be inserted. 1<=KK and KK must not be equal to I1, I2, or I3.
579 integer,intent(in) :: i1 !< First index of the counterclockwise-ordered sequence of vertices of a triangle which contains node KK.
580 integer,intent(in) :: i2 !< Second index.
581 integer,intent(in) :: i3 !< Third index.
582 integer,intent(inout) :: list(*) !< Triangulation data structure created by TRMESH. Triangle (I1,I2,I3) must be included in the triangulation. On output, updated with the addition of node KK. KK will be connected to nodes I1, I2, and I3.
583 integer,intent(inout) :: lptr(*) !< cf. list
584 integer,intent(inout) :: lend(*) !< cf. list
585 integer,intent(inout) :: lnew !< cf. list
586 
587 ! Local variables
588 integer :: k,lp,n1,n2,n3
589 
590 ! Set name
591 
592 
593 ! Probe in
594 
595 
596 ! Initialization.
597 k = kk
598 n1 = i1
599 n2 = i2
600 n3 = i3
601 
602 ! Add K as a neighbor of I1, I2, and I3.
603 call lstptr(lend(n1),n2,list,lptr,lp)
604 call insert(k,lp,list,lptr,lnew)
605 call lstptr(lend(n2),n3,list,lptr,lp)
606 call insert(k,lp,list,lptr,lnew)
607 call lstptr(lend(n3),n1,list,lptr,lp)
608 call insert(k,lp,list,lptr,lnew)
609 
610 ! Add I1, I2, and I3 as neighbors of K.
611 list(lnew) = n1
612 list(lnew+1) = n2
613 list(lnew+2) = n3
614 lptr(lnew) = lnew+1
615 lptr(lnew+1) = lnew+2
616 lptr(lnew+2) = lnew
617 lend(k) = lnew+2
618 lnew = lnew+3
619 
620 ! Probe out
621 
622 
623 end subroutine stripack_intadd
624 
625 !----------------------------------------------------------------------
626 ! Subroutine: stripack_jrand
627 !> Return a random integer between 1 and N
628 !----------------------------------------------------------------------
629 subroutine stripack_jrand(n,ix,iy,iz,output)
630 
631 implicit none
632 
633 ! Passed variables
634 integer,intent(in) :: n !< Maximum value to be returned.
635 integer,intent(inout) :: ix !< First seed initialized to values in the range 1 to 30,000 before the first call to JRAND, and not altered between subsequent calls (unless a sequence of random numbers is to be repeated by reinitializing the seeds).
636 integer,intent(inout) :: iy !< Second seed.
637 integer,intent(inout) :: iz !< Third seed.
638 integer,intent(out) :: output !< A random integer in the range 1 to N.
639 
640 ! Local variables
641 real(kind_real) :: u,x
642 
643 ! Set name
644 
645 
646 ! Probe in
647 
648 
649 ! Initialization
650 ix = mod(171*ix,30269)
651 iy = mod(172*iy,30307)
652 iz = mod(170*iz,30323)
653 
654 ! Get x
655 x = (real(ix,kind_real)/30269.0_kind_real) &
656  & + (real(iy,kind_real)/30307.0_kind_real) &
657  & + (real(iz,kind_real)/30323.0_kind_real)
658 
659 ! Get u
660 u = x-int(x)
661 
662 ! Random integer
663 output = int(real(n,kind_real)*u)+1
664 
665 ! Probe out
666 
667 
668 end subroutine stripack_jrand
669 
670 !----------------------------------------------------------------------
671 ! Subroutine: stripack_left
672 !> Determine whether a node is to the left of a plane through the origin
673 !----------------------------------------------------------------------
674 subroutine stripack_left(x1,y1,z1,x2,y2,z2,x0,y0,z0,output)
675 
676 implicit none
677 
678 ! Passed variables
679 real(kind_real),intent(in) :: x1 !< X-coordinate, term 1
680 real(kind_real),intent(in) :: y1 !< Y-coordinate, term 1
681 real(kind_real),intent(in) :: z1 !< Z-coordinate, term 1
682 real(kind_real),intent(in) :: x2 !< X-coordinate, term 2
683 real(kind_real),intent(in) :: y2 !< Y-coordinate, term 2
684 real(kind_real),intent(in) :: z2 !< Z-coordinate, term 2
685 real(kind_real),intent(in) :: x0 !< X-coordinate, term 0
686 real(kind_real),intent(in) :: y0 !< Y-coordinate, term 0
687 real(kind_real),intent(in) :: z0 !< Z-coordinate, term 0
688 logical,intent(out) :: output !< TRUE if and only if N0 is in the closed left hemisphere.
689 
690 ! Local variables
691 real(kind_real) :: zz
692 
693 ! Set name
694 
695 
696 ! Probe in
697 
698 
699 ! LEFT = TRUE iff <N0,N1 X N2> = det(N0,N1,N2) >= 0.
700 call det(x1,y1,z1,x2,y2,z2,x0,y0,z0,zz)
701 output = sup(zz,zero)
702 
703 ! Probe out
704 
705 
706 end subroutine stripack_left
707 
708 !----------------------------------------------------------------------
709 ! Subroutine: stripack_lstptr
710 !> Return the index of NB in the adjacency list
711 !----------------------------------------------------------------------
712 subroutine stripack_lstptr(lpl,nb,list,lptr,output)
713 
714 implicit none
715 
716 ! Passed variables
717 integer,intent(in) :: lpl !< Equal to LEND(N0).
718 integer,intent(in) :: nb !< Index of the node whose pointer is to be returned. NB must be connected to N0.
719 integer,intent(in) :: list(*) !< Triangulation data structure created by TRMESH. Triangle (I1,I2,I3) must be included in the triangulation. On output, updated with the addition of node KK. KK will be connected to nodes I1, I2, and I3.
720 integer,intent(in) :: lptr(*) !< cf. list
721 integer,intent(out) :: output !< Pointer such that LIST(output) = NB or LIST(output) = -NB, unless NB is not a neighbor of N0, in which case output = LPL.
722 
723 ! Local variables
724 integer :: lp,nd
725 
726 ! Set name
727 
728 
729 ! Probe in
730 
731 
732 ! Initialization
733 lp = lptr(lpl)
734 
735 do
736  nd = list(lp)
737  if (nd==nb) exit
738  lp = lptr(lp)
739  if (lp==lpl) exit
740 end do
741 output = lp
742 
743 ! Probe out
744 
745 
746 end subroutine stripack_lstptr
747 
748 !----------------------------------------------------------------------
749 ! Subroutine: stripack_swap
750 !> Replace the diagonal arc of a quadrilateral with the other diagonal
751 !----------------------------------------------------------------------
752 subroutine stripack_swap(in1,in2,io1,io2,list,lptr,lend,lp21)
753 
754 implicit none
755 
756 ! Passed variables
757 integer,intent(in) :: in1 !< First nodal index of the vertices of the quadrilateral. IO1-IO2 is replaced by IN1-IN2. (IO1,IO2,IN1) and (IO2,IO1,IN2) must be triangles on input.
758 integer,intent(in) :: in2 !< Second nodal index.
759 integer,intent(in) :: io1 !< Third nodal index.
760 integer,intent(in) :: io2 !< Fourth nodal index.
761 integer,intent(inout) :: list(*) !< Triangulation data structure created by TRMESH. On output, updated with the swap; triangles (IO1,IO2,IN1) an (IO2,IO1,IN2) are replaced by (IN1,IN2,IO2) and (IN2,IN1,IO1) unless LP21 = 0.
762 integer,intent(inout) :: lptr(*) !< cf. list
763 integer,intent(inout) :: lend(*) !< cf. list
764 integer,intent(out) :: lp21 !< Index of IN1 as a neighbor of IN2 after the swap is performed unless IN1 and IN2 are adjacent on input, in which case LP21 = 0.
765 
766 ! Local variables
767 integer :: lp,lph,lpsav
768 
769 ! Set name
770 
771 
772 ! Probe in
773 
774 
775 ! Test for IN1 and IN2 adjacent.
776 call lstptr(lend(in1),in2,list,lptr,lp)
777 if (abs(list(lp))==in2) then
778  lp21 = 0
779 
780  return
781 end if
782 
783 ! Delete IO2 as a neighbor of IO1.
784 call lstptr(lend(io1),in2,list,lptr,lp)
785 lph = lptr(lp)
786 lptr(lp) = lptr(lph)
787 
788 ! If IO2 is the last neighbor of IO1, make IN2 the last neighbor.
789 if (lend(io1)==lph) lend(io1) = lp
790 
791 ! Insert IN2 as a neighbor of IN1 following IO1 using the hole created above.
792 call lstptr(lend(in1),io1,list,lptr,lp)
793 lpsav = lptr(lp)
794 lptr(lp) = lph
795 list(lph) = in2
796 lptr(lph) = lpsav
797 
798 ! Delete IO1 as a neighbor of IO2.
799 call lstptr(lend(io2),in1,list,lptr,lp)
800 lph = lptr(lp)
801 lptr(lp) = lptr(lph)
802 
803 ! If IO1 is the last neighbor of IO2, make IN1 the last neighbor.
804 if (lend(io2)==lph) lend(io2) = lp
805 
806 ! Insert IN1 as a neighbor of IN2 following IO2.
807 call lstptr(lend(in2),io2,list,lptr,lp)
808 lpsav = lptr(lp)
809 lptr(lp) = lph
810 list(lph) = in1
811 lptr(lph) = lpsav
812 lp21 = lph
813 
814 ! Probe out
815 
816 
817 end subroutine stripack_swap
818 
819 !----------------------------------------------------------------------
820 ! Subroutine: stripack_swptst
821 !> Decide whether to replace a diagonal arc by the other
822 !----------------------------------------------------------------------
823 subroutine stripack_swptst(n1,n2,n3,n4,x,y,z,output)
824 
825 implicit none
826 
827 integer,intent(in) :: n1 !< First index of the four nodes defining the quadrilateral with N1 adjacent to N2, and (N1,N2,N3) in counterclockwise order. The arc connecting N1 to N2 should be replaced by an arc connecting N3 to N4 if SWPTST = TRUE. Refer to subroutine SWAP.
828 integer,intent(in) :: n2 !< Second index.
829 integer,intent(in) :: n3 !< Third index.
830 integer,intent(in) :: n4 !< Fourth index.
831 real(kind_real),intent(in) :: x(*) !< X-coordinate of the nodes.
832 real(kind_real),intent(in) :: y(*) !< Y-coordinate of the nodes.
833 real(kind_real),intent(in) :: z(*) !< Z-coordinate of the nodes.
834 logical,intent(out) :: output !< TRUE if and only if the arc connecting N1 and N2 should be swapped for an arc connecting N3 and N4.
835 
836 ! Local variables
837 real(kind_real) :: dx1,dx2,dx3,dy1,dy2,dy3,dz1,dz2,dz3,x4,y4,z4,zz
838 
839 ! Set name
840 
841 
842 ! Probe in
843 
844 
845 ! Initialization
846 x4 = x(n4)
847 y4 = y(n4)
848 z4 = z(n4)
849 dx1 = x(n1)-x4
850 dx2 = x(n2)-x4
851 dx3 = x(n3)-x4
852 dy1 = y(n1)-y4
853 dy2 = y(n2)-y4
854 dy3 = y(n3)-y4
855 dz1 = z(n1)-z4
856 dz2 = z(n2)-z4
857 dz3 = z(n3)-z4
858 
859 ! N4 lies above the plane of (N1,N2,N3) iff N3 lies above the plane of (N2,N1,N4) iff Det(N3-N4,N2-N4,N1-N4) = (N3-N4,N2-N4 X N1-N4) > 0.
860 call det(dx2,dy2,dz2,dx1,dy1,dz1,dx3,dy3,dz3,zz)
861 output = sup(zz,zero)
862 
863 ! Probe out
864 
865 
866 end subroutine stripack_swptst
867 
868 !----------------------------------------------------------------------
869 ! Subroutine: stripack_trfind
870 !> Locate a point relative to a triangulation
871 !----------------------------------------------------------------------
872 subroutine stripack_trfind(nst,p,n,x,y,z,list,lptr,lend,b1,b2,b3,i1,i2,i3)
873 
874 implicit none
875 
876 integer,intent(in) :: nst !< Index of a node at which TRFIND begins its search. Search time depends on the proximity of this node to P.
877 real(kind_real) :: p(3) !< X, Y, and Z coordinates (in that order) of the point P to be located.
878 integer,intent(in) :: n !< Number of nodes in the triangulation 3<=N.
879 real(kind_real),intent(in) :: x(n) !< X-coordinate of the triangulation nodes (unit vector).
880 real(kind_real),intent(in) :: y(n) !< Y-coordinate of the triangulation nodes (unit vector).
881 real(kind_real),intent(in) :: z(n) !< Z-coordinate of the triangulation nodes (unit vector).
882 integer,intent(in) :: list(*) !< Triangulation data structure created by TRMESH.
883 integer,intent(in) :: lptr(*) !< cf. list
884 integer,intent(in) :: lend(*) !< cf. list
885 real(kind_real),intent(out) :: b1 !< First unnormalized barycentric coordinate of the central projection of P onto the underlying planar triangle if P is in the convex hull of the nodes. These parameters are not altered if I1 = 0.
886 real(kind_real),intent(out) :: b2 !< Second unnormalized barycentric coordinate.
887 real(kind_real),intent(out) :: b3 !< Third unnormalized barycentric coordinate.
888 integer,intent(out) :: i1 !< First counterclockwise-ordered vertex index of a triangle containing P if P is contained in a triangle. If P is not in the convex hull of the nodes, I1 and I2 are the rightmost and leftmost (boundary) nodes that are visible from P, and I3 = 0. (If all boundary nodes are visible from P, then I1 and I2 coincide.) I1 = I2 = I3 = 0 if P and all of the nodes are coplanar (lie on a common great circle).
889 integer,intent(out) :: i2 !< Second counterclockwise-ordered vertex index.
890 integer,intent(out) :: i3 !< Third counterclockwise-ordered vertex index.
891 
892 ! Local variables
893 integer :: lp,n0,n1,n1s,n2,n2s,n3,n4,next,nf,nl
894 integer,save :: ix = 1,iy = 2,iz = 3
895 real(kind_real) :: output,eps,ptn1,ptn2,q(3),s12,tol,xp,yp,zp
896 
897 ! Set name
898 
899 
900 ! Probe in
901 
902 
903 ! Initialize variables.
904 xp = p(1)
905 yp = p(2)
906 zp = p(3)
907 n0 = nst
908 if ((n0<1).or.(n<n0)) call jrand(n,ix,iy,iz,n0)
909 
910 ! Compute the relative machine precision EPS and TOL.
911 eps = epsilon(eps)
912 tol = hundred*eps
913 
914 ! Set NF and NL to the first and last neighbors of N0, and initialize N1 = NF.
915 2 continue
916 lp = lend(n0)
917 nl = list(lp)
918 lp = lptr(lp)
919 nf = list(lp)
920 n1 = nf
921 
922 ! Find a pair of adjacent neighbors N1,N2 of N0 that define a wedge containing P: P LEFT N0->N1 and P RIGHT N0->N2.
923 if (0<nl) then
924  ! N0 is an interior node. Find N1.
925  3 continue
926  call det(x(n0),y(n0),z(n0),x(n1),y(n1),z(n1),xp,yp,zp,output)
927  if (inf(output,zero)) then
928  lp = lptr(lp)
929  n1 = list(lp)
930  if (n1 == nl) go to 6
931  go to 3
932  end if
933 else
934  ! N0 is a boundary node. Test for P exterior.
935  nl = -nl
936 
937  ! Is P to the right of the boundary edge N0->NF?
938  call det(x(n0),y(n0),z(n0),x(nf),y(nf),z(nf),xp,yp,zp,output)
939  if (inf(output,zero)) then
940  n1 = n0
941  n2 = nf
942  go to 9
943  end if
944 
945  ! Is P to the right of the boundary edge NL->N0?
946  call det(x(nl),y(nl),z(nl),x(n0),y(n0),z(n0),xp,yp,zp,output)
947  if (inf(output,zero)) then
948  n1 = nl
949  n2 = n0
950  go to 9
951  end if
952 end if
953 
954 ! P is to the left of arcs N0->N1 and NL->N0. Set N2 to the next neighbor of N0 (following N1).
955 4 continue
956 lp = lptr(lp)
957 n2 = abs(list(lp))
958 call det(x(n0),y(n0),z(n0),x(n2),y(n2),z(n2),xp,yp,zp,output)
959 if (inf(output,zero)) go to 7
960 n1 = n2
961 if (n1/=nl) go to 4
962 call det(x(n0),y(n0),z(n0),x(nf),y(nf),z(nf),xp,yp,zp,output)
963 if (inf(output,zero)) go to 6
964 
965 ! P is left of or on arcs N0->NB for all neighbors NB of N0. Test for P = +/-N0.
966 if (inf(abs(x(n0)*xp+y(n0)*yp+z(n0)*zp),one-four*eps)) then
967  ! All points are collinear iff P Left NB->N0 for all neighbors NB of N0. Search the neighbors of N0. Note: N1 = NL and LP points to NL.
968  do
969  call det(x(n1),y(n1),z(n1),x(n0),y(n0),z(n0),xp,yp,zp,output)
970  if (inf(output,zero)) exit
971  lp = lptr(lp)
972  n1 = abs(list(lp))
973  if (n1==nl) then
974  i1 = 0
975  i2 = 0
976  i3 = 0
977 
978  return
979  end if
980  end do
981 end if
982 
983 ! P is to the right of N1->N0, or P = +/-N0. Set N0 to N1 and start over.
984 n0 = n1
985 go to 2
986 
987 ! P is between arcs N0->N1 and N0->NF.
988 6 continue
989 n2 = nf
990 
991 ! P is contained in a wedge defined by geodesics N0-N1 and N0-N2, where N1 is adjacent to N2. Save N1 and N2 to test for cycling.
992 7 continue
993 n3 = n0
994 n1s = n1
995 n2s = n2
996 
997 ! Top of edge-hopping loop:
998 8 continue
999 call det(x(n1),y(n1),z(n1),x(n2),y(n2),z(n2),xp,yp,zp,b3)
1000 if (inf(b3,zero)) then
1001  ! Set N4 to the first neighbor of N2 following N1 (the node opposite N2->N1) unless N1->N2 is a boundary arc.
1002  call lstptr(lend(n2),n1,list,lptr,lp)
1003  if (list(lp)<0) go to 9
1004  lp = lptr(lp)
1005  n4 = abs(list(lp))
1006 
1007  ! Define a new arc N1->N2 which intersects the geodesic N0-P.
1008  call det(x(n0),y(n0),z(n0),x(n4),y(n4),z(n4),xp,yp,zp,output)
1009  if (inf(output,zero)) then
1010  n3 = n2
1011  n2 = n4
1012  n1s = n1
1013  if ((n2/=n2s).and.(n2/=n0)) go to 8
1014  else
1015  n3 = n1
1016  n1 = n4
1017  n2s = n2
1018  if ((n1/=n1s).and.(n1/=n0)) go to 8
1019  end if
1020 
1021  ! The starting node N0 or edge N1-N2 was encountered again, implying a cycle (infinite loop). Restart with N0 randomly selected.
1022  call jrand(n,ix,iy,iz,n0)
1023  go to 2
1024 end if
1025 
1026 ! P is in (N1,N2,N3) unless N0, N1, N2, and P are collinear or P is close to -N0.
1027 if (supeq(b3,eps)) then
1028  ! B3 /= 0.
1029  call det(x(n2),y(n2),z(n2),x(n3),y(n3),z(n3),xp,yp,zp,b1)
1030  call det(x(n3),y(n3),z(n3),x(n1),y(n1),z(n1),xp,yp,zp,b2)
1031 
1032  ! Restart with N0 randomly selected.
1033  if (inf(b1,-tol).or.inf(b2,-tol)) then
1034  call jrand(n,ix,iy,iz,n0)
1035  go to 2
1036  end if
1037 else
1038  ! B3 = 0 and thus P lies on N1->N2. Compute B1 = Det(P,N2 X N1,N2) and B2 = Det(P,N1,N2 X N1).
1039  b3 = zero
1040  s12 = x(n1)*x(n2)+y(n1)*y(n2)+z(n1)*z(n2)
1041  ptn1 = xp*x(n1)+yp*y(n1)+zp*z(n1)
1042  ptn2 = xp*x(n2)+yp*y(n2)+zp*z(n2)
1043  b1 = ptn1-s12*ptn2
1044  b2 = ptn2-s12*ptn1
1045 
1046  ! Restart with N0 randomly selected.
1047  if (inf(b1,-tol).or.inf(b2,-tol)) then
1048  call jrand(n,ix,iy,iz,n0)
1049  go to 2
1050  end if
1051 end if
1052 
1053 ! P is in (N1,N2,N3).
1054 i1 = n1
1055 i2 = n2
1056 i3 = n3
1057 b1 = max(b1,zero)
1058 b2 = max(b2,zero)
1059 
1060 return
1061 
1062 ! P Right N1->N2, where N1->N2 is a boundary edge. Save N1 and N2, and set NL = 0 to indicate that NL has not yet been found.
1063 9 continue
1064 n1s = n1
1065 n2s = n2
1066 nl = 0
1067 
1068 ! Counterclockwise Boundary Traversal:
1069 10 continue
1070 lp = lend(n2)
1071 lp = lptr(lp)
1072 next = list(lp)
1073 call det(x(n2),y(n2),z(n2),x(next),y(next),z(next),xp,yp,zp,output)
1074 if (supeq(output,zero)) then
1075  ! N2 is the rightmost visible node if P Forward N2->N1 or NEXT Forward N2->N1. Set Q to (N2 X N1) X N2.
1076  s12 = x(n1)*x(n2)+y(n1)*y(n2)+z(n1)*z(n2)
1077  q(1) = x(n1)-s12*x(n2)
1078  q(2) = y(n1)-s12*y(n2)
1079  q(3) = z(n1)-s12*z(n2)
1080  if (sup(xp*q(1)+yp*q(2)+zp*q(3),zero).or.sup(x(next)*q(1)+y(next)*q(2)+z(next)*q(3),zero)) go to 11
1081 
1082  ! N1, N2, NEXT, and P are nearly collinear, and N2 is the leftmost visible node.
1083  nl = n2
1084 end if
1085 
1086 ! Bottom of counterclockwise loop:
1087 n1 = n2
1088 n2 = next
1089 if (n2/=n1s) go to 10
1090 
1091 ! All boundary nodes are visible from P.
1092 i1 = n1s
1093 i2 = n1s
1094 i3 = 0
1095 
1096 return
1097 
1098 ! N2 is the rightmost visible node.
1099 11 continue
1100 nf = n2
1101 if (nl==0) then
1102  ! Restore initial values of N1 and N2, and begin the search for the leftmost visible node.
1103  n2 = n2s
1104  n1 = n1s
1105 
1106  ! Clockwise Boundary Traversal:
1107  12 continue
1108  lp = lend(n1)
1109  next = -list(lp)
1110  call det(x(next),y(next),z(next),x(n1),y(n1),z(n1),xp,yp,zp,output)
1111  if (supeq(output,zero)) then
1112  ! N1 is the leftmost visible node if P or NEXT is forward of N1->N2. Compute Q = N1 X (N2 X N1).
1113  s12 = x(n1)*x(n2)+y(n1)*y(n2)+z(n1)*z(n2)
1114  q(1) = x(n2)-s12*x(n1)
1115  q(2) = y(n2)-s12*y(n1)
1116  q(3) = z(n2)-s12*z(n1)
1117  if (sup(xp*q(1)+yp*q(2)+zp*q(3),zero).or.sup(x(next)*q(1)+y(next)*q(2)+z(next)*q(3),zero)) go to 13
1118 
1119  ! P, NEXT, N1, and N2 are nearly collinear and N1 is the rightmost visible node.
1120  nf = n1
1121  end if
1122 
1123  ! Bottom of clockwise loop:
1124  n2 = n1
1125  n1 = next
1126  if (n1/=n1s) go to 12
1127 
1128  ! All boundary nodes are visible from P.
1129  i1 = n1
1130  i2 = n1
1131  i3 = 0
1132 
1133  return
1134 
1135  ! N1 is the leftmost visible node.
1136  13 continue
1137  nl = n1
1138 end if
1139 
1140 ! NF and NL have been found.
1141 i1 = nf
1142 i2 = nl
1143 i3 = 0
1144 
1145 ! Probe out
1146 
1147 
1148 end subroutine stripack_trfind
1149 
1150 !----------------------------------------------------------------------
1151 ! Subroutine: stripack_trmesh
1152 !> Create a Delaunay triangulation on the unit sphere
1153 !----------------------------------------------------------------------
1154 subroutine stripack_trmesh(mpl,n,x,y,z,list,lptr,lend,lnew,near,next,dist)
1155 
1156 implicit none
1157 
1158 type(mpl_type),intent(inout) :: mpl !< MPI data
1159 integer,intent(in) :: n !< Number of nodes in the triangulation. 3<=N.
1160 real(kind_real),intent(in) :: x(n) !< X-coordinate of distinct nodes. (X(K),Y(K), Z(K)) is referred to as node K, and K is referred to as a nodal index. It is required that X(K)**2+Y(K)**2+Z(K)**2 = 1 for all K. The first three nodes must not be colinear (lie on a common great circle).
1161 real(kind_real),intent(in) :: y(n) !< Y-coordinate of distinct nodes.
1162 real(kind_real),intent(in) :: z(n) !< Z-coordinate of distinct nodes.
1163 integer,intent(out) :: list(6*(n-2)) !< Nodal indexes which, along with LPTR, LEND, and LNEW, define the triangulation as a set of N adjacency lists; counterclockwise-ordered sequences of neighboring nodes such that the first and last neighbors of a boundary node are boundary nodes (the first neighbor of an interior node is arbitrary). In order to distinguish between interior and boundary nodes, the last neighbor of each boundary node is represented by the negative of its index.
1164 integer,intent(out) :: lptr(6*(n-2)) !< Set of pointers (LIST indexes) in one-to-one correspondence with the elements of LIST. LIST(LPTR(I)) indexes the node which follows LIST(I) in cyclical counterclockwise order (the first neighbor follows the last neighbor).
1165 integer,intent(out) :: lend(n) !< Pointers to adjacency lists. LEND(K) points to the last neighbor of node K. LIST(LEND(K))<0 if and only if K is a boundary node.
1166 integer,intent(out) :: lnew !< Pointer to the first empty location in LIST and LPTR (list length plus one).
1167 integer,intent(inout) :: near(n) !< Workspace used to efficiently determine the nearest triangulation node to each unprocessed node for use by ADDNOD.
1168 integer,intent(inout) :: next(n) !< Workspace used to efficiently determine the nearest triangulation node to each unprocessed node for use by ADDNOD.
1169 real(kind_real),intent(inout) :: dist(n) !< Workspace used to efficiently determine the nearest triangulation node to each unprocessed node for use by ADDNOD.
1170 
1171 ! Local variables
1172 integer :: i,i0,j,k,lp,lpl,nexti,nn
1173 real(kind_real) :: d,d1,d2,d3
1174 logical :: output_1,output_2
1175 
1176 ! Set name
1177 
1178 
1179 ! Probe in
1180 
1181 
1182 ! Initialization
1183 nn = n
1184 if (nn<3) call mpl%abort('stripack_trmesh','N < 3')
1185 list = 0
1186 lptr = 0
1187 lend = 0
1188 
1189 ! Store the first triangle in the linked list.
1190 call left(x(1),y(1),z(1),x(2),y(2),z(2),x(3),y(3),z(3),output_1)
1191 call left(x(2),y(2),z(2),x(1),y(1),z(1),x(3),y(3),z(3),output_2)
1192 
1193 if (.not.output_1) then
1194  ! The first triangle is (3,2,1) = (2,1,3) = (1,3,2).
1195  list(1) = 3
1196  lptr(1) = 2
1197  list(2) = -2
1198  lptr(2) = 1
1199  lend(1) = 2
1200 
1201  list(3) = 1
1202  lptr(3) = 4
1203  list(4) = -3
1204  lptr(4) = 3
1205  lend(2) = 4
1206 
1207  list(5) = 2
1208  lptr(5) = 6
1209  list(6) = -1
1210  lptr(6) = 5
1211  lend(3) = 6
1212 else if (.not.output_2) then
1213  ! The first triangle is (1,2,3): 3 Strictly Left 1->2, i.e., node 3 lies in the left hemisphere defined by arc 1->2.
1214  list(1) = 2
1215  lptr(1) = 2
1216  list(2) = -3
1217  lptr(2) = 1
1218  lend(1) = 2
1219 
1220  list(3) = 3
1221  lptr(3) = 4
1222  list(4) = -1
1223  lptr(4) = 3
1224  lend(2) = 4
1225 
1226  list(5) = 1
1227  lptr(5) = 6
1228  list(6) = -2
1229  lptr(6) = 5
1230  lend(3) = 6
1231 else
1232  ! The first three nodes are colinear.
1233  call mpl%abort('stripack_trmesh','The first three nodes are colinear')
1234 end if
1235 
1236 ! Initialize LNEW and test for N = 3.
1237 lnew = 7
1238 if (nn==3) then
1239 
1240  return
1241 end if
1242 
1243 ! A nearest-node data structure (NEAR, NEXT, and DIST) is used to obtain an expected-time (N*log(N)) incremental algorithm by enabling constant search time for locating each new node in the triangulation. For each unprocessed node K, NEAR(K) is the index of the triangulation node closest to K (used as the starting point for the search in Subroutine TRFIND) and DIST(K) is an increasing function of the arc length (angular distance) between nodes K and NEAR(K): -cos(a) for arc length a. Since it is necessary to efficiently find the subset of unprocessed nodes associated with each triangulation node J (those that have J as their NEAR entries), the subsets are stored in NEAR and NEXT as follows: for each node J in the triangulation, I = NEAR(J) is the first unprocessed node in J's set (with I = 0 if the set is empty), L = NEXT(I) (if 0<I) is the second, NEXT(L) (if 0<L) is the third, etc. The nodes in each set are initially ordered by increasing indexes (which maximizes efficiency) but that ordering is not maintained as the data structure is updated.
1244 
1245 ! Initialize the data structure for the single triangle.
1246 near(1) = 0
1247 near(2) = 0
1248 near(3) = 0
1249 do k=nn,4,-1
1250  d1 = -(x(k)*x(1)+y(k)*y(1)+z(k)*z(1))
1251  d2 = -(x(k)*x(2)+y(k)*y(2)+z(k)*z(2))
1252  d3 = -(x(k)*x(3)+y(k)*y(3)+z(k)*z(3))
1253  if (inf(d1,d2).and.inf(d1,d3)) then
1254  near(k) = 1
1255  dist(k) = d1
1256  next(k) = near(1)
1257  near(1) = k
1258  else if (inf(d2,d1).and.inf(d2,d3)) then
1259  near(k) = 2
1260  dist(k) = d2
1261  next(k) = near(2)
1262  near(2) = k
1263  else
1264  near(k) = 3
1265  dist(k) = d3
1266  next(k) = near(3)
1267  near(3) = k
1268  end if
1269 end do
1270 
1271 ! Add the remaining nodes.
1272 do k=4,nn
1273  call addnod(mpl,near(k),k,x,y,z,list,lptr,lend,lnew)
1274 
1275  ! Remove K from the set of unprocessed nodes associated with NEAR(K).
1276  i = near(k)
1277  i0 = i
1278  if (near(i)==k) then
1279  near(i) = next(k)
1280  else
1281  i = near(i)
1282  do
1283  i0 = i
1284  i = next(i0)
1285  if (i==k) exit
1286  end do
1287  next(i0) = next(k)
1288  end if
1289  near(k) = 0
1290 
1291  ! Loop on neighbors J of node K.
1292  lpl = lend(k)
1293  lp = lpl
1294  3 continue
1295  lp = lptr(lp)
1296  j = abs(list(lp))
1297 
1298  ! Loop on elements I in the sequence of unprocessed nodes associated with J: K is a candidate for replacing J as the nearest triangulation node to I. The next value of I in the sequence, NEXT(I), must be saved before I is moved because it is altered by adding I to K's set.
1299  i = near(j)
1300  do
1301  if (i==0) exit
1302  nexti = next(i)
1303 
1304  ! Test for the distance from I to K less than the distance from I to J. Indistinguishability threshold for cross-platform reproducibility
1305  d =-(x(i)*x(k)+y(i)*y(k)+z(i)*z(k))
1306  if (inf(d,dist(i))) then
1307  ! Replace J by K as the nearest triangulation node to I: update NEAR(I) and DIST(I), and remove I from J's set of unprocessed nodes and add it to K's set.
1308  near(i) = k
1309  dist(i) = d
1310  if (i==near(j)) then
1311  near(j) = nexti
1312  else
1313  next(i0) = nexti
1314  end if
1315  next(i) = near(k)
1316  near(k) = i
1317  else
1318  i0 = i
1319  end if
1320  i = nexti
1321  end do
1322 
1323  ! Bottom of loop on neighbors J.
1324  if (lp/=lpl) go to 3
1325 end do
1326 
1327 ! Probe out
1328 
1329 
1330 end subroutine stripack_trmesh
1331 
1332 end module tools_stripack
Subroutines/functions list.
Definition: tools_const.F90:31
real(kind_real), parameter, public one
One.
Definition: tools_const.F90:42
real(kind_real), parameter, public pi
Pi.
Definition: tools_const.F90:51
real(kind_real), parameter, public zero
Zero.
Definition: tools_const.F90:37
real(kind_real), parameter, public hundred
Hundred.
Definition: tools_const.F90:49
real(kind_real), parameter, public four
Four.
Definition: tools_const.F90:45
Kinds definition.
Definition: tools_kinds.F90:9
integer, parameter, public kind_real
Real kind alias for the whole code.
Definition: tools_kinds.F90:25
Generic ranks, dimensions and types.
Definition: tools_repro.F90:42
Subroutines/functions list.
subroutine stripack_trmesh(mpl, n, x, y, z, list, lptr, lend, lnew, near, next, dist)
Create a Delaunay triangulation on the unit sphere.
subroutine stripack_bdyadd(kk, i1, i2, list, lptr, lend, lnew)
Add a boundary node to a triangulation.
subroutine stripack_swap(in1, in2, io1, io2, list, lptr, lend, lp21)
Replace the diagonal arc of a quadrilateral with the other diagonal.
subroutine stripack_insert(k, lp, list, lptr, lnew)
Insert K as a neighbor of N1.
subroutine stripack_jrand(n, ix, iy, iz, output)
Return a random integer between 1 and N.
subroutine stripack_covsph(kk, n0, list, lptr, lend, lnew)
Connect an exterior node to boundary nodes, covering the sphere.
subroutine stripack_area(v1, v2, v3, area)
Compute the area of a spherical triangle.
subroutine stripack_bnodes(n, list, lptr, lend, nodes, nb)
Return the boundary nodes of a triangulation.
subroutine stripack_intadd(kk, i1, i2, i3, list, lptr, lend, lnew)
Add an interior node to a triangulation.
subroutine stripack_trfind(nst, p, n, x, y, z, list, lptr, lend, b1, b2, b3, i1, i2, i3)
Locate a point relative to a triangulation.
subroutine stripack_addnod(mpl, nst, k, x, y, z, list, lptr, lend, lnew)
Add a node to a triangulation.
subroutine stripack_swptst(n1, n2, n3, n4, x, y, z, output)
Decide whether to replace a diagonal arc by the other.
subroutine stripack_det(x1, y1, z1, x2, y2, z2, x0, y0, z0, output)
Compute 3D determinant.
subroutine stripack_left(x1, y1, z1, x2, y2, z2, x0, y0, z0, output)
Determine whether a node is to the left of a plane through the origin.
subroutine stripack_lstptr(lpl, nb, list, lptr, output)
Return the index of NB in the adjacency list.
Generic ranks, dimensions and types.
Definition: type_mpl.F90:42