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,R0902,R0904,R0914 00026 00027 from __future__ import division, print_function 00028 from itertools import izip 00029 00030 from numpy import array, cross, allclose 00031 from numpy.linalg import norm 00032 00033 from pyNastran.bdf.cards.loads.loads import Load, LoadCombination 00034 from pyNastran.bdf.fieldWriter import set_blank_if_default 00035 from ..baseCard import BaseCard, expandThru, expandThruBy 00036 00037 class LOAD(LoadCombination): 00038 type = 'LOAD' 00039 def __init__(self, card=None, data=None): 00040 LoadCombination.__init__(self, card, data) 00041 00042 def getLoadIDs(self): 00043 """ 00044 @note requires a cross referenced load 00045 """ 00046 load_IDs = [] 00047 for loads in self.loadIDs: 00048 for load in loads: 00049 #if isinstance(load,int): 00050 #load_IDs += [load] 00051 00052 if isinstance(load, LOAD): 00053 lid = load.lid 00054 if isinstance(lid, list): 00055 load_IDs += load.lid 00056 else: # int 00057 load_IDs += load.getLoadIDs() 00058 elif (isinstance(load, Force) or isinstance(load, Moment) or 00059 isinstance(load, PLOAD4) or isinstance(load, GRAV)): 00060 load_IDs += [load.lid] 00061 else: 00062 msg = ('The getLoadIDs method doesnt support %s cards.\n' 00063 '%s' % (load.__class__.__name__,str(load))) 00064 raise NotImplementedError(msg) 00065 00066 ### 00067 ### 00068 load_IDs = list(set(load_IDs)) 00069 #print "load_IDs = ",load_IDs 00070 return load_IDs 00071 00072 def getLoadTypes(self): 00073 """ 00074 @note requires a cross referenced load 00075 """ 00076 loadTypes = [] 00077 for loads in self.loadIDs: 00078 for load in loads: 00079 if isinstance(load, LOAD): 00080 lid = load.lid 00081 if isinstance(lid, list): 00082 loadTypes += load.type 00083 else: # int 00084 loadTypes += [load.type]+load.getLoadTypes() 00085 elif (isinstance(load, Force) or isinstance(load, Moment) or 00086 isinstance(load, PLOAD4) or isinstance(load, GRAV)): 00087 loadTypes += [load.type] 00088 else: 00089 raise RuntimeError(load) 00090 ### 00091 ### 00092 loadTypes = list(set(loadTypes)) 00093 #print "loadTypes = ",loadTypes 00094 return loadTypes 00095 00096 def writeCalculixGRAV(self, gx, gy, gz): 00097 msg = '*DLOAD\n' 00098 msg += 'AllElements,GRAV,%s,%s,%s\n' % (gx, gy, gz) 00099 return msg 00100 00101 def writeCodeAsterLoad(self, model, gridWord='node'): 00102 loadIDs = self.getLoadIDs() 00103 loadTypes = self.getLoadTypes() 00104 00105 #msg = '# Loads\n' 00106 msg = '' 00107 (typesFound, forceLoads, momentLoads, 00108 forceConstraints, momentConstraints, 00109 gravityLoads) = self.organizeLoads(model) 00110 00111 nids = [] 00112 for nid in forceLoads: 00113 nids.append(nid) 00114 for nid in momentLoads: 00115 nids.append(nid) 00116 00117 if nids: 00118 msg += '# typesFound = %s\n' % (list(typesFound)) 00119 msg += '# loadIDs = %s\n' % (loadIDs) 00120 msg += "load_bc=AFFE_CHAR_MECA(MODELE=modmod,\n" 00121 #msg += " DDL_IMPO=(_F(GROUP_MA='Lleft',\n" 00122 msg += " FORCE_NODALE=(\n" 00123 00124 #CHAR=AFFE_CHAR_MECA(MODELE=MODE, 00125 # FORCE_NODALE=( 00126 # _F(NOEUD='N1', 00127 # FZ=-500.0),) 00128 00129 #print("nids = ",nids) 00130 spaces = " " 00131 for nid in sorted(nids): # ,load in sorted(forceLoads.iteritems()) 00132 #print("nid = ",nid) 00133 msg += spaces + "_F(NOEUD='%s%s',\n" % (gridWord, nid) 00134 #print "load = ",load 00135 00136 if nid in forceLoads: 00137 force = forceLoads[nid] 00138 if abs(force[0]) > 0.: 00139 msg += spaces + " FX=%s,\n" % (force[0]) 00140 if abs(force[1]) > 0.: 00141 msg += spaces + " FY=%s,\n" % (force[1]) 00142 if abs(force[2]) > 0.: 00143 msg += spaces + " FZ=%s,\n" % (force[2]) 00144 00145 if nid in momentLoads: 00146 moment = momentLoads[nid] 00147 if abs(moment[0]) > 0.: 00148 msg += spaces + " MX=%s,\n" % (moment[0]) 00149 if abs(moment[1]) > 0.: 00150 msg += spaces + " MY=%s,\n" % (moment[1]) 00151 if abs(moment[2]) > 0.: 00152 msg += spaces + " MZ=%s,\n" % (moment[2]) 00153 msg = msg[:-2] 00154 msg += '),\n' 00155 # finish the load 00156 00157 #if moment in 00158 #msg += " DX=0.0,\n" 00159 #msg += " DY=0.0,\n" 00160 #msg += " DZ=0.0,),\n" 00161 #msg += " _F(GROUP_MA='Lright',\n" 00162 #msg += " DZ=0.0,),),\n" 00163 msg = msg[:-2] 00164 msg += ');\n' 00165 00166 for gravityLoad in gravityLoads: 00167 msg += 'CA_GRAVITY(%s);\n' % (str(gravityLoad)) 00168 return (msg, loadIDs, loadTypes) 00169 00170 def getReducedLoads(self): 00171 """ 00172 Get all load objects in a simplified form, 00173 which means all scale factors are already applied and 00174 only base objects (no LOAD cards) will be returned. 00175 @todo lots more object types to support 00176 """ 00177 scaleFactors = [] 00178 loads = [] 00179 scale = self.scale 00180 for (loadsPack, scaleFactorI) in izip(self.loadIDs, self.scaleFactors): 00181 scale2 = scaleFactorI*scale 00182 for load in loadsPack: 00183 if (isinstance(load, Force) or isinstance(load, Moment) or 00184 isinstance(load, PLOAD4) or isinstance(load, GRAV)): 00185 loads.append(load) 00186 scaleFactors.append(scale2) 00187 elif isinstance(load, LOAD): 00188 (scaleFactorsi, loadsi) = load.getReducedLoads() 00189 loads += loadsi 00190 scaleFactors += [scale2*scalei for scalei in scaleFactorsi] 00191 else: 00192 msg = ('%s isnt supported in getReducedLoads method' 00193 % (load.__class__.__name__)) 00194 raise NotImplementedError(msg) 00195 ### 00196 ### 00197 ### 00198 return (scaleFactors, loads) 00199 00200 def organizeLoads(self, model): 00201 """ 00202 Figures out magnitudes of the loads to be applied to the various nodes. 00203 This includes figuring out scale factors. 00204 """ 00205 forceLoads = {} # spc enforced displacement (e.g. FORCE=0) 00206 momentLoads = {} 00207 forceConstraints = {} 00208 momentConstraints = {} 00209 gravityLoads = [] 00210 #print("self.loadIDs = ",self.loadIDs) 00211 00212 typesFound = set() 00213 (scaleFactors, loads) = self.getReducedLoads() 00214 00215 for (scaleFactor, load) in izip(scaleFactors, loads): 00216 #print("*load = ",load) 00217 out = load.transformLoad() 00218 typesFound.add(load.__class__.__name__) 00219 if isinstance(load, Force): 00220 (isLoad, node, vector) = out 00221 if isLoad: #load 00222 if node not in forceLoads: 00223 forceLoads[node] = vector*scaleFactor 00224 else: 00225 forceLoads[node] += vector*scaleFactor 00226 ### 00227 else: # constraint 00228 if node not in forceLoads: 00229 forceConstraints[node] = vector*scaleFactor 00230 else: 00231 forceConstraints[node] += vector*scaleFactor 00232 ### 00233 ### 00234 elif isinstance(load, Moment): 00235 (isLoad, node, vector) = out 00236 if isLoad: # load 00237 if node not in momentLoads: 00238 momentLoads[node] = vector*scaleFactor 00239 else: 00240 momentLoads[node] += vector*scaleFactor 00241 ### 00242 else: # constraint 00243 if node not in momentLoads: 00244 momentConstraints[node] = vector*scaleFactor 00245 else: 00246 momentConstraints[node] += vector*scaleFactor 00247 ### 00248 ### 00249 elif isinstance(load, PLOAD4): 00250 (isLoad, nodes, vectors) = out 00251 for (nid, vector) in izip(nodes, vectors): 00252 # not the same vector for all nodes 00253 forceLoads[nid] = vector*scaleFactor 00254 00255 elif isinstance(load, GRAV): 00256 #(grav) = out 00257 gravityLoads.append(out*scaleFactor) # grav 00258 else: 00259 msg = '%s not supported' % (load.__class__.__name__) 00260 raise NotImplementedError(msg) 00261 ### 00262 ### 00263 return (typesFound, forceLoads, momentLoads, forceConstraints, 00264 momentConstraints, gravityLoads) 00265 00266 def rawFields(self): 00267 fields = ['LOAD', self.sid, self.scale] 00268 for (scaleFactor, loadID) in izip(self.scaleFactors, self.loadIDs): 00269 fields += [scaleFactor, self.LoadID(loadID)] 00270 return fields 00271 00272 def reprFields(self): 00273 return self.rawFields() 00274 00275 #------------------------------------------------------------------------------ 00276 class GRAV(BaseCard): 00277 """ 00278 Defines acceleration vectors for gravity or other acceleration loading 00279 GRAV SID CID A N1 N2 N3 MB 00280 GRAV 1 3 32.2 0.0 0.0 -1.0 00281 """ 00282 type = 'GRAV' 00283 def __init__(self, card=None, data=None): 00284 if card: 00285 ## Set identification number 00286 self.sid = card.field(1) 00287 ## Coordinate system identification number. 00288 self.cid = card.field(2, 0) 00289 ## scale factor 00290 self.scale = card.field(3) 00291 ## Acceleration vector components measured in coordinate system CID 00292 self.N = array(card.fields(4, 7, [0., 0., 0.])) 00293 ## Indicates whether the CID coordinate system is defined in the 00294 ## main Bulk Data Section (MB = -1) or the partitioned superelement 00295 ## Bulk Data Section (MB = 0). Coordinate systems referenced in the 00296 ## main Bulk Data Section are considered stationary with respect to 00297 ## the assembly basic coordinate system. See Remark 10. 00298 ## (Integer; Default = 0) 00299 self.mb = card.field(7, 0) 00300 else: 00301 self.sid = data[0] 00302 self.cid = data[1] 00303 self.a = data[2] 00304 self.N = array(data[3:6]) 00305 self.mb = data[6] 00306 self.scale = 1. 00307 assert len(data)==7 00308 00309 assert not allclose(max(abs(self.N)), 0.),('GRAV N is a zero vector, ' 00310 'N=%s' % (str(self.N))) 00311 00312 def getLoads(self): 00313 return [self] 00314 00315 def organizeLoads(self, model): 00316 typesFound = [self.type] 00317 forceLoads = {} 00318 momentLoads = {} 00319 forceConstraints = {} 00320 momentConstraints = {} 00321 gravityLoad = self.transformLoad() 00322 return (typesFound, forceLoads, momentLoads, 00323 forceConstraints, momentConstraints, 00324 gravityLoad) 00325 00326 def transformLoad(self): 00327 g = self.GravityVector() 00328 (g2, matrix) = self.cid.transformToGlobal(g) 00329 return (g2) 00330 00331 #def writeCodeAster(self,mag): 00332 #p = self.GravityVector() 00333 #msg = 'GRAV([%s,%s,%s])' %(p) 00334 #return msg 00335 00336 def crossReference(self, model): 00337 #print("xref GRAV") 00338 self.cid = model.Coord(self.cid) 00339 00340 def Cid(self): 00341 if isinstance(self.cid, int): 00342 return self.cid 00343 return self.cid.cid 00344 00345 def GravityVector(self): 00346 """returns the gravity vector in absolute coordinates""" 00347 (p, matrix) = self.cid.transformToGlobal(self.N) 00348 return self.scale*p 00349 00350 def rawFields(self): 00351 N = list(self.N) 00352 fields = ['GRAV', self.sid, self.Cid(), self.scale]+N+[self.mb] 00353 return fields 00354 00355 def reprFields(self): 00356 N = [] 00357 for n in self.N: 00358 N.append(set_blank_if_default(n, 0.0)) 00359 00360 mb = set_blank_if_default(self.mb, 0) 00361 fields = ['GRAV', self.sid, self.Cid(), self.scale]+N+[mb] 00362 return fields 00363 00364 class ACCEL1(BaseCard): 00365 """ 00366 Acceleration Load 00367 Defines static acceleration loads at individual GRID points. 00368 """ 00369 type = 'ACCEL1' 00370 def __init__(self, card=None, data=None): 00371 ## Load set identification number (Integer>0) 00372 self.sid = card.field(1) 00373 00374 ## Coordinate system identification number. (Integer>0: Default=0) 00375 self.cid = card.field(2, 0) 00376 00377 ## Acceleration vector scale factor. (Real) 00378 self.scale = card.field(3) 00379 00380 ## Components of the acceleration vector measured in coordinate system 00381 ## CID. (Real; at least one Ni != 0) 00382 self.N = array(card.fields(4, 7, [0., 0., 0.])) 00383 assert max(abs(self.N))>0. 00384 ## nodes to apply the acceleration to 00385 self.nodes = expandThruBy(card.fields(9)) 00386 00387 def crossReference(self, model): 00388 self.cid = model.Coord(self.cid) 00389 self.nodes = model.Nodes(self.nodes, allowEmptyNodes=True) 00390 00391 def Cid(self): 00392 if isinstance(self.cid, int): 00393 return self.cid 00394 return self.cid.cid 00395 00396 def nodeIDs(self, nodes=None): # this function comes from BaseCard.py 00397 """returns nodeIDs for repr functions""" 00398 if not nodes: 00399 nodes = self.nodes 00400 if isinstance(nodes[0], int): 00401 nodeIDs = [node for node in nodes] 00402 else: 00403 nodeIDs = [node.nid for node in nodes] 00404 ### 00405 assert 0 not in nodeIDs, 'nodeIDs = %s' % (nodeIDs) 00406 return nodeIDs 00407 00408 def rawFields(self): 00409 fields = ['ACCEL1', self.sid, self.Cid(), self.scale, 00410 self.N[0], self.N[1], self.N[2], None, None]+self.nodeIDs() 00411 return fields 00412 00413 00414 #------------------------------------------------------------------------------ 00415 class OneDeeLoad(Load): # FORCE/MOMENT 00416 type = '1D_Load' 00417 def __init__(self, card, data): 00418 self.cid = None 00419 self.mag = None 00420 self.xyz = None 00421 Load.__init__(self, card, data) 00422 00423 def getLoads(self): 00424 return [self] 00425 00426 def transformLoad(self): 00427 #print("self.xyz = ",self.xyz) 00428 (xyz, matrix) = self.cid.transformToGlobal(self.xyz) 00429 if self.mag > 0.: 00430 #print("mag=%s xyz=%s" % (self.mag, xyz)) 00431 return (True, self.node, self.mag*xyz) # load 00432 return (False, self.node, xyz) # enforced displacement 00433 00434 def normalize(self): 00435 """ 00436 adjust the vector to a unit length 00437 scale up the magnitude of the vector 00438 """ 00439 if self.mag != 0.0: # enforced displacement 00440 normXYZ = norm(self.xyz) 00441 #mag = self.mag*normXYZ 00442 self.mag *= normXYZ 00443 self.xyz = self.xyz/normXYZ 00444 00445 #------------------------------------------------------------------------------ 00446 class Force(OneDeeLoad): 00447 """Generic class for all Forces""" 00448 type = '1D_Load' 00449 def __init__(self, card, data): 00450 OneDeeLoad.__init__(self, card, data) 00451 00452 def getLoads(self): 00453 return [self] 00454 00455 def F(self): 00456 return self.xyz*self.mag 00457 00458 def getReducedLoads(self): 00459 scaleFactors = [1.] 00460 loads = self.F() 00461 return(scaleFactors, loads) 00462 00463 def organizeLoads(self, model): 00464 (scaleFactors, forceLoads) = self.getReducedLoads() 00465 00466 typesFound = [self.type] 00467 momentLoads = {} 00468 forceConstraints = {} 00469 momentConstraints = {} 00470 gravityLoads = [] 00471 return (typesFound, forceLoads, momentLoads, 00472 forceConstraints, momentConstraints, 00473 gravityLoads) 00474 00475 class Moment(OneDeeLoad): 00476 """Generic class for all Moments""" 00477 type = 'Moment' 00478 def __init__(self, card, data): 00479 OneDeeLoad.__init__(self, card, data) 00480 00481 def getLoads(self): 00482 return [self] 00483 00484 def getReducedLoads(self): 00485 scaleFactors = [1.] 00486 loads = self.F() 00487 return(scaleFactors, loads) 00488 00489 def organizeLoads(self, model): 00490 (scaleFactors, momentLoads) = self.getReducedLoads() 00491 00492 typesFound = [self.type] 00493 forceLoads = {} 00494 forceConstraints = {} 00495 momentConstraints = {} 00496 gravityLoads = [] 00497 return (typesFound, forceLoads, momentLoads, 00498 forceConstraints, momentConstraints, 00499 gravityLoads) 00500 def M(self): 00501 return self.xyz*self.mag 00502 00503 #------------------------------------------------------------------------------ 00504 class FORCE(Force): 00505 type = 'FORCE' 00506 def __init__(self, card=None, data=None): 00507 """ 00508 FORCE 3 1 100. 0. 0. 1. 00509 """ 00510 Force.__init__(self, card, data) 00511 if card: 00512 self.sid = card.field(1) 00513 self.node = card.field(2) 00514 self.cid = card.field(3, 0) 00515 self.mag = card.field(4) 00516 xyz = card.fields(5, 8, [0., 0., 0.]) 00517 else: 00518 self.sid = data[0] 00519 self.node = data[1] 00520 self.cid = data[2] 00521 self.mag = data[3] 00522 xyz = data[4:7] 00523 00524 assert len(xyz)==3, 'xyz=%s' % (xyz) 00525 self.xyz = array(xyz) 00526 00527 def Cid(self): 00528 if isinstance(self.cid, int): 00529 return self.cid 00530 return self.cid.cid 00531 00532 def F(self): 00533 return {self.node: self.mag*self.xyz} 00534 00535 #def nodeID(self): 00536 #return self.node 00537 00538 def crossReference(self, model): 00539 """@todo cross reference and fix repr function""" 00540 self.cid = model.Coord(self.cid) 00541 00542 def rawFields(self): 00543 fields = ['FORCE', self.sid, self.node, self.Cid(), self.mag 00544 ] + list(self.xyz) 00545 return fields 00546 00547 def reprFields(self): 00548 cid = set_blank_if_default(self.Cid(), 0) 00549 fields = ['FORCE', self.sid, self.node, cid, self.mag] + list(self.xyz) 00550 return fields 00551 00552 class FORCE1(Force): 00553 """ 00554 Defines a static concentrated force at a grid point by specification of a 00555 magnitude and two grid points that determine the direction. 00556 """ 00557 type = 'FORCE1' 00558 def __init__(self, card=None, data=None): 00559 Force.__init__(self, card, data) 00560 if card: 00561 self.sid = card.field(1) 00562 self.node = card.field(2) 00563 self.mag = card.field(3) 00564 self.g1 = card.field(4) 00565 self.g2 = card.field(5) 00566 else: 00567 self.sid = data[0] 00568 self.node = data[1] 00569 self.mag = data[2] 00570 self.g1 = data[3] 00571 self.g2 = data[4] 00572 ### 00573 00574 def crossReference(self, model): 00575 """@todo cross reference and fix repr function""" 00576 self.node = model.Node(self.node) 00577 self.g1 = model.Node(self.g1) 00578 self.g2 = model.Node(self.g2) 00579 self.xyz = self.g2.Position()-self.g1.Position() 00580 self.Normalize() 00581 00582 def G1(self): 00583 if isinstance(self.g1, int) or isinstance(self.g1, float): 00584 return self.g1 00585 return self.g1.nid 00586 00587 def G2(self): 00588 if isinstance(self.g2, int) or isinstance(self.g1, float): 00589 return self.g2 00590 return self.g2.nid 00591 00592 def NodeID(self): 00593 if isinstance(self.node, int): 00594 return self.node 00595 return self.node.nid 00596 00597 def rawFields(self): 00598 (node, g1, g2) = self.nodeIDs([self.node, self.G1(), self.G2()]) 00599 fields = ['FORCE1', self.sid, node, self.mag, g1, g2] 00600 return fields 00601 00602 def reprFields(self): 00603 return self.rawFields() 00604 00605 class FORCE2(Force): 00606 """ 00607 Defines a static concentrated force at a grid point by specification of a 00608 magnitude and four grid points that determine the direction. 00609 """ 00610 type = 'FORCE2' 00611 def __init__(self, card=None, data=None): 00612 """ 00613 FORCE2 SID G F G1 G2 G3 G4 00614 """ 00615 Force.__init__(self, card, data) 00616 if card: 00617 self.sid = card.field(1) 00618 self.node = card.field(2) 00619 self.mag = card.field(3) 00620 self.g1 = card.field(4) 00621 self.g2 = card.field(5) 00622 self.g3 = card.field(5) 00623 self.g4 = card.field(5) 00624 else: 00625 self.sid = data[0] 00626 self.node = data[1] 00627 self.mag = data[2] 00628 self.g1 = data[3] 00629 self.g2 = data[4] 00630 self.g3 = data[5] 00631 self.g4 = data[6] 00632 ### 00633 00634 def crossReference(self, model): 00635 """@todo cross reference and fix repr function""" 00636 self.node = model.Node(self.node) 00637 00638 v12 = model.Node(self.g2).Position() - model.Node(self.g1).Position() 00639 v34 = model.Node(self.g4).Position() - model.Node(self.g3).Position() 00640 v12 = v12/norm(v12) 00641 v34 = v34/norm(v34) 00642 self.xyz = cross(v12, v34) 00643 self.Normalize() 00644 00645 def NodeID(self): 00646 if isinstance(self.node, int): 00647 return self.node 00648 return self.node.nid 00649 00650 def rawFields(self): 00651 (node, g1, g2, g3, g4) = self.nodeIDs([self.node, self.g1, self.g2, 00652 self.g3, self.g4]) 00653 fields = ['FORCE2', self.sid, node, self.mag, g1, g2, g3, g4] 00654 return fields 00655 00656 def reprFields(self): 00657 return self.rawFields() 00658 00659 #------------------------------------------------------------------------------ 00660 class MOMENT(Moment): 00661 type = 'MOMENT' 00662 def __init__(self, card=None, data=None): 00663 """ 00664 Defines a static concentrated moment at a grid point by specifying a 00665 scale factor and a vector that determines the direction. 00666 00667 MOMENT SID G CID M N1 N2 N3 00668 MOMENT 2 5 6 2.9 0.0 1.0 0.0 00669 """ 00670 Moment.__init__(self, card, data) 00671 self.sid = card.field(1) 00672 self.node = card.field(2) 00673 self.cid = card.field(3, 0) 00674 self.mag = card.field(4) 00675 00676 xyz = card.fields(5, 8, [0., 0., 0.]) 00677 assert len(xyz)==3,'xyz=%s' %(xyz) 00678 self.xyz = array(xyz) 00679 00680 def Cid(self): 00681 if isinstance(self.cid, int): 00682 return self.cid 00683 return self.cid.cid 00684 00685 def crossReference(self, model): 00686 """@todo cross reference and fix repr function""" 00687 pass 00688 00689 def rawFields(self): 00690 fields = ['MOMENT', self.sid, self.node, self.Cid(), self.mag 00691 ] + list(self.xyz) 00692 return fields 00693 00694 def reprFields(self): 00695 cid = set_blank_if_default(self.Cid(), 0) 00696 fields = ['MOMENT', self.sid, self.node, cid, self.mag 00697 ] + list(self.xyz) 00698 return fields 00699 00700 class MOMENT1(Moment): 00701 type = 'MOMENT1' 00702 def __init__(self, card=None, data=None): 00703 """ 00704 Defines a static concentrated moment at a grid point by specifying a 00705 magnitude and two grid points that determine the direction 00706 00707 MOMENT1 SID G M G1 G2 00708 """ 00709 Moment.__init__(self, card, data) 00710 if card: 00711 self.sid = card.field(1) 00712 self.node = card.field(2) 00713 self.mag = card.field(3) 00714 self.g1 = card.field(4) 00715 self.g2 = card.field(5) 00716 self.g3 = card.field(6) 00717 self.g4 = card.field(7) 00718 xyz = card.fields(5, 8, [0., 0., 0.]) 00719 else: 00720 self.sid = data[0] 00721 self.node = data[1] 00722 self.mag = data[2] 00723 self.g1 = data[3] 00724 self.g2 = data[4] 00725 self.g3 = data[5] 00726 self.g4 = data[6] 00727 xyz = data[7:10] 00728 ### 00729 00730 assert len(xyz)==3, 'xyz=%s' %(xyz) 00731 self.xyz = array(xyz) 00732 00733 def crossReference(self, model): 00734 """@todo cross reference and fix repr function""" 00735 self.node = model.Node(self.node) 00736 self.xyz = model.Node(self.g2).Position() - model.Node(self.g1).Position() 00737 self.Normalize() 00738 00739 def rawFields(self): 00740 (node, g1, g2) = self.nodeIDs([self.node, self.g1, self.g2]) 00741 fields = ['MOMENT1', self.sid, node, self.mag, g1, g2] 00742 return fields 00743 00744 def reprFields(self): 00745 return self.rawFields() 00746 00747 00748 class MOMENT2(Moment): 00749 type = 'MOMENT2' 00750 def __init__(self, card=None, data=None): 00751 """ 00752 Defines a static concentrated moment at a grid point by specification 00753 of a magnitude and four grid points that determine the direction. 00754 00755 MOMENT2 SID G M G1 G2 G3 G4 00756 """ 00757 Moment.__init__(self, card, data) 00758 if card: 00759 self.sid = card.field(1) 00760 self.node = card.field(2) 00761 self.mag = card.field(3) 00762 self.g1 = card.field(4) 00763 self.g2 = card.field(5) 00764 self.g3 = card.field(6) 00765 self.g4 = card.field(7) 00766 xyz = card.fields(5, 8, [0., 0., 0.]) 00767 else: 00768 self.sid = data[0] 00769 self.node = data[1] 00770 self.mag = data[2] 00771 self.g1 = data[3] 00772 self.g2 = data[4] 00773 self.g3 = data[5] 00774 self.g4 = data[6] 00775 xyz = data[7:10] 00776 ### 00777 assert len(xyz) == 3, 'xyz=%s' % (xyz) 00778 self.xyz = array(xyz) 00779 00780 def crossReference(self, model): 00781 """@todo cross reference and fix repr function""" 00782 (self.g1, self.g2, self.g3, self.g4) = model.Nodes(self.g1, self.g2, 00783 self.g3, self.g4) 00784 v12 = self.g2.Position()-self.g1.Position() 00785 v34 = self.g4.Position()-self.g3.Position() 00786 v12 = v12/norm(v12) 00787 v34 = v34/norm(v34) 00788 self.xyz = cross(v12, v34) 00789 00790 def rawFields(self): 00791 (node, g1, g2, g3, g4) = self.nodeIDs([self.node, self.g1, self.g2, 00792 self.g3, self.g4]) 00793 fields = ['MOMENT2', self.sid, node, self.mag, g1, g2, g3, g4] 00794 return fields 00795 00796 def reprFields(self): 00797 return self.rawFields() 00798 00799 #------------------------------------------------------------------------------ 00800 class PLOAD(Load): 00801 type = 'PLOAD' 00802 def __init__(self, card=None, data=None): 00803 if card: 00804 self.sid = card.field(1) 00805 self.p = card.field(2) 00806 nodes = card.fields(3, 7) 00807 self.nodes = self._wipeEmptyFields(nodes) 00808 else: 00809 self.sid = data[0] 00810 self.p = data[1] 00811 self.nodes = data[2:] 00812 print("PLOAD = %s" %(data)) 00813 raise NotImplementedError('PLOAD') 00814 assert len(self.nodes) in [3, 4], 'nodes=%s' %(self.nodes) 00815 00816 def crossReference(self, model): 00817 """@todo cross reference and fix repr function""" 00818 pass 00819 00820 def getLoads(self): 00821 return [self] 00822 00823 def rawFields(self): 00824 fields = ['PLOAD', self.sid, self.p]+self.nodeIDs() 00825 return fields 00826 00827 def reprFields(self): 00828 return self.rawFields() 00829 00830 class PLOAD1(Load): 00831 type = 'PLOAD1' 00832 validTypes = ['FX', 'FY', 'FZ', 'FXE', 'FYE', 'FZE', 00833 'MX', 'MY', 'MZ', 'MXE', 'MYE', 'MZE'] 00834 validScales = ['LE', 'FR', 'LEPR', 'FRPR'] 00835 def __init__(self, card=None, data=None): 00836 if card: 00837 self.sid = card.field(1) 00838 self.eid = card.field(2) 00839 self.Type = card.field(3) 00840 self.scale = card.field(4) 00841 self.x1 = card.field(5) 00842 self.p1 = card.field(6) 00843 self.x2 = card.field(7) 00844 self.p2 = card.field(8) 00845 else: 00846 self.sid = data[0] 00847 self.eid = data[1] 00848 self.Type = data[2] 00849 self.scale = data[3] 00850 self.x1 = data[4] 00851 self.p1 = data[5] 00852 self.x2 = data[6] 00853 self.p2 = data[7] 00854 ### 00855 assert self.Type in self.validTypes, '%s is an invalid type on the PLOAD1 card' % (self.Type) 00856 assert self.scale in self.validScales, '%s is an invalid scale on the PLOAD1 card' % (self.scale) 00857 00858 def crossReference(self, model): 00859 """@todo cross reference and fix repr function""" 00860 pass 00861 00862 def getLoads(self): 00863 return [self] 00864 00865 def rawFields(self): 00866 fields = ['PLOAD1', self.sid, self.eid, self.Type, self.scale, self.x1, 00867 self.p1, self.x2, self.p2] 00868 return fields 00869 00870 def reprFields(self): 00871 return self.rawFields() 00872 00873 class PLOAD2(Load): 00874 type = 'PLOAD2' 00875 def __init__(self, card=None, data=None): 00876 if card: 00877 self.sid = card.field(1) 00878 self.p = card.field(2) 00879 eids = card.fields(3, 9) 00880 00881 if card.field(4)=='THRU': 00882 #print "PLOAD2 %s %s" %(eids[0],eids[-1]) 00883 eids = [i for i in xrange(eids[0], eids[2]+1)] 00884 #print "found a THRU on PLOAD2" 00885 #raise NotImplementedError('PLOAD2') 00886 ### 00887 self.eids = eids 00888 else: 00889 self.sid = data[0] 00890 self.p = data[1] 00891 self.eids = list(data[2:]) 00892 #print "PLOAD2 = ",data 00893 ### 00894 00895 def crossReference(self, model): 00896 """@todo cross reference and fix repr function""" 00897 pass 00898 00899 def getLoads(self): 00900 return [self] 00901 00902 def rawFields(self): 00903 fields = ['PLOAD2', self.sid, self.p] 00904 if len(self.eids)>6: 00905 fields += [self.eids[0], 'THRU', self.eids[-1]] 00906 else: 00907 fields += self.eids 00908 return fields 00909 00910 def reprFields(self): 00911 return self.rawFields() 00912 00913 class PLOAD4(Load): 00914 type = 'PLOAD4' 00915 def __init__(self, card=None, data=None): 00916 if card: 00917 self.sid = card.field(1) 00918 self.eid = card.field(2) 00919 p1 = card.field(3) 00920 p = card.fields(4, 7, [p1, p1, p1]) # [p1,p1,p1] are the defaults 00921 self.pressures = [p1]+p 00922 00923 self.eids = [self.eid] 00924 if card.field(7)=='THRU' and card.field(8): # plates 00925 eid2 = card.field(8) 00926 if eid2: 00927 self.eids = expandThru([self.eid, 'THRU', eid2]) 00928 00929 self.g1 = None 00930 self.g34 = None 00931 else: 00932 ## used for CPENTA, CHEXA 00933 self.eids = [self.eid] 00934 ## used for solid element only 00935 self.g1 = card.field(7) 00936 ## g3/g4 - different depending on CHEXA/CPENTA or CTETRA 00937 self.g34 = card.field(8) 00938 ### 00939 00940 ## Coordinate system identification number. See Remark 2. 00941 ## (Integer >= 0;Default=0) 00942 self.cid = card.field(9, 0) 00943 #print "PLOAD4 cid = ",self.cid 00944 self.NVector = card.fields(10, 13, [0., 0., 0.]) 00945 self.sorl = card.field(13, 'SURF') 00946 self.ldir = card.field(14, 'NORM') 00947 else: 00948 #print "PLOAD4 = ",data 00949 self.sid = data[0] 00950 self.eid = data[1] 00951 self.pressures = data[2] 00952 00953 self.g1 = data[3] 00954 self.g34 = data[4] 00955 self.cid = data[5] 00956 self.NVector = data[6] 00957 00958 self.sorl = data[7] 00959 #self.ldir = data[8] 00960 #assert len(data)==8 00961 00962 self.g1 = self.g1 00963 self.g34 = self.g34 00964 self.eids = [self.eid] 00965 ### 00966 00967 def getLoads(self): 00968 return [self] 00969 00970 def transformLoad(self): 00971 """ 00972 @warning sorl=SURF is supported (not LINE) 00973 @warning ldir=NORM is supported (not X,Y,Z) 00974 """ 00975 assert self.sorl == 'SURF', 'only surface loads are supported. required_sorl=SURF. actual=%s' % (self.sorl) 00976 assert self.ldir == 'NORM', 'only normal loads are supported. required_ldir=NORM. actual=%s' % (self.ldir) 00977 assert len(self.eids) == 1, 'only one load may be defined on each PLOAD4. nLoads=%s\n%s' % (len(self.eids), str(self)) 00978 00979 if self.g1 and self.g34: # solid elements 00980 nid = self.g1.nid 00981 nidOpposite = self.g34.nid 00982 (faceNodeIDs, Area) = self.eid.getFaceNodesAndArea(self, nid, 00983 nidOpposite) 00984 else: 00985 faceNodeIDs = self.eid.nodeIDs() 00986 Area = self.eid.Area() 00987 n = len(faceNodeIDs) 00988 00989 vector = array(self.eid.Normal()) 00990 vectors = [] 00991 for (nid, p) in izip(faceNodeIDs, self.pressures): 00992 ## @warning only supports normal pressures 00993 vectors.append(vector*p*Area/n) # Force_i 00994 00995 isLoad = None 00996 return (isLoad, faceNodeIDs, vectors) 00997 00998 def Cid(self): 00999 if isinstance(self.cid, int): 01000 return self.cid 01001 return self.cid.cid 01002 01003 def crossReference(self, model): 01004 self.eid = model.Element(self.eid) 01005 self.cid = model.Coord(self.cid) 01006 if self.g1: 01007 self.g1 = model.Node(self.g1) 01008 if self.g34: 01009 self.g34 = model.Node(self.g34) 01010 if self.eids: 01011 self.eids = model.Elements(self.eids) 01012 01013 def Eid(self, eid): 01014 if isinstance(eid, int): 01015 return eid 01016 return eid.eid 01017 01018 def getElementIDs(self, eid=None): 01019 if eid: 01020 return self.Eid(eid) 01021 eids = [] 01022 for element in self.eids: 01023 eids.append(self.Eid(element)) 01024 return eids 01025 01026 def rawFields(self): 01027 eid = self.Eid(self.eid) 01028 cid = set_blank_if_default(self.Cid(), 0) 01029 sorl = set_blank_if_default(self.sorl, 'SURF') 01030 ldir = set_blank_if_default(self.ldir, 'NORM') 01031 p1 = self.pressures[0] 01032 p2 = set_blank_if_default(self.pressures[1], p1) 01033 p3 = set_blank_if_default(self.pressures[2], p1) 01034 p4 = set_blank_if_default(self.pressures[3], p1) 01035 fields = ['PLOAD4', self.sid, eid, self.pressures[0], p2, p3, p4] 01036 01037 #print "g3=|%s| g4=%s eids=|%s|" %(self.g3,self.g4,self.eids) 01038 if self.g1 is not None: # is it a SOLID element 01039 (g1, g34) = self.nodeIDs([self.g1, self.g34]) 01040 fields.append(g1) 01041 fields.append(g34) 01042 else: 01043 #print "eids = %s" %(self.eids) 01044 if len(self.eids) > 1: 01045 #print("self.eids = %s" %(self.eids)) 01046 try: 01047 fields.append('THRU') 01048 eid = self.eids[-1] 01049 except: 01050 print("g1 = %s" % (self.g1)) 01051 print("g34 = %s" % (self.g34)) 01052 print("self.eids = %s" % (self.eids)) 01053 raise 01054 ### 01055 fields.append(self.getElementIDs(eid)) 01056 else: 01057 fields += [None, None] 01058 ### 01059 fields.append(cid) 01060 01061 n1 = set_blank_if_default(self.NVector[0], 0.0) 01062 n2 = set_blank_if_default(self.NVector[1], 0.0) 01063 n3 = set_blank_if_default(self.NVector[2], 0.0) 01064 fields += [n1, n2, n3] 01065 fields.append(sorl) 01066 fields.append(ldir) 01067 return fields 01068 01069 def reprFields(self): 01070 return self.rawFields() 01071 01072 class PLOADX1(Load): 01073 type = 'PLOADX1' 01074 def __init__(self, card=None, data=None): 01075 if card: 01076 self.sid = card.field(1) 01077 self.eid = card.field(2) 01078 self.pa = card.field(3) # float 01079 self.pb = card.field(4,self.pa) # float 01080 self.ga = card.field(5) # int 01081 self.gb = card.field(6) # int 01082 self.theta = card.field(7,0.) 01083 else: 01084 self.sid = data[0] 01085 print("PLOADX1 = %s" %(data)) 01086 raise NotImplementedError('PLOADX1') 01087 01088 def crossReference(self, model): 01089 #self.eid = model.Element(self.eid) 01090 #self.ga = model.Node(self.ga) 01091 #self.gb = model.Node(self.gb) 01092 pass 01093 01094 def getLoads(self): 01095 return [self] 01096 01097 def rawFields(self): 01098 fields = ['PLOADX1', self.sid, self.eid, self.pa, self.pb, 01099 self.ga, self.gb, self.theta] 01100 return fields 01101 01102 def reprFields(self): 01103 return self.rawFields() 01104