def validComposition(userInput): if not userInput: return False try: splitInput = validValueAndUnits.match(userInput) except AttributeError: print('Invalid input for concentration. Example: %s. %s' % (util.limeText('15ppb'), util.underlineMagenta('Please try again.'))) return False unit = splitInput.group(5) if not unit: unit = 'concentration' if unit not in COMPOSITION_UNITS: print('Invalid units. Accepted units are %s.' % (util.limeText(', '.join(COMPOSITION_UNITS)))) return False textNumber = '' for i in range(1, 5): if splitInput.group(i): textNumber += splitInput.group(i) value = float(textNumber) if value <= 0: print('Concentration must be greater than 0') return False return value, unit
def editLayerDepth(layer): print('Current %s for %s is : %s\n' % (util.limeText('depth'), util.limeText( layer.name), util.cyanText('%scm' % layer.depth))) depth = inputLayerDepth(default=layer.depth) layer.changeDepth(depth) menuEditLayerParam(layer)
def editLayerPressure(layer): print('Current %s for %s is : %s\n' % (util.limeText('pressure'), util.limeText( layer.name), util.cyanText('%smbar' % layer.P))) pressure = inputLayerPressure(default=layer.P) layer.changePressure(pressure) menuEditLayerParam(layer)
def editLayerTemperature(layer): print('Current %s for %s is : %s\n' % (util.limeText('temperature'), util.limeText( layer.name), util.cyanText('%sK' % layer.T))) temperature = inputLayerTemperature(default=layer.T) layer.changeTemperature(temperature) menuEditLayerParam(layer)
def editLayerRange(layer): print('Current %s for %s is %s\n' % (util.limeText('range'), util.limeText(layer.name), util.cyanText('%s-%scm-1' % (layer.rangeMin, layer.rangeMax)))) rangeMin, rangeMax = inputLayerRange(defaultMin=layer.rangeMin, defaultMax=layer.rangeMax) layer.changeRange(rangeMin, rangeMax) menuEditLayerParam(layer)
def inputPlanckTemps(): text = 'Enter the temperature of the planck curves.\t\t\t' tempList = receiveMultiInput( '%s\n' 'If no units entered, temperature will be assumed %s.\n' 'Other valid units are %s .Multiple temperatures can be separated with a comma: ' % (util.underlineCyan(text), util.limeText('K'), util.limeText('C and F')), validTemperature) return tempList
def inputLayerPressure(default=None): if not default: default = 1013.25 text = 'Enter the pressure of the layer.\t\t\t' getPressure = '%s\n' \ 'If no units are specified, %s will be assumed.\n' \ 'Other valid units are %s . If no value given, default will be %s: ' % \ (util.underlineCyan(text), util.limeText('mBar'), util.limeText('pa, bar, and atm.'), util.limeText('%smbar' % default)) pressure = receiveInput(getPressure, validPressure, default=default) return pressure
def inputLayerDepth(default=None): if not default: default = 10 text = 'Enter the thickness of the layer.\t\t\t' getDepth = '%s\n' \ 'If no units are specified, %s will be assumed.\n' \ 'Other valid units are %s . If no value given, default will be %s: ' % \ (util.underlineCyan(text), util.limeText('cm'), util.limeText('m, in, ft.'), util.limeText('%scm' % default)) depth = receiveInput(getDepth, validDepth, default=default) return depth
def inputLayerTemperature(default=None): if not default: default = 300 text = 'Enter the temperature of the layer.\t\t\t' getTemperature = '%s\n' \ 'If no units are specified, %s will be assumed.\n' \ 'Other valid units are %s . If no value given, default will be %s: ' % \ (util.underlineCyan(text), util.limeText('K'), util.limeText('C or F'), util.limeText('%sK' % default)) temperature = receiveInput(getTemperature, validTemperature, default=default) return temperature
def validPressure(userInput): if not userInput: return False try: splitInput = validValueAndUnits.match(userInput) except AttributeError: print('Invalid input for pressure. Example: %s. %s' % (util.limeText('1.35atm'), util.underlineMagenta('Please try again.'))) return False unit = splitInput.group(5) if not unit: unit = 'mbar' unit = unit.lower() if unit not in PRESSURE_UNITS: print('Invalid units. Accepted units are %s.' % ', '.join(PRESSURE_UNITS)) return False textNumber = '' for i in range(1, 5): if splitInput.group(i): textNumber += splitInput.group(i) value = float(textNumber) return pyrad.convertPressure(value, unit)
def createLayer(atmosphere): defaultLayerName = atmosphere.nextLayerName() getLayerName = '\n%s\n' \ 'If no value given, default will be %s : ' \ % (util.underlineCyan('Enter the name of the layer.\t\t'), util.limeText(defaultLayerName)) depth = inputLayerDepth() pressure = inputLayerPressure() temperature = inputLayerTemperature() rangeMin, rangeMax = inputLayerRange() validName = False while not validName: layerName = input(getLayerName) if layerName not in genericAtmosphere: validName = True else: print('Name already taken. Please try again.') layer = atmosphere.addLayer(depth, temperature, pressure, rangeMin, rangeMax, name=layerName) createMolecule(layer) return
def inputPlanckRange(units): rangeMin = -1 rangeMax = -1 text = '%s\nUnits are %s. Scientific notation is accepted (1e14):' \ % (util.underlineCyan('Enter the minimum range of the planck spectrum.'),util.limeText(units)) while rangeMin < 0: rangeMin = receiveInput(text, validNumber) if rangeMin < 0: print('Range min must be %s than zero' % util.magentaText('greater')) text = '%s\nUnits are %s. Scientific notation is accepted (1e14):' \ % (util.underlineCyan('Enter the maximum range of the planck spectrum.'), util.limeText(units)) while rangeMax <= rangeMin: rangeMax = receiveInput(text, validNumber) if rangeMax <= rangeMin: print('Range min must be %s than range min of %s' % (util.magentaText('greater'), util.cyanText(rangeMin))) return rangeMin, rangeMax
def inputMoleculeName(default=None): if not default: default = 'co2' text = 'Enter the short molecule name.\t\t\t' moleculeName = receiveInput( '%s\n' 'For a full list of options, type %s. For a list of cross-section only molecules, type %s. If no value given, %s will be used: ' % (util.underlineCyan(text), util.magentaText('help'), util.magentaText('xsc'), util.limeText(default)), validMoleculeName, default=default) return moleculeName
def inputLayerRange(defaultMin=None, defaultMax=None): if not defaultMin: defaultMin = 600 if not defaultMax: defaultMax = 700 rangeMin = -1 rangeMax = -1 text = 'Enter the minimum range of the layer.\t\t\t' getRangeMin = '%s\n' \ 'If no units are specified, %s will be assumed.\n' \ 'Other valid units are %s . If no value given, default will be %s: ' % \ (util.underlineCyan(text), util.limeText('cm-1'), util.limeText('um'), util.limeText('%scm' % defaultMin)) while rangeMin < 0: rangeMin = receiveInput(getRangeMin, validRange, default=defaultMin) if rangeMin < 0: print('Range min must be %s than zero' % util.magentaText('greater')) text = 'Enter the maximum range of the layer.\t\t\t' getRangeMax = '%s\n' \ 'If no units are specified, %s will be assumed.\n' \ 'Other valid units are %s . If no value given, default will be %s: ' % \ (util.underlineCyan(text), util.limeText('cm-1'), util.limeText('um'), util.limeText('%scm' % defaultMax)) while rangeMax <= rangeMin: rangeMax = receiveInput(getRangeMax, validRange, default=defaultMax) if rangeMax <= rangeMin: print('Range min must be %s than range min of %s' % (util.magentaText('greater'), util.cyanText(rangeMin))) return rangeMin, rangeMax
def displayMenu(self): titleStr = '\t' + self.title while len(titleStr) < 60: titleStr += ' ' print('\n%s' % util.underlineCyan(titleStr)) i = 1 validEntry = ['x'] for entry in self.entries: if entry.selectionKey: validEntry.append(entry.selectionKey.lower()) print( ' %s) %s' % (util.magentaText(entry.selectionKey.upper()), entry.name)) else: validEntry.append(str(i)) print(' %s) %s' % (util.magentaText(i), entry.name)) i += 1 if 'Main' not in self.title: print(' %s Previous menu' % util.magentaText('B)')) validEntry.append('b') print(' %s Exit' % util.magentaText('X)')) validChoice = False if self.hint: print(util.limeText('**' + self.hint)) while not validChoice: userInput = input('Choose an option: ') if userInput.lower() == 'x': print('Goodbye') exit(1) elif userInput.lower() == 'b' and 'Main' not in self.title: return elif userInput in validEntry: try: userChoice = self.entries[int(userInput) - 1] except ValueError: # this means the user entered a letter but it is in the valid choices # roll through the entries to find the matching choice userChoice = next( filter( lambda x: x.selectionKey and x.selectionKey.lower( ) == userInput.lower(), self.entries)) if userChoice.nextFunction: userChoice.nextFunction(userChoice.functionParams) validChoice = True elif userChoice.nextMenu: userChoice.nextMenu.displayMenu() validChoice = True else: print('Invalid entry. Try again.')
def validDepth(userInput): if not userInput: return False try: splitInput = validValueAndUnits.match(userInput) except AttributeError: print('Invalid input for depth. Example: %s. %s' % (util.limeText('10cm'), util.underlineMagenta('Please try again.'))) return False unit = splitInput.group(5) if not unit: unit = 'cm' unit = unit.lower() if unit not in DEPTH_UNITS: print('Invalid units. Accepted units are %s' % (util.limeText(', '.join(DEPTH_UNITS)))) return False textNumber = '' for i in range(1, 5): if splitInput.group(i): textNumber += splitInput.group(i) value = float(textNumber) return pyrad.convertLength(value, unit)
def validTemperature(userInput): if not userInput: return False try: splitInput = validValueAndUnits.match(userInput) except AttributeError: print( 'Invalid input for temperature. Example: %s. %s' % (util.limeText('20C'), util.underlineMagenta('Please try again.'))) return False unit = splitInput.group(5) if not unit: unit = 'K' unit = unit.upper()[0] if unit not in TEMPERATURE_UNITS: print('Invalid units. Accepted units are %s.' % (util.limeText(', '.join(TEMPERATURE_UNITS)))) return False textNumber = '' for i in range(1, 5): if splitInput.group(i): textNumber += splitInput.group(i) value = float(textNumber) return pyrad.convertTemperature(value, unit)
def inputMoleculeComposition(obj=None, default=None): if not default: default = '400ppm' text = 'Enter the molecule composition.\t\t\t' composition, units = receiveInput( '%s\n' 'If no units entered, composition will be assumed %s.\n' 'Other valid units are %s . If no value given, %s will be used: ' % (util.underlineCyan(text), util.limeText('parts per 1'), util.limeText('ppm, ppb, or percentage'), util.limeText(default)), validComposition, default=default) if obj: if units == 'ppm': obj.setPPM(composition) elif units == 'ppb': obj.setPPB(composition) elif 'perc' in units or units == '%': obj.setPercentage(composition) else: obj.setConcentrationPercentage(composition) return else: return composition, units
def editComposition(molecule): print('Current concentration for %s is %s\n' % (util.limeText(molecule.name), util.limeText(molecule.concText))) return inputMoleculeComposition(molecule, default=molecule.concText)
def selectXscFile(params): def relevanceScore(layerT, layerP, fileT, fileP, weightedT=1, weightedP=1.1): tDiff = abs(layerT - fileT) * weightedT pDiff = abs(layerP - fileP) * weightedP total = tDiff + pDiff return total layer = params['layer'] xsc = params['xsc'] if 'sort' not in params: params['sort'] = 'RELEVANT_P' sort = params['sort'] entries = [] unsortedFiles = util.returnXscFilesInDirectory(xsc) if unsortedFiles is False or unsortedFiles == []: question = "Either that directory doesn't exist or it was empty. Would you like to try downloading the data from HITRAN?" if receiveInput(question, validYorN) == 'y': filepath = util.downloadXscZipFile(xsc) util.unzipFile(filepath) util.mergeXsc(xsc) selectXscFile(params) else: return else: hintText = "Layer P and T will be adjusted according to the xsc file" unsortedValues = list( map(lambda file: util.parseXscFileName(file), unsortedFiles)) if sort == 'TEMP': sortedValues = sorted(unsortedValues, key=lambda i: (float(i['TEMP']), float(i['PRESSURE']))) sortedValues.reverse() hintText += '\nCurrently sorted by temperature with largest values at bottom' elif sort == 'PRESSURE': sortedValues = sorted(unsortedValues, key=lambda i: (float(i['PRESSURE']), float(i['TEMP']))) sortedValues.reverse() hintText += '\nCurrently sorted by pressure with largest values at bottom' elif sort == 'RELEVANT_P': sortedValues = sorted( unsortedValues, key=lambda i: (relevanceScore(layer.T, layer.P, float(i['TEMP']), float(i['PRESSURE']) * 1.31579))) sortedValues.reverse() hintText += '\nCurrently sorted closest minimizing pressure difference, with closest match at bottom' elif sort == 'RELEVANT_T': sortedValues = sorted( unsortedValues, key=lambda i: (relevanceScore(layer.T, layer.P, float(i['TEMP']), float(i['PRESSURE']) * 1.31579, weightedP=1, weightedT=1.1))) hintText += '\nCurrently sorted closest minimizing temperature difference, with closest match at bottom' sortedValues.reverse() for v in sortedValues: if sort == 'TEMP' or sort == 'RELEVANT_T': displayName = 'Temp: %s -- Pressure: %s -- Range: %s' % ( util.limeText(v['TEMP'] + 'K'), util.cyanText(v['PRESSURE'] + 'Torr'), util.magentaText(v['RANGE'] + 'cm-1')) elif sort == 'PRESSURE' or sort == 'RELEVANT_P': displayName = 'Pressure: %s -- Temp: %s -- Range: %s' % ( util.cyanText(v['PRESSURE'] + 'Torr'), util.limeText(v['TEMP'] + 'K'), util.magentaText(v['RANGE'] + 'cm-1')) entries.append( Entry(displayName, nextFunction=addXscToLayer, functionParams={ 'layer': layer, 'file': v['LONG_FILENAME'], 'xsc': xsc })) pressureParams = params.copy() pressureParams.update({'sort': 'PRESSURE'}) entries.append( Entry('Sort by pressure', nextFunction=selectXscFile, functionParams=pressureParams, selectionKey='P')) tempParams = params.copy() tempParams.update({'sort': 'TEMP'}) entries.append( Entry('Sort by temperature', nextFunction=selectXscFile, functionParams=tempParams, selectionKey='T')) tempParams = params.copy() tempParams.update({'sort': 'RELEVANT_T'}) entries.append( Entry('Sort by closest temperature', nextFunction=selectXscFile, functionParams=tempParams, selectionKey='minT')) tempParams = params.copy() tempParams.update({'sort': 'RELEVANT_P'}) entries.append( Entry('Sort by closest pressure', nextFunction=selectXscFile, functionParams=tempParams, selectionKey='minP')) menu = Menu('Choose file to use', entries, hint=hintText) menu.displayMenu() return
def createTransmission(params): layer = params['plots'][0] text = 'A plot for transmission requires an initial surface temperature.\n'\ 'Please choose a temperature different from the layer temperature of %sK:' % util.limeText(layer.T) temperature = receiveMultiInput(text, validTemperature) objList = [] for item in params['plots']: objList.append(item) temperature.append(layer.T) pyrad.plotSpectrum(layer, objList=objList, surfaceSpectrum=pyradPlanck.planckWavenumber( layer.xAxis, temperature[0]), planckTemperatureList=temperature) return