Advanced Examples

Here we show some fancier examples using the tools available in abapy all together.

Indentation

2D / 3D , multi material indentation

All files used in this example are available in doc/advanced_examples/indentation/simulations

In this example, we focus on the indentation behavior of an elastic-plastic (von Mises) sample indented by an axisymmetric cone. To build this example, we first need to create 2 classes: Simulation and Database_Manager as follows in the file classes.py:

# VON MISES CLASSES
# Parametric indentation tool

#----------------------------------------------------------------------------------------------------------------
# IMPORTS
from sqlalchemy import create_engine, Column, Integer, String, Float, Boolean, PickleType, UniqueConstraint, desc
from sqlalchemy.ext.declarative import declarative_base
from sqlalchemy.orm import sessionmaker
#----------------------------------------------------------------------------------------------------------------


Base = declarative_base()




#---------------------------------------------------------------------------------------------------------------- 
# SIMULATION CLASS 
# Declaration of the Simulation class which stores all simulation data so that each simulation is an instance of the Simulation class. This class uses widely SQL Alchemy's ORM capabilities. To go deeper into this class, please read the (very good) tutorial or SQL Alchemy. If you just want to see the spirit of this class, just see it as a database when each attribute is mirrored as a database entry. The structure of the class itself is surprising because SQL Alchemy allows automatic constructor building so any attribute is automatically available in the constructor (i. e. __init__).
class Simulation(Base):
  __tablename__ = 'simulations'
  id = Column(Integer, primary_key=True)
  # Inputs
  three_dimensional            = Column(Boolean, default = False, nullable = False)
  sweep_angle         = Column(Float, nullable = False, default = 60.)
  rigid_indenter               = Column(Boolean, default = True, nullable = False)
  indenter_half_angle          = Column(Float, nullable = False, default = 70.3)
  indenter_pyramid             = Column(Boolean, default = True, nullable = False)
  indenter_mat_type            = Column(String, nullable = False, default = 'elastic')
  indenter_mat_args            = Column(PickleType, 
    nullable = False, 
    default = {'young_modulus': 1., 'poisson_ratio': 0.3})
  sample_mat_type              = Column(String, nullable = False, default = 'vonmises')
  sample_mat_args              = Column(PickleType, 
    nullable = False, 
    default = {'young_modulus': 1., 'poisson_ratio': 0.3, 'yield_stress': 0.01})
  friction                     = Column(Float, nullable = False, default = 0.) 
  mesh_Na                      = Column(Integer, default = 4,  nullable = False)
  mesh_Nb                      = Column(Integer, default = 4,  nullable = False)
  mesh_Ns                      = Column(Integer, default = 16, nullable = False)
  mesh_Nf                      = Column(Integer, default = 2,  nullable = False)
  mesh_Nsweep                  = Column(Integer, default = 8,  nullable = False)
  indenter_mesh_Na             = Column(Integer, default = 0,  nullable = False)
  indenter_mesh_Nb             = Column(Integer, default = 0,  nullable = False)
  indenter_mesh_Ns             = Column(Integer, default = 0,  nullable = False)
  indenter_mesh_Nf             = Column(Integer, default = 0,  nullable = False)
  indenter_mesh_Nsweep         = Column(Integer, default = 0,  nullable = False)
  mesh_l                       = Column(Float,   default = 1., nullable = False)
  max_disp                     = Column(Float,   default = 1., nullable = False)
  sample_mesh_disp             = Column(PickleType, nullable = False, default = False )
  # Internal parameters
  frames                       = Column(Integer, default = 30, nullable = False)
  completed                    = Column(Boolean, default = False, nullable = False)
  priority                     = Column(Integer, default = 1, nullable = False)
  # Preprocess
  mesh                         = Column(PickleType)
  indenter                     = Column(PickleType)
  sample_mat                   = Column(PickleType)
  indenter_mat                 = Column(PickleType)
  steps                        = Column(PickleType)
  # Time histories
  force_hist                   = Column(PickleType)
  disp_hist                    = Column(PickleType)
  tip_penetration_hist         = Column(PickleType)
  elastic_work_hist            = Column(PickleType)
  plastic_work_hist            = Column(PickleType)
  friction_work_hist           = Column(PickleType)
  total_work_hist              = Column(PickleType)
  # Contact data
  contact_data                 =  Column(PickleType)
  # Fields
  stress_field                 = Column(PickleType)
  disp_field                   = Column(PickleType)
  total_strain_field           = Column(PickleType)
  plastic_strain_field         = Column(PickleType)
  elastic_strain_field         = Column(PickleType)
  equivalent_plastic_strain_field = Column(PickleType)
  disp_field                   = Column(PickleType)
  ind_disp_field               = Column(PickleType)
  
  # Table args 
  __table_args__ = (
    UniqueConstraint(
    'three_dimensional',
    'indenter_pyramid',
    'rigid_indenter',
    'sample_mat_type',
    'sample_mat_args',
    'indenter_mat_type',
    'indenter_mat_args',
    'indenter_half_angle',
    'sweep_angle',
    'friction',
    'mesh_Na',
    'mesh_Nb', 
    'mesh_Ns', 
    'mesh_Nf',
    'mesh_l',
    'mesh_Nsweep',
    'indenter_mesh_Na',
    'indenter_mesh_Nb', 
    'indenter_mesh_Ns', 
    'indenter_mesh_Nf',
    'indenter_mesh_Nsweep',
    'max_disp',
    'sample_mesh_disp'),
    {})
  
  # Post processing script
  def abqpostproc_byRpt(self):
    if self.three_dimensional: # 3D post processing script
      out = """# ABQPOSTPROC.PY
# Warning: executable only in abaqus abaqus viewer -noGUI,... not regular python.
import sys
from abapy.postproc import GetFieldOutput_byRpt as gfo
from abapy.postproc import GetVectorFieldOutput_byRpt as gvfo
from abapy.postproc import GetTensorFieldOutput_byRpt as gtfo
from abapy.postproc import GetHistoryOutputByKey as gho
from abapy.indentation import Get_ContactData
from abapy.misc import dump
from odbAccess import openOdb
from abaqusConstants import JOB_STATUS_COMPLETED_SUCCESSFULLY



# Odb opening  
file_name = '#FILE_NAME'
odb = openOdb(file_name + '.odb')
data = {}

# Check job status:
job_status = odb.diagnosticData.jobStatus

if job_status == JOB_STATUS_COMPLETED_SUCCESSFULLY:
  data['completed'] = True 
  # Field Outputs
  data['field'] = {}
  fo = data['field']
  fo['Uind'] = [
    gvfo(odb = odb, 
      instance = 'I_INDENTER', 
      step = 1,
      frame = -1,
      original_position = 'NODAL', 
      new_position = 'NODAL', 
      position = 'node',
      field = 'U', 
      delete_report = True),
    gvfo(odb = odb, 
      instance = 'I_INDENTER', 
      step = 2,
      frame = -1,
      original_position = 'NODAL', 
      new_position = 'NODAL', 
      position = 'node',
      field = 'U', 
      delete_report = True)]
  
  fo['U'] = [
    gvfo(odb = odb, 
      instance = 'I_SAMPLE', 
      step = 1,
      frame = -1,
      original_position = 'NODAL', 
      new_position = 'NODAL', 
      position = 'node',
      field = 'U', 
      sub_set_type = 'element', 
      delete_report = True),
    gvfo(odb = odb, 
      instance = 'I_SAMPLE', 
      step = 2,
      frame = -1,
      original_position = 'NODAL', 
      new_position = 'NODAL', 
      position = 'node',
      field = 'U', 
      sub_set_type = 'element', 
      delete_report = True)]
      
  fo['S'] = [
    gtfo(odb = odb, 
      instance = 'I_SAMPLE', 
      step = 1,
      frame = -1,
      original_position = 'INTEGRATION_POINT', 
      new_position = 'NODAL', 
      position = 'node',
      field = 'S', 
      sub_set_type = 'element', 
      delete_report = True),
    gtfo(odb = odb, 
      instance = 'I_SAMPLE', 
      step = 2,
      frame = -1,
      original_position = 'INTEGRATION_POINT', 
      new_position = 'NODAL', 
      position = 'node',
      field = 'S', 
      sub_set_type = 'element', 
      delete_report = True)]
   
  fo['LE'] = [
    gtfo(odb = odb, 
      instance = 'I_SAMPLE', 
      step = 1,
      frame = -1,
      original_position = 'INTEGRATION_POINT', 
      new_position = 'NODAL', 
      position = 'node',
      field = 'LE', 
      sub_set_type = 'element', 
      delete_report = True),
    gtfo(odb = odb, 
      instance = 'I_SAMPLE', 
      step = 2,
      frame = -1,
      original_position = 'INTEGRATION_POINT', 
      new_position = 'NODAL', 
      position = 'node',
      field = 'LE', 
      sub_set_type = 'element', 
      delete_report = True)] 
      
  fo['EE'] = [
    gtfo(odb = odb, 
      instance = 'I_SAMPLE', 
      step = 1,
      frame = -1,
      original_position = 'INTEGRATION_POINT', 
      new_position = 'NODAL', 
      position = 'node',
      field = 'EE', 
      sub_set_type = 'element', 
      delete_report = True),
    gtfo(odb = odb, 
      instance = 'I_SAMPLE', 
      step = 2,
      frame = -1,
      original_position = 'INTEGRATION_POINT', 
      new_position = 'NODAL', 
      position = 'node',
      field = 'EE', 
      sub_set_type = 'element', 
      delete_report = True)]     
  
  fo['PE'] = [
    gtfo(odb = odb, 
      instance = 'I_SAMPLE', 
      step = 1,
      frame = -1,
      original_position = 'INTEGRATION_POINT', 
      new_position = 'NODAL', 
      position = 'node',
      field = 'PE', 
      sub_set_type = 'element', 
      delete_report = True),
    gtfo(odb = odb, 
      instance = 'I_SAMPLE', 
      step = 2,
      frame = -1,
      original_position = 'INTEGRATION_POINT', 
      new_position = 'NODAL', 
      position = 'node',
      field = 'PE', 
      sub_set_type = 'element', 
      delete_report = True)] 
  
  fo['PEEQ'] = [
    gfo(odb = odb, 
      instance = 'I_SAMPLE', 
      step = 1,
      frame = -1,
      original_position = 'INTEGRATION_POINT', 
      new_position = 'NODAL', 
      position = 'node',
      field = 'PEEQ', 
      sub_set_type = 'element', 
      delete_report = True),
    gfo(odb = odb, 
      instance = 'I_SAMPLE', 
      step = 2,
      frame = -1,
      original_position = 'INTEGRATION_POINT', 
      new_position = 'NODAL', 
      position = 'node',
      field = 'PEEQ', 
      sub_set_type = 'element', 
      delete_report = True)] 
  # History Outputs
  data['history'] = {} 
  ho = data['history']
  ref_node = odb.rootAssembly.instances['I_INDENTER'].nodeSets['REF_NODE'].nodes[0].label
  ho['force'] =  gho(odb,'RF2')['Node I_INDENTER.'+str(ref_node)] # GetFieldOutputByKey returns all the occurences of the required output (here 'RF2') and stores it in a dict. Each dict key refers to a location. Here we have to specify the location ('Node I_INDENTER.1') mainly for displacement which has been requested at several locations.
  ho['disp'] =   gho(odb,'U2')['Node I_INDENTER.'+str(ref_node)]
  tip_node = odb.rootAssembly.instances['I_INDENTER'].nodeSets['TIP_NODE'].nodes[0].label
  ho['tip_penetration'] =   gho(odb,'U2')['Node I_INDENTER.'+str(tip_node)]
  ho['allse'] =   gho(odb,'ALLSE').values()[0]
  ho['allpd'] =   gho(odb,'ALLPD').values()[0]
  ho['allfd'] =   gho(odb,'ALLFD').values()[0]
  ho['allwk'] =   gho(odb,'ALLWK').values()[0]
  #ho['carea'] =  gho(odb,'CAREA    ASSEMBLY_I_SAMPLE_SURFACE_FACES/ASSEMBLY_I_INDENTER_SURFACE_FACES').values()[0]
  
  # CONTACT DATA PROCESSING
  ho['contact'] = Get_ContactData(odb = odb, instance = 'I_SAMPLE', node_set = 'TOP_NODES')
 
else:
  data['completed'] = False
# Closing and dumping
odb.close()
dump(data, file_name+'.pckl')"""
    else:
      out = """# ABQPOSTPROC.PY
# Warning: executable only in abaqus abaqus viewer -noGUI,... not regular python.
import sys
from abapy.postproc import GetFieldOutput_byRpt as gfo
from abapy.postproc import GetVectorFieldOutput_byRpt as gvfo
from abapy.postproc import GetTensorFieldOutput_byRpt as gtfo
from abapy.postproc import GetHistoryOutputByKey as gho
from abapy.indentation import Get_ContactData
from abapy.misc import dump
from odbAccess import openOdb
from abaqusConstants import JOB_STATUS_COMPLETED_SUCCESSFULLY



# Odb opening  
file_name = '#FILE_NAME'
odb = openOdb(file_name + '.odb')
data = {}

# Check job status:
job_status = odb.diagnosticData.jobStatus

if job_status == JOB_STATUS_COMPLETED_SUCCESSFULLY:
  data['completed'] = True 
  # Field Outputs
  data['field'] = {}
  fo = data['field']
  fo['Uind'] = [
    gvfo(odb = odb, 
      instance = 'I_INDENTER', 
      step = 1,
      frame = -1,
      original_position = 'NODAL', 
      new_position = 'NODAL', 
      position = 'node',
      field = 'U', 
      delete_report = True),
    gvfo(odb = odb, 
      instance = 'I_INDENTER', 
      step = 2,
      frame = -1,
      original_position = 'NODAL', 
      new_position = 'NODAL', 
      position = 'node',
      field = 'U', 
      delete_report = True)]
  
  fo['U'] = [
    gvfo(odb = odb, 
      instance = 'I_SAMPLE', 
      step = 1,
      frame = -1,
      original_position = 'NODAL', 
      new_position = 'NODAL', 
      position = 'node',
      field = 'U', 
      sub_set_type = 'element', 
      delete_report = True),
    gvfo(odb = odb, 
      instance = 'I_SAMPLE', 
      step = 2,
      frame = -1,
      original_position = 'NODAL', 
      new_position = 'NODAL', 
      position = 'node',
      field = 'U', 
      sub_set_type = 'element', 
      delete_report = True)]
      
  fo['S'] = [
    gtfo(odb = odb, 
      instance = 'I_SAMPLE', 
      step = 1,
      frame = -1,
      original_position = 'INTEGRATION_POINT', 
      new_position = 'NODAL', 
      position = 'node',
      field = 'S', 
      sub_set_type = 'element', 
      delete_report = True),
    gtfo(odb = odb, 
      instance = 'I_SAMPLE', 
      step = 2,
      frame = -1,
      original_position = 'INTEGRATION_POINT', 
      new_position = 'NODAL', 
      position = 'node',
      field = 'S', 
      delete_report = True)]
   
  fo['LE'] = [
    gtfo(odb = odb, 
      instance = 'I_SAMPLE', 
      step = 1,
      frame = -1,
      original_position = 'INTEGRATION_POINT', 
      new_position = 'NODAL', 
      position = 'node',
      field = 'LE', 
      sub_set_type = 'element', 
      delete_report = True),
    gtfo(odb = odb, 
      instance = 'I_SAMPLE', 
      step = 2,
      frame = -1,
      original_position = 'INTEGRATION_POINT', 
      new_position = 'NODAL', 
      position = 'node',
      field = 'LE', 
      sub_set_type = 'element', 
      delete_report = True)] 
      
  fo['EE'] = [
    gtfo(odb = odb, 
      instance = 'I_SAMPLE', 
      step = 1,
      frame = -1,
      original_position = 'INTEGRATION_POINT', 
      new_position = 'NODAL', 
      position = 'node',
      field = 'EE', 
      sub_set_type = 'element', 
      delete_report = True),
    gtfo(odb = odb, 
      instance = 'I_SAMPLE', 
      step = 2,
      frame = -1,
      original_position = 'INTEGRATION_POINT', 
      new_position = 'NODAL', 
      position = 'node',
      field = 'EE', 
      sub_set_type = 'element', 
      delete_report = True)]     
  
  fo['PE'] = [
    gtfo(odb = odb, 
      instance = 'I_SAMPLE', 
      step = 1,
      frame = -1,
      original_position = 'INTEGRATION_POINT', 
      new_position = 'NODAL', 
      position = 'node',
      field = 'PE', 
      sub_set_type = 'element', 
      delete_report = True),
    gtfo(odb = odb, 
      instance = 'I_SAMPLE', 
      step = 2,
      frame = -1,
      original_position = 'INTEGRATION_POINT', 
      new_position = 'NODAL', 
      position = 'node',
      field = 'PE', 
      sub_set_type = 'element', 
      delete_report = True)] 
  
  fo['PEEQ'] = [
    gfo(odb = odb, 
      instance = 'I_SAMPLE', 
      step = 1,
      frame = -1,
      original_position = 'INTEGRATION_POINT', 
      new_position = 'NODAL', 
      position = 'node',
      field = 'PEEQ', 
      sub_set_type = 'element', 
      delete_report = True),
    gfo(odb = odb, 
      instance = 'I_SAMPLE', 
      step = 2,
      frame = -1,
      original_position = 'INTEGRATION_POINT', 
      new_position = 'NODAL', 
      position = 'node',
      field = 'PEEQ', 
      sub_set_type = 'element', 
      delete_report = True)] 
  # History Outputs
  data['history'] = {} 
  ho = data['history']
  ref_node = odb.rootAssembly.instances['I_INDENTER'].nodeSets['REF_NODE'].nodes[0].label
  ho['force'] =  gho(odb,'RF2')['Node I_INDENTER.'+str(ref_node)] # GetFieldOutputByKey returns all the occurences of the required output (here 'RF2') and stores it in a dict. Each dict key refers to a location. Here we have to specify the location ('Node I_INDENTER.1') mainly for displacement which has been requested at several locations.
  ho['disp'] =   gho(odb,'U2')['Node I_INDENTER.'+str(ref_node)]
  tip_node = odb.rootAssembly.instances['I_INDENTER'].nodeSets['TIP_NODE'].nodes[0].label
  ho['tip_penetration'] =   gho(odb,'U2')['Node I_INDENTER.'+str(tip_node)]
  ho['allse'] =   gho(odb,'ALLSE').values()[0]
  ho['allpd'] =   gho(odb,'ALLPD').values()[0]
  ho['allfd'] =   gho(odb,'ALLFD').values()[0]
  ho['allwk'] =   gho(odb,'ALLWK').values()[0]
  #ho['carea'] =  gho(odb,'CAREA    ASSEMBLY_I_SAMPLE_SURFACE_FACES/ASSEMBLY_I_INDENTER_SURFACE_FACES').values()[0]
  
  # CONTACT DATA PROCESSING
  ho['contact'] = Get_ContactData(odb = odb, instance = 'I_SAMPLE', node_set = 'TOP_NODES')
 
else:
  data['completed'] = False
# Closing and dumping
odb.close()
dump(data, file_name+'.pckl')"""
    return out
  # Scalar Outputs
  # Load Prefactor
  load_prefactor = Column(Float)
  def Load_prefactor(self, update = False):
    '''
    Defined during loading phase by force = c * penetration **2 where c is the load prefactor.
    '''
    load_prefactor = (self.force_hist[1] / self.disp_hist[1]**2).average(method = 'simps')
    if update: 
      self.load_prefactor = load_prefactor
    else: 
      return load_prefactor
 
  # Irreversible work ratio:
  irreversible_work_ratio = Column(Float)
  def Irreversible_work_ratio(self, update = False):
    '''
    Irreversible work divided by the total work
    '''
    unload = self.total_work_hist[2]
    irreversible_work_ratio = 3* unload.data_min() / self.load_prefactor
    if update: 
      self.irreversible_work_ratio = irreversible_work_ratio
    else: 
      return irreversible_work_ratio
  
  # Plastic work ratio:
  plastic_work_ratio = Column(Float)
  def Plastic_work_ratio(self, update = False):
    '''
    Plastic work divided by the total work
    '''
    plastic_work_ratio = (self.plastic_work_hist[1] / self.total_work_hist[1]).average()
    if update: 
      self.plastic_work_ratio = plastic_work_ratio
    else: 
      return plastic_work_ratio
  
  # Unloading fit
  contact_stiffness = Column(Float)
  final_displacement = Column(Float)
  unload_exponent = Column(Float)
  def Unloading_fit(self):
    '''
    Computes the contact stiffness and the final displacement using a power fit of the unloading curve between 0% and 100% of the max force. The final penetration is divided by the maximum penetration and the contact stiffness is multiplied by the ratio of the max displacement by the max force.
    '''
    import numpy as np
    from scipy.optimize import leastsq
    unload = 2
    disp = np.array(self.disp_hist[unload].data[0])
    force = np.array(self.force_hist[unload].data[0])
    max_force = force.max()
    max_disp = disp.max()
    loc = np.where(force >= max_force * .1)
    disp = disp[loc] /max_disp
    force = force[loc] / max_force
    func = lambda k, x: ( (x - k[0]) / (1. - k[0] ) )**k[1] 
    err = lambda v, x, y: (func(v,x)-y)
    k0 = [0., 1.]
    k, success = leastsq(err, k0, args=(disp,force), maxfev=10000)
    self.final_displacement = k[0] / max_disp
    self.contact_stiffness = k[1] / (1. - k[0]) 
    self.unload_exponent = k[1] 
       
  # Contact area:
  contact_area = Column(Float)
  def Contact_area(self, update = False):
    '''
    Cross contact areat under load divided by the square of the indenter displacement.
    '''
    import numpy as np
    from abapy.postproc import HistoryOutput
    contact_step = self.contact_data[1] # we only look at the loading 1 here
    ca= np.array([contact_step[i].contact_area() for i in xrange(len(contact_step))])
    disp = np.array(self.disp_hist[1].data)
    ca = ca / (disp**2)
    contact_area = ca.mean()
    if update: 
      self.contact_area = contact_area
    else: 
      return contact_area
  
  
  # Tip penetration    
  tip_penetration = Column(PickleType)
  def Tip_penetration(self, update = True):
    '''
    Tip penetration under load divided by the displacement.
    '''
    tip_pen = self.tip_penetration_hist[1]
    disp = self.disp_hist[1]
    tip_pen = (-tip_pen/disp).average()
    if update: 
      self.tip_penetration = tip_pen
    else: 
      return tip_penetration
  
  
  
 
  def __repr__(self):
    return '<Simulation: id={0}>'.format(self.id)
  
  def difficulty(self):
    if self.sample_mat_type == 'elastic': mat_diff = 1.
    if self.sample_mat_type == 'vonmises': 
      args = self.sample_mat_args
      mat_diff = args['young_modulus'] / args['yield_stress']
    if self.sample_mat_type == 'druckerprager': 
      args = self.sample_mat_args
      mat_diff = args['young_modulus'] / args['yield_stress']
    if self.sample_mat_type == 'hollomon': 
      args = self.sample_mat_args
      mat_diff = args['young_modulus'] / args['yield_stress']
    mesh_diff = self.max_disp /self.mesh_l * (self.mesh_Na + self.mesh_Nb) / 2.
    return mat_diff * mesh_diff
  
  def preprocess(self):
    from abapy.indentation import IndentationMesh, Step, DeformableCone2D, DeformableCone3D
    from abapy.materials import VonMises, Elastic, DruckerPrager, Hollomon
    from math import tan, radians
    mesh_l = 2 * max( self.max_disp , tan(radians(self.indenter_half_angle)) ) # Adjusting mesh size to max_disp
    if self.three_dimensional:
      self.mesh = IndentationMesh(
        Na = self.mesh_Na, 
        Nb = self.mesh_Nb, 
        Ns = self.mesh_Ns, 
        Nf = self.mesh_Nf, 
        l = mesh_l).sweep(
        sweep_angle = self.sweep_angle,
        N = self.mesh_Nsweep)
      if self.sample_mesh_disp != False:
        field = self.mesh.nodes.eval_vectorFunction(self.sample_mesh_disp)
        self.mesh.nodes.apply_displacement(field)
      if self.indenter_mesh_Nf == 0: Nf_i = self.mesh_Nf 
      self.indenter = DeformableCone3D(
        half_angle = self.indenter_half_angle, 
        sweep_angle = self.sweep_angle,
        pyramid = self.indenter_pyramid,
        l = mesh_l, 
        Na = self.mesh_Na * (self.indenter_mesh_Na == 0) + self.indenter_mesh_Na * (self.indenter_mesh_Na != 0), 
        Nb = self.mesh_Nb * (self.indenter_mesh_Nb == 0) + self.indenter_mesh_Nb * (self.indenter_mesh_Nb != 0), 
        Ns = self.mesh_Ns * (self.indenter_mesh_Ns == 0) + self.indenter_mesh_Ns * (self.indenter_mesh_Ns != 0), 
        Nf = self.mesh_Nf * (self.indenter_mesh_Nf == 0) + self.indenter_mesh_Nf * (self.indenter_mesh_Nf != 0), 
        N =  self.mesh_Nsweep * (self.indenter_mesh_Nsweep == 0) + self.indenter_mesh_Nsweep * (self.indenter_mesh_Nsweep != 0),
        rigid = self.rigid_indenter)
      
    else:
      self.mesh = IndentationMesh(
        Na = self.mesh_Na, 
        Nb = self.mesh_Nb, 
        Ns = self.mesh_Ns, 
        Nf = self.mesh_Nf, 
        l = mesh_l)
      self.indenter = DeformableCone2D(
        half_angle = self.indenter_half_angle, 
        l = mesh_l, 
        Na = self.mesh_Na * (self.indenter_mesh_Na == 0) + self.indenter_mesh_Na * (self.indenter_mesh_Na != 0), 
        Nb = self.mesh_Nb * (self.indenter_mesh_Nb == 0) + self.indenter_mesh_Nb * (self.indenter_mesh_Nb != 0), 
        Ns = self.mesh_Ns * (self.indenter_mesh_Ns == 0) + self.indenter_mesh_Ns * (self.indenter_mesh_Ns != 0), 
        Nf = self.mesh_Nf * (self.indenter_mesh_Nf == 0) + self.indenter_mesh_Nf * (self.indenter_mesh_Nf != 0), 
        rigid = self.rigid_indenter)
    self.steps = [                                              
      Step(name='loading0', 
        nframes = self.frames, 
        disp = self.max_disp/2., 
        boundaries_3D= self.three_dimensional),
      Step(name='loading1', 
        nframes = self.frames, 
        disp = self.max_disp,
        boundaries_3D= self.three_dimensional), 
      Step(name = 'unloading', 
        nframes = self.frames, 
        disp = 0.,
        boundaries_3D= self.three_dimensional)] 
    if self.sample_mat_type == 'hollomon':
      self.sample_mat = Hollomon(
        labels = 'SAMPLE_MAT', 
        E =  self.sample_mat_args['young_modulus'], 
        nu = self.sample_mat_args['poisson_ratio'], 
        sy = self.sample_mat_args['yield_stress'],
        n = self.sample_mat_args['hardening'])
    if self.sample_mat_type == 'druckerprager':
      self.sample_mat = DruckerPrager(
        labels = 'SAMPLE_MAT', 
        E =  self.sample_mat_args['young_modulus'], 
        nu = self.sample_mat_args['poisson_ratio'], 
        sy = self.sample_mat_args['yield_stress'],
        beta = self.sample_mat_args['beta'],
        psi = self.sample_mat_args['psi'],
        k = self.sample_mat_args['k'])   
    if self.sample_mat_type == 'vonmises':
      self.sample_mat = VonMises(
        labels = 'SAMPLE_MAT', 
        E =  self.sample_mat_args['young_modulus'], 
        nu = self.sample_mat_args['poisson_ratio'], 
        sy = self.sample_mat_args['yield_stress'])   
    if self.sample_mat_type == 'elastic':
      self.sample_mat = Elastic(
        labels = 'SAMPLE_MAT', 
        E = self.sample_mat_args['young_modulus'], 
        nu = self.sample_mat_args['poisson_ratio'])  
    if self.indenter_mat_type == 'elastic':
      self.indenter_mat = Elastic(
        labels = 'INDENTER_MAT', 
        E = self.indenter_mat_args['young_modulus'], 
        nu = self.indenter_mat_args['poisson_ratio'])  
    
  
  
  def run(self, work_dir = 'workdir/', abqlauncher = '/opt/Abaqus/6.9/Commands/abaqus'):
    print '# Running {0}: id={1}, frames = {2}'.format(self.__class__.__name__, self.id, self.frames)
    self.preprocess()
    from abapy.indentation import Manager
    import numpy as np
    from copy import copy
    simname = self.__class__.__name__ + '_{0}'.format(self.id)
    # Creating abq postproc script
    f = open('{0}{1}_abqpostproc.py'.format(work_dir,self.__class__.__name__),'w')
    name = self.__class__.__name__ + '_' + str(self.id)
    out = self.abqpostproc_byRpt().replace('#FILE_NAME', name)
    f.write(out)
    f.close()
    abqpostproc = '{0}_abqpostproc.py'.format(self.__class__.__name__)
    #---------------------------------------
    # Setting simulation manager
    m = Manager()
    m.set_abqlauncher('/opt/Abaqus/6.9/Commands/abaqus')
    m.set_workdir(work_dir)
    m.set_simname(self.__class__.__name__ + '_{0}'.format(self.id))
    m.set_abqpostproc(abqpostproc)
    m.set_samplemesh(self.mesh)
    m.set_samplemat(self.sample_mat)
    m.set_indentermat(self.indenter_mat)
    m.set_friction(self.friction)
    m.set_steps(self.steps)
    m.set_indenter(self.indenter)
    m.set_is_3D(self.three_dimensional)
    m.set_pypostprocfunc(lambda data: data) # Here we just want to get back data
    #---------------------------------------
    # Running simulation and post processing
    m.erase_files()           # Workdir cleaning
    m.make_inp()              # INP creation
    m.run_sim()               # Running the simulation
    m.run_abqpostproc()       # First round of post processing in Abaqus
    data = m.run_pypostproc() # Second round of custom post processing in regular Python
    #m.erase_files()          # Workdir cleaning
    #---------------------------------------
    if data['completed']:
      print '# Simulation completed.'
      # Storing raw data
      self.completed = True
      sweep_factor = 1. # This factor aims to modify values that are affected by the fact that only a portion of the problem is solved due to symmetries.
      if self.three_dimensional: sweep_factor = 360. / self.sweep_angle
      self.force_hist = - sweep_factor * data['history']['force'] 
      self.disp_hist = -data['history']['disp'] 
      self.elastic_work_hist = sweep_factor * data['history']['allse'] 
      self.plastic_work_hist = sweep_factor * data['history']['allpd'] 
      self.friction_work_hist = sweep_factor * data['history']['allfd'] 
      self.total_work_hist = sweep_factor * data['history']['allwk'] 
      self.tip_penetration_hist = data['history']['tip_penetration'] 
      self.disp_field = data['field']['U']
      self.ind_disp_field = data['field']['Uind']
      self.stress_field = data['field']['S']
      self.total_strain_field = data['field']['LE']
      self.elastic_strain_field = data['field']['EE']
      self.plastic_strain_field = data['field']['PE']
      self.equivalent_plastic_strain_field = data['field']['PEEQ']
      self.contact_data = data['history']['contact']
      # Updating data
      self.Load_prefactor(update = True)
      self.Irreversible_work_ratio(update = True)
      self.Plastic_work_ratio(update = True)
      self.Tip_penetration(update = True)
      self.Contact_area(update = True)
      self.Unloading_fit()
    #---------------------------------------
    else:
      print '# Simulation not completed.'
