def off_diagonal_block_same_layer(context, layers, id1, id2):
    """Off-diagonal interaction between two different layers. Returns a tuple of two operators.
    """

    pwc_id1 = layers[id1]['spaces']['c']
    plc_id1 = layers[id1]['spaces']['l']
    pwc_id2 = layers[id2]['spaces']['c']
    plc_id2 = layers[id2]['spaces']['l']

    k = layers[layers[id1]['father']]['k']
    kappa = layers[layers[id1]['father']]['kappa']

    D = kappa * lib.createModifiedHelmholtz3dHypersingularBoundaryOperator(
        context, plc_id2, pwc_id1, plc_id1, k)
    T = lib.createModifiedHelmholtz3dAdjointDoubleLayerBoundaryOperator(
        context, pwc_id2, pwc_id1, plc_id1, k)
    K = lib.createModifiedHelmholtz3dDoubleLayerBoundaryOperator(
        context, plc_id2, plc_id1, pwc_id1, k)
    S = 1. / kappa * lib.createModifiedHelmholtz3dSingleLayerBoundaryOperator(
        context, pwc_id2, plc_id1, pwc_id1, k)

    D2 = lib.adjoint(D, pwc_id2)
    T2 = lib.adjoint(K, pwc_id2)
    K2 = lib.adjoint(T, plc_id2)
    S2 = lib.adjoint(S, plc_id2)

    op1 = lib.createBlockedBoundaryOperator(context, [[-D, -T], [K, -S]])
    op2 = lib.createBlockedBoundaryOperator(context, [[-D2, -T2], [K2, -S2]])

    return (op1, op2)
def diagonal_block(context,layers,layer_id,impedance):
    """Create a diagonal block associated with a given layer_id
    
    """

    plc = layers[layer_id]['spaces']['l']
    pwc = layers[layer_id]['spaces']['c']
    k = layers[layer_id]['k']
    kappa = layers[layer_id]['kappa']

    if layer_id == 0:
        I_00  = lib.createIdentityOperator(context,plc,pwc,plc,label="I00")
        I_01 = lib.createIdentityOperator(context,pwc,pwc,plc,label="I01")
        I_10 = lib.createIdentityOperator(context,plc,plc,pwc,label="I10")
        K = lib.createModifiedHelmholtz3dDoubleLayerBoundaryOperator(context,plc,plc,pwc,k,label="K10")
        S = 1./kappa*lib.createModifiedHelmholtz3dSingleLayerBoundaryOperator(context,pwc,plc,pwc,k,label="S11")

        return lib.createBlockedBoundaryOperator(context,[[I_00,impedance*I_01],[-.5*I_10-K,S]])
    else:
        kf = layers[layers[layer_id]['father']]['k']
        kappaf = layers[layers[layer_id]['father']]['kappa']
        DD = (-kappaf*lib.createModifiedHelmholtz3dHypersingularBoundaryOperator(context,plc,pwc,plc,kf,label="Df"+str(layer_id)+"_"+str(layer_id))
              -kappa*lib.createModifiedHelmholtz3dHypersingularBoundaryOperator(context,plc,pwc,plc,k,label="D"+str(layer_id)+"_"+str(layer_id)))
        TT = (-lib.createModifiedHelmholtz3dAdjointDoubleLayerBoundaryOperator(context,pwc,pwc,plc,kf,label="Tf"+str(layer_id)+"_"+str(layer_id))
              -lib.createModifiedHelmholtz3dAdjointDoubleLayerBoundaryOperator(context,pwc,pwc,plc,k,label="T"+str(layer_id)+"_"+str(layer_id)))
        KK = (lib.createModifiedHelmholtz3dDoubleLayerBoundaryOperator(context,plc,plc,pwc,kf,label="Kf"+str(layer_id)+"_"+str(layer_id))
              +lib.createModifiedHelmholtz3dDoubleLayerBoundaryOperator(context,plc,plc,pwc,k,label="K"+str(layer_id)+"_"+str(layer_id)))
        SS = (-1./kappaf*lib.createModifiedHelmholtz3dSingleLayerBoundaryOperator(context,pwc,plc,pwc,kf,label="Sf"+str(layer_id)+"_"+str(layer_id))
              -1./kappa*lib.createModifiedHelmholtz3dSingleLayerBoundaryOperator(context,pwc,plc,pwc,k,label="S"+str(layer_id)+"_"+str(layer_id)))
        
        return lib.createBlockedBoundaryOperator(context,[[DD,TT],[KK,SS]])
def off_diagonal_block_same_layer(context,layers,id1,id2):
    """Off-diagonal interaction between two different layers. Returns a tuple of two operators.
    """

    pwc_id1 = layers[id1]['spaces']['c']
    plc_id1 = layers[id1]['spaces']['l']
    pwc_id2 = layers[id2]['spaces']['c']
    plc_id2 = layers[id2]['spaces']['l']

    k = layers[layers[id1]['father']]['k']
    kappa = layers[layers[id1]['father']]['kappa']

    D = kappa*lib.createModifiedHelmholtz3dHypersingularBoundaryOperator(context,plc_id2,pwc_id1,plc_id1,k)
    T = lib.createModifiedHelmholtz3dAdjointDoubleLayerBoundaryOperator(context,pwc_id2,pwc_id1,plc_id1,k)
    K = lib.createModifiedHelmholtz3dDoubleLayerBoundaryOperator(context,plc_id2,plc_id1,pwc_id1,k)
    S = 1./kappa*lib.createModifiedHelmholtz3dSingleLayerBoundaryOperator(context,pwc_id2,plc_id1,pwc_id1,k)

    D2 = lib.adjoint(D,pwc_id2)
    T2 = lib.adjoint(K,pwc_id2)
    K2  = lib.adjoint(T,plc_id2)
    S2  = lib.adjoint(S,plc_id2)

    op1 = lib.createBlockedBoundaryOperator(context,[[-D,-T],[K,-S]])
    op2 = lib.createBlockedBoundaryOperator(context,[[-D2,-T2],[K2,-S2]])
    
    return (op1,op2)
