Ejemplo n.º 1
0
    def Is_Convergence(self):
        '''
        # relative difference in a mean stress for the last 5 iterations must be < tolerance
        # i >= iterations_limit 
        '''
        global i, i_violated, difference_last, continue_iterations, check_tolerance, mass_goal_i
        if len(FI_mean) > 5:
            difference_last = []
            for last in range(1, 6):
                difference_last.append(
                    abs(FI_mean[i] - FI_mean[i - last]) / FI_mean[i])
            difference = max(difference_last)
            if check_tolerance is True:
                print(
                    "maximum relative difference in FI_mean for the last 5 iterations = {}"
                    .format(difference))
            if difference < tolerance:
                continue_iterations = False
            elif FI_mean[i] == FI_mean[i - 1] == FI_mean[i - 2]:
                continue_iterations = False
                print("FI_mean[i] == FI_mean[i-1] == FI_mean[i-2]")

        # start of the new iteration or finish of the iteration process
        if continue_iterations is False or i >= iterations_limit:
            # break
            return True
        else:
            # export the present mesh
            if save_iteration_results and np.mod(float(i - 1),
                                                 save_iteration_results) == 0:
                if "frd" in save_iteration_format:
                    beso_lib.export_frd(path_export + "/file" + str(), nodes,
                                        Elements, elm_states, number_of_states)
                if "inp" in save_iteration_format:
                    beso_lib.export_inp(path_export + "/file" + str(), nodes,
                                        Elements, elm_states, number_of_states)
        i += 1  # iteration number
        print("\n----------- new iteration number %d ----------" % i)

        # check for number of violated elements
        if sum(FI_violated[i -
                           1]) > sum(FI_violated[0]) + FI_violated_tolerance:
            mass_goal_i = mass[i - 1]  # use mass_new from previous iteration
            if i_violated == 0:
                i_violated = i
                check_tolerance = True
        elif mass[i -
                  1] <= mass_goal_ratio * mass_full:  # goal volume achieved
            if not i_violated:
                i_violated = i  # to start decaying
                check_tolerance = True
            try:
                mass_goal_i
            except NameError:
                msg = "ERROR: mass goal is lower than initial mass. Check mass_goal_ratio"
                beso_lib.write_to_log(file_name, msg + "\n")
        else:
            mass_goal_i = mass_goal_ratio * mass_full

        return False
Ejemplo n.º 2
0
def run1(file_name, sensitivity_number, weight_factor_node, M,
         weight_factor_distance, near_nodes, nodes, opt_domains):
    sensitivity_number_node = {
    }  # hypothetical sensitivity number of each node
    for nn in nodes:
        if nn in M:
            sensitivity_number_node[nn] = 0
            for en in M[nn]:
                sensitivity_number_node[
                    nn] += weight_factor_node[nn][en] * sensitivity_number[en]
    sensitivity_number_filtered = sensitivity_number.copy(
    )  # sensitivity number of each element after filtering
    for en in opt_domains:
        numerator = 0
        denominator = 0
        for nn in near_nodes[en]:
            try:
                numerator += weight_factor_distance[
                    (en, nn)] * sensitivity_number_node[nn]
                denominator += weight_factor_distance[(en, nn)]
            except KeyError:
                pass
        if denominator != 0:
            sensitivity_number_filtered[en] = numerator / denominator
        else:
            msg = "\nERROR: filter over nodes failed due to division by 0." \
                  "Some element CG has not a node in distance <= r_min.\n"
            print(msg)
            beso_lib.write_to_log(file_name, msg)
            filter_on_sensitivity = 0
            return sensitivity_number
    return sensitivity_number_filtered
