WSL/SLF GitLab Repository

Array3D.h 22.7 KB
Newer Older
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
/***********************************************************************************/
/*  Copyright 2009 WSL Institute for Snow and Avalanche Research    SLF-DAVOS      */
/***********************************************************************************/
/* This file is part of MeteoIO.
    MeteoIO is free software: you can redistribute it and/or modify
    it under the terms of the GNU Lesser General Public License as published by
    the Free Software Foundation, either version 3 of the License, or
    (at your option) any later version.

    MeteoIO is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    GNU Lesser General Public License for more details.

    You should have received a copy of the GNU Lesser General Public License
    along with MeteoIO.  If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef ARRAY3D_H
#define ARRAY3D_H

#include <meteoio/IOUtils.h>
#include <meteoio/IOExceptions.h>

#include <vector>
#include <limits>
#include <iostream>

#define NOSAFECHECKS

namespace mio {

template <class T> class Array3D;
template <class T> class Array3DProxy2;

/**
 * @class Array3DProxy
 * @brief The template class Array3DProxy is a helper class for the template class Array3D
38
 *        with the purpose of adding the [][] operator to Array3D
39
40
41
42
43
44
 *
 * @author Thomas Egger
 */
template <class T> class Array3DProxy {
 	public:
		friend class Array3D<T>;
45
46
		Array3DProxy2<T> operator[](const unsigned int& i_any) {
			return Array3DProxy2<T>(array3D, anx, i_any);
47
48
49
		}

 	private:
50
 		Array3DProxy(Array3D<T>& i_array3D, const unsigned int& i_anx) : array3D(i_array3D), anx(i_anx){}
51
52
53
54
55
56
57
58
59
60
61
62
63
64
		Array3D<T>& array3D;
		const unsigned int anx;
};

/**
 * @class Array3DProxy2
 * @brief The template class Array3DProxy2 is a helper class for the template class Array3D
 *        with the purpose of adding the [][][] operator to Array3D
 *
 * @author Thomas Egger
 */
template <class T> class Array3DProxy2 {
 	public:
		friend class Array3DProxy<T>;
65
66
		T& operator[](const unsigned int& i_anz) {
			return array3D(anx, any, i_anz);
67
68
69
		}

	private:
70
71
 		Array3DProxy2(Array3D<T>& i_array3D, const unsigned int& i_anx,
				    const unsigned int& i_any) : array3D(i_array3D), anx(i_anx), any(i_any){}
72
73
74
		Array3D<T>& array3D;
		const unsigned int anx;
		const unsigned int any;
75
};
76
77
78
79


/**
 * @class Array3D
80
 * @brief The template class Array3D is a 3D Array (Tensor) able to hold any type of object as datatype.
81
82
 * It relies on the Array3DProxy2 class to provide the [][][] operator (slower than the (i,j,k) call).
 * @ingroup data_str
83
84
85
86
87
88
89
90
91
 * @date  2009-07-19
 * @author Thomas Egger
 */
