Beispiel #1
0
def test_full_enchilada(n):
    a = -4
    b = 5

    def u_true(x):
        return np.sin(5 * x**2)

    def p(x):
        return np.cos(x)

    def q(x):
        return 1 / (x + 7)

    def r(x):
        return (np.sin(5 * x**2) / (x + 7) - 100 * x**2 * np.sin(5 * x**2) +
                10 * x * np.cos(x) * np.cos(5 * x**2) + 10 * np.cos(5 * x**2))

    mesh = np.linspace(a, b, n)
    u = solve_bvp(mesh, p, q, r, ua=u_true(a), ub=u_true(b))

    u_true_val = u_true(mesh)
    err = u - u_true_val

    L2_err = np.sqrt(np.trapz(err**2, mesh))

    return mesh[1] - mesh[0], L2_err
Beispiel #2
0
def test_full_enchilada(n):
    a = -4
    b = 5

    def u_true(x):
        return np.sin(5*x**2)

    def p(x):
        return np.cos(x)

    def q(x):
        return 1/(x+7)

    def r(x):
        return (np.sin(5*x**2)/(x+7)
                - 100*x**2*np.sin(5*x**2)
                + 10*x*np.cos(x)*np.cos(5*x**2)+10*np.cos(5*x**2))

    mesh = np.linspace(a, b, n)
    u = solve_bvp(mesh, p, q, r, ua=u_true(a), ub=u_true(b))

    u_true_val = u_true(mesh)
    err = u-u_true_val

    L2_err = np.sqrt(np.trapz(err**2, mesh))

    return mesh[1] - mesh[0], L2_err
Beispiel #3
0
def test_poisson(n):
    a = -4
    b = 5

    def u_true(x):
        return np.sin(5 * x) * np.exp(x)

    def r(x):
        return 10 * np.exp(x) * np.cos(5 * x) - 24 * np.exp(x) * np.sin(5 * x)

    def p(x):
        return 0

    def q(x):
        return 0

    mesh = np.linspace(a, b, n)
    u = solve_bvp(mesh, p, q, r, ua=u_true(a), ub=u_true(b))

    u_true_val = u_true(mesh)
    err = u - u_true_val

    L2_err = np.sqrt(np.trapz(err**2, mesh))

    return mesh[1] - mesh[0], L2_err
def test_with_p(n):
    a = -4
    b = 5

    def u_true(x):
        return np.sin(5*x**2)

    def p(x):
        return np.cos(x)

    def q(x):
        return 0

    def r(x):
        return (
                - 100*x**2*np.sin(5*x**2)
                + 10*x*np.cos(x)*np.cos(5*x**2)+10*np.cos(5*x**2)
                )

    mesh = np.linspace(a, b, n)
    u,nit = solve_bvp(mesh, p, q, r, ua=u_true(a), ub=u_true(b),iter_count=True)

    

    return nit
Beispiel #5
0
def test_poisson(n):
    a = -4
    b = 5

    def u_true(x):
        return np.sin(5*x)*np.exp(x)

    def r(x):
        return 10*np.exp(x)*np.cos(5*x)-24*np.exp(x)*np.sin(5*x)

    def p(x):
        return 0

    def q(x):
        return 0

    mesh = np.linspace(a, b, n)
    u = solve_bvp(mesh, p, q, r, ua=u_true(a), ub=u_true(b))

    u_true_val = u_true(mesh)
    err = u-u_true_val

    L2_err = np.sqrt(np.trapz(err**2, mesh))

    return mesh[1] - mesh[0], L2_err
Beispiel #6
0
def calculate_psi_PB(epsilon_0, epsilon, C_aq, Z_aq_vec, psi_pb_0, distance,
                     temp):
    kb = 1.38064852e-23  # J/K other units --> kb=8,6173303e-5  eV/K
    Na = 6.022140857e23  # 1/mol
    elec_charge = 1.60217662e-19  #electron charge in C
    ni = Na * 1000 * C_aq
    e_kbt = elec_charge / (kb * temp)
    me_ee0 = -elec_charge / (epsilon_0 * epsilon)
    args = [me_ee0, Z_aq_vec, ni, e_kbt, psi_pb_0]
    psi_PB = solve_bvp(fun_PB, bc_PB, distance, psi_pb_0, tol=1e-4, args=args)
    return psi_PB
def test_poisson(n):
    a = -4
    b = 5

    def u_true(x):
        return np.sin(5*x)*np.exp(x)

    def r(x):
        return 10*np.exp(x)*np.cos(5*x)-24*np.exp(x)*np.sin(5*x)

    def p(x):
        return 0

    def q(x):
        return 0

    mesh = np.linspace(a, b, n)
    u, nit = solve_bvp(mesh, p, q, r, ua=u_true(a), ub=u_true(b),iter_count=True)


    return nit
def test_full_enchilada(n):
    a = -4
    b = 5

    def u_true(x):
        return np.sin(5*x**2)

    def p(x):
        return np.cos(x)

    def q(x):
        return 1/(x+7)

    def r(x):
        return (np.sin(5*x**2)/(x+7)
                - 100*x**2*np.sin(5*x**2)
                + 10*x*np.cos(x)*np.cos(5*x**2)+10*np.cos(5*x**2))

    mesh = np.linspace(a, b, n)
    u, nit = solve_bvp(mesh, p, q, r, ua=u_true(a), ub=u_true(b),iter_count=True)


    return nit
Beispiel #9
0
Q = Z * elec_charge  # Q is the charve of the aqueous elements times the electron charge
A = Na * 1000 / ew  # a prefactor = Avogadro * 1000 /ew
kbt = 1.38064852e-23 * temp  # kb (J/K) * T in K

y0 = np.zeros((2, x.size))
y0[0, 0] = X[8]
y0[0, -1] = X[12]
y0[1, 0] = -sigma_S1_dTLM / ew
y0[1, -1] = sigma_S2_dTLM / ew
args = [Q, C_aq, A, kbt, y0]
y02 = np.zeros((2, x.size))
y02[0, 0] = X[8]
y02[0, -1] = X[12]
args2 = [Q, C_aq, A, kbt, y02]
tol_PB = 1e-3
result = solve_bvp(fun_PB, bc_PB, x, y0, args=args, tol=tol_PB, verbose=2)
result2 = solve_bvp(fun_PB, bc_PB, x, y02, args=args2, tol=tol_PB, verbose=2)
plt.figure()
plt.plot(result.x, result.y[0])

