File: weather_test.cpp

package info (click to toggle)
cataclysm-dda 0.H-1
  • links: PTS, VCS
  • area: main
  • in suites: forky, sid, trixie
  • size: 710,808 kB
  • sloc: cpp: 524,019; python: 11,580; sh: 1,228; makefile: 1,169; xml: 507; javascript: 150; sql: 56; exp: 41; perl: 37
file content (473 lines) | stat: -rw-r--r-- 25,225 bytes parent folder | download
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
#include <algorithm>
#include <cstdlib>
#include <map>
#include <vector>

#include "calendar.h"
#include "cata_catch.h"
#include "cata_scope_helpers.h"
#include "options_helpers.h"
#include "point.h"
#include "type_id.h"
#include "weather.h"
#include "weather_gen.h"
#include "weather_type.h"

static double mean_abs_running_diff( std::vector<double> const &v )
{
    double x = 0;
    int n = v.size() - 1;
    for( int i = 0 ; i < n ; ++i ) {
        x += std::abs( v[i + 1] - v[i] );
    }
    return x / n;
}

static double mean_pairwise_diffs( std::vector<double> const &a, std::vector<double> const &b )
{
    double x = 0;
    int n = a.size();
    for( int i = 0 ; i < n ; ++i ) {
        x += a[i] - b[i];
    }
    return x / n;
}

static double proportion_gteq_x( std::vector<double> const &v, double x )
{
    int count = 0;
    for( double i : v ) {
        count += ( i >= x );
    }
    return static_cast<double>( count ) / v.size();
}

static constexpr int n_hours = to_hours<int>( 1_days );
static constexpr int n_minutes = to_minutes<int>( 1_days );

struct year_of_weather_data {
    explicit year_of_weather_data( int n_days )
        : temperature( n_days, std::vector<double>( n_minutes, 0 ) )
        , hourly_precip( n_days * n_hours, 0 )
        , highs( n_days )
        , lows( n_days )
    {}

    std::vector<std::vector<double>> temperature;
    std::vector<double> hourly_precip;
    std::vector<double> highs;
    std::vector<double> lows;
};

static year_of_weather_data collect_weather_data( unsigned seed )
{
    scoped_weather_override null_weather( WEATHER_NULL );
    const weather_generator &wgen = get_weather().get_cur_weather_gen();

    const time_point begin = calendar::turn_zero;
    const time_point end = begin + calendar::year_length();
    const int n_days = to_days<int>( end - begin );
    year_of_weather_data result( n_days );

    // Collect generated weather data for a single year.
    for( time_point i = begin ; i < end ; i += 1_minutes ) {
        w_point w = wgen.get_weather( tripoint_abs_ms( tripoint_zero ), i, seed );
        int day = to_days<int>( time_past_new_year( i ) );
        int minute = to_minutes<int>( time_past_midnight( i ) );
        result.temperature[day][minute] = units::to_fahrenheit( w.temperature );
        int hour = to_hours<int>( time_past_new_year( i ) );
        *get_weather().weather_precise = w;
        result.hourly_precip[hour] +=
            precip_mm_per_hour(
                wgen.get_weather_conditions( w )->precip )
            / 60;
    }

    // Collect daily highs and lows.
    for( int do_highs = 0 ; do_highs < 2 ; ++do_highs ) {
        std::vector<double> &t = do_highs ? result.highs : result.lows;
        std::transform( result.temperature.begin(), result.temperature.end(), t.begin(),
        [&]( std::vector<double> const & day ) {
            return do_highs
                   ? *std::max_element( day.begin(), day.end() )
                   : *std::min_element( day.begin(), day.end() );
        } );
    }

    return result;
}

