pyNastran  0.5.0
pyNastran BDF Reader/Writer, OP2 Parser, and GUI
resultTable.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 
00026 from __future__ import division, print_function
00027 import sys
00028 import copy
00029 from numpy import array
00030 from struct import unpack
00031 
00032 from pyNastran.op2.tables.oug.oug  import OUG
00033 from pyNastran.op2.tables.oes_stressStrain.oes import OES
00034 #from pyNastran.op2.tables.oes_stressStrain.oesnlxr import OESNLXR
00035 #from pyNastran.op2.tables.oes_stressStrain.oesnlxd import OESNLXD
00036 
00037 from pyNastran.op2.tables.oqg_constraintForces.oqg   import OQG
00038 from pyNastran.op2.tables.oef_forces.oef import OEF
00039 from pyNastran.op2.tables.opg_appliedLoads.opg import OPG
00040 from pyNastran.op2.tables.oee_energy.oee import OEE
00041 from pyNastran.op2.tables.ogf_gridPointForces.ogf import OGF
00042 #from pyNastran.op2.tables.hisadd import HISADD - combined with R1TAB for now
00043 from pyNastran.op2.tables.r1tab  import R1TAB
00044 from pyNastran.op2.tables.destab import DESTAB
00045 from pyNastran.op2.tables.lama_eigenvalues.lama import LAMA
00046 
00047 
00048 
00049 class ResultTable(OQG,OUG,OEF,OPG,OES,OEE,OGF,R1TAB,DESTAB,LAMA):  # OESNLXR,OESNLXD,
00050 
00051     def readTableA_DUMMY(self):
00052         """reads a dummy geometry table"""
00053         self.iTableMap = {}
00054         self.readRecordTable('DUMMY')
00055 
00056     def readTableB_DUMMY(self):
00057         """reads a dummy results table"""
00058         self.tableName = 'DUMMY'
00059         table3     = self.readTable_DUMMY_3
00060         table4Data = self.readDUMMY_Data
00061         self.readResultsTable(table3,table4Data)
00062         self.deleteAttributes_OPG()
00063 
00064     def readTable_DUMMY_3(self,iTable):
00065         """sets dummy parameters"""
00066         self.analysisCode = None
00067         self.tableCode    = None
00068         self.formatCode   = None
00069         self.sortCode     = None
00070 
00071     def readDUMMY_Data(self):
00072         """creates a dummy object and skips the results"""
00073         self.obj = None
00074         self.readOES_Element()
00075 
00076     def updateSort1(self):
00077         extract = self.extractSort1
00078         return 'i',extract
00079 
00080     def updateSort2(self):
00081         extract = self.extractSort2
00082         return 'f'
00083 
00084     def extractSort1(self,eidDevice,dt):
00085         #eidDevice, = unpack(b'i',data)
00086         #print "eidDevice=%s dt=%s eid-dev=%s out=%s" %(eidDevice,dt,eidDevice-self.deviceCode,(eidDevice-self.deviceCode)/10.)
00087         return (eidDevice-self.deviceCode)//10
00088 
00089     def extractSort2(self,timeFreq,eid):
00090         #print "timeFreq=%s eid=%s" %(timeFreq,eid)
00091         #gridDevice, = unpack(b'i',data)
00092         return timeFreq
00093     
00094     def addDataParameter(self,data,Name,Type,fieldNum,applyNonlinearFactor=True,fixDeviceCode=False):
00095         """
00096         self.mode = self.getValues(data,'i',5) ## mode number
00097         """
00098         value = self.getValues(data,Type,fieldNum)
00099         if fixDeviceCode:
00100             value = (value-self.deviceCode)//10
00101         #print "Name=%s Type=%s fieldNum=%s aCode=%s value=%s" %(Name,Type,fieldNum,self.analysisCode,value)
00102         setattr(self,Name,value)
00103         self.dataCode[Name] = value
00104         
00105         if applyNonlinearFactor:
00106             self.nonlinearFactor = value
00107             self.dataCode['nonlinearFactor'] = value
00108             self.dataCode['name'] = Name
00109     
00110     def setNullNonlinearFactor(self):
00111         self.nonlinearFactor = None
00112         self.dataCode['nonlinearFactor'] = None
00113 
00114     def applyDataCodeValue(self,Name,value):
00115         self.dataCode[Name] = value
00116         
00117     def createTransientObject(self,storageObj,classObj,debug=False):
00118         """
00119         Creates a transient object (or None if the subcase should be skippied).
00120         @param storageObj  the dictionary to store the object in (e.g. self.bars)
00121         @param classObj    the class object to instantiate
00122         @note dt can also be loadStep depending on the class
00123         """
00124         if debug:
00125             print("create Transient Object")
00126             print("***NF = %s" %(self.nonlinearFactor))
00127             #print "DC = ",self.dataCode
00128         
00129         if self.iSubcase in storageObj:
00130             #print "updating dt..."
00131             self.obj = storageObj[self.iSubcase]
00132             #print "obj = ",self.obj.__class__.__name__
00133             #print self.obj.writeF06(['',''],'PAGE ',1)[0]
00134             
00135             try:
00136                 self.obj.updateDataCode(self.dataCode)
00137                 #self.obj.updateDt(self.dataCode,self.nonlinearFactor)
00138             except:
00139                 #try:
00140                     #print "objName = ",self.obj.name()
00141                 #except:
00142                     #print "objName = ",self.obj
00143                 raise
00144             ###
00145         else:
00146             #if self.isRegular:
00147                 #self.obj = classObj(self.dataCode,not(self.isRegular),self.iSubcase,self.nonlinearFactor)
00148             #else:
00149             self.obj = classObj(self.dataCode,self.isSort1(),self.iSubcase,self.nonlinearFactor)
00150             #print "obj2 = ",self.obj.__class__.__name__
00151         storageObj[self.iSubcase] = self.obj
00152         ###
00153 
00154     def createThermalTransientObject(self,resultName,objClass,isSort1):
00155         #print resultName
00156         if self.iSubcase in resultName:
00157             self.obj = resultName[self.iSubcase]
00158             #print "returning iSubcase result=%s" %(self.iSubcase)
00159         else:
00160             self.obj = objClass(self.dataCode,isSort1,self.iSubcase,self.nonlinearFactor)
00161             resultName[self.iSubcase] = self.obj
00162             #print "creating iSubcase result=%s" %(self.iSubcase)
00163         ###
00164         #return self.obj
00165 
00166     def readResultsTable(self,table3,table4Data,flag=0):
00167         self.dtMap = {}
00168         tableName = self.readTableName(rewind=False) # OEF
00169         self.tableInit(tableName)
00170         #print "tableName = |%r|" %(tableName)
00171 
00172         self.readMarkers([-1,7],tableName)
00173         ints = self.readIntBlock()
00174         #print "*ints = ",ints
00175 
00176         self.readMarkers([-2,1,0],tableName) # 7
00177         bufferWords = self.getMarker()
00178         #print "1-bufferWords = ",bufferWords,bufferWords*4
00179         ints = self.readIntBlock()
00180         #print "*ints = ",ints
00181         
00182         markerA = -4
00183         markerB = 0
00184 
00185         iTable=-3
00186         self.readMarkers([iTable,1,0],tableName)
00187 
00188         exitFast = False
00189         while [markerA,markerB]!=[0,2]:
00190             self.isBufferDone = False
00191             #print self.printSection(140)
00192             #print "reading iTable3=%s" %(iTable)
00193             #self.obj = None
00194 
00195             ## the results object
00196             self.obj = None
00197             ## dt/loadFactor/frequency/loadStep value (or None for static)
00198             self.nonlinearFactor = None
00199             self.dataCode = {}
00200 
00201             n = self.op2.tell()
00202             marker = self.getMarker()
00203             self.goto(n)
00204             if marker != 146:
00205                 self.log.debug("marker = %s" %(marker))
00206                 exitFast = True
00207                 break
00208 
00209             table3(iTable)
00210             self.dataCode['tableName'] = self.tableName
00211             ## developer parameter - Analysis/Table/Format/Sort Codes
00212             self.atfsCode = [self.analysisCode,self.tableCode,self.formatCode,self.sortCode]
00213             #print "self.tellA = ",self.op2.tell()
00214             
00215             ## ???
00216             self.isMarker = False
00217 
00218             isBlockDone = self.readTable4(table4Data,flag,iTable-1)
00219             #self.firstPass = False
00220 
00221             #print "self.tellB = ",self.op2.tell()
00222             iTable -= 2
00223             #print "isBlockDone = ",isBlockDone
00224             #sys.exit('stopping')
00225             if isBlockDone:
00226                 #print "iTable = ",iTable
00227                 #self.n = self.markerStart
00228                 #self.op2.seek(self.n)
00229                 break
00230             ###
00231             n = self.n
00232             #print self.printSection(100)
00233             self.readMarkers([iTable,1,0],tableName)
00234             #self.log.debug("")
00235             #print "i read the markers!!!"
00236    
00237         ###
00238         nOld = self.op2.tell()
00239         #try:
00240         if not(exitFast):
00241             #print self.printSection(100000)
00242             self.readMarkers([iTable,1,0],tableName)
00243             #self.getMarker()
00244             #self.getMarker()
00245             #self.getMarker()
00246         #except InvalidMarkersError:
00247         #    self.goto(nOld)
00248             #print self.printBlock(self.data)
00249             #print self.printSection(100)
00250             #markerZero = self.getMarker()
00251             #assert markerZero==0
00252             #self.goto(nOld)
00253             #print "finished markerZero"
00254             #return
00255             
00256         
00257         #print str(self.obj)
00258         if self.makeOp2Debug:
00259             self.op2Debug.write("***end of %s table***\n" %(tableName))
00260         del self.dtMap
00261 
00262     def readTable4(self,table4Data,flag,iTable):
00263         """loops over repeated table -4s"""
00264         #self.readMarkers([iTable,1,0])
00265         markerA = 4
00266         
00267         while markerA is not None:
00268             self.markerStart = copy.deepcopy(self.n)
00269             #self.printSection(180)
00270             self.readMarkers([iTable, 1, 0])
00271             #print "starting OEF table 4..."
00272             if flag:
00273                 isTable4Done,isBlockDone = table4Data(iTable)
00274             else:
00275                 isTable4Done,isBlockDone = self.readTable4DataSetup(table4Data,iTable)
00276             if isTable4Done:
00277                 #print "done with OEF4"
00278                 self.n = self.markerStart
00279                 self.op2.seek(self.n)
00280                 break
00281             #print "finished reading oef table..."
00282             markerA = self.getMarker('A')
00283             self.n -= 12
00284             self.op2.seek(self.n)
00285             
00286             self.n = self.op2.tell()
00287             #print "***markerA = ",markerA
00288             
00289             iTable-=1
00290             #print "isBlockDone = ",isBlockDone
00291         ###    
00292         #print "isBlockDone = ",isBlockDone
00293         return isBlockDone
00294 
00295     def readTable4DataSetup(self,table4Data,iTable): # iTable=-4
00296         """checks to see if table 4 is done, loads the data, and handles skipping"""
00297         isTable4Done = False
00298         isBlockDone  = False
00299 
00300         bufferWords = self.getMarker(self.tableName)
00301         #print "bufferWords = ",bufferWords
00302         #print len(bufferWords)
00303         self.data = self.readBlock()
00304         #self.printBlock(data)
00305 
00306         if bufferWords == 146:  # table -4 is done, restarting table -3
00307             isTable4Done = True
00308             return isTable4Done,isBlockDone
00309         elif bufferWords == 0:
00310             #print "bufferWords 0 - done with Table4"
00311             isTable4Done = True
00312             isBlockDone = True
00313             return isTable4Done,isBlockDone
00314 
00315         isBlockDone = not(bufferWords)
00316 
00317         if self.isValidSubcase(): # lets the user skip a certain subcase
00318             table4Data()
00319         else:
00320             self.log.debug("***skipping table=%s iSubcase=%s" %(self.tableName,self.iSubcase))
00321             self.skipOES_Element()
00322         ###
00323         return (isTable4Done,isBlockDone)
00324 
00325     def updateDtMap(self):
00326         """
00327         Interfaces with setTransientTimes(times) to limit the amount
00328         of output that is in the transient results.  This allows
00329         for models with 1000s of time steps that would otherwise
00330         crash with memory errors to run.  Every result may be extracted
00331         if the OP2 is read multiple times.
00332         
00333         While not ideal, this function prevents having to drastically
00334         change the code to support large models, which would
00335         make the OP2 reader not as useful for reasonably sized models.
00336         
00337         The code works by taking the user-provided array of values
00338         for a given subcase and b/c it's an array can be subtracted
00339         from the current value of dt.  Then the minimum absolute value
00340         is found and that is mapped back to the original value.  If a
00341         closer value to the target user-specified value is found, the
00342         previous result will be deleted, which keeps memory usage down.
00343         The new result will then be read.  If a dt is not closer than
00344         an existing value to a given case, that case will not be read.
00345         """
00346         #numArray = array([1.,2.])
00347         iSubcase = self.iSubcase
00348         numArray = self.expectedTimes[iSubcase]
00349         #nums = [0.9,1.11,  1.89,2.1]
00350         num = self.obj.getTransients()[-1] # they're sorted so the last value is the current dt
00351 
00352         readCase = True
00353         delta = numArray-num
00354         absDelta = list(abs(delta))
00355         closest = min(absDelta)
00356         iclose = absDelta.index(closest)
00357         actualValue = numArray[iclose]
00358 
00359         if iSubcase not in self.dtMap:
00360             self.dtMap[iSubcase] = {}
00361         if iclose in self.dtMap[iSubcase]:
00362             v1 = self.dtMap[iSubcase][iclose]
00363             vact = get_close_num(v1,num,actualValue)
00364 
00365             if vact!=self.dtMap[iSubcase][iclose]:
00366                 del self.dtMap[iSubcase][iclose]
00367                 self.obj.deleteTransient(v1)
00368                 #print "num=%s closest=%s iclose=%s" %(num,actualValue,iclose)
00369                 #print "***deleted v1=%s num=%s vact=%s actual=%s" %(v1,num,vact,actualValue)
00370                 self.dtMap[iSubcase][iclose] = vact
00371                 readCase = True
00372                 #print self.dtMap
00373                 #print "A"
00374             else: # cleanup previous creation of empty dt case (happened in updateDt outside this function)
00375                 readCase = False
00376                 #print self.dtMap
00377                 #print "num=%s closest=%s iclose=%s" %(num,actualValue,iclose)
00378                 #print "B"
00379                 self.obj.deleteTransient(num)
00380             ###
00381         else: # read case
00382             self.dtMap[iSubcase][iclose] = num
00383             readCase = True
00384             #print "num=%s closest=%s iclose=%s" %(num,actualValue,iclose)
00385             #print self.dtMap
00386             #print "C"
00387         ###
00388         #print "delta = ",delta,'\n'
00389         #print "readCase = ",readCase
00390         #if num>=0.14:
00391             #print self.obj.getTransients()
00392             #sys.exit('OUG !!!')
00393             
00394         return readCase
00395 
00396     def handleResultsBufferShort(self,func,debug=False):
00397         raise RuntimeError('this function has been removed...')
00398         nOld = self.n
00399         markers = self.readHeader()
00400 
00401         if markers < 0:  # not a buffer, the table may be done
00402             self.goto(nOld)
00403             if markers is not None and markers%2==1:
00404                 self.isBufferDone = True
00405         else:
00406             data = self.readBlock()
00407             self.data += data
00408             func()
00409         ###
00410 
00411     def handleResultsBufferNoRecursion(self,f,debug=False):
00412         """prototype method for getting results without recursion"""
00413         raise RuntimeError('this function has been removed...')
00414         stopBuffer = False
00415         while not(stopBuffer):
00416             f()
00417             nOld = self.n
00418             markers = self.readHeader()
00419 
00420             if markers < 0:  # not a buffer, the table may be done
00421                 self.goto(nOld)
00422                 if markers is not None and markers%2==1:
00423                     self.isBufferDone = True
00424             else:
00425                 data = self.readBlock()
00426                 self.data += data
00427                 stopBuffer = True
00428             ###
00429         ###
00430 
00431     def NotImplementedOrSkip(self,msg=''):
00432         """stops if code is in development and continues otherwise"""
00433         if False:
00434             raise NotImplementedError(msg)
00435         else:
00436             self.log.info("skipping...")
00437             self.log.info("\n"+self.codeInformation())
00438             self.skipOES_Element()
00439 
00440     def handleResultsBuffer3(self, f, resultName, debug=False):
00441         """method for getting results without recursion"""
00442         #if resultName not in self.allowedResultNames:
00443         #    return self.self.skipOES_Element()
00444 
00445         #stopBuffer = False
00446         i = 0
00447         #print self.codeInformation()
00448         while not(self.isBufferDone):
00449             #print "n=%s len(data)=%s" %(self.n,len(self.data))
00450             #sys.stdout.flush()
00451             f()
00452             nOld = self.n
00453             markers = self.readHeader()
00454             #print "nOld=%s markers=%s" %(nOld,markers)
00455 
00456             if markers<0:  # not a buffer, the table may be done
00457                 self.goto(nOld)
00458                 #print "markers%%2 = %s" %(markers%2)
00459                 if markers is not None and markers%2 == 1:
00460                     self.isBufferDone = True
00461             else:
00462                 data = self.readBlock()
00463                 if type(data) != type(self.data):
00464                     msg = 'The function f=%s has a str error\n'%(f.__name__)
00465                     msg += ("type(self.data)=%s type(data)=%s"
00466                           % (type(self.data), type(data)))
00467                 sys.stdout.flush()
00468                 self.data += data
00469             ###
00470             i += 1
00471             if i == 2000:
00472                 raise RuntimeError('Infinite Loop or a really big model...')
00473             #print "isBufferDone=%s" %(self.isBufferDone)
00474         ###
00475         #print "---------------------------------"
00476 
00477     def handleResultsBuffer(self, func, debug=False):
00478         """
00479         Works by knowing that:
00480         the end of an unbuffered table has a
00481           - [4]
00482         the end of an table with a buffer has a
00483           - [4,4,x,4] where x is the next buffer size, which may have another
00484             buffer
00485         the end of the final buffer block has
00486           - nothing!
00487 
00488         @param self
00489           the object pointer
00490         @param func
00491           the function to recursively call (the function that called this)
00492         @param debug
00493           developer debug
00494 
00495         @note
00496           The code knows that the large buffer is the default size and the
00497           only way there will be a smaller buffer is if there are no more
00498           buffers.  So, the op2 is shifted by 1 word (4 bytes) to account for
00499           this end shift.  An extra marker value is read, but no big deal.
00500           Beyond that it's just appending some data to the binary string and
00501           calling the function that's passed in
00502         @note
00503           this will soon be replaced by handleResultsBuffer3 (and then
00504           renamed to handleResultsBuffer after this is removed)
00505 
00506         @warning
00507           Dont modify this without LOTS of testing.
00508           It's a VERY important function
00509         """
00510         raise RuntimeError('this function has been removed...')
00511         #print self.obj
00512         #print "len(data) = ",len(self.data)
00513         #if marker[0]==4:
00514         #    self.log.debug("found a 4 - end of unbuffered table")
00515 
00516         #if debug:
00517         #    self.log.debug(self.printSection(120))
00518         
00519         nOld = self.n
00520         #try:
00521         markers = self.readHeader()
00522         #except AssertionError:  # end of table - poor catch
00523         #    self.goto(nOld)
00524         #   self.log.debug(self.printSection(120))
00525         #    return
00526 
00527         #print "markers = ",markers
00528         #print self.printSection(160)
00529         
00530         if markers < 0:  # not a buffer, the table may be done
00531             self.goto(nOld)
00532             if markers is not None and markers%2 == 1:
00533                 self.isBufferDone = True
00534 
00535             #print self.printSection(120)
00536             #sys.exit('found a marker')
00537             #print 'found a marker'
00538 
00539         else:
00540             #print "*******len(self.data)=%s...assuming a buffer block" %(len(self.data))
00541             #markers = self.readHeader()
00542             #print "markers = ",markers
00543             data = self.readBlock()
00544             #if len(data)<marker:
00545             #    self.goto(self.n-4) # handles last buffer not having an extra 4
00546             self.data += data
00547             func()
00548         ###
00549 
00550     def readMappedScalarsOut(self, debug=False):
00551         raise RuntimeError('this function must be modified...')
00552         readCase = True
00553         #print "isSort1() = ",self.isSort1()
00554         if self.iSubcase in self.expectedTimes and len(self.expectedTimes[self.iSubcase])>0:
00555             readCase = self.updateDtMap()
00556         
00557         if self.obj and readCase and self.isSort1():
00558             self.readScalarsOut(debug=False)
00559         else:
00560             self.skipOES_Element()
00561         ###
00562 
00563     def readScalarsOut(self, debug=False):
00564         """
00565         reads len(strFormat) values and puts it into the result object
00566         the "o" in readScalars4o means "out" b/c it creates an out tuple
00567         instead of 4 values like readScalars4
00568         @note
00569             nTotal is the number of bytes
00570             strFormat = 'iiii'
00571         """
00572         raise RuntimeError('this function has been removed...')
00573         data = self.data
00574         #print type(self.obj)
00575         (nTotal,iFormat) = self.obj.getLength()
00576         iFormat = bytes(iFormat)
00577         n = 0
00578         #print  "strFormat = ",strFormat
00579         nEntries = len(data)//nTotal
00580         for i in xrange(nEntries):
00581             eData = data[n:n+nTotal]
00582             out  = unpack(iFormat,eData)
00583             if debug:
00584                 self.log.debug("*out = %s" % (out))
00585             self.obj.add(out)
00586             n+=nTotal
00587         ###
00588         self.data = data[n:]
00589         #print self.printSection(200)
00590         self.handleResultsBuffer(self.readScalarsOut, debug=False)
00591 
00592 def get_close_num(v1, v2, closePoint):
00593     numList = [v1, v2]
00594     delta = array([v1, v2])-closePoint
00595     #print "**delta=%s" %(delta)
00596     absDelta = list(abs(delta))
00597     closest = min(absDelta)
00598     iclose = absDelta.index(closest)
00599     actualValue = numList[iclose]
00600     return actualValue
00601 
00602     
 All Classes Namespaces Files Functions Variables