Exemplo n.º 1
0
class GendaylitTestCase(unittest.TestCase):
    """Test for (honeybee/radiance/command/gendaylit.py)."""

    # preparing to test.
    def setUp(self):
        # instantiate gendaylit with monthdayhour
        self.genday_month_day = Gendaylit(month_day_hour=(11, 12, '11EST'))
        self.genday_month_day.output_file = 'room/temp/genday.sky'
        # instantiate gendaylit params and add some values
        gendaylit_param1 = GendaylitParameters()

        # add params to gendaylit class.
        self.gendayMonthDay.gendaylit_parameters = gendaylit_param1

        # instantiate another gendaylit, with altitude and azimuth angles.
        self.genday_alt_azi = Gendaylit()
        genday_param2 = GendaylitParameters(altitude_azimuth=(32, 11))
        self.genday_alt_azi.gendaylit_parameters = genday_param2

    def tearDown(self):
        "Clean stuff created during the test"
        os.remove('room/temp/genday.sky')

    def test_default_values(self):
        "Test the command runs correctly"
        # gendaylit_month_day_string = self.genday_month_day.to_rad_string()
        self.genday_month_day.execute()
        # This prints gendaylit 11 12 11EST -ang 32 11 -g 0.2 +s -c
        # The -ang 32 11 and +s where not assigned for this instance but they
        # pop up for some reason.

        gendaylit_alt_azi_string = self.genday_alt_azi.gendaylit_parameters \
            .to_rad_string()
        self.assertEqual(gendaylit_alt_azi_string, '-ang 32.0 11.0')
Exemplo n.º 2
0
    def setUp(self):
        # instantiate gendaylit with monthdayhour
        self.genday_month_day = Gendaylit(month_day_hour=(11, 12, '11EST'))
        self.genday_month_day.output_file = 'room/temp/genday.sky'
        # instantiate gendaylit params and add some values
        gendaylit_param1 = GendaylitParameters()

        # add params to gendaylit class.
        self.gendayMonthDay.gendaylit_parameters = gendaylit_param1

        # instantiate another gendaylit, with altitude and azimuth angles.
        self.genday_alt_azi = Gendaylit()
        genday_param2 = GendaylitParameters(altitude_azimuth=(32, 11))
        self.genday_alt_azi.gendaylit_parameters = genday_param2
