void solve_with_f90(PArray<MultiFab>& rhs, PArray<MultiFab>& phi, Array< PArray<MultiFab> >& grad_phi_edge, const Array<Geometry>& geom, int base_level, int finest_level, Real tol, Real abs_tol) { int nlevs = finest_level - base_level + 1; int mg_bc[2*BL_SPACEDIM]; // This tells the solver that we are using periodic bc's if (Geometry::isAllPeriodic()) { for (int dir = 0; dir < BL_SPACEDIM; ++dir) { mg_bc[2*dir + 0] = 0; mg_bc[2*dir + 1] = 0; } } else { BoxLib::Abort("non periodic boundraies not supported here"); } // Have to do some packing because these arrays does not always start with base_level PArray<Geometry> geom_p(nlevs); PArray<MultiFab> rhs_p(nlevs); PArray<MultiFab> phi_p(nlevs); for (int ilev = 0; ilev < nlevs; ++ilev) { geom_p.set(ilev, &geom[ilev+base_level]); rhs_p.set (ilev, &rhs[ilev+base_level]); phi_p.set (ilev, &phi[ilev+base_level]); } // Refinement ratio is hardwired to 2 here. IntVect crse_ratio = (base_level == 0) ? IntVect::TheZeroVector() : IntVect::TheUnitVector() * 2; FMultiGrid fmg(geom_p, base_level, crse_ratio); if (base_level == 0) { fmg.set_bc(mg_bc, phi[base_level]); } else { fmg.set_bc(mg_bc, phi[base_level-1], phi[base_level]); } fmg.set_const_gravity_coeffs(); int always_use_bnorm = 0; int need_grad_phi = 1; fmg.set_verbose(1); fmg.solve(phi_p, rhs_p, tol, abs_tol, always_use_bnorm, need_grad_phi); for (int ilev = 0; ilev < nlevs; ++ilev) { int amr_level = ilev + base_level; fmg.get_fluxes(grad_phi_edge[amr_level], ilev); } }
void solve_with_F90(MultiFab& soln, MultiFab& gphi, Real a, Real b, MultiFab& alpha, PArray<MultiFab>& beta, MultiFab& rhs, const BoxArray& bs, const Geometry& geom) { BL_PROFILE("solve_with_F90()"); FMultiGrid fmg(geom); int mg_bc[2*BL_SPACEDIM]; if (bc_type == Periodic) { // Define the type of boundary conditions to be periodic for ( int n = 0; n < BL_SPACEDIM; ++n ) { mg_bc[2*n + 0] = MGT_BC_PER; mg_bc[2*n + 1] = MGT_BC_PER; } } else if (bc_type == Neumann) { // Define the type of boundary conditions to be Neumann for ( int n = 0; n < BL_SPACEDIM; ++n ) { mg_bc[2*n + 0] = MGT_BC_NEU; mg_bc[2*n + 1] = MGT_BC_NEU; } } else if (bc_type == Dirichlet) { // Define the type of boundary conditions to be Dirichlet for ( int n = 0; n < BL_SPACEDIM; ++n ) { mg_bc[2*n + 0] = MGT_BC_DIR; mg_bc[2*n + 1] = MGT_BC_DIR; } } fmg.set_bc(mg_bc); fmg.set_maxorder(maxorder); fmg.set_scalars(a, b); fmg.set_coefficients(alpha, beta); int always_use_bnorm = 0; int need_grad_phi = 1; fmg.solve(soln, rhs, tolerance_rel, tolerance_abs, always_use_bnorm, need_grad_phi); PArray<MultiFab> grad_phi(BL_SPACEDIM, PArrayManage); for (int n = 0; n < BL_SPACEDIM; ++n) grad_phi.set(n, new MultiFab(BoxArray(soln.boxArray()).surroundingNodes(n), 1, 0)); fmg.get_fluxes(grad_phi); // Average edge-centered gradients to cell centers. BoxLib::average_face_to_cellcenter(gphi, grad_phi, geom); }
void Diffusion::applyop (int level, MultiFab& Temperature, MultiFab& CrseTemp, MultiFab& DiffTerm, PArray<MultiFab>& temp_cond_coef) { if (verbose && ParallelDescriptor::IOProcessor()) { std::cout << " " << '\n'; std::cout << "... compute diffusive term at level " << level << '\n'; } PArray<MultiFab> coeffs_curv; #if (BL_SPACEDIM < 3) // NOTE: we just pass DiffTerm here to use in the MFIter loop... if (Geometry::IsRZ() || Geometry::IsSPHERICAL()) { coeffs_curv.resize(BL_SPACEDIM, PArrayManage); for (int i = 0; i< BL_SPACEDIM; ++i) { coeffs_curv.set(i, new MultiFab(temp_cond_coef[i].boxArray(), 1, 0, Fab_allocate)); MultiFab::Copy(coeffs_curv[i], temp_cond_coef[i], 0, 0, 1, 0); } applyMetricTerms(0, DiffTerm, coeffs_curv); } #endif PArray<MultiFab> & coeffs = (coeffs_curv.size() > 0) ? coeffs_curv : temp_cond_coef; IntVect crse_ratio = level > 0 ? parent->refRatio(level-1) : IntVect::TheZeroVector(); FMultiGrid fmg(parent->Geom(level), level, crse_ratio); if (level == 0) { fmg.set_bc(mg_bc, Temperature); } else { fmg.set_bc(mg_bc, CrseTemp, Temperature); } fmg.set_diffusion_coeffs(coeffs); fmg.applyop(Temperature, DiffTerm); #if (BL_SPACEDIM < 3) // Do this to unweight Res if (Geometry::IsSPHERICAL() || Geometry::IsRZ() ) unweight_cc(level, DiffTerm); #endif }
void fmg_mexFunction(int nlhs, mxArray *plhs[], int nrhs, const mxArray *prhs[]) { const int *dm; int cyc=1, nit=1, rtype=2; double *A, *b, *x, *scratch; static double param[] = {1.0, 1.0, 1.0, 1.0, 0.0}; if (nrhs!=3 || nlhs>1) mexErrMsgTxt("Incorrect usage"); if (!mxIsNumeric(prhs[0]) || mxIsComplex(prhs[0]) || mxIsSparse(prhs[0]) || !mxIsDouble(prhs[0])) mexErrMsgTxt("Data must be numeric, real, full and double"); if (mxGetNumberOfDimensions(prhs[0])!=3) mexErrMsgTxt("Wrong number of dimensions."); if (!mxIsNumeric(prhs[1]) || mxIsComplex(prhs[1]) || mxIsSparse(prhs[1]) || !mxIsDouble(prhs[1])) mexErrMsgTxt("Data must be numeric, real, full and double"); if (mxGetNumberOfDimensions(prhs[1])!=3) mexErrMsgTxt("Wrong number of dimensions."); dm = mxGetDimensions(prhs[1]); if (mxGetDimensions(prhs[0])[0] != dm[0]) mexErrMsgTxt("Incompatible 1st dimension."); if (mxGetDimensions(prhs[0])[1] != dm[1]) mexErrMsgTxt("Incompatible 2nd dimension."); if (mxGetDimensions(prhs[0])[2] != dm[2]) mexErrMsgTxt("Incompatible 3rd dimension."); if (!mxIsNumeric(prhs[2]) || mxIsComplex(prhs[2]) || mxIsSparse(prhs[2]) || !mxIsDouble(prhs[2])) mexErrMsgTxt("Data must be numeric, real, full and double"); if (mxGetNumberOfElements(prhs[2]) != 4) mexErrMsgTxt("Third argument should contain rtype, lambda, ncycles and relax-its."); rtype = (int)(mxGetPr(prhs[2])[0]); param[3] = mxGetPr(prhs[2])[1]; cyc = (int)(mxGetPr(prhs[2])[2]); nit = (int)(mxGetPr(prhs[2])[3]); plhs[0] = mxCreateNumericArray(3,dm, mxDOUBLE_CLASS, mxREAL); A = (double *)mxGetPr(prhs[0]); b = (double *)mxGetPr(prhs[1]); x = (double *)mxGetPr(plhs[0]); scratch = (double *)mxCalloc(fmg_scratchsize((int *)dm),sizeof(double)); fmg((int *)dm, A, b, rtype, param, cyc, nit, x, scratch); mxFree((void *)scratch); }
void Diffusion::applyViscOp (int level, MultiFab& Vel, MultiFab& CrseVel, MultiFab& ViscTerm, PArray<MultiFab>& visc_coeff) { if (verbose && ParallelDescriptor::IOProcessor()) { std::cout << " " << '\n'; std::cout << "... compute second part of viscous term at level " << level << '\n'; } IntVect crse_ratio = level > 0 ? parent->refRatio(level-1) : IntVect::TheZeroVector(); FMultiGrid fmg(parent->Geom(level), level, crse_ratio); if (level == 0) { fmg.set_bc(mg_bc, Vel); } else { fmg.set_bc(mg_bc, CrseVel, Vel); } // Here we DO NOT multiply the coefficients by (1/r^2) for spherical coefficients // because we are computing (1/r^2) d/dr (const * d/dr(r^2 u)) fmg.set_diffusion_coeffs(visc_coeff); #if (BL_SPACEDIM < 3) // Here we weight the Vel going into the FMG applyop if (Geometry::IsSPHERICAL() || Geometry::IsRZ() ) weight_cc(level, Vel); #endif fmg.applyop(Vel, ViscTerm); #if (BL_SPACEDIM < 3) // Do this to unweight Res if (Geometry::IsSPHERICAL() || Geometry::IsRZ() ) unweight_cc(level, ViscTerm); #endif }
static void fmg_mexFunction(int nlhs, mxArray *plhs[], int nrhs, const mxArray *prhs[]) { int nd, i; int dm[4]; int cyc=1, nit=1, rtype=0; float *A, *b, *x, *scratch; static double param[6] = {1.0, 1.0, 1.0, 1.0, 0.0, 0.0}; double scal[256]; if ((nrhs!=3 && nrhs!=4) || nlhs>1) mexErrMsgTxt("Incorrect usage"); if (!mxIsNumeric(prhs[0]) || mxIsComplex(prhs[0]) || mxIsSparse(prhs[0]) || !mxIsSingle(prhs[0])) mexErrMsgTxt("Data must be numeric, real, full and single"); if (!mxIsNumeric(prhs[1]) || mxIsComplex(prhs[1]) || mxIsSparse(prhs[1]) || !mxIsSingle(prhs[1])) mexErrMsgTxt("Data must be numeric, real, full and single"); nd = mxGetNumberOfDimensions(prhs[1]); if (nd>4) mexErrMsgTxt("Wrong number of dimensions."); for(i=0; i<nd; i++) dm[i] = mxGetDimensions(prhs[1])[i]; for(i=nd; i<4; i++) dm[i] = 1; nd = mxGetNumberOfDimensions(prhs[0]); if (nd>4) mexErrMsgTxt("Wrong number of dimensions."); if ((nd==4) && (mxGetDimensions(prhs[0])[3] != (dm[3]*(dm[3]+1))/2)) mexErrMsgTxt("Incompatible 4th dimension (must be (n*(n+1))/2)."); if (nd>3) nd=3; for(i=0; i<nd; i++) if (mxGetDimensions(prhs[0])[i] != dm[i]) mexErrMsgTxt("Incompatible dimensions."); for(i=nd; i<3; i++) if (dm[i] != 1) mexErrMsgTxt("Incompatible dimensions."); if (!mxIsNumeric(prhs[2]) || mxIsComplex(prhs[2]) || mxIsSparse(prhs[2]) || !mxIsDouble(prhs[2])) mexErrMsgTxt("Data must be numeric, real, full and double"); if (mxGetNumberOfElements(prhs[2]) != 9) mexErrMsgTxt("Third argument should contain rtype, vox1, vox2, vox3, param1, param2, param3, ncycles and relax-its."); rtype = (int)(mxGetPr(prhs[2])[0]); param[0] = 1/mxGetPr(prhs[2])[1]; param[1] = 1/mxGetPr(prhs[2])[2]; param[2] = 1/mxGetPr(prhs[2])[3]; param[3] = mxGetPr(prhs[2])[4]; param[4] = mxGetPr(prhs[2])[5]; param[5] = mxGetPr(prhs[2])[6]; cyc = mxGetPr(prhs[2])[7]; nit = (int)(mxGetPr(prhs[2])[8]); if (nrhs==4) { double *s; if (!mxIsNumeric(prhs[3]) || mxIsComplex(prhs[3]) || mxIsSparse(prhs[3]) || !mxIsDouble(prhs[3])) mexErrMsgTxt("Data must be numeric, real, full and double"); if (mxGetNumberOfElements(prhs[3]) != dm[3]) mexErrMsgTxt("Incompatible number of scales."); s = (double *)mxGetPr(prhs[3]); for(i=0; i< dm[3]; i++) scal[i] = s[i]; } else { for(i=0; i<dm[3]; i++) scal[i] = 1.0; } plhs[0] = mxCreateNumericArray(4,(unsigned int *)dm, mxSINGLE_CLASS, mxREAL); A = (float *)mxGetPr(prhs[0]); b = (float *)mxGetPr(prhs[1]); x = (float *)mxGetPr(plhs[0]); scratch = (float *)mxCalloc(fmg_scratchsize((int *)dm),sizeof(float)); fmg((int *)dm, A, b, rtype, param, scal, cyc, nit, x, scratch); mxFree((void *)scratch); }