template<class T> class Array3D {
	public:
		Array3D();

		/**
		* A constructor that can be used to create an Array3D object that is contained in the
92
93
94
95
96
97
98
99
100
		* one passed as i_array3D argument. The resulting Array3D object is a by value copy of
		* a subvolume of the volume spanned by the i_array3D
		* @param i_array3D array containing to extract the values from
		* @param i_nx lower left corner cell X index
		* @param i_ny lower left corner cell Y index
		* @param i_nz lower left corner cell Z index
		* @param i_ncols number of columns of the new array
		* @param i_nrows number of rows of the new array
		* @param i_ndepth number of depths of the new array
101
		*/
102
103
104
		Array3D(const Array3D<T>& i_array3D,
		        const unsigned int& i_nx, const unsigned int& i_ny, const unsigned int& i_nz,
		        const unsigned int& i_ncols, const unsigned int& i_nrows, const unsigned int& i_ndepth);
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124

		/**
		* A constructor that creates an array of a given size
		* @param anx number of columns of the new array
		* @param any number of rows of the new array
		* @param anz number of rows of the new array
		*/
		Array3D(const unsigned int& anx, const unsigned int& any, const unsigned int& anz);

		/**
		* A constructor that creates an array filled with constant values
		* @param anx number of columns of the new array
		* @param any number of rows of the new array
		* @param anz number of depths of the new array
		* @param init initial value to fill the array with
		*/
		Array3D(const unsigned int& anx, const unsigned int& any, const unsigned int& anz, const T& init);

		/**
		* A method that can be used to create an Array3D object that is contained in the
125
126
127
128
129
130
131
132
133
		* one passed as i_array3D argument. The resulting Array3D object is a by value copy of
		* a subvolume of the volume spanned by the i_array3D
		* @param i_array3D array containing to extract the values from
		* @param i_nx lower left corner cell X index
		* @param i_ny lower left corner cell Y index
		* @param i_nz lower left corner cell Z index
		* @param i_ncols number of columns of the new array
		* @param i_nrows number of rows of the new array
		* @param i_ndepth number of depths of the new array
134
		*/
135
136
137
		void subset(const Array3D<T>& i_array3D,
		            const unsigned int& i_nx, const unsigned int& i_ny, const unsigned int& i_nz,
		            const unsigned int& i_ncols, const unsigned int& i_nrows, const unsigned int& i_ndepth);
138

139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
		/**
		* @brief A method that can be used to insert a subplane into an existing Array2D object
		* that is passed as i_array2D argument. This is exactly the opposite of the subset method
		* an can be used to rebuild an array from subsets.
		* @param i_array3D array containing to extract the values from
		* @param i_nx lower left corner cell X index
		* @param i_ny lower left corner cell Y index
		* @param i_nz lower left corner cell Z index
		* @param i_ncols number of columns of the new array
		* @param i_nrows number of rows of the new array
		* @param i_ndepth number of depths of the new array
		*/
		void fill(const Array3D<T>& i_array3D,
		          const unsigned int& i_nx, const unsigned int& i_ny, const unsigned int& i_nz,
		          const unsigned int& i_ncols, const unsigned int& i_nrows, const unsigned int& i_ndepth);

155
156
		void fill(const Array3D<T>& i_array3D, const unsigned int& i_nx, const unsigned int& i_ny, const unsigned int& i_nz);

157
158
		/**
		* @brief set how to process nodata values (ie: as nodata or as normal numbers)
159
160
		* @param i_keep_nodata true means that NODATA is interpreted as NODATA, false means that it is a normal number
		By default, arrays keep nodata.
161
		*/
162
163
164
165
166
167
168
		void setKeepNodata(const bool i_keep_nodata);

		/**
		* @brief get how to process nodata values (ie: as nodata or as normal numbers)
		* @return true means that NODATA is interpreted as NODATA, false means that it is a normal number
		*/
		bool getKeepNodata();
169

170
171
172
		void resize(const unsigned int& anx, const unsigned int& any, const unsigned int& anz);
		void resize(const unsigned int& anx, const unsigned int& any, const unsigned int& anz, const T& init);
		void size(unsigned int& anx, unsigned int& any, unsigned int& anz) const;
173
174
175
176
177
178
		void clear();

		/**
		* @brief returns the minimum value contained in the grid
		* @return minimum value
		*/
179
		T getMin() const;
180
181
182
183
		/**
		* @brief returns the maximum value contained in the grid
		* @return maximum value
		*/
184
		T getMax() const;
185
186
187
188
		/**
		* @brief returns the mean value contained in the grid
		* @return mean value
		*/
189
		T getMean() const;
190
		/**
191
		* @brief returns the number of points contained in the grid.
192
193
		* If setNodataHandling(IOUtils::RAW_NODATA), then the number of points is the size of the grid.
		* If setNodataHandling(IOUtils::PARSE_NODATA), then it is the number of non-nodata values in the grid
194
		* @return count
195
		*/
196
		size_t getCount() const;
197
198
199
200
		/**
		* @brief returns the grid of the absolute value of values contained in the grid
		* @return grid of abs(grid)
		*/
201
202
		const Array3D<T> getAbs() const;
		void abs();
203
204

		template<class P> friend std::ostream& operator<<(std::ostream& os, const Array3D<P>& array);
205

206
207
		T& operator ()(const unsigned int& i);
		const T operator ()(const unsigned int& i) const;
208
209
210
211
212
		T& operator ()(const unsigned int& x, const unsigned int& y, const unsigned int& z);
		const T operator ()(const unsigned int& x, const unsigned int& y, const unsigned int& z) const;
		Array3DProxy<T> operator[](const unsigned int& i);

		Array3D<T>& operator =(const Array3D<T>&);
213
		Array3D<T>& operator =(const T& value);
214

215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
		Array3D<T>& operator+=(const T& rhs);
		const Array3D<T> operator+(const T& rhs);
		Array3D<T>& operator+=(const Array3D<T>& rhs);
		const Array3D<T> operator+(const Array3D<T>& rhs);

		Array3D<T>& operator-=(const T& rhs);
		const Array3D<T> operator-(const T& rhs);
		Array3D<T>& operator-=(const Array3D<T>& rhs);
		const Array3D<T> operator-(const Array3D<T>& rhs);

		Array3D<T>& operator*=(const T& rhs);
		const Array3D<T> operator*(const T& rhs);
		Array3D<T>& operator*=(const Array3D<T>& rhs);
		const Array3D<T> operator*(const Array3D<T>& rhs);

		Array3D<T>& operator/=(const T& rhs);
		const Array3D<T> operator/(const T& rhs);
		Array3D<T>& operator/=(const Array3D<T>& rhs);
		const Array3D<T> operator/(const Array3D<T>& rhs);

	protected:
		std::vector<T> vecData; ///< The actual objects are stored in a one-dimensional vector
		unsigned int nx;
		unsigned int ny;
		unsigned int nz;
		unsigned int nxny; //nx times ny
241
		bool keep_nodata;
242
243
};

