Top

ladybugdynamo.ladybug.epw module

import os
import core

class EPW:
    def __init__(self, epwFileAddress = None):
        """
        Import epw data from a local epw file

        epwFileAddress: Local file address to an epw file

        """
        if not epwFileAddress: return
        self.fileAddress = self.checkEpwFileAddress(epwFileAddress)
        self.filePath, self.fileName = os.path.split(self.fileAddress)
        self.__isDataLoaded = False
        self.__isLocationLoaded = False
        self.__data = dict()
        self.epwHeader = None
        self.numOfFields = 35 # it is 35 for TMY3 files

    @property
    def isDataLoaded(self):
        return self.__isDataLoaded

    @property
    def isLocationLoaded(self):
        return self.__isLocationLoaded

    @staticmethod
    def checkEpwFileAddress(epwFileAddress):
        """ Checks the path and checks the type for an epw file"""
        if not os.path.isfile(epwFileAddress):
            raise Exception(epwFileAddress + ' is not a valid address.')
        if not epwFileAddress.lower().endswith('epw'):
            raise Exception(epwFileAddress + ' is not an .epw file.')
        return epwFileAddress

    @property
    def location(self):
        if not self.isLocationLoaded: self.importData(True)
        return self.stationLocation

    #TODO: import EPW header. Currently I just ignore header data
    def importData(self, onlyImportLocation = False):
        """
        imports data from an epw file.
        Hourly data will be saved in self.data and location data
        will be saved in self.location
        """

        with open(self.fileAddress, 'rb') as epwin:
            epwlines = epwin.readlines()

        # import location data
        # first line has location data - Here is an example
        # LOCATION,Denver Centennial  Golden   Nr,CO,USA,TMY3,724666,39.74,-105.18,-7.0,1829.0
        if not self.__isLocationLoaded:
            locationData = epwlines[0].strip().split(',')
            self.stationLocation = core.Location()
            self.stationLocation.city = locationData[1]
            self.stationLocation.state = locationData[2]
            self.stationLocation.country = locationData[3]
            self.stationLocation.source = locationData[4]
            self.stationLocation.stationId = locationData[5]
            self.stationLocation.latitude = float(locationData[6])
            self.stationLocation.longitude = float(locationData[7])
            self.stationLocation.timeZone = float(locationData[8])
            self.stationLocation.elevation = float(locationData[9])

            self.__isLocationLoaded = True
            if onlyImportLocation: return

        # TODO: create an object from the header and analyze data
        # get epw header
        self.epwHeader = epwlines[:8]

        self.numOfFields = len(epwlines[8].strip().split(','))
        # import hourly data
        analysisPeriod = core.AnalysisPeriod()
        for fieldNumber in range(0, self.numOfFields):
            # create header
            field = EPWDataTypes.get_fieldByNumber(fieldNumber)
            header = core.LBHeader(city = self.stationLocation.city, frequency ='Hourly', \
                    analysisPeriod = analysisPeriod, \
                    dataType = field.name, unit =field.units)

            # create an empty data list with the header
            self.__data[fieldNumber] = core.DataList(header =header)

        for line in epwlines[8:]:
            data = line.strip().split(',')

            year, month, day, hour = map(int, data[:4])
            # in an epw file year can be different for each month
            # since I'm using this timestamp as the key and will be using it for sorting
            # I'm setting it up to 2000 - the real year will be collected under modelYear
            timestamp = core.LBDateTime(month, day, hour)

            for fieldNumber in range(0, self.numOfFields):
                valueType = EPWDataTypes.get_fieldByNumber(fieldNumber).valueType
                value = map(valueType, [data[fieldNumber]])[0]
                self.__data[fieldNumber].append(core.LBData(value, timestamp))

        del(epwlines)
        self.__isDataLoaded = True

    def __get_dataByField(self, fieldNumber):
        """Return a data field by field number
        This is a useful method to get the values for fields that Ladybug currently
        doesn't import by default. You can find list of fields by typing EPWDataTypes.fields

        Args:
            fieldNumber: a value between 0 to 34 for different available epw fields.

        Returns:
            An annual Ladybug list
        """
        if not self.isDataLoaded: self.importData()

        # check input data
        if not 0 <= fieldNumber < self.numOfFields:
            raise ValueError("Field number should be between 0-%d"%self.numOfFields)

        return self.__data[fieldNumber]

    # TODO: Add utility library to check file path, filename, etc
    def save(self, filePath = None, fileName = None):
        """Save epw object as an epw file"""
        # check filePath
        if not filePath:
            filePath = self.filePath

        if not fileName:
            fileName = ".".join((self.fileName).split(".")[:-1]) + "_modified.epw"

        fullPath = os.path.join(filePath, fileName)

        # load data if it's  not loaded
        if not self.isDataLoaded: self.importData()

        # write the file
        with open(fullPath, 'wb') as modEpwFile:
            modEpwFile.writelines(self.epwHeader)

            try:
                lines = []
                for hour in range(0, 8760):
                    line = []
                    for field in range(0, self.numOfFields):
                        line.append(str(self.__data[field].values[hour].value))
                    lines.append(",".join(line) + "\n")
            except IndexError:
                # cleaning up
                modEpwFile.close()
                del(lines)

                lengthErrorMsg = "Data length is not 8760 hours! Data can't be saved to epw file. " + \
                    "Did you filtered the data by AnalysisPeriod or by ConditionalStatment?"
                raise ValueError(lengthErrorMsg)

            modEpwFile.writelines(lines)
        del(lines)

        print "New epw file is written to [%s]"%fullPath

    def import_dataByField(self, fieldNumber):
        """Return annual values for any fieldNumber in epw file.

        This is a useful method to get the values for fields that Ladybug currently
        doesn't import by default. You can find list of fields by typing EPWDataTypes.fields

        Args:
            fieldNumber: a value between 0 to 34 for different available epw fields.
            0 Year
            1 Month
            2 Day
            3 Hour
            4 Minute
            -
            6 Dry Bulb Temperature
            7 Dew Point Temperature
            8 Relative Humidity
            9 Atmospheric Station Pressure
            10 Extraterrestrial Horizontal Radiation
            11 Extraterrestrial Direct Normal Radiation
            12 Horizontal Infrared Radiation Intensity
            13 Global Horizontal Radiation
            14 Direct Normal Radiation
            15 Diffuse Horizontal Radiation
            16 Global Horizontal Illuminance
            17 Direct Normal Illuminance
            18 Diffuse Horizontal Illuminance
            19 Zenith Luminance
            20 Wind Direction
            21 Wind Speed
            22 Total Sky Cover
            23 Opaque Sky Cover
            24 Visibility
            25 Ceiling Height
            26 Present Weather Observation
            27 Present Weather Codes
            28 Precipitable Water
            29 Aerosol Optical Depth
            30 Snow Depth
            31 Days Since Last Snowfall
            32 Albedo
            33 Liquid Precipitation Depth
            34 Liquid Precipitation Quantity
        Returns:
            An annual Ladybug list
        """
        return self.__get_dataByField(fieldNumber)

    # TODO: Copy proper descriptions from epw documentation
    @property
    def years(self):
        """Return years as a Ladybug Data List"""
        return self.__get_dataByField(0)

    @property
    def dryBulbTemperature(self):
        """Return annual Dry Bulb Temperature as a Ladybug Data List

            This is the dry bulb temperature in C at the time indicated. Note that this is a full numeric field (i.e. 23.6) and not an integer representation with tenths. Valid values range from -70 C to 70 C. Missing value for this field is 99.9
            Read more at: https://energyplus.net/sites/all/modules/custom/nrel_custom/pdfs/pdfs_v8.4.0/AuxiliaryPrograms.pdf (Chapter 2.9.1)
        """
        return self.__get_dataByField(6)

    @property
    def dewPointTemperature(self):
        """Return annual Dew Point Temperature as a Ladybug Data List

            This is the dew point temperature in C at the time indicated. Note that this is a full numeric field (i.e. 23.6) and not an integer representation with tenths. Valid values range from -70 C to 70 C. Missing value for this field is 99.9
            Read more at: https://energyplus.net/sites/all/modules/custom/nrel_custom/pdfs/pdfs_v8.4.0/AuxiliaryPrograms.pdf (Chapter 2.9.1)
        """
        return self.__get_dataByField(7)

    @property
    def relativeHumidity(self):
        """Return annual Relative Humidity as a Ladybug Data List

            This is the Relative Humidity in percent at the time indicated. Valid values range from 0% to 110%. Missing value for this field is 999.
            Read more at: https://energyplus.net/sites/all/modules/custom/nrel_custom/pdfs/pdfs_v8.4.0/AuxiliaryPrograms.pdf (Chapter 2.9.1)
        """
        return self.__get_dataByField(8)

    @property
    def atmosphericStationPressure(self):
        """Return annual Atmospheric Station Pressure as a Ladybug Data List

            This is the station pressure in Pa at the time indicated. Valid values range from 31,000 to 120,000. (These values were chosen from the standard barometric pressure for all elevations of the World). Missing value for this field is 999999.
            Read more at: https://energyplus.net/sites/all/modules/custom/nrel_custom/pdfs/pdfs_v8.4.0/AuxiliaryPrograms.pdf (Chapter 2.9.1)
        """
        return self.__get_dataByField(9)

    @property
    def extraterrestrialHorizontalRadiation(self):
        """Return annual Extraterrestrial Horizontal Radiation as a Ladybug Data List

            This is the Extraterrestrial Horizontal Radiation in Wh/m2. It is not currently used in EnergyPlus calculations. It should have a minimum value of 0; missing value for this field is 9999
            Read more at: https://energyplus.net/sites/all/modules/custom/nrel_custom/pdfs/pdfs_v8.4.0/AuxiliaryPrograms.pdf (Chapter 2.9.1)
        """
        return self.__get_dataByField(10)

    @property
    def extraterrestrialDirectNormalRadiation(self):
        """Return annual Extraterrestrial Direct Normal Radiation as a Ladybug Data List

            This is the Extraterrestrial Direct Normal Radiation in Wh/m2. (Amount of solar radiation in Wh/m2 received on a surface normal to the rays of the sun at the top of the atmosphere during the number of minutes preceding the time indicated). It is not currently used in EnergyPlus calculations. It should have a minimum value of 0; missing value for this field is 9999.
            Read more at: https://energyplus.net/sites/all/modules/custom/nrel_custom/pdfs/pdfs_v8.4.0/AuxiliaryPrograms.pdf (Chapter 2.9.1)
        """
        return self.__get_dataByField(11)

    @property
    def horizontalInfraredRadiationIntensity(self):
        """Return annual Horizontal Infrared Radiation Intensity as a Ladybug Data List

            This is the Horizontal Infrared Radiation Intensity in Wh/m2. If it is missing, it is calculated from the Opaque Sky Cover field as shown in the following explanation. It should have a minimum value of 0; missing value for this field is 9999.
            Read more at: https://energyplus.net/sites/all/modules/custom/nrel_custom/pdfs/pdfs_v8.4.0/AuxiliaryPrograms.pdf (Chapter 2.9.1)
        """
        return self.__get_dataByField(12)

    @property
    def globalHorizontalRadiation(self):
        """Return annual Global Horizontal Radiation as a Ladybug Data List

            This is the Global Horizontal Radiation in Wh/m2. (Total amount of direct and diffuse solar radiation in Wh/m2 received on a horizontal surface during the number of minutes preceding the time indicated.) It is not currently used in EnergyPlus calculations. It should have a minimum value of 0; missing value for this field is 9999.
            Read more at: https://energyplus.net/sites/all/modules/custom/nrel_custom/pdfs/pdfs_v8.4.0/AuxiliaryPrograms.pdf (Chapter 2.9.1)
        """
        return self.__get_dataByField(13)

    @property
    def directNormalRadiation(self):
        """Return annual Direct Normal Radiation as a Ladybug Data List

            This is the Direct Normal Radiation in Wh/m2. (Amount of solar radiation in Wh/m2 received directly from the solar disk on a surface perpendicular to the sun's rays, during the number of minutes preceding the time indicated.) If the field is missing ( >= 9999) or invalid ( < 0), it is set to 0. Counts of such missing values are totaled and presented at the end of the runperiod.
            Read more at: https://energyplus.net/sites/all/modules/custom/nrel_custom/pdfs/pdfs_v8.4.0/AuxiliaryPrograms.pdf (Chapter 2.9.1)
        """
        return self.__get_dataByField(14)

    @property
    def diffuseHorizontalRadiation(self):
        """Return annual Diffuse Horizontal Radiation as a Ladybug Data List

            This is the Diffuse Horizontal Radiation in Wh/m2. (Amount of solar radiation in Wh/m2 received from the sky (excluding the solar disk) on a horizontal surface during the number of minutes preceding the time indicated.) If the field is missing ( >= 9999) or invalid ( < 0), it is set to 0. Counts of such missing values are totaled and presented at the end of the runperiod
            Read more at: https://energyplus.net/sites/all/modules/custom/nrel_custom/pdfs/pdfs_v8.4.0/AuxiliaryPrograms.pdf (Chapter 2.9.1)
        """
        return self.__get_dataByField(15)

    @property
    def globalHorizontalIlluminance(self):
        """Return annual Global Horizontal Illuminance as a Ladybug Data List

            This is the Global Horizontal Illuminance in lux. (Average total amount of direct and diffuse illuminance in hundreds of lux received on a horizontal surface during the number of minutes preceding the time indicated.) It is not currently used in EnergyPlus calculations. It should have a minimum value of 0; missing value for this field is 999999 and will be considered missing if greater than or equal to 999900.
            Read more at: https://energyplus.net/sites/all/modules/custom/nrel_custom/pdfs/pdfs_v8.4.0/AuxiliaryPrograms.pdf (Chapter 2.9.1)
        """
        return self.__get_dataByField(16)

    @property
    def directNormalIlluminance(self):
        """Return annual Direct Normal Illuminance as a Ladybug Data List

            This is the Direct Normal Illuminance in lux. (Average amount of illuminance in hundreds of lux received directly from the solar disk on a surface perpendicular to the sun's rays, during the number of minutes preceding the time indicated.) It is not currently used in EnergyPlus calculations. It should have a minimum value of 0; missing value for this field is 999999 and will be considered missing if greater than or equal to 999900.
            Read more at: https://energyplus.net/sites/all/modules/custom/nrel_custom/pdfs/pdfs_v8.4.0/AuxiliaryPrograms.pdf (Chapter 2.9.1)
        """
        return self.__get_dataByField(17)

    @property
    def diffuseHorizontalIlluminance(self):
        """Return annual Diffuse Horizontal Illuminance as a Ladybug Data List

            This is the Diffuse Horizontal Illuminance in lux. (Average amount of illuminance in hundreds of lux received from the sky (excluding the solar disk) on a horizontal surface during the number of minutes preceding the time indicated.) It is not currently used in EnergyPlus calculations. It should have a minimum value of 0; missing value for this field is 999999 and will be considered missing if greater than or equal to 999900.
            Read more at: https://energyplus.net/sites/all/modules/custom/nrel_custom/pdfs/pdfs_v8.4.0/AuxiliaryPrograms.pdf (Chapter 2.9.1)
        """
        return self.__get_dataByField(18)

    @property
    def zenithLuminance(self):
        """Return annual Zenith Luminance as a Ladybug Data List

            This is the Zenith Illuminance in Cd/m2. (Average amount of luminance at the sky's zenith in tens of Cd/m2 during the number of minutes preceding the time indicated.) It is not currently used in EnergyPlus calculations. It should have a minimum value of 0; missing value for this field is 9999.
            Read more at: https://energyplus.net/sites/all/modules/custom/nrel_custom/pdfs/pdfs_v8.4.0/AuxiliaryPrograms.pdf (Chapter 2.9.1)
        """
        return self.__get_dataByField(19)

    @property
    def windDirection(self):
        """Return annual Wind Direction as a Ladybug Data List

            This is the Wind Direction in degrees where the convention is that North=0.0, East=90.0, South=180.0, West=270.0. (Wind direction in degrees at the time indicated. If calm, direction equals zero.) Values can range from 0 to 360. Missing value is 999.
            Read more at: https://energyplus.net/sites/all/modules/custom/nrel_custom/pdfs/pdfs_v8.4.0/AuxiliaryPrograms.pdf (Chapter 2.9.1)
        """
        return self.__get_dataByField(20)

    @property
    def windSpeed(self):
        """Return annual Wind Speed as a Ladybug Data List

            This is the wind speed in m/sec. (Wind speed at time indicated.) Values can range from 0 to 40. Missing value is 999.
            Read more at: https://energyplus.net/sites/all/modules/custom/nrel_custom/pdfs/pdfs_v8.4.0/AuxiliaryPrograms.pdf (Chapter 2.9.1)
        """
        return self.__get_dataByField(21)

    @property
    def totalSkyCover(self):
        """Return annual Total Sky Cover as a Ladybug Data List

            This is the value for total sky cover (tenths of coverage). (i.e. 1 is 1/10 covered. 10 is total coverage). (Amount of sky dome in tenths covered by clouds or obscuring phenomena at the hour indicated at the time indicated.) Minimum value is 0; maximum value is 10; missing value is 99.
            Read more at: https://energyplus.net/sites/all/modules/custom/nrel_custom/pdfs/pdfs_v8.4.0/AuxiliaryPrograms.pdf (Chapter 2.9.1)
        """
        return self.__get_dataByField(22)

    @property
    def opaqueSkyCover(self):
        """Return annual Opaque Sky Cover as a Ladybug Data List

            This is the value for opaque sky cover (tenths of coverage). (i.e. 1 is 1/10 covered. 10 is total coverage). (Amount of sky dome in tenths covered by clouds or obscuring phenomena that prevent observing the sky or higher cloud layers at the time indicated.) This is not used unless the field for Horizontal Infrared Radiation Intensity is missing and then it is used to calculate Horizontal Infrared Radiation Intensity. Minimum value is 0; maximum value is 10; missing value is 99.
            Read more at: https://energyplus.net/sites/all/modules/custom/nrel_custom/pdfs/pdfs_v8.4.0/AuxiliaryPrograms.pdf (Chapter 2.9.1)
        """
        return self.__get_dataByField(23)

    @property
    def visibility(self):
        """Return annual Visibility as a Ladybug Data List

            This is the value for visibility in km. (Horizontal visibility at the time indicated.) It is not currently used in EnergyPlus calculations. Missing value is 9999.
            Read more at: https://energyplus.net/sites/all/modules/custom/nrel_custom/pdfs/pdfs_v8.4.0/AuxiliaryPrograms.pdf (Chapter 2.9.1)
        """
        return self.__get_dataByField(24)

    @property
    def ceilingHeight(self):
        """Return annual Ceiling Height as a Ladybug Data List

            This is the value for ceiling height in m. (77777 is unlimited ceiling height. 88888 is cirroform ceiling.) It is not currently used in EnergyPlus calculations. Missing value is 99999
            Read more at: https://energyplus.net/sites/all/modules/custom/nrel_custom/pdfs/pdfs_v8.4.0/AuxiliaryPrograms.pdf (Chapter 2.9.1)
        """
        return self.__get_dataByField(25)

    @property
    def presentWeatherObservation(self):
        """Return annual Present Weather Observation as a Ladybug Data List.

        If the value of the field is 0, then the observed weather codes are taken from the following field. If the value of the field is 9, then "missing" weather is assumed. Since the primary use of these fields (Present Weather Observation and Present Weather Codes) is for rain/wet surfaces, a missing observation field or a missing weather code implies no rain.
        Read more at: https://energyplus.net/sites/all/modules/custom/nrel_custom/pdfs/pdfs_v8.4.0/AuxiliaryPrograms.pdf (Chapter 2.9.1)
        """
        return self.__get_dataByField(26)

    @property
    def presentWeatherCodes(self):
        """Return annual Present Weather Codes as a Ladybug Data List.

        The present weather codes field is assumed to follow the TMY2 conventions for this field. Note that though this field may be represented as numeric (e.g. in the CSV format), it is really a text field of 9 single digits. This convention along with values for each "column" (left to right) is presented in Table 16. Note that some formats (e.g. TMY) does not follow this convention - as much as possible, the present weather codes are converted to this convention during WeatherConverter processing. Also note that the most important fields are those representing liquid precipitation - where the surfaces of the building would be wet. EnergyPlus uses "Snow Depth" to determine if snow is on the ground.
        Read more at: https://energyplus.net/sites/all/modules/custom/nrel_custom/pdfs/pdfs_v8.4.0/AuxiliaryPrograms.pdf (Chapter 2.9.1)
        """
        return self.__get_dataByField(27)

    @property
    def precipitableWater(self):
        """Return annual Precipitable Water as a Ladybug Data List.

        This is the value for Precipitable Water in mm. (This is not rain - rain is inferred from the PresWeathObs field but a better result is from the Liquid Precipitation Depth field)). It is not currently used in EnergyPlus calculations (primarily due to the unreliability of the reporting of this value). Missing value is 999.
        Read more at: https://energyplus.net/sites/all/modules/custom/nrel_custom/pdfs/pdfs_v8.4.0/AuxiliaryPrograms.pdf (Chapter 2.9.1)
        """
        return self.__get_dataByField(28)

    @property
    def aerosolOpticalDepth(self):
        """Return annual Aerosol Optical Depth as a Ladybug Data List

            This is the value for Aerosol Optical Depth in thousandths. It is not currently used in EnergyPlus calculations. Missing value is .999.
            Read more at: https://energyplus.net/sites/all/modules/custom/nrel_custom/pdfs/pdfs_v8.4.0/AuxiliaryPrograms.pdf (Chapter 2.9.1)
        """
        return self.__get_dataByField(29)

    @property
    def snowDepth(self):
        """Return annual Snow Depth as a Ladybug Data List

            This is the value for Snow Depth in cm. This field is used to tell when snow is on the ground and, thus, the ground reflectance may change. Missing value is 999.
            Read more at: https://energyplus.net/sites/all/modules/custom/nrel_custom/pdfs/pdfs_v8.4.0/AuxiliaryPrograms.pdf (Chapter 2.9.1)
        """
        return self.__get_dataByField(30)

    @property
    def daysSinceLastSnowfall(self):
        """Return annual Days Since Last Snow Fall as a Ladybug Data List

            This is the value for Days Since Last Snowfall. It is not currently used in EnergyPlus calculations. Missing value is 99.
            Read more at: https://energyplus.net/sites/all/modules/custom/nrel_custom/pdfs/pdfs_v8.4.0/AuxiliaryPrograms.pdf (Chapter 2.9.1)
        """
        return self.__get_dataByField(31)

    @property
    def albedo(self):
        """Return annual Albedo values as a Ladybug Data List

            The ratio (unitless) of reflected solar irradiance to global horizontal irradiance. It is not currently used in EnergyPlus
            Read more at: https://energyplus.net/sites/all/modules/custom/nrel_custom/pdfs/pdfs_v8.4.0/AuxiliaryPrograms.pdf (Chapter 2.9.1)
        """
        return self.__get_dataByField(32)

    @property
    def liquidPrecipitationDepth(self):
        """Return annual liquid precipitation depth as a Ladybug Data List

            The amount of liquid precipitation (mm) observed at the indicated time for the period indicated in the liquid precipitation quantity field. If this value is not missing, then it is used and overrides the "precipitation" flag as rainfall. Conversely, if the precipitation flag shows rain and this field is missing or zero, it is set to 1.5 (mm).
            Read more at: https://energyplus.net/sites/all/modules/custom/nrel_custom/pdfs/pdfs_v8.4.0/AuxiliaryPrograms.pdf (Chapter 2.9.1)
        """
        return self.__get_dataByField(33)

    @property
    def liquidPrecipitationQuantity(self):
        """Return annual Liquid Precipitation Quantity as a Ladybug Data List

            The period of accumulation (hr) for the liquid precipitation depth field. It is not currently used in EnergyPlus
            Read more at: https://energyplus.net/sites/all/modules/custom/nrel_custom/pdfs/pdfs_v8.4.0/AuxiliaryPrograms.pdf (Chapter 2.9.1)
        """
        return self.__get_dataByField(34)

    def __getWEAHeader(self):
        return  "place %s\n"%self.location.city + \
                "latitude %.2f\n"%self.location.latitude + \
                "longitude %.2f\n"%-self.location.longitude + \
                "time_zone %d\n"%(-self.location.timeZone * 15) + \
                "site_elevation %.1f\n"%self.location.elevation + \
                "weather_data_file_units 1\n"

    def epw2wea(self, filePath = None):
        """Write wea file from epw file
            WEA carries radiation values from epw ans is what gendaymtx uses to generate the sky
            I'm wrote my own implementation to avoid shipping epw2wea.exe file. Now epw2wea is
            part of the Radiance distribution
        """
        if not filePath:
            filePath = self.fileAddress[:-3] + "wea"

        with open(filePath, "wb") as weaFile:
            weaFile.write(self.__getWEAHeader())
            for dirRad, difRad in zip(self.directNormalRadiation, self.diffuseHorizontalRadiation):
                line = "%d %d %.3f %d %d\n"%(dirRad.datetime.month, dirRad.datetime.day, dirRad.datetime.hour - 0.5, dirRad, difRad)
                weaFile.write(line)

        return filePath

    def __repr__(self):
        return "EPW Data [%s]"%self.stationLocation.city

