usnistgov / fipy

FiPy is a Finite Volume PDE solver written in Python
http://pages.nist.gov/fipy/en/latest
Other
512 stars 149 forks source link

1D Time-Dependent Coupled PDEs: Factor is exactly singular #788

Closed JDS19 closed 2 years ago

JDS19 commented 3 years ago

I wrote this problem on another site but realized this site is probably the better place for it. I'm solving a nonlinearly coupled system of PDEs. Here's the post, with equation format used from Jupyter Notebook formatting (I'm new to this site, so if it's easier for me to add images of the equations, I can do that): The system I am solving is described as: $ \frac{\partial c_1}{\partial t} = -\nabla N_1 - \nabla i/F $ \ $ \frac{\partial c_2}{\partial t} = -\nabla N_2 + \nabla i/F $ \ $ \sum{z_i \nabla N_i} = \nabla i/F $ \ where $ N_i = -D\nabla c_i - Dz_ic_i\nabla \phi_2 $ \ and $ \nabla i = ai0/por(c_1/c_1^0 e^{z_1ctF/(RT)(\phi_1 - \phi_2 - \phi_0)} - c_2/c_2^0 e^{z_2ctF/(RT)(\phi_1 - \phi_2 - \phi_0)}) $

a,i0,F,D,phi_1,z_1,ct,R,T, c_1^0, and c_2^0 are constants phi_2, c_1, and c_2 are time-dependent, time-evolving variables to solve for. In the problem, z_2 is 0 which simplifies the flux and exponent terms for c_2.

In implementing the flux terms in my code given by N, the chain rule is used to better couple the system and try to stay implicit:

$\nabla (c \nabla \phi) \equiv \nabla c \cdot \nabla \phi + c \nabla^2 \phi$

For simplicity, start with 0 flux boundary conditions on the bounds of x on [0,L]. The initial conditions are:

$ c_1(x,0) = 0.1 $ \ $ c_2(x,0) = 0. $ \ $ \phi_2 (x,0) = \phi_0 $

When I run the attached code, I get "RuntimeError: Factor is exactly singular" I've messed around with this code a bit, and in some formulations of this problem, with very small time changes, the code will solve, but the values don't change. I've looked into changing the iterations or tolerance of the solver, but it either doesn't change the final solution or the code doesn't run. Another issue is the long runtime because dt seems limited by the diffusion coefficient. Here's the code. Any help is greatly appreciated, as I've tried making my own solver but found that FiPy can greatly reduce my number of lines of code so it may be easier to de-bug.

import numpy as np
import scipy
from fipy import *
from fipy import Variable, FaceVariable, CellVariable, Grid1D, TransientTerm, DiffusionTerm, Viewer
from fipy import ImplicitSourceTerm, ExplicitDiffusionTerm
from fipy.tools import numerix
from builtins import range

phi_0 = 0.0 # arbitrarily set to 0
phi_app = 0.2 # Applied voltage 
c1_0 = 0.1 # M  
c2_0 = 0.1 # M
z1 = -1.0
z2 = 0.
phi_1 = phi_0 + phi_app/2 
L = .25 # cm of electrode thickness 
por = 0.4 # porosoity 
D = 5*10**-5 # diffusion coefficient, cm^2/s
a = 360. #cm^2 per cm^3, specific interfacial area for GFD2.5
ct,R,F,T = 0.5, 8.3143, 96487., 293.
ne, s = 1, 1
i0 = 0.005 # from Exchange Current Densities 

nx = 10000
dx = L/nx
mesh = Grid1D(nx=nx,dx=dx)
x = mesh.cellCenters[0]
#dt = .01
dt = 0.5*dx**2/(2*D)
steps = 1000
t = dt * steps
time = Variable(0.)

phi2 = CellVariable(name="phi2",mesh=mesh,hasOld=True)
c1 =  CellVariable(name="c1",mesh=mesh,hasOld=True)
c2 =  CellVariable(name="c2",mesh=mesh,hasOld=True)
phi2.setValue(phi_0)
c1.setValue(c1_0)
c2.setValue(c2_0)

# No flux at one end
c1.faceGrad.constrain(0,mesh.facesRight)
c2.faceGrad.constrain(0,mesh.facesRight)
phi2.faceGrad.constrain(0,mesh.facesRight)

