void DUAL_ELLIPTIC_SOLVER::solve2d(double *soln) { int index,index_nb[4],size; double k_nb[4]; double rhs,coeff[4]; int I,I_nb[4]; int i,j,ii,jj,l,icoords[MAXD]; COMPONENT comp; double aII; int num_nb; GRID_DIRECTION dir[4] = {WEST,EAST,SOUTH,NORTH}; boolean use_neumann_solver = YES; PetscInt num_iter = 0; double rel_residual = 0.0; HYPER_SURF *hs; double crx_coords[MAXD]; int status; POINTER intfc_state; int icrds_max[MAXD],icrds_min[MAXD]; if (debugging("trace")) (void) printf("Entering DUAL_ELLIPTIC_SOLVER::solve2d()\n"); PETSc solver; solver.Create(ilower, iupper-1, 5, 5); solver.Reset_A(); solver.Reset_b(); solver.Reset_x(); size = iupper - ilower; max_soln = -HUGE; min_soln = HUGE; for (j = cjmin; j <= cjmax; j++) for (i = cimin; i <= cimax; i++) { index = d_index2d(i,j,ctop_gmax); comp = ctop_comp[index]; I = ij_to_I[i][j]; if (I == -1) continue; I_nb[0] = ij_to_I[i-1][j]; I_nb[1] = ij_to_I[i+1][j]; I_nb[2] = ij_to_I[i][j-1]; I_nb[3] = ij_to_I[i][j+1]; icoords[0] = i; icoords[1] = j; get_dual_D(icoords,k_nb); num_nb = 0; for (l = 0; l < 4; ++l) { status = (*findStateAtCrossing)(front,icoords,dir[l],comp, &intfc_state,&hs,crx_coords); if (status != CONST_V_PDE_BOUNDARY) num_nb++; coeff[l] = k_nb[l]/(top_h[l/2]*top_h[l/2]); } rhs = source[index]; aII = 0.0; for (l = 0; l < 4; ++l) { if (num_nb == 0) break; status = (*findStateAtCrossing)(front,icoords,dir[l],comp, &intfc_state,&hs,crx_coords); if (status == CONST_P_PDE_BOUNDARY) { rhs += -coeff[l]*getStateVar(intfc_state); aII += -coeff[l]; use_neumann_solver = NO; } else { if (I_nb[l] == -1) /*CONST_V_PDE_BOUNDARY*/ continue; else /*NO_PDE_BOUNDARY*/ { solver.Set_A(I,I_nb[l],coeff[l]); aII += -coeff[l]; } } } /* * This change reflects the need to treat point with only one * interior neighbor (a convex point). Not sure why PETSc cannot * handle such case. If we have better understanding, this should * be changed back. */ if(num_nb > 0) { solver.Set_A(I,I,aII); } else { (void) printf("WARNING: isolated value!\n"); solver.Set_A(I,I,1.0); rhs = soln[index]; } solver.Set_b(I,rhs); } use_neumann_solver = pp_min_status(use_neumann_solver); solver.SetMaxIter(40000); solver.SetTol(1e-10); start_clock("Petsc Solver"); if (use_neumann_solver) { (void) printf("\nUsing Neumann Solver!\n"); if (size < 6) { (void) printf("Isolated small region for solve2d()\n"); stop_clock("Petsc Solver"); } solver.Solve_withPureNeumann(); solver.GetNumIterations(&num_iter); solver.GetFinalRelativeResidualNorm(&rel_residual); if(rel_residual > 1) { (void) printf("\n The solution diverges! The residual " "is %g. Solve again using GMRES!\n",rel_residual); solver.Reset_x(); solver.Solve_withPureNeumann_GMRES(); solver.GetNumIterations(&num_iter); solver.GetFinalRelativeResidualNorm(&rel_residual); } } else { (void) printf("\nUsing non-Neumann Solver!\n"); solver.Solve(); solver.GetNumIterations(&num_iter); solver.GetFinalRelativeResidualNorm(&rel_residual); if(rel_residual > 1) { (void) printf("\n The solution diverges! The residual " "is %g. Solve again using GMRES!\n",rel_residual); solver.Reset_x(); solver.Solve_GMRES(); solver.GetNumIterations(&num_iter); solver.GetFinalRelativeResidualNorm(&rel_residual); } } stop_clock("Petsc Solver"); double *x; FT_VectorMemoryAlloc((POINTER*)&x,size,sizeof(double)); solver.Get_x(x); if (debugging("PETSc")) (void) printf("In poisson_solver(): " "num_iter = %d, rel_residual = %g \n", num_iter, rel_residual); for (j = cjmin; j <= cjmax; j++) for (i = cimin; i <= cimax; i++) { index = d_index2d(i,j,ctop_gmax); I = ij_to_I[i][j]; if (I == -1) continue; else soln[index] = x[I-ilower]; if (max_soln < soln[index]) { icrds_max[0] = i; icrds_max[1] = j; max_soln = soln[index]; } if (min_soln > soln[index]) { icrds_min[0] = i; icrds_min[1] = j; min_soln = soln[index]; } } FT_ParallelExchCompGridArrayBuffer(soln,front,NULL); pp_global_max(&max_soln,1); pp_global_min(&min_soln,1); if (debugging("step_size")) { (void) printf("Max solution = %20.14f occuring at: %d %d\n", max_soln,icrds_max[0],icrds_max[1]); checkSolver(icrds_max,YES); (void) printf("Min solution = %20.14f occuring at: %d %d\n", min_soln,icrds_min[0],icrds_min[1]); checkSolver(icrds_min,YES); } if (debugging("elliptic_error")) { double error,max_error = 0.0; for (j = cjmin; j <= cjmax; j++) for (i = cimin; i <= cimax; i++) { icoords[0] = i; icoords[1] = j; if (ij_to_I[i][j] == -1) continue; error = checkSolver(icoords,NO); if (error > max_error) { max_error = error; icrds_max[0] = i; icrds_max[1] = j; } } (void) printf("In dual elliptic solver:\n"); (void) printf("Max relative elliptic error: %20.14f\n",max_error); (void) printf("Occuring at (%d %d)\n",icrds_max[0],icrds_max[1]); error = checkSolver(icrds_max,YES); } FT_FreeThese(1,x); if (debugging("trace")) (void) printf("Leaving DUAL_ELLIPTIC_SOLVER::solve2d()\n"); } /* end solve2d */
LOCAL void collect_cell_ptst( INTRP_CELL *blk_cell, int *icoords, COMPONENT comp, Front *front, float *grid_array, float (*get_state)(Locstate)) { INTERFACE *grid_intfc = front->grid_intfc; Table *T = table_of_interface(grid_intfc); RECT_GRID *gr = &topological_grid(grid_intfc); int dim = gr->dim; int *gmax = gr->gmax; float *L = gr->L; float *h = gr->h; COMPONENT *gr_comp = T->components; static COMPONENT cell_comp1d[2]; static COMPONENT cell_comp2d[2][2]; static COMPONENT cell_comp3d[2][2][2]; int i,j,k,index,nv,nc; CRXING *crx,*crxs[MAX_NUM_CRX]; GRID_DIRECTION dir; int ic[MAXD]; bool fr_crx_grid_seg; float state_at_crx; float crx_coords[MAXD]; blk_cell->is_bilinear = YES; blk_cell->dim = dim; nv = 0; switch (dim) { case 1: for (i = 0; i < 2; ++i) { ic[0] = icoords[0] + i; index = d_index1d(ic[0],gmax); cell_comp1d[i] = gr_comp[index]; if (gr_comp[index] == comp) { blk_cell->coords[nv][0] = L[0] + ic[0]*h[0]; blk_cell->var[nv] = grid_array[index]; nv++; } else blk_cell->is_bilinear = NO; } break; case 2: for (i = 0; i < 2; ++i) for (j = 0; j < 2; ++j) { ic[0] = icoords[0] + i; ic[1] = icoords[1] + j; index = d_index2d(ic[0],ic[1],gmax); cell_comp2d[i][j] = gr_comp[index]; if (gr_comp[index] == comp) { blk_cell->coords[nv][0] = L[0] + ic[0]*h[0]; blk_cell->coords[nv][1] = L[1] + ic[1]*h[1]; blk_cell->var[nv] = grid_array[index]; nv++; } else blk_cell->is_bilinear = NO; } break; case 3: for (i = 0; i < 2; ++i) for (j = 0; j < 2; ++j) for (k = 0; k < 2; ++k) { ic[0] = icoords[0] + i; ic[1] = icoords[1] + j; ic[2] = icoords[2] + k; index = d_index3d(ic[0],ic[1],ic[2],gmax); cell_comp3d[i][j][k] = gr_comp[index]; if (gr_comp[index] == comp) { blk_cell->coords[nv][0] = L[0] + ic[0]*h[0]; blk_cell->coords[nv][1] = L[1] + ic[1]*h[1]; blk_cell->coords[nv][2] = L[2] + ic[2]*h[2]; blk_cell->var[nv] = grid_array[index]; nv++; } else blk_cell->is_bilinear = NO; } break; } if (blk_cell->is_bilinear == YES) { blk_cell->nv = nv; return; } switch (dim) { case 1: for (i = 0; i < 2; ++i) { ic[0] = icoords[0] + i; if (cell_comp1d[i] == comp) { if (cell_comp1d[(i+1)%2] != comp) { dir = (i < (i+1)%2) ? EAST : WEST; fr_crx_grid_seg = FrontStateAtGridCrossing(front,ic,dir, comp,get_state,&state_at_crx,crx_coords); if (!fr_crx_grid_seg) { screen("ERROR: no crxing between (%d) and (%d)\n", icoords[0]+i,icoords[0]+(i+1)%2); } blk_cell->var[nv] = state_at_crx; blk_cell->coords[nv][0] = crx_coords[0]; nv++; } } } break; case 2: for (i = 0; i < 2; ++i) for (j = 0; j < 2; ++j) { ic[0] = icoords[0] + i; ic[1] = icoords[1] + j; if (cell_comp2d[i][j] == comp) { if (cell_comp2d[(i+1)%2][j] != comp) { dir = (i < (i+1)%2) ? EAST : WEST; fr_crx_grid_seg = FrontStateAtGridCrossing(front,ic,dir, comp,get_state,&state_at_crx,crx_coords); if (!fr_crx_grid_seg) { screen("ERROR: no crxing between (%d %d) " "and (%d %d)\n",icoords[0]+i,icoords[1]+j, icoords[0]+(i+1)%2,icoords[1]+j); } blk_cell->var[nv] = state_at_crx; blk_cell->coords[nv][0] = crx_coords[0]; blk_cell->coords[nv][1] = crx_coords[1]; nv++; } if (cell_comp2d[i][(j+1)%2] != comp) { dir = (j < (j+1)%2) ? NORTH : SOUTH; fr_crx_grid_seg = FrontStateAtGridCrossing(front,ic,dir, comp,get_state,&state_at_crx,crx_coords); if (!fr_crx_grid_seg) { screen("ERROR: no crxing between (%d %d) " "and (%d %d)\n",icoords[0]+i,icoords[1]+j, icoords[0]+i,icoords[1]+(j+1)%2); } blk_cell->var[nv] = state_at_crx; blk_cell->coords[nv][0] = crx_coords[0]; blk_cell->coords[nv][1] = crx_coords[1]; nv++; } } } break; case 3: for (i = 0; i < 2; ++i) for (j = 0; j < 2; ++j) for (k = 0; k < 2; ++k) { ic[0] = icoords[0] + i; ic[1] = icoords[1] + j; ic[2] = icoords[2] + k; if (cell_comp3d[i][j][k] == comp) { if (cell_comp3d[(i+1)%2][j][k] != comp) { dir = (i < (i+1)%2) ? EAST : WEST; fr_crx_grid_seg = FrontStateAtGridCrossing(front,ic,dir, comp,get_state,&state_at_crx,crx_coords); if (!fr_crx_grid_seg) { screen("ERROR: no crxing between (%d %d %d) " "and (%d %d %d)\n",icoords[0]+i,icoords[1]+j, icoords[2]+k,icoords[0]+(i+1)%2,icoords[1]+j, icoords[2]+k); } blk_cell->var[nv] = state_at_crx; blk_cell->coords[nv][0] = crx_coords[0]; blk_cell->coords[nv][1] = crx_coords[1]; blk_cell->coords[nv][2] = crx_coords[2]; nv++; } if (cell_comp3d[i][(j+1)%2][k] != comp) { dir = (j < (j+1)%2) ? NORTH : SOUTH; fr_crx_grid_seg = FrontStateAtGridCrossing(front,ic,dir, comp,get_state,&state_at_crx,crx_coords); if (!fr_crx_grid_seg) { screen("ERROR: no crxing between (%d %d %d) " "and (%d %d %d)\n",icoords[0]+i,icoords[1]+j, icoords[2]+k,icoords[0]+i,icoords[1]+(j+1)%2, icoords[2]+k); } blk_cell->var[nv] = state_at_crx; blk_cell->coords[nv][0] = crx_coords[0]; blk_cell->coords[nv][1] = crx_coords[1]; blk_cell->coords[nv][2] = crx_coords[2]; nv++; } if (cell_comp3d[i][j][(k+1)%2] != comp) { dir = (k < (k+1)%2) ? UPPER : LOWER; fr_crx_grid_seg = FrontStateAtGridCrossing(front,ic,dir, comp,get_state,&state_at_crx,crx_coords); if (!fr_crx_grid_seg) { screen("ERROR: no crxing between (%d %d %d) " "and (%d %d %d)\n",icoords[0]+i,icoords[1]+j, icoords[2]+k,icoords[0]+i,icoords[1]+j, icoords[2]+(k+1)%2); } blk_cell->var[nv] = state_at_crx; blk_cell->coords[nv][0] = crx_coords[0]; blk_cell->coords[nv][1] = crx_coords[1]; blk_cell->coords[nv][2] = crx_coords[2]; nv++; } } } break; } blk_cell->nv = nv; } /* end collect_cell_ptst */