Source code for ladybug.location

# coding=utf-8
"""Ladybug location."""
from __future__ import division

import re


[docs]class Location(object): """Ladybug Location. Args: city: Name of the city as a string. state: Optional state in which the city is located. country: Name of the country as a string. latitude: Location latitude between -90 and 90 (Default: 0). longitude: Location longitude between -180 (west) and 180 (east) (Default: 0). time_zone: Time zone between -12 hours (west) and +14 hours (east). If None, the time zone will be an estimated integer value derived from the longitude in accordance with solar time (Default: None). elevation: A number for elevation of the location in meters. (Default: 0). station_id: ID of the location if the location is representing a weather station. source: Source of data (e.g. TMY, TMY3). Properties: * city * country * elevation * latitude * longitude * meridian * source * state * station_id * time_zone * is_default """ __slots__ = ('city', 'state', 'country', '_lat', '_lon', '_tz', '_elev', 'station_id', 'source') def __init__(self, city=None, state=None, country=None, latitude=0, longitude=0, time_zone=None, elevation=0, station_id=None, source=None): """Create a Ladybug location.""" self.city = '-' if not city else str(city) self.state = '-' if not state else str(state) self.country = '-' if not country else str(country) self.latitude = latitude or 0 self.longitude = longitude or 0 self.time_zone = time_zone self.elevation = elevation or 0 self.station_id = None if not station_id else str(station_id) self.source = source
[docs] @classmethod def from_dict(cls, data): """Create a location from a dictionary. Args: data: A python dictionary in the following format .. code-block:: python { "city": "-", "latitude": 0, "longitude": 0, "time_zone": 0, "elevation": 0 } """ optional_keys = ('city', 'state', 'country', 'latitude', 'longitude', 'time_zone', 'elevation', 'station_id', 'source') auto_dict = {'type': 'Autocalculate'} for key in optional_keys: if key not in data or data[key] == auto_dict: data[key] = None return cls(data['city'], data['state'], data['country'], data['latitude'], data['longitude'], data['time_zone'], data['elevation'], data['station_id'], data['source'])
[docs] @classmethod def from_location(cls, location): """Try to create a Ladybug location from a location string. Args: locationString: Location string Usage: .. code-block:: python l = Location.from_location(locationString) """ if not location: return cls() try: if isinstance(location, Location): # Ladybug location return location elif hasattr(location, 'Latitude'): # Revit's location return cls(city=str(location.Name.replace(",", " ")), latitude=location.Latitude, longitude=location.Longitude) elif location.startswith('Site:'): return cls.from_idf(location) else: try: city, latitude, longitude, time_zone, elevation = \ [key.split(":")[-1].strip() for key in location.split(",")] except ValueError: # it's just the city name return cls(city=location) return cls(city=city, country=None, latitude=latitude, longitude=longitude, time_zone=time_zone, elevation=elevation) except Exception as e: raise ValueError( "Failed to create a Location from %s!\n%s" % (location, e))
[docs] @classmethod def from_idf(cls, idf_string): """Create a Ladybug location from an EnergyPlus IDF string. Args: idf_string: A full IDF string representing a Site:Location. """ # format the object into a list of properties idf_string = idf_string.strip() assert idf_string.startswith('Site:Location'), 'Expected Site' \ ':Location but received a different object: {}'.format(idf_string) idf_string = idf_string.replace(';', ',') idf_string = re.sub(r'!.*\n', '', idf_string) ep_fields = [e_str.strip() for e_str in idf_string.split(',')] ep_fields.pop(0) # remove the EnergyPlus object name return cls(city=ep_fields[0], latitude=ep_fields[1], longitude=ep_fields[2], time_zone=ep_fields[3], elevation=ep_fields[4])
@property def latitude(self): """Get or set the location latitude in degrees.""" return self._lat @latitude.setter def latitude(self, lat): self._lat = 0 if not lat else float(lat) assert -90 <= self._lat <= 90, \ 'latitude must be between -90 and 90. Got {}.'.format(self._lat) @property def longitude(self): """Get or set the location longitude in degrees.""" return self._lon @longitude.setter def longitude(self, lon): self._lon = 0 if not lon else float(lon) assert -180 <= self._lon <= 180, \ 'longitude must be between -180 and 180. Got {}.'.format(self._lon) @property def time_zone(self): """Get or set the location time zone as a number between -12 and +14.""" return self._tz @time_zone.setter def time_zone(self, tz): self._tz = round(self._lon / 15) if tz is None else float(tz) assert -12 <= self._tz <= 14, \ 'Time zone must be between -12 and +14 Got {}.'.format(self._tz) @property def elevation(self): """Get or set a number for the location elevation in meters.""" return self._elev @elevation.setter def elevation(self, elev): try: self._elev = float(elev) except TypeError: raise ValueError("Failed to convert {} to an elevation".format(elev)) @property def meridian(self): """Get a number between -180 and +180 for the meridian west of Greenwich.""" return -15 * self.time_zone @property def is_default(self): """Get a boolean for whether the Location properties are defaulted.""" return self.latitude == 0 and self.longitude == 0 and self.elevation == 0
[docs] def duplicate(self): """Duplicate location.""" return self.__copy__()
[docs] def to_idf(self): """Get the Location as an EnergyPlus IDF string.""" return "Site:Location,\n " + \ self.city + ',\n ' + \ str(self.latitude) + ', !Latitude\n ' + \ str(self.longitude) + ', !Longitude\n ' + \ str(self.time_zone) + ', !Time Zone\n ' + \ str(self.elevation) + '; !Elevation'
[docs] def to_dict(self): """Get location as a a dictionary.""" return { "city": self.city, "state": self.state, "country": self.country, "latitude": self.latitude, "longitude": self.longitude, "time_zone": self.time_zone, "elevation": self.elevation, "station_id": self.station_id, "source": self.source, "type": 'Location' }
[docs] def ToString(self): """Overwrite .NET ToString.""" return self.__repr__()
def __copy__(self): return Location(self.city, self.state, self.country, self.latitude, self.longitude, self.time_zone, self.elevation, self.station_id, self.source) def __key(self): """A tuple based on the object properties, useful for hashing.""" return (self.city, self.state, self.country, self.latitude, self.longitude, self.time_zone, self.elevation, self.station_id, self.source) def __hash__(self): return hash(self.__key()) def __eq__(self, other): return isinstance(other, Location) and self.__key() == other.__key() def __ne__(self, other): return not self.__eq__(other) def __str__(self): """Return location as a string.""" return "%s" % (self.to_idf()) def __repr__(self): """Return location as a string.""" # Tehran, lat:36, lon:34, tz:3.5, elev:54 return "%s, lat:%.2f, lon:%.2f, tz:%.1f, elev:%.2f" % ( self.city, self.latitude, self.longitude, self.time_zone, self.elevation)