y03 = np.zeros((2, x.size))
y03[0, 0:50] = psi_y[0:50]
ff = psi_y[::-1]
y03[0, 50:] = ff[50:]
args3 = [Q, C_aq, A, kbt, y03]
result3 = solve_bvp(fun_PB, bc_PB, x, y03, args=args3, tol=tol_PB, verbose=2)
plt.figure()
plt.plot(result3.x, result3.y[0])

x = np.linspace(0, 800e-9, 62)
y04 = np.zeros((2, 62))
Beispiel #10
0
def Jacobian_NR_FLM(X,
                    A,
                    log_k,
                    temp,
                    idx_Aq,
                    sS1,
                    aS1,
                    sS2,
                    aS2,
                    e,
                    CapacitancesS1,
                    CapacitancesS2,
                    T,
                    Zi,
                    zel,
                    pos_psi_S1_vec,
                    pos_psi_S2_vec,
                    x,
                    idx_fix_species=None):
    '''
        This function should give the Jacobian. Here The jacobian is calculated as Westall (1980), except the electrostatic terms that are slightly different.
        The reason is because there seems to be some typos in Westall paper.
        Also, if idx_fix_species is given then the rows of the unknown will be 1 for the unknown and 0 for the other points.
    '''
    #  constant
    F = 96485.3328959  # C/mol [Faraday constant]
    R = 8.314472  # J/(K*mol) [universal constant gas]
    eo = 8.854187871e-12  # Farrads = F/m   - permittivity in vaccuum
    elec_charge = 1.60217662e-19  #electron charge in C
    # Speciation - mass action law
    #log_C = log_k + A*np.log10(X)
    Xmod = X.copy()
    for i in range(len(X)):
        if X[i] <= 0:
            Xmod[i] = 1
    log_C = log_k + np.matmul(A, np.log10(Xmod))
    # transf
    C = 10**(log_C)
    C_aq = C[idx_Aq]
    #I = Calculate_ionic_strength(Z, C_aq)
    # instantiate Jacobian
    length_X = X.size
    Z = np.zeros((length_X, length_X))
    # First part is the common of the Jacbian derivation
    for i in range(0, length_X):
        for j in range(0, length_X):
            Z[i, j] = np.matmul(np.multiply(A[:, i], A[:, j]), (C / X[j]))
    # Now the electrostatic part must be modified, one question hang on the air:
    # Should we check that the electrostatic part is as we expected?
    ############S1#######################
    sa_F2S1 = (sS1 * aS1) / (F * F)
    C1_sa_F2_RTS1 = sa_F2S1 * CapacitancesS1[0] * R * temp
    # Assigning in Jacobian (plane 0)
    Z[pos_psi_S1_vec[0], pos_psi_S1_vec[0]] = Z[
        pos_psi_S1_vec[0],
        pos_psi_S1_vec[0]] + C1_sa_F2_RTS1 / X[pos_psi_S1_vec[0]]
    Z[pos_psi_S1_vec[0], pos_psi_S1_vec[1]] = Z[
        pos_psi_S1_vec[0],
        pos_psi_S1_vec[1]] - C1_sa_F2_RTS1 / X[pos_psi_S1_vec[1]]
    #### plane alpha
    C1C2_sa_F2_RTS1 = sa_F2S1 * R * temp * (CapacitancesS1[0] +
                                            CapacitancesS1[1])
    C2_sa_F2_RTS1 = sa_F2S1 * CapacitancesS1[1] * R * temp
    # Assigning in Jacobian (plane alpha)
    Z[pos_psi_S1_vec[1], pos_psi_S1_vec[0]] = Z[
        pos_psi_S1_vec[1],
        pos_psi_S1_vec[0]] - C1_sa_F2_RTS1 / X[pos_psi_S1_vec[0]]
    Z[pos_psi_S1_vec[1], pos_psi_S1_vec[1]] = Z[
        pos_psi_S1_vec[1],
        pos_psi_S1_vec[1]] + C1C2_sa_F2_RTS1 / X[pos_psi_S1_vec[1]]
    Z[pos_psi_S1_vec[1], pos_psi_S1_vec[2]] = Z[
        pos_psi_S1_vec[1],
        pos_psi_S1_vec[2]] - C2_sa_F2_RTS1 / X[pos_psi_S1_vec[2]]
    #### plane beta
    C3C2_sa_F2_RTS1 = sa_F2S1 * R * temp * (CapacitancesS1[1] +
                                            CapacitancesS1[2])
    C3_sa_F2_RTS1 = sa_F2S1 * CapacitancesS1[2] * R * temp
    # Assigning in Jacobian (plane beta)
    Z[pos_psi_S1_vec[2], pos_psi_S1_vec[1]] = Z[
        pos_psi_S1_vec[2],
        pos_psi_S1_vec[1]] - C2_sa_F2_RTS1 / X[pos_psi_S1_vec[1]]
    Z[pos_psi_S1_vec[2], pos_psi_S1_vec[2]] = Z[
        pos_psi_S1_vec[2],
        pos_psi_S1_vec[2]] + C3C2_sa_F2_RTS1 / X[pos_psi_S1_vec[2]]
    Z[pos_psi_S1_vec[2],
      pos_psi_S1_vec[3]] = Z[pos_psi_S1_vec[2],
                             pos_psi_S1_vec[3]] - CapacitancesS1[2] * (
                                 (sS1 * aS1) / F)
    #Z[pos_psi_S1_vec[2], pos_psi_S1_vec[3]] = Z[pos_psi_S1_vec[2],pos_psi_S1_vec[3]] - C3_sa_F2_RTS1/X[pos_psi_S1_vec[3]]
    #### plane gamma [diffusive plane]
    #Z[pos_psi_S1_vec[3],pos_psi_S1_vec[2]] = Z[pos_psi_S1_vec[3],pos_psi_S1_vec[2]] - C3_sa_F2_RTS1/X[pos_psi_S1_vec[2]]
    # d_d plane
    #psi_d = Boltzman_factor_2_psi(X[pos_psi_S1_vec[3]], temp)
    #DY_Dpsid = -np.sqrt(8*1000*R*temp*e*eo*I)*np.cosh((zel*F*psi_d)/(2*R*temp))*((zel*F)/(2*R*temp)) - CapacitancesS1[2]
    #Dpsid_DpsidB = (-R*temp)/(F*X[pos_psi_S1_vec[3]])
    #Z[pos_psi_S1_vec[3], pos_psi_S1_vec[3]] = Z[pos_psi_S1_vec[3], pos_psi_S1_vec[3]] + (DY_Dpsid*Dpsid_DpsidB*((sS1*aS1)/F))

    #(Problably S1 and S2 can be enclosed in a for loop, reducing lines of code. If I have time and will, I will look at it.)
    ############S1#######################
    sa_F2S2 = (sS2 * aS2) / (F * F)
    C1_sa_F2_RTS2 = sa_F2S2 * CapacitancesS2[0] * R * temp
    # Assigning in Jacobian (plane 0)
    Z[pos_psi_S2_vec[0], pos_psi_S2_vec[0]] = Z[
        pos_psi_S2_vec[0],
        pos_psi_S2_vec[0]] + C1_sa_F2_RTS2 / X[pos_psi_S2_vec[0]]
    Z[pos_psi_S2_vec[0], pos_psi_S2_vec[1]] = Z[
        pos_psi_S2_vec[0],
        pos_psi_S2_vec[1]] - C1_sa_F2_RTS2 / X[pos_psi_S2_vec[1]]
    #### plane alpha
    C1C2_sa_F2_RTS2 = sa_F2S2 * R * temp * (CapacitancesS2[0] +
                                            CapacitancesS2[1])
    C2_sa_F2_RTS2 = sa_F2S2 * CapacitancesS2[1] * R * temp
    # Assigning in Jacobian (plane alpha)
    Z[pos_psi_S2_vec[1], pos_psi_S2_vec[0]] = Z[
        pos_psi_S2_vec[1],
        pos_psi_S2_vec[0]] - C1_sa_F2_RTS2 / X[pos_psi_S2_vec[0]]
    Z[pos_psi_S2_vec[1], pos_psi_S2_vec[1]] = Z[
        pos_psi_S2_vec[1],
        pos_psi_S2_vec[1]] + C1C2_sa_F2_RTS2 / X[pos_psi_S2_vec[1]]
    Z[pos_psi_S2_vec[1], pos_psi_S2_vec[2]] = Z[
        pos_psi_S2_vec[1],
        pos_psi_S2_vec[2]] - C2_sa_F2_RTS2 / X[pos_psi_S2_vec[2]]
    #### plane beta
    C3C2_sa_F2_RTS2 = sa_F2S2 * R * temp * (CapacitancesS2[1] +
                                            CapacitancesS2[2])
    C3_sa_F2_RTS2 = sa_F2S2 * CapacitancesS2[2] * R * temp
    # Assigning in Jacobian (plane beta)
    Z[pos_psi_S2_vec[2], pos_psi_S2_vec[1]] = Z[
        pos_psi_S2_vec[2],
        pos_psi_S2_vec[1]] - C2_sa_F2_RTS2 / X[pos_psi_S2_vec[1]]
    Z[pos_psi_S2_vec[2], pos_psi_S2_vec[2]] = Z[
        pos_psi_S2_vec[2],
        pos_psi_S2_vec[2]] + C3C2_sa_F2_RTS2 / X[pos_psi_S2_vec[2]]
    Z[pos_psi_S2_vec[2],
      pos_psi_S2_vec[3]] = Z[pos_psi_S2_vec[2],
                             pos_psi_S2_vec[3]] - CapacitancesS2[2] * (
                                 (sS2 * aS2) / F)
    #Z[pos_psi_S2_vec[2], pos_psi_S2_vec[3]] = Z[pos_psi_S2_vec[2],pos_psi_S2_vec[3]] - C3_sa_F2_RTS2/X[pos_psi_S2_vec[3]]
    #### plane gamma [diffusive plane]
    #Z[pos_psi_S2_vec[3],pos_psi_S2_vec[2]] = Z[pos_psi_S2_vec[3],pos_psi_S2_vec[2]] - C3_sa_F2_RTS2/X[pos_psi_S2_vec[2]]
    # d_d plane
    #psi_dS2 = Boltzman_factor_2_psi(X[pos_psi_S2_vec[3]], temp)
    #DY_Dpsid = -np.sqrt(8*1000*R*temp*e*eo*I)*np.cosh((zel*F*psi_dS2)/(2*R*temp))*((zel*F)/(2*R*temp)) - CapacitancesS2[2]
    #Dpsid_DpsidB = (-R*temp)/(F*X[pos_psi_S2_vec[3]])
    #Z[pos_psi_S2_vec[3], pos_psi_S2_vec[3]] = Z[pos_psi_S2_vec[3], pos_psi_S2_vec[3]] + (DY_Dpsid*Dpsid_DpsidB*((sS2*aS2)/F))

    #### plane gamma [diffusive plane]
    dpsiA_dXpsiA = (-R * temp) / (F * X[pos_psi_S2_vec[2]])
    Z[pos_psi_S1_vec[3], pos_psi_S1_vec[2]] = Z[
        pos_psi_S1_vec[3],
        pos_psi_S1_vec[2]] - CapacitancesS1[2] * dpsiA_dXpsiA
    Z[pos_psi_S2_vec[3], pos_psi_S2_vec[2]] = Z[
        pos_psi_S2_vec[3],
        pos_psi_S2_vec[2]] - CapacitancesS2[2] * dpsiA_dXpsiA
    #
    ew = eo * e
    Q = Zi * elec_charge  # Q is the charve of the aqueous elements times the electron charge
    Cb = C_aq
    A = 6.02214e23 * 1000 / ew  # a prefactor = Avogadro * 1000 /ew
    kbt = 1.38064852e-23 * temp  # kb (J/K) * T in K
    delta_psi = 0.001

    y0 = np.zeros((2, x.size))
    y0[0, 0] = X[pos_psi_S1_vec[3]]
    'I think that  y0[1,0] and y0[1,-1] are not necessary to solve the problem, I would say that its values do not have implications. Although I am not 100% sure.'
    y0[1, 0] = (
        CapacitancesS1[2] * (X[pos_psi_S1_vec[3]] -
                             Boltzman_factor_2_psi(X[pos_psi_S1_vec[2]], temp))
    ) / ew  # The negative value that I am given here is extremely arbitrary I am not sure why. IT MUST BE DISCUSSED
    # y0[1,0] = dpsi_d                dpsi_d = -(sig_0 + sig_b + sig_d)/ew   # electric field at diffuse layer, x>d
    y0[0, -1] = X[pos_psi_S2_vec[3]]
    y0[1, -1] = -(CapacitancesS2[2] *
                  (X[pos_psi_S2_vec[3]] -
                   Boltzman_factor_2_psi(X[pos_psi_S2_vec[2]], temp))) / ew

    y1 = np.zeros((2, x.size))
    y1[0, 0] = X[pos_psi_S1_vec[3]] + delta_psi
    y1[1, 0] = (CapacitancesS1[2] *
                ((X[pos_psi_S1_vec[3]] + delta_psi) -
                 Boltzman_factor_2_psi(X[pos_psi_S1_vec[2]], temp))) / ew
    y1[0, -1] = X[pos_psi_S2_vec[3]]
    y1[1, -1] = -(CapacitancesS2[2] *
                  (X[pos_psi_S2_vec[3]] -
                   Boltzman_factor_2_psi(X[pos_psi_S2_vec[2]], temp))) / ew

    y2 = np.zeros((2, x.size))
    y2[0, 0] = X[pos_psi_S1_vec[3]]
    y2[1, 0] = (CapacitancesS1[2] *
                ((X[pos_psi_S1_vec[3]]) -
                 Boltzman_factor_2_psi(X[pos_psi_S1_vec[2]], temp))) / ew
    y2[0, -1] = X[pos_psi_S2_vec[3]] + delta_psi
    y2[1, -1] = -(CapacitancesS2[2] *
                  ((X[pos_psi_S2_vec[3]] + delta_psi) -
                   Boltzman_factor_2_psi(X[pos_psi_S2_vec[2]], temp))) / ew

    args0 = [Q, Cb, A, kbt, y0]
    args1 = [Q, Cb, A, kbt, y1]
    args2 = [Q, Cb, A, kbt, y2]

    #PB solving
    result0 = solve_bvp(fun_PB, bc_PB, x, y0, tol=1e-4, args=args0)
    result1 = solve_bvp(fun_PB, bc_PB, x, y1, tol=1e-4, args=args1)
    result2 = solve_bvp(fun_PB, bc_PB, x, y2, tol=1e-4, args=args2)

    d_sigma_d_psi_S1 = -(ew / delta_psi) * (result1.y[1, 0] - result0.y[1, 0])
    d_sigma_d_psi_S2 = (ew / delta_psi) * (result2.y[1, -1] - result0.y[1, -1])

    Z[pos_psi_S1_vec[3],
      pos_psi_S1_vec[3]] = CapacitancesS1[2] + d_sigma_d_psi_S1
    Z[pos_psi_S2_vec[3],
      pos_psi_S2_vec[3]] = CapacitancesS2[2] + d_sigma_d_psi_S2

    # finally just return Z
    if idx_fix_species != None:
        for d in idx_fix_species:
            v = np.zeros(length_X)
            v[d] = 1
            Z[d, :] = v
    return Z