def generate_local_block_operator(context, my_proc, graph, layers, alpha):
    """Generate the local system matrix.
    """
    def copy_to_structure(brow, bcol, block, structure):
        """Small helper routine to copy a 2x2 block at the right position into a structure
        """
        structure.setBlock(2 * brow, 2 * bcol, block.block(0, 0))
        structure.setBlock(2 * brow, 2 * bcol + 1, block.block(0, 1))
        structure.setBlock(2 * brow + 1, 2 * bcol, block.block(1, 0))
        structure.setBlock(2 * brow + 1, 2 * bcol + 1, block.block(1, 1))

    nproc = Epetra.PyComm().NumProc()

    process_map = procmap(blockmap(graph), nproc)
    scheduler = partition(process_map)

    # Initialize structure of local system matrix

    nb = process_map.shape[0]  # Block-dimension of global matrix
    structure = lib.createBlockedOperatorStructure(context)
    for i in range(nb):
        plc = layers[i]['spaces']['l']
        pwc = layers[i]['spaces']['c']
        null_op_00 = lib.createNullOperator(context, plc, pwc, plc)
        null_op_11 = lib.createNullOperator(context, pwc, plc, pwc)
        structure.setBlock(2 * i, 2 * i, null_op_00)
        structure.setBlock(2 * i + 1, 2 * i + 1, null_op_11)

    # Iterate through elements from scheduler and fill up local system matrix

    if not scheduler.has_key(my_proc + 1):
        A = lib.createBlockedBoundaryOperator(context, structure)
        return A

    for elem in scheduler[my_proc + 1]:
        if elem[0] == elem[1]:
            # Diagonal Block
            block = diagonal_block(context, layers, elem[0], alpha)
            copy_to_structure(elem[0], elem[1], block, structure)
        else:
            if layers[elem[0]]['sons'].count(elem[1]):
                # elem[1] is a son of elem[0]
                block1, block2 = off_diagonal_block_father_son(
                    context, layers, elem[0], elem[1])
            else:
                # elements must be on the same level
                block1, block2 = off_diagonal_block_same_layer(
                    context, layers, elem[0], elem[1])
            copy_to_structure(elem[0], elem[1], block1, structure)
            copy_to_structure(elem[1], elem[0], block2, structure)
    A = lib.createBlockedBoundaryOperator(context, structure)
    return A
def generate_local_block_operator(context,my_proc,graph,layers,alpha):
    """Generate the local system matrix.
    """

    def copy_to_structure(brow,bcol,block,structure):
        """Small helper routine to copy a 2x2 block at the right position into a structure
        """
        structure.setBlock(2*brow,2*bcol,block.block(0,0))
        structure.setBlock(2*brow,2*bcol+1,block.block(0,1))
        structure.setBlock(2*brow+1,2*bcol,block.block(1,0))
        structure.setBlock(2*brow+1,2*bcol+1,block.block(1,1))

    nproc = Epetra.PyComm().NumProc()

    process_map = procmap(blockmap(graph),nproc)
    scheduler = partition(process_map)

    # Initialize structure of local system matrix

    nb = process_map.shape[0] # Block-dimension of global matrix
    structure = lib.createBlockedOperatorStructure(context)
    for i in range(nb):
        plc = layers[i]['spaces']['l']
        pwc = layers[i]['spaces']['c']
        null_op_00 = lib.createNullOperator(context,plc,pwc,plc)
        null_op_11 = lib.createNullOperator(context,pwc,plc,pwc)
        structure.setBlock(2*i,2*i,null_op_00)
        structure.setBlock(2*i+1,2*i+1,null_op_11)

    # Iterate through elements from scheduler and fill up local system matrix

    if not scheduler.has_key(my_proc+1):
        A = lib.createBlockedBoundaryOperator(context,structure)
        return A
        
    for elem in scheduler[my_proc+1]:
        if elem[0]==elem[1]:
            # Diagonal Block
            block = diagonal_block(context,layers,elem[0],alpha)
            copy_to_structure(elem[0],elem[1],block,structure)
        else:
            if layers[elem[0]]['sons'].count(elem[1]):
                # elem[1] is a son of elem[0]
                block1,block2 = off_diagonal_block_father_son(context,layers,elem[0],elem[1])
            else:
                # elements must be on the same level
                block1,block2 = off_diagonal_block_same_layer(context,layers,elem[0],elem[1])
            copy_to_structure(elem[0],elem[1],block1,structure)
            copy_to_structure(elem[1],elem[0],block2,structure)
    A = lib.createBlockedBoundaryOperator(context,structure)
    return A
