Ejemplo n.º 1
0
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)
Ejemplo n.º 2
0
    fil.close()
    showFile(filnam,mono=True)

    if ack("Shall I run the Calix analysis?"):
        # Run the analysis
        outfile = utils.changeExt(filnam,'res')
        cmd = "calix %s %s" % (filnam,outfile)
        utils.runCommand(cmd)
        showFile(outfile,mono=True)
        
        if ack("Shall I read the results for postprocessing?"):
            from plugins import flavia
            meshfile = utils.changeExt(filnam,'flavia.msh')
            resfile = utils.changeExt(filnam,'flavia.res')
            DB = flavia.readFlavia(meshfile,resfile)
            postproc_menu.setDB(DB)
            export({name:DB})
            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_results_dialog()
    

##############################################################################

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
Ejemplo n.º 3
0
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})
Ejemplo n.º 4
0
def run():
    reset()
    clear()

    processor = 'abq'   # set to 'ccx' for calculix

    # Create a thin rectangular plate.
    # Because it is thin, we use a 2D model (in the xy plane.
    # We actually only model 1/4 of the plate'
    # The full plate could be found from mirroring wrt x and y axes.
    L = 400. # length of the plate (mm)
    B = 100. # width of the plate (mm)
    th = 10. # thickness of the plate (mm)
    L2,B2 = L/2, B/2  # dimensions of the quarter plate
    nl,nb = 10,16     # number of elements along length, width
    nl,nb = 2,2     # number of elements along length, width
    D = 20.
    r = D/2
    e0 = 0.3

    # User input
    res = askItems([
        _I('geometry',choices=['Rectangle','Square with hole'],text='Plate geometry'),
        _I('material',choices=['Elastic','Plastic'],text='Material model'),
        _I('eltype',choices=['quad4','quad8','hex8','hex20'],text='Element type'),
        _I('interpolation',choices=['Linear','Quadratic'],text='Degree of interpolation'),
        _I('format',choices=['CalculiX','Abaqus'],text='FEA input format'),
        _I('run',True,text='Run simulation'),
        ])

    if not res:
        return

    cmd = None
    if res['run']:
        cmd = {'CalculiX':'ccx','Abaqus':'abaqus'}[res['format']]
        if not utils.hasExternal(res['format'].lower()):
            ans = pf.warning("I did not find the command '%s' on your system.\nIf you continue, I can prepare the model and write the input file,but not run the simulation" % cmd,actions=['Cancel','Continue'])
            if ans == 'Continue':
                cmd = None
            else:
                return


    # Create geometry
    if res['geometry'] == 'Rectangle':
        plate = simple.rectangle(nl,nb,L2,B2).toMesh()
    else:
        plate = rectangle_with_hole(L2,B2,r,nl,nb,e0)


    if res['eltype'].startswith('hex'):
        plate = plate.extrude(1,step=1.0,dir=2)

    plate = plate.convert(res['eltype'])

    draw(plate)

    # model is completely shown, keep camera bbox fixed
    setDrawOptions({'bbox':'last','marksize':8})

    # Assemble the FEmodel (this may renumber the nodes!)
    FEM = Model(meshes=[plate])

    # Create an empty property database
    P = PropertyDB()

    # Define the material data: here we use an elasto-plastic model
    # for the steel
    steel = {
        'name': 'steel',
        'young_modulus': 207000e-6,
        'poisson_ratio': 0.3,
        'density': 7.85e-9,
        }

    if res['material'] == 'Plastic':
        steel.update(
            {'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),
                ]
             })

    # Define the thin steel plate section
    steel_plate = {
        'name': 'steel_plate',
        'sectiontype': 'solid',
        'thickness': th,
        'material': 'steel',   # Reference to the material name above
        }

    # Give the elements their properties: this is simple here because
    # all elements have the same properties. The element type is
    # for an Abaqus plain stress quadrilateral element with 4 nodes.
    P.elemProp(name='Plate',eltype='CPS4',section=ElemSection(section=steel_plate,material=steel))

    # Set the boundary conditions
    # The xz and yz planes should be defined as symmetry planes.
    # First, we find the node numbers along the x, y axes:
    elsize = min(L2/nl,B2/nb)  # smallest size of elements
    tol = 0.001*elsize         # a tolerance to avoid roundoff errors
    nyz = FEM.coords.test(dir=0,max=tol)  # test for points in the yz plane
    nxz = FEM.coords.test(dir=1,max=tol)  # test for points in the xz plane
    nyz = where(nyz)[0]  # the node numbers passing the above test
    nxz = where(nxz)[0]
    draw(FEM.coords[nyz],color=cyan)
    draw(FEM.coords[nxz],color=green)

    # Define the boundary conditions
    # For Abaqus, we could define it like follows
    #P.nodeProp(tag='init',set=nyz,name='YZ_plane',bound='XSYMM')
    #P.nodeProp(tag='init',set=nxz,name='XZ_plane',bound='YSYMM')
    # But as Calculix does not have the XSYMM/YSYMM possibilities
    # we define the conditions explicitely
    P.nodeProp(tag='init',set=nyz,name='YZ_plane',bound=[1,0,0,0,0,0])
    P.nodeProp(tag='init',set=nxz,name='XZ_plane',bound=[0,1,0,0,0,0])

    # The plate is loaded by a uniform tensile stress in the x-direction
    # First we detect the border
    brd,ind = FEM.meshes()[0].getBorder(return_indices=True)
    BRD = Mesh(FEM.coords,brd).compact()
    draw(BRD,color=red,linewidth=2)
    xmax = BRD.bbox()[1][0]   # the maximum x coordinate
    loaded = BRD.test(dir=0,min=xmax-tol)
    # The loaded border elements
    loaded = where(loaded)[0]
    draw(BRD.select(loaded),color=blue,linewidth=4)
    sortedelems = sortElemsByLoadedFace(ind[loaded])
    # Define the load
    # Apply 4 load steps:
    # 1: small load (10 MPa)
    # 2: higher load, but still elastic (100 MPa)
    # 3: slightly exceeding yield stress (320 MPa)
    # 4: high plastic deformation (400MPa)
    loads = [10.,100.,320.,400.]  # tensile load in MPa
    steps = ['step%s'%(i+1) for i in range(len(loads)) ]   # step names
    for face in sortedelems:
        abqface = face+1 # BEWARE: Abaqus numbers start with 1
        for step,load in zip(steps,loads):
            P.elemProp(tag=step,set=sortedelems[face],name='Loaded-%s'%face,dload=ElemLoad('P%s'%(abqface),-load))

    # Print the property database
    P.print()

    # 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)
    if res['format'] == 'Abaqus':
        result = [
            Result(kind='NODE',keys=['U']),
            Result(kind='ELEMENT',keys=['S'],set='Plate'),
            Result(kind='ELEMENT',keys=['S'],pos='AVERAGED AT NODES',set='Plate'),
            Result(kind='ELEMENT',keys=['SP','SINV'],set='Plate'),
            ]
    else:
        result = [
            Result(kind='NODE',keys=['U'],output='PRINT'),
            Result(kind='ELEMENT',keys=['S'],output='PRINT'),
            ]


    # Define the simulation steps
    # The tags refer to the property database
    simsteps = [ Step('STATIC',time=[1., 1., 0.01, 1.],tags=[step]) for step in steps ]

    data = AbqData(FEM,prop=P,steps=simsteps,res=result,bound=['init'])

    fn = askNewFilename(pf.cfg['workdir']+'/feplast.inp',filter='*.inp')
    if fn:
        data.write(jobname=fn,group_by_group=True)

        if cmd:
            chdir(fn)
            job = os.path.basename(fn)[:-4]
            if cmd == 'ccx':
                cmd = "ccx -i %s" % job
            elif cmd == 'abaqus':
                cmd == "abaqus job=%s" % job
            sta,out = utils.runCommand("ccx -i %s" % job)
            print(out)

            if ack('Create the result database?'):
                DB = ccxdat.createResultDB(FEM)
                ngp = 8
                fn = utils.changeExt(fn,'.dat')
                ccxdat.readResults(fn,DB,DB.nnodes,DB.nelems,ngp)
                DB.printSteps()
                name = 'FeResult-%s'%job
                export({name:DB})
                postproc_menu.setDB(DB)
                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()
