### 2.2.7. Evaluating Custom Failure Criteria

User-defined plots and the Python scripting interface allow you to implement custom postprocessing evaluations. The following example shows how a custom core failure criterion is evaluated.

This script should be executed within an ACP-Post analysis system. The ACP-Post should be linked to a solution. The script should be copied into a text editor and saved as a .py file, and then executed from ACP-Post using File > Run Script.

The script evaluates the following failure function for homogeneous and honeycomb core material types:

    # Background Information
    ########################
    # This script serves as an example on how to evaluate custom failure criteria.
    # The failure criteria evaluation is based on stresses or strains at integration point level.
    # The script shows how stresses at integration point level are accessed. It is worth noting that stress
    # and strain plots shown in the scene or the sampling point are elemental averages.

    # The script requires two inputs: the name of an element set as a data scope for the evaluation as
    # well as the name of the attached solution.

    # The script loops through all analysis plies of the model and checks whether there is core material.
    # For plies containing core material the s13 and s23 stresses are retrieved. The maximum stress per
    # element across its integration points is used to calculate the inverse reserve factor (IRF)
    ################################
    element_set_name = 'All_Elements'
    solution_name = 'Solution.1'

    # Start of Script
    # NO INPUT NECESSARY!
    #####################

    # Loading Python modules
    import numpy
    import os
    import logging

    # initialize logger
    log = logging.getLogger(__name__)

    # num_ip dictionary maps the element type to the number of integration points
    num_ip = {125: 1, 128: 3, 123: 1, 124: 4, 126: 4}

    # get active ACP model and update it
    model = db.active_model
    model.update()

    # Define Data Scopes
    ####################

    element_set = model.element_sets.get(element_set_name)

    if element_set is None: log.error("element set %s not found!" % element_set_name)
    elem_scope = [element_set]
    model.select_elements(selection='sel0', op='new', attached_to=element_set)
    labels = model.mesh_query(name='labels', position='centroid', selection='sel0')

    # create a dictionary that maps element labels to element indices
    label2index_map = {}
    for i, v in enumerate(labels):
       label2index_map[v] = i

    # results array initialization with -1. This means areas that do not contain core can be shown in grey in the plots
    irf = numpy.ones(len(labels)) * -1

    # Create shear stress plot
    ##########################
    solution = model.solutions[solution_name]
    if solution is None: log.error("solution %s not found!" % solution_name)

    # Within the script, the stress plots are only used to retrieve element labels of an analysis ply.
    # They can also be used to retrieve stress values at averaged at element level.
    s13_plot = solution.plots.create_stress_plot(
       name='s13_plywise',
       ply_wise=True,
       solution_set=-1,
       active=True,
       component='s13',
       show_ply_offsets=False,
       ply_offset_scale_factor=1.0,
       spot='bot',
       interlaminar_normal_stresses=False,
       show_on_solids=False,
       data_scope=[element_set])
    s13_plot.update()

    s23_plot = solution.plots.create_stress_plot(
       name='s23_plywise',
       ply_wise=True,
       solution_set=-1,
       active=True,
       component='s23',
       show_ply_offsets=False,
       ply_offset_scale_factor=1.0,
       spot='bot',
       interlaminar_normal_stresses=False,
       show_on_solids=False,
       data_scope=[element_set])
    s23_plot.update()

    # Loop thru all analysis plies
    ##############################

    # Loop thru Modeling Groups
    for mg_name in model.modeling_groups.keys():
       mg = model.modeling_groups[mg_name]
       # Loop thru Modeling Plies
       for mp_name in mg.plies:
           mp = mg.plies[mp_name]
           # Loop thru Production Plies
           for pp in mp.production_plies.values():
               # Loop thru Production Plies
               for ap in pp.analysis_plies.values():
                   material = ap.ply_material.material
                   is_core = False
                   # Check if the analysis ply material is a core material
                   if material.ply_type.find('core') > -1 or material.ply_type.find('honeycomb') > -1:
                       is_core = True

                       log.info("evaluate core failure for analysis ply %s of type %s" % (ap.id, material.ply_type))

                       # Get stresses and eval irf
                       ###########################

                       # Common analysis ply properties
                       ap_elem_labels = s13_plot.get_element_labels(visible=s13_plot.data_scope, selected=[ap])
                       ap_material = model.material_data.materials[ap.material.name]
                       ap_s13_stress_limit = ap_material['stress_limits'].get('Sxz')
                       ap_s23_stress_limit = ap_material['stress_limits'].get('Syz')

                       model.select_elements(selection='sel0', op='new', labels=[int(v) for v in ap_elem_labels])
                       etypes = model.mesh_query(name='etypes', selection='sel0', position='centroid')

                       # ip-wise stresses for bot, mid and top
                       for spot in ['bot', 'mid', 'top']:

                           s13 = solution.query(
                               definition='stresses',
                               position='integration_point',
                               component='s13',
                               selection='sel0',
                               entity=ap,
                               spot=spot)
                           s23 = solution.query(
                               definition='stresses',
                               position='integration_point',
                               component='s23',
                               selection='sel0',
                               entity=ap,
                               spot=spot)

                           ap_irf_absolute = numpy.absolute(s13 / ap_s13_stress_limit) + numpy.absolute(
                               s23 / ap_s23_stress_limit)

                           # need to check whether both element labels arrays are the same
                           if len(s13) != len(s23): log.error("s13 and s23 are of different shape!")

                           index = 0
                           for i, et in enumerate(etypes):
                               elem_irf_max = -1.
                               for n in range(0, num_ip[et]):
                                   elem_irf_max = max(elem_irf_max, ap_irf_absolute[index])
                                   index += 1

                               # insert results into the global irf results array
                               global_index = label2index_map[ap_elem_labels[i]]
                               irf[global_index] = max(irf[global_index], elem_irf_max)

    # Delete shear stress plots
    del (solution.plots[s13_plot.name])
    del (solution.plots[s23_plot.name])

    # Create user defined plot for IRFs
    ###################################

    plot_name = "Core Shear Failure"

    # User defined plot basic settings
    udp = solution.plots.create_user_defined_plot(name=plot_name)
    udp.user_script_enabled = False
    udp.user_script = ""
    udp.show_ply_offsets = False
    udp.ply_offset_scale_factor = 1.0
    udp.show_on_solids = False
    udp.data_scope = [element_set]
    # plot color settings
    udp.color_table.use_defaults = False
    udp.color_table.auto_lower_value = False
    udp.color_table.auto_upper_value = False
    udp.color_table.upper_value_as_threshold = True
    udp.color_table.grey_values_below = True
    udp.color_table.lower_value = 0.0
    udp.color_table.upper_value = 1.0
    # load irf data in plot
    udp.user_data = irf
    udp.update()

    # End of script
    log.info("End of script")

Release 18.2 - © ANSYS, Inc. All rights reserved.