def execute(self): if False == self.mInitialized: raise ThermError("IndivNetworkBuilder (%s) not initialized." % self.mNetwork) try: ## Read the TdNetworkConfig file. tdData = self.readThermalDesktopData() ## Parse and analyze ThermRegistry. self.readThermRegistry() ## Perform Mass Analysis. self.performMassAnalysis() ## Append ThermalDesktop data to the end of the xml config-files. self.appendThermalDesktopData(tdData) ## Heaters and panels are both derived from GunnsThermalSource, and they both have very ## similar registry schemas. They can be parsed with the same function. self.readThermSourceFile("heater", self.mHtrFile, self.mHtrList) self.readThermSourceFile("panel", self.mPanFile, self.mPanList) self.readThermSourceFile("source", self.mHtrFile, self.mSrcList) ## Write XML trees to file. self.mPrinter.printThermXml(self.mNodeXml, self.mNodeFile, self.mCallingScript) self.mPrinter.printThermXml(self.mCondXml, self.mCondFile, self.mCallingScript) self.mPrinter.printThermXml(self.mRadXml, self.mRadFile, self.mCallingScript) self.mPrinter.printThermXml(self.mEtcXml, self.mEtcFile, self.mCallingScript) except ThermError, e: print e, raise ThermError("Error executing network (%s)." % self.mNetwork)
def execute(self): if False == self.mInitialized: raise ThermError("ThermAspectBuilder not initialized.") ## Instantiate a ThermPrinter object. myPrinter = ThermPrinter() ## Open enum and icd files. try: f_enum = myPrinter.openFileForWriting(self.mEnumFile) f_icd = myPrinter.openFileForWriting(self.mIcdFile) ## Write enum headers. f_enum.write(ThermHeaders().enum % self.mCallingScript) guard = os.path.basename(self.mEnumFile).replace('.hh', '_') f_enum.write("#ifndef %sEXISTS\n" % guard) f_enum.write("#define %sEXISTS\n\n" % guard) ## Write icd header. f_icd.write(ThermHeaders().icd % (self.mRegisDir, self.mCallingScript)) except ThermError, e: print e raise ThermError("Error setting up PTCS enum/icd files.")
def registerNode(self, entryObj): ## Check for repeated node name. if entryObj.mName in self.regisNodeList: raise ThermError("Node previously defined in ThermRegistry.") ## Raise error if editGroup not defined in the header at the top of the registry. if None != entryObj.mEditGroup and entryObj.mEditGroup not in self.mEditCapGroupList: raise ThermError("editGroup not defined in <capEditing> (%s)." % entryObj.mEditGroup) ## Append or Overwrite node's mass in the dictionary. self.mMassDict[entryObj.mName] = entryObj.mMass ## Find the enumIndex of this node. enumIndex = len(self.regisNodeList) ## If no initial temperature given, default to either the value from Thermal Desktop or just ## a neutral value. if -1 == entryObj.mInitTemp: try: entryObj.mInitTemp = self.mTempDict[entryObj.mName] except: entryObj.mInitTemp = 296.0 ## Create <node> element. n = self.mParser.newElement("node", self.mNodeXml) self.mParser.newElement("enum", n).text = str(enumIndex) self.mParser.newElement("name", n).text = entryObj.mName self.mParser.newElement("mass", n, {"units": "kg"}).text = \ self.mParser.roundValue(entryObj.mMass, 2) self.mParser.newElement("temperature", n, {"units": "K"}).text = \ self.mParser.roundValue(entryObj.mInitTemp, 2) self.mParser.newElement("capacitance", n, {"units": "J/K"}).text = \ self.mParser.roundValue(entryObj.mCapacitance, 2) ## Create an <editGroup> subelement if applicable. if None != entryObj.mEditGroup: ## Create element for editGroup. self.mParser.newElement("editGroup", n).text = entryObj.mEditGroup ## Add node to nodeLists for enumeration. self.regisNodeList.append(entryObj.mName) ## Check if the registry node has a duplicate in ThermalDesktop. if entryObj.mName in self.tdNodeList: self.isRegistered[entryObj.mName] = True else: self.masterNodeList.append(entryObj.mName) ## Process ICD jobs contained in the entryObj. self.mIcdBuilder.extractAndProcessIcd(entryObj, "capacitor", enumIndex)
def registerRad(self, entryObj): ## Loop through all radiation links in the radiation map. for (radName, toNode, coeff, element) in entryObj.mRadiationList: try: ## Verify not previously added. if radName in self.mRadList: raise ThermError("Radiation link previously defined.") ## Check that the <to> nodes are valid. self.validateNode(toNode, "to") ## Create <radiation> element. r = self.mParser.newElement("radiation", self.mRadXml) self.mParser.newElement("node0", r).text = entryObj.mName self.mParser.newElement("node1", r).text = toNode self.mParser.newElement("coefficient", r, { "units": "m2" }).text = self.mParser.roundValue(coeff, 6) ## Find the enumIndex of this radiation link. enumIndex = len(self.mRadList) ## Add radName to radList for enumeration. self.mRadList.append(radName) ## Build Icd jobs. self.mIcdBuilder.processIcd(element, radName, "radiation", enumIndex, entryObj.mDescription) ## Do not write data if <to> tag not found or node not registered. except (ThermError, TagNotFound), e: print e, "Radiation link \"%s\" will be skipped (for entry %s)." % ( radName, entryObj.mName)
def loadConduction(self): ## Loop through all <cond> tags. for condElement in self.mParser.getElements(self.mEntry, "conduction"): try: ## Make sure the cond value, defined with symbols, can be properly evaluated. conductivity = self.mParser.getChildText( condElement, "conductivity", self.mName) conductivity = self.getValidatedValue(conductivity, self.mName) ## The conduction will be skipped unless exactly one <to> tag is found. toNodeElems = self.mParser.getElements(condElement, "to", True, self.mName) if 1 == len(toNodeElems): toNode = self.mParser.getText(toNodeElems[0]) else: raise ThermError("Must provide exactly one <to> node.") ## Define the conductor using a map that provides {toNode : conductivity} self.mConductionList.append((toNode, conductivity)) ## Do not write data if <to> tag not found or node not registered. except (ThermError, TagNotFound), e: print e, print "Conduction link will be skipped (%s)." % self.mName
def loadFile(self, xmlFile): # Get root from the xml. try: root = ET.parse(xmlFile, parser = CommentedTreeBuilder()).getroot() except IOError, e: print e raise ThermError("Error opening file: %s" % xmlFile)
def registerPot(self, entryObj): ## Loop through all potential links in the radiation map. for (potName, conductivity, element) in entryObj.mPotentialList: try: ## Create <potential> element. p = self.mParser.newElement("potential", self.mEtcXml) self.mParser.newElement("name", p).text = potName self.mParser.newElement("node", p).text = entryObj.mName self.mParser.newElement("temperature", p, {"units": "K"}).text = \ self.mParser.roundValue(entryObj.mInitTemp,2) self.mParser.newElement("conductivity", p, {"units": "W/K"}).text = \ self.mParser.roundValue(conductivity,6) ## Find the enumIndex of this potential. enumIndex = len(self.mPotList) ## Process ICD jobs contained in the entryObj. self.mIcdBuilder.extractAndProcessIcd(entryObj, "potential", enumIndex) ## Add potential to mPotList for enumeration. self.mPotList.append(potName) except (ThermError, TagNotFound), e: print e, raise ThermError("Error in <potential>.")
def evaluateExpression(self, name, expr, symMap): try: return eval(expr, globals(), symMap) except (SyntaxError), e: print e print "***File: %s." % self.mCurrentFile print "***Symbol: %s." % name print "***Expression: %s." % expr raise ThermError("Cannot evaluate symbol expression.")
def roundValue(self, val, dec): ## Default code to floating point notation. code = "f" try: rnd = round(float(val),dec) ## If the number is large, use scientific notation. if abs(rnd) > 1e9: code = "e" format = "%." + str(dec) + code; return (format % rnd) except ValueError, e: raise ThermError("Cannot be coverted to a float: %s" % val)
class XmlParser: #=============================================================================================== ## @brief: ## Open an xml document and return the entire data tree. ## @param[in]: xmlFile file name of well-formed xml document to parse ## @return: root ElementTree of entire xml data structure def loadFile(self, xmlFile): # Get root from the xml. try: root = ET.parse(xmlFile, parser = CommentedTreeBuilder()).getroot() except IOError, e: print e raise ThermError("Error opening file: %s" % xmlFile) except ExpatError, e: print e raise ThermError("Error parsing file: %s" % xmlFile)
def initialize(self, thermAspectConfig): ## Initialize members. self.mCallingScript = thermAspectConfig.cCallingScript self.mHome = thermAspectConfig.cHome self.mIcdFile = thermAspectConfig.cIcdFile self.mEnumFile = thermAspectConfig.cEnumFile self.mSymFiles = thermAspectConfig.cSymFiles ## Load symbols dictionary from symbol xml files. print "Loading symbols." try: symMap = self.loadSymbols() except ThermError, e: print e raise ThermError("Error while loading symbols.")
def initialize(self, linkType, entry, symMap={}): ## The initial temperature of the node. self.mLinkType = linkType.lower() if self.mLinkType != "heater" and \ self.mLinkType != "source" and \ self.mLinkType != "panel": raise ThermError("Link type does not exist (%s)." % self.mLinkType) ## Base class initializer XmlEntryAnalyzer.initialize(self, entry, symMap) ## Initialize properties specific to ThermalSource entries. self.loadData() ## Raise the flag only if we've made it this far. self.mIsInitialized = True
def createIcdExchange(self, id, linkType, enumIndex, category, iter, writeElement, readElements,\ pui, subsys, varType, comments): ## Create a default Ptcs icd job. ptcsIcdElement = self.mParser.newElement("icd", None, {"isReadyForIcd": 'true'}) self.mParser.newElement( "rate", ptcsIcdElement).text = self.mIcdSettings.mPtcsRate self.mParser.newElement( "simObject", ptcsIcdElement).text = self.mIcdSettings.mPtcsSimObject self.mParser.newElement("simVarName", ptcsIcdElement).text = "[not set]" ## If no writeElement passed, then Ptcs does the writing. if None == writeElement: ## Substitute the simVarName for Ptcs writes. ptcsIcdElement.find( "simVarName" ).text = self.mNetwork + self.mIcdSettings.mSvnWrite[linkType] % id writeElement = ptcsIcdElement ## If no readElements passed, then Ptcs does the reading. elif None == readElements: ## Substitute the simVarName for Ptcs reads. simVarName = self.mNetwork + self.mIcdSettings.mSvnRead[ linkType].replace("%i", iter) ptcsIcdElement.find("simVarName").text = simVarName % id readElements = [ptcsIcdElement] else: # We have a problem. raise ThermError( "At least one element (read or write) must be None. (%s)" % id) ## Instantiate newIcdExchange newIcdExchange = IcdExchange() ## Set units for Exchange. units = self.mIcdSettings.mUnitsMap[category] varName = id + "_" + self.getVarNameSuffix(category, iter) ## Initialize IcdExchange object with tailored data. newIcdExchange.initialize(id, enumIndex, varName, writeElement, readElements,\ pui, subsys, varType, units, comments) ## Append to list of jobs. self.mListOfExchanges.append(newIcdExchange)
def registerSrc(self, entryObj, theType, srcList): ## Verify not previously added. if entryObj.mName in srcList: raise ThermError("Link previously defined.") ## Find the enumIndex of this source. enumIndex = len(srcList) ## Check that the <to> nodes are valid. for node in entryObj.mNodeList: self.validateNode(node, "node") ## Append source to list of successfully-build sources. srcList.append(entryObj.mName) ## Build Icd jobs. self.mIcdBuilder.processIcd(entryObj.mEntry, entryObj.mName, theType, enumIndex, entryObj.mDescription)
def initialize(self, entry, symMap={}): ## An xml entry from a registry file. This object is only associated with a single entry. self.mEntry = entry ## A dictionary with the definitions of symbols used in the registries self.mSymMap = symMap ## Name of the Thermal Gunns node/link, as read from the registry entry. self.mName = entry.get("name") ## The node entry must have a name. Raise exception if otherwise. if None == self.mName: raise ThermError("Must have a name attribute.") ## The link's description as read from registry entry. try: self.mDescription = self.mParser.getChildText(entry, "des") except TagNotFound: self.mDescription = ""
def defineSymbols(self, nameList, expList, localVars, attemptsMax=5): try: ## Initialize. symMap = {} all_defined = False attempts = 0 ## Loop until all symbols have been resolved. while False == all_defined: ## If not all symbols are resolved after so many attempts, raise exception. if attempts > attemptsMax: raise StopIteration(undefined) ## Reset define info. all_defined = True undefined = [] ## Loop over symbol names in list. for name, exp in zip(nameList, expList): ## To save time, skip those symbols who are already defined in the symMap. if name in symMap: continue ## Try to evaluate the expression. A NameError is raised and caught if the ## a symbol contained in the expression has not been defined yet. try: symMap[name] = self.evaluateExpression( name, exp, symMap) ## If a symbol name is not recognized, then not all symbols are defined yet. except NameError, detail: all_defined = False undefined.append(str(detail)) ## Monitor attempts. This is to make sure you don't get stuck in infinite loop. attempts = attempts + 1 except StopIteration, e: undefined = e.args[0] for u in undefined: print " ", u raise ThermError("Cannot resolve symbols.")
def loadRadiation(self): ## Loop through all <radiation> tags. radElements = self.mParser.getElements(self.mEntry, "radiation") for i in range(0, len(radElements)): ## Set name. radName = "rad%i_%s" % (i, self.mName) try: ## Make sure the coeff value, defined with symbols, can be properly evaluated. coeff = self.mParser.getChildText(radElements[i], "coefficient", radName) ## If no <coefficient> is found, we will default to the TD value. Store a 0.0 for now. except TagNotFound, e: coeff = "0.0" try: ## Verify coefficient value found above. coeff = self.getValidatedValue(coeff, radName) ## The radiation will be skipped unless exactly one <to> tag is found. toNodeElems = self.mParser.getElements(radElements[i], "to", True, self.mName) if 1 == len(toNodeElems): toNode = self.mParser.getText(toNodeElems[0]) else: raise ThermError("Must provide exactly one <to> node.") ## Define the radiation link using a map that provides: ## {radName : (toNode, coefficient, element)} self.mRadiationList.append( (radName, toNode, coeff, radElements[i])) ## Do not write data if <to> tag not found or node not registered. except (ThermError, TagNotFound), e: print e, "Radiation link \"%s\" will be skipped (%s)." % ( radName, self.mName) continue
def loadNode(self): ## Get capacitor data capacitors = self.mParser.getElements(self.mEntry, "capacitor") ## Make sure only zero or one <capacitor> is given. if 0 == len(capacitors): self.mMass = 0 self.mCapacitance = 0 return elif len(capacitors) > 1: raise ThermError("Can only have one <capacitor> per node.") ## Read capacitor's editGroup if found. Otherwise, leave it as None. try: self.mEditGroup = self.mParser.getChildText( capacitors[0], "editGroup", self.mName) except TagNotFound: pass ## Make sure the cap value, defined with symbols, can be properly evaluated. capExpr = self.mParser.getChildText(capacitors[0], "capacitance", self.mName) capacitance = self.getValidatedValue(capExpr, self.mName) ## Default the mass to an estimation based on an assumed specific heat. mass = capacitance / self.mAssumedCp ## The capacitance expression is typically just a previously defined symbol. ## If so, and its properly prefixed with "cap_", then a "mass_" symbol will also exist. if "cap_" in capExpr: try: massSym = capExpr.replace("cap_", "mass_") mass = self.getValidatedValue(massSym, self.mName) ## If there's an error, like a negative mass, just use the previous estimation. except ThermError: pass ## Set the entry's mass and capacitance. self.mMass = mass self.mCapacitance = capacitance
def loadPotential(self): ## Get potential data potentials = self.mParser.getElements(self.mEntry, "potential") ## Set name. potName = 'pot_' + self.mName ## Make sure only zero or one <potential> is given. if 0 == len(potentials): return elif len(potentials) > 1: raise ThermError("Can only have one <potential> per node.") ## The conductivity of the link, in this case a value in W/K. Check if tag ## <conductivity> is given; if not, set it to a default. conductivity = self.getUnrequiredData(potentials[0], "conductivity") if None == conductivity: conductivity = 1e12 ## Define the potential using a map that provides: ## {potName : (conductivity, element)} self.mPotentialList.append((potName, conductivity, potentials[0]))
def getText(self, element, info=''): text = self.checkForUnicode(element.text, info) if None == text or "" == text: format = (element.tag, info) raise ThermError("No text provided in tag <%s> (%s)." % format ) return text
def checkForUnicode(self, s, info=''): if isinstance(s, unicode): raise ThermError("Unicode character detected.") else: return s
def validateNode(self, node, tagInfo=''): if node not in self.masterNodeList: warning = "Node does not exist: <%s>%s</%s>." % (tagInfo, node, tagInfo) raise ThermError(warning)
class XmlEntryAnalyzer: ## @brief: ## Default constructs the object with default, uninitialized members. def __init__(self): uninitialized = "[not initialized]" ## An XmlParser() object for getting data from xml elements. self.mParser = XmlParser() ## An xml entry from a registry file. This object is only associated with a single entry. self.mEntry = uninitialized ## A dictionary with the definitions of symbols used in the registries self.mSymMap = uninitialized ## Name of the Thermal Gunns link, as read from the registry entry. self.mName = uninitialized ## The link's number in the network's array. Initialized to an invalid value of -1. self.mEnumIndex = -1 ## The link's description self.mDescription = uninitialized ## Initialization flag. self.mIsInitialized = False #=============================================================================================== ## @brief: ## Constructs the class using two arguments. ## @param[in]: entry ElementTree xml-element of data from Thermal, Htr, or Panel registry ## @param[in]: symMap dictionary with the definitions of symbols used in the registries def initialize(self, entry, symMap={}): ## An xml entry from a registry file. This object is only associated with a single entry. self.mEntry = entry ## A dictionary with the definitions of symbols used in the registries self.mSymMap = symMap ## Name of the Thermal Gunns node/link, as read from the registry entry. self.mName = entry.get("name") ## The node entry must have a name. Raise exception if otherwise. if None == self.mName: raise ThermError("Must have a name attribute.") ## The link's description as read from registry entry. try: self.mDescription = self.mParser.getChildText(entry, "des") except TagNotFound: self.mDescription = "" #=============================================================================================== ## @brief: ## Evaluate an expression value based on symbols defined in mSymMap. ## @param[in]: expr a mathematical expression that may contain symbols defined in mSymMap ## @param[in]: info optional string used in error reporting ## @return: the evaluated expression in numerical form def getValidatedValue(self, expr, info=''): try: value = eval(expr, globals(), self.mSymMap) except (NameError, SyntaxError), e: print e, raise ThermError("Invalid value: %s (%s)." % (expr, info)) ## Do not accept negative values. if value < 0: raise ThermError("Cannot accept a negative. %s = %f" % (expr, value)) return value
def loadSymbolsFrom(self, symFile): ## Set current file for error reporting purposes. self.mCurrentFile = symFile ## Try to open the symbol file. Open it for reading and save its xml data. symbols = self.mParser.loadFile(symFile) ## Initialize lists. nameList = [] expList = [] desList = [] groupList = [] ## Loop over the symbols. for symbol in symbols: ## Initialize name for error reporting. name = "[error reading name]" ## Get data. try: name = self.mParser.getChildText(symbol, "name") expElem = self.mParser.getElements(symbol, "exp", True, name)[0] expText = self.mParser.getText(expElem, name) if name in nameList: ## If the symbol is a mass, it can overwrite a previous instance. if 'mass_' == name[:5]: expList[nameList.index(name)] = expText continue else: raise ThermError("Symbol previously defined (%s)." % name) ## Special instructions for capacitance symbols, for mass accounting purposes. if 'cap_' == name[:4]: try: ## Read the given mass from the symbols element. specHeatText = self.mParser.getChildText( expElem, "specHeat", name) massText = self.mParser.getChildText( expElem, "mass", name).replace('%Cp', specHeatText) expText = "(%s) * (%s)" % (massText, specHeatText) except (TagNotFound), e: ## Store a "-1" as an indication that no mass data was provided. massText = "-1" ## Append a symbol for the mass. nameList.append(name.replace("cap_", "mass_")) expList.append(massText) ## Append name and expression to list. nameList.append(name) expList.append(expText) except (TagNotFound, ThermError), e: print e, print "Symbol will be ignored (%s)." % name continue
def getValidatedValue(self, expr, info=''): try: value = eval(expr, globals(), self.mSymMap) except (NameError, SyntaxError), e: print e, raise ThermError("Invalid value: %s (%s)." % (expr, info))