Beispiel #11
0
def Update_T_FLM(T, sS1, sS2, e, temp, aS1, aS2, Z, CapacitancesS1,
                 CapacitancesS2, psi_S1_v, psi_S2_v, zel, pos_psi_S1_vec,
                 pos_psi_S2_vec, C_aq, x):

    #  constant
    F = 96485.3328959  # C/mol
    R = 8.314472  # J/(K*mol)
    eo = 8.854187871e-12  # Farrads = F/m   - permittivity in vaccuum
    #e  = 1.602176620898e-19                             # C
    kb = 1.38064852e-23  # J/K other units --> kb=8,6173303e-5  eV/K
    Na = 6.022140857e23  # 1/mol
    elec_charge = 1.60217662e-19  #electron charge in C
    ########## S1  #####################
    sigma_S1_0 = CapacitancesS1[0] * (psi_S1_v[0] - psi_S1_v[1])
    sigma_S1_alpha = -sigma_S1_0 + CapacitancesS1[1] * (psi_S1_v[1] -
                                                        psi_S1_v[2])
    sigma_S1_beta = -sigma_S1_0 - sigma_S1_alpha + CapacitancesS1[2] * (
        psi_S1_v[2] - psi_S1_v[3])
    sigma_S1_gamma = -sigma_S1_0 - sigma_S1_alpha - sigma_S1_beta
    ########## S2  #####################
    sigma_S2_0 = CapacitancesS2[0] * (psi_S2_v[0] - psi_S2_v[1])
    sigma_S2_alpha = -sigma_S2_0 + CapacitancesS2[1] * (psi_S2_v[1] -
                                                        psi_S2_v[2])
    sigma_S2_beta = -sigma_S2_0 - sigma_S2_alpha + CapacitancesS2[2] * (
        psi_S2_v[2] - psi_S2_v[3])
    sigma_S2_gamma = -sigma_S2_0 - sigma_S2_alpha - sigma_S2_beta
    ########## T  S1  #####################
    T_S1_0 = ((sS1 * aS1) / F) * sigma_S1_0
    # units mol/L or mol/kg
    T_S1_alpha = ((sS1 * aS1) / F) * sigma_S1_alpha
    # units mol/L or mol/kg
    T_S1_beta = ((sS1 * aS1) / F) * sigma_S1_beta
    # units mol/L or mol/kg
    ########## T  S2  #####################
    T_S2_0 = ((sS2 * aS2) / F) * sigma_S2_0
    # units mol/L or mol/kg
    T_S2_alpha = ((sS2 * aS2) / F) * sigma_S2_alpha
    # units mol/L or mol/kg
    T_S2_beta = ((sS2 * aS2) / F) * sigma_S2_beta
    # units mol/L or mol/kg

    ################## PB part starts heres ########################################################################
    ew = eo * e
    Q = Z * elec_charge  # Q is the charve of the aqueous elements times the electron charge
    C = C_aq
    A = Na * 1000 / ew  # a prefactor = Avogadro * 1000 /ew
    kbt = 1.38064852e-23 * temp  # kb (J/K) * T in K
    y0 = np.zeros((2, x.size))
    y0[0, 0] = psi_S1_v[3]
    'I think that  y0[1,0] and y0[1,-1] are not necessary to solve the problem, I would say that its values do not have implications. Although I am not 100% sure.'
    y0[1,
       0] = -sigma_S1_gamma / ew  # The negative value that I am given here is extremely arbitrary I am not sure why. IT MUST BE DISCUSSED
    # y0[1,0] = dpsi_d                dpsi_d = -(sig_0 + sig_b + sig_d)/ew   # electric field at diffuse layer, x>d
    y0[0, -1] = psi_S2_v[3]
    y0[1, -1] = sigma_S2_gamma / ew
    args = [Q, C, A, kbt, y0]
    result = solve_bvp(fun_PB, bc_PB, x, y0, tol=1e-4, args=args)
    #
    #plt.figure(1)
    #plt.plot(result.x, result.y[0])
    #plt.figure(2)
    #plt.plot(result.x, result.y[1])
    #assert 1==-1
    sigma_S1_d = -result.y[1][0] * ew
    sigma_S2_d = result.y[1][-1] * ew
    #
    T_S1_gammad = sigma_S1_gamma + sigma_S1_d
    T_S2_gammad = sigma_S2_gamma + sigma_S2_d
    # Now the values must be put in T
    T[pos_psi_S1_vec[0]] = T_S1_0
    T[pos_psi_S1_vec[1]] = T_S1_alpha
    T[pos_psi_S1_vec[2]] = T_S1_beta
    T[pos_psi_S1_vec[3]] = T_S1_gammad

    T[pos_psi_S2_vec[0]] = T_S2_0
    T[pos_psi_S2_vec[1]] = T_S2_alpha
    T[pos_psi_S2_vec[2]] = T_S2_beta
    T[pos_psi_S2_vec[3]] = T_S2_gammad

    return T
