def cone(r0, r1, h, t=360., nr=1, nt=24, diag=None): """Constructs a Formex which is (a sector of) a circle / (truncated) cone / cylinder. r0,r1,h are the lower and upper radius and the height of the truncated cone. All can be positive, negative or zero. Special cases: r0 = r1 : cylinder h = 0 : (flat) circle r0 = 0 or r1 = 0 : untruncated cone Only a sector of the structure, with opening angle t, is modeled. The default results in a full circumference. The cone is modeled by nr elements in height direction and nt elements in circumferential direction. By default, the result is a 4-plex Formex whose elements are quadrilaterals (some of which may collapse into triangles). If diag='up' or diag = 'down', all quads are divided by an up directed diagonal and a plex-3 Formex results. """ B = simple.rectangle(nt, nr, 1., 1., diag=diag) # grid with size 1x1 B = B.map(lambda x, y, z: [x, y, r0 - y * (r0 - r1)]) # translate and tilt it B = B.scale([t, h, 1.]) # scale to fit parameters return B.cylindrical(dir=[2, 0, 1]) # roll it into a cone
def createRectPart(res=None): """Create a rectangular domain from user input""" if not checkNoModel(): return if res is None: res = askItems([ _I('P0', P[0], itemtype='point', ndim=2, tooltip='The x- and y-value of one of the corners'), _I('P2', P[2], itemtype='point', ndim=2, tooltip='The x- and y-value of the opposite corner'), _I('nx', nx, tooltip='Number of elements along side 0-1'), _I('ny', ny, tooltip='Number of elements along side 1-2'), _I('eltype', eltype, itemtype='radio', choices=['quad', 'tri-u', 'tri-d']), ]) if res: storeData(res) x, y = P.x, P.y if x[0] > x[2]: x[0], x[2] = x[2], x[0] if y[0] > y[2]: y[0], y[2] = y[2], y[0] diag = {'quad': '', 'tri-u': 'u', 'tri-d': 'd'}[eltype] M = rectangle(nx, ny, x[2] - x[0], y[2] - y[0], diag=diag).toMesh().trl([x[0], y[0], 0]) addPart(M)
def run(): clear() smoothwire() layout(3) F = simple.rectangle(4, 3) M = F.toMesh() #M.attrib(color=yellow) # add some fields # 1. distance from point 7, defined at nodes data = length(M.coords - M.coords[7]) M.addField('node', data, 'dist') # 2. convert to field defined at element nodes M.convertField('dist', 'elemn', 'distn') # 3. convert to field constant over elements M.convertField('distn', 'elemc', 'distc') print(M.fieldReport()) # draw two fields viewport(0) drawField(M.getField('distn')) zoom(1.25) viewport(1) drawField(M.getField('distc')) zoom(1.25) viewport(2) drawField(M.getField('dist')) zoom(1.25)
def run(): clear() smoothwire() nx = 4 ny = 3 nz = 7 delay(2) # A rectangular mesh M1 = simple.rectangle(nx, ny).toMesh().setProp(1) # Same mesh, rotated and translated M2 = M1.rotate(45, 0).translate([1., -1., nz]).setProp(3) draw([M1, M2]) # Leave out the first and the last two elements sel = arange(M1.nelems())[1:-2] m1 = M1.select(sel) m2 = M2.select(sel) clear() draw([m1, m2], view=None) # Connect both meshes to a hexaeder mesh m = m1.connect(m2, nz) clear() draw(m, color=red, view=None)
def run(): clear() smoothwire() view('iso') # create a 2D xy mesh nx, ny = 6, 2 G = simple.rectangle(1, 1, 1., 1.).replic2(nx, ny) M = G.toMesh() draw(M, color='red') # create a 3D axial-symmetric mesh by REVOLVING n, a = 8, 45. R = M.revolve(n, angle=a, axis=1, around=[1., 0., 0.]) draw(R, color='yellow') # reduce the degenerate elements to WEDGE6 clear() ML = R.fuse().splitDegenerate() # keep only the non-empty meshes ML = [m for m in ML if m.nelems() > 0] print("After splitting: %s meshes:" % len(ML)) for m in ML: print(" %s elements of type %s" % (m.nelems(), m.elName())) ML = [Mi.setProp(i + 4) for i, Mi in enumerate(ML)] draw(ML)
def icon_wirenone(): view('front') F = rectangle(2, 2) draw(F, color=red) smooth() zoomAll() zoomIn() zoomIn()
def icon_wireall(): view('front') F = rectangle(2, 2) draw(F, color=red, linewidth=2) smoothwire() zoomAll() zoomIn() zoomIn()
def icon_wireborder(): view('front') F = rectangle(2, 2) draw(F, color=red) B = F.toMesh().getBorderMesh() draw(B, color=black, linewidth=2, ontop=True, opak=True, nolight=True) smooth() zoomAll() zoomIn() zoomIn()
def createGrid(): """Create the grid from global parameters""" global B nx, ny = grid_size b, h = x_range[1]-x_range[0], y_range[1]-y_range[0] if grid_base.startswith('tri'): diag = grid_base[-1] else: diag = '' B = rectangle(nx, ny, b, h, diag=diag, bias=grid_bias).translate([x_range[0], y_range[0], 1.]) if grid_skewness != 0.0: B = B.shear(0, 1, grid_skewness*b*ny/(h*nx)) if x_clip: B = B.clip(B.test('any', dir=0, min=x_clip[0]+tol*b, max=x_clip[1]-tol*b)) if y_clip: B = B.clip(B.test('any', dir=1, min=y_clip[0]+tol*h, max=y_clip[1]-tol*h)) export({grid_name:B})
def run(): reset() smoothwire() transparent() lights(True) nx, ny = 20, 10 F = simple.rectangle(nx, ny) F = F.trl(-F.center() + [0., 0., nx / 2]) draw(F) G = F.projectOnSphere(ny) draw(G, color=red) H = F.rotate(30).projectOnCylinder(ny) draw(H, color=blue)
def run(): reset() clear() linewidth(1) delay(1) if roof is None: createRoof() F = roof.rotate(-90, 0) # put the structure upright draw(F) createView('myview1', (30., 0., 0.), True) view('myview1', True) setDrawOptions({'bbox': 'last'}) for i in range(19): createView('myview2', (i * 10., 20., 0.), True) view('myview2', True) delay(0.1) # fly tru if ack("Do you want to fly through the structure?"): totaltime = 10 nsteps = 50 # make sure bottom iz at y=0 and structure is centered in (x,z) F = F.centered() F = F.translate(1, -F.bbox()[0, 1]) clear() linewidth(1) draw(F) bb = F.bbox() # create a bottom plate B = simple.rectangle(1, 1).swapAxes(1, 2).centered().scale( F.sizes()[0] * 1.5) smooth() draw(B, color='slategrey') # Fly at reasonable height bb[0, 1] = bb[1, 1] = 170. ends = interpolate(Formex([[bb[0]]]), Formex([[bb[1]]]), [-0.5, 0.6]) path = Formex(ends.coords.reshape(-1, 2, 3)).divide(nsteps) linewidth(2) draw(path) steptime = float(totaltime) / nsteps flyAlong(path, sleeptime=steptime)
def createQuadPart(res=None): """Create a quadrilateral domain from user input""" if not checkNoModel(): return if res is None: res = askItems([ _I('isopar', isopar, choices=['quad4', 'quad8', 'quad9'], tooltip='Isoparametric model'), _I('P0', P[0], itemtype='point', ndim=2, tooltip='First corner'), _I('P1', P[1], itemtype='point', ndim=2, tooltip='Second corner'), _I('P2', P[2], itemtype='point', ndim=2, tooltip='Third corner'), _I('P3', P[3], itemtype='point', ndim=2, tooltip='Fourth corner'), _I('P4', P[4], itemtype='point', ndim=2, tooltip='Midside P0-P1'), _I('P5', P[5], itemtype='point', ndim=2, tooltip='Midside P1-P2'), _I('P6', P[6], itemtype='point', ndim=2, tooltip='Midside P2-P3'), _I('P7', P[7], itemtype='point', ndim=2, tooltip='Midside P3-P4'), _I('P8', P[8], itemtype='point', ndim=2, tooltip='Center point'), _I('nx', nx), _I('ny', ny), _I('eltype', eltype, itemtype='radio', choices=['quad', 'tri-u', 'tri-d']), ], enablers=[ ('isopar', 'quad8', 'P4', 'P5', 'P6', 'P7'), ('isopar', 'quad9', 'P4', 'P5', 'P6', 'P7', 'P8'), ]) if res: storeData(res) diag = {'quad': '', 'tri-u': 'u', 'tri-d': 'd'}[eltype] xold = Coords(getattr(elements, isopar.capitalize()).vertices) np = int(isopar[-1]) xnew = P[:np] M = rectangle(nx, ny, 1., 1., diag=diag).toMesh().isopar(isopar, xnew, xold) addPart(M)
def run(): resetAll() setDrawOptions({'clear': True, 'shrink': True}) delay(1) # A square domain of triangles n = 16 F = simple.rectangle(n, n, diag='d') # Novation (Spots) m = 4 h = 0.15 * n r = n // m s = n // r a = [[r * i, r * j, h] for j in range(1, s) for i in range(1, s)] for p in a: F = F.bump(2, p, lambda x: exp(-0.75 * x), [0, 1]) # Define a plane plane_p = [3.2, 3.0, 0.0] plane_n = [2.0, 1.0, 0.0] #compute number of nodes above/below the plane dist = F.distanceFromPlane(plane_p, plane_n) above = (dist > 0.0).sum(-1) below = (dist < 0.0).sum(-1) # Define a line by a point and direction line_p = [0.0, 0.0, 0.0] line_n = [1., 1., 1. / 3] d = F.distanceFromLine(line_p, line_n) # compute number of nodes closer that 2.2 to line close = (d < 2.2).sum(-1) sel = [ F.test(nodes=0, dir=0, min=1.5, max=3.5), F.test(nodes=[0, 1], dir=0, min=1.5, max=3.5), F.test(nodes=[0, 1, 2], dir=0, min=1.5, max=3.5), F.test(nodes='all', dir=1, min=1.5, max=3.5), F.test(nodes='any', dir=1, min=1.5, max=3.5), F.test(nodes='none', dir=1, min=1.5), (above > 0) * (below > 0), close == 3, ] txt = [ 'First node has x between 1.5 and 3.5', 'First two nodes have x between 1.5 and 3.5', 'First 3 nodes have x between 1.5 and 3.5', 'All nodes have y between 1.5 and 3.5', 'Any node has y between 1.5 and 3.5', 'No node has y larger than 1.5', 'Touching the plane P = [3.2,3.0,0.0], n = [2.0,1.0,0.0]', '3 nodes close to line through [0.0,0.0,0.0] and [1.0,1.0,1.0]', ] draw(F) color = getcfg('canvas/colormap')[1:] # omit the black while len(color) < len(sel): color.extend(color) color[0:0] = ['black'] # restore the black prop = zeros(F.nelems()) i = 1 for s, t in zip(sel, txt): prop[s] = i F.setProp(prop) print('%s (%s): %s' % (color[i], sum(s), t)) draw(F) i += 1 print('Clip Formex to last selection') draw(F.clip(s), view=None) print('Clip complement') draw(F.cclip(s))
def Grid(nx=(1, 1, 1), ox=(0.0, 0.0, 0.0), dx=(1.0, 1.0, 1.0), lines='b', planes='b', linecolor=colors.black, planecolor=colors.white, alpha=0.3, **kargs): """Creates a (set of) grid(s) in (some of) the coordinate planes. Parameters: - `nx`: a list of 3 integers, specifying the number of divisions of the grid in the three coordinate directions. A zero value may be specified to avoid the grid to extend in that direction. Thus, setting the last value to zero will result in a planar grid in the xy-plane. - `ox`: a list of 3 floats: the origin of the grid. - `dx`: a list of 3 floats: the step size in each coordinate direction. - `planes`: one of 'first', 'box', 'all', 'no' (the string can be shortened to the first chartacter): specifies how many planes are drawn in each direction: 'f' only draws the first, 'b' draws the first and the last, resulting in a box, 'a' draws all planes, 'n' draws no planes. Returns a list with up to two Meshes: the planes, and the lines. """ from pyformex import simple from pyformex.olist import List from pyformex.mesh import Mesh G = List() planes = planes[:1].lower() P = [] L = [] for i in range(3): n0, n1, n2 = np.roll(nx, i) d0, d1, d2 = np.roll(dx, i) if n0 * n1: if planes != 'n': M = simple.rectangle(b=n0 * d0, h=n1 * d1) if n2: if planes == 'b': M = M.replic(2, dir=2, step=n2 * d2) elif planes == 'a': M = M.replic(n2 + 1, dir=2, step=d2) P.append(M.rollAxes(-i).toMesh()) if lines != 'n': M = Formex('1').scale(n0*d0).replic(n1+1,dir=1,step=d1) + \ Formex('2').scale(n1*d1).replic(n0+1,dir=0,step=d0) if n2: if lines == 'b': M = M.replic(2, dir=2, step=n2 * d2) elif lines == 'a': M = M.replic(n2 + 1, dir=2, step=d2) L.append(M.rollAxes(-i).toMesh()) if P: M = Mesh.concatenate(P) M.attrib(name='__grid_planes__', mode='flat', lighting=False, color=planecolor, alpha=alpha, **kargs) G.append(M) if L: M = Mesh.concatenate(L) M.attrib(name='__grid_lines__', mode='flat', lighting=False, color=linecolor, alpha=0.6, **kargs) G.append(M) return G.trl(ox)
def __init__(self, colorscale, ncolors, x, y, w, h, ngrid=0, linewidth=None, nlabel=-1, size=18, font=None, dec=2, scale=0, lefttext=False, **kargs): """Initialize the ColorLegend.""" from pyformex.gui import colorscale as cs self.cl = cs.ColorLegend(colorscale, ncolors) self.x = float(x) self.y = float(y) self.w = float(w) self.h = float(h) self.ngrid = int(ngrid) if self.ngrid < 0: self.ngrid = ncolors if self.ngrid > 50: self.ngrid = 0 self.linewidth = saneLineWidth(linewidth) self.nlabel = int(nlabel) if self.nlabel < 0: if self.ngrid > 0: self.nlabel = self.ngrid else: self.nlabel = ncolors self.dec = dec # number of decimals self.scale = 10**scale # scale all numbers with 10**scale self.lefttext = lefttext self.xgap = 4 # hor. gap between color bar and labels self.ygap = 4 # (min) vert. gap between labels F = simple.rectangle(1, ncolors, self.w, self.h).trl([self.x, self.y, 0.]) Actor.__init__(self, F, rendertype=2, lighting=False, color=self.cl.colors, **kargs) if self.ngrid > 0: F = simple.rectangle(1, self.ngrid, self.w, self.h).trl([self.x, self.y, 0.]) G = Actor(F, rendertype=2, lighting=False, color=colors.black, linewidth=self.linewidth, mode='wireframe') self.children.append(G) # labels # print("LABELS: %s" % self.nlabel) if self.nlabel > 0: from pyformex.opengl import textext if font is None: font = FontTexture.default() elif isinstance(font, (str, unicode)): font = FontTexture(font, size) self.font = font fh = self.font.height pf.debug("FONT HEIGHT %s" % fh, pf.DEBUG.DRAW) if self.lefttext: x = F.coords[0, 0, 0] - self.xgap gravity = 'W' else: x = F.coords[0, 1, 0] + self.xgap gravity = 'E' # minimum label distance dh = fh + self.ygap da = self.h / self.nlabel # Check if labels will fit if da < dh and self.nlabel == ncolors: # reduce number of labels self.nlabel = int(self.h / dh) da = self.h / self.nlabel vals = cs.ColorLegend(colorscale, self.nlabel).limits #print("VALS",vals) ypos = self.y + da * np.arange(self.nlabel + 1) yok = self.y - 0.01 * dh for (y, v) in zip(ypos, vals): #print(y,v,yok) if y >= yok: t = textext.Text(("%%.%df" % self.dec) % (v * self.scale), (x, y), size=size, gravity=gravity) self.children.append(t) yok = y + dh
def run(): reset() clear() # Property numbers used pbol = 1 # Bol ptop = 2 # Top plate pbot = 3 # Bottom plate scale = 15. # scale (grid unit in mm) # Create a solid sphere BolSurface = simple.sphere().scale(scale) try: # tetgen may not be available Bol = BolSurface.tetgen(quality=True).setProp(pbol) except: return draw(Bol) # Create top and bottom plates plate = simple.rectangle(4, 4).toMesh().centered() topplate = plate.setProp(ptop).trl(2, 1.).scale(scale) botplate = plate.setProp(pbot).trl(2, -1.).scale(scale) draw([topplate, botplate]) # model is completely drawn, keep fixed bbox setDrawOptions({'bbox':'last','marksize':8}) # Assemble the model M = Model(meshes=[Bol, topplate, botplate]) # Create the property database P = PropertyDB() # In this simple example, we do not use a material/section database, # but define the data directly steel = { 'name': 'steel', 'young_modulus': 207000, 'poisson_ratio': 0.3, 'density': 7.85e-9, 'plastic': [ (305.45, 0.), (306.52, 0.003507), (308.05, 0.008462), (310.96, 0.01784), (316.2, 0.018275), (367.5, 0.047015), (412.5, 0.093317), (448.11, 0.154839), (459.6, 0.180101), (494., 0.259978), (506.25, 0.297659), (497., 0.334071), (482.8, 0.348325), (422.5, 0.366015), (399.58, 0.3717), (1., 0.37363), ], } solid_steel = { 'name': 'solid_steel', 'sectiontype': 'solid', 'material': 'steel', # Need material reference for Abaqus } steel_plate = { 'name': 'solid_steel', 'sectiontype': 'solid', 'thickness': 3, 'material': 'steel', # Need material reference for Abaqus } # Set the element properties eset = dict([(p, where(M.prop==p)[0]) for p in [pbol, ptop, pbot]]) # Bol is elasto/plastic P.elemProp(set=eset[pbol], name='Bol', eltype='C3D4', section=ElemSection(section=solid_steel, material=steel)) # Top plate is rigid or elasto-plastic topplate_rigid = True if topplate_rigid: # Rigid bodies need a reference node. # We select the most central node, but any node would also work, # e.g. pbref = M.elems[1][0][0], the very first node in the group reftop = groupCentralPoint(M, 1) print("Top plate refnode: %s" % reftop) draw(M.coords[reftop], color=green) P.elemProp(set=eset[ptop], name='TopPlate', eltype='R3D4', section=ElemSection(sectiontype='rigid', refnode=reftop)) else: P.elemProp(set=eset[ptop], name='TopPlate', eltype='CPS4', section=ElemSection(section=steel_plate, material=steel)) # Bottom plate is rigid or elasto-plastic refbot = groupCentralPoint(M, 2) print("Bottom plate refnode: %s" % refbot) draw(M.coords[refbot], color=blue) P.elemProp(set=eset[pbot], name='BottomPlate', eltype='R3D4', section=ElemSection(sectiontype='rigid', refnode=refbot)) # Set the boundary conditions # Bottom plate is fixed fixed = unique(M.elems[2]) P.nodeProp(tag='init', set=[refbot], name='Fixed', bound=[1, 1, 1, 1, 1, 1]) # Set the loading conditions # Top plate gets z-displacement of -5 mm displ = unique(M.elems[1]) P.nodeProp(tag='init', set=[reftop], name='Displ', bound=[1, 1, 0, 1, 1, 1]) P.nodeProp(tag='step1', set=[reftop], name='Refnod', displ=[(2, -0.5)]) ## # Set the loading conditions ## # All elements of Plate1 have a pressure loading of 10 MPa ## loaded = M.elemNrs(1) ## P.elemProp(tag='step1',set=loaded,name='Loaded',dload=ElemLoad('P',10.0)) from pyformex.plugins.fe_abq import Interaction P.Prop(tag='init', generalinteraction=Interaction(name='interaction1', friction=0.1)) P.Prop(tag='init', generalcontact='interaction1') print("Element properties") for p in P.getProp('e'): print(p) print("Node properties") for p in P.getProp('n'): print(p) print("Model properties") for p in P.getProp(''): print(p) out = [ Output(type='history'), Output(type='field'), ] # Create requests for output to the .fil file. # - the displacements in all nodes # - the stress components in all elements # - the stresses averaged at the nodes # - the principal stresses and stress invariants in the elements of part B. # (add output='PRINT' to get the results printed in the .dat file) res = [ Result(kind='NODE', keys=['U']), Result(kind='ELEMENT', keys=['S'], set='Bol'), Result(kind='ELEMENT', keys=['S'], pos='AVERAGED AT NODES', set='Bol'), Result(kind='ELEMENT', keys=['SP', 'SINV'], set='Bol'), ] # Define steps (default is static) step1 = Step('DYNAMIC', time=[1., 1., 0.01, 1.], tags=['step1']) data = AbqData(M, prop=P, steps=[step1], res=res, initial=['init']) if ack('Export this model in ABAQUS input format?', default='No'): fn = askNewFilename(filter='inp') if fn: data.write(jobname=fn, group_by_group=True)
def run(): smoothwire() # GEOMETRICAL PARAMETERS FOR HE200B wide flange beam h = 200. #beam height b = 200. #flange width tf = 15. #flange thickness tw = 9. #body thickness l = 400. #beam length r = 18. #filling radius # MESH PARAMETERS el = 20 #number of elements along the length etb = 2 #number of elements over half of the thickness of the body ehb = 5 #number of elements over half of the height of the body etf = 5 #number of elements over the thickness of the flange ewf = 8 #number of elements over half of the width of the flange er = 6 #number of elements in the circular segment Body = simple.rectangle(etb, ehb, tw / 2., h / 2. - tf - r) Flange1 = simple.rectangle(er // 2, etf - etb, tw / 2. + r, tf - tw / 2.).translate( [0., h / 2. - (tf - tw / 2.), 0.]) Flange2 = simple.rectangle(ewf, etf - etb, b / 2. - r - tw / 2., tf - tw / 2.).translate( [tw / 2. + r, h / 2. - (tf - tw / 2.), 0.]) Flange3 = simple.rectangle(ewf, etb, b / 2. - r - tw / 2., tw / 2.).translate([tw / 2. + r, h / 2. - tf, 0.]) c1a = simple.line([0, h / 2 - tf - r, 0], [0, h / 2 - tf + tw / 2, 0], er // 2) c1b = simple.line([0, h / 2 - tf + tw / 2, 0], [tw / 2 + r, h / 2 - tf + tw / 2, 0], er // 2) c1 = c1a + c1b c2 = simple.circle(90. / er, 0., 90.).reflect(0).scale(r).translate( [tw / 2 + r, h / 2 - tf - r, 0]) Filled = simple.connectCurves(c2, c1, etb) Quarter = Body + Filled + Flange1 + Flange2 + Flange3 Half = Quarter + Quarter.reflect(1).reverse() Full = Half + Half.reflect(0).reverse() Section = Full.toMesh() clear() draw(Section, name='Section', color=red) #pause() method = ask("Choose extrude method:", [ 'Cancel', 'Sweep', 'Connect', 'Extrude', 'ExtrudeQuadratic', 'RevolveLoop', 'Revolve' ]) from pyformex import timer t = timer.Timer() if method == 'Sweep': path = simple.line([0, 0, 0], [0, 0, l], el).toCurve() Beam = Section.sweep(path, normal=[0., 0., 1.], upvector=[0., 1., 0.]) elif method == 'Connect': Section1 = Section.trl([0, 0, l]) Beam = Section.connect(Section1, el) elif method == 'Extrude': Beam = Section.extrude(el, dir=2, length=l) elif method == 'ExtrudeQuadratic': Section = Section.convert('quad9') Beam = Section.extrude(el, dir=2, length=l, degree=2) elif method == 'Revolve': Beam = Section.revolve(el, axis=1, angle=60., around=[-l, 0., 0.]) elif method == 'RevolveLoop': Beam = Section.revolve(el, axis=1, angle=240., around=[-l, 0., 0.], loop=True) else: return print("Computing: %s seconds" % t.seconds()) #print Beam.prop #print Beam.elems.shape t.reset() #clear() #draw(Beam,name='Beam',color='red',linewidth=2) draw(Beam.getBorderMesh(), name='Beam', color='red', linewidth=2) print("Drawing: %s seconds" % t.seconds()) export({'Beam': Beam})