WSL/SLF GitLab Repository

EnergyBalance.cc 7.53 KB
Newer Older
1
/***********************************************************************************/
2
/*  Copyright 2009-2015 WSL Institute for Snow and Avalanche Research    SLF-DAVOS      */
3
/***********************************************************************************/
4
5
/* This file is part of Alpine3D.
    Alpine3D is free software: you can redistribute it and/or modify
6
7
8
9
    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.

10
    Alpine3D is distributed in the hope that it will be useful,
11
12
13
14
15
    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
16
    along with Alpine3D.  If not, see <http://www.gnu.org/licenses/>.
17
*/
18
#include <alpine3d/ebalance/EnergyBalance.h>
19
20
#include <alpine3d/MPIControl.h>
#include <alpine3d/OMPControl.h>
21

22
23
24
using namespace mio;
using namespace std;

25
26
// FELIX: added pv_pts, pv_points
EnergyBalance::EnergyBalance(const unsigned int& i_nbworkers, const mio::Config& cfg_in, const mio::DEMObject &dem_in, const std::vector<std::vector<double> > &pv_pts)
27
              : snowpack(NULL), terrain_radiation(NULL), radfields(i_nbworkers), dem(dem_in), vecMeteo(),
28
                albedo(dem_in, 0.), direct_unshaded_horizontal(), direct(), diffuse(), reflected(),
Julien Esseiva's avatar
Julien Esseiva committed
29
                timer(), dimx(dem_in.getNx()), dimy(dem_in.getNy()), nbworkers(i_nbworkers), pv_points(pv_pts), PVP(nullptr), cfg(cfg_in)
30
31
{	

32
33
34
35
36
	MPIControl& instance = MPIControl::instance();

	size_t startx = 0, nx = dimx;
	instance.getArraySliceParams(dimx, startx, nx);

37
	#pragma omp parallel for schedule(static)
38
39
	for (size_t ii=0; ii<nbworkers; ii++) {
		size_t thread_startx, thread_nx;
40
		OMPControl::getArraySliceParams(nx, nbworkers, ii, thread_startx, thread_nx);
41
		const size_t offset = startx + thread_startx;
42

43
		#pragma omp critical(ebWorkers_status)
44
		std::cout << "[i] EnergyBalance worker " << ii << " on process " << instance.rank() << " will start at offset " << offset << " with nx " << thread_nx << "\n";
45
		radfields[ii] = new RadiationField(dem_in, offset, thread_nx);
46
	}
47

48
	if (instance.master())
49
		std::cout << "[i] EnergyBalance initialized a total of " << instance.size() << " process(es) with " << nbworkers << " worker(s) each\n";
50

51
52
53
54
55
56
57
	// FELIX
        if (cfg.keyExists("PVP", "Input"))
        {
            if(cfg.get("Terrain_Radiation", "EBalance")) PVP= new SolarPanel(cfg, dem, pv_points, radfields[0]);
        }


58
	// Every MPI process will have its own copy of terrain_radiation object with full DEM
59
	const bool enable_terrain_radiation = cfg.get("Terrain_Radiation", "EBalance");
60
	if (enable_terrain_radiation) {
61
		terrain_radiation = TerrainRadiationFactory::getAlgorithm(cfg, dem, nbworkers, radfields[0], PVP); 	// FELIX:  radfields[0]
62
		const std::string algo = terrain_radiation->algo;
63
64
		if (instance.master())
			std::cout << "[i] Using terrain radiation with model: " << algo << "\n";
65
	}
66
67
68
69
70
71
}

EnergyBalance::~EnergyBalance() {
	Destroy( );
}

72
73
74
75
76
77
EnergyBalance& EnergyBalance::operator=(const EnergyBalance& source) {
	if (this != &source) {
		snowpack = source.snowpack;
		terrain_radiation = source.terrain_radiation;
		radfields = source.radfields;
		dem = source.dem;
78
79
		vecMeteo = source.vecMeteo;
		albedo = source.albedo;
80
81
82
		direct = source.direct;
		diffuse = source.diffuse;
		reflected = source.reflected;
83
		direct_unshaded_horizontal = source.reflected;
84
85
86
87
88
89
90
91
		timer = source.timer;
		dimx = source.dimx;
		dimy = source.dimy;
		nbworkers = source.nbworkers;
	}
	return *this;
}

92
93
std::string EnergyBalance::getGridsRequirements() const
{
94
	return "TOP_ALB";
95
96
}

97
98
void EnergyBalance::Destroy()
{
99
100
101
102
103
104
105
106
107
	while (!radfields.empty()) {
		delete radfields.back();
		radfields.pop_back();
	}

	if (terrain_radiation) {
		delete terrain_radiation;
		terrain_radiation = NULL;
	}
Julien Esseiva's avatar
Julien Esseiva committed
108
109
110
111
	if (PVP) {
		delete PVP;
		PVP = nullptr;
	}
112
113
}

Thomas Egger's avatar
Thomas Egger committed
114
void EnergyBalance::setSnowPack(SnowpackInterface& mysnowpack)
115
116
117
118
{
	snowpack = &mysnowpack;
}

