Source code for OpenPisco.MuscatExtentions.PartitionRefining

# -*- coding: utf-8 -*-
#
# This file is subject to the terms and conditions defined in
# file 'LICENSE', which is part of this source code package.
#
#!/usr/bin/python3
# -*- coding: utf-8 -*-
""" 
This module displays a technique called Partition refinement
https://en.wikipedia.org/wiki/Partition_refinement
"""

from typing import Dict,List,Union
import numpy as np


[docs]class PartitionRefining(): """ Class display a technique representing a partition of a set as a data structure that allows the partition to be refined by splitting its sets into a larger number of smaller sets. From here onwards we denote by a family an elementary set, meaning that a so-called group must be the union of several families. """ def __init__(self,cellsByGroupnumber:Dict,cells:Union[np.ndarray,List[int]]): """Constructor of the class PartitionRefining Parameters ---------- cellsByGroupnumber : Dict expressing the association between each group and the cells belonging to them (in FE method either a set of nodes or a set of elements) cells : Union[np.ndarray,List[int]] array of int cells: set of all cells to be partitionned """ self.cellsByGroupnumber=cellsByGroupnumber self.cells=cells self.groupsByFamily=dict() self.cellsByFamily=dict()
[docs] def GetGroupsByFamily(self)->dict: """Get association between groups and family Returns ------- dict groups by family """ return self.groupsByFamily
[docs] def GetCellsByFamily(self)->dict: """Retrieve association between groups and cells Returns ------- dict cells by family """ return self.cellsByFamily
[docs] def ExecutePartitioning(self): """ Implementation of the algorithm Provide a partition of the original set by updating it, cellsByFamily, in a larger number of smaller disjoints sets (minimum required to describe the groups) Provide the association between each family and the groups that contain them by updating groupsByFamily """ #initialized to an empty group associated to family 1 groupsByFamily = {1 : []} #initialized to the trivial family 1 that contains every cells cellsByFamily={1 : self.cells} # At each step of the algorithm, a set X is presented to the algorithm, for newgroup, groupcells in self.cellsByGroupnumber.items(): split_by_family = {} for family, familycells in cellsByFamily.items(): intersect = np.intersect1d(familycells, groupcells, assume_unique=True) if len(intersect) == 0: # family and group are disjoint, nothing to do for this family continue # family intersects with this group if len(intersect) == len(familycells): # family and group are coincident, this is the expected result diff = None else: # group is partially intersecting family, need to split this family diff = np.setdiff1d(familycells, groupcells, assume_unique=True) split_by_family[family] = (intersect, diff) for family, split in split_by_family.items(): intersect, diff = split if diff is not None: cellsByFamily[family] = intersect newfamily = len(cellsByFamily) + 1 cellsByFamily[newfamily] = diff groupsByFamily[newfamily] = list(groupsByFamily[family]) groupsByFamily[family].append(newgroup) self.groupsByFamily=groupsByFamily self.cellsByFamily=cellsByFamily
[docs]def CheckIntegrity(): node_ids = range(1, 9 + 1) cellsByGroupnumber = {1:np.unique([1,2,3,4]), 2:np.unique([2,4,5]),3:np.unique([1,6]), 4:np.unique([7,8,9]), 5:np.unique([1,2,3,4,6])} PRef=PartitionRefining(cellsByGroupnumber,node_ids) PRef.ExecutePartitioning() groupsByFamily,cellsByFamily=PRef.GetGroupsByFamily(),PRef.GetCellsByFamily() print("cellsByFamily: ",cellsByFamily) print("groupsByFamily: ",groupsByFamily) from functools import reduce for family in groupsByFamily.keys(): group=tuple(cellsByGroupnumber[elem] for elem in groupsByFamily[family]) cells=reduce(np.intersect1d,group) cells.sort() ref=cellsByFamily[family] if cells.all()!=ref.all(): print("For family ",family," Cells obtained: ",cells," Cells expected: ",ref) raise Exception("The partition refining has failed") return "Ok"
if __name__ == '__main__': print(CheckIntegrity())# pragma: no cover