Beispiel #12
0
    def solve_PB(self, FULL_OUTPUT=False):
        #function to solve the boundary value problem using Poisson Boltzmann for arbitrary electrolyte
        #some constants
        ew = 78.5 * 8.854187e-12  # permittivity of water (F/m)
        kbt = 1.38064852e-23 * 298.15  # kb (J/K) * T in K
        e = 1.60217662e-19  # electron charge in C
        A = 6.02214e23 * 1000 / ew  # a prefactor = Avogadro * 1000 /ew

        Q = self.Zspec * e
        C = 10**(self.C - self.G2)
        psi_d = self.psi[1]
        dbl = self.dist * 1e-9  # dbl = considered x-range

        tol_PB = 1e-6
        x = num.linspace(0, dbl,
                         100)  # x-axis, discretizatioan of dbl, n steps

        #numerical solution of PB using scipy solve_bvp
        y0 = num.zeros((2, x.size), dtype=float)
        y0[0, 0] = psi_d
        y0[1, 0] = 0
        y0[0, -1] = psi_d
        y0[1, -1] = 0

        args = [Q, C, A, kbt, y0]

        def fun(x, y, args):
            Q = args[0]
            C = args[1]
            A = args[2]
            kbt = args[3]
            arg1 = num.zeros((x.size))
            for i in range(len(Q)):
                arg1 += Q[i] * C[i] * num.exp(-Q[i] * y[0] / kbt)
            arg1 = -A * arg1
            return num.vstack((y[1], arg1))

        def bc(ya, yb, args):
            y0 = args[4]
            return num.array([ya[0] - y0[0, 0], yb[0] - y0[0, -1]])

        result = solve_bvp(fun,
                           bc,
                           x,
                           y0,
                           tol=tol_PB,
                           max_nodes=1000,
                           args=args)
        self.dpsi_d = result.sol(0)[1]
        if FULL_OUTPUT == False:
            return
        elif FULL_OUTPUT == True:
            x_plot = num.linspace(0, dbl, 1001)
            psi = result.sol(x_plot)[0]
            feld = result.sol(x_plot)[1]
            sig = num.zeros((x_plot.size), dtype=float)
            for i in range(len(Q)):
                sig = sig + A * ew * Q[i] * C[i] * num.exp(-Q[i] * psi / kbt)
            sig_diff_bvp = num.trapz(sig, dx=x_plot[1])

            #calculation of osmotic pressure and ion_charge_balance throughout the pore
            ion_balance = num.zeros(len(psi), dtype=float)
            osmo = num.zeros(len(psi), dtype=float)
            for i in range(len(C)):
                osmo = osmo + C[i] * (num.exp(-Q[i] * psi / kbt) - 1
                                      )  #for two parallel plates
                ion_balance = ion_balance + Q[i] / e * C[i] * num.exp(
                    -Q[i] * psi / kbt)
            osmo = 6.02214e23 * 1000 * kbt * osmo - ew / 2 * feld**2
            osmo = osmo[int(
                len(osmo) / 2
            )]  #osmotic pressure is independent of distance to wall, therefore represented by one selected value close to the middle
            return psi, feld, ion_balance, sig_diff_bvp, osmo