Ejemplo n.º 3
0
def prepare3_tetra_grid(file_name, cg, r_min, opt_domains):
    weight_factor3 = {}
    near_points = {}
    near_elm = {}
    grid = 1.0 * r_min  # ranges of xyz cycles should be set according to preset coefficient

    # searching for near points of each element
    for en in opt_domains:  # domain to take elements for filtering
        x_elm, y_elm, z_elm = cg[en]

        # set starting point of the cell
        # grid is the length of tetrahedral edge, which is also cell x size
        x_en_cell = x_elm - x_elm % grid
        # v = grid * np.sqrt(3) / 2 is the high of triangle, which is the half of cell y size
        v = grid * 0.8660
        y_en_cell = y_elm - y_elm % (2 * v)
        # h = grid * np.sqrt(2 / 3.0)  is the high of tetrahedron, which is the half of cell z size
        h = grid * 0.8165
        z_en_cell = z_elm - z_elm % (2 * h)

        near_points[en] = []
        # comparing distance in cells around element en
        for x_cell in [x_en_cell - grid, x_en_cell, x_en_cell + grid]:
            for y_cell in [y_en_cell - 2 * v, y_en_cell, y_en_cell + 2 * v]:
                for z_cell in [
                        z_en_cell - 2 * h, z_en_cell, z_en_cell + 2 * h
                ]:
                    for [x, y, z] in [
                        [x_cell, y_cell, z_cell],
                        [x_cell + grid / 2.0, y_cell + v, z_cell],
                        [x_cell + grid / 2.0, y_cell + v / 3.0, z_cell + h],
                        [x_cell, y_cell + 4 / 3.0 * v, z_cell + h]
                    ]:  # grid point coordinates
                        distance = ((x_elm - x)**2 + (y_elm - y)**2 +
                                    (z_elm - z)**2)**0.5
                        if distance < r_min:
                            weight_factor3[(en, (x, y, z))] = r_min - distance
                            near_points[en].append((x, y, z))
                            try:
                                near_elm[(x, y, z)].append(en)
                            except KeyError:
                                near_elm[(x, y, z)] = [en]

    # summarize histogram of near elements
    hist_near_points = list(np.zeros(10))
    for en in near_points:
        if isinstance(near_points[en], int):
            le = 1
        else:
            le = len(near_points[en])
        if le >= len(hist_near_points):
            while len(hist_near_points) <= le:
                hist_near_points.append(0)
        hist_near_points[le] += 1
    msg = "\nfilter over points statistics:\n"
    msg += "histogram - number of near points (list index) vs. number of elements (value)\n"
    msg += str(hist_near_points) + "\n"
    beso_lib.write_to_log(file_name, msg)
    return weight_factor3, near_elm, near_points
Ejemplo n.º 4
0
    def write_log(self):
        # writing log file with settings
        msg = "\n"
        msg += "---------------------------------------------------\n"
        msg += ("file_name = %s\n" % file_name)
        msg += ("Start at    " + time.ctime() + "\n\n")
        for dn in domain_optimized:
            msg += ("elset_name              = %s\n" % dn)
            msg += ("domain_optimized        = %s\n" % domain_optimized[dn])
            msg += ("domain_density          = %s\n" % domain_density[dn])
            msg += ("domain_thickness        = %s\n" % domain_thickness[dn])
            msg += ("domain_FI               = %s\n" % domain_FI[dn])
            msg += ("domain_material         = %s\n" % domain_material[dn])
            msg += "\n"
        msg += ("mass_goal_ratio         = %s\n" % mass_goal_ratio)
        msg += ("filter_list             = %s\n" % filter_list)
        msg += ("r_min                   = %s\n" % r_min)
        msg += ("filter_on_sensitivity   = %s\n" % filter_on_sensitivity)
        msg += ("cpu_cores               = %s\n" % cpu_cores)
        msg += ("FI_violated_tolerance   = %s\n" % FI_violated_tolerance)
        msg += ("decay_coefficient       = %s\n" % decay_coefficient)
        msg += ("shells_as_composite     = %s\n" % shells_as_composite)
        msg += ("reference_points        = %s\n" % reference_points)
        msg += ("reference_value         = %s\n" % reference_value)
        msg += ("mass_addition_ratio     = %s\n" % mass_addition_ratio)
        msg += ("mass_removal_ratio      = %s\n" % mass_removal_ratio)
        msg += ("ratio_type              = %s\n" % ratio_type)
        msg += ("sensitivity_averaging   = %s\n" % sensitivity_averaging)
        msg += ("iterations_limit        = %s\n" % iterations_limit)
        msg += ("tolerance               = %s\n" % tolerance)
        msg += ("save_iteration_results  = %s\n" % save_iteration_results)
        msg += ("save_iteration_format   = %s\n" % save_iteration_format)
        msg += "\n"
        beso_lib.write_to_log(file_name, msg)

        # writing log table header
        msg = "\n"
        msg += "domain order: \n"
        dorder = 0
        for dn in domains_from_config:
            msg += str(dorder) + ") " + dn + "\n"
            dorder += 1
        msg += "\niteration              mass FI_violated_0)"
        for dno in range(len(domains_from_config) - 1):
            msg += (" " + str(dno + 1)).rjust(4, " ") + ")"
        if len(domains_from_config) > 1:
            msg += " all)"
        msg += "          FI_mean    _without_state0         FI_max 0)"
        for dno in range(len(domains_from_config) - 1):
            msg += str(dno + 1).rjust(17, " ") + ")"
        if len(domains_from_config) > 1:
            msg += "all".rjust(17, " ") + ")"
        msg += "\n"
        beso_lib.write_to_log(file_name, msg)
