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
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
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
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 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
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))
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
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
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
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
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
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