class EPWDataTypes:
    """EPW weather file fields
        Read more at: https://energyplus.net/sites/all/modules/custom/nrel_custom/pdfs/pdfs_v8.4.0/AuxiliaryPrograms.pdf (Chapter 2.9.1)

    """
    __fields = {
        0 : { 'name'  : 'Year',
                'type' : int
            },

        1 : { 'name'  : 'Month',
                'type' : int
            },

        2 : { 'name'  : 'Day',
                'type' : int
            },

        3 : { 'name'  : 'Hour',
                'type' : int
            },

        4 : { 'name'  : 'Minute',
                'type' : int
            },

        5 : { 'name'  : 'Uncertainty Flags',
                'type' : str
            },

        6 : { 'name'  : 'Dry Bulb Temperature',
                'type' : float,
                'units' : 'C',
                'min'   : -70,
                'max'   : 70,
                'missing' : 99.9
            },

        7 : { 'name' : 'Dew Point Temperature',
                'type' : float,
                'units' : 'C',
                'min' : -70,
                'max' : 70,
                'missing' : 99.9
            },

        8 : { 'name' : 'Relative Humidity',
                'type' : int,
                'missing' : 999,
                'min' : 0,
                'max' : 110
            },

        9 : { 'name' : 'Atmospheric Station Pressure',
                'type' : int,
                'units' : 'Pa',
                'missing' : 999999,
                'min' : 31000,
                'max' : 120000
            },

        10 : { 'name' : 'Extraterrestrial Horizontal Radiation',
                'type' : int,
                'units' : 'Wh/m2',
                'missing' :  9999,
                'min' : 0
            },

        11 : { 'name' : 'Extraterrestrial Direct Normal Radiation',
                'type' : int,
                'units' :  'Wh/m2',
                'missing' : 9999,
                'min' : 0
            },

        12 : { 'name' : 'Horizontal Infrared Radiation Intensity',
                'type' : int,
                'units' : 'Wh/m2',
                'missing' : 9999,
                'min' : 0
            },

        13 : { 'name' : 'Global Horizontal Radiation',
                'type' : int,
                'units' : 'Wh/m2',
                'missing' : 9999,
                'min' : 0
            },

        14 : { 'name' : 'Direct Normal Radiation',
                'type' : int,
                'units' : 'Wh/m2',
                'missing' : 9999,
                'min' : 0
            },

        15 : { 'name' : 'Diffuse Horizontal Radiation',
                'type' : int,
                'units' : 'Wh/m2',
                'missing' : 9999,
                'min' : 0
            },

        16 : { 'name' : 'Global Horizontal Illuminance',
                'type' : int,
                'units' : 'lux',
                'missing' : 999999, # note will be missing if >= 999900
                'min' : 0
            },

        17 : { 'name' : 'Direct Normal Illuminance',
                'type' : int,
                'units' : 'lux',
                'missing' : 999999, # note will be missing if >= 999900
                'min' : 0
            },

        18 : { 'name' : 'Diffuse Horizontal Illuminance',
                'type' : int,
                'units' : 'lux',
                'missing' : 999999, # note will be missing if >= 999900
                'min' : 0
            },

        19 : { 'name' : 'Zenith Luminance',
                'type' : int,
                'units' : 'Cd/m2',
                'missing' : 9999, # note will be missing if >= 9999
                'min' : 0
            },

        20 : { 'name' : 'Wind Direction',
                'type' : int,
                'units' : 'degrees',
                'missing' : 999,
                'min' : 0,
                'max' : 360
            },

        21 : { 'name' : 'Wind Speed',
                'type' : float,
                'units' : 'm/s',
                'missing' : 999,
                'min' : 0,
                'max' : 40
            },

        22 : { 'name' : 'Total Sky Cover', # (used if Horizontal IR Intensity missing)
                'type' : int,
                'missing' : 99,
                'min' : 0,
                'max' : 10
            },

        23 : { 'name' : 'Opaque Sky Cover', #(used if Horizontal IR Intensity missing)
                'type' : int,
                'missing' : 99
            },

        24 : { 'name' : 'Visibility',
                'type' : float,
                'units' : 'km',
                'missing' : 9999
            },

        25 : { 'name' : 'Ceiling Height',
                'type' : int,
                'units' : 'm',
                'missing' : 99999
            },

        26 : { 'name' : 'Present Weather Observation',
                'type' : int
            },

        27 : { 'name' : 'Present Weather Codes',
                'type' : int
            },

        28 : { 'name' : 'Precipitable Water',
                'type' : int,
                'units' : 'mm',
                'missing' : 999
            },

        29 : { 'name' : 'Aerosol Optical Depth',
                'type' : float,
                'units' : 'thousandths',
                'missing' : 999
            },

        30 : { 'name' : 'Snow Depth',
                'type' : int,
                'units' : 'cm',
                'missing' : 999
            },

        31 : { 'name' :  'Days Since Last Snowfall',
                'type' : int,
                'missing' : 99
            },

        32 : { 'name' :  'Albedo',
                'type' : float,
                'missing': 999
            },

        33 : { 'name' :  'Liquid Precipitation Depth',
                'type' : float,
                'units': 'mm',
                'missing': 999
            },

        34 : { 'name' :  'Liquid Precipitation Quantity',
                'type' : float,
                'units': 'hr',
                'missing': 99
            }
        }

    class EPWField:
        def __init__(self, dataDict):
            self.name = dataDict['name']
            self.valueType = dataDict['type']
            if 'units' in dataDict:
                self.units = dataDict['units']
            else:
                self.units = 'N/A'

    @classmethod
    def fieldNumbers(cls):
        for key, value in cls.__fields.items():
            print key, value['name']

    @classmethod
    def fields(cls):
        """Return fields as a dictionary.

        If you are looking for field numbers try fieldNumbers method instead.
        """
        return cls.__fields

    @classmethod
    def get_fieldByNumber(cls, fieldNumber):
        """Return an EPWField based on field number.

        0 Year
        1 Month
        2 Day
        3 Hour
        4 Minute
        -
        6 Dry Bulb Temperature
        7 Dew Point Temperature
        8 Relative Humidity
        9 Atmospheric Station Pressure
        10 Extraterrestrial Horizontal Radiation
        11 Extraterrestrial Direct Normal Radiation
        12 Horizontal Infrared Radiation Intensity
        13 Global Horizontal Radiation
        14 Direct Normal Radiation
        15 Diffuse Horizontal Radiation
        16 Global Horizontal Illuminance
        17 Direct Normal Illuminance
        18 Diffuse Horizontal Illuminance
        19 Zenith Luminance
        20 Wind Direction
        21 Wind Speed
        22 Total Sky Cover
        23 Opaque Sky Cover
        24 Visibility
        25 Ceiling Height
        26 Present Weather Observation
        27 Present Weather Codes
        28 Precipitable Water
        29 Aerosol Optical Depth
        30 Snow Depth
        31 Days Since Last Snowfall
        32 Albedo
        33 Liquid Precipitation Depth
        34 Liquid Precipitation Quantity
        """
        return cls.EPWField(cls.__fields[fieldNumber])