#----------------------------------------------------------------------------------------------------------------      



#----------------------------------------------------------------------------------------------------------------    
# DATABASE MANAGEMENT CLASS
# 
class Database_Manager:
  def __init__(self, database_dir, database_name, cls , work_dir, abqlauncher):
    db = 'sqlite:///{0}{1}.db'.format(database_dir, database_name)
    engine = create_engine(db,echo=False)
    Base.metadata.create_all(engine) 
    Session = sessionmaker(bind=engine)
    self.session = Session()
    self.cls = cls
    self.work_dir = work_dir
    self.abqlauncher = abqlauncher
    
  def add_simulation(self, simulation):
    '''
    Adds a simulation to the database.
    
    Args:
    * simulation: Simulation class instance
    '''
    if isinstance(simulation, self.cls) == False: raise Exception, 'simulation must be Simulation instance'
    try:
      self.session.add(simulation)
      self.session.commit()
    except: 
      print 'simulation already exists or has not been declared corectly, nothing changed' 
      self.session.rollback()
      
  def get_next(self):
    '''
    Returns the next simulation to do regarding to difficulty criterias defined under.
    '''
    simus = self.session.query(self.cls).filter(self.cls.completed == False)
    if simus.all() != []:
      # finding max priority
      max_priority = self.session.query(self.cls).filter(self.cls.completed == False).order_by(desc(self.cls.priority)).first().priority
      # finding less difficult simulation with max priority
      simus = simus.filter(self.cls.priority == max_priority)
      simus = sorted(simus, key=lambda simu: simu.difficulty())
      simu = simus[0]
      # Adjusting number of requested frames
      diff = simu.difficulty()
      completed_simus = self.session.query(self.cls).filter(self.cls.completed == True)
      for csim in completed_simus:
        if csim.difficulty() <= diff:
          if csim.frames > simu.frames: simu.frames = csim.frames
      completed_simus = [c_simu for c_simu in completed_simus if c_simu.difficulty <= diff]
      self.session.commit()
    else:
      simu = None
    return simu
    
  def run_next(self):
    '''
    Runs the next simulation.
    '''
    simu = self.get_next()
    if simu != None:
      while True:
        simu.run(work_dir = self.work_dir, abqlauncher = self.abqlauncher)  
        if simu.completed: break
        simu.frames = int(simu.frames * 1.5)
        self.session.commit()
        print '# Number of frames changed to {0}.'.format(simu.frames)
      self.session.commit()
    else:
      print '# No more simulations to run'
  
  def run_all(self):
    '''
    Runs all the simulation in the right order until they all have been completed.
    '''
    while True:
      left_sims = self.session.query(self.cls).filter(self.cls.completed == False).count()
      if left_sims == 0: 
        print '# All simulations have been run.'
        break
      print '# {0} simulations left to run.'.format(left_sims)
      self.run_next()
  
  def query(self):
    '''
    Shortcut for database queries.
    '''
    return self.session.query(self.cls)
 #----------------------------------------------------------------------------------------------------------------

