def runCalpyAnalysis(jobname=None,verbose=False,flavia=False): """Create data for Calpy analysis module and run Calpy on the data. While we could write an analysis file in the Calpy format and then run the Calpy program on it (like we did with Abaqus), we can (and do) take another road here: Calpy has a Python/numpy interface, allowing us to directly present the numerical data in arrays to the analysis module. It is supposed that the Finite Element model has been created and exported under the name 'fe_model'. """ ############################ # Load the needed calpy modules from plugins import calpy_itf calpy_itf.check() ## # Load development version #import sys #sys.path.insert(0,'/home/bene/prj/calpy') #print sys.path import calpy reload(calpy) print calpy.__path__ calpy.options.optimize=True from calpy import femodel,fe_util,plane from calpy.arrayprint import aprint ############################ checkWorkdir() if model is None: warn() return if jobname is None: # ask job name from user res = askItems([('JobName',feresult_name.peek()),('Verbose Mode',False)]) if res: jobname = res['JobName'] verbose = res['Verbose Mode'] if not jobname: print "No Job Name: bailing out" return # OK, start calpy print "Starting the Calpy analysis module --- this might take some time" pf.app.processEvents() starttime = time.clock() calpyModel = femodel.FeModel(2,"elast","Plane_Stress") calpyModel.nnodes = model.coords.shape[0] calpyModel.nelems = model.celems[-1] print [ e.shape for e in model.elems ]
def computeAveragedNodalStresses(M, data, gprule): """Compute averaged nodal stresses from GP stresses in 2D quad8 mesh""" ############################ # Load the needed calpy modules from plugins import calpy_itf calpy_itf.check() gprule = (2, 2) # integration rule: minimum (1,1), maximum (5,5) Q = calpy_itf.QuadInterpolator(M.nelems(), M.nplex(), gprule) ngp = prod(gprule) # number of datapoints per element print("Number of data points per element: %s" % ngp) print("Original element data: %s" % str(data.shape)) # compute the data at the nodes, per element endata = Q.GP2Nodes(data) print("Element nodal data: %s" % str(endata.shape)) # compute nodal averages nodata = Q.NodalAvg(M.elems + 1, endata, M.nnodes()) print("Average nodal data: %s" % str(nodata.shape)) # extract the colors per element return nodata
def computeAveragedNodalStresses(M,data,gprule): """Compute averaged nodal stresses from GP stresses in 2D quad8 mesh""" ############################ # Load the needed calpy modules from plugins import calpy_itf calpy_itf.check() gprule = (2,2) # integration rule: minimum (1,1), maximum (5,5) Q = calpy_itf.QuadInterpolator(M.nelems(),M.nplex(),gprule) ngp = prod(gprule) # number of datapoints per element print("Number of data points per element: %s" % ngp) print("Original element data: %s" % str(data.shape)) # compute the data at the nodes, per element endata = Q.GP2Nodes(data) print("Element nodal data: %s" % str(endata.shape)) # compute nodal averages nodata = Q.NodalAvg(M.elems+1,endata,M.nnodes()) print("Average nodal data: %s" % str(nodata.shape)) # extract the colors per element return nodata
def runCalpyAnalysis(jobname=None, verbose=False, flavia=False): """Create data for Calpy analysis module and run Calpy on the data. While we could write an analysis file in the Calpy format and then run the Calpy program on it (like we did with Abaqus), we can (and do) take another road here: Calpy has a Python/numpy interface, allowing us to directly present the numerical data in arrays to the analysis module. It is supposed that the Finite Element model has been created and exported under the name 'fe_model'. """ ############################ # Load the needed calpy modules from plugins import calpy_itf calpy_itf.check() import calpy calpy.options.optimize = True from calpy import femodel, fe_util, plane from calpy.arrayprint import aprint ############################ checkWorkdir() if model is None: warn() return if jobname is None: # ask job name from user res = askItems([("JobName", feresult_name.peek()), ("Verbose Mode", False)]) if res: jobname = res["JobName"] verbose = res["Verbose Mode"] if not jobname: print "No Job Name: bailing out" return # OK, start calpy print "Starting the Calpy analysis module --- this might take some time" GD.app.processEvents() starttime = time.clock() calpyModel = femodel.FeModel(2, "elast", "Plane_Stress") calpyModel.nnodes = model.coords.shape[0] calpyModel.nelems = model.celems[-1] calpyModel.nnodel = 4 # 2D model in calpy needs 2D coordinates coords = model.coords[:, :2] if verbose: fe_util.PrintNodes(coords) # Boundary conditions bcon = zeros((calpyModel.nnodes, 2), dtype=int32) bcon[:, 2:6] = 1 # leave only ux and uy for p in PDB.getProp(kind="n", attr=["bound"]): bnd = where(p.bound)[0] if p.set is None: nod = arange(calpyModel.nnodes) else: nod = array(p.set) for i in bnd: bcon[p.set, i] = 1 fe_util.NumberEquations(bcon) if verbose: fe_util.PrintDofs(bcon, header=["ux", "uy"]) # The number of free DOFs remaining calpyModel.ndof = bcon.max() print "Number of DOF's: %s" % calpyModel.ndof # We extract the materials/sections from the property database matprops = PDB.getProp(kind="e", attr=["section"]) # E, nu, thickness, rho mats = array( [ [mat.young_modulus, mat.poisson_ratio, mat.thickness, 0.0] # rho was not defined in material for mat in matprops ] ) calpyModel.nmats = mats.shape[0] if verbose: fe_util.PrintMats(mats, header=["E", "nu", "thick", "rho"]) ########### Find number of load cases ############ calpyModel.nloads = 1 calpyModel.PrintModelData() ngp = 2 nzem = 3 calpyModel.banded = True # Create element definitions: # In calpy, each element is represented by nnod + 1 integer numbers: # matnr, node1, node2, .... # Also notice that Calpy numbering starts at 1, not at 0 as customary # in pyFormex; therefore we add 1 to elems. matnr = zeros(calpyModel.nelems, dtype=int32) for i, mat in enumerate(matprops): # proces in same order as above! matnr[mat.set] = i + 1 NodesGrp = [] MatnrGrp = [] PlaneGrp = [] for i, e in enumerate(model.elems): j, k = model.celems[i : i + 2] Plane = plane.Quad("part-%s" % i, [ngp, ngp], calpyModel) Plane.debug = 0 PlaneGrp.append(Plane) NodesGrp.append(e + 1) MatnrGrp.append(matnr[j:k]) if verbose: fe_util.PrintElements(NodesGrp[-1], MatnrGrp[-1]) # Plane.AddElements(e+1,matnr[j:k],mats,coords,bcon) for Plane, nodenrs, matnrs in zip(PlaneGrp, NodesGrp, MatnrGrp): Plane.AddElements(nodenrs, matnrs, mats, coords, bcon) # Create load vectors # Calpy allows for multiple load cases in a single analysis. # However, our script currently puts all loads together in a single # load case. So the processing hereafter is rather simple, especially # since Calpy provides a function to assemble a single concentrated # load into the load vector. We initialize the load vector to zeros # and then add all the concentrated loads from the properties database. # A single concentrated load consists of 6 components, corresponding # to the 6 DOFs of a node. # # AssembleVector takes 3 arguments: the global vector in which to # assemble a nodal vector (length ndof), the nodal vector values # (length 6), and a list of indices specifying the positions of the # nodal DOFs in the global vector. # Beware: The function does not change the global vector, but merely # returns the value after assembling. # Also notice that the indexing inside the bcon array uses numpy # convention (starting at 0), thus no adding 1 is needed! print "Assembling Concentrated Loads" calpyModel.nloads = 1 f = zeros((calpyModel.ndof, calpyModel.nloads), float) for p in PDB.getProp("n", attr=["cload"]): if p.set is None: nodeset = range(calpyModel.nnodes) else: nodeset = p.set F = [0.0, 0.0] for i, v in p.cload: if i in [0, 1]: F[i] = v for n in nodeset: f[:, 0] = fe_util.AssembleVector(f[:, 0], F, bcon[n]) print "Assembling distributed loads" # This is a bit more complex. See Calpy for details # We first generate the input data in a string, then read them with the # calpy femodel.ReadBoundaryLoads function and finally assemble them with # plane.addBoundaryLoads. We have to this operation per element group. # The group number is stored in the property record. ngroups = model.ngroups() s = [""] * ngroups nb = [0] * ngroups loadcase = 1 for p in PDB.getProp("e", attr=["eload"]): xload = yload = 0.0 if p.label == "x": xload = p.value elif p.label == "y": yload = p.value # Because of the way we constructed the database, the set will # contain only one element, but let's loop over it anyway in case # one day we make the storage more effective # Also, remember calpy numbers are +1 ! g = p.group print "Group %s" % g for e in p.set: s[g] += "%s %s %s %s %s\n" % (e + 1, p.edge + 1, loadcase, xload, yload) nb[g] += 1 # print s,nb for nbi, si, nodes, matnr, Plane in zip(nb, s, NodesGrp, MatnrGrp, PlaneGrp): if nbi > 0: idloads, dloads = fe_util.ReadBoundaryLoads(nbi, calpyModel.ndim, si) # print idloads,dloads Plane.AddBoundaryLoads(f, calpyModel, idloads, dloads, nodes, matnr, coords, bcon, mats) if verbose: print "Calpy.Loads" print f ############ Create global stiffness matrix ########## s = calpyModel.ZeroStiffnessMatrix(0) for elgrp in PlaneGrp: s = elgrp.Assemble(s, mats, calpyModel) # print "The complete stiffness matrix" # print s ############ Solve the system of equations ########## v = calpyModel.SolveSystem(s, f) print "Calpy analysis has finished --- Runtime was %s seconds." % (time.clock() - starttime) displ = fe_util.selectDisplacements(v, bcon) if verbose: print "Displacements", displ if flavia: flavia.WriteMeshFile(jobname, "Quadrilateral", model.nnodel, coord, nodes, matnr) res = flavia.ResultsFile(jobname) # compute stresses for l in range(calpyModel.nloads): print "Results for load case %d" % (l + 1) print "Displacements" aprint(displ[:, :, l], header=["x", "y"], numbering=True) if flavia: flavia.WriteResultsHeader(res, '"Displacement" "Elastic Analysis"', l + 1, "Vector OnNodes") flavia.WriteResults(res, displ[:, :, l]) stresn = count = None i = 0 for e, P in zip(model.elems, PlaneGrp): i += 1 # P.debug = 1 stresg = P.StressGP(v[:, l], mats) if verbose: print "elem group %d" % i print "GP Stress\n", stresg strese = P.GP2Nodes(stresg) if verbose: print "Nodal Element Stress\n", strese # print "Nodes",e+1 stresn, count = P.NodalAcc(e + 1, strese, nnod=calpyModel.nnodes, nodata=stresn, nodn=count) # print stresn,count # print stresn.shape # print count.shape # print "TOTAL",stresn,count stresn /= count.reshape(-1, 1) # print "AVG",stresn if verbose: print "Averaged Nodal Stress\n" aprint(stresn, header=["sxx", "syy", "sxy"], numbering=True) if flavia: flavia.WriteResultsHeader(res, '"Stress" "Elastic Analysis"', l + 1, "Matrix OnNodes") flavia.WriteResults(res, stresn) DB = FeResult() DB.nodes = model.coords DB.nnodes = model.coords.shape[0] DB.nodid = arange(DB.nnodes) DB.elems = dict(enumerate(model.elems)) DB.nelems = model.celems[-1] DB.Finalize() DB.data_size["S"] = 3 # print DB.elems for lc in range(calpyModel.nloads): DB.Increment(lc, 0) d = zeros((calpyModel.nnodes, 3)) d[:, :2] = displ[:, :, lc] DB.R["U"] = d DB.R["S"] = stresn postproc_menu.setDB(DB) name = feresult_name.next() export({name: DB}) showInfo("The results have been exported as %s\nYou can now use the postproc menu to display results" % name)
## ## This file is part of pyFormex 0.5 Release Fri Aug 10 12:04:07 2007 ## pyFormex is a Python implementation of Formex algebra ## Website: http://pyformex.berlios.de/ ## Copyright (C) Benedict Verhegghe ([email protected]) ## ## This program is distributed under the GNU General Public License ## version 2 or later (see file COPYING for details) ## """X-shaped truss analysis""" ############################ # Load the needed calpy modules from plugins import calpy_itf calpy_itf.check() from fe_util import * from truss3d import * ############################ import time ########################### linewidth(1.0) clear() from examples.X_truss import X_truss bgcolor(lightgrey) # create a truss (Vandepitte, Chapter 1, p.16)
def runCalpyAnalysis(): """Create data for Calpy analysis module and run Calpy on the data. While we could write an analysis file in the Calpy format and then run the Calpy program on it (like we did with Abaqus), we can (and do) take another road here: Calpy has a Python/numpy interface, allowing us to directly present the numerical data in arrays to the analysis module. It is supposed that the Finite Element model has been created and exported under the name 'fe_model'. """ ############################ # Load the needed calpy modules from plugins import calpy_itf calpy_itf.check() import calpy calpy.options.optimize=True from calpy import fe_util,beam3d ############################ try: FE = named('fe_model') ## print FE.keys() ## nodes = FE.nodes ## elems = FE.elems ## prop = FE.prop ## nodloads = FE.loads ## botnodes = FE.botnodes ## nsteps = FE.nsteps except: warning("I could not find the finite element model.\nMaybe you should try to create it first?") return # ask job name from user res = askItems([('JobName','hesperia_frame'),('Verbose Mode',False)]) if not res: return jobname = res['JobName'] if not jobname: print "No Job Name: bailing out" return verbose = res['Verbose Mode'] nnod = FE.nodes.shape[0] nel = FE.elems.shape[0] print "Number of nodes: %s" % nnod print "Number of elements: %s" % nel # Create an extra node for beam orientations # # !!! This is ok for the support beams, but for the structural beams # !!! this should be changed to the center of the sphere !!! extra_node = array([[0.0,0.0,0.0]]) coords = concatenate([FE.nodes,extra_node]) nnod = coords.shape[0] print "Adding a node for orientation: %s" % nnod # We extract the materials/sections from the property database matprops = FE.prop.getProp(kind='e',attr=['section']) # Beam Properties in Calpy consist of 7 values: # E, G, rho, A, Izz, Iyy, J # The beam y-axis lies in the plane of the 3 nodes i,j,k. mats = array([[mat.young_modulus, mat.shear_modulus, mat.density, mat.cross_section, mat.moment_inertia_11, mat.moment_inertia_22, mat.moment_inertia_12, ] for mat in matprops]) if verbose: print "Calpy.materials" print mats # Create element definitions: # In calpy, each beam element is represented by 4 integer numbers: # i j k matnr, # where i,j are the node numbers, # k is an extra node for specifying orientation of beam (around its axis), # matnr refers to the material/section properties (i.e. the row nr in mats) # Also notice that Calpy numbering starts at 1, not at 0 as customary # in pyFormex; therefore we add 1 to elems. # The third node for all beams is the last (extra) node, numbered nnod. # We need to reshape tubeprops to allow concatenation matnr = zeros(nel,dtype=int32) for i,mat in enumerate(matprops): # proces in same order as above! matnr[mat.set] = i+1 elements = concatenate([FE.elems + 1, # the normal node numbers nnod * ones(shape=(nel,1),dtype=int), # extra node matnr.reshape((-1,1))], # mat number axis=1) if verbose: print "Calpy.elements" print elements # Boundary conditions # While we could get the boundary conditions from the node properties # database, we will formulate them directly from the numbers # of the supported nodes (botnodes). # Calpy (currently) only accepts boundary conditions in global # (cartesian) coordinates. However, as we only use fully fixed # (though hinged) support nodes, that presents no problem here. # For each supported node, a list of 6 codes can (should)be given, # corresponding to the six Degrees Of Freedom (DOFs): ux,uy,uz,rx,ry,rz. # The code has value 1 if the DOF is fixed (=0.0) and 0 if it is free. # The easiest way to set the correct boundary conditions array for Calpy # is to put these codes in a text field and have them read with # ReadBoundary. s = "" for n in FE.botnodes + 1: # again, the +1 is to comply with Calpy numbering! s += " %d 1 1 1 1 1 1\n" % n # a fixed hinge # Also clamp the fake extra node s += " %d 1 1 1 1 1 1\n" % nnod if verbose: print "Specified boundary conditions" print s bcon = fe_util.ReadBoundary(nnod,6,s) fe_util.NumberEquations(bcon) if verbose: print "Calpy.DOF numbering" print bcon # all DOFs are numbered from 1 to ndof # The number of free DOFs remaining ndof = bcon.max() print "Number of DOF's: %s" % ndof # Create load vectors # Calpy allows for multiple load cases in a single analysis. # However, our script currently puts all loads together in a single # load case. So the processing hereafter is rather simple, especially # since Calpy provides a function to assemble a single concentrated # load into the load vector. We initialize the load vector to zeros # and then add all the concentrated loads from the properties database. # A single concentrated load consists of 6 components, corresponding # to the 6 DOFs of a node. # # AssembleVector takes 3 arguments: the global vector in which to # assemble a nodal vector (length ndof), the nodal vector values # (length 6), and a list of indices specifying the positions of the # nodal DOFs in the global vector. # Beware: The function does not change the global vector, but merely # returns the value after assembling. # Also notice that the indexing inside the bcon array uses numpy # convention (starting at 0), thus no adding 1 is needed! print "Assembling Concentrated Loads" nlc = 1 loads = zeros((ndof,nlc),float) for p in FE.prop.getProp('n',attr=['cload']): loads[:,0] = fe_util.AssembleVector(loads[:,0],p.cload,bcon[p.set,:]) if verbose: print "Calpy.Loads" print loads # Perform analysis # OK, that is really everything there is to it. Now just run the # analysis, and hope for the best ;) # Enabling the Echo will print out the data. # The result consists of nodal displacements and stress resultants. print "Starting the Calpy analysis module --- this might take some time" GD.app.processEvents() starttime = time.clock() displ,frc = beam3d.static(coords,bcon,mats,elements,loads,Echo=True) print "Calpy analysis has finished --- Runtime was %s seconds." % (time.clock()-starttime) # Export the results, but throw way these for the extra (last) node export({'calpy_results':(displ[:-1],frc)})
def runCalpyAnalysis(jobname=None,verbose=False,flavia=False): """Create data for Calpy analysis module and run Calpy on the data. While we could write an analysis file in the Calpy format and then run the Calpy program on it (like we did with Abaqus), we can (and do) take another road here: Calpy has a Python/numpy interface, allowing us to directly present the numerical data in arrays to the analysis module. It is supposed that the Finite Element model has been created and exported under the name 'fe_model'. """ ############################ # Load the needed calpy modules from plugins import calpy_itf calpy_itf.check() import calpy calpy.options.optimize=True from calpy import femodel,fe_util,plane from calpy.arrayprint import aprint ############################ if model is None: warn() return if jobname is None: # ask job name from user res = askItems([('JobName','FeEx'),('Verbose Mode',False)]) if res: jobname = res['JobName'] verbose = res['Verbose Mode'] if not jobname: print "No Job Name: bailing out" return # OK, start calpy print "Starting the Calpy analysis module --- this might take some time" GD.app.processEvents() starttime = time.clock() Model = femodel.FeModel(2,"elast","Plane_Stress") Model.nnodes = model.coords.shape[0] Model.nelems = model.celems[-1] Model.nnodel = 4 # 2D model in calpy needs 2D coordinates coords = model.coords[:,:2] if verbose: fe_util.PrintNodes(coords) # Boundary conditions bcon = zeros((Model.nnodes,2),dtype=int32) bcon[:,2:6] = 1 # leave only ux and uy for p in PDB.getProp(kind='n',attr=['bound']): bnd = where(p.bound)[0] if p.set is None: nod = arange(Model.nnodes) else: nod = array(p.set) for i in bnd: bcon[p.set,i] = 1 fe_util.NumberEquations(bcon) if verbose: fe_util.PrintDofs(bcon,header=['ux','uy']) # The number of free DOFs remaining Model.ndof = bcon.max() print "Number of DOF's: %s" % Model.ndof # We extract the materials/sections from the property database matprops = PDB.getProp(kind='e',attr=['section']) # E, nu, thickness, rho mats = array([[mat.young_modulus, mat.poisson_ratio, mat.thickness, 0.0, # rho was not defined in material ] for mat in matprops]) Model.nmats = mats.shape[0] if verbose: fe_util.PrintMats(mats,header=['E','nu','thick','rho']) ########### Find number of load cases ############ Model.nloads = 1 Model.PrintModelData() ngp = 2 nzem = 3 Model.banded = True # Create element definitions: # In calpy, each element is represented by nnod + 1 integer numbers: # matnr, node1, node2, .... # Also notice that Calpy numbering starts at 1, not at 0 as customary # in pyFormex; therefore we add 1 to elems. matnr = zeros(Model.nelems,dtype=int32) for i,mat in enumerate(matprops): # proces in same order as above! matnr[mat.set] = i+1 PlaneGrp = [] for i,e in enumerate(model.elems): j,k = model.celems[i:i+2] Plane = plane.Quad("part-%s" % i,[ngp,ngp],Model) Plane.debug = 0 fe_util.PrintElements(e+1,matnr[j:k]) Plane.AddElements(e+1,matnr[j:k],mats,coords,bcon) PlaneGrp.append(Plane) # Create load vectors # Calpy allows for multiple load cases in a single analysis. # However, our script currently puts all loads together in a single # load case. So the processing hereafter is rather simple, especially # since Calpy provides a function to assemble a single concentrated # load into the load vector. We initialize the load vector to zeros # and then add all the concentrated loads from the properties database. # A single concentrated load consists of 6 components, corresponding # to the 6 DOFs of a node. # # AssembleVector takes 3 arguments: the global vector in which to # assemble a nodal vector (length ndof), the nodal vector values # (length 6), and a list of indices specifying the positions of the # nodal DOFs in the global vector. # Beware: The function does not change the global vector, but merely # returns the value after assembling. # Also notice that the indexing inside the bcon array uses numpy # convention (starting at 0), thus no adding 1 is needed! print "Assembling Concentrated Loads" Model.nloads = 1 f = zeros((Model.ndof,Model.nloads),float) for p in PDB.getProp('n',attr=['cload']): if p.set is None: nodeset = range(Model.nnodes) else: nodeset = p.set F = [0.0,0.0] for i,v in p.cload: if i in [0,1]: F[i] = v for n in nodeset: print F print "HALLO" f[:,0] = fe_util.AssembleVector(f[:,0],F,bcon[n]) print "Assembling distributed loads" # This is a bit more complex. See Calpy for details # We first generate the input data, then read them with the # calpy femodel.ReadBoundaryLoads function and finally # assemble them with plane.addBoundaryLoads. for p in PDB.getProp('n',attr=['dload']): print p #idloads,dloads = plane.ReadBoundaryLoads(*nb,model.ndim) if verbose: print "Calpy.Loads" print f ############ Create global stiffness matrix ########## s = Model.ZeroStiffnessMatrix(0) for elgrp in PlaneGrp: s = elgrp.Assemble(s,mats,Model) #print "The complete stiffness matrix" #print s print f v = Model.SolveSystem(s,f) if verbose: print "Displacements",v print "Calpy analysis has finished --- Runtime was %s seconds." % (time.clock()-starttime) displ = fe_util.selectDisplacements (v,bcon) print displ.shape if verbose: print displ if flavia: flavia.WriteMeshFile(jobname,"Quadrilateral",model.nnodel,coord,nodes,matnr) res=flavia.ResultsFile(jobname) # compute stresses for l in range(Model.nloads): print "Results for load case %d" %(l+1) print "Displacements" aprint(displ[:,:,l],header=['x','y'],numbering=True) if flavia: flavia.WriteResultsHeader(res,'"Displacement" "Elastic Analysis"',l+1,'Vector OnNodes') flavia.WriteResults(res,displ[:,:,l]) stresn = count = None i = 0 for e,P in zip(model.elems,PlaneGrp): i += 1 #P.debug = 1 stresg = P.StressGP (v[:,l],mats) if verbose: print "elem group %d" % i print "GP Stress\n", stresg strese = P.GP2Nodes(stresg) if verbose: print "Nodal Element Stress\n", strese #print "Nodes",e+1 stresn,count = P.NodalAcc(e+1,strese,nnod=Model.nnodes,nodata=stresn,nodn=count) #print stresn,count #print stresn.shape #print count.shape #print "TOTAL",stresn,count stresn /= count.reshape(-1,1) #print "AVG",stresn if verbose: print "Averaged Nodal Stress\n" aprint(stresn,header=['sxx','syy','sxy'],numbering=True) if flavia: flavia.WriteResultsHeader(res,'"Stress" "Elastic Analysis"',l+1,'Matrix OnNodes') flavia.WriteResults(res,stresn) DB = FeResult() DB.nodes = model.coords DB.nnodes = model.coords.shape[0] DB.nodid = arange(DB.nnodes) DB.elems = dict(enumerate(model.elems)) DB.nelems = model.celems[-1] DB.Finalize() DB.data_size['S'] = 3 #print DB.elems for lc in range(Model.nloads): DB.Increment(lc,0) d = zeros((Model.nnodes,3)) d[:,:2] = displ[:,:,lc] DB.R['U'] = d DB.R['S'] = stresn postproc_menu.setDB(DB) info("You can now use the postproc menu to display results") export({'FeResult':DB})
def runCalpyAnalysis(): """Create data for Calpy analysis module and run Calpy on the data. While we could write an analysis file in the Calpy format and then run the Calpy program on it (like we did with Abaqus), we can (and do) take another road here: Calpy has a Python/numpy interface, allowing us to directly present the numerical data in arrays to the analysis module. It is supposed that the Finite Element model has been created and exported under the name 'fe_model'. """ checkWorkdir() ############################ # Load the needed calpy modules # You can prepend your own path here to override the installed calpy # sys.path[0:0] = ['/home/bene/prj/calpy'] from plugins import calpy_itf calpy_itf.check() import calpy print(calpy) calpy.options.optimize = True from calpy import fe_util, beam3d ############################ try: FE = named('fe_model') ## print FE.keys() ## nodes = FE.nodes ## elems = FE.elems ## prop = FE.prop ## nodloads = FE.loads ## botnodes = FE.botnodes ## nsteps = FE.nsteps except: warning( "I could not find the finite element model.\nMaybe you should try to create it first?" ) return # ask job name from user res = askItems([('JobName', 'hesperia_frame'), ('Verbose Mode', False)]) if not res: return jobname = res['JobName'] if not jobname: print("No Job Name: bailing out") return verbose = res['Verbose Mode'] nnod = FE.nodes.shape[0] nel = FE.elems.shape[0] print("Number of nodes: %s" % nnod) print("Number of elements: %s" % nel) # Create an extra node for beam orientations # # !!! This is ok for the support beams, but for the structural beams # !!! this should be changed to the center of the sphere !!! extra_node = array([[0.0, 0.0, 0.0]]) coords = concatenate([FE.nodes, extra_node]) nnod = coords.shape[0] print("Adding a node for orientation: %s" % nnod) # We extract the materials/sections from the property database matprops = FE.prop.getProp(kind='e', attr=['section']) # Beam Properties in Calpy consist of 7 values: # E, G, rho, A, Izz, Iyy, J # The beam y-axis lies in the plane of the 3 nodes i,j,k. mats = array([[ mat.young_modulus, mat.shear_modulus, mat.density, mat.cross_section, mat.moment_inertia_11, mat.moment_inertia_22, mat.moment_inertia_12, ] for mat in matprops]) if verbose: print("Calpy.materials") print(mats) # Create element definitions: # In calpy, each beam element is represented by 4 integer numbers: # i j k matnr, # where i,j are the node numbers, # k is an extra node for specifying orientation of beam (around its axis), # matnr refers to the material/section properties (i.e. the row nr in mats) # Also notice that Calpy numbering starts at 1, not at 0 as customary # in pyFormex; therefore we add 1 to elems. # The third node for all beams is the last (extra) node, numbered nnod. # We need to reshape tubeprops to allow concatenation matnr = zeros(nel, dtype=int32) for i, mat in enumerate(matprops): # proces in same order as above! matnr[mat.set] = i + 1 elements = concatenate( [ FE.elems + 1, # the normal node numbers nnod * ones(shape=(nel, 1), dtype=int), # extra node matnr.reshape((-1, 1)) ], # mat number axis=1) if verbose: print("Calpy.elements") print(elements) # Boundary conditions # While we could get the boundary conditions from the node properties # database, we will formulate them directly from the numbers # of the supported nodes (botnodes). # Calpy (currently) only accepts boundary conditions in global # (cartesian) coordinates. However, as we only use fully fixed # (though hinged) support nodes, that presents no problem here. # For each supported node, a list of 6 codes can (should)be given, # corresponding to the six Degrees Of Freedom (DOFs): ux,uy,uz,rx,ry,rz. # The code has value 1 if the DOF is fixed (=0.0) and 0 if it is free. # The easiest way to set the correct boundary conditions array for Calpy # is to put these codes in a text field and have them read with # ReadBoundary. s = "" for n in FE.botnodes + 1: # again, the +1 is to comply with Calpy numbering! s += " %d 1 1 1 1 1 1\n" % n # a fixed hinge # Also clamp the fake extra node s += " %d 1 1 1 1 1 1\n" % nnod if verbose: print("Specified boundary conditions") print(s) bcon = fe_util.ReadBoundary(nnod, 6, s) fe_util.NumberEquations(bcon) if verbose: print("Calpy.DOF numbering") print(bcon) # all DOFs are numbered from 1 to ndof # The number of free DOFs remaining ndof = bcon.max() print("Number of DOF's: %s" % ndof) # Create load vectors # Calpy allows for multiple load cases in a single analysis. # However, our script currently puts all loads together in a single # load case. So the processing hereafter is rather simple, especially # since Calpy provides a function to assemble a single concentrated # load into the load vector. We initialize the load vector to zeros # and then add all the concentrated loads from the properties database. # A single concentrated load consists of 6 components, corresponding # to the 6 DOFs of a node. # # AssembleVector takes 3 arguments: the global vector in which to # assemble a nodal vector (length ndof), the nodal vector values # (length 6), and a list of indices specifying the positions of the # nodal DOFs in the global vector. # Beware: The function does not change the global vector, but merely # returns the value after assembling. # Also notice that the indexing inside the bcon array uses numpy # convention (starting at 0), thus no adding 1 is needed! print("Assembling Concentrated Loads") nlc = 1 loads = zeros((ndof, nlc), float) for p in FE.prop.getProp('n', attr=['cload']): cload = zeros(6) for i, v in p.cload: cload[i] += v print(cload) print(cload.shape) loads[:, 0] = fe_util.AssembleVector(loads[:, 0], cload, bcon[p.set, :]) if verbose: print("Calpy.Loads") print(loads) # Perform analysis # OK, that is really everything there is to it. Now just run the # analysis, and hope for the best ;) # Enabling the Echo will print out the data. # The result consists of nodal displacements and stress resultants. print("Starting the Calpy analysis module --- this might take some time") pf.app.processEvents() starttime = time.clock() displ, frc = beam3d.static(coords, bcon, mats, elements, loads, Echo=True) print("Calpy analysis has finished --- Runtime was %s seconds." % (time.clock() - starttime)) # Export the results, but throw way these for the extra (last) node export({'calpy_results': (displ[:-1], frc)})
def runCalpyAnalysis(jobname=None,verbose=False): """Create data for Calpy analysis module and run Calpy on the data. While we could write an analysis file in the Calpy format and then run the Calpy program on it (like we did with Abaqus), we can (and do) take another road here: Calpy has a Python/numpy interface, allowing us to directly present the numerical data in arrays to the analysis module. It is supposed that the Finite Element model has been created and exported under the name 'fe_model'. """ ############################ # Load the needed calpy modules from plugins import calpy_itf calpy_itf.check() import calpy calpy.options.optimize=True from calpy import femodel,fe_util,plane ############################ if model is None: warn() return if jobname is None: # ask job name from user res = askItems([('JobName','FeEx'),('Verbose Mode',False)]) if res: jobname = res['JobName'] verbose = res['Verbose Mode'] if not jobname: print "No Job Name: bailing out" return Model = femodel.FeModel(2,"elast","Plane_Stress") Model.nnodes = model.nodes.shape[0] Model.nelems = model.celems[-1] Model.nnodel = 4 # 2D model in calpy needs 2D coordinates coords = model.nodes[:,:2] if verbose: fe_util.PrintNodes(coords) # Boundary conditions bcon = zeros((Model.nnodes,2),dtype=int32) bcon[:,2:6] = 1 # leave only ux and uy for p in PDB.getProp(kind='n',attr=['bound']): bnd = where(p.bound)[0] if p.set is None: nod = arange(Model.nnodes) else: nod = array(p.set) for i in bnd: bcon[p.set,i] = 1 fe_util.NumberEquations(bcon) if verbose: fe_util.PrintDofs(bcon,header=['ux','uy']) # The number of free DOFs remaining Model.ndof = bcon.max() print "Number of DOF's: %s" % Model.ndof # We extract the materials/sections from the property database matprops = PDB.getProp(kind='e',attr=['section']) # E, nu, thickness, rho mats = array([[mat.young_modulus, mat.poisson_ratio, mat.thickness, 0.0, # rho was not defined in material ] for mat in matprops]) Model.nmats = mats.shape[0] if verbose: fe_util.PrintMats(mats,header=['E','nu','thick','rho']) ########### Find number of load cases ############ Model.nloads = 1 Model.PrintModelData() ngp = 2 nzem = 3 Model.banded = True # Create element definitions: # In calpy, each element is represented by nnod + 1 integer numbers: # matnr, node1, node2, .... # Also notice that Calpy numbering starts at 1, not at 0 as customary # in pyFormex; therefore we add 1 to elems. matnr = zeros(Model.nelems,dtype=int32) for i,mat in enumerate(matprops): # proces in same order as above! matnr[mat.set] = i+1 PlaneGrp = [] for i,e in enumerate(model.elems): j,k = model.celems[i:i+2] Plane = plane.Quad("part-%s" % i,[ngp,ngp],Model) Plane.debug = 0 fe_util.PrintElements(e+1,matnr[j:k]) Plane.AddElements(e+1,matnr[j:k],mats,coords,bcon) PlaneGrp.append(Plane) # Create load vectors # Calpy allows for multiple load cases in a single analysis. # However, our script currently puts all loads together in a single # load case. So the processing hereafter is rather simple, especially # since Calpy provides a function to assemble a single concentrated # load into the load vector. We initialize the load vector to zeros # and then add all the concentrated loads from the properties database. # A single concentrated load consists of 6 components, corresponding # to the 6 DOFs of a node. # # AssembleVector takes 3 arguments: the global vector in which to # assemble a nodal vector (length ndof), the nodal vector values # (length 6), and a list of indices specifying the positions of the # nodal DOFs in the global vector. # Beware: The function does not change the global vector, but merely # returns the value after assembling. # Also notice that the indexing inside the bcon array uses numpy # convention (starting at 0), thus no adding 1 is needed! print "Assembling Concentrated Loads" Model.nloads = 1 f = zeros((Model.ndof,Model.nloads),float) print f.shape for p in PDB.getProp('n',attr=['cload']): if p.set is None: nodeset = range(Model.nnodes) else: nodeset = p.set for n in nodeset: print p.cload[:2] print f[:,0] = fe_util.AssembleVector(f[:,0],p.cload[:2],bcon[n]) if verbose: print "Calpy.Loads" print f # Perform analysis # OK, that is really everything there is to it. Now just run the # analysis, and hope for the best ;) # Enabling the Echo will print out the data. # The result consists of nodal displacements and stress resultants. print "Starting the Calpy analysis module --- this might take some time" GD.app.processEvents() starttime = time.clock() ############ Create global stiffness matrix ########## s = Model.ZeroStiffnessMatrix(0) for elgrp in PlaneGrp: s = elgrp.Assemble(s,mats,Model) #print "The complete stiffness matrix" #print s print f v = Model.SolveSystem(s,f) print "Displacements",v print "Calpy analysis has finished --- Runtime was %s seconds." % (time.clock()-starttime) displ = fe_util.selectDisplacements (v,bcon) print displ.shape print displ DB = FeResult() DB.nodes = model.nodes DB.nnodes = model.nodes.shape[0] DB.nodid = arange(DB.nnodes) DB.elems = dict(enumerate(model.elems)) DB.nelems = model.celems[-1] DB.Finalize() print DB.elems for lc in range(Model.nloads): DB.Increment(lc,0) d = zeros((Model.nnodes,3)) d[:,:2] = displ[:,:,lc] DB.R['U'] = d postproc_menu.setDB(DB) info("You can now use the postproc menu to display results") export({'FeResult':DB})
def runCalpyAnalysis(jobname=None,verbose=False,flavia=False): """Create data for Calpy analysis module and run Calpy on the data. While we could write an analysis file in the Calpy format and then run the Calpy program on it (like we did with Abaqus), we can (and do) take another road here: Calpy has a Python/numpy interface, allowing us to directly present the numerical data in arrays to the analysis module. It is supposed that the Finite Element model has been created and exported under the name 'fe_model'. """ ############################ # Load the needed calpy modules from plugins import calpy_itf calpy_itf.check() ## # Load development version #import sys #sys.path.insert(0,'/home/bene/prj/calpy') #print sys.path import calpy reload(calpy) print(calpy.__path__) calpy.options.optimize=True from calpy import femodel,fe_util,plane from calpy.arrayprint import aprint ############################ checkWorkdir() if model is None: warn() return if jobname is None: # ask job name from user res = askItems([('JobName',feresult_name.peek()),('Verbose Mode',False)]) if res: jobname = res['JobName'] verbose = res['Verbose Mode'] if not jobname: print("No Job Name: bailing out") return # OK, start calpy print("Starting the Calpy analysis module --- this might take some time") pf.app.processEvents() starttime = time.clock() calpyModel = femodel.FeModel(2,"elast","Plane_Stress") calpyModel.nnodes = model.coords.shape[0] calpyModel.nelems = model.celems[-1] print([ e.shape for e in model.elems ]) nplex = [ e.shape[1] for e in model.elems ] if min(nplex) != max(nplex): warning("All parts should have same element type") return calpyModel.nnodel = nplex[0] # 2D model in calpy needs 2D coordinates coords = model.coords[:,:2] if verbose: fe_util.PrintNodes(coords) # Boundary conditions bcon = zeros((calpyModel.nnodes,2),dtype=int32) bcon[:,2:6] = 1 # leave only ux and uy for p in PDB.getProp(kind='n',attr=['bound']): bnd = where(p.bound)[0] if p.set is None: nod = arange(calpyModel.nnodes) else: nod = array(p.set) for i in bnd: bcon[p.set,i] = 1 fe_util.NumberEquations(bcon) if verbose: fe_util.PrintDofs(bcon,header=['ux','uy']) # The number of free DOFs remaining calpyModel.ndof = bcon.max() print("Number of DOF's: %s" % calpyModel.ndof) # We extract the materials/sections from the property database secprops = PDB.getProp(kind='e',attr=['section']) # E, nu, thickness, rho mats = array([[mat.young_modulus, mat.poisson_ratio, mat.thickness, 0.0, # rho was not defined in material ] for mat in secprops]) calpyModel.nmats = mats.shape[0] if verbose: fe_util.PrintMats(mats,header=['E','nu','thick','rho']) ########### Find number of load cases ############ calpyModel.nloads = nsteps calpyModel.PrintModelData() ngp = 2 nzem = 3 calpyModel.banded = True # Create element definitions: # In calpy, each element is represented by nnod + 1 integer numbers: # matnr, node1, node2, .... # Also notice that Calpy numbering starts at 1, not at 0 as customary # in pyFormex; therefore we add 1 to elems. matnr = zeros(calpyModel.nelems,dtype=int32) for i,mat in enumerate(secprops): # proces in same order as above! matnr[mat.set] = i+1 NodesGrp = [] MatnrGrp = [] PlaneGrp = [] for i,e in enumerate(model.elems): j,k = model.celems[i:i+2] Plane = plane.Quad("part-%s" % i,[ngp,ngp],calpyModel) Plane.debug = 0 PlaneGrp.append(Plane) NodesGrp.append(e+1) MatnrGrp.append(matnr[j:k]) if verbose: fe_util.PrintElements(NodesGrp[-1],MatnrGrp[-1]) #Plane.AddElements(e+1,matnr[j:k],mats,coords,bcon) for Plane,nodenrs,matnrs in zip(PlaneGrp,NodesGrp,MatnrGrp): Plane.AddElements(nodenrs,matnrs,mats,coords,bcon) # Create load vectors # Calpy allows for multiple load cases in a single analysis. # However, our script currently puts all loads together in a single # load case. So the processing hereafter is rather simple, especially # since Calpy provides a function to assemble a single concentrated # load into the load vector. We initialize the load vector to zeros # and then add all the concentrated loads from the properties database. # A single concentrated load consists of 6 components, corresponding # to the 6 DOFs of a node. # # AssembleVector takes 3 arguments: the global vector in which to # assemble a nodal vector (length ndof), the nodal vector values # (length 6), and a list of indices specifying the positions of the # nodal DOFs in the global vector. # Beware: The function does not change the global vector, but merely # returns the value after assembling. # Also notice that the indexing inside the bcon array uses numpy # convention (starting at 0), thus no adding 1 is needed! print("Assembling Concentrated Loads") f = zeros((calpyModel.ndof,calpyModel.nloads),float) for p in PDB.getProp('n',attr=['cload']): lc = loadcaseFromTag(p)-1 # calpy loadcases start from 0 if p.set is None: nodeset = range(calpyModel.nnodes) else: nodeset = p.set F = [0.0,0.0] for i,v in p.cload: if i in [0,1]: F[i] = v for n in nodeset: f[:,lc] = fe_util.AssembleVector(f[:,lc],F,bcon[n]) print("Assembling distributed loads") # This is a bit more complex. See Calpy for details # We first generate the input data in a string, then read them with the # calpy femodel.ReadBoundaryLoads function and finally assemble them with # plane.addBoundaryLoads. We have to do this operation per element group. # The group number is stored in the property record. ngroups = model.ngroups() s = [ "" ] * ngroups nb = [ 0 ] * ngroups for p in PDB.getProp('e',attr=['eload']): lc = loadcaseFromTag(p)-1 # calpy loadcases start from 0 xload = yload = 0. if p.label == 'x': xload = p.value elif p.label == 'y': yload = p.value # Because of the way we constructed the database, the set will # contain only one element, but let's loop over it anyway in case # one day we make the storage more effective # Also, remember calpy numbers are +1 ! g = p.group print("Group %s" % g) for e in p.set: s[g] += "%s %s %s %s %s\n" % (e+1,p.edge+1,lc,xload,yload) nb[g] += 1 #print s,nb for nbi,si,nodes,matnr,Plane in zip(nb,s,NodesGrp,MatnrGrp,PlaneGrp): if nbi > 0: idloads,dloads = fe_util.ReadBoundaryLoads(nbi,calpyModel.ndim,si) #print idloads,dloads Plane.AddBoundaryLoads(f,calpyModel,idloads,dloads,nodes,matnr,coords,bcon,mats) if verbose: print("Calpy.Loads") print(f) ############ Create global stiffness matrix ########## s = calpyModel.ZeroStiffnessMatrix(0) for elgrp in PlaneGrp: s = elgrp.Assemble(s,mats,calpyModel) # print "The complete stiffness matrix" # print s ############ Solve the system of equations ########## v = calpyModel.SolveSystem(s,f) print("Calpy analysis has finished --- Runtime was %s seconds." % (time.clock()-starttime)) displ = fe_util.selectDisplacements (v,bcon) if verbose: print("Displacements",displ) if flavia: flavia.WriteMeshFile(jobname,"Quadrilateral",model.nnodel,coord,nodes,matnr) res=flavia.ResultsFile(jobname) # compute stresses for lc in range(calpyModel.nloads): print("Results for load case %d" %(lc+1)) print("Displacements") aprint(displ[:,:,lc],header=['x','y'],numbering=True) if flavia: flavia.WriteResultsHeader(res,'"Displacement" "Elastic Analysis"',lc+1,'Vector OnNodes') flavia.WriteResults(res,displ[:,:,lc]) stresn = count = None i = 0 for e,P in zip(model.elems,PlaneGrp): i += 1 #P.debug = 1 stresg = P.StressGP (v[:,lc],mats) if verbose: print("elem group %d" % i) print("GP Stress\n", stresg) strese = P.GP2Nodes(stresg) if verbose: print("Nodal Element Stress\n", strese) #print "Nodes",e+1 stresn,count = P.NodalAcc(e+1,strese,nnod=calpyModel.nnodes,nodata=stresn,nodn=count) #print stresn,count #print stresn.shape #print count.shape #print "TOTAL",stresn,count stresn /= count.reshape(-1,1) #print "AVG",stresn if verbose: print("Averaged Nodal Stress\n") aprint(stresn,header=['sxx','syy','sxy'],numbering=True) if flavia: flavia.WriteResultsHeader(res,'"Stress" "Elastic Analysis"',lc+1,'Matrix OnNodes') flavia.WriteResults(res,stresn) DB = FeResult() DB.nodes = model.coords DB.nnodes = model.coords.shape[0] DB.nodid = arange(DB.nnodes) DB.elems = dict(enumerate(model.elems)) DB.nelems = model.celems[-1] DB.Finalize() DB.datasize['S'] = 3 #print DB.elems for lc in range(calpyModel.nloads): DB.Increment(lc,0) d = zeros((calpyModel.nnodes,3)) d[:,:2] = displ[:,:,lc] DB.R['U'] = d DB.R['S'] = stresn postproc_menu.setDB(DB) name = feresult_name.next() export({name:DB}) print("STEPS:",DB.getSteps()) print("INCS:",DB.getIncs(DB.getSteps()[0])) if showInfo("The results have been exported as %s\nYou can now use the postproc menu to display results" % name,actions=['Cancel','OK']) == 'OK': postproc_menu.selection.set(name) postproc_menu.selectDB(DB) postproc_menu.open_dialog()