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-09-02 15:58:15 [INFO] idaes.init.fs.econ.side_1: Initialization Complete 2021-09-02 15:58:15 [INFO] idaes.init.fs.econ.side_2.properties_in: Initialisation Complete, optimal - Optimal Solution Found. 2021-09-02 15:58:16 [INFO] idaes.init.fs.econ.side_2.properties_out: Initialisation Complete, optimal - Optimal Solution Found. 2021-09-02 15:58:16 [INFO] idaes.init.fs.econ.side_2.properties_out: fs.econ.side_2.properties_out State Released. 2021-09-02 15:58:16 [INFO] idaes.init.fs.econ.side_2: Initialization Complete 2021-09-02 15:58:16 [INFO] idaes.init.fs.econ: fs.econ Initialisation Step 1 Complete. 2021-09-02 15:58:16 [INFO] idaes.init.fs.econ.side_2.properties_in: fs.econ.side_2.properties_in State Released. 2021-09-02 15:58:16 [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()
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.1622227267477236 1 -- optimal, objective: 0.8197881540804665 2 -- optimal, objective: 1.4704961756860009 3 -- optimal, objective: 1.1898683973939073 4 -- optimal, objective: 6.266875727768015 5 -- optimal, objective: 2.353825037717043 6 -- optimal, objective: 0.5232293871180911 7 -- optimal, objective: 1.0234536307431457 8 -- optimal, objective: 1.6923868337124404 9 -- optimal, objective: 5.2001791228894945 10 -- optimal, objective: 2.0256916107501506 11 -- optimal, objective: 1.3755108208586757 12 -- optimal, objective: 1.8040192166107314 13 -- optimal, objective: 1.0820617353510786 14 -- optimal, objective: 2.872560865484746 15 -- optimal, objective: 4.679395550949352 16 -- optimal, objective: 2.5285609881579645 17 -- optimal, objective: 3.419089519402572 18 -- optimal, objective: 0.673341855201661 19 -- optimal, objective: 1.3191361601576406 20 -- optimal, objective: 2.591094538468207 21 -- optimal, objective: 0.7284917916188187 22 -- optimal, objective: 3.0961198470749545 23 -- optimal, objective: 8.046910612157626 24 -- optimal, objective: 9.43446787232482 25 -- optimal, objective: 2.90869932819942 26 -- optimal, objective: 5.764857210566872 27 -- optimal, objective: 1.5869915338535017 28 -- optimal, objective: 0.9849808635599643 29 -- optimal, objective: 5.420715582434442 30 -- optimal, objective: 0.15987321041189692 31 -- optimal, objective: 1.9662708564310052 32 -- optimal, objective: 4.631964135793527 33 -- optimal, objective: 0.7898364826192953 34 -- optimal, objective: 4.935317631382527 35 -- optimal, objective: 2.782254721512846 36 -- optimal, objective: 3.793558504591789 37 -- optimal, objective: 7.399727809415612 38 -- optimal, objective: 1.8234865166600738 39 -- optimal, objective: 8.123224199178962 40 -- optimal, objective: 2.4669745912045187 41 -- optimal, objective: 2.0590147462740016 42 -- optimal, objective: 4.824860326020595 43 -- optimal, objective: 2.9053571960692355 44 -- optimal, objective: 1.2573333384737084 45 -- optimal, objective: 2.7626548687168437 46 -- optimal, objective: 3.9105621874505987 47 -- optimal, objective: 0.36385114388096135 48 -- optimal, objective: 6.48207075131405 49 -- optimal, objective: 0.8862863572807927 50 -- optimal, objective: 0.35333271386302767 51 -- optimal, objective: 0.6741788395561905 52 -- optimal, objective: 1.4465659660224153 53 -- optimal, objective: 2.365712477678529 54 -- optimal, objective: 1.4293043476046117 55 -- optimal, objective: 11.608878616087802 56 -- optimal, objective: 2.58455852181556 57 -- optimal, objective: 2.228038588968435 58 -- optimal, objective: 2.495375700856505 59 -- optimal, objective: 1.6473059536498185 60 -- optimal, objective: 8.024782999051263 61 -- optimal, objective: 5.943571679649429 62 -- optimal, objective: 2.3358029808076184 63 -- optimal, objective: 4.385136256674179 64 -- optimal, objective: 0.5607930691618417 65 -- optimal, objective: 2.1768732856567903 66 -- optimal, objective: 2.8233151497317923 67 -- optimal, objective: 4.396913088762424 68 -- optimal, objective: 3.391832817508344 69 -- optimal, objective: 0.6148676050767218 70 -- optimal, objective: 0.3708290390409646 71 -- optimal, objective: 0.8762486395429888 72 -- optimal, objective: 3.0086242664115774 73 -- optimal, objective: 6.178298889668418 74 -- optimal, objective: 2.4515810478692264 75 -- optimal, objective: 8.97478473639633 76 -- optimal, objective: 1.7706895755220056 77 -- optimal, objective: 3.1265400749414534 78 -- optimal, objective: 5.203571840723421 79 -- optimal, objective: 4.769621582501686 80 -- optimal, objective: 4.816642172570757 81 -- optimal, objective: 0.653274109417307 82 -- optimal, objective: 2.4965287219119565 83 -- optimal, objective: 0.8032383968120483 84 -- optimal, objective: 0.3628374751580809 85 -- optimal, objective: 1.523842549686509 86 -- optimal, objective: 3.8657617083927285 87 -- optimal, objective: 1.7222675119802968 88 -- optimal, objective: 3.9538723729634717 89 -- optimal, objective: 1.65236263434971 90 -- optimal, objective: 3.351100064860052 91 -- optimal, objective: 1.2094028270637767 92 -- optimal, objective: 1.5787041255816414 93 -- optimal, objective: 3.4104171739555014 94 -- optimal, objective: 1.2638821516691674 95 -- optimal, objective: 3.295021190107275 96 -- optimal, objective: 1.5307192842207231 97 -- optimal, objective: 2.0576184713664 98 -- optimal, objective: 1.7332046587097982 99 -- optimal, objective: 4.58827941036682 100 -- optimal, objective: 0.9293015277967474 101 -- optimal, objective: 1.1035467025831935 102 -- optimal, objective: 0.005403092725190185 103 -- optimal, objective: 4.030370198029041 104 -- optimal, objective: 2.5977866074240206 105 -- optimal, objective: 3.7186375390924087 106 -- optimal, objective: 2.2200082219901534 107 -- optimal, objective: 1.736160641358132 108 -- optimal, objective: 1.7827907915253507 109 -- optimal, objective: 0.8012179144633598 110 -- optimal, objective: 0.48908220135812036 111 -- optimal, objective: 4.625444642903938 112 -- optimal, objective: 4.07306180330844 113 -- optimal, objective: 4.984149658953242 114 -- optimal, objective: 4.500903765842288 115 -- optimal, objective: 0.8012381845209076 116 -- optimal, objective: 2.687554378776392 117 -- optimal, objective: 6.864920838087276 118 -- optimal, objective: 3.0375522321897814 119 -- optimal, objective: 2.4940980097073884 120 -- optimal, objective: 0.46083201829370657 121 -- optimal, objective: 0.04447225222365364 122 -- optimal, objective: 1.9092110321559406 123 -- optimal, objective: 4.153938460441821 124 -- optimal, objective: 5.635804261323757 125 -- optimal, objective: 4.722399489601871 126 -- optimal, objective: 4.837813299841362 127 -- optimal, objective: 2.8953995802785957 128 -- optimal, objective: 0.17007289875026932 129 -- optimal, objective: 0.983791567030946 130 -- optimal, objective: 8.052254099295862 131 -- optimal, objective: 6.2603162943051345 132 -- optimal, objective: 2.572598330268635 133 -- optimal, objective: 3.733201338067713 134 -- optimal, objective: 0.3400624609820915 135 -- optimal, objective: 3.6033161609589324 136 -- optimal, objective: 2.5015730968089547 137 -- optimal, objective: 0.39640424029665267 138 -- optimal, objective: 0.141403509224298 139 -- optimal, objective: 8.31731177795957 140 -- optimal, objective: 5.4244312679188464 141 -- optimal, objective: 2.835742168672142 142 -- optimal, objective: 1.5376013961506825 143 -- optimal, objective: 3.624196357700532 144 -- optimal, objective: 4.954703626295084 145 -- optimal, objective: 0.585159563006968 146 -- optimal, objective: 4.8995725253608935 147 -- optimal, objective: 3.6822688057449238 148 -- optimal, objective: 2.1210898431019127 149 -- optimal, objective: 1.7199795815279169 150 -- optimal, objective: 3.318912504228596 151 -- optimal, objective: 0.36850785731333546 152 -- optimal, objective: 1.9488329531202324 153 -- optimal, objective: 2.674768080965982 154 -- optimal, objective: 7.5856981034922 155 -- optimal, objective: 3.395738594834346 156 -- optimal, objective: 4.149632062900452 157 -- optimal, objective: 1.000138751954185 158 -- optimal, objective: 3.064483211734531 159 -- optimal, objective: 5.0140215566768225 160 -- optimal, objective: 3.83981890612392 161 -- optimal, objective: 1.657689349909335 162 -- optimal, objective: 0.41176973979173737 163 -- optimal, objective: 2.040678862856759 164 -- optimal, objective: 2.0029963443118484 165 -- optimal, objective: 2.511504386519103 166 -- optimal, objective: 0.4825771048999518 167 -- optimal, objective: 3.8889325125121696 168 -- optimal, objective: 1.0769714540447235 169 -- optimal, objective: 2.499194099134276 170 -- optimal, objective: 1.8452022889718802 171 -- optimal, objective: 4.5162757443335515 172 -- optimal, objective: 3.725984577303651 173 -- optimal, objective: 1.9205831842368086 174 -- optimal, objective: 1.6040433482387828 175 -- optimal, objective: 0.3297059921164121 176 -- optimal, objective: 3.17732925593057 177 -- optimal, objective: 4.892212873755828 178 -- optimal, objective: 1.7344211222125767 179 -- optimal, objective: 2.0930113767062535 180 -- optimal, objective: 1.982194408703398 181 -- optimal, objective: 3.095063944360138 182 -- optimal, objective: 2.5625165342165928 183 -- optimal, objective: 6.469891429283564 184 -- optimal, objective: 2.0674606386801786 185 -- optimal, objective: 2.3845354622360593 186 -- optimal, objective: 1.511992388747981 187 -- optimal, objective: 3.625418156825077 188 -- optimal, objective: 0.9836625190091582 189 -- optimal, objective: 1.9174184223605604 190 -- optimal, objective: 1.0199853616407286 191 -- optimal, objective: 1.8111192038560244 192 -- optimal, objective: 10.407061899274446 193 -- optimal, objective: 5.725243783932939 194 -- optimal, objective: 6.5851885546307 195 -- optimal, objective: 1.1404034774868907 196 -- optimal, objective: 4.63648573951036 197 -- optimal, objective: 3.921803798658364 198 -- optimal, objective: 1.004560737902494 199 -- optimal, objective: 2.418194887917387 200 -- optimal, objective: 2.924381439171225 201 -- optimal, objective: 2.968995475733458 202 -- optimal, objective: 2.615289296528611 203 -- optimal, objective: 2.4914182112444974 204 -- optimal, objective: 1.7943475851127992 205 -- optimal, objective: 5.7083246265968395 206 -- optimal, objective: 2.4056055297694683 207 -- optimal, objective: 0.9383160093488742 208 -- optimal, objective: 4.796686075011124 209 -- optimal, objective: 0.5067752382992995 210 -- optimal, objective: 2.189070601163973 211 -- optimal, objective: 3.2162721207000833 212 -- optimal, objective: 0.0797030982595503 213 -- optimal, objective: 0.39071980305706655 214 -- optimal, objective: 4.02397171505382 215 -- optimal, objective: 3.594247720308196 216 -- optimal, objective: 1.6777755011210225 217 -- optimal, objective: 4.848035154404865 218 -- optimal, objective: 0.48854638442723286 219 -- optimal, objective: 12.374531482863176 220 -- optimal, objective: 1.428390679628554 221 -- optimal, objective: 1.8180474372486606 222 -- optimal, objective: 0.4850181471500386 223 -- optimal, objective: 2.506770452120046 224 -- optimal, objective: 1.3976831205728917 225 -- optimal, objective: 0.9031827797634286 226 -- optimal, objective: 0.7285597986984917 227 -- optimal, objective: 2.4704207267075544 228 -- optimal, objective: 2.6750989066858013 229 -- optimal, objective: 3.3257056456053364 230 -- optimal, objective: 2.599052712780132 231 -- optimal, objective: 4.837619200685974 232 -- optimal, objective: 1.1329374346636611 233 -- optimal, objective: 1.6398640882824427 234 -- optimal, objective: 3.0089508719252076 235 -- optimal, objective: 1.4124059496646608 236 -- optimal, objective: 5.7719654075989295 237 -- optimal, objective: 0.14938189272240587 238 -- optimal, objective: 1.2057413172016875 239 -- optimal, objective: 1.7168330910787664 240 -- optimal, objective: 4.602205543920224 241 -- optimal, objective: 2.123631117523288 242 -- optimal, objective: 2.531613551475251 243 -- optimal, objective: 1.7031605794317395 244 -- optimal, objective: 2.2177892333102562 245 -- optimal, objective: 0.6465633467363429 246 -- optimal, objective: 1.291637880047304 247 -- optimal, objective: 7.789851988626017 248 -- optimal, objective: 1.0605735856125036 249 -- optimal, objective: 1.151469126514051
# 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.