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.core.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.models_extra.power_generation.properties.flue_gas_ideal import FlueGasParameterBlock
from idaes.models.properties import iapws95
from idaes.models_extra.power_generation.unit_models.boiler_heat_exchanger import (
BoilerHeatExchanger,
TubeArrangement,
HeatExchangerFlowPattern
)
import pyomo.environ as pyo
# Create flowsheet with economizer
m = pyo.ConcreteModel()
m.fs = FlowsheetBlock(dynamic=False)
m.fs.prop_water = iapws95.Iapws95ParameterBlock()
m.fs.prop_fluegas = FlueGasParameterBlock()
m.fs.econ = BoilerHeatExchanger(
cold_side={"property_package": m.fs.prop_water,
"has_pressure_change": True},
hot_side={"property_package": m.fs.prop_fluegas,
"has_pressure_change": True},
has_holdup=False,
flow_pattern=HeatExchangerFlowPattern.countercurrent,
tube_arrangement=TubeArrangement.inLine,
cold_side_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.cold_side_inlet.flow_mol[0].fix(24678.26) # mol/s
m.fs.econ.cold_side_inlet.enth_mol[0].fix(h) #J/mol
m.fs.econ.cold_side_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.hot_side.properties_in[0].flow_mol_comp[c].fix(fg_rate*fg_comp[c])
m.fs.econ.hot_side_inlet.temperature[0].fix(682.335) # K
m.fs.econ.hot_side_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.cold_side_inlet.flow_mol[0].value,
"pressure": m.fs.econ.cold_side_inlet.pressure[0].value,
"enth_mol": m.fs.econ.cold_side_inlet.enth_mol[0].value,
},
state_args_2={
"flow_component":{
"H2O": m.fs.econ.hot_side_inlet.flow_mol_comp[0, "H2O"].value,
"CO2": m.fs.econ.hot_side_inlet.flow_mol_comp[0, "CO2"].value,
"N2": m.fs.econ.hot_side_inlet.flow_mol_comp[0, "N2"].value,
"O2": m.fs.econ.hot_side_inlet.flow_mol_comp[0, "O2"].value,
"NO": m.fs.econ.hot_side_inlet.flow_mol_comp[0, "NO"].value,
"SO2": m.fs.econ.hot_side_inlet.flow_mol_comp[0, "SO2"].value,
},
"temperature": m.fs.econ.hot_side_inlet.temperature[0].value,
"pressure": m.fs.econ.hot_side_inlet.pressure[0].value,
}
)
2023-03-04 01:31:56 [INFO] idaes.init.fs.econ.cold_side: Initialization Complete 2023-03-04 01:31:56 [INFO] idaes.init.fs.econ.hot_side.properties_in: Initialisation Complete, optimal - Optimal Solution Found. 2023-03-04 01:31:56 [INFO] idaes.init.fs.econ.hot_side.properties_out: Initialisation Complete, optimal - Optimal Solution Found. 2023-03-04 01:31:56 [INFO] idaes.init.fs.econ.hot_side.properties_out: fs.econ.hot_side.properties_out State Released. 2023-03-04 01:31:56 [INFO] idaes.init.fs.econ.hot_side: Initialization Complete 2023-03-04 01:31:56 [INFO] idaes.init.fs.econ: fs.econ Initialisation Step 1 Complete. 2023-03-04 01:31:56 [INFO] idaes.init.fs.econ.hot_side.properties_in: fs.econ.hot_side.properties_in State Released. 2023-03-04 01:31:56 [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.cold_side.properties_out[:].flow_mol"
df_meta["ECON_OUT_T"]["reference_string"] = "m.fs.econ.cold_side.properties_out[:].temperature"
df_meta["ECON_OUT_P"]["reference_string"] = "m.fs.econ.cold_side.properties_out[:].pressure"
df_meta["BFW_F"]["reference_string"] = "m.fs.econ.cold_side.properties_in[:].flow_mol"
df_meta["BFW_T"]["reference_string"] = "m.fs.econ.cold_side.properties_in[:].temperature"
df_meta["BFW_P"]["reference_string"] = "m.fs.econ.cold_side.properties_in[:].pressure"
df_meta["FG_2_ECON_Fm"]["reference_string"] = "m.fs.econ.hot_side.properties_in[:].flow_mass"
df_meta["FG_2_ECON_T"]["reference_string"] = "m.fs.econ.hot_side.properties_in[:].temperature"
df_meta["FG_2_ECON_P"]["reference_string"] = "m.fs.econ.hot_side.properties_in[:].pressure"
df_meta["FG_2_AIRPH_Fm"]["reference_string"] = "m.fs.econ.hot_side.properties_out[:].flow_mass"
df_meta["FG_2_AIRPH_T"]["reference_string"] = "m.fs.econ.hot_side.properties_out[:].temperature"
df_meta["FG_2_AIRPH_P"]["reference_string"] = "m.fs.econ.hot_side.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
from idaes.core.util.tags import ModelTagGroup
# 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.cold_side_inlet,
"ECON_OUT": m.fs.econ.cold_side_outlet,
"FG_2_ECON": m.fs.econ.hot_side_inlet,
"FG_2_AIRPH": m.fs.econ.hot_side_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 = ModelTagGroup()
prop_dict = {
"flow_mass": "_Fm",
"flow_mol": "_F",
"enth_mol": "_h",
"temperature": "_T",
"pressure": "_P",
}
comp_list = ["O2", "NO", "N2", "SO2", "CO2", "H2O"]
for state, block in state_dict.items():
for prop, suffix in prop_dict.items():
comp = getattr(block, prop)
recon_tags.add(expr=comp, name=state+suffix, format_string="{:.3f}")
# Add tags for molar flow rates of each component
for j in comp_list:
# Not all components appear in all streams
try:
comp = block.flow_mol_comp[j]
recon_tags.add(expr=comp, name=f"{state}_F[{j}]", format_string="{:.3f}")
except KeyError:
pass
# Any addtional tags can be added. This is required for tags that cannot be systematically generated
# from the model streams.
recon_tags.add(expr=m.fs.econ.heat_duty[0], name="ECON_Q", format_string="{:.3f}")
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.tags import svg_tag # utility to place numbers/text in an SVG
with open("econ.svg", "r") as f:
s = svg_tag(svg=f, tag_group=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.hot_side.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.cold_side_inlet.unfix()
m.fs.econ.hot_side_inlet.unfix()
m.fs.econ.cold_side_outlet.unfix()
m.fs.econ.hot_side_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].expression)
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.1622331890495903 1 -- optimal, objective: 0.8197864499890314 2 -- optimal, objective: 1.4705020498257433 3 -- optimal, objective: 1.1898579077047484 4 -- optimal, objective: 6.266862831652643 5 -- optimal, objective: 2.353837799416942 6 -- optimal, objective: 0.5232270065114984 7 -- optimal, objective: 1.0234628569514321 8 -- optimal, objective: 1.692397720851685 9 -- optimal, objective: 5.200192745852479 10 -- optimal, objective: 2.025697843022476 11 -- optimal, objective: 1.3755022829202932 12 -- optimal, objective: 1.8040084546445863 13 -- optimal, objective: 1.0820697968578374 14 -- optimal, objective: 2.872565777305556 15 -- optimal, objective: 4.67937799614271 16 -- optimal, objective: 2.528568205492165 17 -- optimal, objective: 3.419105635591174 18 -- optimal, objective: 0.6733502043659465 19 -- optimal, objective: 1.3191453351997167 20 -- optimal, objective: 2.5910789518941666 21 -- optimal, objective: 0.7284892511624388 22 -- optimal, objective: 3.0961354376473573 23 -- optimal, objective: 8.046924273772184 24 -- optimal, objective: 9.434482098827047 25 -- optimal, objective: 2.9087156182745018 26 -- optimal, objective: 5.764858402612364 27 -- optimal, objective: 1.586994733305022 28 -- optimal, objective: 0.9849858467550563 29 -- optimal, objective: 5.420724866466431 30 -- optimal, objective: 0.15987314723602114 31 -- optimal, objective: 1.966274545593537 32 -- optimal, objective: 4.631981600955086 33 -- optimal, objective: 0.7898383615771404 34 -- optimal, objective: 4.9353180306590225 35 -- optimal, objective: 2.782272921404692 36 -- optimal, objective: 3.7935361234633205 37 -- optimal, objective: 7.39974416375716 38 -- optimal, objective: 1.8234832495958384 39 -- optimal, objective: 8.12319775531671 40 -- optimal, objective: 2.466967374172533 41 -- optimal, objective: 2.058995669731764 42 -- optimal, objective: 4.824845773329273 43 -- optimal, objective: 2.905354510994933 44 -- optimal, objective: 1.2573498031484729 45 -- optimal, objective: 2.762659514639501 46 -- optimal, objective: 3.9105414166260903 47 -- optimal, objective: 0.3638539213532054 48 -- optimal, objective: 6.48204512467072 49 -- optimal, objective: 0.8862853314576087 50 -- optimal, objective: 0.3533301795603448 51 -- optimal, objective: 0.6741716772662831 52 -- optimal, objective: 1.4465656566076062 53 -- optimal, objective: 2.365722448400615 54 -- optimal, objective: 1.4293144956083175 55 -- optimal, objective: 11.60889957738345 56 -- optimal, objective: 2.5845585147163397 57 -- optimal, objective: 2.228041896062202 58 -- optimal, objective: 2.4953667573534735 59 -- optimal, objective: 1.647314373365076 60 -- optimal, objective: 8.024762155447666 61 -- optimal, objective: 5.943580608761248 62 -- optimal, objective: 2.3358112651341743 63 -- optimal, objective: 4.38513490110046 64 -- optimal, objective: 0.5607991758545512 65 -- optimal, objective: 2.176886090478235 66 -- optimal, objective: 2.8233305625187795 67 -- optimal, objective: 4.396916342718716 68 -- optimal, objective: 3.391821500174123 69 -- optimal, objective: 0.614861768709231 70 -- optimal, objective: 0.3708295031059437 71 -- optimal, objective: 0.876241026808678 72 -- optimal, objective: 3.008619356231868 73 -- optimal, objective: 6.178310252873772 74 -- optimal, objective: 2.451573865746587 75 -- optimal, objective: 8.974808392536618 76 -- optimal, objective: 1.770701321328788 77 -- optimal, objective: 3.1265504086289444 78 -- optimal, objective: 5.203564818159552 79 -- optimal, objective: 4.769633196273789 80 -- optimal, objective: 4.816640912308049 81 -- optimal, objective: 0.653270596556715 82 -- optimal, objective: 2.4965339056024445 83 -- optimal, objective: 0.8032403793218241 84 -- optimal, objective: 0.3628436163258187 85 -- optimal, objective: 1.5238517213119334 86 -- optimal, objective: 3.865748917190463 87 -- optimal, objective: 1.7222638616761394 88 -- optimal, objective: 3.953870122426233 89 -- optimal, objective: 1.6523633158686517 90 -- optimal, objective: 3.3511178021618955 91 -- optimal, objective: 1.2094064053344298 92 -- optimal, objective: 1.578703926570243 93 -- optimal, objective: 3.4104161322803077 94 -- optimal, objective: 1.2638744445651577 95 -- optimal, objective: 3.295026970052376 96 -- optimal, objective: 1.5307297912770716 97 -- optimal, objective: 2.057619546085194 98 -- optimal, objective: 1.733201919869821 99 -- optimal, objective: 4.588294007037179 100 -- optimal, objective: 0.9292950798611487 101 -- optimal, objective: 1.1035420871623796 102 -- optimal, objective: 0.0054034303983518895 103 -- optimal, objective: 4.03037968399287 104 -- optimal, objective: 2.5977953040667674 105 -- optimal, objective: 3.718627904476693 106 -- optimal, objective: 2.220011645610575 107 -- optimal, objective: 1.7361501009358982 108 -- optimal, objective: 1.7827888202876916 109 -- optimal, objective: 0.80122559579786 110 -- optimal, objective: 0.4890883099159153 111 -- optimal, objective: 4.625468290421027 112 -- optimal, objective: 4.073067561398391 113 -- optimal, objective: 4.984142249931269 114 -- optimal, objective: 4.500896627466857 115 -- optimal, objective: 0.8012366493659453 116 -- optimal, objective: 2.687559753925411 117 -- optimal, objective: 6.864914207638007 118 -- optimal, objective: 3.0375383483442926 119 -- optimal, objective: 2.4940926825731284 120 -- optimal, objective: 0.4608312841132002 121 -- optimal, objective: 0.044472703115553146 122 -- optimal, objective: 1.9092249228761018 123 -- optimal, objective: 4.153943649844279 124 -- optimal, objective: 5.635795985484567 125 -- optimal, objective: 4.722375449559023 126 -- optimal, objective: 4.837800008333984 127 -- optimal, objective: 2.8954190363534136 128 -- optimal, objective: 0.1700741811184426 129 -- optimal, objective: 0.9837965852424274 130 -- optimal, objective: 8.052261850607346 131 -- optimal, objective: 6.260300019995981 132 -- optimal, objective: 2.572578545638929 133 -- optimal, objective: 3.7331869855918605 134 -- optimal, objective: 0.3400612362222525 135 -- optimal, objective: 3.6033342258730423 136 -- optimal, objective: 2.5015732182201575 137 -- optimal, objective: 0.39639975765004987 138 -- optimal, objective: 0.14140324820957903 139 -- optimal, objective: 8.317346638087258 140 -- optimal, objective: 5.424422727514848 141 -- optimal, objective: 2.8357278805421795 142 -- optimal, objective: 1.5376133193671455 143 -- optimal, objective: 3.62420847455168 144 -- optimal, objective: 4.95468987699023 145 -- optimal, objective: 0.5851604096299909 146 -- optimal, objective: 4.899590933174681 147 -- optimal, objective: 3.682270094664581 148 -- optimal, objective: 2.121080967168293 149 -- optimal, objective: 1.7199975728803218 150 -- optimal, objective: 3.3189081004099528 151 -- optimal, objective: 0.36850247207838444 152 -- optimal, objective: 1.948843909757939 153 -- optimal, objective: 2.6747587962823256 154 -- optimal, objective: 7.5857184235589985 155 -- optimal, objective: 3.3957385323820666 156 -- optimal, objective: 4.149647701070497 157 -- optimal, objective: 1.0001442053929916 158 -- optimal, objective: 3.064493879763522 159 -- optimal, objective: 5.014035878816116 160 -- optimal, objective: 3.8397987755888137 161 -- optimal, objective: 1.6576931969835833 162 -- optimal, objective: 0.4117628605308926 163 -- optimal, objective: 2.0406760523470697 164 -- optimal, objective: 2.00299564496912 165 -- optimal, objective: 2.5115163652865116 166 -- optimal, objective: 0.4825712086517368 167 -- optimal, objective: 3.888910896308239 168 -- optimal, objective: 1.0769836582038614 169 -- optimal, objective: 2.4991945390851953 170 -- optimal, objective: 1.845216182624875 171 -- optimal, objective: 4.5162931330312786 172 -- optimal, objective: 3.7260015810683855 173 -- optimal, objective: 1.9205761596254298 174 -- optimal, objective: 1.6040412254147172 175 -- optimal, objective: 0.329705327804772 176 -- optimal, objective: 3.1773422885568405 177 -- optimal, objective: 4.892213973195785 178 -- optimal, objective: 1.7344107256429018 179 -- optimal, objective: 2.0929976586354795 180 -- optimal, objective: 1.982201826026842 181 -- optimal, objective: 3.0950888485043486 182 -- optimal, objective: 2.5625036101031307 183 -- optimal, objective: 6.469916654594622 184 -- optimal, objective: 2.067453311742428 185 -- optimal, objective: 2.3845301568016093 186 -- optimal, objective: 1.5120049498654422 187 -- optimal, objective: 3.625438657158909 188 -- optimal, objective: 0.9836691585294073 189 -- optimal, objective: 1.9174264005471389 190 -- optimal, objective: 1.0199757612465605 191 -- optimal, objective: 1.8111213854884887 192 -- optimal, objective: 10.40708854331168 193 -- optimal, objective: 5.725259035852611 194 -- optimal, objective: 6.585221622378499 195 -- optimal, objective: 1.140414780445981 196 -- optimal, objective: 4.636480679503139 197 -- optimal, objective: 3.9218197675248376 198 -- optimal, objective: 1.0045560725784408 199 -- optimal, objective: 2.4181848045168044 200 -- optimal, objective: 2.9243929060255587 201 -- optimal, objective: 2.969005091737908 202 -- optimal, objective: 2.615291414013147 203 -- optimal, objective: 2.4914226639464307 204 -- optimal, objective: 1.7943475807253635 205 -- optimal, objective: 5.708343478588351 206 -- optimal, objective: 2.4056070209689806 207 -- optimal, objective: 0.9383083089043902 208 -- optimal, objective: 4.796697378270856 209 -- optimal, objective: 0.5067761258605348 210 -- optimal, objective: 2.189061857466013 211 -- optimal, objective: 3.2162690886396597 212 -- optimal, objective: 0.07970527067968351 213 -- optimal, objective: 0.3907213231728188 214 -- optimal, objective: 4.023957133776389 215 -- optimal, objective: 3.5942319390503137 216 -- optimal, objective: 1.6777705156089673 217 -- optimal, objective: 4.848036844041122 218 -- optimal, objective: 0.4885522475247492 219 -- optimal, objective: 12.37451227722671 220 -- optimal, objective: 1.4283806999185058 221 -- optimal, objective: 1.8180497328202705 222 -- optimal, objective: 0.4850228697954107 223 -- optimal, objective: 2.506763240151633 224 -- optimal, objective: 1.3976840129134172 225 -- optimal, objective: 0.9031881755465401 226 -- optimal, objective: 0.7285671677648223 227 -- optimal, objective: 2.470435148231497 228 -- optimal, objective: 2.675081338576942 229 -- optimal, objective: 3.3257208414747335 230 -- optimal, objective: 2.599060260920109 231 -- optimal, objective: 4.83762577330625 232 -- optimal, objective: 1.1329442637595963 233 -- optimal, objective: 1.639875911401635 234 -- optimal, objective: 3.008934968366903 235 -- optimal, objective: 1.4124067533104043 236 -- optimal, objective: 5.7719491959694 237 -- optimal, objective: 0.1493783831652131 238 -- optimal, objective: 1.2057382957613423 239 -- optimal, objective: 1.7168431018295964 240 -- optimal, objective: 4.60219948744476 241 -- optimal, objective: 2.123639453209505 242 -- optimal, objective: 2.531625086777071 243 -- optimal, objective: 1.7031702437789407 244 -- optimal, objective: 2.217786898491411 245 -- optimal, objective: 0.6465620718112349 246 -- optimal, objective: 1.291638547305462 247 -- optimal, objective: 7.789842761895717 248 -- optimal, objective: 1.0605811788975477 249 -- optimal, objective: 1.151459058786545
# 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.