static void do_test(MAP *rmap, MAP *cmap) { MAT *A; VEC *x, *y; INT i, j, m0, n0; INT *cols = phgAlloc(cmap->nglobal * sizeof(*cols)); FLOAT *data = phgAlloc(cmap->nglobal * sizeof(*data)); A = phgMapCreateMat(rmap, cmap); m0 = A->rmap->partition[A->rmap->rank]; n0 = A->cmap->partition[A->cmap->rank]; /* Matrix entries: A(I,J) = 1 + (I-1) + (J-1) */ for (i = m0; i < m0 + A->rmap->nlocal; i++) { #if 0 /* Test MatAddEntry */ for (j = 0; j < A->cmap->nglobal; j++) phgMatAddGlobalEntry(A, i, j, 1.0 + i + j); #else /* Test MatAddEntries */ for (j = 0; j < A->cmap->nglobal; j++) { cols[j] = j; data[j] = 1.0 + i + j; } phgMatAddGlobalEntries(A, 1, &i, A->cmap->nglobal, cols, data); #endif } phgFree(cols); phgFree(data); phgMatAssemble(A); phgInfo(-1, "y = A * x\n"); x = phgMapCreateVec(A->cmap, 1); for (i = 0; i < x->map->nlocal; i++) x->data[i] = 1.0 + i + n0; phgVecAssemble(x); y = phgMatVec(MAT_OP_N, 1.0, A, x, 0.0, NULL); for (i = 0; i < y->map->nlocal; i++) phgInfo(-1, " y->data[%d] = %lg\n", i + m0, (double)y->data[i]); phgVecDestroy(&x); phgVecDestroy(&y); phgInfo(-1, "y = A' * x\n"); x = phgMapCreateVec(A->rmap, 1); for (i = 0; i < x->map->nlocal; i++) x->data[i] = 1.0 + i + m0; phgVecAssemble(x); y = phgMatVec(MAT_OP_T, 1.0, A, x, 0.0, NULL); for (i = 0; i < y->map->nlocal; i++) phgInfo(-1, " y->data[%d] = %lg\n", i + n0, (double)y->data[i]); phgVecDestroy(&x); phgVecDestroy(&y); phgMatDestroy(&A); }
/* * Jacobi smoother2: * Implement using details of matvec * ref: matvec in matvec.c * * */ void mg_Jacobi2(MAT *A, VEC *x, VEC *b, int nsmooth, void *ctx) { INT i, j, k, n, *pc, *pc_offp; FLOAT *pd, *pd_offp, *vx, *vx0, *vb; FLOAT sum, omega = _p->smooth_damp;; VEC *x0; #if USE_MPI FLOAT *offp_data = NULL; #endif /* USE_MPI */ MagicCheck(VEC, x); MagicCheck(VEC, b); assert(x == NULL || x->nvec == 1); assert(b == NULL || b->nvec == 1); if (x != NULL && !x->assembled) phgVecAssemble(x); if (b != NULL && !b->assembled) phgVecAssemble(b); x0 = phgMapCreateVec(x->map, 1); assert(A->type != PHG_DESTROYED); if (!A->assembled) phgMatAssemble(A); assert(A->type != PHG_MATRIX_FREE); phgMatPack(A); #if USE_MPI if (A->cmap->nprocs > 1) { offp_data = phgAlloc(A->cinfo->rsize * sizeof(*offp_data)); } #endif /* USE_MPI */ if (A->cmap->nlocal != A->rmap->nlocal || A->cmap->nlocal != x->map->nlocal || A->cmap->nlocal != b->map->nlocal) phgError(1, "%s:%d: inconsistent matrix-vector.", __FILE__, __LINE__); #if USE_MPI if (A->cmap->nprocs > 1) { phgMapScatterBegin(A->cinfo, x->nvec, x->data, offp_data); phgMapScatterEnd(A->cinfo, x->nvec, x->data, offp_data); } #endif /* USE_MPI */ /* iteration */ for (k = 0; k < nsmooth; k++) { phgVecCopy(x, &x0); /* multiply with local data */ vx = x->data; vx0 = x0->data; vb = b->data; pc = A->packed_cols; pd = A->packed_data; if (A->cmap->nprocs > 1) { pc_offp = A->packed_cols + A->rmap->nlocal + A->nnz_d; pd_offp = A->packed_data + A->nnz_d; } else { pc_offp = NULL; pd_offp = NULL; } for (i = 0; i < A->rmap->nlocal; i++) { INT jcol; FLOAT aa = 0., dx; /* x_i = (b_i - \sum_{j ~= i} a_ij * x_j) / a_ii */ sum = vb[i]; /* local data */ if ((n = *(pc++)) != 0) { for (j = 0; j < n; j++) { jcol = *(pc++); if (jcol != i) { sum -= *(pd++) * vx0[jcol]; } else { aa = *(pd++); assert(fabs(aa) > 1e-14); } } } /* remote data */ if (pc_offp != NULL && (n = *(pc_offp++)) != 0) { for (j = 0; j < n; j++) { jcol = *(pc_offp++); sum -= *(pd_offp++) * offp_data[jcol]; } } dx = sum / aa - vx[i]; vx[i] += omega * dx; } #if USE_MPI if (A->cmap->nprocs > 1) { phgMapScatterBegin(A->cinfo, x->nvec, x->data, offp_data); phgMapScatterEnd(A->cinfo, x->nvec, x->data, offp_data); } #endif /* USE_MPI */ } phgVecDestroy(&x0); #if USE_MPI phgFree(offp_data); #endif /* USE_MPI */ return; }
/* * Gauss-Sidel smoother for vector: * * As GS: * 1. exchange off proc data * 2. smooth local dof * * Assumption: * 1. unknow dof is vector of dim 3 * 2. Matrix block for vector is * | a1 -b 0 | * | b a2 0 | * | 0 0 a3 | * * */ void mg_GaussSidel_vec(MAT *A, VEC *x, VEC *b, int nsmooth, void *ctx) { INT i, j, k, l, n, *pc, *pc0, *pc_offp, nlocal; FLOAT *pd, *pd0, *pd_offp, *vx, *vb; size_t *ps; FLOAT sum[Dim], omega = _p->smooth_damp; #if USE_MPI FLOAT *offp_data = NULL; #endif /* USE_MPI */ MagicCheck(VEC, x); MagicCheck(VEC, b); assert(x == NULL || x->nvec == 1); assert(b == NULL || b->nvec == 1); if (x != NULL && !x->assembled) phgVecAssemble(x); if (b != NULL && !b->assembled) phgVecAssemble(b); assert(A->type != PHG_DESTROYED); if (!A->assembled) phgMatAssemble(A); assert(A->type != PHG_MATRIX_FREE); phgMatPack(A); #if USE_MPI if (A->cmap->nprocs > 1) { offp_data = phgAlloc(A->cinfo->rsize * sizeof(*offp_data)); } #endif /* USE_MPI */ if (A->cmap->nlocal != A->rmap->nlocal || A->cmap->nlocal != x->map->nlocal || A->cmap->nlocal != b->map->nlocal) phgError(1, "%s:%d: inconsistent matrix-vector.", __FILE__, __LINE__); if (A->cmap->nlocal % Dim != 0) phgError(1, "%s: assume vector dof of dim 3!\n", __FUNCTION__); #if USE_MPI if (A->cmap->nprocs > 1) { phgMapScatterBegin(A->cinfo, x->nvec, x->data, offp_data); phgMapScatterEnd(A->cinfo, x->nvec, x->data, offp_data); } #endif /* USE_MPI */ /* iteration */ for (l = 0; l < nsmooth; l++) { INT i_start, i_add; /* multiply with local data */ vx = x->data; vb = b->data; pc0 = A->packed_cols; pd0 = A->packed_data; ps = A->packed_ind; nlocal = A->rmap->nlocal; /* * lexicographic order: low to high * Note: low->high and high->low alternatively does not help. * */ if (TRUE || l % 2 == 0) { i_start = 0; i_add = Dim; } else { i_start = nlocal - Dim; i_add = -Dim; } //for (i = i_start; i < A->rmap->nlocal && i >= 0; i += i_add) { for (i = 0; i < nlocal ; i += Dim) { INT jcol; FLOAT aa[Dim][Dim], det, dx[Dim]; memset(aa, 0, sizeof(aa)); sum[0] = vb[i ]; sum[1] = vb[i+1]; sum[2] = vb[i+2]; /* local data */ pc = pc0 + PACK_COL(ps, i); pd = pd0 + PACK_DAT(ps, i); for (k = 0; k < Dim; k++) { if ((n = *(pc++)) != 0) { for (j = 0; j < n; j++) { jcol = *(pc++); if (jcol < i || jcol > i+2) { sum[k] -= *(pd++) * vx[jcol]; } else { /* offD, jcol = i,i+1,i+2 */ aa[k][jcol - i] = *(pd++); } } } } /* remote data */ if (A->cmap->nprocs > 1) { pc_offp = pc0 + PACK_COL_OFFP(ps, i, nlocal); pd_offp = pd0 + PACK_DAT_OFFP(ps, i, nlocal); for (k = 0; k < Dim; k++) { if ((n = *(pc_offp++)) != 0) { for (j = 0; j < n; j++) { jcol = *(pc_offp++); sum[k] -= *(pd_offp++) * offp_data[jcol]; } } } } /* solve */ det = (aa[0][0] * aa[1][1] - aa[0][1] * aa[1][0]); assert(Fabs(det) > 1e-12); det = 1. / det; dx[0] = (aa[1][1] * sum[0] - aa[0][1] * sum[1]) * det - vx[i ]; dx[1] = (aa[0][0] * sum[1] - aa[1][0] * sum[1]) * det - vx[i+1]; dx[2] = (1./aa[2][2] * sum[2]) - vx[i+2]; vx[i ] += omega * dx[0]; vx[i+1] += omega * dx[1]; vx[i+2] += omega * dx[2]; } #if USE_MPI if (A->cmap->nprocs > 1) { phgMapScatterBegin(A->cinfo, x->nvec, x->data, offp_data); phgMapScatterEnd(A->cinfo, x->nvec, x->data, offp_data); } #endif /* USE_MPI */ } #if USE_MPI phgFree(offp_data); #endif /* USE_MPI */ return; }
/* * Gauss-Sidel smoother2: * * 1. interior dof (!REMOTE) is smoothed, and then offp data is updated; * 2. proc boundary dof (REMOTE) is smoothed, and then offp data is updated. * * Note: need types_vec. * */ void mg_GaussSidel2(MAT *A, VEC *x, VEC *b, int nsmooth, void *ctx) { MG_LEVEL *ml = (MG_LEVEL *)ctx; INT i, j, k, n, *pc, *pc_offp; FLOAT *pd, *pd_offp, *vx, *vb; FLOAT sum, omega = _p->smooth_damp;; #if USE_MPI FLOAT *offp_data = NULL; #endif /* USE_MPI */ MagicCheck(VEC, x); MagicCheck(VEC, b); assert(x == NULL || x->nvec == 1); assert(b == NULL || b->nvec == 1); if (x != NULL && !x->assembled) phgVecAssemble(x); if (b != NULL && !b->assembled) phgVecAssemble(b); assert(A->type != PHG_DESTROYED); if (!A->assembled) phgMatAssemble(A); assert(A->type != PHG_MATRIX_FREE); phgMatPack(A); #if USE_MPI if (A->cmap->nprocs > 1) { offp_data = phgAlloc(A->cinfo->rsize * sizeof(*offp_data)); } #endif /* USE_MPI */ if (A->cmap->nlocal != A->rmap->nlocal || A->cmap->nlocal != x->map->nlocal || A->cmap->nlocal != b->map->nlocal) phgError(1, "%s:%d: inconsistent matrix-vector.", __FILE__, __LINE__); #if USE_MPI if (A->cmap->nprocs > 1) { phgMapScatterBegin(A->cinfo, x->nvec, x->data, offp_data); phgMapScatterEnd(A->cinfo, x->nvec, x->data, offp_data); } #endif /* USE_MPI */ /* iteration */ for (k = 0; k < nsmooth; k++) { /* multiply with local data */ vx = x->data; vb = b->data; /* First, interior dof (!REMOTE) is smoothed, and then offp data is updated */ pc = A->packed_cols; pd = A->packed_data; if (A->cmap->nprocs > 1) { pc_offp = A->packed_cols + A->rmap->nlocal + A->nnz_d; pd_offp = A->packed_data + A->nnz_d; } else { pc_offp = NULL; pd_offp = NULL; } for (i = 0; i < A->rmap->nlocal; i++) { INT jcol; FLOAT aa = 0., dx; if (ml->types_vec[i] & REMOTE) { if ((n = *(pc++)) != 0) { pc += n; pd += n; } if (pc_offp != NULL && (n = *(pc_offp++)) != 0) { pc_offp += n; pd_offp += n; } continue; } sum = vb[i]; /* local data */ if ((n = *(pc++)) != 0) { for (j = 0; j < n; j++) { jcol = *(pc++); if (jcol != i) { sum -= *(pd++) * vx[jcol]; } else { aa = *(pd++); assert(fabs(aa) > 1e-14); } } } /* remote data */ if (pc_offp != NULL && (n = *(pc_offp++)) != 0) { for (j = 0; j < n; j++) { jcol = *(pc_offp++); sum -= *(pd_offp++) * offp_data[jcol]; } } dx = sum / aa - vx[i]; vx[i] += omega * dx; } #if USE_MPI if (A->cmap->nprocs > 1) { phgMapScatterBegin(A->cinfo, x->nvec, x->data, offp_data); phgMapScatterEnd(A->cinfo, x->nvec, x->data, offp_data); } #endif /* USE_MPI */ /* Second, proc boundary dof (!REMOTE) is smoothed, and then offp data is updated */ pc = A->packed_cols; pd = A->packed_data; if (A->cmap->nprocs > 1) { pc_offp = A->packed_cols + A->rmap->nlocal + A->nnz_d; pd_offp = A->packed_data + A->nnz_d; } else { pc_offp = NULL; pd_offp = NULL; } for (i = 0; i < A->rmap->nlocal; i++) { INT jcol; FLOAT aa = 0., dx; if (!(ml->types_vec[i] & REMOTE)) { if ((n = *(pc++)) != 0) { pc += n; pd += n; } if (pc_offp != NULL && (n = *(pc_offp++)) != 0) { pc_offp += n; pd_offp += n; } continue; } sum = vb[i]; /* local data */ if ((n = *(pc++)) != 0) { for (j = 0; j < n; j++) { jcol = *(pc++); if (jcol != i) { sum -= *(pd++) * vx[jcol]; } else { aa = *(pd++); assert(fabs(aa) > 1e-14); } } } /* remote data */ if (pc_offp != NULL && (n = *(pc_offp++)) != 0) { for (j = 0; j < n; j++) { jcol = *(pc_offp++); sum -= *(pd_offp++) * offp_data[jcol]; } } dx = sum / aa - vx[i]; vx[i] += omega * dx; } #if USE_MPI if (A->cmap->nprocs > 1) { phgMapScatterBegin(A->cinfo, x->nvec, x->data, offp_data); phgMapScatterEnd(A->cinfo, x->nvec, x->data, offp_data); } #endif /* USE_MPI */ } #if USE_MPI phgFree(offp_data); #endif /* USE_MPI */ return; }
static void build_matrices(MAT *matA, MAT *matM, MAT *matC, MAT *S, FLOAT s, DOF *u_h, DOF *p_h) /* S is used to store s*diag(M(p_h))^(-1) */ { int N = u_h->type->nbas; /* number of basis functions in an element */ int M = p_h->type->nbas; int i, j; GRID *g = u_h->g; ELEMENT *e; FLOAT A[N][N], B[N][N], C[N][M]; INT I[N], Ip[M]; INT k, n0; VEC *V = phgMapCreateVec(S->rmap, 1); phgVecDisassemble(V); /* for phgVecAddEntry */ ForAllElements(g, e) { for (i = 0; i < N; i++) { I[i] = phgMapE2L(matA->rmap, 0, e, i); for (k = 0; k < M; k++) { /* \int \grad\psi_k\cdot\phi_i */ C[i][k] = phgQuadGradBasDotBas(e, p_h, k, u_h, i, QUAD_DEFAULT); } for (j = 0; j <= i; j++) { /* \int \phi_i\cdot\phi_j */ B[j][i] = B[i][j] = phgQuadBasDotBas(e, u_h, j, u_h, i, QUAD_DEFAULT); /* \int \curl\phi_i\cdot\curl\phi_j */ A[j][i] = A[i][j] = phgQuadCurlBasDotCurlBas(e, u_h, j, u_h, i, QUAD_DEFAULT); } } for (i = 0; i < M; i++) { Ip[i] = phgMapE2L(matC->cmap, 0, e, i); if (Ip[i] < 0) /* boundary entry */ continue; phgVecAddEntry(V, 0, Ip[i], phgQuadBasDotBas(e, p_h, i, p_h, i, QUAD_DEFAULT)); } /* loop on basis functions */ for (i = 0; i < N; i++) { if (phgDofDirichletBC(u_h, e, i, NULL, NULL, NULL, DOF_PROJ_CROSS)) continue; phgMatAddEntries(matA, 1, I + i, N, I, A[i]); phgMatAddEntries(matM, 1, I + i, N, I, B[i]); phgMatAddEntries(matC, 1, I + i, M, Ip, C[i]); } } phgVecAssemble(V); n0 = V->map->partition[V->map->rank]; for (k = 0; k < V->map->nlocal; k++) phgMatAddGlobalEntry(S, k + n0, k + n0, s / V->data[k]); phgVecDestroy(&V); phgMatAssemble(S); phgMatSetupDiagonal(S); phgMatAssemble(matA); phgMatAssemble(matM); phgMatAssemble(matC); }