def off_diagonal_block_father_son(context,layers,father_id,son_id):
    """Off-diagonal interaction between two different layers. Returns a tuple of two operators.
    """

    plc_father = layers[father_id]['spaces']['l']
    pwc_father = layers[father_id]['spaces']['c']
    plc_son = layers[son_id]['spaces']['l']
    pwc_son = layers[son_id]['spaces']['c']

    kf = layers[father_id]['k']
    kappaf = layers[father_id]['kappa']
    
    if father_id==0:
        null_00 = lib.createNullOperator(context,plc_son,pwc_father,plc_father,label="Null_00")
        null_01 = lib.createNullOperator(context,pwc_son,pwc_father,plc_father,label="Null_01")
        Kf = lib.createModifiedHelmholtz3dDoubleLayerBoundaryOperator(context,plc_son,plc_father,pwc_father,kf,label="Kf0_"+str(son_id))
        Sf = 1./kappaf*lib.createModifiedHelmholtz3dSingleLayerBoundaryOperator(context,pwc_son,plc_father,pwc_father,kf,label="Sf0_"+str(son_id))

        op_father_son = lib.createBlockedBoundaryOperator(context,[[null_00,null_01],[Kf,-Sf]])

        Ds = kappaf*lib.createModifiedHelmholtz3dHypersingularBoundaryOperator(context,plc_father,pwc_son,plc_son,kf,label="Ds"+str(son_id)+"_0")
        Ts = lib.adjoint(Kf,pwc_son)
        Ks = lib.createModifiedHelmholtz3dDoubleLayerBoundaryOperator(context,plc_father,plc_son,pwc_son,kf,label="Ks"+str(son_id)+"_0")
        Ss = lib.adjoint(Sf,plc_son)

        op_son_father = lib.createBlockedBoundaryOperator(context,[[Ds,Ts],[-Ks,Ss]])

    else:
        Df = kappaf*lib.createModifiedHelmholtz3dHypersingularBoundaryOperator(context,plc_son,pwc_father,plc_father,kf)
        Tf = lib.createModifiedHelmholtz3dAdjointDoubleLayerBoundaryOperator(context,pwc_son,pwc_father,plc_father,kf)
        Kf = lib.createModifiedHelmholtz3dDoubleLayerBoundaryOperator(context,plc_son,plc_father,pwc_father,kf)
        Sf = 1./kappaf*lib.createModifiedHelmholtz3dDoubleLayerBoundaryOperator(context,pwc_son,plc_father,pwc_father,kf)

        op_father_son = lib.createBlockedBoundaryOperator(context,[[Df,Tf],[-Kf,Sf]])

        Ds = lib.adjoint(Df,pwc_son)
        Ts = lib.adjoint(Kf,pwc_son)
        Ks = lib.adjoint(Tf,plc_son)
        Ss = lib.adjoint(Sf,plc_son)

        op_son_father = lib.createBlockedBoundaryOperator(context,[[Ds,Ts],[-Ks,Ss]])

    return (op_father_son,op_son_father)
    def buildBlockInverses(self, aca_tol):
        """Generate the Block LU decompositions
        """

        from bempp import tools

        A = self.__A
        layers = self.__layers
        nproc = self.__comm.NumProc()
        my_id = self.__comm.MyPID()
        scheduler = self.__scheduler
        local_diag_blocks = []
        if scheduler.has_key(my_id + 1):
            for elem in scheduler[my_id + 1]:
                if elem[0] == elem[1]:
                    local_diag_blocks.append(elem[0])

        # Create a vector with index offsets
        offsets = np.cumsum([0] +
                            [layer['spaces']['ndof'] for layer in layers])

        total_time = 0

        # Now create the LU blocks and store together with offsets
        blocks = []
        for id in local_diag_blocks:
            op00 = A.block(2 * id, 2 * id)
            op01 = A.block(2 * id, 2 * id + 1)
            op10 = A.block(2 * id + 1, 2 * id)
            op11 = A.block(2 * id + 1, 2 * id + 1)
            op = lib.createBlockedBoundaryOperator(
                self.__context, [[op00, op01], [op10, op11]])
            print "Generate approximate LU for block %(id)i on process %(my_id)i..." % {
                'id': id,
                'my_id': my_id
            }
            tstart = time()
            lu = lib.acaOperatorApproximateLuInverse(
                op.weakForm().asDiscreteAcaBoundaryOperator(), aca_tol)
            tend = time()
            total_time += tend - tstart
            print "Finished generating approximate LU for block %(id)i on process %(my_id)i in %(tval)f seconds." % {
                'id': id,
                'my_id': my_id,
                'tval': tend - tstart
            }
            blocks.append({
                'lu': tools.RealOperator(lu),
                'start': offsets[id],
                'end': offsets[id + 1],
                'ndof': offsets[id + 1] - offsets[id],
                'id': id
            })
        self.__total_time_prec_initialisation = total_time
        return blocks, local_diag_blocks
    def buildBlockInverses(self, aca_tol):
        """Generate the Block LU decompositions
        """

        from bempp import tools

        A = self.__A
        layers = self.__layers
        nproc = self.__comm.NumProc()
        my_id = self.__comm.MyPID()
        scheduler = partition(procmap(blockmap(graph), nproc))
        local_diag_blocks = []
        if scheduler.has_key(my_id + 1):
            for elem in scheduler[my_id + 1]:
                if elem[0] == elem[1]:
                    local_diag_blocks.append(elem[0])

        # Create a vector with index offsets
        offsets = np.cumsum([0] +
                            [layer['spaces']['ndof'] for layer in layers])

        # Now create the LU blocks and store together with offsets
        blocks = []
        for id in local_diag_blocks:
            op00 = A.block(2 * id, 2 * id)
            op01 = A.block(2 * id, 2 * id + 1)
            op10 = A.block(2 * id + 1, 2 * id)
            op11 = A.block(2 * id + 1, 2 * id + 1)
            op = lib.createBlockedBoundaryOperator(
                self.__context, [[op00, op01], [op10, op11]])
            print "Generate approximate LU for block %(id)i on process %(my_id)i" % {
                'id': id,
                'my_id': my_id
            }
            lu = lib.acaOperatorApproximateLuInverse(
                op.weakForm().asDiscreteAcaBoundaryOperator(), aca_tol)
            print "Finished generating approximate LU for block %(id)i on process %(my_id)i" % {
                'id': id,
                'my_id': my_id
            }
            blocks.append({
                'lu': tools.RealOperator(lu),
                'start': offsets[id],
                'end': offsets[id + 1]
            })
        return blocks
    def buildBlockInverses(self,aca_tol):
        """Generate the Block LU decompositions
        """

        from bempp import tools

        A = self.__A
        layers = self.__layers
        nproc = self.__comm.NumProc()
        my_id = self.__comm.MyPID()
        scheduler = self.__scheduler
        local_diag_blocks = []
        if scheduler.has_key(my_id+1):
            for elem in scheduler[my_id+1]:
                if elem[0] == elem[1]:
                    local_diag_blocks.append(elem[0])

        # Create a vector with index offsets
        offsets = np.cumsum([0]+[layer['spaces']['ndof'] for layer in layers])

        total_time = 0

        # Now create the LU blocks and store together with offsets
        blocks = []
        for id in local_diag_blocks:
            op00 = A.block(2*id,2*id)
            op01 = A.block(2*id,2*id+1)
            op10 = A.block(2*id+1,2*id)
            op11 = A.block(2*id+1,2*id+1)
            op = lib.createBlockedBoundaryOperator(self.__context,[[op00,op01],[op10,op11]])
            print "Generate approximate LU for block %(id)i on process %(my_id)i..." % {'id':id, 'my_id':my_id}
            tstart = time()
            lu = lib.acaOperatorApproximateLuInverse(op.weakForm().asDiscreteAcaBoundaryOperator(),aca_tol)
            tend = time()
            total_time += tend-tstart
            print "Finished generating approximate LU for block %(id)i on process %(my_id)i in %(tval)f seconds." % {'id':id, 'my_id':my_id,'tval':tend-tstart}
            blocks.append({'lu':tools.RealOperator(lu),
                           'start':offsets[id],
                           'end':offsets[id+1],
                           'ndof':offsets[id+1]-offsets[id],
                           'id': id
                           })
        self.__total_time_prec_initialisation = total_time
        return blocks,local_diag_blocks
    def buildBlockInverses(self,aca_tol):
        """Generate the Block LU decompositions
        """

        from bempp import tools

        A = self.__A
        layers = self.__layers
        nproc = self.__comm.NumProc()
        my_id = self.__comm.MyPID()
        scheduler = partition(procmap(blockmap(graph),nproc))
        local_diag_blocks = []
        if scheduler.has_key(my_id+1):
            for elem in scheduler[my_id+1]:
                if elem[0] == elem[1]:
                    local_diag_blocks.append(elem[0])

        # Create a vector with index offsets
        offsets = np.cumsum([0]+[layer['spaces']['ndof'] for layer in layers])

        # Now create the LU blocks and store together with offsets
        blocks = []
        for id in local_diag_blocks:
            op00 = A.block(2*id,2*id)
            op01 = A.block(2*id,2*id+1)
            op10 = A.block(2*id+1,2*id)
            op11 = A.block(2*id+1,2*id+1)
            op = lib.createBlockedBoundaryOperator(self.__context,[[op00,op01],[op10,op11]])
            print "Generate approximate LU for block %(id)i on process %(my_id)i" % {'id':id, 'my_id':my_id}
            lu = lib.acaOperatorApproximateLuInverse(op.weakForm().asDiscreteAcaBoundaryOperator(),aca_tol)
            print "Finished generating approximate LU for block %(id)i on process %(my_id)i" % {'id':id, 'my_id':my_id}
            blocks.append({'lu':tools.RealOperator(lu),
                           'start':offsets[id],
                           'end':offsets[id+1]
                           })
        return blocks    