244
245
246
247
248
249
250
251
template<class T> T& Array3D<T>::operator()(const unsigned int& i) {
	return vecData[i];
}

template<class T> const T Array3D<T>::operator()(const unsigned int& i) const {
	return vecData[i];
}

252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
template<class T> T& Array3D<T>::operator()(const unsigned int& x, const unsigned int& y, const unsigned int& z) {
#ifndef NOSAFECHECKS
	if ((x >= nx) || (y >= ny) || (z >= nz)) {
		throw IndexOutOfBoundsException("", AT);
	}
#endif

	//ROW-MAJOR alignment of the vector: fully C-compatible memory layout
	return vecData[x + y*nx + z*nxny];
}

template<class T> const T Array3D<T>::operator()(const unsigned int& x, const unsigned int& y, const unsigned int& z) const {
#ifndef NOSAFECHECKS
	if ((x >= nx) || (y >= ny) || (z >= nz)) {
		throw IndexOutOfBoundsException("", AT);
	}
#endif
	return vecData[x + y*nx + z*nxny];
}

template<class T> Array3DProxy<T> Array3D<T>::operator[](const unsigned int& i) {
273
	return Array3DProxy<T>(*this, i);
274
275
276
277
278
}


template<class T> Array3D<T>::Array3D() {
	nx = ny = nz = nxny = 0;
279
	keep_nodata = true;
280
281
}

282
283
284
template<class T> Array3D<T>::Array3D(const Array3D<T>& i_array3D,
                                      const unsigned int& i_nx, const unsigned int& i_ny, const unsigned int& i_nz,
                                      const unsigned int& i_ncols, const unsigned int& i_nrows, const unsigned int& i_ndepth)
285
{
286
	subset(i_array3D, i_nx, i_ny, i_nz, i_ncols, i_nrows, i_ndepth);
287
288
}

289
290
291
template<class T> void Array3D<T>::subset(const Array3D<T>& i_array3D,
                                     const unsigned int& i_nx, const unsigned int& i_ny, const unsigned int& i_nz,
                                     const unsigned int& i_ncols, const unsigned int& i_nrows, const unsigned int& i_ndepth)