Ejemplo n.º 5
0
    def Update(self):
        '''
        # computing mean stress from maximums of each element in all steps in the optimization domain
        '''
        global i, FI_max, FI_mean, FI_mean_without_state0, FI_violated
        print("Update")

        FI_mean_sum = 0
        FI_mean_sum_without_state0 = 0
        mass_without_state0 = 0
        for dn in domain_optimized:
            if domain_optimized[dn] is True:
                for en in domain_shells[dn]:
                    mass_elm = domain_density[dn][elm_states[en]] * area_elm[
                        en] * domain_thickness[dn][elm_states[en]]
                    FI_mean_sum += FI_step_max[en] * mass_elm
                    if elm_states[en] != 0:
                        FI_mean_sum_without_state0 += FI_step_max[en] * mass_elm
                        mass_without_state0 += mass_elm
                for en in domain_volumes[dn]:
                    mass_elm = domain_density[dn][
                        elm_states[en]] * volume_elm[en]
                    FI_mean_sum += FI_step_max[en] * mass_elm
                    if elm_states[en] != 0:
                        FI_mean_sum_without_state0 += FI_step_max[en] * mass_elm
                        mass_without_state0 += mass_elm
        FI_mean.append(FI_mean_sum / mass[i])
        FI_mean_without_state0.append(FI_mean_sum_without_state0 /
                                      mass_without_state0)
        print("FI_mean                = {}".format(FI_mean[i]))
        print("FI_mean_without_state0 = {}".format(FI_mean_without_state0[i]))

        # writing log table row
        msg = str().rjust(9, " ") + " " + str(mass[i]).rjust(
            17, " ") + " " + str(FI_violated[i][0]).rjust(13, " ")
        for dno in range(len(domains_from_config) - 1):
            msg += " " + str(FI_violated[i][dno + 1]).rjust(4, " ")
        if len(domains_from_config) > 1:
            msg += " " + str(sum(FI_violated[i])).rjust(4, " ")
        msg += " " + str(FI_mean[i]).rjust(17, " ") + " " + str(
            FI_mean_without_state0[i]).rjust(18, " ")
        FI_max_all = 0
        for dn in domains_from_config:
            msg += " " + str(FI_max[i][dn]).rjust(17, " ")
            FI_max_all = max(FI_max_all, FI_max[i][dn])
        if len(domains_from_config) > 1:
            msg += " " + str(FI_max_all).rjust(17, " ")
        msg += "\n"
        beso_lib.write_to_log(file_name, msg)
Ejemplo n.º 6
0
def check_same_state(domain_same_state, filtered_dn, file_name):
    wrong_domains = False
    filtered_dn_set = set(filtered_dn)
    domains_to_check = set()
    for dn in domain_same_state:
        if domain_same_state[dn] in ["max", "average"]:
            domains_to_check.add(dn)
    if domains_to_check.intersection(filtered_dn_set):
        wrong_domains = True

    if wrong_domains is True:
        msg = "\nERROR: Filtering is used on domain with prescribed same state. It is recommended to exclude this domain" \
              " from filtering.\n"
        beso_lib.write_to_log(file_name, msg)
        print(msg)
Ejemplo n.º 7
0
def run2(file_name, sensitivity_number, weight_factor2, near_elm, opt_domains):
    sensitivity_number_filtered = sensitivity_number.copy(
    )  # sensitivity number of each element after filtering
    for en in opt_domains:
        numerator = 0
        denominator = 0
        for en2 in near_elm[en]:
            ee = (min(en, en2), max(en, en2))
            numerator += weight_factor2[ee] * sensitivity_number[en2]
            denominator += weight_factor2[ee]
        if denominator != 0:
            sensitivity_number_filtered[en] = numerator / denominator
        else:
            msg = "\nERROR: simple filter failed due to division by 0." \
                  "Some element has not a near element in distance <= r_min.\n"
            print(msg)
            beso_lib.write_to_log(file_name, msg)
            filter_on_sensitivity = 0
            return sensitivity_number
    return sensitivity_number_filtered
