1 #include <petscdt.h> /*I "petscdt.h" I*/ 2 3 #include <petscvec.h> 4 #include <petscdraw.h> 5 #include <petsc/private/petscimpl.h> 6 7 const char * const DTProbDensityTypes[] = {"constant", "gaussian", "maxwell_boltzmann", "DTProb Density", "DTPROB_DENSITY_", NULL}; 8 9 /*@ 10 PetscPDFMaxwellBoltzmann1D - PDF for the Maxwell-Boltzmann distribution in 1D 11 12 Not collective 13 14 Input Parameter: 15 . x - Speed in [0, \infty] 16 17 Output Parameter: 18 . p - The probability density at x 19 20 Level: beginner 21 22 .seealso: `PetscCDFMaxwellBoltzmann1D` 23 @*/ 24 PetscErrorCode PetscPDFMaxwellBoltzmann1D(const PetscReal x[], const PetscReal dummy[], PetscReal p[]) 25 { 26 p[0] = PetscSqrtReal(2. / PETSC_PI) * PetscExpReal(-0.5 * PetscSqr(x[0])); 27 return 0; 28 } 29 30 /*@ 31 PetscCDFMaxwellBoltzmann1D - CDF for the Maxwell-Boltzmann distribution in 1D 32 33 Not collective 34 35 Input Parameter: 36 . x - Speed in [0, \infty] 37 38 Output Parameter: 39 . p - The probability density at x 40 41 Level: beginner 42 43 .seealso: `PetscPDFMaxwellBoltzmann1D` 44 @*/ 45 PetscErrorCode PetscCDFMaxwellBoltzmann1D(const PetscReal x[], const PetscReal dummy[], PetscReal p[]) 46 { 47 p[0] = PetscErfReal(x[0] / PETSC_SQRT2); 48 return 0; 49 } 50 51 /*@ 52 PetscPDFMaxwellBoltzmann2D - PDF for the Maxwell-Boltzmann distribution in 2D 53 54 Not collective 55 56 Input Parameter: 57 . x - Speed in [0, \infty] 58 59 Output Parameter: 60 . p - The probability density at x 61 62 Level: beginner 63 64 .seealso: `PetscCDFMaxwellBoltzmann2D` 65 @*/ 66 PetscErrorCode PetscPDFMaxwellBoltzmann2D(const PetscReal x[], const PetscReal dummy[], PetscReal p[]) 67 { 68 p[0] = x[0] * PetscExpReal(-0.5 * PetscSqr(x[0])); 69 return 0; 70 } 71 72 /*@ 73 PetscCDFMaxwellBoltzmann2D - CDF for the Maxwell-Boltzmann distribution in 2D 74 75 Not collective 76 77 Input Parameter: 78 . x - Speed in [0, \infty] 79 80 Output Parameter: 81 . p - The probability density at x 82 83 Level: beginner 84 85 .seealso: `PetscPDFMaxwellBoltzmann2D` 86 @*/ 87 PetscErrorCode PetscCDFMaxwellBoltzmann2D(const PetscReal x[], const PetscReal dummy[], PetscReal p[]) 88 { 89 p[0] = 1. - PetscExpReal(-0.5 * PetscSqr(x[0])); 90 return 0; 91 } 92 93 /*@ 94 PetscPDFMaxwellBoltzmann3D - PDF for the Maxwell-Boltzmann distribution in 3D 95 96 Not collective 97 98 Input Parameter: 99 . x - Speed in [0, \infty] 100 101 Output Parameter: 102 . p - The probability density at x 103 104 Level: beginner 105 106 .seealso: `PetscCDFMaxwellBoltzmann3D` 107 @*/ 108 PetscErrorCode PetscPDFMaxwellBoltzmann3D(const PetscReal x[], const PetscReal dummy[], PetscReal p[]) 109 { 110 p[0] = PetscSqrtReal(2. / PETSC_PI) * PetscSqr(x[0]) * PetscExpReal(-0.5 * PetscSqr(x[0])); 111 return 0; 112 } 113 114 /*@ 115 PetscCDFMaxwellBoltzmann3D - CDF for the Maxwell-Boltzmann distribution in 3D 116 117 Not collective 118 119 Input Parameter: 120 . x - Speed in [0, \infty] 121 122 Output Parameter: 123 . p - The probability density at x 124 125 Level: beginner 126 127 .seealso: `PetscPDFMaxwellBoltzmann3D` 128 @*/ 129 PetscErrorCode PetscCDFMaxwellBoltzmann3D(const PetscReal x[], const PetscReal dummy[], PetscReal p[]) 130 { 131 p[0] = PetscErfReal(x[0] / PETSC_SQRT2) - PetscSqrtReal(2. / PETSC_PI) * x[0] * PetscExpReal(-0.5 * PetscSqr(x[0])); 132 return 0; 133 } 134 135 /*@ 136 PetscPDFGaussian1D - PDF for the Gaussian distribution in 1D 137 138 Not collective 139 140 Input Parameter: 141 . x - Coordinate in [-\infty, \infty] 142 143 Output Parameter: 144 . p - The probability density at x 145 146 Level: beginner 147 148 .seealso: `PetscPDFMaxwellBoltzmann3D` 149 @*/ 150 PetscErrorCode PetscPDFGaussian1D(const PetscReal x[], const PetscReal scale[], PetscReal p[]) 151 { 152 const PetscReal sigma = scale ? scale[0] : 1.; 153 p[0] = PetscSqrtReal(1. / (2.*PETSC_PI)) * PetscExpReal(-0.5 * PetscSqr(x[0] / sigma)) / sigma; 154 return 0; 155 } 156 157 PetscErrorCode PetscCDFGaussian1D(const PetscReal x[], const PetscReal scale[], PetscReal p[]) 158 { 159 const PetscReal sigma = scale ? scale[0] : 1.; 160 p[0] = 0.5 * (1. + PetscErfReal(x[0] / PETSC_SQRT2 / sigma)); 161 return 0; 162 } 163 164 /*@ 165 PetscPDFSampleGaussian1D - Sample uniformly from a Gaussian distribution in 1D 166 167 Not collective 168 169 Input Parameters: 170 + p - A uniform variable on [0, 1] 171 - dummy - ignored 172 173 Output Parameter: 174 . x - Coordinate in [-\infty, \infty] 175 176 Level: beginner 177 178 Note: http://www.mimirgames.com/articles/programming/approximations-of-the-inverse-error-function/ 179 https://stackoverflow.com/questions/27229371/inverse-error-function-in-c 180 @*/ 181 PetscErrorCode PetscPDFSampleGaussian1D(const PetscReal p[], const PetscReal dummy[], PetscReal x[]) 182 { 183 const PetscReal q = 2*p[0] - 1.; 184 const PetscInt maxIter = 100; 185 PetscReal ck[100], r = 0.; 186 PetscInt k, m; 187 188 PetscFunctionBeginHot; 189 /* Transform input to [-1, 1] since the code below computes the inverse error function */ 190 for (k = 0; k < maxIter; ++k) ck[k] = 0.; 191 ck[0] = 1; 192 r = ck[0]* (PetscSqrtReal(PETSC_PI) / 2.) * q; 193 for (k = 1; k < maxIter; ++k) { 194 const PetscReal temp = 2.*k + 1.; 195 196 for (m = 0; m <= k-1; ++m) { 197 PetscReal denom = (m + 1.)*(2.*m + 1.); 198 199 ck[k] += (ck[m]*ck[k-1-m])/denom; 200 } 201 r += (ck[k]/temp) * PetscPowReal((PetscSqrtReal(PETSC_PI)/2.) * q, 2.*k+1.); 202 } 203 /* Scale erfinv() by \sqrt{\pi/2} */ 204 x[0] = PetscSqrtReal(PETSC_PI * 0.5) * r; 205 PetscFunctionReturn(0); 206 } 207 208 /*@ 209 PetscPDFGaussian2D - PDF for the Gaussian distribution in 2D 210 211 Not collective 212 213 Input Parameters: 214 + x - Coordinate in [-\infty, \infty]^2 215 - dummy - ignored 216 217 Output Parameter: 218 . p - The probability density at x 219 220 Level: beginner 221 222 .seealso: `PetscPDFSampleGaussian2D()`, `PetscPDFMaxwellBoltzmann3D()` 223 @*/ 224 PetscErrorCode PetscPDFGaussian2D(const PetscReal x[], const PetscReal dummy[], PetscReal p[]) 225 { 226 p[0] = (1. / PETSC_PI) * PetscExpReal(-0.5 * (PetscSqr(x[0]) + PetscSqr(x[1]))); 227 return 0; 228 } 229 230 /*@ 231 PetscPDFSampleGaussian2D - Sample uniformly from a Gaussian distribution in 2D 232 233 Not collective 234 235 Input Parameters: 236 + p - A uniform variable on [0, 1]^2 237 - dummy - ignored 238 239 Output Parameter: 240 . x - Coordinate in [-\infty, \infty]^2 241 242 Level: beginner 243 244 Note: https://en.wikipedia.org/wiki/Box%E2%80%93Muller_transform 245 246 .seealso: `PetscPDFGaussian2D()`, `PetscPDFMaxwellBoltzmann3D()` 247 @*/ 248 PetscErrorCode PetscPDFSampleGaussian2D(const PetscReal p[], const PetscReal dummy[], PetscReal x[]) 249 { 250 const PetscReal mag = PetscSqrtReal(-2.0 * PetscLogReal(p[0])); 251 x[0] = mag * PetscCosReal(2.0 * PETSC_PI * p[1]); 252 x[1] = mag * PetscSinReal(2.0 * PETSC_PI * p[1]); 253 return 0; 254 } 255 256 /*@ 257 PetscPDFGaussian3D - PDF for the Gaussian distribution in 3D 258 259 Not collective 260 261 Input Parameters: 262 + x - Coordinate in [-\infty, \infty]^3 263 - dummy - ignored 264 265 Output Parameter: 266 . p - The probability density at x 267 268 Level: beginner 269 270 .seealso: `PetscPDFSampleGaussian3D()`, `PetscPDFMaxwellBoltzmann3D()` 271 @*/ 272 PetscErrorCode PetscPDFGaussian3D(const PetscReal x[], const PetscReal dummy[], PetscReal p[]) 273 { 274 p[0] = (1. / PETSC_PI*PetscSqrtReal(PETSC_PI)) * PetscExpReal(-0.5 * (PetscSqr(x[0]) + PetscSqr(x[1]) + PetscSqr(x[2]))); 275 return 0; 276 } 277 278 /*@ 279 PetscPDFSampleGaussian3D - Sample uniformly from a Gaussian distribution in 3D 280 281 Not collective 282 283 Input Parameters: 284 + p - A uniform variable on [0, 1]^3 285 - dummy - ignored 286 287 Output Parameter: 288 . x - Coordinate in [-\infty, \infty]^3 289 290 Level: beginner 291 292 Note: https://en.wikipedia.org/wiki/Box%E2%80%93Muller_transform 293 294 .seealso: `PetscPDFGaussian3D()`, `PetscPDFMaxwellBoltzmann3D()` 295 @*/ 296 PetscErrorCode PetscPDFSampleGaussian3D(const PetscReal p[], const PetscReal dummy[], PetscReal x[]) 297 { 298 PetscCall(PetscPDFSampleGaussian1D(p, dummy, x)); 299 PetscCall(PetscPDFSampleGaussian2D(&p[1], dummy, &x[1])); 300 return 0; 301 } 302 303 /*@ 304 PetscPDFConstant1D - PDF for the uniform distribution in 1D 305 306 Not collective 307 308 Input Parameter: 309 . x - Coordinate in [-1, 1] 310 311 Output Parameter: 312 . p - The probability density at x 313 314 Level: beginner 315 316 .seealso: `PetscCDFConstant1D()`, `PetscPDFSampleConstant1D()`, `PetscPDFConstant2D()`, `PetscPDFConstant3D()` 317 @*/ 318 PetscErrorCode PetscPDFConstant1D(const PetscReal x[], const PetscReal dummy[], PetscReal p[]) 319 { 320 p[0] = x[0] > -1. && x[0] <= 1. ? 0.5 : 0.; 321 return 0; 322 } 323 324 /*@ 325 PetscCDFConstant1D - CDF for the uniform distribution in 1D 326 327 Not collective 328 329 Input Parameter: 330 . x - Coordinate in [-1, 1] 331 332 Output Parameter: 333 . p - The cumulative probability at x 334 335 Level: beginner 336 337 .seealso: `PetscPDFConstant1D()`, `PetscPDFSampleConstant1D()`, `PetscCDFConstant2D()`, `PetscCDFConstant3D()` 338 @*/ 339 PetscErrorCode PetscCDFConstant1D(const PetscReal x[], const PetscReal dummy[], PetscReal p[]) 340 { 341 p[0] = x[0] <= -1. ? 0. : (x[0] > 1. ? 1. : 0.5*(x[0] + 1.)); 342 return 0; 343 } 344 345 /*@ 346 PetscPDFSampleConstant1D - Sample uniformly from a uniform distribution on [-1, 1] in 1D 347 348 Not collective 349 350 Input Parameter: 351 . p - A uniform variable on [0, 1] 352 353 Output Parameter: 354 . x - Coordinate in [-1, 1] 355 356 Level: beginner 357 358 .seealso: `PetscPDFConstant1D()`, `PetscCDFConstant1D()`, `PetscPDFSampleConstant2D()`, `PetscPDFSampleConstant3D()` 359 @*/ 360 PetscErrorCode PetscPDFSampleConstant1D(const PetscReal p[], const PetscReal dummy[], PetscReal x[]) 361 { 362 x[0] = 2.*p[0] - 1.; 363 return 0; 364 } 365 366 /*@ 367 PetscPDFConstant2D - PDF for the uniform distribution in 2D 368 369 Not collective 370 371 Input Parameter: 372 . x - Coordinate in [-1, 1] x [-1, 1] 373 374 Output Parameter: 375 . p - The probability density at x 376 377 Level: beginner 378 379 .seealso: `PetscCDFConstant2D()`, `PetscPDFSampleConstant2D()`, `PetscPDFConstant1D()`, `PetscPDFConstant3D()` 380 @*/ 381 PetscErrorCode PetscPDFConstant2D(const PetscReal x[], const PetscReal dummy[], PetscReal p[]) 382 { 383 p[0] = x[0] > -1. && x[0] <= 1. && x[1] > -1. && x[1] <= 1. ? 0.25 : 0.; 384 return 0; 385 } 386 387 /*@ 388 PetscCDFConstant2D - CDF for the uniform distribution in 2D 389 390 Not collective 391 392 Input Parameter: 393 . x - Coordinate in [-1, 1] x [-1, 1] 394 395 Output Parameter: 396 . p - The cumulative probability at x 397 398 Level: beginner 399 400 .seealso: `PetscPDFConstant2D()`, `PetscPDFSampleConstant2D()`, `PetscCDFConstant1D()`, `PetscCDFConstant3D()` 401 @*/ 402 PetscErrorCode PetscCDFConstant2D(const PetscReal x[], const PetscReal dummy[], PetscReal p[]) 403 { 404 p[0] = x[0] <= -1. || x[1] <= -1. ? 0. : (x[0] > 1. ? 1. : 0.5*(x[0] + 1.))*(x[1] > 1. ? 1. : 0.5*(x[1] + 1.)); 405 return 0; 406 } 407 408 /*@ 409 PetscPDFSampleConstant2D - Sample uniformly from a uniform distribution on [-1, 1] x [-1, 1] in 2D 410 411 Not collective 412 413 Input Parameter: 414 . p - Two uniform variables on [0, 1] 415 416 Output Parameter: 417 . x - Coordinate in [-1, 1] x [-1, 1] 418 419 Level: beginner 420 421 .seealso: `PetscPDFConstant2D()`, `PetscCDFConstant2D()`, `PetscPDFSampleConstant1D()`, `PetscPDFSampleConstant3D()` 422 @*/ 423 PetscErrorCode PetscPDFSampleConstant2D(const PetscReal p[], const PetscReal dummy[], PetscReal x[]) 424 { 425 x[0] = 2.*p[0] - 1.; 426 x[1] = 2.*p[1] - 1.; 427 return 0; 428 } 429 430 /*@ 431 PetscPDFConstant3D - PDF for the uniform distribution in 3D 432 433 Not collective 434 435 Input Parameter: 436 . x - Coordinate in [-1, 1] x [-1, 1] x [-1, 1] 437 438 Output Parameter: 439 . p - The probability density at x 440 441 Level: beginner 442 443 .seealso: `PetscCDFConstant3D()`, `PetscPDFSampleConstant3D()`, `PetscPDFSampleConstant1D()`, `PetscPDFSampleConstant2D()` 444 @*/ 445 PetscErrorCode PetscPDFConstant3D(const PetscReal x[], const PetscReal dummy[], PetscReal p[]) 446 { 447 p[0] = x[0] > -1. && x[0] <= 1. && x[1] > -1. && x[1] <= 1. && x[2] > -1. && x[2] <= 1. ? 0.125 : 0.; 448 return 0; 449 } 450 451 /*@ 452 PetscCDFConstant3D - CDF for the uniform distribution in 3D 453 454 Not collective 455 456 Input Parameter: 457 . x - Coordinate in [-1, 1] x [-1, 1] x [-1, 1] 458 459 Output Parameter: 460 . p - The cumulative probability at x 461 462 Level: beginner 463 464 .seealso: `PetscPDFConstant3D()`, `PetscPDFSampleConstant3D()`, `PetscCDFConstant1D()`, `PetscCDFConstant2D()` 465 @*/ 466 PetscErrorCode PetscCDFConstant3D(const PetscReal x[], const PetscReal dummy[], PetscReal p[]) 467 { 468 p[0] = x[0] <= -1. || x[1] <= -1. || x[2] <= -1. ? 0. : (x[0] > 1. ? 1. : 0.5*(x[0] + 1.))*(x[1] > 1. ? 1. : 0.5*(x[1] + 1.))*(x[2] > 1. ? 1. : 0.5*(x[2] + 1.)); 469 return 0; 470 } 471 472 /*@ 473 PetscPDFSampleConstant3D - Sample uniformly from a uniform distribution on [-1, 1] x [-1, 1] in 3D 474 475 Not collective 476 477 Input Parameter: 478 . p - Three uniform variables on [0, 1] 479 480 Output Parameter: 481 . x - Coordinate in [-1, 1] x [-1, 1] x [-1, 1] 482 483 Level: beginner 484 485 .seealso: `PetscPDFConstant3D()`, `PetscCDFConstant3D()`, `PetscPDFSampleConstant1D()`, `PetscPDFSampleConstant2D()` 486 @*/ 487 PetscErrorCode PetscPDFSampleConstant3D(const PetscReal p[], const PetscReal dummy[], PetscReal x[]) 488 { 489 x[0] = 2.*p[0] - 1.; 490 x[1] = 2.*p[1] - 1.; 491 x[2] = 2.*p[2] - 1.; 492 return 0; 493 } 494 495 /*@C 496 PetscProbCreateFromOptions - Return the probability distribution specified by the argumetns and options 497 498 Not collective 499 500 Input Parameters: 501 + dim - The dimension of sample points 502 . prefix - The options prefix, or NULL 503 - name - The option name for the probility distribution type 504 505 Output Parameters: 506 + pdf - The PDF of this type 507 . cdf - The CDF of this type 508 - sampler - The PDF sampler of this type 509 510 Level: intermediate 511 512 .seealso: `PetscPDFMaxwellBoltzmann1D()`, `PetscPDFGaussian1D()`, `PetscPDFConstant1D()` 513 @*/ 514 PetscErrorCode PetscProbCreateFromOptions(PetscInt dim, const char prefix[], const char name[], PetscProbFunc *pdf, PetscProbFunc *cdf, PetscProbFunc *sampler) 515 { 516 DTProbDensityType den = DTPROB_DENSITY_GAUSSIAN; 517 518 PetscFunctionBegin; 519 PetscOptionsBegin(PETSC_COMM_SELF, prefix, "PetscProb Options", "DT"); 520 PetscCall(PetscOptionsEnum(name, "Method to compute PDF <constant, gaussian>", "", DTProbDensityTypes, (PetscEnum) den, (PetscEnum *) &den, NULL)); 521 PetscOptionsEnd(); 522 523 if (pdf) {PetscValidPointer(pdf, 4); *pdf = NULL;} 524 if (cdf) {PetscValidPointer(cdf, 5); *cdf = NULL;} 525 if (sampler) {PetscValidPointer(sampler, 6); *sampler = NULL;} 526 switch (den) { 527 case DTPROB_DENSITY_CONSTANT: 528 switch (dim) { 529 case 1: 530 if (pdf) *pdf = PetscPDFConstant1D; 531 if (cdf) *cdf = PetscCDFConstant1D; 532 if (sampler) *sampler = PetscPDFSampleConstant1D; 533 break; 534 case 2: 535 if (pdf) *pdf = PetscPDFConstant2D; 536 if (cdf) *cdf = PetscCDFConstant2D; 537 if (sampler) *sampler = PetscPDFSampleConstant2D; 538 break; 539 case 3: 540 if (pdf) *pdf = PetscPDFConstant3D; 541 if (cdf) *cdf = PetscCDFConstant3D; 542 if (sampler) *sampler = PetscPDFSampleConstant3D; 543 break; 544 default: SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Dimension %" PetscInt_FMT " not supported for density type %s", dim, DTProbDensityTypes[den]); 545 } 546 break; 547 case DTPROB_DENSITY_GAUSSIAN: 548 switch (dim) { 549 case 1: 550 if (pdf) *pdf = PetscPDFGaussian1D; 551 if (cdf) *cdf = PetscCDFGaussian1D; 552 if (sampler) *sampler = PetscPDFSampleGaussian1D; 553 break; 554 case 2: 555 if (pdf) *pdf = PetscPDFGaussian2D; 556 if (sampler) *sampler = PetscPDFSampleGaussian2D; 557 break; 558 case 3: 559 if (pdf) *pdf = PetscPDFGaussian3D; 560 if (sampler) *sampler = PetscPDFSampleGaussian3D; 561 break; 562 default: SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Dimension %" PetscInt_FMT " not supported for density type %s", dim, DTProbDensityTypes[den]); 563 } 564 break; 565 case DTPROB_DENSITY_MAXWELL_BOLTZMANN: 566 switch (dim) { 567 case 1: 568 if (pdf) *pdf = PetscPDFMaxwellBoltzmann1D; 569 if (cdf) *cdf = PetscCDFMaxwellBoltzmann1D; 570 break; 571 case 2: 572 if (pdf) *pdf = PetscPDFMaxwellBoltzmann2D; 573 if (cdf) *cdf = PetscCDFMaxwellBoltzmann2D; 574 break; 575 case 3: 576 if (pdf) *pdf = PetscPDFMaxwellBoltzmann3D; 577 if (cdf) *cdf = PetscCDFMaxwellBoltzmann3D; 578 break; 579 default: SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Dimension %" PetscInt_FMT " not supported for density type %s", dim, DTProbDensityTypes[den]); 580 } 581 break; 582 default: SETERRQ(PETSC_COMM_SELF, PETSC_ERR_SUP, "Density type %s is not supported", DTProbDensityTypes[PetscMax(0, PetscMin(den, DTPROB_NUM_DENSITY))]); 583 } 584 PetscFunctionReturn(0); 585 } 586 587 #ifdef PETSC_HAVE_KS 588 EXTERN_C_BEGIN 589 #include <KolmogorovSmirnovDist.h> 590 EXTERN_C_END 591 #endif 592 593 /*@C 594 PetscProbComputeKSStatistic - Compute the Kolmogorov-Smirnov statistic for the empirical distribution for an input vector, compared to an analytic CDF. 595 596 Collective on v 597 598 Input Parameters: 599 + v - The data vector, blocksize is the sample dimension 600 - cdf - The analytic CDF 601 602 Output Parameter: 603 . alpha - The KS statisic 604 605 Level: advanced 606 607 Note: The Kolmogorov-Smirnov statistic for a given cumulative distribution function $F(x)$ is 608 $ 609 $ D_n = \sup_x \left| F_n(x) - F(x) \right| 610 $ 611 where $\sup_x$ is the supremum of the set of distances, and the empirical distribution 612 function $F_n(x)$ is discrete, and given by 613 $ 614 $ F_n = # of samples <= x / n 615 $ 616 The empirical distribution function $F_n(x)$ is discrete, and thus had a ``stairstep'' 617 cumulative distribution, making $n$ the number of stairs. Intuitively, the statistic takes 618 the largest absolute difference between the two distribution functions across all $x$ values. 619 620 .seealso: `PetscProbFunc` 621 @*/ 622 PetscErrorCode PetscProbComputeKSStatistic(Vec v, PetscProbFunc cdf, PetscReal *alpha) 623 { 624 #if !defined(PETSC_HAVE_KS) 625 SETERRQ(PetscObjectComm((PetscObject) v), PETSC_ERR_SUP, "No support for Kolmogorov-Smirnov test.\nReconfigure using --download-ks"); 626 #else 627 PetscViewer viewer = NULL; 628 PetscViewerFormat format; 629 PetscDraw draw; 630 PetscDrawLG lg; 631 PetscDrawAxis axis; 632 const PetscScalar *a; 633 PetscReal *speed, Dn = PETSC_MIN_REAL; 634 PetscBool isascii = PETSC_FALSE, isdraw = PETSC_FALSE, flg; 635 PetscInt n, p, dim, d; 636 PetscMPIInt size; 637 const char *names[2] = {"Analytic", "Empirical"}; 638 char title[PETSC_MAX_PATH_LEN]; 639 PetscOptions options; 640 const char *prefix; 641 MPI_Comm comm; 642 643 PetscFunctionBegin; 644 PetscCall(PetscObjectGetComm((PetscObject) v, &comm)); 645 PetscCall(PetscObjectGetOptionsPrefix((PetscObject) v, &prefix)); 646 PetscCall(PetscObjectGetOptions((PetscObject) v, &options)); 647 PetscCall(PetscOptionsGetViewer(comm, options, prefix, "-ks_monitor", &viewer, &format, &flg)); 648 if (flg) { 649 PetscCall(PetscObjectTypeCompare((PetscObject) viewer, PETSCVIEWERASCII, &isascii)); 650 PetscCall(PetscObjectTypeCompare((PetscObject) viewer, PETSCVIEWERDRAW, &isdraw)); 651 } 652 if (isascii) { 653 PetscCall(PetscViewerPushFormat(viewer, format)); 654 } else if (isdraw) { 655 PetscCall(PetscViewerPushFormat(viewer, format)); 656 PetscCall(PetscViewerDrawGetDraw(viewer, 0, &draw)); 657 PetscCall(PetscDrawLGCreate(draw, 2, &lg)); 658 PetscCall(PetscDrawLGSetLegend(lg, names)); 659 } 660 661 PetscCallMPI(MPI_Comm_size(PetscObjectComm((PetscObject) v), &size)); 662 PetscCall(VecGetLocalSize(v, &n)); 663 PetscCall(VecGetBlockSize(v, &dim)); 664 n /= dim; 665 /* TODO Parallel algorithm is harder */ 666 if (size == 1) { 667 PetscCall(PetscMalloc1(n, &speed)); 668 PetscCall(VecGetArrayRead(v, &a)); 669 for (p = 0; p < n; ++p) { 670 PetscReal mag = 0.; 671 672 for (d = 0; d < dim; ++d) mag += PetscSqr(PetscRealPart(a[p*dim+d])); 673 speed[p] = PetscSqrtReal(mag); 674 } 675 PetscCall(PetscSortReal(n, speed)); 676 PetscCall(VecRestoreArrayRead(v, &a)); 677 for (p = 0; p < n; ++p) { 678 const PetscReal x = speed[p], Fn = ((PetscReal) p) / n; 679 PetscReal F, vals[2]; 680 681 PetscCall(cdf(&x, NULL, &F)); 682 Dn = PetscMax(PetscAbsReal(Fn - F), Dn); 683 if (isascii) PetscCall(PetscViewerASCIIPrintf(viewer, "x: %g F: %g Fn: %g Dn: %.2g\n", x, F, Fn, Dn)); 684 if (isdraw) {vals[0] = F; vals[1] = Fn; PetscCall(PetscDrawLGAddCommonPoint(lg, x, vals));} 685 } 686 if (speed[n-1] < 6.) { 687 const PetscReal k = (PetscInt) (6. - speed[n-1]) + 1, dx = (6. - speed[n-1])/k; 688 for (p = 0; p <= k; ++p) { 689 const PetscReal x = speed[n-1] + p*dx, Fn = 1.0; 690 PetscReal F, vals[2]; 691 692 PetscCall(cdf(&x, NULL, &F)); 693 Dn = PetscMax(PetscAbsReal(Fn - F), Dn); 694 if (isascii) PetscCall(PetscViewerASCIIPrintf(viewer, "x: %g F: %g Fn: %g Dn: %.2g\n", x, F, Fn, Dn)); 695 if (isdraw) {vals[0] = F; vals[1] = Fn; PetscCall(PetscDrawLGAddCommonPoint(lg, x, vals));} 696 } 697 } 698 PetscCall(PetscFree(speed)); 699 } 700 if (isdraw) { 701 PetscCall(PetscDrawLGGetAxis(lg, &axis)); 702 PetscCall(PetscSNPrintf(title, PETSC_MAX_PATH_LEN, "Kolmogorov-Smirnov Test (Dn %.2g)", Dn)); 703 PetscCall(PetscDrawAxisSetLabels(axis, title, "x", "CDF(x)")); 704 PetscCall(PetscDrawLGDraw(lg)); 705 PetscCall(PetscDrawLGDestroy(&lg)); 706 } 707 if (viewer) { 708 PetscCall(PetscViewerFlush(viewer)); 709 PetscCall(PetscViewerPopFormat(viewer)); 710 PetscCall(PetscViewerDestroy(&viewer)); 711 } 712 *alpha = KSfbar((int) n, (double) Dn); 713 PetscFunctionReturn(0); 714 #endif 715 } 716