Beispiel #13
0
def Update_T_FLM(T, sS1, sS2, e, temp, aS1, aS2, Z, CapacitancesS1,
                 CapacitancesS2, psi_S1_v, psi_S2_v, zel, pos_psi_S1_vec,
                 pos_psi_S2_vec, C_aq, d0, df, bvp_solver, tol_PB):

    #  constant
    F = 96485.3328959  # C/mol
    R = 8.314472  # J/(K*mol)
    eo = 8.854187871e-12  # Farrads = F/m   - permittivity in vaccuum
    #e  = 1.602176620898e-19                             # C
    kb = 1.38064852e-23  # J/K other units --> kb=8,6173303e-5  eV/K
    Na = 6.022140857e23  # 1/mol
    elec_charge = 1.60217662e-19  #electron charge in C
    ########## S1  #####################
    sigma_S1_0 = CapacitancesS1[0] * (psi_S1_v[0] - psi_S1_v[1])
    sigma_S1_alpha = -sigma_S1_0 + CapacitancesS1[1] * (psi_S1_v[1] -
                                                        psi_S1_v[2])
    sigma_S1_beta = -sigma_S1_0 - sigma_S1_alpha + CapacitancesS1[2] * (
        psi_S1_v[2] - psi_S1_v[3])
    sigma_S1_gamma = -sigma_S1_0 - sigma_S1_alpha - sigma_S1_beta
    ########## S2  #####################
    sigma_S2_0 = CapacitancesS2[0] * (psi_S2_v[0] - psi_S2_v[1])
    sigma_S2_alpha = -sigma_S2_0 + CapacitancesS2[1] * (psi_S2_v[1] -
                                                        psi_S2_v[2])
    sigma_S2_beta = -sigma_S2_0 - sigma_S2_alpha + CapacitancesS2[2] * (
        psi_S2_v[2] - psi_S2_v[3])
    sigma_S2_gamma = -sigma_S2_0 - sigma_S2_alpha - sigma_S2_beta
    ########## T  S1  #####################
    T_S1_0 = ((sS1 * aS1) / F) * sigma_S1_0
    # units mol/L or mol/kg
    T_S1_alpha = ((sS1 * aS1) / F) * sigma_S1_alpha
    # units mol/L or mol/kg
    T_S1_beta = ((sS1 * aS1) / F) * sigma_S1_beta
    # units mol/L or mol/kg
    ########## T  S2  #####################
    T_S2_0 = ((sS2 * aS2) / F) * sigma_S2_0
    # units mol/L or mol/kg
    T_S2_alpha = ((sS2 * aS2) / F) * sigma_S2_alpha
    # units mol/L or mol/kg
    T_S2_beta = ((sS2 * aS2) / F) * sigma_S2_beta
    # units mol/L or mol/kg

    ################## PB part starts heres ########################################################################
    ew = eo * e
    Q = Z * elec_charge  # Q is the charve of the aqueous elements times the electron charge
    C = C_aq
    A = Na * 1000 / ew  # a prefactor = Avogadro * 1000 /ew
    #A = Na/ew
    kbt = 1.38064852e-23 * temp  # kb (J/K) * T in K
    #y0 = np.zeros((2, x.size))
    if type(bvp_solver) == list:
        y_0 = bvp_solver[0].copy()
        x = np.linspace(d0, df, y_0.shape[1])
        #deltaing this
        #y1= bvp_solver[0].copy()
        #y2= bvp_solver[0].copy()
        #y3= bvp_solver[0].copy()
    else:
        y_0 = bvp_solver.y
        x = bvp_solver.x
    'I think that  y0[1,0] and y0[1,-1] are not necessary to solve the problem, I would say that its values do not have implications. Although I am not 100% sure.'
    y_0[1,
        0] = sigma_S1_gamma / ew  # The negative value that I am given here is extremely arbitrary I am not sure why. IT MUST BE DISCUSSED
    #    dpsi_d = -(sig_0 + sig_b + sig_d)/ew   # electric field at diffuse layer, x>d
    y_0[1, -1] = -sigma_S2_gamma / ew
    y_0[0, 0] = psi_S1_v[3]
    y_0[0, -1] = psi_S2_v[3]
    #y0[1,-1]= sigma_S2_gamma/ew
    args = [Q, C, A, kbt, y_0]

    result = solve_bvp(fun_PB, bc_PB, x, y_0, args=args, tol=tol_PB)
    # Looking further
    #y1[0,0] = psi_S1_v[0]
    #y1[0,-1] = psi_S2_v[0]
    #y1[1,0] = sigma_S1_0/ew
    #y1[1,-1] = -sigma_S2_0/ew
    #args=[Q,C,A,kbt,y1]

    #result1 = solve_bvp(fun_PB, bc_PB, x, y1,  args = args, tol=tol_PB)
    #y2[0,0] = psi_S1_v[1]
    #y2[0,-1] = psi_S2_v[1]
    #y2[1,0] = sigma_S1_alpha/ew
    #y2[1,-1] = -sigma_S2_alpha/ew
    #args=[Q,C,A,kbt,y2]

    #result2 = solve_bvp(fun_PB, bc_PB, x, y2,  args = args, tol=tol_PB)
    #y3[0,0] = psi_S1_v[2]
    #y3[0,-1] = psi_S2_v[2]
    #y3[1,0] = sigma_S1_beta/ew
    #y3[1,-1] = -sigma_S2_beta/ew
    #args=[Q,C,A,kbt,y3]

    #result3 = solve_bvp(fun_PB, bc_PB, x, y3,  args = args, tol=tol_PB)

    #si1=-result1.y[1][0]*ew
    #si2=-result2.y[1][0]*ew
    #si3=-result3.y[1][0]*ew

    plt.figure(3)
    plt.plot(result.x, result.y[0])
    #
    #assert 5==3
    sigma_S1_d = -result.y[1][0] * ew
    sigma_S2_d = result.y[1][-1] * ew
    #sigma_S1_d=-result.y[1][0]*ew + CapacitancesS1[2]*(psi_S1_v[2]-psi_S1_v[3])
    #sigma_S2_d=result.y[1][-1]*ew + CapacitancesS2[2]*(psi_S2_v[2]-psi_S2_v[3])
    #
    T_S1_gammad = sigma_S1_gamma + sigma_S1_d
    T_S2_gammad = sigma_S2_gamma + sigma_S2_d
    #
    #print([sigma_S1_gamma, sigma_S2_gamma, sigma_S1_d, sigma_S2_d])
    #print([psi_S1_v[3], psi_S2_v[3]])
    # Now the values must be put in T
    T[pos_psi_S1_vec[0]] = T_S1_0
    T[pos_psi_S1_vec[1]] = T_S1_alpha
    T[pos_psi_S1_vec[2]] = T_S1_beta
    T[pos_psi_S1_vec[3]] = T_S1_gammad

    T[pos_psi_S2_vec[0]] = T_S2_0
    T[pos_psi_S2_vec[1]] = T_S2_alpha
    T[pos_psi_S2_vec[2]] = T_S2_beta
    T[pos_psi_S2_vec[3]] = T_S2_gammad

    return T, result