292
{
293

294
	if (((i_nx+i_ncols) > i_array3D.nx) || ((i_ny+i_nrows) > i_array3D.ny) || ((i_nz+i_ndepth) > i_array3D.nz))
295
		throw IndexOutOfBoundsException("Trying to cut an array to a size bigger than its original size!", AT);
296

297
	if ((i_ncols == 0) || (i_nrows == 0) || (i_ndepth == 0)) //the space has to make sense
298
		throw IndexOutOfBoundsException("Copying an array into a null sized array!", AT);
299

300
	resize(i_ncols, i_nrows, i_ndepth); //create new Array3D object
301
	if(i_array3D.keep_nodata==false)
302
		setKeepNodata(false);
303
304

	//Copy by value subspace
305
	for (unsigned int ii=0; ii<nz; ii++) {
306
307
308
		for (unsigned int jj=0; jj<ny; jj++) {
			for (unsigned int kk=0; kk<nx; kk++) {
				//Running through the vector in order of memory alignment
309
				operator()(kk,jj,ii) = i_array3D(i_nx+kk, i_ny+jj, i_nz+ii);
310
311
312
313
314
			}
		}
	}
}

315
316
317
318
319
320
321
template<class T> void Array3D<T>::fill(const Array3D<T>& i_array3D, const unsigned int& i_nx, const unsigned int& i_ny, const unsigned int& i_nz)
{
	unsigned int i_ncols, i_nrows, i_ndepth;
	i_array3D.size(i_ncols, i_nrows, i_ndepth);
	fill(i_array3D, i_nx, i_ny, i_nz, i_ncols, i_nrows, i_ndepth);
}

322
323
324
325
326
327
328
329
330
331
332
template<class T> void Array3D<T>::fill(const Array3D<T>& i_array3D,
                                     const unsigned int& i_nx, const unsigned int& i_ny, const unsigned int& i_nz,
                                     const unsigned int& i_ncols, const unsigned int& i_nrows, const unsigned int& i_ndepth)
{

	if (((i_nx+i_ncols) > i_array3D.nx) || ((i_ny+i_nrows) > i_array3D.ny) || ((i_nz+i_ndepth) > i_array3D.nz))
		throw IndexOutOfBoundsException("Trying to insert an array whose size is too big!", AT);

	if ((i_ncols == 0) || (i_nrows == 0) || (i_ndepth == 0)) //the space has to make sense
		throw IndexOutOfBoundsException("Copying a null sized array!", AT);

333
	if(i_array3D.keep_nodata==false)
334
		setKeepNodata(false);
335

336
337
338
339
340
341
342
343
344
345
346
347
348
349
	//Copy by value subspace
	for (unsigned int ii=i_nz; ii<(i_nz+i_ndepth); ii++) {
		for (unsigned int jj=i_ny; jj<(i_ny+i_nrows); jj++) {
			for (unsigned int kk=i_nx; kk<(i_nx+i_ncols); kk++) {
				const unsigned int ix = kk-i_nx;
				const unsigned int iy = jj-i_ny;
				const unsigned int iz = ii-i_nz;
				operator()(kk,jj,ii) = i_array3D(ix, iy, iz);
			}
		}
	}
}


350
351
template<class T> Array3D<T>::Array3D(const unsigned int& anx, const unsigned int& any, const unsigned int& anz) {
	resize(anx, any, anz);
352
	keep_nodata = true;
353
354
}

355
356
template<class T> Array3D<T>::Array3D(const unsigned int& anx, const unsigned int& any, const unsigned int& anz, const T& init) {
	resize(anx, any, anz, init);
357
	keep_nodata = true;
358
359
}

360
361
362
363
364
365
template<class T> void Array3D<T>::setKeepNodata(const bool i_keep_nodata) {
	keep_nodata = i_keep_nodata;
}

template<class T> bool Array3D<T>::getKeepNodata() {
	return keep_nodata;
366
367
}

368
template<class T> void Array3D<T>::resize(const unsigned int& anx, const unsigned int& any, const unsigned int& anz) {
369
370
371
372
373
374
	clear();  //we won't be able to "rescue" old values, so we reset the whole vector
	vecData.resize(anx*any*anz);
	nx = anx;
	ny = any;
	nz = anz;
	nxny = nx*ny;
375
376
}

377
378
template<class T> void Array3D<T>::resize(const unsigned int& anx, const unsigned int& any, const unsigned int& anz, const T& init) {
	resize(anx, any, anz);
379
	std::fill(vecData.begin(), vecData.end(), init);
380
381
}

382
383
384
385
template<class T> void Array3D<T>::size(unsigned int& anx, unsigned int& any, unsigned int& anz) const {
	anx=nx;
	any=ny;
	anz=nz;
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
}