Exemplo n.º 3
0
def analemma(epwFile,
             sunDiscRadPath,
             sunListPath=None,
             solarRadiationMatrixPath=None,
             HOYlist=range(8760)):
    """Sun analemma calculator.

    This function can be used for multiple purposes. For just generating the
    sunDiscRadPath for visualizing physically-accurate sun positions, specify
    only that variable. For calculating ASE or for Daylight Coefficient
    calculations, specify the sunListPath and solarRadiationMatrixPath as well.

    Args:
        epwFile: A standard epw file containing 8760 data points. Hacked epws will
            also work but then the HOY input needs to be adjusted accordingly.
            Required input.
        sunDiscRadPath: The path for the rad file to which the Radiance definitions
            of solar discs will be written to.
        sunListPath: The path for the list of suns which is required for daylighting
            calculations.
        solarRadiationMatrixPath: The path for the matrix containing solar radiation.
        HOYlist: A list of hours of the year.

    Returns: Paths for sunDiscRadPath, sunListPath and solarRadiationMatrixPath

    usage:
        sunRad,sunList,sunMtx = analemma(epwFile,sunRad,...)
        And then to other processes.
    """

    if sunListPath or solarRadiationMatrixPath:
        assert sunListPath and solarRadiationMatrixPath,\
            'If either sunListPath (%s) or solarRadiationMatrixPath (%s) ' \
            'are specified, the other variable needs to be specified' \
            ' as well.' % (sunListPath, solarRadiationMatrixPath)

    logger.info('Starting calculations')

    monthDateTime = (DateTime.fromHoy(idx) for idx in HOYlist)

    epw = EPW(epwFile)
    latitude, longitude = epw.location.latitude, -epw.location.longitude
    meridian = -(15 * epw.location.timezone)

    # Create a directory for ASE test.

    # Defining these upfront so that this data may be used for validation without
    # rerunning calcs every time

    # instantiating classes before looping makes sense as it will avoid the same calls
    # over and over.
    genParam = GendaylitParameters()
    genParam.meridian = meridian
    genParam.longitude = longitude
    genParam.latitude = latitude

    genDay = Gendaylit()

    sunValues = []
    sunValuesHour = []

    logger.info('Calculating sun positions and radiation values')

    # We need to throw out all the warning values arising from times when sun isn't
    # present.
    # os.devnull serves that purpose.
    with open(os.devnull, 'w') as warningDump:
        for timeStamp in monthDateTime:
            month, day, hour = timeStamp.month, timeStamp.day, timeStamp.hour + 0.5
            dnr, dhr = epw.directNormalRadiation[timeStamp.intHOY], \
                epw.diffuseHorizontalRadiation[timeStamp.intHOY]

            if dnr + dhr == 0:
                # no need to run gendaylit as there is no radiation / sun
                continue

            genParam.dirNormDifHorzIrrad = (dnr, dhr)

            genDay.monthDayHour = (month, day, hour)
            genDay.gendaylitParameters = genParam
            gendayCmd = genDay.toRadString().split('|')[0]

            # run cmd, get results in the form of a list of lines.
            cmdRun = Popen(gendayCmd, stdout=PIPE, stderr=warningDump)
            data = cmdRun.stdout.read().split('\n')
            print(data)
            assert False
            # clean the output by throwing out comments and brightness functions.
            sunCurrentValue = []
            for lines in data:
                if not lines.strip().startswith("#"):
                    if "brightfunc" in lines:
                        break
                    if lines.strip():
                        sunCurrentValue.extend(lines.strip().split())

            # If a sun definition was captured in the last for-loop, store info.
            if sunCurrentValue and max(map(float, sunCurrentValue[6:9])):
                sunCurrentValue[2] = 'solar%s' % (len(sunValues) + 1)
                sunCurrentValue[9] = 'solar%s' % (len(sunValues) + 1)
                sunValues.append(sunCurrentValue)
                sunValuesHour.append(timeStamp.intHOY)

    numOfSuns = len(sunValues)

    logger.info('Writing sun definitions to disc')

    # create solar discs.
    with open(sunDiscRadPath, 'w') as solarDiscFile:
        solarDiscFile.write("\n".join([" ".join(sun) for sun in sunValues]))

    logger.info('Sun definitions are written to: %s' % sunDiscRadPath)

    if solarRadiationMatrixPath:
        # create list of suns.
        with open(sunListPath, 'w') as sunListPathData:
            sunListPathData.write("\n".join(
                ["solar%s" % (idx + 1) for idx in xrange(numOfSuns)]))

        # Start creating header for the sun matrix.
        fileHeader = ['#?RADIANCE']
        fileHeader += ['Sun matrix created by Honeybee']
        fileHeader += ['LATLONG= %s %s' % (latitude, -longitude)]
        fileHeader += ['NROWS=%s' % numOfSuns]
        fileHeader += ['NCOLS=%s' % len(HOYlist)]
        fileHeader += ['NCOMP=3']
        fileHeader += ['FORMAT=ascii']

        # Write the matrix to file.
        with open(solarRadiationMatrixPath, 'w') as sunMtx:
            sunMtx.write("\n".join(fileHeader) + '\n' + '\n')
            for idx, sunValue in enumerate(sunValues):
                sunRadList = ["0 0 0"] * len(HOYlist)
                sunRadList[sunValuesHour[idx]] = " ".join(sunValue[6:9])
                sunMtx.write("\n".join(sunRadList) + "\n" + "\n")

            # This last one is for the ground.
            sunRadList = ["0 0 0"] * len(HOYlist)
            sunMtx.write("\n".join(sunRadList))

    return sunDiscRadPath, sunListPath, solarRadiationMatrixPath
