30#include <libdap/BaseType.h>
31#include <libdap/Float64.h>
32#include <libdap/Byte.h>
33#include <libdap/Str.h>
34#include <libdap/Structure.h>
35#include <libdap/Array.h>
36#include <libdap/Grid.h>
37#include <libdap/D4RValue.h>
39#include <libdap/Error.h>
40#include <libdap/DDS.h>
43#include <libdap/debug.h>
44#include <libdap/util.h>
48#include "RangeFunction.h"
55 string(
"<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n")
56 +
"<function name=\"linear_scale\" version=\"1.0b1\" href=\"http://docs.opendap.org/index.php/Server_Side_Processing_Functions#range\">\n"
68static double string_to_double(
const char *val)
70 istringstream iss(val);
74 double abs_val = fabs(v);
75 if (abs_val > DODS_DBL_MAX || (abs_val != 0.0 && abs_val < DODS_DBL_MIN))
76 throw Error(malformed_expr,
string(
"Could not convert the string '") + val +
"' to a double.");
94static double get_attribute_double_value(BaseType *var, vector<string> &attributes)
98 AttrTable &attr = var->get_attr_table();
99 string attribute_value =
"";
101 vector<string>::iterator i = attributes.begin();
102 while (attribute_value ==
"" && i != attributes.end()) {
104 if (!values.empty()) values +=
", ";
105 attribute_value = attr.get_attr(*i++);
110 if (attribute_value.empty()) {
111 if (var->type() == dods_grid_c)
112 return get_attribute_double_value(
dynamic_cast<Grid&
>(*var).get_array(), attributes);
114 throw Error(malformed_expr,
115 string(
"No COARDS/CF '") + values.substr(0, values.size() - 2)
116 +
"' attribute was found for the variable '" + var->name() +
"'.");
119 return string_to_double(remove_quotes(attribute_value).c_str());
135static double get_attribute_double_value(BaseType *var,
const string &attribute)
137 AttrTable &attr = var->get_attr_table();
138 string attribute_value = attr.get_attr(attribute);
142 if (attribute_value.empty()) {
143 if (var->type() == dods_grid_c)
144 return get_attribute_double_value(
dynamic_cast<Grid&
>(*var).get_array(), attribute);
146 throw Error(malformed_expr,
147 string(
"No COARDS '") + attribute +
"' attribute was found for the variable '" + var->name()
151 return string_to_double(remove_quotes(attribute_value).c_str());
154static double get_missing_value(BaseType *var)
156 return get_attribute_double_value(var,
"missing_value");
168min_max_t find_min_max(
double* data,
int length,
bool use_missing,
double missing)
171 double previous_value;
172 bool increasing, previously_increasing;
175 previous_value = data[0];
177 for (
int i = 0; i < length; ++i) {
178 if (!double_eq(data[i], missing)) {
179 if(v.monotonic && i>0){
180 increasing = (data[i] - previous_value) > 0.0;
182 if(previously_increasing!=increasing){
186 previously_increasing = increasing;
187 previous_value = data[i];
189 v.max_val = max(v.max_val, data[i]);
190 v.min_val = min(v.min_val, data[i]);
195 for (
int i = 0; i < length; ++i) {
196 if(v.monotonic && i>0){
197 increasing = (data[i] - previous_value) > 0.0;
199 if(previously_increasing!=increasing){
203 previously_increasing = increasing;
204 previous_value = data[i];
206 v.max_val = max(v.max_val, data[i]);
207 v.min_val = min(v.min_val, data[i]);
212 for (
int i = 0; i < length; ++i) {
213 if (!use_missing || !double_eq(data[i], missing)) {
214 if(v.monotonic && i>0){
215 increasing = (data[i] - previous_value) > 0.0;
217 if(previously_increasing!=increasing){
221 previously_increasing = increasing;
222 previous_value = data[i];
224 v.max_val = max(v.max_val, data[i]);
225 v.min_val = min(v.min_val, data[i]);
245BaseType *range_worker(BaseType *bt,
double missing,
bool use_missing)
252 if (bt->type() == dods_grid_c) {
254 Grid &source =
dynamic_cast<Grid&
>(*bt);
256 BESDEBUG(
"function",
"range_worker() - Grid send_p: " << source.send_p() << endl);
257 BESDEBUG(
"function",
"range_worker() - Grid Array send_p: " << source.get_array()->send_p() << endl);
261 source.set_send_p(
true);
265 Array *a = source.get_array();
266 double *data = extract_double_array(a);
269 int length = a->length();
271 v = find_min_max(data, length, use_missing, missing);
275 else if (bt->is_vector_type()) {
276 Array &source =
dynamic_cast<Array&
>(*bt);
279 if (source.get_parent() && source.get_parent()->type() == dods_grid_c) {
280 source.get_parent()->set_send_p(
true);
281 source.get_parent()->read();
286 double *data = extract_double_array(&source);
289 int length = source.length();
291 v = find_min_max(data, length, use_missing, missing);
295 else if (bt->is_simple_type() && !(bt->type() == dods_str_c || bt->type() == dods_url_c)) {
296 double data = extract_double_value(bt);
301 throw Error(malformed_expr,
"The range_worker() function works only for numeric Grids, Arrays and scalars.");
305 Structure *rangeResult =
new Structure(
"range_result_unwrap");
307 Float64 *rangeMin =
new Float64(
"min");
308 rangeMin->set_value(v.min_val);
309 rangeResult->add_var_nocopy(rangeMin);
311 Float64 *rangeMax =
new Float64(
"max");
312 rangeMax->set_value(v.max_val);
313 rangeResult->add_var_nocopy(rangeMax);
315 Byte *is_monotonic =
new Byte(
"is_monotonic");
316 is_monotonic->set_value(v.monotonic);
317 rangeResult->add_var_nocopy(is_monotonic);
334void function_dap2_range(
int argc, BaseType * argv[], DDS &, BaseType **btpp)
337 Str *response =
new Str(
"info");
338 response->set_value(range_info);
344 DBG(cerr <<
"argc = " << argc << endl);
345 if (!(argc == 1 || argc == 2 ))
346 throw Error(malformed_expr,
347 "Wrong number of arguments to range(). See range() for more information");
350 bool use_missing =
false;
351 double missing = 0.0;
353 missing = extract_double_value(argv[1]);
361 missing = get_missing_value(argv[0]);
370 "function_dap2_range() - use_missing: " << use_missing <<
", missing: " << missing << endl);
372 *btpp = range_worker(argv[0], missing, use_missing);
387BaseType *function_dap4_range(D4RValueList *args, DMR &dmr)
389 BESDEBUG(
"function",
"function_dap4_range() BEGIN " << endl);
392 if (args == 0 || args->size() == 0) {
393 Str *response =
new Str(
"info");
394 response->set_value(range_info);
400 DBG(cerr <<
"args.size() = " << args.size() << endl);
401 if (!(args->size() == 1 || args->size() == 2))
402 throw Error(malformed_expr,
403 "Wrong number of arguments to linear_scale(). See linear_scale() for more information");
406 bool use_missing =
false;
407 double missing = 0.0;
408 if (args->size() == 2) {
409 missing = extract_double_value(args->get_rvalue(3)->value(dmr));
414 missing = get_missing_value(args->get_rvalue(0)->value(dmr));
422 "function_dap4_range() - use_missing: " << use_missing <<
", missing: " << missing << endl);
424 BESDEBUG(
"function",
"function_dap4_range() END " << endl);
426 return range_worker(args->get_rvalue(0)->value(dmr), missing, use_missing);