pyNastran
0.5.0
pyNastran BDF Reader/Writer, OP2 Parser, and GUI
|
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=C0103,C0111,W0612,R0912,R0914,R0904,W0613,E1101 00026 00027 from __future__ import division, print_function 00028 00029 from pyNastran.bdf.fieldWriter import printCard 00030 00031 class WriteMesh(object): 00032 def __init__(self): 00033 pass 00034 00035 def echoBDF(self, infileName): 00036 """ 00037 This method removes all comment lines from the bdf 00038 A write method is stil required. 00039 @todo maybe add the write method 00040 """ 00041 self.cardsToRead = set([]) 00042 return self.readBDF(infileName) 00043 00044 def autoRejectBDF(self, infileName): 00045 """ 00046 This method parses supported cards, but does not group them into 00047 nodes, elements, properties, etc. 00048 @todo maybe add the write method 00049 """ 00050 self.autoReject = True 00051 return self.readBDF(infileName) 00052 00053 def write_elements_as_CTRIA3(self): 00054 """ 00055 takes the cquad4 elements and splits them 00056 @retval msg string representation of the elements 00057 """ 00058 eids = self.elementIDs() 00059 #print "eids = ",eids 00060 nextEID = max(eids)+1 # set the new ID 00061 msg = '$ELEMENTS\n' 00062 for eid, element in sorted(self.elements.iteritems()): 00063 if element.Is('CQUAD4'): 00064 msg += element.writeAsCTRIA3(nextEID) 00065 nextEID += 1 00066 else: 00067 msg += str(element) 00068 ### 00069 ### 00070 return msg 00071 00072 def write_DMIGs(self): 00073 msg = '' 00074 for (name, dmig) in sorted(self.dmigs.iteritems()): 00075 msg += str(dmig) 00076 for (name, dmi) in sorted(self.dmis.iteritems()): 00077 msg += str(dmi) 00078 for (name, dmij) in sorted(self.dmijs.iteritems()): 00079 msg += str(dmij) 00080 for (name, dmiji) in sorted(self.dmijis.iteritems()): 00081 msg += str(dmiji) 00082 for (name, dmik) in sorted(self.dmiks.iteritems()): 00083 msg += str(dmik) 00084 return msg 00085 00086 def write_common(self): 00087 """ 00088 method to write the common outputs so none get missed... 00089 @param self the object pointer 00090 @retval msg part of the bdf 00091 """ 00092 msg = '' 00093 msg += self.write_rigid_elements() 00094 msg += self.write_DMIGs() 00095 msg += self.write_loads() 00096 msg += self.write_dynamic() 00097 msg += self.write_aero() 00098 msg += self.write_aero_control() 00099 msg += self.write_flutter() 00100 msg += self.write_thermal() 00101 msg += self.write_thermal_materials() 00102 00103 msg += self.write_constraints() 00104 msg += self.write_optimization() 00105 msg += self.write_tables() 00106 msg += self.write_sets() 00107 msg += self.write_rejects() 00108 msg += self.write_coords() 00109 return msg 00110 00111 def writeBDFAsPatran(self, outFileName='fem.out.bdf', debug=False): 00112 """ 00113 Writes a bdf with properties & elements interspersed like how 00114 Patran writes the bdf. This takes longer than the write method 00115 but makes it easier to compare to a Patran-formatted bdf. 00116 @param self the object pointer 00117 @param outFileName the name to call the output bdf 00118 @param debug developer debug (unused) 00119 """ 00120 msg = self.write_header() 00121 msg += self.write_params() 00122 msg += self.write_nodes() 00123 00124 msg += self.write_elements_properties() 00125 msg += self.write_materials() 00126 00127 msg += self.write_common() 00128 msg += 'ENDDATA\n' 00129 00130 fname = self.print_filename(outFileName) 00131 self.log.debug("***writing %s" %(fname)) 00132 00133 outfile = open(outFileName,'wb') 00134 outfile.write(msg) 00135 outfile.close() 00136 00137 def writeBDF(self, outFileName='fem.out.bdf', debug=False): 00138 """ 00139 Writes the bdf. It groups the various sections together to make it 00140 easy to find cards. This method is slightly more stable than 00141 writeAsPatran due to the properties sometimes being a little funny. 00142 @param self the object pointer 00143 @param outFileName the name to call the output bdf 00144 @param debug developer debug (unused) 00145 """ 00146 msg = self.write_header() 00147 msg += self.write_params() 00148 msg += self.write_nodes() 00149 00150 msg += self.write_elements() 00151 msg += self.write_properties() 00152 msg += self.write_materials() 00153 00154 msg += self.write_common() 00155 msg += 'ENDDATA\n' 00156 00157 fname = self.print_filename(outFileName) 00158 self.log.debug("***writing %s" %(fname)) 00159 00160 outfile = open(outFileName, 'wb') 00161 outfile.write(msg) 00162 outfile.close() 00163 00164 def write_as_CTRIA3(self, outFileName='fem.out.bdf', debug=False): 00165 """ 00166 Writes a series of CQUAD4s as CTRIA3s. All other cards are echoed. 00167 @param self the object pointer 00168 @param outFileName the name to call the output bdf 00169 @param debug developer debug (unused) 00170 @warning not tested in a long time 00171 """ 00172 msg = self.write_header() 00173 msg += self.write_params() 00174 msg += self.write_nodes() 00175 msg += self.write_elements_as_CTRIA3() 00176 msg += self.write_properties() 00177 msg += self.write_materials() 00178 00179 msg += self.write_common() 00180 msg += 'ENDDATA\n' 00181 00182 fname = self.print_filename(outFileName) 00183 self.log.debug("***writing %s" % (fname)) 00184 00185 outfile = open(outFileName, 'wb') 00186 outfile.write(msg) 00187 outfile.close() 00188 00189 def write_header(self): 00190 """ 00191 Writes the executive and case control decks. 00192 @param self the object pointer 00193 """ 00194 msg = self.write_executive_control_deck() 00195 msg += self.write_case_control_deck() 00196 return msg 00197 00198 def write_executive_control_deck(self): 00199 """ 00200 Writes the executive control deck. 00201 @param self the object pointer 00202 """ 00203 msg = '$EXECUTIVE CONTROL DECK\n' 00204 00205 if self.sol == 600: 00206 newSol = 'SOL 600,%s' % (self.solMethod) 00207 else: 00208 newSol = 'SOL %s' % (self.sol) 00209 00210 if self.iSolLine is not None: 00211 self.executive_control_lines[self.iSolLine] = newSol 00212 00213 for line in self.executive_control_lines: 00214 msg += line+'\n' 00215 return msg 00216 00217 def write_case_control_deck(self): 00218 """ 00219 Writes the Case Control Deck. 00220 @param self the object pointer 00221 """ 00222 msg = '' 00223 if self.caseControlDeck: 00224 msg += '$CASE CONTROL DECK\n' 00225 msg += str(self.caseControlDeck) 00226 assert 'BEGIN BULK' in msg, msg 00227 00228 return msg 00229 00230 def write_params(self): 00231 """writes the PARAM cards""" 00232 msg = '' 00233 if self.params: 00234 msg += '$PARAMS\n' 00235 #print "self.nodes = ",self.nodes 00236 for (key, param) in sorted(self.params.iteritems()): 00237 #print "param = ",param 00238 msg += str(param) 00239 return msg 00240 00241 def write_nodes(self): 00242 """writes the NODE-type cards""" 00243 msg = [] 00244 if self.nodes: 00245 msg = ['$NODES\n'] 00246 if self.gridSet: 00247 msg.append(str(self.gridSet)) 00248 for (nid, node) in sorted(self.nodes.iteritems()): 00249 msg.append(str(node)) 00250 00251 if 0: 00252 self.write_nodes_associated() 00253 00254 if self.spoints: 00255 msg.append('$SPOINTS\n') 00256 msg.append(str(self.spoints)) 00257 ### 00258 return ''.join(msg) 00259 00260 def write_nodes_associated(self): 00261 """ 00262 Writes the NODE-type in associated and unassociated groups. 00263 @warning Sometimes crashes, probably on invalid BDFs. 00264 """ 00265 msg = '' 00266 00267 associatedNodes = set([]) 00268 for (eid, element) in self.elements.iteritems(): 00269 print(element) 00270 associatedNodes = associatedNodes.union(set(element.nodeIDs())) 00271 00272 allNodes = set(self.nodes.keys()) 00273 unassociatedNodes = list(allNodes.difference(associatedNodes)) 00274 #missingNodes = allNodes.difference( 00275 associatedNodes = list(associatedNodes) 00276 00277 00278 if associatedNodes: 00279 msg += '$ASSOCIATED NODES\n' 00280 if self.gridSet: 00281 msg += str(self.gridSet) 00282 for key in sorted(associatedNodes): 00283 msg += str(self.nodes[key]) 00284 00285 if unassociatedNodes: 00286 msg += '$UNASSOCIATED NODES\n' 00287 if self.gridSet and not associatedNodes: 00288 msg += str(self.gridSet) 00289 for key in sorted(unassociatedNodes): 00290 if key in self.nodes: 00291 msg += str(self.nodes[key]) 00292 else: 00293 msg += '$ Missing NodeID=%s' % (key) 00294 return msg 00295 00296 def write_elements(self): 00297 """writes the elements in a sorted order""" 00298 msg = [] 00299 if self.elements: 00300 msg = ['$ELEMENTS\n'] 00301 for (eid, element) in sorted(self.elements.iteritems()): 00302 try: 00303 msg.append(str(element)) 00304 except: 00305 print('failed printing element...' 00306 'type=%s eid=%s' %(element.type,eid)) 00307 raise 00308 ### 00309 return ''.join(msg) 00310 00311 def write_rigid_elements(self): 00312 """writes the rigid elements in a sorted order""" 00313 msg = [] 00314 if self.rigidElements: 00315 msg += '$RIGID ELEMENTS\n' 00316 for (eid, element) in sorted(self.rigidElements.iteritems()): 00317 try: 00318 msg.append(str(element)) 00319 except: 00320 print('failed printing element...' 00321 'type=%s eid=%s' %(element.type,eid)) 00322 raise 00323 ### 00324 return ''.join(msg) 00325 00326 def write_properties(self): 00327 """writes the properties in a sorted order""" 00328 msg = '' 00329 if self.properties: 00330 msg += '$PROPERTIES\n' 00331 for (pid, prop) in sorted(self.properties.iteritems()): 00332 msg += str(prop) 00333 return msg 00334 00335 def write_elements_properties(self): 00336 """writes the elements and properties in and interspersed order""" 00337 msg = [] 00338 missingProperties = [] 00339 if self.properties: 00340 msg = ['$ELEMENTS_WITH_PROPERTIES\n'] 00341 00342 eidsWritten = [] 00343 for (pid, prop) in sorted(self.properties.iteritems()): 00344 eids = self.getElementIDsWithPID(pid) 00345 00346 if eids: 00347 msg.append(str(prop)) 00348 eids.sort() 00349 for eid in eids: 00350 element = self.Element(eid) 00351 try: 00352 msg.append(str(element)) 00353 except: 00354 print('failed printing element...' 00355 'type=%s eid=%s' %(element.type,eid)) 00356 raise 00357 ### 00358 eidsWritten += eids 00359 else: 00360 missingProperties.append(str(prop)) 00361 ### 00362 ### 00363 00364 eidsMissing = set(self.elements.keys()).difference(set(eidsWritten)) 00365 if eidsMissing: 00366 msg.append('$ELEMENTS_WITH_NO_PROPERTIES ' 00367 '(PID=0 and unanalyzed properties)\n') 00368 for eid in sorted(eidsMissing): 00369 element = self.Element(eid) 00370 try: 00371 msg.append(str(element)) 00372 except: 00373 print('failed printing element...' 00374 'type=%s eid=%s' %(element.type, eid)) 00375 raise 00376 ### 00377 ### 00378 00379 if missingProperties: 00380 msg.append('$UNASSOCIATED_PROPERTIES\n') 00381 for missingProperty in missingProperties: 00382 msg.append(str(missingProperty)) 00383 return ''.join(msg) 00384 00385 def write_materials(self): 00386 """writes the materials in a sorted order""" 00387 msg = '' 00388 if self.materials: 00389 msg += '$MATERIALS\n' 00390 for (mid, material) in sorted(self.materials.iteritems()): 00391 msg += str(material) 00392 for (mid, material) in sorted(self.creepMaterials.iteritems()): 00393 msg += str(material) 00394 for (mid, material) in sorted(self.materialDeps.iteritems()): 00395 msg += str(material) 00396 return msg 00397 00398 def write_thermal_materials(self): 00399 """writes the thermal materials in a sorted order""" 00400 msg = '' 00401 if self.thermalMaterials: 00402 msg += '$THERMAL MATERIALS\n' 00403 for (mid, material) in sorted(self.thermalMaterials.iteritems()): 00404 msg += str(material) 00405 return msg 00406 00407 def write_constraints(self): 00408 """writes the constraint cards sorted by ID""" 00409 msg = '' 00410 if self.suports: 00411 msg += '$CONSTRAINTS\n' 00412 for suport in self.suports: 00413 msg += str(suport) 00414 ### 00415 00416 if self.spcs or self.spcadds: 00417 msg += '$SPCs\n' 00418 strSPC = str(self.spcObject2) 00419 if strSPC: 00420 msg += strSPC 00421 else: 00422 for (spcID, spcadd) in sorted(self.spcadds.iteritems()): 00423 msg += str(spcadd) 00424 for (spcID, spcs) in sorted(self.spcs.iteritems()): 00425 for spc in spcs: 00426 msg += str(spc) 00427 ### 00428 ### 00429 ### 00430 ### 00431 00432 if self.mpcs or self.mpcadds: 00433 msg += '$MPCs\n' 00434 strMPC = str(self.mpcObject2) 00435 if strMPC: 00436 msg += strMPC 00437 else: 00438 for (mpcID, mpcadd) in sorted(self.mpcadds.iteritems()): 00439 msg += str(mpcadd) 00440 for (mpcID, mpcs) in sorted(self.mpcs.iteritems()): 00441 for mpc in mpcs: 00442 msg += str(mpc) 00443 return msg 00444 00445 def write_loads(self): 00446 """writes the load cards sorted by ID""" 00447 msg = '' 00448 if self.loads: 00449 msg += '$LOADS\n' 00450 for (key, loadcase) in sorted(self.loads.iteritems()): 00451 for load in loadcase: 00452 try: 00453 msg += str(load) 00454 except: 00455 print('failed printing load...type=%s key=%s' 00456 %(load.type, key)) 00457 raise 00458 return msg 00459 00460 def write_optimization(self): 00461 """writes the optimization cards sorted by ID""" 00462 msg = '' 00463 if (self.dconstrs or self.desvars or self.ddvals or self.dresps 00464 or self.dvprels or self.dvmrels or self.doptprm or self.dlinks): 00465 msg += '$OPTIMIZATION\n' 00466 for (ID, dconstr) in sorted(self.dconstrs.iteritems()): 00467 msg += str(dconstr) 00468 for (ID, desvar) in sorted(self.desvars.iteritems()): 00469 msg += str(desvar) 00470 for (ID, ddval) in sorted(self.ddvals.iteritems()): 00471 msg += str(ddval) 00472 for (ID, dlink) in sorted(self.dlinks.iteritems()): 00473 msg += str(dlink) 00474 for (ID, dresp) in sorted(self.dresps.iteritems()): 00475 msg += str(dresp) 00476 for (ID, dvmrel) in sorted(self.dvmrels.iteritems()): 00477 msg += str(dvmrel) 00478 for (ID, dvprel) in sorted(self.dvprels.iteritems()): 00479 msg += str(dvprel) 00480 for (ID, equation) in sorted(self.dequations.iteritems()): 00481 msg += str(equation) 00482 if self.doptprm is not None: 00483 msg += str(self.doptprm) 00484 return msg 00485 00486 def write_tables(self): 00487 """writes the TABLEx cards sorted by ID""" 00488 msg = '' 00489 if self.tables: 00490 msg += '$TABLES\n' 00491 for (ID, table) in sorted(self.tables.iteritems()): 00492 msg += str(table) 00493 if self.randomTables: 00494 msg += '$RANDOM TABLES\n' 00495 for (ID, table) in sorted(self.randomTables.iteritems()): 00496 msg += str(table) 00497 return msg 00498 00499 def write_sets(self): 00500 """writes the SETx cards sorted by ID""" 00501 msg = '' 00502 if (self.sets or self.setsSuper or self.asets or self.bsets or 00503 self.csets or self.qsets): 00504 msg += '$SETS\n' 00505 for (ID, setObj) in sorted(self.sets.iteritems()): # dict 00506 msg += str(setObj) 00507 for setObj in self.asets: # list 00508 msg += str(setObj) 00509 for setObj in self.bsets: # list 00510 msg += str(setObj) 00511 for setObj in self.csets: # list 00512 msg += str(setObj) 00513 for setObj in self.qsets: # list 00514 msg += str(setObj) 00515 for (ID, setObj) in sorted(self.setsSuper.iteritems()): # dict 00516 msg += str(setObj) 00517 return msg 00518 00519 def write_dynamic(self): 00520 """writes the dynamic cards sorted by ID""" 00521 msg = '' 00522 if (self.dareas or self.nlparms or self.frequencies or self.methods or 00523 self.cMethods or self.tsteps or self.tstepnls): 00524 msg += '$DYNAMIC\n' 00525 for (ID, method) in sorted(self.methods.iteritems()): 00526 msg += str(method) 00527 for (ID, cMethod) in sorted(self.cMethods.iteritems()): 00528 msg += str(cMethod) 00529 for (ID, darea) in sorted(self.dareas.iteritems()): 00530 msg += str(darea) 00531 for (ID, nlparm) in sorted(self.nlparms.iteritems()): 00532 msg += str(nlparm) 00533 for (ID, tstep) in sorted(self.tsteps.iteritems()): 00534 msg += str(tstep) 00535 for (ID, tstepnl) in sorted(self.tstepnls.iteritems()): 00536 msg += str(tstepnl) 00537 for (ID, freq) in sorted(self.frequencies.iteritems()): 00538 msg += str(freq) 00539 return msg 00540 00541 def write_aero(self): 00542 """writes the aero cards""" 00543 msg = '' 00544 if (self.aero or self.aeros or self.gusts or self.caeros 00545 or self.paeros or self.trims): 00546 msg = '$AERO\n' 00547 for (ID, caero) in sorted(self.caeros.iteritems()): 00548 msg += str(caero) 00549 for (ID, paero) in sorted(self.paeros.iteritems()): 00550 msg += str(paero) 00551 for (ID, spline) in sorted(self.splines.iteritems()): 00552 msg += str(spline) 00553 for (ID, trim) in sorted(self.trims.iteritems()): 00554 msg += str(trim) 00555 00556 for (ID, aero) in sorted(self.aero.iteritems()): 00557 msg += str(aero) 00558 for (ID, aero) in sorted(self.aeros.iteritems()): 00559 msg += str(aero) 00560 00561 for (ID, gust) in sorted(self.gusts.iteritems()): 00562 msg += str(gust) 00563 return msg 00564 00565 def write_aero_control(self): 00566 """writes the aero control surface cards""" 00567 msg = '' 00568 if (self.aefacts or self.aeparams or self.aelinks or self.aelists or 00569 self.aestats or self.aesurfs): 00570 msg = '$AERO CONTROL SURFACES\n' 00571 for (ID, aelinks) in sorted(self.aelinks.iteritems()): 00572 for aelink in aelinks: 00573 msg += str(aelink) 00574 for (ID, aeparam) in sorted(self.aeparams.iteritems()): 00575 msg += str(aeparam) 00576 for (ID, aestat) in sorted(self.aestats.iteritems()): 00577 msg += str(aestat) 00578 00579 for (ID, aelist) in sorted(self.aelists.iteritems()): 00580 msg += str(aelist) 00581 for (ID, aesurf) in sorted(self.aesurfs.iteritems()): 00582 msg += str(aesurf) 00583 for (ID, aefact) in sorted(self.aefacts.iteritems()): 00584 msg += str(aefact) 00585 return msg 00586 00587 def write_flutter(self): 00588 """writes the flutter cards""" 00589 msg = [] 00590 if (self.flfacts or self.flutters or self.mkaeros): 00591 msg = ['$FLUTTER\n'] 00592 for (ID, flfact) in sorted(self.flfacts.iteritems()): 00593 #if ID!=0: 00594 msg.append(str(flfact)) 00595 for (ID, flutter) in sorted(self.flutters.iteritems()): 00596 msg.append(str(flutter)) 00597 for mkaero in self.mkaeros: 00598 msg.append(str(mkaero)) 00599 return ''.join(msg) 00600 00601 def write_thermal(self): 00602 """writes the thermal cards""" 00603 msg = '' 00604 # PHBDY 00605 00606 if self.phbdys or self.convectionProperties or self.bcs: 00607 # self.thermalProperties or 00608 msg = '$THERMAL\n' 00609 00610 for (key, phbdy) in sorted(self.phbdys.iteritems()): 00611 msg += str(phbdy) 00612 00613 #for key,prop in sorted(self.thermalProperties.iteritems()): 00614 # msg += str(prop) 00615 for (key, prop) in sorted(self.convectionProperties.iteritems()): 00616 msg += str(prop) 00617 00618 # BCs 00619 for (key, bcs) in sorted(self.bcs.iteritems()): 00620 for bc in bcs: # list 00621 msg += str(bc) 00622 ### 00623 ### 00624 return msg 00625 00626 def write_coords(self): 00627 """writes the coordinate cards in a sorted order""" 00628 msg = '' 00629 if len(self.coords) > 1: 00630 msg += '$COORDS\n' 00631 for (ID, coord) in sorted(self.coords.iteritems()): 00632 if ID != 0: 00633 msg += str(coord) 00634 return msg 00635 00636 def write_rejects(self): 00637 """ 00638 writes the rejected (processed) cards and the rejected unprocessed 00639 cardLines 00640 """ 00641 msg = '' 00642 if self.reject_cards: 00643 msg += '$REJECTS\n' 00644 for reject_card in self.reject_cards: 00645 try: 00646 msg += printCard(reject_card) 00647 except RuntimeError: 00648 for field in reject_card: 00649 if field is not None and '=' in field: 00650 raise SyntaxError('cannot reject equal signed ' 00651 'cards\ncard=%s\n' %(reject_card)) 00652 raise 00653 00654 if self.rejects: 00655 msg += '$REJECT_LINES\n' 00656 for reject_lines in self.rejects: 00657 if reject_lines[0][0] == ' ': 00658 continue 00659 else: 00660 for reject in reject_lines: 00661 reject2 = reject.rstrip() 00662 if reject2: 00663 msg += str(reject2)+'\n' 00664 return msg 00665