def diagonal_block(context, layers, layer_id, impedance):
    """Create a diagonal block associated with a given layer_id
    
    """

    plc = layers[layer_id]['spaces']['l']
    pwc = layers[layer_id]['spaces']['c']
    k = layers[layer_id]['k']
    kappa = layers[layer_id]['kappa']

    if layer_id == 0:
        I_00 = lib.createIdentityOperator(context, plc, pwc, plc, label="I00")
        I_01 = lib.createIdentityOperator(context, pwc, pwc, plc, label="I01")
        I_10 = lib.createIdentityOperator(context, plc, plc, pwc, label="I10")
        K = lib.createModifiedHelmholtz3dDoubleLayerBoundaryOperator(
            context, plc, plc, pwc, k, label="K10")
        S = 1. / kappa * lib.createModifiedHelmholtz3dSingleLayerBoundaryOperator(
            context, pwc, plc, pwc, k, label="S11")

        return lib.createBlockedBoundaryOperator(
            context, [[I_00, impedance * I_01], [-.5 * I_10 - K, S]])
    else:
        kf = layers[layers[layer_id]['father']]['k']
        kappaf = layers[layers[layer_id]['father']]['kappa']
        DD = (
            -kappaf *
            lib.createModifiedHelmholtz3dHypersingularBoundaryOperator(
                context,
                plc,
                pwc,
                plc,
                kf,
                label="Df" + str(layer_id) + "_" + str(layer_id)) -
            kappa * lib.createModifiedHelmholtz3dHypersingularBoundaryOperator(
                context,
                plc,
                pwc,
                plc,
                k,
                label="D" + str(layer_id) + "_" + str(layer_id)))
        TT = (-lib.createModifiedHelmholtz3dAdjointDoubleLayerBoundaryOperator(
            context,
            pwc,
            pwc,
            plc,
            kf,
            label="Tf" + str(layer_id) + "_" + str(layer_id)) -
              lib.createModifiedHelmholtz3dAdjointDoubleLayerBoundaryOperator(
                  context,
                  pwc,
                  pwc,
                  plc,
                  k,
                  label="T" + str(layer_id) + "_" + str(layer_id)))
        KK = (lib.createModifiedHelmholtz3dDoubleLayerBoundaryOperator(
            context,
            plc,
            plc,
            pwc,
            kf,
            label="Kf" + str(layer_id) + "_" + str(layer_id)) +
              lib.createModifiedHelmholtz3dDoubleLayerBoundaryOperator(
                  context,
                  plc,
                  plc,
                  pwc,
                  k,
                  label="K" + str(layer_id) + "_" + str(layer_id)))
        SS = (-1. / kappaf *
              lib.createModifiedHelmholtz3dSingleLayerBoundaryOperator(
                  context,
                  pwc,
                  plc,
                  pwc,
                  kf,
                  label="Sf" + str(layer_id) + "_" + str(layer_id)) - 1. /
              kappa * lib.createModifiedHelmholtz3dSingleLayerBoundaryOperator(
                  context,
                  pwc,
                  plc,
                  pwc,
                  k,
                  label="S" + str(layer_id) + "_" + str(layer_id)))

        return lib.createBlockedBoundaryOperator(context, [[DD, TT], [KK, SS]])