# No flux at other end
c1.faceGrad.constrain(0,mesh.facesLeft)
c2.faceGrad.constrain(0,mesh.facesLeft)
phi2.faceGrad.constrain(0,mesh.facesLeft)

far = a*i0/F*(c1/c1_0*numerix.exp(z1*ct*F*(phi_1-phi2-phi_0)/(R*T))-\
              c2/c2_0*numerix.exp(-z2*ct*F*(phi_1-phi2-phi_0)/(R*T)))

# Equation for first species
eq1 = TransientTerm(var=c1) == DiffusionTerm(coeff=D,var=c1) \
# add migration
+ DiffusionTerm(coeff=c1*z1*D,var=phi2)
# Replaced below  line w/ above because below is not
# very implicit and we want to couple the equations
+ (ImplicitSourceTerm(coeff=phi2.faceGrad.divergence*D*z1,var=c1) 
- phi2.grad.dot(c1.grad)*D*z1)  \

# subtract Faradaic term
- a*i0/F/por*c1/c1_0*numerix.exp(z1*ct*F*(phi_1-phi2-phi_0)/(R*T)) \
- ImplicitSourceTerm(coeff=a*i0*(-c2/c2_0),var=None) 
# Used above line because z2=0

# c2 equation; migration has no effect, z2=0. 
# Faradaic term is added, broken into
# two terms, one to be a variable of c2
eq2 = TransientTerm(var=c2) == DiffusionTerm(coeff=D,var=c2) \
+ ImplicitSourceTerm(coeff=-a*i0/F/por/c2_0,var=c2) 
# z2=0 for ^^
+ ImplicitSourceTerm(a*i0/por/F*(c1/c1_0*numerix.exp(z1*ct*F*(phi_1- \
                                                              phi2 - phi_0)/(R*T))),var=None)

# Equation relating flux to current for electrolyte potential
# Can't simplify to one Diffusion term because 
# of z1 multiplying both flux terms
eq3 = DiffusionTerm(coeff=c1*D,var=phi2) +  D*c1.grad.dot(phi2.grad) \
    # Add diffusion
# + D*z1*c1.faceGrad.divergence <--- don/t use this?
+ DiffusionTerm(coeff=z1*D,var=c1)
# Add Faradaic contributions, 
# can't use ImplicitSourceTerm because it's nonlinear in phi
+ a*i0/F/por*(c1/c1_0*numerix.exp(z1*ct*F*(phi_1-phi2-phi_0)/(R*T)) \
              -c2/c2_0*numerix.exp(-z2*ct*F*(phi_1-phi2-phi_0)/(R*T)))

eq = eq3&eq1&eq2

# mySolver = LinearPCGSolver(iterations=3000,tolerance=1e-10)
from builtins import range
result_c1 = []
result_c2 = []
result_phi2 = []
t_list = []
for i in range(steps):
    t_list.append(float(i*dt))
    result_c1.append(float(c1.max()))
    result_c2.append(float(c2.max()))
    result_phi2.append(float(phi2.max()))
    c1.updateOld()
    c2.updateOld()
    phi2.updateOld()
    for j in range(5):
        res=eq.sweep(dt=dt)
        print(res)
    #eq1.solve(c1,dt=dt)
    #eq2.solve(c2,dt=dt)
    #eq3.solve(var=phi2,solver=mySolver,dt=dt)
    print(i,'step')
    viewer = Matplotlib1DViewer(vars=(c1,c2,phi2))
    viewer.plot()

Python is version 3.8.8 used in Jupyter Notebook. FiPy is version 3.4.2. Thank you again for any input.

JDS19 commented 3 years ago