template<class T> void Array3D<T>::clear() {
	vecData.clear();
	nx = ny = nz = nxny = 0;
}

template<class T> std::ostream& operator<<(std::ostream& os, const Array3D<T>& array) {
	os << "<array3d>\n";
	for (unsigned int kk=0; kk<array.nz; kk++) {
		os << "depth[" << kk << "]\n";
		for(unsigned int ii=0; ii<array.nx; ii++) {
			for (unsigned int jj=0; jj<array.ny; jj++) {
				os << array(ii,jj,kk) << " ";
			}
			os << "\n";
		}
	}
	os << "</array3d>\n";
	return os;
}

408
template<class T> T Array3D<T>::getMin() const {
409
410

	T min = std::numeric_limits<T>::max();
411
	const unsigned int nxyz = ny*nx*nz;
412

413
	if(keep_nodata==false) {
414
415
416
		for (unsigned int jj=0; jj<nxyz; jj++) {
			const T val = operator()(jj);
			if(val<min) min=val;
417
418
		}
		return min;
419
	} else {
420
421
422
		for (unsigned int jj=0; jj<nxyz; jj++) {
			const T val = operator()(jj);
			if(val!=IOUtils::nodata && val<min) min=val;
423
424
425
426
427
428
		}
		if(min!=std::numeric_limits<T>::max()) return min;
		else return (T)IOUtils::nodata;
	}
}

429
template<class T> T Array3D<T>::getMax() const {
430
431

	T max = -std::numeric_limits<T>::max();
432
	const unsigned int nxyz = ny*nx*nz;
433

434
	if(keep_nodata==false) {
435
436
437
		for (unsigned int jj=0; jj<nxyz; jj++) {
			const T val = operator()(jj);
			if(val>max) max=val;
438
439
		}
		return max;
440
	} else {
441
442
443
		for (unsigned int jj=0; jj<nxyz; jj++) {
			const T val = operator()(jj);
			if(val!=IOUtils::nodata && val>max) max=val;
444
445
446
447
448
449
		}
		if(max!=-std::numeric_limits<T>::max()) return max;
		else return (T)IOUtils::nodata;
	}
}

450
template<class T> T Array3D<T>::getMean() const {
451
452

	T mean = 0;
453
	const unsigned int nxyz = nx*ny*nz;
454

455
	if(keep_nodata==false) {
456
457
458
		for (unsigned int jj=0; jj<nxyz; jj++) {
			const T val = operator()(jj);
			mean += val;
459
		}
460
		if(nxyz>0) return mean/(T)(nxyz);
461
		else return (T)0;
462
	} else {
463
		unsigned int count = 0;
464
465
466
467
468
		for (unsigned int jj=0; jj<nxyz; jj++) {
			const T val = operator()(jj);
			if(val!=IOUtils::nodata) {
				mean += val;
				count++;
469
470
471
472
473
474
475
			}
		}
		if(count>0) return mean/(T)(count);
		else return (T)IOUtils::nodata;
	}
}

476
template<class T> size_t Array3D<T>::getCount() const
477
{
478
479
	const unsigned int nxyz = nx*ny*nz;

480
	if(keep_nodata==false) {
481
		return (size_t)nxyz;
482
	} else {
483
		size_t count = 0;
484
		for (unsigned int ii=0; ii<nxyz; ii++) {
485
			if(vecData[ii]!=IOUtils::nodata) count++;
486
		}
487
		return count;
488
489
490
	}
}

491
template<class T> void Array3D<T>::abs() {
492
493
	if(std::numeric_limits<T>::is_signed) {
		const unsigned int nxyz = nx*ny*nz;
494
		if(keep_nodata==false) {
495
496
497
498
			for (unsigned int ii=0; ii<nxyz; ii++) {
				T& val = operator()(ii);
				if(val<0) val=-val;
			}
499
		} else {
500
501
502
503
504
505
506
507
508
			for (unsigned int ii=0; ii<nxyz; ii++) {
				T& val = operator()(ii);
				if(val<0 && val!=IOUtils::nodata) val=-val;
			}
		}
	}
}


509
template<class T> const Array3D<T> Array3D<T>::getAbs() const {
510
	Array3D<T> result = *this; //make a copy
511
	result.abs(); //already implemented
512
513
514
515

	return result;
}

