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 import sys 00029 00030 from numpy import array,eye,cross #zeros,dot 00031 from numpy.linalg import det # inv 00032 00033 from pyNastran.bdf.fieldWriter import (set_blank_if_default, 00034 set_default_if_blank) 00035 from pyNastran.bdf.cards.baseCard import Element 00036 from pyNastran.general.generalMath import (Area, Triangle_AreaCentroidNormal, 00037 Normal) 00038 00039 class ShellElement(Element): 00040 type = 'ShellElement' 00041 def __init__(self, card, data): 00042 Element.__init__(self, card, data) 00043 00044 def Area(self): 00045 raise NotImplementedError('Area undefined for %s' %(self.type)) 00046 00047 def Thickness(self): 00048 return self.pid.Thickness() 00049 00050 def mid(self): 00051 return self.pid.mid() 00052 00053 def Mid(self): 00054 return self.pid.Mid() 00055 00056 def Rho(self): 00057 return self.pid.mid().rho 00058 00059 def Nsm(self): 00060 return self.pid.Nsm() 00061 00062 def MassPerArea(self): 00063 return self.pid.MassPerArea() 00064 00065 def Mass(self): 00066 """ 00067 \f[ \large mass = \frac{mass}{area} area \f] 00068 """ 00069 return self.pid.MassPerArea()*self.Area() 00070 00071 def flipNormal(self): 00072 raise NotImplementedError('flipNormal undefined for %s' %(self.type)) 00073 00074 def crossReference(self,mesh): 00075 self.nodes = mesh.Nodes(self.nodes) 00076 self.pid = mesh.Property(self.pid) 00077 00078 class TriShell(ShellElement): 00079 def __init__(self, card, data): 00080 ShellElement.__init__(self, card, data) 00081 00082 def Thickness(self): 00083 return self.pid.Thickness() 00084 00085 def AreaCentroidNormal(self): 00086 """ 00087 returns area,centroid, normal as it's more efficient to do them together 00088 """ 00089 (n0,n1,n2) = self.nodePositions() 00090 return Triangle_AreaCentroidNormal([n0,n1,n2]) 00091 00092 def Area(self): 00093 """ 00094 returns the normal vector 00095 \f[ \large A = \frac{1}{2} (n_0-n_1) \cross (n_0-n_2) \f] 00096 """ 00097 (n0,n1,n2) = self.nodePositions() 00098 a = n0-n1 00099 b = n0-n2 00100 area = Area(a,b) 00101 return area 00102 00103 def Normal(self): 00104 """ 00105 returns the normal vector 00106 \f[ \large a = (n_0-n_1) \cross (n_0-n_2) \f] 00107 \f[ \large n = \frac{n}{norm(N)} \f] 00108 """ 00109 (n0,n1,n2) = self.nodePositions() 00110 a = n0-n1 00111 b = n0-n2 00112 return Normal(a,b) 00113 00114 def Centroid(self,debug=False): 00115 """ 00116 returns the centroid 00117 \f[ \large CG = \frac{1}{3} (n_0+n_1+n_2) \f] 00118 """ 00119 (n0,n1,n2) = self.nodePositions() 00120 centroid = self.CentroidTriangle(n0,n1,n2,debug) 00121 return centroid 00122 00123 def MassMatrix(self, isLumped=True): 00124 """ 00125 6x6 mass matrix triangle 00126 http://www.colorado.edu/engineering/cas/courses.d/IFEM.d/IFEM.Ch32.d/IFEM.Ch32.pdf 00127 """ 00128 mass = self.Mass() # rho*A*t 00129 if isLumped: # lumped mass matrix 00130 Mass = mass/3*eye(6) 00131 else: # consistent mass 00132 M = eye(6)*2. 00133 M[2,0] = M[4,0] = M[0,2] = M[0,4] = 1. 00134 M[3,1] = M[5,1] = M[1,3] = M[1,5] = 1. 00135 M[4,2] = M[2,4] = 1. 00136 M[5,3] = M[5,3] = 1. 00137 Mass = mass/12*M 00138 return Mass 00139 00140 class CTRIA3(TriShell): 00141 type = 'CTRIA3' 00142 asterType = 'TRIA3' 00143 calculixType = 'S3' 00144 def __init__(self,card=None,data=None): 00145 TriShell.__init__(self, card, data) 00146 if card: 00147 ## element ID number 00148 self.eid = int(card.field(1)) 00149 self.pid = card.field(2) 00150 00151 nids = card.fields(3,6) 00152 00153 self.thetaMcid = card.field(6,0.0) 00154 self.zOffset = card.field(7,0.0) 00155 00156 self.TFlag = card.field(10,0) 00157 self.T1 = card.field(11,1.0) 00158 self.T2 = card.field(12,1.0) 00159 self.T3 = card.field(13,1.0) 00160 else: 00161 self.eid = data[0] 00162 self.pid = data[1] 00163 nids = data[2:5] 00164 00165 self.thetaMcid = data[5] 00166 self.zOffset = data[6] 00167 self.TFlag = data[7] 00168 self.T1 = data[8] 00169 self.T2 = data[9] 00170 self.T3 = data[10] 00171 if self.T1==-1.0: self.T1=1.0 00172 if self.T2==-1.0: self.T2=1.0 00173 if self.T3==-1.0: self.T3=1.0 00174 ### 00175 self.prepareNodeIDs(nids) 00176 assert len(self.nodes)==3 00177 00178 def flipNormal(self): 00179 """ 00180 1 1 00181 * * --> * * 00182 * * * * 00183 2-----3 3-----2 00184 """ 00185 (n1,n2,n3) = self.nodes 00186 self.nodes = [n1,n3,n2] 00187 00188 def Interp(self,un): 00189 """ 00190 Interpolation based on the area coordinates 00191 """ 00192 (n0,n1,n2) = self.nodePositions() 00193 nc = (n0+n1+n2)/3. 00194 00195 a = n0-nc 00196 b = n1-nc 00197 c = n2-nc 00198 00199 tA1 = det(cross(b,c)) # 2*A1 00200 tA2 = det(cross(c,a)) # 2*A2 00201 tA3 = det(cross(a,b)) # 2*A3 00202 otA = 1./(tA1+tA2+tA3) # 1/2A 00203 00204 S = array([tA1,tA2,tA3])*otA # Ai/A 00205 u = S*un 00206 return u 00207 00208 def Jacob(self): 00209 (n0, n1, n2) = self.nodePositions() 00210 (nx0, ny0, nz0) = n0 00211 (nx1, ny1, nz1) = n1 00212 (nx2, ny2, nz2) = n2 00213 #J = matrix([n0,n1-n0,n2-n0]) 00214 00215 J = array([ [nx0, nx1-nx0, nx2-nx0], 00216 [ny0, ny1-ny0, ny2-ny0], 00217 [nz0, nz1-nz0, nz2-nz0], ]) 00218 detJ = J.det() 00219 return J 00220 00221 def getReprDefaults(self): 00222 zOffset = set_blank_if_default(self.zOffset, 0.0) 00223 TFlag = set_blank_if_default(self.TFlag, 0) 00224 thetaMcid = set_blank_if_default(self.thetaMcid, 0.0) 00225 00226 T1 = set_blank_if_default(self.T1, 1.0) 00227 T2 = set_blank_if_default(self.T2, 1.0) 00228 T3 = set_blank_if_default(self.T3, 1.0) 00229 return (thetaMcid, zOffset, TFlag, T1, T2, T3) 00230 00231 def rawFields(self): 00232 fields = ['CTRIA3', self.eid, self.Pid()]+self.nodeIDs()+[self.thetaMcid, self.zOffset, None]+[ 00233 None, self.TFlag, self.T1, self.T2, self.T3] 00234 return fields 00235 00236 def reprFields(self): 00237 (thetaMcid,zOffset,TFlag,T1,T2,T3) = self.getReprDefaults() 00238 fields = [self.type,self.eid,self.Pid()]+self.nodeIDs()+[thetaMcid,zOffset,None]+[ 00239 None,TFlag,T1,T2,T3] 00240 return fields 00241 00242 class CTRIA6(TriShell): 00243 type = 'CTRIA6' 00244 asterType = 'TRIA6' 00245 calculixType = 'S6' 00246 def __init__(self,card=None,data=None): 00247 TriShell.__init__(self, card, data) 00248 if card: 00249 ## element ID number 00250 self.eid = int(card.field(1)) 00251 self.pid = card.field(2) 00252 00253 nids = card.fields(3,9) 00254 self.thetaMcid = card.field(9 ,0.0) 00255 self.zOffset = card.field(10,0.0) 00256 00257 self.T1 = card.field(11,1.0) 00258 self.T2 = card.field(12,1.0) 00259 self.T3 = card.field(13,1.0) 00260 self.TFlag = card.field(14,0) 00261 else: 00262 self.eid = data[0] 00263 self.pid = data[1] 00264 nids = data[2:8] 00265 self.thetaMcid = data[8] 00266 self.zOffset = data[8] 00267 self.T1 = data[9] 00268 self.T2 = data[10] 00269 self.T3 = data[11] 00270 self.TFlag = data[12] 00271 self.prepareNodeIDs(nids,allowEmptyNodes=True) 00272 assert len(nids)==6,'error on CTRIA6' 00273 00274 #print self.thetaMcid 00275 #print card 00276 00277 #print "self.xi = ",self.xi 00278 #raise 00279 00280 def Thickness(self): 00281 return self.pid.Thickness() 00282 00283 def AreaCentroidNormal(self): 00284 """ 00285 returns area,centroid, normal as it's more efficient to do them together 00286 """ 00287 (n1, n2, n3, n4, n5, n6) = self.nodePositions() 00288 return Triangle_AreaCentroidNormal([n1, n2, n3]) 00289 00290 def Area(self): 00291 """ 00292 returns the normal vector 00293 \f[ \large A = \frac{1}{2} (n_0-n_1) \cross (n_0-n_2) \f] 00294 """ 00295 (n1, n2, n3, n4, n5, n6) = self.nodePositions() 00296 a = n1-n2 00297 b = n1-n3 00298 area = Area(a, b) 00299 return area 00300 00301 def Normal(self): 00302 """ 00303 returns the normal vector 00304 \f[ \large a = (n_0-n_1) \cross (n_0-n_2) \f] 00305 \f[ \large n = \frac{n}{norm(N)} \f] 00306 """ 00307 (n1,n2,n3,n4,n5,n6) = self.nodePositions() 00308 a = n1-n2 00309 b = n1-n3 00310 return Normal(a,b) 00311 00312 def Centroid(self,debug=False): 00313 """ 00314 returns the centroid 00315 \f[ \large CG = \frac{1}{3} (n_1+n_2+n_3) \f] 00316 """ 00317 (n1,n2,n3,n4,n5,n6) = self.nodePositions() 00318 centroid = self.CentroidTriangle(n1,n2,n3,debug) 00319 return centroid 00320 00321 def flipNormal(self): 00322 """ 00323 1 1 00324 ** ** 00325 * * * * 00326 4 6 --> 6 4 00327 * * * * 00328 2----5---3 3----5---2 00329 """ 00330 (n1,n2,n3,n4,n5,n6) = self.nodes 00331 self.nodes = [n1,n3,n2,n6,n5,n4] 00332 00333 def getReprDefaults(self): 00334 zOffset = set_blank_if_default(self.zOffset,0.0) 00335 TFlag = set_blank_if_default(self.TFlag,0) 00336 thetaMcid = set_blank_if_default(self.thetaMcid,0.0) 00337 00338 T1 = set_blank_if_default(self.T1,1.0) 00339 T2 = set_blank_if_default(self.T2,1.0) 00340 T3 = set_blank_if_default(self.T3,1.0) 00341 return (thetaMcid,zOffset,TFlag,T1,T2,T3) 00342 00343 def rawFields(self): 00344 fields = ['CTRIA6',self.eid,self.Pid()]+self.nodeIDs()+[self.thetaMcid,self.zOffset,None]+[ 00345 None,self.TFlag,self.T1,self.T2,self.T3] 00346 return fields 00347 00348 def reprFields(self): 00349 (thetaMcid,zOffset,TFlag,T1,T2,T3) = self.getReprDefaults() 00350 fields = ['CTRIA6',self.eid,self.Pid()]+self.nodeIDs()+[thetaMcid,zOffset,None]+[ 00351 None,TFlag,T1,T2,T3] 00352 return fields 00353 00354 class CTRIAR(TriShell): 00355 type = 'CTRIAR' 00356 def __init__(self,card=None,data=None): 00357 TriShell.__init__(self, card, data) 00358 ## element ID number 00359 self.eid = int(card.field(1)) 00360 self.pid = card.field(2) 00361 00362 nids = card.fields(3,6) 00363 self.prepareNodeIDs(nids) 00364 assert len(self.nodes)==3 00365 00366 self.thetaMcid = card.field(6,0.0) 00367 self.zOffset = card.field(7,0.0) 00368 00369 self.TFlag = card.field(10,0) 00370 self.T1 = card.field(11,1.0) 00371 self.T2 = card.field(12,1.0) 00372 self.T3 = card.field(13,1.0) 00373 00374 def Thickness(self): 00375 return self.pid.Thickness() 00376 00377 def flipNormal(self): 00378 """ 00379 1 1 00380 * * --> * * 00381 * * * * 00382 2-----3 3-----2 00383 """ 00384 (n1,n2,n3) = self.nodes 00385 self.nodes = [n1,n3,n2] 00386 00387 def getReprDefaults(self): 00388 zOffset = set_blank_if_default(self.zOffset,0.0) 00389 TFlag = set_blank_if_default(self.TFlag,0) 00390 thetaMcid = set_blank_if_default(self.thetaMcid,0.0) 00391 00392 T1 = set_blank_if_default(self.T1,1.0) 00393 T2 = set_blank_if_default(self.T2,1.0) 00394 T3 = set_blank_if_default(self.T3,1.0) 00395 return (thetaMcid,zOffset,TFlag,T1,T2,T3) 00396 00397 def rawFields(self): 00398 fields = [self.eid,self.Pid()]+self.nodeIDs()+[self.thetaMcid,self.zOffset,self.TFlag,self.T1,self.T2,self.T3] 00399 return fields 00400 00401 def reprFields(self): 00402 (thetaMcid,zOffset,TFlag,T1,T2,T3) = self.getReprDefaults() 00403 fields = ['CTRIAR',self.eid,self.Pid()]+self.nodeIDs()+[thetaMcid,zOffset,None, 00404 None,TFlag,T1,T2,T3] 00405 return fields 00406 00407 class CTRIAX(TriShell): 00408 type = 'CTRIAX' 00409 calculixType = 'CAX6' 00410 def __init__(self,card=None,data=None): 00411 TriShell.__init__(self, card, data) 00412 ## element ID number 00413 self.eid = int(card.field(1)) 00414 00415 nids = card.fields(3,9) 00416 self.prepareNodeIDs(nids,allowEmptyNodes=True) 00417 assert len(nids)==6,'error on CTRIAX' 00418 00419 def rawFields(self): 00420 fields = ['CTRIAX',self.eid,self.Pid()]+self.nodeIDs() 00421 return fields 00422 00423 def reprFields(self): 00424 return self.rawFields() 00425 00426 class CTRIAX6(TriShell): 00427 """ 00428 Nodes defined in a non-standard way 00429 5 00430 / \ 00431 6 4 00432 / \ 00433 1----2----3 00434 """ 00435 type = 'CTRIAX6' 00436 #calculixType = 'CAX6' 00437 def __init__(self,card=None,data=None): 00438 TriShell.__init__(self, card, data) 00439 ## element ID number 00440 self.eid = int(card.field(1)) 00441 self.mid = int(card.field(2)) 00442 00443 nids = card.fields(3,9) 00444 self.prepareNodeIDs(nids,allowEmptyNodes=True) 00445 assert len(nids)==6,'error on CTRIAX6' 00446 00447 ## theta 00448 self.th = card.field(10,0.0) 00449 00450 def Area(self): 00451 """ 00452 returns the normal vector 00453 \f[ \large A = \frac{1}{2} (n_0-n_1) \cross (n_0-n_2) \f] 00454 """ 00455 (n1,n2,n3,n4,n5,n6) = self.nodePositions() 00456 a = n1-n3 00457 b = n1-n5 00458 area = Area(a,b) 00459 return area 00460 00461 def Thickness(self): 00462 raise AttributeError('CTRIAX6 does not have a thickness') 00463 00464 def Nsm(self): 00465 raise AttributeError('CTRIAX6 does not have a non-structural mass') 00466 00467 def crossReference(self,model): 00468 self.nodes = model.Nodes(self.nodes) 00469 self.mid = model.Material(self.mid) 00470 00471 def Mid(self): 00472 if isinstance(self.mid,int): 00473 return self.mid 00474 return self.mid.mid 00475 00476 def flipNormal(self): 00477 """ 00478 5 5 00479 / \ / \ 00480 6 4 --> 6 4 00481 / \ / \ 00482 1----2----3 1----2----3 00483 """ 00484 (n1,n2,n3,n4,n5,n6) = self.nodes 00485 self.nodes = [n1,n6,n5,n4,n3,n2] 00486 00487 def rawFields(self): 00488 fields = ['CTRIAX6',self.eid,self.Mid(),self.Pid()]+self.nodeIDs()+[ 00489 self.th] 00490 return fields 00491 00492 def reprFields(self): 00493 th = set_default_if_blank(self.th, 0.0) 00494 fields = ['CTRIAX6', self.eid, self.Mid()]+self.nodeIDs()+[th] 00495 return fields 00496 00497 class QuadShell(ShellElement): 00498 def __init__(self,card=None,data=None): 00499 ShellElement.__init__(self, card, data) 00500 00501 def Thickness(self): 00502 return self.pid.Thickness() 00503 00504 def Normal(self): 00505 (n1,n2,n3,n4) = self.nodePositions() 00506 a = n1-n3 00507 b = n2-n4 00508 return Normal(a,b) 00509 00510 def AreaCentroidNormal(self): 00511 (area,centroid) = self.AreaCentroid() 00512 normal = self.Normal() 00513 return (area,centroid,normal) 00514 00515 def AreaCentroid(self,debug=False): 00516 """ 00517 1-----2 00518 | /| 00519 | A1/ | 00520 | / | 00521 |/ A2 | 00522 4-----3 00523 00524 centroid 00525 c = sum(ci*Ai)/sum(A) 00526 where: 00527 c=centroid 00528 A=area 00529 """ 00530 #if debug: 00531 # print("nodes = %s" %(self.nodes)) 00532 (n1,n2,n3,n4) = self.nodePositions() 00533 a = n1-n2 00534 b = n2-n4 00535 area1 = Area(a,b) 00536 c1 = self.CentroidTriangle(n1,n2,n4) 00537 00538 a = n2-n4 00539 b = n2-n3 00540 area2 = Area(a,b) 00541 c2 = self.CentroidTriangle(n2,n3,n4) 00542 00543 area = area1+area2 00544 centroid = (c1*area1+c2*area2)/area 00545 if debug: 00546 print("c1=%s \n c2=%s \n a1=%s a2=%s" %(c1,c2,area1,area2)) 00547 print("type(centroid=%s centroid=%s \n" %(type(centroid),centroid)) 00548 return(area,centroid) 00549 ### 00550 00551 def Centroid(self,debug=False): 00552 #nodes = self.nodePositions() 00553 (area,centroid) = self.AreaCentroid(debug) 00554 return centroid 00555 00556 def Area(self): 00557 """ 00558 \f[ A = \frac{1}{2} \lvert (n_1-n_3) \times (n_2-n_4) \rvert \f] 00559 where a and b are the quad's cross node point vectors 00560 """ 00561 (n1,n2,n3,n4) = self.nodePositions() 00562 a = n1-n3 00563 b = n2-n4 00564 area = Area(a,b) 00565 return area 00566 ### 00567 00568 def MassMatrix(self, isLumped=True, gauss=1): 00569 """ 00570 6x6 mass matrix triangle 00571 http://www.colorado.edu/engineering/cas/courses.d/IFEM.d/IFEM.Ch32.d/IFEM.Ch32.pdf 00572 """ 00573 mass = self.Mass() # rho*A*t 00574 if isLumped: # lumped mass matrix 00575 Mass = mass/3*eye(6) 00576 else: # consistent mass 00577 if gauss==1: 00578 M = eye(8)*1. # 1x1 Gauss Rule 00579 M[2,0] = M[3,1] = M[4,2] = M[5,3] = M[6,4] = M[7,5] = 1. 00580 M[4,0] = M[5,1] = M[6,2] = M[7,3] = 1. 00581 M[6,0] = M[7,1] = 1. 00582 00583 M[0,2] = M[1,3] = M[2,4] = M[3,5] = M[4,6] = M[5,7] = 1. 00584 M[0,4] = M[1,5] = M[2,6] = M[3,7] = 1. 00585 M[0,6] = M[1,7] = 1. 00586 Mass = mass/32*M 00587 if gauss==2: 00588 M = eye(8)*4. # 2x2 Gauss Rule 00589 M[2,0] = M[3,1] = M[4,2] = M[5,3] = M[6,4] = M[7,5] = 2. 00590 M[4,0] = M[5,1] = M[6,2] = M[7,3] = 1. 00591 M[6,0] = M[7,1] = 2. 00592 00593 M[0,2] = M[1,3] = M[2,4] = M[3,5] = M[4,6] = M[5,7] = 2. 00594 M[0,4] = M[1,5] = M[2,6] = M[3,7] = 1. 00595 M[0,6] = M[1,7] = 2. 00596 Mass = mass/72*M 00597 return Mass 00598 00599 def flipNormal(self): 00600 """ 00601 1---2 1---4 00602 | | --> | | 00603 | | | | 00604 4---3 2---3 00605 """ 00606 (n1,n2,n3,n4) = self.nodes 00607 self.nodes = [n1,n4,n3,n2] 00608 00609 def getReprDefaults(self,debug=False): 00610 zOffset = set_blank_if_default(self.zOffset,0.0) 00611 TFlag = set_blank_if_default(self.TFlag,0) 00612 thetaMcid = set_blank_if_default(self.thetaMcid,0.0) 00613 00614 T1 = set_blank_if_default(self.T1,1.0) 00615 T2 = set_blank_if_default(self.T2,1.0) 00616 T3 = set_blank_if_default(self.T3,1.0) 00617 T4 = set_blank_if_default(self.T4,1.0) 00618 if debug: 00619 #if 1: 00620 print("eid = %s" %(self.eid)) 00621 print("nodes = %s" %(self.nodes)) 00622 00623 print("self.zOffset = %s" %(self.zOffset)) 00624 print("self.TFlag = %s" %(self.TFlag)) 00625 print("self.thetaMcid = %s" %(self.thetaMcid)) 00626 00627 print("zOffset = %s" %(zOffset)) 00628 print("TFlag = %s" %(TFlag)) 00629 print("thetaMcid = %s" %(thetaMcid)) 00630 00631 print("T1 = %s" %(T1)) 00632 print("T2 = %s" %(T2)) 00633 print("T3 = %s" %(T3)) 00634 print("T4 = %s\n" %(T4)) 00635 return (thetaMcid,zOffset,TFlag,T1,T2,T3,T4) 00636 00637 class CSHEAR(QuadShell): 00638 type = 'CSHEAR' 00639 calculixType = 'S4' 00640 def __init__(self,card=None,data=None): 00641 QuadShell.__init__(self, card, data) 00642 if card: 00643 self.eid = card.field(1) 00644 self.pid = card.field(2) 00645 nids = card.fields(3,7) 00646 else: 00647 self.eid = data[0] 00648 self.pid = data[1] 00649 nids = data[2:] 00650 ### 00651 self.prepareNodeIDs(nids) 00652 assert len(self.nodes)==4 00653 00654 def Normal(self): 00655 (n1,n2,n3,n4) = self.nodePositions() 00656 a = n1-n3 00657 b = n2-n4 00658 return Normal(a,b) 00659 00660 def AreaCentroidNormal(self): 00661 (area,centroid) = self.AreaCentroid() 00662 normal = self.Normal() 00663 return (area,centroid,normal) 00664 00665 def AreaCentroid(self,debug=False): 00666 """ 00667 1-----2 00668 | /| 00669 | A1/ | 00670 | / | 00671 |/ A2 | 00672 4-----3 00673 00674 centroid 00675 c = sum(ci*Ai)/sum(A) 00676 where: 00677 c=centroid 00678 A=area 00679 """ 00680 #if debug: 00681 # print("nodes = %s" %(self.nodes)) 00682 (n1,n2,n3,n4) = self.nodePositions() 00683 a = n1-n2 00684 b = n2-n4 00685 area1 = Area(a,b) 00686 c1 = self.CentroidTriangle(n1,n2,n4) 00687 00688 a = n2-n4 00689 b = n2-n3 00690 area2 = Area(a,b) 00691 c2 = self.CentroidTriangle(n2,n3,n4) 00692 00693 area = area1+area2 00694 centroid = (c1*area1+c2*area2)/area 00695 if debug: 00696 print("c1=%s \n c2=%s \n a1=%s a2=%s" %(c1,c2,area1,area2)) 00697 print("type(centroid=%s centroid=%s \n" %(type(centroid),centroid)) 00698 return(area,centroid) 00699 ### 00700 00701 def Centroid(self,debug=False): 00702 (area,centroid) = self.AreaCentroid(debug) 00703 return centroid 00704 00705 def Area(self): 00706 """ 00707 \f[ A = \frac{1}{2} \lvert (n_1-n_3) \times (n_2-n_4) \rvert \f] 00708 where a and b are the quad's cross node point vectors 00709 """ 00710 (n1,n2,n3,n4) = self.nodePositions() 00711 a = n1-n3 00712 b = n2-n4 00713 area = Area(a,b) 00714 return area 00715 ### 00716 00717 def flipNormal(self): 00718 """ 00719 1---2 1---4 00720 | | --> | | 00721 | | | | 00722 4---3 2---3 00723 """ 00724 (n1,n2,n3,n4) = self.nodes 00725 self.nodes = [n1,n4,n3,n2] 00726 00727 def rawFields(self): 00728 fields = ['CSHEAR',self.eid,self.Pid()]+self.nodeIDs() 00729 return fields 00730 00731 def reprFields(self): 00732 return self.rawFields() 00733 00734 00735 class CQUAD4(QuadShell): 00736 type = 'CQUAD4' 00737 asterType = 'QUAD4 # CQUAD4' 00738 calculixType = 'S4' 00739 def __init__(self,card=None,data=None): 00740 QuadShell.__init__(self, card, data) 00741 if card: 00742 ## element ID number 00743 self.eid = int(card.field(1)) 00744 self.pid = card.field(2) 00745 00746 nids = card.fields(3,7) 00747 00748 self.thetaMcid = card.field(7,0.0) 00749 self.zOffset = card.field(8,0.0) 00750 00751 self.TFlag = card.field(10,0) 00752 self.T1 = card.field(11,1.0) 00753 self.T2 = card.field(12,1.0) 00754 self.T3 = card.field(13,1.0) 00755 self.T4 = card.field(14,1.0) 00756 else: 00757 self.eid = data[0] 00758 self.pid = data[1] 00759 nids = data[2:6] 00760 00761 self.thetaMcid = data[6] 00762 self.zOffset = data[7] 00763 self.TFlag = data[8] 00764 self.T1 = data[9] 00765 self.T2 = data[10] 00766 self.T3 = data[11] 00767 self.T4 = data[12] 00768 if self.T1==-1.0: self.T1=1.0 00769 if self.T2==-1.0: self.T2=1.0 00770 if self.T3==-1.0: self.T3=1.0 00771 if self.T4==-1.0: self.T4=1.0 00772 ### 00773 self.prepareNodeIDs(nids) 00774 assert len(self.nodes)==4,'CQUAD4' 00775 00776 #print "self.xi = ",self.xi 00777 #print "nodes = ",self.nodes 00778 #for nid in nids: 00779 # self.nodes.append(int(nid)) 00780 00781 #print 'self.T1 = ',self.T1 00782 #if self.id==20020: 00783 #print "thetaMcid = ",card.field(7) 00784 #print "actual = ",self.thetaMcid 00785 #print str(self) 00786 00787 def flipNormal(self): 00788 """ 00789 1---2 1---4 00790 | | --> | | 00791 | | | | 00792 4---3 2---3 00793 """ 00794 (n1,n2,n3,n4) = self.nodes 00795 self.nodes = [n1,n4,n3,n2] 00796 00797 def writeAsCTRIA3(self, newID): 00798 """ 00799 triangle - 012 00800 triangle - 023 00801 """ 00802 zOffset = set_blank_if_default(self.zOffset, 0.0) 00803 nodes1 = [self.nodes[0], self.nodes[1], self.nodes[2]] 00804 nodes2 = [self.nodes[0], self.nodes[2], self.nodes[3]] 00805 fields1 = ['CTRIA3', self.eid, self.Pid()]+nodes1+[self.thetaMcid, zOffset] 00806 fields2 = ['CTRIA3', newID, self.Pid()]+nodes2+[self.thetaMcid, zOffset] 00807 return self.printCard(fields1)+self.printCard(fields2) 00808 00809 def rawFields(self): 00810 fields = [self.type,self.eid,self.Pid()]+self.nodeIDs()+[self.thetaMcid,self.zOffset,self.TFlag,self.T1,self.T2,self.T3,self.T4] 00811 return fields 00812 00813 def reprFields(self): 00814 debug = False 00815 (thetaMcid,zOffset,TFlag,T1,T2,T3,T4) = self.getReprDefaults(debug=debug) 00816 00817 fields = ['CQUAD4',self.eid,self.Pid()]+self.nodeIDs()+[thetaMcid,zOffset, 00818 None,TFlag,T1,T2,T3,T4] 00819 return fields 00820 00821 class CQUADR(QuadShell): 00822 type = 'CQUADR' 00823 #calculixType = 'CAX8' 00824 def __init__(self,card=None,data=None): 00825 QuadShell.__init__(self, card, data) 00826 if card: 00827 ## element ID number 00828 self.eid = int(card.field(1)) 00829 self.pid = card.field(2) 00830 00831 nids = card.fields(3,7) 00832 00833 self.thetaMcid = card.field(7,0.0) 00834 self.zOffset = card.field(8,0.0) 00835 00836 self.TFlag = card.field(10,0) 00837 self.T1 = card.field(11,1.0) 00838 self.T2 = card.field(12,1.0) 00839 self.T3 = card.field(13,1.0) 00840 self.T4 = card.field(14,1.0) 00841 else: 00842 self.eid = data[0] 00843 self.pid = data[1] 00844 nids = data[2:6] 00845 00846 self.thetaMcid = data[6] 00847 self.zOffset = data[7] 00848 self.TFlag = data[8] 00849 self.T1 = data[9] 00850 self.T2 = data[10] 00851 self.T3 = data[11] 00852 self.T4 = data[12] 00853 if self.T1==-1.0: self.T1=1.0 00854 if self.T2==-1.0: self.T2=1.0 00855 if self.T3==-1.0: self.T3=1.0 00856 if self.T4==-1.0: self.T4=1.0 00857 ### 00858 self.prepareNodeIDs(nids) 00859 assert len(self.nodes)==4,'CQUADR' 00860 00861 def Thickness(self): 00862 return self.pid.Thickness() 00863 00864 def flipNormal(self): 00865 """ 00866 1---2 1---4 00867 | | --> | | 00868 | | | | 00869 4---3 2---3 00870 """ 00871 (n1,n2,n3,n4) = self.nodes 00872 self.nodes = [n1,n4,n3,n2] 00873 00874 def rawFields(self): 00875 fields = ['CQUADR',self.eid,self.Pid()]+self.nodeIDs()+[self.thetaMcid,self.zOffset, 00876 None,self.TFlag,self.T1,self.T2,self.T3,self.T4,] 00877 return fields 00878 00879 def reprFields(self): 00880 (thetaMcid,zOffset,TFlag,T1,T2,T3,T4) = self.getReprDefaults() 00881 fields = ['CQUADR',self.eid,self.Pid()]+self.nodeIDs()+[thetaMcid,zOffset, 00882 None,TFlag,T1,T2,T3,T4] 00883 return fields 00884 00885 class CQUAD(QuadShell): 00886 type = 'CQUAD' 00887 def __init__(self,card=None,data=None): 00888 QuadShell.__init__(self, card, data) 00889 ## element ID number 00890 self.eid = int(card.field(1)) 00891 self.pid = card.field(2) 00892 00893 nids = card.fields(3,12) 00894 self.prepareNodeIDs(nids) 00895 assert len(self.nodes)==9 00896 00897 self.thetaMcid = card.field(7,0.0) 00898 self.zOffset = card.field(8,0.0) 00899 00900 self.TFlag = card.field(10,0) 00901 self.T1 = card.field(11,1.0) 00902 self.T2 = card.field(12,1.0) 00903 self.T3 = card.field(13,1.0) 00904 self.T4 = card.field(14,1.0) 00905 00906 def Thickness(self): 00907 return self.pid.Thickness() 00908 00909 def flipNormal(self): 00910 """ 00911 1--5--2 1--8--4 00912 | | --> | | 00913 8 9 6 5 9 7 00914 | | | | 00915 4--7--3 2--6--3 00916 """ 00917 (n1,n2,n3,n4,n5,n6,n7,n8,n9) = self.nodes 00918 self.nodes = [n1,n4,n3,n2, n8,n7,n6,n5, n9] 00919 00920 def rawFields(self): 00921 fields = ['CQUAD',self.eid,self.Pid()]+self.nodeIDs() 00922 return fields 00923 00924 def reprFields(self): 00925 (thetaMcid,zOffset,TFlag,T1,T2,T3,T4) = self.getReprDefaults() 00926 fields = ['CQUAD',self.eid,self.Pid()]+self.nodeIDs() 00927 return fields 00928 00929 class CQUAD8(QuadShell): 00930 type = 'CQUAD8' 00931 asterType = 'QUAD8' 00932 def __init__(self,card=None,data=None): 00933 QuadShell.__init__(self, card, data) 00934 if card: 00935 ## element ID number 00936 self.eid = int(card.field(1)) 00937 self.pid = card.field(2) 00938 nids = card.fields(3,11) 00939 self.T1 = card.field(11,1.0) 00940 self.T2 = card.field(12,1.0) 00941 self.T3 = card.field(13,1.0) 00942 self.T4 = card.field(14,1.0) 00943 self.thetaMcid = card.field(15,0.0) 00944 self.zOffset = card.field(16,0.0) 00945 self.TFlag = card.field(17,0) 00946 else: 00947 #print "CQUAD8 = ",data 00948 #(6401, 00949 #6400, 00950 #6401, 6402, 6405, 6403, 0, 0, 6404, 0, 00951 #-1.0, -1.0, -1.0, -1.0, 00952 #0.0, 0) 00953 self.eid = data[0] 00954 self.pid = data[1] 00955 nids = data[2:10] 00956 self.T1 = data[10] 00957 self.T2 = data[11] 00958 self.T3 = data[12] 00959 self.T4 = data[13] 00960 self.thetaMcid = data[14] 00961 self.zOffset = data[14] 00962 self.TFlag = data[15] 00963 ### 00964 self.prepareNodeIDs(nids,allowEmptyNodes=True) 00965 assert len(self.nodes)==8 00966 00967 def Thickness(self): 00968 return self.pid.Thickness() 00969 00970 def flipNormal(self): 00971 """ 00972 1--5--2 1--8--4 00973 | | --> | | 00974 8 6 5 7 00975 | | | | 00976 4--7--3 2--6--3 00977 """ 00978 (n1,n2,n3,n4,n5,n6,n7,n8) = self.nodes 00979 self.nodes = [n1,n4,n3,n2, n8,n7,n6,n5] 00980 00981 def Normal(self): 00982 (n1,n2,n3,n4,n5,n6,n7,n8) = self.nodePositions() 00983 a = n1-n3 00984 b = n2-n4 00985 return Normal(a,b) 00986 00987 def AreaCentroid(self,debug=False): 00988 """ 00989 1-----2 00990 | /| 00991 | A1/ | 00992 | / | 00993 |/ A2 | 00994 4-----3 00995 00996 centroid 00997 c = sum(ci*Ai)/sum(A) 00998 where: 00999 c=centroid 01000 A=area 01001 """ 01002 #if debug: 01003 # print("nodes = %s" %(self.nodes)) 01004 (n1,n2,n3,n4,n5,n6,n7,n8) = self.nodePositions() 01005 a = n1-n2 01006 b = n2-n4 01007 area1 = Area(a,b) 01008 c1 = self.CentroidTriangle(n1,n2,n4) 01009 01010 a = n2-n4 01011 b = n2-n3 01012 area2 = Area(a,b) 01013 c2 = self.CentroidTriangle(n2,n3,n4) 01014 01015 area = area1+area2 01016 centroid = (c1*area1+c2*area2)/area 01017 if debug: 01018 print("c1=%s \n c2=%s \n a1=%s a2=%s" %(c1,c2,area1,area2)) 01019 print("type(centroid=%s centroid=%s \n" %(type(centroid),centroid)) 01020 return(area,centroid) 01021 ### 01022 01023 def Area(self): 01024 """ 01025 \f[ A = \frac{1}{2} \lvert (n_1-n_3) \times (n_2-n_4) \rvert \f] 01026 where a and b are the quad's cross node point vectors 01027 """ 01028 (n1,n2,n3,n4,n5,n6,n7,n8) = self.nodePositions() 01029 a = n1-n3 01030 b = n2-n4 01031 area = Area(a,b) 01032 return area 01033 ### 01034 01035 def rawFields(self): 01036 fields = ['CQUAD8',self.eid,self.Pid()]+self.nodeIDs()+[ 01037 self.T1,self.T2,self.T3,self.T4,self.thetaMcid,self.zOffset, 01038 self.TFlag] 01039 return fields 01040 01041 def reprFields(self): 01042 (thetaMcid,zOffset,TFlag,T1,T2,T3,T4) = self.getReprDefaults() 01043 fields = ['CQUAD8',self.eid,self.Pid()]+self.nodeIDs()+[ 01044 T1,T2,T3,T4,thetaMcid,zOffset, 01045 TFlag] 01046 return fields 01047 01048 class CQUADX(QuadShell): 01049 type = 'CQUADX' 01050 calculixType = 'CAX8' 01051 def __init__(self,card=None,data=None): 01052 QuadShell.__init__(self, card, data) 01053 ## element ID number 01054 self.eid = int(card.field(1)) 01055 self.pid = card.field(2) 01056 01057 nids = card.fields(3,12) 01058 self.prepareNodeIDs(nids,allowEmptyNodes=True) 01059 assert len(self.nodes)==9 01060 01061 def Thickness(self): 01062 return self.pid.Thickness() 01063 01064 def flipNormal(self): 01065 """ 01066 1--5--2 1--8--4 01067 | | --> | | 01068 8 9 6 5 9 7 01069 | | | | 01070 4--7--3 2--6--3 01071 """ 01072 (n1,n2,n3,n4,n5,n6,n7,n8,n9) = self.nodes 01073 self.nodes = [n1,n4,n3,n2, n8,n7,n6,n5, n9] 01074 01075 def rawFields(self): 01076 fields = ['CQUADX',self.eid,self.Pid()]+self.nodeIDs() 01077 return fields 01078 01079 def reprFields(self): 01080 return self.rawFields()