Then we need to define some basic settings here settings.py:

from classes import Simulation, Database_Manager

#----------------------------------------------------------------------------------------------------------------
# SETTINGS
work_dir      = 'workdir/'
plot_dir      = 'plots/'
database_dir  = 'database/'
database_name = 'database'
abqlauncher   = '/opt/Abaqus/6.9/Commands/abaqus'
cls           = Simulation
#----------------------------------------------------------------------------------------------------------------

#----------------------------------------------------------------------------------------------------------------
# Starting Database Manager
db_manager =  Database_Manager(
  work_dir = work_dir,
  database_dir = database_dir,
  database_name = database_name,
  abqlauncher = abqlauncher,
  cls = cls)
#----------------------------------------------------------------------------------------------------------------

Then we can load simulations request in the SQLite database settings.py:

# LOADER: loads simulations to do in the database
import numpy as np
from copy import copy
from abapy.indentation import equivalent_half_angle

# Setting up the database
execfile('settings.py')

# creating some shortcuts
d = db_manager     # database manager
c = db_manager.cls # useful to call Simulation attributs 


#--------------------------
# FIXED PARAMETERS
#--------------------------

# Fixed Parameters  
Na_berk, Nb_berk     = 8, 8  # Mesh parameters
Ns_berk, Nf_berk     = 16, 2 # Mesh parameters
Na_cone, Nb_cone     = 16, 16  # Mesh parameters
Ns_cone, Nf_cone     = 16, 2 # Mesh parameters
Nsweep, sweep_angle = 8, 60. # Mesh sweep parameters
E_s        = 1.   # Sample's Young's modulus
nu         = 0.2   # Poisson's ratio
half_angle = 65.27  # Indenter half angle of the modified Berkovich
frames     = 50    # Number frames per step