516
517
518
//arithmetic operators
template<class T> Array3D<T>& Array3D<T>::operator=(const Array3D<T>& source) {
	if(this != &source) {
519
		keep_nodata = source.keep_nodata;
520
521
522
523
524
525
526
527
528
		nx = source.nx;
		ny = source.ny;
		nz = source.nz;
		nxny = source.nxny;
		vecData = source.vecData;
	}
	return *this;
}

529
530
531
532
533
template<class T> Array3D<T>& Array3D<T>::operator=(const T& value) {
	std::fill(vecData.begin(), vecData.end(), value);
	return *this;
}

534
535
536
537
538
539
540
template<class T> Array3D<T>& Array3D<T>::operator+=(const Array3D<T>& rhs)
{
	//They have to have equal size
	if ((rhs.nx != nx) || (rhs.ny != ny) || (rhs.nz != nz))
		throw IOException("Trying to add two Array3D objects with different dimensions", AT);

	//Add to every single member of the Array3D<T>
541
542
543
544
545
546
547
548
549
550
551
	const unsigned int nxyz = nx*ny*nz;
	if(keep_nodata==false) {
		for (unsigned int jj=0; jj<nxyz; jj++) {
			operator()(jj) += rhs(jj);
		}
	} else {
		for (unsigned int jj=0; jj<nxyz; jj++) {
			if(operator()(jj)==IOUtils::nodata || rhs(jj)==IOUtils::nodata)
				operator()(jj) = IOUtils::nodata;
			else
				operator()(jj) += rhs(jj);
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
		}
	}

	return *this;
}

template<class T> const Array3D<T> Array3D<T>::operator+(const Array3D<T>& rhs)
{
	Array3D<T> result = *this; //make a copy
	result += rhs; //already implemented

	return result;
}

template<class T> Array3D<T>& Array3D<T>::operator+=(const T& rhs)
{
	//Add to every single member of the Array3D<T>
569
570
571
572
573
574
575
576
577
	const unsigned int nxyz = nx*ny*nz;
	if(keep_nodata==false) {
		for (unsigned int jj=0; jj<nxyz; jj++) {
			operator()(jj) += rhs;
		}
	} else {
		for (unsigned int jj=0; jj<nxyz; jj++) {
			if(operator()(jj)!=IOUtils::nodata)
				operator()(jj) += rhs;
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
		}
	}

	return *this;
}

template<class T> const Array3D<T> Array3D<T>::operator+(const T& rhs)
{
	Array3D<T> result = *this;
	result += rhs; //already implemented

	return result;
}

template<class T> Array3D<T>& Array3D<T>::operator-=(const Array3D<T>& rhs)
{
	//They have to have equal size
	if ((rhs.nx != nx) || (rhs.ny != ny) || (rhs.nz != nz))
		throw IOException("Trying to substract two Array3D objects with different dimensions", AT);

	//Substract to every single member of the Array3D<T>
599
600
601
602
603
604
605
606
607
608
609
	const unsigned int nxyz = nx*ny*nz;
	if(keep_nodata==false) {
		for (unsigned int jj=0; jj<nxyz; jj++) {
			operator()(jj) -= rhs(jj);
		}
	} else {
		for (unsigned int jj=0; jj<nxyz; jj++) {
			if(operator()(jj)==IOUtils::nodata || rhs(jj)==IOUtils::nodata)
				operator()(jj) = IOUtils::nodata;
			else
				operator()(jj) -= rhs(jj);
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
		}
	}

	return *this;
}

template<class T> const Array3D<T> Array3D<T>::operator-(const Array3D<T>& rhs)
{
	Array3D<T> result = *this; //make a copy
	result -= rhs; //already implemented

	return result;
}

template<class T> Array3D<T>& Array3D<T>::operator-=(const T& rhs)
{
	//Substract to every single member of the Array3D<T>
627
628
629
630
631
632
633
634
635
	const unsigned int nxyz = nx*ny*nz;
	if(keep_nodata==false) {
		for (unsigned int jj=0; jj<nxyz; jj++) {
			operator()(jj) -= rhs;
		}
	} else {
		for (unsigned int jj=0; jj<nxyz; jj++) {
			if(operator()(jj)!=IOUtils::nodata)
				operator()(jj) -= rhs;
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
		}
	}

	return *this;
}