Correction: The flux term is $ N_i = -D\nabla c_i - DF/(RT)z_ic_i\nabla \phi_2 $ and thus the replaced equations in the code are:

        # Constants in equations
        beta = ct*F/R/T
        mig = D*F/R/T
        bv = a*i0/F/por

        # Equation for first species
        eq1 = TransientTerm(var=c1) == DiffusionTerm(coeff=D,var=c1) \
        # add migration
        + DiffusionTerm(coeff=c1*z1*mig,var=phi2)
        # subtract Faradaic term
        - bv*c1/c1_0*numerix.exp(z1*bv*(phi_1-phi2-phi_0)) \
        - ImplicitSourceTerm(coeff=bv*(-c2/c2_0),var=None) 

        eq2 = TransientTerm(var=c2) == DiffusionTerm(coeff=D,var=c2) \
        + ImplicitSourceTerm(coeff=-bv/c2_0,var=c2) 
        # z2=0 for ^^
        + ImplicitSourceTerm(bv*c1/c1_0*numerix.exp(z1*beta*(phi_1- \
                                                                      phi2 - phi_0)),var=None)

        # Equation relating flux to current for electrolyte potential
        # Can't simplify to one Diffusion term because 
        # of z1 multiplying both flux terms
        eq3 = DiffusionTerm(coeff=c1*mig,var=phi2) +  mig*c1.grad.dot(phi2.grad) \
            # Add diffusion
            # + D*z1*c1.faceGrad.divergence <--- don/t use this?
        + DiffusionTerm(coeff=z1*D*c1,var=None)
            # Add Faradaic contributions, 
            # can't use ImplicitSourceTerm because it's nonlinear in phi
        + bv*(c1/c1_0*numerix.exp(z1*beta*(phi_1-phi2-phi_0)) \
                      -c2/c2_0)

The question stays the same on if I'm including these nonlinear terms in each equation correctly.

guyer commented 3 years ago

This is going to take some debugging to get things working, but here are some things to consider:

JDS19 commented 3 years ago

Thank you for your comments! I've included some of you changes and initiated some of the others. I used the homogeneous Neumann BCs to keep things simple, but really I would like the flux terms for c2 to cancel each other out at x = 0, so $ \nabla \phi_2 = 2(\phi_2 - \phi_1 - \phi_0 ) $ \ and $ \nabla c_1 = z_1F/(RT) c_1 \nabla \phi_2 $ and the c2 derivative is still 0. I've attempted to implement this now.

One thing I'm still unsure of is having things like DiffusionTerm(coeff=k,var=phi2) in the equation for c1 and DiffusionTerm(coeff=k,var=c1) for phi2's equation. Some of the ways I wrote these terms come from post recommendations I've read, so if they're completely incorrect, I apologize.

For the $z_1$ only on the left, are you referring to the relation of the sum of the fluxes to the total current equation (the one without the time derivative)? I believe that equation to be correct because the right hand side is for the total current at some point.

For implementing the Newton-Raphson stepping, I've started adding that in, but I don't quite understand the deltaC1.constrain(0.,where=mesh.facesLeft) part or why the values of the unknown and their incremental changes are set to 0. I also want to make sure my DiffusionTerms in the original equations are written correctly before I differentiate them completely, but I've started some of them.

Hopefully this code is more along the right path:

