Skip to content

Commit

Permalink
Merge pull request #125 from NREL/Kempe-Edge-Seals
Browse files Browse the repository at this point in the history
Kempe edge seals
  • Loading branch information
martin-springer authored Sep 30, 2024
2 parents edf6074 + 08d739a commit 0ef212c
Show file tree
Hide file tree
Showing 5 changed files with 238 additions and 138 deletions.
8 changes: 4 additions & 4 deletions pvdeg/data/O2permeation.json
Original file line number Diff line number Diff line change
Expand Up @@ -36,10 +36,10 @@
"Fickian": true,
"Ead": 29.43112031,
"Do": 0.129061678,
"Eas": 32.3137806,
"So": 87.81142774,
"Eap": 61.7449009,
"Po": 97917899126
"Eas": 16.6314948252219,
"So": 0.136034525059804,
"Eap": 49.1083457348515,
"Po": 528718258.338532
},
"OX004": {
"name": "AAA polyamide backsheet",
Expand Down
153 changes: 100 additions & 53 deletions pvdeg/diffusion.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,25 +8,24 @@
from pvdeg import DATA_DIR
from numba import jit
import numpy as np
from typing import Callable

def esdiffusion(
temperature,
edge_seal=None,
encapsulant=None,
edge_seal="OX005",
encapsulant="OX003",
edge_seal_width=1.5,
encapsulant_width=10,
seal_nodes=20,
encapsulant_nodes=50,
press = 0.209,
repeat = 1,
Dos=None,
Eads=None,
Sos=None,
Eass=None,
Doe=None,
Eade=None,
Soe=None,
Ease=None,
Dos=None, Eads=None, Sos=None,Eass=None, Doe=None, Eade=None, Soe=None, Ease=None,
react_func = None,
deg_func = None,
deg = None,
perm = None,
printout = True,
**kwarg
):

Expand Down Expand Up @@ -58,40 +57,68 @@ def esdiffusion(
This is the partial pressure of oxygen.
repeat : integer, optional
This is the number of times to do the calculation for the whole dataset. E.g. repeat the 1-y data for 10 years.
react_func : string, optional
This is the name of the function that will be calculating the consumption of oxygen.
deg_func :string, optional
This is the name of the function that will be calculating the degradation.
printout : Boolean
This allows you to suppress printing messages during code execution by setting it to false.
deg : Numpy Array
One can send in an array with predefined degradation data already in it if desired.
I.e. you can have some pre degradation or areas that require more degradation.
perm : Numpy Array
One can send in an array with the permeant already in it if desired.
kwargs : dict, optional
If es or enc are left at 'None' then the use parameters, Dos, Eads, Sos, Eass, Doe, Eade, Soe, Ease in units of
If edge_seal or encapsulant are set at 'None' then you can enter your own parameters for, Dos, Eads, Sos, Eass, Doe, Eade, Soe, Ease in units of
[cm²/s], [g/cm³], or [kJ/mol] for diffusivity, solubility, or activation energy respectively. If specific parameters are provided,
then the JSON ones can be overridden.
then the JSON ones will be overridden.
Should also contain any key word arguments that need to be passed to the function calculating consumption of the permeant or degradation.
Returns
-------
ingress_data : pandas.DataFrame
This will give the concentration profile as a function of temperature along with degradation parameters in futur iterations..
This will give the concentration profile as a function of time.
If there is a degradation function called, this data will also be inclueded on a node by node basis under a third index.
"""

with open(os.path.join(DATA_DIR, "O2permeation.json")) as user_file:
O2 = json.load(user_file)
user_file.close()
# O2
if edge_seal == None:
esp = O2.get("OX005") # This is the number for the edge seal in the json file
else:
esp = O2.get(edge_seal)
with open(os.path.join(DATA_DIR, "H2Opermeation.json")) as user_file:
H2O = json.load(user_file)
user_file.close()

if encapsulant == None:
encp = O2.get(
"OX003"
) # This is the number for the encapsulant in the json file
if edge_seal[0:2]=="OX":
esp = O2.get(edge_seal)
if printout:
print("Oxygen ingress parameters loaded for the edge seal.")
else:
encp = O2.get(encapsulant)
if edge_seal[0:1]=="W":
esp = H2O.get(edge_seal)
if printout:
print("Water ingress parameters loaded for the edge seal.")
else:
print("Edge seal material not found")

try:
print("The edge seal is", esp.get("name"), ".")
print("The encapsulant is", encp.get("name"), ".")
except:
print("")
if encapsulant[0:2]=="OX":
encp = O2.get(encapsulant)
if printout:
print("Oxygen ingress parameters loaded for the encapsulant.")
else:
if encapsulant[0:1]=="W":
encp = H2O.get(encapsulant)
if printout:
print("Water ingress parameters loaded for the eencapsulant.")
else:
print("Encapsulant material not found")
if printout:
try:
print("The edge seal is", esp.get("name"), ".")
print("The encapsulant is", encp.get("name"), ".")
except:
print("Unknown material selected.")

# These are the edge seal oxygen permeation parameters
# These are the edge seal oxygen or water permeation parameters
if Dos == None:
Dos = esp.get("Do")
if Eads == None:
Expand Down Expand Up @@ -136,12 +163,14 @@ def esdiffusion(

perm_mid = np.array(
np.zeros((seal_nodes + encapsulant_nodes + 3)), dtype=np.float64
) # This is the profile at a transition point between output points.
perm = np.array(
np.zeros(
(len(temperature) * repeat - repeat + 1, seal_nodes + encapsulant_nodes + 3), dtype=np.float64
)
) # It adds in two nodes for the interface concentration for both materials and one for the hour column.
) # This is the profile at a transition point between output points.
if perm == None:
perm = np.array(
np.zeros(
(len(temperature) * repeat - repeat + 1, seal_nodes + encapsulant_nodes + 3), dtype=np.float64
)
) # It adds in two nodes for the interface concentration for both materials and one for the hour column.

temperature = pd.DataFrame(
temperature, columns=["module_temperature", "time", "time_step"]
) # This adds the number of time steps to be used as a subdivision between data points. [s]
Expand All @@ -163,7 +192,8 @@ def esdiffusion(
time_step[row] = np.trunc(fos / f_max) + 1
else:
time_step[row] = np.trunc(foe / f_max) + 1

if deg_func != None and deg == None: # Sets up an array to do the degradation calculation.
deg=perm
perm[0][1] = Sos * np.exp(-Eass / met_data[0][0])
perm_mid = perm[0]
for rp_num in range(repeat):
Expand All @@ -187,10 +217,9 @@ def esdiffusion(
)
# Cs edge seal/Ce encapsulant
r1 = so * np.exp(-eas / (met_data[row][0] + dtemp * mid_point))
r2 = (
dod * np.exp(-ead / (met_data[row][0] + dtemp * mid_point))
* r1 * encapsulant_width / edge_seal_width
) # Ds/De*Cs/Ce*We/Ws
r2 = dod * np.exp(-ead / (met_data[row][0] + dtemp * mid_point)
)* r1 * encapsulant_width / edge_seal_width
# Ds/De*Cs/Ce*We/Ws
# Calculates the edge seal nodes. Adjusted to not calculate ends and to have the first node be temperature.
for node in range(2, seal_nodes):
perm[row + 1 + rp_row][node] = perm_mid[node] + fos * (
Expand All @@ -201,36 +230,54 @@ def esdiffusion(
perm[row + 1 + rp_row][node] = perm_mid[node] + foe * (
perm_mid[node - 1] + perm_mid[node + 1] - 2 * perm_mid[node]
)
# Calculates the center encapsulant node. Accounts for temperature and two interfade nodes.
# Calculates the center encapsulant node. Accounts for temperature and two interface nodes.
perm[row + 1 + rp_row][encapsulant_nodes + seal_nodes + 2] = perm_mid[
encapsulant_nodes + seal_nodes + 2
] + 2 * foe * (perm_mid[encapsulant_nodes + seal_nodes + 1] - perm_mid[encapsulant_nodes + seal_nodes + 2])
encapsulant_nodes + seal_nodes + 2] + 2 * foe * (
perm_mid[encapsulant_nodes + seal_nodes + 1] -
perm_mid[encapsulant_nodes + seal_nodes + 2])

# Calculated edge seal node adjacent to the first encapsulant node. Node numbers shifted.
perm[row + 1 + rp_row][seal_nodes] = perm_mid[seal_nodes] + fos * (
perm_mid[seal_nodes - 1]
+ perm_mid[seal_nodes + 3] * r1 * 2 / (1 + r2)
- perm_mid[seal_nodes] * (1 + 2 / (1 + r2))
)
- perm_mid[seal_nodes] * (1 + 2 / (1 + r2)))

# Calculated encapsulant node adjacent to the last edge seal node. Node numbers shifted.
perm[row + 1 + rp_row][seal_nodes + 3] = perm_mid[seal_nodes + 3] + foe * (
perm_mid[seal_nodes] / r1 * 2 / (1 + 1 / r2)
+ perm_mid[seal_nodes + 4]
- perm_mid[seal_nodes + 3] * (1 + 2 / (1 + 1 / r2))
)
- perm_mid[seal_nodes + 3] * (1 + 2 / (1 + 1 / r2)))

# sets the concentration at the edge seal to air interface.
perm[row + 1 + rp_row][1] = Sos * np.exp(
-Eass / (met_data[row + 1][0] + dtemp * mid_point)
)


# Runs the degradation calculation.
if deg_func != None:
print('oops')
# Runs the reaction with permeant function.
if react_func != None:
print('oops')

perm_mid = perm[row + 1 + rp_row]

# calculate edge seal at interface to encapsulant.
perm[row + 1 + rp_row][seal_nodes + 1] = (
perm_mid[seal_nodes + 3] / r2 * r1 + perm_mid[seal_nodes]
) / (1 / r2 + 1)
# calculate encapsulant at interface to the edge seal.
perm[row + 1 + rp_row][seal_nodes + 2] = perm[row + 1 + rp_row][seal_nodes + 1] / r1
# Calculate edge seal at interface to encapsulant.
# Blocked out code did weird things and was based on equal fluxes. Actually using a simple averaging. This looks better and is not used in the diffusion calculations.
#perm[row + 1 + rp_row][seal_nodes + 1] = (perm_mid[seal_nodes + 3]*r1
# + perm_mid[seal_nodes]*r2) / (1+r2)
perm[row + 1 + rp_row][seal_nodes + 1] = perm_mid[seal_nodes ]+(perm_mid[seal_nodes]-perm_mid[seal_nodes-1])/2

# Calculate encapsulant at interface to the edge seal.
#perm[row + 1 + rp_row][seal_nodes + 2] = perm[row + 1 + rp_row][seal_nodes + 1] / r1
perm[row + 1 + rp_row][seal_nodes + 2] = perm_mid[seal_nodes + 3]+(perm_mid[seal_nodes + 4]-perm_mid[seal_nodes+3])/2

# Puts in the time for the first column.
perm[row + 1 + rp_row][0] = rp_time + met_data[row + 1][1]



# Because it is cycling around, it needs to start with the last temperature.
met_data[0][0] = met_data[met_data.shape[0] - 1][0]

Expand Down
15 changes: 13 additions & 2 deletions pvdeg/utilities.py
Original file line number Diff line number Diff line change
Expand Up @@ -515,10 +515,21 @@ def _read_material(name, fname="O2permeation.json"):
fpath = os.path.join(DATA_DIR, fname)
with open(fpath) as f:
data = json.load(f)
f.close()

if name is None:
material_list = data.keys()
return [*material_list]
return list(data.keys())

# Mike Added
# broke test
# ===========
# material_list = ''
# print('working')
# for key in data:
# if 'name' in data[key].keys():
# material_list = material_list + key + "=" + data[key]['name'] + '\n'
# material_list = material_list[0:len(material_list)-1]
# return [*material_list]

mat_dict = data[name]
return mat_dict
Expand Down
8 changes: 4 additions & 4 deletions tests/data/test-scenario.json
Original file line number Diff line number Diff line change
Expand Up @@ -14,10 +14,10 @@
"Fickian": true,
"Ead": 29.43112031,
"Do": 0.129061678,
"Eas": 32.3137806,
"So": 87.81142774,
"Eap": 61.7449009,
"Po": 97917899126
"Eas": 16.6314948252219,
"So": 0.136034525059804,
"Eap": 49.1083457348515,
"Po": 528718258.338532

},
"temp_model": "sapm",
Expand Down
Loading

0 comments on commit 0ef212c

Please sign in to comment.