diff --git a/oneflux_steps/Makefile b/oneflux_steps/Makefile index d56115bf..fdfba63c 100644 --- a/oneflux_steps/Makefile +++ b/oneflux_steps/Makefile @@ -70,7 +70,7 @@ SW_IN_POT_OBJ := $(SW_IN_POT_SRC:.c=.o) SW_IN_POT_BIN := $(join ${TGTDIR}, sw_in_pot) METEO_PROC_DIR := $(join ${SRCDIR}, meteo_proc/src/) -METEO_PROC_SRC := dataset.c main.c +METEO_PROC_SRC := dataset.c main.c defs.c mds_vars.c METEO_PROC_OBJ := $(METEO_PROC_SRC:.c=.o) METEO_PROC_BIN := $(join ${TGTDIR}, meteo_proc) diff --git a/oneflux_steps/common/common.c b/oneflux_steps/common/common.c index c1f251bb..d2960533 100644 --- a/oneflux_steps/common/common.c +++ b/oneflux_steps/common/common.c @@ -56,6 +56,7 @@ static const char filter[] = "*.*"; static const char dd_field_delimiter[] = ",\r\n"; static const char *dds[DETAILS_SIZE] = { "site", "year", "lat", "lon", "timezone", "htower", "timeres", "sc_negl", "notes" }; static const char *timeress[TIMERES_SIZE] = { "spot", "quaterhourly", "halfhourly", "hourly", "daily", "monthly" }; +static const char variadic[] = "variadic"; /* error strings */ static const char err_unable_open_path[] = "unable to open path: %s\n\n"; @@ -64,6 +65,7 @@ static const char err_path_too_big[] = "specified path \"%s\" is too big.\n\n"; static const char err_filename_too_big[] = "filename \"%s\" is too big.\n\n"; static const char err_empty_argument[] = "empty argument\n"; static const char err_unknown_argument[] = "unknown argument: \"%s\"\n\n"; +static const char err_too_long_arg[] = "too long argument\n"; static const char err_gf_too_less_values[] = "too few valid values to apply gapfilling\n"; static const char err_wildcards_with_no_extension_used[] = "wildcards with no extension used\n"; @@ -815,8 +817,50 @@ int parse_arguments(int argc, char *argv[], const ARGUMENT *const args, const in /* */ if ( !ok ) { - printf(err_unknown_argument, argv[1]+1); - return 0; + for ( i = 0; i < arg_count; i++ ) { + if ( !string_compare_i(args[i].name, variadic) ) { + #define ARG_MAX_LEN 31 + + char arg[ARG_MAX_LEN+1] = { 0 }; + int n = (int)strlen(argv[1]); + + param = strrchr(argv[1], '='); + if ( param ) { + n = param - argv[1]; + ++param; + } + --n; /* we keep '-' in case of no param or '=' out */ + + if ( n > ARG_MAX_LEN ) { + printf(err_too_long_arg); + return 0; + } + strncpy(arg, argv[1]+1, n); + + /* check if function is present */ + assert(args[i].f); + + /* call function */ + ok = args[i].f(arg, param, args[i].p); + if ( ! ok ) { + return 0; + } + + /* in this way we can alert about unknown argument */ + if ( -1 == ok ) { + i = arg_count; + } + + break; + + #undef ARG_MAX_LEN + } + } + + if ( i == arg_count ) { + printf(err_unknown_argument, argv[1]+1); + return 0; + } } /* */ diff --git a/oneflux_steps/common/common.h b/oneflux_steps/common/common.h index 01058d77..91d093b6 100644 --- a/oneflux_steps/common/common.h +++ b/oneflux_steps/common/common.h @@ -16,6 +16,7 @@ #endif /* includes */ +#include #include /* defines stolen to http://www.gnu.org/software/libtool/manual/autoconf/Function-Portability.html */ diff --git a/oneflux_steps/meteo_proc/meteo_proc.vcproj b/oneflux_steps/meteo_proc/meteo_proc.vcproj index 8b3f478d..a51f5244 100644 --- a/oneflux_steps/meteo_proc/meteo_proc.vcproj +++ b/oneflux_steps/meteo_proc/meteo_proc.vcproj @@ -1,7 +1,7 @@ + + + + #include #include "dataset.h" +#include "defs.h" #include "info_swc_hh.h" #include "info_swc_dd_ww_mm_yy.h" #include "info_ts_hh.h" @@ -65,6 +66,11 @@ typedef struct { PREC corr; } STAT; +typedef struct { + const char* name; + int column; +} USER_DRIVER; + /* strings */ static const char dataset_delimiter[] = " ,\r\n"; static const char output_file_hh[] = "%s%s_meteo_hh.csv"; @@ -775,7 +781,7 @@ static int get_dataset_details(DATASET *const dataset) { } /* */ -static int import_meteo_values(DATASET *const dataset) { +static int import_meteo_values(DATASET *const dataset, MDS_VARS* mds_vars) { typedef struct { int profile; int index; @@ -791,7 +797,7 @@ static int import_meteo_values(DATASET *const dataset) { int error; int year; int columns_found_count; - int columns_index[MET_VALUES]; + int columns_index[MET_VALUES+USER_DRIVERS_COUNT]; int profile; int *int_no_leak; COLUMN *column_no_leak; @@ -1232,7 +1238,7 @@ static int import_meteo_values(DATASET *const dataset) { } /* reset columns */ - for ( i = 0; i < MET_VALUES; i++ ) { + for ( i = 0; i < MET_VALUES+USER_DRIVERS_COUNT; i++ ) { columns_index[i] = -1; } @@ -1241,6 +1247,8 @@ static int import_meteo_values(DATASET *const dataset) { if ( !f ) { printf("not found. set null values..."); for ( i = 0; i < rows_count; i++ ) { + int y; + dataset->rows[index+i].value[TA_MET] = INVALID_VALUE; dataset->rows[index+i].value[VPD_MET] = INVALID_VALUE; dataset->rows[index+i].value[PRECIP_MET] = INVALID_VALUE; @@ -1248,6 +1256,10 @@ static int import_meteo_values(DATASET *const dataset) { dataset->rows[index+i].value[SW_IN_MET] = INVALID_VALUE; dataset->rows[index+i].value[LW_IN_MET] = INVALID_VALUE; dataset->rows[index+i].value[PA_MET] = INVALID_VALUE; + + for ( y = USER_DRIVERS_BEGIN; y < USER_DRIVERS_END; ++y ) { + dataset->rows[index+i].value[y] = INVALID_VALUE; + } } /* set rpot */ @@ -1305,8 +1317,8 @@ static int import_meteo_values(DATASET *const dataset) { /* check itp */ strcpy(buffer2, "itp"); strcat(buffer2, met_values_tokens[y]); - if ( ! string_compare_i(token, met_values_tokens[y]) || - ! string_compare_i(token, buffer2) ) { + if ( !string_compare_i(token, met_values_tokens[y]) || + !string_compare_i(token, buffer2) ) { /* check if it is already assigned */ if ( columns_index[y] != -1 ) { printf("column %s already found at index %d\n", token, columns_index[y]); @@ -1318,6 +1330,30 @@ static int import_meteo_values(DATASET *const dataset) { } } } + /* check for user mds vars */ + if ( mds_vars ) { + ///* check if token is defs */ + //for ( y = 0; y < DEF_VARS_COUNT; ++y ) { + // if ( !string_compare_i(token, sz_defs[y]) ) { + // break; + // } + //} + //if ( DEF_VARS_COUNT == i ) { + for ( y = 0; y < mds_vars->count; ++y ) { + int z; + + /* we loop for each vars name of mds vars */ + /* we skip MDS_VAR_TO_FILL, it is mandatory! */ + for ( z = MDS_VAR_DRIVER_1; z < MDS_VARS_COUNT; ++z ) { + if ( mds_vars->vars[y].columns[z] >= USER_DRIVERS_BEGIN ) { + if ( !string_compare_i(token, mds_vars->vars[y].name[z]) ) { + columns_index[MET_VALUES + (z-1) + (y*3)] = i; + } + } + } + } + //} + } /* check for TS */ if ( ! string_n_compare_i(token, "TS_", 3) || ! string_n_compare_i(token, "itpTS_", 6) ) { @@ -1386,7 +1422,7 @@ static int import_meteo_values(DATASET *const dataset) { /* check found columns */ columns_found_count = swc_columns_count+ts_columns_count; - for ( i = 0; i < MET_VALUES; i++ ) { + for ( i = 0; i < MET_VALUES+USER_DRIVERS_COUNT; i++ ) { if ( columns_index[i] != -1 ) { ++columns_found_count; } @@ -1500,12 +1536,17 @@ static int import_meteo_values(DATASET *const dataset) { } } /* check other vars */ - for ( y = 0; y < MET_VALUES; y++ ) { + for ( y = 0; y < MET_VALUES+USER_DRIVERS_COUNT; y++ ) { if ( i == columns_index[y] ) { /* convert string to prec */ value = convert_string_to_prec(token, &error); if ( error ) { - printf("unable to convert value %s at row %d, column %s\n", token, element+1, met_values_tokens[y]); + if ( y < MET_VALUES ) { + printf("unable to convert value %s at row %d, column %s\n", token, element+1, met_values_tokens[y]); + } else { + /* TODO - print column name instead of index */ + printf("unable to convert value %s at row %d, column %d\n", token, element+1, i+1); + } free(swc_columns); free(ts_columns); fclose(f); @@ -1517,58 +1558,105 @@ static int import_meteo_values(DATASET *const dataset) { value = INVALID_VALUE; } - switch ( y ) { - case 1: /* TA */ - if ( (value < -50) || (value > 50) ) { - value = INVALID_VALUE; + /* user driver can use defaults vars too, so we need to adjust index */ + { + int index = y; + if ( (index >= MET_VALUES) && mds_vars ) { + const char* vars[] = { "TA", "VPD", "P", "WS", "SW_IN", "LW_IN", "PA" }; + const char* p; + int z; + + index -= MET_VALUES; + ++index; /* we keep TO_FILL out */ + p = mds_vars->vars[index / 3].name[index % 3]; + for ( z = 0; z < SIZEOF_ARRAY(vars); ++z ) { + if ( !string_compare_i(p, vars[z]) ) { + break; + } } - break; - - case 2: /* VPD */ - if ( (value < -5) || (value > 120) ) { - value = INVALID_VALUE; - } else if ( !IS_INVALID_VALUE(value) && (value < 0.0) ) { - value = 0.0; + if ( z < SIZEOF_ARRAY(vars) ) { + #if 1 + index = z + 1; + #else + /* check if user specify oor for default var */ + if ( IS_INVALID_VALUE(mds_vars->vars[index / 3].oors[index % 3][MDS_VAR_OOR_MIN]) ) { + index = z + 1; + } else { + index = -1; + if ( (value < mds_vars->vars[index / 3].oors[index % 3][MDS_VAR_OOR_MIN]) + || (value > mds_vars->vars[index / 3].oors[index % 3][MDS_VAR_OOR_MAX]) ) { + value = INVALID_VALUE; + } + } + #endif // 0 + } else { + if ( !IS_INVALID_VALUE(value) && !IS_INVALID_VALUE(mds_vars->vars[index / 3].oors[index % 3][MDS_VAR_OOR_MIN]) ) { + if ( (value < mds_vars->vars[index / 3].oors[index % 3][MDS_VAR_OOR_MIN]) + || (value > mds_vars->vars[index / 3].oors[index % 3][MDS_VAR_OOR_MAX]) ) { + value = INVALID_VALUE; + } + } + index = -1; } - break; + } - case 3: /* PRECIP */ - if ( (value < -0.1) || (value > 200) ) { - value = INVALID_VALUE; - } else if ( !IS_INVALID_VALUE(value) && (value < 0.0) ) { - value = 0.0; - } - break; + switch ( index ) { + case 1: /* TA */ + if ( (value < -50) || (value > 50) ) { + value = INVALID_VALUE; + } + break; - case 4: /* WS */ - if ( (value < 0) || (value > 40) ) { - value = INVALID_VALUE; - } - break; + case 2: /* VPD */ + if ( (value < -5) || (value > 120) ) { + value = INVALID_VALUE; + } else if ( !IS_INVALID_VALUE(value) && (value < 0.0) ) { + value = 0.0; + } + break; - case 5: /* SW_IN */ - if ( (value < -50) || (value > 1400) ) { - value = INVALID_VALUE; - } else if ( !IS_INVALID_VALUE(value) && (value < 0.0) ) { - value = 0.0; - } - break; + case 3: /* PRECIP */ + if ( (value < -0.1) || (value > 200) ) { + value = INVALID_VALUE; + } else if ( !IS_INVALID_VALUE(value) && (value < 0.0) ) { + value = 0.0; + } + break; - case 6: /* LW_IN */ - if ( (value < 50) || (value > 700) ) { - value = INVALID_VALUE; - } - break; + case 4: /* WS */ + if ( (value < 0) || (value > 40) ) { + value = INVALID_VALUE; + } + break; - case 7: /* PA */ - if ( (value < 70) || (value > 130) ) { - value = INVALID_VALUE; - } - break; + case 5: /* SW_IN */ + if ( (value < -50) || (value > 1400) ) { + value = INVALID_VALUE; + } else if ( !IS_INVALID_VALUE(value) && (value < 0.0) ) { + value = 0.0; + } + break; + + case 6: /* LW_IN */ + if ( (value < 50) || (value > 700) ) { + value = INVALID_VALUE; + } + break; + + case 7: /* PA */ + if ( (value < 70) || (value > 130) ) { + value = INVALID_VALUE; + } + break; + } } /* assign value */ - dataset->rows[index+element-1].value[CO2_MET+y] = value; + if ( y < MET_VALUES ) { + dataset->rows[index+element-1].value[CO2_MET+y] = value; + } else { + dataset->rows[index+element-1].value[y-MET_VALUES+USER_DRIVERS_BEGIN] = value; + } ++assigned; } } @@ -1615,6 +1703,69 @@ static int import_meteo_values(DATASET *const dataset) { return 0; } + /* debug stuff */ +#if _DEBUG + if ( mds_vars ) + { + int v; + int c = 0; + for ( v = 0; v < mds_vars->count; ++v ) { + int d; + for ( d = 0; d < MDS_VARS_COUNT; ++d ) { + if ( mds_vars->vars[v].columns[d] >= USER_DRIVERS_BEGIN ) { + ++c; + } + } + } + + if ( c ) { + char buf[256] = { 0 }; /* should be enough */ + FILE* f; + int n = sprintf(buf, "%s_%d", dataset->site, dataset->years[0]); + if ( dataset->years_count > 1 ) { + sprintf(buf+n, "_%d", dataset->years[dataset->years_count-1]); + } + strcat(buf, "_imported_dataset.csv"); + f = fopen(buf, "w"); + if ( ! f ) { + printf("DEBUG: unable to create '%s' filename!\n\n", buf); + } else { + /* print header */ + c = 0; + for ( v = 0; v < mds_vars->count; ++v ) { + int d; + for ( d = 0; d < MDS_VARS_COUNT; ++d ) { + if ( mds_vars->vars[v].columns[d] >= USER_DRIVERS_BEGIN ) { + fprintf(f, "%s%s", (c>0)?",":"", mds_vars->vars[v].name[d]); + ++c; + } + } + } + fputs("\n", f); + + /* print values */ + { + int i; + for ( i = 0; i < dataset->rows_count; ++i ) { + c = 0; + for ( v = 0; v < mds_vars->count; ++v ) { + int d; + for ( d = 0; d < MDS_VARS_COUNT; ++d ) { + if ( mds_vars->vars[v].columns[d] >= USER_DRIVERS_BEGIN ) { + fprintf(f, "%s%g", (c>0)?",":"", dataset->rows[i].value[mds_vars->vars[v].columns[d]]); + ++c; + } + } + } + fputs("\n", f); + } + } + fclose(f); + } + } + } +#endif + /* */ return 1; } @@ -4172,7 +4323,10 @@ int check_met_files(DATASET *const dataset) { } /* */ -int compute_datasets(DATASET *const datasets, const int datasets_count) { +int compute_datasets(DATASET *const datasets, const int datasets_count, MDS_VARS* mds_vars) { + //USER_DRIVER* uds = NULL; /* mandatory */ + //int uds_count = 0; /* mandatory */ + int ret = 0; /* defaults to err */ int i; int j; int dataset; @@ -4184,6 +4338,42 @@ int compute_datasets(DATASET *const datasets, const int datasets_count) { DATASET *current_dataset; GF_ROW *gf_rows; + if ( mds_vars->count != DEF_VARS_COUNT ) { + printf("count of mds vars must be %d\n\n", DEF_VARS_COUNT); + return 0; + } + + /* we loop for each mds vars */ + for ( i = 0; i < mds_vars->count; ++i ) { + /* we loop for each vars name of mds vars */ + /* we skip MDS_VAR_TO_FILL, it is mandatory! */ + for ( j = MDS_VAR_DRIVER_1; j < MDS_VARS_COUNT; ++j ) { + int y; + /* we need to seek if a mds_vars is a default one */ + for ( y = 0; y < DEF_VARS_COUNT; ++y ) { + if ( !string_compare_i(sz_defs[y], mds_vars->vars[i].name[j]) ) { + break; + } + } + if ( DEF_VARS_COUNT == y ) { + mds_vars->vars[i].columns[j] = USER_DRIVERS_BEGIN + (j-1) + (i*3); + } else { + /* set default columns */ + if ( ! string_compare_i(sz_defs[y], sz_defs[TA_DEF_VAR]) ) { + mds_vars->vars[i].columns[j] = TA_MET; + } else if ( ! string_compare_i(sz_defs[y], sz_defs[SW_IN_DEF_VAR]) ) { + mds_vars->vars[i].columns[j] = SW_IN_MET; + } else if ( ! string_compare_i(sz_defs[y], sz_defs[LW_IN_DEF_VAR]) ) { + mds_vars->vars[i].columns[j] = LW_IN_MET; + } else if ( ! string_compare_i(sz_defs[y], sz_defs[VPD_DEF_VAR]) ) { + mds_vars->vars[i].columns[j] = VPD_MET; + } else if ( ! string_compare_i(sz_defs[y], sz_defs[CO2_DEF_VAR]) ) { + mds_vars->vars[i].columns[j] = CO2_MET; + } + } + } + } + /* loop on each dataset */ for ( dataset = 0; dataset < datasets_count; dataset++ ) { /* set pointers */ @@ -4276,7 +4466,7 @@ int compute_datasets(DATASET *const datasets, const int datasets_count) { } /* import meteo values */ - if ( !import_meteo_values(current_dataset) ) { + if ( !import_meteo_values(current_dataset, mds_vars) ) { /* free memory */ free_dataset(current_dataset); continue; @@ -4288,520 +4478,139 @@ int compute_datasets(DATASET *const datasets, const int datasets_count) { rows_per_day /= 2; } - /* gapfilling TA */ - printf("- gapfilling TA..."); - - /* compute start and end row */ - start_row = -1; - end_row = -1; - for ( i = 0; i < current_dataset->rows_count; i++ ) { - if ( !IS_INVALID_VALUE(current_dataset->rows[i].value[TA_MET]) ) { - start_row = i; - break; - } - } - if ( -1 == start_row ) { - for ( i = 0; i < current_dataset->rows_count; i++ ) { - current_dataset->rows[i].value[TA_FILLED] = INVALID_VALUE; - current_dataset->rows[i].value[TA_QC] = INVALID_VALUE; - } - puts("ok but is missing!"); - } else { - for ( i = current_dataset->rows_count - 1; i >= 0 ; i-- ) { - if ( !IS_INVALID_VALUE(current_dataset->rows[i].value[TA_MET]) ) { - end_row = i; - break; - } - } - if ( start_row == end_row ) { - puts("only one valid value for TA!"); - /* free memory */ - free_dataset(current_dataset); - continue; - } - - /* adjust bounds */ - start_row -= (DAYS_FOR_GF*rows_per_day); - if ( start_row < 0 ) { - start_row = 0; - } - - end_row += (DAYS_FOR_GF*rows_per_day); - if ( end_row > current_dataset->rows_count ) { - end_row = current_dataset->rows_count; - } - - gf_rows = gf_mds( current_dataset->rows->value, - sizeof(ROW), - current_dataset->rows_count, - VALUES, - current_dataset->hourly ? HOURLY_TIMERES : HALFHOURLY_TIMERES, - GF_DRIVER_1_TOLERANCE_MIN, - GF_DRIVER_1_TOLERANCE_MAX, - GF_DRIVER_2A_TOLERANCE_MIN, - GF_DRIVER_2A_TOLERANCE_MAX, - GF_DRIVER_2B_TOLERANCE_MIN, - GF_DRIVER_2B_TOLERANCE_MAX, - TA_MET, - SW_IN_MET, - TA_MET, - VPD_MET, - -1, - -1, - -1, - INVALID_VALUE, - INVALID_VALUE, - INVALID_VALUE, - GF_ROWS_MIN, - 0, - start_row, - end_row, - ¬_gf_count, - 0, - 0, - 0, - NULL, - 0 - - ); - - if ( !gf_rows ) { - /* free memory */ - free_dataset(current_dataset); - continue; - } - - if ( !not_gf_count ) { - puts("ok"); - } else { - printf("ok (%d values unfilled)\n", not_gf_count); - } - - /* copy gf values and qc */ - for ( i = 0; i < current_dataset->rows_count; i++ ) { - current_dataset->rows[i].value[TA_FILLED] = current_dataset->rows[i].value[TA_MET]; - current_dataset->rows[i].value[TA_QC] = INVALID_VALUE; - if ( (i >= start_row) && (i <= end_row) ) { - current_dataset->rows[i].value[TA_FILLED] = IS_FLAG_SET(gf_rows[i].mask, GF_TOFILL_VALID) ? current_dataset->rows[i].value[TA_MET] : gf_rows[i].filled; - current_dataset->rows[i].value[TA_QC] = IS_FLAG_SET(gf_rows[i].mask, GF_TOFILL_VALID) ? 0 : gf_rows[i].quality; - } - } - - /* free memory */ - free(gf_rows); - gf_rows = NULL; - } - - /* gapfilling SW_IN */ - printf("- gapfilling SW_IN..."); - - /* compute start and end row */ - start_row = -1; - end_row = -1; - for ( i = 0; i < current_dataset->rows_count; i++ ) { - if ( !IS_INVALID_VALUE(current_dataset->rows[i].value[SW_IN_MET]) ) { - start_row = i; - break; - } - } - if ( -1 == start_row ) { - for ( i = 0; i < current_dataset->rows_count; i++ ) { - current_dataset->rows[i].value[SW_IN_FILLED] = INVALID_VALUE; - current_dataset->rows[i].value[SW_IN_QC] = INVALID_VALUE; - } - puts("ok but is missing!"); - } else { - for ( i = current_dataset->rows_count - 1; i >= 0 ; i-- ) { - if ( !IS_INVALID_VALUE(current_dataset->rows[i].value[SW_IN_MET]) ) { - end_row = i; - break; - } - } - if ( start_row == end_row ) { - puts("only one valid value for SW_IN!"); - /* free memory */ - free_dataset(current_dataset); - continue; - } - - /* adjust bounds */ - start_row -= (DAYS_FOR_GF*rows_per_day); - if ( start_row < 0 ) { - start_row = 0; - } - - end_row += (DAYS_FOR_GF*rows_per_day); - if ( end_row > current_dataset->rows_count ) { - end_row = current_dataset->rows_count; - } - - gf_rows = gf_mds( current_dataset->rows->value, - sizeof(ROW), - current_dataset->rows_count, - VALUES, - current_dataset->hourly ? HOURLY_TIMERES : HALFHOURLY_TIMERES, - GF_DRIVER_1_TOLERANCE_MIN, - GF_DRIVER_1_TOLERANCE_MAX, - GF_DRIVER_2A_TOLERANCE_MIN, - GF_DRIVER_2A_TOLERANCE_MAX, - GF_DRIVER_2B_TOLERANCE_MIN, - GF_DRIVER_2B_TOLERANCE_MAX, - SW_IN_MET, - SW_IN_MET, - TA_MET, - VPD_MET, - -1, - -1, - -1, - INVALID_VALUE, - INVALID_VALUE, - INVALID_VALUE, - GF_ROWS_MIN, - 0, - start_row, - end_row, - ¬_gf_count, - 0, - 0, - 0, - NULL, - 0 - ); - - if ( !gf_rows ) { - /* free memory */ - free_dataset(current_dataset); - continue; - } - - if ( !not_gf_count ) { - puts("ok"); - } else { - printf("ok (%d values unfilled)\n", not_gf_count); - } - - /* copy gf values and qc */ - for ( i = 0; i < current_dataset->rows_count; i++ ) { - current_dataset->rows[i].value[SW_IN_FILLED] = current_dataset->rows[i].value[SW_IN_MET]; - current_dataset->rows[i].value[SW_IN_QC] = INVALID_VALUE; - if ( (i >= start_row) && (i <= end_row) ) { - current_dataset->rows[i].value[SW_IN_FILLED] = IS_FLAG_SET(gf_rows[i].mask, GF_TOFILL_VALID) ? current_dataset->rows[i].value[SW_IN_MET] : gf_rows[i].filled; - current_dataset->rows[i].value[SW_IN_QC] = IS_FLAG_SET(gf_rows[i].mask, GF_TOFILL_VALID) ? 0 : gf_rows[i].quality; - } - } - - /* free memory */ - free(gf_rows); - gf_rows = NULL; - } - - /* gapfilling LW_IN */ - printf("- gapfilling LW_IN..."); - - /* compute start and end row */ - start_row = -1; - end_row = -1; - for ( i = 0; i < current_dataset->rows_count; i++ ) { - if ( !IS_INVALID_VALUE(current_dataset->rows[i].value[LW_IN_MET]) ) { - start_row = i; - break; - } - } - if ( -1 == start_row ) { - for ( i = 0; i < current_dataset->rows_count; i++ ) { - current_dataset->rows[i].value[LW_IN_FILLED] = INVALID_VALUE; - current_dataset->rows[i].value[LW_IN_QC] = INVALID_VALUE; - } - puts("ok but is missing!"); - } else { - for ( i = current_dataset->rows_count - 1; i >= 0 ; i-- ) { - if ( !IS_INVALID_VALUE(current_dataset->rows[i].value[LW_IN_MET]) ) { - end_row = i; - break; - } - } - if ( start_row == end_row ) { - puts("only one valid value for LW_IN!"); - /* free memory */ - free_dataset(current_dataset); - continue; - } - - /* adjust bounds */ - start_row -= (DAYS_FOR_GF*rows_per_day); - if ( start_row < 0 ) { - start_row = 0; - } - - end_row += (DAYS_FOR_GF*rows_per_day); - if ( end_row > current_dataset->rows_count ) { - end_row = current_dataset->rows_count; - } - - gf_rows = gf_mds( current_dataset->rows->value, - sizeof(ROW), - current_dataset->rows_count, - VALUES, - current_dataset->hourly ? HOURLY_TIMERES : HALFHOURLY_TIMERES, - GF_DRIVER_1_TOLERANCE_MIN, - GF_DRIVER_1_TOLERANCE_MAX, - GF_DRIVER_2A_TOLERANCE_MIN, - GF_DRIVER_2A_TOLERANCE_MAX, - GF_DRIVER_2B_TOLERANCE_MIN, - GF_DRIVER_2B_TOLERANCE_MAX, - LW_IN_MET, - SW_IN_MET, - TA_MET, - VPD_MET, - -1, - -1, - -1, - INVALID_VALUE, - INVALID_VALUE, - INVALID_VALUE, - GF_ROWS_MIN, - 0, - start_row, - end_row, - ¬_gf_count, - 0, - 0, - 0, - NULL, - 0 - ); - - if ( !gf_rows ) { - /* free memory */ - free_dataset(current_dataset); - continue; - } - - if ( !not_gf_count ) { - puts("ok"); - } else { - printf("ok (%d values unfilled)\n", not_gf_count); - } - - /* copy gf values and qc */ - for ( i = 0; i < current_dataset->rows_count; i++ ) { - current_dataset->rows[i].value[LW_IN_FILLED] = current_dataset->rows[i].value[LW_IN_MET]; - current_dataset->rows[i].value[LW_IN_QC] = INVALID_VALUE; - if ( (i >= start_row) && (i <= end_row) ) { - current_dataset->rows[i].value[LW_IN_FILLED] = IS_FLAG_SET(gf_rows[i].mask, GF_TOFILL_VALID) ? current_dataset->rows[i].value[LW_IN_MET] : gf_rows[i].filled; - current_dataset->rows[i].value[LW_IN_QC] = IS_FLAG_SET(gf_rows[i].mask, GF_TOFILL_VALID) ? 0 : gf_rows[i].quality; - } - } - - /* free memory */ - free(gf_rows); - gf_rows = NULL; - } - - /* gapfilling VPD */ - printf("- gapfilling VPD..."); - - /* compute start and end row */ - start_row = -1; - end_row = -1; - for ( i = 0; i < current_dataset->rows_count; i++ ) { - if ( !IS_INVALID_VALUE(current_dataset->rows[i].value[VPD_MET]) ) { - start_row = i; - break; - } - } - if ( -1 == start_row ) { - for ( i = 0; i < current_dataset->rows_count; i++ ) { - current_dataset->rows[i].value[VPD_FILLED] = INVALID_VALUE; - current_dataset->rows[i].value[VPD_QC] = INVALID_VALUE; - } - puts("ok but is missing!"); - } else { - for ( i = current_dataset->rows_count - 1; i >= 0 ; i-- ) { - if ( !IS_INVALID_VALUE(current_dataset->rows[i].value[VPD_MET]) ) { - end_row = i; - break; - } - } - if ( start_row == end_row ) { - puts("only one valid value for VPD!"); - /* free memory */ - free_dataset(current_dataset); - continue; - } - - /* adjust bounds */ - start_row -= (DAYS_FOR_GF*rows_per_day); - if ( start_row < 0 ) { - start_row = 0; - } - - end_row += (DAYS_FOR_GF*rows_per_day); - if ( end_row > current_dataset->rows_count ) { - end_row = current_dataset->rows_count; - } - - gf_rows = gf_mds( current_dataset->rows->value, - sizeof(ROW), - current_dataset->rows_count, - VALUES, - current_dataset->hourly ? HOURLY_TIMERES : HALFHOURLY_TIMERES, - GF_DRIVER_1_TOLERANCE_MIN, - GF_DRIVER_1_TOLERANCE_MAX, - GF_DRIVER_2A_TOLERANCE_MIN, - GF_DRIVER_2A_TOLERANCE_MAX, - GF_DRIVER_2B_TOLERANCE_MIN, - GF_DRIVER_2B_TOLERANCE_MAX, - VPD_MET, - SW_IN_MET, - TA_MET, - VPD_MET, - -1, - -1, - -1, - INVALID_VALUE, - INVALID_VALUE, - INVALID_VALUE, - GF_ROWS_MIN, - 0, - start_row, - end_row, - ¬_gf_count, - 0, - 0, - 0, - NULL, - 0 - ); - - if ( !gf_rows ) { - /* free memory */ - free_dataset(current_dataset); - continue; - } - - if ( !not_gf_count ) { - puts("ok"); - } else { - printf("ok (%d values unfilled)\n", not_gf_count); - } - - /* copy gf values and qc */ - for ( i = 0; i < current_dataset->rows_count; i++ ) { - current_dataset->rows[i].value[VPD_FILLED] = current_dataset->rows[i].value[VPD_MET]; - current_dataset->rows[i].value[VPD_QC] = INVALID_VALUE; - if ( (i >= start_row) && (i <= end_row) ) { - current_dataset->rows[i].value[VPD_FILLED] = IS_FLAG_SET(gf_rows[i].mask, GF_TOFILL_VALID) ? current_dataset->rows[i].value[VPD_MET] : gf_rows[i].filled; - current_dataset->rows[i].value[VPD_QC] = IS_FLAG_SET(gf_rows[i].mask, GF_TOFILL_VALID) ? 0 : gf_rows[i].quality; - } - } - - /* free memory */ - free(gf_rows); - gf_rows = NULL; - } - - /* gapfilling CO2 */ - printf("- gapfilling CO2..."); - - /* compute start and end row */ - start_row = -1; - end_row = -1; - for ( i = 0; i < current_dataset->rows_count; i++ ) { - if ( !IS_INVALID_VALUE(current_dataset->rows[i].value[CO2_MET]) ) { - start_row = i; - break; - } - } - if ( -1 == start_row ) { - for ( i = 0; i < current_dataset->rows_count; i++ ) { - current_dataset->rows[i].value[CO2_FILLED] = INVALID_VALUE; - current_dataset->rows[i].value[CO2_QC] = INVALID_VALUE; - } - puts("ok but is missing!"); - } else { - for ( i = current_dataset->rows_count - 1; i >= 0 ; i-- ) { - if ( !IS_INVALID_VALUE(current_dataset->rows[i].value[CO2_MET]) ) { - end_row = i; - break; + /* gapfilling... */ + { + int m; + + const int meteo_index[TS_DEF_VAR] = { + TA_MET, + SW_IN_MET, + LW_IN_MET, + VPD_MET, + CO2_MET + }; + + const int filled_index[TS_DEF_VAR] = { + TA_FILLED, + SW_IN_FILLED, + LW_IN_FILLED, + VPD_FILLED, + CO2_FILLED + }; + + const int qc_index[TS_DEF_VAR] = { + TA_QC, + SW_IN_QC, + LW_IN_QC, + VPD_QC, + CO2_QC + }; + + /* TS and SWC has profiles so we can't uniform mds...they are computed separately */ + for ( m = 0; m < TS_DEF_VAR; ++m ) { + printf("- gapfilling %s...", mds_vars->vars[m].name[MDS_VAR_TO_FILL]); + + /* compute start and end row */ + start_row = -1; + end_row = -1; + for ( i = 0; i < current_dataset->rows_count; i++ ) { + if ( !IS_INVALID_VALUE(current_dataset->rows[i].value[meteo_index[m]]) ) { + start_row = i; + break; + } } - } - if ( start_row == end_row ) { - puts("only one valid value for CO2!"); - /* free memory */ - free_dataset(current_dataset); - continue; - } + if ( -1 == start_row ) { + for ( i = 0; i < current_dataset->rows_count; i++ ) { + current_dataset->rows[i].value[filled_index[m]] = INVALID_VALUE; + current_dataset->rows[i].value[qc_index[m]] = INVALID_VALUE; + } + puts("ok but is missing!"); + } else { + for ( i = current_dataset->rows_count - 1; i >= 0 ; i-- ) { + if ( !IS_INVALID_VALUE(current_dataset->rows[i].value[meteo_index[m]]) ) { + end_row = i; + break; + } + } + if ( start_row == end_row ) { + puts("only one valid value for TA!"); + /* free memory */ + free_dataset(current_dataset); + continue; + } - /* adjust bounds */ - start_row -= (DAYS_FOR_GF*rows_per_day); - if ( start_row < 0 ) { - start_row = 0; - } + /* adjust bounds */ + start_row -= (DAYS_FOR_GF*rows_per_day); + if ( start_row < 0 ) { + start_row = 0; + } - end_row += (DAYS_FOR_GF*rows_per_day); - if ( end_row > current_dataset->rows_count ) { - end_row = current_dataset->rows_count; - } - - gf_rows = gf_mds( current_dataset->rows->value, - sizeof(ROW), - current_dataset->rows_count, - VALUES, - current_dataset->hourly ? HOURLY_TIMERES : HALFHOURLY_TIMERES, - GF_DRIVER_1_TOLERANCE_MIN, - GF_DRIVER_1_TOLERANCE_MAX, - GF_DRIVER_2A_TOLERANCE_MIN, - GF_DRIVER_2A_TOLERANCE_MAX, - GF_DRIVER_2B_TOLERANCE_MIN, - GF_DRIVER_2B_TOLERANCE_MAX, - CO2_MET, - SW_IN_MET, - TA_MET, - VPD_MET, - -1, - -1, - -1, - INVALID_VALUE, - INVALID_VALUE, - INVALID_VALUE, - GF_ROWS_MIN, - 0, - start_row, - end_row, - ¬_gf_count, - 0, - 0, - 0, - NULL, - 0 - ); + end_row += (DAYS_FOR_GF*rows_per_day); + if ( end_row > current_dataset->rows_count ) { + end_row = current_dataset->rows_count; + } + + gf_rows = gf_mds( current_dataset->rows->value, + sizeof(ROW), + current_dataset->rows_count, + VALUES, + current_dataset->hourly ? HOURLY_TIMERES : HALFHOURLY_TIMERES, + mds_vars->vars[m].tolerances[MDS_VAR_DRIVER_1][MDS_VAR_TOLERANCE_MIN], + mds_vars->vars[m].tolerances[MDS_VAR_DRIVER_1][MDS_VAR_TOLERANCE_MAX], + mds_vars->vars[m].tolerances[MDS_VAR_DRIVER_2A][MDS_VAR_TOLERANCE_MIN], + mds_vars->vars[m].tolerances[MDS_VAR_DRIVER_2A][MDS_VAR_TOLERANCE_MAX], + mds_vars->vars[m].tolerances[MDS_VAR_DRIVER_2B][MDS_VAR_TOLERANCE_MIN], + mds_vars->vars[m].tolerances[MDS_VAR_DRIVER_2B][MDS_VAR_TOLERANCE_MAX], + mds_vars->vars[m].columns[MDS_VAR_TO_FILL], + mds_vars->vars[m].columns[MDS_VAR_DRIVER_1], + mds_vars->vars[m].columns[MDS_VAR_DRIVER_2A], + mds_vars->vars[m].columns[MDS_VAR_DRIVER_2B], + -1, + -1, + -1, + INVALID_VALUE, + INVALID_VALUE, + INVALID_VALUE, + GF_ROWS_MIN, + 0, + start_row, + end_row, + ¬_gf_count, + 0, + 0, + 0, + NULL, + 0 + + ); + + if ( !gf_rows ) { + /* free memory */ + free_dataset(current_dataset); + continue; + } - if ( !gf_rows ) { - /* free memory */ - free_dataset(current_dataset); - continue; - } + if ( !not_gf_count ) { + puts("ok"); + } else { + printf("ok (%d values unfilled)\n", not_gf_count); + } - if ( !not_gf_count ) { - puts("ok"); - } else { - printf("ok (%d values unfilled)\n", not_gf_count); - } + /* copy gf values and qc */ + for ( i = 0; i < current_dataset->rows_count; i++ ) { + current_dataset->rows[i].value[filled_index[m]] = current_dataset->rows[i].value[meteo_index[m]]; + current_dataset->rows[i].value[qc_index[m]] = INVALID_VALUE; + if ( (i >= start_row) && (i <= end_row) ) { + current_dataset->rows[i].value[filled_index[m]] = IS_FLAG_SET(gf_rows[i].mask, GF_TOFILL_VALID) ? current_dataset->rows[i].value[meteo_index[m]] : gf_rows[i].filled; + current_dataset->rows[i].value[qc_index[m]] = IS_FLAG_SET(gf_rows[i].mask, GF_TOFILL_VALID) ? 0 : gf_rows[i].quality; + } + } - /* copy gf values and qc */ - for ( i = 0; i < current_dataset->rows_count; i++ ) { - current_dataset->rows[i].value[CO2_FILLED] = current_dataset->rows[i].value[CO2_MET]; - current_dataset->rows[i].value[CO2_QC] = INVALID_VALUE; - if ( (i >= start_row) && (i <= end_row) ) { - current_dataset->rows[i].value[CO2_FILLED] = IS_FLAG_SET(gf_rows[i].mask, GF_TOFILL_VALID) ? current_dataset->rows[i].value[CO2_MET] : gf_rows[i].filled; - current_dataset->rows[i].value[CO2_QC] = IS_FLAG_SET(gf_rows[i].mask, GF_TOFILL_VALID) ? 0 : gf_rows[i].quality; + /* free memory */ + free(gf_rows); + gf_rows = NULL; } } - - /* free memory */ - free(gf_rows); - gf_rows = NULL; } /* Ts filling */ @@ -4855,16 +4664,16 @@ int compute_datasets(DATASET *const datasets, const int datasets_count) { current_dataset->rows_count, VALUES, current_dataset->hourly ? HOURLY_TIMERES : HALFHOURLY_TIMERES, - GF_DRIVER_1_TOLERANCE_MIN, - GF_DRIVER_1_TOLERANCE_MAX, - GF_DRIVER_2A_TOLERANCE_MIN, - GF_DRIVER_2A_TOLERANCE_MAX, - GF_DRIVER_2B_TOLERANCE_MIN, - GF_DRIVER_2B_TOLERANCE_MAX, + mds_vars->vars[TS_DEF_VAR].tolerances[MDS_VAR_DRIVER_1][MDS_VAR_TOLERANCE_MIN], + mds_vars->vars[TS_DEF_VAR].tolerances[MDS_VAR_DRIVER_1][MDS_VAR_TOLERANCE_MAX], + mds_vars->vars[TS_DEF_VAR].tolerances[MDS_VAR_DRIVER_2A][MDS_VAR_TOLERANCE_MIN], + mds_vars->vars[TS_DEF_VAR].tolerances[MDS_VAR_DRIVER_2A][MDS_VAR_TOLERANCE_MAX], + mds_vars->vars[TS_DEF_VAR].tolerances[MDS_VAR_DRIVER_2B][MDS_VAR_TOLERANCE_MIN], + mds_vars->vars[TS_DEF_VAR].tolerances[MDS_VAR_DRIVER_2B][MDS_VAR_TOLERANCE_MAX], TEMP, - SW_IN_MET, - TA_MET, - VPD_MET, + mds_vars->vars[TS_DEF_VAR].columns[MDS_VAR_DRIVER_1], + mds_vars->vars[TS_DEF_VAR].columns[MDS_VAR_DRIVER_2A], + mds_vars->vars[TS_DEF_VAR].columns[MDS_VAR_DRIVER_2B], -1, -1, -1, @@ -4962,16 +4771,16 @@ int compute_datasets(DATASET *const datasets, const int datasets_count) { current_dataset->rows_count, VALUES, current_dataset->hourly ? HOURLY_TIMERES : HALFHOURLY_TIMERES, - GF_DRIVER_1_TOLERANCE_MIN, - GF_DRIVER_1_TOLERANCE_MAX, - GF_DRIVER_2A_TOLERANCE_MIN, - GF_DRIVER_2A_TOLERANCE_MAX, - GF_DRIVER_2B_TOLERANCE_MIN, - GF_DRIVER_2B_TOLERANCE_MAX, + mds_vars->vars[SWC_DEF_VAR].tolerances[MDS_VAR_DRIVER_1][MDS_VAR_TOLERANCE_MIN], + mds_vars->vars[SWC_DEF_VAR].tolerances[MDS_VAR_DRIVER_1][MDS_VAR_TOLERANCE_MAX], + mds_vars->vars[SWC_DEF_VAR].tolerances[MDS_VAR_DRIVER_2A][MDS_VAR_TOLERANCE_MIN], + mds_vars->vars[SWC_DEF_VAR].tolerances[MDS_VAR_DRIVER_2A][MDS_VAR_TOLERANCE_MAX], + mds_vars->vars[SWC_DEF_VAR].tolerances[MDS_VAR_DRIVER_2B][MDS_VAR_TOLERANCE_MIN], + mds_vars->vars[SWC_DEF_VAR].tolerances[MDS_VAR_DRIVER_2B][MDS_VAR_TOLERANCE_MAX], TEMP, - SW_IN_MET, - TA_MET, - VPD_MET, + mds_vars->vars[SWC_DEF_VAR].columns[MDS_VAR_DRIVER_1], + mds_vars->vars[SWC_DEF_VAR].columns[MDS_VAR_DRIVER_2A], + mds_vars->vars[SWC_DEF_VAR].columns[MDS_VAR_DRIVER_2B], -1, -1, -1, @@ -5136,7 +4945,7 @@ int compute_datasets(DATASET *const datasets, const int datasets_count) { /* free memory */ free_dataset(current_dataset); } - + /* free memory */ free(datasets); diff --git a/oneflux_steps/meteo_proc/src/dataset.h b/oneflux_steps/meteo_proc/src/dataset.h index 62eab62a..f280569e 100644 --- a/oneflux_steps/meteo_proc/src/dataset.h +++ b/oneflux_steps/meteo_proc/src/dataset.h @@ -14,6 +14,7 @@ /* includes */ #include "types.h" +#include "mds_vars.h" /* enumerations */ enum { @@ -76,7 +77,7 @@ typedef struct { /* prototypes */ void free_datasets(DATASET *datasets, const int datasets_count); DATASET *get_datasets(int *const datasets_count); -int compute_datasets(DATASET *const datasets, const int datasets_count); +int compute_datasets(DATASET *const datasets, const int datasets_count, MDS_VARS* mds_vars); /* */ #endif /* DATASET_H */ diff --git a/oneflux_steps/meteo_proc/src/defs.c b/oneflux_steps/meteo_proc/src/defs.c new file mode 100644 index 00000000..213a682d --- /dev/null +++ b/oneflux_steps/meteo_proc/src/defs.c @@ -0,0 +1,22 @@ +/* + defs.c + + this file is part of meteo_proc + + author: Alessio Ribeca + owner: DIBAF - University of Tuscia, Viterbo, Italy + + scientific contact: Dario Papale +*/ + +#include "defs.h" + +const char* sz_defs[DEF_VARS_COUNT] = { + "TA", + "SW_IN", + "LW_IN", + "VPD", + "CO2", + "TS", + "SWC" +}; \ No newline at end of file diff --git a/oneflux_steps/meteo_proc/src/defs.h b/oneflux_steps/meteo_proc/src/defs.h new file mode 100644 index 00000000..07ff09fd --- /dev/null +++ b/oneflux_steps/meteo_proc/src/defs.h @@ -0,0 +1,29 @@ +/* + defs.h + + this file is part of meteo_proc + + author: Alessio Ribeca + owner: DIBAF - University of Tuscia, Viterbo, Italy + + scientific contact: Dario Papale +*/ + +#ifndef DEFS_H +#define DEFS_H + +enum { + TA_DEF_VAR, + SW_IN_DEF_VAR, + LW_IN_DEF_VAR, + VPD_DEF_VAR, + CO2_DEF_VAR, + TS_DEF_VAR, + SWC_DEF_VAR, + + DEF_VARS_COUNT +}; + +const char* sz_defs[DEF_VARS_COUNT]; + +#endif /* DEFS_H */ diff --git a/oneflux_steps/meteo_proc/src/main.c b/oneflux_steps/meteo_proc/src/main.c index d2281d09..726049e0 100644 --- a/oneflux_steps/meteo_proc/src/main.c +++ b/oneflux_steps/meteo_proc/src/main.c @@ -12,6 +12,12 @@ scientific contact: Dario Papale */ +/* + MDS rules + + on overwritting default values, ALL mds parameters must be specified! +*/ + /* includes */ #include #include @@ -19,11 +25,13 @@ #include #include "dataset.h" #include "types.h" +#include "mds_vars.h" +#include "defs.h" #include "../../common/common.h" #include "../../compiler.h" /* constants */ -#define PROGRAM_VERSION "v1.01" +#define PROGRAM_VERSION "v1.02" #define BUFFER_SIZE 1024 #define QC_AUTO_PATH "qc_auto" #define ERA_PATH "era" @@ -35,11 +43,6 @@ char *era_files_path = NULL; /* mandatory */ char *output_files_path = NULL; /* mandatory */ char folder_delimiter_str[2]; /* used to get folder delimiter string from FOLDER_DELIMITER char in common.h*/ -PREC swin_tolerance_min = GF_DRIVER_1_TOLERANCE_MIN; /* see common.h */ -PREC swin_tolerance_max = GF_DRIVER_1_TOLERANCE_MAX; /* see common.h */ -PREC ta_tolerance = GF_DRIVER_2A_TOLERANCE_MIN; /* see common.h */ -PREC vpd_tolerance = GF_DRIVER_2B_TOLERANCE_MIN; /* see common.h */ - /* strings */ static const char banner[] = "\nmeteo_proc "PROGRAM_VERSION"\n" "by Alessio Ribeca\n\n" @@ -55,14 +58,26 @@ static const char err_path_already_specified[] = "path already specified for %s: static const char err_unable_get_current_directory[] = "unable to retrieve current directory.\n"; static const char err_unable_to_convert_value_for[] = "unable to convert value \"%s\" for %s\n\n"; static const char err_unable_open_output_path[] = "unable to open output path.\n"; +static const char err_var_name_too_long[] = "mds var name too long.\n"; static const char msg_usage[] = "How to use: meteo_proc parameter\n\n" " parameters:\n\n" - " -qc_auto_path=qc_auto_files_folder -> set input files folder\n" - " if not specified, files will be searched into \"%s\" folder\n\n" - " -era_path=era_files_folder -> set era files folder\n" - " if not specified, files will be searched into \"%s\" folder\n\n" - " -output_path=output_files_folder -> set output files folder\n" - " if not specified, files will be created into executable folder\n\n" + " path:\n\n" + " -qc_auto_path=qc_auto_files_folder -> set input files folder\n" + " if not specified, files will be searched into \"%s\" folder\n\n" + " -era_path=era_files_folder -> set era files folder\n" + " if not specified, files will be searched into \"%s\" folder\n\n" + " -output_path=output_files_folder -> set output files folder\n" + " if not specified, files will be created into executable folder\n\n" + " mds:\n\n" + #if 0 + " -XXX_oor=min,max -> values of oor for XXX\n" + #endif + " -XXX_driver1=YYY -> name of the main driver for XXX filling with MDS\n" + " -XXX_driver2a=YYY -> name of the first additional driver for XXX filling with MDS\n" + " -XXX_driver2b=YYY -> name of the second additional driver for XXX filling with MDS\n" + " -XXX_tdriver1=min[,max] -> set the tolerance values used to define similar conditions related to XXX_driver1\n" + " -XXX_tdriver2a=min[,max] -> set the tolerance values used to define similar conditions related to XXX_driver2a\n" + " -XXX_tdriver2b=min[,max] -> set the tolerance values used to define similar conditions related to XXX_driver2a\n\n" " -h -> show this help\n"; /* */ @@ -124,18 +139,241 @@ static int set_path(char *arg, char *param, void *p) { static int show_help(char *arg, char *param, void *p) { if ( param ) { printf(err_arg_no_needs_param, arg); - return 0; + } else { + printf(msg_usage, QC_AUTO_PATH, ERA_PATH); } - /* */ - printf(msg_usage, QC_AUTO_PATH, - ERA_PATH - ); - /* must return error */ return 0; } +static int parse_mds(char *arg, char *param, void *p) { + int ret = 0; /* defaults to err */ + + if ( !param || !param[0] ) { + printf(err_arg_needs_param, arg); + } else { + /* + get var name getting last occurency of '_' + 'cause we can have var that has an underscore in the name + e.g.: SW_IN + */ + char* pp = strrchr(arg, '_'); + if ( !pp ) { + ret = -1; /* unknown argument */ + } else { + #define VAR_MAX_LEN 15 + + int i = pp - arg; + if ( i > VAR_MAX_LEN ) { + printf(err_var_name_too_long); + } else { + char var[VAR_MAX_LEN+1] = { 0 }; + int index; + int is_tolerance = 0; + int is_oor = 0; + + strncpy(var, arg, i); + + /* skip underscore */ + ++pp; + + /* check if var name is allowed, e.g. it is one of allowed */ + for ( i = 0; i < DEF_VARS_COUNT; ++i ) { + if ( !string_compare_i(var, sz_defs[i]) ) { + break; + } + } + + ret = (DEF_VARS_COUNT == i) ? -1 : 0; + if ( ret != -1 ) { + #if 0 + /* check for oor for main var */ + if ( ! string_compare_i(pp, "oor") ) { + is_oor = 1; + index = MDS_VAR_TO_FILL; + } + + /* + 1234567 + driver1 + + 7 is minimal accepted length of arg after var name + */ + else + #endif + if ( strlen(pp) < 7 ) { + ret = -1; /* unknown argument */ + } else { + /* what we are parsing ? driver or tolerance ? */ + is_tolerance = ! string_n_compare_i(pp, "tdriver", 7); + is_oor = ! string_n_compare_i(pp, "odriver", 7); + if ( ! is_tolerance && ! is_oor ) { + /* we must be sure that we have 'driver' as suffix */ + if ( string_n_compare_i(pp, "driver", 6) ) { + is_tolerance = -1; + } + } + if ( -1 == is_tolerance ) { + ret = -1; /* unknown argument */ + } else { + /* which index ? 6 is lenght of "driver" string */ + index = ! string_n_compare_i(pp+6+is_tolerance+is_oor, "1", 1); + if ( !index ) { + index = ! string_n_compare_i(pp+6+is_tolerance+is_oor, "2a", 2); + if ( index ) { + ++index; + } else { + index = ! string_n_compare_i(pp+6+is_tolerance+is_oor, "2b", 2); + if ( index ) { + index += 2; + } else { + ret = -1; /* unknown argument */ + } + } + } + } + } + + if ( ret != -1 ) { + const char* driver_name = NULL; + int error = 0; + PREC min = INVALID_VALUE; + PREC max = INVALID_VALUE; + + const char err_unable_convert_tolerance[] = "unable to convert tolerance \"%s\" for %s.\n\n"; + const char err_unable_convert_oor[] = "unable to convert oor \"%s\" for %s.\n\n"; + const char err_driver_already_specified[] = "driver already specified: \"%s\" for %s.\n\n"; + const char err_oor_needs_min_and_max[] = "oor for %s needs 2 values. min and max.\n\n"; + + if ( !is_tolerance && !is_oor ) { + /* get driver name */ + driver_name = param; + } else { + pp = strchr(param, ','); + if ( ! pp ) { + if ( is_oor ) { + printf(err_oor_needs_min_and_max, arg); + error = 1; + is_oor = 0; /* we disable to print error below */ + } else { + /* get min */ + min = convert_string_to_prec(param, &error); + } + } else { + *pp = '\0'; /* remove comma */ + min = convert_string_to_prec(param, &error); + *pp = ','; /* re-add comma */ + if ( ! error ) { + /* get max */ + ++pp; /* skip comma */ + error = ! pp[0]; /* check for missing value */ + if ( ! error ) { + max = convert_string_to_prec(pp, &error); + } + } + } + } + + if ( error ) { + if ( is_tolerance ) { + printf(err_unable_convert_tolerance, param, arg); + } else if ( is_oor ) { + printf(err_unable_convert_oor, param, arg); + } + } else { + MDS_VARS* vars = p; + + /* check if we already have that var */ + for ( i = 0; i < vars->count; ++i ) { + if (!string_compare_i(var, vars->vars[i].name[MDS_VAR_TO_FILL]) ) { + break; + } + } + + if ( i == vars->count ) { + MDS_VAR* vars_noleak = realloc(vars->vars, (vars->count+1)*sizeof*vars_noleak); + if ( !vars_noleak ) { + printf("%s for %s\n\n", err_out_of_memory, arg); + } else { + vars->vars = vars_noleak; + memset(&vars->vars[vars->count], 0, sizeof(vars->vars[vars->count])); + + Mds_Var_Init(&vars->vars[vars->count]); + ++vars->count; + } + } + + ret = 1; /* ok...for now */ + + /* + err codes + + 0 -> out of memory + 1 -> ok (no error) + 2 -> driver or tolerances already specified + */ + + if ( ! vars->vars[i].name[MDS_VAR_TO_FILL] ) { + vars->vars[i].name[MDS_VAR_TO_FILL] = string_copy(var); + ret = vars->vars[i].name[MDS_VAR_TO_FILL] ? 1 : 0; + } + + if ( 1 == ret ) { + if ( !is_tolerance && !is_oor ) { + if ( vars->vars[i].name[index] ) { + ret = 2; + } else { + vars->vars[i].name[index] = string_copy(param); + if ( !vars->vars[i].name[index] ) { + ret = 0; + } + + } + } else { + if ( ( is_tolerance && (!IS_INVALID_VALUE(vars->vars[i].tolerances[index][MDS_VAR_TOLERANCE_MIN]) + || !IS_INVALID_VALUE(vars->vars[i].tolerances[index][MDS_VAR_TOLERANCE_MAX]))) + || + ( is_oor && (!IS_INVALID_VALUE(vars->vars[i].oors[index][MDS_VAR_OOR_MIN]) + || !IS_INVALID_VALUE(vars->vars[i].oors[index][MDS_VAR_OOR_MAX]))) + ){ + ret = 2; + } else if ( is_tolerance ) { + vars->vars[i].tolerances[index][MDS_VAR_TOLERANCE_MIN] = min; + vars->vars[i].tolerances[index][MDS_VAR_TOLERANCE_MAX] = max; + } else { /* is_oor */ + vars->vars[i].oors[index][MDS_VAR_OOR_MIN] = min; + vars->vars[i].oors[index][MDS_VAR_OOR_MAX] = max; + } + } + } + + if ( ret != 1 ) { + switch ( ret ) { + case 0: + printf("%s for %s\n\n", err_out_of_memory, arg); + break; + + case 2: + printf(err_driver_already_specified, param, arg); + break; + } + + /* return with valid values...0 or 1 */ + ret = 0; + } + } + } + } + } + + #undef VAR_MAX_LEN + } + } + + return ret; +} + /* */ static void clean_up(void) { free(program_path); @@ -145,19 +383,185 @@ static void clean_up(void) { check_memory_leak(); } +static int get_digits_count(int v) +{ + return (int)floor(log10((float)v)+1); +} + +static int setup_default_mds(MDS_VARS* vars) { +#define DEFAULT_TOLERANCES \ + { \ + (PREC)INVALID_VALUE, \ + (PREC)INVALID_VALUE, \ + (PREC)GF_DRIVER_1_TOLERANCE_MIN, \ + (PREC)GF_DRIVER_1_TOLERANCE_MAX, \ + (PREC)GF_DRIVER_2A_TOLERANCE_MIN, \ + (PREC)GF_DRIVER_2A_TOLERANCE_MAX, \ + (PREC)GF_DRIVER_2B_TOLERANCE_MIN, \ + (PREC)GF_DRIVER_2B_TOLERANCE_MAX \ + } + +#define DEFAULT_OOR \ + { \ + (PREC)INVALID_VALUE, \ + (PREC)INVALID_VALUE, \ + (PREC)INVALID_VALUE, \ + (PREC)INVALID_VALUE, \ + (PREC)INVALID_VALUE, \ + (PREC)INVALID_VALUE, \ + (PREC)INVALID_VALUE, \ + (PREC)INVALID_VALUE \ + } + + int ret = 0; /* defaults to err */ + + MDS_VAR defs[] = { + { DEFAULT_TOLERANCES, DEFAULT_OOR, { TA_MET, -1, -1, -1 }, { sz_defs[TA_DEF_VAR], sz_defs[SW_IN_DEF_VAR], sz_defs[TA_DEF_VAR], sz_defs[VPD_DEF_VAR] } } + , { DEFAULT_TOLERANCES, DEFAULT_OOR, { SW_IN_MET, -1, -1, -1 }, { sz_defs[SW_IN_DEF_VAR], sz_defs[SW_IN_DEF_VAR], sz_defs[TA_DEF_VAR], sz_defs[VPD_DEF_VAR] } } + , { DEFAULT_TOLERANCES, DEFAULT_OOR, { LW_IN_MET, -1, -1, -1 }, { sz_defs[LW_IN_DEF_VAR], sz_defs[SW_IN_DEF_VAR], sz_defs[TA_DEF_VAR], sz_defs[VPD_DEF_VAR] } } + , { DEFAULT_TOLERANCES, DEFAULT_OOR, { VPD_MET, -1, -1, -1 }, { sz_defs[VPD_DEF_VAR], sz_defs[SW_IN_DEF_VAR], sz_defs[TA_DEF_VAR], sz_defs[VPD_DEF_VAR] } } + , { DEFAULT_TOLERANCES, DEFAULT_OOR, { CO2_MET, -1, -1, -1 }, { sz_defs[CO2_DEF_VAR], sz_defs[SW_IN_DEF_VAR], sz_defs[TA_DEF_VAR], sz_defs[VPD_DEF_VAR] } } + , { DEFAULT_TOLERANCES, DEFAULT_OOR, { -1, -1, -1, -1 }, { sz_defs[TS_DEF_VAR], sz_defs[SW_IN_DEF_VAR], sz_defs[TA_DEF_VAR], sz_defs[VPD_DEF_VAR] } } + , { DEFAULT_TOLERANCES, DEFAULT_OOR, { -1, -1, -1, -1 }, { sz_defs[SWC_DEF_VAR], sz_defs[SW_IN_DEF_VAR], sz_defs[TA_DEF_VAR], sz_defs[VPD_DEF_VAR] } } + }; + + vars->count = SIZEOF_ARRAY(defs); + vars->vars = malloc(vars->count*sizeof*vars->vars); + if ( vars->vars ) { + int i; + + for ( i = 0; i < vars->count; ++i ) { + int y; + for ( y = MDS_VAR_TO_FILL; y < MDS_VARS_COUNT; ++y ) { + vars->vars[i].name[y] = string_copy(defs[i].name[y]); + if ( ! vars->vars[i].name[y] ) { + break; + } + vars->vars[i].columns[y] = defs[i].columns[y]; + vars->vars[i].tolerances[y][MDS_VAR_TOLERANCE_MIN] = defs[i].tolerances[y][MDS_VAR_TOLERANCE_MIN]; + vars->vars[i].tolerances[y][MDS_VAR_TOLERANCE_MAX] = defs[i].tolerances[y][MDS_VAR_TOLERANCE_MAX]; + vars->vars[i].oors[y][MDS_VAR_OOR_MIN] = defs[i].oors[y][MDS_VAR_OOR_MIN]; + vars->vars[i].oors[y][MDS_VAR_OOR_MAX] = defs[i].oors[y][MDS_VAR_OOR_MAX]; + } + } + + if ( i < vars->count ) { + Mds_Vars_Clear(vars); + } else { + ret = 1; + } + } + + return ret; + +#undef DEFAULT_OOR +#undef DEFAULT_TOLERANCES +} + +static void mds_summary(MDS_VARS* vars) { + const char* drivers[MDS_VARS_COUNT] = { NULL, "driver1", "driver2a", "driver2b" }; + int i; + int digits_count = get_digits_count(vars->count); + if ( digits_count < 2 ) { + digits_count = 2; + } + puts("MDS summary:\n"); + for ( i = 0; i < vars->count; i++ ) { + int y; + + printf("[%0*d / %0*d] - var to gf: %s", digits_count, i+1, digits_count, vars->count, vars->vars[i].name[MDS_VAR_TO_FILL]); + if ( ! IS_INVALID_VALUE(vars->vars[i].oors[MDS_VAR_TO_FILL][MDS_VAR_OOR_MIN]) ) { + printf(" (o: %g,%g)" , vars->vars[i].oors[MDS_VAR_TO_FILL][MDS_VAR_OOR_MIN] + , vars->vars[i].oors[MDS_VAR_TO_FILL][MDS_VAR_OOR_MAX] + ); + } + for ( y = MDS_VAR_DRIVER_1; y < MDS_VARS_COUNT; ++y ) { + printf(", %s: %s", drivers[y], vars->vars[i].name[y]); + if ( IS_INVALID_VALUE(vars->vars[i].tolerances[y][MDS_VAR_TOLERANCE_MAX]) ) { + printf(" (t: %g)", vars->vars[i].tolerances[y][MDS_VAR_TOLERANCE_MIN]); + } else { + printf(" (t: %g,%g)" , vars->vars[i].tolerances[y][MDS_VAR_TOLERANCE_MIN] + , vars->vars[i].tolerances[y][MDS_VAR_TOLERANCE_MAX] + ); + } + if ( ! IS_INVALID_VALUE(vars->vars[i].oors[y][MDS_VAR_OOR_MIN]) ) { + printf(" (o: %g,%g)" , vars->vars[i].oors[y][MDS_VAR_OOR_MIN] + , vars->vars[i].oors[y][MDS_VAR_OOR_MAX] + ); + } + } + puts(""); + } +} + +static int mds_merge(MDS_VARS* vars, MDS_VARS* user_vars) { + int u; /* as user */ + int ret = 0; /* defaults to err */ + for ( u = 0; u < user_vars->count; ++u ) { + int i; + int y; + + /* check if we need to overwrite default ones */ + for ( i = 0; i < vars->count; ++i ) { + if ( ! string_compare_i(user_vars->vars[u].name[MDS_VAR_TO_FILL], vars->vars[i].name[MDS_VAR_TO_FILL]) ) { + break; + } + } + if ( vars->count == i ) { + /* add */ + MDS_VAR* var_no_leak = realloc(vars->vars, (vars->count+1)*sizeof*var_no_leak); + if ( var_no_leak ) { + vars->vars = var_no_leak; + memset(&vars->vars[vars->count], 0, sizeof(vars->vars[vars->count])); + Mds_Var_Clear(&vars->vars[vars->count]); + i = vars->count++; + } + } + + /* if any */ + vars->vars[i].oors[MDS_VAR_TO_FILL][MDS_VAR_OOR_MIN] = user_vars->vars[u].oors[MDS_VAR_TO_FILL][MDS_VAR_OOR_MIN]; + vars->vars[i].oors[MDS_VAR_TO_FILL][MDS_VAR_OOR_MAX] = user_vars->vars[u].oors[MDS_VAR_TO_FILL][MDS_VAR_OOR_MAX]; + + for ( y = MDS_VAR_DRIVER_1; y < MDS_VARS_COUNT; ++y ) { + if ( vars->vars[i].name[y] ) { + free((void*)vars->vars[i].name[y]); + } + vars->vars[i].name[y] = string_copy(user_vars->vars[u].name[y]); + if ( !vars->vars[i].name[y] ) { + break; + } + vars->vars[i].tolerances[y][MDS_VAR_TOLERANCE_MIN] = user_vars->vars[u].tolerances[y][MDS_VAR_TOLERANCE_MIN]; + vars->vars[i].tolerances[y][MDS_VAR_TOLERANCE_MAX] = user_vars->vars[u].tolerances[y][MDS_VAR_TOLERANCE_MAX]; + vars->vars[i].oors[y][MDS_VAR_OOR_MIN] = user_vars->vars[u].oors[y][MDS_VAR_OOR_MIN]; + vars->vars[i].oors[y][MDS_VAR_OOR_MAX] = user_vars->vars[u].oors[y][MDS_VAR_OOR_MAX]; + } + + ret = (MDS_VARS_COUNT == y); + } + + return ret; +} + /* */ int main(int argc, char *argv[]) { int i; - DATASET *datasets; - int datasets_count; + int ret = 1; /* defaults to err */ + MDS_VARS mds_vars_by_user; + MDS_VARS mds_vars; + DATASET *datasets = NULL; /* mandatory */ + int datasets_count = 0; /* mandatory */ const ARGUMENT args[] = { { "qc_auto_path", set_path, &qc_auto_files_path }, { "era_path", set_path, &era_files_path }, { "output_path", set_path, &output_files_path }, + { "variadic", parse_mds, &mds_vars_by_user }, { "h", show_help, NULL }, { "help", show_help, NULL }, { "?", show_help, NULL }, }; + + Mds_Vars_Init(&mds_vars_by_user); + Mds_Vars_Init(&mds_vars); /* show banner */ puts(banner); @@ -165,77 +569,136 @@ int main(int argc, char *argv[]) { /* register atexit */ if ( -1 == atexit(clean_up) ) { puts(err_unable_to_register_atexit); - return 1; - } + } else { + /* get program path */ + program_path = get_current_directory(); + if ( !program_path ) { + puts(err_unable_get_current_directory); + } else if ( parse_arguments(argc, argv, args, SIZEOF_ARRAY(args)) ) { + ret = 0; /* ok */ + /* check for user mds */ + if ( mds_vars_by_user.count ) { + for ( i = 0; i < mds_vars_by_user.count; i++ ) { + if ( ! mds_vars_by_user.vars[i].name[MDS_VAR_DRIVER_1] ) { + printf("error: missing driver1 var for %s\n", mds_vars_by_user.vars[i].name[MDS_VAR_TO_FILL]); + break; + } + if ( ! mds_vars_by_user.vars[i].name[MDS_VAR_DRIVER_2A] ) { + printf("error: missing driver2a var for %s\n", mds_vars_by_user.vars[i].name[MDS_VAR_TO_FILL]); + break; + } + if ( ! mds_vars_by_user.vars[i].name[MDS_VAR_DRIVER_2B] ) { + printf("error: missing driver2b var for %s\n", mds_vars_by_user.vars[i].name[MDS_VAR_TO_FILL]); + break; + } + if ( IS_INVALID_VALUE(mds_vars_by_user.vars[i].tolerances[MDS_VAR_DRIVER_1][MDS_VAR_TOLERANCE_MIN]) ) { + printf("error: missing driver1 tolerances var for %s\n", mds_vars_by_user.vars[i].name[MDS_VAR_TO_FILL]); + break; + } + if ( IS_INVALID_VALUE(mds_vars_by_user.vars[i].tolerances[MDS_VAR_DRIVER_2A][MDS_VAR_TOLERANCE_MIN]) ) { + printf("error: missing driver2a tolerances var for %s\n", mds_vars_by_user.vars[i].name[MDS_VAR_TO_FILL]); + break; + } + if ( IS_INVALID_VALUE(mds_vars_by_user.vars[i].tolerances[MDS_VAR_DRIVER_2B][MDS_VAR_TOLERANCE_MIN]) ) { + printf("error: missing driver2b tolerances var for %s\n", mds_vars_by_user.vars[i].name[MDS_VAR_TO_FILL]); + break; + } + } + ret = (i < mds_vars_by_user.count); + } + if ( ! ret ) { + printf("setting default values for mds..."); + if ( ! setup_default_mds(&mds_vars) ) { + printf("%s\n\n", err_out_of_memory); + } else { + puts("ok!\n"); + } - /* get program path */ - program_path = get_current_directory(); - if ( !program_path ) { - puts(err_unable_get_current_directory); - return 1; - } + if ( !ret ) { + /* merge user mds with defaults ones */ + if ( mds_vars_by_user.count ) { + printf("merging default values for mds with user..."); + ret = !mds_merge(&mds_vars, &mds_vars_by_user); + if ( ret ) { + printf("%s\n\n", err_out_of_memory); + } else { + puts("ok!\n"); + } + } - /* parse arguments */ - if ( !parse_arguments(argc, argv, args, SIZEOF_ARRAY(args)) ) { - return 1; - } + if ( !ret ) { + /* summary for mds */ + mds_summary(&mds_vars); - /* get input path */ - if ( !qc_auto_files_path ) { - for ( i = 0; QC_AUTO_PATH[i]; i++ ); i += 2; - qc_auto_files_path = malloc(i*sizeof*qc_auto_files_path); - if ( !qc_auto_files_path ) { - puts(err_out_of_memory); - return 1; - } - sprintf(qc_auto_files_path, "%s%c", QC_AUTO_PATH, FOLDER_DELIMITER); - } + /* get input path */ + if ( !qc_auto_files_path ) { + for ( i = 0; QC_AUTO_PATH[i]; i++ ); i += 2; + ret = !(qc_auto_files_path = malloc(i*sizeof*qc_auto_files_path)); + if ( ret ) { + printf("%s\n\n", err_out_of_memory); + } else { + sprintf(qc_auto_files_path, "%s%c", QC_AUTO_PATH, FOLDER_DELIMITER); + } + } - /* get era path */ - if ( !era_files_path ) { - for ( i = 0; ERA_PATH[i]; i++ ); i += 2; - era_files_path = malloc(i*sizeof*era_files_path); - if ( !era_files_path ) { - puts(err_out_of_memory); - return 1; - } - sprintf(era_files_path, "%s%c", ERA_PATH, FOLDER_DELIMITER); - } + if ( !ret ) { + /* get era path */ + if ( !era_files_path ) { + for ( i = 0; ERA_PATH[i]; i++ ); i += 2; + ret = !(era_files_path = malloc(i*sizeof*era_files_path)); + if ( ret ) { + printf("%s\n\n", err_out_of_memory); + } else { + sprintf(era_files_path, "%s%c", ERA_PATH, FOLDER_DELIMITER); + } + } - /* output path specified ? */ - if ( !output_files_path ) { - output_files_path = string_copy(program_path); - if ( !output_files_path ) { - puts(err_out_of_memory); - return 1; - } - } + if ( !ret ) { + /* output path specified ? */ + if ( !output_files_path ) { + ret = !(output_files_path = string_copy(program_path)); + if ( ret ) { + printf("%s\n\n", err_out_of_memory); + } + } - /* check output path */ - if ( !path_exists(output_files_path) ) { - /* trying to create output path */ - if ( !create_dir(output_files_path) ) { - printf("unable to create output folder: %s\n", output_files_path); - return 1; - } - } + if ( !ret ) { + /* check output path */ + if ( !path_exists(output_files_path) ) { + /* trying to create output path */ + ret = !create_dir(output_files_path); + if ( ret ) { + printf("unable to create output folder: %s\n", output_files_path); + } + } - /* get datasets */ - datasets = get_datasets(&datasets_count); - if ( !datasets ) { - return 1; + if ( ! ret ) { + /* get datasets */ + ret = !(datasets = get_datasets(&datasets_count)); + if ( !ret ) { + /* compute datasets */ + if ( !compute_datasets(datasets, datasets_count, &mds_vars) ) { + free_datasets(datasets, datasets_count); + } else { + /* show datasets */ + printf("%d dataset%s found%s.\n", datasets_count, + (datasets_count>1) ? "s" : "", + (datasets_count>1) ? "ed" : ""); + } + } + } + } + } + } + } + } + } + } } - /* compute datasets */ - if ( !compute_datasets(datasets, datasets_count) ) { - free_datasets(datasets, datasets_count); - return 1; - } + Mds_Vars_Clear(&mds_vars); + Mds_Vars_Clear(&mds_vars_by_user); - /* show datasets */ - printf("%d dataset%s found%s.\n", datasets_count, - (datasets_count>1) ? "s" : "", - (datasets_count>1) ? "ed" : ""); /* */ - return 0; + return ret; } diff --git a/oneflux_steps/meteo_proc/src/mds_vars.c b/oneflux_steps/meteo_proc/src/mds_vars.c new file mode 100644 index 00000000..84de9b02 --- /dev/null +++ b/oneflux_steps/meteo_proc/src/mds_vars.c @@ -0,0 +1,63 @@ +/* + mds_vars.c + + this file is part of meteo_proc + + author: Alessio Ribeca + owner: DIBAF - University of Tuscia, Viterbo, Italy + + scientific contact: Dario Papale +*/ + +#include "mds_vars.h" +#include /* for free */ + +void Mds_Var_Init(MDS_VAR* var) { + int i; + for ( i = MDS_VAR_TO_FILL; i < MDS_VARS_COUNT; ++i ) { + var->name[i] = NULL; + var->columns[i] = -1; + var->tolerances[i][MDS_VAR_TOLERANCE_MIN] = INVALID_VALUE; + var->tolerances[i][MDS_VAR_TOLERANCE_MAX] = INVALID_VALUE; + var->oors[i][MDS_VAR_OOR_MIN] = INVALID_VALUE; + var->oors[i][MDS_VAR_OOR_MAX] = INVALID_VALUE; + } +} + +void Mds_Var_Clear(MDS_VAR* var) { + int i; + for ( i = MDS_VAR_TO_FILL; i < MDS_VARS_COUNT; ++i ) { + if ( var->name[i] ) { + free((void*)var->name[i]); + } + } + Mds_Var_Init(var); +} + +/* +void Mds_Var_Free(MDS_VAR* var) { + Mds_Var_Clear(var); + free(var); +} +*/ + +void Mds_Vars_Init(MDS_VARS* vars) { + vars->vars = NULL; + vars->count = 0; +} + +void Mds_Vars_Clear(MDS_VARS* vars) { + int i; + for ( i = 0; i < vars->count; ++i ) { + Mds_Var_Clear(&vars->vars[i]); + } + free(vars->vars); + Mds_Vars_Init(vars); +} + +/* +void Mds_Vars_Free(MDS_VARS* vars) { + Mds_Vars_Clear(vars); + free(vars); +} +*/ diff --git a/oneflux_steps/meteo_proc/src/mds_vars.h b/oneflux_steps/meteo_proc/src/mds_vars.h new file mode 100644 index 00000000..4ee4dcb0 --- /dev/null +++ b/oneflux_steps/meteo_proc/src/mds_vars.h @@ -0,0 +1,71 @@ +/* + mds_vars.h + + this file is part of meteo_proc + + author: Alessio Ribeca + owner: DIBAF - University of Tuscia, Viterbo, Italy + + scientific contact: Dario Papale +*/ + +#ifndef MDS_VARS_H +#define MDS_VARS_H + +#include "../../common/common.h" + +enum { + MDS_VAR_TOLERANCE_MIN = 0 + , MDS_VAR_TOLERANCE_MAX + + , MDS_VAR_TOLERANCES_COUNT +}; + +enum { + MDS_VAR_OOR_MIN = 0 + , MDS_VAR_OOR_MAX + + , MDS_VAR_OORS_COUNT +}; + +enum { + MDS_VAR_TO_FILL = 0 + , MDS_VAR_DRIVER_1 + , MDS_VAR_DRIVER_2A + , MDS_VAR_DRIVER_2B + + , MDS_VARS_COUNT +}; + +typedef struct +{ + /* + DO NOT CHANGE ORDER + ADJUSTED FOR BYTES PADDING + + PLEASE NOTE THAT, IN THIS WAY (tolerances[MDS_VARS_COUNT] and oor[MDS_VARS_COUNT]) + WE HAVE TOLERANCES FOR VAR_TO_FILL TOO BUT, + OF COURSE, THEY WILL BE INVALID_VALUE AND UNUSED + */ + + PREC tolerances[MDS_VARS_COUNT][MDS_VAR_TOLERANCES_COUNT]; + PREC oors[MDS_VARS_COUNT][MDS_VAR_OORS_COUNT]; + int columns[MDS_VARS_COUNT]; + const char* name[MDS_VARS_COUNT]; + +} MDS_VAR; + +typedef struct +{ + MDS_VAR* vars; + int count; + +} MDS_VARS; + +void Mds_Var_Init(MDS_VAR* var); +void Mds_Var_Clear(MDS_VAR* var); + +void Mds_Vars_Init(MDS_VARS* vars); +void Mds_Vars_Clear(MDS_VARS* vars); + +#endif /* MDS_VARS_H */ diff --git a/oneflux_steps/meteo_proc/src/types.h b/oneflux_steps/meteo_proc/src/types.h index 569dd26c..b7a21eaa 100644 --- a/oneflux_steps/meteo_proc/src/types.h +++ b/oneflux_steps/meteo_proc/src/types.h @@ -99,7 +99,41 @@ enum { TEMP, - VALUES + USER_DRIVERS_BEGIN, + + TA_MET_DRIVER_1 = USER_DRIVERS_BEGIN, + TA_MET_DRIVER_2A, + TA_MET_DRIVER_2B, + + SW_IN_MET_DRIVER_1, + SW_IN_MET_DRIVER_2A, + SW_IN_MET_DRIVER_2B, + + LW_IN_MET_DRIVER_1, + LW_IN_MET_DRIVER_2A, + LW_IN_MET_DRIVER_2B, + + VPD_MET_DRIVER_1, + VPD_MET_DRIVER_2A, + VPD_MET_DRIVER_2B, + + CO2_MET_DRIVER_1, + CO2_MET_DRIVER_2A, + CO2_MET_DRIVER_2B, + + TS_MET_DRIVER_1, + TS_MET_DRIVER_2A, + TS_MET_DRIVER_2B, + + SWC_MET_DRIVER_1, + SWC_MET_DRIVER_2A, + SWC_MET_DRIVER_2B, + + USER_DRIVERS_END, + + USER_DRIVERS_COUNT = USER_DRIVERS_END - USER_DRIVERS_BEGIN, + + VALUES = USER_DRIVERS_END }; /* */ @@ -110,12 +144,14 @@ typedef struct { /* */ typedef struct { - char mask; - PREC value[VALUES]; PREC similiar; PREC stddev; PREC nights_count; PREC days_count; + PREC value[VALUES]; + char mask; + + char padding[3]; } ROW; /* */