Beispiel #14
0
def Update_T_PB_FLM(T, sS1, sS2, e, temp, aS1, aS2, CapS1, CapS2, psi_vS1,
                    psi_vS2, pos_psi0S1, pos_psialphaS1, pos_psibetaS1,
                    pos_psigammaS1, pos_psi0S2, pos_psialphaS2, pos_psibetaS2,
                    pos_psigammaS2, x, Z, C_aq):
    """
        This equation is linked to func_NR_PB_FLM. It updates the values of T for the electrostatic parameters.
        CapS1       is the vector of capacitances for surface 1. The units are supossed to be F/m². 
        CapS2       is the vector of capacitances for surface 2. The units are supossed to be F/m². 
        psi_vS1   is the vector of electrostatic potentials for the surface1. The units are supposed to be volts
        psi_vS2   is the vector of electrostatic potentials for the surface2. The units are supposed to be volts
        s       is the specific surface area
        a       concentration of suspended solid
        temp    is the temperature in Kelvins
        e       is the relative permittivity
        I       is the ionic strenght mol/m³
    """
    #  constant
    F = 96485.3328959  # C/mol
    R = 8.314472  # J/(K*mol)
    elec_charge = 1.60217662e-19  #electron charge in C
    eo = 8.854187871e-12  # Farrads = F/m   - permittivity in vaccuum
    Na = 6.02214e23  # 1/mol
    # Update of T
    # T = (sa/F)*sigma
    # sigma = C*(psi-psi_0) <-- The sigma depends on the plane

    # NOTE: I JUST REALISED I DID SOMETHING WRONG THE WHOLE TIME. In the T vector, It must be checked in the other approaches (TLM)
    # The equations os the layers that are not in contact with the diffusion layer must be mol/kg or mol/l
    # while the third component is the total charge balance.

    # Surface 1
    sigma_0_S1 = CapS1[0] * (psi_vS1[0] - psi_vS1[1])
    sigma_alpha_S1 = -sigma_0_S1 + CapS1[1] * (psi_vS1[1] - psi_vS1[2])
    sigma_beta_S1 = -sigma_0_S1 - sigma_alpha_S1 + CapS1[2] * (psi_vS1[2] -
                                                               psi_vS1[3])
    sigma_gamma_S1 = -sigma_0_S1 - sigma_alpha_S1 - sigma_beta_S1
    #Surface 2
    sigma_0_S2 = CapS2[0] * (psi_vS2[0] - psi_vS2[1])
    sigma_alpha_S2 = -sigma_0_S2 + CapS2[1] * (psi_vS2[1] - psi_vS2[2])
    sigma_beta_S2 = -sigma_0_S2 - sigma_alpha_S2 + CapS2[2] * (psi_vS2[2] -
                                                               psi_vS2[3])
    sigma_gamma_S2 = -sigma_0_S2 - sigma_alpha_S2 - sigma_beta_S2

    # T
    T_0S1 = ((sS1 * aS1) / F) * sigma_0_S1
    # units mol/L or mol/kg
    T_alphaS1 = ((sS1 * aS1) / F) * sigma_alpha_S1
    # units mol/L or mol/kg
    T_betaS1 = ((sS1 * aS1) / F) * sigma_beta_S1
    # units mol/L or mol/kg

    T_0S2 = ((sS2 * aS2) / F) * sigma_0_S2
    # units mol/L or mol/kg
    T_alphaS2 = ((sS2 * aS2) / F) * sigma_alpha_S2
    # units mol/L or mol/kg
    T_betaS2 = ((sS2 * aS2) / F) * sigma_beta_S2
    # units mol/L or mol/kg
    #!! Important!! Here starts the PB part
    ew = eo * e
    #
    Q = Z * elec_charge  # Q is the charve of the aqueous elements times the electron charge
    C = C_aq
    A = Na * 1000 / ew  # a prefactor = Avogadro * 1000 /ew
    kbt = 1.38064852e-23 * temp  # kb (J/K) * T in K
    y0[0, 0] = psi_vS1[3]
    'I think that  y0[1,0] and y0[1,-1] are not necessary to solve the problem, I would say that its values do not have implications. Although I am not 100% sure.'
    y0[1,
       0] = -sigma_gamma_S1 / ew  # The negative value that I am given here is extremely arbitrary I am not sure why. IT MUST BE DISCUSSED
    # y0[1,0] = dpsi_d                dpsi_d = -(sig_0 + sig_b + sig_d)/ew   # electric field at diffuse layer, x>d
    y0[0, -1] = psi_vS2[3]
    y0[1, -1] = sigma_gamma_S2 / ew
    args = [Q, C, A, kbt, y0]
    result = solve_bvp(fun_PB, bc_PB, x, y0, tol=1e-8, args=args)
    #
    sigma_dS1 = result.y[1][1] * ew
    sigma_dS2 = result.y[1][-1] * ew
    #

    T_gammadS1 = -sigma_gamma_S1 + sigma_dS1  # This part should be equal to C[2]*(psi_beta-psi_dorgamma)+sigma_d
    T_gammadS2 = -sigma_gamma_S2 + sigma_dS2  # This part should be equal to C[2]*(psi_beta-psi_dorgamma)+sigma_d
    # Now the values must be put in T
    T[pos_psi0S1] = T_0S1
    T[pos_psialphaS1] = T_alphaS1
    T[pos_psibetaS1] = T_betaS1
    T[pos_psi0S2] = T_0S2
    T[pos_psialphaS2] = T_alphaS2
    T[pos_psibetaS2] = T_betaS2

    T[pos_psigammaS1] = T_gammadS1
    T[pos_psigammaS2] = T_gammadS2
    return T
