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-08-25 20:10:18 [INFO] idaes.init.fs.econ.side_1: Initialization Complete 2021-08-25 20:10:18 [INFO] idaes.init.fs.econ.side_2.properties_in: Initialisation Complete, optimal - Optimal Solution Found. 2021-08-25 20:10:18 [INFO] idaes.init.fs.econ.side_2.properties_out: Initialisation Complete, optimal - Optimal Solution Found. 2021-08-25 20:10:18 [INFO] idaes.init.fs.econ.side_2.properties_out: fs.econ.side_2.properties_out State Released. 2021-08-25 20:10:18 [INFO] idaes.init.fs.econ.side_2: Initialization Complete 2021-08-25 20:10:18 [INFO] idaes.init.fs.econ: fs.econ Initialisation Step 1 Complete. 2021-08-25 20:10:18 [INFO] idaes.init.fs.econ.side_2.properties_in: fs.econ.side_2.properties_in State Released. 2021-08-25 20:10:18 [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.162222726747723 1 -- optimal, objective: 0.8197881540804663 2 -- optimal, objective: 1.4704961756860007 3 -- optimal, objective: 1.189868397393907 4 -- optimal, objective: 6.2668757277680145 5 -- optimal, objective: 2.353825037717043 6 -- optimal, objective: 0.5232293871180911 7 -- optimal, objective: 1.0234536307431459 8 -- optimal, objective: 1.6923868337124404 9 -- optimal, objective: 5.2001791228894945 10 -- optimal, objective: 2.02569161075015 11 -- optimal, objective: 1.3755108208586757 12 -- optimal, objective: 1.8040192166107316 13 -- optimal, objective: 1.0820617353510784 14 -- optimal, objective: 2.8725608654847457 15 -- optimal, objective: 4.679395550949352 16 -- optimal, objective: 2.528560988157964 17 -- optimal, objective: 3.419089519402572 18 -- optimal, objective: 0.6733418552016611 19 -- optimal, objective: 1.3191361601576406 20 -- optimal, objective: 2.5910945384682056 21 -- optimal, objective: 0.7284917916188188 22 -- optimal, objective: 3.096119847074955 23 -- optimal, objective: 8.046910612157625 24 -- optimal, objective: 9.43446787232482 25 -- optimal, objective: 2.9086993281994196 26 -- optimal, objective: 5.764857210566871 27 -- optimal, objective: 1.5869915338535017 28 -- optimal, objective: 0.9849808635599643 29 -- optimal, objective: 5.420715582434443 30 -- optimal, objective: 0.1598732104118969 31 -- optimal, objective: 1.9662708564310052 32 -- optimal, objective: 4.631964135793527 33 -- optimal, objective: 0.7898364826192952 34 -- optimal, objective: 4.935317631382528 35 -- optimal, objective: 2.782254721512846 36 -- optimal, objective: 3.7935585045917892 37 -- optimal, objective: 7.3997278094156105 38 -- optimal, objective: 1.8234865166600738 39 -- optimal, objective: 8.12322419917896 40 -- optimal, objective: 2.4669745912045187 41 -- optimal, objective: 2.059014746274002 42 -- optimal, objective: 4.824860326020595 43 -- optimal, objective: 2.905357196069236 44 -- optimal, objective: 1.2573333384737082 45 -- optimal, objective: 2.762654868716844 46 -- optimal, objective: 3.9105621874505982 47 -- optimal, objective: 0.3638511438809614 48 -- optimal, objective: 6.482070751314051 49 -- optimal, objective: 0.8862863572807927 50 -- optimal, objective: 0.3533327138630277 51 -- optimal, objective: 0.6741788395561906 52 -- optimal, objective: 1.4465659660224157 53 -- optimal, objective: 2.3657124776785285 54 -- optimal, objective: 1.4293043476046114 55 -- optimal, objective: 11.608878616087802 56 -- optimal, objective: 2.5845585218155596 57 -- optimal, objective: 2.228038588968436 58 -- optimal, objective: 2.4953757008565054 59 -- optimal, objective: 1.6473059536498185 60 -- optimal, objective: 8.024782999051263 61 -- optimal, objective: 5.943571679649429 62 -- optimal, objective: 2.335802980807619 63 -- optimal, objective: 4.385136256674179 64 -- optimal, objective: 0.5607930691618417 65 -- optimal, objective: 2.1768732856567903 66 -- optimal, objective: 2.823315149731792 67 -- optimal, objective: 4.396913088762425 68 -- optimal, objective: 3.391832817508344 69 -- optimal, objective: 0.6148676050767216 70 -- optimal, objective: 0.37082903904096465 71 -- optimal, objective: 0.8762486395429889 72 -- optimal, objective: 3.0086242664115765 73 -- optimal, objective: 6.178298889668418 74 -- optimal, objective: 2.4515810478692264 75 -- optimal, objective: 8.97478473639633 76 -- optimal, objective: 1.7706895755220058 77 -- optimal, objective: 3.1265400749414534 78 -- optimal, objective: 5.203571840723419 79 -- optimal, objective: 4.769621582501686 80 -- optimal, objective: 4.816642172570757 81 -- optimal, objective: 0.6532741094173069 82 -- optimal, objective: 2.4965287219119565 83 -- optimal, objective: 0.8032383968120484 84 -- optimal, objective: 0.36283747515808096 85 -- optimal, objective: 1.5238425496865087 86 -- optimal, objective: 3.8657617083927276 87 -- optimal, objective: 1.7222675119802966 88 -- optimal, objective: 3.9538723729634717 89 -- optimal, objective: 1.6523626343497104 90 -- optimal, objective: 3.351100064860053 91 -- optimal, objective: 1.2094028270637767 92 -- optimal, objective: 1.5787041255816414 93 -- optimal, objective: 3.410417173955501 94 -- optimal, objective: 1.2638821516691674 95 -- optimal, objective: 3.2950211901072746 96 -- optimal, objective: 1.5307192842207231 97 -- optimal, objective: 2.057618471366399 98 -- optimal, objective: 1.733204658709798 99 -- optimal, objective: 4.58827941036682 100 -- optimal, objective: 0.9293015277967475 101 -- optimal, objective: 1.1035467025831933 102 -- optimal, objective: 0.005403092725190185 103 -- optimal, objective: 4.030370198029042 104 -- optimal, objective: 2.5977866074240206 105 -- optimal, objective: 3.718637539092409 106 -- optimal, objective: 2.2200082219901534 107 -- optimal, objective: 1.7361606413581323 108 -- optimal, objective: 1.7827907915253505 109 -- optimal, objective: 0.8012179144633597 110 -- optimal, objective: 0.48908220135812036 111 -- optimal, objective: 4.625444642903937 112 -- optimal, objective: 4.073061803308441 113 -- optimal, objective: 4.984149658953241 114 -- optimal, objective: 4.500903765842289 115 -- optimal, objective: 0.8012381845209074 116 -- optimal, objective: 2.687554378776392 117 -- optimal, objective: 6.864920838087275 118 -- optimal, objective: 3.037552232189781 119 -- optimal, objective: 2.494098009707388 120 -- optimal, objective: 0.4608320182937066 121 -- optimal, objective: 0.04447225222365364 122 -- optimal, objective: 1.9092110321559406 123 -- optimal, objective: 4.153938460441821 124 -- optimal, objective: 5.635804261323758 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.05225409929586 131 -- optimal, objective: 6.260316294305136 132 -- optimal, objective: 2.5725983302686344 133 -- optimal, objective: 3.733201338067713 134 -- optimal, objective: 0.3400624609820915 135 -- optimal, objective: 3.603316160958933 136 -- optimal, objective: 2.501573096808955 137 -- optimal, objective: 0.3964042402966527 138 -- optimal, objective: 0.14140350922429804 139 -- optimal, objective: 8.317311777959569 140 -- optimal, objective: 5.424431267918848 141 -- optimal, objective: 2.835742168672142 142 -- optimal, objective: 1.5376013961506827 143 -- optimal, objective: 3.6241963577005314 144 -- optimal, objective: 4.954703626295083 145 -- optimal, objective: 0.5851595630069681 146 -- optimal, objective: 4.899572525360894 147 -- optimal, objective: 3.6822688057449238 148 -- optimal, objective: 2.1210898431019127 149 -- optimal, objective: 1.7199795815279166 150 -- optimal, objective: 3.3189125042285954 151 -- optimal, objective: 0.36850785731333535 152 -- optimal, objective: 1.9488329531202326 153 -- optimal, objective: 2.674768080965982 154 -- optimal, objective: 7.585698103492201 155 -- optimal, objective: 3.395738594834345 156 -- optimal, objective: 4.149632062900453 157 -- optimal, objective: 1.000138751954185 158 -- optimal, objective: 3.0644832117345313 159 -- optimal, objective: 5.014021556676822 160 -- optimal, objective: 3.8398189061239196 161 -- optimal, objective: 1.6576893499093353 162 -- optimal, objective: 0.41176973979173737 163 -- optimal, objective: 2.040678862856759 164 -- optimal, objective: 2.0029963443118484 165 -- optimal, objective: 2.5115043865191033 166 -- optimal, objective: 0.4825771048999518 167 -- optimal, objective: 3.888932512512169 168 -- optimal, objective: 1.0769714540447233 169 -- optimal, objective: 2.4991940991342765 170 -- optimal, objective: 1.8452022889718802 171 -- optimal, objective: 4.5162757443335515 172 -- optimal, objective: 3.7259845773036506 173 -- optimal, objective: 1.920583184236809 174 -- optimal, objective: 1.604043348238783 175 -- optimal, objective: 0.3297059921164121 176 -- optimal, objective: 3.1773292559305704 177 -- optimal, objective: 4.892212873755829 178 -- optimal, objective: 1.734421122212577 179 -- optimal, objective: 2.0930113767062535 180 -- optimal, objective: 1.982194408703398 181 -- optimal, objective: 3.095063944360138 182 -- optimal, objective: 2.5625165342165928 183 -- optimal, objective: 6.469891429283565 184 -- optimal, objective: 2.0674606386801786 185 -- optimal, objective: 2.3845354622360593 186 -- optimal, objective: 1.5119923887479807 187 -- optimal, objective: 3.6254181568250767 188 -- optimal, objective: 0.9836625190091582 189 -- optimal, objective: 1.9174184223605606 190 -- optimal, objective: 1.0199853616407288 191 -- optimal, objective: 1.8111192038560247 192 -- optimal, objective: 10.407061899274446 193 -- optimal, objective: 5.725243783932939 194 -- optimal, objective: 6.585188554630699 195 -- optimal, objective: 1.140403477486891 196 -- optimal, objective: 4.63648573951036 197 -- optimal, objective: 3.921803798658364 198 -- optimal, objective: 1.004560737902494 199 -- optimal, objective: 2.4181948879173865 200 -- optimal, objective: 2.924381439171226 201 -- optimal, objective: 2.968995475733458 202 -- optimal, objective: 2.6152892965286108 203 -- optimal, objective: 2.491418211244498 204 -- optimal, objective: 1.7943475851127995 205 -- optimal, objective: 5.708324626596838 206 -- optimal, objective: 2.4056055297694687 207 -- optimal, objective: 0.9383160093488742 208 -- optimal, objective: 4.796686075011125 209 -- optimal, objective: 0.5067752382992995 210 -- optimal, objective: 2.189070601163973 211 -- optimal, objective: 3.2162721207000837 212 -- optimal, objective: 0.0797030982595503 213 -- optimal, objective: 0.39071980305706655 214 -- optimal, objective: 4.02397171505382 215 -- optimal, objective: 3.5942477203081955 216 -- optimal, objective: 1.6777755011210227 217 -- optimal, objective: 4.848035154404866 218 -- optimal, objective: 0.4885463844272328 219 -- optimal, objective: 12.374531482863175 220 -- optimal, objective: 1.428390679628554 221 -- optimal, objective: 1.8180474372486606 222 -- optimal, objective: 0.4850181471500386 223 -- optimal, objective: 2.5067704521200462 224 -- optimal, objective: 1.3976831205728917 225 -- optimal, objective: 0.9031827797634285 226 -- optimal, objective: 0.7285597986984916 227 -- optimal, objective: 2.4704207267075544 228 -- optimal, objective: 2.6750989066858017 229 -- optimal, objective: 3.3257056456053355 230 -- optimal, objective: 2.599052712780132 231 -- optimal, objective: 4.837619200685972 232 -- optimal, objective: 1.132937434663661 233 -- optimal, objective: 1.6398640882824427 234 -- optimal, objective: 3.008950871925208 235 -- optimal, objective: 1.412405949664661 236 -- optimal, objective: 5.771965407598931 237 -- optimal, objective: 0.14938189272240587 238 -- optimal, objective: 1.205741317201688 239 -- optimal, objective: 1.7168330910787666 240 -- optimal, objective: 4.602205543920224 241 -- optimal, objective: 2.1236311175232885 242 -- optimal, objective: 2.5316135514752514 243 -- optimal, objective: 1.7031605794317393 244 -- optimal, objective: 2.2177892333102567 245 -- optimal, objective: 0.6465633467363427 246 -- optimal, objective: 1.2916378800473038 247 -- optimal, objective: 7.789851988626017 248 -- optimal, objective: 1.0605735856125036 249 -- optimal, objective: 1.1514691265140509
# 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.