def readOutputProfile(fname): fp = open(fname, 'r') profTable = {} ignColor = (107, 165, 210) unknownColor = (255, 0, 255) try: for line in fp: if ((line[0] != '#') and (not (line.isspace()))): rmatch = re.match(r"""\s*([^:]+)\s*:\s*\(\s*([0-9]+\s*,\s*[0-9]+\s*,\s*[0-9]+\s*)\s*\)""", line) if rmatch: oColor = rmatch.group(2) rgbVals = oColor.split(',') rval = int(rgbVals[0].strip()) gval = int(rgbVals[1].strip()) bval = int(rgbVals[2].strip()) key = rmatch.group(1).strip() if ((rval < 0) or (rval > 255) or (gval < 0) or (gval > 255) or (bval < 0) or (bval > 255)): raise SKCCError('Invalid RGB color in output profile: ' + str((rval, gval, bval))) if (key == 'Ignored') or (key == 'Ocean'): ignColor = (rval, gval, bval) if (key == 'Unknown'): unknownColor = (rval, gval, bval) if (key in profTable): print('Warning: Duplicate entries for key | ' + kClass + ' | in output profile') profTable[key] = (rval, gval, bval) else: raise SKCCError('Invalid line in output profile: ' + line) finally: fp.close() return OutputProfile(profTable, ignColor, unknownColor)
def readInputProfile(fname): fp = open(fname, 'r') profTable = {} ignoredColors = [] defaultVal = None try: for line in fp: if ((line[0] != '#') and (not (line.isspace()))): rmatch = re.match( r"""[^:]*:\s*\((Default|[0-9]+,\s*[0-9]+,\s*[0-9]+\s*)\)\s*:\s*(-?[0-9.]*X?O?)""", line) if rmatch: iColor = rmatch.group(1) if (iColor == 'Default'): iValue = rmatch.group(2) if (not (defaultVal is None)): print( 'Warning: Duplicate default value in input profile: ' + iValue) if ((iValue == 'X') or (iValue == 'O')): defaultVal = 'X' else: defaultVal = float(iValue) else: rgbVals = iColor.split(',') rval = int(rgbVals[0].strip()) gval = int(rgbVals[1].strip()) bval = int(rgbVals[2].strip()) if ((rval < 0) or (rval > 255) or (gval < 0) or (gval > 255) or (bval < 0) or (bval > 255)): raise SKCCError( 'Invalid RGB color in input profile: ' + str((rval, gval, bval))) iValue = rmatch.group(2) if ((rval, gval, bval) in profTable): print( 'Warning: Duplicate color in input profile: ' + str((rval, gval, bval))) if ((iValue == 'X') or (iValue == 'O')): ignoredColors.append((rval, gval, bval)) else: ival = float(iValue) profTable[(rval, gval, bval)] = ival else: raise SKCCError('Invalid line in input profile: ' + line) finally: fp.close() return InputProfile(profTable, ignoredColors, default=defaultVal)
def getPrecipitationPattern(tType, tempTuple, precTuple, annualPrecip): if (tType == 'A'): if ((precTuple[0] > 60) and (precTuple[1] > 60)): return 'f' else: wThresh = 100 - (annualPrecip / 25.0) dryPrecip = min(precTuple[0], precTuple[1]) if (dryPrecip >= wThresh): return 'm' elif (precTuple[1] < 60): return 'w' else: return 's' elif ((tType == 'C') or (tType == 'D')): if (precTuple[1] < (precTuple[0] * 0.1)): return 'w' elif ((precTuple[0] < (precTuple[1] * 0.33)) and (precTuple[0] < 40)): return 's' else: return 'f' elif (tType == 'E'): if (max(tempTuple[0], tempTuple[1]) < 0): return 'F' else: return 'T' else: raise SKCCError( 'Invalid climate category for getPrecipitationPattern; should never happen' )
def makeRGBConversion(img1, img2, img3, img4): bands = [ img1.getbands(), img2.getbands(), img3.getbands(), img4.getbands() ] bandIds = [] for bandList in bands: if not ('R' in bandList): raise SKCCError( 'No red color channel in one or more input images.') elif not ('G' in bandList): raise SKCCError( 'No green color channel in one or more input images.') elif not ('B' in bandList): raise SKCCError( 'No blue color channel in one or more input images.') else: bandIds.append((bandList.index('R'), bandList.index('G'), bandList.index('B'))) if (bandList[0] == ('R', 'G', 'B')) and (bandList[1] == ( 'R', 'G', 'B')) and (bandList[2] == ('R', 'G', 'B')) and (bandList[3] == ('R', 'G', 'B')): # Special case to improve performance if input is all RGB images with no channels def retRGB(pxTuple): return pxTuple return retRGB else: def getRGB(pxTuple): return ((pxTuple[0][bandIds[0][0]], pxTuple[0][bandIds[0][1]], pxTuple[0][bandIds[0][2]]), (pxTuple[1][bandIds[1][0]], pxTuple[1][bandIds[1][1]], pxTuple[1][bandIds[1][2]]), (pxTuple[2][bandIds[2][0]], pxTuple[2][bandIds[2][1]], pxTuple[2][bandIds[2][2]]), (pxTuple[3][bandIds[3][0]], pxTuple[3][bandIds[3][1]], pxTuple[3][bandIds[3][2]])) return getRGB
def getValue(self, rgbColor): if not (rgbColor in self.colorTable): if self.defaultValue is None: raise SKCCError( 'Invalid color in input data (did not match input profile): (' + str(rgbColor[0]) + ', ' + str(rgbColor[1]) + ', ' + str(rgbColor[2]) + ')') else: return self.defaultValue else: return self.colorTable[rgbColor]
def readAndValidateHoldridgeOutputProfile(fname): profile = readOutputProfile(fname) for zone in profile.colorTable: if not (zone == 'Ocean'): if (not (zone in hColorTableDefault)): raise SKCCError( 'Invalid Holdridge category in output profile: ' + zone) else: if profile.ignoredColor != defaultOceanColor: profile.ignoredColor = profile.colorTable[zone] if ('Ocean' in profile.colorTable): profile.colorTable.pop('Ocean', None) return profile
def readAndValidateKoppenOutputProfile(fname): profile = readOutputProfile(fname) for climate in profile.colorTable: if not (climate == 'Ocean'): if (not (climate in kColorTableDefault)): raise SKCCError( 'Invalid Köppen-Geiger class in output profile: ' + climate) else: if profile.ignoredColor != defaultOceanColor: profile.ignoredColor = profile.colorTable[climate] if ('Ocean' in profile.colorTable): profile.colorTable.pop(climate, None) return profile
def getClimateColor(pxTuple, tempProfile, precProfile, outProfile, isNorthernHemis): # pxTuple contains a tuple of four pixels, for (temp1, temp2, precip1, precip2). # If this pixel in any input has the ocean color we treat this pixel as ocean and ignore it. if (tempProfile.isIgnored(pxTuple[0]) or tempProfile.isIgnored(pxTuple[1]) or precProfile.isIgnored(pxTuple[2]) or precProfile.isIgnored(pxTuple[3])): return outProfile.ignoredColor else: tempTuple, precTuple = convertPixelData(pxTuple, tempProfile, precProfile, isNorthernHemis) #Temptuple is (avg. for summer, avg. for winter) #precTuple is (category for summer, category for winter) tType = getTemperatureType(tempTuple) pType = 'f' #Placeholder value annualPrecip = 0.0 # Placeholder value #Check for aridity (polar climate category exempted) if (tType != 'E'): evaporation, annualPrecip = getEvaEstimate(tempTuple, precTuple) if (annualPrecip < (evaporation / 2.0)): tType = 'B' pType = 'W' elif (annualPrecip < evaporation): tType = 'B' pType = 'S' if (tType != 'B'): pType = getPrecipitationPattern(tType, tempTuple, precTuple, annualPrecip) stType = getSeasonalPattern(tType, tempTuple) climateCode = tType + pType if (stType != 'x'): climateCode = climateCode + stType if (climateCode in outProfile.colorTable): return outProfile.colorTable[climateCode] else: raise SKCCError( 'Invalid Köppen-Geiger climate class (should never happen): ' + climateCode)
def validateMode(md): if md in modes: return md else: raise SKCCError('Invalid mode specified: ' + mode)
def outputToFile(filename, img): try: img.save(filename) except: raise SKCCError('Could not write to file' + filename)
def optErr(): raise SKCCError( 'Invalid options. Use the \'-h\' or \'--help\' options for usage information.' )
precProfile = readInputProfile(a[1]) if a[0] == '-k' or a[0] == '--outprof': if a[1] == '': optErr() else: # Output profiles differ by mode if (mode == 'koppen'): outProfile = readAndValidateKoppenOutputProfile(a[1]) elif (mode == 'holdridge'): outProfile = readAndValidateHoldridgeOutputProfile( a[1]) if a[0] == '-s' or a[0] == '--quiet': quiet = True if ((not tempFileNameNS) or (not tempFileNameNW) or (not precFileNameNS) or (not precFileNameNW)): raise SKCCError( 'One or more required input data files were not specified.') if (not outfileName): raise SKCCError('No output filename specified.') # Generate the output. outputToFile( outfileName, buildOutput(tempFileNameNS, tempFileNameNW, precFileNameNS, precFileNameNW, tempProfile, precProfile, outProfile, mode)) if not quiet: stopTime = time.time() timeDiffRounded = format(stopTime - startTime, '.2f') print('Output climate map to ' + outfileName + ' (' + timeDiffRounded + 's).') except Exception as e: