Exemple #1
0
    def _setup_equation(self, biomass_height):
        height = biomass_height + self._layer_height
        size = height * self._layer
        mesh = self.space.construct_mesh(height)
        variables, terms = [], []
        phi = CellVariable(name=self.solute.name, mesh=mesh, hasOld=True)
        for r in self.reactions:
            variables.append(
                CellVariable(name=f"{r.bacteria.name}_rate",
                             mesh=mesh,
                             value=0.0))
            terms.append(
                ImplicitSourceTerm(coeff=(variables[-1] / (phi + self._sr))))
        equation = DiffusionTerm(coeff=self.diffusivity) - sum(terms)
        phi.constrain(1, where=mesh.facesTop)

        for var, coef in zip(
                variables,
            [r.rate_coefficient()[:size] for r in self.reactions]):
            try:
                var.setValue(coef / self.space.dV)
            except ValueError as err:
                print("Boundary layer height greater than system size")
                raise err
        phi.setValue(self.solute.value.reshape(-1)[:size])
        return equation, phi, size
    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
 def define_convection_variable(self, current_time):
     x_convection, y_convection = self.get_convection_x_and_y(current_time)
     if self.baseline_convection is None:
         convection_variable = CellVariable(mesh=self.mesh, rank=1) #  Only define the variable from scratch once
     else:
         convection_variable = self.baseline_convection
     convection_variable.setValue((x_convection, y_convection))
     return convection_variable
Exemple #4
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
    eq.solve(dt=dt, solver=solver)
    phi.setValue(0.0, where=phi < 0.0)
    phi.setValue(1.0, where=phi > 1.0)
    print(elapsed)
    if (elapsed % 50 == 0):
        vw = VTKCellViewer(vars=(phi, psi))
        vw.plot(filename="%s_vashista_output.vtk" % (elapsed))
Exemple #5
0
def runLeveler(kLeveler=0.018,
               bulkLevelerConcentration=0.02,
               cellSize=0.1e-7,
               rateConstant=0.00026,
               initialAcceleratorCoverage=0.0,
               levelerDiffusionCoefficient=5e-10,
               numberOfSteps=400,
               displayRate=10,
               displayViewers=True):

    kLevelerConsumption = 0.0005
    aspectRatio = 1.5
    faradaysConstant = 9.6485e4
    gasConstant = 8.314
    acceleratorDiffusionCoefficient = 4e-10
    siteDensity = 6.35e-6
    atomicVolume = 7.1e-6
    charge = 2
    metalDiffusionCoefficient = 4e-10
    temperature = 298.
    overpotential = -0.25
    bulkMetalConcentration = 250.
    bulkAcceleratorConcentration = 50.0e-3
    initialLevelerCoverage = 0.
    cflNumber = 0.2
    cellsBelowTrench = 10
    trenchDepth = 0.4e-6
    trenchSpacing = 0.6e-6
    boundaryLayerDepth = 98.7e-6
    i0Suppressor = 0.3
    i0Accelerator = 22.5
    alphaSuppressor = 0.5
    alphaAccelerator = 0.4
    alphaAdsorption = 0.62
    m = 4
    b = 2.65
    A = 0.3
    Ba = -40
    Bb = 60
    Vd = 0.098
    Bd = 0.0008

    etaPrime = faradaysConstant * overpotential / gasConstant / temperature

    mesh = TrenchMesh(cellSize=cellSize,
                      trenchSpacing=trenchSpacing,
                      trenchDepth=trenchDepth,
                      boundaryLayerDepth=boundaryLayerDepth,
                      aspectRatio=aspectRatio,
                      angle=numerix.pi * 4. / 180.)

    distanceVar = GapFillDistanceVariable(name='distance variable',
                                          mesh=mesh,
                                          value=-1.)

    distanceVar.setValue(1., where=mesh.electrolyteMask)

    distanceVar.calcDistanceFunction()
    levelerVar = SurfactantVariable(name="leveler variable",
                                    value=initialLevelerCoverage,
                                    distanceVar=distanceVar)

    acceleratorVar = SurfactantVariable(name="accelerator variable",
                                        value=initialAcceleratorCoverage,
                                        distanceVar=distanceVar)

    bulkAcceleratorVar = CellVariable(name='bulk accelerator variable',
                                      mesh=mesh,
                                      value=bulkAcceleratorConcentration)

    bulkLevelerVar = CellVariable(name='bulk leveler variable',
                                  mesh=mesh,
                                  value=bulkLevelerConcentration)

    metalVar = CellVariable(name='metal variable',
                            mesh=mesh,
                            value=bulkMetalConcentration)

    def depositionCoeff(alpha, i0):
        expo = numerix.exp(-alpha * etaPrime)
        return 2 * i0 * (expo - expo * numerix.exp(etaPrime))

    coeffSuppressor = depositionCoeff(alphaSuppressor, i0Suppressor)
    coeffAccelerator = depositionCoeff(alphaAccelerator, i0Accelerator)

    exchangeCurrentDensity = acceleratorVar.interfaceVar * (
        coeffAccelerator - coeffSuppressor) + coeffSuppressor

    currentDensity = metalVar / bulkMetalConcentration * exchangeCurrentDensity

    depositionRateVariable = currentDensity * atomicVolume / charge / faradaysConstant

    extensionVelocityVariable = CellVariable(name='extension velocity',
                                             mesh=mesh,
                                             value=depositionRateVariable)

    kAccelerator = rateConstant * numerix.exp(-alphaAdsorption * etaPrime)
    kAcceleratorConsumption = Bd + A / (numerix.exp(Ba *
                                                    (overpotential + Vd)) +
                                        numerix.exp(Bb * (overpotential + Vd)))
    q = m * overpotential + b

    levelerSurfactantEquation = AdsorbingSurfactantEquation(
        levelerVar,
        distanceVar=distanceVar,
        bulkVar=bulkLevelerVar,
        rateConstant=kLeveler,
        consumptionCoeff=kLevelerConsumption * depositionRateVariable)

    accVar1 = acceleratorVar.interfaceVar
    accVar2 = (accVar1 > 0) * accVar1
    accConsumptionCoeff = kAcceleratorConsumption * (accVar2**(q - 1))

    acceleratorSurfactantEquation = AdsorbingSurfactantEquation(
        acceleratorVar,
        distanceVar=distanceVar,
        bulkVar=bulkAcceleratorVar,
        rateConstant=kAccelerator,
        otherVar=levelerVar,
        otherBulkVar=bulkLevelerVar,
        otherRateConstant=kLeveler,
        consumptionCoeff=accConsumptionCoeff)

    advectionEquation = TransientTerm() + FirstOrderAdvectionTerm(
        extensionVelocityVariable)

    metalEquation = buildMetalIonDiffusionEquation(
        ionVar=metalVar,
        distanceVar=distanceVar,
        depositionRate=depositionRateVariable,
        diffusionCoeff=metalDiffusionCoefficient,
        metalIonMolarVolume=atomicVolume)

    metalVar.constrain(bulkMetalConcentration, mesh.facesTop)

    bulkAcceleratorEquation = buildSurfactantBulkDiffusionEquation(
        bulkVar=bulkAcceleratorVar,
        distanceVar=distanceVar,
        surfactantVar=acceleratorVar,
        otherSurfactantVar=levelerVar,
        diffusionCoeff=acceleratorDiffusionCoefficient,
        rateConstant=kAccelerator * siteDensity)

    bulkAcceleratorVar.constrain(bulkAcceleratorConcentration, mesh.facesTop)

    bulkLevelerEquation = buildSurfactantBulkDiffusionEquation(
        bulkVar=bulkLevelerVar,
        distanceVar=distanceVar,
        surfactantVar=levelerVar,
        diffusionCoeff=levelerDiffusionCoefficient,
        rateConstant=kLeveler * siteDensity)

    bulkLevelerVar.constrain(bulkLevelerConcentration, mesh.facesTop)

    eqnTuple = ((advectionEquation, distanceVar, (),
                 None), (levelerSurfactantEquation, levelerVar, (), None),
                (acceleratorSurfactantEquation, acceleratorVar, (),
                 None), (metalEquation, metalVar, (), None),
                (bulkAcceleratorEquation, bulkAcceleratorVar, (),
                 GeneralSolver()), (bulkLevelerEquation, bulkLevelerVar, (),
                                    GeneralSolver()))

    narrowBandWidth = 20 * cellSize
    levelSetUpdateFrequency = int(0.7 * narrowBandWidth / cellSize /
                                  cflNumber / 2)

    totalTime = 0.0

    if displayViewers:
        try:
            raise Exception
            from mayaviSurfactantViewer import MayaviSurfactantViewer
            viewers = (MayaviSurfactantViewer(distanceVar,
                                              acceleratorVar.interfaceVar,
                                              zoomFactor=1e6,
                                              datamax=0.5,
                                              datamin=0.0,
                                              smooth=1,
                                              title='accelerator coverage'),
                       MayaviSurfactantViewer(distanceVar,
                                              levelerVar.interfaceVar,
                                              zoomFactor=1e6,
                                              datamax=0.5,
                                              datamin=0.0,
                                              smooth=1,
                                              title='leveler coverage'))
        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))

            viewers = (Viewer(PlotVariable(var=acceleratorVar.interfaceVar)),
                       Viewer(PlotVariable(var=levelerVar.interfaceVar)))

    for step in range(numberOfSteps):

        if displayViewers:
            if step % displayRate == 0:
                for viewer in viewers:
                    viewer.plot()

        if step % levelSetUpdateFrequency == 0:
            distanceVar.calcDistanceFunction()

        extensionVelocityVariable.setValue(depositionRateVariable)

        extOnInt = numerix.where(
            distanceVar.globalValue > 0,
            numerix.where(distanceVar.globalValue < 2 * cellSize,
                          extensionVelocityVariable.globalValue, 0), 0)

        dt = cflNumber * cellSize / extOnInt.max()

        distanceVar.extendVariable(extensionVelocityVariable)

        for eqn, var, BCs, solver in eqnTuple:
            eqn.solve(var, boundaryConditions=BCs, dt=dt, solver=solver)

        totalTime += dt

    point = ((1.25e-08, ), (3.125e-07, ))
    value = 2.02815779e-08
    return abs(float(distanceVar(point, order=1)) - value) < cellSize / 10.0
