Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add new modifier +e to 1-D array creation option -T to handle rounding #161

Merged
merged 1 commit into from
Nov 4, 2018
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Add enw modifier +e to 1-D array creation to handle rounding
When inc is specified and min/max are determined from data there is the chance that (max-min)/inc is NOT an integer, which is required. By defailt we adjust the increment to fit, while +e changes this to adjust max instead.  This matches the behavior for grid setup.
  • Loading branch information
PaulWessel committed Nov 4, 2018
commit 4004b37af13bd09ebc8f584cf56e6d366cb5d77e
4 changes: 4 additions & 0 deletions doc_classic/rst/source/explain_array.rst_
Original file line number Diff line number Diff line change
Expand Up @@ -24,3 +24,7 @@ geospatial distance unit from the list
**d**\ egree (arc), **m**\ inute (arc), **s**\ econd (arc), m\ **e**\ ter, **f**\ oot, **k**\ ilometer,
**M**\ iles (statute), **n**\ autical miles, or s\ **u**\ rvey foot. For Cartesian distances, you must
use the special unit **c**.

Finally, if you are only providing an increment and obtain *min* and *max* from the data, then it is
possible (*max* - *min*)/*inc* is not an integer, as required. If so then *inc* will be adjusted to accordingly.
Alternatively, append **+e** to keep *inc* exact and adjust *max* instead.
4 changes: 2 additions & 2 deletions doc_classic/rst/source/filter1d.rst
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ Synopsis
[ |-D|\ *increment* ] [ |-E| ]
[ |-L|\ *lack\_width* ] [ |-N|\ *t\_col* ] [ |-Q|\ *q\_factor* ]
[ |-S|\ *symmetry\_factor* ]
[ |-T|\ [\ *min/max*\ /]\ *inc*\ [**+a**\ \|\ **n**] \|\ |-T|\ *file*\ \|\ *list* ]
[ |-T|\ [\ *min/max*\ /]\ *inc*\ [**+e**\ \|\ **+a**\ \|\ **n**] \|\ |-T|\ *file*\ \|\ *list* ]
[ |SYN_OPT-V| ]
[ |SYN_OPT-b| ]
[ |SYN_OPT-d| ]
Expand Down Expand Up @@ -138,7 +138,7 @@ Optional Arguments

.. _-T:

**-T**\ [\ *min/max*\ /]\ *inc*\ [**+a**\ \|\ **n**] \|\ |-T|\ *file*\ \|\ *list*
**-T**\ [\ *min/max*\ /]\ *inc*\ [**+e**\ \|\ **+a**\ \|\ **n**] \|\ |-T|\ *file*\ \|\ *list*
Make evenly spaced time-steps from *min* to *max* by *inc* [Default uses input times].
For details on array creation, see `Generate 1D Array`_.

Expand Down
4 changes: 4 additions & 0 deletions doc_modern/rst/source/explain_array.rst_
Original file line number Diff line number Diff line change
Expand Up @@ -24,3 +24,7 @@ geospatial distance unit from the list
**d**\ egree (arc), **m**\ inute (arc), **s**\ econd (arc), m\ **e**\ ter, **f**\ oot, **k**\ ilometer,
**M**\ iles (statute), **n**\ autical miles, or s\ **u**\ rvey foot. For Cartesian distances, you must
use the special unit **c**.

Finally, if you are only providing an increment and obtain *min* and *max* from the data, then it is
possible (*max* - *min*)/*inc* is not an integer, as required. If so then *inc* will be adjusted to accordingly.
Alternatively, append **+e** to keep *inc* exact and adjust *max* instead.
4 changes: 2 additions & 2 deletions doc_modern/rst/source/filter1d.rst
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ Synopsis
[ |-D|\ *increment* ] [ |-E| ]
[ |-L|\ *lack\_width* ] [ |-N|\ *t\_col* ] [ |-Q|\ *q\_factor* ]
[ |-S|\ *symmetry\_factor* ]
[ |-T|\ [\ *min/max*\ /]\ *inc*\ [**+a**\ \|\ **n**] \|\ |-T|\ *file*\ \|\ *list* ]
[ |-T|\ [\ *min/max*\ /]\ *inc*\ [**+e**\ \|\ **+a**\ \|\ **n**] \|\ |-T|\ *file*\ \|\ *list* ]
[ |SYN_OPT-V| ]
[ |SYN_OPT-b| ]
[ |SYN_OPT-d| ]
Expand Down Expand Up @@ -138,7 +138,7 @@ Optional Arguments

.. _-T:

**-T**\ [\ *min/max*\ /]\ *inc*\ [**+a**\ \|\ **n**] \|\ |-T|\ *file*\ \|\ *list*
**-T**\ [\ *min/max*\ /]\ *inc*\ [**+e**\ \|\ **+a**\ \|\ **n**] \|\ |-T|\ *file*\ \|\ *list*
Make evenly spaced time-steps from *min* to *max* by *inc* [Default uses input times].
For details on array creation, see `Generate 1D Array`_.

Expand Down
5 changes: 3 additions & 2 deletions src/filter1d.c
Original file line number Diff line number Diff line change
Expand Up @@ -181,7 +181,7 @@ GMT_LOCAL int usage (struct GMTAPI_CTRL *API, int level) {
const char *name = gmt_show_name_and_purpose (API, THIS_MODULE_LIB, THIS_MODULE_NAME, THIS_MODULE_PURPOSE);
if (level == GMT_MODULE_PURPOSE) return (GMT_NOERROR);
GMT_Message (API, GMT_TIME_NONE, "usage: %s [<table>] -F<type><width>[<modifiers>] [-D<increment>] [-E] [-I<ignore_val>]\n", name);
GMT_Message (API, GMT_TIME_NONE, "\t[-L<lack_width>] [-N<t_col>] [-Q<q_factor>] [-S<symmetry>] [-T[<min>/<max>/][-|+]<inc>[<unit>][+n|a]]\n");
GMT_Message (API, GMT_TIME_NONE, "\t[-L<lack_width>] [-N<t_col>] [-Q<q_factor>] [-S<symmetry>] [-T[<min>/<max>/][-|+]<inc>[<unit>][+e|n|a]]\n");
GMT_Message (API, GMT_TIME_NONE, "\t[%s] [%s] [%s] [%s] [%s]\n\t[%s] [%s]\n\t[%s] [%s] [%s] [%s]\n\n",
GMT_V_OPT, GMT_b_OPT, GMT_d_OPT, GMT_e_OPT, GMT_f_OPT, GMT_g_OPT, GMT_h_OPT, GMT_i_OPT, GMT_o_OPT, GMT_colon_OPT, GMT_PAR_OPT);

Expand Down Expand Up @@ -228,6 +228,7 @@ GMT_LOCAL int usage (struct GMTAPI_CTRL *API, int level) {
GMT_Message (API, GMT_TIME_NONE, "\t then no output will be given at this point [Default does not check Symmetry].\n");
GMT_Message (API, GMT_TIME_NONE, "\t-T Make evenly spaced output time steps from <min> to <max> by <inc> [Default uses input times].\n");
GMT_Message (API, GMT_TIME_NONE, "\t Append +n to indicate <inc> is the number of t-values to produce instead.\n");
GMT_Message (API, GMT_TIME_NONE, "\t If only <inc< is given, optionally append +e to keep increment exact [Default will adjust to fit range].\n");
GMT_Message (API, GMT_TIME_NONE, "\t For absolute time filtering, append a valid time unit (%s) to the increment.\n", GMT_TIME_UNITS_DISPLAY);
GMT_Message (API, GMT_TIME_NONE, "\t For spatial filtering with distance computed from the first two columns, specify increment as\n");
GMT_Message (API, GMT_TIME_NONE, "\t [-|+][<unit>]<inc>, with - for fast (Flat Earth) or + for slow (ellipsoidal) calculations [great circle].\n");
Expand Down Expand Up @@ -384,7 +385,7 @@ GMT_LOCAL int parse (struct GMT_CTRL *GMT, struct FILTER1D_CTRL *Ctrl, struct GM
}

if (Ctrl->T.active) /* Do this one here since we need Ctrl->N.col to be set first, if selected */
n_errors += gmt_parse_array (GMT, 'T', t_arg, &(Ctrl->T.T), GMT_ARRAY_TIME | GMT_ARRAY_DIST, Ctrl->N.col);
n_errors += gmt_parse_array (GMT, 'T', t_arg, &(Ctrl->T.T), GMT_ARRAY_TIME | GMT_ARRAY_DIST | GMT_ARRAY_ROUND, Ctrl->N.col);
if (Ctrl->N.spatial) Ctrl->T.T.spatial = Ctrl->N.spatial; /* Obsolete -N settings propagated to -T */
if (Ctrl->N.add_col) Ctrl->T.T.add = true; /* Obsolete -N+a settings propagated to -T */