Ejemplo n.º 8
0
msg += ("reference_value         = %s\n" % reference_value)
msg += ("mass_addition_ratio     = %s\n" % mass_addition_ratio)
msg += ("mass_removal_ratio      = %s\n" % mass_removal_ratio)
msg += ("ratio_type              = %s\n" % ratio_type)
msg += ("compensate_state_filter = %s\n" % compensate_state_filter)
msg += ("sensitivity_averaging   = %s\n" % sensitivity_averaging)
msg += ("steps_superposition     = %s\n" % steps_superposition)
msg += ("iterations_limit        = %s\n" % iterations_limit)
msg += ("tolerance               = %s\n" % tolerance)
msg += ("displacement_graph      = %s\n" % displacement_graph)
msg += ("save_iteration_results  = %s\n" % save_iteration_results)
msg += ("save_solver_files       = %s\n" % save_solver_files)
msg += ("save_resulting_format   = %s\n" % save_resulting_format)
msg += "\n"
file_name = os.path.join(path, file_name)
beso_lib.write_to_log(file_name, msg)

# mesh and domains importing
[nodes, Elements, domains, opt_domains, en_all, plane_strain, plane_stress, axisymmetry] = beso_lib.import_inp(
    file_name, domains_from_config, domain_optimized, shells_as_composite)
domain_shells = {}
domain_volumes = {}
for dn in domains_from_config:  # distinguishing shell elements and volume elements
    domain_shells[dn] = set(domains[dn]).intersection(list(Elements.tria3.keys()) + list(Elements.tria6.keys()) +
                                                      list(Elements.quad4.keys()) + list(Elements.quad8.keys()))
    domain_volumes[dn] = set(domains[dn]).intersection(list(Elements.tetra4.keys()) + list(Elements.tetra10.keys()) +
                                                       list(Elements.hexa8.keys()) + list(Elements.hexa20.keys()) +
                                                       list(Elements.penta6.keys()) + list(Elements.penta15.keys()))

# initialize element states
elm_states = {}
Ejemplo n.º 9
0
msg += ("reference_value         = %s\n" % reference_value)
msg += ("mass_addition_ratio     = %s\n" % mass_addition_ratio)
msg += ("mass_removal_ratio      = %s\n" % mass_removal_ratio)
msg += ("ratio_type              = %s\n" % ratio_type)
msg += ("compensate_state_filter = %s\n" % compensate_state_filter)
msg += ("sensitivity_averaging   = %s\n" % sensitivity_averaging)
msg += ("steps_superposition     = %s\n" % steps_superposition)
msg += ("iterations_limit        = %s\n" % iterations_limit)
msg += ("tolerance               = %s\n" % tolerance)
msg += ("displacement_graph      = %s\n" % displacement_graph)
msg += ("save_iteration_results  = %s\n" % save_iteration_results)
msg += ("save_solver_files       = %s\n" % save_solver_files)
msg += ("save_resulting_format   = %s\n" % save_resulting_format)
msg += "\n"
file_name = os.path.join(path, file_name)
beso_lib.write_to_log(file_name, msg)

if optimization_base == "stiffness" and reference_points == "nodes":
    msg = "reference_points set to 'nodes' is not supported for optimization_base as 'stiffness'"
    beso_lib.write_to_log(file_name, "\nERROR: " + msg + "\n")
    assert False, msg

# mesh and domains importing
[nodes, Elements, domains, opt_domains, en_all, plane_strain, plane_stress, axisymmetry] = beso_lib.import_inp(
    file_name, domains_from_config, domain_optimized, shells_as_composite)
