Skip to content

Commit

Permalink
r.sun: Fix metadata update on parallel computation (#1514)
Browse files Browse the repository at this point in the history
Add test cases to check for metadata consistency
  • Loading branch information
aaronsms committed May 6, 2021
1 parent 5150953 commit f222a5c
Show file tree
Hide file tree
Showing 2 changed files with 141 additions and 22 deletions.
8 changes: 6 additions & 2 deletions raster/r.sun/main.c
Original file line number Diff line number Diff line change
Expand Up @@ -1837,9 +1837,13 @@ void calculate(double singleSlope, double singleAspect, double singleAlbedo,
}
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,sunGeom,sunVarGeom,sunSlopeGeom,sunRadVar, 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 )
#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)
{
#pragma omp for schedule(dynamic)
#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()) {
Expand Down
155 changes: 135 additions & 20 deletions raster/r.sun/testsuite/test_rsun.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,105 @@
from grass.gunittest.gmodules import SimpleModule


class TestRSunMode1Metadata(TestCase):
"""Tests the consistency of metadata when computing instantaneous solar
incidence angle and irradiance.
"""

elevation = "elevation"
slope = "rsun_slope"
aspect = "rsun_aspect"
incidout = "incidout"

# expected metadata with the relevant `nprocs` field
metadata = """\"\
----------------------------------------------------------------\
Day [1-365]: 172\
Local (solar) time (decimal hr.): 18.0000\
Solar constant (W/m^2): 1367.000000\
Extraterrestrial irradiance (W/m^2): 1322.508495\
Declination (rad): 0.409115\
Latitude min-max(deg): 35.7328 - 35.7642\
Sunrise time (hr.): 4.79\
Sunset time (hr.): 19.21\
Daylight time (hr.): 14.43\
Solar altitude (deg): 13.4438\
Solar azimuth (deg): 289.3828\
Linke turbidity factor: 3.0\
Ground albedo: 0.200\
-----------------------------------------------------------------\
\
r.sun --overwrite elevation="elevation" aspect="rsun_aspect" aspect_\\\
value=270.0 slope="rsun_slope" slope_value=0.0 linke_value=3.0 albed\\\
o_value=0.2 incidout="incidout" day=172 step=0.5 solar_constant=1367\\\
.0 time=18 nprocs={nprocs} distance_step=1.0 npartitions=1"\
"""

@classmethod
def setUpClass(cls):
cls.use_temp_region()
cls.runModule("g.region", n=223500, s=220000, e=640000, w=635000, res=10)
cls.runModule(
"r.slope.aspect",
elevation=cls.elevation,
slope=cls.slope,
aspect=cls.aspect,
)

@classmethod
def tearDownClass(cls):
cls.del_temp_region()
cls.runModule(
"g.remove",
type=["raster"],
name=[
cls.slope,
cls.aspect,
cls.incidout,
],
flags="f",
)

def setUp(self):
self.rsun = SimpleModule(
"r.sun",
elevation=self.elevation,
slope=self.slope,
aspect=self.aspect,
incidout=self.incidout,
day=172,
time=18,
overwrite=True,
)

def test_more_threads(self):
"""Checks metadata correctness in threaded cases."""
self.rsun.inputs["nprocs"].value = 4
self.assertModule(self.rsun)
self.assertRasterExists(name=self.incidout)
self.assertModuleKeyValue(
"r.info",
map=self.incidout,
flags="e",
reference=dict(comments=self.metadata.format(nprocs=4)),
precision=0,
sep="=",
)

def test_run_outputs(self):
"""Checks metadata correctness in non-threaded cases."""
self.assertModule(self.rsun)
self.assertRasterExists(name=self.incidout)
self.assertModuleKeyValue(
"r.info",
map=self.incidout,
flags="e",
reference=dict(comments=self.metadata.format(nprocs=1)),
precision=0,
sep="=",
)


class TestRSunMode2(TestCase):
elevation = "elevation"
elevation_attrib = "elevation_attrib"
Expand All @@ -12,7 +111,9 @@ class TestRSunMode2(TestCase):
beam_rad = "beam_rad"
glob_rad = "glob_rad"
insol_time = "insol_time"
beam_rad_threads = "beam_rad_threads"
glob_rad_threads = "glob_rad_threads"
insol_time_threads = "insol_time_threads"

@classmethod
def setUpClass(cls):
Expand All @@ -37,7 +138,9 @@ def tearDownClass(cls):
cls.insol_time,
cls.beam_rad,
cls.glob_rad,
cls.beam_rad_threads,
cls.glob_rad_threads,
cls.insol_time_threads,
],
flags="f",
)
Expand All @@ -57,16 +160,20 @@ def setUp(self):

def test_more_threads(self):
self.assertModule(self.rsun)
try:
self.rsun.inputs["nprocs"].value = 4
self.rsun.outputs.glob_rad = self.glob_rad_threads
self.assertModule(self.rsun)
self.assertRastersNoDifference(
self.glob_rad, self.glob_rad_threads, precision=1e-8
)
except KeyError:
# original version of r.sun without parallel processing
return
self.rsun.inputs["nprocs"].value = 4
self.rsun.outputs.beam_rad = self.beam_rad_threads
self.rsun.outputs.glob_rad = self.glob_rad_threads
self.rsun.outputs.insol_time = self.insol_time_threads
self.assertModule(self.rsun)
self.assertRastersNoDifference(
self.beam_rad, self.beam_rad_threads, precision=1e-8
)
self.assertRastersNoDifference(
self.glob_rad, self.glob_rad_threads, precision=1e-8
)
self.assertRastersNoDifference(
self.insol_time, self.insol_time_threads, precision=1e-8
)

def test_run_outputs(self):
self.assertModule(self.rsun)
Expand Down Expand Up @@ -99,7 +206,9 @@ class TestRSunMode1(TestCase):
beam_rad = "beam_rad"
glob_rad = "glob_rad"
incidout = "incidout"
beam_rad_threads = "beam_rad_threads"
glob_rad_threads = "glob_rad_threads"
incidout_threads = "incidout_threads"

@classmethod
def setUpClass(cls):
Expand All @@ -124,7 +233,9 @@ def tearDownClass(cls):
cls.incidout,
cls.beam_rad,
cls.glob_rad,
cls.beam_rad_threads,
cls.glob_rad_threads,
cls.incidout_threads,
],
flags="f",
)
Expand All @@ -145,16 +256,20 @@ def setUp(self):

def test_more_threads(self):
self.assertModule(self.rsun)
try:
self.rsun.inputs["nprocs"].value = 4
self.rsun.outputs.glob_rad = self.glob_rad_threads
self.assertModule(self.rsun)
self.assertRastersNoDifference(
self.glob_rad, self.glob_rad_threads, precision=1e-8
)
except KeyError:
# original version of r.sun without parallel processing
return
self.rsun.inputs["nprocs"].value = 4
self.rsun.outputs.beam_rad = self.beam_rad_threads
self.rsun.outputs.glob_rad = self.glob_rad_threads
self.rsun.outputs.incidout = self.incidout_threads
self.assertModule(self.rsun)
self.assertRastersNoDifference(
self.beam_rad, self.beam_rad_threads, precision=1e-8
)
self.assertRastersNoDifference(
self.glob_rad, self.glob_rad_threads, precision=1e-8
)
self.assertRastersNoDifference(
self.incidout, self.incidout_threads, precision=1e-8
)

def test_run_outputs(self):
self.assertModule(self.rsun)
Expand Down

0 comments on commit f222a5c

Please sign in to comment.