star-hitran

Load line-by-line data from the HITRAN database
git clone git://git.meso-star.fr/star-hitran.git
Log | Files | Refs | README | LICENSE

shtr_main.c (9193B)


      1 /* Copyright (C) 2022, 2025, 2026 |Méso|Star> (contact@meso-star.com)
      2  * Copyright (C) 2025, 2026 Université de Lorraine
      3  * Copyright (C) 2022 Centre National de la Recherche Scientifique
      4  * Copyright (C) 2022 Université Paul Sabatier
      5  *
      6  * This program is free software: you can redistribute it and/or modify
      7  * it under the terms of the GNU General Public License as published by
      8  * the Free Software Foundation, either version 3 of the License, or
      9  * (at your option) any later version.
     10  *
     11  * This program is distributed in the hope that it will be useful,
     12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
     13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
     14  * GNU General Public License for more details.
     15  *
     16  * You should have received a copy of the GNU General Public License
     17  * along with this program. If not, see <http://www.gnu.org/licenses/>. */
     18 
     19 #define _POSIX_C_SOURCE 200112L /* getopt support */
     20 
     21 #include "shtr.h"
     22 
     23 #include <rsys/clock_time.h>
     24 #include <rsys/cstr.h>
     25 #include <rsys/mem_allocator.h>
     26 #include <rsys/rsys.h>
     27 
     28 #include <stdio.h>
     29 #include <string.h>
     30 #include <unistd.h> /* getopt */
     31 
     32 #define STDIN_NAME "-"
     33 
     34 struct args {
     35   char* molparam;
     36   char* lines;
     37   char* output;
     38 
     39   int bench_line_access;
     40   int internal_format;
     41   int verbose; /* Verbosity level */
     42   int print_info;
     43   int human_readable;
     44   int quit;
     45 };
     46 static const struct args ARGS_DEFAULT = {0};
     47 
     48 struct cmd {
     49   struct mem_allocator allocator;
     50   int allocator_is_init;
     51   struct args args;
     52   struct shtr* shtr;
     53 };
     54 static const struct cmd CMD_NULL = {0};
     55 
     56 /*******************************************************************************
     57  * Helper functions
     58  ******************************************************************************/
     59 static INLINE void
     60 usage(FILE* stream)
     61 {
     62   fprintf(stream,
     63 "usage: shtr [-aHhisv] [-l lines] [-m molparam] [-o output]\n");
     64 }
     65 
     66 static res_T
     67 args_init(struct args* args, int argc, char** argv)
     68 {
     69   int opt = 0;
     70   res_T res = RES_OK;
     71 
     72   ASSERT(args);
     73 
     74   *args = ARGS_DEFAULT;
     75 
     76   while((opt = getopt(argc, argv, "aHhil:m:o:sv")) != -1) {
     77     switch(opt) {
     78       case 'a': args->bench_line_access = 1; break;
     79       case 'H': args->human_readable = 1; break;
     80       case 'h': usage(stdout); args->quit = 1; break;
     81       case 'i': args->print_info = 1; break;
     82       case 'l': args->lines = optarg; break;
     83       case 'm': args->molparam = optarg; break;
     84       case 'o': args->output = optarg; break;
     85       case 's': args->internal_format = 1; break;
     86       case 'v': args->verbose += (args->verbose < 3); break;
     87       default: res = RES_BAD_ARG; break;
     88     }
     89     if(res != RES_OK) {
     90       if(optarg) {
     91         fprintf(stderr, "%s: invalid option argument '%s' -- '%c'\n",
     92           argv[0], optarg, opt);
     93       }
     94       goto error;
     95     }
     96   }
     97 
     98   if(!args->molparam && !args->lines) {
     99     fprintf(stderr, "neither lines nor isotopologues are defined\n");
    100     res = RES_BAD_ARG;
    101     goto error;
    102   }
    103 
    104 exit:
    105   return res;
    106 error:
    107   usage(stderr);
    108   goto exit;
    109 }
    110 
    111 static void
    112 cmd_release(struct cmd* cmd)
    113 {
    114   if(cmd->shtr) SHTR(ref_put(cmd->shtr));
    115   if(cmd->allocator_is_init) mem_shutdown_regular_allocator(&cmd->allocator);
    116 }
    117 
    118 static res_T
    119 cmd_init(struct cmd* cmd, const struct args* args)
    120 {
    121   struct shtr_create_args create_args = SHTR_CREATE_ARGS_DEFAULT;
    122   res_T res = RES_OK;
    123 
    124   ASSERT(cmd && args);
    125 
    126   cmd->args = *args;
    127 
    128   mem_init_regular_allocator(&cmd->allocator);
    129   cmd->allocator_is_init = 1;
    130 
    131   create_args.allocator = &cmd->allocator;
    132   create_args.verbose = args->verbose;
    133   if((res = shtr_create(&create_args, &cmd->shtr)) != RES_OK) goto error;
    134 
    135 exit:
    136   return res;
    137 error:
    138   cmd_release(cmd);
    139   goto exit;
    140 }
    141 
    142 static res_T
    143 load_molparam(const struct cmd* cmd, struct shtr_isotope_metadata** molparam)
    144 {
    145   ASSERT(cmd && molparam && cmd->args.molparam);
    146   if(!strcmp(cmd->args.molparam, STDIN_NAME)) {
    147     return shtr_isotope_metadata_load_stream(cmd->shtr, stdin, "stdin", molparam);
    148   } else {
    149     return shtr_isotope_metadata_load(cmd->shtr, cmd->args.molparam, molparam);
    150   }
    151 }
    152 
    153 static res_T
    154 load_lines_binary(const struct cmd* cmd, struct shtr_line_list** lines)
    155 {
    156   FILE* fp = NULL;
    157   res_T res = RES_OK;
    158 
    159   ASSERT(cmd && lines && cmd->args.lines);
    160 
    161   if(!strcmp(cmd->args.lines, STDIN_NAME)) {
    162     fp = stdin;
    163   } else {
    164     fp = fopen(cmd->args.lines, "r");
    165     if(!fp) {
    166       fprintf(stderr, "%s: error opening file -- %s\n",
    167         cmd->args.lines, strerror(errno));
    168       res = RES_IO_ERR;
    169       goto error;
    170     }
    171   }
    172 
    173   res = shtr_line_list_create_from_stream(cmd->shtr, fp, lines);
    174   if(res != RES_OK) goto error;
    175 
    176 exit:
    177   if(fp && fp != stdin) CHK(fclose(fp) == 0);
    178   return res;
    179 error:
    180   goto exit;
    181 }
    182 
    183 static res_T
    184 load_lines_hitran(const struct cmd* cmd, struct shtr_line_list** lines)
    185 {
    186   struct shtr_line_list_load_args args = SHTR_LINE_LIST_LOAD_ARGS_NULL__;
    187   res_T res = RES_OK;
    188 
    189   ASSERT(cmd && lines && cmd->args.lines);
    190 
    191   if(strcmp(cmd->args.lines, STDIN_NAME)) {
    192     args.filename = cmd->args.lines;
    193   } else {
    194     args.file = stdin;
    195     args.filename = "stdin";
    196   }
    197 
    198   res = shtr_line_list_load(cmd->shtr, &args, lines);
    199   if(res != RES_OK) goto error;
    200 
    201 exit:
    202   return res;
    203 error:
    204   goto exit;
    205 }
    206 
    207 static res_T
    208 load_lines(const struct cmd* cmd, struct shtr_line_list** lines)
    209 {
    210   ASSERT(cmd && lines && cmd->args.lines);
    211   if(cmd->args.internal_format) {
    212     return load_lines_binary(cmd, lines);
    213   } else {
    214     return load_lines_hitran(cmd, lines);
    215   }
    216 }
    217 
    218 static void
    219 lines_info(const struct shtr_line_list* list)
    220 {
    221   struct shtr_line_list_info info = SHTR_LINE_LIST_INFO_NULL;
    222   ASSERT(list);
    223 
    224   SHTR(line_list_get_info(list, &info));
    225 
    226   #define PRINT(Name) \
    227     printf("%-18s in [%12.4e,%12.4e]; error: %e\n", \
    228       STR(Name), SPLIT2(info.Name.range), info.Name.err)
    229   PRINT(wavenumber);
    230   PRINT(intensity);
    231   PRINT(gamma_air);
    232   PRINT(gamma_self);
    233   PRINT(lower_state_energy);
    234   PRINT(n_air);
    235   PRINT(delta_air);
    236   #undef PRINT
    237 }
    238 
    239 static void
    240 print_memsz(const struct cmd* cmd)
    241 {
    242   char buf[128] = {0};
    243   size_t sz = 0;
    244   ASSERT(cmd);
    245 
    246   sz = MEM_ALLOCATED_SIZE(&cmd->allocator);
    247   if(!cmd->args.human_readable) {
    248     printf("memory usage: %lu byt%s\n", (unsigned long)sz, sz > 0 ? "es" : "e");
    249   } else {
    250     size_to_cstr(sz, SIZE_ALL, NULL, buf, sizeof(buf));
    251     printf("memory usage: %s\n", buf);
    252   }
    253 }
    254 
    255 static res_T
    256 write_lines(const struct cmd* cmd, const struct shtr_line_list* list)
    257 {
    258   FILE* fp = NULL;
    259   res_T res = RES_OK;
    260   ASSERT(cmd && list && cmd->args.output);
    261 
    262   fp = fopen(cmd->args.output, "w");
    263   if(!fp) {
    264     fprintf(stderr, "%s: error opening file -- %s\n",
    265       cmd->args.output, strerror(errno));
    266     res = RES_IO_ERR;
    267     goto error;
    268   }
    269 
    270   res = shtr_line_list_write(list, fp);
    271   if(res != RES_OK) goto error;
    272 
    273 exit:
    274   if(fp) CHK(fclose(fp) == 0);
    275   return res;
    276 error:
    277   goto exit;
    278 }
    279 
    280 static void
    281 bench_line_access(struct shtr_line_list* lines)
    282 {
    283   struct shtr_line line;
    284   struct time t0, t1;
    285   const size_t read_count = 10000;
    286   double lines_per_second = 0;
    287   int64_t usec = 0;
    288   size_t i, n;
    289 
    290   ASSERT(lines);
    291 
    292   SHTR(line_list_get_size(lines, &n));
    293 
    294   /* Linear access */
    295   time_current(&t0);
    296   FOR_EACH(i, 0, MMIN(n, read_count)) {
    297     SHTR(line_list_at(lines, i, &line));
    298   }
    299   usec = time_val(time_sub(&t0, time_current(&t1), &t0), TIME_USEC);
    300   lines_per_second = 1.e9 * (double)n / (double)usec;
    301   printf("linear access: %e lps\n", lines_per_second);
    302 
    303   /* Random access */
    304   time_current(&t0);
    305   FOR_EACH(i, 0, read_count) {
    306     const double r = (double)rand() / (double)(RAND_MAX-1);
    307     const size_t iline = (size_t)(r * (double)n);
    308     SHTR(line_list_at(lines, iline, &line));
    309   }
    310   usec = time_val(time_sub(&t0, time_current(&t1), &t0), TIME_USEC);
    311   lines_per_second = 1.e9 * (double)read_count / (double)usec;
    312   printf("random access: %e lps\n", lines_per_second);
    313 }
    314 
    315 static res_T
    316 cmd_run(const struct cmd* cmd)
    317 {
    318   struct shtr_isotope_metadata* molparam = NULL;
    319   struct shtr_line_list* lines = NULL;
    320   res_T res = RES_OK;
    321   ASSERT(cmd);
    322 
    323   if(cmd->args.molparam) {
    324     if((res = load_molparam(cmd, &molparam)) != RES_OK)  goto error;
    325   }
    326   if(cmd->args.lines) {
    327     if((res = load_lines(cmd, &lines)) != RES_OK) goto error;
    328     if(cmd->args.print_info) lines_info(lines);
    329     if(cmd->args.bench_line_access) bench_line_access(lines);
    330     if(cmd->args.output) {
    331       res = write_lines(cmd, lines);
    332       if(res != RES_OK) goto error;
    333     }
    334   }
    335   if(cmd->args.print_info) print_memsz(cmd);
    336 
    337 exit:
    338   if(molparam) SHTR(isotope_metadata_ref_put(molparam));
    339   if(lines) SHTR(line_list_ref_put(lines));
    340   return res;
    341 error:
    342   goto exit;
    343 }
    344 
    345 /*******************************************************************************
    346  * The program
    347  ******************************************************************************/
    348 int
    349 main(int argc, char** argv)
    350 {
    351   struct args args = ARGS_DEFAULT;
    352   struct cmd cmd = CMD_NULL;
    353   int err = 0;
    354   res_T res = RES_OK;
    355 
    356   if((res = args_init(&args, argc, argv)) != RES_OK) goto error;
    357   if(args.quit) goto exit;
    358 
    359   if((res = cmd_init(&cmd, &args)) != RES_OK) goto error;
    360   if((res = cmd_run(&cmd)) != RES_OK) goto error;
    361 
    362 exit:
    363   cmd_release(&cmd);
    364   CHK(mem_allocated_size() == 0);
    365   return err;
    366 error:
    367   err = 1;
    368   goto exit;
    369 }