Beispiel #1
0
 def Solve(self):
     """
     determine variable to solve for and call appropriate method
     (supplied by derived class)
     """
     p0 = self.GetPort(IN_PORT_0)
     p1 = self.GetPort(IN_PORT_1)
     pOut = self.GetPort(OUT_PORT)
     
     value0 = p0.GetValue()
     value1 = p1.GetValue()
     result = pOut.GetValue()
     
     if value0 != None:
         if value1 != None:
             try:
                 result = self.CalcResult(value0, value1)
             except ValueError:
                 return
             pOut.SetValue(result, CALCULATED_V)
         elif result != None:
             try:
                 value1 = self.CalcValue1(value0, result)
             except ValueError:
                 return
             p1.SetValue(value1, CALCULATED_V)
     elif value1 != None and result != None:
         try:
             value0 = self.CalcValue0(value1, result)
         except ValueError:
             raise Error.SimError('EqnCalcError', self.GetPath())
         p0.SetValue(value0, CALCULATED_V)
Beispiel #2
0
 def CalcJacobian(self):
     """
     Use crude numerical differences to approximate Jacobian
     return inverse
     """
     jacobian = zeros((self.numberActive, self.numberActive), Float)
     for cont in self.activeControllers:
         cont.SaveBase()
     self.errors = self.GetErrors()
         
     delta = 0.1
     for i in range(self.numberActive):
         self.flowsheet.InfoMessage('ContDerivCalc', (self.flowsheet.GetPath(), i))
         cont = self.activeControllers[i]
         cont.SetOutput(delta)
         self.flowsheet.InnerSolve()
         jacobian[:,i] = (self.GetErrors() - self.errors)/delta
         cont.SetOutput(0.0)
         
     self.flowsheet.InnerSolve()
     
     try:
         self.jacobian = inverse(jacobian)
     except:
         raise Error.SimError('CouldNotInvertJacobian', self.flowsheet.GetPath())
Beispiel #3
0
 def ProcessParen(self):
     """
     work back up operator stack until matching '(' is found
     """
     while 1:
         if len(self.operatorStack) == 0:
             raise Error.SimError(EqnParenMismatch, (self.currentEqn, self.GetPath()))
         op = self.operatorStack[-1]
         if op == '(':
             self.operatorStack.pop()  # just throw away matching paren
             return
         else:
             self.ProcessTopOperator()
Beispiel #4
0
 def ParseEquation(self, tokens):
     """
     tokens is list of tokens
     """
     if len(tokens) == 0: return
     
     self.operatorStack = ['(']  # start with paren to make end of input easy
     self.operandStack = []
     for token in tokens:
         # find first operand
         if token == '(':
             self.operatorStack.append(token)
             
         elif token == ')':
             self.ProcessParen()
  
         elif token in _operators:
             opClass = _operators[token]
             op = opClass()
             self.AddObject(op, '%s_%d' % (opClass.__name__, self.opCount))
             self.installedOps.append(op)
             self.opCount += 1
             prevOp = self.operatorStack[-1]
             while prevOp != '(' and prevOp.precedence >= op.precedence:
                 self.ProcessTopOperator()
                 prevOp = self.operatorStack[-1]
             self.operatorStack.append(op)
             
         elif token in self.GetPortNames(SIG):
             signal = self.GetChildUO(MakeSignalName(token))
             self.operandStack.append(signal)
             
         else:
             # should be a number
             try:
                 value = float(token)
             except ValueError:
                 raise Error.SimError('EqnUnknownToken', (token, self.currentEqn, self.GetPath()))
             self.operandStack.append(value)
     # process everything back to that initial paren
     self.ProcessParen()
     
     if len(self.operandStack) > 1 or len(self.operatorStack):
         self.SyntaxError()