Classes

class EPW

class EPW:
    def __init__(self, epwFileAddress = None):
        """
        Import epw data from a local epw file

        epwFileAddress: Local file address to an epw file

        """
        if not epwFileAddress: return
        self.fileAddress = self.checkEpwFileAddress(epwFileAddress)
        self.filePath, self.fileName = os.path.split(self.fileAddress)
        self.__isDataLoaded = False
        self.__isLocationLoaded = False
        self.__data = dict()
        self.epwHeader = None
        self.numOfFields = 35 # it is 35 for TMY3 files

    @property
    def isDataLoaded(self):
        return self.__isDataLoaded

    @property
    def isLocationLoaded(self):
        return self.__isLocationLoaded

    @staticmethod
    def checkEpwFileAddress(epwFileAddress):
        """ Checks the path and checks the type for an epw file"""
        if not os.path.isfile(epwFileAddress):
            raise Exception(epwFileAddress + ' is not a valid address.')
        if not epwFileAddress.lower().endswith('epw'):
            raise Exception(epwFileAddress + ' is not an .epw file.')
        return epwFileAddress

    @property
    def location(self):
        if not self.isLocationLoaded: self.importData(True)
        return self.stationLocation

    #TODO: import EPW header. Currently I just ignore header data
    def importData(self, onlyImportLocation = False):
        """
        imports data from an epw file.
        Hourly data will be saved in self.data and location data
        will be saved in self.location
        """

        with open(self.fileAddress, 'rb') as epwin:
            epwlines = epwin.readlines()

        # import location data
        # first line has location data - Here is an example
        # LOCATION,Denver Centennial  Golden   Nr,CO,USA,TMY3,724666,39.74,-105.18,-7.0,1829.0
        if not self.__isLocationLoaded:
            locationData = epwlines[0].strip().split(',')
            self.stationLocation = core.Location()
            self.stationLocation.city = locationData[1]
            self.stationLocation.state = locationData[2]
            self.stationLocation.country = locationData[3]
            self.stationLocation.source = locationData[4]
            self.stationLocation.stationId = locationData[5]
            self.stationLocation.latitude = float(locationData[6])
            self.stationLocation.longitude = float(locationData[7])
            self.stationLocation.timeZone = float(locationData[8])
            self.stationLocation.elevation = float(locationData[9])

            self.__isLocationLoaded = True
            if onlyImportLocation: return

        # TODO: create an object from the header and analyze data
        # get epw header
        self.epwHeader = epwlines[:8]

        self.numOfFields = len(epwlines[8].strip().split(','))
        # import hourly data
        analysisPeriod = core.AnalysisPeriod()
        for fieldNumber in range(0, self.numOfFields):
            # create header
            field = EPWDataTypes.get_fieldByNumber(fieldNumber)
            header = core.LBHeader(city = self.stationLocation.city, frequency ='Hourly', \
                    analysisPeriod = analysisPeriod, \
                    dataType = field.name, unit =field.units)

            # create an empty data list with the header
            self.__data[fieldNumber] = core.DataList(header =header)

        for line in epwlines[8:]:
            data = line.strip().split(',')

            year, month, day, hour = map(int, data[:4])
            # in an epw file year can be different for each month
            # since I'm using this timestamp as the key and will be using it for sorting
            # I'm setting it up to 2000 - the real year will be collected under modelYear
            timestamp = core.LBDateTime(month, day, hour)

            for fieldNumber in range(0, self.numOfFields):
                valueType = EPWDataTypes.get_fieldByNumber(fieldNumber).valueType
                value = map(valueType, [data[fieldNumber]])[0]
                self.__data[fieldNumber].append(core.LBData(value, timestamp))

        del(epwlines)
        self.__isDataLoaded = True

    def __get_dataByField(self, fieldNumber):
        """Return a data field by field number
        This is a useful method to get the values for fields that Ladybug currently
        doesn't import by default. You can find list of fields by typing EPWDataTypes.fields

        Args:
            fieldNumber: a value between 0 to 34 for different available epw fields.

        Returns:
            An annual Ladybug list
        """
        if not self.isDataLoaded: self.importData()

        # check input data
        if not 0 <= fieldNumber < self.numOfFields:
            raise ValueError("Field number should be between 0-%d"%self.numOfFields)

        return self.__data[fieldNumber]

    # TODO: Add utility library to check file path, filename, etc
    def save(self, filePath = None, fileName = None):
        """Save epw object as an epw file"""
        # check filePath
        if not filePath:
            filePath = self.filePath

        if not fileName:
            fileName = ".".join((self.fileName).split(".")[:-1]) + "_modified.epw"

        fullPath = os.path.join(filePath, fileName)

        # load data if it's  not loaded
        if not self.isDataLoaded: self.importData()

        # write the file
        with open(fullPath, 'wb') as modEpwFile:
            modEpwFile.writelines(self.epwHeader)

            try:
                lines = []
                for hour in range(0, 8760):
                    line = []
                    for field in range(0, self.numOfFields):
                        line.append(str(self.__data[field].values[hour].value))
                    lines.append(",".join(line) + "\n")
            except IndexError:
                # cleaning up
                modEpwFile.close()
                del(lines)

                lengthErrorMsg = "Data length is not 8760 hours! Data can't be saved to epw file. " + \
                    "Did you filtered the data by AnalysisPeriod or by ConditionalStatment?"
                raise ValueError(lengthErrorMsg)

            modEpwFile.writelines(lines)
        del(lines)

        print "New epw file is written to [%s]"%fullPath

    def import_dataByField(self, fieldNumber):
        """Return annual values for any fieldNumber in epw file.

        This is a useful method to get the values for fields that Ladybug currently
        doesn't import by default. You can find list of fields by typing EPWDataTypes.fields

        Args:
            fieldNumber: a value between 0 to 34 for different available epw fields.
            0 Year
            1 Month
            2 Day
            3 Hour
            4 Minute
            -
            6 Dry Bulb Temperature
            7 Dew Point Temperature
            8 Relative Humidity
            9 Atmospheric Station Pressure
            10 Extraterrestrial Horizontal Radiation
            11 Extraterrestrial Direct Normal Radiation
            12 Horizontal Infrared Radiation Intensity
            13 Global Horizontal Radiation
            14 Direct Normal Radiation
            15 Diffuse Horizontal Radiation
            16 Global Horizontal Illuminance
            17 Direct Normal Illuminance
            18 Diffuse Horizontal Illuminance
            19 Zenith Luminance
            20 Wind Direction
            21 Wind Speed
            22 Total Sky Cover
            23 Opaque Sky Cover
            24 Visibility
            25 Ceiling Height
            26 Present Weather Observation
            27 Present Weather Codes
            28 Precipitable Water
            29 Aerosol Optical Depth
            30 Snow Depth
            31 Days Since Last Snowfall
            32 Albedo
            33 Liquid Precipitation Depth
            34 Liquid Precipitation Quantity
        Returns:
            An annual Ladybug list
        """
        return self.__get_dataByField(fieldNumber)

    # TODO: Copy proper descriptions from epw documentation
    @property
    def years(self):
        """Return years as a Ladybug Data List"""
        return self.__get_dataByField(0)

    @property
    def dryBulbTemperature(self):
        """Return annual Dry Bulb Temperature as a Ladybug Data List

            This is the dry bulb temperature in C at the time indicated. Note that this is a full numeric field (i.e. 23.6) and not an integer representation with tenths. Valid values range from -70 C to 70 C. Missing value for this field is 99.9
            Read more at: https://energyplus.net/sites/all/modules/custom/nrel_custom/pdfs/pdfs_v8.4.0/AuxiliaryPrograms.pdf (Chapter 2.9.1)
        """
        return self.__get_dataByField(6)

    @property
    def dewPointTemperature(self):
        """Return annual Dew Point Temperature as a Ladybug Data List

            This is the dew point temperature in C at the time indicated. Note that this is a full numeric field (i.e. 23.6) and not an integer representation with tenths. Valid values range from -70 C to 70 C. Missing value for this field is 99.9
            Read more at: https://energyplus.net/sites/all/modules/custom/nrel_custom/pdfs/pdfs_v8.4.0/AuxiliaryPrograms.pdf (Chapter 2.9.1)
        """
        return self.__get_dataByField(7)

    @property
    def relativeHumidity(self):
        """Return annual Relative Humidity as a Ladybug Data List

            This is the Relative Humidity in percent at the time indicated. Valid values range from 0% to 110%. Missing value for this field is 999.
            Read more at: https://energyplus.net/sites/all/modules/custom/nrel_custom/pdfs/pdfs_v8.4.0/AuxiliaryPrograms.pdf (Chapter 2.9.1)
        """
        return self.__get_dataByField(8)

    @property
    def atmosphericStationPressure(self):
        """Return annual Atmospheric Station Pressure as a Ladybug Data List

            This is the station pressure in Pa at the time indicated. Valid values range from 31,000 to 120,000. (These values were chosen from the standard barometric pressure for all elevations of the World). Missing value for this field is 999999.
            Read more at: https://energyplus.net/sites/all/modules/custom/nrel_custom/pdfs/pdfs_v8.4.0/AuxiliaryPrograms.pdf (Chapter 2.9.1)
        """
        return self.__get_dataByField(9)

    @property
    def extraterrestrialHorizontalRadiation(self):
        """Return annual Extraterrestrial Horizontal Radiation as a Ladybug Data List

            This is the Extraterrestrial Horizontal Radiation in Wh/m2. It is not currently used in EnergyPlus calculations. It should have a minimum value of 0; missing value for this field is 9999
            Read more at: https://energyplus.net/sites/all/modules/custom/nrel_custom/pdfs/pdfs_v8.4.0/AuxiliaryPrograms.pdf (Chapter 2.9.1)
        """
        return self.__get_dataByField(10)

    @property
    def extraterrestrialDirectNormalRadiation(self):
        """Return annual Extraterrestrial Direct Normal Radiation as a Ladybug Data List

            This is the Extraterrestrial Direct Normal Radiation in Wh/m2. (Amount of solar radiation in Wh/m2 received on a surface normal to the rays of the sun at the top of the atmosphere during the number of minutes preceding the time indicated). It is not currently used in EnergyPlus calculations. It should have a minimum value of 0; missing value for this field is 9999.
            Read more at: https://energyplus.net/sites/all/modules/custom/nrel_custom/pdfs/pdfs_v8.4.0/AuxiliaryPrograms.pdf (Chapter 2.9.1)
        """
        return self.__get_dataByField(11)

    @property
    def horizontalInfraredRadiationIntensity(self):
        """Return annual Horizontal Infrared Radiation Intensity as a Ladybug Data List

            This is the Horizontal Infrared Radiation Intensity in Wh/m2. If it is missing, it is calculated from the Opaque Sky Cover field as shown in the following explanation. It should have a minimum value of 0; missing value for this field is 9999.
            Read more at: https://energyplus.net/sites/all/modules/custom/nrel_custom/pdfs/pdfs_v8.4.0/AuxiliaryPrograms.pdf (Chapter 2.9.1)
        """
        return self.__get_dataByField(12)

    @property
    def globalHorizontalRadiation(self):
        """Return annual Global Horizontal Radiation as a Ladybug Data List

            This is the Global Horizontal Radiation in Wh/m2. (Total amount of direct and diffuse solar radiation in Wh/m2 received on a horizontal surface during the number of minutes preceding the time indicated.) It is not currently used in EnergyPlus calculations. It should have a minimum value of 0; missing value for this field is 9999.
            Read more at: https://energyplus.net/sites/all/modules/custom/nrel_custom/pdfs/pdfs_v8.4.0/AuxiliaryPrograms.pdf (Chapter 2.9.1)
        """
        return self.__get_dataByField(13)

    @property
    def directNormalRadiation(self):
        """Return annual Direct Normal Radiation as a Ladybug Data List

            This is the Direct Normal Radiation in Wh/m2. (Amount of solar radiation in Wh/m2 received directly from the solar disk on a surface perpendicular to the sun's rays, during the number of minutes preceding the time indicated.) If the field is missing ( >= 9999) or invalid ( < 0), it is set to 0. Counts of such missing values are totaled and presented at the end of the runperiod.
            Read more at: https://energyplus.net/sites/all/modules/custom/nrel_custom/pdfs/pdfs_v8.4.0/AuxiliaryPrograms.pdf (Chapter 2.9.1)
        """
        return self.__get_dataByField(14)

    @property
    def diffuseHorizontalRadiation(self):
        """Return annual Diffuse Horizontal Radiation as a Ladybug Data List

            This is the Diffuse Horizontal Radiation in Wh/m2. (Amount of solar radiation in Wh/m2 received from the sky (excluding the solar disk) on a horizontal surface during the number of minutes preceding the time indicated.) If the field is missing ( >= 9999) or invalid ( < 0), it is set to 0. Counts of such missing values are totaled and presented at the end of the runperiod
            Read more at: https://energyplus.net/sites/all/modules/custom/nrel_custom/pdfs/pdfs_v8.4.0/AuxiliaryPrograms.pdf (Chapter 2.9.1)
        """
        return self.__get_dataByField(15)

    @property
    def globalHorizontalIlluminance(self):
        """Return annual Global Horizontal Illuminance as a Ladybug Data List

            This is the Global Horizontal Illuminance in lux. (Average total amount of direct and diffuse illuminance in hundreds of lux received on a horizontal surface during the number of minutes preceding the time indicated.) It is not currently used in EnergyPlus calculations. It should have a minimum value of 0; missing value for this field is 999999 and will be considered missing if greater than or equal to 999900.
            Read more at: https://energyplus.net/sites/all/modules/custom/nrel_custom/pdfs/pdfs_v8.4.0/AuxiliaryPrograms.pdf (Chapter 2.9.1)
        """
        return self.__get_dataByField(16)

    @property
    def directNormalIlluminance(self):
        """Return annual Direct Normal Illuminance as a Ladybug Data List

            This is the Direct Normal Illuminance in lux. (Average amount of illuminance in hundreds of lux received directly from the solar disk on a surface perpendicular to the sun's rays, during the number of minutes preceding the time indicated.) It is not currently used in EnergyPlus calculations. It should have a minimum value of 0; missing value for this field is 999999 and will be considered missing if greater than or equal to 999900.
            Read more at: https://energyplus.net/sites/all/modules/custom/nrel_custom/pdfs/pdfs_v8.4.0/AuxiliaryPrograms.pdf (Chapter 2.9.1)
        """
        return self.__get_dataByField(17)

    @property
    def diffuseHorizontalIlluminance(self):
        """Return annual Diffuse Horizontal Illuminance as a Ladybug Data List

            This is the Diffuse Horizontal Illuminance in lux. (Average amount of illuminance in hundreds of lux received from the sky (excluding the solar disk) on a horizontal surface during the number of minutes preceding the time indicated.) It is not currently used in EnergyPlus calculations. It should have a minimum value of 0; missing value for this field is 999999 and will be considered missing if greater than or equal to 999900.
            Read more at: https://energyplus.net/sites/all/modules/custom/nrel_custom/pdfs/pdfs_v8.4.0/AuxiliaryPrograms.pdf (Chapter 2.9.1)
        """
        return self.__get_dataByField(18)

    @property
    def zenithLuminance(self):
        """Return annual Zenith Luminance as a Ladybug Data List

            This is the Zenith Illuminance in Cd/m2. (Average amount of luminance at the sky's zenith in tens of Cd/m2 during the number of minutes preceding the time indicated.) It is not currently used in EnergyPlus calculations. It should have a minimum value of 0; missing value for this field is 9999.
            Read more at: https://energyplus.net/sites/all/modules/custom/nrel_custom/pdfs/pdfs_v8.4.0/AuxiliaryPrograms.pdf (Chapter 2.9.1)
        """
        return self.__get_dataByField(19)

    @property
    def windDirection(self):
        """Return annual Wind Direction as a Ladybug Data List

            This is the Wind Direction in degrees where the convention is that North=0.0, East=90.0, South=180.0, West=270.0. (Wind direction in degrees at the time indicated. If calm, direction equals zero.) Values can range from 0 to 360. Missing value is 999.
            Read more at: https://energyplus.net/sites/all/modules/custom/nrel_custom/pdfs/pdfs_v8.4.0/AuxiliaryPrograms.pdf (Chapter 2.9.1)
        """
        return self.__get_dataByField(20)

    @property
    def windSpeed(self):
        """Return annual Wind Speed as a Ladybug Data List

            This is the wind speed in m/sec. (Wind speed at time indicated.) Values can range from 0 to 40. Missing value is 999.
            Read more at: https://energyplus.net/sites/all/modules/custom/nrel_custom/pdfs/pdfs_v8.4.0/AuxiliaryPrograms.pdf (Chapter 2.9.1)
        """
        return self.__get_dataByField(21)

    @property
    def totalSkyCover(self):
        """Return annual Total Sky Cover as a Ladybug Data List

            This is the value for total sky cover (tenths of coverage). (i.e. 1 is 1/10 covered. 10 is total coverage). (Amount of sky dome in tenths covered by clouds or obscuring phenomena at the hour indicated at the time indicated.) Minimum value is 0; maximum value is 10; missing value is 99.
            Read more at: https://energyplus.net/sites/all/modules/custom/nrel_custom/pdfs/pdfs_v8.4.0/AuxiliaryPrograms.pdf (Chapter 2.9.1)
        """
        return self.__get_dataByField(22)

    @property
    def opaqueSkyCover(self):
        """Return annual Opaque Sky Cover as a Ladybug Data List

            This is the value for opaque sky cover (tenths of coverage). (i.e. 1 is 1/10 covered. 10 is total coverage). (Amount of sky dome in tenths covered by clouds or obscuring phenomena that prevent observing the sky or higher cloud layers at the time indicated.) This is not used unless the field for Horizontal Infrared Radiation Intensity is missing and then it is used to calculate Horizontal Infrared Radiation Intensity. Minimum value is 0; maximum value is 10; missing value is 99.
            Read more at: https://energyplus.net/sites/all/modules/custom/nrel_custom/pdfs/pdfs_v8.4.0/AuxiliaryPrograms.pdf (Chapter 2.9.1)
        """
        return self.__get_dataByField(23)

    @property
    def visibility(self):
        """Return annual Visibility as a Ladybug Data List

            This is the value for visibility in km. (Horizontal visibility at the time indicated.) It is not currently used in EnergyPlus calculations. Missing value is 9999.
            Read more at: https://energyplus.net/sites/all/modules/custom/nrel_custom/pdfs/pdfs_v8.4.0/AuxiliaryPrograms.pdf (Chapter 2.9.1)
        """
        return self.__get_dataByField(24)

    @property
    def ceilingHeight(self):
        """Return annual Ceiling Height as a Ladybug Data List

            This is the value for ceiling height in m. (77777 is unlimited ceiling height. 88888 is cirroform ceiling.) It is not currently used in EnergyPlus calculations. Missing value is 99999
            Read more at: https://energyplus.net/sites/all/modules/custom/nrel_custom/pdfs/pdfs_v8.4.0/AuxiliaryPrograms.pdf (Chapter 2.9.1)
        """
        return self.__get_dataByField(25)

    @property
    def presentWeatherObservation(self):
        """Return annual Present Weather Observation as a Ladybug Data List.

        If the value of the field is 0, then the observed weather codes are taken from the following field. If the value of the field is 9, then "missing" weather is assumed. Since the primary use of these fields (Present Weather Observation and Present Weather Codes) is for rain/wet surfaces, a missing observation field or a missing weather code implies no rain.
        Read more at: https://energyplus.net/sites/all/modules/custom/nrel_custom/pdfs/pdfs_v8.4.0/AuxiliaryPrograms.pdf (Chapter 2.9.1)
        """
        return self.__get_dataByField(26)

    @property
    def presentWeatherCodes(self):
        """Return annual Present Weather Codes as a Ladybug Data List.

        The present weather codes field is assumed to follow the TMY2 conventions for this field. Note that though this field may be represented as numeric (e.g. in the CSV format), it is really a text field of 9 single digits. This convention along with values for each "column" (left to right) is presented in Table 16. Note that some formats (e.g. TMY) does not follow this convention - as much as possible, the present weather codes are converted to this convention during WeatherConverter processing. Also note that the most important fields are those representing liquid precipitation - where the surfaces of the building would be wet. EnergyPlus uses "Snow Depth" to determine if snow is on the ground.
        Read more at: https://energyplus.net/sites/all/modules/custom/nrel_custom/pdfs/pdfs_v8.4.0/AuxiliaryPrograms.pdf (Chapter 2.9.1)
        """
        return self.__get_dataByField(27)

    @property
    def precipitableWater(self):
        """Return annual Precipitable Water as a Ladybug Data List.

        This is the value for Precipitable Water in mm. (This is not rain - rain is inferred from the PresWeathObs field but a better result is from the Liquid Precipitation Depth field)). It is not currently used in EnergyPlus calculations (primarily due to the unreliability of the reporting of this value). Missing value is 999.
        Read more at: https://energyplus.net/sites/all/modules/custom/nrel_custom/pdfs/pdfs_v8.4.0/AuxiliaryPrograms.pdf (Chapter 2.9.1)
        """
        return self.__get_dataByField(28)

    @property
    def aerosolOpticalDepth(self):
        """Return annual Aerosol Optical Depth as a Ladybug Data List

            This is the value for Aerosol Optical Depth in thousandths. It is not currently used in EnergyPlus calculations. Missing value is .999.
            Read more at: https://energyplus.net/sites/all/modules/custom/nrel_custom/pdfs/pdfs_v8.4.0/AuxiliaryPrograms.pdf (Chapter 2.9.1)
        """
        return self.__get_dataByField(29)

    @property
    def snowDepth(self):
        """Return annual Snow Depth as a Ladybug Data List

            This is the value for Snow Depth in cm. This field is used to tell when snow is on the ground and, thus, the ground reflectance may change. Missing value is 999.
            Read more at: https://energyplus.net/sites/all/modules/custom/nrel_custom/pdfs/pdfs_v8.4.0/AuxiliaryPrograms.pdf (Chapter 2.9.1)
        """
        return self.__get_dataByField(30)

    @property
    def daysSinceLastSnowfall(self):
        """Return annual Days Since Last Snow Fall as a Ladybug Data List

            This is the value for Days Since Last Snowfall. It is not currently used in EnergyPlus calculations. Missing value is 99.
            Read more at: https://energyplus.net/sites/all/modules/custom/nrel_custom/pdfs/pdfs_v8.4.0/AuxiliaryPrograms.pdf (Chapter 2.9.1)
        """
        return self.__get_dataByField(31)

    @property
    def albedo(self):
        """Return annual Albedo values as a Ladybug Data List

            The ratio (unitless) of reflected solar irradiance to global horizontal irradiance. It is not currently used in EnergyPlus
            Read more at: https://energyplus.net/sites/all/modules/custom/nrel_custom/pdfs/pdfs_v8.4.0/AuxiliaryPrograms.pdf (Chapter 2.9.1)
        """
        return self.__get_dataByField(32)

    @property
    def liquidPrecipitationDepth(self):
        """Return annual liquid precipitation depth as a Ladybug Data List

            The amount of liquid precipitation (mm) observed at the indicated time for the period indicated in the liquid precipitation quantity field. If this value is not missing, then it is used and overrides the "precipitation" flag as rainfall. Conversely, if the precipitation flag shows rain and this field is missing or zero, it is set to 1.5 (mm).
            Read more at: https://energyplus.net/sites/all/modules/custom/nrel_custom/pdfs/pdfs_v8.4.0/AuxiliaryPrograms.pdf (Chapter 2.9.1)
        """
        return self.__get_dataByField(33)

    @property
    def liquidPrecipitationQuantity(self):
        """Return annual Liquid Precipitation Quantity as a Ladybug Data List

            The period of accumulation (hr) for the liquid precipitation depth field. It is not currently used in EnergyPlus
            Read more at: https://energyplus.net/sites/all/modules/custom/nrel_custom/pdfs/pdfs_v8.4.0/AuxiliaryPrograms.pdf (Chapter 2.9.1)
        """
        return self.__get_dataByField(34)

    def __getWEAHeader(self):
        return  "place %s\n"%self.location.city + \
                "latitude %.2f\n"%self.location.latitude + \
                "longitude %.2f\n"%-self.location.longitude + \
                "time_zone %d\n"%(-self.location.timeZone * 15) + \
                "site_elevation %.1f\n"%self.location.elevation + \
                "weather_data_file_units 1\n"

    def epw2wea(self, filePath = None):
        """Write wea file from epw file
            WEA carries radiation values from epw ans is what gendaymtx uses to generate the sky
            I'm wrote my own implementation to avoid shipping epw2wea.exe file. Now epw2wea is
            part of the Radiance distribution
        """
        if not filePath:
            filePath = self.fileAddress[:-3] + "wea"

        with open(filePath, "wb") as weaFile:
            weaFile.write(self.__getWEAHeader())
            for dirRad, difRad in zip(self.directNormalRadiation, self.diffuseHorizontalRadiation):
                line = "%d %d %.3f %d %d\n"%(dirRad.datetime.month, dirRad.datetime.day, dirRad.datetime.hour - 0.5, dirRad, difRad)
                weaFile.write(line)

        return filePath

    def __repr__(self):
        return "EPW Data [%s]"%self.stationLocation.city