#--------------------------
# DRUCKER PRAGER SIMULATIONS
#--------------------------

ey  = [0.01, 0.015,0.02, 0.025,0.03, 0.035,0.04, 0.045, 0.05] # Yield strain
beta = [0., 5., 10., 15., 20., 25., 30.]

print 'LOADING DRUCKER PRAGER SIMULATIONS'

for i in xrange(len(ey)):
  print '* epsilon_y = ', ey[i]
  for j in xrange(len(beta)):
    print 'beta= ', beta[j]
    print '* Conical indenter'
    simu = Simulation( 
      rigid_indenter= True, 
      indenter_pyramid = True,
      three_dimensional = False,
      sweep_angle = sweep_angle,
      sample_mat_type = 'druckerprager',
      sample_mat_args = {'young_modulus': 1., 'poisson_ratio': 0.3, 'yield_stress': ey[i] * E_s, 'beta': beta[j], 'psi':beta[j], 'k': 1. },
      indenter_mat_type = 'elastic',
      indenter_mat_args = {'young_modulus': 1., 'poisson_ratio': 0.3},
      mesh_Na = Na_cone, 
      mesh_Nb = Nb_cone, 
      mesh_Ns = Ns_cone,
      mesh_Nf = Nf_cone, 
      indenter_mesh_Na = 2, 
      indenter_mesh_Nb = 2, 
      indenter_mesh_Ns = 1,
      indenter_mesh_Nf = 1, 
      indenter_mesh_Nsweep = 2,
      mesh_Nsweep = Nsweep,
      indenter_half_angle = equivalent_half_angle(half_angle, sweep_angle),
      frames = frames )
    db_manager.add_simulation(simu)
    
    '''
    print '* Berkovich indenter'
    simu = Simulation( 
      rigid_indenter= True, 
      indenter_pyramid = True,
      three_dimensional = True,
      sweep_angle = sweep_angle,
      sample_mat_type = 'druckerprager',
      sample_mat_args = {'young_modulus': 1., 'poisson_ratio': 0.3, 'yield_stress': ey[i] * E_s, 'beta': beta[j], 'psi':beta[j], 'k': 1. },
      indenter_mat_type = 'elastic',
      indenter_mat_args = {'young_modulus': 1., 'poisson_ratio': 0.3},
      mesh_Na = Na_berk, 
      mesh_Nb = Nb_berk, 
      mesh_Ns = Ns_berk,
      mesh_Nf = Nf_berk, 
      mesh_Nsweep = Nsweep,
      indenter_mesh_Na = 2, 
      indenter_mesh_Nb = 2, 
      indenter_mesh_Ns = 1,
      indenter_mesh_Nf = 2, 
      indenter_mesh_Nsweep = 2,
      indenter_half_angle = half_angle,
      sample_mesh_disp = False,
      frames = frames )
    db_manager.add_simulation(simu)
    '''
  
