void iceInit(GRID *g, LAYERED_MESH **gL_ptr) { // SIMPLEX *e; LAYERED_MESH *gL; //GEO_INFO *geo = (GEO_INFO *) phgCalloc(1, sizeof(*geo)); // read data //data_bed = read_txt_data(ns_params->bed_txt_file); //data_sur = read_txt_data_1D(ns_params->sur_txt_file); //data_thk = read_txt_data_1D(ns_params->thk_txt_file); //data_bot = read_txt_data_1D(ns_params->bot_txt_file); data_sur = read_txt_data(ns_params->sur_txt_file); data_thk = read_txt_data(ns_params->thk_txt_file); data_bot = read_txt_data(ns_params->bot_txt_file); data_x = read_txt_data(ns_params->x_txt_file); data_y = read_txt_data(ns_params->y_txt_file); data_vx = read_txt_data(ns_params->vx_txt_file); data_vy = read_txt_data(ns_params->vy_txt_file); ice_grid(g); //free(data_bed[0]); //free(data_bed); //free(data_sur[0]); //free(data_sur); //free(data_thk[0]); //free(data_thk); //free(data_sur_grad_x[0]); //free(data_sur_grad_x); //free(data_sur_grad_y[0]); //free(data_sur_grad_y); checkBdry(g); /* build layered mesh */ gL = import_layered_mesh(ns_params->tria_file, ns_params->layer_file, ns_params->nodeZ_file, NULL, phgNProcs); build_layered_mesh(g, gL); //phgExportVTK(g, "TEST1.vtk", NULL); part_layered_mesh(g, gL); /* Partition saved in e->mark. */ destory_layerd_mesh(&gL); phgPartUserSetFunc(iceParter); if (phgBalanceGrid(g, 1.1, -1, NULL, 0.)) { phgPrintf("\nRepartition mesh, %d submesh%s, load imbalance: %lg", g->nprocs, g->nprocs > 1 ? "es" : "", (double)g->lif); elapsed_time(g, TRUE, phgPerfGetMflops(g, NULL, NULL)); } if (0) { phgExportVTK(g, "parted.vtk", NULL); } gL = import_layered_mesh(ns_params->tria_file, ns_params->layer_file, ns_params->nodeZ_file, NULL, phgNProcs); build_layered_mesh(g, gL); if (0) { phgExportTecplot(g, "parted.plt", NULL); phgExportVTK(g, OUTPUT_DIR "/ins_" NS_PROBLEM "_init.vtk", NULL); } int ii; for (ii = 0; ii < gL->nvert; ii++) { gL->verts[ii][0] *= 1000; gL->verts[ii][1] *= 1000; //gL->verts[ii][2] *= 1000; } TRIA *t = gL->trias; for (ii = 0; ii < gL->ntria; ii++, t++) { t->area *= 1000*1000; } *gL_ptr = gL; //return geo; return; }
int main(int argc, char *argv[]) { GRID *g; DOF *u_h; MAT *A, *A0, *B; MAP *map; INT i; size_t nnz, mem, mem_peak; VEC *x, *y0, *y1, *y2; double t0, t1, dnz, dnz1, mflops, mop; char *fn = "../test/cube.dat"; FLOAT mem_max = 300; INT refine = 0; phgOptionsRegisterFilename("-mesh_file", "Mesh file", (char **)&fn); phgOptionsRegisterInt("-loop_count", "Loop count", &loop_count); phgOptionsRegisterInt("-refine", "Refinement level", &refine); phgOptionsRegisterFloat("-mem_max", "Maximum memory", &mem_max); phgInit(&argc, &argv); g = phgNewGrid(-1); if (!phgImport(g, fn, FALSE)) phgError(1, "can't read file \"%s\".\n", fn); phgRefineAllElements(g, refine); u_h = phgDofNew(g, DOF_DEFAULT, 1, "u_h", DofNoAction); while (TRUE) { phgPrintf("\n"); if (phgBalanceGrid(g, 1.2, 1, NULL, 0.)) phgPrintf("Repartition mesh, %d submeshes, load imbalance: %lg\n", g->nprocs, (double)g->lif); map = phgMapCreate(u_h, NULL); A = phgMapCreateMat(map, map); A->handle_bdry_eqns = TRUE; build_matrix(A, u_h); phgMatAssemble(A); /* Note: A is unsymmetric (A' != A) if boundary entries not removed */ phgMatRemoveBoundaryEntries(A); #if 0 /* test block matrix operation */ A0 = phgMatCreateBlockMatrix(g->comm, 1, 1, &A, NULL); #else A0 = A; #endif phgPrintf("%d DOF, %d elems, %d submeshes, matrix size: %d, LIF: %lg\n", DofGetDataCountGlobal(u_h), g->nleaf_global, g->nprocs, A->rmap->nglobal, (double)g->lif); /* test PHG mat-vec multiply */ x = phgMapCreateVec(A->cmap, 1); y1 = phgMapCreateVec(A->rmap, 1); phgVecRandomize(x, 123); phgMatVec(MAT_OP_N, 1.0, A0, x, 0.0, &y1); phgPerfGetMflops(g, NULL, NULL); /* reset flops counter */ t0 = phgGetTime(NULL); for (i = 0; i < loop_count; i++) { phgMatVec(MAT_OP_N, 1.0, A0, x, 0.0, &y1); } t1 = phgGetTime(NULL); mflops = phgPerfGetMflops(g, NULL, NULL); y0 = phgVecCopy(y1, NULL); nnz = A->nnz_d + A->nnz_o; #if USE_MPI dnz1 = nnz; MPI_Reduce(&dnz1, &dnz, 1, MPI_DOUBLE, MPI_SUM, 0, g->comm); #else dnz = nnz; #endif mop = loop_count * (dnz + dnz - A->rmap->nlocal) * 1e-6; phgPrintf("\n"); t1 -= t0; phgPrintf(" PHG: time %0.4lf, nnz %0.16lg, %0.2lfMF (%0.2lfMF)\n", t1, dnz, mop / (t1 == 0 ? 1. : t1), mflops); /* test trans(A)*x */ phgPerfGetMflops(g, NULL, NULL); /* reset flops counter */ t0 = phgGetTime(NULL); for (i = 0; i < loop_count; i++) { phgMatVec(MAT_OP_T, 1.0, A0, x, 0.0, &y1); } t1 = phgGetTime(NULL); mflops = phgPerfGetMflops(g, NULL, NULL); t1 -= t0; phgPrintf(" A'*x: time %0.4lf, nnz %0.16lg, %0.2lfMF (%0.2lfMF), " "err: %le\n", t1, dnz, mop / (t1 == 0 ? 1. : t1), mflops, (double)phgVecNorm2(phgVecAXPBY(-1.0, y0, 1.0, &y1), 0, NULL)); /* time A * trans(A) */ phgPerfGetMflops(g, NULL, NULL); /* reset flops counter */ t0 = phgGetTime(NULL); B = phgMatMat(MAT_OP_N, MAT_OP_N, 1.0, A, A, 0.0, NULL); t1 = phgGetTime(NULL); mflops = phgPerfGetMflops(g, NULL, NULL); nnz = B->nnz_d + B->nnz_o; #if USE_MPI dnz1 = nnz; MPI_Reduce(&dnz1, &dnz, 1, MPI_DOUBLE, MPI_SUM, 0, g->comm); #else dnz = nnz; #endif /* compare B*x <--> A*A*x */ y2 = phgMatVec(MAT_OP_N, 1.0, B, x, 0.0, NULL); phgMatVec(MAT_OP_N, 1.0, A0, y0, 0.0, &y1); phgMatDestroy(&B); t1 -= t0; phgPrintf(" A*A: time %0.4lf, nnz %0.16lg, %0.2lfMF, err: %le\n", t1, dnz, mflops, (double)phgVecNorm2(phgVecAXPBY(-1.0, y1, 1.0, &y2), 0, NULL)); #if USE_PETSC { Mat ma, mb; MatInfo info; Vec va, vb, vc; PetscScalar *vec; ma = phgPetscCreateMatAIJ(A); MatGetVecs(ma, PETSC_NULL, &va); VecDuplicate(va, &vb); VecGetArray(va, &vec); memcpy(vec, x->data, x->map->nlocal * sizeof(*vec)); VecRestoreArray(va, &vec); MatMult(ma, va, vb); phgPerfGetMflops(g, NULL, NULL); /* reset flops counter */ t0 = phgGetTime(NULL); for (i = 0; i < loop_count; i++) { MatMult(ma, va, vb); } t1 = phgGetTime(NULL); mflops = phgPerfGetMflops(g, NULL, NULL); VecGetArray(vb, &vec); memcpy(y1->data, vec, x->map->nlocal * sizeof(*vec)); VecRestoreArray(vb, &vec); MatGetInfo(ma, MAT_GLOBAL_SUM, &info); /*phgPrintf(" --------------------------------------------" "-------------------------\n");*/ phgPrintf("\n"); t1 -= t0; dnz = info.nz_used; phgPrintf(" PETSc: time %0.4lf, nnz %0.16lg, %0.2lfMF (%0.2lfMF), " "err: %le\n", t1, dnz, mop / (t1==0 ? 1.:t1), mflops, (double)phgVecNorm2(phgVecAXPBY(-1.0, y0, 1.0, &y1), 0, NULL)); phgPerfGetMflops(g, NULL, NULL); /* reset flops counter */ t0 = phgGetTime(NULL); for (i = 0; i < loop_count; i++) { MatMultTranspose(ma, va, vb); } t1 = phgGetTime(NULL); mflops = phgPerfGetMflops(g, NULL, NULL); VecGetArray(vb, &vec); memcpy(y1->data, vec, x->map->nlocal * sizeof(*vec)); VecRestoreArray(vb, &vec); t1 -= t0; phgPrintf(" A'*x: time %0.4lf, nnz %0.16lg, %0.2lfMF (%0.2lfMF), " "err: %le\n", t1, dnz, mop / (t1==0 ? 1.:t1), mflops, (double)phgVecNorm2(phgVecAXPBY(-1.0, y0, 1.0, &y1), 0, NULL)); phgPerfGetMflops(g, NULL, NULL); /* reset flops counter */ t0 = phgGetTime(NULL); MatMatMult(ma, ma, MAT_INITIAL_MATRIX, PETSC_DEFAULT, &mb); t1 = phgGetTime(NULL); mflops = phgPerfGetMflops(g, NULL, NULL); t1 -= t0; MatGetInfo(mb, MAT_GLOBAL_SUM, &info); dnz = info.nz_used; VecDuplicate(va, &vc); /* compare B*x <--> A*A*x */ MatMult(ma, vb, vc); MatMult(mb, va, vb); VecGetArray(vb, &vec); memcpy(y1->data, vec, x->map->nlocal * sizeof(*vec)); VecRestoreArray(vb, &vec); VecGetArray(vc, &vec); memcpy(y2->data, vec, x->map->nlocal * sizeof(*vec)); VecRestoreArray(vc, &vec); phgPrintf(" A*A: time %0.4lf, nnz %0.16lg, %0.2lfMF, err: %le\n", t1, dnz, mflops, (double)phgVecNorm2(phgVecAXPBY(-1.0, y1, 1.0, &y2), 0, NULL)); phgPetscMatDestroy(&mb); phgPetscMatDestroy(&ma); phgPetscVecDestroy(&va); phgPetscVecDestroy(&vb); phgPetscVecDestroy(&vc); } #endif /* USE_PETSC */ #if USE_HYPRE { HYPRE_IJMatrix ma; HYPRE_IJVector va, vb, vc; HYPRE_ParCSRMatrix par_ma; hypre_ParCSRMatrix *par_mb; HYPRE_ParVector par_va, par_vb, par_vc; HYPRE_Int offset, *ni, start, end; assert(sizeof(INT)==sizeof(int) && sizeof(FLOAT)==sizeof(double)); setup_hypre_mat(A, &ma); ni = phgAlloc(2 * A->rmap->nlocal * sizeof(*ni)); offset = A->cmap->partition[A->cmap->rank]; for (i = 0; i < A->rmap->nlocal; i++) ni[i] = i + offset; HYPRE_IJVectorCreate(g->comm, offset, offset + A->rmap->nlocal - 1, &va); HYPRE_IJVectorCreate(g->comm, offset, offset + A->rmap->nlocal - 1, &vb); HYPRE_IJVectorCreate(g->comm, offset, offset + A->rmap->nlocal - 1, &vc); HYPRE_IJVectorSetObjectType(va, HYPRE_PARCSR); HYPRE_IJVectorSetObjectType(vb, HYPRE_PARCSR); HYPRE_IJVectorSetObjectType(vc, HYPRE_PARCSR); HYPRE_IJVectorSetMaxOffProcElmts(va, 0); HYPRE_IJVectorSetMaxOffProcElmts(vb, 0); HYPRE_IJVectorSetMaxOffProcElmts(vc, 0); HYPRE_IJVectorInitialize(va); HYPRE_IJVectorInitialize(vb); HYPRE_IJVectorInitialize(vc); HYPRE_IJMatrixGetObject(ma, (void **)(void *)&par_ma); HYPRE_IJVectorGetObject(va, (void **)(void *)&par_va); HYPRE_IJVectorGetObject(vb, (void **)(void *)&par_vb); HYPRE_IJVectorGetObject(vc, (void **)(void *)&par_vc); HYPRE_IJVectorSetValues(va, A->cmap->nlocal, ni, (double *)x->data); HYPRE_IJVectorAssemble(va); HYPRE_IJVectorAssemble(vb); HYPRE_IJVectorAssemble(vc); HYPRE_IJMatrixGetRowCounts(ma, A->cmap->nlocal, ni, ni + A->rmap->nlocal); for (i = 0, nnz = 0; i < A->rmap->nlocal; i++) nnz += ni[A->rmap->nlocal + i]; #if USE_MPI dnz1 = nnz; MPI_Reduce(&dnz1, &dnz, 1, MPI_DOUBLE, MPI_SUM, 0, g->comm); #else dnz = nnz; #endif HYPRE_ParCSRMatrixMatvec(1.0, par_ma, par_va, 0.0, par_vb); phgPerfGetMflops(g, NULL, NULL); /* reset flops counter */ t0 = phgGetTime(NULL); for (i = 0; i < loop_count; i++) { HYPRE_ParCSRMatrixMatvec(1.0, par_ma, par_va, 0.0, par_vb); } t1 = phgGetTime(NULL); mflops = phgPerfGetMflops(g, NULL, NULL); HYPRE_IJVectorGetValues(vb, A->rmap->nlocal, ni, (double*)y1->data); /*phgPrintf(" --------------------------------------------" "-------------------------\n");*/ phgPrintf("\n"); t1 -= t0; phgPrintf(" HYPRE: time %0.4lf, nnz %0.16lg, %0.2lfMF (%0.2lfMF), " "err: %le\n", t1, dnz, mop / (t1==0 ? 1.:t1), mflops, (double)phgVecNorm2(phgVecAXPBY(-1.0, y0, 1.0, &y1), 0, NULL)); phgPerfGetMflops(g, NULL, NULL); /* reset flops counter */ t0 = phgGetTime(NULL); for (i = 0; i < loop_count; i++) { HYPRE_ParCSRMatrixMatvecT(1.0, par_ma, par_va, 0.0, par_vb); } t1 = phgGetTime(NULL); mflops = phgPerfGetMflops(g, NULL, NULL); HYPRE_IJVectorGetValues(vb, A->rmap->nlocal, ni, (double*)y1->data); t1 -= t0; phgPrintf(" A'*x: time %0.4lf, nnz %0.16lg, %0.2lfMF (%0.2lfMF), " "err: %le\n", t1, dnz, mop / (t1==0 ? 1.:t1), mflops, (double)phgVecNorm2(phgVecAXPBY(-1.0, y0, 1.0, &y1), 0, NULL)); phgPerfGetMflops(g, NULL, NULL); /* reset flops counter */ t0 = phgGetTime(NULL); /* Note: 'HYPRE_ParCSRMatrix' is currently typedef'ed to * 'hypre_ParCSRMatrix *' */ par_mb = hypre_ParMatmul((hypre_ParCSRMatrix *)par_ma, (hypre_ParCSRMatrix *)par_ma); t1 = phgGetTime(NULL); mflops = phgPerfGetMflops(g, NULL, NULL); start = hypre_ParCSRMatrixFirstRowIndex(par_mb); end = hypre_ParCSRMatrixLastRowIndex(par_mb) + 1; for (i = start, nnz = 0; i < end; i++) { HYPRE_Int ncols; hypre_ParCSRMatrixGetRow(par_mb, i, &ncols, NULL, NULL); hypre_ParCSRMatrixRestoreRow(par_mb, i, &ncols, NULL, NULL); nnz += ncols; } #if USE_MPI dnz1 = nnz; MPI_Reduce(&dnz1, &dnz, 1, MPI_DOUBLE, MPI_SUM, 0, g->comm); #else dnz = nnz; #endif /* compare B*x <--> A*A*x */ HYPRE_ParCSRMatrixMatvec(1.0, par_ma, par_vb, 0.0, par_vc); HYPRE_ParCSRMatrixMatvec(1.0, (void *)par_mb, par_va, 0.0, par_vb); HYPRE_IJVectorGetValues(vb, A->rmap->nlocal, ni, (double*)y1->data); HYPRE_IJVectorGetValues(vc, A->rmap->nlocal, ni, (double*)y2->data); hypre_ParCSRMatrixDestroy((par_mb)); t1 -= t0; phgPrintf(" A*A: time %0.4lf, nnz %0.16lg, %0.2lfMF, err: %le\n", t1, dnz, mflops, (double)phgVecNorm2(phgVecAXPBY(-1.0, y1, 1.0, &y2), 0, NULL)); phgFree(ni); HYPRE_IJMatrixDestroy(ma); HYPRE_IJVectorDestroy(va); HYPRE_IJVectorDestroy(vb); HYPRE_IJVectorDestroy(vc); } #endif /* USE_HYPRE */ if (A0 != A) phgMatDestroy(&A0); #if 0 if (A->rmap->nglobal > 1000) { VEC *v = phgMapCreateVec(A->rmap, 3); for (i = 0; i < v->map->nlocal; i++) { v->data[i + 0 * v->map->nlocal] = 1 * (i + v->map->partition[g->rank]); v->data[i + 1 * v->map->nlocal] = 2 * (i + v->map->partition[g->rank]); v->data[i + 2 * v->map->nlocal] = 3 * (i + v->map->partition[g->rank]); } phgMatDumpMATLAB(A, "A", "A.m"); phgVecDumpMATLAB(v, "v", "v.m"); phgFinalize(); exit(0); } #endif phgMatDestroy(&A); phgVecDestroy(&x); phgVecDestroy(&y0); phgVecDestroy(&y1); phgVecDestroy(&y2); phgMapDestroy(&map); mem = phgMemoryUsage(g, &mem_peak); dnz = mem / (1024.0 * 1024.0); dnz1 = mem_peak / (1024.0 * 1024.0); /*phgPrintf(" --------------------------------------------" "-------------------------\n");*/ phgPrintf("\n"); phgPrintf(" Memory: current %0.4lgMB, peak %0.4lgMB\n", dnz, dnz1); #if 0 { static int loop_count = 0; if (++loop_count == 4) break; } #endif if (mem_peak > 1024 * (size_t)1024 * mem_max) break; phgRefineAllElements(g, 1); } phgDofFree(&u_h); phgFreeGrid(&g); phgFinalize(); return 0; }
int main(int argc, char *argv[]) { ELEMENT *e; GRID *g; DOF *u, *v, *u_hp, *v_hp; HP_TYPE *hp; MAP *map; char *fn = "cube.dat"; char *dof_u = "P2", *dof_v = "P1"; INT step = 0, pre_refines = 0; phgOptionsRegisterFilename("-mesh_file", "Mesh file", &fn); phgOptionsRegisterInt("-pre_refines", "Pre-refinements", &pre_refines); phgOptionsRegisterString("-dof_u", "DOF type for u", &dof_u); phgOptionsRegisterString("-dof_v", "DOF type for v", &dof_v); phgInit(&argc, &argv); g = phgNewGrid(-1); if (!phgImport(g, fn, FALSE)) phgError(1, "can't read file \"%s\".\n", fn); phgRefineAllElements(g, pre_refines); phgOptionsSetHandler("-dof_type", dof_u); u = phgDofNew(g, DOF_DEFAULT, 1, "u", DofInterpolation); phgOptionsSetHandler("-dof_type", dof_v); v = phgDofNew(g, DOF_DEFAULT, 1, "v", DofInterpolation); phgPrintf("u->type = %s, v->type = %s\n", u->type->name, v->type->name); hp = phgHPNew(g, HP_HB); u_hp = phgHPDofNew(g, hp, 1, "u_hp", DofInterpolation); phgHPFree(&hp); hp = phgHPNew(g, HP_HC); v_hp = phgHPDofNew(g, hp, 1, "v_hp", DofInterpolation); phgHPFree(&hp); while (TRUE) { if (phgBalanceGrid(g, 1.1, 1, NULL, 0.)) phgPrintf("Repartition mesh, %d submeshes, load imbalance: %lg\n", g->nprocs, (double)g->lif); phgPrintf("Testing map with non HP DOFs:\n"); map = phgMapCreate(u, v, NULL); phgPrintf(" nlocal = %d, nglobal = %d\n", map->nlocal, map->nglobal); phgMapDestroy(&map); phgPrintf("Testing map with HP DOFs:\n"); ForAllElements(g, e) e->hp_order = 1 + GlobalElement(g, e->index) % 4; phgHPSetup(u_hp->hp, FALSE); ForAllElements(g, e) e->hp_order = 1 + (3 - GlobalElement(g, e->index) % 4); phgHPSetup(v_hp->hp, FALSE); map = phgMapCreate(u_hp, v_hp, NULL); phgPrintf(" nlocal = %d, nglobal = %d\n", map->nlocal, map->nglobal); phgMapDestroy(&map); phgPrintf("Testing map with HP and non HP DOFs:\n"); map = phgMapCreate(u, u_hp, v, v_hp, NULL); phgPrintf(" nlocal = %d, nglobal = %d\n", map->nlocal, map->nglobal); phgMapDestroy(&map); if (++step >= 1) break; phgRefineAllElements(g, 1); } phgDofFree(&u_hp); phgDofFree(&v_hp); phgDofFree(&u); phgDofFree(&v); phgFreeGrid(&g); phgFinalize(); return 0; }
int main(int argc, char *argv[]) { GRID *g; DOF *u, *v, *w, *u0, *v0, *w0; SOLVER *solver; INT i, j; char *fn = "cube.dat"; phgVerbosity = 0; phgInit(&argc, &argv); /*phgPause(0);*/ g = phgNewGrid(-1); if (!phgImport(g, fn, FALSE)) phgError(1, "can't read file \"%s\".\n", fn); for (i = 0; i < 4; i++) phgRefineAllElements(g, 1); phgBalanceGrid(g, 1.0, 0, NULL, 0.); for (i = 0; i < 8; i++) { phgRefineRandomElements(g, "25%"); phgBalanceGrid(g, 1.2, -1, NULL, 0.); } phgCheckConformity(g); u = phgDofNew(g, DOF_P1, 1, "u", DofNoAction); v = phgDofNew(g, DOF_ND1, 1, "v", DofNoAction); w = phgDofNew(g, DOF_P1, 1, "w", DofNoAction); phgDofSetDataByValue(u, 0.0); phgDofSetDataByValue(v, 0.0); phgDofSetDataByValue(w, 0.0); u0 = phgDofNew(g, u->type, u->dim, "u0", DofNoAction); v0 = phgDofNew(g, v->type, v->dim, "v0", DofNoAction); w0 = phgDofNew(g, w->type, w->dim, "w0", DofNoAction); solver = phgSolverCreate(SOLVER_DEFAULT, u, v, w, NULL); for (i = 0; i < DofGetDataCount(u); i++) { j = phgSolverMapD2L(solver, 0, i); u0->data[i] = (FLOAT)(phgSolverMapL2G(solver, j) % 3); phgSolverAddMatrixEntry(solver, j, j, 1.0); phgSolverAddRHSEntry(solver, j, u0->data[i]); } for (i = 0; i < DofGetDataCount(v); i++) { j = phgSolverMapD2L(solver, 1, i); v0->data[i] = (FLOAT)(phgSolverMapL2G(solver, j) % 5); phgSolverAddMatrixEntry(solver, j, j, 1.0); phgSolverAddRHSEntry(solver, j, v0->data[i]); } for (i = 0; i < DofGetDataCount(w); i++) { j = phgSolverMapD2L(solver, 2, i); w0->data[i] = (FLOAT)(phgSolverMapL2G(solver, j) % 7); phgSolverAddMatrixEntry(solver, j, j, 1.0); phgSolverAddRHSEntry(solver, j, w0->data[i]); } phgSolverSolve(solver, TRUE, u, v, w, NULL); phgSolverDestroy(&solver); phgDofAXPY(-1.0, u0, &u); phgDofAXPY(-1.0, v0, &v); phgDofAXPY(-1.0, w0, &w); phgPrintf("Error: u = %lg, v = %lg, w = %lg\n", (double)phgDofNormInftyVec(u), (double)phgDofNormInftyVec(v), (double)phgDofNormInftyVec(w)); phgDofFree(&u); phgDofFree(&v); phgDofFree(&w); phgDofFree(&u0); phgDofFree(&v0); phgDofFree(&w0); phgFreeGrid(&g); phgFinalize(); return 0; }