def TwoGaussianImmuneResponse2D(strength, x, y, Ra): #Test : plt.plot(r,10*numerix.exp(-r**2/(2*dz))/numerix.sqrt(2*numerix.pi*2*dz)) return ((strength) * numerix.exp(-((x + 0.6)**2 + (y - 0.3)**2) / (2 * Ra)) + (strength) * numerix.exp(-((x - 0.6)**2 + (y - 0.2)**2) / (2 * Ra))) / (numerix.sqrt( 2 * numerix.pi * Ra))
def calc_dep_vars(self, params): Fbar = params.faradaysConstant / params.gasConstant / params.temperature self.coeff_forward0 = params.alpha0 * Fbar self.coeff_backward0 = (params.alpha_ - params.alpha0) * Fbar self.coeff_forward1 = params.alpha1 * Fbar self.coeff_backward1 = (params.alpha_ - params.alpha1) * Fbar exp_forward0 = numerix.exp(self.coeff_forward0 * self.potential) exp_backward0 = numerix.exp(-self.coeff_backward0 * self.potential) exp_forward1 = numerix.exp(self.coeff_forward1 * self.potential) exp_backward1 = numerix.exp(-self.coeff_backward1 * self.potential) cbar = self.cupric / params.bulkCupric I0 = params.i0 * (1 - self.interfaceTheta) I1 = params.i1 * self.interfaceTheta self.beta_forward0 = cbar * I0 * exp_forward0 self.beta_backward0 = cbar * I0 * exp_backward0 self.beta_forward1 = cbar * I1 * exp_forward1 self.beta_backward1 = cbar * I1 * exp_backward1 self.baseCurrent = I0 * (exp_forward0 - exp_backward0) + I1 * (exp_forward1 - exp_backward1) self.currentDensity = cbar * self.baseCurrent self.currentDerivative = cbar * (I0 * (self.coeff_forward0 * exp_forward0 + self.coeff_backward0 * exp_backward0) \ + I1 * (self.coeff_forward1 * exp_forward1 + self.coeff_backward1 * exp_backward1)) self.depositionRate = self.currentDensity * params.omega / params.charge / params.faradaysConstant
def calc_BV(self, j0, overpotential): # Coded here is the RHS of the BV equation # print(overpotential) # Code to debug the exponential overflow issue when the number of nodes in each domain is changed # print(numerix.exp(((1-self.alpha)*F*(overpotential))/(R*self.T))) # Overpotential values are high, causing the exponents to overflow, it seems.. # print(numerix.exp((-self.alpha*F*(overpotential))/(R*self.T))) return (j0 * ( numerix.exp( ((1 - self.alpha) * F * (overpotential)) / (R * self.T) ) # Returns a value for "j", flux density on the LHS of the equation - numerix.exp((-self.alpha * F * (overpotential)) / (R * self.T))))
def __call__(self, x): """Evaluate the solver.""" self.phi.value = 0. x_center = x[:2] tau = x[2] h = x[3] s = x[4] x, y = self.mesh.cellCenters self.source.value = 0.5 * s / (math.pi * h**2) * numerix.exp(-0.5 * ( (x_center[0] - x)**2 + (x_center[1] - y)**2) / (2. * h**2)) y_all = [] t = 0. self._times = [] next_time = 0 while t < self.max_time: t += self.dt add = False if next_time < len(self.T) and t >= self.T[next_time]: t = self.T[next_time] next_time += 1 add = True if t >= tau: self.source.value = 0. self.eq.solve(var=self.phi, dt=self.dt) if add: self._times.append(t) y_all.append([self.phi.value[i] for i in self.idx]) y = np.hstack(y_all) y = y.reshape((self.T.shape[0], len(self.idx))).flatten(order='F') return y
def __call__(self, x): """Evaluate the solver.""" self.phi.value = 0. x_center = x[:2] tau = x[2] h = x[3] s = x[4] x, y = self.mesh.cellCenters self.source.value = 0.5 * s / (math.pi * h ** 2) * numerix.exp(-0.5 * ((x_center[0] - x) ** 2 + (x_center[1] - y) ** 2) / (2. * h ** 2)) y_all = [] t = 0. self._times = [] next_time = 0 while t < self.max_time: t += self.dt add = False if next_time < len(self.T) and t >= self.T[next_time]: t = self.T[next_time] next_time += 1 add = True if t >= tau: self.source.value = 0. self.eq.solve(var=self.phi, dt=self.dt) if add: self._times.append(t) y_all.append([self.phi.value[i] for i in self.idx]) y = np.hstack(y_all) y = y.reshape((self.T.shape[0], len(self.idx))).flatten(order='F') return y
def define_non_uniform_comp_domain_rad( self, shells_per_particle, normalised_particle_radius ): # Non-uniform radial domain, electrode particles self.nr = int(shells_per_particle) self.Rs_normalised = normalised_particle_radius self.dr = numerix.diff( numerix.log(1 - numerix.linspace( 0, 1.0 - numerix.exp(self.Rs_normalised), self.nr + 1))) self.p2d_mesh = Grid2D(dx=self.dx, dy=self.dr, Lx=self.L_normalised, Ly=self.Rs_normalised) self.dummy, self.radial_faces = self.p2d_mesh.faceCenters # Create a shorthand name for accessing y-axis faces in the particle mesh
def fluxes(self, ts): # wind-independent roughness as in doi:10.3189/2014JoG13J045 Tsurf = ts.variables['T_right'][self.indexCell(ts)] # Tsurf = ts.variables['T'][self.indexCell] # sat; T in Celsius; in Pa VPsurf = 100 * 6.1094 * numerix.exp( (17.625 * Tsurf) / (Tsurf + 243.04)) # T in Celsius flux_radiation = (self.Sin * (1 - self.bc_parameters['albedo']) + self.bc_parameters['emissivity'] * self.Lin - self.bc_parameters['emissivity'] * Stefan_Boltzmann * (Tsurf + 273.15)**4) C = von_Karman**2 / (numerix.log( (self.meas_height - self.bc_parameters['d0']) / self.bc_parameters['z0m']) * numerix.log( (self.meas_height - self.bc_parameters['d0']) / self.bc_parameters['z0a'])) flux_latent = (self.bc_parameters['beta'] * C * rho_air * Le * 0.622 * self.wind * (self.VPair - VPsurf) / self.pressure) flux_sensible = C * rho_air * cp_air * self.wind * (self.Tair - Tsurf) return Fluxes(radiation=flux_radiation, latent=flux_latent, sensible=flux_sensible, total=flux_radiation + flux_latent + flux_sensible)
def loopGaussianKernel(z, dz): n = z.shape[0] m = z.shape[0] kern = sp.lil_matrix((n, m), dtype=np.float64) # kern = numerix.zeros((n,m)) # eps = 1e-10 eps = dz**2 digits = len(str(n - 1)) delete = "\b" * (digits + 1) for i in range(n): #if i>0: # for j in range(m): # if j>0: # kern[i, j] = numerix.exp((-(2*z[i] - z[j])**2)/(2*eps)) kern[i] = numerix.exp((-(2 * z[i] - z)**2) / (2 * eps)) # kern = kern + sp.coo_matrix((np.array([numerix.exp((-(2*z[i] - z[j])**2)/(2*eps))]), (np.array([i]), np.array([j]))), shape=(n, m)) # kern.tocsc() #/numerix.sqrt(2*numerix.pi*eps) # print "{0}{1:{2}}".format(delete, i, digits), # level = int((np.float(i)/np.float(n))*100) # print "{0}%\r".format((np.float(i)/np.float(n)*100)) # print "#"*(level+1), return kern / numerix.sqrt(2 * numerix.pi * eps)
def SigmaF2D(amp, x,y, Rs): #Test : plt.plot(r,10*numerix.exp(-r**2/(2*dz**2))/(numerix.sqrt(dz**2)*numerix.sqrt(2*numerix.pi))) return amp*numerix.exp(-(x**2 + y**2)/(2*Rs))/(numerix.sqrt(2*numerix.pi*Rs))
def gaussian(x, mu, sig): return numerix.exp(-numerix.power(x - mu, 2.) / (2 * numerix.power(sig, 2.)))
def gaussianDivisionRate(z, mean, sigma): #Test : plt.plot(r,10*numerix.exp(-r**2/(2*dz))/numerix.sqrt(2*numerix.pi*2*dz)) return numerix.exp(-(z - mean)**2 / (2 * sigma**2)) / (sigma * numerix.sqrt(2 * numerix.pi))
def AxiSymetricGaussianImmuneResponse(r, Ra): #Test : plt.plot(r,10*numerix.exp(-r**2/(2*dz))/numerix.sqrt(2*numerix.pi*2*dz)) return 22 * numerix.exp(-r**2 / (2 * Ra)) / (numerix.sqrt(2 * numerix.pi * Ra))
def GaussianKernel2D(strength, x, y, Ra): return strength * numerix.exp(-( (x**2) + (y**2)) / (2 * Ra)) / (numerix.sqrt(2 * numerix.pi * Ra))
def run(self, dt=.5e-7, dtMax=1e+20, dtMin=.5e-7, totalSteps=400, view=False, PRINT=False, sweeps=5, tol=1e-10, delta=150e-6, deltaRef=0.03, featureDepth=56e-6, i1=-40., i0=40., diffusionCupric=2.65e-10, appliedPotential=-0.25, faradaysConstant=9.6485e4, gasConstant=8.314, temperature=298., alpha=0.4, charge=2, bulkCupric=1000., bulkSuppressor=.02, diffusionSuppressor=9.2e-11, kappa=15.26, kPlus=150., kMinus=2.45e7, omega=7.1e-6, gamma=2.5e-7, perimeterRatio=1. / 2.8e-6 * 0.093, areaRatio=0.093, capacitance=0.3, dt_mult=1e+10): r""" Run an individual simulation. :Parameters: - `dt`: time step size - `dtMax`: maximum time step size - `dtMin`: minimum time step size - `totalSteps`: total time steps - `view`: whether to view the simulation while running - `PRINT`: print convergence data - `sweeps`: number of sweeps at each time step - `tol`: tolerance to exit sweep loop - `delta`: boundary layer depth - `deltaRef`: distance to reference electrode - `featureDepth`: depth of the feature - `i1`: current density constant - `i0`: current density constant - `diffusionCupric`: cupric diffusion - `appliedPotential`: applied potential - `faradaysConstant`: Faraday's constant - `gasConstant`: gas constant - `temperature`: temperature - `alpha`: kinetic factor - `charge`: charge - `bulkCupric`: bulk cupric concentration - `bulkSuppressor`: bulk suppressor concentration - `diffusionSuppressor`: suppressor diffusion - `kappa`: conductivity - `kPlus`: suppressor adsorption factor - `kMinus`: suppressor incorporation factor - `omega`: copper molar volume - `gamma`: saturation suppressor coverage, - `perimeterRatio`: feature perimeter ratio - `areaRatio`: feature area ratio - `capacitance`: capacitance """ Fbar = faradaysConstant / gasConstant / temperature self.parameters = locals().copy() del self.parameters['self'] self.parameters['trenchWidth'] = 2 * 0.093 / perimeterRatio self.parameters['fieldWidth'] = 2 / perimeterRatio epsilon = 1e-30 L = delta + featureDepth N = 1000 dx = L / N mesh = fipy.Grid1D(nx=N, dx=dx) - [[featureDepth]] potential = fipy.CellVariable(mesh=mesh, hasOld=True, name=r'$\psi$') potential[:] = -appliedPotential cupric = fipy.CellVariable(mesh=mesh, hasOld=True, name=r'$c_{cu}$') cupric[:] = bulkCupric cupric.constrain(bulkCupric, mesh.facesRight) suppressor = fipy.CellVariable(mesh=mesh, hasOld=True, name=r'$c_{\theta}$') suppressor[:] = bulkSuppressor suppressor.constrain(bulkSuppressor, mesh.facesRight) theta = fipy.CellVariable(mesh=mesh, hasOld=True, name=r'$\theta$') I0 = (i0 + i1 * theta) baseCurrent = I0 * (numerix.exp(alpha * Fbar * potential) \ - numerix.exp(-(2 - alpha) * Fbar * potential)) cbar = cupric / bulkCupric current = cbar * baseCurrent currentDerivative = cbar * I0 * (alpha * Fbar * numerix.exp(alpha * Fbar * potential) \ + (2 - alpha) * Fbar * numerix.exp(-(2 - alpha) * Fbar * potential)) def dirac(x): value = numerix.zeros(mesh.numberOfCells, 'd') ID = numerix.argmin(abs(mesh.x - x)) if mesh.x[ID] < x: ID = ID + 1 value[ID] = 1. / dx return value THETA = (mesh.x < 0) * perimeterRatio + dirac(0) * (1 - areaRatio) + dirac(-featureDepth) * areaRatio AREA = (mesh.x < 0) * (areaRatio - 1) + 1 THETA_UPPER = fipy.CellVariable(mesh=mesh) THETA_UPPER[-1] = kappa / dx / (deltaRef - delta) potentialEq = fipy.TransientTerm(capacitance * THETA) == fipy.DiffusionTerm(kappa * AREA) \ - THETA * (current - potential * currentDerivative) \ - fipy.ImplicitSourceTerm(THETA * currentDerivative) \ - THETA_UPPER * appliedPotential - fipy.ImplicitSourceTerm(THETA_UPPER) cupricEq = fipy.TransientTerm(AREA) == fipy.DiffusionTerm(diffusionCupric * AREA) \ - fipy.ImplicitSourceTerm(baseCurrent * THETA / (bulkCupric * charge * faradaysConstant)) suppressorEq = fipy.TransientTerm(AREA) == fipy.DiffusionTerm(diffusionSuppressor * AREA) \ - fipy.ImplicitSourceTerm(gamma * kPlus * (1 - theta) * THETA) thetaEq = fipy.TransientTerm(THETA + epsilon) == kPlus * suppressor * THETA \ - fipy.ImplicitSourceTerm(THETA * (kPlus * suppressor + kMinus * current * (omega / charge / faradaysConstant))) t = 0. if view: potentialBar = -potential / appliedPotential potentialBar.name = r'$\bar{\eta}$' cbar.name = r'$\bar{c_{cu}}$' suppressorBar = suppressor / bulkSuppressor suppressorBar.name = r'$\bar{c_{\theta}}$' viewer = fipy.Viewer((theta, suppressorBar, cbar, potentialBar), datamax=1, datamin=0.0, xmin=-featureDepth) viewer.axes.legend([var.name for var in viewer.vars], loc='lower right', prop={'size':16}) viewer.axes.tick_params(labelsize=14) viewer.axes.set_xticks((-50e-6, 0e-6, 50e-6, 100e-6, 150e-6)) viewer.axes.set_xticklabels((-50, 0, 50, 100, 150)) viewer.axes.set_xlabel(r'$x$ ($\mu$m)', fontsize=16) potentials = [] for step in range(totalSteps): if view: viewer.axes.set_title(r'$t=%1.2e$ (s)' % t, fontsize=18) viewer.plot(filename='movie/movie%s.png' % str(step).rjust(6, '0')) potential.updateOld() cupric.updateOld() suppressor.updateOld() theta.updateOld() for sweep in range(sweeps): potentialRes = potentialEq.sweep(potential, dt=dt) cupricRes = cupricEq.sweep(cupric, dt=dt) suppressorRes = suppressorEq.sweep(suppressor, dt=dt) thetaRes = thetaEq.sweep(theta, dt=dt) res = numpy.array((potentialRes, cupricRes, suppressorRes, thetaRes)) if sweep == 0: res0 = res else: if ((res / res0) < tol).all(): break if PRINT: print res / res0 if sweep == sweeps - 1 and PRINT: print 'Did not reach sufficient tolerance' print 'kPlus',kPlus print 'kMinus',kMinus print 'res',res if PRINT: print 'theta',theta[0] print 'cBar_supp',suppressor[0] / bulkSuppressor print 'cBar_cu',cupric[0] / bulkCupric print 'potentialBar',-potential[0] / appliedPotential print 'dt',dt print 'step',step t += dt dt = dt * dt_mult dt = min((dt, dtMax)) dt = max((dt, dtMin)) potentials.append(-float(potential[0])) if view: viewer.plot() self.parameters['potential'] = numpy.array(potential) self.parameters['cupric'] = numpy.array(cupric) self.parameters['suppressor'] = numpy.array(suppressor) self.parameters['theta'] = numpy.array(theta) self.parameters['potentials'] = numpy.array(potentials)
def SigmaF1D(x, Rs): #Test : plt.plot(r,10*numerix.exp(-r**2/(2*dz**2))/(numerix.sqrt(dz**2)*numerix.sqrt(2*numerix.pi))) # return 0.00001*numerix.exp(-((x)**2)/(2*Rs))/(numerix.sqrt(2*numerix.pi*Rs)) return 10.*numerix.exp(-((x)**2)/(2*Rs))/(numerix.sqrt(2*numerix.pi*Rs))
def GaussianKernel(strength, x, Ra): return strength * numerix.exp(-(x**2) / (2 * Ra)) / (numerix.sqrt( 2 * numerix.pi * Ra))
def TwoSigmaF2D(x,y, Rs): #Test : plt.plot(r,10*numerix.exp(-r**2/(2*dz**2))/(numerix.sqrt(dz**2)*numerix.sqrt(2*numerix.pi))) return ((200e-3+0.)*numerix.exp(-((x+0.6)**2 + (y-0.3)**2)/(2*Rs)) +(300e-3+0.)*numerix.exp(-((x-0.6)**2 + (y-0.2)**2)/(2*Rs)))/(numerix.sqrt(2*numerix.pi*Rs))
def AxiSymmetricSigmaF(r, Rs): #Test : plt.plot(r,10*numerix.exp(-r**2/(2*dz**2))/(numerix.sqrt(dz**2)*numerix.sqrt(2*numerix.pi))) return 10*numerix.exp(-((r)**2)/(2*Rs))/(numerix.sqrt(2*numerix.pi*Rs))
def GaussianImmuneResponse2D(strength, x, y, Ra): #Test : plt.plot(r,10*numerix.exp(-r**2/(2*dz))/numerix.sqrt(2*numerix.pi*2*dz)) return strength * numerix.exp(-( (x**2) + (y**2)) / (2 * Ra)) / (numerix.sqrt(2 * numerix.pi * Ra))
def AxiSymmetricGaussianGammaF(r, Rs): #Test : plt.plot(r,10*numerix.exp(-r**2/(2*dz**2))/(numerix.sqrt(dz**2)*numerix.sqrt(2*numerix.pi))) return 0.03 * numerix.exp(-(r**2) / (2 * Rs)) / (numerix.sqrt(2 * numerix.pi * Rs))
def gaussianGammaF(x, Rs): #Test : plt.plot(r,10*numerix.exp(-r**2/(2*dz**2))/(numerix.sqrt(dz**2)*numerix.sqrt(2*numerix.pi))) return 0.3 * numerix.exp(-(x**2) / (2 * Rs)) / (numerix.sqrt(2 * numerix.pi * Rs))
def GaussianConversionRate(r, mean, Rp): #Test : plt.plot(r,10*numerix.exp(-r**2/(2*dz**2))/(numerix.sqrt(dz**2)*numerix.sqrt(2*numerix.pi))) return 0.3*numerix.exp(-(r-mean)**2/(2*Rp))/(numerix.sqrt(2*numerix.pi*Rp))
def GaussianConversionRate2D(amp, x,y, mean, Rp): #Test : plt.plot(r,10*numerix.exp(-r**2/(2*dz**2))/(numerix.sqrt(dz**2)*numerix.sqrt(2*numerix.pi))) return amp*numerix.exp(-((x-mean)**2 + (y-mean)**2)/(2*Rp))/(numerix.sqrt(2*numerix.pi*Rp))