libSUFR
a LIBrary of Some Useful Fortran Routines
All Classes Namespaces Files Functions Variables Pages
statistics.f90
Go to the documentation of this file.
1!> \file statistics.f90 Procedures to compute statistics
2
3
4! Copyright (c) 2002-2025 Marc van der Sluys - Nikhef/Utrecht University - marc.vandersluys.nl
5!
6! This file is part of the libSUFR package,
7! see: http://libsufr.sourceforge.net/
8!
9! This is free software: you can redistribute it and/or modify it under the terms of the European Union
10! Public Licence 1.2 (EUPL 1.2). This software is distributed in the hope that it will be useful, but
11! WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
12! PURPOSE. See the EU Public Licence for more details. You should have received a copy of the European
13! Union Public Licence along with this code. If not, see <https://www.eupl.eu/1.2/en/>.
14!
15!
16
17
18
19
20!***********************************************************************************************************************************
21!> \brief Procedures to do statistics
22
24 implicit none
25 save
26
27contains
28
29
30 !*********************************************************************************************************************************
31 !> \brief Compute the median of a data array
32 !!
33 !! \param data 1D array of data points
34 !! \param mask Mask to apply to data (optional)
35 !! \retval median The median of a data array
36
37 function median(data, mask)
38 use sufr_kinds, only: double
41
42 implicit none
43 real(double), intent(in) :: data(:)
44 logical, intent(in), optional :: mask(:)
45
46 integer :: indexx(size(data)), ni
47 real(double) :: median
48 logical :: locmask(size(data))
49
50 ni = size(data)
51 locmask = .true.
52 if(present(mask)) then
53 if(size(data).ne.size(mask)) call quit_program_error('libSUFR median(): data and mask must have the same size', 0)
54 locmask = mask
55 end if
56
57 median = 0.d0
58
59 ! Sort the array:
60 call sorted_index_list(data,indexx, mask=locmask, index_n=ni)
61
62 if(ni.eq.0) then
63 median = 0.d0
64 else
65 ! Determine the median:
66 if(mod(ni,2).eq.0) then ! ni is even
67 median = 0.5d0*(data(indexx(ni/2)) + data(indexx(ni/2+1)))
68 else ! ni is odd
69 median = data(indexx((ni+1)/2))
70 end if
71 end if
72
73 end function median
74 !*********************************************************************************************************************************
75
76
77
78 !*********************************************************************************************************************************
79 !> \brief Compute the median of a data array - single-precision wrapper for median()
80 !!
81 !! \param data 1D array of data points
82 !! \param mask Mask to apply to data (optional)
83 !! \retval median_sp The median of a data array
84
85 function median_sp(data, mask)
86 use sufr_kinds, only: double
88
89 implicit none
90 real, intent(in) :: data(:)
91 logical, intent(in), optional :: mask(:)
92
93 real :: median_sp
94 real(double) :: data_d(size(data)), median_d
95 logical :: locmask(size(data))
96
97 locmask = .true.
98 if(present(mask)) then
99 if(size(data).ne.size(mask)) call quit_program_error('libSUFR median_sp(): data and mask must have the same size', 0)
100 locmask = mask
101 end if
102
103 data_d = dble(data)
104 median_d = median(data_d, mask=locmask)
105 median_sp = real(median_d)
106
107 end function median_sp
108 !*********************************************************************************************************************************
109
110
111
112 !*********************************************************************************************************************************
113 !> \brief Compute the mean of a data array
114 !!
115 !! \param data 1D array of data points
116 !! \param mask Mask to apply to data (optional)
117 !! \retval mean The mean of a data array
118
119 function mean(data, mask)
120 use sufr_kinds, only: double
122
123 implicit none
124 real(double), intent(in) :: data(:)
125 logical, intent(in), optional :: mask(:)
126
127 integer :: ni
128 real(double) :: mean
129 logical :: locmask(size(data))
130
131 locmask = .true.
132 if(present(mask)) then
133 if(size(data).ne.size(mask)) call quit_program_error('libSUFR mean(): data and mask must have the same size', 0)
134 locmask = mask
135 end if
136
137 ni = count(locmask) ! Number of .true. elements in locmask
138
139 if(ni.eq.0) then
140 !call warn('libSUFR mean(): data() has fewer than two elements', 0)
141 mean = 0.d0
142 else
143 mean = sum(data, mask=locmask)/dble(ni)
144 end if
145
146 end function mean
147 !*********************************************************************************************************************************
148
149
150
151 !*********************************************************************************************************************************
152 !> \brief Compute the mean of a data array - single-precision wrapper for mean()
153 !!
154 !! \param data 1D array of data points
155 !! \param mask Mask to apply to data (optional)
156 !! \retval mean_sp The mean of a data array
157
158 function mean_sp(data, mask)
159 use sufr_kinds, only: double
161
162 implicit none
163 real, intent(in) :: data(:)
164 logical, intent(in), optional :: mask(:)
165
166 real :: mean_sp
167 real(double) :: data_d(size(data)), mean_d
168 logical :: locmask(size(data))
169
170 locmask = .true.
171 if(present(mask)) then
172 if(size(data).ne.size(mask)) call quit_program_error('libSUFR mean_sp(): data and mask must have the same size', 0)
173 locmask = mask
174 end if
175
176 data_d = dble(data)
177 mean_d = mean(data_d, mask=locmask)
178 mean_sp = real(mean_d)
179
180 end function mean_sp
181 !*********************************************************************************************************************************
182
183
184
185 !*********************************************************************************************************************************
186 !> \brief Compute the weighted mean of a data array
187 !!
188 !! \param data 1D array of data points
189 !! \param wgts Weights for all data points
190 !! \param mask Mask to apply to data (optional)
191 !!
192 !! \retval mean_weight The weighted mean of a data array
193 !!
194 !! \see https://en.wikipedia.org/wiki/Weighted_arithmetic_mean
195
196 function mean_weight(data, wgts, mask)
197 use sufr_kinds, only: double
199
200 implicit none
201 real(double), intent(in) :: data(:), wgts(:)
202 logical, intent(in), optional :: mask(:)
203
204 integer :: ni, i
205 real(double) :: mean_weight, totdat,totwgt
206 logical :: locmask(size(data))
207
208 locmask = .true.
209 if(present(mask)) then
210 if(size(data).ne.size(mask)) call quit_program_error('libSUFR mean_weight(): data and mask must have the same size', 0)
211 locmask = mask
212 end if
213
214 ni = 0
215 totdat=0.d0
216 totwgt=0.d0
217 do i=1,size(data)
218 if(locmask(i)) then
219 if(wgts(i).lt.0.d0) call quit_program_error('libSUFR mean_weight(): weights cannot be negative', 0)
220 totdat = totdat + wgts(i)*data(i)
221 totwgt = totwgt + wgts(i)
222 if(wgts(i).gt.0.d0) ni = ni + 1
223 end if
224 end do
225
226 if(ni.eq.0) then
227 call error('libSUFR mean_weight(): data() has fewer than two weighted elements', 0)
228 mean_weight = 0.d0
229 else
230 mean_weight = totdat/totwgt
231 end if
232
233 end function mean_weight
234 !*********************************************************************************************************************************
235
236
237
238 !*********************************************************************************************************************************
239 !> \brief Compute the standard deviation of a data array with mean 'mean'
240 !!
241 !! \param data 1D array with data points
242 !! \param dMean Mean of the data points (optional; will be computed if not provided)
243 !! \param mask Mask to apply to data (optional)
244 !! \param var Variance of the data (output)
245 !!
246 !! \retval stDev The standard deviation
247 !!
248 !! \see https://en.wikipedia.org/wiki/Standard_deviation
249
250 function stdev(data, dMean, mask, var)
251 use sufr_kinds, only: double
253
254 implicit none
255 real(double), intent(in) :: data(:)
256 real(double), intent(in), optional :: dmean
257 logical, intent(in), optional :: mask(:)
258 real(double), intent(out), optional :: var
259
260 integer :: i, ni
261 real(double) :: stdev, lmean, lvar
262 logical :: locmask(size(data))
263
264 locmask = .true.
265 if(present(mask)) then
266 if(size(data).ne.size(mask)) call quit_program_error('libSUFR stDev(): data and mask must have the same size', 0)
267 locmask = mask
268 end if
269
270 if(present(dmean)) then
271 lmean = dmean
272 else
273 lmean = mean(data, locmask)
274 end if
275
276 lvar = 0.d0
277 ni = 0
278 do i=1,size(data)
279 if(locmask(i)) then
280 lvar = lvar + (data(i)-lmean)**2
281 ni = ni + 1
282 end if
283 end do
284
285 if(ni.le.1) then
286 call error('libSUFR stDev(): data() has fewer than two elements', 0)
287 lvar = 0.d0
288 else
289 lvar = lvar/dble(ni-1)
290 end if
291
292 stdev = sqrt(lvar) ! Compute the standard deviation
293 if(present(var)) var = lvar ! Return the variance if desired
294
295 end function stdev
296 !*********************************************************************************************************************************
297
298
299 !*********************************************************************************************************************************
300 !> \brief Compute the standard deviation of a data array with mean 'mean' - single-precision wrapper for stDev()
301 !!
302 !! \param data 1D array with data points
303 !! \param mean Mean of the data points
304 !! \param mask Mask to apply to data (optional)
305 !!
306 !! \retval stDev The standard deviation
307
308 function stdev_sp(data, mean, mask)
309 use sufr_kinds, only: double
311
312 implicit none
313 real, intent(in) :: data(:), mean
314 logical, intent(in), optional :: mask(:)
315
316 real :: stdev_sp
317 real(double) :: stdevd
318 logical :: locmask(size(data))
319
320 locmask = .true.
321 if(present(mask)) then
322 if(size(data).ne.size(mask)) call quit_program_error('libSUFR stDev_sp(): data and mask must have the same size', 0)
323 locmask = mask
324 end if
325
326 stdevd = stdev(dble(data), dble(mean), mask=locmask)
327 stdev_sp = real(stdevd)
328
329 end function stdev_sp
330 !*********************************************************************************************************************************
331
332
333 !*********************************************************************************************************************************
334 !> \brief Compute the weighted standard deviation of a data array with weighted mean 'wMean'
335 !!
336 !! \param data 1D array with data points
337 !! \param wgts Weights for all data points
338 !! \param wMean Weighted mean of the data points (optional)
339 !! \param mask Mask to apply to data (optional)
340 !!
341 !! \retval stDev_weight The weighted standard deviation
342
343 function stdev_weight(data, wgts, wMean, mask)
344 use sufr_kinds, only: double
346
347 implicit none
348 real(double), intent(in) :: data(:), wgts(:)
349 real(double), intent(in), optional :: wmean
350 logical, intent(in), optional :: mask(:)
351
352 integer :: i, nw
353 real(double) :: stdev_weight, lwmean, totwgt,totwgt2
354 logical :: locmask(size(data))
355
356 locmask = .true.
357 if(present(mask)) then
358 if(size(data).ne.size(mask)) call quit_program_error('libSUFR stDev_weight(): data and mask must have the same size', 0)
359 locmask = mask
360 end if
361
362 if(present(wmean)) then
363 lwmean = wmean
364 else
365 lwmean = mean_weight(data, wgts, locmask)
366 end if
367
368
369 stdev_weight = 0.d0
370 totwgt = 0.d0
371 totwgt2 = 0.d0
372 nw = 0
373 do i=1,size(data)
374 if(locmask(i)) then
375 if(wgts(i).lt.0.d0) call quit_program_error('libSUFR stDev_weight(): weights cannot be negative', 0)
376 stdev_weight = stdev_weight + wgts(i) * (data(i)-lwmean)**2
377 totwgt = totwgt + wgts(i)
378 totwgt2 = totwgt2 + wgts(i)**2
379 if(wgts(i).gt.0.d0) nw = nw + 1
380 end if
381 end do
382
383 if(nw.le.1) then
384 call error('libSUFR stDev_weight(): data() has fewer than 2 weighted elements', 0)
385 stdev_weight = 0.d0
386 else
387 stdev_weight = sqrt( stdev_weight / (totwgt - totwgt2 / totwgt) )
388 !stDev_weight = sqrt(stDev_weight / (dble(nw-1)/dble(nw)*totWgt) )
389 end if
390
391 end function stdev_weight
392 !*********************************************************************************************************************************
393
394
395 !*********************************************************************************************************************************
396 !> \brief Compute a running mean and variance by adding a data point and the data point number to existing values. If num=1,
397 !! initialise. Note that mean and var are I/O variables and cannot be dummy variables or values. Num must be accurate,
398 !! and increased by one between calls by the user. Optionally, return the standard deviation.
399 !!
400 !! \param mean Running mean (I/O)
401 !! \param var Running variance (I/O)
402 !! \param data New/current data point
403 !! \param num Number of the current data point
404 !! \param stDev Current standard deviation (output; optional)
405 !!
406 !! \see https://en.wikipedia.org/wiki/Algorithms_for_calculating_variance#Na%C3%AFve_algorithm
407
408 pure subroutine mean_var_running(mean, var, data, num, stDev)
409 use sufr_kinds, only: double
410 implicit none
411 real(double), intent(inout) :: mean, var
412 real(double), intent(in) :: data
413 integer, intent(in) :: num
414 real(double), intent(out), optional :: stdev
415 real(double) :: oldmean, var1,oldvar
416
417 if(num.eq.1) then ! Initialise
418 mean = data ! initial mean = first data point
419 var = 0.d0 ! initial variance = 0 for a single data point
420 if(present(stdev)) stdev = 0.d0 ! initial standard deviation = 0 for a single data point
421 else
422 oldmean = mean ! save old mean for the variance
423 mean = mean + (data - mean)/dble(num) ! add new data point -> new mean
424
425 oldvar = var*(num-2) ! since var = var1/(num-1) in the previous iteration
426 var1 = oldvar + (data - oldmean) * (data - mean) ! add the new data point
427 var = var1/dble(num-1) ! new variance
428
429 if(present(stdev)) stdev = sqrt(var1/dble(num)) ! new standard deviation, if wanted
430 end if
431
432 end subroutine mean_var_running
433 !*********************************************************************************************************************************
434
435
436 !*********************************************************************************************************************************
437 !> \brief Find a given probability range for a data array - the narrowest range that contains a given fraction of data points
438 !!
439 !! \param data 1D array of data points
440 !! \param range Probability range - e.g. 0.95 = 95% probability ~ "2-sigma"
441 !!
442 !! \param llim Lower limit of probability range (output)
443 !! \param ulim Upper limit of probability range (output)
444 !!
445 !! \param mask Mask to apply to data (optional)
446
447 subroutine prob_range(data, range, llim, ulim, mask)
448 use sufr_kinds, only: double
451 use sufr_numerics, only: deq
452
453 implicit none
454 real(double), intent(in) :: data(:), range
455 real(double), intent(out) :: llim, ulim
456 logical, intent(in), optional :: mask(:)
457
458 real(double) :: diff, mindiff
459 integer :: indexx(size(data)), ni, i0,i1,i1max,i2,di
460 logical :: locmask(size(data))
461
462 ni = size(data)
463 if(ni.eq.0) then
464 call error('libSUFR prob_range(): data() has size 0', 0)
465 llim = 0.d0
466 ulim = 0.d0
467 return
468 end if
469
470 locmask = .true.
471 if(present(mask)) then
472 if(size(data).ne.size(mask)) call quit_program_error('libSUFR prob_range(): data and mask must have the same size', 0)
473 locmask = mask
474 end if
475
476 ! Sort the array:
477 call sorted_index_list(data,indexx, mask=locmask, index_n=ni)
478
479 di = nint(dble(ni)*range)
480 i1max = nint(dble(ni)*(1.d0-range))
481 i0 = 1
482 mindiff = huge(mindiff)
483 do i1 = 1,i1max
484 i2 = i1 + di
485 if(i2.gt.ni) exit
486 diff = data(indexx(i2))-data(indexx(i1))
487
488 ! If the new range is smaller, or equal and closer to the middle (may happen when many identical values exist):
489 if(diff.lt.mindiff .or. (deq(diff,mindiff).and.i1-ni/2.lt.i0-ni/2)) then
490 mindiff = diff
491 i0 = i1
492 end if
493 end do
494
495 i1 = i0 + di
496 if(i1.gt.ni) then
497 call warn('prob_range(): results are shaky...')
498 i1 = ni ! Prevent crashes in extreme cases - probably only when very few data points...
499 end if
500
501 llim = data(indexx(i0))
502 ulim = data(indexx(i1))
503
504 end subroutine prob_range
505 !*********************************************************************************************************************************
506
507
508
509 !*********************************************************************************************************************************
510 !> \brief Find a given probability range for a data array - the narrowest range that contains a given fraction of data points -
511 !! single-precision wrapper for prob_range()
512 !!
513 !! \param data 1D array of data points
514 !! \param range Probability range - e.g. 0.95 = 95% probability ~ "2-sigma"
515 !!
516 !! \param llim Lower limit of probability range (output)
517 !! \param ulim Upper limit of probability range (output)
518 !!
519 !! \param mask Mask to apply to data (optional)
520
521 subroutine prob_range_sp(data, range, llim, ulim, mask)
522 use sufr_kinds, only: double
525
526 implicit none
527 real, intent(in) :: data(:), range
528 real, intent(out) :: llim, ulim
529 logical, intent(in), optional :: mask(:)
530
531 real(double) :: data_d(size(data)), range_d, llim_d,ulim_d
532 logical :: locmask(size(data))
533
534 locmask = .true.
535 if(present(mask)) then
536 if(size(data).ne.size(mask)) call quit_program_error('libSUFR prob_range_sp(): data and mask must have the same size', 0)
537 locmask = mask
538 end if
539
540
541 data_d = dble(data)
542 range_d = dble(range)
543
544 call prob_range(data_d, range_d, llim_d, ulim_d, locmask)
545
546 llim = real(llim_d)
547 ulim = real(ulim_d)
548
549 end subroutine prob_range_sp
550 !*********************************************************************************************************************************
551
552
553
554
555
556
557
558 !*********************************************************************************************************************************
559 !> \brief Roughly estimate the number of 1D bins needed, from the number of data points
560 !!
561 !! \param npoints Number of data points
562 !! \retval determine_nbin_1d Number of bins
563
564 pure function determine_nbin_1d(npoints)
565 implicit none
566 integer, intent(in) :: npoints
567 integer :: determine_nbin_1d
568
569 if(npoints.le.100) then
570 determine_nbin_1d = floor(2*sqrt(real(npoints)))
571 else
572 determine_nbin_1d = floor(10*log10(real(npoints)))
573 end if
575
576 end function determine_nbin_1d
577 !*********************************************************************************************************************************
578
579
580 !*********************************************************************************************************************************
581 !> \brief Bin data in 1D bins by counting the number of data points in each bin
582 !!
583 !! \param xDat Data to be binned (ndat points)
584 !! \param Nbin Desired number of bins. Note that the binned-data arrays xbin and ybin must have size >= Nbin+1
585 !!
586 !! \param norm Normalise histogram (T) or not (F)
587 !! \param mode Mode: -1: xbin is left of bin, 0: xbin is centre of bin, 1: xbin is right of bin
588 !! \param cumul Make a cumulative histogram (T/F)
589 !!
590 !! \param xMin Minimum value of the binning range. Set xMin=xMax to auto-determine (I/O)
591 !! \param xMax Maximum value of the binning range. Set xMin=xMax to auto-determine (I/O)
592 !!
593 !! \param xBin Binned data, location of the bins. The x values are the left side of the bin! (output)
594 !! \param yBin Binned data, height of the bins. I/O so that the array size can be checked (output)
595
596 subroutine bin_data_1d(xDat, Nbin, norm,mode,cumul, xMin,xMax, xBin,yBin)
597 use sufr_kinds, only: double
599 implicit none
600 real(double), intent(in) :: xDat(:)
601 integer, intent(in) :: Nbin, mode
602 logical, intent(in) :: norm, cumul
603 real(double), intent(inout) :: xMin,xMax
604 real(double), intent(inout) :: xBin(:),yBin(:)
605
606 integer :: i,k
607 real(double) :: dx, dk
608
609
610 ! Check array size for consistency:
611 if(size(xbin).le.nbin) call quit_program_error('libSUFR bin_data_1d(): xBin must have size >= Nbin+1',1)
612 if(size(ybin).le.nbin) call quit_program_error('libSUFR bin_data_1d(): yBin must have size >= Nbin+1',1)
613
614 if(abs((xmin-xmax)/(xmax+tiny(xmax))).lt.sqrt(tiny(xmax))) then ! Autodetermine ranges
615 xmin = minval(xdat)
616 xmax = maxval(xdat)
617 end if
618
619 ! Make limits wider by 2 x epsilon, in order to include data points on the boundaries:
620 xmin = xmin - epsilon(xmin)*xmin
621 xmax = xmax + epsilon(xmax)*xmax
622 dx = abs(xmax - xmin)/dble(nbin)
623
624 dk = dble(min(max(mode,-1),1))/2.d0 ! mode = -1,0,1 -> dk = -0.5, 0.0, 0.5 when xBin is the left, centre, right of the bin
625 do k=1,nbin+1
626 xbin(k) = xmin + (dble(k)-0.5d0+dk)*dx
627 end do
628
629 ybin = 0.
630 do i=1,size(xdat)
631 do k=1,nbin
632 if(xdat(i).ge.xbin(k)) then
633 if(xdat(i).lt.xbin(k+1)) then
634 ybin(k) = ybin(k) + 1.d0
635 exit ! If point i fits in this bin, don't try the others
636 end if
637 end if
638 end do ! k (bin)
639 end do
640
641 if(norm) ybin = ybin / (sum(ybin) + sqrt(tiny(ybin)))
642
643
644 if(cumul) then ! Create a cumulative histogram
645 do k = 2,nbin+1
646 ybin(k) = ybin(k-1) + ybin(k)
647 end do
648 end if
649
650 end subroutine bin_data_1d
651 !*********************************************************************************************************************************
652
653
654 !*********************************************************************************************************************************
655 !> \brief Bin data in 1D bins by counting the number of data points in each bin - single-precision wrapper for bin_data_1d()
656 !!
657 !! \param xDat Data to be binned (ndat points)
658 !! \param Nbin Desired number of bins. Note that the binned-data arrays xBin and yBin must have size >= Nbin+1
659 !!
660 !! \param norm Normalise histogram (T) or not (F)
661 !! \param mode Mode: -1: xBin is left of bin, 0: xBin is centre of bin, 1: xBin is right of bin
662 !! \param cumul Make a cumulative histogram (T/F)
663 !!
664 !! \param xMin Minimum value of the binning range. Set xMin=xMax to auto-determine (I/O)
665 !! \param xMax Maximum value of the binning range. Set xMin=xMax to auto-determine (I/O)
666 !!
667 !! \param xBin Binned data, location of the bins. The x values are the left side of the bin! (output)
668 !! \param yBin Binned data, height of the bins. I/O so that the array size can be checked (output)
669
670 subroutine bin_data_1d_sp(xDat, Nbin, norm,mode,cumul, xMin,xMax, xBin,yBin)
671 use sufr_kinds, only: double
673 implicit none
674 real, intent(in) :: xDat(:)
675 integer, intent(in) :: Nbin, mode
676 logical, intent(in) :: norm, cumul
677 real, intent(inout) :: xMin,xMax
678 real, intent(inout) :: xBin(:),yBin(:)
679
680 real(double) :: dxDat(size(xDat)), dxMin,dxMax, dxBin(size(xBin)),dyBin(size(yBin))
681
682 ! Copy single- to double-precision:
683 dxdat = dble(xdat)
684 dxmin = dble(xmin)
685 dxmax = dble(xmax)
686
687 call bin_data_1d(dxdat, nbin, norm,mode,cumul, dxmin,dxmax, dxbin,dybin)
688
689 ! Copy double- to single-precision:
690 xmin = real(dxmin)
691 xmax = real(dxmax)
692 xbin = real(dxbin)
693 ybin = real(dybin)
694
695 end subroutine bin_data_1d_sp
696 !*********************************************************************************************************************************
697
698
699 !*********************************************************************************************************************************
700 !> \brief Create a 1D histogram on the fly (point by point). Bin data points by computing the bin they should be in.
701 !!
702 !! \note Call this routine once to initialise (init=1; set xBin), then call many times to collect data and construct yBin (init=0)
703 !!
704 !! \param xDat Data point to be binned
705 !! \param Nbin Desired number of bins. Note that the binned-data arrays xBin and yBin must have size >= Nbin+1
706 !!
707 !! \param mode Mode: -1: xBin is left of bin, 0: xBin is centre of bin, 1: xBin is right of bin
708 !! \param cumul Make a cumulative histogram (T/F)
709 !!
710 !! \param xMin Minimum value of the binning range. Set xMin=xMax to auto-determine (I/O)
711 !! \param xMax Maximum value of the binning range. Set xMin=xMax to auto-determine (I/O)
712 !!
713 !! \param xBin Binned data, location of the bins. The x values are the left side of the bin! (output)
714 !! \param yBin Binned data, height of the bins. I/O so that the array size can be checked (output)
715 !!
716 !! \param init Initialisation call: true/false (data collection). Optional; default=false.
717 !! \param weight Add weight to the bin, rather than 1. Optional; default=1.
718
719 pure subroutine histogram_1d_onthefly(xDat, Nbin, mode,cumul, xMin,xMax, xBin,yBin, init, weight)
720 use sufr_kinds, only: double
722 implicit none
723 real(double), intent(in) :: xdat, xmin,xmax
724 integer, intent(in) :: nbin, mode
725 logical, intent(in) :: cumul
726 real(double), intent(inout) :: xbin(:),ybin(:)
727 real(double), intent(in), optional :: weight
728 logical, intent(in), optional :: init
729
730 integer :: ibin
731 real(double) :: weightl
732 logical :: initl
733
734 ! Deal with optional variables:
735 initl = .false.
736 if(present(init)) initl = init
737
738 weightl = 1.d0 ! Add one to bin by default
739 if(present(weight)) weightl = weight
740
741
742 if(initl) then ! Initialisation mode
743 do ibin=1,nbin+1
744 if(mode.le.-1) then
745 xbin(ibin) = xmin + dble(ibin-1)/dble(nbin) * (xmax-xmin) ! X value indicates left of bin
746 else if(mode.eq.0) then
747 xbin(ibin) = xmin + (dble(ibin-1)+0.5d0)/dble(nbin) * (xmax-xmin) ! X value indicates centre of bin
748 else
749 xbin(ibin) = xmin + dble(ibin)/dble(nbin) * (xmax-xmin) ! X value indicates right of bin
750 end if
751 end do
752
753 ybin = 0.d0
754
755 return ! Initialisation done
756 end if
757
758
759 ! Data-collection mode: create a histogram on the fly:
760
761 ! Determine the bin xDat belongs in:
762 if(mode.le.-1) then
763 ibin = ceiling( (xdat-xmin) / (xmax-xmin) * nbin ) ! X value indicates left of bin
764 else if(mode.eq.0) then
765 ibin = nint( (xdat-xmin) / (xmax-xmin) * nbin ) ! X value indicates centre of bin
766 else
767 ibin = floor( (xdat-xmin) / (xmax-xmin) * nbin ) ! X value indicates right of bin
768 end if
769
770 ! Add to that bin:
771 if(ibin.ge.1 .and. ibin.le.nbin) then
772 if(cumul) then
773 ybin(1:ibin) = ybin(1:ibin) + weightl
774 else
775 ybin(ibin) = ybin(ibin) + weightl
776 end if
777 end if
778
779 end subroutine histogram_1d_onthefly
780 !*********************************************************************************************************************************
781
782
783 !*********************************************************************************************************************************
784 !> \brief Bin data in 2 dimensions - computing the bin number rather than searching for it is ~10x faster
785 !!
786 !! \param xDat Input data: x values - array size: ndat
787 !! \param yDat Input data: y values - array size: ndat
788 !!
789 !! \param norm Normalise the bins (1) or not (0)
790 !!
791 !! \param nxBin Desired number of bins in the x direction
792 !! \param nyBin Desired number of bins in the y direction
793 !!
794 !! \param xMin Lower limit for the binning range in the x direction - autodetermine if xMin = xMax
795 !! \param xMax Upper limit for the binning range in the x direction - autodetermine if xMin = xMax
796 !! \param yMin Lower limit for the binning range in the y direction - autodetermine if yMin = yMax
797 !! \param yMax Upper limit for the binning range in the y direction - autodetermine if yMin = yMax
798 !!
799 !! \param z Binned data set z(nxBin+1,nyBin+1) - this array may be larger than you expect - nbin bins have nbin+1 borders (output)
800 !! \param tr Transformation elements for pgplot tr(6) (output)
801 !!
802 !! \param weights Weights to use when binning data, same size as xDat,yDat (optional)
803
804 subroutine bin_data_2d(xDat,yDat, norm, nxBin,nyBin, xMin,xMax,yMin,yMax, z, tr, weights)
805 use sufr_kinds, only: double
807
808 implicit none
809 integer, intent(in) :: nxBin,nyBin, norm
810 real(double), intent(in) :: xDat(:),yDat(:)
811 real(double), intent(in), optional :: weights(size(xDat))
812 real(double), intent(inout) :: xMin,xMax,yMin,yMax
813 real(double), intent(out) :: z(nxBin+1,nyBin+1),tr(6)
814
815 integer :: i,bx,by, ndat
816 real(double) :: dx,dy, weightsl(size(xDat))
817
818 ! Check data array sizes for consistency:
819 ndat = size(xdat)
820 if(size(ydat).ne.ndat) call quit_program_error('libSUFR bin_data_2d(): data arrays xDat and yDat must have the same size',1)
821
822 weightsl = 1.d0
823 if(present(weights)) weightsl = weights
824
825 if(abs((xmin-xmax)/(xmax + sqrt(huge(xmax)))) .lt. sqrt(huge(xmax))) then ! Autodetermine x ranges
826 xmin = minval(xdat(1:ndat))
827 xmax = maxval(xdat(1:ndat))
828 end if
829 xmin = xmin - epsilon(xmin)*xmin
830 xmax = xmax + epsilon(xmax)*xmax
831 dx = abs(xmax - xmin)/dble(nxbin)
832
833 if(abs((ymin-ymax)/(ymax + sqrt(huge(ymax)))) .lt. sqrt(huge(ymax))) then ! Autodetermine y ranges
834 ymin = minval(ydat(1:ndat))
835 ymax = maxval(ydat(1:ndat))
836 end if
837 ymin = ymin - epsilon(ymin)*ymin
838 ymax = ymax + epsilon(ymax)*ymax
839 dy = abs(ymax - ymin)/dble(nybin)
840
841
842
843 ! Determine transformation elements for pgplot (pggray, pgcont, pgimag):
844 tr(1) = xmin - dx/2.d0
845 tr(2) = dx
846 tr(3) = 0.d0
847 tr(4) = ymin - dy/2.d0
848 tr(5) = 0.d0
849 tr(6) = dy
850
851 z = 0.d0
852 do i=1,ndat
853 bx = floor((xdat(i) - xmin)/dx) + 1
854 by = floor((ydat(i) - ymin)/dy) + 1
855
856 !if(bx.lt.1.or.bx.gt.nxBin.or.by.lt.1.or.by.gt.nyBin) then
857 ! if(bx.eq.0.or.bx.eq.nxBin+1) bx = max(min(bx,nxBin),1) !Treat an error of 1 x bin as round-off
858 ! if(by.eq.0.or.by.eq.nyBin+1) by = max(min(by,nyBin),1) !Treat an error of 1 y bin as round-off
859 !
860 ! if(bx.lt.0.or.bx.gt.nxBin+1) then
861 ! !write(stdErr,'(A,I7,A2,F8.3,A,I4,A,I4,A1)') &
862 !' Bindata2d: error for X data point',i,' (',xDat(i),'). I found bin',bx,', but it should lie between 1 and',nxBin,'.'
863 ! else if(by.lt.0.or.by.gt.nyBin+1) then
864 ! !write(stdErr,'(A,I7,A2,F8.3,A,I4,A,I4,A1)') &
865 !' Bindata2d: error for Y data point',i,' (',yDat(i),'). I found bin',by,', but it should lie between 1 and',nyBin,'.'
866 ! else
867 ! z(bx,by) = z(bx,by) + 1.
868 ! end if
869 !else
870 ! z(bx,by) = z(bx,by) + 1.
871 !end if
872
873 ! Don't treat 1-bin errors as round-off:
874 !if(bx.ge.1.and.bx.le.nxBin.and.by.ge.1.and.by.le.nyBin) z(bx,by) = z(bx,by) + 1.
875
876 if(bx.ge.1.and.bx.le.nxbin.and.by.ge.1.and.by.le.nybin) z(bx,by) = z(bx,by) + weightsl(i)
877 end do
878
879 !if(norm.eq.1) z = z/(ztot+sqrt(huge(z)))
880 if(norm.eq.1) z = z/maxval(z+sqrt(huge(z)))
881
882 end subroutine bin_data_2d
883 !*********************************************************************************************************************************
884
885 !*********************************************************************************************************************************
886 !> \brief Bin data in 2 dimensions - single-precision wrapper for bin_data_2d()
887 !!
888 !! \param xDat Input data: x values - array size: ndat
889 !! \param yDat Input data: y values - array size: ndat
890 !!
891 !! \param norm Normalise the bins (1) or not (0)
892 !!
893 !! \param nxBin Desired number of bins in the x direction
894 !! \param nyBin Desired number of bins in the y direction
895 !!
896 !! \param xMin Lower limit for the binning range in the x direction - autodetermine if xMin = xMax
897 !! \param xMax Upper limit for the binning range in the x direction - autodetermine if xMin = xMax
898 !! \param yMin Lower limit for the binning range in the y direction - autodetermine if yMin = yMax
899 !! \param yMax Upper limit for the binning range in the y direction - autodetermine if yMin = yMax
900 !!
901 !! \param z Binned data set z(nxBin+1,nyBin+1) - this array may be larger than you expect - nbin bins have nbin+1 borders (output)
902 !! \param tr Transformation elements for pgplot tr(6) (output)
903 !!
904 !! \param weights Weights to use when binning data, same size as xDat,yDat (optional)
905
906 subroutine bin_data_2d_sp(xDat,yDat, norm, nxBin,nyBin, xMin,xMax,yMin,yMax, z, tr, weights)
907 use sufr_kinds, only: double
909
910 implicit none
911 integer, intent(in) :: nxBin,nyBin, norm
912 real, intent(in) :: xDat(:),yDat(:)
913 real, intent(in), optional :: weights(size(xDat))
914 real, intent(inout) :: xMin,xMax,yMin,yMax
915 real, intent(out) :: z(nxBin+1,nyBin+1),tr(6)
916
917 real(double) :: dxDat(size(xDat)),dyDat(size(yDat)), dweights(size(xDat)), dxMin,dxMax,dyMin,dyMax, dz(nxBin+1,nyBin+1),dtr(6)
918
919 ! Copy single- to double-precision:
920 dxdat = dble(xdat)
921 dydat = dble(ydat)
922 dxmin = dble(xmin)
923 dxmax = dble(xmax)
924 dymin = dble(ymin)
925 dymax = dble(ymax)
926
927 dweights = 1.d0
928 if(present(weights)) dweights = dble(weights)
929
930 call bin_data_2d(dxdat,dydat, norm, nxbin,nybin, dxmin,dxmax,dymin,dymax, dz, dtr, dweights)
931
932 ! Copy double- to single-precision:
933 xmin = real(dxmin)
934 xmax = real(dxmax)
935 ymin = real(dymin)
936 ymax = real(dymax)
937 z = real(dz)
938 tr = real(dtr)
939
940 end subroutine bin_data_2d_sp
941 !*********************************************************************************************************************************
942
943
944
945
946
947 !*********************************************************************************************************************************
948 !> \brief Bin data in 2 dimensions - computing the bin number rather than searching for it is ~10x faster
949 !!
950 !! \param xDat Input data point: x value
951 !! \param yDat Input data point: y value
952 !!
953 !! \param nxBin Desired number of bins in the x direction
954 !! \param nyBin Desired number of bins in the y direction
955 !!
956 !! \param xMin Lower limit for the binning range in the x direction - autodetermine if xMin = xMax
957 !! \param xMax Upper limit for the binning range in the x direction - autodetermine if xMin = xMax
958 !! \param yMin Lower limit for the binning range in the y direction - autodetermine if yMin = yMax
959 !! \param yMax Upper limit for the binning range in the y direction - autodetermine if yMin = yMax
960 !!
961 !! \param z Binned data set z(nxBin+1,nyBin+1) - this array may be larger than you expect - nbin bins have nbin+1 borders (output)
962 !!
963 !! \param init Init mode: true/false (optional)
964 !! \param weight Weight to use when binning data, same size as xDat,yDat (optional)
965 !! \param tr Transformation elements for pgplot tr(6) (output; optional)
966
967 subroutine histogram_2d_onthefly(xDat,yDat, nxBin,nyBin, xMin,xMax,yMin,yMax, z, init, weight, tr)
968 use sufr_kinds, only: double
970
971 implicit none
972 integer, intent(in) :: nxBin,nyBin
973 real(double), intent(in) :: xDat,yDat, xMin,xMax,yMin,yMax
974 real(double), intent(out) :: z(nxBin+1,nyBin+1)
975 real(double), intent(out), optional :: tr(6)
976 logical, intent(in), optional :: init
977 real(double), intent(in), optional :: weight
978
979 integer :: bx,by
980 real(double), save :: dx,dy
981 real(double) :: weightl
982 logical :: initl
983
984 initl = .false.
985 if(present(init)) initl = init
986
987 if(initl) then ! Initialisation mode
988 z = 0.d0
989
990 dx = abs(xmax - xmin)/dble(nxbin)
991 dy = abs(ymax - ymin)/dble(nybin)
992
993 ! Determine transformation elements for pgplot (pggray, pgcont, pgimag):
994 if(present(tr)) then
995 tr(1) = xmin - dx/2.d0
996 tr(2) = dx
997 tr(3) = 0.d0
998 tr(4) = ymin - dy/2.d0
999 tr(5) = 0.d0
1000 tr(6) = dy
1001 end if
1002
1003 end if
1004
1005
1006 ! Check array size:
1007 if(size(z,1).lt.nxbin+1) call quit_program_error('histogram_2d_onthefly: the first dimension of z is too small; the 2D '// &
1008 'array should have a size of at least nxBin+1 x nyBin+1', 1)
1009 if(size(z,2).lt.nybin+1) call quit_program_error('histogram_2d_onthefly: the second dimension of z is too small; the 2D '// &
1010 'array should have a size of at least nxBin+1 x nyBin+1', 1)
1011
1012
1013 ! Data gathering mode:
1014 weightl = 1.d0
1015 if(present(weight)) weightl = weight
1016
1017 bx = floor((xdat - xmin)/dx) + 1 ! Bin x
1018 by = floor((ydat - ymin)/dy) + 1 ! bin y
1019
1020 if(bx.ge.1 .and. bx.le.nxbin .and. by.ge.1 .and. by.le.nybin) z(bx,by) = z(bx,by) + weightl
1021
1022 end subroutine histogram_2d_onthefly
1023 !*********************************************************************************************************************************
1024
1025
1026
1027 !*********************************************************************************************************************************
1028 !> \brief Compute the faculty of an integer, returning a long integer
1029 !!
1030 !! \param n Number - up to 20 for long integers (up to 13 for integers)
1031 !! \retval faculty_i Faculty of n; n! - a long integer
1032
1033 pure function faculty_i(n)
1034 use sufr_kinds, only: long
1035 implicit none
1036 integer, intent(in) :: n
1037 integer(long) :: faculty_i, i
1038
1039 faculty_i = 1
1040 do i=2,n
1041 faculty_i = faculty_i * i
1042 end do
1043
1044 end function faculty_i
1045 !*********************************************************************************************************************************
1046
1047
1048
1049 !*********************************************************************************************************************************
1050 !> \brief Compute the faculty of an integer, returning a double-precision real
1051 !!
1052 !! \param n Number - can be up to 170 for double-precision reals (as opposed to 20 for long integers and 13 for integers)
1053 !! \retval faculty Faculty of n; n! (double-precision real)
1054
1055 pure function faculty(n)
1056 use sufr_kinds, only: double
1057 implicit none
1058 integer, intent(in) :: n
1059 real(double) :: faculty
1060 integer :: i
1061
1062 faculty = 1.d0
1063 do i=2,n
1064 faculty = faculty * dble(i)
1065 end do
1066
1067 end function faculty
1068 !*********************************************************************************************************************************
1069
1070
1071 !*********************************************************************************************************************************
1072 !> \brief Compute the binomial coefficient of n and k
1073 !!
1074 !! \param n Total number of trials; n in "n choose k"
1075 !! \param k Number of succesful trials; k in "n choose k"
1076 !! \retval binom_coeff Binomial coefficient n! / [k!(n-k)!]
1077 !!
1078 !! \see https://en.wikipedia.org/wiki/Binomial_coefficient#Binomial_coefficient_in_programming_languages
1079
1080 pure function binom_coeff(n, k)
1081 use sufr_kinds, only: double
1082 implicit none
1083 integer, intent(in) :: n, k
1084 integer :: lk, ik
1085 real(double) :: binom_coeff
1086
1087 ! binom_coeff = faculty(n) / (faculty(k) * faculty(n-k)) ! [n! / k!(n-k)!]
1088
1089 if(k.lt.0 .or. k.gt.n) then
1090 binom_coeff = 0.d0
1091 else if(k.eq.0 .or. k.eq.n) then
1092 binom_coeff = 1.d0
1093 else
1094 lk = min(k, n-k) ! Take advantage of symmetry
1095 binom_coeff = 1
1096 do ik=1,lk
1097 binom_coeff = binom_coeff * (n-ik+1) / dble(ik)
1098 end do
1099 end if
1100
1101 ! F2008 standard - g95, ifort don't like this:
1102 ! binom_coeff = exp( log_gamma(dble(n+1)) - log_gamma(dble(k+1)) - log_gamma(dble(n-k+1)) )
1103
1104 end function binom_coeff
1105 !*********************************************************************************************************************************
1106
1107
1108
1109 !*********************************************************************************************************************************
1110 !> \brief Compute the binomial probability of n and k, and probability p
1111 !!
1112 !! \param n Total number of trials; n in "n choose k"
1113 !! \param k Number of succesful trials; k in "n choose k"
1114 !! \param p Probability of a succesful trial
1115 !! \retval binom_prob Binomial probability n! / [k!(n-k)!] * p^k * (1-p)^(n-k)
1116
1117 pure function binom_prob(n, k, p)
1118 use sufr_kinds, only: double
1119 implicit none
1120 integer, intent(in) :: n, k
1121 real(double), intent(in) :: p
1122 real(double) :: binom_prob
1123
1124 binom_prob = binom_coeff(n,k) * p**k * (1.d0-p)**(n-k) ! n! / [k!(n-k)!] * p^k * (1-p)^(n-k)
1125
1126 end function binom_prob
1127 !*********************************************************************************************************************************
1128
1129
1130
1131
1132 !*********************************************************************************************************************************
1133 !> \brief Compute the cumulative binomial probability of n and k OR FEWER, and probability p
1134 !!
1135 !! \param n Total number of trials; n in "n choose k"
1136 !! \param k Number of succesful trials OR FEWER; k in "n choose k"
1137 !! \param p Probability of a succesful trial
1138 !! \retval binom_cumul_prob Cumulative binomial probability Σ(i=0,k) n! / [i!(n-i)!] * p^i * (1-p)^(n-i)
1139
1140 pure function binom_cumul_prob(n, k, p)
1141 use sufr_kinds, only: double
1142 implicit none
1143 integer, intent(in) :: n, k
1144 real(double), intent(in) :: p
1145 integer :: ki
1146 real(double) :: binom_cumul_prob
1147
1148 binom_cumul_prob = 0.d0
1149 do ki=0,k
1150 binom_cumul_prob = binom_cumul_prob + binom_prob(n, ki, p) ! Probability of EXACTLY k succesful trials
1151 end do
1152
1153 end function binom_cumul_prob
1154 !*********************************************************************************************************************************
1155
1156
1157
1158
1159 !*********************************************************************************************************************************
1160 !> \brief Compute the Poisson probability of EXACTLY k events occurring in a fixed interval for a known
1161 !! average rate lambda, and independently of the time since the last event: P = λ^k e^-λ / k!
1162 !!
1163 !! \param k Number of events
1164 !! \param lambda Average event rate
1165 !! \retval poisson_prob Poisson probability P = λ^k e^-λ / k!
1166
1167 pure function poisson_prob(k, lambda)
1168 use sufr_kinds, only: double
1169 implicit none
1170 integer, intent(in) :: k
1171 real(double), intent(in) :: lambda
1172 real(double) :: poisson_prob
1173
1174 poisson_prob = lambda**k * exp(-lambda) / faculty(k) ! λ^k e^-λ / k!
1175
1176 end function poisson_prob
1177 !*********************************************************************************************************************************
1178
1179
1180
1181
1182 !*********************************************************************************************************************************
1183 !> \brief Compute the cumulative Poisson probability of k OR FEWER events occurring in a fixed interval for
1184 !! a known average rate lambda, and independently of the time since the last event:
1185 !! P = Σ(i=0,k) λ^i e^-λ / i!
1186 !!
1187 !! \param k Number of events
1188 !! \param lambda Average event rate
1189 !! \retval poisson_prob_cumul Cumulative Poisson probability P = Σ(i=0,k) λ^i e^-λ / i!
1190
1191 pure function poisson_prob_cumul(k, lambda)
1192 use sufr_kinds, only: double
1193 implicit none
1194 integer, intent(in) :: k
1195 real(double), intent(in) :: lambda
1196 integer :: ki
1197 real(double) :: poisson_prob_cumul
1198
1199 poisson_prob_cumul = 0.d0
1200 do ki=0,k ! k or fewer -> 0, 1, ..., k
1201 poisson_prob_cumul = poisson_prob_cumul + poisson_prob(ki, lambda) ! Probability of EXACTLY k events
1202 end do
1203
1204 end function poisson_prob_cumul
1205 !*********************************************************************************************************************************
1206
1207
1208
1209
1210 !*********************************************************************************************************************************
1211 !> \brief Compute the normalised correlation between two data series
1212 !!
1213 !! \param data1 Data series 1
1214 !! \param data2 Data series 2 - should have the same length as data1
1215 !! \retval correlation Normalised correlation [-1,1] between the two data series
1216
1217 function correlation(data1, data2)
1218 use sufr_kinds, only: double
1219 use sufr_system, only: warn
1220
1221 implicit none
1222 integer :: nn, ii
1223 real(double), intent(in) :: data1(:), data2(:)
1224 real(double) :: correlation, mean1,mean2, sum12, sum21,sum22
1225
1226 if(size(data1).ne.size(data2)) &
1227 call warn('correlation(): data arrays are of unequal size; using the size of the smalles array',0)
1228 nn = min(size(data1), size(data2))
1229
1230 mean1 = mean(data1)
1231 mean2 = mean(data2)
1232
1233 sum12 = 0.d0
1234 sum21 = 0.d0
1235 sum22 = 0.d0
1236
1237 do ii=1,nn
1238 sum12 = sum12 + (data1(ii)-mean1) * (data2(ii)-mean2) ! Denominator
1239 sum21 = sum21 + (data1(ii)-mean1)**2 ! Numerator pt.1
1240 sum22 = sum22 + (data2(ii)-mean2)**2 ! Numerator pt.2
1241 end do
1242
1243 correlation = sum12/sqrt(sum21*sum22)
1244
1245 end function correlation
1246 !*********************************************************************************************************************************
1247
1248end module sufr_statistics
1249!***********************************************************************************************************************************
1250
Provides kinds and related constants/routines.
Definition kinds.f90:26
integer, parameter double
Double-precision float. Precision = 15, range = 307.
Definition kinds.f90:35
integer, parameter long
Long integer.
Definition kinds.f90:31
Procedures for numerical operations.
Definition numerics.f90:23
elemental logical function deq(x1, x2, eps)
Test whether two double-precision variables are equal to better than a given value (default: 2x machi...
Definition numerics.f90:90
Procedures for sorting.
Definition sorting.f90:23
subroutine sorted_index_list(array, index_list, mask, index_n)
Return a list of indices index_list that sorts the members of array to ascending value,...
Definition sorting.f90:45
Procedures to do statistics.
subroutine bin_data_2d(xdat, ydat, norm, nxbin, nybin, xmin, xmax, ymin, ymax, z, tr, weights)
Bin data in 2 dimensions - computing the bin number rather than searching for it is ~10x faster.
pure real(double) function faculty(n)
Compute the faculty of an integer, returning a double-precision real.
real function median_sp(data, mask)
Compute the median of a data array - single-precision wrapper for median()
subroutine histogram_2d_onthefly(xdat, ydat, nxbin, nybin, xmin, xmax, ymin, ymax, z, init, weight, tr)
Bin data in 2 dimensions - computing the bin number rather than searching for it is ~10x faster.
pure real(double) function poisson_prob_cumul(k, lambda)
Compute the cumulative Poisson probability of k OR FEWER events occurring in a fixed interval for a k...
pure real(double) function binom_coeff(n, k)
Compute the binomial coefficient of n and k.
real(double) function correlation(data1, data2)
Compute the normalised correlation between two data series.
subroutine bin_data_1d(xdat, nbin, norm, mode, cumul, xmin, xmax, xbin, ybin)
Bin data in 1D bins by counting the number of data points in each bin.
pure real(double) function binom_cumul_prob(n, k, p)
Compute the cumulative binomial probability of n and k OR FEWER, and probability p.
real(double) function stdev_weight(data, wgts, wmean, mask)
Compute the weighted standard deviation of a data array with weighted mean 'wMean'.
subroutine bin_data_1d_sp(xdat, nbin, norm, mode, cumul, xmin, xmax, xbin, ybin)
Bin data in 1D bins by counting the number of data points in each bin - single-precision wrapper for ...
real(double) function mean(data, mask)
Compute the mean of a data array.
pure subroutine mean_var_running(mean, var, data, num, stdev)
Compute a running mean and variance by adding a data point and the data point number to existing valu...
pure integer function determine_nbin_1d(npoints)
Roughly estimate the number of 1D bins needed, from the number of data points.
real(double) function mean_weight(data, wgts, mask)
Compute the weighted mean of a data array.
pure integer(long) function faculty_i(n)
Compute the faculty of an integer, returning a long integer.
real function mean_sp(data, mask)
Compute the mean of a data array - single-precision wrapper for mean()
subroutine prob_range(data, range, llim, ulim, mask)
Find a given probability range for a data array - the narrowest range that contains a given fraction ...
subroutine prob_range_sp(data, range, llim, ulim, mask)
Find a given probability range for a data array - the narrowest range that contains a given fraction ...
real(double) function stdev(data, dmean, mask, var)
Compute the standard deviation of a data array with mean 'mean'.
pure real(double) function poisson_prob(k, lambda)
Compute the Poisson probability of EXACTLY k events occurring in a fixed interval for a known average...
real(double) function median(data, mask)
Compute the median of a data array.
subroutine bin_data_2d_sp(xdat, ydat, norm, nxbin, nybin, xmin, xmax, ymin, ymax, z, tr, weights)
Bin data in 2 dimensions - single-precision wrapper for bin_data_2d()
pure real(double) function binom_prob(n, k, p)
Compute the binomial probability of n and k, and probability p.
real function stdev_sp(data, mean, mask)
Compute the standard deviation of a data array with mean 'mean' - single-precision wrapper for stDev(...
pure subroutine histogram_1d_onthefly(xdat, nbin, mode, cumul, xmin, xmax, xbin, ybin, init, weight)
Create a 1D histogram on the fly (point by point). Bin data points by computing the bin they should b...
System-related procedures.
Definition system.f90:23
subroutine error(message, unit)
Print an error to StdOut or StErr.
Definition system.f90:671
subroutine quit_program_error(message, status)
Print an error message to StdErr and stop the execution of the current program.
Definition system.f90:78
subroutine warn(message, unit)
Print a warning to StdOut or StErr.
Definition system.f90:646