def define_facemirrors( self, phi_s_initial, phi_e_initial ): # Facemirrors are copies of the variables solved on the axial meshes.. self.phi_s_facemirror = FaceVariable( mesh=self.p2d_mesh, value=phi_s_initial ) # ..and applied to the upper face of the p2d mesh in each domain self.phi_e_facemirror = FaceVariable(mesh=self.p2d_mesh, value=phi_e_initial) self.j0_facemirror = FaceVariable(mesh=self.p2d_mesh, value=self.j0[0])
def Cs_p2d_diffcoeff_function(self): self.Cs_p2d_diffCoeff = FaceVariable( mesh=self.p2d_mesh, rank=2, value=[[[0., 0.], [0., 0.]]] ) # As always with FiPy, diffusion coefficients are defined on the faces (hence facevar) self.numerixed_Cs_p2d_diffCoeff = numerix.array( self.Cs_p2d_diffCoeff ) # Temporarily convert to a NumPy array to edit the values (self.numerixed_Cs_p2d_diffCoeff[1][1]) = self.Ds * ( self.radial_faces**2.0 ) / self.Rs # Assign a non-zero value to the diff. coefficient in the y-axis only.. self.Cs_p2d_diffCoeff = FaceVariable( mesh=self.p2d_mesh, rank=2, value=self.numerixed_Cs_p2d_diffCoeff ) # ..which constrains diffusion to 1D. Now recreate the facevar with the new value
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 Battery_facevariables(self, neg_De_eff, sep_De_eff, pos_De_eff, neg_epsilon_e, sep_epsilon_e, pos_epsilon_e, normalised_neg_length, normalised_sep_length): self.De_eff = FaceVariable( mesh=self.axial_mesh ) # Define effective diffusion coefficient as a FiPy facevariable self.De_eff.setValue( neg_De_eff, where=(self.axial_mesh.faceCenters[0] <= normalised_neg_length) ) # Set its value to that for the neg. diff. coefficient in the negative electrode domain self.De_eff.setValue( sep_De_eff, where=(( normalised_neg_length # Set its value to the correct value in the separator < self.axial_mesh.faceCenters[0]) & (self.axial_mesh.faceCenters[0] < (normalised_neg_length + normalised_sep_length)))) self.De_eff.setValue( pos_De_eff, where=( self.axial_mesh.faceCenters[ 0] # Set its value to the correct value in the positive electrode domain >= (normalised_neg_length + normalised_sep_length))) self.epsilon_e_eff_facevariable = FaceVariable( mesh=self.axial_mesh ) # Define electrolyte phase volume fraction as a FiPy facevariable self.epsilon_e_eff_facevariable.setValue( neg_epsilon_e**self. brug, # Compute eff. value for neg. domain & set it in neg. electrode domain where=(self.axial_mesh.faceCenters[0] <= normalised_neg_length)) self.epsilon_e_eff_facevariable.setValue( sep_epsilon_e**self. brug, # Compute eff. value for sep. domain & set it in sep. electrode domain where=((normalised_neg_length < self.axial_mesh.faceCenters[0]) & (self.axial_mesh.faceCenters[0] < (normalised_neg_length + normalised_sep_length)))) self.epsilon_e_eff_facevariable.setValue( pos_epsilon_e**self. brug, # Compute eff. value for pos. domain & set it in pos. electrode domain where=(self.axial_mesh.faceCenters[0] >= (normalised_neg_length + normalised_sep_length)))
def Battery_cellvariables(self, neg_epsilon_e, sep_epsilon_e, pos_epsilon_e, neg_a_s, pos_a_s, nx_neg, nx_sep, nx_pos, j_battery_value, ce_initial, phi_e_initial, neg_L, sep_L, pos_L, neg_De_eff, sep_De_eff, pos_De_eff): self.Ce = CellVariable(mesh=self.axial_mesh, value=ce_initial, hasOld=True) self.phi_e = CellVariable(mesh=self.axial_mesh, value=phi_e_initial) self.epsilon_e_value = numerix.zeros(nx_neg + nx_sep + nx_pos) self.epsilon_e_value[0:nx_neg], self.epsilon_e_value[ nx_neg:nx_neg + nx_sep] = neg_epsilon_e, sep_epsilon_e self.epsilon_e_value[nx_neg + nx_sep:] = pos_epsilon_e self.epsilon_e = CellVariable(mesh=self.axial_mesh, value=self.epsilon_e_value) self.epsilon_e_eff_value = numerix.zeros(nx_neg + nx_sep + nx_pos) self.epsilon_e_eff_value[0:nx_neg] = neg_epsilon_e**self.brug self.epsilon_e_eff_value[nx_neg:nx_neg + nx_sep] = sep_epsilon_e**self.brug self.epsilon_e_eff_value[nx_neg + nx_sep:] = pos_epsilon_e**self.brug self.epsilon_e_eff = CellVariable(mesh=self.axial_mesh, value=self.epsilon_e_eff_value) self.a_s_value = numerix.zeros(nx_neg + nx_pos + nx_sep) self.a_s_value[0:nx_neg] = neg_a_s self.a_s_value[nx_neg:nx_neg + nx_sep] = 0.0 self.a_s_value[nx_neg + nx_sep:] = pos_a_s self.a_s = CellVariable(mesh=self.axial_mesh, value=self.a_s_value) self.L_value = numerix.zeros(nx_neg + nx_pos + nx_sep) self.L_value[0:nx_neg], self.L_value[nx_neg:nx_neg + nx_sep] = neg_L, sep_L self.L_value[nx_neg + nx_sep:] = pos_L self.L = CellVariable(mesh=self.axial_mesh, value=self.L_value) self.De_eff_value = numerix.zeros(nx_neg + nx_pos + nx_sep) self.De_eff_value[0:nx_neg], self.De_eff_value[ nx_neg:nx_neg + nx_sep], self.De_eff_value[ nx_neg + nx_sep:] = neg_De_eff, sep_De_eff, pos_De_eff self.De_eff = CellVariable(mesh=self.axial_mesh, value=self.De_eff_value) self.j_battery = CellVariable(mesh=self.axial_mesh, value=j_battery_value)
def initializeDiagnostic(self, variable, funpointer, default=0.0, face_variable=False, output_variable=True): if not face_variable: self.variables[variable] = CellVariable(name=variable, mesh=self.mesh.mesh, value=default) else: self.variables[variable] = FaceVariable(name=variable, mesh=self.mesh.mesh, value=default) self.diagnostic_modules[variable] = DiagnosticModule(funpointer, self) if output_variable: self.variables_store.append(variable) self.diagnostic_update_order.append(variable)
class Battery(): def __init__( self, cell_temperature_celcius, capacity_Ah, bruggeman_coefficient, charge_transfer_coefficient, current_collector_cross_section_area, electrolyte_diffusivity, transference_number): # Initialises physical properties of cell ########################################## Compute & Assign Constants ################################################## self.T = 273.0 + cell_temperature_celcius # Could move into electrode-level later self.Q = capacity_Ah * 3600.0 self.brug = bruggeman_coefficient # Could move into electrode-level later when electrodes may have unique brug. values self.alpha = charge_transfer_coefficient # Could move into electrode-level later when electrodes may have unique alpha values self.A = current_collector_cross_section_area self.De = electrolyte_diffusivity self.t_plus = transference_number def Battery_scale_quantities(self, overall_thickness, kappa_string): # self.L = overall_thickness self.kappa = lambdify( Ce, sympify(kappa_string), "numpy" ) # Function to return electrolyte electrical conductivity, given a species concentration # NOTE: Consider changing this function's name since it's only the kappa definition now ######################################## Battery-level Mesh Generation ################################################# def define_global_mesh(self, node_spacing, normalised_domain_thickness ): # Only Ce & phi_e are solved on this mesh self.dx = node_spacing # node_spacing vector passed can be either uniformly or non-uniformly spaced points self.L_normalised = normalised_domain_thickness self.axial_mesh = Grid1D(Lx=self.L_normalised, dx=self.dx) def Battery_cellvariables(self, neg_epsilon_e, sep_epsilon_e, pos_epsilon_e, neg_a_s, pos_a_s, nx_neg, nx_sep, nx_pos, j_battery_value, ce_initial, phi_e_initial, neg_L, sep_L, pos_L, neg_De_eff, sep_De_eff, pos_De_eff): self.Ce = CellVariable(mesh=self.axial_mesh, value=ce_initial, hasOld=True) self.phi_e = CellVariable(mesh=self.axial_mesh, value=phi_e_initial) self.epsilon_e_value = numerix.zeros(nx_neg + nx_sep + nx_pos) self.epsilon_e_value[0:nx_neg], self.epsilon_e_value[ nx_neg:nx_neg + nx_sep] = neg_epsilon_e, sep_epsilon_e self.epsilon_e_value[nx_neg + nx_sep:] = pos_epsilon_e self.epsilon_e = CellVariable(mesh=self.axial_mesh, value=self.epsilon_e_value) self.epsilon_e_eff_value = numerix.zeros(nx_neg + nx_sep + nx_pos) self.epsilon_e_eff_value[0:nx_neg] = neg_epsilon_e**self.brug self.epsilon_e_eff_value[nx_neg:nx_neg + nx_sep] = sep_epsilon_e**self.brug self.epsilon_e_eff_value[nx_neg + nx_sep:] = pos_epsilon_e**self.brug self.epsilon_e_eff = CellVariable(mesh=self.axial_mesh, value=self.epsilon_e_eff_value) self.a_s_value = numerix.zeros(nx_neg + nx_pos + nx_sep) self.a_s_value[0:nx_neg] = neg_a_s self.a_s_value[nx_neg:nx_neg + nx_sep] = 0.0 self.a_s_value[nx_neg + nx_sep:] = pos_a_s self.a_s = CellVariable(mesh=self.axial_mesh, value=self.a_s_value) self.L_value = numerix.zeros(nx_neg + nx_pos + nx_sep) self.L_value[0:nx_neg], self.L_value[nx_neg:nx_neg + nx_sep] = neg_L, sep_L self.L_value[nx_neg + nx_sep:] = pos_L self.L = CellVariable(mesh=self.axial_mesh, value=self.L_value) self.De_eff_value = numerix.zeros(nx_neg + nx_pos + nx_sep) self.De_eff_value[0:nx_neg], self.De_eff_value[ nx_neg:nx_neg + nx_sep], self.De_eff_value[ nx_neg + nx_sep:] = neg_De_eff, sep_De_eff, pos_De_eff self.De_eff = CellVariable(mesh=self.axial_mesh, value=self.De_eff_value) self.j_battery = CellVariable(mesh=self.axial_mesh, value=j_battery_value) ############################# Define Eff. Diff. Coefficients & Volume Fractions ######################################## def Battery_facevariables(self, neg_De_eff, sep_De_eff, pos_De_eff, neg_epsilon_e, sep_epsilon_e, pos_epsilon_e, normalised_neg_length, normalised_sep_length): self.De_eff = FaceVariable( mesh=self.axial_mesh ) # Define effective diffusion coefficient as a FiPy facevariable self.De_eff.setValue( neg_De_eff, where=(self.axial_mesh.faceCenters[0] <= normalised_neg_length) ) # Set its value to that for the neg. diff. coefficient in the negative electrode domain self.De_eff.setValue( sep_De_eff, where=(( normalised_neg_length # Set its value to the correct value in the separator < self.axial_mesh.faceCenters[0]) & (self.axial_mesh.faceCenters[0] < (normalised_neg_length + normalised_sep_length)))) self.De_eff.setValue( pos_De_eff, where=( self.axial_mesh.faceCenters[ 0] # Set its value to the correct value in the positive electrode domain >= (normalised_neg_length + normalised_sep_length))) self.epsilon_e_eff_facevariable = FaceVariable( mesh=self.axial_mesh ) # Define electrolyte phase volume fraction as a FiPy facevariable self.epsilon_e_eff_facevariable.setValue( neg_epsilon_e**self. brug, # Compute eff. value for neg. domain & set it in neg. electrode domain where=(self.axial_mesh.faceCenters[0] <= normalised_neg_length)) self.epsilon_e_eff_facevariable.setValue( sep_epsilon_e**self. brug, # Compute eff. value for sep. domain & set it in sep. electrode domain where=((normalised_neg_length < self.axial_mesh.faceCenters[0]) & (self.axial_mesh.faceCenters[0] < (normalised_neg_length + normalised_sep_length)))) self.epsilon_e_eff_facevariable.setValue( pos_epsilon_e**self. brug, # Compute eff. value for pos. domain & set it in pos. electrode domain where=(self.axial_mesh.faceCenters[0] >= (normalised_neg_length + normalised_sep_length)))
#run gmsh gui to produce this mesh (.msh file) #gmsh infiniteCylinder01.geo 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)
nx = 10 ny = 1 valueLeft = 0. fluxRight = 1. timeStepDuration = 1. L = 10. dx = L / nx dy = 1. mesh = Tri2D(dx, dy, nx, ny) var = CellVariable(name="solution variable", mesh=mesh, value=valueLeft) diffCoeff = FaceVariable(mesh=mesh, value=1.0) x = mesh.faceCenters[0] diffCoeff.setValue(0.1, where=(L / 4. <= x) & (x < 3. * L / 4.)) var.faceGrad.constrain([[1.], [0.]], mesh.facesRight) var.constrain(valueLeft, mesh.facesLeft) if __name__ == '__main__': import fipy.tests.doctestPlus exec(fipy.tests.doctestPlus._getScript()) input('finished')
c0[20:50] = 1.0 # mobile domain concentration cm = CellVariable(name="$c_m$", mesh=m, value=c0) # immobile domain concentration cim = CellVariable(name="$c_{im}$", mesh=m, value=0.0) cm.constrain(0, m.facesLeft) cm.constrain(0, m.facesRight) cim.constrain(0, m.facesLeft) cim.constrain(0, m.facesRight) # advective flow velocity u = FaceVariable(mesh=m, value=(0.0,), rank=1) # 1D convection diffusion equation (mobile domain) # version with \frac{\partial c_{im}}{\partial t} eqM = (TransientTerm(1.0,var=cm) + TransientTerm(betaT,var=cim) == DiffusionTerm(DR,var=cm) - ExponentialConvectionTerm(u/(Rm*phim),var=cm)) # immobile domain (lumped approach) eqIM = TransientTerm(Rim*phiim,var=cim) == beta/Rim*(cm - ImplicitSourceTerm(1.0,var=cim)) # couple equations eqn = eqM & eqIM viewer = Viewer(vars=(cm,cim), datamin=0.0, datamax=1.0) viewer.plot() time = 0.0
nx = 800 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__':
'''.format(cellSize, l1, l2, math.tan(beta) * (l2 - l1), l3, math.tan(alpha) * l3) mesh = Gmsh3D(geometryTemplate) phi = CellVariable(name="Pressure", mesh=mesh, value=P0) # Berechnete Werte ------------------------------------------------------------ Dx = material["k_x"] * fluid["dichte"] Dy = material["k_y"] * fluid["dichte"] Dz = material["k_y"] * fluid["dichte"] # D ist eine Face Variable, da der Koeffizient für jede Flaeche einzelnd berechenet wird D = FaceVariable(mesh=mesh, value=((Dx, 0, 0), (0, Dy, 0), (0, 0, Dz))) # boundry conditions ---------------------------------------------------------- phi.constrain(Pres, where=mesh.physicalFaces["inner"]) phi.constrain(Pamb, where=mesh.physicalFaces["outer"]) # Solving --------------------------------------------------------------------- eq = DiffusionTerm(coeff=D) sweep = 0 phi_old = phi.copy() max_diff = 10e10
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)
The diffusion coefficient in the first half of the slab is double that in the second half """ from fipy import Variable, FaceVariable, CellVariable, Grid1D, TransientTerm, DiffusionTerm, Viewer from fipy.tools import numerix # Setting up a mesh nx = 50 dx = 0.02 L = nx * dx mesh = Grid1D(nx=nx, dx=dx) c = CellVariable(mesh=mesh, name=r"$c$", value=0.0) # Setting up the spatially varying diffusion coefficient # Due to the mechanics of the solver, the diffusion coefficient variable must be defined on the mesh face D = FaceVariable(mesh=mesh, value=2.0) x = mesh.faceCenters[0] D.setValue(1.0, where=(x > L / 2.0)) # Boundary conditions valueLeft = 1.0 valueRight = 0.0 c.constrain(valueLeft, mesh.facesLeft) c.constrain(valueRight, mesh.facesRight) #Equation eq = (TransientTerm() == DiffusionTerm(coeff=D)) dt = 0.001 t = Variable(0.0) time_stride = 20
// create remaining 7/8 inner shells t1[] = Rotate {{0,0,1},{0,0,0},Pi/2} {Duplicata{Surface{1};}}; t2[] = Rotate {{0,0,1},{0,0,0},Pi} {Duplicata{Surface{1};}}; t3[] = Rotate {{0,0,1},{0,0,0},Pi*3/2} {Duplicata{Surface{1};}}; t4[] = Rotate {{0,1,0},{0,0,0},-Pi/2} {Duplicata{Surface{1};}}; t5[] = Rotate {{0,0,1},{0,0,0},Pi/2} {Duplicata{Surface{t4[0]};}}; t6[] = Rotate {{0,0,1},{0,0,0},Pi} {Duplicata{Surface{t4[0]};}}; t7[] = Rotate {{0,0,1},{0,0,0},Pi*3/2} {Duplicata{Surface{t4[0]};}}; // create entire inner and outer shell Surface Loop(100)={1,t1[0],t2[0],t3[0],t7[0],t4[0],t5[0],t6[0]}; ''', order=2).extrude(extrudeFunc=lambda r: 1.05 * r) # doctest: +GMSH # mmag = FaceVariable(name=r"$mmag$", mesh=mesh) # doctest: +GMSH gridCoor = mesh.cellCenters print("mesh created") ## Constants kBoltzmann = 1.38064852e-23 mu0 = numerix.pi * 4.0e-7 ## LLG parameters ##gamFac = 1.7608e11 * pi * 4.0e-7 gamFac = 2.2128e5 alphaDamping = 0.01 Temperature = 300 Msat = 500e3 magVolume = 2.0e-9 * (25e-9 * 25e-9) * numerix.pi D = alphaDamping * gamFac * kBoltzmann * Temperature / ((1 + alphaDamping) * Msat * magVolume)
filename = 'infiniteCylinder01_solve_dimensionless.msh' mesh = Gmsh2D(filename, communicator=serialComm) del filename #T_initial=425.08 #deg K T_initial = 0. var = CellVariable(mesh=mesh, value=T_initial, hasOld=True) # 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) D = FaceVariable(mesh=mesh, value=1.) 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
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. #SETTING #Bi_desired=1e5 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) 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) b = k #RobinCoeff = (mask * Gamma0 * Af * mesh.faceNormals / (-dPf.dot(a) + b)).divergence #I changed a sign in the denominator since I suspect a sign error #a is convectionCoeff times n_hat #20181211: I am getting same result whichever sign in the denominator I go with; solution is stuck at initial condition RobinCoeff = ( mask * Gamma0 * Af * mesh.faceNormals / (-convectionCoeff * dPf.dot(mesh.faceNormals) + b) ).divergence #I changed a sign in the denominator since I suspect a sign error g = convectionCoeff * T_infinity
surfaceFaces = (Y_faces > 0) & ( (X_faces**2 + Y_faces**2)**.5 > R_outer - cellSize / 10.) #convectionCoeff=200. #W/m^2/K Bi_desired = 10. #SETTING 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) #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()
valueLeft = 0. fluxRight = 1. timeStepDuration = 1. L = 10. dx = L / nx dy = 1. mesh = Tri2D(dx, dy, nx, ny) var = CellVariable( name = "solution variable", mesh = mesh, value = valueLeft) diffCoeff = FaceVariable(mesh = mesh, value = 1.0) x = mesh.faceCenters[0] diffCoeff.setValue(0.1, where=(L/4. <= x) & (x < 3. * L / 4.)) var.faceGrad.constrain([[1.], [0.]], mesh.facesRight) var.constrain(valueLeft, mesh.facesLeft) if __name__ == '__main__': import fipy.tests.doctestPlus exec(fipy.tests.doctestPlus._getScript()) input('finished')