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)
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
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)
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)
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)
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)