Material properties

        phi_0 = 0.0 # arbitrarily set to 0
        phi_app = 0.2 # Applied voltage 
        c1_0 = 0.1 # M  
        c2_0 = 0.1 # M
        z1 = -1.0
        z2 = 0.
        phi_1 = phi_0 + phi_app/2 
        L = .25 # cm of electrode thickness 
        por = 0.4 # porosoity 
        D = 5*10**-5 # diffusion coefficient, cm^2/s
        a = 360. #cm^2 per cm^3, specific interfacial area for GFD2.5
        ct,R,F,T = 0.5, 8.3143, 96487., 293.
        ne, s = 1, 1
        i0 = 0.005 # from Exchange Current Densities 

        # New code
        nx = 10000
        dx = L/nx
        mesh = Grid1D(nx=nx,dx=dx)
        x = mesh.cellCenters[0]
        dt = .01
        #dt = 0.5*dx**2/(2*D)
        steps = 100
        t = dt * steps
        time = Variable(0.)

        phi2 = CellVariable(name="phi2",mesh=mesh,hasOld=True)
        c1 =  CellVariable(name="c1",mesh=mesh,hasOld=True)
        c2 =  CellVariable(name="c2",mesh=mesh,hasOld=True)
        phi2.setValue(phi_0)
        c1.setValue(c1_0)
        c2.setValue(c2_0)

        # No flux at x=0, dc2/dx = 0 automatically
        # Flux for c1 has concentration & potential gradient
        # Set up Robin BC;
        # unsure about this set up; folllowed this website:
        # https://www.ctcms.nist.gov/fipy/documentation/
        #USAGE.html#applying-robin-boundary-conditions

        #Make point to apply Robin BC, where x=0
        mask = (x=0.)
        # Create values to put into equation for phi2
        phi_a = FaceVariable(mesh=mesh,rank=1)
        phi_a.setValue(-2.,where=mask)
        phi_b = FaceVariable(mesh=mesh,rank=0)
        phi_b.setValue(1.,where=mask)
        phi_g =  FaceVariable(mesh=mesh,rank=0)
        phi_g.setValue(-2.0*(phi_1+phi_0),where=mask)

        # Repeat for c1 whose concentration gradient 
        # cancels the migration gradient
        c1_a = FaceVariable(mesh=mesh,rank=1)
        c1_a.setValue(-1.,where=mask)
        c1_b = FaceVariable(mesh=mesh,rank=0)
        c1_b.setValue(1.,where=mask)

        c1.faceGrad.constrain(0,mesh.facesRight)
        phi2.faceGrad.constrain(0,mesh.facesRight)

        # No gradients at x = L
        c1.faceGrad.constrain(0,mesh.facesRight)
        c2.faceGrad.constrain(0,mesh.facesRight)
        phi2.faceGrad.constrain(0,mesh.facesRight)

        # Constants in equations
        beta = ct*F/R/T # For exponential
        mig = D*F/R/T # in front of migration term
        bv = a*i0/F/por # in front of Faradaic reaction

        # Equation for first species
        eq1 = (TransientTerm(var=c1) == DiffusionTerm(coeff=D,var=c1) 
            # Migration effect (is this OK??)
            + DiffusionTerm(coeff=c1*z1*mig,var=phi2)
            # subtract Faradaic term
            - bv*c1/c1_0*numerix.exp(z1*beta*(phi_1-phi2-phi_0))
            + bv*c2/c2_0  
              # incorporate Robin BC at x =0
            + PowerLawConvectionTerm(coeff=c1_a)
            + DiffusionTerm(coeff=b) )

        # Equation for second species
        eq2 = (TransientTerm(var=c2) == DiffusionTerm(coeff=D,var=c2)
            + bv*c1/c1_0*numerix.exp(z1*beta*(phi_1-phi2-phi_0)) 
            - bv*c2/c2_0  )

        # Equation relating flux to current for electrolyte potential
        eq3 = (DiffusionTerm(coeff=c1*mig,var=phi2) +  mig*c1.grad.dot(phi2.grad) 
            # Add diffusion
            # + D*z1*c1.faceGrad.divergence <- don't use this?
            # + DiffusionTerm(coeff=z1*D*c1,var=None) <- don't use!
            + DiffusionTerm(coeff=z1*D,var=c1)
            # Add Faradaic contributions, 
            # can't use ImplicitSourceTerm because it's nonlinear in phi
            + bv*(c1/c1_0*numerix.exp(z1*beta*(phi_1-phi2-phi_0)) 
            - c2/c2_0) 
              # Add Robin BCs
            + PowerLawConvectionTerm(coeff=phi_a)
            + DiffusionTerm(coeff=phi_b) + (g*mask*mesh.faceNormals).divergence )

        # Need to do Newton steps
        deltaC1 = CellVariable(mesh=mesh,name="delta C1",hasOld=True)
        deltaC2 = CellVariable(mesh=mesh,name="delta C2",hasOld=True)
        deltaPhi2 = CellVariable(mesh=mesh,name="delta Phi2",hasOld=True)

        # Add new Newton Equations; need to do derivatives and fill in
        newton_eqC1 = (TransientTerm(var=deltaC1)
                    == DiffusionTerm(coeff=D*c1.grad,var=deltaC1) 
                    + DiffusionTerm(coeff=z1*mig*phi2,var=deltaC1)
                    + DiffusionTerm(coeff=z1*mig*c1,var=deltaPhi2)
                    # subtract Faradaic term
                    - bv*deltaC1/c1_0*numerix.exp(z1*beta*(phi_1-phi2-phi_0))
                    + bv*deltaC2/c2_0   
                    - bv*c1/c1_0*numerix.exp(z1*beta*(phi_1-phi2-phi_0))*(-beta*deltaPhi2) 
                    # incorporate Robin BC at x =0
                    + PowerLawConvectionTerm(coeff=c1_a)
                    + DiffusionTerm(coeff=b) 
                    + ResidualTerm(equation=eq1)   )

        newton_eqC2 = (TransientTerm(var=deltaC1)
                    == DiffusionTerm(coeff=D*c2.grad,var=deltaC2) 
                    # subtract Faradaic term
                    + bv*deltaC1/c1_0*numerix.exp(z1*beta*(phi_1-phi2-phi_0))
                    - bv*deltaC2/c2_0   
                    + bv*c1/c1_0*numerix.exp(z1*beta*(phi_1-phi2-phi_0))*(-beta*deltaPhi2)
                    + ResidualTerm(equation=eq3) )

        newton_eqPhi2 = ( DiffusionTerm(coeff=z1*D*c1.grad,var=deltaC1) 
                    + DiffusionTerm(coeff=mig*phi2,var=deltaC1)
                    + DiffusionTerm(coeff=mig*c1,var=deltaPhi2)
                    # add Faradaic term
                    + bv*deltaC1/c1_0*numerix.exp(z1*beta*(phi_1-phi2-phi_0))
                    - bv*deltaC2/c2_0   
                    + bv*c1/c1_0*numerix.exp(z1*beta*(phi_1-phi2-phi_0))*(-beta*deltaPhi2)  
                    # Add Robin BCs
                    + PowerLawConvectionTerm(coeff=phi_a)
                    + DiffusionTerm(coeff=phi_b) + (g*mask*mesh.faceNormals).divergence 
                    + ResidualTerm(equation=eq3)    )

        # deltaC1.constrain(0.,where=mesh.facesLeft) ... don't understand this
        # deltaC2.constrain(...)
        # deltaPhi2.constrain(...)

        # Set values for c1,c2,phi2, and their deltas to 0.?.

        newtonC1 = []
        newtonC2 = []
        newtonPhi2 = []

        c1.updateOld()
        c2.updateOld()
        phi2.updateOld()
        deltaC1.updateOld()
        deltaC2.updateOld()
        deltaPhi2.updateOld()
        for sweep in range(20):
            res_c1 = newton_eqC1.sweep(dt=1)
            res_c2 = newton_eqC2.sweep(dt=1)
            res_phi2 = newton_eqPhi2.sweep(dt=1)
            newtonC1.append([sweep,res_c1,max(abs(deltaC1))])
            newtonC2.append([sweep,res_c2,max(abs(deltaC2))])
            newtonPhi2.append([sweep,res_phi2,max(abs(deltaPhi2))])