#--------------------------
# HOLLOMON SIMULATIONS
#--------------------------
#ey  = [0.001, 0.002, 0.003, 0.004, 0.005, 0.006, 0.007, 0.008, 0.009, 0.01] # Yield strain
ey = [0.001]
#n = [0., .1, .2, .3, .4]
n = [.3, .4]

print 'LOADING HOLLOMON SIMULATIONS'

for i in xrange(len(ey)):
  print '* epsilon_y = ', ey[i]
  for j in xrange(len(n)):
    print '* n = ', n[j]  
    print '* Conical indenter'
    simu = Simulation( 
      rigid_indenter= True, 
      indenter_pyramid = True,
      three_dimensional = False,
      sweep_angle = sweep_angle,
      sample_mat_type = 'hollomon',
      sample_mat_args = {'young_modulus': 1., 'poisson_ratio': 0.3, 'yield_stress': ey[i] * E_s, 'hardening': n[j]},
      indenter_mat_type = 'elastic',
      indenter_mat_args = {'young_modulus': 1., 'poisson_ratio': 0.3},
      mesh_Na = Na_cone, 
      mesh_Nb = Nb_cone, 
      mesh_Ns = Ns_cone,
      mesh_Nf = Nf_cone, 
      indenter_mesh_Na = 2, 
      indenter_mesh_Nb = 2, 
      indenter_mesh_Ns = 1,
      indenter_mesh_Nf = 2, 
      indenter_mesh_Nsweep = 2,
      mesh_Nsweep = Nsweep,
      indenter_half_angle = equivalent_half_angle(half_angle, sweep_angle),
      frames = frames )
    db_manager.add_simulation(simu)
  
  '''
    print '* Berkovich indenter'
    simu = Simulation( 
      rigid_indenter= True, 
      indenter_pyramid = True,
      three_dimensional = True,
      sweep_angle = sweep_angle,
      sample_mat_type = 'hollomon',
      sample_mat_args = {'young_modulus': 1., 'poisson_ratio': 0.3, 'yield_stress': ey[i] * E_s, 'hardening': n[j]},
      indenter_mat_type = 'elastic',
      indenter_mat_args = {'young_modulus': 1., 'poisson_ratio': 0.3},
      mesh_Na = Na_berk, 
      mesh_Nb = Nb_berk, 
      mesh_Ns = Ns_berk,
      mesh_Nf = Nf_berk, 
      mesh_Nsweep = Nsweep,
      indenter_mesh_Na = 2, 
      indenter_mesh_Nb = 2, 
      indenter_mesh_Ns = 1,
      indenter_mesh_Nf = 2, 
      indenter_mesh_Nsweep = 2,
      indenter_half_angle = half_angle,
      sample_mesh_disp = False,
      frames = frames )
    db_manager.add_simulation(simu)
   '''
   