Ancestors (in MRO)

Static methods

def checkEpwFileAddress(

epwFileAddress)

Checks the path and checks the type for an epw file

@staticmethod
def checkEpwFileAddress(epwFileAddress):
    """ Checks the path and checks the type for an epw file"""
    if not os.path.isfile(epwFileAddress):
        raise Exception(epwFileAddress + ' is not a valid address.')
    if not epwFileAddress.lower().endswith('epw'):
        raise Exception(epwFileAddress + ' is not an .epw file.')
    return epwFileAddress

Instance variables

var aerosolOpticalDepth

Return annual Aerosol Optical Depth as a Ladybug Data List

This is the value for Aerosol Optical Depth in thousandths. It is not currently used in EnergyPlus calculations. Missing value is .999. Read more at: https://energyplus.net/sites/all/modules/custom/nrel_custom/pdfs/pdfs_v8.4.0/AuxiliaryPrograms.pdf (Chapter 2.9.1)

var albedo

Return annual Albedo values as a Ladybug Data List

The ratio (unitless) of reflected solar irradiance to global horizontal irradiance. It is not currently used in EnergyPlus Read more at: https://energyplus.net/sites/all/modules/custom/nrel_custom/pdfs/pdfs_v8.4.0/AuxiliaryPrograms.pdf (Chapter 2.9.1)

