Argiope: pythonic FEM data management toolbox

Tutorials:

Notebooks

Notebooks

Note

This notebook can be downloaded here: mesh_tutorial.ipynb

Mesh tutorial
%load_ext autoreload
%autoreload 2
import argiope as ag
import numpy as np
import pandas as pd
import matplotlib.pyplot as plt
import matplotlib as mpl
from string import Template
%matplotlib nbagg
Geometry setup
geom_template = """
lc = $lc;
Point(1) = {0,0,0,lc};
Point(2) = {.5,0,0,lc};
Point(3) = {.5,.5,0,lc};
Point(4) = {1,.5,0,lc};
Point(5) = {1,1,0,lc};
Point(6) = {0,1,0,lc};
Point(7) = {.5,.25,0,lc};
Point(8) = {.5,.75,0,lc};
Point(9) = {.125,.875,0,lc};
Point(10) = {.125,.875-.05,0,lc};
Point(11) = {.125,.875+.05,0,lc};

Line(1)  = {1,2};
Circle(2)  = {2,3,4};
Line(3)  = {4,5};
Line(4)  = {5,6};
Line(5)  = {6,1};
Circle(6)  = {7,3,8};
Circle(7)  = {8,3,7};
Circle(8)  = {10,9,11};
Circle(9)  = {11,9,10};

Line Loop(1) = {6,7}; // interior loop
Line Loop(2) = {1,2,3,4,5}; // exterior loop
Line Loop(3) = {8,9};// hole
Plane Surface(2) = {2,1,3}; // exterior surface (with a hole)
Recombine Surface {2};
Physical Surface("SURFACE") = {2};
"""
open("./_workdir/mesh.geo", "w").write(Template(geom_template).substitute(lc = 0.025))
725
Mesh creation

GMSH can be run directly as a shell command.

!gmsh -2 ./_workdir/mesh.geo -algo 'delquad'
Info    : Running 'gmsh -2 ./_workdir/mesh.geo -algo delquad' [Gmsh 2.10.1, 1 node, max. 1 thread]
Info    : Started on Tue Jan  9 11:29:41 2018
Info    : Reading './_workdir/mesh.geo'...
Info    : Done reading './_workdir/mesh.geo'
Info    : Meshing 1D...
Info    : Meshing curve 1 (Line)
Info    : Meshing curve 2 (Circle)
Info    : Meshing curve 3 (Line)
Info    : Meshing curve 4 (Line)
Info    : Meshing curve 5 (Line)
Info    : Meshing curve 6 (Circle)
Info    : Meshing curve 7 (Circle)
Info    : Meshing curve 8 (Circle)
Info    : Meshing curve 9 (Circle)
Info    : Done meshing 1D (0 s)
Info    : Meshing 2D...
Info    : Meshing surface 2 (Plane, Frontal Quad)
Info    : Blossom: 3661 internal 232 closed
Info    : BEFORE OPTIMIZATION :  1259 quads     0 triangles    2 invalid quads   14 quads with Q < 0.1 Avg Q =  8.36104E-01 Min -1.36604E-01
Info    : IN OPTIMIZATION :  1244 quads     0 triangles    0 invalid quads    0 quads with Q < 0.1 Avg Q =  8.81967E-01 Min  4.14368E-01
Info    : Blossom recombination algorithm completed (0.152 s)
Info    : AFTER OPTIMIZATION :  1244 quads     0 triangles    0 invalid quads    0 quads with Q < 0.1 Avg Q =  8.90361E-01 Min  4.14368E-01
Info    : Done meshing 2D (0.612 s)
Info    : 2873 vertices 1487 elements
Info    : Writing './_workdir/mesh.msh'...
Info    : Done writing './_workdir/mesh.msh'
Info    : Stopped on Tue Jan  9 11:29:42 2018

It is even simpler to use the dedicated function in argiope.utils.

ag.utils.run_gmsh(gmsh_path = "gmsh",
                  gmsh_space = 2,
                  gmsh_options = "-algo 'del2d'",
                  name = "./_workdir/mesh.geo")
Mesh reading
mesh = ag.mesh.read_msh("./_workdir/mesh.msh")
mesh.nodes.head()
coords
x y z
node
1 0.0 0.0 0.0
2 0.5 0.0 0.0
3 1.0 0.5 0.0
4 1.0 1.0 0.0
5 0.0 1.0 0.0
mesh.elements.head()
conn materials sets type
n0 n1 n2 n3 SURFACE argiope solver
element
1 428 1655 762 761 True quad4
2 344 739 689 1513 True quad4
3 426 856 237 695 True quad4
4 1366 809 255 1227 True quad4
5 864 675 438 1446 True quad4
Putting it all together

Let’s now do all these operations in a single function and do fun stuff.

def make_mesh(lc, algorithm = "del2d"):
    """
    A mesh function that creates a mesh.
    """
    open("./_workdir/mesh.geo", "w").write(Template(geom_template).substitute(lc = lc))
    ag.utils.run_gmsh(gmsh_path = "gmsh",
                  gmsh_space = 2,
                  gmsh_options = "-algo '{0}'".format(algorithm),
                  name = "./_workdir/mesh.geo")
    mesh = ag.mesh.read_msh("./_workdir/mesh.msh")
    return mesh

