star-meteo

Time varying meteorological data
git clone git://git.meso-star.fr/star-meteo.git
Log | Files | Refs | README | LICENSE

test_smeteo_load.c (7663B)


      1 /* Copyright (C) 2025 |Méso|Star> (contact@meso-star.com)
      2  *
      3  * This program is free software: you can redismeteobute it and/or modify
      4  * it under the terms of the GNU General Public License as published by
      5  * the Free Software Foundation, either version 3 of the License, or
      6  * (at your option) any later version.
      7  *
      8  * This program is dismeteobuted in the hope that it will be useful,
      9  * but WITHOUT ANY WARRANTY; without even the implied warranty of
     10  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
     11  * GNU General Public License for more details.
     12  *
     13  * You should have received a copy of the GNU General Public License
     14  * along with this program. If not, see <http://www.gnu.org/licenses/>. */
     15 
     16 #define _POSIX_C_SOURCE 200112L /* strcasecmp */
     17 
     18 #include "smeteo.h"
     19 
     20 #include <rsys/mem_allocator.h>
     21 
     22 #include <string.h>
     23 #include <strings.h> /* strcasecmp */
     24 
     25 /*******************************************************************************
     26  * Helper functions
     27  ******************************************************************************/
     28 static void
     29 check_api(struct smeteo* smeteo)
     30 {
     31   struct smeteo_desc desc = SMETEO_DESC_NULL;
     32   const char* filename = "test.txt";
     33   const double albedo = 0.314;
     34   const double latitude  = 43.559962; /* [deg] */
     35   const double longitude = 1.468150; /* [deg] */
     36   FILE* fp = NULL;
     37 
     38   CHK((fp = fopen(filename, "w+")) != NULL);
     39 
     40   #define CHECK_NO_DATA(Name) { \
     41     CHK(smeteo_get_desc(smeteo, &desc) == RES_OK); \
     42     CHK(!strcmp(desc.filename, Name)); \
     43     CHK(desc.albedo == albedo); \
     44     CHK(desc.longitude == longitude); \
     45     CHK(desc.latitude == latitude); \
     46     CHK(desc.entries == NULL); \
     47     CHK(desc.nentries == 0); \
     48   } (void)0
     49 
     50   CHK(smeteo_load(smeteo, NULL) == RES_BAD_ARG);
     51   CHK(smeteo_load(NULL, filename) == RES_BAD_ARG);
     52   CHK(smeteo_load(smeteo, "none.txt") == RES_IO_ERR);
     53 
     54   /* An empty file is not valid: at least the header is required */
     55   CHK(smeteo_load(smeteo, filename) == RES_BAD_ARG);
     56 
     57   CHK(fprintf(fp, "%a # Albedo\n", albedo) > 0);
     58   CHK(fprintf(fp, "%a # Longitude [deg]\n", longitude) > 0);
     59   CHK(fprintf(fp, "%a # Latitude [deg]\n", latitude) > 0);
     60   CHK(fprintf(fp, "0 # Date count\n") > 0);
     61   CHK(fflush(fp) == 0);
     62 
     63   CHK(smeteo_load(smeteo, filename) == RES_OK);
     64 
     65   CHK(smeteo_get_desc(NULL, &desc) == RES_BAD_ARG);
     66   CHK(smeteo_get_desc(smeteo, NULL) == RES_BAD_ARG);
     67 
     68   CHECK_NO_DATA(filename);
     69 
     70   rewind(fp);
     71   CHK(smeteo_load_stream(NULL, fp, "foo") == RES_BAD_ARG);
     72   CHK(smeteo_load_stream(smeteo, NULL, "foo") == RES_BAD_ARG);
     73   CHK(smeteo_load_stream(smeteo, fp, NULL) == RES_BAD_ARG);
     74   CHK(smeteo_load_stream(smeteo, fp, "foo") == RES_OK);
     75   CHECK_NO_DATA("foo");
     76 
     77   #undef CHECK_EMPTY_FILE
     78 
     79   CHK(fclose(fp) == 0);
     80 }
     81 
     82 static void
     83 check_n_time_intervals
     84   (struct smeteo* smeteo,
     85    const double albedo,
     86    const double longitude, /* [deg] */
     87    const double latitude, /* [deg] */
     88    const size_t nintervals,
     89    const char* date[],
     90    const double Tsrf[], /* [K] */
     91    const double Tatm[], /* [K] */
     92    const double Ahum[], /* [g(water)/kg(air)] */
     93    const double Rhum[],
     94    const double SWdn_direct[], /* [W/m^2] */
     95    const double SWdn_diffuse[], /* [W/m^2] */
     96    const double SWup[], /* [W.m^2] */
     97    const double Trad[], /* [K] */
     98    const double H[], /* [W/K/m^2] */
     99    const double LE[], /* W/m^2] */
    100    const double day_1850[])
    101 {
    102   struct smeteo_desc desc = SMETEO_DESC_NULL;
    103 
    104   char buf[32] = {0};
    105   FILE* fp = NULL;
    106   size_t i = 0;
    107 
    108   CHK((fp = tmpfile()) != NULL);
    109 
    110   CHK(fprintf(fp, "%a # albedo\n", albedo) > 0);
    111   CHK(fprintf(fp, "%a # longitude [deg]\n", longitude) > 0);
    112   CHK(fprintf(fp, "%a # latitude [deg]\n", latitude) > 0);
    113   CHK(fprintf(fp, "%lu  # Date count\n", (unsigned long)nintervals) > 0);
    114 
    115   FOR_EACH(i, 0, nintervals) {
    116     CHK(fprintf(fp, "%s %a %a %a %a %a %a %a %a %a %a %a %a\n",
    117       date[i],
    118       Tsrf[i],
    119       Tatm[i],
    120       Ahum[i],
    121       Rhum[i],
    122       SWdn_direct[i] + SWdn_diffuse[i],
    123       SWdn_direct[i],
    124       SWdn_diffuse[i],
    125       SWup[i],
    126       Trad[i],
    127       H[i],
    128       LE[i],
    129       day_1850[i]) > 0);
    130   }
    131 
    132   rewind(fp);
    133 
    134   CHK(smeteo_load_stream(smeteo, fp, "Test") == RES_OK);
    135   CHK(smeteo_get_desc(smeteo, &desc) == RES_OK);
    136 
    137   /* Check header */
    138   #define CHK_HEADER(Var) CHK(Var == desc.Var)
    139   CHK_HEADER(albedo);
    140   CHK_HEADER(longitude);
    141   CHK_HEADER(latitude);
    142   CHK(desc.nentries == nintervals);
    143   #undef CHK_HEADER
    144 
    145   #define CHK_ENTRY(Var) CHK(Var[i] == desc.entries[i].Var)
    146   FOR_EACH(i, 0, nintervals) {
    147     /* Check entry time */
    148     CHK(strftime(buf, sizeof(buf), "%d-%b-%Y %H:%M:%S", &desc.entries[i].time));
    149     CHK(strcasecmp(buf, date[i]) == 0);
    150 
    151     /* Check entry data */
    152     CHK_ENTRY(Tsrf);
    153     CHK_ENTRY(Tatm);
    154     CHK_ENTRY(Ahum);
    155     CHK_ENTRY(Rhum);
    156     CHK_ENTRY(SWdn_direct);
    157     CHK_ENTRY(SWdn_diffuse);
    158     CHK_ENTRY(SWup);
    159     CHK_ENTRY(Trad);
    160     CHK_ENTRY(H);
    161     CHK_ENTRY(LE);
    162     CHK_ENTRY(day_1850);
    163 
    164   }
    165   #undef CHK_ENTRY
    166 
    167   CHK(fclose(fp) == 0);
    168 }
    169 
    170 static void
    171 check_1_time_interval(struct smeteo* smeteo)
    172 {
    173   /* Header */
    174   const double albedo = 1;
    175   const double longitude = 91.1; /* [deg] */
    176   const double latitude = 46.2; /* [deg] */
    177 
    178   /* Time interval data */
    179   const char* date = "01-JAN-1850 01:30:00";
    180   const double Tsrf = 287.85; /* [K] */
    181   const double Tatm = 289.62; /* [K] */
    182   const double Ahum = 4.23; /* [g(water)/kg(air)] */
    183   const double Rhum = 12.28;
    184   const double SWdn_direct = 175.08; /* [W/m^2] */
    185   const double SWdn_diffuse = 0; /* [W/m^2] */
    186   const double SWup = 55.43; /* [W/m^2] */
    187   const double Trad = 271.21; /* [K] */
    188   const double H = 12.60; /* [W/K/m^2] */
    189   const double LE = 0.51; /* [W/m^2] */
    190   const double day_1850 = 0.0625;
    191 
    192   check_n_time_intervals(smeteo, albedo, longitude, latitude, 1, &date, &Tsrf,
    193     &Tatm, &Ahum, &Rhum, &SWdn_direct, &SWdn_diffuse, &SWup, &Trad, &H, &LE,
    194     &day_1850);
    195 }
    196 
    197 static void
    198 check_4_time_intervals(struct smeteo* smeteo)
    199 {
    200   /* Header */
    201   const double albedo = 0.31659812657071051;
    202   const double longitude = 10.428827285766602; /* [deg] */
    203   const double latitude = 16.388128280639648; /* [deg] */
    204 
    205   /* Time interval data */
    206   const char* date[] = {
    207     "01-JAN-1850 01:30:00", "01-JAN-1850 04:30:00",
    208     "01-JAN-1850 07:30:00", "01-JAN-1850 10:30:00",
    209   };
    210   const double Tsrf[] = { 287.85, 286.18, 293.25, 307.28 }; /* [K] */
    211   const double Tatm[] = { 289.62, 287.77, 291.16, 298.31 }; /* [K] */
    212   const double Ahum[] = { 4.23, 0, 0, 0 }; /* [g(water)/kg(air)] */
    213   const double Rhum[] = { 12.28, 0, 0, 0 };
    214   const double SWdn_direct[] = { 0, 0, 175.08, 679.01 }; /* [W/m^2] */
    215   const double SWdn_diffuse[] = { 0, 0, 0, 0 }; /* [W/m^2] */
    216   const double SWup[] = { 0, 0, 55.43, 213.37 }; /* [W/m^2] */
    217   const double Trad[] = { 271.21, 269.50, 268.62, 271.61 }; /* [K] */
    218   const double H[] = { 12.60, 8.74, 7.32, 17.80 }; /* [W/K/m^2] */
    219   const double LE[] = { 0.51, 0.52, 0.87, 1.78 }; /* [W/m^2] */
    220   const double day_1850[] = { 0.0625, 0.1875, 0.3125, 0.4375 };
    221 
    222   check_n_time_intervals(smeteo, albedo, longitude, latitude, 4, date,
    223     Tsrf, Tatm, Ahum, Rhum, SWdn_direct, SWdn_diffuse, SWup, Trad, H, LE,
    224     day_1850);
    225 }
    226 
    227 /*******************************************************************************
    228  * The test
    229  ******************************************************************************/
    230 int
    231 main(void)
    232 {
    233   struct smeteo* smeteo = NULL;
    234   struct smeteo_create_args args = SMETEO_CREATE_ARGS_DEFAULT;
    235 
    236   args.verbose = 3;
    237   CHK(smeteo_create(&args, &smeteo) == RES_OK);
    238 
    239   check_api(smeteo);
    240   check_1_time_interval(smeteo);
    241   check_4_time_intervals(smeteo);
    242 
    243   CHK(smeteo_ref_put(smeteo) == RES_OK);
    244   CHK(mem_allocated_size() == 0);
    245   return 0;
    246 }