pyNastran  0.5.0
pyNastran BDF Reader/Writer, OP2 Parser, and GUI
caseControlDeck.py
Go to the documentation of this file.
00001 ## GNU Lesser General Public License
00002 ## 
00003 ## Program pyNastran - a python interface to NASTRAN files
00004 ## Copyright (C) 2011-2012  Steven Doyle, Al Danial
00005 ## 
00006 ## Authors and copyright holders of pyNastran
00007 ## Steven Doyle <mesheb82@gmail.com>
00008 ## Al Danial    <al.danial@gmail.com>
00009 ## 
00010 ## This file is part of pyNastran.
00011 ## 
00012 ## pyNastran is free software: you can redistribute it and/or modify
00013 ## it under the terms of the GNU Lesser General Public License as published by
00014 ## the Free Software Foundation, either version 3 of the License, or
00015 ## (at your option) any later version.
00016 ## 
00017 ## pyNastran is distributed in the hope that it will be useful,
00018 ## but WITHOUT ANY WARRANTY; without even the implied warranty of
00019 ## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00020 ## GNU General Public License for more details.
00021 ## 
00022 ## You should have received a copy of the GNU Lesser General Public License
00023 ## along with pyNastran.  If not, see <http://www.gnu.org/licenses/>.
00024 ## 
00025 # pylint: disable=R0904,R0902,C0103
00026 
00027 from __future__ import division, print_function
00028 import sys
00029 import copy
00030 from pyNastran.bdf.subcase import Subcase
00031 from pyNastran.bdf.errors import ParamParseError
00032 
00033 class CaseControlDeck(object):
00034     def __init__(self, lines, log=None):
00035         """
00036         @param self
00037           the case control deck object
00038         @param lines
00039           list of lines that represent the case control deck ending with
00040           BEGIN BULK
00041         @param log
00042           a logger object
00043         """
00044         if log is None:
00045         #if 1:
00046             from pyNastran.general.logger import dummyLogger
00047             word = 'debug'
00048             loggerObj = dummyLogger()
00049             log = loggerObj.startLog(word) # or info
00050         self.debug = False
00051         #self.debug = True
00052 
00053         self.log = log
00054         self.lines = lines
00055         self.subcases = {0:Subcase(id=0)}
00056         self._read(self.lines)
00057 
00058     def hasParameter(self, iSubcase, paramName):
00059         """@see has_parameter"""
00060         return self.has_parameter(iSubcase, paramName)
00061 
00062     def getSubcaseParameter(self, iSubcase, paramName):
00063         """@see get_subcase_parameter"""
00064         return self.get_subcase_parameter(iSubcase, paramName)
00065 
00066     def hasSubcase(self, iSubcase):
00067         """@see has_subcase"""
00068         return self.has_subcase(iSubcase)
00069 
00070     def createNewSubcase(self, iSubcase):
00071         """@see create_new_subcase"""
00072         self.create_new_subcase(iSubcase)
00073 
00074     def deleteSubcase(self, iSubcase):
00075         """@see delete_subcase"""
00076         self.delete_subcase(iSubcase)
00077 
00078     def copySubcase(self, iFromSubcase, iToSubcase, overwriteSubcase=True):
00079         """@see copy_subcase"""
00080         self.copy_subcase(iFromSubcase, iToSubcase, overwriteSubcase=True)
00081 
00082     def getSubcaseList(self):
00083         """@see get_subcase_list"""
00084         return self.get_subcase_list()
00085 
00086     def getLocalSubcaseList(self):
00087         """@see get_local_subcase_list"""
00088         self.get_local_subcase_list()
00089 
00090     def updateSolution(self, iSubcase, sol):
00091         """@see update_solution"""
00092         self.update_solution(iSubcase, sol)
00093 
00094     def addParameterToGlobalSubcase(self, param):
00095         """@see add_parameter_to_global_subcase"""
00096         self.add_parameter_to_global_subcase(param)
00097 
00098     def addParameterToLocalSubcase(self, iSubcase, param):
00099         """@see add_parameter_to_local_subcase"""
00100         self.add_parameter_to_local_subcase(iSubcase, param)
00101 
00102 #-----------------------
00103     def has_parameter(self, iSubcase, paramName):
00104         if self.hasSubcase(iSubcase):
00105             return self.subcases[iSubcase].hasParameter(paramName.upper())
00106 
00107     def get_subcase_parameter(self, iSubcase, paramName):
00108         if self.hasSubcase(iSubcase):
00109             return self.subcases[iSubcase].getParameter(paramName.upper())
00110         raise RuntimeError('iSubcase=%s does not exist...' %(iSubcase))
00111 
00112     def has_subcase(self, iSubcase):
00113         """
00114         Checks to see if a subcase exists.
00115         @param self the case control deck object
00116         @param iSubcase the subcase ID
00117         @retval does_subcase_exist (type = bool)
00118         """
00119         if iSubcase in self.subcases:
00120             return True
00121         return False
00122 
00123     def create_new_subcase(self, iSubcase):
00124         """
00125         @warning
00126           be careful you dont add data to the global subcase after running
00127           this...is this True???
00128         """
00129         if self.hasSubcase(iSubcase):
00130             sys.stderr.write('subcase=%s already exists...skipping\n' %(iSubcase))
00131         self.copy_subcase(iFromSubcase=0, iToSubcase=iSubcase,overwriteSubcase=True)
00132         #self.subcases[iSubcase] = Subcase(id=iSubcase)
00133 
00134     def delete_subcase(self, iSubcase):
00135         if not self.hasSubcase(iSubcase):
00136             sys.stderr.write('subcase %s doesnt exist...skipping\n' %(iSubcase))
00137         del self.subcases[iSubcase]
00138 
00139     def copy_subcase(self, iFromSubcase, iToSubcase, overwriteSubcase=True):
00140         """
00141         overwrites the parameters from one subcase to another
00142         @param self             the case control deck object
00143         @param iFromSubcase     the subcase to pull the data from
00144         @param iToSubcase       the subcase to map the data to
00145         @param overwriteSubcase NULLs iToSubcase before copying iFromSubcase
00146         """
00147         if not self.hasSubcase(iFromSubcase):
00148             msg = 'iFromSubcase=|%s| does not exist' %(iFromSubcase)
00149             raise RuntimeError(msg)
00150         subcaseFrom = self.subcases[iFromSubcase]
00151         if overwriteSubcase:
00152             subcaseTo = copy.deepcopy(subcaseFrom)
00153             subcaseTo.id = iToSubcase
00154             self.subcases[iToSubcase] = subcaseTo
00155         else:
00156             if not self.has_subcase(iToSubcase):
00157                 msg = 'iToSubcase=|%s| does not exist' %(iToSubcase)
00158                 raise RuntimeError(msg)
00159             subcaseTo = self.subcases[iToSubcase]
00160             for key,param in subcaseFrom.iteritems():
00161                 subcaseTo[key] = copy.deepcopy(param)
00162             ###
00163         ###
00164 
00165     def get_subcase_list(self):
00166         return sorted(self.subcases.keys())
00167 
00168     def get_local_subcase_list(self):
00169         keyList = [key for key in self.subcases if key != 0] # skip the global
00170         return sorted(keyList)
00171 
00172     def update_solution(self, iSubcase, sol):
00173         """sol = STATICS, FLUTTER, MODAL, etc."""
00174         self.add_parameter_to_local_subcase(iSubcase, 'ANALYSIS %s' %(sol))
00175 
00176     def add_parameter_to_global_subcase(self, param):
00177         """
00178         takes in a single-lined string
00179         @note
00180             dont worry about overbounding the line
00181         """
00182         (j, key, value, options, paramType) = self._parse_data_from_user(param)
00183         subcaseList = self.get_subcase_list()
00184         for iSubcase in subcaseList:
00185             self._add_parameter_to_subcase(key, value, options, paramType,
00186                                         iSubcase)
00187 
00188     def add_parameter_to_local_subcase(self, iSubcase, param):
00189         (j, key, value, options, paramType) = self._parse_data_from_user(param)
00190         self._addParameterToSubcase(key, value, options, paramType, iSubcase)
00191 
00192     def _parse_data_from_user(self, param):
00193         if '\n' in param or '\r' in param or '\t' in param:
00194             msg = 'doesnt support embedded endline/tab characters\n'
00195             msg += '  param = |%r|' %(param)
00196             raise SyntaxError(msg)
00197         #self.read([param])
00198         lines = self.clean_lines([param])
00199         (j, key, value, options, paramType) = self._parse_entry(lines)
00200         return (j, key, value, options, paramType)
00201 
00202     def _clean_lines(self, lines):
00203         """removes comment characters $"""
00204         lines2 = []
00205         for line in lines:
00206             line = line.strip(' \n\r').split('$')[0].rstrip()
00207             if line:
00208                 lines2.append(line)
00209             ###
00210         ###
00211         #for line in lines2:
00212             #print "L2 = ",line
00213         return lines2
00214 
00215     def _read(self, lines):
00216         """
00217         reads the case control deck
00218         @note supports comment lines
00219         @warning
00220             doesnt check for 72 character width lines, but will follow that
00221             when it's written out
00222         """
00223         iSubcase = 0
00224         lines = self._clean_lines(lines)
00225         i = 0
00226         while i < len(lines):
00227             line = lines[i]
00228             #print "rawLine = |%s|" %(line)
00229             #self.log.debug("rawLine = |%r|" %(line))
00230 
00231             lines2 = [line]
00232             while ',' in lines[i][-1]:
00233                 #print "lines[%s] = %s" %(i,lines[i])
00234                 i+=1
00235                 lines2.append(lines[i])
00236                 if i>10000:
00237                     msg =  'There are too many lines in case control deck.\n'
00238                     msg += 'Assuming an infinite loop was found.'
00239                     raise RuntimeError(msg)
00240             (j, key, value, options, paramType) = self._parse_entry(lines2)
00241             i+=1
00242             #print ""
00243             #print "key=|%s| value=|%s| options=|%s| paramType=%s" %(key,value,options,paramType)
00244             iSubcase = self._addParameterToSubcase(key, value, options, paramType, iSubcase)
00245             #print "--------------"
00246             if i == 10000:
00247                 msg = 'too many lines in Case Control Deck < 10000...'
00248                 raise RuntimeError(msg)
00249         ###
00250         #print "done with while loop...\n"
00251         
00252         #print str(self)
00253         self.finish_subcases()
00254     ###
00255 
00256     def _parse_entry(self, lines):
00257         """
00258         @brief
00259             internal method for parsing a card of the case control deck
00260 
00261             parses a single case control deck card into 4 sections
00262             1.  paramName - obvious
00263             2.  Value     - still kind of obvious
00264             3.  options   - rarely used data
00265             4.  paramType - STRESS-type, SUBCASE-type, PARAM-type, SET-type, BEGIN_BULK-type
00266 
00267             It's easier with examples:
00268 
00269             paramType = SUBCASE-type
00270               SUBCASE 1              ->   paramName=SUBCASE  value=1            options=[] 
00271             paramType = STRESS-type
00272               STRESS       = ALL     ->   paramName=STRESS    value=ALL         options=[]
00273               STRAIN(PLOT) = 5       ->   paramName=STRAIN    value=5           options=[PLOT]
00274               TITLE        = stuff   ->   paramName=TITLE     value=stuff       options=[]
00275             paramType = SET-type
00276               SET 1 = 10,20,30       ->   paramName=SET       value=[10,20,30]  options = 1
00277             paramType = BEGIN_BULK-type
00278               BEGIN BULK             ->   paramName=BEGIN     value=BULK        options = []
00279             paramType = CSV-type
00280               PARAM,FIXEDB,-1        ->   paramName=PARAM     value=FIXEDB      options = [-1]
00281 
00282             The paramType is the "macro" form of the data (similar to integer, float, string).
00283             The value is generally whats on the RHS of the equals sign (assuming it's there).
00284             Options are modifiers on the data.  Form things like the PARAM card or the SET card
00285             they arent as clear, but the paramType lets the program know how to format it
00286             when writing it out.
00287 
00288         @param self  the case control deck object
00289         @param lines list of lines
00290         @retval paramName see brief
00291         @retval value     see brief
00292         @retval options   see brief
00293         @retval paramType see brief
00294         """
00295         i = 0
00296         options   = []
00297         value     = None
00298         key       = None
00299         paramType = None
00300 
00301         line = lines[i]
00302         #print line
00303         #print "*****lines = ", lines
00304         
00305         equalsCount = 0
00306         for letter in line:
00307             if letter == '=':
00308                 equalsCount += 1
00309         lineUpper = line.upper()
00310 
00311         if lineUpper.startswith('SUBCASE'):
00312             #print "line = |%r|" %(line)
00313             line2 = line.replace('=', '')
00314             sline = line2.split()
00315             if len(sline) != 2:
00316                 msg = "trying to parse |%s|..." %(line)
00317                 raise RuntimeError(msg)
00318             (key, iSubcase) = sline
00319             #print "key=|%s| iSubcase=|%s|" %(key,iSubcase)
00320             value = int(iSubcase)
00321             #self.iSubcase = int(iSubcase)
00322             paramType = 'SUBCASE-type'
00323         elif (lineUpper.startswith('LABEL') or lineUpper.startswith('SUBTITLE')
00324               or lineUpper.startswith('TITLE')):
00325             try:
00326                 eIndex = line.index('=')
00327             except:
00328                 msg  = "cannot find an = sign in LABEL/SUBTITLE/TITLE line\n"
00329                 msg += "line = |%s|" %(lineUpper.strip())
00330                 raise RuntimeError(msg)
00331 
00332             key   = line[0:eIndex].strip()
00333             value = line[eIndex+1:].strip()
00334             options = []
00335             paramType = 'STRING-type'
00336         elif equalsCount == 1: # STRESS
00337             if '=' in line:
00338                 (key, value) = line.strip().split('=')
00339             else:
00340                 msg = 'expected item of form "name = value"   line=|%r|' %(line.strip())
00341                 raise RuntimeError(msg)
00342 
00343             key = key.strip()
00344             value = value.strip()
00345             if self.debug:
00346                 self.log.debug("key=|%s| value=|%s|" %(key, value))
00347             paramType = 'STRESS-type'
00348 
00349             if '(' in key:  # comma may be in line - STRESS-type
00350                 #paramType = 'STRESS-type'
00351                 sline = key.strip(')').split('(')
00352                 key = sline[0]
00353                 options = sline[1].split(',')
00354 
00355                 # handle TEMPERATURE(INITIAL) and TEMPERATURE(LOAD) cards
00356                 if key == 'TEMPERATURE' or key == 'TEMP':
00357                     key = 'TEMPERATURE(%s)' %(options[0])
00358                     options = []
00359                 #print "key=|%s| options=%s" %(key,options)
00360 
00361             elif ' ' in key and ',' in value: # SET-type
00362                 (key, ID) = key.split()
00363                 key = key+' '+ID
00364 
00365                 if self.debug:
00366                     self.log.debug('SET-type key=%s ID=%s' %(key, ID))
00367                 fivalues = value.rstrip(' ,').split(',') # float/int values
00368 
00369                 ## @todo should be more efficient multiline reader...
00370                 # read more lines....
00371                 if line[-1].strip() == ',':
00372                     i+=1
00373                     #print "rawSETLine = |%r|" %(lines[i])
00374                     while 1:
00375                         if ','== lines[i].strip()[-1]:
00376                             fivalues += lines[i][:-1].split(',')
00377                         else: # last case
00378                             fivalues += lines[i].split(',')
00379                             #print "fivalues last = i=%s |%r|" %(i,lines[i])
00380                             i+=1
00381                             break
00382                         i+=1
00383                     ###
00384                 ###
00385                 #print "len(fivalues) = ",len(fivalues)
00386                 value = fivalues
00387 
00388                 options = ID # needed a place to put it...
00389                 paramType = 'SET-type'
00390             elif ',' in value: # STRESS-type; special TITLE = stuffA,stuffB
00391                 #print 'A ??? line = ',line
00392                 #raise RuntimeError(line)
00393                 pass
00394             else:  # STRESS-type; TITLE = stuff
00395                 #print 'B ??? line = ',line
00396                 pass
00397             ###
00398         ### = in line
00399         elif lineUpper.startswith('BEGIN'): # begin bulk
00400             try:
00401                 (key, value) = lineUpper.split(' ')
00402             except:
00403                 msg = 'excepted "BEGIN BULK" found=|%r|' %(line)
00404                 raise RuntimeError(msg)
00405             paramType = 'BEGIN_BULK-type'
00406         elif 'PARAM' in lineUpper: # param
00407             sline = line.split(',')
00408             if len(sline) != 3:
00409                 raise ParamParseError("trying to parse |%s|..." %(line))
00410             (key, value, options) = sline
00411             ###
00412             paramType = 'CSV-type'
00413         elif ' ' not in line:
00414             key = line.strip()
00415             value = line.strip()
00416             options = None
00417             paramType = 'KEY-type'
00418         else:
00419             msg = 'generic catch all...line=|%r|' %(line)
00420             #print 'C ??? line = ',line
00421             #raise RuntimeError(msg)
00422             key = ''
00423             value = line
00424             options = None
00425             paramType = 'KEY-type'
00426         ###
00427         i+=1
00428         #print "done with ",key
00429         return (i, key, value, options, paramType)
00430 
00431     def finish_subcases(self):
00432         """
00433         removes any unwanted data in the subcase...specifically the SUBCASE
00434         data member.  Otherwise it will print out after a key like stress.
00435         """
00436         for (iSubcase, subcase) in sorted(self.subcases.iteritems()):
00437             subcase.finish_subcase()
00438         ###
00439     ###
00440 
00441     def _addParameterToSubcase(self, key, value, options, paramType, iSubcase):
00442         """internal method"""
00443         if self.debug:
00444             a = 'key=|%s|'       %(key)
00445             b = 'value=|%s|'     %(value)
00446             c = 'options=|%s|'   %(options)
00447             d = 'paramType=|%s|' %(paramType)
00448             msg = "_adding iSubcase=%s %-12s %-12s %-12s %-12s" %(iSubcase, a,
00449                                                                   b, c, d)
00450             self.log.debug(msg)
00451 
00452         if key == 'SUBCASE':
00453             assert value not in self.subcases
00454             assert isinstance(value, int)
00455             iSubcase = value
00456             #print "value=", value
00457             self.copy_subcase(iFromSubcase=0, iToSubcase=iSubcase,
00458                              overwriteSubcase=True)
00459             if self.debug:
00460                 msg = "copied subcase iFromSubcase=%s to iToSubcase=%s" %(0, iSubcase)
00461                 self.log.debug(msg)
00462         elif iSubcase not in self.subcases: # initialize new subcase
00463             #self.iSubcase += 1 # is handled in the read code
00464             msg = 'iSubcase=%s is not a valid subcase...' %(iSubcase)
00465             raise RuntimeError(msg)
00466 
00467         subcase = self.subcases[iSubcase]
00468         subcase._add_data(key,value,options,paramType)
00469         
00470         #print "\n%s\n" %(self.subcases[iSubcase])
00471         return iSubcase
00472 
00473     #def __str__(self):
00474     #    return self.__repr__()
00475 
00476     def crossReference(self, model):
00477         for (iSubcase, subcase) in sorted(self.subcases.iteritems()):
00478             subcase.crossReference(model)
00479 
00480     def get_op2_data(self):
00481         """
00482         returns the relevant op2 parameters required for a given subcase
00483         """
00484         cases = {}
00485         for (iSubcase, subcase) in sorted(self.subcases.iteritems()):
00486             if iSubcase != 0:
00487                 cases[iSubcase] = subcase.getOp2Data(self.sol,
00488                                                      self.solmap_toValue)
00489         return cases
00490 
00491     def __repr__(self):
00492         msg = ''
00493         subcase0 = self.subcases[0]
00494         for (iSubcase, subcase) in sorted(self.subcases.iteritems()):
00495             #if iSubcase==0:
00496             #print("iSubcase = %s" %(iSubcase))
00497             #print(subcase)
00498             #print("********")
00499             msg += subcase.write_subcase(subcase0)
00500             #msg += str(subcase)
00501             #else:
00502             #    msg += subcase.writeSubcase(subcase0)
00503             #print "\n"
00504             #break
00505         if len(self.subcases) == 1:
00506             msg += 'BEGIN BULK\n'
00507         #print msg
00508         return msg
00509     ###
00510 ###
00511 
00512     #def parseParam(self,param):
00513     #    """
00514     #    @warning doesnt support comment characters
00515     #    """
00516     #    param = param.substr('\n','').substr('\r','') # remove line endings
00517     #    parse(param)
00518     #    #param2 = [''.join(param)]
00519     #    #print 'param2 = ',param2
00520 
00521 def test1():
00522     lines = ['SPC=2',
00523              'MPC =3',
00524              'STRESS= ALL',
00525              'DISPLACEMENT(PLOT,PUNCH) = 8',]
00526     deck = CaseControlDeck(lines)
00527     print("has SPC  True  = %s" %(deck.has_parameter(0, 'SPC')))
00528     print("has sPC  True  = %s" %(deck.has_parameter(0, 'sPC')))
00529     print("has junk False = %s" %(deck.has_parameter(0, 'JUNK')))
00530     
00531     print("getSubcaseParameter(MPC) 3 = ", deck.get_subcase_parameter(0, 'MPC'))
00532     deck.add_parameter_to_global_subcase('GPFORCE = 7')
00533     print("")
00534     print(deck)
00535     deck.create_new_subcase(1)
00536     deck.create_new_subcase(2)
00537     print(deck)
00538     
00539     deck.addParameterToLocalSubcase(1, 'STRAIN = 7')
00540     #print "-----added----"
00541 
00542     out = deck.getSubcaseParameter(0, 'GPFORCE')
00543     print("getSubcaseParameter(STRAIN) 7 = %s" %(out))
00544 
00545     deck.addParameterToLocalSubcase(1, 'ANALYSIS = SAERO')
00546     deck.addParameterToLocalSubcase(2, 'ANALYSIS = STATIC')
00547     print("-----added2----")
00548     out = deck.getSubcaseParameter(2, 'ANALYSIS')
00549     print("getSubcaseParameter(ANALYSIS) = %s" %(out))
00550     
00551 
00552     deck.addParameterToLocalSubcase(1, 'SET 1 = 100')
00553     deck.addParameterToLocalSubcase(1, 'SET 2 = 200')
00554     print(deck)
00555     
00556 if __name__=='__main__':
00557     test1()
00558     lines = [
00559         'SUBCASE 1',
00560         '    ACCELERATION(PLOT,PRINT,PHASE) = ALL',
00561         '    DISPLACEMENT(PLOT,PRINT,PHASE) = ALL',
00562         '    DLOAD = 32',
00563         '    M2GG = 111',
00564         '    SET 88  = 5, 6, 7, 8, 9, 10 THRU 55 EXCEPT 15, 16, 77, 78, 79, 100 THRU 300',
00565         '    SET 99  = 1 THRU 10',
00566         '    SET 105 = 1.009, 10.2, 13.4, 14.0, 15.0',
00567         '    SET 111 = MAAX1,MAAX2',
00568         '    SET 1001 = 101/T1, 501/T3, 991/R3',
00569         '    SET = ALL',
00570         '    SPC = 42',
00571         '    TSTEPNL = 22',
00572         '    VELOCITY(PLOT,PRINT,PHASE) = ALL',
00573         'BEGIN BULK',
00574         ]
00575     deck = CaseControlDeck(lines)
00576     deck.createNewSubcase(2)
00577     deck.addParameterToLocalSubcase(1,'SET 2 = 11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,1000000000000000000000000000000000000000000000000000000,33')
00578     print(deck+'\n\n')
00579 
00580     deck2 = CaseControlDeck(['ACCELERATION(PLOT,PRINT,PHASE) = ALL',
00581                              'DISPLACEMENT(PLOT,PRINT,PHASE) = ALL',
00582                              'BEGIN BULK'])
00583     print('\n\n'+deck2)
 All Classes Namespaces Files Functions Variables