domain_shells = {}
domain_volumes = {}
for dn in domains_from_config:  # distinguishing shell elements and volume elements
    domain_shells[dn] = set(domains[dn]).intersection(list(Elements.tria3.keys()) + list(Elements.tria6.keys()) +
                                                      list(Elements.quad4.keys()) + list(Elements.quad8.keys()))
    domain_volumes[dn] = set(domains[dn]).intersection(list(Elements.tetra4.keys()) + list(Elements.tetra10.keys()) +
Ejemplo n.º 10
0
def prepare3_ortho_grid(file_name, cg, cg_min, r_min, opt_domains):
    weight_factor3 = {}
    near_points = {}
    near_elm = {}
    grid_size = 0.7 * r_min  # constant less than sqrt(6)/2 is chosen ensuring that each element has at least 3 near points
    # if codes below are done for situation where grid_size > 0.5 * r_min

    # searching for near points of each element
    for en in opt_domains:  # domain to take elements for filtering
        x_elm, y_elm, z_elm = cg[en]

        # set proper starting point coordinates
        reminder = divmod(x_elm - cg_min[0], grid_size)[1]
        if (grid_size + reminder) < r_min:
            x = x_elm - grid_size - reminder
        else:
            x = x_elm - reminder
        reminder = divmod(y_elm - cg_min[1], grid_size)[1]
        if (grid_size + reminder) < r_min:
            yy = y_elm - grid_size - reminder
        else:
            yy = y_elm - reminder
        reminder = divmod(z_elm - cg_min[2], grid_size)[1]
        if (grid_size + reminder) < r_min:
            zz = z_elm - grid_size - reminder
        else:
            zz = z_elm - reminder
        near_points[en] = []

        # through points in the cube around element centre of gravity
        while x < x_elm + r_min:
            y = yy
            while y < y_elm + r_min:
                z = zz
                while z < z_elm + r_min:
                    distance = ((x_elm - x)**2 + (y_elm - y)**2 +
                                (z_elm - z)**2)**0.5
                    if distance < r_min:
                        weight_factor3[(en, (x, y, z))] = r_min - distance
                        near_points[en].append((x, y, z))
                        try:
                            near_elm[(x, y, z)].append(en)
                        except KeyError:
                            near_elm[(x, y, z)] = [en]
                    z += grid_size
                y += grid_size
            x += grid_size
    hist_near_elm = list(np.zeros(25))
    hist_near_points = list(np.zeros(25))
    for pn in near_elm:
        if isinstance(near_elm[pn], int):
            le = 1
        else:
            le = len(near_elm[pn])
        if le >= len(hist_near_elm):
            while len(hist_near_elm) <= le:
                hist_near_elm.append(0)
        hist_near_elm[le] += 1
    for en in near_points:
        if isinstance(near_points[en], int):
            le = 1
        else:
            le = len(near_points[en])
        if le >= len(hist_near_points):
            while len(hist_near_points) <= le:
                hist_near_points.append(0)
        hist_near_points[le] += 1
    msg = "\nfilter3 statistics:\n"
    msg += "histogram - number of near elements (list index) vs. number of points (value)\n"
    msg += str(hist_near_elm) + "\n"
    msg += "histogram - number of near points (list index) vs. number of elements (value)\n"
    msg += str(hist_near_points) + "\n"
    beso_lib.write_to_log(file_name, msg)
    return weight_factor3, near_elm, near_points
Ejemplo n.º 11
0
    def Swith_Element_State(self):
        '''
        # switch element states
        '''
        global i, mass_referential, elm_states, mass, elm_states_before_last, elm_states_last, continue_iterations

        if ratio_type == "absolute":
            mass_referential = mass_full
        elif ratio_type == "relative":
            mass_referential = mass[i - 1]
        [elm_states, mass] = beso_lib.switching(
            elm_states, domains_from_config, domain_optimized, domains,
            FI_step_max, domain_density, domain_thickness, domain_shells,
            area_elm, volume_elm, sensitivity_number, mass, mass_referential,
            mass_addition_ratio, mass_removal_ratio, decay_coefficient,
            FI_violated, i_violated, i, mass_goal_i)

        # check for oscillation state
        if elm_states_before_last == elm_states:  # oscillating state
            msg = "OSCILLATION: model turns back to " + str(
                i - 2) + "th iteration\n"
            beso_lib.write_to_log(file_name, msg)
            print(msg)
            continue_iterations = False
        elm_states_before_last = elm_states_last.copy()
        elm_states_last = elm_states.copy()

        # filtering state
        for ft in filter_list:
            if ft[0] and ft[1]:
                if len(ft) == 2:
                    domains_to_filter = list(opt_domains)
                else:
                    domains_to_filter = []
                    for dn in ft[2:]:
                        domains_to_filter += domains[dn]

                if ft[0].split()[0] in [
                        "erode", "dilate", "open", "close", "open-close",
                        "close-open", "combine"
                ]:
                    if ft[0].split()[1] == "state":
                        # the same filter as for sensitivity numbers
                        elm_states_filtered = beso_filters.run_morphology(
                            elm_states, near_elm, opt_domains,
                            ft[0].split()[0])
                        # compute mass difference
                        for dn in domains_from_config:
                            if domain_optimized[dn] is True:
                                for en in domain_shells[dn]:
                                    if elm_states[en] != elm_states_filtered[
                                            en]:
                                        mass[i] += area_elm[en] * (
                                            domain_density[dn][
                                                elm_states_filtered[en]] *
                                            domain_thickness[dn][
                                                elm_states_filtered[en]] -
                                            domain_density[dn][elm_states[en]]
                                            * domain_thickness[dn][
                                                elm_states[en]])
                                        elm_states[en] = elm_states_filtered[
                                            en]
                                for en in domain_volumes[dn]:
                                    if elm_states[en] != elm_states_filtered[
                                            en]:
                                        mass[i] += volume_elm[en] * (
                                            domain_density[dn][
                                                elm_states_filtered[en]] -
                                            domain_density[dn][elm_states[en]])
                                        elm_states[en] = elm_states_filtered[
                                            en]
        print("mass = {}".format(mass[i]))
        print("Swith_Element_State")
Ejemplo n.º 12
0
    def FEA(self):
        global i, FI_step, sensitivity_number, FI_violated, FI_step_max

        print("FEA")
        # creating a new .inp file for CalculiX
        file_nameW = path_export + '/' + str(i).zfill(3)
        beso_lib.write_inp(file_name, file_nameW, elm_states, number_of_states,
                           domains, domains_from_config, domain_optimized,
                           domain_thickness, domain_offset, domain_material,
                           domain_volumes, domain_shells, plane_strain,
                           plane_stress, axisymmetry, save_iteration_results,
                           i, reference_points, shells_as_composite)
        # running CalculiX analysis
        subprocess.call(os.path.normpath(path_calculix) + " " +
                        os.path.join(path, file_nameW),
                        shell=True)

        # reading results and computing failure indeces
        if reference_points == "integration points":  # from .dat file
            FI_step = beso_lib.import_FI_int_pt(reference_value, file_nameW,
                                                domains, criteria, domain_FI,
                                                file_name, elm_states,
                                                domains_from_config)
        elif reference_points == "nodes":  # from .frd file
            FI_step = beso_lib.import_FI_node(reference_value, file_nameW,
                                              domains, criteria, domain_FI,
                                              file_name, elm_states)
        os.remove(file_nameW + ".inp")
        if not save_iteration_results or np.mod(float(i - 1),
                                                save_iteration_results) != 0:
            os.remove(file_nameW + ".dat")
            os.remove(file_nameW + ".frd")
        os.remove(file_nameW + ".sta")
        os.remove(file_nameW + ".cvg")
        FI_max.append({})
        for dn in domains_from_config:
            FI_max[i][dn] = 0
            for en in domains[dn]:
                for sn in range(len(FI_step)):
                    try:
                        FI_step_en = list(
                            filter(lambda a: a is not None,
                                   FI_step[sn][en]))  # drop None FI
                        FI_max[i][dn] = max(FI_max[i][dn], max(FI_step_en))
                    except ValueError:
                        msg = "FI_max computing failed. Check if each domain contains at least one failure criterion."
                        beso_lib.write_to_log(file_name,
                                              "ERROR: " + msg + "\n")
                        raise Exception(msg)
                    except KeyError:
                        msg = "Some result values are missing. Check available disk space."
                        beso_lib.write_to_log(file_name,
                                              "ERROR: " + msg + "\n")
                        raise Exception(msg)
        print("domain ordered \nFI_max and number of violated elements")

        # handling with more steps
        FI_step_max = {
        }  # maximal FI over all steps for each element in this iteration
        FI_violated.append([])
        dno = 0
        for dn in domains_from_config:
            FI_violated[i].append(0)
            for en in domains[dn]:
                FI_step_max[en] = 0
                for sn in range(len(FI_step)):
                    FI_step_en = list(
                        filter(lambda a: a is not None,
                               FI_step[sn][en]))  # drop None FI
                    FI_step_max[en] = max(FI_step_max[en], max(FI_step_en))
                sensitivity_number[en] = FI_step_max[en] / domain_density[dn][
                    elm_states[en]]
                if FI_step_max[en] >= 1:
                    FI_violated[i][dno] += 1
            print(
                str(FI_max[i][dn]).rjust(15) + " " +
                str(FI_violated[i][dno]).rjust(4))
            dno += 1