def generate_local_block_operator(context,my_proc,process_map,layers,impedance):
    """Generate the local system matrix.
    """

    nproc = Epetra.PyComm().NumProc()
    total_time = 0

    scheduler = process_map.scheduler

    # Initialize structure of local system matrix

    nb = process_map.block_matrix_layout.shape[0] # Block-dimension of global matrix
    structure = lib.createBlockedOperatorStructure(context)
    for i in range(nb):
        plc = layers[i]['spaces']['l']
        pwc = layers[i]['spaces']['c']
        null_op_00 = lib.createNullOperator(context,plc,pwc,plc)
        null_op_11 = lib.createNullOperator(context,pwc,plc,pwc)
        structure.setBlock(2*i,2*i,null_op_00)
        structure.setBlock(2*i+1,2*i+1,null_op_11)

    # Iterate through elements from scheduler and fill up local system matrix

    if not scheduler.has_key(my_proc+1):
        A = lib.createBlockedBoundaryOperator(context,structure)
        return (A,total_time)
        
    for elem in scheduler[my_proc+1]:
        if elem[0]==elem[1]:
            # Diagonal Block
            print "Generating block element [%(e0)i,%(e1)i] on process %(my_proc)i... " % {'e0':elem[0],
                                                                                        'e1':elem[1],
                                                                                        'my_proc':my_proc}

            tstart=time()
            block = diagonal_block(context,layers,elem[0],impedance)
            block.weakForm()
            copy_to_structure(elem[0],elem[1],block,structure)
            tend=time()
            print "Block element [%(e0)i,%(e1)i] on process %(my_proc)i generated in %(tval)f seconds" % {'e0':elem[0],
                                                                                                          'e1':elem[1],
                                                                                                          'my_proc':my_proc,
                                                                                                          'tval':tend-tstart}
            total_time +=tend-tstart
        else:
            print "Generating block elements [%(e0)i,%(e1)i] and [%(e1)i,%(e0)i] on process %(my_proc)i... " % {'e0':elem[0],
                                                                                                           'e1':elem[1],
                                                                                                           'my_proc':my_proc}
            tstart=time()
            if layers[elem[0]]['sons'].count(elem[1]):
                # elem[1] is a son of elem[0]
                block1,block2 = off_diagonal_block_father_son(context,layers,elem[0],elem[1])
            else:
                # elements must be on the same level
                block1,block2 = off_diagonal_block_same_layer(context,layers,elem[0],elem[1])
            block1.weakForm()
            block2.weakForm()
            copy_to_structure(elem[0],elem[1],block1,structure)
            copy_to_structure(elem[1],elem[0],block2,structure)
            tend = time()
            print "Block elements [%(e0)i,%(e1)i] and [%(e1)i,%(e0)i] on process %(my_proc)i generated in %(tval)f seconds " % {'e0':elem[0],
                                                                                                                                'e1':elem[1],
                                                                                                                                'my_proc':my_proc,
                                                                                                                                'tval':tend-tstart
                                                                                                                                }
            total_time +=tend-tstart

    A = lib.createBlockedBoundaryOperator(context,structure)
    return (A,total_time)