After executing loader, we see that all simulation have been entered in the database:

>>> execfile('loader.py')

Then we just launch the simulations using launcher.py:

# Setting up the database
execfile('settings.py')

# Running all simulations
db_manager.run_all()
#db_manager.run_next()
>>> execfile('launcher.py')

And now after these fast simulations it’s time to collect some results or perform some reverse analysis. Here is a very brief example of ploting basic_plot_DP.py:

# Importing packages
from matplotlib import pyplot as plt
import numpy as np
from matplotlib import cm
from scipy.spatial import Delaunay

# Setting up the database
execfile('settings.py')


# creating some shortcuts
d = db_manager     # database manager
c = db_manager.cls # useful to call Simulation attributs 

# Load simulations
simus = d.query().filter(c.completed == True).filter(c.sample_mat_type == 'druckerprager').all()

#--------------------------
# PLOTING CONSTRAINT FACTOR
#--------------------------

# Getting primary data
sy = np.array([s.sample_mat_args['yield_stress'] for s in simus])
E = np.array([s.sample_mat_args['young_modulus'] for s in simus])
beta = np.array([s.sample_mat_args['beta'] for s in simus])
C = np.array([s.load_prefactor for s in simus])
Ac = np.array([s.contact_area for s in simus])
hmax = np.array([s.max_disp for s in simus])
phi = np.array([s.indenter_half_angle for s in simus])
wirr_wtot = np.array([s.irreversible_work_ratio for s in simus])

