def simulate(case): """ Radial flow by well injection into or extracting from the central cell of the model. The model is cubic, with cubic cells and the number of cells are teh same in each direction. All walls of the cubic model obtain prescribed head equal to zero. The finite difference model is run to get the flows across the cell faces. Together with the effecive porosity (and an implicit retardation of 1), the particles are tracked. The particles are initially on a sphere with given radius. Their track should be radial and there location expressed in terms of distance form the center of the model is easily verified by the analytically computed distance as a function of the times given. The two cases use the same flow but with opposite signs. The starting radius of the second case is equal to the analytically computed end radius of the first case and vice versa, to ease comparison of the analytical with the numerical solutions. @ TO161116 """ # Parameters to set up a grid for the model # Lx wx Ly wy D d gridpar = (1050., 100., 1050., 100., 1050., 100.) crit = 0.05 k = 10. peff = 0.35 T = np.linspace(0., 720., 21) Q = [0.5e6, -0.5e6] # two cases # run fdm model out, gr, IBOUND = setup_and_run_fdm(gridpar, k, Q[case]) #### Particle tracking r = [ 217., # with Q = -0.5e6 rechage in 720 d from r1 634. ] # with Q = 0.5e6 reached in 720 d from r0 # The x,y and z ditributd regularly over a sphere of given radius xyz = xyz_radial(r[case]) Peff = gr.const(0.35) pcl = mfpath.particle_tracker(gr, out, Peff, T, xyz) #mfpath.visualize(gr, pcl, ugrid=False, phi=out.Phi[:,:,0]) #mfpath.visualize(gr, pcl, ugrid=True) R_sim = np.sqrt(pcl.x**2 + pcl.y**2 + pcl.z**2) R_analytic = rad(r[case], Q[case], T, peff) return np.mean(R_sim, axis=0), R_analytic, crit, pcl, out
def simulate(case): """ Test example: Tesing particle tracking with varable velocity but only in one direction. Like it is the case for a fully penetrating well in a confined aquifer. We take a cubic model with cubic cells and install a linear screen in its center like pencel, fully penetrating. The heads on the opposite sites are kept constant at zero. The flow should be axial and can be computed analytically. Constant velocity between opposite cell faces in x, y and z There are 3 directions to compare both for an infiltrating and an exfiltrating well. @ TO161115 """ # Parameters to set up a grid for the model # Lx wx Ly wy D d gridpar= (1050., 100., 1050., 100., 1050., 100.) # odd number of cells crit = 0.05 Np = 25 k = 10. peff = 0.35 T = np.arange(0., 750., 30) # the six test cases: Q = 1.5e6 * np.array([1, -1, 1, -1, 1, -1], dtype=float) well_axis = [2, 2, 0, 0, 1, 1] # run fdm model out, gr, IBOUND = set_up_and_run_fdm(gridpar, k, Q[case], well_axis[case]) Peff = gr.const(0.35) # initial distance for each case # starting at 200 will bring the particles at 726 after 750 days if Q>0 # starting at 726 will bring the particles at 200 after 750 days if Q<0 r = [200, 726, 200, 726, 200, 726] # initial distances # The x,y and z of the particles are computed vorm u, v and w norm.coords. xyz = xyz_points(r[case], Np, well_axis[case]) # Track particles pcl = mfpath.particle_tracker(gr, out, Peff, T, xyz) #mfpath.visualize(gr, pcl, ugrid=False, phi=out.Phi[:,:,0]) #mfpath.visualize(gr, pcl, ugrid=True) if well_axis[case] == 2: # i.e. z R_sim = np.sqrt(pcl.x**2 + pcl.y**2) H = sum(gr.dz)
def simulate(case): """ Simulates particle tracking with variable velocity. The particles move parelle to each of the axes in turn. The variable velocity is obtained by means of recharge. The model has cobic shape and so has all its cells. It is symmetric in all three axis directions. The recharge is divided uniformly over all cells of the model The flow along one axis is created by setting the head fixed at two of the opposite model faces in turn. Flow inward and outward is created by using positive and negative specific recharge. The displacement results are compared with the analytical solution. @ TO161115 """ global t_hand, t_sim print("I'm Testing the code.") print("Setting up the test.") Np = 25 crit = 0.05 # Parameters to set up a grid for the model # Lx wx Ly wy D d gridpar = (1050., 100., 1050., 100., 1050., 100.) # odd number of cells k = 10. peff = 0.35 T = np.arange(0., 750., 30.) rch = 0.0005 # [1/d] specific rechare i.e recharge/aqufier thickness spec_rech = np.array([0, -1, 0, -1, 0, -1 ]) * rch # spec. recharge for all 6 cases axis = [0, 0, 1, 1, 2, 2] # for each case # run fdm model out, gr, IBOUND = setup_and_run_fdm(gridpar, k, spec_rech[case], axis=axis[case]) #### particle tracking Peff = gr.const(0.35) s1 = 200. # with this rch particles starting at 200 m end at 723 m after 720d s2 = 720. # with this rch particles starting at 723 m end at 200 m after 720 d s0 = [s1, s2, s1, s2, s1, s2] # for each case xyz = get_particles(gr, Np, s0[case], axis=axis[case]) pcl = mfpath.particle_tracker(gr, out, Peff, T, xyz) #mfpath.visualize(gr, pcl, ugrid=False, phi=out.Phi[:,:,0]) #mfpath.visualize(gr, pcl, ugrid=True) print('Finished') # # expected distances, sa is the analytically computed particle position sa = analytic_travel_pos(spec_rech[case], T, s0[case], peff) # sn is the simulated particle position along the axis of the flow if axis[case] == 0: sn = pcl.y
def simulate(case): """ Test example: Constant velocity between opposite cell faces in x, y and z directions. Altnernatively the fixed heads are set at two opposite planes, one direction at a time. Once to let the flow be along the positive axis direction, once to let the flow be in the opposite direction. To make sure that the particle velocities are constant, we start them at the second cell face. The particles are automatically captured when the reach the last-but-one cell face at the opposite side of the grid. Hence, we have 6 cases that are captured by the hound array, which specifies the heads in all outer planes for each case, where None means that no head is prescribed. With the boundary heads and the correcponding IBOUND set, the heads and the flows are computed by fdm.fdm3. With thes flows, the particles are tracked in each of the cases. The results are collected and comapared with the hand-calculated travel time for each case. While the staring position of the particles in the researched direction is set as described above, the positions in the other directions are chosen randomly within that plane. All these particles should have the the same travel time. We make the grid a pure cube, so that both times and positions can eas- ily be compared betweeen the directions. The must all match exactly. @ TO161115 """ global t_hand, t_sim print("I'm Testing the code.") print("Setting up the test.") crit = 0.01 Np = 25 # Parameters to set up a grid for the model # Lx wx Ly wy D d gridpar= (1050., 100., 1050., 100., 1050., 100.) k = 10. peff = 0.35 T = np.arange(0., 16000., 2000.) # FH @ N S W E T B hbound= np.array([[ 9, 0], [ 0, 9], [ 0, 9], [ 9, 0], [ 0, 9], [ 9, 0]], dtype=float) flow_axis = [1, 1, 0, 0, 2, 2] # run fdm model out, gr, IBOUND = set_up_and_run_fdm(gridpar, k, hbound[case], axis=flow_axis[case]) Peff = gr.const(0.35) # The x,y and z of the particles are computed vorm u, v and w norm.coords. # starting at -900 will bring particles to +900 in 14000 d when dh = -9 m # sarting at +900 will bring particles to -900 in 14000 d when dh = +9 m s0 = 900 * np.array([-1, 1, -1, 1, -1, 1], dtype=float) xyz = get_points(gr, Np, s0[case], flow_axis[case]) # Track particles pcl = mfpath.particle_tracker(gr, out, Peff, T, xyz) #mfpath.visualize(gr, pcl, ugrid=False, phi=out.Phi[:,:,0]) #mfpath.visualize(gr, pcl, ugrid=True) print('Finished') # # sa is the analytically computed position at all t # sn is the numerically computed position at all t if case == 0: L = np.abs(np.diff(gr.xm[[0,-1]])) sa = pos(s0[case], np.diff(hbound[case]), L, k, peff, T) sn = pcl.x elif case == 1: L = np.abs(np.diff(gr.xm[[0,-1]])) sa = pos(s0[case], np.diff(hbound[case]), L, k, peff, T) sn = pcl.x elif case == 2: L = np.abs(np.diff(gr.ym[[0,-1]])) sa = pos(s0[case], -np.diff(hbound[case]), L, k, peff, T) sn = pcl.y elif case == 3: L = np.abs(np.diff(gr.ym[[0,-1]])) sa = pos(s0[case], -np.diff(hbound[case]), L, k, peff, T) sn = pcl.y elif case == 4: L = np.abs(np.diff(gr.zm[[0,-1]])) sa = pos(s0[case], -np.diff(hbound[case]), L, k, peff, T) sn = pcl.z elif case == 5: L = np.abs(np.diff(gr.zm[[0,-1]])) sa = pos(s0[case], -np.diff(hbound[case]), L, k, peff, T) sn = pcl.z return sa, np.mean(sn, axis=0), crit, pcl, out
T = np.linspace(0, 3650, 100) #time series if True: Xp = np.linspace(200, 2000., 19) Yp = np.zeros(Xp.shape) Zp = np.ones(Xp.shape) * -5. else: Zp = np.linspace(-5., -95., 19) Yp = np.zeros(Zp.shape) Xp = np.ones(Zp.shape) * 1000. #Pcl = mfpath.particle_tracker(gr, Out, por, T, Xp, Yp, Zp) Pcl = mfpath.particle_tracker(gr, Out, gr.const(por), T=T, particles=(Xp, Yp, Zp), markers='+o*.xsdph^v<>', retardation=1.0, sinkfrac=0.75, tol=1e-12, central_point=(0., 0., 0.)) mfpath.plot_particles(Pcl, axes=ax, first_axis='y', color='green', markers='o....', markersize=4) plt.show() #R = np.sqrt(Q * T[-1] / (np.pi * por * np.sum(gr.dy)))