// Try a few randomly selected seeds.
static const std::array<unsigned, 3> seeds = { {317'024'741, 870'078'684, 1'192'447'748} };

TEST_CASE( "weather_realism", "[weather]" )
// Check our simulated weather against numbers from real data
// from a few years in a few locations in New England. The numbers
// are based on NOAA's Local Climatological Data (LCD). Analysis code
// can be found at:
// https://gist.github.com/Kodiologist/e2f1e6685e8fd865650f97bb6a67ad07
{
    for( unsigned int seed : seeds ) {
        year_of_weather_data data = collect_weather_data( seed );

        // Check the mean absolute difference between the highs or lows
        // of adjacent days (Fahrenheit).
        const double mad_highs = mean_abs_running_diff( data.highs );
        CHECK( mad_highs >= 5.5 );
        CHECK( mad_highs <= 7.5 );
        const double mad_lows = mean_abs_running_diff( data.lows );
        CHECK( mad_lows >= 4 );
        CHECK( mad_lows <= 7 );

        // Check the daily mean of the range in temperatures (Fahrenheit).
        const double mean_of_ranges = mean_pairwise_diffs( data.highs, data.lows );
        CHECK( mean_of_ranges >= 14 );
        CHECK( mean_of_ranges <= 25 );

        // Check that summer and winter temperatures are very different.
        size_t half = data.highs.size() / 4;
        double summer_low = data.lows[half];
        double winter_high = data.highs[0];
        {
            CAPTURE( summer_low );
            CAPTURE( winter_high );
            CHECK( summer_low - winter_high >= 10 );
        }

        // Check the proportion of hours with light precipitation
        // or more, counting snow (mm of rain equivalent per hour).
        const double at_least_light_precip = proportion_gteq_x( data.hourly_precip, 1 );
        CHECK( at_least_light_precip >= .025 );
        CHECK( at_least_light_precip <= .05 );

        // Likewise for heavy precipitation.
        const double heavy_precip = proportion_gteq_x( data.hourly_precip, 2.5 );
        CHECK( heavy_precip >= .005 );
        CHECK( heavy_precip <= .02 );
    }
}

TEST_CASE( "eternal_season", "[weather]" )
{
    on_out_of_scope restore_eternal_season( []() {
        calendar::set_eternal_season( false );
    } );
    calendar::set_eternal_season( true );
    override_option override_eternal_season( "ETERNAL_SEASON", "true" );

    for( unsigned int seed : seeds ) {
        year_of_weather_data data = collect_weather_data( seed );

        // Check that summer and winter temperatures are very similar.
        size_t half = data.highs.size() / 4;
        double summer_low = data.lows[half];
        double winter_high = data.highs[0];
        {
            CAPTURE( summer_low );
            CAPTURE( winter_high );
            CHECK( summer_low - winter_high <= -10 );
        }

        // Check the temperatures still vary from day to day.
        const double mad_highs = mean_abs_running_diff( data.highs );
        CHECK( mad_highs >= 5.5 );
        CHECK( mad_highs <= 7.5 );
        const double mad_lows = mean_abs_running_diff( data.lows );
        CHECK( mad_lows >= 4 );
        CHECK( mad_lows <= 7 );
    }
}

TEST_CASE( "local_wind_chill_calculation", "[weather][wind_chill]" )
{
    // `get_local_windchill` returns degrees F offset from current temperature,
    // representing the amount of temperature difference from wind chill alone.
    //
    // It uses one of two formulas or models depending on the current temperature.
    // Below 50F, the North American / UK "wind chill index" is used. At 50F or above,
    // the Australian "apparent temperature" is used.
    //
    // All "quoted text" below is paraphrased from the Wikipedia article:
    // https://en.wikipedia.org/wiki/Wind_chill

    // CHECK expressions have the expected result on the left for readability.

    units::temperature temp_f;
    double humidity;
    double wind_mph;

    SECTION( "below 50F - North American and UK wind chill index" ) {

        // "Windchill temperature is defined only for temperatures at or below 10C (50F)
        // and wind speeds above 4.8 kilometres per hour (3.0 mph)."

        WHEN( "wind speed is less than 3 mph" ) {
            THEN( "windchill is undefined and effectively 0" ) {
                CHECK( 0 == units::to_kelvin_delta( get_local_windchill( units::from_fahrenheit( 30.0f ), 0.0f,
                                                    2.9f ) ) );
                CHECK( 0 == units::to_kelvin_delta( get_local_windchill( units::from_fahrenheit( 30.0f ), 0.0f,
                                                    2.0f ) ) );
                CHECK( 0 == units::to_kelvin_delta( get_local_windchill( units::from_fahrenheit( 30.0f ), 0.0f,
                                                    1.0f ) ) );
                CHECK( 0 == units::to_kelvin_delta( get_local_windchill( units::from_fahrenheit( 30.0f ), 0.0f,
                                                    0.0f ) ) );
            }
        }

        // "As the air temperature falls, the chilling effect of any wind that is present increases.
        // For example, a 16 km/h (9.9 mph) wind will lower the apparent temperature by a wider
        // margin at an air temperature of −20C (−4F), than a wind of the same speed would if
        // the air temperature were −10C (14F)."

        GIVEN( "constant wind of 10mph" ) {
            wind_mph = 10.0f;

            WHEN( "temperature is -10C (14F)" ) {
                temp_f = units::from_fahrenheit( 14.0f );

                THEN( "the wind chill effect is -7C (-12.6F)" ) {
                    CHECK( units::to_kelvin_delta( get_local_windchill( temp_f, 0.0f,
                                                   wind_mph ) ) == Approx( -7.0 ).margin( 0.1 ) );
                }
            }

            WHEN( "temperature is -20C (-4F)" ) {
                temp_f = units::from_fahrenheit( -4.0f );

                THEN( "there is more wind chill, an effect of -9.4C (-17F)" ) {
                    CHECK( units::to_kelvin_delta( get_local_windchill( temp_f, 0.0f,
                                                   wind_mph ) ) == Approx( -9.4 ).margin( 0.1 ) );
                }
            }
        }

        // More generally:

        WHEN( "wind speed is at least 3 mph" ) {
            THEN( "windchill gets colder as temperature decreases" ) {
                CHECK( units::to_kelvin_delta( get_local_windchill( units::from_fahrenheit( 40.0f ), 0.0f,
                                               15.0f ) ) == Approx( -4.5 ).margin( 0.1 ) );
                CHECK( units::to_kelvin_delta( get_local_windchill( units::from_fahrenheit( 30.0f ), 0.0f,
                                               15.0f ) ) == Approx( -6.1 ).margin( 0.1 ) );
                CHECK( units::to_kelvin_delta( get_local_windchill( units::from_fahrenheit( 20.0f ), 0.0f,
                                               15.0f ) ) == Approx( -7.7 ).margin( 0.1 ) );
                CHECK( units::to_kelvin_delta( get_local_windchill( units::from_fahrenheit( 10.0f ), 0.0f,
                                               15.0f ) ) == Approx( -9.2 ).margin( 0.1 ) );
                CHECK( units::to_kelvin_delta( get_local_windchill( units::from_fahrenheit( 0.0f ), 0.0f,
                                               15.0f ) ) == Approx( -10.8 ).margin( 0.1 ) );
                CHECK( units::to_kelvin_delta( get_local_windchill( units::from_fahrenheit( -10.0f ), 0.0f,
                                               15.0f ) ) == Approx( -12.4 ).margin( 0.1 ) );
                CHECK( units::to_kelvin_delta( get_local_windchill( units::from_fahrenheit( -20.0f ), 0.0f,
                                               15.0f ) ) == Approx( -13.9 ).margin( 0.1 ) );
                CHECK( units::to_kelvin_delta( get_local_windchill( units::from_fahrenheit( -30.0f ), 0.0f,
                                               15.0f ) ) == Approx( -15.5 ).margin( 0.1 ) );
                CHECK( units::to_kelvin_delta( get_local_windchill( units::from_fahrenheit( -40.0f ), 0.0f,
                                               15.0f ) ) == Approx( -17.1 ).margin( 0.1 ) );
            }
        }

        // "When the temperature is −20C (−4F) and the wind speed is 5 km/h (3.1 mph),
        // the wind chill index is -4.3C. If the temperature remains at −20C and the wind
        // speed increases to 30 km/h (19 mph), the wind chill index falls to −12.7C."

        GIVEN( "constant temperature of -20C (-4F)" ) {
            temp_f = units::from_fahrenheit( -4.0f );

            WHEN( "wind speed is 3.1mph" ) {
                wind_mph = 3.1f;

                THEN( "wind chill is -4.3C (-7.74F)" ) {
                    // -4C offset from -20C =~ -7.2F offset from -4F
                    CHECK( units::to_kelvin_delta( get_local_windchill( temp_f, 0.0f,
                                                   wind_mph ) ) == Approx( -4.3 ).margin( 0.1 ) );
                }
            }
            WHEN( "wind speed increases to 19mph" ) {
                wind_mph = 19.0f;

                THEN( "wind chill is -12.7C (-22.9F)" ) {
                    CHECK( units::to_kelvin_delta( get_local_windchill( temp_f, 0.0f,
                                                   wind_mph ) ) == Approx( -12.7 ).margin( 0.1 ) );
                }
            }
        }

        // Or more generally:

        WHEN( "wind speed is at least 3 mph" ) {
            THEN( "windchill gets colder as wind increases" ) {
                // Just below freezing
                CHECK( units::to_kelvin_delta( get_local_windchill( units::from_fahrenheit( 30.0f ), 0.0f,
                                               3.0f ) ) == Approx( -1.6 ).margin( 0.1 ) );
                CHECK( units::to_kelvin_delta( get_local_windchill( units::from_fahrenheit( 30.0f ), 0.0f,
                                               4.0f ) ) == Approx( -2.4 ).margin( 0.1 ) );
                CHECK( units::to_kelvin_delta( get_local_windchill( units::from_fahrenheit( 30.0f ), 0.0f,
                                               5.0f ) ) == Approx( -2.9 ).margin( 0.1 ) );
                CHECK( units::to_kelvin_delta( get_local_windchill( units::from_fahrenheit( 30.0f ), 0.0f,
                                               10.0f ) ) == Approx( -4.9 ).margin( 0.1 ) );
                CHECK( units::to_kelvin_delta( get_local_windchill( units::from_fahrenheit( 30.0f ), 0.0f,
                                               20.0f ) ) == Approx( -7.0 ).margin( 0.1 ) );
                CHECK( units::to_kelvin_delta( get_local_windchill( units::from_fahrenheit( 30.0f ), 0.0f,
                                               30.0f ) ) == Approx( -8.4 ).margin( 0.1 ) );
                CHECK( units::to_kelvin_delta( get_local_windchill( units::from_fahrenheit( 30.0f ), 0.0f,
                                               40.0f ) ) == Approx( -9.5 ).margin( 0.1 ) );
                CHECK( units::to_kelvin_delta( get_local_windchill( units::from_fahrenheit( 30.0f ), 0.0f,
                                               50.0f ) ) == Approx( -10.3 ).margin( 0.1 ) );

                // Well below zero
                CHECK( units::to_kelvin_delta( get_local_windchill( units::from_fahrenheit( -30.0f ), 0.0f,
                                               3.0f ) ) == Approx( -6.0 ).margin( 0.1 ) );
                CHECK( units::to_kelvin_delta( get_local_windchill( units::from_fahrenheit( -30.0f ), 0.0f,
                                               4.0f ) ) == Approx( -7.6 ).margin( 0.1 ) );
                CHECK( units::to_kelvin_delta( get_local_windchill( units::from_fahrenheit( -30.0f ), 0.0f,
                                               5.0f ) ) == Approx( -8.8 ).margin( 0.1 ) );
                CHECK( units::to_kelvin_delta( get_local_windchill( units::from_fahrenheit( -30.0f ), 0.0f,
                                               10.0f ) ) == Approx( -12.9 ).margin( 0.1 ) );
                CHECK( units::to_kelvin_delta( get_local_windchill( units::from_fahrenheit( -30.0f ), 0.0f,
                                               20.0f ) ) == Approx( -17.5 ).margin( 0.1 ) );
                CHECK( units::to_kelvin_delta( get_local_windchill( units::from_fahrenheit( -30.0f ), 0.0f,
                                               30.0f ) ) == Approx( -20.4 ).margin( 0.1 ) );
                CHECK( units::to_kelvin_delta( get_local_windchill( units::from_fahrenheit( -30.0f ), 0.0f,
                                               40.0f ) ) == Approx( -22.6 ).margin( 0.1 ) );
                CHECK( units::to_kelvin_delta( get_local_windchill( units::from_fahrenheit( -30.0f ), 0.0f,
                                               50.0f ) ) == Approx( -24.3 ).margin( 0.1 ) );
            }
        }

        // The function accepts a humidity argument, but this model does not use it.
        //
        // "The North American formula was designed to be applied at low temperatures
        // (as low as −46C or −50F) when humidity levels are also low."

        THEN( "wind chill index is unaffected by humidity" ) {
            CHECK( units::to_kelvin_delta( get_local_windchill( units::from_fahrenheit( 40.0f ), 0.0f,
                                           10.0f ) ) == Approx( -3.5 ).margin( 0.1 ) );
            CHECK( units::to_kelvin_delta( get_local_windchill( units::from_fahrenheit( 40.0f ), 50.0f,
                                           10.0f ) ) == Approx( -3.5 ).margin( 0.1 ) );
            CHECK( units::to_kelvin_delta( get_local_windchill( units::from_fahrenheit( 40.0f ), 100.0f,
                                           10.0f ) ) == Approx( -3.5 ).margin( 0.1 ) );

            CHECK( units::to_kelvin_delta( get_local_windchill( units::from_fahrenheit( 10.0f ), 0.0f,
                                           30.0f ) ) == Approx( -12.4 ).margin( 0.1 ) );
            CHECK( units::to_kelvin_delta( get_local_windchill( units::from_fahrenheit( 10.0f ), 50.0f,
                                           30.0f ) ) == Approx( -12.4 ).margin( 0.1 ) );
            CHECK( units::to_kelvin_delta( get_local_windchill( units::from_fahrenheit( 10.0f ), 100.0f,
                                           30.0f ) ) == Approx( -12.4 ).margin( 0.1 ) );

            CHECK( units::to_kelvin_delta( get_local_windchill( units::from_fahrenheit( -20.0f ), 0.0f,
                                           30.0f ) ) == Approx( -18.4 ).margin( 0.1 ) );
            CHECK( units::to_kelvin_delta( get_local_windchill( units::from_fahrenheit( -20.0f ), 50.0f,
                                           30.0f ) ) == Approx( -18.4 ).margin( 0.1 ) );
            CHECK( units::to_kelvin_delta( get_local_windchill( units::from_fahrenheit( -20.0f ), 100.0f,
                                           30.0f ) ) == Approx( -18.4 ).margin( 0.1 ) );
        }
    }

    SECTION( "50F and above - Australian apparent temperature" ) {
        GIVEN( "constant temperature of 50F" ) {
            temp_f = units::from_fahrenheit( 50.0f );

            WHEN( "wind is steady at 10mph" ) {
                wind_mph = 10.0f;

                THEN( "apparent temp increases as humidity increases" ) {
                    CHECK( units::to_kelvin_delta( get_local_windchill( temp_f, 0.0f,
                                                   wind_mph ) ) == Approx( -7.1 ).margin( 0.1 ) );
                    CHECK( units::to_kelvin_delta( get_local_windchill( temp_f, 20.0f,
                                                   wind_mph ) ) == Approx( -6.3 ).margin( 0.1 ) );
                    CHECK( units::to_kelvin_delta( get_local_windchill( temp_f, 40.0f,
                                                   wind_mph ) ) == Approx( -5.5 ).margin( 0.1 ) );
                    CHECK( units::to_kelvin_delta( get_local_windchill( temp_f, 60.0f,
                                                   wind_mph ) ) == Approx( -4.7 ).margin( 0.1 ) );
                    CHECK( units::to_kelvin_delta( get_local_windchill( temp_f, 80.0f,
                                                   wind_mph ) ) == Approx( -3.9 ).margin( 0.1 ) );
                    CHECK( units::to_kelvin_delta( get_local_windchill( temp_f, 100.0f,
                                                   wind_mph ) ) == Approx( -3.1 ).margin( 0.1 ) );
                }
            }

            WHEN( "humidity is steady at 90%%" ) {
                humidity = 90.0f;

                THEN( "apparent temp decreases as wind increases" ) {
                    CHECK( units::to_kelvin_delta( get_local_windchill( temp_f, humidity,
                                                   0.0f ) ) == Approx( -0.36 ).margin( 0.01 ) );
                    CHECK( units::to_kelvin_delta( get_local_windchill( temp_f, humidity,
                                                   10.0f ) ) == Approx( -3.5 ).margin( 0.1 ) );
                    CHECK( units::to_kelvin_delta( get_local_windchill( temp_f, humidity,
                                                   20.0f ) ) == Approx( -6.6 ).margin( 0.1 ) );
                    CHECK( units::to_kelvin_delta( get_local_windchill( temp_f, humidity,
                                                   30.0f ) ) == Approx( -9.7 ).margin( 0.1 ) );
                    CHECK( units::to_kelvin_delta( get_local_windchill( temp_f, humidity,
                                                   40.0f ) ) == Approx( -12.9 ).margin( 0.1 ) );
                    CHECK( units::to_kelvin_delta( get_local_windchill( temp_f, humidity,
                                                   50.0f ) ) == Approx( -16.0 ).margin( 0.1 ) );
                }
            }
        }

        GIVEN( "humidity is zero" ) {
            humidity = 0.0f;

            THEN( "apparent temp offset is only influenced by wind speed" ) {
                CHECK( units::to_kelvin_delta( get_local_windchill( units::from_fahrenheit( 50.0f ), humidity,
                                               0.0f ) ) == Approx( -4.0 ).margin( 0.1 ) );
                CHECK( units::to_kelvin_delta( get_local_windchill( units::from_fahrenheit( 70.0f ), humidity,
                                               0.0f ) ) == Approx( -4.0 ).margin( 0.1 ) );
                CHECK( units::to_kelvin_delta( get_local_windchill( units::from_fahrenheit( 90.0f ), humidity,
                                               0.0f ) ) == Approx( -4.0 ).margin( 0.1 ) );

                // 25mph wind == -11.8K (-21F) to temperature
                CHECK( units::to_kelvin_delta( get_local_windchill( units::from_fahrenheit( 50.0f ), humidity,
                                               25.0f ) ) == Approx( -11.8 ).margin( 0.1 ) );
                CHECK( units::to_kelvin_delta( get_local_windchill( units::from_fahrenheit( 70.0f ), humidity,
                                               25.0f ) ) == Approx( -11.8 ).margin( 0.1 ) );
                CHECK( units::to_kelvin_delta( get_local_windchill( units::from_fahrenheit( 90.0f ), humidity,
                                               25.0f ) ) == Approx( -11.8 ).margin( 0.1 ) );
            }
        }

        GIVEN( "humidity is 50 percent" ) {
            humidity = 50.0f;

            WHEN( "there is no wind" ) {
                wind_mph = 0.0f;

                THEN( "apparent temp increases more as it gets hotter" ) {
                    CHECK( units::to_kelvin_delta( get_local_windchill( units::from_fahrenheit( 50.0f ), humidity,
                                                   wind_mph ) ) == Approx( -2.0 ).margin( 0.1 ) );
                    CHECK( units::to_kelvin_delta( get_local_windchill( units::from_fahrenheit( 60.0f ), humidity,
                                                   wind_mph ) ) == Approx( -1.1 ).margin( 0.1 ) );
                    CHECK( units::to_kelvin_delta( get_local_windchill( units::from_fahrenheit( 70.0f ), humidity,
                                                   wind_mph ) ) == Approx( 0.12 ).margin( 0.01 ) );
                    CHECK( units::to_kelvin_delta( get_local_windchill( units::from_fahrenheit( 80.0f ), humidity,
                                                   wind_mph ) ) == Approx( 1.8 ).margin( 0.1 ) );
                    CHECK( units::to_kelvin_delta( get_local_windchill( units::from_fahrenheit( 90.0f ), humidity,
                                                   wind_mph ) ) == Approx( 3.9 ).margin( 0.1 ) );
                    CHECK( units::to_kelvin_delta( get_local_windchill( units::from_fahrenheit( 100.0f ), humidity,
                                                   wind_mph ) ) == Approx( 6.8 ).margin( 0.1 ) );
                }
            }

            WHEN( "wind is steady at 10mph" ) {
                wind_mph = 10.0f;

                THEN( "apparent temp is less but still increases more as it gets hotter" ) {
                    CHECK( units::to_kelvin_delta( get_local_windchill( units::from_fahrenheit( 50.0f ), humidity,
                                                   wind_mph ) ) == Approx( -5.1 ).margin( 0.1 ) );
                    CHECK( units::to_kelvin_delta( get_local_windchill( units::from_fahrenheit( 60.0f ), humidity,
                                                   wind_mph ) ) == Approx( -4.2 ).margin( 0.1 ) );
                    CHECK( units::to_kelvin_delta( get_local_windchill( units::from_fahrenheit( 70.0f ), humidity,
                                                   wind_mph ) ) == Approx( -3.0 ).margin( 0.1 ) );
                    CHECK( units::to_kelvin_delta( get_local_windchill( units::from_fahrenheit( 80.0f ), humidity,
                                                   wind_mph ) ) == Approx( -1.4 ).margin( 0.1 ) );
                    CHECK( units::to_kelvin_delta( get_local_windchill( units::from_fahrenheit( 90.0f ), humidity,
                                                   wind_mph ) ) == Approx( 0.78 ).margin( 0.01 ) );
                    CHECK( units::to_kelvin_delta( get_local_windchill( units::from_fahrenheit( 100.0f ), humidity,
                                                   wind_mph ) ) == Approx( 3.6 ).margin( 0.1 ) );
                }
            }
        }
    }
}