Thomas Egger's avatar
Thomas Egger committed
119
120
void EnergyBalance::setAlbedo(const mio::Grid2DObject& in_albedo)
{
121
	albedo = in_albedo;
122

123
	direct_unshaded_horizontal.resize(0, 0); //FELIX
124
125
	direct.resize(0, 0); //resetting these grids that are not valid anymore
	diffuse.resize(0, 0);
126
	reflected.resize(0, 0);
127
128
}

129
void EnergyBalance::setStations(const std::vector<mio::MeteoData>& in_vecMeteo)
Thomas Egger's avatar
Thomas Egger committed
130
{
131
	vecMeteo = in_vecMeteo;
132

133
	direct_unshaded_horizontal.resize(0, 0); //FELIX
134
135
	direct.resize(0, 0); //resetting these grids that are not valid anymore
	diffuse.resize(0, 0);
136
	reflected.resize(0, 0);
137
138
139
}

void EnergyBalance::setMeteo(const mio::Grid2DObject& in_ilwr,
Thomas Egger's avatar
Thomas Egger committed
140
141
                             const mio::Grid2DObject& in_ta, const mio::Grid2DObject& in_rh, const mio::Grid2DObject& in_p, const mio::Date timestamp)
{
142
	timer.restart();
143
144
	direct.resize(dimx, dimy);
	diffuse.resize(dimx, dimy);
145
	direct_unshaded_horizontal.resize(dimx, dimy);
146

147
	#pragma omp parallel for schedule(dynamic)
148
	for (size_t ii=0; ii<nbworkers; ii++) {
149
		radfields[ii]->setStations(vecMeteo, albedo); //calculate the parameters at the radiation stations
150
151
		size_t startx, nx;
		radfields[ii]->getBandOffsets(startx, nx);
152
153
154
155
		radfields[ii]->setMeteo(mio::Grid2DObject(in_ta, startx, 0, nx, dimy),
		                       mio::Grid2DObject(in_rh, startx, 0, nx, dimy),
		                       mio::Grid2DObject(in_p, startx, 0, nx, dimy),
		                       mio::Grid2DObject(albedo, startx, 0, nx, dimy));
156

157
158
		mio::Array2D<double> band_direct, band_diffuse, band_direct_unshaded_horizontal;
		radfields[ii]->getRadiation(band_direct, band_diffuse, band_direct_unshaded_horizontal);
159
160
		direct.fill(band_direct, startx, 0, nx, dimy);
		diffuse.fill(band_diffuse, startx, 0, nx, dimy);
161
		direct_unshaded_horizontal.fill(band_direct_unshaded_horizontal, startx, 0, nx, dimy);
162
163
164
	}
	MPIControl::instance().allreduce_sum(direct);
	MPIControl::instance().allreduce_sum(diffuse);
165
166
167
168
169
170
171
172
	MPIControl::instance().allreduce_sum(direct_unshaded_horizontal);


	// FELIX
	if (cfg.keyExists("PVP", "Input"))
	{
		PVP->setGridRadiation(albedo, direct, diffuse, direct_unshaded_horizontal);
	}
173
174

	if (terrain_radiation) {
175
		// note: parallelization has to take place inside the TerrainRadiationAlgorithm implementations
176
		terrain_radiation->setMeteo(albedo.grid2D, in_ta.grid2D, in_rh.grid2D, in_ilwr.grid2D);
177
		terrain_radiation->getRadiation(direct, diffuse, reflected, direct_unshaded_horizontal);
178
	}
179

Thomas Egger's avatar
Thomas Egger committed
180
	if (MPIControl::instance().master())
181
		cout << "[i] Ebalance simulation done for " << timestamp.toString(Date::ISO) << "\n";
182

183
	if (snowpack) {
184
185
		double solarAzimuth, solarElevation;
		radfields[0]->getPositionSun(solarAzimuth, solarElevation); //we need it only for handing over to snowpack
186

187
188
		mio::Array2D<double> ilwr = in_ilwr.grid2D;
		mio::Array2D<double> global = direct+diffuse; //otherwise the compiler does not match the types
189

190
		if (!reflected.empty()) global += reflected;
191

192
		timer.stop();
193
194
195
		try {
			snowpack->setRadiationComponents(global, ilwr, diffuse, solarElevation, timestamp); //this triggers Snowpack calculation
		} catch(std::exception& e) {
196
			std::cout << "[E] Exception in snowpack->setRadiationComponents()\n";
197
			cout << e.what() << endl;
198
			std::abort(); //force core dump
199
		}
200
201
202
203
	}
	timer.stop();
}

204
205
206
207
208
209
210
211
212
213
void EnergyBalance::setPVP(const mio::Date timestamp){
	
	if (cfg.keyExists("PVP", "Input")) PVP->setPVP(timestamp);
}

void EnergyBalance::writeSumPVP(const unsigned int max_steps){
	
	if (cfg.keyExists("PVP", "Input")) PVP->writeSumPVP(max_steps);
}

214
215
216
217
double EnergyBalance::getTiming() const
{
	return timer.getElapsed();
}