Exemplo n.º 4
0
def directSunCalcs(epwFile,
                   materialFile,
                   geometryFiles,
                   pointsFile,
                   calcASE=True,
                   calcASEptsSummary=True,
                   illumForASE=1000,
                   hoursForASE=250,
                   hoyForValidation=13,
                   repeatValidationOnly=False):
    """

    Args:
        epwFile: path.
        materialFile: path.
        geometryFiles: path(s).
        pointsFile: path.
        calcASE: Boolean. If set to False, only raytrace and illuminance calcs will be
            performed.
        calcASEptsSummary: If set to True, will produce a summary of points and the number
            of hours for which they are above the value set for illumForASE. If set to
            False only the direct value of ASE (as specified by LM-83-12 will be calculated.)
        illumForASE: Illuminance for ASE. Has been set to a default of 1000 lux as per
            LM-83-12.
        hoursForASE: Hour-threshold for ASE. Has been set to a default of 250 hours as per
            LM-83-12. This option is only relevant if the the calcASEptsSummary option has
            been set to False. As otherwise, an entire list of hours will be produced regardless.
        hoyForValidation: A value between 0 to 8759 to check the annual results against an
            independent point-in-time ray-trace calc using rtrace. No validation will be
            performed if this value is set to None.
        repeatValidationOnly: Once the claculations have been run. Validation for more
            hours can be performed by setting this to True. Default is False.

    Returns: This function prints out. Does not return anything.

    """

    #a sad logging hack
    statusMsg = lambda msg: "\n%s:%s\n%s\n" % (time.ctime(), msg, "*~" * 25)

    print(statusMsg('Starting calculations'))

    sceneData = [materialFile]
    #Append if single, extend if multiple
    if isinstance(geometryFiles, basestring):
        sceneData.append(geometryFiles)
    elif isinstance(geometryFiles, (tuple, list)):
        sceneData.extend(geometryFiles)

    monthDateTime = [DateTime.fromHoy(idx) for idx in xrange(8760)]

    epw = EPW(epwFile)
    latitude, longitude = epw.location.latitude, -epw.location.longitude
    meridian = -(15 * epw.location.timezone)

    #Create a directory for ASE test.
    dirName = 'tests/ASEtest'
    if not os.path.exists(dirName):
        os.mkdir(dirName)
    #Defining these upfront so that this data may be used for validation without rerunning
    #calcs every time
    sunList = os.path.join(dirName, 'sunlist')
    sunDiscRadFile = os.path.join(dirName, 'sunFile.rad')
    radiationMatrix = os.path.join(dirName, 'sunRadiation.mtx')
    annualResultsFile = os.path.join(dirName, 'illum.ill')

    if not repeatValidationOnly:
        # preCalcFiles = (sunList,sunDiscRadFile,radiationMatrix,annualResultsFile)
        # for files in preCalcFiles:
        #     assert os.path.exists(files),'Precalculated data cannot be used as the file ' \
        #                                  '%s, which is required for calculations cannot be' \
        #                                  'found.'

        #instantiating classes before looping makes sense as it will avoid the same calls over
        #   and over.
        genParam = GendaylitParameters()
        genParam.meridian = meridian
        genParam.longitude = longitude
        genParam.latitude = latitude

        genDay = Gendaylit()

        sunValues = []
        sunValuesHour = []

        print(statusMsg('Calculating sun positions and radiation values'))

        # We need to throw out all the warning values arising from times when sun isn't present.
        # os.devnull serves that purpose.
        with open(os.devnull, 'w') as warningDump:
            for idx, timeStamp in enumerate(monthDateTime):
                month, day, hour = timeStamp.month, timeStamp.day, timeStamp.hour + 0.5
                genParam.dirNormDifHorzIrrad = (
                    epw.directNormalRadiation[idx],
                    epw.diffuseHorizontalRadiation[idx])

                genDay.monthDayHour = (month, day, hour)
                genDay.gendaylitParameters = genParam
                gendayCmd = genDay.toRadString().split('|')[0]

                #run cmd, get results in the form of a list of lines.
                cmdRun = Popen(gendayCmd, stdout=PIPE, stderr=warningDump)
                data = cmdRun.stdout.read().split('\n')

                #clean the output by throwing out comments as well as brightness functions.
                sunCurrentValue = []
                for lines in data:
                    if not lines.strip().startswith("#"):
                        if "brightfunc" in lines:
                            break
                        if lines.strip():
                            sunCurrentValue.extend(lines.strip().split())

                #If a sun definition was captured in the last for-loop, store info.
                if sunCurrentValue and max(map(float, sunCurrentValue[6:9])):
                    sunCurrentValue[2] = 'solar%s' % (len(sunValues) + 1)
                    sunCurrentValue[9] = 'solar%s' % (len(sunValues) + 1)
                    sunValues.append(sunCurrentValue)
                    sunValuesHour.append(idx)

        numOfSuns = len(sunValues)

        print(statusMsg('Writing sun definitions to disc'))
        #create list of suns.
        with open(sunList, 'w') as sunList:
            sunList.write("\n".join(
                ["solar%s" % (idx + 1) for idx in xrange(numOfSuns)]))

        #create solar discs.
        with open(sunDiscRadFile, 'w') as solarDiscFile:
            solarDiscFile.write("\n".join([" ".join(sun)
                                           for sun in sunValues]))

        #Start creating header for the sun matrix.
        fileHeader = ['#?RADIANCE']
        fileHeader += ['Sun matrix created by Honeybee']
        fileHeader += ['LATLONG= %s %s' % (latitude, -longitude)]
        fileHeader += ['NROWS=%s' % numOfSuns]
        fileHeader += ['NCOLS=8760']
        fileHeader += ['NCOMP=3']
        fileHeader += ['FORMAT=ascii']

        #Write the matrix to file.
        with open(radiationMatrix, 'w') as sunMtx:
            sunMtx.write("\n".join(fileHeader) + '\n' + '\n')
            for idx, sunValue in enumerate(sunValues):
                sunRadList = ["0 0 0"] * 8760
                sunRadList[sunValuesHour[idx]] = " ".join(sunValue[6:9])
                sunMtx.write("\n".join(sunRadList) + "\n" + "\n")

            #This last one is for the ground.
            sunRadList = ["0 0 0"] * 8760
            sunMtx.write("\n".join(sunRadList))

        print(statusMsg('Starting Raytrace calculations.'))

        octree = Oconv()
        octree.sceneFiles = sceneData + [r'tests/ASEtest/sunFile.rad']
        octree.outputFile = r'tests/ASEtest/roomSun.oct'
        octree.execute()

        rctPara = RcontribParameters()
        rctPara.ambientBounces = 0
        rctPara.directJitter = 0
        rctPara.directCertainty = 1
        rctPara.directThreshold = 0
        rctPara.modFile = r'tests/ASEtest/sunlist'
        rctPara.irradianceCalc = True

        rctb = Rcontrib()
        rctb.octreeFile = r'tests/ASEtest/roomSun.oct'
        rctb.outputFile = r'tests/ASEtest/sunCoeff.dc'
        rctb.pointsFile = pointsFile
        rctb.rcontribParameters = rctPara

        rctb.execute()

        dct = Dctimestep()
        dct.daylightCoeffSpec = r'tests/ASEtest/sunCoeff.dc'
        dct.skyVectorFile = r'tests/ASEtest/sunRadiation.mtx'
        dct.outputFile = r'tests/ASEtest/illum.tmp'
        dct.execute()

        mtx2Param = RmtxopParameters()
        mtx2Param.outputFormat = 'a'
        mtx2Param.combineValues = (47.4, 119.9, 11.6)
        mtx2Param.transposeMatrix = True
        mtx2 = Rmtxop(matrixFiles=[r'tests/ASEtest/illum.tmp'],
                      outputFile=annualResultsFile)
        mtx2.rmtxopParameters = mtx2Param
        mtx2.execute()

        print(statusMsg('Finished raytrace.'))

    # get points Data
    pointsList = []
    with open(pointsFile) as pointsData:
        for lines in pointsData:
            if lines.strip():
                pointsList.append(map(float, lines.strip().split()[:3]))

    hourlyIlluminanceValues = []
    with open(annualResultsFile) as resData:
        for lines in resData:
            lines = lines.strip()
            if lines:
                try:
                    tempIllData = map(float, lines.split())
                    hourlyIlluminanceValues.append(tempIllData)
                except ValueError:
                    pass
    if calcASE:
        #As per IES-LM-83-12 ASE is the percent of sensors in the analysis area that are
        # found to be exposed to more than 1000lux of direct sunlight for more than 250hrs
        # per year. The present script allows user to define what the lux and hour value
        # should be.
        sensorIllumValues = zip(*hourlyIlluminanceValues)
        aseData = []
        for idx, sensor in enumerate(sensorIllumValues):
            x, y, z = pointsList[idx]
            countAboveThreshold = len(
                [val for val in sensor if val > illumForASE])
            aseData.append([x, y, z, countAboveThreshold])

        sensorsWithHoursAboveLimit = [
            hourCount for x, y, z, hourCount in aseData
            if hourCount > hoursForASE
        ]
        percentOfSensors = len(sensorsWithHoursAboveLimit) / len(
            pointsList) * 100
        print(
            "ASE RESULT: Percent of sensors above %sLux for more than %s hours = %s%%"
            % (illumForASE, hoursForASE, percentOfSensors))

        if calcASEptsSummary:
            print(
                "ASE RESULT: Location of sensors and # of hours above threshold of %sLux\n"
                % illumForASE)
            print("%12s %12s %12s %12s" % ('xCor', 'yCor', 'zCor', 'Hours'))
            for x, y, z, countAboveThreshold in aseData:
                print("%12.4f %12.4f %12.4f %12d" %
                      (x, y, z, countAboveThreshold))

    #Stage 2: Check values from ASE calc against
    if hoyForValidation in xrange(8760):
        print(statusMsg('Starting validation calcs.'))

        #Create a sky for a point in time calc.
        timeStamp = monthDateTime[hoyForValidation]
        month, day, hour = timeStamp.month, timeStamp.day, timeStamp.hour + 0.5
        print(
            "VALIDATION RESULTS: Comparing illuminancevalues for (month,day,hour):(%s, %s, %s)\n"
            % (month, day, hour))

        # msgString="\t\tComparing values for (month,day,hour):(%s, %s, %s)"%(month,day,hour)
        # print(msgString)
        # print("\t\t%s\n"%("~"*len(msgString)))

        genParam = GendaylitParameters()
        genParam.meridian = meridian
        genParam.longitude = longitude
        genParam.latitude = latitude

        genDay = Gendaylit()
        genParam.dirNormDifHorzIrrad = (
            epw.directNormalRadiation[hoyForValidation],
            epw.diffuseHorizontalRadiation[hoyForValidation])

        genDay.monthDayHour = (month, day, hour)
        genDay.gendaylitParameters = genParam
        genDay.outputFile = r'tests/ASEtest/genday.sky'
        genDay.execute()

        octGenday = Oconv()
        octGenday.sceneFiles = sceneData + [r'tests/ASEtest/genday.sky']
        octGenday.outputFile = r'tests/ASEtest/roomSunGenday.oct'
        octGenday.execute()

        rtcPara = GridBasedParameters()
        rtcPara.irradianceCalc = True
        rtcPara.ambientBounces = 0
        rtcPara.directJitter = 1
        rtcPara.directCertainty = 1
        rtcPara.directThreshold = 0

        rtc = Rtrace()
        rtc.radianceParameters = rtcPara
        rtc.octreeFile = r'tests/ASEtest/roomSunGenday.oct'
        rtc.pointsFile = pointsFile
        rtc.outputFile = r'tests/ASEtest/rtraceTest.res'
        rtc.execute()

        #This is a quick hack to get values out of rtrace. I think the option to turn of header is
        # nested inside.

        rtraceIllValues = []
        with open(r'tests/ASEtest/rtraceTest.res') as resFile:
            for lines in resFile:
                lines = lines.strip()
                if lines:
                    try:
                        r, g, b = map(float, lines.strip().split())
                        r, g, b = r * 47.4, g * 119.9, b * 11.6
                        rtraceIllValues.append(r + g + b)
                    except ValueError:
                        pass

        print("%12s %12s %12s %12s %12s %12s%%" %
              ('xCor', 'yCor', 'zCor', 'Annual-Ill', 'Rtrace-Ill', 'Diff'))
        for point, aseVal, rtraceVal in zip(
                pointsList, hourlyIlluminanceValues[hoyForValidation],
                rtraceIllValues):
            x, y, z = point
            if rtraceVal:
                diff = (rtraceVal - aseVal) / rtraceVal
                aseVal, rtraceVal, diff = map(lambda x: round(x, 4),
                                              (aseVal, rtraceVal, diff * 100))
            else:
                aseVal, rtraceVal, diff = 0.0, 0.0, 0.0
                aseVal, rtraceVal, diff = map(lambda x: round(x, 4),
                                              (aseVal, rtraceVal, diff * 100))
            print("%12.4f %12.4f %12.4f %12.4f %12.4f %12.4f%%" %
                  (x, y, z, aseVal, rtraceVal, diff))

    print(statusMsg('Done!'))