Beispiel #5
0
    def ParseFormula(self):
        eqnStr = self.parameters[RXNFFORMULA_PAR]
        eqn = eqnStr    # keep a copy of the original equation
        if (eqnStr == None or eqnStr == ''): return
        
        # reset all coeffs to zero
        cmpNames = self.GetCompoundNames()
        self.cmpNames = cmpNames

        self.stoichCoeffs = []
        for i in range(len(cmpNames)):
            self.stoichCoeffs.append(0)

        # replace compounds within quotes by the index
        # for compounds with '-'
        cmps = re.findall(r'"[^"]+"|\'[^\']+\'', eqnStr)
        for token in cmps:
            # strip out the quote
            cmp = token[1:-1]
            try:
                idx = self.CompoundIndex(cmp)
                #eqnStr = re.sub(token, str(idx), eqnStr)
                eqnStr = eqnStr.replace(token, str(idx))
            except:
                pass
        
        try:
            # extract the reaction name
            tokens = re.split(r'\:', eqnStr, 1)
            if (len(tokens) == 2):
                eqnStr = string.strip(tokens[1])
                self.rxnName = string.strip(tokens[0])

            # replace all - by +- so that when i split the tokens,
            # the signs of the coeff are preserved
            eqnStr = re.sub('\-', '+-', eqnStr)
            tokens = re.split('\+', eqnStr)
            for token in tokens:
                if (string.strip(token) == ''):
                    continue
                x = re.split('\*', string.strip(token))
                # if coeff is missing, assume 1 or -1
                if len(x) == 1:
                    x0 = x[0]
                    if x0[0] == '-':
                        x.append(x0[1:])
                        x[0] = '-1'
                    else:    
                        x.append(x0)
                        x[0] = '1'
                # let underscores stand for spaces
                cmp = re.sub('_', ' ', string.strip(x[1]))
                # base compound indicator
                baseCmp = 0
                if (cmp[0] == '!'):
                    cmp = cmp[1:]
                    baseCmp = 1
                # if the input compound name is numeric, it is the compound index
                try:
                    idx = int(cmp)
                except:
                    idx = cmpNames.index(cmp)
                coef = float(string.strip(x[0]))
                self.stoichCoeffs[idx]= coef
                if baseCmp:
                    self.baseCompIdx = idx
        except:
            #self.SetParameterValue(RXNFFORMULA_PAR, '')            
            self.stoichCoeffs = []
            raise Error.SimError('EqnSyntax', (eqn, self.GetPath()))
        
        # base compound must be a reactant
        # check for equation mass balance later (need MW of selected compounds)
        if self.baseCompIdx < 0:
            raise Error.SimError('EqnSyntax', (eqn, self.GetPath()))            
        elif self.stoichCoeffs[self.baseCompIdx] >= 0:
            raise Error.SimError('EqnSyntax', (eqn, self.GetPath()))
Beispiel #6
0
 def SyntaxError(self):
     raise Error.SimError('EqnSyntax', (self.currentEqn, self.GetPath()))
Beispiel #7
0
    def SetParameterValue(self, name, value):
        """
        do the main work of parsing the equation and setting up the solution network
        """
        super(Equation, self).SetParameterValue(name, value)
        if name == EQUATION_PAR:
            # eliminate the old operators
            for op in self.installedOps:
                self.DeleteObject(op)
            self.installedOps = []
            self.opCount = 0
            
            # remove any clone ports from installed signal streams
            for name in self.GetPortNames(SIG):
                sig = self.GetChildUO(MakeSignalName(name))
                if sig:
                    nTimesUsed = sig.GetParameterValue(USEDCOUNT_PAR)
                    for i in range(1, nTimesUsed):
                        sig.DeletePortNamed('Clone_%d' % i)
                    sig.SetParameterValue(USEDCOUNT_PAR, 0)
            
            lines = re.split(r'\n', value)
            signals = []
            eqns = []
            for line in lines:
                line = string.strip(line)
                if _reSignal.match(line):
                    signals.append(line)
                else:
                    eqns.append(line)

            newNames = []
            for sigDcl in signals:
                # step over word signal
                sigDcl = string.lstrip(sigDcl[6:])
                dclTypes = _reTypeDcl.findall(sigDcl)
                for dclType in dclTypes:
                    (sigType, sigNames, junk) = _reEitherParen.split(dclType)
                    sigNames = _reSpaceComma.split(sigNames)
                    for name in sigNames:
                        if not name: continue
                        if name in newNames:
                            raise Error.SimError('EqnDuplicateSigName', (name, self.GetPath()))
                        newNames.append(name)
                        if name not in self.GetPortNames(SIG):
                            stream = Stream.Stream_Signal()
                            stream.SetParameterValue(SIGTYPE_PAR, sigType)
                            stream.SetParameterValue(USEDCOUNT_PAR, 0)

                            self.AddObject(stream, MakeSignalName(name))
                            self.BorrowChildPort(stream.GetPort(IN_PORT), name)
                            
            # any current ports not in new list need to be removed
            missingNames = []
            for name in self.GetPortNames(SIG):
                if name not in newNames:
                    missingNames.append(name)
                    
            for name in missingNames:
                stream = self.GetObject(MakeSignalName(name))
                port = self.GetPort(name)
                self.DelUnitOperation(MakeSignalName(portName))
                self.DeleteObject(port)
                    
            # now parse the equations
            for eqn in eqns:
                # transform string into list of tokens
                if not eqn: continue
                tokens = _reTokenizeEqn.findall(eqn)
                self.currentEqn = eqn   # for error reporting
                self.ParseEquation(tokens)