def __init__(self, X=None, T=None, time_steps=5, max_time=0.4, num_cells=25, L=1.): """Initialize the objet. Keyword Arguments: X --- The sensor locations. T --- The sensor measurment times. time_steps --- How many timesteps do you want to measure. max_time --- The maximum solution time. num_cells --- The number of cells per dimension. L --- The size of the computational domain. """ assert isinstance(num_cells, int) self._num_cells = num_cells assert isinstance(L, float) and L > 0. self._dx = L / self.num_cells self._mesh = Grid2D(dx=self.dx, dy=self.dx, nx=self.num_cells, ny=self.num_cells) self._phi = CellVariable(name='solution variable', mesh=self.mesh) self._source = CellVariable(name='source term', mesh=self.mesh, hasOld=True) self._eqX = TransientTerm() == ExplicitDiffusionTerm( coeff=1.) + self.source self._eqI = TransientTerm() == DiffusionTerm(coeff=1.) + self.source self._eq = self._eqX + self._eqI assert isinstance(max_time, float) and max_time > 0. self._max_time = max_time #self.max_time / time_steps #. if X is None: idx = range(self.num_cells**2) else: idx = [] x1, x2 = self.mesh.cellCenters for x in X: dist = (x1 - x[0])**2 + (x2 - x[1])**2 idx.append(np.argmin(dist)) self._idx = idx if T is None: T = np.linspace(0, self.max_time, time_steps)[1:] self._max_time = T[-1] self._T = T self._dt = self.T[0] / time_steps super(Diffusion, self).__init__(5, len(self.T) * len(self.idx), name='Diffusion Solver')
def _buildEq(self): """ Build the equation to solve, we can change this method to impelement other schemes, e.g. Crank-Nicholson. """ # The current scheme is an implicit-upwind if self.q > 0.0: self.vr = self.vrVisc + self.vrTid self.eq = TransientTerm(var=self.Sigma) == - ExplicitUpwindConvectionTerm(coeff=self.vr, var=self.Sigma) else: self.vr = self.vrVisc mask_coeff = (self.mesh.facesLeft * self.mesh.faceNormals).getDivergence() self.eq = TransientTerm(var=self.Sigma) == - ExplicitUpwindConvectionTerm(coeff=self.vr, var=self.Sigma)\ - mask_coeff*3.0/2*self.nu/self.mesh.x*self.Sigma.old
def __solve_diffusion(self, model): oxygen_grid = model.environments[self.oxygen_env_name] nx = oxygen_grid.xsize ny = oxygen_grid.ysize nz = oxygen_grid.zsize dx = dy = dz = 1.0 D = self.oxygen_diffusion_coeff mesh = Grid3D(dx=dx, dy=dy, nx=nx, ny=ny, dz=dz, nz=nz) phi = CellVariable(name="solutionvariable", mesh=mesh) phi.setValue(0.) start = time.time() for _ in range(self.diffusion_solve_iterations): source_grid, sink_grid = self.__get_source_sink_grids(phi, model) eq = TransientTerm() == DiffusionTerm( coeff=D) + source_grid - sink_grid eq.solve(var=phi, dt=1) eq = TransientTerm() == DiffusionTerm(coeff=D) eq.solve(var=phi, dt=self.dt) end = time.time() print("Solving oxygen diffusion took %s seconds" % str(end - start)) return phi, nx, ny, nz
class Diffusion: def __init__(self, x, y, z, patch_l, D, timeStepDuration, steps): # Domain self.nx = int(x / patch_l) self.ny = int(y / patch_l) self.nz = int(z / patch_l) self.patch_l = patch_l self.D = D # mm2/hr self.timeStepDuration = timeStepDuration # hr self.steps = steps # number of steps self.mesh = PeriodicGrid3D(dx=self.patch_l, dy=self.patch_l, dz=self.patch_l, nx=self.nx, ny=self.ny, nz=self.nz) self.eq = TransientTerm() == DiffusionTerm(coeff=D) print("dx = {}, nx = {} zx {}".format(self.patch_l, self.nx, self.nz)) def run(self, initialConditions, step_n): pinit = np.zeros( self.nx * self.ny * self.nz) #TODO: how to map from the ABM domain to this form if initialConditions == None: for i in range(self.nx * self.ny * self.nz): pinit[i] = float( decimal.Decimal(random.randrange(8, 50)) / 1000000) #ng/mm3 else: pass print("Initial values:") print(pinit) phi = CellVariable(name="Concentration (ng/ml)", mesh=self.mesh, value=pinit) t = Variable(0.) for step in range(step_n): print("Time = {}".format(t.value)) self.eq.solve(var=phi, dt=self.timeStepDuration) t.setValue(t.value + self.timeStepDuration) return phi.value
def __init__(self, x, y, z, patch_l, D, timeStepDuration, steps): # Domain self.nx = int(x / patch_l) self.ny = int(y / patch_l) self.nz = int(z / patch_l) self.patch_l = patch_l self.D = D # mm2/hr self.timeStepDuration = timeStepDuration # hr self.steps = steps # number of steps self.mesh = PeriodicGrid3D(dx=self.patch_l, dy=self.patch_l, dz=self.patch_l, nx=self.nx, ny=self.ny, nz=self.nz) self.eq = TransientTerm() == DiffusionTerm(coeff=D) print("dx = {}, nx = {} zx {}".format(self.patch_l, self.nx, self.nz))
def test_init(self, model): with pytest.raises(TypeError): eqn = ModelEquation() COEFF = 3 eqn = ModelEquation(model, 'domain.abc', coeff=COEFF) assert eqn.varpath == 'domain.abc' assert eqn.term_transient == TransientTerm(var=eqn.var, coeff=COEFF) assert eqn.term_transient.coeff == COEFF assert eqn.term_diffusion is None assert eqn.sources_total is None assert not eqn.track_budget
def solve_pde( xmin, # domain min xmax, # domain max Tmax, # time max theta=1, # dynamics drift mu=0, # dynamics stable level sigma=1, # dynamics noise dx=0.01, # space discretization dt=0.01, # time discretization gbm=False): # state-dependent drift mesh = Grid1D(dx=dx, nx=(xmax - xmin) / dx) + xmin Tsteps = int(Tmax / dt) + 1 x_face = mesh.faceCenters x_cell = mesh.cellCenters[0] V = CellVariable(name="V", mesh=mesh, value=0.) # PDE if gbm: eq = TransientTerm( var=V) == (DiffusionTerm(coeff=float(sigma) * sigma / 2, var=V) - UpwindConvectionTerm( coeff=float(theta) * (x_face - float(mu)), var=V) + V * (float(theta) - x_cell)) else: eq = TransientTerm( var=V) == (DiffusionTerm(coeff=float(sigma) * sigma / 2, var=V) - UpwindConvectionTerm(coeff=float(theta) * (x_face - float(mu)), var=V) + V * float(theta)) # Boundary conditions V.constrain(1., mesh.facesRight) V.faceGrad.constrain([0.], mesh.facesLeft) # Solve by stepping in time sol = np.zeros((Tsteps, mesh.nx)) for step in range(Tsteps): eq.solve(var=V, dt=dt) sol[step] = V.value X = mesh.cellCenters.value[0] T = dt * np.arange(Tsteps) return T, X, sol
def define_ode(self, current_time): x, y = self.mesh.faceCenters # Internal source specificatio - currently no functional internal_source_value = self.parameter.internal_source_value internal_source_region = self.parameter.internal_source_region internal_source_mask = ( (x > internal_source_region.xmin) & (x < internal_source_region.xmax) & (y > internal_source_region.ymin) & (y < internal_source_region.ymax) ) # Get convection data convection = self.define_convection_variable(current_time) eq = TransientTerm() == - ConvectionTerm(coeff=convection) \ + DiffusionTerm(coeff=self.parameter.Diffusivity)\ - ImplicitSourceTerm(coeff=self.parameter.Decay)\ # + ImplicitSourceTerm(coeff=internal_source_value*internal_source_mask) # Internal source not working return eq
#!/usr/bin/env python from fipy import Grid1D, CellVariable, TransientTerm, DiffusionTerm, Viewer # m = Grid1D(nx=100, Lx=1.) # v0 = CellVariable(mesh=m, hasOld=True, value=0.5) v1 = CellVariable(mesh=m, hasOld=True, value=0.5) # v0.constrain(0, m.facesLeft) v0.constrain(1, m.facesRight) # v1.constrain(1, m.facesLeft) v1.constrain(0, m.facesRight) # eq0 = TransientTerm() == DiffusionTerm(coeff=0.01) - v1.faceGrad.divergence eq1 = TransientTerm() == v0.faceGrad.divergence + DiffusionTerm(coeff=0.01) # vi = Viewer((v0, v1)) # for t in range(100): v0.updateOld() v1.updateOld() res0 = res1 = 1e100 while max(res0, res1) > 0.1: res0 = eq0.sweep(var=v0, dt=1e-5) res1 = eq1.sweep(var=v1, dt=1e-5) if t % 10 == 0: vi.plot()
timeStepDuration = cfl * dx / abs(velocity) steps = 1000 mesh = Grid1D(dx = dx, nx = nx) startingArray = numerix.zeros(nx, 'd') startingArray[50:90] = 1. var = CellVariable( name = "advection variable", mesh = mesh, value = startingArray) var.constrain(valueLeft, mesh.facesLeft) var.constrain(valueRight, mesh.facesRight) eq = TransientTerm() - PowerLawConvectionTerm(coeff = (velocity,)) if __name__ == '__main__': viewer = Viewer(vars=(var,)) viewer.plot() raw_input("press key to continue") for step in range(steps): eq.solve(var, dt = timeStepDuration, solver = LinearLUSolver(tolerance = 1.e-15)) viewer.plot() viewer.plot() raw_input('finished')
shift = 1. KMVar = CellVariable(mesh=mesh, value=params['KM'] * shift, hasOld=1) KCVar = CellVariable(mesh=mesh, value=params['KC'] * shift, hasOld=1) TMVar = CellVariable(mesh=mesh, value=params['TM'] * shift, hasOld=1) TCVar = CellVariable(mesh=mesh, value=params['TC'] * shift, hasOld=1) P3Var = CellVariable(mesh=mesh, value=params['P3'] * shift, hasOld=1) P2Var = CellVariable(mesh=mesh, value=params['P2'] * shift, hasOld=1) RVar = CellVariable(mesh=mesh, value=params['R'], hasOld=1) PN = P3Var + P2Var KMscCoeff = params['chiK'] * (RVar + 1) * (1 - KCVar - KMVar.cellVolumeAverage) KMspCoeff = params['lambdaK'] / (1 + PN / params['kappaK']) KMEq = TransientTerm() - KMscCoeff + ImplicitSourceTerm(KMspCoeff) TMscCoeff = params['chiT'] * (1 - TCVar - TMVar.cellVolumeAverage) TMspCoeff = params['lambdaT'] * (KMVar + params['zetaT']) TMEq = TransientTerm() - TMscCoeff + ImplicitSourceTerm(TMspCoeff) TCscCoeff = params['lambdaT'] * (TMVar * KMVar).cellVolumeAverage TCspCoeff = params['lambdaTstar'] TCEq = TransientTerm() - TCscCoeff + ImplicitSourceTerm(TCspCoeff) PIP2PITP = PN / (PN / params['kappam'] + PN.cellVolumeAverage / params['kappac'] + 1) + params['zetaPITP'] P3spCoeff = params['lambda3'] * (TMVar + params['zeta3T']) P3scCoeff = params['chi3'] * KMVar * (PIP2PITP / (1 + KMVar / params['kappa3']) +
# d2gdx_a2 = grad(dgdx_a) # print (dgdx_a(0.4)) if GIBBS == "FH": dgdx_a = ((1.0 / N_A) - (1.0 / N_B)) + (1.0 / N_A) * numerix.log(x_a) - ( 1.0 / N_B) * numerix.log(1.0 - x_a) + chi_AB * (1.0 - 2 * x_a) d2gdx_a2 = (1.0 / (N_A * x_a)) + (1.0 / (N_B * (1.0 - x_a))) - 2 * chi_AB elif GIBBS != "FH": print("Implent more stuff you lazy f**k") # Define the equations # evaluating kappa kappa = (2.0 / 3.0) * chi_AB # eqn 1 is the 2nd order transport equation eq1 = (TransientTerm(var=x_a)) == DiffusionTerm(coeff=x_a * (1 - x_a), var=mu_AB) # Try constant mobility eq0 = (TransientTerm(var=x_a)) == DiffusionTerm(coeff=1, var=mu_AB) # eqn 2 is the chemical potential definition eq2 = (ImplicitSourceTerm(coeff=1., var=mu_AB)) == ImplicitSourceTerm( coeff=d2gdx_a2, var=x_a) - d2gdx_a2 * x_a + dgdx_a - DiffusionTerm( coeff=kappa, var=x_a) # write eq2 without the fipy trick: eq3 = (ImplicitSourceTerm( coeff=1, var=mu_AB)) == dgdx_a - DiffusionTerm(coeff=kappa, var=x_a) # Adding the equations together
dx = L / nx dy = L / ny mesh = Grid2D(dx, dy, nx, ny) phase = CellVariable(name = 'PhaseField', mesh = mesh, value = 1.) theta = ModularVariable(name = 'Theta', mesh = mesh, value = 1.) x, y = mesh.cellCenters theta.setValue(0., where=(x - L / 2.)**2 + (y - L / 2.)**2 < (L / 4.)**2) mPhiVar = phase - 0.5 + temperature * phase * (1 - phase) thetaMag = theta.old.grad.mag implicitSource = mPhiVar * (phase - (mPhiVar < 0)) implicitSource += (2 * s + epsilon**2 * thetaMag) * thetaMag phaseEq = TransientTerm(phaseTransientCoeff) == \ ExplicitDiffusionTerm(alpha**2) \ - ImplicitSourceTerm(implicitSource) \ + (mPhiVar > 0) * mPhiVar * phase if __name__ == '__main__': phaseViewer = Viewer(vars = phase) phaseViewer.plot() for step in range(steps): phaseEq.solve(phase, dt = timeStepDuration) phaseViewer.plot() input('finished')
#EQUATION SETUP BASIC DESCRIPTION '''Equations to solve for each varible must be defined: -TransientTerm = dvar/dt -ConvectionTerm = dvar/dx -DiffusionTerm = d^2var/dx^2 -Source terms can be described as they would appear mathematically Notes: coeff = terms that are multiplied by the Term.. must be rank-1 FaceVariable for ConvectionTerm "var" must be defined for each Term if they are not all the variable being solved for, otherwise will see "fipy.terms.ExplicitVariableError: Terms with explicit Variables cannot mix with Terms with implicit Variables." ''' #In English: dPion/dt = -1/q * divergence.Jp(x,t) - k_rec * Nion(x,t) * Pion(x,t) where # Jp = q * mu_p * E(x,t) * Pion(x,t) - q * Dp * grad.Pion(x,t) and E(x,t) = -grad.potential(x,t) # Continuity Equation Pion.equation = TransientTerm( coeff=1, var=Pion) == mu_p * (ConvectionTerm(coeff=potential.faceGrad, var=Pion) + Pion * potential.faceGrad.divergence) + DiffusionTerm( coeff=Dp, var=Pion) - k_rec * Pion * Nion #In English: dNion/dt = 1/q * divergence.Jn(x,t) - k_rec * Nion(x,t) * Pion(x,t) where # Jn = q * mu_n * E(x,t) * Nion(x,t) - q * Dn * grad.Nion(x,t) and E(x,t) = -grad.potential(x,t) # Continuity Equation Nion.equation = TransientTerm( coeff=1, var=Nion ) == -mu_n * (ConvectionTerm(coeff=potential.faceGrad, var=Nion) + Nion * potential.faceGrad.divergence) + DiffusionTerm( coeff=Dn, var=Nion) - k_rec * Pion * Nion #In English: d^2potential/dx^2 = -q/epsilon * Charge_Density and Charge Density = Pion + Nion
#ref: https://github.com/usnistgov/fipy/blob/develop/documentation/USAGE.rst#applying-robin-boundary-conditions #warning: avoid confusion between convectionCoeff in that fipy documentation, which refers to terms involving "a", and convectionCoeff here, which refers to a heat transfer convection coefficient at a boundary Gamma0 = D_thermal Gamma = FaceVariable(mesh=mesh, value=Gamma0) mask = surfaceFaces Gamma.setValue(0., where=mask) dPf = FaceVariable(mesh=mesh, value=mesh._faceToCellDistanceRatio * mesh.cellDistanceVectors) Af = FaceVariable(mesh=mesh, value=mesh._faceAreas) #RobinCoeff = (mask * Gamma0 * Af / (dPf.dot(a) + b)).divergence #a is zero in our case b = 1. RobinCoeff = (mask * Gamma0 * Af / b).divergence #a is zero in our case #eq = (TransientTerm() == DiffusionTerm(coeff=Gamma) + RobinCoeff * g - ImplicitSourceTerm(coeff=RobinCoeff * mesh.faceNormals.dot(a))) #a is zero in our case # g in this formulation is -convectionCoeff/k*var, where var=T-T_infinity eq = (TransientTerm() == DiffusionTerm(coeff=Gamma) + ImplicitSourceTerm(RobinCoeff * -convectionCoeff / k)) # embed() # sys.exit() #either show the fipy viewer or make a T(s,t) plot; doing both at once is too much of a hassle to debug showViewer = False #SETTING if showViewer: #viewer=Viewer(vars=var,datamin=T_infinity,datamax=T_initial) viewer = Viewer(vars=var) viewer.plot() dt_explicit = cellSize**2 / 2. / D_thermal
mesh = Grid2D(dx=dx, dy=dx, nx=nx, ny=ny) x0 = (L - boxSize) / 2 x1 = (L + boxSize) / 2 distanceVariable = DistanceVariable(mesh=mesh, value=1., hasOld=1) x, y = mesh.cellCenters distanceVariable.setValue(-1, where=((x0 < x) & (x < x1)) & ((x0 < y) & (y < x1))) surfactantVariable = SurfactantVariable(distanceVar=distanceVariable, value=1.) from fipy.variables.surfactantConvectionVariable import SurfactantConvectionVariable surfactantEquation = TransientTerm() - \ ExplicitUpwindConvectionTerm(SurfactantConvectionVariable(distanceVariable)) advectionEquation = TransientTerm() + AdvectionTerm(velocity) if __name__ == '__main__': distanceViewer = Viewer(vars=distanceVariable, datamin=-.001, datamax=.001) surfactantViewer = Viewer(vars=surfactantVariable, datamin=0., datamax=2.) distanceVariable.calcDistanceFunction() for step in range(steps): print numerix.sum(surfactantVariable) distanceVariable.updateOld() surfactantEquation.solve(surfactantVariable, dt=1) advectionEquation.solve(distanceVariable, dt=timeStepDuration)
dx = L / nx m = Grid1D(nx=nx, dx=dx) + X0 x, = m.cellCenters q = CellVariable(mesh=m, rank=1, elementshape=(2, )) q[0, :] = numerix.exp(-50 * (x - 0.3)**2) * numerix.cos(20 * (x - 0.3)) q[0, x > 0.3] = 0. Ax = FaceVariable(mesh=m, rank=3, value=[((0, K), (1 / rho, 0))], elementshape=(1, 2, 2)) eqn = TransientTerm() + CentralDifferenceConvectionTerm(Ax) == 0 if __name__ == '__main__': from fipy import MatplotlibViewer as Viewer vi = Viewer((q[0], q[1])) vi.plot() for step in range(500): eqn.solve(q, dt=cfl * dx) if step % 10 == 0 and __name__ == '__main__': vi.plot() if __name__ == '__main__': import fipy.tests.doctestPlus exec(fipy.tests.doctestPlus._getScript())
def runSimpleTrenchSystem(faradaysConstant=9.6e4, gasConstant=8.314, transferCoefficient=0.5, rateConstant0=1.76, rateConstant3=-245e-6, catalystDiffusion=1e-9, siteDensity=9.8e-6, molarVolume=7.1e-6, charge=2, metalDiffusion=5.6e-10, temperature=298., overpotential=-0.3, metalConcentration=250., catalystConcentration=5e-3, catalystCoverage=0., currentDensity0=0.26, currentDensity1=45., cellSize=0.1e-7, trenchDepth=0.5e-6, aspectRatio=2., trenchSpacing=0.6e-6, boundaryLayerDepth=0.3e-6, numberOfSteps=5, displayViewers=True): cflNumber = 0.2 numberOfCellsInNarrowBand = 10 cellsBelowTrench = 10 yCells = cellsBelowTrench \ + int((trenchDepth + boundaryLayerDepth) / cellSize) xCells = int(trenchSpacing / 2 / cellSize) from fipy.tools import serialComm mesh = Grid2D(dx = cellSize, dy = cellSize, nx = xCells, ny = yCells, communicator=serialComm) narrowBandWidth = numberOfCellsInNarrowBand * cellSize distanceVar = DistanceVariable( name = 'distance variable', mesh = mesh, value = -1., hasOld = 1) bottomHeight = cellsBelowTrench * cellSize trenchHeight = bottomHeight + trenchDepth trenchWidth = trenchDepth / aspectRatio sideWidth = (trenchSpacing - trenchWidth) / 2 x, y = mesh.cellCenters distanceVar.setValue(1., where=(y > trenchHeight) | ((y > bottomHeight) & (x < xCells * cellSize - sideWidth))) distanceVar.calcDistanceFunction(order=2) catalystVar = SurfactantVariable( name = "catalyst variable", value = catalystCoverage, distanceVar = distanceVar) bulkCatalystVar = CellVariable( name = 'bulk catalyst variable', mesh = mesh, value = catalystConcentration) metalVar = CellVariable( name = 'metal variable', mesh = mesh, value = metalConcentration) expoConstant = -transferCoefficient * faradaysConstant / (gasConstant * temperature) tmp = currentDensity1 * catalystVar.interfaceVar exchangeCurrentDensity = currentDensity0 + tmp expo = numerix.exp(expoConstant * overpotential) currentDensity = expo * exchangeCurrentDensity * metalVar / metalConcentration depositionRateVariable = currentDensity * molarVolume / (charge * faradaysConstant) extensionVelocityVariable = CellVariable( name = 'extension velocity', mesh = mesh, value = depositionRateVariable) surfactantEquation = AdsorbingSurfactantEquation( surfactantVar = catalystVar, distanceVar = distanceVar, bulkVar = bulkCatalystVar, rateConstant = rateConstant0 + rateConstant3 * overpotential**3) advectionEquation = TransientTerm() + AdvectionTerm(extensionVelocityVariable) metalEquation = buildMetalIonDiffusionEquation( ionVar = metalVar, distanceVar = distanceVar, depositionRate = depositionRateVariable, diffusionCoeff = metalDiffusion, metalIonMolarVolume = molarVolume, ) metalVar.constrain(metalConcentration, mesh.facesTop) from .surfactantBulkDiffusionEquation import buildSurfactantBulkDiffusionEquation bulkCatalystEquation = buildSurfactantBulkDiffusionEquation( bulkVar = bulkCatalystVar, distanceVar = distanceVar, surfactantVar = catalystVar, diffusionCoeff = catalystDiffusion, rateConstant = rateConstant0 * siteDensity ) bulkCatalystVar.constrain(catalystConcentration, mesh.facesTop) if displayViewers: try: from .mayaviSurfactantViewer import MayaviSurfactantViewer viewer = MayaviSurfactantViewer(distanceVar, catalystVar.interfaceVar, zoomFactor = 1e6, datamax=0.5, datamin=0.0, smooth = 1, title = 'catalyst coverage') except: viewer = MultiViewer(viewers=( Viewer(distanceVar, datamin=-1e-9, datamax=1e-9), Viewer(catalystVar.interfaceVar))) else: viewer = None levelSetUpdateFrequency = int(0.8 * narrowBandWidth \ / (cellSize * cflNumber * 2)) for step in range(numberOfSteps): if step>5 and step % 5 == 0 and viewer is not None: viewer.plot() if step % levelSetUpdateFrequency == 0: distanceVar.calcDistanceFunction(order=2) extensionVelocityVariable.setValue(depositionRateVariable()) distanceVar.updateOld() distanceVar.extendVariable(extensionVelocityVariable, order=2) dt = cflNumber * cellSize / extensionVelocityVariable.max() advectionEquation.solve(distanceVar, dt = dt) surfactantEquation.solve(catalystVar, dt = dt) metalEquation.solve(metalVar, dt = dt) bulkCatalystEquation.solve(bulkCatalystVar, dt = dt, solver=GeneralSolver(tolerance=1e-15, iterations=2000)) try: import os filepath = os.path.splitext(__file__)[0] + '.gz' print(catalystVar.allclose(numerix.loadtxt(filepath), rtol = 1e-4)) except: return 0
value = 1., hasOld = 1 ) x, y = mesh.cellCenters cellRadius = numerix.sqrt((x - L / 2.)**2 + (y - L / 2.)**2) distanceVariable.setValue(cellRadius - initialRadius) initialSurfactantValue = 1. surfactantVariable = SurfactantVariable( value = initialSurfactantValue, distanceVar = distanceVariable ) advectionEquation = TransientTerm() + AdvectionTerm(velocity) from fipy.variables.surfactantConvectionVariable import SurfactantConvectionVariable surfactantEquation = TransientTerm() - \ ExplicitUpwindConvectionTerm(SurfactantConvectionVariable(distanceVariable)) if __name__ == '__main__': distanceViewer = Viewer(vars=distanceVariable, datamin=-initialRadius, datamax=initialRadius) surfactantViewer = Viewer(vars=surfactantVariable, datamin=-1., datamax=100.) distanceViewer.plot() surfactantViewer.plot() print('total surfactant before:', numerix.sum(surfactantVariable * mesh.cellVolumes))
class Circumbinary(object): def __init__(self, rmax=1.0e4, ncell=300, dt=1.0e-6, delta=1.0e-100, fudge=1.0e-3, q=1.0, gamma=100, mdisk=0.1, odir='output', bellLin=True, emptydt=0.001, **kargs): self.rmax = rmax self.ncell = ncell self.dt = dt self.delta = delta self.mDisk = mdisk Omega0 = (G*M/(gamma*a)**3)**0.5 nu0 = alpha*cs**2/Omega0 self.chi = 2*fudge*q**2*np.sqrt(G*M)/nu0/a*(gamma*a)**1.5 self.T0 = mu*Omega0/alpha/k*nu0 self.gamma = gamma self.fudge = fudge self.q = q self.nu0 = nu0 self.t = 0.0 self.odir = odir self.bellLin = bellLin self.emptydt = emptydt self._genGrid() self.r = self.mesh.cellCenters.value[0] self.rF = self.mesh.faceCenters.value[0] if self.q > 0.0: self.gap = np.where(self.rF < 1.7/gamma) else: self.gap = np.where(self.rF < 1.0/gamma) self._genSigma() self._genTorque() self._genT(bellLin=self.bellLin, **kargs) self._genVr() self._buildEq() def _genGrid(self, inB=1.0): """Generate a logarithmically spaced grid""" logFaces = np.linspace(-np.log(self.gamma/inB), np.log(self.rmax), num=self.ncell+1) logFacesLeft = logFaces[:-1] logFacesRight = logFaces[1:] dr = tuple(np.exp(logFacesRight) - np.exp(logFacesLeft)) self.mesh = CylindricalGrid1D(dr=dr, origin=(inB/self.gamma,)) def _genSigma(self, width=0.1): """Create dependent variable Sigma""" # Gaussian initial condition value = self.mDisk*M/np.sqrt(2*np.pi)/(self.gamma*a*width)*\ np.exp(-0.5*np.square(self.r-1.0)/width**2)/(2*np.pi*self.gamma*self.r*a) # Make it dimensionless value /= self.mDisk*M/(self.gamma*a)**2 idxs = np.where(self.r < 0.1) value[idxs] = 0.0 value = tuple(value) # Create the dependent variable and set the boundary conditions # to zero self.Sigma = CellVariable(name='Surface density', mesh=self.mesh, hasOld=True, value=value) #self.Sigma.constrain(0, self.mesh.facesLeft) #self.Sigma.constrain(0, self.mesh.facesRight) def _genTorque(self): """Generate Torque""" self.Lambda = FaceVariable(name='Torque at cell faces', mesh=self.mesh, rank=1) self.LambdaCell = CellVariable(name='Torque at cell centers', mesh=self.mesh) LambdaArr = np.zeros(self.rF.shape) LambdaArr[1:] = self.chi*np.power(1.0/(self.rF[1:]*self.gamma-1.0), 4) #LambdaArr[self.gap] = 0.0; LambdaArr[self.gap] = LambdaArr.max() self.Lambda.setValue(LambdaArr) self.LambdaCell.setValue(self.chi*np.power(1.0/(self.r*self.gamma-1.0), 4)) self.LambdaCell[np.where(self.LambdaCell > LambdaArr.max())] = LambdaArr.max() def _interpT(self): """ Get an initial guess for T using an interpolation of the solutions for T in the various thermodynamic limits. """ Lambda = self.Lambda/self.chi*self.fudge*self.q**2*G*M/a LambdaCell = self.LambdaCell/self.chi*self.fudge*self.q**2*G*M/a Sigma = self.Sigma*M/(self.gamma*a)**2 r = self.r*a*self.gamma #In physical units (cgs) self.Omega = np.sqrt(G*M/r**3) self.TvThin = np.power(9.0/4*alpha*k/sigma/mu/kappa0*self.Omega, 1.0/(3.0+beta)) self.TtiThin = np.power(1/sigma/kappa0*(OmegaIn-self.Omega)*LambdaCell, 1.0/(4.0+beta)) self.Ti = np.power(np.square(eta/7*L/4/np.pi/sigma)*k/mu/G/M*r**(-3), 1.0/7) self.TvThick = np.power(27.0/64*kappa0*alpha*k/sigma/mu*self.Omega*Sigma**2, 1.0/(3.0-beta)) self.TtiThick = np.power(3*kappa0/16/sigma*Sigma**2*(OmegaIn-self.Omega)*LambdaCell, 1.0/(4.0-beta)) #return np.power(self.TvThin**4 + self.TvThick**4 + self.TtiThin**4 + self.TtiThick**4 + self.Ti**4, 1.0/4)/self.T0 return np.power(self.TvThin**4 + self.TvThick**4 + self.Ti**4, 1.0/4)/self.T0 def _genT(self, bellLin=True, **kargs): """Create a cell variable for temperature""" if bellLin: @pickle_results(os.path.join(self.odir, "interpolator.pkl")) def buildInterpolator(r, gamma, q, fudge, mDisk, **kargs): # Keep in mind that buildTemopTable() returns the log10's of the values rGrid, SigmaGrid, temp = thermopy.buildTempTable(r*a*gamma, q=q, f=fudge, **kargs) # Go back to dimensionless units rGrid -= np.log10(a*gamma) SigmaGrid -= np.log10(mDisk*M/gamma**2/a**2) # Get the range of values for Sigma in the table rangeSigma = (np.power(10.0, SigmaGrid.min()), np.power(10.0, SigmaGrid.max())) # Interpolate in the log of dimensionless units return rangeSigma, RectBivariateSpline(rGrid, SigmaGrid, temp) # Pass the radial grid in phsyical units # Get back interpolator in logarithmic space rangeSigma, log10Interp = buildInterpolator(self.r, self.gamma, self.q, self.fudge, self.mDisk, **kargs) rGrid = np.log10(self.r) SigmaMin = np.ones(rGrid.shape)*rangeSigma[0] SigmaMax = np.ones(rGrid.shape)*rangeSigma[1] r = self.r*a*self.gamma #In physical units (cgs) self.Omega = np.sqrt(G*M/r**3) Ti = np.power(np.square(eta/7*L/4/np.pi/sigma)*k/mu/G/M*r**(-3), 1.0/7) T = np.zeros(Ti.shape) # Define wrapper function that uses the interpolator and stores the results # in an array given as a second argument. It can handle zero or negative # Sigma values. def func(Sigma): good = np.logical_and(Sigma > rangeSigma[0], Sigma < rangeSigma[1]) badMin = np.logical_and(True, Sigma < rangeSigma[0]) badMax = np.logical_and(True, Sigma > rangeSigma[1]) if np.sum(good) > 0: T[good] = np.power(10.0, log10Interp.ev(rGrid[good], np.log10(Sigma[good]))) if np.sum(badMin) > 0: T[badMin] = np.power(10.0, log10Interp.ev(rGrid[badMin], np.log10(SigmaMin[badMin]))) if np.sum(badMax) > 0: raise ValueError("Extrapolation to large values of Sigma is not allowed, build a table with a larger Sigmax") T[badMax] = np.power(10.0, log10Interp.ev(rGrid[badMax], np.log10(SigmaMax[badMax]))) return T # Store interpolator as an instance method self._bellLinT = func # Save the temperature as an operator variable self.T = self.Sigma._UnaryOperatorVariable(lambda x: self._bellLinT(x)) # Initialize T with the interpolation of the various thermodynamic limits else: self.T = self._interpT() def _genVr(self): """Generate the face variable that stores the velocity values""" r = self.r #In dimensionless units (cgs) # viscosity at cell centers in cgs self.nu = alpha*k/mu/self.Omega/self.nu0*self.T self.visc = r**0.5*self.nu*self.Sigma #self.visc.grad.constrain([self.visc/2/self.r[0]], self.mesh.facesLeft) #self.Sigma.constrain(self.visc.grad/self.nu*2*self.r**0.5, where=self.mesh.facesLeft) # I add the delta to avoid divisions by zero self.vrVisc = -3/self.rF**(0.5)/(self.Sigma.faceValue + self.delta)*self.visc.faceGrad if self.q > 0.0: self.vrTid = self.Lambda*np.sqrt(self.rF) def _buildEq(self): """ Build the equation to solve, we can change this method to impelement other schemes, e.g. Crank-Nicholson. """ # The current scheme is an implicit-upwind if self.q > 0.0: self.vr = self.vrVisc + self.vrTid self.eq = TransientTerm(var=self.Sigma) == - ExplicitUpwindConvectionTerm(coeff=self.vr, var=self.Sigma) else: self.vr = self.vrVisc mask_coeff = (self.mesh.facesLeft * self.mesh.faceNormals).getDivergence() self.eq = TransientTerm(var=self.Sigma) == - ExplicitUpwindConvectionTerm(coeff=self.vr, var=self.Sigma)\ - mask_coeff*3.0/2*self.nu/self.mesh.x*self.Sigma.old def dimensionalSigma(self): """ Return Sigma in dimensional form (cgs) """ return self.Sigma.value*self.mDisk*M/(self.gamma*a)**2 def dimensionalFJ(self): """ Return the viscous torque in dimensional units (cgs) """ return 3*np.pi*self.nu.value*self.nu0*self.dimensionalSigma()*np.sqrt(G*M*self.r*a*self.gamma) def dimensionalTime(self, t=None, mode='yr'): """ Return current time in dimensional units (years or seconds) """ if t == None: t = self.t if mode == 'yr' or mode == 'years' or mode == 'year': return t*(a*self.gamma)**2/self.nu0/(365*24*60*60) else: return t*(a*self.gamma)**2/self.nu0 def dimensionlessTime(self, t, mode='yr'): """ Returns the dimensionless value of the time given as an argument """ if mode == 'yr' or mode == 'years' or mode == 'year': return t/(a*self.gamma)**2*self.nu0*(365*24*60*60) else: return t/(a*self.gamma)**2*self.nu0 def singleTimestep(self, dtMax=0.001, dt=None, update=True, emptyDt=False): """ Evolve the system for a single timestep of size `dt` """ if dt: self.dt = dt if emptyDt: vr = self.vr.value[0] if self.q == 0.0: vr[0] = -3.0/2*self.nu.faceValue.value[0]/self.rF[0] #vr[np.where(self.Sigma.value)] = self.delta self.flux = self.rF[1:]*vr[1:]-self.rF[:-1]*vr[:-1] self.flux = np.maximum(self.flux, self.delta) self.dts = self.mesh.cellVolumes/(self.flux) self.dts[np.where(self.Sigma.value == 0.0)] = np.inf self.dts[self.gap] = np.inf self.dt = self.emptydt*np.amin(self.dts) self.dt = min(dtMax, self.dt) try: self.eq.sweep(dt=self.dt) if np.any(self.Sigma.value < 0.0): self.singleTimestep(dt=self.dt/2) if update: self.Sigma.updateOld() self.t += self.dt except FloatingPointError: import ipdb; ipdb.set_trace() def evolve(self, deltaTime, **kargs): """ Evolve the system using the singleTimestep method """ tEv = self.t + deltaTime while self.t < tEv: dtMax = tEv - self.t self.singleTimestep(dtMax=dtMax, **kargs) def revert(self): """ Revert evolve method if update=False was used, otherwise it has no effect. """ self.Sigma.setValue(self.Sigma.old.value) def writeToFile(self): fName = self.odir + '/t{0}.pkl'.format(self.t) with open(fName, 'wb') as f: pickle.dump((self.t, self.Sigma.getValue()), f) def readFromFile(self, fName): with open(fName, 'rb') as f: t, Sigma = pickle.load(f) self.t = t self.Sigma.setValue(Sigma) def loadTimesList(self): path = self.odir files = os.listdir(path) if '.DS_Store' in files: files.remove('.DS_Store') if 'interpolator.pkl' in files: files.remove('interpolator.pkl') if 'init.pkl' in files: files.remove('init.pkl') self.times = np.zeros((len(files),)) for i, f in enumerate(files): match = re.match(r"^t((\d+(\.\d*)?|\.\d+)([eE][+-]?\d+)?)\.pkl", f) if match == None: print "WARNING: File {0} has an unexepected name".format(f) files.remove(f) continue self.times[i] = float(match.group(1)) self.times.sort() self.files = files def loadTime(self, t): """ Load the file with the time closest to `t` """ idx = (np.abs(self.times-t)).argmin() fName = self.odir + '/t'+str(self.times[idx]) + '.pkl' self.readFromFile(fName)
cfl = 0.1 K = 4. rho = 1. dx = L / nx m = Grid1D(nx=nx, dx=dx) + X0 x, = m.cellCenters q = CellVariable(mesh=m, rank=1, elementshape=(2,)) q[0,:] = numerix.exp(-50 * (x - 0.3)**2) * numerix.cos(20 * (x - 0.3)) q[0, x > 0.3] = 0. Ax = FaceVariable(mesh=m, rank=3, value=[((0, K), (1 / rho, 0))], elementshape=(1, 2, 2)) eqn = TransientTerm() + CentralDifferenceConvectionTerm(Ax) == 0 if __name__ == '__main__': from fipy import MatplotlibViewer as Viewer vi = Viewer((q[0], q[1])) vi.plot() for step in range(500): eqn.solve(q, dt=cfl * dx) if step % 10 == 0 and __name__ == '__main__': vi.plot() if __name__ == '__main__': import fipy.tests.doctestPlus exec(fipy.tests.doctestPlus._getScript())
timeStepDuration = cfl * dx / abs(velocity) steps = 1000 mesh = Grid1D(dx = dx, nx = nx) startingArray = numerix.zeros(nx, 'd') startingArray[50:90] = 1. var = CellVariable( name = "advection variable", mesh = mesh, value = startingArray) var.constrain(valueLeft, mesh.facesLeft) var.constrain(valueRight, mesh.facesRight) eq = TransientTerm() - PowerLawConvectionTerm(coeff = (velocity,)) if __name__ == '__main__': viewer = Viewer(vars=(var,)) viewer.plot() input("press key to continue") for step in range(steps): eq.solve(var, dt = timeStepDuration, solver = LinearLUSolver(tolerance = 1.e-15)) viewer.plot() viewer.plot() input('finished')
filename = 'infiniteCylinder01.msh' mesh = Gmsh2D(filename, communicator=serialComm) del filename T_initial = 425.08 #deg K var = CellVariable(mesh=mesh, value=T_initial) rho = 6980. #kg/m^3 cp = 227. #J/kg/K k = 59.6 #W/m/K D_thermal = k / rho / cp D = FaceVariable(mesh=mesh, value=D_thermal) eq = TransientTerm() == DiffusionTerm(coeff=D) X_faces, Y_faces = mesh.faceCenters surfaceFaces = (Y_faces > 0) & ( (X_faces**2 + Y_faces**2)**.5 > R_outer - cellSize / 10.) #convectionCoeff=200. #W/m^2/K Bi_desired = 10. convectionCoeff = Bi_desired * k / R_inner logging.info('convection coefficient is %.2E' % convectionCoeff) Bi = convectionCoeff * R_inner / k #Biot number logging.info('Biot number is %.2E' % Bi) T_infinity = 293.15 #deg K
phi[:] = noise D = a = epsilon = 1. # kappa = log(phi) N_A = 400 N_B = 400 chi_AB = 0.0075 kappa = chi_AB / 6.0 # dfdphi = a**2 * phi * (1 - phi) * (1 - 2 * phi) # dfdphi_ = a**2 * (1 - phi) * (1 - 2 * phi) # d2fdphi2 = a**2 * (1 - 6 * phi * (1 - phi)) dfdphi = ((1.0 / N_A) - (1.0 / N_B)) + (1.0 / N_A) * numerix.log(phi) - ( 1.0 / N_B) * numerix.log(1.0 - phi) + chi_AB * (1.0 - 2 * phi) d2fdphi2 = (1.0 / (N_A * phi)) + (1.0 / (N_B * (1.0 - phi))) - 2 * chi_AB eq1 = (TransientTerm(var=phi) == DiffusionTerm(coeff=D, var=psi)) eq2 = (ImplicitSourceTerm( coeff=1., var=psi) == ImplicitSourceTerm(coeff=d2fdphi2, var=phi) - d2fdphi2 * phi + dfdphi - DiffusionTerm(coeff=kappa, var=phi)) eq = eq1 & eq2 elapsed = 0. dt = 1.0 if __name__ == "__main__": duration = 1000. solver = LinearLUSolver(tolerance=1e-9, iterations=500) while elapsed < duration: elapsed += dt
def runSimpleTrenchSystem(faradaysConstant=9.6e4, gasConstant=8.314, transferCoefficient=0.5, rateConstant0=1.76, rateConstant3=-245e-6, catalystDiffusion=1e-9, siteDensity=9.8e-6, molarVolume=7.1e-6, charge=2, metalDiffusion=5.6e-10, temperature=298., overpotential=-0.3, metalConcentration=250., catalystConcentration=5e-3, catalystCoverage=0., currentDensity0=0.26, currentDensity1=45., cellSize=0.1e-7, trenchDepth=0.5e-6, aspectRatio=2., trenchSpacing=0.6e-6, boundaryLayerDepth=0.3e-6, numberOfSteps=5, displayViewers=True): cflNumber = 0.2 numberOfCellsInNarrowBand = 10 cellsBelowTrench = 10 yCells = cellsBelowTrench \ + int((trenchDepth + boundaryLayerDepth) / cellSize) xCells = int(trenchSpacing / 2 / cellSize) from fipy.tools import serialComm mesh = Grid2D(dx=cellSize, dy=cellSize, nx=xCells, ny=yCells, communicator=serialComm) narrowBandWidth = numberOfCellsInNarrowBand * cellSize distanceVar = DistanceVariable(name='distance variable', mesh=mesh, value=-1., hasOld=1) bottomHeight = cellsBelowTrench * cellSize trenchHeight = bottomHeight + trenchDepth trenchWidth = trenchDepth / aspectRatio sideWidth = (trenchSpacing - trenchWidth) / 2 x, y = mesh.cellCenters distanceVar.setValue(1., where=(y > trenchHeight) | ((y > bottomHeight) & (x < xCells * cellSize - sideWidth))) distanceVar.calcDistanceFunction(order=2) catalystVar = SurfactantVariable(name="catalyst variable", value=catalystCoverage, distanceVar=distanceVar) bulkCatalystVar = CellVariable(name='bulk catalyst variable', mesh=mesh, value=catalystConcentration) metalVar = CellVariable(name='metal variable', mesh=mesh, value=metalConcentration) expoConstant = -transferCoefficient * faradaysConstant \ / (gasConstant * temperature) tmp = currentDensity1 * catalystVar.interfaceVar exchangeCurrentDensity = currentDensity0 + tmp expo = numerix.exp(expoConstant * overpotential) currentDensity = expo * exchangeCurrentDensity * metalVar \ / metalConcentration depositionRateVariable = currentDensity * molarVolume \ / (charge * faradaysConstant) extensionVelocityVariable = CellVariable(name='extension velocity', mesh=mesh, value=depositionRateVariable) surfactantEquation = AdsorbingSurfactantEquation( surfactantVar=catalystVar, distanceVar=distanceVar, bulkVar=bulkCatalystVar, rateConstant=rateConstant0 + rateConstant3 * overpotential**3) advectionEquation = TransientTerm() + AdvectionTerm( extensionVelocityVariable) metalEquation = buildMetalIonDiffusionEquation( ionVar=metalVar, distanceVar=distanceVar, depositionRate=depositionRateVariable, diffusionCoeff=metalDiffusion, metalIonMolarVolume=molarVolume, ) metalVar.constrain(metalConcentration, mesh.facesTop) from surfactantBulkDiffusionEquation import buildSurfactantBulkDiffusionEquation bulkCatalystEquation = buildSurfactantBulkDiffusionEquation( bulkVar=bulkCatalystVar, distanceVar=distanceVar, surfactantVar=catalystVar, diffusionCoeff=catalystDiffusion, rateConstant=rateConstant0 * siteDensity) bulkCatalystVar.constrain(catalystConcentration, mesh.facesTop) if displayViewers: try: from mayaviSurfactantViewer import MayaviSurfactantViewer viewer = MayaviSurfactantViewer(distanceVar, catalystVar.interfaceVar, zoomFactor=1e6, datamax=0.5, datamin=0.0, smooth=1, title='catalyst coverage') except: viewer = MultiViewer( viewers=(Viewer(distanceVar, datamin=-1e-9, datamax=1e-9), Viewer(catalystVar.interfaceVar))) else: viewer = None levelSetUpdateFrequency = int(0.8 * narrowBandWidth \ / (cellSize * cflNumber * 2)) for step in range(numberOfSteps): if step > 5 and step % 5 == 0 and viewer is not None: viewer.plot() if step % levelSetUpdateFrequency == 0: distanceVar.calcDistanceFunction(order=2) extensionVelocityVariable.setValue(depositionRateVariable()) distanceVar.updateOld() distanceVar.extendVariable(extensionVelocityVariable, order=2) dt = cflNumber * cellSize / extensionVelocityVariable.max() advectionEquation.solve(distanceVar, dt=dt) surfactantEquation.solve(catalystVar, dt=dt) metalEquation.solve(metalVar, dt=dt) bulkCatalystEquation.solve(bulkCatalystVar, dt=dt, solver=GeneralSolver(tolerance=1e-15, iterations=2000)) try: import os filepath = os.path.splitext(__file__)[0] + '.gz' print catalystVar.allclose(numerix.loadtxt(filepath), rtol=1e-4) except: return 0
Plane Surface(11) = {10}; ''' % locals()) else: nx = 20 ny = nx dx = 1. dy = dx L = dx * nx mesh = Grid2D(dx=dx, dy=dy, nx=nx, ny=ny) #We create a :class:`~fipy.variables.cellVariable.CellVariable` and initialize it to zero: phi = CellVariable(name="solution variable", mesh=mesh, value=0.) #and then create a diffusion equation. This is solved by default with an #iterative conjugate gradient solver. D = 1. eq = TransientTerm() == DiffusionTerm(coeff=D) X, Y = mesh.faceCenters if doBlob: phi.constrain([random.random() for x in X], mesh.exteriorFaces) elif doCirc: phi.constrain(X, mesh.exteriorFaces) else: #We apply Dirichlet boundary conditions valueTopLeft = 0 valueBottomRight = 1 #to the top-left and bottom-right corners. Neumann boundary conditions #are automatically applied to the top-right and bottom-left corners.
# plt.plot(x, y01(x)) # plt.plot(x, y03(x)) # plt.show() mesh = Grid1D(dx=dx, nx=nx) # Establish mesh in how many dimensions necessary Pion = CellVariable(mesh=mesh, name='Positive ion Charge Density', value=y01(x)) Nion = CellVariable(mesh=mesh, name='Negative ion Charge Density', value=y02(x)) # Hole = CellVariable(mesh=mesh, name='Hole Density',value=y03(x)) # Electron = CellVariable(mesh=mesh, name='Electron Density',value=y04(x)) potential = CellVariable(mesh=mesh, name='Potential') #### Equations set-up #### # In English: dPion/dt = -1/q * divergence.Jp(x,t) - k_rec * Nion(x,t) * Pion(x,t) where # Jp = q * mu_p * E(x,t) * Pion(x,t) - q * Dp * grad.Pion(x,t) and E(x,t) = -grad.potential(x,t) # Continuity Equation Pion_equation = TransientTerm(coeff=1., var=Pion) == mu_p_1 * ConvectionTerm(coeff=potential.faceGrad, var=Pion) + Dp_1 * DiffusionTerm(coeff=1., var=Pion) - k_rec * Pion * Nion # In English: dNion/dt = 1/q * divergence.Jn(x,t) - k_rec * Nion(x,t) * Pion(x,t) where # Jn = q * mu_n * E(x,t) * Nion(x,t) - q * Dn * grad.Nion(x,t) and E(x,t) = -grad.potential(x,t) # Continuity Equation Nion_equation = TransientTerm(coeff=1., var=Nion) == -mu_n_1 * ConvectionTerm(coeff=potential.faceGrad, var=Nion) + Dn_1 * DiffusionTerm(coeff=1., var=Nion) - k_rec * Pion * Nion # Electron_equation = TransientTerm(coeff=1., var=Electron) == -mu_n_2 * ConvectionTerm(coeff=potential.faceGrad, var=Electron) + Dn_2 * DiffusionTerm(coeff=1., var=Electron) - k_rec * Electron * Hole # Hole_equation = TransientTerm(coeff=1., var=Hole) == mu_p_2 * ConvectionTerm(coeff=potential.faceGrad, var=Hole) + Dp_2 * DiffusionTerm(coeff=1., var=Hole) - k_rec * Electron * Hole # In English: d^2potential/dx^2 = -q/epsilon * Charge_Density and Charge Density= Pion-Nion # Poisson's Equation potential_equation = DiffusionTerm(coeff=1., var=potential) == -(q / epsilon) * (Pion - Nion) # potential_equation = DiffusionTerm(coeff=1., var=potential) == -(q / epsilon) * (Pion - Nion + Hole - Electron) ### Boundary conditions ### # Fipy is defaulted to be no-flux, so we only need to constrain potential potential.constrain(0., where=mesh.exteriorFaces)
""" # Order of file imports from the following import: input_handling.py, # parameters.py, variable_decl.py, boundary_init_cond from src.boundary_init_cond import * from src.calculate_coeffs import * # fipy.tools.numerix and dump is also imported from the above from fipy import TransientTerm, DiffusionTerm, Viewer, TSVViewer from fipy.solvers import * import os # For saving files to a specified directory from shutil import copyfile # ----------------- PDE Declarations ---------------------- # Density Equation density.equation = TransientTerm(coeff=1.0, var=density)\ == DiffusionTerm(coeff=Diffusivity, var=density) # Energy Equation temperature.equation = TransientTerm(coeff=density, var=temperature)\ == DiffusionTerm(coeff=(Diffusivity * density / zeta), var=temperature)\ + DiffusionTerm(coeff=Diffusivity * temperature, var=density) # Z Equation, Taylor-expanded model G = a + b * (Z - Z_S) + c * (Z - Z_S)**3 S_Z = ((c_n * temperature) / density**2) * density.grad[0]\ + (c_T / density) * temperature.grad[0] + G Z.equation = TransientTerm(coeff=epsilon, var=Z)\ == DiffusionTerm(coeff=mu, var=Z) + S_Z # Fully-Coupled Equation
temp_xR = (2 * temp_i[1:-1, :-2] - 2 * temp_i[1:-1, 1:-1]) / (dy**2) temp_f[1:-1, 1:-1] = temp_xx + temp_yy temp_f[-1, 1:-1] = temp_xR temp_f[0, 1:-1] = temp_xL temp_f[1:-1, 0] = temp_yL return temp_f #%% Phase Field Derivative #%% Phase Field Variable phase = CellVariable(name=r'$\phi$', mesh=mesh, hasOld=True) D_temp = CellVariable(name=r'$\Delta T$', mesh=mesh, hasOld=True) CHANGE_TEMP = 2.25 #%% Heat Equation heatEQ = (TransientTerm() == DiffusionTerm(CHANGE_TEMP) + (phase - phase.old) / D_time) #%% Parameter Setup # ALPHA = 0.015 # Alpha CONSTANT C_ani = 0.02 # Component of (D) the anisotropic diffusion tensor in 2D N = 6. # Symmetry THETA = np.pi / 8 # Orientation psi = THETA + np.arctan2(phase.faceGrad[1], phase.faceGrad[0]) PHI = np.tan(N * psi / 2) PHI_SQ = PHI**2 BETA = (1. - PHI_SQ) / (1. + PHI_SQ) D_BETA_D_PSI = -N * 2 * PHI / (1 + PHI_SQ) D_DIAG = (1 + C_ani * BETA)
def runGold(faradaysConstant=9.6e4, consumptionRateConstant=2.6e+6, molarVolume=10.21e-6, charge=1.0, metalDiffusion=1.7e-9, metalConcentration=20.0, catalystCoverage=0.15, currentDensity0=3e-2 * 16, currentDensity1=6.5e-1 * 16, cellSize=0.1e-7, trenchDepth=0.2e-6, aspectRatio=1.47, trenchSpacing=0.5e-6, boundaryLayerDepth=90.0e-6, numberOfSteps=10, taperAngle=6.0, displayViewers=True): cflNumber = 0.2 numberOfCellsInNarrowBand = 20 mesh = TrenchMesh(cellSize=cellSize, trenchSpacing=trenchSpacing, trenchDepth=trenchDepth, boundaryLayerDepth=boundaryLayerDepth, aspectRatio=aspectRatio, angle=numerix.pi * taperAngle / 180.) narrowBandWidth = numberOfCellsInNarrowBand * cellSize distanceVar = GapFillDistanceVariable(name='distance variable', mesh=mesh, value=-1.) distanceVar.setValue(1., where=mesh.electrolyteMask) distanceVar.calcDistanceFunction() catalystVar = SurfactantVariable(name="catalyst variable", value=catalystCoverage, distanceVar=distanceVar) metalVar = CellVariable(name='metal variable', mesh=mesh, value=metalConcentration) exchangeCurrentDensity = currentDensity0 + currentDensity1 * catalystVar.interfaceVar currentDensity = metalVar / metalConcentration * exchangeCurrentDensity depositionRateVariable = currentDensity * molarVolume / charge / faradaysConstant extensionVelocityVariable = CellVariable(name='extension velocity', mesh=mesh, value=depositionRateVariable) catalystSurfactantEquation = AdsorbingSurfactantEquation( catalystVar, distanceVar=distanceVar, bulkVar=0, rateConstant=0, consumptionCoeff=consumptionRateConstant * extensionVelocityVariable) advectionEquation = TransientTerm() + FirstOrderAdvectionTerm( extensionVelocityVariable) metalEquation = buildMetalIonDiffusionEquation( ionVar=metalVar, distanceVar=distanceVar, depositionRate=depositionRateVariable, diffusionCoeff=metalDiffusion, metalIonMolarVolume=molarVolume) metalVar.constrain(metalConcentration, mesh.facesTop) if displayViewers: try: from .mayaviSurfactantViewer import MayaviSurfactantViewer viewer = MayaviSurfactantViewer(distanceVar, catalystVar.interfaceVar, zoomFactor=1e6, datamax=1.0, datamin=0.0, smooth=1, title='catalyst coverage', animate=True) except: class PlotVariable(CellVariable): def __init__(self, var=None, name=''): CellVariable.__init__(self, mesh=mesh.fineMesh, name=name) self.var = self._requires(var) def _calcValue(self): return numerix.array(self.var(self.mesh.cellCenters)) viewer = MultiViewer( viewers=(Viewer( PlotVariable( var=distanceVar), datamax=1e-9, datamin=-1e-9), Viewer(PlotVariable(var=catalystVar.interfaceVar)))) else: viewer = None levelSetUpdateFrequency = int(0.7 * narrowBandWidth / cellSize / cflNumber / 2) step = 0 while step < numberOfSteps: if step % 10 == 0 and viewer is not None: viewer.plot() if step % levelSetUpdateFrequency == 0: distanceVar.calcDistanceFunction() extensionVelocityVariable.setValue( numerix.array(depositionRateVariable)) dt = cflNumber * cellSize / max(extensionVelocityVariable.globalValue) distanceVar.extendVariable(extensionVelocityVariable) advectionEquation.solve(distanceVar, dt=dt) catalystSurfactantEquation.solve(catalystVar, dt=dt) metalEquation.solve(metalVar, dt=dt) step += 1 point = ((5e-09, ), (1.15e-07, )) value = 1.45346701e-09 return abs(float(distanceVar(point, order=1)) - value) < cellSize / 10.0
def runGold(faradaysConstant=9.6e4, consumptionRateConstant=2.6e+6, molarVolume=10.21e-6, charge=1.0, metalDiffusion=1.7e-9, metalConcentration=20.0, catalystCoverage=0.15, currentDensity0=3e-2 * 16, currentDensity1=6.5e-1 * 16, cellSize=0.1e-7, trenchDepth=0.2e-6, aspectRatio=1.47, trenchSpacing=0.5e-6, boundaryLayerDepth=90.0e-6, numberOfSteps=10, taperAngle=6.0, displayViewers=True): cflNumber = 0.2 numberOfCellsInNarrowBand = 20 mesh = TrenchMesh(cellSize = cellSize, trenchSpacing = trenchSpacing, trenchDepth = trenchDepth, boundaryLayerDepth = boundaryLayerDepth, aspectRatio = aspectRatio, angle = numerix.pi * taperAngle / 180.) narrowBandWidth = numberOfCellsInNarrowBand * cellSize distanceVar = GapFillDistanceVariable( name = 'distance variable', mesh = mesh, value = -1.) distanceVar.setValue(1., where=mesh.electrolyteMask) distanceVar.calcDistanceFunction() catalystVar = SurfactantVariable( name = "catalyst variable", value = catalystCoverage, distanceVar = distanceVar) metalVar = CellVariable( name = 'metal variable', mesh = mesh, value = metalConcentration) exchangeCurrentDensity = currentDensity0 + currentDensity1 * catalystVar.interfaceVar currentDensity = metalVar / metalConcentration * exchangeCurrentDensity depositionRateVariable = currentDensity * molarVolume / charge / faradaysConstant extensionVelocityVariable = CellVariable( name = 'extension velocity', mesh = mesh, value = depositionRateVariable) catalystSurfactantEquation = AdsorbingSurfactantEquation( catalystVar, distanceVar = distanceVar, bulkVar = 0, rateConstant = 0, consumptionCoeff = consumptionRateConstant * extensionVelocityVariable) advectionEquation = TransientTerm() + FirstOrderAdvectionTerm(extensionVelocityVariable) metalEquation = buildMetalIonDiffusionEquation( ionVar = metalVar, distanceVar = distanceVar, depositionRate = depositionRateVariable, diffusionCoeff = metalDiffusion, metalIonMolarVolume = molarVolume) metalVar.constrain(metalConcentration, mesh.facesTop) if displayViewers: try: from .mayaviSurfactantViewer import MayaviSurfactantViewer viewer = MayaviSurfactantViewer(distanceVar, catalystVar.interfaceVar, zoomFactor = 1e6, datamax=1.0, datamin=0.0, smooth = 1, title = 'catalyst coverage', animate=True) except: class PlotVariable(CellVariable): def __init__(self, var = None, name = ''): CellVariable.__init__(self, mesh = mesh.fineMesh, name = name) self.var = self._requires(var) def _calcValue(self): return numerix.array(self.var(self.mesh.cellCenters)) viewer = MultiViewer(viewers=( Viewer(PlotVariable(var = distanceVar), datamax=1e-9, datamin=-1e-9), Viewer(PlotVariable(var = catalystVar.interfaceVar)))) else: viewer = None levelSetUpdateFrequency = int(0.7 * narrowBandWidth / cellSize / cflNumber / 2) step = 0 while step < numberOfSteps: if step % 10 == 0 and viewer is not None: viewer.plot() if step % levelSetUpdateFrequency == 0: distanceVar.calcDistanceFunction() extensionVelocityVariable.setValue(numerix.array(depositionRateVariable)) dt = cflNumber * cellSize / max(extensionVelocityVariable.globalValue) distanceVar.extendVariable(extensionVelocityVariable) advectionEquation.solve(distanceVar, dt = dt) catalystSurfactantEquation.solve(catalystVar, dt = dt) metalEquation.solve(metalVar, dt = dt) step += 1 point = ((5e-09,), (1.15e-07,)) value = 1.45346701e-09 return abs(float(distanceVar(point, order=1)) - value) < cellSize / 10.0
elif GIBBS != "FH": print("Implent more stuff you lazy f**k") # Define the equations # evaluating kappa kappa = (1.0 / 6.0) * chi_AB # # eqn 1 is the 2nd order transport equation # eq1 = (TransientTerm(var=x_a)) == DiffusionTerm(coeff = x_a * (1 - x_a), var=mu_AB) # # eqn 2 is the chemical potential definition # eq2 = (ImplicitSourceTerm(coeff=1. , var=mu_AB)) == ImplicitSourceTerm(coeff=d2gdx_a2, var=x_a) - d2gdx_a2 * x_a + dgdx_a - DiffusionTerm(coeff=kappa, var=x_a) # eq1 is the transport equation eq1 = (TransientTerm(coeff=numerix.exp(a), var=a)) == DiffusionTerm( coeff=numerix.exp(a) * (1.0 - numerix.exp(a)), var=mu_AB) #eq2 is the chemical potential eq2 = (ImplicitSourceTerm( coeff=1., var=mu_AB)) == dgda * (1.0 / numerix.exp(a)) - DiffusionTerm( coeff=kappa, var=exp_a) eq3 = (ImplicitSourceTerm(coeff=1, var=exp_a)) == numerix.exp(a) # Adding the equations together eq = eq1 & eq2 & eq3 elapsed = 0. dt = DT if __name__ == "__main__": duration = TIME_MAX
from fipy import CellVariable, Tri2D, TransientTerm, ExplicitDiffusionTerm, DefaultSolver, Viewer from fipy.tools import numerix dx = 1. dy = 1. nx = 10 ny = 1 valueLeft = 0. valueRight = 1. timeStepDuration = 0.02 mesh = Tri2D(dx, dy, nx, ny) var = CellVariable(name="concentration", mesh=mesh, value=valueLeft) eq = TransientTerm() == ExplicitDiffusionTerm() solver = DefaultSolver(tolerance=1e-6, iterations=1000) var.constrain(valueLeft, mesh.facesLeft) var.constrain(valueRight, mesh.facesRight) answer = numerix.array([ 0.00000000e+00, 0.00000000e+00, 0.00000000e+00, 0.00000000e+00, 0.00000000e+00, 0.00000000e+00, 1.58508452e-07, 6.84325019e-04, 7.05111362e-02, 7.81376523e-01, 0.00000000e+00, 0.00000000e+00, 0.00000000e+00, 0.00000000e+00, 0.00000000e+00, 0.00000000e+00, 0.00000000e+00, 4.99169535e-05, 1.49682805e-02, 3.82262622e-01, 0.00000000e+00, 0.00000000e+00, 0.00000000e+00, 0.00000000e+00, 0.00000000e+00, 0.00000000e+00, 0.00000000e+00, 4.06838361e-06, 3.67632029e-03, 1.82227062e-01, 0.00000000e+00, 0.00000000e+00,
def solve_Te(Qe_tot=2e6, H0=0, Hw=0.1, Te_bc=100, chi=1, a0=1, R0=3, E0=1.5, b_pos=0.98, b_height=6e19, b_sol=2e19, b_width=0.01, b_slope=0.01, nr=100, dt=100, plots=True): """ :param Qe_tot: heating power [W] :type Qe_tot: numpy float :param H0: position of Gaussian [-] :type H0: numpy float :param Hw: width of Gaussian [-] :type Hw: numpy float :param Te_bc: outer edge Te boundary condition [eV] :type Te_bc: numpy float :param chi: thermal diffusivity [?] :type chi: numpy float :param a0: minor radius [m] :type a0: numpy float :param R0: major radius [m] :type R0: numpy float :param E0: ellipticity :type E0: numpy float :param b_pos: position of density pedestal [-] :type b_pos: numpy float :param b_height: height of density pedestal [m^-3] :type b_height: numpy float :param b_sol: sol value for density pedestal [m^-3] :type b_sol: numpy float :param b_width: width of density pedestal [-] :type b_width: numpy float :param b_slope: slope of density pedestal [?] :type b_slope: numpy float :param nr: number of radial grid points :type nr: inteher :param dt: time-step [s] :type dt: numpy float :param plots: enable plots :type plots: boolean :return: array of Te values [eV] :type: numpy float array :return: array of ne values [m^-3] :type: numpy float array :return: rho values corresponding to the Te and ne values [m] :type: numpy float array :return: rho_norm values corresponding to the Te and ne values [-] :type: numpy float array [email protected] """ if plots: import os import matplotlib if not os.getenv("DISPLAY"): matplotlib.use('Agg') import matplotlib.pylab as plt import scipy.constants from fipy import Variable, FaceVariable, CellVariable, TransientTerm, DiffusionTerm, Viewer, meshes a = a0 * np.sqrt(E0) V = 2 * np.pi * 2 * np.pi * R0 mesh = meshes.CylindricalGrid1D(nr=nr, Lr=a) Te = CellVariable(name="Te", mesh=mesh, value=1e3) ne = CellVariable(name="ne", mesh=mesh, value=F_ped(mesh.cellCenters.value[0] / a, b_pos, b_height, b_sol, b_width, b_slope)) Qe = CellVariable(name="Qe", mesh=mesh, value=np.exp(-((mesh.cellCenters.value / a - H0) / (Hw))**2)[0]) Qe = Qe * Qe_tot / ((mesh.cellVolumes * Qe.value).sum() * V) print('Volume = %s m^3' % (mesh.cellVolumes.sum() * V)) print('Heating power = %0.3e W' % ((mesh.cellVolumes * Qe).sum() * V)) Te.constrain(Te_bc, mesh.facesRight) eqI = TransientTerm( coeff=scipy.constants.e * ne * 1.5) == DiffusionTerm(coeff=scipy.constants.e * ne * chi) + Qe if plots: viewer = Viewer(vars=(Te), title='Heating power = %0.3e W\nchi = %s' % (Qe.cellVolumeAverage.value * V, chi), datamin=0, datamax=5000) eqI.solve(var=Te, dt=dt) if plots: viewer.plot() return Te.value, ne.value, mesh.cellCenters.value[ 0], mesh.cellCenters.value[0] / a
Pion = CellVariable(mesh=mesh, name='Positive ion Charge Density', value=y01(mesh.x)) Nion = CellVariable(mesh=mesh, name='Negative ion Charge Density', value=y02(mesh.x)) potential = CellVariable(mesh=mesh, name='Potential', value=y03(mesh.x)) Jp = CellVariable(mesh=mesh, name='Positive ion Current Density', value=0.) Jn = CellVariable(mesh=mesh, name='Negative ion Current Density', value=0.) Jp.value = -mu_p * Pion * potential.arithmeticFaceValue.divergence + Dn * Pion.arithmeticFaceValue.divergence Jn.value = -mu_n * Nion * potential.arithmeticFaceValue.divergence + Dn * Pion.arithmeticFaceValue.divergence Pion.equation = TransientTerm( coeff=1, var=Pion) == -k_rec * Pion * Nion + (Jp.arithmeticFaceValue).divergence Nion.equation = TransientTerm( coeff=1, var=Nion) == -k_rec * Pion * Nion - (Jn.arithmeticFaceValue).divergence potential.equation = DiffusionTerm(coeff=epsilon, var=potential) == Pion - Nion Pion.constrain(0., where=mesh.facesLeft) Pion.constrain(0., where=mesh.facesRight) Nion.constrain(0., where=mesh.facesLeft) Nion.constrain(0., where=mesh.facesRight) potential.constrain(0., where=mesh.facesLeft) potential.constrain(0., where=mesh.facesRight) eq = Pion.equation & Nion.equation & potential.equation
# Setting the initial composition of the system with noise noise = UniformNoiseVariable(mesh=mesh, minimum=(a_0 - noise_mag), maximum=(a_0 + noise_mag)) a[:] = noise # differentiate g(a) dgda = ((1.0 / n_a) - (1.0 / n_b)) + (1.0 / n_a) * numerix.log(a) - ( 1.0 / n_b) * numerix.log(1.0 - a) + chi_AB * (1.0 - 2 * a) d2gda2 = (1.0 / (n_a * a)) + (1.0 / (n_b * (1.0 - a))) - 2 * chi_AB # Evaluate kappa kappa = (2.0 / 3.0) * chi_AB # Defining the equations eq1 = (TransientTerm(var=a)) == DiffusionTerm(coeff=a * (1.0 - a), var=mu_AB) eq2 = (ImplicitSourceTerm( coeff=1.0, var=mu_AB)) == dgda - DiffusionTerm(coeff=kappa, var=a) # eq2 = (ImplicitSourceTerm(coeff=1.0, var=mu_AB)) == ImplicitSourceTerm(coeff=d2gda2, var=a) - d2gda2*a + dgda - DiffusionTerm(coeff=kappa, var=a) # Coupling the equations eq = eq1 & eq2 # Setting up the solver solver = LinearLUSolver(tolerance=1e-9, iterations=50, precon="ilu") # Set up time stepping dt = 10.0 duration = 20000 time_stride = 100 timestep = 0
alpha = 0.015 temperature = 1. dx = L / nx mesh = Grid1D(dx=dx, nx=nx) phase = CellVariable(name='PhaseField', mesh=mesh, value=1.) theta = ModularVariable(name='Theta', mesh=mesh, value=1.) theta.setValue(0., where=mesh.cellCenters[0] > L / 2.) mPhiVar = phase - 0.5 + temperature * phase * (1 - phase) thetaMag = theta.old.grad.mag implicitSource = mPhiVar * (phase - (mPhiVar < 0)) implicitSource += (2 * s + epsilon**2 * thetaMag) * thetaMag phaseEq = TransientTerm(phaseTransientCoeff) == \ ExplicitDiffusionTerm(alpha**2) \ - ImplicitSourceTerm(implicitSource) \ + (mPhiVar > 0) * mPhiVar * phase if __name__ == '__main__': phaseViewer = Viewer(vars=phase) phaseViewer.plot() for step in range(steps): phaseEq.solve(phase, dt=timeStepDuration) phaseViewer.plot() input('finished')
C.append( CellVariable(name=components[i].encode(), mesh=mesh, value=c[i * nxyz:(i + 1) * nxyz])) C[i].constrain(bc_conc[i], mesh.facesLeft) C[i].faceGrad.constrain(0, mesh.facesRight) if __name__ == '__main__': viewer = Viewer(vars=(C[4]), datamin=0., datamax=1e-4) viewer.plot() #=================================================== D = 0.0 # assume there is no diffusion except numerical diffusion hahahaha u = (1.5 / 432000, ) # m/s equivalent to 1 dt/day eqX = [] for i in range(ncomps): if (i != 4): eqX.append(TransientTerm() == DiffusionTerm(coeff=D) - UpwindConvectionTerm(coeff=u)) else: # I am assuming that microbes are attached #eqX.append(TransientTerm() == DiffusionTerm(coeff=D)) eqX.append(TransientTerm() == DiffusionTerm(coeff=D) - UpwindConvectionTerm(coeff=u)) #timeStepDuration = 0.9 * dx**2 / (2 * D) # the maximum time step time_step = 432000.0 t = 0 C_old = list(C) steps = -1 t_final = 120 * 432000.0 tol = 0.1 trial = 0 H2SProductionData = np.zeros((maxTimeStep, nxyz), dtype='float')
steps = int(L / 4. / dt / velocity) mesh = Grid1D(dx=dx, nx=nx) periodicMesh = PeriodicGrid1D(dx=dx, nx=nx // 2) startingArray = numerix.zeros(nx, 'd') startingArray[2 * nx // 10:3 * nx // 10] = 1. var1 = CellVariable(name="non-periodic", mesh=mesh, value=startingArray) var2 = CellVariable(name="periodic", mesh=periodicMesh, value=startingArray[:nx // 2]) eq1 = TransientTerm() - VanLeerConvectionTerm(coeff=(-velocity, )) eq2 = TransientTerm() - VanLeerConvectionTerm(coeff=(-velocity, )) if __name__ == '__main__': viewer1 = Viewer(vars=var1) viewer2 = Viewer(vars=var2) viewer1.plot() viewer2.plot() newVar2 = var2.copy() for step in range(steps): eq1.solve(var=var1, dt=dt, solver=DefaultAsymmetricSolver()) eq2.solve(var=var2, dt=dt, solver=DefaultAsymmetricSolver()) viewer1.plot()
source = (phase - lamda * uu * (1 - phase**2)) * (1 - phase**2) theta = numerix.arctan2(phase.faceGrad[1], phase.faceGrad[0]) W = W_0 * (1 + epsilon_m * numerix.cos(mm * theta - theta_0)) W_theta = - W_0 * mm * epsilon_m * numerix.sin(mm * theta - theta_0) # Build up the diffusivity matrix I0 = Variable(value=((1,0), (0,1))) I1 = Variable(value=((0,-1), (1,0))) Dphase = W**2 * I0 + W * W_theta * I1 heat_eqn = TransientTerm() == DiffusionTerm(DD) + (phase - phase.old) / dt / 2. phase_eqn = TransientTerm(tau) == DiffusionTerm(Dphase) + source initialize() solid_area = (np.array(phase.globalValue)>0).sum()*dx*dy # initial size of solid nucleus if parallelComm.procID==0: print 'solid area', solid_area total_steps = 20000 sweeps = 2 tolerance = 0.5 # Serial: #from fipy.solvers.pysparse import LinearLUSolver as Solver