Econ Recon¶

Data Reconciliation for a Single Unit - Economizer¶
This notebook demonstrates data reconciliation with a single unit model, an economizer. Data for this example was generated by adding noise to supercritical power plant simulations.
Why reconcile data?¶
Data reconciliation uses mass and energy balances along with redundant measurements to improve data quality by:
- reducing measurement error,
- ensuring measurements satisfy mass and energy balances, and
- filling in unmeasured quantities.
Data reconciliation is used to refine process data before parameter estimation.
1. Read Plant Data¶
The first step is to read in process data. In this case, data was simulated by adding measurement error to supercritical steam cycle simulation results. IDAES includes functions to read process data, convert units to match a model, and map data to a model.
# IDAES module with functions to read, analyze and visualize plant data
import idaes.dmf.model_data as da
# Suppress some warnings
from idaes.logger import getLogger
import logging
getLogger('idaes.core').setLevel(logging.ERROR)
Process data is contained in two CSV files, a data file and a metadata file. The first column in the data file is row indexes and the first row is process measurement tags. The index column has an entry for each data row, and is often a time-stamp. The data file format is illustrated by the table below.
tag1 | tag2 | tag3 | ... | |
---|---|---|---|---|
index1 | data(1,1) | data(1,2) | data(1, 3) | ... |
index2 | data(2,1) | data(2,2) | data(2, 3) | ... |
... | ... | ... | ... | ... |
The metadata file contains information about the tags including units of measurement, description, and model mapping information. The meta data format is show below, any of the columns my be empty.
tag1 | model reference 1 | description 1 | unit of measure 1 | Additional comments, additional columns are ignored |
tag2 | model reference 2 | description 2 | unit of measure 2 | ... |
tag3 | model reference 3 | description 3 | unit of measure 3 | ... |
... | ... | ... | ... | ... |
Once the process data is read in, the data is assigned to bins based on the value in a given column, in this case gross power. Dividing the data into bins allows rough estimation of measurement uncertainty.
# Read data and column metadata
df, df_meta = da.read_data("plant_data.csv", "plant_data_meta.csv")
# Add bin information where the data is sorted into 5 MW bins based on the "GROSS_POWER" column
# A bin number column is added along with a column for nominal gross power in the bin.
bin_count = da.bin_data(df, bin_by="POWER_GROSS", bin_no="bin_no", bin_nom="bin_power", bin_size=5e6)
# Calculate the standard deviation by bin for each column. The resulting standard devations can be
# accessed like so: bin_stdev[bin number][column name]
bin_stdev = da.bin_stdev(df, bin_no="bin_no")
It can be useful to visualize the measurement data and estimated uncertainty. The following creates box and whisker plots for each tag based on the data bins. A large number of plots may be created, so to manage them more easily, they are saved as PDFs and merged into a single multi-page PDF document. The deafault file name for the resulting PDF is "data_plot_book.pdf."
# Create a pdf book of plots that shows box and whisker plots for each column by bin
import os
if not os.path.isfile("data_plot_book.pdf"):
da.data_plot_book(df, bin_nom="bin_power", xlabel="gross power (W)", metadata=df_meta, file="data_plot_book.pdf")
# There should now be a data_plot_book.pdf file in this directory
2. Create Unit model¶
Now that we have the plant data, we need to create a unit model that we can use for data reconciliation. Although we need a model that has just mass and energy balances and feasibility constraints for the data reconciliation problem, we start with the full economizer model here. Using the same model for data reconciliation, parameter estimation, validation, and simulation reduces the work required to move between steps in the workflow.
Once the full model is created, constraints that are not needed for data reconciliation can be deactivated.
# Import models
from idaes.core import FlowsheetBlock
from idaes.power_generation.properties.flue_gas_ideal import FlueGasParameterBlock
from idaes.generic_models.properties import iapws95
from idaes.power_generation.unit_models.boiler_heat_exchanger import (
BoilerHeatExchanger,
TubeArrangement,
DeltaTMethod
)
import pyomo.environ as pyo
# Create flowsheet with economizer
m = pyo.ConcreteModel()
m.fs = FlowsheetBlock(default={"dynamic": False})
m.fs.prop_water = iapws95.Iapws95ParameterBlock()
m.fs.prop_fluegas = FlueGasParameterBlock()
m.fs.econ = BoilerHeatExchanger(default={
"side_1_property_package": m.fs.prop_water,
"side_2_property_package": m.fs.prop_fluegas,
"has_pressure_change": True,
"has_holdup": False,
"delta_T_method": DeltaTMethod.counterCurrent,
"tube_arrangement": TubeArrangement.inLine,
"side_1_water_phase": "Liq",
"has_radiation": False
}
)
# Set up and initialize the model
# The steam properties use enthalpy as a state variable, so use the known
# temperature and pressure to calculate the feedwater inlet enthalpy
h = pyo.value(iapws95.htpx(563.706*pyo.units.K, 2.5449e7*pyo.units.Pa))
m.fs.econ.side_1_inlet.flow_mol[0].fix(24678.26) # mol/s
m.fs.econ.side_1_inlet.enth_mol[0].fix(h) #J/mol
m.fs.econ.side_1_inlet.pressure[0].fix(2.5449e7) # Pa
# Set the flue gas flow and composition
fg_rate = 28.3876e3 # mol/s equivalent of ~1930.08 klb/hr
fg_comp = { # mol fraction of flue gas components
"H2O":8.69/100,
"CO2":14.49/100,
"O2":2.47/100,
"NO":0.0006,
"SO2":0.002,
}
# The rest is N2
fg_comp["N2"] = 1 - sum(fg_comp[i] for i in fg_comp)
# Set economizer inlets
for c in fg_comp:
m.fs.econ.side_2.properties_in[0].flow_mol_comp[c].fix(fg_rate*fg_comp[c])
m.fs.econ.side_2_inlet.temperature[0].fix(682.335) # K
m.fs.econ.side_2_inlet.pressure[0].fix(100145) # Pa
# Set economizer design variables and parameters
ITM = 0.0254 # inch to meter conversion
# Based on NETL Baseline Report Rev4
m.fs.econ.tube_thickness.fix(0.188*ITM) # tube thickness
m.fs.econ.tube_di.fix((2.0 - 2.0 * 0.188)*ITM) # calc inner diameter
m.fs.econ.pitch_x.fix(3.5*ITM)
m.fs.econ.pitch_y.fix(5.03*ITM)
m.fs.econ.tube_length.fix(53.41*12*ITM) # use tube length (53.41 ft)
m.fs.econ.tube_nrow.fix(36*2.5) # use to match baseline performance
m.fs.econ.tube_ncol.fix(130) # 130 from thermoflow
m.fs.econ.nrow_inlet.fix(2)
m.fs.econ.delta_elevation.fix(50)
m.fs.econ.tube_r_fouling = 0.000176
m.fs.econ.shell_r_fouling = 0.00088
m.fs.econ.fcorrection_htc.fix(1.5)
m.fs.econ.fcorrection_dp_tube.fix(1.0)
m.fs.econ.fcorrection_dp_shell.fix(1.0)
# Initialize economizer
m.fs.econ.initialize(
state_args_1={
"flow_mol": m.fs.econ.side_1_inlet.flow_mol[0].value,
"pressure": m.fs.econ.side_1_inlet.pressure[0].value,
"enth_mol": m.fs.econ.side_1_inlet.enth_mol[0].value,
},
state_args_2={
"flow_component":{
"H2O": m.fs.econ.side_2_inlet.flow_mol_comp[0, "H2O"].value,
"CO2": m.fs.econ.side_2_inlet.flow_mol_comp[0, "CO2"].value,
"N2": m.fs.econ.side_2_inlet.flow_mol_comp[0, "N2"].value,
"O2": m.fs.econ.side_2_inlet.flow_mol_comp[0, "O2"].value,
"NO": m.fs.econ.side_2_inlet.flow_mol_comp[0, "NO"].value,
"SO2": m.fs.econ.side_2_inlet.flow_mol_comp[0, "SO2"].value,
},
"temperature": m.fs.econ.side_2_inlet.temperature[0].value,
"pressure": m.fs.econ.side_2_inlet.pressure[0].value,
}
)
2021-03-03 18:47:00 [INFO] idaes.init.fs.econ.side_1: Initialization Complete 2021-03-03 18:47:00 [INFO] idaes.init.fs.econ.side_2.properties_in: Initialisation Complete, optimal - Optimal Solution Found. 2021-03-03 18:47:00 [INFO] idaes.init.fs.econ.side_2.properties_out: Initialisation Complete, optimal - Optimal Solution Found. 2021-03-03 18:47:00 [INFO] idaes.init.fs.econ.side_2.properties_out: fs.econ.side_2.properties_out State Released. 2021-03-03 18:47:00 [INFO] idaes.init.fs.econ.side_2: Initialization Complete 2021-03-03 18:47:00 [INFO] idaes.init.fs.econ: fs.econ Initialisation Step 1 Complete. 2021-03-03 18:47:00 [INFO] idaes.init.fs.econ.side_2.properties_in: fs.econ.side_2.properties_in State Released. 2021-03-03 18:47:00 [INFO] idaes.init.fs.econ: fs.econ Initialisation Complete.
3. Simplify to Mass and Energy Balances¶
For data reconciliation, the model should be reduced to mass and energy balances and potentially limited performance constraints to keep the results feasible.
# Deactivate constraints for heat transfer
m.fs.econ.overall_heat_transfer_coefficient_eqn.deactivate()
m.fs.econ.rcond_wall_eqn.deactivate()
m.fs.econ.hconv_shell_total_eqn.deactivate()
m.fs.econ.hconv_shell_conv_eqn.deactivate()
m.fs.econ.N_Nu_shell_eqn.deactivate()
m.fs.econ.N_Pr_shell_eqn.deactivate()
m.fs.econ.deltaP_shell_eqn.deactivate()
m.fs.econ.friction_factor_shell_eqn.deactivate()
m.fs.econ.N_Re_shell_eqn.deactivate()
m.fs.econ.v_shell_eqn.deactivate()
m.fs.econ.hconv_tube_eqn.deactivate()
m.fs.econ.N_Nu_tube_eqn.deactivate()
m.fs.econ.N_Pr_tube_eqn.deactivate()
m.fs.econ.deltaP_tube_eqn.deactivate()
m.fs.econ.deltaP_tube_uturn_eqn.deactivate()
m.fs.econ.deltaP_tube_friction_eqn.deactivate()
m.fs.econ.friction_factor_tube_eqn.deactivate()
m.fs.econ.N_Re_tube_eqn.deactivate()
m.fs.econ.v_tube_eqn.deactivate()
m.fs.econ.LMTD.deactivate()
4. Map Data to the Model¶
Although the model mapping can be included in the tag metadata file, here we just add the mapping information to the tag metadata after reading the data. Sometime a data set may be used with more than one model or you may want to examine data before creating a model, in which case it is convenient to defer mapping the data to the model as we have done here.
df_meta["ECON_OUT_F"]["reference_string"] = "m.fs.econ.side_1.properties_out[:].flow_mol"
df_meta["ECON_OUT_T"]["reference_string"] = "m.fs.econ.side_1.properties_out[:].temperature"
df_meta["ECON_OUT_P"]["reference_string"] = "m.fs.econ.side_1.properties_out[:].pressure"
df_meta["BFW_F"]["reference_string"] = "m.fs.econ.side_1.properties_in[:].flow_mol"
df_meta["BFW_T"]["reference_string"] = "m.fs.econ.side_1.properties_in[:].temperature"
df_meta["BFW_P"]["reference_string"] = "m.fs.econ.side_1.properties_in[:].pressure"
df_meta["FG_2_ECON_Fm"]["reference_string"] = "m.fs.econ.side_2.properties_in[:].flow_mass"
df_meta["FG_2_ECON_T"]["reference_string"] = "m.fs.econ.side_2.properties_in[:].temperature"
df_meta["FG_2_ECON_P"]["reference_string"] = "m.fs.econ.side_2.properties_in[:].pressure"
df_meta["FG_2_AIRPH_Fm"]["reference_string"] = "m.fs.econ.side_2.properties_out[:].flow_mass"
df_meta["FG_2_AIRPH_T"]["reference_string"] = "m.fs.econ.side_2.properties_out[:].temperature"
df_meta["FG_2_AIRPH_P"]["reference_string"] = "m.fs.econ.side_2.properties_out[:].pressure"
# Add the model references to the tag metadata based on the strings above.
da.upadate_metadata_model_references(m, df_meta)
# Create a dictionary of data tags that we want to use for the data reconciliation problem.
# The key is the tag and the value is a reference to a quantity in the model.
data_tags = {k:v["reference"][0] for k, v in df_meta.items() if v["reference"] is not None}
# Now for result output, the data reconciliation usually can give full stream information for a flowsheet
# including quantities that are unmeasured. To more easily use the results, it is good practice to map most of
# the data reconciliation results to flowsheet stream names.
import idaes.core.util.tables as ta
# This function creates a dictionary of streams based of streams based on model arcs. The function
# also takes an addtional set of stream-like objects for add to the stream dictionary. In this case,
# this is a single unit and the flowsheet doesn't contain any arcs, so we add the economized inlet and
# outlet ports to the stream dictionary.
stream_dict = ta.arcs_to_stream_dict(
m,
additional={
"BFW": m.fs.econ.side_1_inlet,
"ECON_OUT": m.fs.econ.side_1_outlet,
"FG_2_ECON": m.fs.econ.side_2_inlet,
"FG_2_AIRPH": m.fs.econ.side_2_outlet,
},
sort=True,
)
# The next function converts the stream dictionary into a dictionary of state block representing the
# streams at a given time point. In this case, we have a steady state model, so we only have one
# time point (0).
state_dict = ta.stream_states_dict(stream_dict, time_point=0)
# The 'tag_state_quantities()' function below iterates through the state block dictionary and
# creates tags for the listed attributes by combining the state block label with the attribute label
# in the labels argument. For example, pressure in the S001 state block would get the tag 'S001_P'.
recon_tags = ta.tag_state_quantities(
blocks=state_dict,
attributes=(
"flow_mass",
"flow_mol",
"enth_mol",
"temperature",
"pressure",
("flow_mol_comp", "O2"),
("flow_mol_comp", "NO"),
("flow_mol_comp", "N2"),
("flow_mol_comp", "SO2"),
("flow_mol_comp", "CO2"),
("flow_mol_comp", "H2O"),
),
labels=("_Fm", "_F", "_h", "_T", "_P", "_F[O2]", "_F[NO]", "_F[N2]", "_F[SO2]", "_F[CO2]", "_F[H2O]"),
)
# Any addtional tags can be added. This is required for tags that cannot be systematically generated
# from the model streams.
recon_tags["ECON_Q"] = m.fs.econ.heat_duty[0]
5. View model flowsheet¶
Model results or other quantities can be added to a process flow diagram. The PFD was drawn beforehand and the model results are added to tagged locations on the PFD.
from idaes.core.util.misc import svg_tag # utility to place numbers/text in an SVG
with open("econ.svg", "r") as f:
s = svg_tag(svg=f, tags={"subtitle":"Initialized Model"})
s = svg_tag(svg=s, tags=recon_tags, outfile="econ_init.svg")
from IPython.display import SVG, display
display(SVG(s))
6. Write Objective¶
Next we write the objective function and additional constraints for the data reconciliation problem. The objective is
$$\min \sum_i \left(\frac{x_{\text{data}, i} - x_{\text{model}, i}}{\sigma_i} \right)^2$$Where $i \in \{\text{Measured Quantities}\}$ and $\sigma_i$ is the standard deviation of measurement i. In this case, for lack of better information, the standard deviation was estimated by binning the data and calculating the standard deviation of each measured variable in each bin.
# Add model parameters to contain measured data. These are mutable so we can set a specific data point later.
m.data = pyo.Param(data_tags, mutable=True, doc="Process data for a specific point in time.")
m.data_stdev = pyo.Param(data_tags, mutable=True, doc="Process data standard deviation.")
# The 'set_data' function below takes data from the process data DataFrame and updates the
# data parameters in the model.
def set_data(m, df, data_tags, index=None, indexindex=None):
if index is None:
index = df.index[indexindex]
m.bin_no = df.iloc[index]["bin_no"]
for t in data_tags:
m.data[t] = df.iloc[index][t]
m.data_stdev[t] = bin_stdev[m.bin_no][t]
# So we have something reasonable to start, set the data attached to the model to the first
# data point.
set_data(m, df, data_tags, indexindex=0)
Add an expression for error divided by the standard deviation, and use it to write the data reconciliation objective function.
@m.Expression(data_tags)
def err(m, i):
return (m.data[i] - data_tags[i])/m.data_stdev[i]
m.objective = pyo.Objective(expr=sum(m.err[t]**2 for t in m.err))
Add constraints that ensure reasonable temperature and keep the flue gas composition correct.
# Limit temperature approach
m.c1 = pyo.Constraint(expr=m.fs.econ.deltaT_1[0] >= 1.0)
m.c2 = pyo.Constraint(expr=m.fs.econ.deltaT_2[0] >= 1.0)
# Constrain flue gas composition
m.flow_fg = pyo.Var(initialize=fg_rate)
@m.Constraint(fg_comp)
def eq_fg_comp(b, c):
return m.fs.econ.side_2.properties_in[0].flow_mol_comp[c] == fg_comp[c]*m.flow_fg
7. Solve Optimization¶
Now we need to solve the data reconciliation problem for every data point. The important results are stored in two DataFrames df_result
, which contains results tagged based on model stream names to be used in the parameter estimation step and df_result_cmp
which contains reconciled data based on the original measurement tags and can be used to compare the original measurements to the reconciled results.
# Make sure the inlet and outlet ports are unfixed. We want to leave these free
# to best match the data.
m.fs.econ.side_1_inlet.unfix()
m.fs.econ.side_2_inlet.unfix()
m.fs.econ.side_1_outlet.unfix()
m.fs.econ.side_2_outlet.unfix()
# Create a Pyomo solver object
solver = pyo.SolverFactory('ipopt')
import pandas as pd
# Add bin information to reconciliation results so it can be used in parameter estimation
df_result = pd.DataFrame(columns=list(recon_tags.keys())+["termination", "bin_no", "bin_power"], index=df.index)
df_result_cmp = pd.DataFrame(columns=list(data_tags.keys())+["termination"], index=df.index)
# Loop through each data point and solve the data reconciliation problem.
for i in df.index:
set_data(m, df, data_tags, index=i)
res = solver.solve(m)
tc = str(res.solver.termination_condition)
df_result.iloc[i]["termination"] = tc
df_result.iloc[i]["bin_no"] = df.iloc[i]["bin_no"]
df_result.iloc[i]["bin_power"] = df.iloc[i]["bin_power"]
df_result_cmp.iloc[i]["termination"] = tc
for t in recon_tags:
df_result.iloc[i][t] = pyo.value(recon_tags[t])
for t in data_tags:
df_result_cmp.iloc[i][t] = pyo.value(data_tags[t])
# Show something so you can tell progress is happening
print(f"{i} -- {tc}, objective: {pyo.value(m.objective)}")
0 -- optimal, objective: 3.162222726747968 1 -- optimal, objective: 0.8197881545980185 2 -- optimal, objective: 1.470496175685844 3 -- optimal, objective: 1.1898689454668425 4 -- optimal, objective: 6.266875727768326 5 -- optimal, objective: 2.3538250377171823 6 -- optimal, objective: 0.5232313790289039 7 -- optimal, objective: 1.0234536307430704 8 -- optimal, objective: 1.6923868337123018 9 -- optimal, objective: 5.200209442856769 10 -- optimal, objective: 2.0256916107502394 11 -- optimal, objective: 1.375510820858698 12 -- optimal, objective: 1.804019216610838 13 -- optimal, objective: 1.08206173535119 14 -- optimal, objective: 2.8725608654848287 15 -- optimal, objective: 4.679395550949055 16 -- optimal, objective: 2.5285609881579614 17 -- optimal, objective: 3.4190895194024344 18 -- optimal, objective: 0.6733418552017972 19 -- optimal, objective: 1.3191361601576488 20 -- optimal, objective: 2.5910945384684085 21 -- optimal, objective: 0.728491791618817 22 -- optimal, objective: 3.096119847075016 23 -- optimal, objective: 8.046910612157816 24 -- optimal, objective: 9.43446787232504 25 -- optimal, objective: 2.9086993281997673 26 -- optimal, objective: 5.764857210566854 27 -- optimal, objective: 1.58699153385346 28 -- optimal, objective: 0.9849808635599673 29 -- optimal, objective: 5.4207155824345215 30 -- optimal, objective: 0.1606656770535343 31 -- optimal, objective: 1.9662708564310243 32 -- optimal, objective: 4.631964135793516 33 -- optimal, objective: 0.7898364826193093 34 -- optimal, objective: 4.935317631382524 35 -- optimal, objective: 2.78225472151281 36 -- optimal, objective: 3.793558504591668 37 -- optimal, objective: 7.39972780941562 38 -- optimal, objective: 1.8234865166601 39 -- optimal, objective: 8.123224199179202 40 -- optimal, objective: 2.46697459120451 41 -- optimal, objective: 2.0590147535300045 42 -- optimal, objective: 4.824860326020504 43 -- optimal, objective: 2.905357196069195 44 -- optimal, objective: 1.257333338473369 45 -- optimal, objective: 2.76265486871704 46 -- optimal, objective: 3.9105621874505854 47 -- optimal, objective: 0.3638511438811604 48 -- optimal, objective: 6.482070751314464 49 -- optimal, objective: 0.8862863572808333 50 -- optimal, objective: 0.3533327138629876 51 -- optimal, objective: 0.6741788395561827 52 -- optimal, objective: 1.446565966022411 53 -- optimal, objective: 2.365712477678524 54 -- optimal, objective: 1.4293043476045446 55 -- optimal, objective: 11.608878616087884 56 -- optimal, objective: 2.584558521815561 57 -- optimal, objective: 2.228038588968418 58 -- optimal, objective: 2.495375700856382 59 -- optimal, objective: 1.6473059536498238 60 -- optimal, objective: 8.024782999051054 61 -- optimal, objective: 5.943571679649568 62 -- optimal, objective: 2.335802980807593 63 -- optimal, objective: 4.385136256674274 64 -- optimal, objective: 0.5607930691618319 65 -- optimal, objective: 2.1768732856568835 66 -- optimal, objective: 2.823315149731952 67 -- optimal, objective: 4.396913088762367 68 -- optimal, objective: 3.3918328175085604 69 -- optimal, objective: 0.6148676050770127 70 -- optimal, objective: 0.3708290390409603 71 -- optimal, objective: 0.8762486395431996 72 -- optimal, objective: 3.008624266411604 73 -- optimal, objective: 6.178298889668614 74 -- optimal, objective: 2.4515810478691464 75 -- optimal, objective: 8.974784736396623 76 -- optimal, objective: 1.770689575521973 77 -- optimal, objective: 3.126540074941558 78 -- optimal, objective: 5.205287002120055 79 -- optimal, objective: 4.769621582501587 80 -- optimal, objective: 4.816642172570766 81 -- optimal, objective: 0.6532741094173582 82 -- optimal, objective: 2.4965287219127754 83 -- optimal, objective: 0.8032383968120292 84 -- optimal, objective: 0.3628374751580951 85 -- optimal, objective: 1.5238425496864934 86 -- optimal, objective: 3.8657617083925864 87 -- optimal, objective: 1.7222675119803528 88 -- optimal, objective: 3.953872372963456 89 -- optimal, objective: 1.6523626343497047 90 -- optimal, objective: 3.3511000648603217 91 -- optimal, objective: 1.2094028270637631 92 -- optimal, objective: 1.5787041255816434 93 -- optimal, objective: 3.4104171739555547 94 -- optimal, objective: 1.2638821516690988 95 -- optimal, objective: 3.295021190107257 96 -- optimal, objective: 1.5307192842206216 97 -- optimal, objective: 2.0576184713663865 98 -- optimal, objective: 1.7332046587097525 99 -- optimal, objective: 4.588279548069923 100 -- optimal, objective: 0.9295043769734126 101 -- optimal, objective: 1.1035467025832209 102 -- optimal, objective: 0.005403092725190978 103 -- optimal, objective: 4.030370198029115 104 -- optimal, objective: 2.5977866074242697 105 -- optimal, objective: 3.7186375390922226 106 -- optimal, objective: 2.220008221990124 107 -- optimal, objective: 1.7361606413580666 108 -- optimal, objective: 1.7827907915253882 109 -- optimal, objective: 0.8012179144633669 110 -- optimal, objective: 0.48908220135822317 111 -- optimal, objective: 4.625444642904321 112 -- optimal, objective: 4.073061803308539 113 -- optimal, objective: 4.984149658953359 114 -- optimal, objective: 4.500903765842314 115 -- optimal, objective: 0.8012381845209081 116 -- optimal, objective: 2.6875543787764764 117 -- optimal, objective: 6.864920838087304 118 -- optimal, objective: 3.037552232197139 119 -- optimal, objective: 2.4940980097073764 120 -- optimal, objective: 0.46083201829371145 121 -- optimal, objective: 0.04447225222365011 122 -- optimal, objective: 1.909211032156085 123 -- optimal, objective: 4.153938460441966 124 -- optimal, objective: 5.635804261323822 125 -- optimal, objective: 4.7223994896017265 126 -- optimal, objective: 4.838394177659147 127 -- optimal, objective: 2.8953995802787063 128 -- optimal, objective: 0.1700728987512572 129 -- optimal, objective: 0.9837915670309542 130 -- optimal, objective: 8.052258242765056 131 -- optimal, objective: 6.2603162943050155 132 -- optimal, objective: 2.572598330268942 133 -- optimal, objective: 3.7332013380678513 134 -- optimal, objective: 0.3400624609820808 135 -- optimal, objective: 3.603316160959041 136 -- optimal, objective: 2.501573096808961 137 -- optimal, objective: 0.39640424029669047 138 -- optimal, objective: 0.141403509224551 139 -- optimal, objective: 8.317311777960114 140 -- optimal, objective: 5.4244312679188464 141 -- optimal, objective: 2.83574216867205 142 -- optimal, objective: 1.5376013961506176 143 -- optimal, objective: 3.624196357700736 144 -- optimal, objective: 4.9547036262952275 145 -- optimal, objective: 0.5851595630069605 146 -- optimal, objective: 4.899572525361231 147 -- optimal, objective: 3.6822688057452084 148 -- optimal, objective: 2.1210898431019656 149 -- optimal, objective: 1.7199795815280758 150 -- optimal, objective: 3.3189125042286505 151 -- optimal, objective: 0.3685078573134288 152 -- optimal, objective: 1.9488329531202053 153 -- optimal, objective: 2.6747680809658476 154 -- optimal, objective: 7.585698103492058 155 -- optimal, objective: 3.3957385948343433 156 -- optimal, objective: 4.149632062900599 157 -- optimal, objective: 1.000138751954143 158 -- optimal, objective: 3.064483211734674 159 -- optimal, objective: 5.014021556677024 160 -- optimal, objective: 3.839818906127815 161 -- optimal, objective: 1.6576893499093415 162 -- optimal, objective: 0.41176973979165993 163 -- optimal, objective: 2.040678862860498 164 -- optimal, objective: 2.0029963443118493 165 -- optimal, objective: 2.5115043865189794 166 -- optimal, objective: 0.48257710490008476 167 -- optimal, objective: 3.8889325125122527 168 -- optimal, objective: 1.0769714540478792 169 -- optimal, objective: 2.4991940991342885 170 -- optimal, objective: 1.845218524340827 171 -- optimal, objective: 4.516275744333873 172 -- optimal, objective: 3.7259845773037887 173 -- optimal, objective: 1.9205831842368353 174 -- optimal, objective: 1.6040433482387257 175 -- optimal, objective: 0.329705992116415 176 -- optimal, objective: 3.177329255930121 177 -- optimal, objective: 4.892212873755818 178 -- optimal, objective: 1.7344211785701278 179 -- optimal, objective: 2.0930113767061425 180 -- optimal, objective: 1.9821944087033758 181 -- optimal, objective: 3.095063944359873 182 -- optimal, objective: 2.562516534216427 183 -- optimal, objective: 6.46989153194382 184 -- optimal, objective: 2.067460638680131 185 -- optimal, objective: 2.3845354622360735 186 -- optimal, objective: 1.5119923998654472 187 -- optimal, objective: 3.6254181568253823 188 -- optimal, objective: 0.9836625253930571 189 -- optimal, objective: 1.9174184223605648 190 -- optimal, objective: 1.0199853616407706 191 -- optimal, objective: 1.8111192038560597 192 -- optimal, objective: 10.407061899281672 193 -- optimal, objective: 5.7252437839675965 194 -- optimal, objective: 6.585188554630548 195 -- optimal, objective: 1.1404034774870133 196 -- optimal, objective: 4.636485739510397 197 -- optimal, objective: 3.921803798658291 198 -- optimal, objective: 1.0045607379024837 199 -- optimal, objective: 2.418194887917503 200 -- optimal, objective: 2.924381439171275 201 -- optimal, objective: 2.968995475733562 202 -- optimal, objective: 2.61528929652863 203 -- optimal, objective: 2.4914182112444854 204 -- optimal, objective: 1.7943475851127995 205 -- optimal, objective: 5.708324626596885 206 -- optimal, objective: 2.405605529769485 207 -- optimal, objective: 0.9383166249962259 208 -- optimal, objective: 4.796686075011132 209 -- optimal, objective: 0.5067752382993186 210 -- optimal, objective: 2.1890706012206813 211 -- optimal, objective: 3.2162721207001193 212 -- optimal, objective: 0.07970309825956173 213 -- optimal, objective: 0.39071980305707377 214 -- optimal, objective: 4.02397171505367 215 -- optimal, objective: 3.5942477203080117 216 -- optimal, objective: 1.6777755212887788 217 -- optimal, objective: 4.848035154404844 218 -- optimal, objective: 0.48854638442716647 219 -- optimal, objective: 12.374531482863102 220 -- optimal, objective: 1.4283906796283696 221 -- optimal, objective: 1.8180474372486768 222 -- optimal, objective: 0.48501814714993935 223 -- optimal, objective: 2.5067704521200924 224 -- optimal, objective: 1.3976831205728764 225 -- optimal, objective: 0.9031827797633734 226 -- optimal, objective: 0.72855979869843 227 -- optimal, objective: 2.470420726707512 228 -- optimal, objective: 2.6750989066859323 229 -- optimal, objective: 3.3257056456052108 230 -- optimal, objective: 2.599052712779955 231 -- optimal, objective: 4.837619200685889 232 -- optimal, objective: 1.132937434663585 233 -- optimal, objective: 1.6398640882825928 234 -- optimal, objective: 3.0089508719252733 235 -- optimal, objective: 1.4124059496646542 236 -- optimal, objective: 5.7719654075990094 237 -- optimal, objective: 0.1493818927224376 238 -- optimal, objective: 1.2057413172019444 239 -- optimal, objective: 1.7168330910787672 240 -- optimal, objective: 4.602205543920195 241 -- optimal, objective: 2.123645709357305 242 -- optimal, objective: 2.5316135514752443 243 -- optimal, objective: 1.7031605794315978 244 -- optimal, objective: 2.2177892333102287 245 -- optimal, objective: 0.6465633467363466 246 -- optimal, objective: 1.2916378800472939 247 -- optimal, objective: 7.790239583323649 248 -- optimal, objective: 1.0605735856125913 249 -- optimal, objective: 1.1514839068115028
# Save the reconciled data to be used for parameter estimation
df_result.to_csv("econ_recon.csv")
try:
# Create a new plot book to compare the original data to the reconciled data.
da.data_rec_plot_book(
df_data=df,
df_rec=df_result_cmp,
file="econ_data_rec_plot_book.pdf",
bin_nom="bin_power",
xlabel="gross power (W)",
metadata=df_meta
)
except:
print("Plotting failed")
Plotting data requires the 'seaborn' and 'PyPDF2' packages. Install the required packages before using the data_book() function. Plot terminated.