Esempio n. 13
0
    context, pconsts, pconsts, pconsts, kInt, "DLP_int")
dlpOpExt = lib.createHelmholtz3dDoubleLayerBoundaryOperator(
    context, pconsts, pconsts, pconsts, kExt, "DLP_ext")
idOp = lib.createIdentityOperator(
    context, pconsts, pconsts, pconsts, "Id")

# Create blocks of the operator on the lhs of the equation...

lhsOp00 =  0.5 * idOp - dlpOpExt
lhsOp01 =  slpOpExt
lhsOp10 =  0.5 * idOp + dlpOpInt
lhsOp11 = -rhoInt / rhoExt * slpOpInt

# ... and combine them into a blocked operator

lhsOp = lib.createBlockedBoundaryOperator(
    context, [[lhsOp00, lhsOp01], [lhsOp10, lhsOp11]])

# Create a grid function representing the Dirichlet trace of the incident wave

def uIncData(point):
    x, y, z = point
    r = np.sqrt(x**2 + y**2 + z**2)
    return np.exp(1j * kExt * x)

uInc = lib.createGridFunction(context, pconsts, pconsts, uIncData)

# Create a grid function representing the Neumann trace of the incident wave

def uIncDerivData(point, normal):
    x, y, z = point
    nx, ny, nz = normal
Esempio n. 14
0
structure.setBlock(0, 1, lhs_k12);
structure.setBlock(0, 2, lhs_k13);
structure.setBlock(1, 0, lhs_k21);
structure.setBlock(1, 1, lhs_k22);
structure.setBlock(1, 2, lhs_k23);
structure.setBlock(2, 1, lhs_k32);
structure.setBlock(2, 2, lhs_k33);
structure.setBlock(2, 3, lhs_k34);
structure.setBlock(2, 4, lhs_k35);
structure.setBlock(3, 1, lhs_k42);
structure.setBlock(3, 2, lhs_k43);
structure.setBlock(3, 3, lhs_k44);
structure.setBlock(3, 4, lhs_k45);
structure.setBlock(4, 3, lhs_k54);
structure.setBlock(4, 4, lhs_k55);
blockedOp = blib.createBlockedBoundaryOperator(context,structure)

rhs1 = scale*slp11
rhs2 = scale*slp21

boundaryData1 = rhs1 * blib.createGridFunction(
    context, sphere1_plc, sphere1_plc, evalBoundaryData)
boundaryData2 = rhs2 * blib.createGridFunction(
    context, sphere1_plc, sphere1_plc, evalBoundaryData)
boundaryData3 = blib.createGridFunction(
    context, sphere2_plc, sphere2_plc, evalNullData)
boundaryData4 = blib.createGridFunction(
    context, sphere3_plc, sphere3_plc, evalNullData)
boundaryData5 = blib.createGridFunction(
    context, sphere3_plc, sphere3_plc, evalNullData)
Esempio n. 15
0
    def solve_bvp(self,wave_number,rhs):
                        
        self._residuals[wave_number] = []
        
        def evaluate_residual(res):
            self._residuals[wave_number].append(res)
        
        
        k_ext = 1.0j*wave_number * _np.sqrt(self._eps_ext * self._mu_ext)
        k_int = 1.0j*wave_number * _np.sqrt(self._eps_int * self._mu_int)
        rho = (k_int * self._mu_ext) / (k_ext * self._mu_int)
                    
        
        op_found_in_cache = False
        if self._operator_cache:
            try:
                op,prec = self._boundary_operator_cache(wave_number)
                op_found_in_cache = True
            except:
                pass
        if not op_found_in_cache:   
            
            context = self._context
            space = self._space

            slpOpExt = _bempplib.createMaxwell3dSingleLayerBoundaryOperator(
                context, space, space, space, k_ext, "SLP_ext")
            dlpOpExt = _bempplib.createMaxwell3dDoubleLayerBoundaryOperator(
                context, space, space, space, k_ext, "DLP_ext")
            slpOpInt = _bempplib.createMaxwell3dSingleLayerBoundaryOperator(
                context, space, space, space, k_int, "SLP_int")
            dlpOpInt = _bempplib.createMaxwell3dDoubleLayerBoundaryOperator(
                context, space, space, space, k_int, "DLP_int")
            idOp = _bempplib.createMaxwell3dIdentityOperator(
                context, space, space, space, "Id")
            
            # Form the left- and right-hand-side operators
            
            lhsOp00 = -(slpOpExt + rho * slpOpInt)
            lhsOp01 = lhsOp10 = dlpOpExt + dlpOpInt
            lhsOp11 = slpOpExt + (1. / rho) * slpOpInt
            
            lhsOp = _bempplib.createBlockedBoundaryOperator(
                context, [[lhsOp00, lhsOp01], [lhsOp10, lhsOp11]])
            

            precTol = self._aca_lu_delta
            invLhsOp00 = _bempplib.acaOperatorApproximateLuInverse(
                lhsOp00.weakForm().asDiscreteAcaBoundaryOperator(), precTol)
            invLhsOp11 = _bempplib.acaOperatorApproximateLuInverse(
                lhsOp11.weakForm().asDiscreteAcaBoundaryOperator(), precTol)
            prec = _bempplib.discreteBlockDiagonalPreconditioner([invLhsOp00, invLhsOp11])
            
            op = lhsOp


            # Construct the grid functions representing the traces of the incident field
            
        incDirichletTrace = _bempplib.createGridFunction(
            context, space, space, coefficients=rhs[0])
        incNeumannTrace = 1./(1j*k_ext)*_bempplib.createGridFunction(
            context, space, space, coefficients=rhs[1])
        
        self._inc_dirichlet_traces[wave_number] = incDirichletTrace
        self._inc_neumann_traces[wave_number] = incNeumannTrace
            
            # Construct the right-hand-side grid function
            
        rhs = [idOp * incNeumannTrace, idOp * incDirichletTrace]
            
            
        
            
        solver = _bempplib.createDefaultIterativeSolver(op)
        solver.initializeSolver(_bempplib.defaultGmresParameterList(self._gmres_tol), prec)
        
            # Solve the equation
            
        solution = solver.solve(rhs)
        print solution.solverMessage()
        
        # Extract the solution components in the form of grid functions
        
        extDirichletTrace = solution.gridFunction(0)
        extNeumannTrace = solution.gridFunction(1)
        

        if self._operator_cache: self._boundary_operator_cache.insert(wave_number,(op,prec))
        
        scatt_dirichlet_ext_fun = extDirichletTrace - self._inc_dirichlet_traces[wave_number]
        print "Dirichlet Error "+str(scatt_dirichlet_ext_fun.L2Norm()/extDirichletTrace.L2Norm())
        scatt_neumann_ext_fun = extNeumannTrace - self._inc_neumann_traces[wave_number]
        print "Neumann Error "+str(scatt_neumann_ext_fun.L2Norm()/extNeumannTrace.L2Norm())                
        


        return [extDirichletTrace.coefficients(),extNeumannTrace.coefficients()]