Beispiel #15
0
def Jacobian_NR_PB_FLM(X, A, log_k, T, sS1, sS2, e, temp, aS1, aS2, CapS1,
                       CapS2, psi_vS1, psi_vS2, pos_psi0S1, pos_psialphaS1,
                       pos_psibetaS1, pos_psigammaS1, pos_psi0S2,
                       pos_psialphaS2, pos_psibetaS2, pos_psigammaS2, x, Z,
                       C_aq):
    #  constant
    F = 96485.3328959  # C/mol [Faraday constant]
    R = 8.314472  # J/(K*mol) [universal constant gas]
    elec_charge = 1.60217662e-19  #electron charge in C
    eo = 8.854187871e-12  # Farrads = F/m   - permittivity in vaccuum
    # Speciation - mass action law
    log_C = log_k + A * np.log10(X)
    # transf
    C = 10**(log_C)
    # First part is the common of the Jacbian derivation
    length_X = X.size
    for i in range(0, length_X):
        for j in range(0, length_X):
            Z[i, j] = np.matmul(np.multiply(A[:, i], A[:, j]), (C / X[j]))

    # Now the electrostatic part must be modified, one question hang on the air:
    # Should we check that the electrostatic part is as we expected?
    sa_F2_S1 = (sS1 * aS1) / (F * F)
    sa_F2_S2 = (sS2 * aS2) / (F * F)
    #### plane 0
    C1_sa_F2_RT_S1 = sa_F2_S1 * CapS1[0] * R * temp
    C1_sa_F2_RT_S2 = sa_F2_S2 * CapS2[0] * R * temp
    # Assigning in Jacobian (plane 0)
    #S1
    Z[pos_psi0S1,
      pos_psi0S1] = Z[pos_psi0S1, pos_psi0S1] + C1_sa_F2_RT_S1 / X[pos_psi0S1]
    Z[pos_psi0S1,
      pos_psialphaS1] = Z[pos_psi0S1,
                          pos_psialphaS1] - C1_sa_F2_RT_S1 / X[pos_psialphaS1]
    #S2
    Z[pos_psi0S2,
      pos_psi0S2] = Z[pos_psi0S2, pos_psi0S2] + C1_sa_F2_RT_S2 / X[pos_psi0S2]
    Z[pos_psi0S2,
      pos_psialphaS2] = Z[pos_psi0S2,
                          pos_psialphaS2] - C1_sa_F2_RT_S2 / X[pos_psialphaS2]

    #### plane alpha
    C1C2_sa_F2_RT_S1 = sa_F2_S1 * R * temp * (CapS1[0] + CapS1[1])
    C2_sa_F2_RT_S1 = sa_F2_S1 * CapS1[1] * R * temp
    C1C2_sa_F2_RT_S2 = sa_F2_S2 * R * temp * (CapS2[0] + CapS2[1])
    C2_sa_F2_RT_S2 = sa_F2_S2 * CapS2[1] * R * temp
    # Assigning in Jacobian (plane alpha)
    #S1
    Z[pos_psialphaS1,
      pos_psi0S1] = Z[pos_psialphaS1,
                      pos_psi0S1] - C1_sa_F2_RT_S1 / X[pos_psi0S1]
    Z[pos_psialphaS1, pos_psialphaS1] = Z[
        pos_psialphaS1, pos_psialphaS1] + C1C2_sa_F2_RT_S1 / X[pos_psialphaS1]
    Z[pos_psialphaS1,
      pos_psibetaS1] = Z[pos_psialphaS1,
                         pos_psibetaS1] - C2_sa_F2_RT_S1 / X[pos_psibetaS1]
    #S2
    Z[pos_psialphaS2,
      pos_psi0S2] = Z[pos_psialphaS2,
                      pos_psi0S2] - C1_sa_F2_RT_S2 / X[pos_psi0S2]
    Z[pos_psialphaS2, pos_psialphaS2] = Z[
        pos_psialphaS2, pos_psialphaS2] + C1C2_sa_F2_RT_S2 / X[pos_psialphaS2]
    Z[pos_psialphaS2,
      pos_psibetaS2] = Z[pos_psialphaS2,
                         pos_psibetaS2] - C2_sa_F2_RT_S2 / X[pos_psibetaS2]

    #### plane beta
    C3C2_sa_F2_RT_S1 = sa_F2_S1 * R * temp * (CapS1[1] + CapS1[2])
    C3_sa_F2_RT_S1 = sa_F2_S1 * CapS1[2] * R * temp
    C3C2_sa_F2_RT_S2 = sa_F2_S2 * R * temp * (CapS2[1] + CapS2[2])
    C3_sa_F2_RT_S2 = sa_F2_S2 * CapS2[2] * R * temp
    # Assigning in Jacobian (plane beta)
    #S1
    Z[pos_psibetaS1,
      pos_psialphaS1] = Z[pos_psibetaS1,
                          pos_psialphaS1] - C2_sa_F2_RT_S1 / X[pos_psialphaS1]
    Z[pos_psibetaS1,
      pos_psibetaS1] = Z[pos_psibetaS1,
                         pos_psibetaS1] + C3C2_sa_F2_RT_S1 / X[pos_psibetaS1]
    Z[pos_psibetaS1,
      pos_psigammaS1] = Z[pos_psibetaS1,
                          pos_psigammaS1] - C3_sa_F2_RT_S1 / X[pos_psigammaS1]
    #S2
    Z[pos_psibetaS2,
      pos_psialphaS2] = Z[pos_psibetaS2,
                          pos_psialphaS2] - C2_sa_F2_RT_S2 / X[pos_psialphaS2]
    Z[pos_psibetaS2,
      pos_psibetaS2] = Z[pos_psibetaS2,
                         pos_psibetaS2] + C3C2_sa_F2_RT_S2 / X[pos_psibetaS2]
    Z[pos_psibetaS2,
      pos_psigammaS2] = Z[pos_psibetaS2,
                          pos_psigammaS2] - C3_sa_F2_RT_S2 / X[pos_psigammaS2]

    #### plane gamma [diffusive plane]

    Z[pos_psigammaS1,
      pos_psibetaS1] = Z[pos_psigammaS1, pos_psibetaS1] - CapS1[2]
    Z[pos_psigammaS2,
      pos_psibetaS2] = Z[pos_psigammaS2, pos_psibetaS2] - CapS2[2]
    #
    ew = eo * e
    #
    Q = Z * elec_charge  # Q is the charve of the aqueous elements times the electron charge
    Cb = C_aq
    A = 6.02214e23 * 1000 / ew  # a prefactor = Avogadro * 1000 /ew
    kbt = 1.38064852e-23 * temp  # kb (J/K) * T in K
    delta_psi = 0.001

    y0 = np.zeros((2, x.size))
    y0[0, 0] = X[pos_psigammaS1]
    'I think that  y0[1,0] and y0[1,-1] are not necessary to solve the problem, I would say that its values do not have implications. Although I am not 100% sure.'
    y0[1, 0] = -(
        CapS1[2] *
        (X[pos_psigammaS1] - Boltzman_factor_2_psi(X[pos_psibetaS1], temp))
    ) / ew  # The negative value that I am given here is extremely arbitrary I am not sure why. IT MUST BE DISCUSSED
    # y0[1,0] = dpsi_d                dpsi_d = -(sig_0 + sig_b + sig_d)/ew   # electric field at diffuse layer, x>d
    y0[0, -1] = X[pos_psigammaS2]
    y0[1,
       -1] = (CapS2[2] * (X[pos_psigammaS2] -
                          Boltzman_factor_2_psi(X[pos_psibetaS2], temp))) / ew

    y1 = np.zeros((2, x.size))
    y1[0, 0] = X[pos_psigammaS1] * delta_psi
    y1[1,
       0] = -(CapS1[2] * ((X[pos_psigammaS1] * delta_psi) -
                          Boltzman_factor_2_psi(X[pos_psibetaS1], temp))) / ew
    y1[0, -1] = X[pos_psigammaS2]
    y1[1,
       -1] = (CapS2[2] * (X[pos_psigammaS2] -
                          Boltzman_factor_2_psi(X[pos_psibetaS2], temp))) / ew

    y2 = np.zeros((2, x.size))
    y2[0, 0] = X[pos_psigammaS1]
    y2[1,
       0] = -(CapS1[2] * ((X[pos_psigammaS1] * delta_psi) -
                          Boltzman_factor_2_psi(X[pos_psibetaS1], temp))) / ew
    y2[0, -1] = X[pos_psigammaS2] * delta_psi
    y2[1,
       -1] = (CapS2[2] * ((X[pos_psigammaS2] * delta_psi) -
                          Boltzman_factor_2_psi(X[pos_psibetaS2], temp))) / ew

    args0 = [Q, Cb, A, kbt, y0]
    args1 = [Q, Cb, A, kbt, y1]
    args2 = [Q, Cb, A, kbt, y2]
    #PB solving
    result0 = solve_bvp(fun_PB, bc_PB, x, y0, tol=1e-8, args=args0)
    result1 = solve_bvp(fun_PB, bc_PB, x, y1, tol=1e-8, args=args1)
    result2 = solve_bvp(fun_PB, bc_PB, x, y2, tol=1e-8, args=args2)

    d_sigma_d_psi_S1 = (ew /
                        (delta_psi * X[pos_psigammaS1])) * (result1.y[1, 0] -
                                                            result0.y[1, 0])
    d_sigma_d_psi_S2 = (ew /
                        (delta_psi * X[pos_psigammaS2])) * (result2.y[1, -1] -
                                                            result0.y[1, -1])

    Z[pos_psigammaS1, pos_psigammaS1] = CapS1[2] + d_sigma_d_psi_S1
    Z[pos_psigammaS2, pos_psigammaS2] = CapS2[2] + d_sigma_d_psi_S2

    return Z