var atmosphericStationPressure

Return annual Atmospheric Station Pressure as a Ladybug Data List

This is the station pressure in Pa at the time indicated. Valid values range from 31,000 to 120,000. (These values were chosen from the standard barometric pressure for all elevations of the World). Missing value for this field is 999999. Read more at: https://energyplus.net/sites/all/modules/custom/nrel_custom/pdfs/pdfs_v8.4.0/AuxiliaryPrograms.pdf (Chapter 2.9.1)

var ceilingHeight

Return annual Ceiling Height as a Ladybug Data List

This is the value for ceiling height in m. (77777 is unlimited ceiling height. 88888 is cirroform ceiling.) It is not currently used in EnergyPlus calculations. Missing value is 99999 Read more at: https://energyplus.net/sites/all/modules/custom/nrel_custom/pdfs/pdfs_v8.4.0/AuxiliaryPrograms.pdf (Chapter 2.9.1)

var daysSinceLastSnowfall

Return annual Days Since Last Snow Fall as a Ladybug Data List

This is the value for Days Since Last Snowfall. It is not currently used in EnergyPlus calculations. Missing value is 99. Read more at: https://energyplus.net/sites/all/modules/custom/nrel_custom/pdfs/pdfs_v8.4.0/AuxiliaryPrograms.pdf (Chapter 2.9.1)

