Rsun Main
Rsun Main
r.sun: This program was written by Jaro Hofierka in Summer 1993 and
re-engineered in 1996-1999. In cooperation with Marcel Suri and Thomas Huld
from JRC in Ispra a new version of r.sun was prepared using ESRA solar
radiation formulas.
See manual pages for details.
(C) 2002 Copyright Jaro Hofierka, Gresaka 22, 085 01 Bardejov, Slovakia,
and GeoModel, s.r.o., Bratislava, Slovakia
email: [email protected],[email protected],
[email protected] [email protected]
(c) 2003-2013 by The GRASS Development Team
******************************************************************************/
/*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
*
* This program 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 General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the
* Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
#if defined(_OPENMP)
#include <omp.h>
#endif
#include <stdio.h>
#include <stdlib.h>
#include <math.h>
#ifdef USE_OPENCL
#ifdef __APPLE__
#include <OpenCL/opencl.h>
#else
#include <CL/cl.h>
#endif
#endif
#include <grass/gis.h>
#include <grass/raster.h>
#include <grass/gmath.h>
#include <grass/gprojects.h>
#include <grass/glocale.h>
#include "sunradstruct.h"
#include "local_proto.h"
#include "rsunglobals.h"
/* default values */
#define NUM_PARTITIONS "1"
#define SKIP "1"
#define BIG 1.e20
#define LINKE "3.0"
#define SLOPE "0.0"
#define ASPECT "270"
#define ALB "0.2"
#define STEP "0.5"
#define BSKY 1.0
#define DSKY 1.0
#define DIST "1.0"
size_t decimals;
char *str_step;
/*
* double startTime, endTime;
*/
double xmin, xmax, ymin, ymax;
double declin, step, dist;
double linke_max = 0., linke_min = 100., albedo_max = 0., albedo_min = 1.0,
lat_max = -90., lat_min = 90.;
double offsetx = 0.5, offsety = 0.5;
char *ttime;
/*
* double slope;
*/
double o_orig, z1;
/*
* double lum_C11, lum_C13, lum_C22, lum_C31, lum_C33;
* double sinSolarAltitude; */
/*
* double lum_C31_l, lum_C33_l;
*/
double beam_e, diff_e, refl_e, rr, insol_t;
double cbh, cdh;
double TOLER;
int threads;
struct {
struct Flag *noshade, *saveMemory;
} flag;
G_gisinit(argv[0]);
module = G_define_module();
G_add_keyword(_("raster"));
G_add_keyword(_("solar"));
G_add_keyword(_("sun energy"));
G_add_keyword(_("shadow"));
G_add_keyword(_("parallel"));
module->label = _("Solar irradiance and irradiation model.");
module->description = _(
"Computes direct (beam), diffuse and reflected solar irradiation "
"raster "
"maps for given day, latitude, surface and atmospheric conditions. "
"Solar "
"parameters (e.g. sunrise, sunset times, declination, extraterrestrial "
"irradiance, daylight length) are saved in the map history file. "
"Alternatively, a local time can be specified to compute solar "
"incidence angle and/or irradiance raster maps. The shadowing effect "
"of "
"the topography is optionally incorporated.");
parm.elevin = G_define_option();
parm.elevin->key = "elevation";
parm.elevin->type = TYPE_STRING;
parm.elevin->required = YES;
parm.elevin->gisprompt = "old,cell,raster";
parm.elevin->description =
_("Name of the input elevation raster map [meters]");
parm.elevin->guisection = _("Input");
parm.aspin = G_define_option();
parm.aspin->key = "aspect";
parm.aspin->type = TYPE_STRING;
parm.aspin->required = NO;
parm.aspin->gisprompt = "old,cell,raster";
parm.aspin->description =
_("Name of the input aspect map (terrain aspect or azimuth of the "
"solar panel) [decimal degrees]");
parm.aspin->guisection = _("Input");
parm.aspect = G_define_option();
parm.aspect->key = "aspect_value";
parm.aspect->type = TYPE_DOUBLE;
parm.aspect->answer = ASPECT;
parm.aspect->required = NO;
parm.aspect->description =
_("A single value of the orientation (aspect), 270 is south");
parm.aspect->guisection = _("Input");
parm.slopein = G_define_option();
parm.slopein->key = "slope";
parm.slopein->type = TYPE_STRING;
parm.slopein->required = NO;
parm.slopein->gisprompt = "old,cell,raster";
parm.slopein->description =
_("Name of the input slope raster map (terrain slope or solar panel "
"inclination) [decimal degrees]");
parm.slopein->guisection = _("Input");
parm.slope = G_define_option();
parm.slope->key = "slope_value";
parm.slope->type = TYPE_DOUBLE;
parm.slope->answer = SLOPE;
parm.slope->required = NO;
parm.slope->description = _("A single value of inclination (slope)");
parm.slope->guisection = _("Input");
parm.linkein = G_define_option();
parm.linkein->key = "linke";
parm.linkein->type = TYPE_STRING;
parm.linkein->required = NO;
parm.linkein->gisprompt = "old,cell,raster";
parm.linkein->description = _("Name of the Linke atmospheric turbidity "
"coefficient input raster map [-]");
parm.linkein->guisection = _("Input");
parm.lin = G_define_option();
parm.lin->key = "linke_value";
parm.lin->type = TYPE_DOUBLE;
parm.lin->answer = LINKE;
parm.lin->required = NO;
parm.lin->description =
_("A single value of the Linke atmospheric turbidity coefficient [-]");
parm.lin->guisection = _("Input");
parm.albedo = G_define_option();
parm.albedo->key = "albedo";
parm.albedo->type = TYPE_STRING;
parm.albedo->required = NO;
parm.albedo->gisprompt = "old,cell,raster";
parm.albedo->description =
_("Name of the ground albedo coefficient input raster map [-]");
parm.albedo->guisection = _("Input");
parm.alb = G_define_option();
parm.alb->key = "albedo_value";
parm.alb->type = TYPE_DOUBLE;
parm.alb->answer = ALB;
parm.alb->required = NO;
parm.alb->description =
_("A single value of the ground albedo coefficient [-]");
parm.alb->guisection = _("Input");
parm.latin = G_define_option();
parm.latin->key = "lat";
parm.latin->type = TYPE_STRING;
parm.latin->required = NO;
parm.latin->gisprompt = "old,cell,raster";
parm.latin->description =
_("Name of input raster map containing latitudes [decimal degrees]");
parm.latin->guisection = _("Input");
parm.longin = G_define_option();
parm.longin->key = "long";
parm.longin->type = TYPE_STRING;
parm.longin->required = NO;
parm.longin->gisprompt = "old,cell,raster";
parm.longin->description =
_("Name of input raster map containing longitudes [decimal degrees]");
parm.longin->guisection = _("Input");
parm.coefbh = G_define_option();
parm.coefbh->key = "coeff_bh";
parm.coefbh->type = TYPE_STRING;
parm.coefbh->required = NO;
parm.coefbh->gisprompt = "old,cell,raster";
parm.coefbh->description = _("Name of real-sky beam radiation coefficient "
"(thick cloud) input raster map [0-1]");
parm.coefbh->guisection = _("Input");
parm.coefdh = G_define_option();
parm.coefdh->key = "coeff_dh";
parm.coefdh->type = TYPE_STRING;
parm.coefdh->required = NO;
parm.coefdh->gisprompt = "old,cell,raster";
parm.coefdh->description = _("Name of real-sky diffuse radiation "
"coefficient (haze) input raster map [0-1]");
parm.coefdh->guisection = _("Input");
parm.horizon = G_define_standard_option(G_OPT_R_BASENAME_INPUT);
parm.horizon->key = "horizon_basename";
parm.horizon->required = NO;
parm.horizon->gisprompt = "old,cell,raster";
parm.horizon->description = _("The horizon information input map basename");
parm.horizon->guisection = _("Input");
parm.horizonstep = G_define_option();
parm.horizonstep->key = "horizon_step";
parm.horizonstep->type = TYPE_DOUBLE;
parm.horizonstep->required = NO;
parm.horizonstep->description =
_("Angle step size for multidirectional horizon [degrees]");
parm.horizonstep->guisection = _("Input");
parm.incidout = G_define_option();
parm.incidout->key = "incidout";
parm.incidout->type = TYPE_STRING;
parm.incidout->required = NO;
parm.incidout->gisprompt = "new,cell,raster";
parm.incidout->description =
_("Output incidence angle raster map (mode 1 only)");
parm.incidout->guisection = _("Output");
parm.beam_rad = G_define_option();
parm.beam_rad->key = "beam_rad";
parm.beam_rad->type = TYPE_STRING;
parm.beam_rad->required = NO;
parm.beam_rad->gisprompt = "new,cell,raster";
parm.beam_rad->description =
_("Output beam irradiance [W.m-2] (mode 1) or irradiation raster map "
"[Wh.m-2.day-1] (mode 2)");
parm.beam_rad->guisection = _("Output");
parm.diff_rad = G_define_option();
parm.diff_rad->key = "diff_rad";
parm.diff_rad->type = TYPE_STRING;
parm.diff_rad->required = NO;
parm.diff_rad->gisprompt = "new,cell,raster";
parm.diff_rad->description =
_("Output diffuse irradiance [W.m-2] (mode 1) or irradiation raster "
"map [Wh.m-2.day-1] (mode 2)");
parm.diff_rad->guisection = _("Output");
parm.refl_rad = G_define_option();
parm.refl_rad->key = "refl_rad";
parm.refl_rad->type = TYPE_STRING;
parm.refl_rad->required = NO;
parm.refl_rad->gisprompt = "new,cell,raster";
parm.refl_rad->description =
_("Output ground reflected irradiance [W.m-2] (mode 1) or irradiation "
"raster map [Wh.m-2.day-1] (mode 2)");
parm.refl_rad->guisection = _("Output");
parm.glob_rad = G_define_option();
parm.glob_rad->key = "glob_rad";
parm.glob_rad->type = TYPE_STRING;
parm.glob_rad->required = NO;
parm.glob_rad->gisprompt = "new,cell,raster";
parm.glob_rad->description =
_("Output global (total) irradiance/irradiation [W.m-2] (mode 1) or "
"irradiance/irradiation raster map [Wh.m-2.day-1] (mode 2)");
parm.glob_rad->guisection = _("Output");
parm.insol_time = G_define_option();
parm.insol_time->key = "insol_time";
parm.insol_time->type = TYPE_STRING;
parm.insol_time->required = NO;
parm.insol_time->gisprompt = "new,cell,raster";
parm.insol_time->description =
_("Output insolation time raster map [h] (mode 2 only)");
parm.insol_time->guisection = _("Output");
parm.day = G_define_option();
parm.day->key = "day";
parm.day->type = TYPE_INTEGER;
parm.day->required = YES;
parm.day->description = _("No. of day of the year (1-365)");
parm.day->options = "1-365";
parm.day->guisection = _("Time");
parm.step = G_define_option();
parm.step->key = "step";
parm.step->type = TYPE_DOUBLE;
parm.step->answer = STEP;
parm.step->required = NO;
parm.step->description =
_("Time step when computing all-day radiation sums [decimal hours]");
parm.step->guisection = _("Time");
parm.declin = G_define_option();
parm.declin->key = "declination";
parm.declin->type = TYPE_DOUBLE;
parm.declin->required = NO;
parm.declin->description = _("Declination value (overriding the internally "
"computed value) [radians]");
parm.solar_cnst = G_define_option();
parm.solar_cnst->key = "solar_constant";
parm.solar_cnst->type = TYPE_DOUBLE;
parm.solar_cnst->required = NO;
parm.solar_cnst->answer = "1367";
parm.solar_cnst->description = _("Solar constant [W/m^2]");
parm.ltime = G_define_option();
parm.ltime->key = "time";
parm.ltime->type = TYPE_DOUBLE;
/* parm.ltime->answer = TIME; */
parm.ltime->required = NO;
parm.ltime->description =
_("Local (solar) time (to be set for mode 1 only) [decimal hours]");
parm.ltime->options = "0-24";
parm.ltime->guisection = _("Time");
parm.threads = G_define_option();
parm.threads->key = "nprocs";
parm.threads->type = TYPE_INTEGER;
parm.threads->answer = "1";
parm.threads->options = "1-1000";
parm.threads->required = NO;
parm.threads->description =
_("Number of threads which will be used for parallel computing");
/*
* parm.startTime = G_define_option();
* parm.startTime->key = "start_time";
* parm.startTime->type = TYPE_DOUBLE;
* parm.startTime->required = NO;
* parm.startTime->description = _("Starting time for calculating results
* for several different times.");
*
* parm.endTime = G_define_option();
* parm.endTime->key = "end_time";
* parm.endTime->type = TYPE_DOUBLE;
* parm.endTime->required = NO;
* parm.endTime->description = _("End time for calculating results for
* several different times.)";
*/
parm.dist = G_define_option();
parm.dist->key = "distance_step";
parm.dist->type = TYPE_DOUBLE;
parm.dist->answer = DIST;
parm.dist->required = NO;
parm.dist->description = _("Sampling distance step coefficient (0.5-1.5)");
parm.numPartitions = G_define_option();
parm.numPartitions->key = "npartitions";
parm.numPartitions->type = TYPE_INTEGER;
parm.numPartitions->answer = NUM_PARTITIONS;
parm.numPartitions->required = NO;
parm.numPartitions->description =
_("Read the input files in this number of chunks");
parm.civilTime = G_define_option();
parm.civilTime->key = "civil_time";
parm.civilTime->type = TYPE_DOUBLE;
parm.civilTime->required = NO;
parm.civilTime->description =
_("Civil time zone value, if none, the time will be local solar time");
parm.civilTime->guisection = _("Time");
flag.noshade = G_define_flag();
flag.noshade->key = 'p';
flag.noshade->description =
_("Do not incorporate the shadowing effect of terrain");
flag.saveMemory = G_define_flag();
flag.saveMemory->key = 'm';
flag.saveMemory->description =
_("Use the low-memory version of the program");
if (G_parser(argc, argv))
exit(EXIT_FAILURE);
G_get_set_window(&cellhd);
gridGeom.stepx = cellhd.ew_res;
gridGeom.stepy = cellhd.ns_res;
invstepx = 1. / gridGeom.stepx;
invstepy = 1. / gridGeom.stepy;
n /*n_cols */ = cellhd.cols;
m /*n_rows */ = cellhd.rows;
xmin = cellhd.west;
ymin = cellhd.south;
xmax = cellhd.east;
ymax = cellhd.north;
gridGeom.deltx = fabs(cellhd.east - cellhd.west);
gridGeom.delty = fabs(cellhd.north - cellhd.south);
setUseShadow(!flag.noshade->answer);
saveMemory = flag.saveMemory->answer;
elevin = parm.elevin->answer;
aspin = parm.aspin->answer;
slopein = parm.slopein->answer;
linkein = parm.linkein->answer;
albedo = parm.albedo->answer;
latin = parm.latin->answer;
longin = parm.longin->answer;
civiltime = parm.civilTime->answer;
if (civiltime != NULL) {
setUseCivilTime(TRUE);
if (longin == NULL)
G_fatal_error(
_("You must give the longitude raster if you use civil time"));
coefbh = parm.coefbh->answer;
coefdh = parm.coefdh->answer;
incidout = parm.incidout->answer;
horizon = parm.horizon->answer;
setUseHorizonData(horizon != NULL);
beam_rad = parm.beam_rad->answer;
insol_time = parm.insol_time->answer;
diff_rad = parm.diff_rad->answer;
refl_rad = parm.refl_rad->answer;
glob_rad = parm.glob_rad->answer;
if (parm.horizonstep->answer != NULL) {
if (sscanf(parm.horizonstep->answer, "%lf", &horizonStep) != 1)
G_fatal_error(_("Error reading horizon step size"));
str_step = parm.horizonstep->answer;
if (horizonStep > 0.)
setHorizonInterval(deg2rad * horizonStep);
else
G_fatal_error(_("The horizon step size must be greater than 0."));
}
else if (useHorizonData()) {
G_fatal_error(_("If you use the horizon option you must also set the "
"'horizonstep' parameter."));
}
ttime = parm.ltime->answer;
if (parm.ltime->answer != NULL) {
if (insol_time != NULL)
G_fatal_error(_("Time and insol_time are incompatible options"));
/*
* if (parm.startTime->answer != NULL) sscanf(parm.startTime->answer, "%lf",
* &startTime); if (parm.endTime->answer != NULL)
* sscanf(parm.endTime->answer, "%lf", &endTime);
*
* if((parm.startTime->answer != NULL) ||(parm.endTime->answer != NULL))
* {
*/
/* The start and end times should only be defined if the single
* time is not defined, and if the step size *is* defined. */
/*
* if(parm.step->answer==NULL)
* G_fatal_error("If you want to use a time interval you must also define
* a step size."); if(parm.ltime->answer!=NULL) G_fatal_error("If you want
* to use a time interval you can't define a single time value.\n");
* if((parm.startTime->answer==NULL)||(parm.endTime->answer==NULL))
* G_fatal_error("If you want to use a time interval both the start and
* end times must be defined.\n");
* }
*/
if (parm.linkein->answer == NULL) {
sscanf(parm.lin->answer, "%lf", &singleLinke);
G_message(_("Using Linke constant: %lf"), singleLinke);
}
else {
G_message(_("Using Linke map <%s>"), parm.linkein->answer);
}
if (parm.albedo->answer == NULL) {
sscanf(parm.alb->answer, "%lf", &singleAlbedo);
G_message(_("Using albedo constant: %lf"), singleAlbedo);
}
else {
G_message(_("Using albedo map <%s>"), parm.albedo->answer);
}
if (parm.slopein->answer == NULL) {
sscanf(parm.slope->answer, "%lf", &singleSlope);
G_message(_("Using slope constant: %lf"), singleSlope);
singleSlope *= deg2rad;
}
else {
G_message(_("Using slope map <%s>"), parm.slopein->answer);
}
if (parm.aspin->answer == NULL) {
sscanf(parm.aspect->answer, "%lf", &singleAspect);
G_message(_("Using aspect constant: %lf"), singleAspect);
singleAspect *= deg2rad;
}
else {
G_message(_("Using aspect map <%s>"), parm.aspin->answer);
}
if (parm.coefbh->answer == NULL)
cbh = BSKY;
if (parm.coefdh->answer == NULL)
cdh = DSKY;
sscanf(parm.dist->answer, "%lf", &dist);
if (parm.numPartitions->answer != NULL) {
sscanf(parm.numPartitions->answer, "%d", &numPartitions);
if (useShadow() && (!useHorizonData()) && (numPartitions != 1)) {
/* If you calculate shadows on the fly, the number of partitions
* must be one.
*/
G_fatal_error(_("If you use -s and no horizon rasters, "
"numpartitions must be =1"));
}
}
/* The save memory scheme will not work if you want to calculate shadows
* on the fly. If you calculate without shadow effects or if you have the
* shadows pre-calculated, there is no problem. */
if (parm.declin->answer == NULL)
declination = com_declin(day);
else {
sscanf(parm.declin->answer, "%lf", &declin);
declination = -declin;
}
if (parm.solar_cnst->answer)
sscanf(parm.solar_cnst->answer, "%lf", &solar_constant);
else
solar_constant = 1367;
if (ttime != 0) {
/* Shadow for just one time during the day */
if (horizon == NULL) {
arrayNumInt = 1;
}
else if (useHorizonData()) {
arrayNumInt = (int)(360. / horizonStep);
}
}
else {
if (useHorizonData()) {
/* Number of bytes holding the horizon information */
arrayNumInt = (int)(360. / horizonStep);
}
}
if (ttime != NULL) {
G_free_key_value(in_proj_info);
G_free_key_value(in_unit_info);
oproj.pj = NULL;
tproj.def = NULL;
if ((G_projection() == PROJECTION_LL))
ll_correction = TRUE;
exit(EXIT_SUCCESS);
}
numRows = m / numPartitions;
cell1 = Rast_allocate_f_buf();
if (z == NULL) {
if (!(z = G_alloc_fmatrix(numRows, n))) {
G_fatal_error(_("Out of memory"));
}
}
if (slopein != NULL) {
cell3 = Rast_allocate_f_buf();
if (s == NULL) {
if (!(s = G_alloc_fmatrix(numRows, n))) {
G_fatal_error(_("Out of memory"));
}
}
fd3 = Rast_open_old(slopein, "");
}
if (aspin != NULL) {
cell2 = Rast_allocate_f_buf();
if (o == NULL) {
if (!(o = G_alloc_fmatrix(numRows, n))) {
G_fatal_error(_("Out of memory"));
}
}
fd2 = Rast_open_old(aspin, "");
}
if (linkein != NULL) {
cell4 = Rast_allocate_f_buf();
if (li == NULL) {
if (!(li = G_alloc_fmatrix(numRows, n))) {
G_fatal_error(_("Out of memory"));
}
}
fd4 = Rast_open_old(linkein, "");
}
if (albedo != NULL) {
cell5 = Rast_allocate_f_buf();
if (a == NULL) {
if (!(a = G_alloc_fmatrix(numRows, n))) {
G_fatal_error(_("Out of memory"));
}
}
fd5 = Rast_open_old(albedo, "");
}
if (latin != NULL) {
cell6 = Rast_allocate_f_buf();
if (latitudeArray == NULL) {
if (!(latitudeArray = G_alloc_fmatrix(numRows, n))) {
G_fatal_error(_("Out of memory"));
}
}
fd6 = Rast_open_old(latin, "");
}
if (longin != NULL) {
cell7 = Rast_allocate_f_buf();
if (longitudeArray == NULL) {
if (!(longitudeArray = G_alloc_fmatrix(numRows, n))) {
G_fatal_error(_("Out of memory"));
}
}
if (coefbh != NULL) {
rast1 = Rast_allocate_f_buf();
if (cbhr == NULL) {
if (!(cbhr = G_alloc_fmatrix(numRows, n))) {
G_fatal_error(_("Out of memory"));
}
}
fr1 = Rast_open_old(coefbh, "");
}
if (coefdh != NULL) {
rast2 = Rast_allocate_f_buf();
if (cdhr == NULL) {
if (!(cdhr = G_alloc_fmatrix(numRows, n))) {
G_fatal_error(_("Out of memory"));
}
}
fr2 = Rast_open_old(coefdh, "");
}
if (useHorizonData()) {
if (horizonarray == NULL) {
horizonarray = (unsigned char *)G_calloc(arrayNumInt * numRows * n,
sizeof(char));
if (useHorizonData()) {
row_rev = m - row - 1;
rowrevoffset = row_rev - offset;
Rast_get_f_row(fd_shad[i], horizonbuf[i], row);
horizonpointer =
horizonarray + (ssize_t)arrayNumInt * n * rowrevoffset;
for (j = 0; j < n; j++) {
horizonpointer[i] =
(char)(rint(SCALING_FACTOR *
AMIN1(horizonbuf[i][j], 256 * invScale)));
horizonpointer += arrayNumInt;
}
}
}
}
row_rev = m - row - 1;
rowrevoffset = row_rev - offset;
if (aspin != NULL) {
if (!Rast_is_f_null_value(cell2 + j))
o[rowrevoffset][j] = (float)cell2[j];
else
o[rowrevoffset][j] = UNDEFZ;
}
if (slopein != NULL) {
if (!Rast_is_f_null_value(cell3 + j))
s[rowrevoffset][j] = (float)cell3[j];
else
s[rowrevoffset][j] = UNDEFZ;
}
if (linkein != NULL) {
if (!Rast_is_f_null_value(cell4 + j))
li[rowrevoffset][j] = (float)cell4[j];
else
li[rowrevoffset][j] = UNDEFZ;
}
if (albedo != NULL) {
if (!Rast_is_f_null_value(cell5 + j))
a[rowrevoffset][j] = (float)cell5[j];
else
a[rowrevoffset][j] = UNDEFZ;
}
if (latin != NULL) {
if (!Rast_is_f_null_value(cell6 + j))
latitudeArray[rowrevoffset][j] = (float)cell6[j];
else
latitudeArray[rowrevoffset][j] = UNDEFZ;
}
if (longin != NULL) {
if (!Rast_is_f_null_value(cell7 + j))
longitudeArray[rowrevoffset][j] = (float)cell7[j];
else
longitudeArray[rowrevoffset][j] = UNDEFZ;
}
if (coefbh != NULL) {
if (!Rast_is_f_null_value(rast1 + j))
cbhr[rowrevoffset][j] = (float)rast1[j];
else
cbhr[rowrevoffset][j] = UNDEFZ;
}
if (coefdh != NULL) {
if (!Rast_is_f_null_value(rast2 + j))
cdhr[rowrevoffset][j] = (float)rast2[j];
else
cdhr[rowrevoffset][j] = UNDEFZ;
}
}
}
Rast_close(fd1);
G_free(cell1);
if (aspin != NULL) {
G_free(cell2);
Rast_close(fd2);
}
if (slopein != NULL) {
G_free(cell3);
Rast_close(fd3);
}
if (linkein != NULL) {
G_free(cell4);
Rast_close(fd4);
}
if (albedo != NULL) {
G_free(cell5);
Rast_close(fd5);
}
if (latin != NULL) {
G_free(cell6);
Rast_close(fd6);
}
if (longin != NULL) {
G_free(cell7);
Rast_close(fd7);
}
if (coefbh != NULL) {
G_free(rast1);
Rast_close(fr1);
}
if (coefdh != NULL) {
G_free(rast2);
Rast_close(fr2);
}
if (useHorizonData()) {
for (i = 0; i < arrayNumInt; i++) {
Rast_close(fd_shad[i]);
G_free(horizonbuf[i]);
}
}
/* needs to be eliminated */
return 1;
}
int OUTGR(void)
{
FCELL *cell7 = NULL, *cell8 = NULL, *cell9 = NULL, *cell10 = NULL,
*cell11 = NULL, *cell12 = NULL;
int fd7 = -1, fd8 = -1, fd9 = -1, fd10 = -1, fd11 = -1, fd12 = -1;
int i, iarc, j;
if (incidout != NULL) {
cell7 = Rast_allocate_f_buf();
fd7 = Rast_open_fp_new(incidout);
}
if (beam_rad != NULL) {
cell8 = Rast_allocate_f_buf();
fd8 = Rast_open_fp_new(beam_rad);
}
if (insol_time != NULL) {
cell11 = Rast_allocate_f_buf();
fd11 = Rast_open_fp_new(insol_time);
}
if (diff_rad != NULL) {
cell9 = Rast_allocate_f_buf();
fd9 = Rast_open_fp_new(diff_rad);
}
if (refl_rad != NULL) {
cell10 = Rast_allocate_f_buf();
fd10 = Rast_open_fp_new(refl_rad);
}
if (glob_rad != NULL) {
cell12 = Rast_allocate_f_buf();
fd12 = Rast_open_fp_new(glob_rad);
}
if (m != Rast_window_rows())
G_fatal_error("OOPS: rows changed from %d to %d", m,
Rast_window_rows());
if (n != Rast_window_cols())
G_fatal_error("OOPS: cols changed from %d to %d", n,
Rast_window_cols());
if (beam_rad != NULL) {
for (j = 0; j < n; j++) {
if (beam[i][j] == UNDEFZ)
Rast_set_f_null_value(cell8 + j, 1);
else
cell8[j] = (FCELL)beam[i][j];
}
Rast_put_f_row(fd8, cell8);
}
if (glob_rad != NULL) {
for (j = 0; j < n; j++) {
if (globrad[i][j] == UNDEFZ)
Rast_set_f_null_value(cell12 + j, 1);
else
cell12[j] = (FCELL)globrad[i][j];
}
Rast_put_f_row(fd12, cell12);
}
if (insol_time != NULL) {
for (j = 0; j < n; j++) {
if (insol[i][j] == UNDEFZ)
Rast_set_f_null_value(cell11 + j, 1);
else
cell11[j] = (FCELL)insol[i][j];
}
Rast_put_f_row(fd11, cell11);
}
if (diff_rad != NULL) {
for (j = 0; j < n; j++) {
if (diff[i][j] == UNDEFZ)
Rast_set_f_null_value(cell9 + j, 1);
else
cell9[j] = (FCELL)diff[i][j];
}
Rast_put_f_row(fd9, cell9);
}
if (refl_rad != NULL) {
for (j = 0; j < n; j++) {
if (refl[i][j] == UNDEFZ)
Rast_set_f_null_value(cell10 + j, 1);
else
cell10[j] = (FCELL)refl[i][j];
}
Rast_put_f_row(fd10, cell10);
}
}
if (incidout != NULL) {
Rast_close(fd7);
Rast_write_history(incidout, &hist);
}
if (beam_rad != NULL) {
Rast_close(fd8);
Rast_write_history(beam_rad, &hist);
}
if (diff_rad != NULL) {
Rast_close(fd9);
Rast_write_history(diff_rad, &hist);
}
if (refl_rad != NULL) {
Rast_close(fd10);
Rast_write_history(refl_rad, &hist);
}
if (insol_time != NULL) {
Rast_close(fd11);
Rast_write_history(insol_time, &hist);
}
if (glob_rad != NULL) {
Rast_close(fd12);
Rast_write_history(glob_rad, &hist);
}
return 1;
}
/**********************************************************/
sunGeom->timeAngle = firstAngle;
varCount_global = 0;
dfr = step;
while (ss == 1) {
/*////////////////////////////////////////////////////////////////////// */
/*
* void where_is_point(void)
* {
* double sx, sy;
* double dx, dy;
* double adx, ady;
* int i, j;
*
* sx = xx0 * invstepx + TOLER;
* sy = yy0 * invstepy + TOLER;
*
* i = (int)sx;
* j = (int)sy;
* if (i < n - 1 && j < m - 1) {
*
* dx = xx0 - (double)i *stepx;
* dy = yy0 - (double)j *stepy;
*
* adx = fabs(dx);
* ady = fabs(dy);
*
* if ((adx > TOLER) && (ady > TOLER)) {
* cube(j, i);
* return;
* }
* else if ((adx > TOLER) && (ady < TOLER)) {
* line_x(j, i);
* return;
* }
* else if ((adx < TOLER) && (ady > TOLER)) {
* line_y(j, i);
* return;
* }
* else if ((adx < TOLER) && (ady < TOLER)) {
* vertex(j, i);
* return;
* }
*
*
* }
* else {
* func = NULL;
* }
* }
*
*/
sx = gridGeom->xx0 * invstepx +
offsetx; /* offset 0.5 cell size to get the right cell i, j */
sy = gridGeom->yy0 * invstepy + offsety;
i = (int)sx;
j = (int)sy;
dx = (double)i * gridGeom->stepx;
dy = (double)j * gridGeom->stepy;
*length = distance(
gridGeom->xg0, dx, gridGeom->yg0,
dy); /* dist from orig. grid point to the current grid point */
sunVarGeom->zp = z[j][i];
/*
* cube(j, i);
*/
}
}
/*
* void vertex(jmin, imin)
* int jmin, imin;
* {
* zp = z[jmin][imin];
* if ((zp == UNDEFZ))
* func = NULL;
* }
* void line_x(jmin, imin)
* int jmin, imin;
* {
* double c1, c2;
* double d1, d2, e1, e2;
* e1 = (double)imin *stepx;
* e2 = (double)(imin + 1) * stepx;
*
* c1 = z[jmin][imin];
* c2 = z[jmin][imin + 1];
* if (!((c1 == UNDEFZ) || (c2 == UNDEFZ))) {
*
* if (dist <= 1.0) {
* d1 = (xx0 - e1) / (e2 - e1);
* d2 = 1 - d1;
* if (d1 < d2)
* zp = c1;
* else
* zp = c2;
* }
*
* if (dist > 1.0)
* zp = AMAX1(c1, c2);
* }
* else
* func = NULL;
* }
*
*
* void line_y(jmin, imin)
* int jmin, imin;
* {
* double c1, c2;
* double d1, d2, e1, e2;
* e1 = (double)jmin *stepy;
* e2 = (double)(jmin + 1) * stepy;
*
* c1 = z[jmin][imin];
* c2 = z[jmin + 1][imin];
* if (!((c1 == UNDEFZ) || (c2 == UNDEFZ))) {
*
* if (dist <= 1.0) {
* d1 = (yy0 - e1) / (e2 - e1);
* d2 = 1 - d1;
* if (d1 < d2)
* zp = c1;
* else
* zp = c2;
* }
*
* if (dist > 1.0)
* zp = AMAX1(c1, c2);
*
* }
* else
* func = NULL;
*
* }
*
* void cube(jmin, imin)
* int jmin, imin;
* {
* int i, ig = 0;
* double x1, x2, y1, y2;
* double v[4], vmin = BIG;
* double c[4], cmax = -BIG;
*
* x1 = (double)imin *stepx;
* x2 = x1 + stepx;
*
* y1 = (double)jmin *stepy;
* y2 = y1 + stepy;
*
* v[0] = DISTANCE2(x1, y1);
*
* if (v[0] < vmin) {
* ig = 0;
* vmin = v[0];
* }
* v[1] = DISTANCE2(x2, y1);
*
* if (v[1] < vmin) {
* ig = 1;
* vmin = v[1];
* }
*
* v[2] = DISTANCE2(x2, y2);
* if (v[2] < vmin) {
* ig = 2;
* vmin = v[2];
* }
*
* v[3] = DISTANCE2(x1, y2);
* if (v[3] < vmin) {
* ig = 3;
* vmin = v[3];
* }
*
* c[0] = z[jmin][imin];
* c[1] = z[jmin][imin + 1];
* c[2] = z[jmin + 1][imin + 1];
* c[3] = z[jmin + 1][imin];
*
*
* if (dist <= 1.0) {
*
* if (c[ig] != UNDEFZ)
* zp = c[ig];
* else
* func = NULL;
* return;
* }
*
* if (dist > 1.0) {
* for (i = 0; i < 4; i++) {
* if (c[i] != UNDEFZ) {
* cmax = AMAX1(cmax, c[i]);
* zp = cmax;
* }
* else
* func = NULL;
* }
* }
* }
*/
/*
* void cube(jmin, imin)
* int jmin, imin;
* {
* zp = z[jmin][imin];
*
* }
*/
/*////////////////////////////////////////////////////////////////////// */
/* double energy; */
int someRadiation;
int numRows;
int arrayOffset;
double lum = 0.0, q1 = 0.0;
double dayRad;
double latid_l = 0.0, cos_u = 0.0, cos_v = 0.0, sin_u = 0.0, sin_v = 0.0;
double sin_phi_l = 0.0, tan_lam_l = 0.0;
double zmax = 0;
double longitTime = 0.;
double locTimeOffset;
double latitude, longitude;
double coslat = 0.0;
bool shouldBeBestAM = false;
bool isBestAM = false;
sunSlopeGeom.slope = singleSlope;
sunSlopeGeom.aspect = singleAspect;
sunRadVar.alb = singleAlbedo;
sunRadVar.linke = singleLinke;
sunRadVar.cbh = 1.0;
sunRadVar.cdh = 1.0;
sunGeom.sindecl = sin(declination);
sunGeom.cosdecl = cos(declination);
if (incidout != NULL) {
lumcl = (float **)G_calloc((m), sizeof(float *));
for (l = 0; l < m; l++) {
lumcl[l] = (float *)G_calloc((n), sizeof(float *));
}
for (j = 0; j < m; j++) {
for (i = 0; i < n; i++)
lumcl[j][i] = UNDEFZ;
}
}
if (beam_rad != NULL) {
beam = (float **)G_calloc((m), sizeof(float *));
for (l = 0; l < m; l++) {
beam[l] = (float *)G_calloc((n), sizeof(float *));
}
if (insol_time != NULL) {
insol = (float **)G_calloc((m), sizeof(float *));
for (l = 0; l < m; l++) {
insol[l] = (float *)G_calloc((n), sizeof(float *));
}
if (diff_rad != NULL) {
diff = (float **)G_calloc((m), sizeof(float *));
for (l = 0; l < m; l++) {
diff[l] = (float *)G_calloc((n), sizeof(float *));
}
if (refl_rad != NULL) {
refl = (float **)G_calloc((m), sizeof(float *));
for (l = 0; l < m; l++) {
refl[l] = (float *)G_calloc((n), sizeof(float *));
}
if (glob_rad != NULL) {
globrad = (float **)G_calloc((m), sizeof(float *));
for (l = 0; l < m; l++) {
globrad[l] = (float *)G_calloc((n), sizeof(float *));
}
sunRadVar.G_norm_extra = com_sol_const(day);
numRows = m / numPartitions;
if (useCivilTime()) {
/* We need to calculate the deviation of the local solar time from the
* "local clock time". */
dayRad = 2. * M_PI * day / 365.25;
locTimeOffset =
+0.128 * sin(dayRad - 0.04887) + 0.165 * sin(2 * dayRad + 0.34383);
locTimeOffset += civilTime;
setTimeOffset(locTimeOffset);
}
else {
setTimeOffset(0.);
}
int shadowoffset_base = shadowoffset;
if (j % (numRows) == 0) {
INPUT_part(j, &zmax);
arrayOffset = 0;
shadowoffset = 0;
}
sunVarGeom.zmax = zmax;
shadowoffset_base = (j % (numRows)) * n * arrayNumInt;
#pragma omp parallel firstprivate( \
q1, tan_lam_l, z1, i, shadowoffset, longitTime, coslat, coslatsq, \
latitude, longitude, sin_phi_l, latid_l, sin_u, cos_u, sin_v, \
cos_v, lum, gridGeom, elevin, aspin, slopein, civiltime, linkein, \
albedo, latin, coefbh, coefdh, incidout, longin, horizon, \
beam_rad, insol_time, diff_rad, refl_rad, glob_rad, mapset, per, \
decimals, str_step, shouldBeBestAM, isBestAM)
{
#pragma omp for schedule(dynamic) \
firstprivate(sunGeom, sunVarGeom, sunSlopeGeom, sunRadVar) \
lastprivate(sunGeom, sunVarGeom, sunSlopeGeom, sunRadVar) \
reduction(max : linke_max, albedo_max, lat_max, sunrise_max, sunset_max) \
reduction(min : linke_min, albedo_min, lat_min, sunrise_min, sunset_min)
for (i = 0; i < n; i++) {
shadowoffset = shadowoffset_base + (arrayNumInt * i);
if (useCivilTime()) {
/* sun travels 15deg per hour, so 1 TZ every 15 deg and 15
* TZs * 24hrs = 360deg */
longitTime = -longitudeArray[arrayOffset][i] / 15.;
}
if (ll_correction) {
coslat = cos(deg2rad * gridGeom.yp);
coslatsq = coslat * coslat;
}
/* func = NULL; */
if ((G_projection() != PROJECTION_LL)) {
if (coefbh != NULL) {
sunRadVar.cbh = cbhr[arrayOffset][i];
}
if (coefdh != NULL) {
sunRadVar.cdh = cdhr[arrayOffset][i];
}
cos_u =
cos(M_PI / 2 - sunSlopeGeom.slope); /* = sin(slope) */
sin_u =
sin(M_PI / 2 - sunSlopeGeom.slope); /* = cos(slope) */
cos_v = cos(M_PI / 2 + sunSlopeGeom.aspect);
sin_v = sin(M_PI / 2 + sunSlopeGeom.aspect);
if (ttime != NULL)
sunGeom.timeAngle = tim;
gridGeom.sinlat = sin(-latitude);
gridGeom.coslat = cos(-latitude);
if (q1 != 0.0) {
tan_lam_l = -cos_u * cos_v / q1;
sunSlopeGeom.longit_l = atan(tan_lam_l);
isBestAM = (tan_lam_l > 0);
}
else {
sunSlopeGeom.longit_l = pihalf;
isBestAM = true;
}
if (incidout != NULL) {
com_par(&sunGeom, &sunVarGeom, &gridGeom, latitude,
longitude);
lum = lumcline2(&sunGeom, &sunVarGeom, &sunSlopeGeom,
&gridGeom, horizonarray + shadowoffset);
if (lum > 0.) {
lum = rad2deg * asin(lum);
lumcl[j][i] = (float)lum;
}
else
lumcl[j][i] = UNDEFZ;
}
if (someRadiation) {
joules2(
&sunGeom, &sunVarGeom, &sunSlopeGeom, &sunRadVar,
&gridGeom, horizonarray + shadowoffset, latitude,
longitude, &Pbeam_e, &Pdiff_e, &Prefl_e, &Pinsol_t);
if (beam_rad != NULL)
beam[j][i] = (float)Pbeam_e;
if (insol_time != NULL)
insol[j][i] = (float)Pinsol_t;
/* G_debug(3,"\n %f",insol[j][i]); */
if (diff_rad != NULL)
diff[j][i] = (float)Pdiff_e;
if (refl_rad != NULL)
refl[j][i] = (float)Prefl_e;
if (glob_rad != NULL)
globrad[j][i] =
(float)(Pbeam_e + Pdiff_e + Prefl_e);
}
} /* undefs */
}
}
arrayOffset++;
}
Rast_append_format_history(
&hist,
" ----------------------------------------------------------------");
Rast_append_format_history(
&hist, " Day [1-365]: %d", day);
if (ttime != NULL)
Rast_append_format_history(
&hist, " Local (solar) time (decimal hr.): %.4f", timo);
Rast_append_format_history(
&hist, " Solar constant (W/m^2): %f", solar_constant);
Rast_append_format_history(&hist,
" Extraterrestrial irradiance (W/m^2): %f",
sunRadVar.G_norm_extra);
Rast_append_format_history(
&hist, " Declination (rad): %f", -declination);
Rast_append_format_history(
&hist, " Latitude min-max(deg): %.4f - %.4f",
lat_min, lat_max);
if (ttime != NULL) {
Rast_append_format_history(
&hist, " Sunrise time (hr.): %.2f",
sunGeom.sunrise_time);
Rast_append_format_history(
&hist, " Sunset time (hr.): %.2f",
sunGeom.sunset_time);
Rast_append_format_history(
&hist, " Daylight time (hr.): %.2f",
sunGeom.sunset_time - sunGeom.sunrise_time);
}
else {
Rast_append_format_history(
&hist, " Sunrise time min-max (hr.): %.2f - %.2f",
sunrise_min, sunrise_max);
Rast_append_format_history(
&hist, " Sunset time min-max (hr.): %.2f - %.2f",
sunset_min, sunset_max);
Rast_append_format_history(
&hist, " Time step (hr.): %.4f", step);
}
if (linkein == NULL)
Rast_append_format_history(
&hist, " Linke turbidity factor: %.1f",
sunRadVar.linke);
else
Rast_append_format_history(
&hist, " Linke turbidity factor min-max: %.1f-%.1f",
linke_min, linke_max);
if (albedo == NULL)
Rast_append_format_history(
&hist, " Ground albedo: %.3f",
sunRadVar.alb);
else
Rast_append_format_history(
&hist, " Ground albedo min-max: %.3f-%.3f",
albedo_min, albedo_max);
Rast_append_format_history(
&hist,
" -----------------------------------------------------------------");
Rast_command_history(&hist);
/* don't call Rast_write_history() until after Rast_close() or it just gets
* overwritten */
} /* End of ) function */
return (decl);
}
int test(void)
{
/* not finished yet */
int dej;