pyNastran  0.5.0
pyNastran BDF Reader/Writer, OP2 Parser, and GUI
baseCard.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
00026 
00027 from __future__ import division, print_function
00028 import sys
00029 from itertools import izip
00030 
00031 from pyNastran.bdf.fieldWriter import (printCard, set_default_if_blank,
00032                                        is_same)
00033 from pyNastran.bdf.bdfInterface.BDF_Card import BDFCard
00034 
00035 class BaseCard(BDFCard):
00036     #def __init__(self,card):
00037     #    pass
00038 
00039     def writeCodeAster(self):
00040         return '# skipping %s  because writeCodeAster is not implemented\n' %(self.type)
00041 
00042     def writeCodeAsterLoad(self, model, gridWord='node'):
00043         return '# skipping %s (lid=%s) because writeCodeAsterLoad is not implemented\n' %(self.type, self.lid)
00044 
00045     def verify(self, model, iSubcase):
00046         """
00047         this method checks performs checks on the cards such as
00048         that the PBEAML has a proper material type
00049         """
00050         pass
00051 
00052     def isSameFields(self, fields1, fields2):
00053         for (field1, field2) in izip(fields1, fields2):
00054             if not is_same(field1, field2):
00055                 return False
00056             ###
00057         ###
00058         return True
00059 
00060     def Is(self, typeCheck):
00061         """retruns True if the card type is the same as the object"""
00062         if self.type==typeCheck:
00063             return True
00064         return False
00065 
00066     def removeTrailingNones(self, fields):
00067         """removes blank fields at the end of a card object"""
00068         self._wipeEmptyFields(fields)
00069 
00070     def printCard(self, fields, tol=0.):
00071         """prints a card object"""
00072         #print "fields = ",fields
00073         return printCard(fields, tol)
00074 
00075     def crossReference(self, model):
00076         #self.mid = model.Material(self.mid)
00077         msg = "%s needs to implement the 'crossReference' method" %(self.type)
00078         raise NotImplementedError(msg)
00079 
00080     def buildTableLines(self, fields, nStart=1, nEnd=0):
00081         """
00082         builds a table of the form:
00083         'DESVAR' DVID1 DVID2 DVID3 DVID4 DVID5 DVID6 DVID7
00084                  DVID8 -etc.-
00085         'UM'     VAL1  VAL2  -etc.-
00086         and then pads the rest of the fields with None's
00087         @param fields the fields to enter, including DESVAR
00088         @param nStart the number of blank fields at the start of the line (default=1)
00089         @param nEnd the number of blank fields at the end of the line (default=0)
00090         
00091         @note will be used for DVPREL2, RBE1, RBE3
00092         @warning only works for small field format???
00093         """
00094         fieldsOut = []
00095         n = 8-nStart-nEnd
00096 
00097         # pack all the fields into a list.  Only consider an entry as isolated
00098         for (i,field) in enumerate(fields):
00099             fieldsOut.append(field)
00100             if i>0 and i%n==0: # beginning of line
00101                 #print "i=%s" %(i)
00102                 #pad = [None]*(i+j)
00103                 #fieldsOut += pad
00104                 fieldsOut += [None]*(nStart+nEnd)
00105             ###
00106         ###
00107         # make sure they're aren't any trailing None's (from a new line)
00108         fieldsOut = self._wipeEmptyFields(fieldsOut)
00109         #print "fieldsOut = ",fieldsOut,len(fieldsOut)
00110 
00111         # push the next key (aka next fields[0]) onto the next line
00112         nSpaces = 8-(len(fieldsOut))%8  # puts UM onto next line
00113         #print "nSpaces[%s] = %s max=%s" %(fields[0],nSpaces,nSpaceMax)
00114         if nSpaces<8:
00115             fieldsOut += [None]*(nSpaces)
00116         #print ""
00117         return fieldsOut
00118 
00119     def isSameCard(self, card, debug=False):
00120         fields1 = self.rawFields()
00121         fields2 = card.rawFields()
00122         if debug:
00123             print("fields1=%s fields2=%s" %(fields1, fields2))
00124         return self.isSameFields(fields1, fields2)
00125 
00126     def printRawFields(self):
00127         """A card's raw fields include all defaults for all fields"""
00128         fields = self.rawFields()
00129         return self.printCard(fields)
00130         
00131     def reprFields(self):
00132         return self.rawFields()
00133 
00134     def __repr__(self):  # ,tol=1e-8
00135         """
00136         Prints a card in the simplest way possible
00137         (default values are left blank).
00138         """
00139         #print "tol = ",tol
00140         fields = self.reprFields()
00141         try:
00142             return self.printCard(fields)
00143         except:
00144             print('problem printing %s card' %(self.type))
00145             print("fields = ",fields)
00146             raise
00147 
00148 def Mid(self):
00149     #print str(self)
00150     if isinstance(self.mid,int):
00151         return self.mid
00152     else:
00153         return self.mid.mid
00154     ###
00155 
00156 class Property(BaseCard):
00157     def __init__(self, card, data):
00158         assert card is None or data is None
00159         pass
00160 
00161     def Mid(self):
00162         return Mid(self)
00163 
00164     def isSameCard(self, prop, debug=False):
00165         if self.type!=prop.type:  return False
00166         fields1 = self.rawFields()
00167         fields2 = prop.rawFields()
00168         if debug:
00169             print("fields1=%s fields2=%s" %(fields1, fields2))
00170         return self.isSameFields(fields1, fields2)
00171 
00172     def crossReference(self, model):
00173         self.mid = model.Material(self.mid)
00174 
00175 class Material(BaseCard):
00176     """Base Material Class"""
00177     def __init__(self, card, data):
00178         pass
00179         #self.type = card[0]
00180 
00181     def isSameCard(self, mat, debug=False):
00182         if self.type!=mat.type:  return False
00183         fields1 = self.rawFields()
00184         fields2 = mat.rawFields()
00185         if debug:
00186             print("fields1=%s fields2=%s" %(fields1, fields2))
00187         return self.isSameFields(fields1, fields2)
00188 
00189     def crossReference(self, model):
00190         pass
00191 
00192     def Mid(self):
00193         return self.mid
00194 
00195 class Element(BaseCard):
00196     pid = 0 # CONM2, rigid
00197     def __init__(self, card, data):
00198         assert card is None or data is None
00199         ## the list of node IDs for an element (default=None)
00200         self.nodes = None
00201         #self.nids = []
00202         pass
00203 
00204     def isSameCard(self, element, debug=False):
00205         if self.type!=element.type:  return False
00206         fields1 = self.rawFields()
00207         fields2 = element.rawFields()
00208         if debug:
00209             print("fields1=%s fields2=%s" %(fields1, fields2))
00210         return self.isSameFields(fields1, fields2)
00211 
00212     def Pid(self):
00213         """returns the property ID of an element"""
00214         if isinstance(self.pid, int):
00215             return self.pid
00216         else:
00217             return self.pid.pid
00218         ###
00219 
00220     def nodePositions(self, nodes=None):
00221         """returns the positions of multiple node objects"""
00222         if not nodes:
00223            nodes = self.nodes
00224         return [node.Position() for node in nodes]
00225 
00226     def nodeIDs(self,nodes=None, allowEmptyNodes=False, msg=''):
00227         """returns nodeIDs for repr functions"""
00228         try:
00229             if not nodes:
00230                nodes = self.nodes
00231 
00232             if allowEmptyNodes:
00233                 nodes2 = []
00234                 for i,node in enumerate(nodes):
00235                     if node==0 or node is None:
00236                         nodes2.append(None)
00237                     elif isinstance(node, int):
00238                         nodes2.append(node)
00239                     else:
00240                         nodes2.append(node.nid)
00241                 return nodes2
00242             else:
00243                 if isinstance(nodes[0], int):
00244                     nodeIDs = [node     for node in nodes]
00245                 else:
00246                     nodeIDs = [node.nid for node in nodes]
00247                 ###
00248                 assert 0 not in nodeIDs, 'nodeIDs = %s' %(nodeIDs)
00249                 return nodeIDs
00250         except:
00251             print("nodes=%s allowEmptyNodes=%s\nmsg=%s" %(nodes, allowEmptyNodes, msg))
00252             raise
00253 
00254     def prepareNodeIDs(self, nids, allowEmptyNodes=False):
00255         """verifies all node IDs exist and that they're integers"""
00256         self.nodes = []
00257         for nid in nids:
00258             if isinstance(nid, int):
00259                 self.nodes.append(int(nid))
00260             elif nid==None and allowEmptyNodes:
00261                 self.nodes.append(nid)
00262             else: # string???
00263                 self.nodes.append(int(nid))
00264                 #raise RuntimeError('this element may not have missing nodes...nids=%s allowEmptyNodes=False' %(nids))
00265             ###
00266 
00267     #def Normal(self,a,b):
00268     #    """finds the unit normal vector of 2 vectors"""
00269     #    return Normal(a,b)
00270 
00271     def CentroidTriangle(self, n1, n2, n3, debug=False):
00272         if debug:
00273             print("n1=%s \nn2=%s \nn3=%s" %(n1, n2, n3))
00274         centroid = (n1+n2+n3)/3.
00275         return centroid
00276 
00277     def Centroid(self):
00278         msg = 'Centroid not implemented in the %s class' %(self.__class__.__name__)
00279         raise NotImplementedError(msg)
00280     def Length(self):
00281         msg = 'Length not implemented in the %s class' %(self.__class__.__name__)
00282         raise NotImplementedError(msg)
00283     def Area(self):
00284         msg = 'Area not implemented in the %s class' %(self.__class__.__name__)
00285         raise NotImplementedError(msg)
00286     def Volume(self):
00287         msg = 'Volume not implemented in the %s class' %(self.__class__.__name__)
00288         raise NotImplementedError(msg)
00289     def Mass(self):
00290         msg = 'Mass not implemented in the %s class' %(self.__class__.__name__)
00291         raise NotImplementedError(msg)
00292 
00293     def B(self):
00294         msg = 'B matrix not implemented in the %s class' %(self.__class__.__name__)
00295         raise NotImplementedError(msg)
00296     def D(self):
00297         msg = 'D matrix not implemented in the %s class' %(self.__class__.__name__)
00298         raise NotImplementedError(msg)
00299     def Jacobian(self):
00300         msg = 'Jacobian not implemented for %s' %(self.self.__class__.__name__)
00301         raise NotImplementedError(msg)
00302 
00303     def stiffnessMatrix(self):
00304         msg = 'stiffnessMatrix not implemented in the %s class' %(self.__class__.__name__)
00305         raise NotImplementedError(msg)
00306     def massMatrix(self):
00307         msg = 'massMatrix not implemented in the %s class' %(self.__class__.__name__)
00308         raise NotImplementedError(msg)
00309 
00310 
00311 def expandThru(fields):
00312     """
00313     expands a list of values of the form [1,5,THRU,9,13]
00314     to be [1,5,6,7,8,9,13]
00315     """
00316     if len(fields) == 1:
00317         return fields
00318     #print("expandThru")
00319     #print("fields = ", fields)
00320     out = []
00321     nFields = len(fields)
00322     i=0
00323     while(i<nFields):
00324         if fields[i] == 'THRU':
00325             for j in xrange(fields[i-1], fields[i+1]+1):
00326                 out.append(j)
00327             ###
00328             i+=2
00329         else:
00330             out.append(fields[i])
00331             i+=1
00332         ###
00333     ###
00334     #print "out = ",out,'\n'
00335     return list(set(out))
00336     
00337 def expandThruBy(fields):
00338     """
00339     expands a list of values of the form [1,5,THRU,9,BY,2,13]
00340     to be [1,5,7,9,13]
00341     @todo not tested
00342     @note used for QBDY3, ???
00343     """
00344     if len(fields) == 1:
00345         return fields
00346     #print "expandThruBy"
00347     #print "fields = ",fields
00348     out = []
00349     nFields = len(fields)
00350     i=0
00351     by = 1
00352     while(i<nFields):
00353         if fields[i] == 'THRU':
00354             by = 1
00355             if i+2<nFields and fields[i+2] == 'BY':
00356                 by = fields[i+3]
00357                 #sys.stderr.write("BY was found...untested...")
00358                 #raise NotImplementedError('implement BY support\nfields=%s' %(fields))
00359             else:
00360                 by = 1
00361             minValue = fields[i-1]
00362             maxValue = fields[i+1]
00363             #print "minValue=%s maxValue=%s by=%s" %(minValue,maxValue,by)
00364             for j in xrange(0,(maxValue-minValue)//by+1): # +1 is to include final point
00365                 value = minValue+by*j
00366                 out.append(value)
00367             ###
00368             if by==1: # null/standard case
00369                 i+=2
00370             else:     # BY case
00371                 i+=3
00372             ###
00373         else:
00374             out.append(fields[i])
00375             i+=1
00376         ###
00377     ###
00378     #out = list(set(out))
00379     #out.sort()
00380     #print "out = ",out,'\n'
00381     return list(set(out))
00382 
00383 def expandThruExclude(self, fields):
00384     """
00385     expands a list of values of the form [1,5,THRU,11,EXCEPT,7,8,13]
00386     to be [1,5,6,9,10,11,13]
00387     @todo not tested
00388     """
00389     fieldsOut = []
00390     nFields = len(fields)
00391     for i in xrange(nFields):
00392         if fields[i] == 'THRU':
00393             storedList = []
00394             for j in xrange(fields[i-1], fields[i+1]):
00395                 storedList.append(fields[j])
00396             ###
00397         elif fields[i] == 'EXCLUDE':
00398             storedSet = set(storedList)
00399             while fields[i] < max(storedList):
00400                 storedSet.remove(fields[i])
00401             storedList = list(storedSet)
00402         else:
00403             if storedList:
00404                 fieldsOut += storedList
00405             fieldsOut.append(fields[i])
00406         ###
00407     ###
00408 
00409 def collapseThru(fields):
00410     return fields
00411 
00412 def collapseThruBy(fields):
00413     return fields
00414 
00415 def _collapseThru(fields):
00416     """
00417     1,THRU,10
00418     1,3,THRU,19,15
00419     @warning doesnt work
00420     """
00421     fields = list(set(fields))
00422     
00423     #assumes sorted...
00424 
00425     dnMax = 1
00426     (pre, i) = _preCollapse(fields, dnMax=dnMax)
00427     mid = _midCollapse(pre, dnMax=dnMax)
00428     #out = self._postCollapse(mid)
00429 
00430     out = []
00431     print("running post...")
00432     for data in mid:
00433         print("data = %s" %(data))
00434         nData = len(data)
00435         if nData == 1:
00436             out.append(data[0]) # 1 field only
00437         else:
00438             assert data[2] == 1 # dn
00439             out += [data[0], 'THRU', data[1]]
00440         ###
00441     ###
00442     print("dataOut = ",out)
00443     return out
00444 
00445 def _midCollapse(preCollapse, dnMax=10000000):
00446     """
00447     input is lists of [[1,3,5,7],2]  dn=2
00448     dNmax = 2
00449     output is [1,7,2]
00450     """
00451     out = []
00452     print(preCollapse)
00453     for collapse in preCollapse:
00454         print("collapse = ", collapse)
00455         (data,dn) = collapse
00456         print("data = ",data)
00457         print("dn = ",dn)
00458         if len(data)>1:
00459             if dn<=dnMax: # 1:11:2 - patran syntax
00460                 fields = [data[0], data[-1], dn]
00461                 out.append(fields)
00462             ###
00463             else: # bigger than dn
00464                 for field in data:
00465                     out.append(field)
00466                 ###
00467             ###
00468         else: # 1 item
00469             out.append([data[0]])
00470         ###
00471     return out
00472 
00473 def _preCollapse(fields, dnMax=10000000): # assumes sorted
00474     out = []
00475     nFields = len(fields)-1
00476     i=0
00477     while(i<nFields):
00478         dn = fields[i+1]-fields[i]
00479         print("preFields = %s" %(fields[i:]))
00480         (outFields,j) = _subCollapse(fields[i:], dn, dnMax)
00481         print("outFields = %s" %(outFields))
00482         out.append([outFields, dn])
00483         i+=j
00484         ###
00485         #if i==nFields+1:
00486         #    out.append([[fields[i-1]],1])
00487         #    print("lastOut = ",out[-1])
00488         ###
00489     ###
00490     
00491     print("i=%s out=%s" %(i,out))
00492     print("--end of preCollapse")
00493     return (out, i)
00494 
00495 def _subCollapse(fields, dn, dnMax=10000000):
00496     """
00497     in  = [1,2,3,  7]
00498     out = [1,2,3]
00499     """
00500     # dn=1
00501     print("subIn = %s" %(fields))
00502     out = [fields[0]]
00503     nFields = len(fields)
00504 
00505     for i in xrange(1, nFields):
00506         dn = fields[i]-fields[i-1]
00507         print("i=%s field[%s]=%s fields[%s]=%s dn=%s dnMax=%s" % (i, i, fields[i], i-1, fields[i-1], dn, dnMax))
00508         if dn != dnMax:
00509             #i += 1
00510             #out.append(fields[i])
00511             break
00512         out.append(fields[i])
00513     #i -= 1
00514     print("subOut = %s" %(out))
00515     #i += 1
00516     print("iSubEnd = %s\n" %(i))
00517     return (out,i)
00518 ###
00519         
00520 
00521 #dnMax = 2
00522 if __name__=='__main__':
00523     card = BaseCard()
00524 
00525     """
00526     1,THRU,10
00527     1,3,THRU,19,15
00528     """
00529     card.collapseThru([1,2,3,4,5,10])
00530     card.collapseThru([1,3,4,5,6,17])
00531 
 All Classes Namespaces Files Functions Variables