mesh = make_mesh(0.02, "meshadapt")
mesh
<Mesh, 2350 nodes, 2208 elements, 0 fields>
fig = plt.figure()
algos = ["frontal", "del2d", "delquad", "meshadapt"]
for i in range(len(algos)):
    mesh = make_mesh(0.03, algos[i])
    patches = mesh.to_polycollection(edgecolor = "black", linewidth = .5, alpha = 1.)
    stats = mesh.stats()
    #patches.set_array( stats.stats.max_abs_angular_deviation )
    patches.set_array( stats.stats.aspect_ratio )
    patches.set_cmap(mpl.cm.terrain)
    ax = fig.add_subplot(2, 2, i+1)
    ax.set_aspect("equal")
    ax.set_xlim(mesh.nodes.coords.x.min(), mesh.nodes.coords.x.max())
    ax.set_ylim(mesh.nodes.coords.y.min(), mesh.nodes.coords.y.max())
    ax.add_collection(patches)
    cbar = plt.colorbar(patches, orientation = "vertical")
    cbar.set_label("Max Abs. Ang. Dev. [$^o$]")
    ax.set_title(algos[i])
    #plt.xlabel("$x$")
    #plt.ylabel("$y$")
    #plt.grid()
    ax.axis('off')
plt.show()
<IPython.core.display.Javascript object>
Mesh quality investigation

For example, let’s investigate the effect of the mesh algorithm on the overall quality of the mesh.

stats = mesh.stats()
stats.stats.describe().loc[["min", "max", "mean", "std"]][["max_angular_deviation", "aspect_ratio"]]
max_angular_deviation aspect_ratio
min 0.812189 1.005641
max 57.488325 2.633344
mean 21.067222 1.342344
std 11.070150 0.234528

Package documentation:

Mesh

Mesh processing tools.

Mesh class

class argiope.mesh.Mesh(**kwargs)[source]

A single class to handle meshes.

Mesh.__init__(**kwargs)[source]

The constructor only a redirection to the following methods:

  • set_nodes
  • set_elements
  • set_fields
import argiope as ag
import numpy as np

nlabels = np.arange(4) + 1 
coords = np.array([[0., 0., 0.],
                   [1., 0., 0.],
                   [1., 1., 0.],
                   [0., 1., 0.],])
elabels = np.array([1])
conn = np.array([[1, 2, 3, 4]])
types = ["quad4"]   
stypes = ["CPS4"]   
                
mesh = ag.mesh.Mesh(nlabels = nlabels,
                    coords = coords,
                    elabels = elabels,
                    conn = conn,
                    types = types,
                    stype = stypes)                   
Set
Mesh.set_nodes(nlabels=None, coords=None, nsets={}, **kwargs)[source]

Sets the node data.

import argiope as ag
import numpy as np

nlabels = np.arange(4) + 1 
coords = np.array([[0., 0., 0.],
                   [1., 0., 0.],
                   [1., 1., 0.],
                   [0., 1., 0.],])
                
mesh = ag.mesh.Mesh()
mesh.set_nodes(nlabels = nlabels, coords = coords)

Mesh.set_elements(elabels=None, types=None, stypes='', conn=None, esets={}, surfaces={}, materials='', **kwargs)[source]

Sets the element data.

import argiope as ag
import numpy as np

nlabels = np.arange(4) + 1 
coords = np.array([[0., 0., 0.],
                   [1., 0., 0.],
                   [1., 1., 0.],
                   [0., 1., 0.],])
elabels = np.array([1])
conn = np.array([[1, 2, 3, 4]])
types = ["quad4"]   
stypes = ["CPS4"]   

mesh = ag.mesh.Mesh()
mesh.set_nodes(nlabels = nlabels, coords = coords)
mesh.set_elements(elabels = elabels,
                  conn = conn,
                  types = types,
                  stype = stypes)                   
Mesh.set_fields(fields=None, **kwargs)[source]

Sets the fields.

Verify
Mesh.check_elements()[source]

Checks element definitions.

Mesh.nvert()[source]

Returns the number of vertices of eache element according to its type/

Mesh.centroids_and_volumes(sort_index=True)[source]

Returns a dataframe containing volume and centroids of all the elements.

Mesh.angles()[source]

Returns the internal angles of all elements and the associated statistics

Mesh.edges()[source]

Returns the aspect ratio of all elements.

Mesh.stats()[source]

Returns mesh quality and geometric stats.

Mesh.fields_metadata()[source]

Returns fields metadata as a dataframe.

Modify
Mesh.element_set_to_node_set(tag)[source]

Makes a node set from an element set.

Mesh.node_set_to_surface(tag)[source]

Converts a node set to surface.

Mesh.surface_to_element_sets(tag)[source]

Creates elements sets corresponding to a surface.

Plot with Matplotlib
Mesh.to_polycollection(*args, **kwargs)[source]

