def calculate_potential(depletion_mask=None, y_dep_new=None): potential = fipy.CellVariable(mesh=mesh, name='potential', value=0.) electrons = fipy.CellVariable(mesh=mesh, name='e-') electrons.valence = -1 charge = electrons * electrons.valence charge.name = "charge" # Uniform charge distribution by setting a uniform concentration of # electrons = 1 electrons.setValue(rho_scale) # A depletion zone within the bulk requires an internal boundary # condition. Internal boundary conditions seem to challenge fipy, see: # http://www.ctcms.nist.gov/fipy/documentation/USAGE.html#applying-internal-boundary-conditions large_value = 1e+10 # Hack for optimizer if depletion_mask is not None: # FIXME: Generic depletion_mask not working # Is overwritten here with a simple 1D depletion mask depletion_mask = np.logical_and(potential.mesh.y > y_dep_new[0], potential.mesh.y > y_dep_new[0]) potential.equation = (fipy.DiffusionTerm(coeff=epsilon_scaled) + charge == fipy.ImplicitSourceTerm( depletion_mask * large_value) - depletion_mask * large_value * V_bias) else: potential.equation = (fipy.DiffusionTerm(coeff=epsilon_scaled) + charge == 0.) # Calculate boundaries backplane = mesh.getFacesTop() readout_plane = mesh.getFacesBottom() electrodes = readout_plane bcs = [fipy.FixedValue(value=V_bias, faces=backplane)] X, _ = mesh.getFaceCenters() for pixel in range(n_pixel): pixel_position = width * (pixel + 1. / 2.) - width * n_pixel / 2. bcs.append( fipy.FixedValue( value=V_readout if pixel_position == 0. else 0., faces=electrodes & (X > pixel_position - pitch / 2.) & (X < pixel_position + pitch / 2.))) solver.solve(potential, equation=potential.equation, boundaryConditions=bcs) return potential
def solveSectionThermal(self, TPrim, hConvPrim, TSec, hConvSec, TExt, hConvExt): # Initialize convergence criteria res = 1e10 n = 0 # Run the non-linear iteration loop while (res > self.fvSolverSettings.tolerance and n < self.fvSolverSettings.maxNumIterations): # Interpolate temperature on faces TFaces = self.T.arithmeticFaceValue() # Compute thermal conductivity self.thermCond.setValue(self.thermCondModel(TFaces)) # Set up the equation ## Diffusion term eqT = FP.DiffusionTerm(coeff=self.thermCond) ## Source terms (implicit + explicit) emulating boundary conditions eqT += -FP.ImplicitSourceTerm( self.cPrimCoeff * hConvPrim) + self.cPrimCoeff * hConvPrim * TPrim eqT += -FP.ImplicitSourceTerm( self.cSecCoeff * hConvSec) + self.cSecCoeff * hConvSec * TSec eqT += -FP.ImplicitSourceTerm( self.cExtCoeff * hConvExt) + self.cExtCoeff * hConvExt * TExt # Linear solve res = eqT.sweep( var=self.T, solver=self.linSolver, underRelaxation=self.fvSolverSettings.relaxationFactor) #print n, res n += 1
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 __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 calculate_planar_sensor_potential(width, pitch, n_pixel, thickness, resolution, V_backplane, V_readout=0): points, cells = pg.generate_mesh(mesh_planar_sensor(x=width * n_pixel, thickness=thickness, resolution=resolution)) mio.write('sensor.msh', points, cells) mesh = fipy.GmshImporter2D('sensor.msh') potential = fipy.CellVariable(mesh=mesh, name='potential', value=0.) permittivity = 1. potential.equation = (fipy.DiffusionTerm(coeff=permittivity) == 0.) # Calculate boundaries V_backplane = V_backplane backplane = mesh.getFacesTop() V_readout = V_readout readout_plane = mesh.getFacesBottom() electrodes = readout_plane bcs = [fipy.FixedValue(value=V_backplane, faces=backplane)] X, _ = mesh.getFaceCenters() for pixel in range(n_pixel): pixel_position = width * (pixel + 1. / 2.) - width * n_pixel / 2. bcs.append(fipy.FixedValue(value=V_readout, faces=electrodes & (X > pixel_position - pitch / 2.) & (X < pixel_position + pitch / 2.))) potential.equation.solve(var=potential, boundaryConditions=bcs) return potential
def _Execute(self): input = self.GetPolyDataInput() self.mesh = FiPyTriangleMesher(input).GetMesh() self.speed = fipy.CellVariable(name="speed", mesh=self.mesh, value=0.) self.speed.constrain(0., where=self.mesh.exteriorFaces) # self.BCs = (fipy.FixedValue(faces=self.mesh.exteriorFaces, value=0),) self.equation = fipy.DiffusionTerm() + 1. == 0. self.equation.solve(var=self.speed) #, boundaryConditions=self.BCs) # FiPy API doesn't seem to have an integrate method #volumeFlux = self.speed.getCellVolumeAverage() * self.speed.mesh.getCellVolumes().sum() # Scale such that the flux will be unity #self.speed /= volumeFlux self.speed /= self.speed.mesh.getCellVolumes().sum() #print self.speed #print self.speed.getCellVolumeAverage(), self.speed.mesh.getCellVolumes().sum() output = self.GetPolyDataOutput() output.ShallowCopy(input) speed = convert.numpy_to_vtk(self.speed.getValue()) output.GetCellData().SetScalars(speed) return
def calculate_3D_sensor_potential(pitch_x, pitch_y, n_pixel_x, n_pixel_y, radius, resolution, V_readout, V_bias, nD=2): points, cells = pg.generate_mesh(mesh_3D_sensor(x=pitch_x, y=pitch_y, n_pixel_x=n_pixel_x, n_pixel_y=n_pixel_y, radius=radius, nD=nD, resolution=resolution)) mio.write('sensor.msh', points, cells) mesh = fipy.GmshImporter2D('sensor.msh') plot.plot_mesh(mesh) potential = fipy.CellVariable(mesh=mesh, name='potential', value=0.) permittivity = 1. potential.equation = (fipy.DiffusionTerm(coeff=permittivity) == 0.) bcs = [] allfaces = mesh.getExteriorFaces() X,Y = mesh.getFaceCenters() # Readout pillars for pillar in range(nD): position = pitch_x / nD * (pillar + 1. / 2.) - pitch_x / 2. ring = allfaces & ( (X-position)**2+(Y)**2 < (radius)**2) bcs.append(fipy.FixedValue(value=V_readout,faces=ring)) # Bias pillars # Edges positions = [(- pitch_x / 2., - pitch_y / 2.), (+ pitch_x / 2., - pitch_y / 2.), (+ pitch_x / 2., + pitch_y / 2.), (- pitch_x / 2., + pitch_y / 2.)] # Sides positions += [(0, - pitch_y / 2.), (0, + pitch_y / 2.)] for pos_x, pos_y in positions: ring = allfaces & ( (X-pos_x)**2+(Y-pos_y)**2 < (radius)**2) bcs.append(fipy.FixedValue(value=V_bias, faces=ring)) # # Calculate boundaries # p_pillars = mesh.getFaces() # n_pillars = mesh.getFacesTop() # # electrodes = readout_plane # bcs = [fipy.FixedValue(value=V_backplane, faces=backplane)] # # for pixel in range(n_pixel): # pixel_position = width * (pixel + 1. / 2.) - width * n_pixel / 2. # bcs.append(fipy.FixedValue(value=V_readout, # faces=electrodes & # (X > pixel_position - pitch / 2.) & # (X < pixel_position + pitch / 2.))) potential.equation.solve(var=potential, boundaryConditions=bcs) return potential
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 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 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_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 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 solve(self): sideFaceFactor = fp.CellVariable( name="sideFaceFactor", mesh=self.mesh, value=self.areaExtFaces / (self.AcsMult * self.mesh.cellVolumes)) # Create variables self.TCore = fp.CellVariable(name="coreTemperature", mesh=self.mesh, value=self.TAmb) self.TSurface = fp.CellVariable(name="surfaceTemperature", mesh=self.mesh, value=self.TAmb) # Apply boundary conditions: self.applyBC(self.mesh.facesLeft(), self.BC[0], self.mesh.scaledFaceAreas[0] * self.AcsMult) self.applyBC(self.mesh.facesRight(), self.BC[1], self.mesh.scaledFaceAreas[-1] * self.AcsMult) # Create linear solver linSolver = LinearLUSolver(tolerance=1e-10) # Create base equation (thermal conduction): eq = fp.DiffusionTerm(coeff=self.thermalConductivity, var=self.TCore) if (self.jouleHeating['active']): eq += self.jouleHeating['j']**2 * self.jouleHeating['eResistivity'] if (self.radiation['active']): raise NotImplementedError('Radiation not implemented yet!') else: if (self.convection['active']): RAmb = 1. / self.convection['coefficient'] if (self.insulation['active']): RAmb += self.insulation['thickness'] / self.insulation[ 'thermConductivity'] eq += 1. / RAmb * (sideFaceFactor * self.TAmb - fp.ImplicitSourceTerm(coeff=sideFaceFactor, var=self.TCore)) eq.solve(var=self.TCore, solver=linSolver) if (self.convection['active'] and self.insulation['active']): # 0 - limited by conduction, 1 - limited by convection a1 = 1. / (RAmb * self.convection['coefficient']) self.TSurface.setValue(a1 * self.TCore() + (1 - a1) * self.TAmb) else: self.TSurface.setValue(self.TCore())
def solve(self): sideFaceFactor = fp.CellVariable(name = "sideFaceFactor", mesh = self.mesh, value = self.sideFaceAreas / (self.areaMult * self.mesh.cellVolumes)) # Initial conditions self.T.setValue(self.TAmb) # Run solverSettings solver = LinearLUSolver(tolerance=1e-10) if (self.solverSettings['nonlinear']): res = 1 sweep = 0 self.resVector = [] TFaces = self.T.arithmeticFaceValue() self.TLeft = [] self.TRight = [] self.QLeft = [] self.QRight = [] while (res > self.solverSettings['tolerance'] and sweep < self.solverSettings['maxIterations']): # Compute temperature dependent thermal conductivity self.thermCond.setValue(self.conduction['model'](TFaces)) # Add the conductivity term to the equation eqX = fp.DiffusionTerm(coeff = self.thermCond) if (self.radiation['active']): # Compute temperature dependent emissivity self.emissivity.setValue(self.emissivityCalculator(self.T())) # Add radiation term to the equation radMultiplier = sigmaSB * self.emissivity * sideFaceFactor eqX = eqX + radMultiplier * (self.TAmb**4 - self.T**4) # Perform iteration res = eqX.sweep(var = self.T, solver = solver, underRelaxation = self.solverSettings['relaxationFactor']) # Save residual self.resVector.append(res) # Save temperature and fluxes at the ends TFaces = self.T.arithmeticFaceValue() self.TLeft.append(TFaces[0]) self.TRight.append(TFaces[-1]) self.QLeft.append(self.QAx[0]) self.QRight.append(self.QAx[-1]) sweep += 1 else: eqX.solve(var = self.T)
def calculate_planar_sensor_w_potential(mesh, width, pitch, n_pixel, thickness): ''' Calculates the weighting field of a planar sensor. ''' _LOGGER.info('Calculating weighting potential') # Mesh validity check mesh_width = mesh.getFaceCenters()[0, :].max() - mesh.getFaceCenters()[ 0, :].min() if mesh_width != width * n_pixel: raise ValueError( 'The provided mesh width does not correspond to the sensor width') if mesh.getFaceCenters()[1, :].min() != 0: raise ValueError('The provided mesh does not start at 0.') if mesh.getFaceCenters()[1, :].max() != thickness: raise ValueError('The provided mesh does not end at sensor thickness.') potential = fipy.CellVariable(mesh=mesh, name='potential', value=0.) permittivity = 1. potential.equation = (fipy.DiffusionTerm(coeff=permittivity) == 0.) # Calculate boundaries backplane = mesh.getFacesTop() readout_plane = mesh.getFacesBottom() electrodes = readout_plane bcs = [fipy.FixedValue(value=0., faces=backplane)] X, _ = mesh.getFaceCenters() for pixel in range(n_pixel): pixel_position = width * (pixel + 1. / 2.) - width * n_pixel / 2. bcs.append( fipy.FixedValue(value=1.0 if pixel_position == 0. else 0., faces=electrodes & (X > pixel_position - pitch / 2.) & (X < pixel_position + pitch / 2.))) solver.solve(potential, equation=potential.equation, boundaryConditions=bcs) return potential
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 calculate_potential(mesh, rho, epsilon, V_read, V_bias, x_dep): r''' Calculate the potential with a given space charge distribution. If the depletion width is too large the resulting potential will have a minimum < bias voltage. This is unphysical. ''' # The field scales with rho / epsilon, thus scale to proper value to # counteract numerical instabilities epsilon_scaled = 1. rho_scale = rho / epsilon potential = fipy.CellVariable(mesh=mesh, name='potential', value=0.) electrons = fipy.CellVariable(mesh=mesh, name='e-') electrons.valence = -1 electrons.setValue(rho_scale) charge = electrons * electrons.valence charge.name = "charge" # A depletion zone within the bulk requires an internal boundary condition # Internal boundary conditions seem to challenge fipy, see: # http://www.ctcms.nist.gov/fipy/documentation/USAGE.html#applying-internal-boundary-conditions large_value = 1e+15 # Hack for optimizer mask = mesh.x > x_dep potential.equation = (fipy.DiffusionTerm(coeff=epsilon_scaled) - fipy.ImplicitSourceTerm(mask * large_value) + mask * large_value * V_bias + charge == 0) potential.constrain(V_read, mesh.facesLeft) potential.constrain(V_bias, mesh.facesRight) solver.solve(potential, equation=potential.equation) return potential
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 test_steady_state(): """ Test that we can create a steady-state model using FiPy that is similar to that given by our 'naive' solver """ continental_crust.heat_generation = u(1, 'mW/m^3') _ = continental_crust.to_layer(u(3000, 'm')) section = Section([_]) heatflow = u(15, 'mW/m^2') surface_temperature = u(0, 'degC') m = continental_crust q = heatflow k = m.conductivity a = m.heat_generation Cp = m.specific_heat rho = m.density def simple_heat_flow(x): # Density and heat capacity matter don't matter in steady-state T0 = surface_temperature return T0.to('K') + q * x / k + a / (2 * k) * x**2 p = simple_heat_flow(section.cell_centers) dx = section.cell_sizes[0] test_profile = p.into('degC') grad = (-q / k).into('K/m') # Divergence div = (-a / k).into('K/m^2') a_ = -N.gradient(N.gradient(test_profile, dx), dx) assert all(a_ < 0) assert N.allclose(a_.min(), div) res = steady_state(section, heatflow, surface_temperature) profile = res.profile.into('degC') assert N.allclose(test_profile, profile) solver = FiniteSolver(_) solver.constrain(surface_temperature, None) solver.constrain(heatflow, None) res2 = solver.steady_state() # Make sure it's nonlinear and has constant 2nd derivative arr = solver.var.faceGrad.divergence.value assert N.allclose(sum(arr - arr[0]), 0) assert N.allclose(arr.mean(), div) # Test simple finite element model mesh = F.Grid1D(nx=section.n_cells, dx=section.cell_sizes[0].into('m')) T = F.CellVariable(name="Temperature", mesh=mesh) T.constrain(surface_temperature.into("K"), mesh.facesLeft) A = F.FaceVariable(mesh=mesh, value=m.diffusivity.into("m**2/s")) rad_heat = F.CellVariable(mesh=mesh, value=(a / Cp / rho).into("K/s")) D = F.DiffusionTerm(coeff=A) + F.ImplicitSourceTerm(coeff=rad_heat) sol = D.solve(var=T) val = T.faceGrad.divergence.value arr = T.value - 273.15 #assert N.allclose(val.mean(), div) assert N.allclose(test_profile, arr) P = res2.profile.into('degC') assert N.allclose(test_profile, P)
# 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)) volumes = fp.CellVariable(mesh=mesh, value=mesh.cellVolumes)
meshmodule = import_module("mesh{}".format(params["problem"])) (mesh, inlet, outlet, walls, top_right) = meshmodule.mesh_and_boundaries(params) 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 x, y = mesh.cellCenters top_right_cell = fp.CellVariable(mesh=mesh, value=(x > max(x) - params["cellSize"]) & (y > max(y) - params["cellSize"])) large_value = 1e10 pressureCorrectionEq = ( fp.DiffusionTerm(coeff=coeff) - velocity.divergence -
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
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,
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$"
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 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
coeffD = D() * fp.numerix.exp(0.01 * phi) # --- Assign boundary conditions valueTop = -1.5 valueGradBottom = 0. phi.constrain(valueTop, where=mesh.facesTop) phi.constrain(valueGradBottom, where=mesh.facesBottom) if __name__ == '__main__': viewer = fp.Viewer(vars=phi) #, datamin=-1.5, datamax=0.) viewer.plot() # --- Solve steady state groundwater flow equation eqSteady = (fp.DiffusionTerm(coeff=D() * fp.numerix.exp(0.01 * phi)) + np.gradient(coeffD())[0]) eqSteady.solve(var=phi) print phi() if __name__ == '__main__': viewer.plot() if __name__ == '__main__': raw_input("Implicit steady-state diffusion. Press <return> to proceed...") ################################################################################ ################################################################################ ##### -------------------- Solve the transport equation ------------------ ##### ################################################################################ theta = 0.4 # Effective porosity