def test_vs_noaa_sydney(self): sydney = Location('Sydney', 'AUS', latitude=-33.87, longitude=151.22, time_zone=10) sp = Sunpath.from_location(sydney) sun = sp.calculate_sun(month=11, day=15, hour=11.0) assert round(sun.altitude, 2) == 72.26 assert round(sun.azimuth, 2) == 32.37
def test_vs_noaa_new_york(self): nyc = Location('New_York', 'USA', latitude=40.72, longitude=-74.02, time_zone=-5) sp = Sunpath.from_location(nyc) sun = sp.calculate_sun(month=9, day=15, hour=11.0) assert round(sun.altitude, 2) == 50.35 assert round(sun.azimuth, 2) == 159.72
def test_from_location(self): sydney = Location('Sydney', 'AUS', latitude=-33.87, longitude=151.22, time_zone=10) sunpath = Sunpath.from_location(sydney) assert sunpath.latitude == -33.87 assert sunpath.longitude == 151.22 assert sunpath.time_zone == 10
def _calculate_solar_values(self): """Calculate solar values for requested hours of the year. This method is called everytime that output type is set. """ wea = self.wea hoys_set = set(wea.hoys) output_type = self.output_type month_date_time = (DateTime.from_hoy(idx) for idx in self.hoys) sp = Sunpath.from_location(wea.location, self.north) # use gendaylit to calculate radiation values for each hour. print('Calculating solar values...') for timecount, dt in enumerate(month_date_time): if dt.hoy not in hoys_set: print('Warn: Wea data for {} is not available!'.format(dt)) continue month, day, hour = dt.month, dt.day, dt.float_hour dnr, dhr = wea.get_radiation_values(month, day, hour) sun = sp.calculate_sun(month, day, hour) if sun.altitude < 0: continue if dnr == 0: solarradiance = 0 else: solarradiance = \ int(gendaylit(sun.altitude, month, day, hour, dnr, dhr, output_type)) self._solar_values.append(solarradiance) # keep the number of hour relative to hoys in this sun matrix self._sun_up_hours_indices.append(timecount)
def from_json(cls, rec_json): """Create the solar access recipe from json. { "id": "solar_access", "type": "gridbased", "location": null, // a honeybee location - see below "hoys": [], // list of hours of the year "surfaces": [], // list of honeybee surfaces "analysis_grids": [] // list of analysis grids "sun_vectors": [] // list of sun vectors if location is not provided } """ hoys = rec_json["hoys"] if 'sun_vectors' not in rec_json or not rec_json['sun_vectors']: # create sun vectors from location inputs loc = Location.from_json(rec_json['location']) sp = Sunpath.from_location(loc) suns = (sp.calculate_sun_from_hoy(hoy) for hoy in hoys) sun_vectors = tuple(s.sun_vector for s in suns if s.is_during_day) else: sun_vectors = rec_json['sun_vectors'] analysis_grids = \ tuple(AnalysisGrid.from_json(ag) for ag in rec_json["analysis_grids"]) hb_objects = tuple(HBSurface.from_json(srf) for srf in rec_json["surfaces"]) return cls(sun_vectors, hoys, analysis_grids, 1, hb_objects)
def test_daylight_saving(self): nyc = Location('New_York', 'USA', latitude=40.72, longitude=-74.02, time_zone=-5) sp = Sunpath.from_location(nyc) dt1 = DateTime(6, 21, 12, 0) dt2 = DateTime(12, 21, 12, 0) # TODO(mostapha): This is not implemented yet # assert sp.is_daylight_saving_hour(dt1) is True assert sp.is_daylight_saving_hour(dt1) is False assert sp.is_daylight_saving_hour(dt2) is False
def test_leap_year(self): nyc = Location('New_York', 'USA', latitude=40.72, longitude=-74.02, time_zone=-5) sp = Sunpath.from_location(nyc) sp.is_leap_year = True sun = sp.calculate_sun(month=2, day=29, hour=11.0) assert sun.datetime == DateTime(2, 29, 11, leap_year=True) assert sun.datetime.year == 2016 assert sun.datetime.month == 2 assert sun.datetime.day == 29 assert sun.datetime.hour == 11
def from_location_and_hoys(cls, location, hoys, point_groups, vector_groups=[], timestep=1, hb_objects=None, sub_folder='sunlighthour'): """Create sunlighthours recipe from Location and hours of year.""" sp = Sunpath.from_location(location) suns = (sp.calculate_sun_from_hoy(hoy) for hoy in hoys) sun_vectors = tuple(s.sun_vector for s in suns if s.is_during_day) analysis_grids = cls.analysis_grids_from_points_and_vectors(point_groups, vector_groups) return cls(sun_vectors, hoys, analysis_grids, timestep, hb_objects, sub_folder)
def test_daylight_saving(): nyc = Location('New_York', 'USA', latitude=40.72, longitude=-74.02, time_zone=-5) sp = Sunpath.from_location(nyc) dt1 = DateTime(6, 21, 12, 0) dt2 = DateTime(12, 21, 12, 0) # TODO(mostapha): This is not implemented yet # assert sp.is_daylight_saving_hour(dt1) is True assert sp.is_daylight_saving_hour(dt1) is False assert sp.is_daylight_saving_hour(dt2) is False
def test_calculate_sun(): """Test the varios calculate_sun methods to be sure they all give the same result.""" nyc = Location('New_York', 'USA', latitude=40.72, longitude=-74.02, time_zone=-5) sp = Sunpath.from_location(nyc) dt1 = DateTime(3, 21, 9, 30) sun1 = sp.calculate_sun(dt1.month, dt1.day, dt1.float_hour) sun2 = sp.calculate_sun_from_hoy(dt1.hoy) sun3 = sp.calculate_sun_from_moy(dt1.moy) sun4 = sp.calculate_sun_from_date_time(dt1) assert sun1 == sun2 == sun3 == sun4 assert round(sun1.altitude, 2) == 36.90 assert round(sun1.azimuth, 2) == 129.23
def test_north_angle(): """Test the north_angle property on the sun path.""" nyc = Location('New_York', country='USA', latitude=40.72, longitude=-74.02, time_zone=-5) sp = Sunpath.from_location(nyc) sp.north_angle = 90 assert sp.north_angle == 90 sun = sp.calculate_sun(3, 21, 6, True) assert sun.azimuth == approx(90, rel=1e-2) assert sun.is_solar_time assert sun.north_angle == 90 assert sun.position_3d(radius=1).y == approx(1, rel=1e-2) assert sun.position_3d(radius=1).x < 1e-9
def test_daylight_saving(): nyc = Location('New_York', 'USA', latitude=40.72, longitude=-74.02, time_zone=-5) daylight_saving = AnalysisPeriod(st_month=3, st_day=8, end_month=11, end_day=1) sp = Sunpath.from_location(nyc, daylight_saving_period=daylight_saving) dt1 = DateTime(6, 21, 12, 0) dt2 = DateTime(12, 21, 12, 0) assert sp.is_daylight_saving_hour(dt1) assert not sp.is_daylight_saving_hour(dt2)
def test_vs_noaa_sydney(): """Test to be sure that the sun positions align with the NOAA formula.""" sydney = Location('Sydney', country='AUS', latitude=-33.87, longitude=151.22, time_zone=10) sp = Sunpath.from_location(sydney) sun = sp.calculate_sun(month=11, day=15, hour=11.0) assert round(sun.altitude, 2) == 72.26 assert round(sun.azimuth, 2) == 32.37 sun2 = sp.calculate_sun_from_date_time(datetime.datetime(2019, 6, 21, 9)) assert round(sun2.altitude, 2) == 18.99 assert round(sun2.azimuth, 2) == 42.54
def test_analemma_geometry(): """Test the analemma_suns method.""" nyc = Location('New_York', country='USA', latitude=40.72, longitude=-74.02, time_zone=-5) sp = Sunpath.from_location(nyc) radius = 100 analemma_geo = sp.hourly_analemma_polyline3d(radius=radius) assert len(analemma_geo) == 15 for pline in analemma_geo: assert isinstance(pline, Polyline3D) analemma_geo = sp.hourly_analemma_polyline2d(radius=radius) assert len(analemma_geo) == 15 for pline in analemma_geo: assert isinstance(pline, Polyline2D)
def test_analemma_daytime_with_linesegment(): """Test the hourly_analemma_polyline3d with a latitude that yields a line segment.""" test_loc = Location('Test Location', latitude=51, longitude=0) sp = Sunpath.from_location(test_loc) l_seg_count = 0 for pline in sp.hourly_analemma_polyline3d(): if isinstance(pline, LineSegment3D): l_seg_count += 1 assert l_seg_count == 0 l_seg_count = 0 for pline in sp.hourly_analemma_polyline2d(): if isinstance(pline, LineSegment2D): l_seg_count += 1 assert l_seg_count == 0
def from_location_and_analysis_period( cls, location, analysis_period, point_groups, vector_groups=None, hb_objects=None, sub_folder='sunlighthour'): """Create sunlighthours recipe from Location and analysis period.""" vector_groups = vector_groups or () sp = Sunpath.from_location(location) suns = (sp.calculate_sun_from_hoy(hoy) for hoy in analysis_period.float_hoys) sun_vectors = tuple(s.sun_vector for s in suns if s.is_during_day) hoys = tuple(s.hoy for s in suns if s.is_during_day) analysis_grids = cls.analysis_grids_from_points_and_vectors(point_groups, vector_groups) return cls(sun_vectors, hoys, analysis_grids, analysis_period.timestep, hb_objects, sub_folder)
def test_body_dir_from_dir_normal(): """Test body_solar_flux_from_parts gainst its horizontal counterpart.""" wea_obj = Wea.from_epw_file('./tests/epw/chicago.epw') diff_hr = wea_obj.diffuse_horizontal_irradiance.values dir_nr = wea_obj.direct_normal_irradiance.values dir_hr = wea_obj.direct_horizontal_irradiance.values dts = wea_obj.datetimes sp = Sunpath.from_location(wea_obj.location) for i in xrange(8760): sun = sp.calculate_sun_from_date_time(dts[i]) alt, az = sun.altitude, sun.azimuth sharp = sharp_from_solar_and_body_azimuth(az, 180) sflux1 = body_solar_flux_from_parts(diff_hr[i], dir_nr[i], alt, sharp) sflux2 = body_solar_flux_from_horiz_solar(diff_hr[i], dir_hr[i], alt, sharp) assert sflux1 == pytest.approx(sflux2, rel=1e-2)
def _solar_calc(self, hoys, wea, output_type, leap_year=False, reverse_vectors=False): """Calculate sun vectors and radiance values from the properties.""" solar_calc = LBSunpath.from_location(self.location, self.north) solar_calc.is_leap_year = leap_year if not hoys: # set hours to an annual hourly sunpath hoys = range(8760) if not leap_year else range(8760 + 24) sun_up_hours = [] sun_vectors = [] radiance_values = [] altitudes = [] for hour in hoys: sun = solar_calc.calculate_sun_from_hoy(hour) if sun.altitude < 0: continue sun_vectors.append(sun.sun_vector) sun_up_hours.append(hour) altitudes.append(sun.altitude) # calculate irradiance value if wea: # this is a climate_based sunpath. Get the values from wea assert isinstance(wea, Wea), 'Expected Wea not %s' % type(wea) for altitude, hoy in zip(altitudes, sun_up_hours): dnr, dhr = wea.get_irradiance_value_for_hoy(hoy) if dnr == 0: radiance_value = 0 else: radiance_value = gendaylit(altitude, hoy, dnr, dhr, output_type, leap_year) radiance_values.append(int(radiance_value)) else: radiance_values = [1e6] * len(sun_up_hours) if reverse_vectors: sun_vectors = [v.reverse() for v in sun_vectors] return sun_vectors, sun_up_hours, radiance_values
def draw_sunpath(self): """Calculate and draw sun path to Rhino.""" self.clear_conduit() _location = self.epw.location north_ = 0 _centerPt_ = None _scale_ = 1 _sunScale_ = 1 _annual_ = True daylight_saving_period = None # temporary until we fully implement it _hoys_ = range(23) # initiate sunpath based on location sp = Sunpath.from_location(_location, north_, daylight_saving_period) # draw sunpath geometry sunpath_geo = \ sp.draw_sunpath(_hoys_, _centerPt_, _scale_, _sunScale_, _annual_) analemma = sunpath_geo.analemma_curves compass = sunpath_geo.compass_curves daily = sunpath_geo.daily_curves sun_pts = sunpath_geo.sun_geos suns = sunpath_geo.suns vectors = (geo.vector(*sun.sun_vector) for sun in suns) altitudes = (sun.altitude for sun in suns) azimuths = (sun.azimuth for sun in suns) center_pt = _centerPt_ or geo.point(0, 0, 0) hoys = (sun.hoy for sun in suns) datetimes = (sun.datetime for sun in suns) # draw the curves to canvas self.conduit = DrawSunPath( list(analemma) + list(compass) + list(daily), sun_pts) self.conduit.Enabled = True # add lights for sun in suns: light = Rhino.Geometry.Light.CreateSunLight( north_, sun.azimuth - 90, sun.altitude) sc.doc.Lights.Add(light) sc.doc.Views.Redraw()
def _get_altitudes_and_sharps(self): """Get altitudes and sharps from solar position.""" sp = Sunpath.from_location(self._location) _altitudes = [] if self._body_par.body_azimuth is None: _sharps = [self._body_par.sharp] * self._calc_length for t_date in self._base_collection.datetimes: sun = sp.calculate_sun_from_date_time(t_date) _altitudes.append(sun.altitude) else: _sharps = [] for t_date in self._base_collection.datetimes: sun = sp.calculate_sun_from_date_time(t_date) sharp = sharp_from_solar_and_body_azimuth( sun.azimuth, self._body_par.body_azimuth) _sharps.append(sharp) _altitudes.append(sun.altitude) return _altitudes, _sharps
def test_sunrise_sunset(): """Test to be sure that the sunrise/sunset aligns with the NOAA formula.""" sydney = Location('Sydney', country='AUS', latitude=-33.87, longitude=151.22, time_zone=10) sp = Sunpath.from_location(sydney) # use the depression for apparent sunrise/sunset srss_dict = sp.calculate_sunrise_sunset(6, 21, depression=0.8333) assert srss_dict['sunrise'] == DateTime(6, 21, 7, 0) assert srss_dict['noon'] == DateTime(6, 21, 11, 57) assert srss_dict['sunset'] == DateTime(6, 21, 16, 54) # use the depression for actual sunrise/sunset srss_dict = sp.calculate_sunrise_sunset(6, 21, depression=0.5334) assert srss_dict['sunrise'] == DateTime(6, 21, 7, 2) assert srss_dict['noon'] == DateTime(6, 21, 11, 57) assert srss_dict['sunset'] == DateTime(6, 21, 16, 52)
def from_location_and_analysis_period( cls, location, analysis_period, point_groups, vector_groups=None, hb_objects=None, sub_folder='sunlighthour' ): """Create sunlighthours recipe from Location and analysis period.""" vector_groups = vector_groups or () sp = Sunpath.from_location(location) suns = (sp.calculate_sun_from_hoy(hoy) for hoy in analysis_period.float_hoys) sun_vectors = tuple(s.sun_vector for s in suns if s.is_during_day) hoys = tuple(s.hoy for s in suns if s.is_during_day) analysis_grids = cls.analysis_grids_from_points_and_vectors(point_groups, vector_groups) return cls(sun_vectors, hoys, analysis_grids, analysis_period.timestep, hb_objects, sub_folder)
def from_location_and_hoys(cls, location, hoys, point_groups, vector_groups=[], timestep=1, hb_objects=None, sub_folder='sunlighthour'): """Create sunlighthours recipe from Location and hours of year.""" sp = Sunpath.from_location(location) suns = tuple(sp.calculate_sun_from_hoy(hoy) for hoy in hoys) sun_vectors = tuple(s.sun_vector for s in suns if s.is_during_day) sun_up_hoys = tuple(s.hoy for s in suns if s.is_during_day) analysis_grids = cls.analysis_grids_from_points_and_vectors( point_groups, vector_groups) return cls(sun_vectors, sun_up_hoys, analysis_grids, timestep, hb_objects, sub_folder)
def test_analemma_suns(): """Test the analemma_suns method.""" nyc = Location('New_York', country='USA', latitude=40.72, longitude=-74.02, time_zone=-5) sp = Sunpath.from_location(nyc) assert len(sp.analemma_suns(Time(12), True, True)) == 12 assert len(sp.analemma_suns(Time(6), True, True)) == 7 assert len(sp.analemma_suns(Time(0), True, True)) == 0 assert len(sp.analemma_suns(Time(6), False, True)) == 12 assert len(sp.analemma_suns(Time(0), False, True)) == 12 for sun in sp.analemma_suns(Time(12)): assert isinstance(sun, Sun) assert len(sp.hourly_analemma_suns()) == 24 for hr in sp.hourly_analemma_suns(): for sun in hr: assert isinstance(sun, Sun)
def test_daylight_saving(): """Test the applicaiton of daylight saving time.""" nyc = Location('New_York', country='USA', latitude=40.72, longitude=-74.02, time_zone=-5) daylight_saving = AnalysisPeriod(st_month=3, st_day=8, st_hour=2, end_month=11, end_day=1, end_hour=2) sp = Sunpath.from_location(nyc, daylight_saving_period=daylight_saving) dt1 = DateTime(6, 21, 12, 0) dt2 = DateTime(12, 21, 12, 0) dt3 = DateTime(6, 21, 0) dt4 = DateTime(12, 21, 0) assert sp.is_daylight_saving_hour(dt1) assert not sp.is_daylight_saving_hour(dt2) assert sp.is_daylight_saving_hour(dt3) assert not sp.is_daylight_saving_hour(dt4) sun1ds = sp.calculate_sun_from_date_time(dt1) sun2ds = sp.calculate_sun_from_date_time(dt2) sun3ds = sp.calculate_sun_from_date_time(dt3) sun4ds = sp.calculate_sun_from_date_time(dt4) sp.daylight_saving_period = None assert sun1ds != sp.calculate_sun_from_date_time(dt1) assert sun3ds != sp.calculate_sun_from_date_time(dt3) assert sun1ds.altitude == \ approx(sp.calculate_sun_from_date_time(dt1.sub_hour(1)).altitude, rel=1e-2) assert sun3ds.altitude == \ approx(sp.calculate_sun_from_date_time(dt3.sub_hour(1)).altitude, rel=1e-2) sun2 = sp.calculate_sun_from_date_time(dt2) sun4 = sp.calculate_sun_from_date_time(dt4) assert sun2 == sun2ds assert sun4 == sun4ds
def process(self): if not any(socket.is_linked for socket in self.outputs): return location_s = self.inputs['Location'].sv_get() month_s = self.inputs['Month'].sv_get() day_s = self.inputs['Day'].sv_get() hour_s = self.inputs['Hour'].sv_get() altitude_s, azimuth_s = [], [] sun_pos = [] for location, months, days, hours in zip_long_repeat( location_s, month_s, day_s, hour_s): sp = Sunpath.from_location(location) # sp = Sunpath.from_location(location, north_angle=40) altitude, azimuth = [], [] for mo, day, ho in zip_long_repeat(months, days, hours): sun = sp.calculate_sun(month=mo, day=day, hour=ho) alt_l = sun.altitude azi_l = sun.azimuth altitude.append(sun.altitude) azimuth.append(sun.azimuth) angles = (alt_l * pi / 180, 0, -azi_l * pi / 180 + self.north_angle * pi / 180) euler = Euler(angles, 'XYZ') mat_r = euler.to_quaternion().to_matrix().to_4x4() pos = mat_r @ Vector((0, self.sun_dist, 0)) mat_t = Matrix.Translation(pos) angles = ((90 - alt_l) * pi / 180, 0, (180 - azi_l) * pi / 180 + self.north_angle * pi / 180) euler = Euler(angles, 'XYZ') mat_r = euler.to_quaternion().to_matrix().to_4x4() m = mat_t @ mat_r sun_pos.append(m) altitude_s.append(altitude) azimuth_s.append(azimuth) self.outputs['Altitude'].sv_set(altitude_s) self.outputs['Azimuth'].sv_set(azimuth_s) self.outputs['Sun Position'].sv_set(sun_pos)
def from_location_sun_up_hours(cls, location, sun_up_hours, north=0, is_leap_year=False): """Generate a radiance-based analemma for a location. Args: location: A ladybug location. sun_up_hours: A list of hours of the year to be included in analemma. north: North angle from Y direction (default: 0). is_leap_year: A boolean to indicate if hours are for a leap year (default: False). """ sun_vectors = [] north = north or 0 sp = Sunpath.from_location(location, north) sp.is_leap_year = is_leap_year for hour in sun_up_hours: sun = sp.calculate_sun_from_hoy(hour) sun_vectors.append(sun.sun_vector) return cls(sun_vectors, sun_up_hours)
def from_location(cls, location, hoys=None, north=0): """Generate a radiance-based analemma for a location. Args: location: A ladybug location. hoys: A list of hours of the year (default: range(8760)). north: North angle from Y direction (default: 0). """ sun_vectors = [] sun_up_hours = [] hoys = hoys or range(8760) north = north or 0 sp = Sunpath.from_location(location, north) for hour in hoys: sun = sp.calculate_sun_from_hoy(hour) if sun.altitude < 0: continue sun_vectors.append(sun.sun_vector) sun_up_hours.append(hour) return cls(sun_vectors, sun_up_hours)
def _calculate_solar_values(wea, hoys, output_type, north=0, is_leap_year=False): """Calculate solar values for requested hours of the year. This method is called everytime that output type is set. """ month_date_time = (DateTime.from_hoy(idx, is_leap_year) for idx in hoys) sp = Sunpath.from_location(wea.location, north) sp.is_leap_year = is_leap_year solar_values = [] sun_up_hours = [] # use gendaylit to calculate radiation values for each hour. print('Calculating solar values...') for timecount, dt in enumerate(month_date_time): month, day, hour = dt.month, dt.day, dt.float_hour sun = sp.calculate_sun(month, day, hour) if sun.altitude < 0: continue else: dnr, dhr = wea.get_irradiance_value(month, day, hour) if dnr == 0: solarradiance = 0 else: solarradiance = \ int(gendaylit(sun.altitude, month, day, hour, dnr, dhr, output_type)) solar_values.append(solarradiance) # keep the number of hour relative to hoys in this sun matrix sun_up_hours.append(dt.hoy) return solar_values, sun_up_hours
def test_day_arc_geometry(): """Test the day_arc3d method.""" nyc = Location('New_York', country='USA', latitude=40.72, longitude=-74.02, time_zone=-5) sp = Sunpath.from_location(nyc) radius = 100 arc_geo = sp.day_arc3d(3, 21, radius=radius) assert isinstance(arc_geo, Arc3D) assert arc_geo.length == approx(math.pi * radius, rel=1e-2) arc_geo = sp.day_polyline2d(3, 21, radius=radius) assert isinstance(arc_geo, Polyline2D) arc_geo = sp.monthly_day_arc3d(radius=radius) assert len(arc_geo) == 12 for pline in arc_geo: assert isinstance(pline, Arc3D) arc_geo = sp.monthly_day_polyline2d(radius=radius) assert len(arc_geo) == 12 for pline in arc_geo: assert isinstance(pline, Polyline2D)
def test_split_modifiers(): ap = AnalysisPeriod(timestep=4) sp = Sunpath(location) lb_sp = LBSunpath.from_location(location) folder = './tests/assets/temp' filename = 'sunpath_timestep_4' sp.to_file(folder, filename, hoys=ap.hoys) sp_file = os.path.join(folder, '%s.rad' % filename) sp_mod_files = [ os.path.join(folder, '%s_%d.mod' % (filename, count)) for count in range(2) ] assert os.path.isfile(sp_file) lb_tot = [ i for i in ap.hoys if lb_sp.calculate_sun_from_hoy(i).is_during_day ] sun_count = [int(len(lb_tot) / 2) - 1, int(len(lb_tot) / 2)] for sp_count, sp_mod_file in enumerate(sp_mod_files): assert os.path.isfile(sp_mod_file) with open(sp_mod_file) as inf: for count, _ in enumerate(inf): pass assert count == sun_count[sp_count]
def oiko_make_epw(api_key, city, country, latitude, longitude, year): ''' Args:} api_key: User API key for OikoLab. city: city name as string country: country name as string. latitude: Location latitude between -90 and 90 longitude: Location longitude between -180 (west) and 180 (east) year: year between 1980 and 2019 ''' parameters = [ 'temperature', 'dewpoint_temperature', 'surface_solar_radiation', 'surface_thermal_radiation', 'surface_direct_solar_radiation', 'surface_diffuse_solar_radiation', 'relative_humidity', 'wind_speed', 'surface_pressure', 'total_cloud_cover' ] location = Location(city=city, country=country, latitude=latitude, longitude=longitude) # create the payload payload = { 'param': parameters, 'start': '{}-01-01T00:00:00'.format(year), 'end': '{}-12-31T23:00:00'.format(year), 'lat': location.latitude, 'lon': location.longitude, } # make the request r = requests.get('https://api.oikolab.com/weather', params=payload, headers={ 'content-encoding': 'gzip', 'Connection': 'close', 'api-key': '{}'.format(api_key) }) if r.status_code == 200: attributes = r.json()['attributes'] weather_data = json.loads(r.json()['data']) else: print(r.text) return None # set the UTC offset on the location based on the request location.time_zone = attributes['utc_offset'] leap_yr = True if year % 4 == 0 else False # create a dictionary of timeseries data streams data_dict = {} data_values = zip(*weather_data['data']) for param, data in zip(parameters, data_values): data_dict[param] = data # compute solar radiation components and estimate illuminance from irradiance datetimes = AnalysisPeriod(is_leap_year=leap_yr).datetimes direct_normal_irr = [] gh_ill = [] dn_ill = [] dh_ill = [] sp = Sunpath.from_location(location) sp.is_leap_year = leap_yr for dt, glob_hr, dir_hr, dif_hr, dp in zip( datetimes, data_dict['surface_solar_radiation'], data_dict['surface_direct_solar_radiation'], data_dict['surface_diffuse_solar_radiation'], data_dict['dewpoint_temperature']): sun = sp.calculate_sun_from_date_time(dt) alt = sun.altitude dir_nr = dir_hr / math.sin(math.radians(alt)) if alt > 1 else 0 direct_normal_irr.append(dir_nr) gh, dn, dh, z = estimate_illuminance_from_irradiance( alt, glob_hr, dir_nr, dif_hr, dp) gh_ill.append(gh) dn_ill.append(dn) dh_ill.append(dh) # create the EPW object and set properties epw = EPW.from_missing_values(is_leap_year=leap_yr) epw.location = location epw.years.values = [year] * 8760 if not leap_yr else [year] * 8784 epw.dry_bulb_temperature.values = data_dict['temperature'] epw.dew_point_temperature.values = data_dict['dewpoint_temperature'] epw.global_horizontal_radiation.values = data_dict[ 'surface_solar_radiation'] epw.direct_normal_radiation.values = direct_normal_irr epw.diffuse_horizontal_radiation.values = data_dict[ 'surface_diffuse_solar_radiation'] epw.global_horizontal_illuminance.values = gh_ill epw.direct_normal_illuminance.values = dn_ill epw.diffuse_horizontal_illuminance.values = dh_ill epw.horizontal_infrared_radiation_intensity.values = data_dict[ 'surface_thermal_radiation'] epw.relative_humidity.values = [ val * 100.0 for val in data_dict['relative_humidity'] ] epw.atmospheric_station_pressure.values = data_dict['surface_pressure'] epw.total_sky_cover.values = data_dict['total_cloud_cover'] epw.wind_speed.values = data_dict['wind_speed'] # write EPW to a file file_path = os.path.join(folders.default_epw_folder, '{}_{}.epw'.format(location.city, year)) epw.save(file_path) print('EPW file generated and saved to - %s' % file_path) return file_path
projection_ = projection_.title() if projection_ is not None else None # create a intersection of the input hoys_ and the data hoys if len(data_) > 0 and len(hoys_) > 0: all_aligned = all(data_[0].is_collection_aligned(d) for d in data_[1:]) assert all_aligned, 'All collections input to data_ must be aligned for ' \ 'each Sunpath.\nGrafting the data_ and suplying multiple grafted ' \ '_center_pt_ can be used to view each data on its own path.' if statement_ is not None: data_ = HourlyContinuousCollection.filter_collections_by_statement( data_, statement_) data_hoys = set(dt.hoy for dt in data_[0].datetimes) hoys_ = list(data_hoys.intersection(set(hoys_))) # initialize sunpath based on location sp = Sunpath.from_location(_location, north_, dl_saving_) # process all of the input hoys into altitudes, azimuths and vectors altitudes, azimuths, datetimes, moys, hoys, vectors, suns = [], [], [], [], [], [], [] for hoy in hoys_: sun = sp.calculate_sun_from_hoy(hoy, solar_time_) if sun.is_during_day: altitudes.append(sun.altitude) azimuths.append(sun.azimuth) datetimes.append(sun.datetime) moys.append(sun.datetime.moy) hoys.append(sun.datetime.hoy) vectors.append(from_vector3d(sun.sun_vector)) suns.append(sun) if len(data_) > 0 and len(
def sun_altitude(epw_file): epw = EPW(epw_file) sun_path = Sunpath.from_location(epw.location) return np.array( [sun_path.calculate_sun_from_hoy(i).altitude for i in range(8760)])
def execute(self, working_dir, reuse=True): """Generate sun matrix. Args: working_dir: Folder to execute and write the output. reuse: Reuse the matrix if already existed in the folder. Returns: Full path to analemma, sunlist and sun_matrix. """ fp = os.path.join(working_dir, self.analemmafile) lfp = os.path.join(working_dir, self.sunlistfile) mfp = os.path.join(working_dir, self.sunmtxfile) hrf = os.path.join(working_dir, self.name + '.hrs') output_type = self.sky_type if reuse: if self.hours_match(hrf): for f in (fp, lfp, mfp): if not os.path.isfile(f): break else: return fp, lfp, mfp with open(hrf, 'wb') as outf: outf.write(','.join(str(h) for h in self.hoys) + '\n') wea = self.wea month_date_time = (DateTime.from_hoy(idx) for idx in self.hoys) latitude, longitude = wea.location.latitude, -wea.location.longitude sp = Sunpath.from_location(wea.location, self.north) solarradiances = [] sun_values = [] sun_up_hours = [] # collect hours that sun is up solarstring = \ 'void light solar{0} 0 0 3 {1} {1} {1} ' \ 'solar{0} source sun 0 0 4 {2:.6f} {3:.6f} {4:.6f} 0.533' # use gendaylit to calculate radiation values for each hour. print('Calculating sun positions and radiation values.') count = 0 for timecount, timeStamp in enumerate(month_date_time): month, day, hour = timeStamp.month, timeStamp.day, timeStamp.hour + 0.5 dnr, dhr = int(wea.direct_normal_radiation[timeStamp.int_hoy]), \ int(wea.diffuse_horizontal_radiation[timeStamp.int_hoy]) if dnr == 0: continue count += 1 sun = sp.calculate_sun(month, day, hour) if sun.altitude < 0: continue x, y, z = sun.sun_vector solarradiance = \ int(gendaylit(sun.altitude, month, day, hour, dnr, dhr, output_type)) cur_sun_definition = solarstring.format(count, solarradiance, -x, -y, -z) solarradiances.append(solarradiance) sun_values.append(cur_sun_definition) # keep the number of hour relative to hoys in this sun matrix sun_up_hours.append(timecount) sun_count = len(sun_up_hours) assert sun_count > 0, ValueError('There is 0 sun up hours!') print('# Number of sun up hours: %d' % sun_count) print('Writing sun positions and radiation values to {}'.format(fp)) # create solar discs. with open(fp, 'w') as annfile: annfile.write("\n".join(sun_values)) annfile.write('\n') print('Writing list of suns to {}'.format(lfp)) # create list of suns. with open(lfp, 'w') as sunlist: sunlist.write("\n".join( ("solar%s" % (idx + 1) for idx in xrange(sun_count)))) sunlist.write('\n') # Start creating header for the sun matrix. file_header = ['#?RADIANCE'] file_header += ['Sun matrix created by Honeybee'] file_header += ['LATLONG= %s %s' % (latitude, -longitude)] file_header += ['NROWS=%s' % sun_count] file_header += ['NCOLS=%s' % len(self.hoys)] file_header += ['NCOMP=3'] file_header += ['FORMAT=ascii'] print('Writing sun matrix to {}'.format(mfp)) # Write the matrix to file. with open(mfp, 'w') as sunMtx: sunMtx.write('\n'.join(file_header) + '\n' + '\n') for idx, sunValue in enumerate(solarradiances): sun_rad_list = ['0 0 0'] * len(self.hoys) sun_rad_list[sun_up_hours[idx]] = '{0} {0} {0}'.format( sunValue) sunMtx.write('\n'.join(sun_rad_list) + '\n\n') sunMtx.write('\n') return fp, lfp, mfp
def post_process_solar_tracking(result_folders, sun_up_file, location, north=0, tracking_increment=5, destination_folder=None): """Postprocess a list of result folders to account for dynamic solar tracking. This function essentially takes .ill files for each state of a dynamic tracking system and produces a single .ill file that models the tracking behavior. Args: result_folders: A list of folders containing .ill files and each representing a state of the dynamic solar tracking system. These file should be ordered from eastern-most to wester-most, tracing the path of the tracking system over the day. The names of the .ill files should be the same in each folder (representing the same sensor grid in a different state). sun_up_file: Path to a sun-up-hours.txt that contains the sun-up hours of the simulation. location: A Ladybug Location object to be used to generate sun poisitions. north_: A number between -360 and 360 for the counterclockwise difference between the North and the positive Y-axis in degrees. (Default: 0). tracking_increment: An integer for the increment angle of each state in degrees. (Default: 5). destination_folder: A path to a destination folder where the final .ill files of the dynamic tracking system will be written. If None, all files will be written into the directory above the first result_folder. (Default: None). """ # get the orientation angles of the panels for each model st_angle = int(90 - (len(result_folders) * tracking_increment / 2)) + 1 end_angle = int(90 + (len(result_folders) * tracking_increment / 2)) angles = list(range(st_angle, end_angle, tracking_increment)) # create a sun path ang get the sun-up hours to be used to get solar positions sp = Sunpath.from_location(location, north) with open(sun_up_file) as suh_file: sun_up_hours = [float(hour) for hour in suh_file.readlines()] # for each hour of the sun_up_hours, figure out which file is the one to use mtx_to_use, ground_vec = [], Vector3D(1, 0, 0) for hoy in sun_up_hours: sun = sp.calculate_sun_from_hoy(hoy) vec = Vector3D(sun.sun_vector_reversed.x, 0, sun.sun_vector_reversed.z) orient = math.degrees(ground_vec.angle(vec)) for i, ang in enumerate(angles): if ang > orient: mtx_to_use.append(i) break else: mtx_to_use.append(-1) # parse the grids_info in the first folder to understand the sensor grids grids_info_file = os.path.join(result_folders[0], 'grids_info.json') with open(grids_info_file) as gi_file: grids_data = json.load(gi_file) grid_ids = [g['full_id'] for g in grids_data] # prepare the destination folder and copy the grids_info to it if destination_folder is None: destination_folder = os.path.dirname(result_folders[0]) if not os.path.isdir(destination_folder): os.mkdir(destination_folder) shutil.copyfile(grids_info_file, os.path.join(destination_folder, 'grids_info.json')) # convert the .ill files of each sensor grid into a single .ill file for grid_id in grid_ids: grid_mtx = [] for i, model in enumerate(result_folders): grid_file = os.path.join(model, '{}.ill'.format(grid_id)) with open(grid_file) as ill_file: grid_mtx.append([lin.split() for lin in ill_file]) grid_ill = [] for i, hoy_mtx in enumerate(mtx_to_use): hoy_vals = [] for pt in range(len(grid_mtx[0])): hoy_vals.append(grid_mtx[hoy_mtx][pt][i]) grid_ill.append(hoy_vals) dest_file = os.path.join(destination_folder, '{}.ill'.format(grid_id)) with open(dest_file, 'w') as ill_file: for row in zip(*grid_ill): ill_file.write(' '.join(row) + '\n')
) # create the points representing the human geometry human_points = [] human_line = [] for pos in _position: hpts, hlin = human_height_points(pos, _height_, _pt_count_) human_points.extend(hpts) human_line.append(hlin) if _run: # mesh the context for the intersection calculation shade_mesh = join_geometry_to_mesh(_context) # generate the sun vectors for each sun-up hour of the year sp = Sunpath.from_location(_location, north_) sun_vecs = [] day_pattern = [] for hoy in range(8760): sun = sp.calculate_sun_from_hoy(hoy) day_pattern.append(sun.is_during_day) if sun.is_during_day: sun_vecs.append(from_vector3d(sun.sun_vector_reversed)) # intersect the sun vectors with the context and compute fraction exposed sun_int_matrix, angles = intersect_mesh_rays(shade_mesh, human_points, sun_vecs, cpu_count=workers) fract_body_exp = [] for i in range(0, len(human_points), _pt_count_):
north_, _location, _hoys_, _centerPt_, _scale_, _sunScale_, _annual_ = IN vectors = altitudes = azimuths = sunPts = analemma = compass = daily = centerPt = hoys = datetimes = None try: from ladybug.sunpath import Sunpath import ladybug.geometry as geo except ImportError as e: raise ImportError('\nFailed to import ladybug:\n\t{}'.format(e)) if _location: daylightSavingPeriod = None # temporary until we fully implement it _hoys_ = _hoys_ or () # initiate sunpath based on location sp = Sunpath.from_location(_location, north_, daylightSavingPeriod) # draw sunpath geometry sunpath_geo = \ sp.draw_sunpath(_hoys_, _centerPt_, _scale_, _sunScale_, _annual_) analemma = sunpath_geo.analemma_curves compass = sunpath_geo.compass_curves daily = sunpath_geo.daily_curves sunPts = sunpath_geo.sun_geos suns = sunpath_geo.suns vectors = (geo.vector(*sun.sun_vector) for sun in suns) altitudes = (sun.altitude for sun in suns) azimuths = (sun.azimuth for sun in suns)
def shortwave_mrt_map(location, longwave_data, sun_up_hours, total_ill, direct_ill, ref_ill=None, solarcal_par=None): """Get MRT data collections adjusted for shortwave using Radiance .ill files. Args: location: A ladybug Location object to dictate the solar positions used in the calculation. longwave_data: An array of data collections for each point within a thermal map. All collections must be aligned with one another. The analysis period on the collections does not have to be annual. sun_up_hours: File path to a sun-up-hours.txt file output by Radiance. total_ill: Path to an .ill file output by Radiance containing total irradiance for each longwave_data collection. direct_ill: Path to an .ill file output by Radiance containing direct irradiance for each longwave_data collection. ref_ill: Path to an .ill file output by Radiance containing total ground- reflected irradiance for each longwave_data collection. If None, a default ground reflectance of 0.25 will be assumed. solarcal_par: Optional SolarCalParameter object to account for properties of the human geometry. """ # determine the analysis period and open the sun_up_hours file a_per = longwave_data[0].header.analysis_period is_annual, t_step, lp_yr = a_per.is_annual, a_per.timestep, a_per.is_leap_year with open(sun_up_hours) as soh_f: sun_indices = [int(float(h) * t_step) for h in soh_f] # parse each of the .ill files into annual irradiance data collections total = _ill_file_to_data(total_ill, sun_indices, t_step, lp_yr) direct = _ill_file_to_data(direct_ill, sun_indices, t_step, lp_yr) ref = _ill_file_to_data(ref_ill, sun_indices, t_step, lp_yr) \ if ref_ill is not None else None # if the analysis is not annual, apply analysis periods if not is_annual: total = [data.filter_by_analysis_period(a_per) for data in total] direct = [data.filter_by_analysis_period(a_per) for data in direct] if ref is not None: ref = [data.filter_by_analysis_period(a_per) for data in ref] # convert total irradiance into indirect irradiance indirect = [t_rad - d_rad for t_rad, d_rad in zip(total, direct)] # compute solar altitudes and sharps body_par = SolarCalParameter() if solarcal_par is None else solarcal_par sp = Sunpath.from_location(location) _altitudes = [] if body_par.body_azimuth is None: _sharps = [body_par.sharp] * len(a_per) for t_date in a_per.datetimes: sun = sp.calculate_sun_from_date_time(t_date) _altitudes.append(sun.altitude) else: _sharps = [] for t_date in a_per.datetimes: sun = sp.calculate_sun_from_date_time(t_date) sharp = sharp_from_solar_and_body_azimuth(sun.azimuth, body_par.body_azimuth) _sharps.append(sharp) _altitudes.append(sun.altitude) # pass all data through the solarcal collections and return MRT data collections mrt_data = [] if ref is not None: # fully-detailed SolarCal with ground reflectance for l_mrt, d_rad, i_rad, r_rad in zip(longwave_data, direct, indirect, ref): scl_obj = _HorizontalRefSolarCalMap(_altitudes, _sharps, d_rad, i_rad, r_rad, l_mrt, None, body_par) mrt_data.append(scl_obj.mean_radiant_temperature) else: # simpler SolarCal assuming default ground reflectance for l_mrt, d_rad, i_rad in zip(longwave_data, direct, indirect): scl_obj = _HorizontalSolarCalMap(_altitudes, _sharps, d_rad, i_rad, l_mrt, None, None, body_par) mrt_data.append(scl_obj.mean_radiant_temperature) return mrt_data