def makeDowndate(I_up, normalize=True, verb=0): timer = Timer('AMG downdate formation') Debug.msg3(verb, 'Forming downdate operator') I_down = I_up.transpose(copy=True).tolil() if normalize: for r in range(I_down.shape[0]): row = I_down.getrowview(r) nrm = row.sum() row /= nrm Debug.msg3(verb, 'Done forming downdate operator') return I_down.tocsr()
def smoothUpdate(A, C, verb=0): ''' Create an update operator from a coarse mesh to a fine mesh, based on a matrix A and a set of coarse-mesh nodes C ''' tab0 = Tab() timer = Timer('AMG update formation') Debug.msg3(verb, tab0, 'forming update operator') Debug.msg3(verb, tab0, 'C=', C) if not sp.isspmatrix_csr(A): raise ValueError('makeUpdate() expected a CSR matrix as input') M = A.shape[0] if A.shape[1] != A.shape[0]: raise ValueError('Non-square matrix in makeUpdate(): size is %d by %d' % (A.shape[0], A.shape[1])) c_to_f, f_to_c = makeIndexMaps(C) Debug.msg3(verb, tab0, 'f2c map is ', f_to_c) I_up = sp.dok_matrix((M,len(C))) ip = A.indptr allVals = A.data allCols = A.indices tab1 = Tab() tab2 = Tab() tab3 = Tab() tab4 = Tab() tab5 = Tab() # Main loop over rows for i in range(M): Debug.msg3(verb, tab0, 'row %d' % i) # If the current index is in the coarse mesh, take its value directly # from the fine mesh if i in C: I_up[i, f_to_c[i]] = 1.0 Debug.msg3(verb, tab1, 'coarse-coarse connection, entry is 1') continue Debug.msg3(verb, tab1, 'interpolating value for fine row ', i) # Get arrays of column indices and values for this row cols_i = allCols[ip[i] : ip[i+1]] vals_i = allVals[ip[i] : ip[i+1]] # Find diagonal diag = vals_i[np.where(cols_i==i)] Debug.msg3(verb, tab1, 'diagonal is %g' % diag) # Diagonal must be nonzero! if diag == 0.0: raise ValueError('zero diagonal detected in row %d' % i) # build interpolation matrix for j, a_ij in zip(cols_i, vals_i): if j==i: continue if j not in C: continue Debug.msg3(verb, tab2, 'contrib from coarse node f=%d, c=%d' % (j, f_to_c[j])) w_ij = a_ij Debug.msg3(verb, tab2, 'direct connection: (%d,%d)=%g' % (i,j,w_ij)) Debug.msg3(verb, tab2, 'finding indirect contributions') Debug.msg3(verb, tab2, 'looking at neighbors ', cols_i) for m, a_im in zip(cols_i, vals_i): if m==i: # <--- I forgot this on first pass! continue if m not in C: # Approximate values on F by averaging Debug.msg3(verb, tab3, 'approximating fine node m=%d' % m) cols_m = allCols[ip[m] : ip[m+1]] vals_m = allVals[ip[m] : ip[m+1]] denom = 0.0 num = 0.0 Debug.msg3(verb, tab3, 'neighbors of m=%d are ' % m, cols_m) count = 0 for k,a_mk in zip(cols_m, vals_m): if k in C and k in cols_i: Debug.msg3(verb, tab4, 'indirect contribution from coarse node k=', k) denom += a_mk count += 1 if k==j: num = a_im * a_mk Debug.msg3(verb, tab4, 'numerator=%g, denominator=%g' % (num,denom)) if count>0: if denom==0.0: raise ValueError('zero denominator detected in (%d,%d)' %(i,j)) Debug.msg3(verb, tab3, 'indirect connection through fine node %d: %g' % (m,num/denom)) w_ij += num/denom else: # No need to approximate coarse node values Debug.msg3(verb, tab3, 'no need to approximate value at coarse node m=', m) continue Debug.msg3(verb, tab2, '(%d,%d), val=%g' %(i,j,w_ij)) I_up[i, f_to_c[j]] = -w_ij/diag # end second pass through row i # end loop over rows Debug.msg3(verb, tab0, 'done forming update operator') return I_up.tocsr()