Exemple #6
0
class Yarn1DModel(object):
    """
    Yarn1DModel is a special diffusion model for a single yarn which is composed 
    by a certain amount of fibers. A cross-section of a fiber is 
    generated. The domain is a line from the center of the yarn to the surface. 
    On this line there are some fibers distributed as in the module yarn1Dgrid.
    Only diffusion processes in a single fiber and yarn are considered. 
    ODE of scipy solve the diffusion process in the layers of DEET and permithrine
    which are on the fiber
    An overlap region outside of the yarn can be added for multiscale simulations
    Fipy solve the transient diffusion problem in the whole domain
    """
    def __init__(self, config):
        """ 
        a config class must be passed in that contains the required settings
        """
        self.cfg = config
        self.verbose = self.cfg.get('general.verbose')
        self.time_period = self.cfg.get('time.time_period')
        self.delta_t = self.cfg.get('time.dt')
        self.steps = int((self.time_period*(1.+self.delta_t*1e-6)) // self.delta_t)
        #set correct delta_t
        self.delta_t = self.time_period / self.steps
        if self.verbose:
            print "Timestep used in yarn1d model:", self.delta_t
        
        self.diff_coef = self.cfg.get('diffusion.diffusion_coeff')
        self.init_conc_func = eval(self.cfg.get('initial.init_conc1d'))
        
        self.number_fiber = self.cfg.get('fiber.number_fiber')
        self.blend = self.cfg.get('fiber.blend')
        self.blend = [x/100. for x in self.blend]
        self.nr_models = self.cfg.get('fiber.number_type')
        assert self.nr_models == len(self.blend) == len(self.cfg.get('fiber.fiber_config'))

        #Initialize the tortuosity
        self.tortuosity = self.cfg.get('yarn.tortuosity')
        
        #construct the config for the fibers
        self.cfg_fiber = []
        for filename in self.cfg.get('fiber.fiber_config'):
            if not os.path.isabs(filename):
                filename = os.path.normpath(os.path.join(
                            os.path.dirname(self.cfg.filename), filename))
            self.cfg_fiber.append(FiberConfigManager.get_instance(filename))
            #set values from the yarn on this inifile
            self.cfg_fiber[-1].set("time.time_period", self.time_period)
            if self.cfg_fiber[-1].get("time.dt") > self.cfg.get("time.dt"):
                self.cfg_fiber[-1].set("time.dt", self.cfg.get("time.dt"))
            #we need stepwize solution, we select cvode
            self.cfg_fiber[-1].set("general.method", 'FVM')
            self.cfg_fiber[-1].set("general.submethod", 'cvode_step')
            #we check that boundary is transfer or evaporation
            bty = self.cfg_fiber[-1].get("boundary.type_right")
            if bty not in ['evaporation', 'transfer']:
                raise ValueError, 'Boundary type for a fiber should be evaporation or transfer'
            if self.verbose:
                print 'NOTE: Fiber has boundary out of type %s' %  bty
            #set data in case fiber with extension area is used
            self.cfg_fiber[-1].set("fiber.extenddiff", self.diff_coef/self.tortuosity)

        #some memory
        self.step_old_time = None
        self.step_old_sol = None
        
        #use the area function for calculating porosity
        self.prob_area = eval(self.cfg.get('fiber.prob_area'))
        # boundary data
        self.bound_type = conf.BOUND_TYPE[self.cfg.get('boundary.type_right')]
        self.boundary_conc_out = self.cfg.get('boundary.conc_out')
        self.boundary_D_out = self.cfg.get('boundary.D_out')
        self.boundary_dist = self.cfg.get('boundary.dist_conc_out')
        self.boundary_transf_right = self.cfg.get('boundary.transfer_coef')
        self.nr_fibers = self.cfg.get('fiber.number_fiber')
        
        self.plotevery = self.cfg.get("plot.plotevery")
        self.writeevery = self.cfg.get("plot.writeevery")
        
        #allow a multiscale model to work with a source in overlap zone
        self.source_overlap = 0.

        self.initialized = False
    
        self.fiberconc_center = 0
        self.fiberconc_middle = 0
        self.fiberconc_surface = 0
    
    def times(self, timestep, end=None):
        """ Compute the time at one of our steps
        If end is given, all times between step timestep and step end are 
        returned as a list, with end included
        """
        if end is None:
            return timestep * self.delta_t
        else:
            begin = timestep * self.delta_t
            end = end * self.delta_t
            return np.linspace(begin, end, end-begin + 1)

    def create_mesh(self):
        """
        Create a mesh for use in the model.
        We use an equidistant mesh!
        
        grid: the space position of each central point for every cell element (r-coordinate);
        """
        self.end_point = self.cfg.get('domain.yarnradius')
        self.nr_edge = self.cfg.get('domain.n_edge')
        self.nr_cell = self.nr_edge - 1
        self.use_extend = self.cfg.get("domain.useextension")
        self.fiberlayout_method = self.cfg.get('domain.fiberlayout_method')
        self.areaextend = 0.
        if self.use_extend:
            self.end_extend = self.end_point + \
                self.cfg.get('domain.extensionfraction') * self.end_point
            self.nr_edge_extend = max(2, 
                    int(self.nr_edge*self.cfg.get('domain.extensionfraction')))
            self.areaextend = np.pi * (self.end_extend**2 - self.end_point**2)
        else:
            self.end_extend = self.end_point
            self.nr_edge_extend = 1
        #we now construct the full edge grid
        self.nr_edge_tot = self.nr_edge + self.nr_edge_extend - 1
        self.nr_cell_tot = self.nr_edge_tot - 1
        self.grid_edge = np.empty(self.nr_edge_tot, float)
        self.grid_edge[:self.nr_edge] = np.linspace(0., 
                                    self.end_point, self.nr_edge)
        self.grid_edge[self.nr_edge:] = np.linspace(self.end_point,
                                    self.end_extend, self.nr_edge_extend)[1:]
        #construct cell centers from this
        self.grid = (self.grid_edge[:-1] + self.grid_edge[1:])/2.
        #obtain cell sizes
        self.delta_r = self.grid_edge[1:] - self.grid_edge[:-1]
        grid_square = np.power(self.grid_edge, 2)
        self.delta_rsquare = grid_square[1:] - grid_square[:-1]

        #create fiber models as needed: one per fibertype and per cell in the yarn model
        self.fiber_models = [0] * (self.nr_edge - 1)
        self.fiber_mass = np.empty((self.nr_edge - 1, self.nr_models), float)
        self.source_mass = np.empty((self.nr_edge - 1, self.nr_models), float)
        self.source_conc = np.empty((self.nr_edge - 1, self.nr_models), float)
        self.source = np.zeros(self.nr_edge_tot - 1, float)
        for ind in range(self.nr_edge-1):
            self.fiber_models[ind] = []
            for cfg in self.cfg_fiber:
                cfg.set("fiber.extendinit_conc",  self.init_conc_func(self.grid[ind]))
                self.fiber_models[ind].append(FiberModel(cfg))

        #calculate the porosity as n=(pi Ry^2-nr_fibers pi Rf^2) / pi Ry^2
        #porosity in the yarn
        self.porosity = np.ones(self.nr_cell_tot, float)
        self.volfracfib = []  # volume fraction of the fiber types
        if self.fiberlayout_method == 'virtlocoverlap':
            value_from_areafunction = np.zeros(self.nr_cell, float)
            for i_porosity in range(len(self.prob_area)):
                function_area = self.prob_area[i_porosity]
                value_from_areafunction += function_area(self.grid[:])
                #plot the value from the function and the porosity value to check
                #the calculation for porosity
                plt.figure()
                plt.plot(self.grid[:], 1 - value_from_areafunction, '-', color = 'red')
                plt.plot(self.grid[:], 1 - function_area(self.grid[:]), '*')
                plt.xlabel('Yarn domain')
                plt.ylabel('value')
                plt.ylim(0., 1.0)
                plt.show()
            self.porosity[:self.nr_cell] = 1. - value_from_areafunction[:self.nr_cell]
        else:
            for blend, model in zip(self.blend, self.fiber_models[0]):
                print 'fiberradius', model.radius(), 'yarnradius', self.end_point   
                self.volfracfib.append(
                        blend * self.nr_fibers *  np.power(model.radius(), 2)
                                / np.power(self.end_point, 2) )
                if np.sum(self.volfracfib) > 1:
                    raise ValueError, 'porosity  negative, unrealistic number of fibers in yarn cross section, %f fibers per yarn * Rf^2/Ry^2 = %f' % (self.nr_fibers,np.sum(self.volfracfib))
                    raw_input()
            self.porosity[:self.nr_cell] = 1 - np.sum(self.volfracfib)
            #print 'porosity in yarn', self.porosity[:self.nr_cell], 

        #nrf is number of fibers in the shell at that grid position
        # per radial
        if not self.fiberlayout_method == 'virtlocoverlap':
            self.nrf_shell = (self.delta_rsquare[:self.nr_cell]
                                / (self.end_point**2) * self.nr_fibers)
        else:
            raise NotImplementedError, 'nrfibers per shell still to determine'

        #we now have porosity and fiber models, we can calculate area extend available
        for ind in range(self.nr_edge-1):
            for fibmod in self.fiber_models[ind]:
                area_extend = np.pi * self.delta_rsquare[ind] \
                                    * self.porosity[ind] / self.nrf_shell[ind]
                fibmod.set_areaextend(area_extend) # set fiber.extendarea in the fiber model!

        #create cylindrical 1D grid over domain for using fipy to view.
        if self.plotevery:
            self.mesh_yarn = CylindricalGrid1D(dr=tuple(self.delta_r[:self.nr_cell]))
            self.mesh_yarn.periodicBC = False
            self.mesh_yarn = self.mesh_yarn

        #print 'mesh yarn', self.grid_edge, ', delta_r yarn', self.delta_r

    def initial_yarn1d(self):
        """ initial concentration over the domain"""
        self.init_conc = np.empty(self.nr_cell_tot, float)
        #zero to the outside
        for ind, r in enumerate(self.grid[:self.nr_cell]):
            self.init_conc[ind] = self.init_conc_func(r)
        self.init_conc[self.nr_cell:] = self.boundary_conc_out

    def get_data(self, cellnr):
        index = cellnr
        return index

    def out_conc(self, data, t):
        """
        return the concentration of compound in the void zone of cell cellnr at
        time t
        """
        timenowyarn = self.step_old_time
        if t >= timenowyarn:
            #return data
            return self.step_old_sol[data]
        raise ValueError, 'out concentration should only be requested at a later time'

    def solve_fiber_init(self):
        """
        Solve the diffusion process for a repellent on the fiber at radial position r in the yarn.
        &C/&t = 1/r * &(Dr&C/&r) / &r
        The diffusion coefficient is constant. The finite volume method is used to
        discretize the right side of equation. The mesh in this 1-D condition is 
        uniform.
        """
        for ind, models in enumerate(self.fiber_models):
            for type, model in enumerate(models):
                model.run_init()
                model.solve_init()
                #rebind the out_conc method to a call to yarn1d
                if model.use_extend:
                    model.set_outconc(self.out_conc(ind, 0))
                else:
                    model.set_userdata(self.get_data(ind))
                    model.out_conc = lambda t, data: self.out_conc(data, t)
                self.fiber_mass[ind, type] = model.calc_mass(model.initial_c1)
                self.fiberconc_center = model.initial_c1[0]
                n = int((model.tot_edges_no_extend-2)/2)
                self.fiberconc_middle = model.initial_c1[n]
                self.fiberconc_surface = model.initial_c1[model.tot_edges_no_extend-2]

    def do_fiber_step(self, stoptime):
        """
        Solve the diffusion process on the fiber up to stoptime, starting
        from where we where last. 
        The flux is the BC: S*h(C_equi - C_yarn(t))*H(C-C_b,C_equi-C_yarn(t))
        """
        for ind, models in enumerate(self.fiber_models):
            for type, model in enumerate(models):
                if model.use_extend:
                    model.set_outconc(self.out_conc(ind, self.step_old_time))
                time, result = model.do_step(stoptime, needreinit=True)
                self.fiberconc_center = result[0]
                n = int((model.tot_edges_no_extend-2)/2)
                self.fiberconc_middle = result[n]
                self.fiberconc_surface = result[model.tot_edges_no_extend-2]
                #filedata= open(utils.OUTPUTDIR + os.sep + "fiberconc_%05d" %stoptime + ".txt",'w')
                #filedata.write("conc on %.10f is %s" % (stoptime,result))
                #filedata.close()
                tmp = model.calc_mass(result)
                self.source_mass[ind, type] = self.fiber_mass[ind, type] - tmp
                self.fiber_mass[ind, type] = tmp
                                
    def get_fiber_conc(self):
        """
        method for reading fiberconcentrations from roommodel for last computed
        fiber in the yarn
        """
        return self.fiberconc_center, self.fiberconc_middle, self.fiberconc_surface
                
    def _set_bound_flux(self, flux_edge, conc_r):
        """
        Method that takes BC into account to set flux on edge
        flux here is the flux per radial
        Data is written to flux_edge, conc_r contains solution in the cell centers
        """
        flux_edge[0] = 0.
        #avergage porosity on edge:
        if self.use_extend:
            porright = (self.porosity[self.nr_cell-1] + self.porosity[self.nr_cell]) / 2
        else:
            porright = (self.porosity[self.nr_cell-1] + 1.) / 2
        diffright = (self.diff_coef/self.tortuosity + self.boundary_D_out)/ 2
        if self.bound_type == conf.TRANSFER:
            # tranfer flux, in x: flux_x  = tf * C, so radially per radial a flux
            #  flux_radial = 2 Pi * radius * flux_x / 2 * Pi
            flux_edge[self.nr_edge-1] = self.boundary_transf_right * porright \
                    * conc_r[self.nr_cell-1] * self.grid_edge[self.nr_edge-1]
        elif self.bound_type == conf.DIFF_FLUX:
            # diffusive flux with the outside
            # flux radial = - D_out * (conc_out - yarn_edge_conc)/dist_conc_out * radius
            if self.use_extend:
                conright = conc_r[self.nr_cell]
                bcdist = (self.delta_r[self.nr_cell-1] + self.delta_r[self.nr_cell]) / 2.
            else:
                conright = self.boundary_conc_out
                bcdist = self.boundary_dist
            flux_edge[self.nr_edge-1] = -(diffright * porright * 
                    (conright - conc_r[self.nr_cell-1]) 
                    / bcdist 
                    * self.grid_edge[self.nr_edge-1])
        if self.use_extend:
            #zero flux at right boundary
            flux_edge[-1] = 0.

    def calc_mass(self, conc):
        """
        calculate current amount of mass of volatile based on data currently
        stored
        """
        #first we calculate the mass in the void space:
        mass = np.sum(conc[:self.nr_cell] *
                     (np.power(self.grid_edge[1:self.nr_edge], 2) -
                       np.power(self.grid_edge[:self.nr_edge-1], 2)) *
                     self.porosity[:self.nr_cell]
                    ) * np.pi
##        print "mass in void space yarn", mass
        #now we add the mass in the fibers
        for ind, pos in enumerate(self.grid[:self.nr_cell]):
            for type, blend in enumerate(self.blend):
                #nrf_shell is number of fibers of blend in the shell at that grid position
                massfib = (self.fiber_mass[ind, type]
                            * self.nrf_shell[ind] * blend)
                #print 'mass fiber', self.fiber_mass[ind,type], 'nr fibers per shell', self.nrf_shell[ind]
                mass += massfib
        #print 'yarn conc', conc
        #print 'yarn totalmass',  mass, 'microgram'
        return mass

    def calc_mass_overlap(self, conc):
        """
        calculate current amount of mass of volatile in the overlap region
        based on data currently stored. From mol/microm^2 to mol
        """
        #we calculate the mass in the void space:
        mass = np.sum(conc[self.nr_cell:] * 
                      (np.power(self.grid_edge[self.nr_edge:], 2) -
                        np.power(self.grid_edge[self.nr_edge-1:-1], 2)) *
                      self.porosity[self.nr_cell:]
                     ) * np.pi
        #print "porosity",self.porosity
        ##print 'yarn mass overlap', conc[self.nr_cell:], mass
        return mass

    def set_source(self, timestep):
        ## we calculated the source_mass from a fiber, using upscaling via volume averaging technique:
        ## source conc = nrf_shell * conc_r * \int_{r_{i+1}}^r_i rdr / V = nrf_shell * conc_r / (2*\pi)
        ## source mass = source conc * V = nrf_shell * conc_r * (r_{i+1}^2-r_i^2)*pi / 2*pi

        """
        Method to calculate the radial source term
        Per radial we have the global equation 
           \partial_t (n r C) = \partial_r (D/tau) r \partial_r (n C) + r Source
        where Source is mass per time per volume released/absorbed by the fibers
        So Source = nrf_shell * mass_source_fiber / (V \Delta t)
        This equation is integrated over a shell and devided by n (the porosity),
        and we determine 
           n d_t w, with w = rC, where the sourceterm is \int_{r_i}^{r_{i+1}} r Source dr
        and is the term here calculated and stored in self.source
        As we assume Source constant over a shell by averaging out the mass over
        the area of void space of a shell (nV), we have
            Source = nrf_shell * mass_source_fiber/(nV \Delta t) * \Delta r_i^2 / 2
        self.source_mass contains per shell how much mass was released in 
        previous step by one fiber. Suppose this mass is M. 
        We determine how many fibers there are radially, multiply this with M
        and divide by volume V * porosity n \delta t to obtain Source-concentration,
        since concentration is mass/volume time. 
        Afterwards we multiply this Source with \Delta r_i^2 / (2 n \Delta r)
        coming from the integration (int n d_t w gives the term n \Delta r).
        """
        for ind, pos in enumerate(self.grid_edge[:self.nr_cell]):
            self.source[ind] = 0.
            #V is the area of the shell
            V = np.pi*((pos+self.delta_r[ind])**2-pos**2)
            for type, blend in enumerate(self.blend):
                #nrf_shell is number of fibers of blend in the shell at that grid position
                # per radial
                # self.source_mass is the mass coming out of one fiber, we need a concentration
                # so,nrf_shell * self.source_conc = (nrf_shell * self.source_mass) / (porosity*V_shell)
                self.source_conc[ind,type] = (self.source_mass[ind, type] 
                                                / (self.porosity[ind]*V) )
                self.source[ind] += (self.source_conc[ind, type]
                                        * self.nrf_shell[ind] * blend)
            self.source[ind] /= timestep
        ## Note: source must be per second, so divided by the timestep

    def f_conc1_ode(self, t, conc_r, diff_u_t):
        """
        Solving the radial yarn 1D diffusion equation: 
        
         n \partial_t (rC) =  \partial_r (D/tau r n \partial_r C) + Source * r
        
        with Source the conc amount per time unit added at r. 
        Solution is obtained by integration over a cell, so
        
         n \delta r d_t (r C) = flux_right - flux_left + Source (\delta r^2 /2)
        
        so
        
         n d_t C = 1 / (r \delta r) * (flux_right - flux_left + Source (\delta r^2 /2) )
        """
        grid = self.grid
        #Initialize the flux rate on the edges
        flux_edge = self.__tmp_flux_edge
        #set flux on edge 0, self.nr_edge-1 and -1
        self._set_bound_flux(flux_edge, conc_r)

        #calculate flux rate in each edge of the domain
        flux_edge[1:self.nr_edge-1] = -(2 * (self.diff_coef/self.tortuosity) *
            self.grid_edge[1:self.nr_edge-1] *
            (conc_r[1:self.nr_cell]-conc_r[:self.nr_cell-1])
            /(self.delta_r[:self.nr_cell-1]+self.delta_r[1:self.nr_cell])
            * (self.porosity[:self.nr_cell-1] + self.porosity[1:self.nr_cell])/2
            )
        if self.use_extend:
            # diffusion in the outside region
            flux_edge[self.nr_edge:-1] = -(2 * self.boundary_D_out *
              self.grid_edge[self.nr_edge:-1] *
              (conc_r[self.nr_cell+1:]-conc_r[self.nr_cell:-1])
              /(self.delta_r[self.nr_cell:-1]+self.delta_r[self.nr_cell+1:])
              * (self.porosity[self.nr_cell:-1] + self.porosity[self.nr_cell+1:])/2
              )
        diff_u_t[:] = ((flux_edge[:-1]-flux_edge[1:])
                            / self.delta_r[:]/ self.porosity[:]
                    + self.source[:] * self.delta_rsquare / 2
                      / self.delta_r
                      )
        if self.use_extend and self.source_overlap:
            #porosity assumed 1 in extend!
            diff_u_t[self.nr_cell:] += (self.source_overlap
                            * self.delta_rsquare[self.nr_cell:] / 2
                            / self.delta_r[self.nr_cell:])
        diff_u_t[:] = diff_u_t[:] / self.grid[:]  # still division by r to move from w to C

    def solve_ode_init(self):
        """
        Initialize the ode solver
        """
        self.initial_t = 0.
        self.step_old_time = self.initial_t
        n_cells = len(self.init_conc)
        self.ret_y = np.empty(n_cells, float)
        self.__tmp_flux_edge = np.empty(n_cells+1, float)
        self.tstep = 0
        self.step_old_sol = np.empty(n_cells, float)
        self.step_old_sol[:] = self.init_conc[:]
        
        self.solver = sc_ode('cvode', self.f_conc1_ode,
                             min_step_size=1e-9,
                             first_step_size=1e-16,
                             rtol=1e-6, atol=1e-10,
                             max_steps=50000, lband=1, uband=1)
        self.solver.init_step(self.step_old_time, self.init_conc)
        self.initialized = True

    def do_ode_step(self, stoptime):
        """Solve the yarnmodel up to stoptime, continuing from the present
           state, return the time, concentration after step
        """
        #fix where next to stop
        self.solver.set_options(tstop=stoptime)
        if not self.initialized:
            raise Exception, 'Solver ode not initialized'
        #solve the problem
        flag, realtime = self.solver.step(stoptime, self.ret_y)
        if flag < 0:
            raise Exception, 'could not find solution, flag %d' % flag
        assert np.allclose(realtime, stoptime), "%f %f" % (realtime, stoptime)
        return stoptime, self.ret_y

    def do_yarn_init(self):
        """
        generic initialization needed before yarn can be solved
        """
        self.create_mesh()
        self.initial_yarn1d()
        if not self.initialized:
            self.solve_ode_init()
        self.solve_fiber_init()

    def do_yarn_step(self, stoptime):
        """
        Solve yarn up to time t. This does:
           1. solve the fiber up to t
           2. set correct source term for the yarn
           3. solve the yarn up to t
        """
        compute = True
        #even is step is large, we don't compute for a longer time than delta_t
        t = self.step_old_time
        while compute:
            t +=  self.delta_t
            if  t >= stoptime - self.delta_t/100.:
                t = stoptime
                compute = False
            self.do_fiber_step(t)
            self.set_source(t-self.step_old_time)
            #we need to reinit as rhs changed
            if REINIT_ALWAYS:
                self.solver.init_step(self.step_old_time, self.step_old_sol)
            realtime, self.step_old_sol = self.do_ode_step(t)
            self.tstep += 1
            self.step_old_time = t
#        filedata= open(utils.OUTPUTDIR + os.sep + "fiberconccenter" + ".txt",'w')
#        for i in range(0,len(self.fiberconc_center)):
#            filedata.write("%.5f %.5f\n" % (self.fiberconc_center[i,0],self.fiberconc_center[i,1]))
#        filedata.close()
#        filedata= open(utils.OUTPUTDIR + os.sep + "fiberconcmiddle" + ".txt",'w')
#        for i in range(0,len(self.fiberconc_middle)):
#            filedata.write("%.5f %.5f\n" % (self.fiberconc_middle[i,0],self.fiberconc_middle[i,1]))
#        filedata.close()
#        filedata= open(utils.OUTPUTDIR + os.sep + "fiberconcsurface" + ".txt",'w')
#        for i in range(0,len(self.fiberconc_surface)):
#            filedata.write("%.5f %.5f\n" % (self.fiberconc_surface[i,0],self.fiberconc_surface[i,1]))
#        filedata.close()
        
        return realtime, self.step_old_sol

    def view_sol(self, times, conc):
        """
        Show the solution in conc with times.
        conc[i][:] contains solution at time times[i]
        """
        if self.plotevery:
            self.solution_view = CellVariable(name="Yarn radial concentration",
                        mesh=self.mesh_yarn, value=conc[0][:self.nr_cell])
            if isinstance(conc, np.ndarray):
                maxv = conc.max() * 1.2
                minv = conc.min() * 0.9
            else:
                maxv = np.max(conc) * 1.2
                minv = np.min(conc) * 0.9
            self.viewer =  Matplotlib1DViewer(vars=self.solution_view,
                                datamin=minv, datamax=maxv)
            self.viewerplotcount = 0
            self.viewerwritecount = 0
            for time, con in zip(times, conc):
                self.solution_view.setValue(con[:self.nr_cell])
                if self.viewerplotcount == 0 or (self.writeevery and 
                                            self.viewerwritecount == 0):
                    self.viewer.axes.set_title('time %s' %str(time))
                    if self.writeevery and self.viewerwritecount == 0:
                        #plot and savefig
                        self.viewer.plot(filename=utils.OUTPUTDIR + os.sep \
                                                + 'yarnconc%08.4f.png' % time)
                    else:
                        #only plot
                        self.viewer.plot()
                self.viewerplotcount += 1
                self.viewerplotcount = self.viewerplotcount % self.plotevery
                if self.writeevery:
                    self.viewerwritecount += 1
                    self.viewerwritecount = self.viewerwritecount % self.writeevery

    def run(self, wait=False):
        self.do_yarn_init()
        #data storage, will lead to memerror if many times !
        n_cells = len(self.init_conc)
        self.conc1 = np.empty((self.steps+1, n_cells), float)
        self.conc1[0][:] = self.init_conc[:]
        
        print 'Start mass of DEET per grid cell per fiber type'
        for ind, masses in enumerate(self.fiber_mass):
            print 'cell', ind,
            for mass in masses:
                print mass, ' - ',
            print ' '
        mc1 = self.calc_mass(self.step_old_sol)
        mc2 = self.calc_mass_overlap(self.step_old_sol)
        print 'Total mass in yarn', mc1, ', mass in overlap zone:', mc2, \
                'Sum', mc1 + mc2

        tstep = 0
        t = self.times(tstep+1)
        while t <= self.time_period+self.delta_t/10:
            tstep += 1
            #print 'solving t', t
            rt, rety = self.do_yarn_step(t)
            self.conc1[self.tstep][:] = self.ret_y[:]
            t = self.times(tstep+1)
        

        print 'Final mass of DEET per grid cell per fiber type'
        for ind, masses in enumerate(self.fiber_mass):
            print 'cell', ind,
            for mass in masses:
                print mass, ' - ',
            print ' '
        mc1 = self.calc_mass(self.step_old_sol)
        mc2 = self.calc_mass_overlap(self.step_old_sol)
        print 'Total mass in yarn', mc1, ', mass in overlap zone:', mc2, \
                'Sum', mc1 + mc2

        self.view_sol(self.times(0,self.steps), self.conc1)

        if wait:
            raw_input("Finished yarn1d run")
Exemple #7
0
Line Loop(2) = {7, 8, 9, 10};
Line Loop(3) = {11, 12, 13, 14};
Plane Surface(1) = {1, 2, 3};
Plane Surface(2) = {2};
Plane Surface(3) = {3};

Physical Line("Ground") = {4, 5, 6};
Physical Surface("Field") = {1};
Physical Surface("Anode") = {2};
Physical Surface("Cathode") = {3};
"""
for refinement in range(10):
    mesh = Gmsh2D(geo, background=monitor)

    charge = CellVariable(mesh=mesh, name=r"$\rho$", value=0.)
    charge.setValue(+1, where=mesh.physicalCells["Anode"])
    charge.setValue(-1, where=mesh.physicalCells["Cathode"])

    potential = CellVariable(mesh=mesh, name=r"$\psi$")
    potential.constrain(0., where=mesh.physicalFaces["Ground"])

    eq = DiffusionTerm(coeff=1.) == -charge

    res0 = eq.sweep(var=potential)

    res = eq.justResidualVector(var=potential)

    res1 = numerix.L2norm(res)
    res1a = CellVariable(mesh=mesh, value=abs(res))

    res = CellVariable(mesh=mesh, name="residual", value=abs(res) / mesh.cellVolumes**(1./mesh.dim) / 1e-3)
Exemple #8
0
I1 = Variable(value=((0, -1), (1, 0)))
DIF_COEF = ALPHA**2 * (1. + C_ani * BETA) * (D_DIAG * I0 + D_OFF * I1)

TAU = 0.0003
KAPPA_1 = 0.9
KAPPA_2 = 20.

phase_EQ = (TransientTerm(TAU) == DiffusionTerm(DIF_COEF) + ImplicitSourceTerm(
    (phase - 0.5 - KAPPA_1 / np.pi * np.arctan(KAPPA_2 * D_temp)) *
    (1 - phase)))

#%% Circular Solidified Region in the Center
radius = DX * 5.0
C_circ = (NX * DX / 2, NY * DY / 2)
X, Y = mesh.cellCenters
phase.setValue(1., where=((X - C_circ[0])**2 + (Y - C_circ[1])**2) < radius**2)
D_temp.setValue(-0.5)

#%% Plotting

if __name__ == "__main__":
    try:
        import pylab

        class DendriteViewer(Matplotlib2DGridViewer):
            def __init__(self,
                         phase,
                         D_temp,
                         title=None,
                         limits={},
                         **kwlimits):
Exemple #9
0
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
Exemple #10
0
from fipy import Grid1D, CellVariable, Viewer
from fipy.tools import numerix, dump

import numpy
from scipy.special import wofz


# ----------------- Mesh Generation -----------------------
L = 4.0
nx = 100
mesh = Grid1D(nx=nx, Lx=L)
x = mesh.cellCenters[0] # Cell position

plasma_disp_real = CellVariable(name=r"Re$(X(z))$", mesh=mesh)
plasma_disp_imag = CellVariable(name=r"Im$(X(z))$", mesh=mesh)

full_plasma_disp = numpy.array(1j*numerix.sqrt(numerix.pi)\
		* numerix.exp(-x**2)*wofz(x))
print full_plasma_disp

plasma_disp_real.setValue(full_plasma_disp.real)
plasma_disp_imag.setValue(full_plasma_disp.imag)

initial_viewer = Viewer((plasma_disp_real, plasma_disp_imag),\
		xmin=0.0, legend='best')
raw_input("Pause for Initial Conditions")

Exemple #11
0
    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.1 * r)  # doctest: +GMSH
Phi = CellVariable(name=r"$\Phi$", mesh=mesh)  # doctest: +GMSH

Phi.setValue(GaussianNoiseVariable(mesh=mesh, mean=0.5,
                                   variance=0.01))  # doctest: +GMSH

if __name__ == "__main__":
    try:
        print("\n done")  #Intermediate Print Statement
        #viewer = MayaviClient(vars=phi,datamin=0., datamax=1.,daemon_file="/home/elekrv/Documents/Scripts/CahnSphere/sphereDaemon.py") #Commented as not required anymore
        viewer = VTKViewer(vars=Phi,
                           datamin=0.,
                           datamax=1.,
                           xmin=-2.5,
                           zmax=2.5)  #Changed Statement
        print("\n Daemon file")  #Intermediate Print Statement
    except (NameError, ImportError, SystemError, TypeError):
        viewer = VTKViewer(vars=Phi,
                           datamin=0.,
                           datamax=1.,
Exemple #12
0
import re
import os

# Setting up a mesh
nx = 50
dx = 0.02
L = nx * dx
mesh = Grid1D(nx=nx, dx=dx)

# Defining the cell variable
c = CellVariable(mesh=mesh, name=r"$c$")

# Initialise c with a funky profile
x = mesh.cellCenters[0]
c.value = 0.0
c.setValue((0.3 * numerix.sin(2.0 * x * numerix.pi)) + 0.5)

# Setting up the no-flux boundary conditions
c.faceGrad.constrain(0.0, where=mesh.facesLeft)
c.faceGrad.constrain(0.0, where=mesh.facesRight)

# Provide value for diffusion and reaction coefficient
D = 1.0
k = -2.0

# Specifying our alpha value. We will only use backwards Euler going forward
alpha = 1

# Defining the equation with the reaction term.
eq = TransientTerm() == DiffusionTerm(coeff=D) + ImplicitSourceTerm(coeff=k)
Exemple #13
0
from fipy.tools import numerix
from math import log

nx = 100
dx = 0.3

mesh = Grid1D(dx=dx, nx=nx)
phi = CellVariable(name=r"$\phi$", mesh=mesh)
psi = CellVariable(name=r"$\psi$", mesh=mesh)

# noise = GaussianNoiseVariable(mesh=mesh, mean=0.8, variance=0.002).value
# phi[:] = noise

x = mesh.cellCenters[0]
phi.value = 0.1
phi.setValue(0.2, where=x < 0.3*(nx*dx))
phi.setValue(0.6, where=x > 0.3*(nx*dx))
phi.setValue(0.2, where=x > 0.32*(nx*dx))
phi.setValue(0.6, where=x > 0.7*(nx*dx))
phi.setValue(0.2, where=x > 0.72*(nx*dx))



D = a = epsilon = 1.
N_A = 500
N_B = 500
chi_AB = 0.015
kappa = 2*chi_AB / 3.0

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
Exemple #14
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
Exemple #15
0
    distanceViewer = Viewer(vars=distanceVariable,
                            datamin=-initialRadius,
                            datamax=initialRadius)
    surfactantViewer = Viewer(vars=surfactantVariable,
                              datamin=0.,
                              datamax=100.)
    velocityViewer = Viewer(vars=velocity, datamin=0., datamax=200.)
    distanceViewer.plot()
    surfactantViewer.plot()
    velocityViewer.plot()

    totalTime = 0

    for step in range(steps):
        print('step', step)
        velocity.setValue(surfactantVariable.interfaceVar * k)
        distanceVariable.extendVariable(velocity)
        timeStepDuration = cfl * dx / velocity.max()
        distanceVariable.updateOld()
        advectionEquation.solve(distanceVariable, dt=timeStepDuration)
        surfactantEquation.solve(surfactantVariable, dt=1)

        totalTime += timeStepDuration

        velocityViewer.plot()
        distanceViewer.plot()
        surfactantViewer.plot()

        finalRadius = numerix.sqrt(2 * k * initialRadius *
                                   initialSurfactantValue * totalTime +
                                   initialRadius**2)
Exemple #16
0
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
Exemple #17
0
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)
Exemple #18
0
L = 5.0
mesh = Grid1D(nx=nx, Lx=L)

x = mesh.cellCenters[0]  # Cell position

# ----------------- Variable Declarations -----------------
density = CellVariable(name=r"$n$", mesh=mesh, hasOld=True)
temperature = CellVariable(name=r"$T$", mesh=mesh, hasOld=True)
Z = CellVariable(name=r"$Z$", mesh=mesh, hasOld=True)

Diffusivity = CellVariable(name=r"$D$", mesh=mesh, hasOld=True)

# ----------- Initial Conditions of Z ---------------------
Z0L = 1.0  # L--mode
Z0H = Z_S * (1.0 - numerix.tanh((L * x - L) / 2.0))  # H--mode
Z.setValue(Z0H)

# ----------------- Diffusivities -------------------------
# Itohs'/Zohm's model
D_Zohm = (D_max + D_min) / 2.0 + ((D_max - D_min) * numerix.tanh(Z)) / 2.0
# Stap's Model
alpha_sup = 0.5
D_Staps = D_min + (D_max - D_min) / (1.0 +
                                     alpha_sup * numerix.dot(Z.grad, Z.grad))
# Flow-Shear Model
a1, a3 = 1.0, 0.5  # ASSUMES a2 = 0
D_Shear = D_min + (D_max - D_min) / (1.0 + a1 *
                                     (Z)**2 + a3 * numerix.dot(Z.grad, Z.grad))

# CHOOSE DIFFUSIVITY HERE!
D_choice = D_Staps
Exemple #19
0
x = mesh.cellCenters[0]  # Cell position
X = mesh.faceCenters[0]  # Face position, if needed

# -------------- State Variable Declarations --------------
density = CellVariable(name=r"$n$", mesh=mesh, hasOld=True)

temperature = CellVariable(name=r"$T$", mesh=mesh, hasOld=True)

U = CellVariable(name=r"$U$", mesh=mesh, hasOld=True)

Z = CellVariable(name=r"$Z$", mesh=mesh, hasOld=True)

Diffusivity = CellVariable(name=r"$D$", mesh=mesh, hasOld=True)

U.setValue(density * temperature / (gamma - 1.0))

# -------------- Other Variable Declarations --------------
# Thermal velocities (most probable)
v_Ti = CellVariable(name=r"$v_{th,i}$", mesh=mesh)
v_Te = CellVariable(name=r"$v_{th,e}$", mesh=mesh)

# Neutrals density in use for CX friction
n_0 = CellVariable(name=r"$n_0$", mesh=mesh)

# Poloidal gyro-(Larmor) radii
rho_pi = CellVariable(name=r"$\rho_{\theta i}$", mesh=mesh)
rho_pe = CellVariable(name=r"$\rho_{\theta e}$", mesh=mesh)

# Banana orbit bounce frequencies
omega_bi = CellVariable(name=r"$\omega_{bi}$", mesh=mesh)
Exemple #20
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
Exemple #21
0
# ----------------- Variable Declarations -----------------
density = CellVariable(name=r"$n$", mesh=mesh, hasOld=True)

temperature = CellVariable(name=r"$T$", mesh=mesh, hasOld=True)

Z = CellVariable(name=r"$Z$", mesh=mesh, hasOld=True)

## Diffusivity
D_Zohm = CellVariable(name="Zohm", mesh=mesh, hasOld=True)
D_Staps = CellVariable(name="Staps", mesh=mesh, hasOld=True)
D_Shear = CellVariable(name="Flow-Shear", mesh=mesh, hasOld=True)


# ------------- Initial Conditions and Diffusivity---------
Z0 = Z_S*(1 - numerix.tanh((L*x - L) / 2))
Z.setValue(Z0)

# Zohm's model
D_Zohm.setValue((D_max + D_min) / 2.0 + ((D_max - D_min)*numerix.tanh(Z)) / 2.0)
# Stap's Model
alpha_sup = 0.5
D_Staps.setValue(D_min + (D_max - D_min) / (1.0 + alpha_sup*(Z.grad.mag)**2))
# Flow-Shear Model
a1, a2, a3 = 0.7, 1.25, 0.5
D_Shear.setValue(D_min + (D_max - D_min) / (1.0 + a1*Z**2 + a2*Z*(Z.grad) + a3*(Z.grad)**2))


# ----------------- Boundary Conditions -------------------
# Z Boundary Conditions:
#	d/dx(Z(0,t)) == Z / lambda_Z
#	mu*D/epsilon * d/dx(Z(L,t)) == 0
Exemple #22
0
    duration = TIME_MAX

time_stride = TIME_STRIDE
timestep = 0

# Defining the solver to improve numerical stabilty
solver = LinearLUSolver(tolerance=1e-9, iterations=50, precon="lu")
# solver = PETSc.KSP().create()
start = time.time()

while elapsed < duration:
    if (timestep == 0):
        vw = VTKCellViewer(vars=(x_a, mu_AB))
        vw.plot(filename="0_output.%d.vtk" % (parallelComm.procID))
    elapsed += dt
    timestep += 1
    x_a.updateOld()
    mu_AB.updateOld()
    res = 1e+10
    while res > 1e-10:
        res = eq.sweep(dt=dt, solver=solver)
        x_a.setValue(0.0, where=x_a < 0.0)
        x_a.setValue(1.0, where=x_a > 1.0)
        print("sweep!")
    print(elapsed)
    end = time.time()
    print(end - start)
    if (timestep % time_stride == 0):
        vw = VTKCellViewer(vars=(x_a, mu_AB))
        vw.plot(filename="%s_output.%d.vtk" % (elapsed, parallelComm.procID))
Exemple #23
0
def runLeveler(kLeveler=0.018,
               bulkLevelerConcentration=0.02,
               cellSize=0.1e-7,
               rateConstant=0.00026,
               initialAcceleratorCoverage=0.0,
               levelerDiffusionCoefficient=5e-10,
               numberOfSteps=400,
               displayRate=10,
               displayViewers=True):


    kLevelerConsumption = 0.0005
    aspectRatio = 1.5
    faradaysConstant = 9.6485e4
    gasConstant = 8.314
    acceleratorDiffusionCoefficient = 4e-10
    siteDensity = 6.35e-6
    atomicVolume = 7.1e-6
    charge = 2
    metalDiffusionCoefficient = 4e-10
    temperature = 298.
    overpotential = -0.25
    bulkMetalConcentration = 250.
    bulkAcceleratorConcentration = 50.0e-3
    initialLevelerCoverage = 0.
    cflNumber = 0.2
    cellsBelowTrench = 10
    trenchDepth = 0.4e-6
    trenchSpacing = 0.6e-6
    boundaryLayerDepth = 98.7e-6
    i0Suppressor = 0.3
    i0Accelerator = 22.5
    alphaSuppressor = 0.5
    alphaAccelerator = 0.4
    alphaAdsorption = 0.62
    m = 4
    b = 2.65
    A = 0.3
    Ba = -40
    Bb = 60
    Vd = 0.098
    Bd = 0.0008

    etaPrime = faradaysConstant * overpotential / gasConstant / temperature

    mesh = TrenchMesh(cellSize = cellSize,
                      trenchSpacing = trenchSpacing,
                      trenchDepth = trenchDepth,
                      boundaryLayerDepth = boundaryLayerDepth,
                      aspectRatio = aspectRatio,
                      angle = numerix.pi * 4. / 180.)

    distanceVar = GapFillDistanceVariable(
        name = 'distance variable',
        mesh = mesh,
        value = -1.)

    distanceVar.setValue(1., where=mesh.electrolyteMask)

    distanceVar.calcDistanceFunction()
    levelerVar = SurfactantVariable(
        name = "leveler variable",
        value = initialLevelerCoverage,
        distanceVar = distanceVar)

    acceleratorVar = SurfactantVariable(
        name = "accelerator variable",
        value = initialAcceleratorCoverage,
        distanceVar = distanceVar)

    bulkAcceleratorVar = CellVariable(name = 'bulk accelerator variable',
                                      mesh = mesh,
                                      value = bulkAcceleratorConcentration)

    bulkLevelerVar = CellVariable(
        name = 'bulk leveler variable',
        mesh = mesh,
        value = bulkLevelerConcentration)

    metalVar = CellVariable(
        name = 'metal variable',
        mesh = mesh,
        value = bulkMetalConcentration)

    def depositionCoeff(alpha, i0):
        expo = numerix.exp(-alpha * etaPrime)
        return 2 * i0 * (expo - expo * numerix.exp(etaPrime))

    coeffSuppressor = depositionCoeff(alphaSuppressor, i0Suppressor)
    coeffAccelerator = depositionCoeff(alphaAccelerator, i0Accelerator)

    exchangeCurrentDensity = acceleratorVar.interfaceVar * (coeffAccelerator - coeffSuppressor) + coeffSuppressor

    currentDensity = metalVar / bulkMetalConcentration * exchangeCurrentDensity

    depositionRateVariable = currentDensity * atomicVolume / charge / faradaysConstant

    extensionVelocityVariable = CellVariable(
        name = 'extension velocity',
        mesh = mesh,
        value = depositionRateVariable)

    kAccelerator = rateConstant * numerix.exp(-alphaAdsorption * etaPrime)
    kAcceleratorConsumption =  Bd + A / (numerix.exp(Ba * (overpotential + Vd)) + numerix.exp(Bb * (overpotential + Vd)))
    q = m * overpotential + b

    levelerSurfactantEquation = AdsorbingSurfactantEquation(
        levelerVar,
        distanceVar = distanceVar,
        bulkVar = bulkLevelerVar,
        rateConstant = kLeveler,
        consumptionCoeff = kLevelerConsumption * depositionRateVariable)

    accVar1 = acceleratorVar.interfaceVar
    accVar2 = (accVar1 > 0) * accVar1
    accConsumptionCoeff = kAcceleratorConsumption * (accVar2**(q - 1))

    acceleratorSurfactantEquation = AdsorbingSurfactantEquation(
        acceleratorVar,
        distanceVar = distanceVar,
        bulkVar = bulkAcceleratorVar,
        rateConstant = kAccelerator,
        otherVar = levelerVar,
        otherBulkVar = bulkLevelerVar,
        otherRateConstant = kLeveler,
        consumptionCoeff = accConsumptionCoeff)

    advectionEquation = TransientTerm() + FirstOrderAdvectionTerm(extensionVelocityVariable)

    metalEquation = buildMetalIonDiffusionEquation(
        ionVar = metalVar,
        distanceVar = distanceVar,
        depositionRate = depositionRateVariable,
        diffusionCoeff = metalDiffusionCoefficient,
        metalIonMolarVolume = atomicVolume)

    metalVar.constrain(bulkMetalConcentration, mesh.facesTop)

    bulkAcceleratorEquation = buildSurfactantBulkDiffusionEquation(
        bulkVar = bulkAcceleratorVar,
        distanceVar = distanceVar,
        surfactantVar = acceleratorVar,
        otherSurfactantVar = levelerVar,
        diffusionCoeff = acceleratorDiffusionCoefficient,
        rateConstant = kAccelerator * siteDensity)

    bulkAcceleratorVar.constrain(bulkAcceleratorConcentration, mesh.facesTop)

    bulkLevelerEquation = buildSurfactantBulkDiffusionEquation(
        bulkVar = bulkLevelerVar,
        distanceVar = distanceVar,
        surfactantVar = levelerVar,
        diffusionCoeff = levelerDiffusionCoefficient,
        rateConstant = kLeveler * siteDensity)

    bulkLevelerVar.constrain(bulkLevelerConcentration, mesh.facesTop)

    eqnTuple = ( (advectionEquation, distanceVar, (), None),
                 (levelerSurfactantEquation, levelerVar, (), None),
                 (acceleratorSurfactantEquation, acceleratorVar, (), None),
                 (metalEquation, metalVar,  (), None),
                 (bulkAcceleratorEquation, bulkAcceleratorVar, (), GeneralSolver()),
                 (bulkLevelerEquation, bulkLevelerVar, (), GeneralSolver()))

    narrowBandWidth = 20 * cellSize
    levelSetUpdateFrequency = int(0.7 * narrowBandWidth / cellSize / cflNumber / 2)

    totalTime = 0.0

    if displayViewers:
        try:
            raise Exception
            from .mayaviSurfactantViewer import MayaviSurfactantViewer
            viewers = (
                MayaviSurfactantViewer(distanceVar, acceleratorVar.interfaceVar, zoomFactor = 1e6, datamax=0.5, datamin=0.0, smooth = 1, title = 'accelerator coverage'),
                MayaviSurfactantViewer(distanceVar, levelerVar.interfaceVar, zoomFactor = 1e6, datamax=0.5, datamin=0.0, smooth = 1, title = 'leveler coverage'))
        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))

            viewers = (Viewer(PlotVariable(var=acceleratorVar.interfaceVar)),
                       Viewer(PlotVariable(var=levelerVar.interfaceVar)))


    for step in range(numberOfSteps):

        if displayViewers:
            if step % displayRate == 0:
                for viewer in viewers:
                    viewer.plot()

        if step % levelSetUpdateFrequency == 0:
            distanceVar.calcDistanceFunction()

        extensionVelocityVariable.setValue(depositionRateVariable)

        extOnInt = numerix.where(distanceVar.globalValue > 0,
                                 numerix.where(distanceVar.globalValue < 2 * cellSize,
                                               extensionVelocityVariable.globalValue,
                                               0),
                                 0)

        dt = cflNumber * cellSize / extOnInt.max()

        distanceVar.extendVariable(extensionVelocityVariable)

        for eqn, var, BCs, solver in eqnTuple:
            eqn.solve(var, boundaryConditions = BCs, dt = dt, solver=solver)

        totalTime += dt

    point = ((1.25e-08,), (3.125e-07,))
    value = 2.02815779e-08
    return abs(float(distanceVar(point, order=1)) - value) < cellSize / 10.0