MeteoIODoc  2.10.0
Array1D.h
Go to the documentation of this file.
1 // SPDX-License-Identifier: LGPL-3.0-or-later
2 /***********************************************************************************/
3 /* Copyright 2009 WSL Institute for Snow and Avalanche Research SLF-DAVOS */
4 /***********************************************************************************/
5 /* This file is part of MeteoIO.
6  MeteoIO is free software: you can redistribute it and/or modify
7  it under the terms of the GNU Lesser 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  MeteoIO 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 Lesser General Public License for more details.
15 
16  You should have received a copy of the GNU Lesser General Public License
17  along with MeteoIO. If not, see <http://www.gnu.org/licenses/>.
18 */
19 #ifndef ARRAY1D_H
20 #define ARRAY1D_H
21 
22 #include <vector>
23 #include <limits>
24 #include <iostream>
25 #include <numeric>
26 #include <algorithm>
27 
28 #include <meteoio/IOUtils.h>
29 #include <meteoio/IOExceptions.h>
30 
31 namespace mio {
32 
43 template<class T> class Array1D {
44  public:
45  Array1D(const size_t& asize=0);
46 
52  Array1D(const size_t& asize, const T& init);
53 
59  void setKeepNodata(const bool i_keep_nodata);
60 
65  bool getKeepNodata();
66 
67  void size(size_t& nx) const;
68  size_t size() const;
69  size_t getNx() const;
70 
71  void resize(const size_t& asize);
72  void resize(const size_t& asize, const T& init);
73  void clear();
74  bool empty() const;
75 
76  void insertAt(const int& index, T e);
77  void removeAt(const size_t& index);
78 
83  T getMin() const;
88  T getMax() const;
93  T getMean() const;
100  size_t getCount() const;
105  const Array1D<T> getAbs() const;
106  void abs();
107 
108 
109  const std::string toString() const;
110  template<class P> friend std::ostream& operator<<(std::ostream& os, const Array1D<P>& array);
111  template<class P> friend std::istream& operator>>(std::istream& is, Array1D<P>& array);
112 
113  bool checkEpsilonEquality(const Array1D<double>& rhs, const double& epsilon) const;
114  static bool checkEpsilonEquality(const Array1D<double>& rhs1, const Array1D<double>& rhs2, const double& epsilon);
115 
116  T& operator [](const size_t& index);
117  const T operator [](const size_t& index) const;
118  T& operator ()(const size_t& index);
119  const T operator ()(const size_t& index) const;
120 
121  Array1D<T>& operator =(const T& value);
122 
123  Array1D<T>& operator+=(const T& rhs);
124  const Array1D<T> operator+(const T& rhs) const;
125  Array1D<T>& operator+=(const Array1D<T>& rhs);
126  const Array1D<T> operator+(const Array1D<T>& rhs) const;
127 
128  Array1D<T>& operator-=(const T& rhs);
129  const Array1D<T> operator-(const T& rhs) const;
130  Array1D<T>& operator-=(const Array1D<T>& rhs);
131  const Array1D<T> operator-(const Array1D<T>& rhs) const;
132 
133  Array1D<T>& operator*=(const T& rhs);
134  const Array1D<T> operator*(const T& rhs) const;
135  Array1D<T>& operator*=(const Array1D<T>& rhs);
136  const Array1D<T> operator*(const Array1D<T>& rhs) const;
137 
138  Array1D<T>& operator/=(const T& rhs);
139  const Array1D<T> operator/(const T& rhs) const;
140  Array1D<T>& operator/=(const Array1D<T>& rhs);
141  const Array1D<T> operator/(const Array1D<T>& rhs) const;
142 
143  bool operator==(const Array1D<T>&) const;
144  bool operator!=(const Array1D<T>&) const;
145 
146  protected:
147  std::vector<T> vecData;
148  size_t nx;
150 };
151 
152 template<class T> Array1D<T>::Array1D(const size_t& asize)
153  : vecData(asize), nx(asize), keep_nodata(true)
154 {
155  //resize(asize);
156 }
157 
158 template<class T> Array1D<T>::Array1D(const size_t& asize, const T& init)
159  : vecData(asize, init), nx(asize), keep_nodata(true)
160 {
161  //resize(asize, init);
162 }
163 
164 template<class T> void Array1D<T>::setKeepNodata(const bool i_keep_nodata) {
165  keep_nodata = i_keep_nodata;
166 }
167 
168 template<class T> bool Array1D<T>::getKeepNodata() {
169  return keep_nodata;
170 }
171 
172 template<class T> void Array1D<T>::size(size_t& o_nx) const {
173  o_nx = nx;
174 }
175 
176 template<class T> size_t Array1D<T>::size() const {
177  return nx;
178 }
179 
180 template<class T> size_t Array1D<T>::getNx() const {
181  return nx;
182 }
183 
184 template<class T> void Array1D<T>::resize(const size_t& asize) {
185  vecData.clear();
186  vecData.resize(asize);
187  nx = asize;
188 }
189 
190 template<class T> void Array1D<T>::resize(const size_t& asize, const T& init) {
191  vecData.clear();
192  vecData.resize(asize, init);
193  nx = asize;
194 }
195 
196 template<class T> inline T& Array1D<T>::operator()(const size_t& index) {
197 #ifndef NOSAFECHECKS
198  if (index >= nx) {
199  std::stringstream ss;
200  ss << "Trying to access array(" << index << ")";
201  ss << " while array is (" << nx << ")";
202  throw IndexOutOfBoundsException(ss.str(), AT);
203  }
204 #endif
205  return vecData[index];
206 }
207 
208 template<class T> inline const T Array1D<T>::operator()(const size_t& index) const {
209 #ifndef NOSAFECHECKS
210  if (index >= nx) {
211  std::stringstream ss;
212  ss << "Trying to access array(" << index << ")";
213  ss << " while array is (" << nx << ")";
214  throw IndexOutOfBoundsException(ss.str(), AT);
215  }
216 #endif
217  return vecData[index];
218 }
219 
220 template<class T> inline T& Array1D<T>::operator [](const size_t& index) {
221 #ifndef NOSAFECHECKS
222  return vecData.at(index);
223 #else
224  return vecData[index];
225 #endif
226 }
227 
228 template<class T> inline const T Array1D<T>::operator [](const size_t& index) const {
229 #ifndef NOSAFECHECKS
230  return vecData.at(index);
231 #else
232  return vecData[index];
233 #endif
234 }
235 
236 template<class T> void Array1D<T>::clear() {
237  vecData.clear();
238  nx = 0;
239 }
240 
241 template<class T> bool Array1D<T>::empty() const {
242  return (nx==0);
243 }
244 
245 template<class T> const std::string Array1D<T>::toString() const {
246  std::stringstream os;
247  os << "<array1d>\n";
248  for (size_t ii=0; ii<nx; ii++) {
249  os << vecData[ii] << " ";
250  }
251  os << "\n</array1d>\n";
252  return os.str();
253 }
254 
255 template<class P> std::ostream& operator<<(std::ostream& os, const Array1D<P>& array) {
256  os.write(reinterpret_cast<const char*>(&array.keep_nodata), sizeof(array.keep_nodata));
257  os.write(reinterpret_cast<const char*>(&array.nx), sizeof(array.nx));
258  os.write(reinterpret_cast<const char*>(&array.vecData[0]), static_cast<std::streamsize>(array.nx*sizeof(P)));
259  return os;
260 }
261 
262 template<class P> std::istream& operator>>(std::istream& is, Array1D<P>& array) {
263  is.read(reinterpret_cast<char*>(&array.keep_nodata), sizeof(array.keep_nodata));
264  is.read(reinterpret_cast<char*>(&array.nx), sizeof(array.nx));
265  array.vecData.resize(array.nx);
266  is.read(reinterpret_cast<char*>(&array.vecData[0]), static_cast<std::streamsize>(array.nx*sizeof(P))); //30 times faster than assign() or copy()
267  return is;
268 }
269 
270 template<class T> void Array1D<T>::insertAt(const int& index, T e) {
271  if (index < 0) {
272  vecData.push_back(e);
273  nx++;
274  } else if ((index >= 0) && (index < (int)vecData.size())) {
275  vecData.insert(vecData.begin() + index, e);
276  nx++;
277  } else {
278  std::stringstream ss;
279  ss << "Inserting an element at (" << index << ") in an array of size [" << nx << "]";
280  throw IndexOutOfBoundsException(ss.str(), AT);
281  }
282 }
283 
284 template<class T> void Array1D<T>::removeAt(const size_t& index) {
285  if (index < vecData.size()) {
286  vecData.erase(vecData.begin()+index);
287  nx--;
288  }
289 }
290 
291 template<class T> T Array1D<T>::getMin() const {
292 
293  T min = std::numeric_limits<T>::max();
294 
295  if (keep_nodata==false) {
296  min = *min_element(vecData.begin(), vecData.end());
297  if (min!=std::numeric_limits<T>::max()) return min;
298  else return (T)IOUtils::nodata;
299  } else {
300  for (size_t ii=0; ii<nx; ii++) {
301  const T val = vecData[ii];
302  if (val!=IOUtils::nodata && val<min) min=val;
303  }
304  if (min!=std::numeric_limits<T>::max()) return min;
305  else return (T)IOUtils::nodata;
306  }
307 }
308 
309 template<class T> T Array1D<T>::getMax() const {
310 
311  T max = -std::numeric_limits<T>::max();
312 
313  if (keep_nodata==false) {
314  max = *max_element(vecData.begin(), vecData.end());
315  if (max!=-std::numeric_limits<T>::max()) return max;
316  else return (T)IOUtils::nodata;
317  } else {
318  for (size_t ii=0; ii<nx; ii++) {
319  const T val = vecData[ii];
320  if (val!=IOUtils::nodata && val>max) max=val;
321  }
322  if (max!=-std::numeric_limits<T>::max()) return max;
323  else return (T)IOUtils::nodata;
324  }
325 }
326 
327 template<class T> T Array1D<T>::getMean() const {
328 
329  T mean = 0;
330 
331  if (keep_nodata==false) {
332  if (nx>0) return std::accumulate(vecData.begin(), vecData.end(), 0.) / (T)(nx);
333  else return (T)IOUtils::nodata;
334  } else {
335  size_t count = 0;
336  for (size_t ii=0; ii<nx; ii++) {
337  const T val = vecData[ii];
338  if (val!=IOUtils::nodata) {
339  mean += val;
340  count++;
341  }
342  }
343  if (count>0) return mean/(T)(count);
344  else return (T)IOUtils::nodata;
345  }
346 }
347 
348 template<class T> size_t Array1D<T>::getCount() const
349 {
350  if (keep_nodata==false) {
351  return (size_t)nx;
352  } else {
353  size_t count = 0;
354  for (size_t ii=0; ii<nx; ii++) {
355  if (vecData[ii]!=IOUtils::nodata) count++;
356  }
357  return count;
358  }
359 }
360 
361 template<class T> void Array1D<T>::abs() {
362  if (std::numeric_limits<T>::is_signed) {
363  if (keep_nodata==false) {
364  for (size_t ii=0; ii<nx; ii++) {
365  T& val = vecData[ii];
366  if (val<0) val=-val;
367  }
368  } else {
369  for (size_t ii=0; ii<nx; ii++) {
370  T& val = vecData[ii];
371  if (val<0 && val!=IOUtils::nodata) val=-val;
372  }
373  }
374  }
375 }
376 
377 template<class T> const Array1D<T> Array1D<T>::getAbs() const {
378  Array1D<T> result(*this); //make a copy
379  result.abs(); //already implemented
380 
381  return result;
382 }
383 
384 //arithmetic operators
385 template<class T> bool Array1D<T>::checkEpsilonEquality(const Array1D<double>& rhs, const double& epsilon) const {
386  if (nx!=rhs.nx) return false;
387 
388  for (size_t jj=0; jj<nx; jj++)
389  if (IOUtils::checkEpsilonEquality(vecData[jj], rhs.vecData[jj], epsilon)==false) return false;
390 
391  return true;
392 }
393 
394 template<class T> bool Array1D<T>::checkEpsilonEquality(const Array1D<double>& rhs1, const Array1D<double>& rhs2, const double& epsilon) {
395  return rhs1.checkEpsilonEquality(rhs2, epsilon);
396 }
397 
398 template<class T> Array1D<T>& Array1D<T>::operator=(const T& value) {
399  //reset every single member of the Array1D<T>
400  std::fill(vecData.begin(), vecData.end(), value);
401  return *this;
402 }
403 
404 template<class T> Array1D<T>& Array1D<T>::operator+=(const Array1D<T>& rhs)
405 {
406  //They have to have equal size
407  if (rhs.nx != nx) {
408  std::stringstream ss;
409  ss << "Trying to add two Array1D objects with different dimensions: ";
410  ss << "(" << nx << ") + (" << rhs.nx << ")";
411  throw IOException(ss.str(), AT);
412  }
413 
414  //Add to every single member of the Array1D<T>
415  if (keep_nodata==false) {
416  for (size_t ii=0; ii<nx; ii++) {
417  vecData[ii] += rhs(ii);
418  }
419  } else {
420  for (size_t ii=0; ii<nx; ii++) {
421  if (vecData[ii]==IOUtils::nodata || rhs(ii)==IOUtils::nodata)
422  vecData[ii] = IOUtils::nodata;
423  else
424  vecData[ii] += rhs(ii);
425  }
426  }
427 
428  return *this;
429 }
430 
431 template<class T> const Array1D<T> Array1D<T>::operator+(const Array1D<T>& rhs) const
432 {
433  Array1D<T> result(*this); //make a copy
434  result += rhs; //already implemented
435 
436  return result;
437 }
438 
439 template<class T> Array1D<T>& Array1D<T>::operator+=(const T& rhs)
440 {
441  if (rhs==0.) return *this;
442 
443  //Add to every single member of the Array1D<T>
444  if (keep_nodata==false) {
445  for (size_t ii=0; ii<nx; ii++) {
446  vecData[ii] += rhs;
447  }
448  } else {
449  for (size_t ii=0; ii<nx; ii++) {
450  if (vecData[ii]!=IOUtils::nodata)
451  vecData[ii] += rhs;
452  }
453  }
454 
455  return *this;
456 }
457 
458 template<class T> const Array1D<T> Array1D<T>::operator+(const T& rhs) const
459 {
460  Array1D<T> result(*this);
461  result += rhs; //already implemented
462 
463  return result;
464 }
465 
466 template<class T> Array1D<T>& Array1D<T>::operator-=(const Array1D<T>& rhs)
467 {
468  //They have to have equal size
469  if (rhs.nx != nx) {
470  std::stringstream ss;
471  ss << "Trying to substract two Array1D objects with different dimensions: ";
472  ss << "(" << nx << ") - (" << rhs.nx << ")";
473  throw IOException(ss.str(), AT);
474  }
475 
476  //Substract to every single member of the Array1D<T>
477  if (keep_nodata==false) {
478  for (size_t ii=0; ii<nx; ii++) {
479  vecData[ii] -= rhs(ii);
480  }
481  } else {
482  for (size_t ii=0; ii<nx; ii++) {
483  if (vecData[ii]==IOUtils::nodata || rhs(ii)==IOUtils::nodata)
484  vecData[ii] = IOUtils::nodata;
485  else
486  vecData[ii] -= rhs(ii);
487  }
488  }
489 
490  return *this;
491 }
492 
493 template<class T> const Array1D<T> Array1D<T>::operator-(const Array1D<T>& rhs) const
494 {
495  Array1D<T> result(*this); //make a copy
496  result -= rhs; //already implemented
497 
498  return result;
499 }
500 
501 template<class T> Array1D<T>& Array1D<T>::operator-=(const T& rhs)
502 {
503  *this += -rhs;
504  return *this;
505 }
506 
507 template<class T> const Array1D<T> Array1D<T>::operator-(const T& rhs) const
508 {
509  Array1D<T> result(*this);
510  result += -rhs; //already implemented
511 
512  return result;
513 }
514 
515 template<class T> Array1D<T>& Array1D<T>::operator*=(const Array1D<T>& rhs)
516 {
517  //They have to have equal size
518  if (rhs.nx != nx){
519  std::stringstream ss;
520  ss << "Trying to multiply two Array1D objects with different dimensions: ";
521  ss << "(" << nx << ") * (" << rhs.nx << ")";
522  throw IOException(ss.str(), AT);
523  }
524  //Multiply every single member of the Array1D<T>
525  if (keep_nodata==false) {
526  for (size_t ii=0; ii<nx; ii++) {
527  vecData[ii] *= rhs(ii);
528  }
529  } else {
530  for (size_t ii=0; ii<nx; ii++) {
531  if (vecData[ii]==IOUtils::nodata || rhs(ii)==IOUtils::nodata)
532  vecData[ii] = IOUtils::nodata;
533  else
534  vecData[ii] *= rhs(ii);
535  }
536  }
537 
538  return *this;
539 }
540 
541 template<class T> const Array1D<T> Array1D<T>::operator*(const Array1D<T>& rhs) const
542 {
543  Array1D<T> result(*this); //make a copy
544  result *= rhs; //already implemented
545 
546  return result;
547 }
548 
549 template<class T> Array1D<T>& Array1D<T>::operator*=(const T& rhs)
550 {
551  if (rhs==1.) return *this;
552 
553  //Multiply every single member of the Array1D<T>
554  if (keep_nodata==false) {
555  for (size_t ii=0; ii<nx; ii++) {
556  vecData[ii] *= rhs;
557  }
558  } else {
559  for (size_t ii=0; ii<nx; ii++) {
560  if (vecData[ii]!=IOUtils::nodata)
561  vecData[ii] *= rhs;
562  }
563  }
564 
565  return *this;
566 }
567 
568 template<class T> const Array1D<T> Array1D<T>::operator*(const T& rhs) const
569 {
570  Array1D<T> result(*this);
571  result *= rhs; //already implemented
572 
573  return result;
574 }
575 
576 template<class T> Array1D<T>& Array1D<T>::operator/=(const Array1D<T>& rhs)
577 {
578  //They have to have equal size
579  if (rhs.nx != nx){
580  std::stringstream ss;
581  ss << "Trying to divide two Array1D objects with different dimensions: ";
582  ss << "(" << nx << ") / (" << rhs.nx << ")";
583  throw IOException(ss.str(), AT);
584  }
585  //Divide every single member of the Array1D<T>
586  if (keep_nodata==false) {
587  for (size_t ii=0; ii<nx; ii++) {
588  vecData[ii] /= rhs(ii);
589  }
590  } else {
591  for (size_t ii=0; ii<nx; ii++) {
592  if (vecData[ii]==IOUtils::nodata || rhs(ii)==IOUtils::nodata)
593  vecData[ii] = IOUtils::nodata;
594  else
595  vecData[ii] /= rhs(ii);
596  }
597  }
598 
599  return *this;
600 }
601 
602 template<class T> const Array1D<T> Array1D<T>::operator/(const Array1D<T>& rhs) const
603 {
604  Array1D<T> result(*this); //make a copy
605  result /= rhs; //already implemented
606 
607  return result;
608 }
609 
610 template<class T> Array1D<T>& Array1D<T>::operator/=(const T& rhs)
611 {
612  *this *= (1./rhs);
613  return *this;
614 }
615 
616 template<class T> const Array1D<T> Array1D<T>::operator/(const T& rhs) const
617 {
618  Array1D<T> result(*this);
619  result *= 1./rhs; //already implemented
620 
621  return result;
622 }
623 
624 template<class T> bool Array1D<T>::operator==(const Array1D<T>& in) const {
625  const size_t in_nx = in.getNx();
626 
627  if (nx!=in_nx)
628  return false;
629 
630  for (size_t jj=0; jj<nx; jj++)
631  if ( !IOUtils::checkEpsilonEquality( vecData[jj] , in.vecData[jj], 1e-6) ) return false;
632 
633  return true;
634 }
635 
636 template<class T> bool Array1D<T>::operator!=(const Array1D<T>& in) const {
637  return !(*this==in);
638 }
639 
640 } //end namespace mio
641 
642 #endif
#define AT
Definition: IOExceptions.h:28
The template class Array1D is a 1D array (vector) able to hold any type of object as datatype....
Definition: Array1D.h:43
Array1D< T > & operator/=(const T &rhs)
Definition: Array1D.h:610
void resize(const size_t &asize)
Definition: Array1D.h:184
bool checkEpsilonEquality(const Array1D< double > &rhs, const double &epsilon) const
Definition: Array1D.h:385
void clear()
Definition: Array1D.h:236
const Array1D< T > operator*(const T &rhs) const
Definition: Array1D.h:568
std::vector< T > vecData
the actual data structure, that holds the objects of type T
Definition: Array1D.h:147
friend std::ostream & operator<<(std::ostream &os, const Array1D< P > &array)
Definition: Array1D.h:255
size_t size() const
Definition: Array1D.h:176
T & operator()(const size_t &index)
Definition: Array1D.h:196
void setKeepNodata(const bool i_keep_nodata)
set how to process nodata values (ie: as nodata or as normal numbers)
Definition: Array1D.h:164
bool operator==(const Array1D< T > &) const
Operator that tests for equality.
Definition: Array1D.h:624
void insertAt(const int &index, T e)
Definition: Array1D.h:270
const Array1D< T > operator+(const T &rhs) const
Definition: Array1D.h:458
Array1D< T > & operator-=(const T &rhs)
Definition: Array1D.h:501
void abs()
Definition: Array1D.h:361
size_t getNx() const
Definition: Array1D.h:180
T & operator[](const size_t &index)
Definition: Array1D.h:220
Array1D< T > & operator=(const T &value)
Definition: Array1D.h:398
size_t nx
this is introduced to omit the costly vecData.size()
Definition: Array1D.h:148
void removeAt(const size_t &index)
Definition: Array1D.h:284
bool keep_nodata
Definition: Array1D.h:149
Array1D(const size_t &asize=0)
Definition: Array1D.h:152
T getMean() const
returns the mean value contained in the grid
Definition: Array1D.h:327
bool operator!=(const Array1D< T > &) const
Operator that tests for inequality.
Definition: Array1D.h:636
T getMax() const
returns the maximum value contained in the grid
Definition: Array1D.h:309
friend std::istream & operator>>(std::istream &is, Array1D< P > &array)
Definition: Array1D.h:262
Array1D< T > & operator*=(const T &rhs)
Definition: Array1D.h:549
const std::string toString() const
Definition: Array1D.h:245
bool empty() const
Definition: Array1D.h:241
T getMin() const
returns the minimum value contained in the grid
Definition: Array1D.h:291
const Array1D< T > operator-(const T &rhs) const
Definition: Array1D.h:507
size_t getCount() const
returns the number of points contained in the grid. If setNodataHandling(IOUtils::RAW_NODATA),...
Definition: Array1D.h:348
const Array1D< T > operator/(const T &rhs) const
Definition: Array1D.h:616
const Array1D< T > getAbs() const
returns the grid of the absolute value of values contained in the grid
Definition: Array1D.h:377
bool getKeepNodata()
get how to process nodata values (ie: as nodata or as normal numbers)
Definition: Array1D.h:168
Array1D< T > & operator+=(const T &rhs)
Definition: Array1D.h:439
The basic exception class adjusted for the needs of SLF software.
Definition: IOExceptions.h:40
thrown when an index is out of bounds
Definition: IOExceptions.h:106
static const double e
Definition: Meteoconst.h:68
const double nodata
This is the internal nodata value.
Definition: IOUtils.h:75
size_t count(const std::string &input, const std::string &search)
count how many times a substring appears in a string
Definition: IOUtils.cc:226
bool checkEpsilonEquality(const double &val1, const double &val2, const double &epsilon)
Check whether two values are equal regarding a certain epsilon environment (within certain radius of ...
Definition: IOUtils.h:121
Definition: Config.cc:30
std::ostream & operator<<(std::ostream &os, const Config &cfg)
Definition: Config.cc:419
std::istream & operator>>(std::istream &is, Config &cfg)
Definition: Config.cc:454