Thank you!

guyer commented 3 years ago

I would like the flux terms for c2 to cancel each other out at x = 0

"No-flux" means no flux. If you assign no constraints, then c1 and c2 will not flux out of the domain due to either concentration gradients or electromigration. They will be conserved. You don't need to do anything. This is the natural boundary condition for FiPy. For the conservation equations you give, the flux of $c_i$ is $N_i \pm i/F$, so $(N_i \pm i/F)\cdot \hat{n} = 0$ on all external faces by default.

Setting that aside, given your equations, I don't understand why $ \nabla \phi_2 = 2(\phi_2 - \phi_1 - \phi_0 ) $ is expected to be true at the boundaries.

One thing I'm still unsure of is having things like DiffusionTerm(coeff=k,var=phi2) in the equation for c1 and DiffusionTerm(coeff=k,var=c1) for phi2's equation. Some of the ways I wrote these terms come from post recommendations I've read, so if they're completely incorrect, I apologize.

These cross terms are OK. In fact, if you're going to solve coupled equations, they're desirable.

For the $z_1$ only on the left, are you referring to the relation of the sum of the fluxes to the total current equation (the one without the time derivative)? I believe that equation to be correct because the right hand side is for the total current at some point.

If $i$ is the total current, then I don't understand why it appears in your two conservation equations for c1 and c2. A general conservation law looks like time-rate-of-change-of-STUFF plus divergence-of-flux-of-STUFF equals zero. The current continuity equation results from multiplying each of these equations by the valence and summing, giving time-rate-of-change-of-CHARGE plus divergence-of-CURRENT equals zero, where CHARGE is $\sum z_i C_i$ and CURRENT is $\sum z_i j_i$ where $j_i$ is the flux of species $i$. I do find the electrochemical literature really sloppy about what's a flux and what's a current. In fairness, the semiconductor literature is worse.

I further don't understand your Faradaic expression. $ai0/por(c_1/c_1^0 e^{z_1ctF/(RT)(\phi_1 - \phi_2 - \phi_0)} - c_2/c_2^0 e^{z_2ctF/(RT)(\phi_1 - \phi_2 - \phi_0)})$ looks like a Butler-Volmer expression. This is an expression for the current in terms of the overpotential, not the divergence of the current. I could understand $\nabla\cdot i = \nabla\cdot[ai0/por(c_1/c_1^0 e^{z_1ctF/(RT)(\phi_1 - \phi_2 - \phi_0)} - c_2/c_2^0 e^{z_2ctF/(RT)(\phi_1 - \phi_2 - \phi_0)})]$, but I don't know why you'd apply it everywhere. In my experience, this is an expression for the current passing through an electrode-electrolyte interface, e.g., a boundary condition.

