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-11-30 19:27:10 [INFO] idaes.init.fs.econ.side_1: Initialization Complete 2021-11-30 19:27:10 [INFO] idaes.init.fs.econ.side_2.properties_in: Initialisation Complete, optimal - Optimal Solution Found. 2021-11-30 19:27:10 [INFO] idaes.init.fs.econ.side_2.properties_out: Initialisation Complete, optimal - Optimal Solution Found. 2021-11-30 19:27:10 [INFO] idaes.init.fs.econ.side_2.properties_out: fs.econ.side_2.properties_out State Released. 2021-11-30 19:27:10 [INFO] idaes.init.fs.econ.side_2: Initialization Complete 2021-11-30 19:27:10 [INFO] idaes.init.fs.econ: fs.econ Initialisation Step 1 Complete. 2021-11-30 19:27:11 [INFO] idaes.init.fs.econ.side_2.properties_in: fs.econ.side_2.properties_in State Released. 2021-11-30 19:27:11 [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")
WARNING: DEPRECATED: idaes.core.util.misc.svg_tag has moved to
idaes.core.util.tags.svg_tag (deprecated in 1.12) (called from
/home/lbianchi/opt/conda/envs/build-idaes-
examples-1.12.0rc0/lib/python3.8/site-
packages/IPython/core/interactiveshell.py:3457)
WARNING: DEPRECATED: DEPRECATED: svg_tag, the tags, tag_format and
tag_format_default arguments are deprecated use tag_group instead.
(deprecated in 1.12) (called from /home/lbianchi/opt/conda/envs/build-
idaes-examples-1.12.0rc0/lib/python3.8/site-
packages/idaes/core/util/misc.py:146)
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.8197881540804663 2 -- optimal, objective: 1.4704961756860007 3 -- optimal, objective: 1.1898683973939073 4 -- optimal, objective: 6.2668757277680145 5 -- optimal, objective: 2.353825037717043 6 -- optimal, objective: 0.5232293871180912 7 -- optimal, objective: 1.0234536307431457 8 -- optimal, objective: 1.6923868337124404 9 -- optimal, objective: 5.200179122889494 10 -- optimal, objective: 2.02569161075015 11 -- optimal, objective: 1.375510820858676 12 -- optimal, objective: 1.8040192166107316 13 -- optimal, objective: 1.0820617353510786 14 -- optimal, objective: 2.872560865484746 15 -- optimal, objective: 4.679395550949352 16 -- optimal, objective: 2.528560988157964 17 -- optimal, objective: 3.4190895194025726 18 -- optimal, objective: 0.6733418552016611 19 -- optimal, objective: 1.3191361601576406 20 -- optimal, objective: 2.591094538468206 21 -- optimal, objective: 0.7284917916188187 22 -- optimal, objective: 3.096119847074954 23 -- optimal, objective: 8.046910612157625 24 -- optimal, objective: 9.43446787232482 25 -- optimal, objective: 2.908699328199419 26 -- optimal, objective: 5.76485721056687 27 -- optimal, objective: 1.5869915338535021 28 -- optimal, objective: 0.9849808635599643 29 -- optimal, objective: 5.420715582434443 30 -- optimal, objective: 0.1598732104118969 31 -- optimal, objective: 1.9662708564310054 32 -- optimal, objective: 4.6319641357935275 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.823486516660074 39 -- optimal, objective: 8.123224199178962 40 -- optimal, objective: 2.4669745912045182 41 -- optimal, objective: 2.0590147462740016 42 -- optimal, objective: 4.824860326020594 43 -- optimal, objective: 2.905357196069236 44 -- optimal, objective: 1.2573333384737084 45 -- optimal, objective: 2.762654868716844 46 -- optimal, objective: 3.910562187450599 47 -- optimal, objective: 0.3638511438809614 48 -- optimal, objective: 6.48207075131405 49 -- optimal, objective: 0.8862863572807926 50 -- optimal, objective: 0.35333271386302767 51 -- optimal, objective: 0.6741788395561904 52 -- optimal, objective: 1.4465659660224155 53 -- optimal, objective: 2.3657124776785285 54 -- optimal, objective: 1.4293043476046114 55 -- optimal, objective: 11.608878616087804 56 -- optimal, objective: 2.58455852181556 57 -- optimal, objective: 2.2280385889684355 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.38513625667418 64 -- optimal, objective: 0.5607930691618418 65 -- optimal, objective: 2.1768732856567903 66 -- optimal, objective: 2.8233151497317914 67 -- optimal, objective: 4.396913088762425 68 -- optimal, objective: 3.3918328175083436 69 -- optimal, objective: 0.6148676050767217 70 -- optimal, objective: 0.3708290390409646 71 -- optimal, objective: 0.8762486395429888 72 -- optimal, objective: 3.0086242664115765 73 -- optimal, objective: 6.178298889668417 74 -- optimal, objective: 2.451581047869226 75 -- optimal, objective: 8.974784736396328 76 -- optimal, objective: 1.7706895755220056 77 -- optimal, objective: 3.1265400749414534 78 -- optimal, objective: 5.203571840723419 79 -- optimal, objective: 4.769621582501687 80 -- optimal, objective: 4.816642172570757 81 -- optimal, objective: 0.6532741094173069 82 -- optimal, objective: 2.496528721911957 83 -- optimal, objective: 0.8032383968120484 84 -- optimal, objective: 0.36283747515808096 85 -- optimal, objective: 1.5238425496865087 86 -- optimal, objective: 3.8657617083927285 87 -- optimal, objective: 1.7222675119802966 88 -- optimal, objective: 3.953872372963472 89 -- optimal, objective: 1.6523626343497102 90 -- optimal, objective: 3.3511000648600526 91 -- optimal, objective: 1.2094028270637769 92 -- optimal, objective: 1.5787041255816416 93 -- optimal, objective: 3.410417173955502 94 -- optimal, objective: 1.2638821516691674 95 -- optimal, objective: 3.295021190107275 96 -- optimal, objective: 1.5307192842207231 97 -- optimal, objective: 2.0576184713664 98 -- optimal, objective: 1.733204658709798 99 -- optimal, objective: 4.5882794103668205 100 -- optimal, objective: 0.9293015277967475 101 -- optimal, objective: 1.1035467025831933 102 -- optimal, objective: 0.005403092725190184 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.8012179144633598 110 -- optimal, objective: 0.4890822013581204 111 -- optimal, objective: 4.625444642903938 112 -- optimal, objective: 4.07306180330844 113 -- optimal, objective: 4.984149658953241 114 -- optimal, objective: 4.500903765842289 115 -- optimal, objective: 0.8012381845209076 116 -- optimal, objective: 2.687554378776392 117 -- optimal, objective: 6.864920838087274 118 -- optimal, objective: 3.0375522321897814 119 -- optimal, objective: 2.494098009707389 120 -- optimal, objective: 0.46083201829370657 121 -- optimal, objective: 0.04447225222365364 122 -- optimal, objective: 1.9092110321559408 123 -- optimal, objective: 4.153938460441822 124 -- optimal, objective: 5.635804261323758 125 -- optimal, objective: 4.72239948960187 126 -- optimal, objective: 4.837813299841361 127 -- optimal, objective: 2.8953995802785957 128 -- optimal, objective: 0.1700728987502693 129 -- optimal, objective: 0.983791567030946 130 -- optimal, objective: 8.05225409929586 131 -- optimal, objective: 6.260316294305136 132 -- optimal, objective: 2.572598330268635 133 -- optimal, objective: 3.7332013380677833 134 -- optimal, objective: 0.34006246098208825 135 -- optimal, objective: 3.6033161609590403 136 -- optimal, objective: 2.501573096808958 137 -- optimal, objective: 0.39640424029669713 138 -- optimal, objective: 0.1414035092242955 139 -- optimal, objective: 8.317311777959498 140 -- optimal, objective: 5.424431267918817 141 -- optimal, objective: 2.8357421686721 142 -- optimal, objective: 1.5376013961507509 143 -- optimal, objective: 3.6241963577005194 144 -- optimal, objective: 4.954703626295027 145 -- optimal, objective: 0.585159563006957 146 -- optimal, objective: 4.89957252536089 147 -- optimal, objective: 3.6822688057449264 148 -- optimal, objective: 2.12108984310195 149 -- optimal, objective: 1.7199795815279166 150 -- optimal, objective: 3.318912504228596 151 -- optimal, objective: 0.36850785731333546 152 -- optimal, objective: 1.9488329531202326 153 -- optimal, objective: 2.6747680809659813 154 -- optimal, objective: 7.5856981034921125 155 -- optimal, objective: 3.395738594834344 156 -- optimal, objective: 4.149632062900599 157 -- optimal, objective: 1.0001387519541236 158 -- optimal, objective: 3.0644832117345655 159 -- optimal, objective: 5.014021556676823 160 -- optimal, objective: 3.8398189061238397 161 -- optimal, objective: 1.6576893499093268 162 -- optimal, objective: 0.41176973979161824 163 -- optimal, objective: 2.040678862856759 164 -- optimal, objective: 2.0029963443118506 165 -- optimal, objective: 2.511504386519033 166 -- optimal, objective: 0.4825771048999583 167 -- optimal, objective: 3.888932512512223 168 -- optimal, objective: 1.0769714540448008 169 -- optimal, objective: 2.499194099134282 170 -- optimal, objective: 1.845202288971921 171 -- optimal, objective: 4.5162757443336305 172 -- optimal, objective: 3.7259845773036906 173 -- optimal, objective: 1.9205831842368681 174 -- optimal, objective: 1.6040433482387517 175 -- optimal, objective: 0.3297059921164168 176 -- optimal, objective: 3.1773292559303705 177 -- optimal, objective: 4.89221287375584 178 -- optimal, objective: 1.7344211222125672 179 -- optimal, objective: 2.0930113767061584 180 -- optimal, objective: 1.9821944087033123 181 -- optimal, objective: 3.095063944360138 182 -- optimal, objective: 2.5625165342165928 183 -- optimal, objective: 6.469891429283569 184 -- optimal, objective: 2.067460638680301 185 -- optimal, objective: 2.3845354622360526 186 -- optimal, objective: 1.5119923887480426 187 -- optimal, objective: 3.625418156825069 188 -- optimal, objective: 0.9836625190091582 189 -- optimal, objective: 1.9174184223605604 190 -- optimal, objective: 1.0199853616407286 191 -- optimal, objective: 1.8111192038560038 192 -- optimal, objective: 10.40706189927436 193 -- optimal, objective: 5.725243783933129 194 -- optimal, objective: 6.585188554630437 195 -- optimal, objective: 1.1404034774868888 196 -- optimal, objective: 4.6364857395103485 197 -- optimal, objective: 3.9218037986581695 198 -- optimal, objective: 1.0045607379024488 199 -- optimal, objective: 2.418194887917511 200 -- optimal, objective: 2.924381439171248 201 -- optimal, objective: 2.9689954757333767 202 -- optimal, objective: 2.615289296528611 203 -- optimal, objective: 2.491418211244421 204 -- optimal, objective: 1.7943475851127997 205 -- optimal, objective: 5.708324626597137 206 -- optimal, objective: 2.4056055297694727 207 -- optimal, objective: 0.9383160093489363 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.023971715053819 215 -- optimal, objective: 3.5942477203081955 216 -- optimal, objective: 1.6777755011210227 217 -- optimal, objective: 4.848035154404865 218 -- optimal, objective: 0.48854638442723286 219 -- optimal, objective: 12.374531482863178 220 -- optimal, objective: 1.4283906796285541 221 -- optimal, objective: 1.8180474372486608 222 -- optimal, objective: 0.4850181471500386 223 -- optimal, objective: 2.506770452120046 224 -- optimal, objective: 1.3976831205728915 225 -- optimal, objective: 0.9031827797634284 226 -- optimal, objective: 0.7285597986984916 227 -- optimal, objective: 2.470420726707554 228 -- optimal, objective: 2.6750989066858013 229 -- optimal, objective: 3.325705645605336 230 -- optimal, objective: 2.5990527127801317 231 -- optimal, objective: 4.837619200685973 232 -- optimal, objective: 1.1329374346636611 233 -- optimal, objective: 1.6398640882824427 234 -- optimal, objective: 3.008950871925208 235 -- optimal, objective: 1.4124059496646608 236 -- optimal, objective: 5.7719654075989295 237 -- optimal, objective: 0.14938189272240585 238 -- optimal, objective: 1.205741317201688 239 -- optimal, objective: 1.7168330910788303 240 -- optimal, objective: 4.602205543920219 241 -- optimal, objective: 2.123631117523279 242 -- optimal, objective: 2.5316135514751825 243 -- optimal, objective: 1.7031605794317117 244 -- optimal, objective: 2.2177892333102482 245 -- optimal, objective: 0.64656334673633 246 -- optimal, objective: 1.291637880047304 247 -- optimal, objective: 7.7898519886260615 248 -- optimal, objective: 1.0605735856126097 249 -- optimal, objective: 1.151469126514001
# 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.