Ejemplo n.º 5
0
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})
Ejemplo n.º 6
0
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()
Ejemplo n.º 7
0
def createCalixInput():
    """Write the Calix input file."""

    checkWorkdir()

    if model is None:
        warn()
        return
    
    # ask job name from user
    res = askItems([
        _I('jobname',feresult_name.next(),text='Job Name'),
        _I('header','A Calix example',text='Header Text'),
        _I('zem','3',text='ZEM control',itemtype='radio',choices=['0','3','6'],),
        ])
    if not res:
        return

    jobname = res['jobname']
    header = res['header']
    nzem = int(res['zem'])
    if not jobname:
        print("No Job Name: writing to sys.stdout")
        jobname = None

    filnam = jobname+'.dta'
    print("Writing calix data file %s in %s" % (filnam,os.getcwd()))
    fil = open(filnam,'w')
    
    nnodes = model.coords.shape[0]
    nelems = model.celems[-1]
    nplex = [ e.shape[1] for e in model.elems ]
    if min(nplex) != max(nplex):
        print([ e.shape for e in model.elems ])
        warning("All parts should have same element type")
        return
    nodel = nplex[0]

    # Get materials
    secprops = PDB.getProp(kind='e',attr=['section'])
    print(secprops)
    # need E, nu, thickness, rho
    mats = array([[sec.young_modulus,
                   sec.poisson_ratio,
                   sec.thickness,
                   sec.density,
                   ] for sec in secprops]) 
    matnr = zeros(nelems,dtype=int32)
    for i,mat in enumerate(secprops):  # proces in same order as above!
        matnr[mat.set] = i+1
    print(matnr)
    nmats = mats.shape[0]
    
    # Header
    fil.write("""; calix data file generated by %s
; jobname=%s
start: %s
;use cmdlog 'calix.log'
;use for messages cmdlog
file open 'femodel.tmp' write da 1
yes cmdlog
;yes debug
use for cmdlog output
femodel elast stress 2
use for cmdlog cmdlog
;-----------------------------------------
; Aantal knopen:   %s
; Aantal elementen:   %s
; Aantal materialen:     %s
; Aantal belastingsgevallen: %s
"""% (pf.Version,jobname,header,nnodes,nelems,nmats,nsteps))
    # Nodal coordinates
    fil.write(""";-----------------------------------------
; Knopen
;--------
nodes coord %s 1
""" % nnodes)
    fil.write('\n'.join(["%5i%10.2f%10.2f"%(i,x[0],x[1]) for i,x in zip(arange(nnodes)+1,model.coords)]))
    fil.write('\n\n')
    # Boundary conditions
    fil.write(""";-----------------------------------------
; Verhinderde verplaatsingen
;-------------------------
bound bcon
plane
""")
    for p in PDB.getProp(kind='n',attr=['bound']):
        bnd = "%5i" + "%5i"*2 % (p.bound[0],p.bound[1])
        if p.set is None:
            nod = arange(model.nnodes)
        else:
            nod = array(p.set)
        fil.write('\n'.join([ bnd % i for i in nod+1 ]))
        fil.write('\n')
    fil.write('\n')
    fil.write("""print bcon 3
                           $$$$$$$$$$$$$$$$$$$$$$$
                           $$      D O F S      $$
                           $$$$$$$$$$$$$$$$$$$$$$$
""")
    
    # Materials
    fil.write(""";-----------------------------------------
; Materialen
;-----------
array mat    %s 4
""" % len(mats))
    print(mats)
    fil.write('\n'.join([ "%.4e "*4 % tuple(m) for m in mats]))
    fil.write('\n\n')
    fil.write("""print mat 3
                           $$$$$$$$$$$$$$$$$$$$$$$
                           $$ M A T E R I A L S $$
                           $$$$$$$$$$$$$$$$$$$$$$$
""")
    
    # Elements
    for igrp,grp in enumerate(model.elems):
        nelems,nplex = grp.shape
        fil.write(""";-----------------------------------------
; Elementen
;----------
elements elems-%s matnr-%s  %s %s 1
""" % (igrp,igrp,nplex,nelems))
        fil.write('\n'.join(["%5i"*(nplex+2) % tuple([i,1]+e.tolist()) for i,e in zip(arange(nelems)+1,grp+1)]))
        fil.write('\n\n')
        fil.write("""plane plane-%s coord bcon elems-%s matnr-%s 2 2
""" % (igrp,igrp,igrp))
        
    #########################
    # Nodal Loads
    cloads = [ p for p in PDB.getProp('n',attr=['cload']) ]
    fil.write("""text 3 1
                           $$$$$$$$$$$$$$$$$$$$
                           $$  NODAL  LOADS  $$
                           $$$$$$$$$$$$$$$$$$$$
loads f bcon 1
""")
    if len(cloads) > 0:
        for p in cloads:
            loadcase = loadcaseFromTag(p)
            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
            fil.write(''.join(["%5i%5i%10.2f%10.2f\n" % (n+1,loadcase,F[0],F[1]) for n in nodeset]))
    fil.write('\n')
    
    #########################
    # Distributed loads
    eloads = [ p for p in PDB.getProp('e',attr=['eload']) ]
    if len(eloads) > 0:
        fil.write("""text 4 1
                           $$$$$$$$$$$$$$$$$$$$$$$$$$
                           $$  BOUNDARY  ELEMENTS  $$
                           $$$$$$$$$$$$$$$$$$$$$$$$$$
   elem  loadnr  localnodes
""")
        # get the data from database, group by group
        for igrp in range(len(model.elems)):
            geloads = [ p for p in eloads if p.group==igrp ]
            neloads = len(geloads)
            loaddata = []
            fil.write("array randen integer   %s 4 0 1\n" % neloads)
            i = 1
            for p in geloads:
                loadcase = loadcaseFromTag(p)
                xload = yload = 0.
                if p.label == 'x':
                    xload = p.value
                elif p.label == 'y':
                    yload = p.value
                # Save the load data for later
                loaddata.append((i,loadcase,xload,yload))
                # 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
                for e in p.set:
                    fil.write(("%5s"*4+"\n")%(e+1,i,p.edge+1,(p.edge+1)%4+1))
                i += 1
            fil.write("""print randen
tran randen tranden
boundary  rand-%s coord bcon elems-%s matnr-%s tranden 1
""" % ((igrp,)*3))
            fil.write("""text 3 1
                           $$$$$$$$$$$$$$$$$$$$$$$
                           $$  BOUNDARY  LOADS  $$
                           $$$$$$$$$$$$$$$$$$$$$$$
loadvec boundary rand-%s f 1
""" % igrp)
            for eload in loaddata:
                fil.write("%5s%5s%10s%10s\n" % eload)
            fil.write('\n')

    #########################
    # Print total load vector
    fil.write("""
print f 3
                           $$$$$$$$$$$$$$$$$$$$
                           $$  LOAD  VECTOR  $$
                           $$$$$$$$$$$$$$$$$$$$
;
""")
    # Assemble
    for igrp in range(len(model.elems)):
        fil.write("assemble plane-%s mat s 0 0 0 %s\n" % (igrp,nzem))

    # Solve and output
    fil.write(""";------------------------------------------------solve+output
flavia mesh '%s.flavia.msh' %s
flavia nodes coord
""" %  (jobname,nplex))
    for igrp in range(len(model.elems)):
        fil.write("flavia elems elems-%s matnr-%s %s\n" % (igrp,igrp,nplex))
    fil.write("flavia results '%s.flavia.res'\n" % jobname)
    fil.write("""
solbnd s f
delete s
text named 1
"Displacement" "Elastic Analysis"
text typed 1
Vector OnNodes
text names 1
"Stress" "Elastic Analysis"
text types 1
Matrix OnNodes
intvar set 1 1
loop 1
  displ f bcon displ $1 1
  tran displ disp
  flavia result named typed disp $1
""")
    for igrp in range(len(model.elems)):
        fil.write("""
  stress plane-%s mat f stresg $1 1
  gp2nod plane-%s stresg strese 0 1
  nodavg plane-%s elems-%s strese stren nval 1
  tran stren stre
  flavia result names types stre $1
""" % ((igrp,)*4))
    fil.write("""       
  intvar add 1 1
next
stop
""")

    # Done: Close data file
    fil.close()
    showFile(filnam,mono=True)

    if ack("Shall I run the Calix analysis?"):
        # Run the analysis
        outfile = utils.changeExt(filnam,'res')
        cmd = "calix %s %s" % (filnam,outfile)
        utils.runCommand(cmd)
        showFile(outfile,mono=True)
        
        if ack("Shall I read the results for postprocessing?"):
            from plugins import flavia
            meshfile = utils.changeExt(filnam,'flavia.msh')
            resfile = utils.changeExt(filnam,'flavia.res')
            DB = flavia.readFlavia(meshfile,resfile)
            postproc_menu.setDB(DB)
            export({name:DB})
            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()