Expand Down
3 changes: 2 additions & 1 deletion src/gmt_constants.h
Original file line number Diff line number Diff line change
Expand Up @@ -137,7 +137,8 @@ enum GMT_enum_array {
GMT_ARRAY_DIST = 4,
GMT_ARRAY_NOINC = 8,
GMT_ARRAY_SCALAR = 16,
GMT_ARRAY_NOMINMAX = 32};
GMT_ARRAY_NOMINMAX = 32,
GMT_ARRAY_ROUND = 64};

/*! Handling of swap/no swap in i/o */
enum GMT_swap_direction {
Expand Down
51 changes: 40 additions & 11 deletions src/gmt_support.c
Original file line number Diff line number Diff line change
Expand Up @@ -6596,7 +6596,7 @@ bool gmt_getinc (struct GMT_CTRL *GMT, char *line, double inc[]) {

int n;

/* Syntax: -I<xinc>[m|s|e|f|k|M|n|u|+|=][/<yinc>][m|s|e|f|k|M|n|u|+|=]
/* Syntax: -I<xinc>[m|s|e|f|k|M|n|u|+e|n][/<yinc>][m|s|e|f|k|M|n|u|+e|n]
* Units: d = arc degrees
* m = arc minutes
* s = arc seconds [was c]
Expand All @@ -6606,8 +6606,8 @@ bool gmt_getinc (struct GMT_CTRL *GMT, char *line, double inc[]) {
* k = km [Convert to degrees]
* n = nautical miles [Convert to degrees]
* u = survey feet [Convert to degrees]
* Flags: = = Adjust -R to fit exact -I [Default modifies -I to fit -R]
* + = incs are actually n_columns/n_rows - convert to get xinc/yinc
* Flags: +e = Adjust -R to fit exact -I [Default modifies -I to fit -R]
* +n = incs are actually n_columns/n_rows - convert to get xinc/yinc
*/

if (!line) { GMT_Report (GMT->parent, GMT_MSG_NORMAL, "No argument given to gmt_getinc\n"); return (true); }
Expand Down Expand Up @@ -15323,7 +15323,7 @@ unsigned int gmt_parse_array (struct GMT_CTRL *GMT, char option, char *argument,
* -T<argument>
*
* where <argument> is one of these:
* [<min/max/]<inc>[<unit>|+a|n|b|l]
* [<min/max/]<inc>[<unit>|+a|e|n|b|l]
* <file>
*
* Parsing:
Expand Down Expand Up @@ -15356,6 +15356,9 @@ unsigned int gmt_parse_array (struct GMT_CTRL *GMT, char option, char *argument,
* equidistant in log2(t). Here, inc must be an integer and indicates
* the log2 increment.
* 8) If +a is given then we will add the output array as a new output column.
* 9) If +e is given when only an increment is given then we must keep the
* increment exact and adjust max to ensure (max-min)/inc is an integer.
* The default adjusts inc instead, if flag GMT_ARRAY_ROUND is passed.
*
* Note: The effects in 4) and 5) are only allowed if the corresponding
* flags are passed to the parser.
Expand Down Expand Up @@ -15403,18 +15406,21 @@ unsigned int gmt_parse_array (struct GMT_CTRL *GMT, char option, char *argument,
return (GMT_NOERROR);
}