Returns the mesh as matplotlib polygon collection. (tested only for 2D meshes)

Mesh.to_triangulation()[source]

Returns the mesh as a matplotlib.tri.Triangulation instance. (2D only)

Export
Mesh.write_inp(*args, **kwargs)[source]

Exports the mesh to the Abaqus INP format.

Fields

Meta classes

class argiope.mesh.MetaField(label=None, position='node', step_num=None, step_label=None, part=None, frame=None, frame_value=None, data=None, **kwargs)[source]

A field mother class.

Parameters:
  • label (str) – field label
  • position (in ["node", "element"]) – physical position
copy()

Returns a copy of self.

metadata()[source]

Returns metadata as a dataframe.

save(path)

Saves the instance into a compressed serialized file.

class argiope.mesh.Field(label=None, position='node', step_num=None, step_label=None, part=None, frame=None, frame_value=None, data=None, **kwargs)[source]
copy()

Returns a copy of self.

metadata()

Returns metadata as a dataframe.

save(path)

Saves the instance into a compressed serialized file.

Field classes

class argiope.mesh.ScalarField(label=None, position='node', step_num=None, step_label=None, part=None, frame=None, frame_value=None, data=None, **kwargs)[source]
copy()

Returns a copy of self.

metadata()

Returns metadata as a dataframe.

save(path)

Saves the instance into a compressed serialized file.

class argiope.mesh.Vector2Field(label=None, position='node', step_num=None, step_label=None, part=None, frame=None, frame_value=None, data=None, **kwargs)[source]

2D vector field.

copy()

Returns a copy of self.

metadata()

Returns metadata as a dataframe.

save(path)

Saves the instance into a compressed serialized file.

class argiope.mesh.Vector3Field(label=None, position='node', step_num=None, step_label=None, part=None, frame=None, frame_value=None, data=None, **kwargs)[source]

3D vector field.

copy()

Returns a copy of self.

metadata()

Returns metadata as a dataframe.

save(path)

Saves the instance into a compressed serialized file.

class argiope.mesh.Tensor4Field(label=None, position='node', step_num=None, step_label=None, part=None, frame=None, frame_value=None, data=None, **kwargs)[source]

Second order symmetric 2D tensor field.

copy()

Returns a copy of self.

metadata()

Returns metadata as a dataframe.

save(path)

Saves the instance into a compressed serialized file.

class argiope.mesh.Tensor6Field(label=None, position='node', step_num=None, step_label=None, part=None, frame=None, frame_value=None, data=None, **kwargs)[source]

Second order symmetric tensor field.

copy()

Returns a copy of self.

metadata()

Returns metadata as a dataframe.

save(path)

Saves the instance into a compressed serialized file.

Parsers

argiope.mesh.read_msh(path)[source]

Reads a GMSH MSH file and returns a Mesh instance.

Parameters:path (str) – path to MSH file.

Materials

Materials useable for FEM simulations.

Materials

class argiope.materials.Elastic(young_modulus=1.0, poisson_ratio=0.3, **kwargs)[source]

An isotropic elastic material class.

write_inp()[source]

Returns the material definition as a string in Abaqus INP format.

class argiope.materials.ElasticPerfectlyPlastic(yield_stress=0.01, **kwargs)[source]

A elastic perfectly plastic material.

get_plastic_table()[source]

Calculates the plastic data

write_inp()

Returns the material definition as a string in Abaqus INP format.

class argiope.materials.Hollomon(hardening_exponent=0.3, yield_stress=0.01, **kwargs)[source]

An Hollomon material.

get_plastic_table()[source]

Calculates the plastic data

write_inp()

Returns the material definition as a string in Abaqus INP format.

class argiope.materials.PowerLin(hardening_exponent=0.3, yield_stress=150.0, consistency=200.0, **kwargs)[source]

A Power Linear material : S = Sy + K (Ep)**n

get_plastic_table()[source]

Calculates the plastic data

write_inp()

Returns the material definition as a string in Abaqus INP format.

Models

Classes dedicated to model creation.

Model

The model meta class aims at being subclassed by actual model classes.

class argiope.models.Model(label, parts, steps, materials, solver='abaqus', solver_path='', workdir='./workdir', verbose=False)[source]

Model meta class.

copy()

Returns a copy of self.

make_directories()[source]

Checks if required directories exist and creates them if needed.

run_postproc()[source]

Runs the post-proc script.

run_simulation()[source]

Runs the simulation.

save(path)

Saves the instance into a compressed serialized file.

Part

The part meta class helps creating part classes by providing useful methods.

class argiope.models.Part(gmsh_path='gmsh', file_name='dummy', workdir='./', gmsh_space=2, gmsh_options='', element_map=None, material_map=None)[source]
copy()

Returns a copy of self.

run_gmsh()[source]

Makes the mesh using gmsh.

save(path)

Saves the instance into a compressed serialized file.

Utils

Useful functions and classes.

Meta Classes

class argiope.utils.Container[source]

A container meta class with utilities

copy()[source]

Returns a copy of self.

save(path)[source]

Saves the instance into a compressed serialized file.