def __init__(self, nx=100, ny=100, value_left=1., value_right=0., value_top=0., value_bottom=0., q=None): """ ::param nx:: Number of cells in the x direction. ::param ny:: Number of cells in the y direction. ::param value_left:: Boundary condition on the left face. ::param value_right:: Boundary condition on the right face. ::param value_top:: Boundary condition on the top face. ::param value_bottom:: Boundary condition on the bottom face. ::param q:: Source function. """ #set domain dimensions self.nx = nx self.ny = ny self.dx = 1. / nx self.dy = 1. / ny #define mesh self.mesh = fipy.Grid2D(nx=self.nx, ny=self.ny, dx=self.dx, dy=self.dy) #get the location of the middle of the domain #cellcenters=np.array(self.mesh.cellCenters).T #x=cellcenters[:, 0] #y=cellcenters[:, 1] x, y = self.mesh.cellCenters x_all = x[:self.nx] y_all = y[0:-1:self.ny] loc1 = x_all[(self.nx - 1) / 2] loc2 = y_all[(self.ny - 1) / 2] self.loc = np.intersect1d( np.where(x == loc1)[0], np.where(y == loc2)[0])[0] #get facecenters X, Y = self.mesh.faceCenters #define cell and face variables self.phi = fipy.CellVariable(name='$T(x)$', mesh=self.mesh, value=1.) self.C = fipy.CellVariable(name='$C(x)$', mesh=self.mesh, value=1.) self.source = fipy.CellVariable(name='$f(x)$', mesh=self.mesh, value=0.) #apply boundary conditions #dirichet self.phi.constrain(value_left, self.mesh.facesLeft) self.phi.constrain(value_right, self.mesh.facesRight) #homogeneous Neumann self.phi.faceGrad.constrain(value_top, self.mesh.facesTop) self.phi.faceGrad.constrain(value_bottom, self.mesh.facesBottom) #setup the diffusion problem self.eq = -fipy.DiffusionTerm(coeff=self.C) == self.source
def mesh_and_boundaries(params): """Generate a 2D grid appropriate for the parameters """ def fn(f, N): '''Root solving kernel for compression factor Determine f(N), such that $\Delta x \sum_{i=0}^N f^i = 2 \Delta x$ ''' return (1 - f**N) / (1 - f) - 2. N = 1 + params["compression"] compression = fsolve(fn, x0=[.5], args=(N))[0] dx = dy = params["cellSize"] Nx = int(params["Lx"] / dx) Ny = int(params["Ly"] / dx) dx_variable = [dx] * (Nx - 2) + [dx * compression**i for i in range(N)] dy_variable = [dy] * Ny mesh = fp.Grid2D(dx=dx_variable, dy=dy_variable) X, Y = mesh.faceCenters inlet = mesh.facesLeft outlet = mesh.facesRight walls = mesh.facesTop | mesh.facesBottom top_right = outlet & (Y > params["Ly"] - dy) return mesh, inlet, outlet, walls, top_right
def _eval(self, xs): """ Solves the advection equation for u and its derivatives for a given source location xs. """ xs = view_as_column(xs) assert xs.shape[0] == 2 nx = 50 ny = nx dx = 0.1 dy = dx mesh = fp.Grid2D(dx=dx, dy=dy, nx=nx, ny=ny) vx, vy = make_V_field(mesh) u = f(xs[:, 0], mesh, vx, vy) du1 = df(xs[:, 0], mesh, vx, vy, 1) du2 = df(xs[:, 0], mesh, vx, vy, 2) d2u11 = df2(xs[:, 0], mesh, vx, vy, 1, 1) d2u22 = df2(xs[:, 0], mesh, vx, vy, 1, 1) d2u12 = df2(xs[:, 0], mesh, vx, vy, 1, 2) dU = np.hstack([view_as_column(du1), view_as_column(du2)]) d2U = np.hstack([ view_as_column(d2u11), view_as_column(d2u12), view_as_column(d2u12), view_as_column(d2u22) ]) d2U = d2U.reshape((d2U.shape[0], 2, 2)) state = {} state['f'] = u #view_as_column(u) state['f_grad'] = dU state['f_grad_2'] = d2U return state
def main(): """ NAME 2DFPE.py PURPOSE Integrate time-dependent FPE EXECUTION python 2DFPE.py STARTED CS 24/09/2015 """ nx = 20 ny = nx dx = 1. dy = dx L = dx * nx mesh = fp.Grid2D(dx=dx, dy=dy, nx=nx, ny=ny) y = np.linspace(-ny * dy * 0.5, +ny * dy * 0.5, ny, endpoint=True)[:, np.newaxis] X, Y = mesh.faceCenters ## phi is pdf; psi is y*pdf for convenience phi = fp.CellVariable(mesh=mesh, value=1 / (dx * nx * dy * ny)) psi = fp.CellVariable(mesh=mesh, value=(y * phi.value.reshape((nx, ny))).flatten()) diffCoeff = 1. diffMatri = [[0., 0.], [0., diffCoeff]] convCoeff = np.array([-1., +1.]) eq = fp.TransientTerm(var=phi) == fp.DiffusionTerm( coeff=[diffMatri], var=phi) + 0 * fp.ExponentialConvectionTerm(coeff=convCoeff, var=psi) ##--------------------------------------------------------------------------------------------------------- ## BCs phi = BC_value_at_boundary(phi, mesh) ## Evolution timeStepDuration = 0.5 * min(dy**2 / (2. * diffCoeff), dy / (nx * dx)) steps = 10 for step in range(steps): print np.trapz(np.trapz(phi.value.reshape([nx, ny]), dx=dx), dx=dy) psi.value = (y * phi.value.reshape((nx, ny))).flatten() eq.solve(var=phi, dt=timeStepDuration) print phi.value[5] # plot_pdf(phi.value.reshape([nx,ny]),step+1) plt.contourf(phi.value.reshape([nx, ny]), extent=(-1, 1, -1, 1)) plt.colorbar() plt.title("Density at timestep " + str(steps)) plt.xlabel("$x$", fontsize=18) plt.ylabel("$\eta$", fontsize=18) plt.savefig("fig_FPE/Imp" + str(steps) + ".png") plt.show() return
def forward(xs): nx = 21 ny = nx dx = 1. / 51 dy = dx rho = 0.05 q0 = 1. / (np.pi * rho**2) T = 0.3 mesh = fp.Grid2D(dx=dx, dy=dy, nx=nx, ny=ny) time = fp.Variable() sourceTerm_1 = fp.CellVariable(name="Source term", mesh=mesh, value=0.) for i in range(sourceTerm_1().shape[0]): sourceTerm_1()[i] = q0 * np.exp(-( (mesh.cellCenters[0]()[i] - xs[0])**2 + (mesh.cellCenters[1]()[i] - xs[1])**2) / (2 * rho**2)) * (time() < T) # The equation eq = fp.TransientTerm() == fp.DiffusionTerm( coeff=1.) + sourceTerm_1 # + sourceTerm_2 # The solution variable phi = fp.CellVariable(name="Concentration", mesh=mesh, value=0.) #if __name__ == '__main__': # viewer = fp.Viewer(vars=phi, datamin=0., datamax=3.) # viewer.plot() x = np.arange(0, nx) / nx y = x data = [] dt = 0.005 steps = 60 for step in range(steps): time.setValue(time() + dt) eq.solve(var=phi, dt=dt) #if __name__ == '__main__': # viewer.plot() #if step == 14 or step == 29 or step == 44 or step == 59: # dl = phi()[0] # dr = phi()[nx-1] # ul = phi()[nx**2 - nx] # ur = phi()[nx**2 - 1] # print phi().shape # data = np.hstack([data, np.array([dl, dr, ul, ur])]) #if __name__ == '__main__': # raw_input("Transient diffusion with source term. Press <return> to proceed") return phi().reshape(nx, nx)
def _eval_u(self, xs): """ Solves only the diffusion equation for u for a given source location xs. """ xs = view_as_column(xs) assert xs.shape[0] == 2 nx = 25 ny = nx dx = 0.04 dy = dx mesh = fp.Grid2D(dx=dx, dy=dy, nx=nx, ny=ny) u = f(xs[:,0], mesh) return u
def initialise_mesh(self): if self.has_obstacles(): self.mesh = make_porous_mesh(self.rc, self.Rc, self.dx, self.L) elif self.dim == 1: self.mesh = fipy.Grid1D(Lx=self.L[0], dx=self.dx[0], origin=(-self.L[0] / 2.0, )) elif self.dim == 2: self.mesh = fipy.Grid2D(Lx=self.L[0], Ly=self.L[1], dx=self.dx[0], dy=self.dx[1], origin=((-self.L[0] / 2.0, ), (-self.L[1] / 2.0, )))
def get_mesh(params): """Create the mesh Args: params: the parameter dict Returns: the fipy mesh """ return pipe( fp.Grid2D(Lx=params["lx"], Ly=params["lx"], nx=params["nx"], ny=params["nx"]), lambda x: x - np.array( (params["lx"] / 2., params["lx"] / 2.))[:, None], )
def df2(xs, mesh, i, j): """ Evaluate the model for the 2nd derivatives at the four corners of the domain at times ``t``. It returns a flatten version of the system, i.e.: y_1(t_1) ... y_4(t_1) ... y_1(t_4) ... y_4(t_4) """ assert i == 1 or i == 2 assert j == 1 or j == 2 nx = 25 ny = nx dx = 0.04 dy = dx mesh = fp.Grid2D(dx=dx, dy=dy, nx=nx, ny=ny) time = fp.Variable() q0 = make_source_der_2(xs, mesh, time, i, j) D = 1. # Define the equation eq = fp.TransientTerm() == fp.DiffusionTerm(coeff=D) + q0 # Boundary conditions # The solution variable phi = fp.CellVariable(name="Concentraion", mesh=mesh, value=0.) # Solve dt = 0.005 steps = 60 d2U = [] for step in range(steps): eq.solve(var=phi, dt=dt) if step == 14 or step == 29 or step == 44 or step == 59: dl = phi()[0] #dr = phi()[24] ul = phi()[600] #ur = phi()[624] #d2U = np.hstack([d2U, np.array([dl, dr, ul, ur])]) d2U = np.hstack([d2U, np.array([dl, ul])]) return d2U
'''Root solving kernel for compression factor Determine f(N), such that $\Delta x \sum_{i=0}^N f^i = 2 \Delta x$ ''' return (1 - f**N) / (1 - f) - 2. N = 1 + args.compression compression = fsolve(fn, x0=[.5], args=(N))[0] Nx = int(Lx / dx) Ny = int(Ly / dy) dx_variable = [dx] * (Nx - 2) + [dx * compression**i for i in range(N+1)] dy_variable = [dy] * Ny mesh = fp.Grid2D(dx=dx_variable, dy=dy_variable) volumes = fp.CellVariable(mesh=mesh, value=mesh.cellVolumes) pressure = fp.CellVariable(mesh=mesh, name="$p$") pressureCorrection = fp.CellVariable(mesh=mesh, name="$p'$") xVelocity = fp.CellVariable(mesh=mesh, name="$u_x$") yVelocity = fp.CellVariable(mesh=mesh, name="$u_y$") velocity = fp.FaceVariable(mesh=mesh, name=r"$\vec{u}$", rank=1) xVelocityEq = fp.DiffusionTerm(coeff=viscosity) - pressure.grad.dot([1.,0.]) + density * gravity[0] yVelocityEq = fp.DiffusionTerm(coeff=viscosity) - pressure.grad.dot([0.,1.]) + density * gravity[1] ap = fp.CellVariable(mesh=mesh, value=1.) coeff = 1./ ap.arithmeticFaceValue*mesh._faceAreas * mesh._cellDistances pressureCorrectionEq = fp.DiffusionTerm(coeff=coeff) - velocity.divergence
os.makedirs(pathStr + 'ForwardEvo/') if (not os.path.exists(pathStr + 'ReverseEvoUnupdated/')): os.makedirs(pathStr + 'ReverseEvoUnupdated/') if (not os.path.exists(pathStr + 'ReverseEvoUpdated/')): os.makedirs(pathStr + 'ReverseEvoUpdated/') # Initialize phase-space lattice # Nx, Dx, XMax, Np, Dp, PMax, and Mesh are Global Nx = n1 * n2 Np = Nx Dx = 1. / n1 Dp = Dx XMax = Dx * Nx PMax = Dp * Np comm = fipy.tools.serial Mesh = fipy.Grid2D(dx=Dx, dy=Dp, nx=2*Nx, ny=2*Np, communicator=comm)\ + [[-XMax], [-PMax]] fipy.dump.write(Mesh, filename=pathStr + 'mesh.gz') # Create and save initial distribution phi = distributionInitial() phiInitial = fipy.CellVariable(mesh=Mesh, name=r"\LARGE $\rho_{0}(x,p)$") phiInitial.setValue(phi.value) del phi if (saveResults): fipy.tools.dump.write(phiInitial, \ filename=pathStr+'initialDistribution.gz') # Plot initial distribution genPlots(phiInitial, tStart, saveResults, 'initialDistribution.pdf', pathStr)
import fipy as fp import glob import json import numpy as np import os import sys from fipy.solvers.pysparse import LinearLUSolver as Solver problem = '1' domain = 'b' nx = 200 dx = 1.0 # The first step in implementing any problem in FiPy is to define the mesh. For [Problem 1b]({{ site.baseurl }}/hackathon1/#a.-Square-Periodic) the solution domain is just a square domain with fixed boundary conditions, so a `Grid2D` object is used. No other boundary conditions are required. mesh = fp.Grid2D(nx=nx, ny=nx, dx=dx, dy=dx) # The next step is to define the parameters and create a solution variable. # Constants and initial conditions: # $c_{\alpha}$ and $c_{\beta}$ are concentrations at which the bulk free energy has minima. # $\kappa$ is the gradient energy coefficient. # $\varrho_s$ controls the height of the double-well barrier. c_alpha = 0.3 c_beta = 0.7 kappa = 2.0 M = 5.0 c_0 = 0.5 epsilon = 0.01 rho_s = 5.0
def hydrology(solve_mode, nx, ny, dx, dy, days, ele, phi_initial, catchment_mask, wt_canal_arr, boundary_arr, peat_type_mask, httd, tra_to_cut, sto_to_cut, diri_bc=0.0, neumann_bc=None, plotOpt=False, remove_ponding_water=True, P=0.0, ET=0.0, dt=1.0): """ INPUT: - ele: (nx,ny) sized NumPy array. Elevation in m above c.r.p. - Hinitial: (nx,ny) sized NumPy array. Initial water table in m above c.r.p. - catchment mask: (nx,ny) sized NumPy array. Boolean array = True where the node is inside the computation area. False if outside. - wt_can_arr: (nx,ny) sized NumPy array. Zero everywhere except in nodes that contain canals, where = wl of the canal. - value_for_masked: DEPRECATED. IT IS NOW THE SAME AS diri_bc. - diri_bc: None or float. If None, Dirichlet BC will not be implemented. If float, this number will be the BC. - neumann_bc: None or float. If None, Neumann BC will not be implemented. If float, this is the value of grad phi. - P: Float. Constant precipitation. mm/day. - ET: Float. Constant evapotranspiration. mm/day. """ # dneg = [] track_WT_drained_area = (239, 166) track_WT_notdrained_area = (522, 190) ele[~catchment_mask] = 0. ele = ele.flatten() phi_initial = (phi_initial + 0.0 * np.zeros((ny, nx))) * catchment_mask # phi_initial = phi_initial * catchment_mask phi_initial = phi_initial.flatten() if len(ele) != nx * ny or len(phi_initial) != nx * ny: raise ValueError("ele or Hinitial are not of dim nx*ny") mesh = fp.Grid2D(dx=dx, dy=dy, nx=nx, ny=ny) phi = fp.CellVariable( name='computed H', mesh=mesh, value=phi_initial, hasOld=True) #response variable H in meters above reference level if diri_bc != None and neumann_bc == None: phi.constrain(diri_bc, mesh.exteriorFaces) elif diri_bc == None and neumann_bc != None: phi.faceGrad.constrain(neumann_bc * mesh.faceNormals, where=mesh.exteriorFaces) else: raise ValueError( "Cannot apply Dirichlet and Neumann boundary values at the same time. Contradictory values." ) #*******omit areas outside the catchment. c is input cmask = fp.CellVariable(mesh=mesh, value=np.ravel(catchment_mask)) cmask_not = fp.CellVariable(mesh=mesh, value=np.array(~cmask.value, dtype=int)) # *** drain mask or canal mask dr = np.array(wt_canal_arr, dtype=bool) dr[np.array(wt_canal_arr, dtype=bool) * np.array( boundary_arr, dtype=bool )] = False # Pixels cannot be canals and boundaries at the same time. Everytime a conflict appears, boundaries win. This overwrites any canal water level info if the canal is in the boundary. drmask = fp.CellVariable(mesh=mesh, value=np.ravel(dr)) drmask_not = fp.CellVariable( mesh=mesh, value=np.array(~drmask.value, dtype=int) ) # Complementary of the drains mask, but with ints {0,1} # mask away unnecesary stuff # phi.setValue(np.ravel(H)*cmask.value) # ele = ele * cmask.value source = fp.CellVariable(mesh=mesh, value=0.) # cell variable for source/sink # CC=fp.CellVariable(mesh=mesh, value=C(phi.value-ele)) # differential water capacity def D_value(phi, ele, tra_to_cut, cmask, drmask_not): # Some inputs are in fipy CellVariable type gwt = phi.value * cmask.value - ele d = hydro_utils.peat_map_h_to_tra( soil_type_mask=peat_type_mask, gwt=gwt, h_to_tra_and_C_dict=httd) - tra_to_cut # d <0 means tra_to_cut is greater than the other transmissivity, which in turn means that # phi is below the impermeable bottom. We allow phi to have those values, but # the transmissivity is in those points is equal to zero (as if phi was exactly at the impermeable bottom). d[d < 0] = 1e-3 # Small non-zero value not to wreck the computation dcell = fp.CellVariable( mesh=mesh, value=d ) # diffusion coefficient, transmissivity. As a cell variable. dface = fp.FaceVariable(mesh=mesh, value=dcell.arithmeticFaceValue.value ) # THe correct Face variable. return dface.value def C_value(phi, ele, sto_to_cut, cmask, drmask_not): # Some inputs are in fipy CellVariable type gwt = phi.value * cmask.value - ele c = hydro_utils.peat_map_h_to_sto( soil_type_mask=peat_type_mask, gwt=gwt, h_to_tra_and_C_dict=httd) - sto_to_cut c[c < 0] = 1e-3 # Same reasons as for D ccell = fp.CellVariable( mesh=mesh, value=c ) # diffusion coefficient, transmissivity. As a cell variable. return ccell.value D = fp.FaceVariable( mesh=mesh, value=D_value(phi, ele, tra_to_cut, cmask, drmask_not)) # THe correct Face variable. C = fp.CellVariable( mesh=mesh, value=C_value(phi, ele, sto_to_cut, cmask, drmask_not)) # differential water capacity largeValue = 1e20 # value needed in implicit source term to apply internal boundaries if plotOpt: big_4_raster_plot( title='Before the computation', raster1=( (hydro_utils.peat_map_h_to_tra(soil_type_mask=peat_type_mask, gwt=(phi.value - ele), h_to_tra_and_C_dict=httd) - tra_to_cut) * cmask.value * drmask_not.value).reshape(ny, nx), raster2=(ele.reshape(ny, nx) - wt_canal_arr) * dr * catchment_mask, raster3=ele.reshape(ny, nx), raster4=(ele - phi.value).reshape(ny, nx)) # for later cross-section plots y_value = 270 # print "first cross-section plot" # ele_with_can = copy.copy(ele).reshape(ny,nx) # ele_with_can = ele_with_can * catchment_mask # ele_with_can[wt_canal_arr > 0] = wt_canal_arr[wt_canal_arr > 0] # plot_line_of_peat(ele_with_can, y_value=y_value, title="cross-section", color='green', nx=nx, ny=ny, label="ele") # ********************************** PDE, STEADY STATE ********************************** if solve_mode == 'steadystate': if diri_bc != None: # diri_boundary = fp.CellVariable(mesh=mesh, value= np.ravel(diri_boundary_value(boundary_mask, ele2d, diri_bc))) eq = 0. == ( fp.DiffusionTerm(coeff=D) + source * cmask * drmask_not - fp.ImplicitSourceTerm(cmask_not * largeValue) + cmask_not * largeValue * np.ravel(boundary_arr) - fp.ImplicitSourceTerm(drmask * largeValue) + drmask * largeValue * (np.ravel(wt_canal_arr)) # - fp.ImplicitSourceTerm(bmask_not*largeValue) + bmask_not*largeValue*(boundary_arr) ) elif neumann_bc != None: raise NotImplementedError("Neumann BC not implemented yet!") cmask_face = fp.FaceVariable(mesh=mesh, value=np.array( cmask.arithmeticFaceValue.value, dtype=bool)) D[cmask_face.value] = 0. eq = 0. == ( fp.DiffusionTerm(coeff=D) + source * cmask * drmask_not - fp.ImplicitSourceTerm(cmask_not * largeValue) + cmask_not * largeValue * (diri_bc) - fp.ImplicitSourceTerm(drmask * largeValue) + drmask * largeValue * (np.ravel(wt_canal_arr)) # + fp.DiffusionTerm(coeff=largeValue * bmask_face) # - fp.ImplicitSourceTerm((bmask_face * largeValue *neumann_bc * mesh.faceNormals).divergence) ) elif solve_mode == 'transient': if diri_bc != None: # diri_boundary = fp.CellVariable(mesh=mesh, value= np.ravel(diri_boundary_value(boundary_mask, ele2d, diri_bc))) eq = fp.TransientTerm(coeff=C) == ( fp.DiffusionTerm(coeff=D) + source * cmask * drmask_not - fp.ImplicitSourceTerm(cmask_not * largeValue) + cmask_not * largeValue * np.ravel(boundary_arr) - fp.ImplicitSourceTerm(drmask * largeValue) + drmask * largeValue * (np.ravel(wt_canal_arr)) # - fp.ImplicitSourceTerm(bmask_not*largeValue) + bmask_not*largeValue*(boundary_arr) ) elif neumann_bc != None: raise NotImplementedError("Neumann BC not implemented yet!") #******************************************************** max_sweeps = 10 # inner loop. avg_wt = [] wt_track_drained = [] wt_track_notdrained = [] cumulative_Vdp = 0. #********Finite volume computation****************** for d in range(days): source.setValue( (P[d] - ET[d]) * .001 * np.ones(ny * nx) ) # source/sink. P and ET are in mm/day. The factor of 10^-3 converst to m/day. It does not matter that there are 100 x 100 m^2 in one pixel print("(d, P - ET) = ", (d, (P[d] - ET[d]))) if plotOpt and d != 0: # print "one more cross-section plot" plot_line_of_peat(phi.value.reshape(ny, nx), y_value=y_value, title="cross-section", color='cornflowerblue', nx=nx, ny=ny, label=d) res = 0.0 phi.updateOld() D.setValue(D_value(phi, ele, tra_to_cut, cmask, drmask_not)) C.setValue(C_value(phi, ele, tra_to_cut, cmask, drmask_not)) for r in range(max_sweeps): resOld = res res = eq.sweep(var=phi, dt=dt) # solve linearization of PDE #print "sum of Ds: ", np.sum(D.value)/1e8 #print "average wt: ", np.average(phi.value-ele) #print 'residue diference: ', res - resOld if abs(res - resOld) < 1e-7: break # it has reached to the solution of the linear system if solve_mode == 'transient': #solving in steadystate will remove water only at the very end if remove_ponding_water: s = np.where( phi.value > ele, ele, phi.value ) # remove the surface water. This also removes phi in those masked values (for the plot only) phi.setValue(s) # set new values for water table if (D.value < 0.).any(): print("Some value in D is negative!") # For some plots avg_wt.append(np.average(phi.value - ele)) wt_track_drained.append( (phi.value - ele).reshape(ny, nx)[track_WT_drained_area]) wt_track_notdrained.append( (phi.value - ele).reshape(ny, nx)[track_WT_notdrained_area]) """ Volume of dry peat calc.""" not_peat = np.ones(shape=peat_type_mask.shape) # Not all soil is peat! not_peat[peat_type_mask == 4] = 0 # NotPeat not_peat[peat_type_mask == 5] = 0 # OpenWater peat_vol_weights = utilities.PeatV_weight_calc( np.array(~dr * catchment_mask * not_peat, dtype=int)) dry_peat_volume = utilities.PeatVolume(peat_vol_weights, (ele - phi.value).reshape( ny, nx)) cumulative_Vdp = cumulative_Vdp + dry_peat_volume print("avg_wt = ", np.average(phi.value - ele)) # print "wt drained = ", (phi.value - ele).reshape(ny,nx)[track_WT_drained_area] # print "wt not drained = ", (phi.value - ele).reshape(ny,nx)[track_WT_notdrained_area] print("Cumulative vdp = ", cumulative_Vdp) if solve_mode == 'steadystate': #solving in steadystate we remove water only at the very end if remove_ponding_water: s = np.where( phi.value > ele, ele, phi.value ) # remove the surface water. This also removes phi in those masked values (for the plot only) phi.setValue(s) # set new values for water table # Areas with WT <-1.0; areas with WT >0 # plot_raster_by_value((ele-phi.value).reshape(ny,nx), title="ele-phi in the end, colour keys", bottom_value=0.5, top_value=0.01) if plotOpt: big_4_raster_plot( title='After the computation', raster1=( (hydro_utils.peat_map_h_to_tra(soil_type_mask=peat_type_mask, gwt=(phi.value - ele), h_to_tra_and_C_dict=httd) - tra_to_cut) * cmask.value * drmask_not.value).reshape(ny, nx), raster2=(ele.reshape(ny, nx) - wt_canal_arr) * dr * catchment_mask, raster3=ele.reshape(ny, nx), raster4=(ele - phi.value).reshape(ny, nx)) fig, axes = plt.subplots(nrows=2, ncols=2, figsize=(12, 9), dpi=80) x = np.arange(-21, 1, 0.1) axes[0, 0].plot(httd[1]['hToTra'](x), x) axes[0, 0].set(title='hToTra', ylabel='depth') axes[0, 1].plot(httd[1]['C'](x), x) axes[0, 1].set(title='C') axes[1, 0].plot() axes[1, 0].set(title="Nothing") axes[1, 1].plot(avg_wt) axes[1, 1].set(title="avg_wt_over_time") # plot surface in cross-section ele_with_can = copy.copy(ele).reshape(ny, nx) ele_with_can = ele_with_can * catchment_mask ele_with_can[wt_canal_arr > 0] = wt_canal_arr[wt_canal_arr > 0] plot_line_of_peat(ele_with_can, y_value=y_value, title="cross-section", nx=nx, ny=ny, label="surface", color='peru', linewidth=2.0) plt.show() # change_in_canals = (ele-phi.value).reshape(ny,nx)*(drmask.value.reshape(ny,nx)) - ((ele-H)*drmask.value).reshape(ny,nx) # resulting_phi = phi.value.reshape(ny,nx) phi.updateOld() return (phi.value - ele).reshape(ny, nx)
else: class dummyTreant(object): categories = dict() data = dummyTreant() data.categories['problem'] = "III-2a" data.categories['args'] = " ".join(sys.argv) data.categories['step'] = args.step data.categories['sweeps'] = args.sweeps data.categories['dx'] = args.dx data.categories['commit'] = os.popen('git log --pretty="%H" -1').read().strip() data.categories['diff'] = os.popen('git diff').read() mesh = fp.Grid2D(Lx=100., dx=args.dx, Ly=100., dy=args.dx) volumes = fp.CellVariable(mesh=mesh, value=mesh.cellVolumes) c = fp.CellVariable(mesh=mesh, name="$c$", hasOld=True) psi = fp.CellVariable(mesh=mesh, name=r"$\psi$", hasOld=True) Phi = fp.CellVariable(mesh=mesh, name=r"$\Phi$", hasOld=True) calpha = 0.3 cbeta = 0.7 kappa = 2. rho = 5. M = 5. k = 0.09 epsilon = 90. ceq = fp.TransientTerm(var=c) == fp.DiffusionTerm(coeff=M, var=psi)
def hydrology(mode, sensor_positions, nx, ny, dx, dy, days, ele, phi_initial, catchment_mask, wt_canal_arr, boundary_arr, peat_type_mask, peat_bottom_arr, transmissivity, t0, t1, t2, t_sapric_coef, storage, s0, s1, s2, s_sapric_coef, diri_bc=0.0, plotOpt=False, remove_ponding_water=True, P=0.0, ET=0.0, dt=1.0): """ INPUT: - ele: (nx,ny) sized NumPy array. Elevation in m above c.r.p. - Hinitial: (nx,ny) sized NumPy array. Initial water table in m above c.r.p. - catchment mask: (nx,ny) sized NumPy array. Boolean array = True where the node is inside the computation area. False if outside. - wt_can_arr: (nx,ny) sized NumPy array. Zero everywhere except in nodes that contain canals, where = wl of the canal. - value_for_masked: DEPRECATED. IT IS NOW THE SAME AS diri_bc. - diri_bc: None or float. If None, Dirichlet BC will not be implemented. If float, this number will be the BC. - neumann_bc: None or float. If None, Neumann BC will not be implemented. If float, this is the value of grad phi. - P: Float. Constant precipitation. mm/day. - ET: Float. Constant evapotranspiration. mm/day. """ # dneg = [] # track_WT_drained_area = (239,166) # track_WT_notdrained_area = (522,190) ele[~catchment_mask] = 0. ele = ele.flatten() phi_initial = (phi_initial + 0.0 * np.zeros((ny, nx))) * catchment_mask # phi_initial = phi_initial * catchment_mask phi_initial = phi_initial.flatten() if len(ele) != nx * ny or len(phi_initial) != nx * ny: raise ValueError("ele or Hinitial are not of dim nx*ny") mesh = fp.Grid2D(dx=dx, dy=dy, nx=nx, ny=ny) phi = fp.CellVariable( name='computed H', mesh=mesh, value=phi_initial, hasOld=True) #response variable H in meters above reference level if diri_bc != None: phi.constrain(diri_bc, mesh.exteriorFaces) else: raise ValueError("Dirichlet boundary conditions must have a value") #*******omit areas outside the catchment. c is input cmask = fp.CellVariable(mesh=mesh, value=np.ravel(catchment_mask)) cmask_not = fp.CellVariable(mesh=mesh, value=np.array(~cmask.value, dtype=int)) # *** drain mask or canal mask dr = np.array(wt_canal_arr, dtype=bool) dr[np.array(wt_canal_arr, dtype=bool) * np.array( boundary_arr, dtype=bool )] = False # Pixels cannot be canals and boundaries at the same time. Everytime a conflict appears, boundaries win. This overwrites any canal water level info if the canal is in the boundary. drmask = fp.CellVariable(mesh=mesh, value=np.ravel(dr)) drmask_not = fp.CellVariable( mesh=mesh, value=np.array(~drmask.value, dtype=int) ) # Complementary of the drains mask, but with ints {0,1} # mask away unnecesary stuff # phi.setValue(np.ravel(H)*cmask.value) # ele = ele * cmask.value source = fp.CellVariable(mesh=mesh, value=0.) # cell variable for source/sink # CC=fp.CellVariable(mesh=mesh, value=C(phi.value-ele)) # differential water capacity def T_value(phi, ele, cmask, peat_bottom_arr): # Some inputs are in fipy CellVariable type gwt = (phi.value * cmask.value - ele).reshape(ny, nx) # T(h) - T(bottom) T = transmissivity(gwt, t0, t1, t2, t_sapric_coef) - transmissivity( peat_bottom_arr, t0, t1, t2, t_sapric_coef) # d <0 means tra_to_cut is greater than the other transmissivity, which in turn means that # phi is below the impermeable bottom. We allow phi to have those values, but # the transmissivity is in those points is equal to zero (as if phi was exactly at the impermeable bottom). T[T < 0] = 1e-3 # Small non-zero value not to wreck the computation Tcell = fp.CellVariable(mesh=mesh, value=T.flatten( )) # diffusion coefficient, transmissivity. As a cell variable. Tface = fp.FaceVariable(mesh=mesh, value=Tcell.arithmeticFaceValue.value ) # THe correct Face variable. return Tface.value def S_value(phi, ele, cmask, peat_bottom_arr): # Some inputs are in fipy CellVariable type gwt = (phi.value * cmask.value - ele).reshape(ny, nx) S = storage(gwt, s0, s1, s2, s_sapric_coef) - storage( peat_bottom_arr, s0, s1, s2, s_sapric_coef) S[S < 0] = 1e-3 # Same reasons as for D Scell = fp.CellVariable(mesh=mesh, value=S.flatten( )) # diffusion coefficient, transmissivity. As a cell variable. return Scell.value T = fp.FaceVariable(mesh=mesh, value=T_value( phi, ele, cmask, peat_bottom_arr)) # THe correct Face variable. S = fp.CellVariable(mesh=mesh, value=S_value( phi, ele, cmask, peat_bottom_arr)) # differential water capacity largeValue = 1e20 # value needed in implicit source term to apply internal boundaries if plotOpt: big_4_raster_plot( title='Before the computation', # raster1=((hydro_utils.peat_map_h_to_tra(soil_type_mask=peat_type_mask, gwt=(phi.value - ele), h_to_tra_and_C_dict=httd) - tra_to_cut)*cmask.value *drmask_not.value ).reshape(ny,nx), raster2=(ele.reshape(ny, nx) - wt_canal_arr) * dr * catchment_mask, raster3=ele.reshape(ny, nx), raster4=(ele - phi.value).reshape(ny, nx)) # for later cross-section plots y_value = 270 """ ###### PDE ###### """ if mode == 'steadystate': temp = 0. elif mode == 'transient': temp = fp.TransientTerm(coeff=S) if diri_bc != None: # diri_boundary = fp.CellVariable(mesh=mesh, value= np.ravel(diri_boundary_value(boundary_mask, ele2d, diri_bc)) eq = temp == ( fp.DiffusionTerm(coeff=T) + source * cmask * drmask_not - fp.ImplicitSourceTerm(cmask_not * largeValue) + cmask_not * largeValue * np.ravel(boundary_arr) - fp.ImplicitSourceTerm(drmask * largeValue) + drmask * largeValue * (np.ravel(wt_canal_arr)) # - fp.ImplicitSourceTerm(bmask_not*largeValue) + bmask_not*largeValue*(boundary_arr) ) #******************************************************** max_sweeps = 10 # inner loop. avg_wt = [] # wt_track_drained = [] # wt_track_notdrained = [] cumulative_Vdp = 0. #********Finite volume computation****************** for d in range(days): if type(P) == type(ele): # assume it is a numpy array source.setValue( (P[d] - ET[d]) * .001 * np.ones(ny * nx) ) # source/sink, in mm/day. The factor of 10^-3 takes into account that there are 100 x 100 m^2 in one pixel # print("(d,P) = ", (d, (P[d]-ET[d])* 10.)) else: source.setValue((P - ET) * 10. * np.ones(ny * nx)) # print("(d,P) = ", (d, (P-ET)* 10.)) if plotOpt and d != 0: # print "one more cross-section plot" plot_line_of_peat(phi.value.reshape(ny, nx), y_value=y_value, title="cross-section", color='cornflowerblue', nx=nx, ny=ny, label=d) res = 0.0 phi.updateOld() T.setValue(T_value(phi, ele, cmask, peat_bottom_arr)) S.setValue(S_value(phi, ele, cmask, peat_bottom_arr)) for r in range(max_sweeps): resOld = res res = eq.sweep(var=phi, dt=dt) # solve linearization of PDE #print "sum of Ds: ", np.sum(D.value)/1e8 #print "average wt: ", np.average(phi.value-ele) #print 'residue diference: ', res - resOld if abs(res - resOld) < 1e-7: break # it has reached to the solution of the linear system if remove_ponding_water: s = np.where( phi.value > ele, ele, phi.value ) # remove the surface water. This also removes phi in those masked values (for the plot only) phi.setValue(s) # set new values for water table if (T.value < 0.).any(): print("Some value in D is negative!") # For some plots avg_wt.append(np.average(phi.value - ele)) # wt_track_drained.append((phi.value - ele).reshape(ny,nx)[track_WT_drained_area]) # wt_track_notdrained.append((phi.value - ele).reshape(ny,nx)[track_WT_notdrained_area]) """ Volume of dry peat calc.""" not_peat = np.ones(shape=peat_type_mask.shape) # Not all soil is peat! not_peat[peat_type_mask == 4] = 0 # NotPeat not_peat[peat_type_mask == 5] = 0 # OpenWater peat_vol_weights = utilities.PeatV_weight_calc( np.array(~dr * catchment_mask * not_peat, dtype=int)) dry_peat_volume = utilities.PeatVolume(peat_vol_weights, (ele - phi.value).reshape( ny, nx)) cumulative_Vdp = cumulative_Vdp + dry_peat_volume if plotOpt: big_4_raster_plot( title='After the computation', # raster1=((hydro_utils.peat_map_h_to_tra(soil_type_mask=peat_type_mask, gwt=(phi.value - ele), h_to_tra_and_C_dict=httd) - tra_to_cut)*cmask.value *drmask_not.value ).reshape(ny,nx), raster2=(ele.reshape(ny, nx) - wt_canal_arr) * dr * catchment_mask, raster3=ele.reshape(ny, nx), raster4=(ele - phi.value).reshape(ny, nx)) # fig, axes = plt.subplots(nrows=2, ncols=2, figsize=(12,9), dpi=80) # x = np.arange(-21,1,0.1) # axes[0,0].plot(httd[1]['hToTra'](x),x) # axes[0,0].set(title='hToTra', ylabel='depth') # axes[0,1].plot(httd[1]['C'](x),x) # axes[0,1].set(title='C') # axes[1,0].plot() # axes[1,0].set(title="Nothing") # axes[1,1].plot(avg_wt) # axes[1,1].set(title="avg_wt_over_time") # # plot surface in cross-section # ele_with_can = copy.copy(ele).reshape(ny,nx) # ele_with_can = ele_with_can * catchment_mask # ele_with_can[wt_canal_arr > 0] = wt_canal_arr[wt_canal_arr > 0] # plot_line_of_peat(ele_with_can, y_value=y_value, title="cross-section", nx=nx, ny=ny, label="surface", color='peru', linewidth=2.0) # plt.show() # change_in_canals = (ele-phi.value).reshape(ny,nx)*(drmask.value.reshape(ny,nx)) - ((ele-H)*drmask.value).reshape(ny,nx) # resulting_phi = phi.value.reshape(ny,nx) wtd = (phi.value - ele).reshape(ny, nx) wtd_sensors = [wtd[i] for i in sensor_positions] return np.array(wtd_sensors)
# This example solves a diffusion problem and demonstrates the use of # applying boundary condition patches. try: import fipy except ImportError: raise ImportError('Problem with FiPy Installation') from PyAMGSolver import PyAMGSolver nx = 20 ny = nx dx = 1.0 dy = dx L = dx * nx mesh = fipy.Grid2D(dx=dx, dy=dy, nx=nx, ny=ny) phi = fipy.CellVariable(name="solution variable", mesh=mesh, value=0.) # Apply Dirichlet boundary conditions (else Neumann by default) valueTopLeft = 0 valueBottomRight = 1 x, y = mesh.getFaceCenters() facesTopLeft = ((mesh.getFacesLeft() & (y > L / 2)) | (mesh.getFacesTop() & (x < L / 2))) facesBottomRight = ((mesh.getFacesRight() & (y < L / 2)) | (mesh.getFacesBottom() & (x > L / 2))) BCs = (fipy.FixedValue(faces=facesTopLeft, value=valueTopLeft), fipy.FixedValue(faces=facesBottomRight, value=valueBottomRight)) # set solver # solver = LinearLUSolver(tolerance = 1.e-6, iterations = 100) MGSetupOpts = {'max_coarse': 10}
import fipy as fp import glob import json import numpy as np import os import sys from fipy.solvers.pysparse import LinearLUSolver as Solver problem = '1' domain = 'c' nx = 100 dx = 1.0 # The first step in implementing any problem in FiPy is to define the mesh. In this case, the T-shaped domain is constructed out of two rectangular `Grid2D` objects. No other boundary conditions are required. mesh = fp.Grid2D(Lx=20., Ly=100.0, dx=dx, dy=dx) + ( fp.Grid2D(Ly=20.0, Lx=100.0, dx=dx, dy=dx) + [[-40], [100]]) # The next step is to define the parameters and create a solution variable. # Constants and initial conditions: # $c_{\alpha}$ and $c_{\beta}$ are concentrations at which the bulk free energy has minima. # $\kappa$ is the gradient energy coefficient. # $\varrho_s$ controls the height of the double-well barrier. c_alpha = 0.3 c_beta = 0.7 kappa = 2.0 M = 5.0 c_0 = 0.5 epsilon = 0.01 rho_s = 5.0