I can help with this, and have some background in solving equations like this, but electrochemical equations are really tricky to solve and I don't want to put a lot of effort into helping solve equations that aren't even right. Can you provide a reference for the equations you're trying to solve?

As an aside, I encourage you take care in writing your expressions. If $N_i$ is a flux, then it is a vector (rank 1) field. $\nabla N_i$ will produce a tensor (rank 2) field. What you want is $\nabla\cdot N_i$, a scalar (rank 0) field.

JDS19 commented 3 years ago

The flux of $c_i$ is given by the respective $N_i$. The two contributions to the flux of a species in this case comes from concentration gradients and potential gradients. Then the current density, $i$, is related to the total flux by the constant, F. I do realize that electrochemical transport notation is not very convenient and STILL not consistent across the field, so I appreciate your patience. Most of my responses to your equations come from the first couple pages from my reference for this simulation, which is: Newman, J., & Tiedemann, W. (1974). POROUS-ELECTRODE THEORY WITH BATTERY APPLICATIONS. Lawrence Berkeley National Laboratory. LBNL Report #: LBL-3117. Retrieved from https://escholarship.org/uc/item/9vd6z2g7

You're correct that the Faradaic reaction only occurs at electrolyte-electrode interfaces. Here, I am modeling a porous electrode where instead of simulating an entire 3D porous structure with interfaces throughout the system, I am averaging using the porosity factor, por. Although, I would like to eventually use FiPy to create specific meshes to model that situation so that the Faradaic reaction would become a surface term instead of an averaged volumetric reaction.

Thank you for your comment on my notation to denote vectors, tensors, and scalars correctly. I will be more careful.

The one thing I am not very confident of in my equations is the Robin BC for the potential. My theory for it is that the deviation from the equilibrium + applied potential is what would cause a potential gradient. I have also heard of other simulations using this BC in similar models.

Please let me know if this response does not adequately address your concerns. Thanks again.

guyer commented 3 years ago

Thank you, that article is helpful. I didn't understand that the current density $i$ is in a space effectively orthogonal to the space that $N$ fluxes through ("the superposition of two continua").

Let me see what I can do with this.

guyer commented 3 years ago

I've posted a notebook where I get these equations to solve. For the moment, I discarded your attempts at Robin conditions and went back to the original Dirichlet declarations. We can get into the boundary conditions later, but right now I don't think they're the biggest concern.

While the equations solve, the potential remains at zero. I believe this is because $ \sum{z_i \nabla\cdot N_i} = \nabla\cdot i/F $ is not valid for your system, because the derivation of this expression assumes charge neutrality everywhere. It arises from the charge-weighted sum of the two material balance equations and the assertion that $z_1 c_1 + z_2 c_2 = 0$ (or at least that they're constant). That assertion is not true in your case because you set $z_2 = 0$. As a result, I think your continuity equation has to be $ \frac{\partial z_1 c_1}{\partial t} + \nabla\cdot z_1 N_1 = - z_1 \nabla\cdot i/F $ or $ \frac{\partial c_1}{\partial t} + \nabla\cdot N_1 = - \nabla\cdot i/F $

Even you disagree with the origin of these equations, you can see the same thing if you sum your first and third equations. Algebraically, you'll get $ \frac{\partial c_1}{\partial t} + z_1 \nabla\cdot N_1 = -\nabla\cdot N_1 - \nabla\cdot i/F + \nabla\cdot i/F $ or $ \frac{\partial c_1}{\partial t} = 0 $ which we know isn't true.

guyer commented 3 years ago

Stated another way, you don't have a governing equation for $\phi_2$

JDS19 commented 3 years ago

Stated another way, you don't have a governing equation for $\phi_2$

I see; I will have to look into a correct governing equation. Thank you so much for making that notebook. After I get some time to look for a valid equation for the potential, I will write back.

guyer commented 3 years ago

If you like, email me offline. I've spent a lot of time thinking about electrochemical and hole-electron drift-diffusion problems, so I might be able to help you come up with a formulation that captures what you're interested in.