climate_test.cpp 3.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150
  1. ///////////////////////////////////////////////////////////////////////////////////////
  2. /// \file climate_test.cpp
  3. /// \brief Unit tests for functions processing climate data
  4. ///
  5. /// \author Joe Siltberg
  6. /// $Date: 2013-10-10 10:20:33 +0200 (Thu, 10 Oct 2013) $
  7. ///
  8. ///////////////////////////////////////////////////////////////////////////////////////
  9. #include "config.h"
  10. #include "catch.hpp"
  11. #include "driver.h"
  12. #include <algorithm>
  13. #include <vector>
  14. namespace {
  15. /// Convenience function for testing prdaily
  16. /** Tests prdaily for given monthly conditions, the same conditions
  17. * are used throughout the year, makes it easy to write test cases
  18. * without specifying 24 values.
  19. */
  20. bool verify_prdaily_single_month(double prec, double wetdays) {
  21. double monthly_prec[12];
  22. std::fill(monthly_prec, monthly_prec+12, prec);
  23. double monthly_wetdays[12];
  24. std::fill(monthly_wetdays, monthly_wetdays+12, wetdays);
  25. double days[365];
  26. long seed = 12345678;
  27. prdaily(monthly_prec, days, monthly_wetdays, seed,
  28. false /* truncate set to false since we want to verify the sum */
  29. );
  30. // Verify monthly sums and number of wet days
  31. const double SUM_TOLERANCE = 0.1;
  32. Date date;
  33. int current_day = 0;
  34. for (int m = 0; m < 12; m++) {
  35. double sum = 0;
  36. int wetcount = 0;
  37. for (int d = 0; d < date.ndaymonth[m]; d++) {
  38. sum += days[current_day];
  39. if (days[current_day] > 0) {
  40. wetcount++;
  41. }
  42. current_day++;
  43. }
  44. // Check that the sum for this month isn't too far from
  45. // the prescribed monthly precipitation
  46. if (fabs(sum-prec) > SUM_TOLERANCE) {
  47. return false;
  48. }
  49. // Verify wetcount?
  50. }
  51. return true;
  52. }
  53. bool verify_interp_monthly_means_conserve(const double* mvals,
  54. double minimum = -std::numeric_limits<double>::max(),
  55. double maximum = std::numeric_limits<double>::max()) {
  56. const double TOLERANCE = 0.0001;
  57. // Set upper and lower limits for allowed daily values
  58. // (apart from the limits supplied as parameters)
  59. std::vector<double> upper_limit(12), lower_limit(12);
  60. for (int m = 0; m < 12; m++) {
  61. int next_month = (m+1)%12;
  62. int prev_month = (m+11)%12;
  63. double next = mvals[next_month];
  64. double prev = mvals[prev_month];
  65. double current = mvals[m];
  66. double smallest = std::min(current, std::min(next, prev));
  67. double largest = std::max(current, std::max(next, prev));
  68. upper_limit[m] = std::max(largest, current+(current-smallest));
  69. lower_limit[m] = std::min(smallest, current-(largest-current));
  70. }
  71. double dvals[365];
  72. interp_monthly_means_conserve(mvals, dvals, minimum, maximum);
  73. std::vector<double> sums(12, 0);
  74. // Make sure daily values are within allowed limits
  75. Date date;
  76. date.init(1);
  77. for (int i = 0; i < 365; i++) {
  78. sums[date.month] += dvals[i];
  79. if (dvals[i] > upper_limit[date.month] + TOLERANCE ||
  80. dvals[i] < lower_limit[date.month] - TOLERANCE) {
  81. return false;
  82. }
  83. if (dvals[i] < minimum || dvals[i] > maximum) {
  84. return false;
  85. }
  86. date.next();
  87. }
  88. // Make sure monthly means are conserved
  89. for (int m = 0; m < 12; m++) {
  90. if (fabs(sums[m]/date.ndaymonth[m] - mvals[m]) > TOLERANCE) {
  91. return false;
  92. }
  93. }
  94. return true;
  95. }
  96. }
  97. TEST_CASE("climate/prdaily", "Tests for the prdaily function") {
  98. // Test no water
  99. REQUIRE(verify_prdaily_single_month(0, 0));
  100. // Regression test:
  101. // Very small number of wet days used to cause infinite loop
  102. REQUIRE(verify_prdaily_single_month(1, 0.001));
  103. // Regression test:
  104. // Very little precipitation and many wet days used to cause infinite loop
  105. REQUIRE(verify_prdaily_single_month(0.1, 30));
  106. }
  107. TEST_CASE("climate/interp_monthly_means_conserve", "Tests the monthly to daily interpolation") {
  108. double test1[] = { 0, 10, 20, 15, 15, 15, 40, 0, 40, 30, 20, 5};
  109. REQUIRE(verify_interp_monthly_means_conserve(test1, 0, 40));
  110. }