def generate_local_block_operator(context, my_proc, process_map, layers,
                                  impedance):
    """Generate the local system matrix.
    """

    nproc = Epetra.PyComm().NumProc()
    total_time = 0

    scheduler = process_map.scheduler

    # Initialize structure of local system matrix

    nb = process_map.block_matrix_layout.shape[
        0]  # Block-dimension of global matrix
    structure = lib.createBlockedOperatorStructure(context)
    for i in range(nb):
        plc = layers[i]['spaces']['l']
        pwc = layers[i]['spaces']['c']
        null_op_00 = lib.createNullOperator(context, plc, pwc, plc)
        null_op_11 = lib.createNullOperator(context, pwc, plc, pwc)
        structure.setBlock(2 * i, 2 * i, null_op_00)
        structure.setBlock(2 * i + 1, 2 * i + 1, null_op_11)

    # Iterate through elements from scheduler and fill up local system matrix

    if not scheduler.has_key(my_proc + 1):
        A = lib.createBlockedBoundaryOperator(context, structure)
        return (A, total_time)

    for elem in scheduler[my_proc + 1]:
        if elem[0] == elem[1]:
            # Diagonal Block
            print "Generating block element [%(e0)i,%(e1)i] on process %(my_proc)i... " % {
                'e0': elem[0],
                'e1': elem[1],
                'my_proc': my_proc
            }

            tstart = time()
            block = diagonal_block(context, layers, elem[0], impedance)
            block.weakForm()
            copy_to_structure(elem[0], elem[1], block, structure)
            tend = time()
            print "Block element [%(e0)i,%(e1)i] on process %(my_proc)i generated in %(tval)f seconds" % {
                'e0': elem[0],
                'e1': elem[1],
                'my_proc': my_proc,
                'tval': tend - tstart
            }
            total_time += tend - tstart
        else:
            print "Generating block elements [%(e0)i,%(e1)i] and [%(e1)i,%(e0)i] on process %(my_proc)i... " % {
                'e0': elem[0],
                'e1': elem[1],
                'my_proc': my_proc
            }
            tstart = time()
            if layers[elem[0]]['sons'].count(elem[1]):
                # elem[1] is a son of elem[0]
                block1, block2 = off_diagonal_block_father_son(
                    context, layers, elem[0], elem[1])
            else:
                # elements must be on the same level
                block1, block2 = off_diagonal_block_same_layer(
                    context, layers, elem[0], elem[1])
            block1.weakForm()
            block2.weakForm()
            copy_to_structure(elem[0], elem[1], block1, structure)
            copy_to_structure(elem[1], elem[0], block2, structure)
            tend = time()
            print "Block elements [%(e0)i,%(e1)i] and [%(e1)i,%(e0)i] on process %(my_proc)i generated in %(tval)f seconds " % {
                'e0': elem[0],
                'e1': elem[1],
                'my_proc': my_proc,
                'tval': tend - tstart
            }
            total_time += tend - tstart

    A = lib.createBlockedBoundaryOperator(context, structure)
    return (A, total_time)
Esempio n. 17
0
    context, pconsts, pconsts, pconsts, kInt, "DLP_int")
dlpOpExt = lib.createHelmholtz3dDoubleLayerBoundaryOperator(
    context, pconsts, pconsts, pconsts, kExt, "DLP_ext")
idOp = lib.createIdentityOperator(
    context, pconsts, pconsts, pconsts, "Id")

# Create blocks of the operator on the lhs of the equation...

lhsOp00 =  0.5 * idOp - dlpOpExt
lhsOp01 =  slpOpExt
lhsOp10 =  0.5 * idOp + dlpOpInt
lhsOp11 = -rhoInt / rhoExt * slpOpInt

# ... and combine them into a blocked operator