if ((m = gmt_first_modifier (GMT, argument, "ablnt"))) { /* Process optional modifiers +a, +b, +l, +n, +t */
if ((m = gmt_first_modifier (GMT, argument, "abelnt"))) { /* Process optional modifiers +a, +b, +e, +l, +n, +t */
unsigned int pos = 0; /* Reset to start of new word */
unsigned int n_errors = 0;
char p[GMT_LEN32] = {""};
while (gmt_getmodopt (GMT, 'T', m, "ablnt", &pos, p, &n_errors) && n_errors == 0) {
while (gmt_getmodopt (GMT, 'T', m, "abelnt", &pos, p, &n_errors) && n_errors == 0) {
switch (p[0]) {
case 'a': /* Add spatial distance column to output */
T->add = true;
break;
case 'b': /* Do a log2 grid */
T->logarithmic2 = true;
break;
case 'e': /* Increment must be honored exactly */
T->exact_inc = true;
break;
case 'n': /* Gave number of points instead; calculate inc later */
T->count = true;
break;
Expand Down Expand Up @@ -15456,7 +15462,7 @@ unsigned int gmt_parse_array (struct GMT_CTRL *GMT, char option, char *argument,
ns--; /* ns is now the index to the txt array with the increment or count (2 or 0) */
len = strlen (txt[ns]); if (len) len--; /* Now txt[ns][len] holds a unit (or not) */
if (!has_inc && (T->logarithmic || T->logarithmic2)) {
GMT_Report (GMT->parent, GMT_MSG_NORMAL, "Syntax error -%c: Logarithmic array requires and increment argument\n", option);
GMT_Report (GMT->parent, GMT_MSG_NORMAL, "Syntax error -%c: Logarithmic array requires an increment argument\n", option);
return GMT_PARSE_ERROR;
}
/* 3. Check if we are working with absolute time. This means there must be a T in both min or max arguments */
Expand Down Expand Up @@ -15531,7 +15537,7 @@ unsigned int gmt_parse_array (struct GMT_CTRL *GMT, char option, char *argument,
return GMT_PARSE_ERROR;
}
if (T->logarithmic && !(k_inc == 1 || k_inc == 2 || k_inc == 3 || k_inc < 0)) {
GMT_Report (GMT->parent, GMT_MSG_NORMAL, "Syntax error -%c: Log10 increment must be 1, 2, 3 (or a negative integer)\n", option);
GMT_Report (GMT->parent, GMT_MSG_NORMAL, "Syntax error -%c: Logarithmic increment must be 1, 2, 3 (or a negative integer)\n", option);
return GMT_PARSE_ERROR;
}
}
Expand Down Expand Up @@ -15571,7 +15577,13 @@ unsigned int gmt_parse_array (struct GMT_CTRL *GMT, char option, char *argument,
if (has_inc && ns == 0 && (flags & GMT_ARRAY_NOMINMAX)) { /* The min/max will be set later */
T->delay[GMT_X] = T->delay[GMT_Y] = true;
}

if (flags & GMT_ARRAY_ROUND) /* Adjust increment to fit min/max so (max-min)/inc is an integer */
T->round = true;
if (T->exact_inc && T->set == 3) {
GMT_Report (GMT->parent, GMT_MSG_NORMAL, "Syntax error -%c: Modifier +e only applies when increment is given without any range\n", option);
return GMT_PARSE_ERROR;

}
if (m) m[0] = '+'; /* Restore the modifiers */
T->col = tcol;

Expand Down Expand Up @@ -15635,7 +15647,7 @@ unsigned int gmt_create_array (struct GMT_CTRL *GMT, char option, struct GMT_ARR
return GMT_NOERROR;
}

if (! (min == NULL && max == NULL)) { /* Update min,max now */
if (T->set < 3 && ! (min == NULL && max == NULL)) { /* Update min,max now */
T->min = *min; T->max = *max;
}
if (T->count) /* This means we gave a count instead of increment */
Expand All @@ -15661,7 +15673,24 @@ unsigned int gmt_create_array (struct GMT_CTRL *GMT, char option, struct GMT_ARR
T->n = gmtlib_log_array (GMT, t0, t1, inc, &(T->array));
else if (T->logarithmic2) /* Must call special function that deals with logarithmic arrays */
T->n = gmtlib_log2_array (GMT, t0, t1, inc, &(T->array));
else { /* Equidistant intervals are straightforward - make sure the min/man/inc values harmonize */
else { /* Equidistant intervals are straightforward - make sure the min/max/inc values harmonize */
if (T->exact_inc) { /* Must enforce that max-min is a multiple of inc and adjust max if it is not */
double new, range = t1 - t0;
new = rint (range / inc) * inc;
if (!doubleAlmostEqualZero (new, range)) { /* Must adjust t1 to match proper range */
t1 = t0 + new;
GMT_Report (GMT->parent, GMT_MSG_LONG_VERBOSE, "Range (max - min) is not a whole multiple of inc. Adjusted max to %g\n", option, t1);
}
}
else if (T->round) { /* Must enforce an increment that fits the given range */
double new, range = t1 - t0;
unsigned int nt = urint (range / inc);
new = nt * inc;
if (nt && !doubleAlmostEqualZero (new, range)) { /* Must adjust inc to match proper range */
inc = range / (nt - 1);
GMT_Report (GMT->parent, GMT_MSG_LONG_VERBOSE, "Range (max - min) is not a whole multiple of inc. Adjusted inc to %g\n", option, inc);
}
}
switch (gmt_minmaxinc_verify (GMT, t0, t1, inc, GMT_CONV4_LIMIT)) {
case 1:
GMT_Report (GMT->parent, GMT_MSG_NORMAL, "Syntax error -%c option: (max - min) is not a whole multiple of inc\n", option);
Expand Down
2 changes: 2 additions & 0 deletions src/gmt_types.h
Original file line number Diff line number Diff line change
Expand Up @@ -90,6 +90,8 @@ struct GMT_ARRAY { /* Used by modules that needs to set up 1-D output/bin arrays
bool count; /* true if we got number of items rather than increment */
bool add; /* true if we are asked to add a computed spatial distance column to output */
bool reverse; /* true if we want to reverse the array to give high to low on output */
bool round; /* true if we want to adjust increment to ensure min/max range is a multiple of inc */
bool exact_inc; /* true if we want the increment to be exact and to adjust min/max intstead */
bool logarithmic; /* true if inc = 1,2,3 and we want logarithmic scale */
bool logarithmic2; /* true if inc = integer and we want log2 scale */
bool delay[2]; /* true if min and/or max shall be set from data set extremes after read [false] */
Expand Down