template<class T> const Array3D<T> Array3D<T>::operator-(const T& rhs)
{
	Array3D<T> result = *this;
	result -= rhs; //already implemented

	return result;
}

template<class T> Array3D<T>& Array3D<T>::operator*=(const Array3D<T>& rhs)
{
	//They have to have equal size
	if ((rhs.nx != nx) || (rhs.ny != ny) || (rhs.nz != nz))
		throw IOException("Trying to multiply two Array3D objects with different dimensions", AT);

	//Multiply every single member of the Array3D<T>
657
658
659
660
661
662
663
664
665
666
667
	const unsigned int nxyz = nx*ny*nz;
	if(keep_nodata==false) {
		for (unsigned int jj=0; jj<nxyz; jj++) {
			operator()(jj) *= rhs(jj);
		}
	} else {
		for (unsigned int jj=0; jj<nxyz; jj++) {
			if(operator()(jj)==IOUtils::nodata || rhs(jj)==IOUtils::nodata)
				operator()(jj) = IOUtils::nodata;
			else
				operator()(jj) *= rhs(jj);
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
		}
	}

	return *this;
}

template<class T> const Array3D<T> Array3D<T>::operator*(const Array3D<T>& rhs)
{
	Array3D<T> result = *this; //make a copy
	result *= rhs; //already implemented

	return result;
}

template<class T> Array3D<T>& Array3D<T>::operator*=(const T& rhs)
{
	//Multiply every single member of the Array3D<T>
685
686
687
688
689
690
691
692
693
	const unsigned int nxyz = nx*ny*nz;
	if(keep_nodata==false) {
		for (unsigned int jj=0; jj<nxyz; jj++) {
			operator()(jj) *= rhs;
		}
	} else {
		for (unsigned int jj=0; jj<nxyz; jj++) {
			if(operator()(jj)!=IOUtils::nodata)
				operator()(jj) *= rhs;
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
		}
	}

	return *this;
}

template<class T> const Array3D<T> Array3D<T>::operator*(const T& rhs)
{
	Array3D<T> result = *this;
	result *= rhs; //already implemented

	return result;
}

template<class T> Array3D<T>& Array3D<T>::operator/=(const Array3D<T>& rhs)
{
	//They have to have equal size
	if ((rhs.nx != nx) || (rhs.ny != ny) || (rhs.nz != nz))
		throw IOException("Trying to divide two Array3D objects with different dimensions", AT);

	//Divide every single member of the Array3D<T>
715
716
717
718
719
720
721
722
723
724
725
	const unsigned int nxyz = nx*ny*nz;
	if(keep_nodata==false) {
		for (unsigned int jj=0; jj<nxyz; jj++) {
			operator()(jj) /= rhs(jj);
		}
	} else {
		for (unsigned int jj=0; jj<nxyz; jj++) {
			if(operator()(jj)==IOUtils::nodata || rhs(jj)==IOUtils::nodata)
				operator()(jj) = IOUtils::nodata;
			else
				operator()(jj) /= rhs(jj);
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
		}
	}

	return *this;
}

template<class T> const Array3D<T> Array3D<T>::operator/(const Array3D<T>& rhs)
{
	Array3D<T> result = *this; //make a copy
	result /= rhs; //already implemented

	return result;
}

template<class T> Array3D<T>& Array3D<T>::operator/=(const T& rhs)
{
	//Divide every single member of the Array3D<T>
743
744
745
746
747
748
749
750
751
	const unsigned int nxyz = nx*ny*nz;
	if(keep_nodata==false) {
		for (unsigned int jj=0; jj<nxyz; jj++) {
			operator()(jj) /= rhs;
		}
	} else {
		for (unsigned int jj=0; jj<nxyz; jj++) {
			if(operator()(jj)!=IOUtils::nodata)
				operator()(jj) /= rhs;
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
		}
	}

	return *this;
}

template<class T> const Array3D<T> Array3D<T>::operator/(const T& rhs)
{
	Array3D<T> result = *this;
	result /= rhs; //already implemented

	return result;
}

} //end namespace mio

#endif