lhsOp = lib.createBlockedBoundaryOperator(
    context, [[lhsOp00, lhsOp01], [lhsOp10, lhsOp11]])

# Create a grid function representing the Dirichlet trace of the incident wave

def uIncData(point):
    x, y, z = point
    r = np.sqrt(x**2 + y**2 + z**2)
    return np.exp(1j * kExt * x)

uInc = lib.createGridFunction(context, pconsts, pconsts, uIncData)

# Create a grid function representing the Neumann trace of the incident wave

def uIncDerivData(point, normal):
    x, y, z = point
    nx, ny, nz = normal
def off_diagonal_block_father_son(context, layers, father_id, son_id):
    """Off-diagonal interaction between two different layers. Returns a tuple of two operators.
    """

    plc_father = layers[father_id]['spaces']['l']
    pwc_father = layers[father_id]['spaces']['c']
    plc_son = layers[son_id]['spaces']['l']
    pwc_son = layers[son_id]['spaces']['c']

    kf = layers[father_id]['k']
    kappaf = layers[father_id]['kappa']

    if father_id == 0:
        null_00 = lib.createNullOperator(context,
                                         plc_son,
                                         pwc_father,
                                         plc_father,
                                         label="Null_00")
        null_01 = lib.createNullOperator(context,
                                         pwc_son,
                                         pwc_father,
                                         plc_father,
                                         label="Null_01")
        Kf = lib.createModifiedHelmholtz3dDoubleLayerBoundaryOperator(
            context,
            plc_son,
            plc_father,
            pwc_father,
            kf,
            label="Kf0_" + str(son_id))
        Sf = 1. / kappaf * lib.createModifiedHelmholtz3dSingleLayerBoundaryOperator(
            context,
            pwc_son,
            plc_father,
            pwc_father,
            kf,
            label="Sf0_" + str(son_id))

        op_father_son = lib.createBlockedBoundaryOperator(
            context, [[null_00, null_01], [Kf, -Sf]])

        Ds = kappaf * lib.createModifiedHelmholtz3dHypersingularBoundaryOperator(
            context,
            plc_father,
            pwc_son,
            plc_son,
            kf,
            label="Ds" + str(son_id) + "_0")
        Ts = lib.adjoint(Kf, pwc_son)
        Ks = lib.createModifiedHelmholtz3dDoubleLayerBoundaryOperator(
            context,
            plc_father,
            plc_son,
            pwc_son,
            kf,
            label="Ks" + str(son_id) + "_0")
        Ss = lib.adjoint(Sf, plc_son)

        op_son_father = lib.createBlockedBoundaryOperator(
            context, [[Ds, Ts], [-Ks, Ss]])

    else:
        Df = kappaf * lib.createModifiedHelmholtz3dHypersingularBoundaryOperator(
            context, plc_son, pwc_father, plc_father, kf)
        Tf = lib.createModifiedHelmholtz3dAdjointDoubleLayerBoundaryOperator(
            context, pwc_son, pwc_father, plc_father, kf)
        Kf = lib.createModifiedHelmholtz3dDoubleLayerBoundaryOperator(
            context, plc_son, plc_father, pwc_father, kf)
        Sf = 1. / kappaf * lib.createModifiedHelmholtz3dDoubleLayerBoundaryOperator(
            context, pwc_son, plc_father, pwc_father, kf)

        op_father_son = lib.createBlockedBoundaryOperator(
            context, [[Df, Tf], [-Kf, Sf]])

        Ds = lib.adjoint(Df, pwc_son)
        Ts = lib.adjoint(Kf, pwc_son)
        Ks = lib.adjoint(Tf, plc_son)
        Ss = lib.adjoint(Sf, plc_son)

        op_son_father = lib.createBlockedBoundaryOperator(
            context, [[Ds, Ts], [-Ks, Ss]])

    return (op_father_son, op_son_father)
Esempio n. 19
0
structure.setBlock(0, 1, lhs_k12)
structure.setBlock(0, 2, lhs_k13)
structure.setBlock(1, 0, lhs_k21)
structure.setBlock(1, 1, lhs_k22)
structure.setBlock(1, 2, lhs_k23)
structure.setBlock(2, 1, lhs_k32)
structure.setBlock(2, 2, lhs_k33)
structure.setBlock(2, 3, lhs_k34)
structure.setBlock(2, 4, lhs_k35)
structure.setBlock(3, 1, lhs_k42)
structure.setBlock(3, 2, lhs_k43)
structure.setBlock(3, 3, lhs_k44)
structure.setBlock(3, 4, lhs_k45)
structure.setBlock(4, 3, lhs_k54)
structure.setBlock(4, 4, lhs_k55)
blockedOp = blib.createBlockedBoundaryOperator(context, structure)

rhs1 = scale * slp11
rhs2 = scale * slp21

boundaryData1 = rhs1 * blib.createGridFunction(context, sphere1_plc,
                                               sphere1_plc, evalBoundaryData)
boundaryData2 = rhs2 * blib.createGridFunction(context, sphere1_plc,
                                               sphere1_plc, evalBoundaryData)
boundaryData3 = blib.createGridFunction(context, sphere2_plc, sphere2_plc,
                                        evalNullData)
boundaryData4 = blib.createGridFunction(context, sphere3_plc, sphere3_plc,
                                        evalNullData)
boundaryData5 = blib.createGridFunction(context, sphere3_plc, sphere3_plc,
                                        evalNullData)