# Building secondary data
ey = sy/E
H = C/Ac
hch = Ac / (np.pi*np.tan(np.radians(phi))**2)

# Building Delaunay triangular connectivity
x = ey
y = beta
points = np.array([x,y]).transpose() 
conn = Delaunay(points).vertices

# For checking purpose, let's plot the generated mesh. You may see that the mesh is self improving has the simulations complete (this is quite nice).


# Ploting stuff
title = 'Playing with Drucker-Prager law'

X, xlabel = C, r'$C$'
#X, xlabel = ey, r'$\sigma_{yc}/E$'
#X, xlabel = wirr_wtot, r'$W_{irr}/W_{tot}$'
Y, ylabel = hch, '$\sqrt{A_c / A_{app}}$'
#Y, ylabel = C, '$C/E$'

Z, zlabel = beta, r'$\beta = %1.1f$'
Zlevels = list(set(Z))
Z2, z2label = ey, r'$\epsilon_y = %1.3f$'
Z2levels = list(set(Z2))

# For checking purpose, let's plot the generated mesh. You may see that the mesh is self improving has the simulations complete (this is quite nice).

fig = plt.figure(0)
plt.clf()
fig.add_subplot(121)
plt.triplot(x, y, conn)
plt.title('Delaunay Mesh')
plt.xlabel('x')
plt.ylabel('y')
fig.add_subplot(122)
plt.triplot(X, Y, conn)
plt.title('Deformed Delaunay Mesh')
plt.xlabel('X')
plt.ylabel('Y')
plt.savefig('plots/basic_plot_mesh_DP.png')

