PyESPER 1.0.0__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,266 @@
1
+ def organize_nn_output(Path, DesiredVariables, OutputCoordinates={}, PredictorMeasurements={}, **kwargs):
2
+
3
+ """
4
+ Iteratively calculate uncertainties
5
+
6
+ Inputs:
7
+ Path: User-defined computer path
8
+ Desired Variables: List of variables requested
9
+ OutputCoordinates: Dictionary of geographic coordinates
10
+ PredictorMeasurements: Dictionary of predictor measurements
11
+ **kwargs: Please see README
12
+
13
+ Outputs:
14
+ Uncertainties: Dictionary of uncertainty estimates for each
15
+ equation-variable combination
16
+ """
17
+
18
+ import numpy as np
19
+ from PyESPER.defaults import defaults
20
+ from PyESPER.lir_uncertainties import measurement_uncertainty_defaults
21
+ from PyESPER.inputdata_organize import inputdata_organize
22
+ from PyESPER.temperature_define import temperature_define
23
+ from PyESPER.iterations import iterations
24
+ from PyESPER.define_polygons import define_polygons
25
+ from PyESPER.run_nets import run_nets
26
+ from PyESPER.process_netresults import process_netresults
27
+ from PyESPER.emlr_nn import emlr_nn
28
+
29
+ # Predefine output lists
30
+ PD_final, DPD_final, Unc_final, DUnc_final = [], [], [], []
31
+ emlr = []
32
+
33
+ # Rerun nets for each variable
34
+ for d, var in enumerate(DesiredVariables):
35
+ Pertdv, DPertdv, Unc, DUnc = [], [], [], []
36
+ var = [var] # Wrap single variable in a list
37
+ keys = ["sal_u", "temp_u", "phosphate_u", "nitrate_u", "silicate_u", "oxygen_u"]
38
+
39
+ Equations, n, VerboseTF, EstDates, C, PerKgSwTF, MeasUncerts = defaults(
40
+ var,
41
+ PredictorMeasurements,
42
+ OutputCoordinates,
43
+ **kwargs
44
+ )
45
+ Uncertainties_pre, DUncertainties_pre = measurement_uncertainty_defaults(
46
+ n,
47
+ PredictorMeasurements,
48
+ MeasUncerts
49
+ )
50
+
51
+ InputAll = inputdata_organize(
52
+ EstDates,
53
+ C,
54
+ PredictorMeasurements,
55
+ Uncertainties_pre
56
+ )
57
+
58
+ PredictorMeasurements, InputAll = temperature_define(
59
+ var,
60
+ PredictorMeasurements,
61
+ InputAll,
62
+ **kwargs
63
+ )
64
+
65
+ code, unc_combo_dict, dunc_combo_dict = iterations(
66
+ var,
67
+ Equations,
68
+ PerKgSwTF,
69
+ C,
70
+ PredictorMeasurements,
71
+ InputAll,
72
+ Uncertainties_pre,
73
+ DUncertainties_pre
74
+ )
75
+
76
+ df = define_polygons(C)
77
+
78
+ EstAtl, EstOther = run_nets(var, Equations, code)
79
+
80
+ Estimate = process_netresults(
81
+ Equations,
82
+ code,
83
+ df,
84
+ EstAtl,
85
+ EstOther
86
+ )
87
+
88
+ EMLR = emlr_nn(
89
+ Path,
90
+ var,
91
+ Equations,
92
+ OutputCoordinates,
93
+ PredictorMeasurements
94
+ )
95
+
96
+ emlr.append(EMLR)
97
+ names = list(PredictorMeasurements.keys())
98
+ PMs = list(PredictorMeasurements.values())
99
+
100
+ # Replace "nan" with 0 in PMs using list comprehensions
101
+ PMs_nonan = [[0 if val == "nan" else val for val in pm] for pm in PMs]
102
+
103
+ # Transpose PMs_nonan
104
+ PMs = np.transpose(PMs_nonan)
105
+
106
+ PMs3, DMs3 = {}, {}
107
+
108
+ for pred in range(len(PredictorMeasurements)):
109
+ num_coords = len(OutputCoordinates["longitude"])
110
+ num_preds = len(PredictorMeasurements)
111
+
112
+ # Initialize perturbation arrays
113
+ Pert = np.zeros((num_coords, num_preds))
114
+ DefaultPert = np.zeros((num_coords, num_preds))
115
+
116
+ # Populate perturbation arrays
117
+ Pert[:, pred] = Uncertainties_pre[keys[pred]]
118
+ DefaultPert[:, pred] = DUncertainties_pre[keys[pred]]
119
+
120
+ # Apply perturbations
121
+ PMs2 = PMs + Pert
122
+ DMs2 = PMs + DefaultPert
123
+
124
+ # Update PMs3 and DMs3 dictionaries
125
+ for col, name in enumerate(names):
126
+ PMs3[name] = PMs2[:, col].tolist()
127
+ DMs3[name] = DMs2[:, col].tolist()
128
+
129
+ # Run preprocess_applynets for perturbed and default data
130
+ VTF = False
131
+ Eqs2, n2, VerbTF2, EstDates2, C2, PerKgSwTF2, MeasUncerts2 = defaults(
132
+ var,
133
+ PMs2,
134
+ OutputCoordinates,
135
+ Equations=Equations,
136
+ EstDates=EstDates,
137
+ VerboseTF = VTF,
138
+ )
139
+ U_pre2, DU_pre2 = measurement_uncertainty_defaults(
140
+ n2,
141
+ PMs3,
142
+ MeasUncerts2
143
+ )
144
+ InputAll2 = inputdata_organize(
145
+ EstDates2,
146
+ C2,
147
+ PMs3,
148
+ U_pre2
149
+ )
150
+ InputAll3 = inputdata_organize(
151
+ EstDates2,
152
+ C2,
153
+ DMs3,
154
+ U_pre2
155
+ )
156
+ PMs3, InputAll2 = temperature_define(
157
+ var,
158
+ PMs3,
159
+ InputAll2,
160
+ **kwargs
161
+ )
162
+ DMs3, InputAll3 = temperature_define(
163
+ var,
164
+ DMs3,
165
+ InputAll3,
166
+ **kwargs
167
+ )
168
+ code2, unc_combo_dict2, dunc_combo_dict2 = iterations(
169
+ var,
170
+ Eqs2,
171
+ PerKgSwTF2,
172
+ C2,
173
+ PMs3,
174
+ InputAll2,
175
+ U_pre2,
176
+ DU_pre2
177
+ )
178
+ code3, unc_combo_dict3, dunc_combo_dict3 = iterations(
179
+ var,
180
+ Eqs2,
181
+ PerKgSwTF2,
182
+ C2,
183
+ DMs3,
184
+ InputAll3,
185
+ U_pre2,
186
+ DU_pre2
187
+ )
188
+ df2 = define_polygons(C2)
189
+ EstAtl2, EstOther2 = run_nets(
190
+ var,
191
+ Eqs2,
192
+ code2
193
+ )
194
+ EstAtl3, EstOther3 = run_nets(
195
+ var,
196
+ Eqs2,
197
+ code3
198
+ )
199
+ PertEst = process_netresults(
200
+ Eqs2,
201
+ code2,
202
+ df2,
203
+ EstAtl2,
204
+ EstOther2
205
+ )
206
+ DefaultPertEst = process_netresults(
207
+ Eqs2,
208
+ code3,
209
+ df2,
210
+ EstAtl3,
211
+ EstOther3
212
+ )
213
+
214
+ # Extract estimates and perturbation results
215
+ estimates = [np.array(v) for v in Estimate.values()]
216
+ pertests = [np.array(v) for v in PertEst.values()]
217
+ defaultpertests = [np.array(v) for v in DefaultPertEst.values()]
218
+
219
+ # Initialize result lists
220
+ PertDiff, DefaultPertDiff, Unc_sub2, DUnc_sub2 = [], [], [], []
221
+
222
+ for c in range(len(Equations)):
223
+ # Compute differences and squared differences using numpy
224
+ PD = estimates[c] - pertests[c]
225
+ DPD = estimates[c] - defaultpertests[c]
226
+ Unc_sub1 = (estimates[c] - pertests[c])**2
227
+ DUnc_sub1 = (estimates[c] - defaultpertests[c])**2
228
+
229
+ # Append results
230
+ PertDiff.append(PD)
231
+ DefaultPertDiff.append(DPD)
232
+ Unc_sub2.append(Unc_sub1)
233
+ DUnc_sub2.append(DUnc_sub1)
234
+ Pertdv.append(PertDiff)
235
+ DPertdv.append(DefaultPertDiff)
236
+ Unc.append(Unc_sub2)
237
+ DUnc.append(DUnc_sub2)
238
+ PD_final.append(Pertdv)
239
+ DPD_final.append(DPertdv)
240
+ Unc_final.append(Unc)
241
+ DUnc_final.append(DUnc)
242
+
243
+ # Compute final uncertainty propagation
244
+
245
+ est = [np.array(v) for v in Estimate.values()]
246
+ emlr_combined = {k: v for d in emlr for k, v in d.items()}
247
+ Uncertainties = {}
248
+ for dv in range(0, len(DesiredVariables)):
249
+ dvu = []
250
+ for eq in range(0, len(Equations)):
251
+ sumu = []
252
+ name = DesiredVariables[dv] + str(Equations[eq])
253
+ for n in range(0, len(est[0])):
254
+ # Collect uncertainty contributions from each perturbation
255
+ u = np.array([Unc_final[dv][pre][eq][n] for pre in range(len(PredictorMeasurements))])
256
+ du = np.array([DUnc_final[dv][pre][eq][n] for pre in range(len(PredictorMeasurements))])
257
+ eu = emlr_combined[name][n]
258
+ # Final uncertainty formula
259
+ total_uncertainty = np.sqrt(np.sum(u) - np.sum(du) + eu**2)
260
+ sumu.append(total_uncertainty)
261
+ dvu.append(sumu)
262
+
263
+ Uncertainties[name] = dvu[0]
264
+
265
+ return Uncertainties
266
+
@@ -0,0 +1,189 @@
1
+ def pH_DIC_nn_adjustment(Path, DesiredVariables, Estimates, YouHaveBeenWarnedCanth, OutputCoordinates={}, PredictorMeasurements={}, **kwargs):
2
+
3
+ """
4
+ Calculating the anthropogenic carbon component for DIC and pH, if needed
5
+
6
+ Inputs:
7
+ Path: Path for user computer
8
+ DesiredVariables: List of variables for which estimates are requested
9
+ Estimates: Dictionary of estimates for each equation-variable combination
10
+ YouHaveBeenWarnedCanth: Boolean for avoiding repeat warnings
11
+ OutputCoordinates: Dictionary of coordinates for requested estimates
12
+ PredictorMeasurements: Dictionary of measurements for calculations
13
+ **kwargs: Please see README for full information
14
+
15
+ Outputs:
16
+ Cant_adjusted: Dictionary of estimates adjusted for anthropogenic carbon
17
+ for each equation-variable combination
18
+ """
19
+
20
+ from PyESPER.simplecantestimatelr import simplecantestimatelr
21
+ import numpy as np
22
+ from PyESPER.defaults import defaults
23
+ from PyESPER.lir_uncertainties import measurement_uncertainty_defaults
24
+ from PyESPER.inputdata_organize import inputdata_organize
25
+ from PyESPER.temperature_define import temperature_define
26
+ from PyESPER.iterations import iterations
27
+ from PyESPER.define_polygons import define_polygons
28
+ from PyESPER.run_nets import run_nets
29
+ from PyESPER.process_netresults import process_netresults
30
+ import seawater as sw
31
+ import PyCO2SYS as pyco2
32
+
33
+ # Interpreting kwargs and setting defaults if needed
34
+ VerboseTF = kwargs.get("VerboseTF", True)
35
+ n = max(len(v) for v in OutputCoordinates.values())
36
+ if "EstDates" in kwargs:
37
+ d = np.array(kwargs["EstDates"])
38
+ EstDates = (
39
+ [item for sublist in [kwargs["EstDates"]] * (n + 1) for item in sublist]
40
+ if len(d) != n else list(d)
41
+ )
42
+ else:
43
+ EstDates = [2002.0] * n
44
+
45
+ # Predefining empty dictionary for results and parsing out estimates
46
+ Cant_adjusted = {}
47
+ combos2 = list(Estimates.keys())
48
+ values2 = list(Estimates.values())
49
+
50
+ # Only if dates are available and if needed, continue
51
+ if "EstDates" in kwargs and ("DIC" in DesiredVariables or "pH" in DesiredVariables):
52
+ if not YouHaveBeenWarnedCanth:
53
+ if VerboseTF:
54
+ print("Estimating anthropogenic carbon for PyESPER_NN.")
55
+ longitude = np.mod(OutputCoordinates["longitude"], 360)
56
+ latitude = np.array(OutputCoordinates["latitude"])
57
+ depth = np.array(OutputCoordinates["depth"])
58
+ Cant, Cant2002 = simplecantestimatelr(EstDates, longitude, latitude, depth)
59
+ YouHaveBeenWarnedCanth = True
60
+
61
+ for combo, a in zip(combos2, values2):
62
+ a = np.array(a, dtype=float)
63
+ if combo.startswith("DIC"):
64
+ a = np.where(np.isnan(a), "nan", a + Cant - Cant2002)
65
+ Cant_adjusted[combo] = a.tolist()
66
+ else:
67
+ Cant_adjusted[combo] = a.tolist()
68
+
69
+ # Extra perturbation for pH
70
+ if "pH" in DesiredVariables:
71
+ warning = []
72
+ for combo, values in zip (combos2, values2):
73
+ if combo.startswith("pH"):
74
+ salinity = PredictorMeasurements["salinity"]
75
+ PM_pH = {"salinity": salinity}
76
+ eq = [16]
77
+ _, n, _, EstDates, C, PerKgSwTF, MeasUncerts = defaults(
78
+ ["TA"],
79
+ PM_pH,
80
+ OutputCoordinates,
81
+ **kwargs
82
+ )
83
+ U_pre, DU_pre = measurement_uncertainty_defaults(
84
+ n,
85
+ PM_pH,
86
+ MeasUncerts
87
+ )
88
+ InputAll = inputdata_organize(
89
+ EstDates,
90
+ C,
91
+ PM_pH,
92
+ U_pre
93
+ )
94
+ PM_pH, InputAll = temperature_define(
95
+ ["TA"],
96
+ PM_pH,
97
+ InputAll,
98
+ **kwargs
99
+ )
100
+ code, unc_combo_dict, dunc_combo_dict = iterations(
101
+ ["TA"],
102
+ eq,
103
+ PerKgSwTF,
104
+ C,
105
+ PM_pH,
106
+ InputAll,
107
+ U_pre,
108
+ DU_pre
109
+ )
110
+ df = define_polygons(C)
111
+ EstAtl, EstOther = run_nets(
112
+ ["TA"],
113
+ eq,
114
+ code
115
+ )
116
+ alkest = process_netresults(
117
+ eq,
118
+ code,
119
+ df,
120
+ EstAtl,
121
+ EstOther
122
+ )
123
+ EstAlk = np.array(alkest["TA16"])
124
+ EstSi = EstP = [0] * len(EstAlk)
125
+ Pressure = sw.pres(OutputCoordinates["depth"], OutputCoordinates["latitude"])
126
+ Est = np.array(values)
127
+
128
+ # CO2SYS calculations
129
+ Out = pyco2.sys(
130
+ par1=EstAlk,
131
+ par2=Est,
132
+ par1_type=1,
133
+ par2_type=3,
134
+ salinity=salinity,
135
+ temperature=PredictorMeasurements["temperature"],
136
+ temperature_out=PredictorMeasurements["temperature"],
137
+ pressure=Pressure,
138
+ pressure_out=Pressure,
139
+ total_silicate=EstSi,
140
+ total_phosphate=EstP,
141
+ opt_total_borate= 2
142
+ )
143
+ DICadj = Out["dic"] + Cant - Cant2002
144
+ OutAdj = pyco2.sys(
145
+ par1=EstAlk,
146
+ par2=DICadj,
147
+ par1_type=1,
148
+ par2_type=2,
149
+ salinity=salinity,
150
+ temperature=PredictorMeasurements["temperature"],
151
+ temperature_out=PredictorMeasurements["temperature"],
152
+ pressure=Pressure,
153
+ pressure_out=Pressure,
154
+ total_silicate=EstSi,
155
+ total_phosphate=EstP,
156
+ opt_total_borate=2
157
+ )
158
+ pHadj = OutAdj["pH"]
159
+
160
+ if any(np.isnan(pHadj)):
161
+ warning_message = (
162
+ "Warning: CO2SS took >20 iterations to converge. The correcponding estimate(s) will be NaN. "
163
+ "This typically happens when ESPER_NN is pooorly suited for estimating water with the given properties "
164
+ "(e.g., very high or low salinity or estimates in marginal seas)."
165
+ )
166
+ warning.append(warning_message)
167
+ else:
168
+ pHadj = np.array(values)
169
+
170
+ Cant_adjusted[combo] = pHadj.tolist()
171
+
172
+ # Print warnings if any
173
+ if warning:
174
+ print(warning[0])
175
+
176
+ elif "EstDates" not in kwargs and ("DIC" or "pH" in DesiredVariables) and VerboseTF and not YouHaveBeenWarnedCanth:
177
+ print("Warning: DIC or pH is a requested output but the user did not provide dates for the desired estimates. The estimates will be specific to 2002.0 unless the optional EstDates input is provided (recommended).")
178
+ YouHaveBeenWarnedCanth = True
179
+
180
+ if kwargs.get("pHCalcTF") and "pH" in DesiredVariables:
181
+ if VerboseTF:
182
+ print("Recalculating the pH to be appropriate for pH values calculated from TA and DIC.")
183
+ for combo, pH_values in zip(combos2, values2):
184
+ if combo.startswith("pH"):
185
+ pH_adjcalc_Est = [(pH + 0.3168) / 1.0404 for pH in pH_values]
186
+ Cant_adjusted[combo] = pH_adjcalc_Est
187
+
188
+ return Cant_adjusted
189
+
PyESPER/pH_adjcalc.py ADDED
@@ -0,0 +1,36 @@
1
+ def pH_adjcalc(DesiredVariables, VerboseTF, Est_pre={}, Cant_adjusted={}, **kwargs):
2
+
3
+ """
4
+ Calculating pH adjustment if units are not in molal format
5
+
6
+ Inputs:
7
+ DesiredVariables: List of variables requested
8
+ VerboseTF: Boolean option to suppress warnings
9
+ Est_pre: Dictionary of estimates thus far for each variable equation combination
10
+ Cant_adjusted: Dictionary of estimates adjusted for anthropogenic carbon for each
11
+ combination
12
+ **kwargs: Please see README for full information
13
+
14
+ Outputs:
15
+ Cant_adjusted: Dictionary of estimates adjusted for anthropogenic carbon
16
+ combos2: List of equation case-desired variable combinations
17
+ values2: List of estimates
18
+ """
19
+
20
+ combos2 = list(Est_pre.keys())
21
+ values2 = list(Est_pre.values())
22
+
23
+ if kwargs.get("pHCalcTF") and "pH" in DesiredVariables:
24
+ if VerboseTF:
25
+ print("Recalculating the pH to be appropriate for pH values calculated from TA and DIC.")
26
+
27
+ for combo in range(0, len(combos2)):
28
+ if combos2[combo].startswith("pH"):
29
+ pH_adjcalc_Est = []
30
+ pH_adjcalc = values2[combo]
31
+ for v in pH_adjcalc:
32
+ pH_adjcalc_Est.append((pH_adjcalc[v]+0.3168)/1.0404)
33
+ Cant_adjusted[combos2[combo]] = pH_adjcalc_Est
34
+
35
+ return Cant_adjusted, combos2, values2
36
+
@@ -0,0 +1,179 @@
1
+ def pH_adjustment(
2
+ Path,
3
+ DesiredVariables,
4
+ Dates,
5
+ Cant,
6
+ Cant2002,
7
+ PerKgSwTF,
8
+ Cant_adjusted={},
9
+ Est_pre={},
10
+ PredictorMeasurements={},
11
+ OutputCoordinates={},
12
+ C={},
13
+ Uncertainties_pre={},
14
+ DUncertainties_pre={},
15
+ **kwargs
16
+ ):
17
+
18
+ """
19
+ Adjusting pH for anthropogenic carbon in the second of three Cant adjustment
20
+ scripts
21
+
22
+ Inputs:
23
+ Path: User-defined computer path
24
+ DesiredVariables: List of desired variables to estimate
25
+ Dates: List of dates for measurements
26
+ Cant: Numpy array of anthropogenic carbon estimates for each estimate
27
+ Cant2002: Numpy array of anthropogenic carbon estimates for each
28
+ estimate for the year 2002
29
+ PerKgSwTF: Boolean for whether measurements were in molar or molal units
30
+ Cant_adjusted: Dictionary of estimates adjusted for Cant
31
+ Est_pre: Dictionary of estimates for each combination
32
+ PredictorMeasurements: Dictionary of measurements for estimates
33
+ OutputCoordinates: Dictionary of geographic coordinates for estimates
34
+ C: Dictionary of adjusted coordinates for estimates
35
+ Uncertainties_pre: Dictionary of measurement uncertainties for estimates
36
+ DUncertainties_pre: Dictionary of default measurement uncertainties for
37
+ estimates
38
+ **kwargs: Please see README
39
+
40
+ Output:
41
+ Cant_adjusted: Dictionary of adjusted values for Cant for each combination
42
+ """
43
+
44
+ import numpy as np
45
+ import seawater as sw
46
+ import PyCO2SYS as pyco2
47
+ from PyESPER.inputdata_organize import inputdata_organize
48
+ from PyESPER.temperature_define import temperature_define
49
+ from PyESPER.iterations import iterations
50
+ from PyESPER.fetch_data import fetch_data
51
+ from PyESPER.input_AAinds import input_AAinds
52
+ from PyESPER.coefs_AAinds import coefs_AAinds
53
+ from PyESPER.interpolate import interpolate
54
+ from PyESPER.organize_data import organize_data
55
+
56
+ # Finding the estimates within the dictionary
57
+ combos2 = list(Est_pre.keys())
58
+ values2 = list(Est_pre.values())
59
+
60
+ # Setting the default warning message boolean and Verbose
61
+ YouHaveBeenWarnedCanth = False
62
+ VerboseTF = kwargs.get("VerboseTF", True)
63
+
64
+ # Proceed only if dates are provided and DIC or pH is requested
65
+ if "EstDates" in kwargs and ("DIC" in DesiredVariables or "pH" in DesiredVariables):
66
+ if "pH" in DesiredVariables:
67
+ warning = []
68
+ for combo, values in zip(combos2, values2):
69
+ if combo.startswith("pH"):
70
+ # Rerunning LIRs for when pH is requested to obtain TA estimates
71
+ # based only on salinity input
72
+ salinity = PredictorMeasurements["salinity"]
73
+ PM_pH = {"salinity": salinity}
74
+ eq = [16]
75
+ InputAll2 = inputdata_organize(
76
+ Dates,
77
+ C,
78
+ PM_pH,
79
+ Uncertainties_pre
80
+ )
81
+ PredictorMeasurements2, InputAll2 = temperature_define(
82
+ ["TA"],
83
+ PM_pH,
84
+ InputAll2,
85
+ **kwargs
86
+ )
87
+ code, unc_combo_dict, dunc_combo_dict = iterations(
88
+ ["TA"],
89
+ eq,
90
+ PerKgSwTF,
91
+ C,
92
+ PredictorMeasurements2,
93
+ InputAll2,
94
+ Uncertainties_pre,
95
+ DUncertainties_pre
96
+ )
97
+ LIR_data = fetch_data(["TA"], Path)
98
+ AAdata, Elsedata = input_AAinds(C, code)
99
+ Gdf, CsDesired = coefs_AAinds(eq, LIR_data)
100
+ aaLCs, aaInterpolants_pre, elLCs, elInterpolants_pre = interpolate(
101
+ Gdf,
102
+ AAdata,
103
+ Elsedata
104
+ )
105
+ alkest, _ = organize_data(
106
+ aaLCs,
107
+ elLCs,
108
+ aaInterpolants_pre,
109
+ elInterpolants_pre,
110
+ Gdf,
111
+ AAdata,
112
+ Elsedata
113
+ )
114
+ EstAlk = np.array(alkest["TA16"])
115
+ EstAlk = np.transpose(EstAlk)
116
+ EstSi = EstP = [0] * len(EstAlk)
117
+ # Calculating pressure using the sw package
118
+ Pressure = sw.pres(OutputCoordinates["depth"], OutputCoordinates["latitude"])
119
+ Est = np.array(values)
120
+ Est = np.transpose(Est)
121
+ Est = Est[0]
122
+ temperature = np.array(PredictorMeasurements["temperature"])
123
+ # Now using CO2SYS to calculate DIC based on the above LIR results for TA
124
+ # CO2SYS calculations
125
+ kwargCO2 = {
126
+ "par1":EstAlk,
127
+ "par2":Est,
128
+ "par1_type":1,
129
+ "par2_type":3,
130
+ "salinity":salinity,
131
+ "temperature":temperature,
132
+ "temperature_out":temperature,
133
+ "pressure":Pressure,
134
+ "pressure_out":Pressure,
135
+ "total_silicate":EstSi,
136
+ "total_phosphate":EstP,
137
+ "opt_total_borate":2}
138
+ Out = pyco2.sys(**kwargCO2)
139
+ DICadj = Out["dic"] + Cant - Cant2002
140
+
141
+ # Using this DIC to calculate pH from CO2SYS
142
+ kwargCO2_2 = {
143
+ "par1":EstAlk,
144
+ "par2":DICadj,
145
+ "par1_type":1,
146
+ "par2_type":2,
147
+ "salinity":salinity,
148
+ "temperature":temperature,
149
+ "temperature_out":temperature,
150
+ "pressure":Pressure,
151
+ "pressure_out":Pressure,
152
+ "total_silicate":EstSi,
153
+ "total_phosphate":EstP,
154
+ "opt_total_borate":2}
155
+ OutAdj = pyco2.sys(**kwargCO2_2)
156
+ pHadj = OutAdj["pH"]
157
+
158
+ # Check for convergence warnings
159
+ if np.isnan(pHadj).any():
160
+ warning_message = (
161
+ "Warning: CO2SYS took >20 iterations to converge. The corresponding estimate(s) will be NaN. "
162
+ "This typically happens when ESPER_LIR is poorly suited for estimating water with the given properties "
163
+ "(e.g., very high or low salinity or estimates in marginal seas)."
164
+ )
165
+ warning.append(warning_message)
166
+ # Append to adjusted Cant dictionary
167
+ Cant_adjusted[combo] = pHadj.tolist()
168
+
169
+ # Print warnings if any
170
+ if warning:
171
+ print(warning[0])
172
+
173
+ elif "EstDates" not in kwargs and ("DIC" or "pH" in DesiredVariables) and not VerboseTF and YouHaveBeenWarnedCanth:
174
+ print("Warning: DIC or pH is a requested output but the user did not provide dates for the desired esimtates. The estimates "
175
+ "will be specific to 2002.0 unless the optional EstDates input is provided (recommended).")
176
+
177
+ YouHaveBeenWarnedCanth = True
178
+
179
+ return Cant_adjusted