var dewPointTemperature

Return annual Dew Point Temperature as a Ladybug Data List

This is the dew point temperature in C at the time indicated. Note that this is a full numeric field (i.e. 23.6) and not an integer representation with tenths. Valid values range from -70 C to 70 C. Missing value for this field is 99.9 Read more at: https://energyplus.net/sites/all/modules/custom/nrel_custom/pdfs/pdfs_v8.4.0/AuxiliaryPrograms.pdf (Chapter 2.9.1)

var diffuseHorizontalIlluminance

Return annual Diffuse Horizontal Illuminance as a Ladybug Data List

This is the Diffuse Horizontal Illuminance in lux. (Average amount of illuminance in hundreds of lux received from the sky (excluding the solar disk) on a horizontal surface during the number of minutes preceding the time indicated.) It is not currently used in EnergyPlus calculations. It should have a minimum value of 0; missing value for this field is 999999 and will be considered missing if greater than or equal to 999900. Read more at: https://energyplus.net/sites/all/modules/custom/nrel_custom/pdfs/pdfs_v8.4.0/AuxiliaryPrograms.pdf (Chapter 2.9.1)

var diffuseHorizontalRadiation

Return annual Diffuse Horizontal Radiation as a Ladybug Data List

This is the Diffuse Horizontal Radiation in Wh/m2. (Amount of solar radiation in Wh/m2 received from the sky (excluding the solar disk) on a horizontal surface during the number of minutes preceding the time indicated.) If the field is missing ( >= 9999) or invalid ( < 0), it is set to 0. Counts of such missing values are totaled and presented at the end of the runperiod Read more at: https://energyplus.net/sites/all/modules/custom/nrel_custom/pdfs/pdfs_v8.4.0/AuxiliaryPrograms.pdf (Chapter 2.9.1)

var directNormalIlluminance

Return annual Direct Normal Illuminance as a Ladybug Data List

