def __init__(self, layer, **kwargs): super(SimpleFiniteSolver,self).__init__(layer, **kwargs) try: layers = layer.layers if len(layers) == 1: self.layer = layers[0] else: arg = self.__class__.__name__+" can be initialized only from a single layer or a section containing only one layer." raise ArgumentError(arg) except AttributeError: self.layer = layer self.analytical_solver = HalfSpaceSolver(layer) self.material = self.layer.material self.depth = self.layer.thickness self.dy = self.layer.grid_spacing self.ny = int((self.depth/self.dy).into("dimensionless")) self.mesh = F.Grid1D(nx=self.ny, dx=self.dy.into("m")) t_min,t_max = (i.into("kelvin") for i in self.constraints) self.initial_values = N.empty(self.ny) self.initial_values.fill(t_max) self.var = F.CellVariable(name="Temperature", mesh=self.mesh, value=self.initial_values) self.var.constrain(t_min, self.mesh.facesLeft) self.var.constrain(t_max, self.mesh.facesRight) coefficient = self.material.diffusivity.into("m**2/s") self.equation = F.TransientTerm() == F.DiffusionTerm(coeff=coefficient)
def df2(xs, mesh, vx, vy, i, j): """ Evaluate the model for the 2nd derivatives at the 10 locations of the domain at times ``t``. It returns a flatten version of the system, i.e.: y_1(t_1) ... y_10(t_1) ... y_1(t_4) ... y_10(t_4) """ assert i == 1 or i == 2 assert j == 1 or j == 2 ############################################################################ ############################################################################ ##### ------------------ Solve the transport equation ---------------- ##### ############################################################################ Rd = 2. # Retardation factor convCoeff = fp.CellVariable(mesh=mesh, rank=1) convCoeff()[0, :] = vx convCoeff()[1, :] = vy time = fp.Variable() # --- Make Source --- q0 = make_source_der_2(xs, mesh, time, i, j) # The solution variable var = fp.CellVariable(name="variable", mesh=mesh, value=0.) # Define the equation eqC = fp.TransientTerm(Rd) == -fp.ConvectionTerm(coeff=convCoeff) + q0 # Solve d2U = [] timeStepDuration = 0.005 steps = 400 for step in range(steps): time.setValue(time() + timeStepDuration) eqC.solve(var=var, dt=timeStepDuration) if step == 99 or step == 199 or step == 299 or step == 399: d2U = np.hstack([ d2U, np.array([ var()[8 * 50 + 14], var()[8 * 50 + 34], var()[18 * 50 + 14], var()[18 * 50 + 34], var()[28 * 50 + 14], var()[28 * 50 + 34], var()[38 * 50 + 14], var()[38 * 50 + 34], var()[48 * 50 + 14], var()[48 * 50 + 34] ]) ]) return d2U
def solve_DiracIC(saveplot = False, R_from = 0.7, R_to = 1.0, nr = 1000, duration = 0.001, nt = 1000, diracLoc = 0.85, diracCoeff = 1., diracPercentage = 2, conv_file = 'convC.txt', diff_file = 'diffC.txt', plotcoeff = False, levels = 300, logdiff = 6, ticks = None, figsize=(10,5), hdf5 = False): dr = (R_to - R_from) / nr ## distance between the centers of the mesh cells dt = duration / nt ## length of one timestep solution = np.zeros((nt,nr,2)) for j in range(nr): solution[:,j,0] = (j * dr) + (dr / 2) + R_from mesh = fp.CylindricalGrid1D(dx=dr, nx=nr) ## 1D mesh based on the radial coordinates mesh = mesh + (R_from,) ## translation of the mesh to R_from n = fp.CellVariable(mesh=mesh) ## fipy.CellVariable for the density solution in each timestep diracWidth = int((nr / 100) * diracPercentage) n.setValue(delta_func(mesh.x - diracLoc, diracWidth * dr, diracCoeff)) conv_data = np.genfromtxt(conv_file, delimiter=',') diff_data = np.genfromtxt(diff_file, delimiter=',') conv_i = np.zeros((nr, 2)) diff_i = np.zeros((nr, 2)) for i in range(conv_i.shape[0]): conv_i[i, 0] = R_from + (i * dr) + (dr / 2) for i in range(diff_i.shape[0]): diff_i[i, 0] = R_from + (i * dr) + (dr / 2) conv_i[:,1] = np.interp(conv_i[:,0],conv_data[:,0],conv_data[:,1]) diff_i[:,1] = np.interp(diff_i[:,0],diff_data[:,0],diff_data[:,1]) dC = diff_i[:,1] diffCoeff = fp.CellVariable(mesh=mesh, value=dC) cC = conv_i[:,1] convCoeff = fp.CellVariable(mesh=mesh, value=[cC]) gradLeft = (0.,) ## density gradient (at the "left side of the radius") - must be a vector valueRight = 0. ## density value (at the "right end of the radius") n.faceGrad.constrain(gradLeft, where=mesh.facesLeft) ## applying Neumann boundary condition n.constrain(valueRight, mesh.facesRight) ## applying Dirichlet boundary condition convCoeff.setValue(0, where=mesh.x<(R_from + dr)) ## convection coefficient 0 at the inner edge diffCoeff.setValue(0.001, where=mesh.x<(R_from + dr)) ## diffusion coefficient almost 0 at inner edge eq = (fp.TransientTerm() == fp.DiffusionTerm(coeff=diffCoeff) - fp.ConvectionTerm(coeff=convCoeff)) for i in range(nt): eq.solve(var=n, dt=dt) solution[i,0:nr,1]=copy.deepcopy(n.value) plot_solution(solution,ticks=ticks,levels=levels,logdiff=logdiff,figsize=figsize, duration=duration, nt=nt, saveplot=saveplot) if plotcoeff == True: coeff_plot(conv_i=conv_i, diff_i=diff_i) else: pass if hdf5 == True: hdf5_save(fname="DiracIC",solution=solution, conv=conv_i, diff=diff_i, duration=duration) else: pass return solution
def forwardEvo(phi, tStart, tEnd, path, saveResults): # Initialize step counter and evolution time step = 0 tEvo = tStart # Extract cell centers and faces from mesh X, P = Mesh.cellCenters() xFace, pFace = Mesh.faceCenters() # Create plot for starting distribution target = 'forwardEvo-Step-' + '%05d' % step + '.png' genPlots(phi, tEvo, saveResults, target, path) # Continue to evolve distribution until specified end time while (tEvo < tEnd): # Find current spring constant and location of minimum kT = springConstant(tEvo) zT = potentialMinimum(tEvo) # Calculate time step size timeStepDuration = (1. / (SubDiv * Nx)) * (1. / numpy.sqrt(1. / Tau**2 + kT)) if (tEvo + timeStepDuration > tEnd): timeStepDuration = tEnd - tEvo # Create Diffusion Term gxx = numpy.zeros(X.shape) gxp = numpy.zeros(X.shape) gpx = numpy.zeros(X.shape) gpp = numpy.ones(X.shape) * (2. / Tau) dTerm = fipy.DiffusionTerm( fipy.CellVariable(mesh=Mesh, value=[[gxx, gxp], [gpx, gpp]])) del gxx, gxp, gpx, gpp # Create convection term uX = pFace uP = -kT * (xFace - zT) - (2. / Tau) * pFace cCoeff = fipy.FaceVariable(mesh=Mesh, value=[uX, uP]) cTerm = fipy.ExponentialConvectionTerm(cCoeff) del uX, uP, cCoeff # Create evolution equation eq = fipy.TransientTerm() + cTerm == dTerm # Specify solver solver = fipy.solvers.pysparse.LinearLUSolver(tolerance=10**-15, \ iterations=1000, precon=None) # Evolve system eq.solve(var=phi, dt=timeStepDuration, solver=solver) tEvo = tEvo + timeStepDuration step = step + 1 # Check normalization for possible errors norm = fipy.numerix.sum(phi.value, axis=0) * Dx * Dp if (abs(norm - 1) > 10**(-13)): s1 = 'Distribution is no longer normalized.\n' s2 = 'Abs(1-Norm) = ' s3 = repr(norm - 1.) raise RuntimeError(s1 + s2 + s3) del kT, zT, timeStepDuration, cTerm, eq, norm # Create plot of current distribution target = 'forwardEvo-Step-' + '%05d' % step + '.png' genPlots(phi, tEvo, saveResults, target, path) del tEvo, X, P, xFace, pFace return phi
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 solve_fipy_with_given_N(N, params): s1 = params[0] s2 = params[1] t1 = params[2] t2 = params[3] dx = 100.0 / N dt = 1.0 NDAYS = 10 f_start_time = time.time() mesh = fp.Grid1D(nx=N, dx=dx) v_fp = fp.CellVariable(name="v_fp", mesh=mesh, value=INI_VALUE, hasOld=True) # BC v_fp.constrain(0, where=mesh.facesLeft) # left BC is always Dirichlet # v_fp.faceGrad.constrain(0. * mesh.faceNormals, where=mesh.facesRight) # right: flux=0 def dif_fp(u): b = -4. D = (numerix.exp(t1) / t2 * (numerix.power(s2 * numerix.exp(-s1) * u + numerix.exp(s2 * b), t2 / s2) - numerix.exp(t2 * b))) / ( s2 * u + numerix.exp(s1 + s2 * b)) return D # Boussinesq eq. for theta eq = fp.TransientTerm() == fp.DiffusionTerm(coeff=dif_fp(v_fp)) + SOURCE MAX_SWEEPS = 10000 for t in range(NDAYS): v_fp.updateOld() res = 0.0 for r in range(MAX_SWEEPS): # print(i, res) resOld = res # res = eq.sweep(var=v_fp, dt=dt, underRelaxation=0.1) res = eq.sweep(var=v_fp, dt=dt) if abs(res - resOld) < abs_tolerance: break # it has reached to the solution of the linear system time_spent = time.time() - f_start_time return v_fp.value, time_spent
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 get_eqn(mesh, diff): """Generate a generic 1D diffusion equation with flux from the left Args: mesh: the mesh diff: the diffusion coefficient Returns: a tuple of the flux and the equation """ flux = fipy.CellVariable(mesh, value=0.) eqn = fipy.TransientTerm() == fipy.DiffusionTerm( diff) + fipy.ImplicitSourceTerm(flux * GET_MASK(mesh) / mesh.dx) return (flux, eqn)
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
def df(xs, mesh, i): """ Evaluate the model for the 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 time = fp.Variable() q0 = make_source_der(xs, mesh, time, i) 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 dU = [] for step in range(steps): eq.solve(var=phi, dt=dt) if step == 14 or step == 29 or step == 44 or step == 59: dc = phi()[12] #dr = phi()[24] uc = phi()[612] #ur = phi()[624] #dU = np.hstack([dU, np.array([dl, dr, ul, ur])]) dU = np.hstack([dU, np.array([dc, uc])]) return dU
def f(xs, mesh): """ Evaluate the model for the concentration 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) """ time = fp.Variable() q = make_source(xs, mesh, time) D = 1. # Define the equation eq = fp.TransientTerm() == fp.DiffusionTerm(coeff=D) + q # Boundary conditions # The solution variable phi = fp.CellVariable(name="Concentraion", mesh=mesh, value=0.) # Solve dt = 0.005 steps = 60 U_sol = [] 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] #U_sol = np.hstack([U_sol, np.array([dl, dr, ul, ur])]) U_sol = np.hstack([U_sol, np.array([dl, ul])]) return U_sol
def get_eq(params, eta, d2f): """Get the equation Args: params: the parameter dictionary eta: the phase field variable d2f: the free energy double derivative variable Returns: a dictionary of the equation and variables """ return pipe( fp.CellVariable(mesh=eta.mesh, name="psi"), lambda x: ( fp.TransientTerm(var=eta) == -fp.DiffusionTerm( coeff=params["mobility"], var=x) + fp.DiffusionTerm( coeff=params["mobility"] * d2f, var=eta), fp.ImplicitSourceTerm(coeff=1.0, var=x) == fp.DiffusionTerm( coeff=params["kappa"], var=eta), ), lambda x: x[0] & x[1], )
def solve_both_withI(saveplot=False, R_from=0.7, R_to=1.0, nr=1000, duration=0.001, nt=1000, conv_file='convC.txt', diff_file='diffC.txt', plotcoeff=False, levels=300, logdiff=5, ticks=None, figsize=(10, 5), hdf5=False): dr = (R_to - R_from) / nr ## distance between the centers of the mesh cells dt = duration / nt ## length of one timestep solution = np.zeros((nt, nr, 2)) for j in range(nr): solution[:, j, 0] = (j * dr) + (dr / 2) + R_from mesh = fp.CylindricalGrid1D( dx=dr, nx=nr) ## 1D mesh based on the radial coordinates mesh = mesh + (R_from, ) ## translation of the mesh to R_from n = fp.CellVariable( mesh=mesh ) ## fipy.CellVariable for the density solution in each timestep conv_data = np.genfromtxt(conv_file, delimiter=',') diff_data = np.genfromtxt(diff_file, delimiter=',') conv_i = np.zeros((nr, 2)) diff_i = np.zeros((nr, 2)) for i in range(conv_i.shape[0]): conv_i[i, 0] = R_from + (i * dr) + (dr / 2) for i in range(diff_i.shape[0]): diff_i[i, 0] = R_from + (i * dr) + (dr / 2) conv_i[:, 1] = np.interp(conv_i[:, 0], conv_data[:, 0], conv_data[:, 1]) diff_i[:, 1] = np.interp(diff_i[:, 0], diff_data[:, 0], diff_data[:, 1]) dC = diff_i[:, 1] diffCoeff = fp.CellVariable(mesh=mesh, value=dC) cC = conv_i[:, 1] convCoeff = fp.CellVariable(mesh=mesh, value=[cC]) n.setValue(0.0) idata = np.genfromtxt('island_data.csv', delimiter=',') islands_ratio = np.zeros((nr, 2)) for i in range(nr): islands_ratio[i, 0] = R_from + (i * dr) + (dr / 2) islands_ratio[:, 1] = np.interp(islands_ratio[:, 0], idata[:, 0], idata[:, 1]) w_length = math.ceil(nr / 20) if (w_length % 2) == 0: w_length = w_length + 1 else: pass islands_ratio[:, 1] = savgol_filter(islands_ratio[:, 1], w_length, 3) islands_ratio[islands_ratio < 0] = 0 re_ratio = islands_ratio[:, 1] re_in_islands = re_ratio * n.value gradLeft = ( 0., ) ## density gradient (at the "left side of the radius") - must be a vector valueRight = 0. ## density value (at the "right end of the radius") n.faceGrad.constrain( gradLeft, where=mesh.facesLeft) ## applying Neumann boundary condition n.constrain(valueRight, mesh.facesRight) ## applying Dirichlet boundary condition convCoeff.setValue( 0, where=mesh.x < (R_from + dr)) ## convection coefficient 0 at the inner edge diffCoeff.setValue( 0.001, where=mesh.x < (R_from + dr)) ## diffusion coefficient almost 0 at inner edge modules = MODULE(b"hc_formula_63", False, b"rosenbluth_putvinski", False, False, 1.0, 1.0001) electron_temperature = ct.c_double(300.) electron_density = ct.c_double(1e20) effective_charge = ct.c_double(1.) electric_field = ct.c_double(3.66) magnetic_field = ct.c_double(1.) inv_asp_ratio = ct.c_double(0.30303) rate_values = (ct.c_double * 4)(0., 0., 0., 0.) eq = (fp.TransientTerm() == fp.DiffusionTerm(coeff=diffCoeff) - fp.ConvectionTerm(coeff=convCoeff)) for i in range(nt): for j in range(nr): plasma_local = PLASMA(ct.c_double(mesh.x[j]), electron_density, electron_temperature, effective_charge, electric_field, magnetic_field, ct.c_double(n.value[j])) n.value[j] = adv_RE_pop(ct.byref(plasma_local), dt, inv_asp_ratio, ct.c_double(mesh.x[j]), ct.byref(modules), rate_values) print("{:.1f}".format((i / nt) * 100), '%', end='\r') eq.solve(var=n, dt=dt) if i == 0: solution[i, 0:nr, 1] = copy.deepcopy(n.value) re_in_islands = re_ratio * copy.deepcopy(n.value) n.value = copy.deepcopy(n.value) - re_in_islands else: re_local = PLASMA(ct.c_double(mesh.x[j]), electron_density, electron_temperature, effective_charge, electric_field, magnetic_field, ct.c_double(re_in_islands[j])) re_in_islands[j] = adv_RE_pop(ct.byref(re_local), dt, inv_asp_ratio, ct.c_double(mesh.x[j]), ct.byref(modules), rate_values) re_in_islands[nr - 1] = 0 solution[i, 0:nr, 1] = copy.deepcopy(n.value) + re_in_islands plot_solution(solution, ticks=ticks, levels=levels, logdiff=logdiff, figsize=figsize, duration=duration, nt=nt, saveplot=saveplot) if plotcoeff == True: coeff_plot(conv_i=conv_i, diff_i=diff_i) else: pass if hdf5 == True: hdf5_save(fname="Dreicer_and_avalanche", solution=solution, conv=conv_i, diff=diff_i, duration=duration) else: pass return solution
if parallelComm.procID == 0: dt = data.categories["dt_exact"] else: dt = None dt = parallelComm.bcast(dt) elapsed = fp.Variable(name="$t$", value=startfrom * dt) # linearize double-well m_eta = 2 * (1 - 2 * eta) dm_eta_deta = -4. DW = m_eta * eta * (eta - 1) dDW_deta = dm_eta_deta * eta * (eta - 1) + m_eta * (2 * eta - 1) eq = (fp.TransientTerm() == (DW - dDW_deta * eta) + fp.ImplicitSourceTerm(coeff=dDW_deta) + fp.DiffusionTerm(coeff=kappa_fp) + eq_fp(xx, yy, elapsed)) solver = eq.getDefaultSolver() print "solver:", repr(solver) for step in range(1, numsteps + 1): eta.updateOld() for sweep in range(params['sweeps']): res = eq.sweep(var=eta, dt=dt, solver=solver) elapsed.value = elapsed() + dt del solver error = eta - eta_fp(xx, yy, elapsed - dt)
time = fp.Variable() var = fp.CellVariable(name="variable", mesh=mesh) # --- Make source term rho = 0.35 q0 = 1. / (np.pi * rho**2) T = 0.3 xs_1 = np.array([1.25, 2.]) 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_1[0])**2 + (mesh.cellCenters[1]()[i] - xs_1[1])**2) / (2 * rho**2)) * (time() < T) eqC = fp.TransientTerm( Rd) == -fp.ConvectionTerm(coeff=convCoeff) + sourceTerm_1 if __name__ == '__main__': viewer = fp.Viewer(vars=var, datamin=0., datamax=2.5) viewer.plot() data = [] timeStepDuration = 0.005 steps = 400 for step in range(steps): time.setValue(time() + timeStepDuration) eqC.solve(var=var, dt=timeStepDuration) if step == 99 or step == 199 or step == 299 or step == 399: data = np.hstack([ data, np.array([
def run(): memory1 = resource.getrusage( resource.RUSAGE_SELF).ru_maxrss #get initial memory peak #load in the json parameter file here jsonfile = sys.argv[1] if jsonfile: with open(jsonfile, 'rb') as ff: params = json.load(ff) else: params = dict() print 'my params:', params #extract the parameters N = params.get('N', 20) # dx = params.get('dx', 1) total_steps = params.get('steps', 2) sumatra_label = params.get('sumatra_label', '') c, rho_s, c_alpha, c_beta = sympy.symbols("c_var rho_s c_alpha c_beta") f_0 = rho_s * (c - c_alpha)**2 * (c_beta - c)**2 mesh = fp.PeriodicGrid2D(nx=N, ny=N, dx=.5, dy=.5) 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 filepath = os.path.join('Data', sumatra_label) c_var = fp.CellVariable(mesh=mesh, name=r"$c$", hasOld=True) # array of sample c-values: used in f versus c plot vals = np.linspace(-.1, 1.1, 1000) c_var = fp.CellVariable(mesh=mesh, name=r"$c$", hasOld=True) x, y = np.array(mesh.x), np.array(mesh.y) out = sympy.diff(f_0, c, 2) exec "f_0_var = " + repr(out) #f_0_var = -A + 3*B*(c_var - c_m)**2 + 3*c_alpha*(c_var - c_alpha)**2 + 3*c_beta*(c_var - c_beta)**2 def f_0(c): return rho_s * ((c - c_alpha)**2) * ((c_beta - c)**2) def f_0_var(c_var): return 2 * rho_s * ((c_alpha - c_var)**2 + 4 * (c_alpha - c_var) * (c_beta - c_var) + (c_beta - c_var)**2) # free energy def f(c): return (f_0(c) + .5 * kappa * (c.grad.mag)**2) f_data = [] time_data = [] def save_data(f, time): f_data.append(f.value) time_data.append(time) np.savetxt(os.path.join(filepath, '1a.txt'), zip(time_data, f_data)) eqn = fp.TransientTerm( coeff=1.) == fp.DiffusionTerm(M * f_0_var(c_var)) - fp.DiffusionTerm( (M, kappa)) elapsed = 0.0 steps = 0 dt = 0.01 total_sweeps = 2 tolerance = 1e-1 # duration = 1000.0 c_var[:] = c_0 + epsilon * (np.cos(0.105 * x) * np.cos(0.11 * y) + \ (np.cos(0.13 * x) * np.cos(0.087 * y))**2 + \ + np.cos(0.025 * x - 0.15 * y) * np.cos(0.07 * x - 0.02 * y)) c_var.updateOld() solver = Solver() while steps < total_steps: res0 = eqn.sweep(c_var, dt=dt, solver=solver) for sweeps in range(total_sweeps): res = eqn.sweep(c_var, dt=dt, solver=solver) if (res < (res0 * tolerance)): steps += 1 # elapsed += dt dt *= 1.1 c_var.updateOld() if (steps % (total_steps / 10.0) == 0): # record the volume integral of the free energy save_data( f_0_var(c_var).cellVolumeAverage * mesh.numberOfCells, elapsed) # pickle the data on c as a function of space at this particular time fp.dump.write({ 'time': steps, 'var': c_var }, os.path.join(filepath, '1a{0}.pkl'.format(steps))) else: dt *= 0.8 c_var[:] = c_var.old print ' ' #memory stuff saves filepath = os.path.join('Data', sumatra_label) #Keep track os how much memory was used and dump into a txt file memory2 = resource.getrusage( resource.RUSAGE_SELF).ru_maxrss #final memory peak memory_diff = (memory2 - memory1, ) filename2 = 'memory_usage.txt' np.savetxt(os.path.join(filepath, filename2), memory_diff)
cvar_data = [] f_data = [] def save_data(time, cvar, f, step): time_data.append(time) cvar_data.append(np.array(cvar.value)) f_data.append(f.value) file_name = 'data/1{0}{1}_{2}'.format(domain, nx, str(step).rjust(5, '0')) np.savez(file_name, time=time_data, c_var=cvar_data, f=f_data) # ## Define the Equation eqn = fp.TransientTerm( coeff=1.) == fp.DiffusionTerm(M * f_0_var(c_var)) - fp.DiffusionTerm( (M, kappa)) # ## Solve the Equation # To solve the equation a simple time stepping scheme is used which is decreased or increased based on whether the residual decreases or increases. A time step is recalculated if the required tolerance is not reached. In addition, the time step is kept under 1 unit. The data is saved out every 10 steps. elapsed = 0.0 steps = 0 dt = 0.01 dt_max = 1.0 total_sweeps = 2 tolerance = 1e-1 total_steps = int(sys.argv[1]) checkpoint = int(sys.argv[2]) duration = 900.0
dx = Lx / nx dy = Ly / ny mesh = fp.PeriodicGrid2DLeftRight(nx=nx, dx=dx, ny=ny, dy=dx) xx, yy = mesh.cellCenters[0], mesh.cellCenters[1] XX, YY = mesh.faceCenters[0], mesh.faceCenters[1] elapsed = fp.Variable(name="$t$", value=0.) eta = fp.CellVariable(mesh=mesh, name="$eta$", hasOld=True) eta.constrain(1., where=YY == 0.) eta.constrain(0., where=YY == 0.5) eta.value = eta_fp(xx, yy, 0.) eq = (fp.TransientTerm() == -4 * eta * (eta - 1) * (eta - 0.5) + fp.DiffusionTerm(coeff=kappa_fp) + eq_fp(xx, yy, elapsed)) start = time.time() while elapsed.value <= totaltime: eta.updateOld() eq.solve(var=eta, dt=dt) elapsed.value = elapsed() + dt end = time.time() data.categories["solvetime"] = end - start error = eta - eta_fp(xx, yy, elapsed - dt) error.name = r"$\Delta\eta$"
kappa = 2.0 c_m = (c_alpha + c_beta) / 2. B = A / (c_alpha - c_m)**2 D = D_alpha = D_beta = 2. / (c_beta - c_alpha) c_0 = 0.45 q = np.sqrt((2., 3.)) epsilon = 0.01 c_var = fp.CellVariable(mesh=mesh, name=r"$c$", hasOld=True) r = np.array((mesh.x, mesh.y)) c_var[:] = c_0 + epsilon * np.cos((q[:, None] * r).sum(0)) f_0_var = -A + 3*B*(c_var - c_m)**2 + 3*c_alpha*(c_var - c_alpha)**2 + 3*c_beta*(c_var - c_beta)**2 eqn = fp.TransientTerm(coeff=1.) == fp.DiffusionTerm(D * f_0_var) - fp.DiffusionTerm((D, kappa)) elapsed = 0.0 steps = 0 dt = 0.01 total_sweeps = 2 tolerance = 1e-1 #total_steps = 2 #from 1000 to 100 c_var[:] = c_0 + epsilon * np.cos((q[:, None] * r).sum(0)) c_var.updateOld() from fipy.solvers.pysparse import LinearLUSolver as Solver solver = Solver()
def initialise_food_equation(self): self.food_PDE = ( fipy.TransientTerm() == fipy.DiffusionTerm(coeff=self.D_food) - fipy.ImplicitSourceTerm(coeff=self.gamma * self.rho))
import fipy as fp import numpy as np from matplotlib import pyplot as plt nx = 20 ny = nx dx = 1. dy = dx L = dx * nx mesh = fp.Grid2D(dx=dx, dy=dy, nx=nx, ny=ny) phi = fp.CellVariable(name="solution variable", mesh=mesh, value=0.) D = 1. eq = fp.TransientTerm() == fp.DiffusionTerm(coeff=D) valueTopLeft = 0 valueBottomRight = 1 X, Y = mesh.faceCenters facesTopLeft = ((mesh.facesLeft & (Y > L / 2)) | (mesh.facesTop & (X < L / 2))) facesBottomRight = ((mesh.facesRight & (Y < L / 2)) | (mesh.facesBottom & (X > L / 2))) phi.constrain(valueTopLeft, facesTopLeft) phi.constrain(valueBottomRight, facesBottomRight) timeStepDuration = 10 * 0.9 * dx**2 / (2 * D) steps = 10 for step in range(steps): eq.solve(var=phi, dt=timeStepDuration)
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)
def initialise_density_equation(self): self.density_PDE = (fipy.TransientTerm() == -self.v_0 * fipy.PowerLawConvectionTerm(coeff=self.p))
def create_equation(self, type='implicit'): trans = F.TransientTerm() diff = self.diffusion_term(type) return trans == diff
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)
def initialise_orientation_equation(self): self.orientation_PDE = (fipy.TransientTerm() == fipy.ImplicitSourceTerm(coeff=-self.D_rot) - (self.v_0 / 2.0) * self.rho.grad / self.rho)
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) fchem = rho * (c - calpha)**2 * (cbeta - c)**2 felec = k * c * Phi / 2. f = fchem + (kappa / 2.) * c.grad.mag**2 + felec dfchemdc = 2 * rho * (c - calpha) * (cbeta - c) * (calpha + cbeta - 2 * c) d2fchemd2c = 2 * rho * ((calpha + cbeta - 2 * c)**2 - 2 * (c - calpha) * (cbeta - c)) psieq = (fp.ImplicitSourceTerm( coeff=1., var=psi) == fp.ImplicitSourceTerm(coeff=d2fchemd2c, var=c) - d2fchemd2c * c + dfchemdc - fp.DiffusionTerm(coeff=kappa, var=c) + fp.ImplicitSourceTerm(coeff=k, var=Phi)) stats = [] Phieq = fp.DiffusionTerm(var=Phi) == fp.ImplicitSourceTerm(coeff=-k / epsilon,
# &= m_\phi \phi_\text{old} (1 - \phi_\text{old}) - S_1 \phi_\text{old} # \notag \\ # S_1 &\equiv \left.{\frac{\partial S}{\partial \phi}}\right|_\text{old} # \notag \\ # &= \frac{\partial m_\phi}{\partial \phi} \phi (1 - \phi) + m_\phi (1 - 2\phi) # \notag # \end{align} # In[9]: mPhi = -2 * (1 - 2 * phi) + 30 * phi * (1 - phi) * Delta_f dmPhidPhi = 4 + 30 * (1 - 2 * phi) * Delta_f S1 = dmPhidPhi * phi * (1 - phi) + mPhi * (1 - 2 * phi) S0 = mPhi * phi * (1 - phi) - S1 * phi eq = (fp.TransientTerm() == fp.DiffusionTerm(coeff=1.) + S0 + fp.ImplicitSourceTerm(coeff=S1)) # ## Calculate total free energy # # > \begin{align} # F[\phi] = \int\left[\frac{1}{2}(\nabla\phi)^2 + g(\phi) - \Delta f p(\phi)\right]\,dV \tag{6} # \end{align} # In[10]: ftot = (0.5 * phi.grad.mag**2 + phi**2 * (1 - phi)**2 - Delta_f * phi**3 * (10 - 15 * phi + 6 * phi**2)) volumes = fp.CellVariable(mesh=mesh, value=mesh.cellVolumes) F = ftot.cellVolumeAverage * volumes.sum()
# \notag \\ # S_1 &\equiv \left.{\frac{\partial S}{\partial \phi}}\right|_\text{old} # \notag \\ # &= \frac{\partial m_\phi}{\partial \phi} \phi (1 - \phi) + m_\phi (1 - 2\phi) # \notag # \end{align} # In[8]: mPhi = -2 * (1 - 2 * phi) + 30 * phi * (1 - phi) * Delta_f dmPhidPhi = 4 + 30 * (1 - 2 * phi) * Delta_f S1 = dmPhidPhi * phi * (1 - phi) + mPhi * (1 - 2 * phi) S0 = mPhi * phi * (1 - phi) - S1 * phi eq = (fp.TransientTerm() == fp.DiffusionTerm(coeff=1.) + S0 + fp.ImplicitSourceTerm(coeff=S1)) # ## Calculate total free energy # # > \begin{align} # F[\phi] = \int\left[\frac{1}{2}(\nabla\phi)^2 + g(\phi) - \Delta f p(\phi)\right]\,dV \tag{6} # \end{align} # In[9]: ftot = (0.5 * phi.grad.mag**2 + phi**2 * (1 - phi)**2 - Delta_f * phi**3 * (10 - 15 * phi + 6 * phi**2))
def hydro_1d_fipy(theta_ini, nx, dx, dt, params, ndays, sensor_loc, boundary_values_left, boundary_values_right, precip, evapotra, ele_interp, peat_depth): def zeta_from_theta(x, b): return np.log(np.exp(s2 * b) + s2 * np.exp(-s1) * x) / s2 mesh = fp.Grid1D(nx=nx, dx=dx) ele = ele_interp(mesh.cellCenters.value[0]) b = peat_depth + ele.min() - ele s1 = params[0] s2 = params[1] t1 = params[2] t2 = params[3] source = precip[0] - evapotra[0] theta = fp.CellVariable(name="theta", mesh=mesh, value=theta_ini, hasOld=True) # Choice of parameterization # This is the underlying conductivity: K = exp(t1 + t2*zeta). The # transmissivity is derived from this and written in terms of theta # This is the underlying storage coeff: S = exp(s1 + s2*zeta) # S is hidden in change from theta to h # D = (numerix.exp(t1)/t2 * (numerix.power(s2 * numerix.exp(-s1) * theta + numerix.exp(s2*b), t2/s2) - numerix.exp(t2*b))) * np.power(s2 * (theta + numerix.exp(s1 + s2*b)/s2), -1) # Boussinesq eq. for theta eq = fp.TransientTerm() == fp.DiffusionTerm(coeff=( numerix.exp(t1) / t2 * (numerix.power(s2 * numerix.exp(-s1) * theta + numerix.exp(s2 * b), t2 / s2) - numerix.exp(t2 * b)) ) * np.power(s2 * (theta + numerix.exp(s1 + s2 * b) / s2), -1)) + source theta_sol_list = [] # returned quantity MAX_SWEEPS = 10000 for day in range(ndays): theta.updateOld() # BC and Source/sink update theta_left = boundary_values_left[day] # left BC is always Dirichlet theta.constrain(theta_left, where=mesh.facesLeft) if boundary_values_right == None: # Pxx sensors. Neuman BC on the right theta.faceGrad.constrain(0. * mesh.faceNormals, where=mesh.facesRight) else: theta_right = boundary_values_right[day] theta.constrain(theta_right, where=mesh.facesRight) source = precip[day] - evapotra[day] res = 0.0 for r in range(MAX_SWEEPS): resOld = res res = eq.sweep(var=theta, dt=dt) if abs(res - resOld) < 1e-7: break # it has reached the solution of the linear system if r == MAX_SWEEPS: raise ValueError( 'Solution not converging after maximum number of sweeps') # Append to list theta_sol = theta.value theta_sol_sensors = np.array( [theta_sol[sl] for sl in sensor_loc[1:]] ) # canal sensor is part of the model; cannot be part of the fitness estimation theta_sol_list.append(theta_sol_sensors[0]) b_sensors = np.array([b[sl] for sl in sensor_loc[1:]]) zeta_from_theta_sol_sensors = zeta_from_theta(np.array(theta_sol_list), b_sensors) # print(zeta_from_theta_sol_sensors) return zeta_from_theta_sol_sensors