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-01-13 17:30:56 [INFO] idaes.init.fs.econ.side_1: Initialization Complete 2021-01-13 17:30:56 [INFO] idaes.init.fs.econ.side_2.properties_in: Initialisation Complete, optimal - Optimal Solution Found. 2021-01-13 17:30:56 [INFO] idaes.init.fs.econ.side_2.properties_out: Initialisation Complete, optimal - Optimal Solution Found. 2021-01-13 17:30:56 [INFO] idaes.init.fs.econ.side_2.properties_out: fs.econ.side_2.properties_out State Released. 2021-01-13 17:30:56 [INFO] idaes.init.fs.econ.side_2: Initialization Complete 2021-01-13 17:30:56 [INFO] idaes.init.fs.econ: fs.econ Initialisation Step 1 Complete. 2021-01-13 17:30:56 [INFO] idaes.init.fs.econ.side_2.properties_in: fs.econ.side_2.properties_in State Released. 2021-01-13 17:30: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()
m.fs.econ.LMTD.deactivate()
4. Map Data to the Model¶
Although the model mapping can be included in the tag metadata file, here we just add the mapping information to the tag metadata after reading the data. Sometime a data set may be used with more than one model or you may want to examine data before creating a model, in which case it is convenient to defer mapping the data to the model as we have done here.
df_meta["ECON_OUT_F"]["reference_string"] = "m.fs.econ.side_1.properties_out[:].flow_mol"
df_meta["ECON_OUT_T"]["reference_string"] = "m.fs.econ.side_1.properties_out[:].temperature"
df_meta["ECON_OUT_P"]["reference_string"] = "m.fs.econ.side_1.properties_out[:].pressure"
df_meta["BFW_F"]["reference_string"] = "m.fs.econ.side_1.properties_in[:].flow_mol"
df_meta["BFW_T"]["reference_string"] = "m.fs.econ.side_1.properties_in[:].temperature"
df_meta["BFW_P"]["reference_string"] = "m.fs.econ.side_1.properties_in[:].pressure"
df_meta["FG_2_ECON_Fm"]["reference_string"] = "m.fs.econ.side_2.properties_in[:].flow_mass"
df_meta["FG_2_ECON_T"]["reference_string"] = "m.fs.econ.side_2.properties_in[:].temperature"
df_meta["FG_2_ECON_P"]["reference_string"] = "m.fs.econ.side_2.properties_in[:].pressure"
df_meta["FG_2_AIRPH_Fm"]["reference_string"] = "m.fs.econ.side_2.properties_out[:].flow_mass"
df_meta["FG_2_AIRPH_T"]["reference_string"] = "m.fs.econ.side_2.properties_out[:].temperature"
df_meta["FG_2_AIRPH_P"]["reference_string"] = "m.fs.econ.side_2.properties_out[:].pressure"
# Add the model references to the tag metadata based on the strings above.
da.upadate_metadata_model_references(m, df_meta)
# Create a dictionary of data tags that we want to use for the data reconciliation problem.
# The key is the tag and the value is a reference to a quantity in the model.
data_tags = {k:v["reference"][0] for k, v in df_meta.items() if v["reference"] is not None}
# Now for result output, the data reconciliation usually can give full stream information for a flowsheet
# including quantities that are unmeasured. To more easily use the results, it is good practice to map most of
# the data reconciliation results to flowsheet stream names.
import idaes.core.util.tables as ta
# This function creates a dictionary of streams based of streams based on model arcs. The function
# also takes an addtional set of stream-like objects for add to the stream dictionary. In this case,
# this is a single unit and the flowsheet doesn't contain any arcs, so we add the economized inlet and
# outlet ports to the stream dictionary.
stream_dict = ta.arcs_to_stream_dict(
m,
additional={
"BFW": m.fs.econ.side_1_inlet,
"ECON_OUT": m.fs.econ.side_1_outlet,
"FG_2_ECON": m.fs.econ.side_2_inlet,
"FG_2_AIRPH": m.fs.econ.side_2_outlet,
},
sort=True,
)
# The next function converts the stream dictionary into a dictionary of state block representing the
# streams at a given time point. In this case, we have a steady state model, so we only have one
# time point (0).
state_dict = ta.stream_states_dict(stream_dict, time_point=0)
# The 'tag_state_quantities()' function below iterates through the state block dictionary and
# creates tags for the listed attributes by combining the state block label with the attribute label
# in the labels argument. For example, pressure in the S001 state block would get the tag 'S001_P'.
recon_tags = ta.tag_state_quantities(
blocks=state_dict,
attributes=(
"flow_mass",
"flow_mol",
"enth_mol",
"temperature",
"pressure",
("flow_mol_comp", "O2"),
("flow_mol_comp", "NO"),
("flow_mol_comp", "N2"),
("flow_mol_comp", "SO2"),
("flow_mol_comp", "CO2"),
("flow_mol_comp", "H2O"),
),
labels=("_Fm", "_F", "_h", "_T", "_P", "_F[O2]", "_F[NO]", "_F[N2]", "_F[SO2]", "_F[CO2]", "_F[H2O]"),
)
# Any addtional tags can be added. This is required for tags that cannot be systematically generated
# from the model streams.
recon_tags["ECON_Q"] = m.fs.econ.heat_duty[0]
5. View model flowsheet¶
Model results or other quantities can be added to a process flow diagram. The PFD was drawn beforehand and the model results are added to tagged locations on the PFD.
from idaes.core.util.misc import svg_tag # utility to place numbers/text in an SVG
with open("econ.svg", "r") as f:
s = svg_tag(svg=f, tags={"subtitle":"Initialized Model"})
s = svg_tag(svg=s, tags=recon_tags, outfile="econ_init.svg")
from IPython.display import SVG, display
display(SVG(s))
6. Write Objective¶
Next we write the objective function and additional constraints for the data reconciliation problem. The objective is
$$\min \sum_i \left(\frac{x_{\text{data}, i} - x_{\text{model}, i}}{\sigma_i} \right)^2$$Where $i \in \{\text{Measured Quantities}\}$ and $\sigma_i$ is the standard deviation of measurement i. In this case, for lack of better information, the standard deviation was estimated by binning the data and calculating the standard deviation of each measured variable in each bin.
# Add model parameters to contain measured data. These are mutable so we can set a specific data point later.
m.data = pyo.Param(data_tags, mutable=True, doc="Process data for a specific point in time.")
m.data_stdev = pyo.Param(data_tags, mutable=True, doc="Process data standard deviation.")
# The 'set_data' function below takes data from the process data DataFrame and updates the
# data parameters in the model.
def set_data(m, df, data_tags, index=None, indexindex=None):
if index is None:
index = df.index[indexindex]
m.bin_no = df.iloc[index]["bin_no"]
for t in data_tags:
m.data[t] = df.iloc[index][t]
m.data_stdev[t] = bin_stdev[m.bin_no][t]
# So we have something reasonable to start, set the data attached to the model to the first
# data point.
set_data(m, df, data_tags, indexindex=0)
Add an expression for error divided by the standard deviation, and use it to write the data reconciliation objective function.
@m.Expression(data_tags)
def err(m, i):
return (m.data[i] - data_tags[i])/m.data_stdev[i]
m.objective = pyo.Objective(expr=sum(m.err[t]**2 for t in m.err))
Add constraints that ensure reasonable temperature and keep the flue gas composition correct.
# Limit temperature approach
m.c1 = pyo.Constraint(expr=m.fs.econ.deltaT_1[0] >= 1.0)
m.c2 = pyo.Constraint(expr=m.fs.econ.deltaT_2[0] >= 1.0)
# Constrain flue gas composition
m.flow_fg = pyo.Var(initialize=fg_rate)
@m.Constraint(fg_comp)
def eq_fg_comp(b, c):
return m.fs.econ.side_2.properties_in[0].flow_mol_comp[c] == fg_comp[c]*m.flow_fg
7. Solve Optimization¶
Now we need to solve the data reconciliation problem for every data point. The important results are stored in two DataFrames df_result, which contains results tagged based on model stream names to be used in the parameter estimation step and df_result_cmp which contains reconciled data based on the original measurement tags and can be used to compare the original measurements to the reconciled results.
# Make sure the inlet and outlet ports are unfixed. We want to leave these free
# to best match the data.
m.fs.econ.side_1_inlet.unfix()
m.fs.econ.side_2_inlet.unfix()
m.fs.econ.side_1_outlet.unfix()
m.fs.econ.side_2_outlet.unfix()
# Create a Pyomo solver object
solver = pyo.SolverFactory('ipopt')
import pandas as pd
# Add bin information to reconciliation results so it can be used in parameter estimation
df_result = pd.DataFrame(columns=list(recon_tags.keys())+["termination", "bin_no", "bin_power"], index=df.index)
df_result_cmp = pd.DataFrame(columns=list(data_tags.keys())+["termination"], index=df.index)
# Loop through each data point and solve the data reconciliation problem.
for i in df.index:
set_data(m, df, data_tags, index=i)
res = solver.solve(m)
tc = str(res.solver.termination_condition)
df_result.iloc[i]["termination"] = tc
df_result.iloc[i]["bin_no"] = df.iloc[i]["bin_no"]
df_result.iloc[i]["bin_power"] = df.iloc[i]["bin_power"]
df_result_cmp.iloc[i]["termination"] = tc
for t in recon_tags:
df_result.iloc[i][t] = pyo.value(recon_tags[t])
for t in data_tags:
df_result_cmp.iloc[i][t] = pyo.value(data_tags[t])
# Show something so you can tell progress is happening
print(f"{i} -- {tc}, objective: {pyo.value(m.objective)}")
0 -- optimal, objective: 3.1622013606267907 1 -- optimal, objective: 0.8197916348655789 2 -- optimal, objective: 1.4704841795757935 3 -- optimal, objective: 1.1898903678088835 4 -- optimal, objective: 6.2669020645852225 5 -- optimal, objective: 2.353798975733269 6 -- optimal, objective: 0.5232362409291367 7 -- optimal, objective: 1.02343478899574 8 -- optimal, objective: 1.6923646000433064 9 -- optimal, objective: 5.200181621760986 10 -- optimal, objective: 2.0256788832442947 11 -- optimal, objective: 1.3755282573107501 12 -- optimal, objective: 1.804041195022807 13 -- optimal, objective: 1.0820452721992382 14 -- optimal, objective: 2.87255083467852 15 -- optimal, objective: 4.679431401768802 16 -- optimal, objective: 2.5285462489988135 17 -- optimal, objective: 3.419056606899124 18 -- optimal, objective: 0.6733248046041784 19 -- optimal, objective: 1.3191174229584868 20 -- optimal, objective: 2.591126369762725 21 -- optimal, objective: 0.7284969800023029 22 -- optimal, objective: 3.0960880080286306 23 -- optimal, objective: 8.046882712386477 24 -- optimal, objective: 9.434438819029037 25 -- optimal, objective: 2.9086660605523385 26 -- optimal, objective: 5.7648547763232205 27 -- optimal, objective: 1.586985000119729 28 -- optimal, objective: 0.984970687035872 29 -- optimal, objective: 5.420696622705247 30 -- optimal, objective: 0.16066578746342522 31 -- optimal, objective: 1.9662633227547253 32 -- optimal, objective: 4.631928468438899 33 -- optimal, objective: 0.789832645766975 34 -- optimal, objective: 4.935316816207539 35 -- optimal, objective: 2.7822175536743163 36 -- optimal, objective: 3.7936042118830064 37 -- optimal, objective: 7.399694410586135 38 -- optimal, objective: 1.8234931889047263 39 -- optimal, objective: 8.123278203552482 40 -- optimal, objective: 2.4669893302566903 41 -- optimal, objective: 2.0590537122733528 42 -- optimal, objective: 4.82489004591247 43 -- optimal, objective: 2.9053626799280337 44 -- optimal, objective: 1.2572997144472058 45 -- optimal, objective: 2.7626453809391625 46 -- optimal, objective: 3.9106046062439104 47 -- optimal, objective: 0.36384547188945693 48 -- optimal, objective: 6.4821230867244175 49 -- optimal, objective: 0.8862884524238979 50 -- optimal, objective: 0.35333788962392987 51 -- optimal, objective: 0.674193466689683 52 -- optimal, objective: 1.4465665980891902 53 -- optimal, objective: 2.36569211553337 54 -- optimal, objective: 1.4292836233966975 55 -- optimal, objective: 11.608835808833591 56 -- optimal, objective: 2.584558536493548 57 -- optimal, objective: 2.2280318353693698 58 -- optimal, objective: 2.495393965552233 59 -- optimal, objective: 1.6472887590070486 60 -- optimal, objective: 8.024825566331032 61 -- optimal, objective: 5.943553444690339 62 -- optimal, objective: 2.3357860625599507 63 -- optimal, objective: 4.38513902517736 64 -- optimal, objective: 0.5607805981597604 65 -- optimal, objective: 2.176847135635383 66 -- optimal, objective: 2.8232836736980373 67 -- optimal, objective: 4.396906443658452 68 -- optimal, objective: 3.3918559300377327 69 -- optimal, objective: 0.614879524322046 70 -- optimal, objective: 0.3708280914479124 71 -- optimal, objective: 0.8762641865696106 72 -- optimal, objective: 3.0086342942362223 73 -- optimal, objective: 6.178275683704545 74 -- optimal, objective: 2.4515957154908636 75 -- optimal, objective: 8.97473642570067 76 -- optimal, objective: 1.770665588225432 77 -- optimal, objective: 3.126518971476404 78 -- optimal, objective: 5.205301238989112 79 -- optimal, objective: 4.76959786483013 80 -- optimal, objective: 4.816644746436761 81 -- optimal, objective: 0.6532812835414774 82 -- optimal, objective: 2.496518135836005 83 -- optimal, objective: 0.8032343482262432 84 -- optimal, objective: 0.36282493375250396 85 -- optimal, objective: 1.523823819480709 86 -- optimal, objective: 3.8657878309560236 87 -- optimal, objective: 1.7222749668715736 88 -- optimal, objective: 3.9538769691814224 89 -- optimal, objective: 1.652361242674854 90 -- optimal, objective: 3.3510638416837253 91 -- optimal, objective: 1.209395519639386 92 -- optimal, objective: 1.5787045321362916 93 -- optimal, objective: 3.4104193014724364 94 -- optimal, objective: 1.2638978913499865 95 -- optimal, objective: 3.2950093864133354 96 -- optimal, objective: 1.530697826703603 97 -- optimal, objective: 2.0576162766855446 98 -- optimal, objective: 1.733210252160942 99 -- optimal, objective: 4.588249738737896 100 -- optimal, objective: 0.92951754484715 101 -- optimal, objective: 1.1035561284195947 102 -- optimal, objective: 0.0054024032812002905 103 -- optimal, objective: 4.030350825817906 104 -- optimal, objective: 2.5977688471875235 105 -- optimal, objective: 3.718657215182353 106 -- optimal, objective: 2.220001230383609 107 -- optimal, objective: 1.7361821672875886 108 -- optimal, objective: 1.7827948173523487 109 -- optimal, objective: 0.8012022277039043 110 -- optimal, objective: 0.48906972652973535 111 -- optimal, objective: 4.625396349830533 112 -- optimal, objective: 4.073050044233131 113 -- optimal, objective: 4.984164789951488 114 -- optimal, objective: 4.500918344081629 115 -- optimal, objective: 0.801241319826576 116 -- optimal, objective: 2.687543401764695 117 -- optimal, objective: 6.864934379080611 118 -- optimal, objective: 3.0375805861815914 119 -- optimal, objective: 2.4941088890247958 120 -- optimal, objective: 0.46083351785483423 121 -- optimal, objective: 0.04447133159164325 122 -- optimal, objective: 1.9091826645137384 123 -- optimal, objective: 4.1539278628050935 124 -- optimal, objective: 5.635821162573107 125 -- optimal, objective: 4.722448584729228 126 -- optimal, objective: 4.838421311326324 127 -- optimal, objective: 2.895359847029753 128 -- optimal, objective: 0.1700702801133807 129 -- optimal, objective: 0.9837813189594008 130 -- optimal, objective: 8.052242413116605 131 -- optimal, objective: 6.260349530098593 132 -- optimal, objective: 2.5726387350162483 133 -- optimal, objective: 3.7332306491081377 134 -- optimal, objective: 0.3400649625011723 135 -- optimal, objective: 3.6032792688193607 136 -- optimal, objective: 2.501572849060018 137 -- optimal, objective: 0.3964133950014609 138 -- optimal, objective: 0.14140404247147736 139 -- optimal, objective: 8.31724058642861 140 -- optimal, objective: 5.424448709520636 141 -- optimal, objective: 2.8357713483631617 142 -- optimal, objective: 1.5375770466935483 143 -- optimal, objective: 3.62417161274446 144 -- optimal, objective: 4.954731705445229 145 -- optimal, objective: 0.5851578341559459 146 -- optimal, objective: 4.899534932815304 147 -- optimal, objective: 3.682266173635674 148 -- optimal, objective: 2.121107969962777 149 -- optimal, objective: 1.7199428396592482 150 -- optimal, objective: 3.3189214980332977 151 -- optimal, objective: 0.36851885526625244 152 -- optimal, objective: 1.948810577615916 153 -- optimal, objective: 2.67478704241622 154 -- optimal, objective: 7.585656605848088 155 -- optimal, objective: 3.3957387225186713 156 -- optimal, objective: 4.149600126698557 157 -- optimal, objective: 1.0001276150024228 158 -- optimal, objective: 3.0644614255860447 159 -- optimal, objective: 5.0139923079556645 160 -- optimal, objective: 3.8398600172207185 161 -- optimal, objective: 1.6576814935989073 162 -- optimal, objective: 0.4117837889199685 163 -- optimal, objective: 2.0406846027880032 164 -- optimal, objective: 2.002997772812926 165 -- optimal, objective: 2.511479923614843 166 -- optimal, objective: 0.48258914652156576 167 -- optimal, objective: 3.8889766576259204 168 -- optimal, objective: 1.0769465308249426 169 -- optimal, objective: 2.499193200876663 170 -- optimal, objective: 1.8451901507025137 171 -- optimal, objective: 4.516240233107525 172 -- optimal, objective: 3.7259498522239074 173 -- optimal, objective: 1.9205975302204013 174 -- optimal, objective: 1.604047683771153 175 -- optimal, objective: 0.3297073490067204 176 -- optimal, objective: 3.177302640760672 177 -- optimal, objective: 4.892210628679255 178 -- optimal, objective: 1.7344424108099796 179 -- optimal, objective: 2.0930393921890142 180 -- optimal, objective: 1.9821792611905547 181 -- optimal, objective: 3.0950130851163937 182 -- optimal, objective: 2.562542928308156 183 -- optimal, objective: 6.469840016661604 184 -- optimal, objective: 2.0674756021955227 185 -- optimal, objective: 2.3845462972645826 186 -- optimal, objective: 1.5119667476079248 187 -- optimal, objective: 3.6253762909982634 188 -- optimal, objective: 0.9836489663297104 189 -- optimal, objective: 1.9174021295225794 190 -- optimal, objective: 1.0200049678523286 191 -- optimal, objective: 1.811114748637613 192 -- optimal, objective: 10.40700748664943 193 -- optimal, objective: 5.725212636472607 194 -- optimal, objective: 6.585121023533178 195 -- optimal, objective: 1.1403803946150923 196 -- optimal, objective: 4.636496073472227 197 -- optimal, objective: 3.9217711869994343 198 -- optimal, objective: 1.00457026568275 199 -- optimal, objective: 2.418215480545875 200 -- optimal, objective: 2.924358021526806 201 -- optimal, objective: 2.9689758379686415 202 -- optimal, objective: 2.6152849723015565 203 -- optimal, objective: 2.4914091180308597 204 -- optimal, objective: 1.794347594257792 205 -- optimal, objective: 5.708286126988911 206 -- optimal, objective: 2.4056024845433326 207 -- optimal, objective: 0.9383323510763955 208 -- optimal, objective: 4.796662991506752 209 -- optimal, objective: 0.506773425862618 210 -- optimal, objective: 2.1890884578837966 211 -- optimal, objective: 3.216278312969685 212 -- optimal, objective: 0.07969866183081314 213 -- optimal, objective: 0.39071669881267745 214 -- optimal, objective: 4.024001493294549 215 -- optimal, objective: 3.594279949173519 216 -- optimal, objective: 1.6777857029028622 217 -- optimal, objective: 4.848031703923862 218 -- optimal, objective: 0.48853441088523125 219 -- optimal, objective: 12.374570705038183 220 -- optimal, objective: 1.4284110604965086 221 -- optimal, objective: 1.818042749358927 222 -- optimal, objective: 0.4850085026530443 223 -- optimal, objective: 2.5067851806563355 224 -- optimal, objective: 1.3976812984152867 225 -- optimal, objective: 0.9031717605986198 226 -- optimal, objective: 0.7285447496525985 227 -- optimal, objective: 2.4703912750522545 228 -- optimal, objective: 2.675134784707579 229 -- optimal, objective: 3.325674612581462 230 -- optimal, objective: 2.5990372980399847 231 -- optimal, objective: 4.8376057781493635 232 -- optimal, objective: 1.1329234883415469 233 -- optimal, objective: 1.6398399431286828 234 -- optimal, objective: 3.0089833505496166 235 -- optimal, objective: 1.4124043086038174 236 -- optimal, objective: 5.771998515376791 237 -- optimal, objective: 0.149389060156801 238 -- optimal, objective: 1.205747487805747 239 -- optimal, objective: 1.7168126471500196 240 -- optimal, objective: 4.602217912756729 241 -- optimal, objective: 2.1236286863590923 242 -- optimal, objective: 2.531589994116756 243 -- optimal, objective: 1.7031408430137989 244 -- optimal, objective: 2.2177940017210624 245 -- optimal, objective: 0.6465659506433649 246 -- optimal, objective: 1.2916365175647821 247 -- optimal, objective: 7.7902584211708366 248 -- optimal, objective: 1.0605580786757942 249 -- optimal, objective: 1.1515044674820794
# 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.