Source code for Mordicus.Modules.Mines.OperatorCompressors.HyperReduction
# -*- coding: utf-8 -*-
from Mordicus.Core.Containers.Meshes.MeshBase import MeshBase
from Mordicus.Core.Containers.CollectionProblemData import CollectionProblemData
import numpy as np 
import pdb
[docs]def selection( basis: np.ndarray ) -> list:
    """Function to perform DEIM like selection of unknown to keep for the RID construction. Unknown can be nodal or integrated values
    
    Arguments:
        basis {np.ndarray} -- The full reduced order basis
    
    Returns:
        list -- the unknown rank to keep
    """
    
    n_dof, n_modes = basis.shape
    rid_ddl = []
    V = basis.copy()
    rk_max = np.argmax( np.abs(V[:,0]) )
    rid_ddl.append( rk_max )
    norm0 = abs(V[rk_max,0])
    V[:,0] /= norm0
    V[rk_max, 0] = 0.
    j_cum = [0]
    for m in range(1,n_modes):
        v_red = V[np.ix_(rid_ddl, [m,])]
        u_red = basis[np.ix_(rid_ddl, j_cum)]
        v_tmp = u_red.T.dot( v_red )
        utu = u_red.T.dot(u_red)
        try:
            sol = np.linalg.solve( utu, v_tmp)
        except np.linalg.LinAlgError:
            print("Becarefull the reduce integration domain construction seems badly conditionned")
            continue
        x = np.zeros((V.shape[1],1))
        x[:sol.shape[0], [0,]] = sol
        q = -1.*V.dot(x) + 1.*V[:,[m]]
        rk_max = np.argmax( np.abs(q) )
        q /= np.abs(q[rk_max])
        rid_ddl.append(rk_max)
        j_cum.append( m )
    return rid_ddl 
[docs]def BuildReducedIntegrationOperator(collectionProblemData: CollectionProblemData, mesh: MeshBase, extend=0, listNameDualVarOutput = []):
    """[summary]
    
    Arguments:
        collectionProblemData {CollectionProblemData} -- [description]
        mesh {MeshBase} -- [description]
    
    Keyword Arguments:
        extend {int} -- the number of additional layers to keep (default: {0})
        listNameDualVarOutput {list} -- the list of dual variable to use in addition to nodal ones (default: {[]})
    """
    print("Compute Reduced Integration Domain ... ")
    
    ## Step 1. Select dofs
    reducedOrderBasis = collectionProblemData.GetReducedOrderBasis("U").transpose() 
    rid_ddl = selection(reducedOrderBasis)
    print("DOFs selection done")
    ## Step 2. Select dual variable 
    rid_dual = {}
    
    for name in listNameDualVarOutput:
        reducedOrderBasis = collectionProblemData.GetReducedOrderBasis(name).transpose()
        rid_dual[name] = selection(reducedOrderBasis)
    
    nn = mesh.GetNumberOfNodes()
    selected_nodes = set([ dof % nn for dof in rid_ddl ])
    print("Identify the associated Reduced Integration Domain")
    ## Build reduced mesh 
    elem_to_keep = []
    for node_rk in selected_nodes:
        elem_to_keep += mesh.GetElemAttach(node_rk)
    ## Integration point to element
    for key, value in rid_dual.items():
        nb_comp = collectionProblemData.GetSolutionsNumberOfComponents(key)
        selected_ip =set([ int(ip/nb_comp) for ip in value ])
        elem_to_keep += [ mesh.GetElemContaining( ip_rank ) for ip_rank in selected_ip ]
    elem_to_keep = set(elem_to_keep)
    for _ in range( extend ):
        dirty_list = []
        for elem in elem_to_keep: 
            for node in mesh.GetElement( elem ):
                dirty_list += mesh.GetElemAttach(node) 
        
        new_elems = set(dirty_list) - elem_to_keep
        print(f"{len(new_elems)} elements added in the RID")
        elem_to_keep = set( list(elem_to_keep) + list(new_elems) )
    operatorCompressionData = {}
    operatorCompressionData["dofs"] = rid_ddl
    operatorCompressionData["rid"] = elem_to_keep
    collectionProblemData.SetOperatorCompressionData( operatorCompressionData )