plt.figure(0)
plt.clf()
plt.title(title)
plt.grid()
plt.xlabel(xlabel)
plt.ylabel(ylabel)
#plt.triplot(X,Y,conn)
#plt.tricontourf(X,Y,conn,Z, Zlevels)
cont = plt.tricontour(X,Y,conn,Z, Zlevels, colors = 'blue')
plt.clabel(cont, fmt = zlabel, fontsize=9, inline=1)
cont = plt.tricontour(X,Y,conn,Z2, Z2levels, colors = 'red')
plt.clabel(cont, fmt = z2label, fontsize=9, inline=1)
plt.savefig('plots/basic_plot_DP.png')

'''
#--------------------------
# PLOTING SECTIONS
#--------------------------
plt.figure(0)
plt.clf()
plt.gca().set_aspect('equal')
rmax = 6.
x = np.linspace(0., rmax, 128)
y = np.zeros_like(x)
ey = np.array(list(set(ey)))
ey.sort()
for s in simus:
  cd = s.contact_data[2][-1]
  alt, press = cd.interpolate(x, y, method = 'linear')
  ey_s = s.sample_mat_args['yield_stress']
  loc = np.where(ey==ey_s)[0][0]
  alt += -loc 
  plt.plot(x, alt)
plt.show()
'''
_images/basic_plot_mesh_DP.png _images/basic_plot_DP.png