def createResultDB(model): """Create a results database for the given FE model""" 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() return DB
def createFeResult(model,results): """Create an FeResult from meshes and results""" #model = Model(*mergeMeshes(meshes,fuse=False)) 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() ndisp = results['displacement'].shape[1] nstrs = results['stress'].shape[1] DB.datasize['U'] = ndisp DB.datasize['S'] = nstrs for lc in range(1): # currently only 1 step DB.Increment(lc,0) DB.R['U'] = results['displacement'] DB.R['S'] = results['stress'] return DB
def createFeResult(model, results): """Create an FeResult from meshes and results""" #model = Model(*mergeMeshes(meshes,fuse=False)) 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() ndisp = results['displacement'].shape[1] nstrs = results['stress'].shape[1] DB.datasize['U'] = ndisp DB.datasize['S'] = nstrs for lc in range(1): # currently only 1 step DB.Increment(lc, 0) DB.R['U'] = results['displacement'] DB.R['S'] = results['stress'] return DB
#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})
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)
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(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()