This is the Direct Normal Illuminance in lux. (Average amount of illuminance in hundreds of lux received directly from the solar disk on a surface perpendicular to the sun's rays, during the number of minutes preceding the time indicated.) It is not currently used in EnergyPlus calculations. It should have a minimum value of 0; missing value for this field is 999999 and will be considered missing if greater than or equal to 999900. Read more at: https://energyplus.net/sites/all/modules/custom/nrel_custom/pdfs/pdfs_v8.4.0/AuxiliaryPrograms.pdf (Chapter 2.9.1)

var directNormalRadiation

Return annual Direct Normal Radiation as a Ladybug Data List

This is the Direct Normal Radiation in Wh/m2. (Amount of solar radiation in Wh/m2 received directly from the solar disk on a surface perpendicular to the sun's rays, during the number of minutes preceding the time indicated.) If the field is missing ( >= 9999) or invalid ( < 0), it is set to 0. Counts of such missing values are totaled and presented at the end of the runperiod. Read more at: https://energyplus.net/sites/all/modules/custom/nrel_custom/pdfs/pdfs_v8.4.0/AuxiliaryPrograms.pdf (Chapter 2.9.1)

var dryBulbTemperature

Return annual Dry Bulb Temperature as a Ladybug Data List

This is the dry bulb temperature in C at the time indicated. Note that this is a full numeric field (i.e. 23.6) and not an integer representation with tenths. Valid values range from -70 C to 70 C. Missing value for this field is 99.9 Read more at: https://energyplus.net/sites/all/modules/custom/nrel_custom/pdfs/pdfs_v8.4.0/AuxiliaryPrograms.pdf (Chapter 2.9.1)

var epwHeader

var extraterrestrialDirectNormalRadiation

Return annual Extraterrestrial Direct Normal Radiation as a Ladybug Data List

This is the Extraterrestrial Direct Normal Radiation in Wh/m2. (Amount of solar radiation in Wh/m2 received on a surface normal to the rays of the sun at the top of the atmosphere during the number of minutes preceding the time indicated). It is not currently used in EnergyPlus calculations. It should have a minimum value of 0; missing value for this field is 9999. Read more at: https://energyplus.net/sites/all/modules/custom/nrel_custom/pdfs/pdfs_v8.4.0/AuxiliaryPrograms.pdf (Chapter 2.9.1)

var extraterrestrialHorizontalRadiation

Return annual Extraterrestrial Horizontal Radiation as a Ladybug Data List

This is the Extraterrestrial Horizontal Radiation in Wh/m2. It is not currently used in EnergyPlus calculations. It should have a minimum value of 0; missing value for this field is 9999 Read more at: https://energyplus.net/sites/all/modules/custom/nrel_custom/pdfs/pdfs_v8.4.0/AuxiliaryPrograms.pdf (Chapter 2.9.1)

var fileAddress

var globalHorizontalIlluminance

Return annual Global Horizontal Illuminance as a Ladybug Data List

This is the Global Horizontal Illuminance in lux. (Average total amount of direct and diffuse illuminance in hundreds of lux received on a horizontal surface during the number of minutes preceding the time indicated.) It is not currently used in EnergyPlus calculations. It should have a minimum value of 0; missing value for this field is 999999 and will be considered missing if greater than or equal to 999900. Read more at: https://energyplus.net/sites/all/modules/custom/nrel_custom/pdfs/pdfs_v8.4.0/AuxiliaryPrograms.pdf (Chapter 2.9.1)

var globalHorizontalRadiation

Return annual Global Horizontal Radiation as a Ladybug Data List

This is the Global Horizontal Radiation in Wh/m2. (Total amount of direct and diffuse solar radiation in Wh/m2 received on a horizontal surface during the number of minutes preceding the time indicated.) It is not currently used in EnergyPlus calculations. It should have a minimum value of 0; missing value for this field is 9999. Read more at: https://energyplus.net/sites/all/modules/custom/nrel_custom/pdfs/pdfs_v8.4.0/AuxiliaryPrograms.pdf (Chapter 2.9.1)

var horizontalInfraredRadiationIntensity

Return annual Horizontal Infrared Radiation Intensity as a Ladybug Data List

This is the Horizontal Infrared Radiation Intensity in Wh/m2. If it is missing, it is calculated from the Opaque Sky Cover field as shown in the following explanation. It should have a minimum value of 0; missing value for this field is 9999. Read more at: https://energyplus.net/sites/all/modules/custom/nrel_custom/pdfs/pdfs_v8.4.0/AuxiliaryPrograms.pdf (Chapter 2.9.1)

var isDataLoaded

var isLocationLoaded

var liquidPrecipitationDepth

Return annual liquid precipitation depth as a Ladybug Data List

The amount of liquid precipitation (mm) observed at the indicated time for the period indicated in the liquid precipitation quantity field. If this value is not missing, then it is used and overrides the "precipitation" flag as rainfall. Conversely, if the precipitation flag shows rain and this field is missing or zero, it is set to 1.5 (mm). Read more at: https://energyplus.net/sites/all/modules/custom/nrel_custom/pdfs/pdfs_v8.4.0/AuxiliaryPrograms.pdf (Chapter 2.9.1)

var liquidPrecipitationQuantity

Return annual Liquid Precipitation Quantity as a Ladybug Data List

The period of accumulation (hr) for the liquid precipitation depth field. It is not currently used in EnergyPlus Read more at: https://energyplus.net/sites/all/modules/custom/nrel_custom/pdfs/pdfs_v8.4.0/AuxiliaryPrograms.pdf (Chapter 2.9.1)

var location

var numOfFields

var opaqueSkyCover

Return annual Opaque Sky Cover as a Ladybug Data List

This is the value for opaque sky cover (tenths of coverage). (i.e. 1 is 1/10 covered. 10 is total coverage). (Amount of sky dome in tenths covered by clouds or obscuring phenomena that prevent observing the sky or higher cloud layers at the time indicated.) This is not used unless the field for Horizontal Infrared Radiation Intensity is missing and then it is used to calculate Horizontal Infrared Radiation Intensity. Minimum value is 0; maximum value is 10; missing value is 99. Read more at: https://energyplus.net/sites/all/modules/custom/nrel_custom/pdfs/pdfs_v8.4.0/AuxiliaryPrograms.pdf (Chapter 2.9.1)

var precipitableWater

Return annual Precipitable Water as a Ladybug Data List.

This is the value for Precipitable Water in mm. (This is not rain - rain is inferred from the PresWeathObs field but a better result is from the Liquid Precipitation Depth field)). It is not currently used in EnergyPlus calculations (primarily due to the unreliability of the reporting of this value). Missing value is 999. Read more at: https://energyplus.net/sites/all/modules/custom/nrel_custom/pdfs/pdfs_v8.4.0/AuxiliaryPrograms.pdf (Chapter 2.9.1)

var presentWeatherCodes

Return annual Present Weather Codes as a Ladybug Data List.

The present weather codes field is assumed to follow the TMY2 conventions for this field. Note that though this field may be represented as numeric (e.g. in the CSV format), it is really a text field of 9 single digits. This convention along with values for each "column" (left to right) is presented in Table 16. Note that some formats (e.g. TMY) does not follow this convention - as much as possible, the present weather codes are converted to this convention during WeatherConverter processing. Also note that the most important fields are those representing liquid precipitation - where the surfaces of the building would be wet. EnergyPlus uses "Snow Depth" to determine if snow is on the ground. Read more at: https://energyplus.net/sites/all/modules/custom/nrel_custom/pdfs/pdfs_v8.4.0/AuxiliaryPrograms.pdf (Chapter 2.9.1)

var presentWeatherObservation

Return annual Present Weather Observation as a Ladybug Data List.

If the value of the field is 0, then the observed weather codes are taken from the following field. If the value of the field is 9, then "missing" weather is assumed. Since the primary use of these fields (Present Weather Observation and Present Weather Codes) is for rain/wet surfaces, a missing observation field or a missing weather code implies no rain. Read more at: https://energyplus.net/sites/all/modules/custom/nrel_custom/pdfs/pdfs_v8.4.0/AuxiliaryPrograms.pdf (Chapter 2.9.1)

var relativeHumidity

Return annual Relative Humidity as a Ladybug Data List

This is the Relative Humidity in percent at the time indicated. Valid values range from 0% to 110%. Missing value for this field is 999. Read more at: https://energyplus.net/sites/all/modules/custom/nrel_custom/pdfs/pdfs_v8.4.0/AuxiliaryPrograms.pdf (Chapter 2.9.1)

var snowDepth

Return annual Snow Depth as a Ladybug Data List

This is the value for Snow Depth in cm. This field is used to tell when snow is on the ground and, thus, the ground reflectance may change. Missing value is 999. Read more at: https://energyplus.net/sites/all/modules/custom/nrel_custom/pdfs/pdfs_v8.4.0/AuxiliaryPrograms.pdf (Chapter 2.9.1)

var totalSkyCover

Return annual Total Sky Cover as a Ladybug Data List

This is the value for total sky cover (tenths of coverage). (i.e. 1 is 1/10 covered. 10 is total coverage). (Amount of sky dome in tenths covered by clouds or obscuring phenomena at the hour indicated at the time indicated.) Minimum value is 0; maximum value is 10; missing value is 99. Read more at: https://energyplus.net/sites/all/modules/custom/nrel_custom/pdfs/pdfs_v8.4.0/AuxiliaryPrograms.pdf (Chapter 2.9.1)

var visibility

Return annual Visibility as a Ladybug Data List

This is the value for visibility in km. (Horizontal visibility at the time indicated.) It is not currently used in EnergyPlus calculations. Missing value is 9999. Read more at: https://energyplus.net/sites/all/modules/custom/nrel_custom/pdfs/pdfs_v8.4.0/AuxiliaryPrograms.pdf (Chapter 2.9.1)

var windDirection

Return annual Wind Direction as a Ladybug Data List

This is the Wind Direction in degrees where the convention is that North=0.0, East=90.0, South=180.0, West=270.0. (Wind direction in degrees at the time indicated. If calm, direction equals zero.) Values can range from 0 to 360. Missing value is 999. Read more at: https://energyplus.net/sites/all/modules/custom/nrel_custom/pdfs/pdfs_v8.4.0/AuxiliaryPrograms.pdf (Chapter 2.9.1)

var windSpeed

Return annual Wind Speed as a Ladybug Data List

This is the wind speed in m/sec. (Wind speed at time indicated.) Values can range from 0 to 40. Missing value is 999. Read more at: https://energyplus.net/sites/all/modules/custom/nrel_custom/pdfs/pdfs_v8.4.0/AuxiliaryPrograms.pdf (Chapter 2.9.1)

var years

Return years as a Ladybug Data List

var zenithLuminance

Return annual Zenith Luminance as a Ladybug Data List

This is the Zenith Illuminance in Cd/m2. (Average amount of luminance at the sky's zenith in tens of Cd/m2 during the number of minutes preceding the time indicated.) It is not currently used in EnergyPlus calculations. It should have a minimum value of 0; missing value for this field is 9999. Read more at: https://energyplus.net/sites/all/modules/custom/nrel_custom/pdfs/pdfs_v8.4.0/AuxiliaryPrograms.pdf (Chapter 2.9.1)

Methods

def __init__(

self, epwFileAddress=None)

Import epw data from a local epw file

epwFileAddress: Local file address to an epw file

def __init__(self, epwFileAddress = None):
    """
    Import epw data from a local epw file
    epwFileAddress: Local file address to an epw file
    """
    if not epwFileAddress: return
    self.fileAddress = self.checkEpwFileAddress(epwFileAddress)
    self.filePath, self.fileName = os.path.split(self.fileAddress)
    self.__isDataLoaded = False
    self.__isLocationLoaded = False
    self.__data = dict()
    self.epwHeader = None
    self.numOfFields = 35 # it is 35 for TMY3 files

def epw2wea(

self, filePath=None)

Write wea file from epw file WEA carries radiation values from epw ans is what gendaymtx uses to generate the sky I'm wrote my own implementation to avoid shipping epw2wea.exe file. Now epw2wea is part of the Radiance distribution

def epw2wea(self, filePath = None):
    """Write wea file from epw file
        WEA carries radiation values from epw ans is what gendaymtx uses to generate the sky
        I'm wrote my own implementation to avoid shipping epw2wea.exe file. Now epw2wea is
        part of the Radiance distribution
    """
    if not filePath:
        filePath = self.fileAddress[:-3] + "wea"
    with open(filePath, "wb") as weaFile:
        weaFile.write(self.__getWEAHeader())
        for dirRad, difRad in zip(self.directNormalRadiation, self.diffuseHorizontalRadiation):
            line = "%d %d %.3f %d %d\n"%(dirRad.datetime.month, dirRad.datetime.day, dirRad.datetime.hour - 0.5, dirRad, difRad)
            weaFile.write(line)
    return filePath

def importData(

self, onlyImportLocation=False)

imports data from an epw file. Hourly data will be saved in self.data and location data will be saved in self.location

def importData(self, onlyImportLocation = False):
    """
    imports data from an epw file.
    Hourly data will be saved in self.data and location data
    will be saved in self.location
    """
    with open(self.fileAddress, 'rb') as epwin:
        epwlines = epwin.readlines()
    # import location data
    # first line has location data - Here is an example
    # LOCATION,Denver Centennial  Golden   Nr,CO,USA,TMY3,724666,39.74,-105.18,-7.0,1829.0
    if not self.__isLocationLoaded:
        locationData = epwlines[0].strip().split(',')
        self.stationLocation = core.Location()
        self.stationLocation.city = locationData[1]
        self.stationLocation.state = locationData[2]
        self.stationLocation.country = locationData[3]
        self.stationLocation.source = locationData[4]
        self.stationLocation.stationId = locationData[5]
        self.stationLocation.latitude = float(locationData[6])
        self.stationLocation.longitude = float(locationData[7])
        self.stationLocation.timeZone = float(locationData[8])
        self.stationLocation.elevation = float(locationData[9])
        self.__isLocationLoaded = True
        if onlyImportLocation: return
    # TODO: create an object from the header and analyze data
    # get epw header
    self.epwHeader = epwlines[:8]
    self.numOfFields = len(epwlines[8].strip().split(','))
    # import hourly data
    analysisPeriod = core.AnalysisPeriod()
    for fieldNumber in range(0, self.numOfFields):
        # create header
        field = EPWDataTypes.get_fieldByNumber(fieldNumber)
        header = core.LBHeader(city = self.stationLocation.city, frequency ='Hourly', \
                analysisPeriod = analysisPeriod, \
                dataType = field.name, unit =field.units)
        # create an empty data list with the header
        self.__data[fieldNumber] = core.DataList(header =header)
    for line in epwlines[8:]:
        data = line.strip().split(',')
        year, month, day, hour = map(int, data[:4])
        # in an epw file year can be different for each month
        # since I'm using this timestamp as the key and will be using it for sorting
        # I'm setting it up to 2000 - the real year will be collected under modelYear
        timestamp = core.LBDateTime(month, day, hour)
        for fieldNumber in range(0, self.numOfFields):
            valueType = EPWDataTypes.get_fieldByNumber(fieldNumber).valueType
            value = map(valueType, [data[fieldNumber]])[0]
            self.__data[fieldNumber].append(core.LBData(value, timestamp))
    del(epwlines)
    self.__isDataLoaded = True

def import_dataByField(

self, fieldNumber)

Return annual values for any fieldNumber in epw file.

This is a useful method to get the values for fields that Ladybug currently doesn't import by default. You can find list of fields by typing EPWDataTypes.fields

Args: fieldNumber: a value between 0 to 34 for different available epw fields. 0 Year 1 Month 2 Day 3 Hour 4 Minute - 6 Dry Bulb Temperature 7 Dew Point Temperature 8 Relative Humidity 9 Atmospheric Station Pressure 10 Extraterrestrial Horizontal Radiation 11 Extraterrestrial Direct Normal Radiation 12 Horizontal Infrared Radiation Intensity 13 Global Horizontal Radiation 14 Direct Normal Radiation 15 Diffuse Horizontal Radiation 16 Global Horizontal Illuminance 17 Direct Normal Illuminance 18 Diffuse Horizontal Illuminance 19 Zenith Luminance 20 Wind Direction 21 Wind Speed 22 Total Sky Cover 23 Opaque Sky Cover 24 Visibility 25 Ceiling Height 26 Present Weather Observation 27 Present Weather Codes 28 Precipitable Water 29 Aerosol Optical Depth 30 Snow Depth 31 Days Since Last Snowfall 32 Albedo 33 Liquid Precipitation Depth 34 Liquid Precipitation Quantity Returns: An annual Ladybug list

def import_dataByField(self, fieldNumber):
    """Return annual values for any fieldNumber in epw file.
    This is a useful method to get the values for fields that Ladybug currently
    doesn't import by default. You can find list of fields by typing EPWDataTypes.fields
    Args:
        fieldNumber: a value between 0 to 34 for different available epw fields.
        0 Year
        1 Month
        2 Day
        3 Hour
        4 Minute
        -
        6 Dry Bulb Temperature
        7 Dew Point Temperature
        8 Relative Humidity
        9 Atmospheric Station Pressure
        10 Extraterrestrial Horizontal Radiation
        11 Extraterrestrial Direct Normal Radiation
        12 Horizontal Infrared Radiation Intensity
        13 Global Horizontal Radiation
        14 Direct Normal Radiation
        15 Diffuse Horizontal Radiation
        16 Global Horizontal Illuminance
        17 Direct Normal Illuminance
        18 Diffuse Horizontal Illuminance
        19 Zenith Luminance
        20 Wind Direction
        21 Wind Speed
        22 Total Sky Cover
        23 Opaque Sky Cover
        24 Visibility
        25 Ceiling Height
        26 Present Weather Observation
        27 Present Weather Codes
        28 Precipitable Water
        29 Aerosol Optical Depth
        30 Snow Depth
        31 Days Since Last Snowfall
        32 Albedo
        33 Liquid Precipitation Depth
        34 Liquid Precipitation Quantity
    Returns:
        An annual Ladybug list
    """
    return self.__get_dataByField(fieldNumber)

def save(

self, filePath=None, fileName=None)

Save epw object as an epw file

def save(self, filePath = None, fileName = None):
    """Save epw object as an epw file"""
    # check filePath
    if not filePath:
        filePath = self.filePath
    if not fileName:
        fileName = ".".join((self.fileName).split(".")[:-1]) + "_modified.epw"
    fullPath = os.path.join(filePath, fileName)
    # load data if it's  not loaded
    if not self.isDataLoaded: self.importData()
    # write the file
    with open(fullPath, 'wb') as modEpwFile:
        modEpwFile.writelines(self.epwHeader)
        try:
            lines = []
            for hour in range(0, 8760):
                line = []
                for field in range(0, self.numOfFields):
                    line.append(str(self.__data[field].values[hour].value))
                lines.append(",".join(line) + "\n")
        except IndexError:
            # cleaning up
            modEpwFile.close()
            del(lines)
            lengthErrorMsg = "Data length is not 8760 hours! Data can't be saved to epw file. " + \
                "Did you filtered the data by AnalysisPeriod or by ConditionalStatment?"
            raise ValueError(lengthErrorMsg)
        modEpwFile.writelines(lines)
    del(lines)
    print "New epw file is written to [%s]"%fullPath

class EPWDataTypes

EPW weather file fields Read more at: https://energyplus.net/sites/all/modules/custom/nrel_custom/pdfs/pdfs_v8.4.0/AuxiliaryPrograms.pdf (Chapter 2.9.1)

class EPWDataTypes:
    """EPW weather file fields
        Read more at: https://energyplus.net/sites/all/modules/custom/nrel_custom/pdfs/pdfs_v8.4.0/AuxiliaryPrograms.pdf (Chapter 2.9.1)

    """
    __fields = {
        0 : { 'name'  : 'Year',
                'type' : int
            },

        1 : { 'name'  : 'Month',
                'type' : int
            },

        2 : { 'name'  : 'Day',
                'type' : int
            },

        3 : { 'name'  : 'Hour',
                'type' : int
            },

        4 : { 'name'  : 'Minute',
                'type' : int
            },

        5 : { 'name'  : 'Uncertainty Flags',
                'type' : str
            },

        6 : { 'name'  : 'Dry Bulb Temperature',
                'type' : float,
                'units' : 'C',
                'min'   : -70,
                'max'   : 70,
                'missing' : 99.9
            },

        7 : { 'name' : 'Dew Point Temperature',
                'type' : float,
                'units' : 'C',
                'min' : -70,
                'max' : 70,
                'missing' : 99.9
            },

        8 : { 'name' : 'Relative Humidity',
                'type' : int,
                'missing' : 999,
                'min' : 0,
                'max' : 110
            },

        9 : { 'name' : 'Atmospheric Station Pressure',
                'type' : int,
                'units' : 'Pa',
                'missing' : 999999,
                'min' : 31000,
                'max' : 120000
            },

        10 : { 'name' : 'Extraterrestrial Horizontal Radiation',
                'type' : int,
                'units' : 'Wh/m2',
                'missing' :  9999,
                'min' : 0
            },

        11 : { 'name' : 'Extraterrestrial Direct Normal Radiation',
                'type' : int,
                'units' :  'Wh/m2',
                'missing' : 9999,
                'min' : 0
            },

        12 : { 'name' : 'Horizontal Infrared Radiation Intensity',
                'type' : int,
                'units' : 'Wh/m2',
                'missing' : 9999,
                'min' : 0
            },

        13 : { 'name' : 'Global Horizontal Radiation',
                'type' : int,
                'units' : 'Wh/m2',
                'missing' : 9999,
                'min' : 0
            },

        14 : { 'name' : 'Direct Normal Radiation',
                'type' : int,
                'units' : 'Wh/m2',
                'missing' : 9999,
                'min' : 0
            },

        15 : { 'name' : 'Diffuse Horizontal Radiation',
                'type' : int,
                'units' : 'Wh/m2',
                'missing' : 9999,
                'min' : 0
            },

        16 : { 'name' : 'Global Horizontal Illuminance',
                'type' : int,
                'units' : 'lux',
                'missing' : 999999, # note will be missing if >= 999900
                'min' : 0
            },

        17 : { 'name' : 'Direct Normal Illuminance',
                'type' : int,
                'units' : 'lux',
                'missing' : 999999, # note will be missing if >= 999900
                'min' : 0
            },

        18 : { 'name' : 'Diffuse Horizontal Illuminance',
                'type' : int,
                'units' : 'lux',
                'missing' : 999999, # note will be missing if >= 999900
                'min' : 0
            },

        19 : { 'name' : 'Zenith Luminance',
                'type' : int,
                'units' : 'Cd/m2',
                'missing' : 9999, # note will be missing if >= 9999
                'min' : 0
            },

        20 : { 'name' : 'Wind Direction',
                'type' : int,
                'units' : 'degrees',
                'missing' : 999,
                'min' : 0,
                'max' : 360
            },

        21 : { 'name' : 'Wind Speed',
                'type' : float,
                'units' : 'm/s',
                'missing' : 999,
                'min' : 0,
                'max' : 40
            },

        22 : { 'name' : 'Total Sky Cover', # (used if Horizontal IR Intensity missing)
                'type' : int,
                'missing' : 99,
                'min' : 0,
                'max' : 10
            },

        23 : { 'name' : 'Opaque Sky Cover', #(used if Horizontal IR Intensity missing)
                'type' : int,
                'missing' : 99
            },

        24 : { 'name' : 'Visibility',
                'type' : float,
                'units' : 'km',
                'missing' : 9999
            },

        25 : { 'name' : 'Ceiling Height',
                'type' : int,
                'units' : 'm',
                'missing' : 99999
            },

        26 : { 'name' : 'Present Weather Observation',
                'type' : int
            },

        27 : { 'name' : 'Present Weather Codes',
                'type' : int
            },

        28 : { 'name' : 'Precipitable Water',
                'type' : int,
                'units' : 'mm',
                'missing' : 999
            },

        29 : { 'name' : 'Aerosol Optical Depth',
                'type' : float,
                'units' : 'thousandths',
                'missing' : 999
            },

        30 : { 'name' : 'Snow Depth',
                'type' : int,
                'units' : 'cm',
                'missing' : 999
            },

        31 : { 'name' :  'Days Since Last Snowfall',
                'type' : int,
                'missing' : 99
            },

        32 : { 'name' :  'Albedo',
                'type' : float,
                'missing': 999
            },

        33 : { 'name' :  'Liquid Precipitation Depth',
                'type' : float,
                'units': 'mm',
                'missing': 999
            },

        34 : { 'name' :  'Liquid Precipitation Quantity',
                'type' : float,
                'units': 'hr',
                'missing': 99
            }
        }

    class EPWField:
        def __init__(self, dataDict):
            self.name = dataDict['name']
            self.valueType = dataDict['type']
            if 'units' in dataDict:
                self.units = dataDict['units']
            else:
                self.units = 'N/A'

    @classmethod
    def fieldNumbers(cls):
        for key, value in cls.__fields.items():
            print key, value['name']

    @classmethod
    def fields(cls):
        """Return fields as a dictionary.

        If you are looking for field numbers try fieldNumbers method instead.
        """
        return cls.__fields

    @classmethod
    def get_fieldByNumber(cls, fieldNumber):
        """Return an EPWField based on field number.

        0 Year
        1 Month
        2 Day
        3 Hour
        4 Minute
        -
        6 Dry Bulb Temperature
        7 Dew Point Temperature
        8 Relative Humidity
        9 Atmospheric Station Pressure
        10 Extraterrestrial Horizontal Radiation
        11 Extraterrestrial Direct Normal Radiation
        12 Horizontal Infrared Radiation Intensity
        13 Global Horizontal Radiation
        14 Direct Normal Radiation
        15 Diffuse Horizontal Radiation
        16 Global Horizontal Illuminance
        17 Direct Normal Illuminance
        18 Diffuse Horizontal Illuminance
        19 Zenith Luminance
        20 Wind Direction
        21 Wind Speed
        22 Total Sky Cover
        23 Opaque Sky Cover
        24 Visibility
        25 Ceiling Height
        26 Present Weather Observation
        27 Present Weather Codes
        28 Precipitable Water
        29 Aerosol Optical Depth
        30 Snow Depth
        31 Days Since Last Snowfall
        32 Albedo
        33 Liquid Precipitation Depth
        34 Liquid Precipitation Quantity
        """
        return cls.EPWField(cls.__fields[fieldNumber])

Ancestors (in MRO)

Class variables

var EPWField

Methods

def fieldNumbers(

cls)

@classmethod
def fieldNumbers(cls):
    for key, value in cls.__fields.items():
        print key, value['name']

def fields(

cls)

Return fields as a dictionary.

If you are looking for field numbers try fieldNumbers method instead.

@classmethod
def fields(cls):
    """Return fields as a dictionary.
    If you are looking for field numbers try fieldNumbers method instead.
    """
    return cls.__fields

def get_fieldByNumber(

cls, fieldNumber)

Return an EPWField based on field number.

0 Year 1 Month 2 Day 3 Hour 4 Minute - 6 Dry Bulb Temperature 7 Dew Point Temperature 8 Relative Humidity 9 Atmospheric Station Pressure 10 Extraterrestrial Horizontal Radiation 11 Extraterrestrial Direct Normal Radiation 12 Horizontal Infrared Radiation Intensity 13 Global Horizontal Radiation 14 Direct Normal Radiation 15 Diffuse Horizontal Radiation 16 Global Horizontal Illuminance 17 Direct Normal Illuminance 18 Diffuse Horizontal Illuminance 19 Zenith Luminance 20 Wind Direction 21 Wind Speed 22 Total Sky Cover 23 Opaque Sky Cover 24 Visibility 25 Ceiling Height 26 Present Weather Observation 27 Present Weather Codes 28 Precipitable Water 29 Aerosol Optical Depth 30 Snow Depth 31 Days Since Last Snowfall 32 Albedo 33 Liquid Precipitation Depth 34 Liquid Precipitation Quantity

@classmethod
def get_fieldByNumber(cls, fieldNumber):
    """Return an EPWField based on field number.
    0 Year
    1 Month
    2 Day
    3 Hour
    4 Minute
    -
    6 Dry Bulb Temperature
    7 Dew Point Temperature
    8 Relative Humidity
    9 Atmospheric Station Pressure
    10 Extraterrestrial Horizontal Radiation
    11 Extraterrestrial Direct Normal Radiation
    12 Horizontal Infrared Radiation Intensity
    13 Global Horizontal Radiation
    14 Direct Normal Radiation
    15 Diffuse Horizontal Radiation
    16 Global Horizontal Illuminance
    17 Direct Normal Illuminance
    18 Diffuse Horizontal Illuminance
    19 Zenith Luminance
    20 Wind Direction
    21 Wind Speed
    22 Total Sky Cover
    23 Opaque Sky Cover
    24 Visibility
    25 Ceiling Height
    26 Present Weather Observation
    27 Present Weather Codes
    28 Precipitable Water
    29 Aerosol Optical Depth
    30 Snow Depth
    31 Days Since Last Snowfall
    32 Albedo
    33 Liquid Precipitation Depth
    34 Liquid Precipitation Quantity
    """
    return cls.EPWField(cls.__fields[fieldNumber])