diff --git a/.gitignore b/.gitignore
index 259148f..85a23ad 100644
--- a/.gitignore
+++ b/.gitignore
@@ -30,3 +30,9 @@
*.exe
*.out
*.app
+
+.vscode/
+install/
+src/build*/
+build*/
+
diff --git a/README.md b/docs/README_1.0.0.md
similarity index 99%
rename from README.md
rename to docs/README_1.0.0.md
index 69d8276..e4052d9 100644
--- a/README.md
+++ b/docs/README_1.0.0.md
@@ -154,7 +154,6 @@ $ ./install/bin/hb-list-sensors --config=SensorTable/SensorTable_ATDS.ktf
{ "number": 268435472, "name": "K.RTD2.Acc.AS.ATDS", "default_calibration": "degC:degC+273.15" },
..... (continues)
```
-
The sensor list can be filtered by providing (partial) name matches:
```
### all sensors in the "Diss.AS" section ###
diff --git a/docs/RELEASE_NOTES_1.1.0.md b/docs/RELEASE_NOTES_1.1.0.md
new file mode 100644
index 0000000..0b08de1
--- /dev/null
+++ b/docs/RELEASE_NOTES_1.1.0.md
@@ -0,0 +1,383 @@
+Honeybee Upgraded Calibration Framework Release
+==================================================
+
+## 1. Overview
+
+### 2.1 Architecture Overview
+
+
+
+
+
+
+- Key components and relationships
+The current design is language agnostic so that in the future, other calibration engines from a Rust/python/... source would easily be able to be integrated into the system
+
+- abstraction point:
+ sensor_config is abstract so that we can define sensor_config variants that tailor to a specific calibration engine.
+
+ Ex: derived classes specific to:
+ sensor_config_by_ktf
+ sensor_config_by_rust
+ sensor_config_by_py
+ .
+ .
+ .
+ .
+
+#### Class responsibilities:
+
+honeybee: main orchestrator of application, lifetime of running
+
+ holds: Registry of all sensors, connection to data backend, configuration loader, user-provided runtime variable
+
+ Does: Resolves sensor names to IDs, delegates to data_source for raw data fetch, returns packaged results.
+
+
+sensor_config_by_ktf: Parse KTF files and populate sensor table
+
+ Holds:
+ The Kebap parser instance that compiles all UDFs and global variables, the KTF file path being processed, user-supplied configuration variables
+
+ Does:
+ Reads KTF files, extracts #% script blocks, parses Kebap code, creates sensor objects with calibration objects, registers them in sensor table
+
+sensor: signifies a single measurement point
+
+ Holds: (also some metadata about a sensor)
+ - Sensor's unique ID, full hierarchical name path (e.g., "ATDS.Gas.Inj.Alicat.sccm") and display label
+ - raw calibration formula text, reference to the calibration computer
+
+sensor_table: Manage collection of all sensors
+
+ Holds: Complete registry of all sensors (indexed by unique ID and searchable by hierarchical name)
+ Does: Store/retrieve sensors by ID or name chain. Provides lookup helpers for finding sensors by partial name match. Read-only after configuration
+
+data_source: calibration applied here, fetch data and apply calibration
+
+ Holds: connection to DB, query and etc.
+ Does: binds to sensor table, use each sensor's calibration object to apply and return the transformed series
+
+calibration: Define calibration interface(Abstract)
+
+ Holds: what the calibration does and sensor input is coming from
+
+kebap_calibration: Evaluate Kebap calibration expression during runtime
+
+ Holds: Expression + it's evaluator, ktf source and the line for error sending
+ Does: parse expression and create evaluator when constructing, then use evaluator to transform values during runtime
+
+
+evaluator: runtime calculator for calibration expression
+
+ Holds: Compiled expression tree, reference to the global symbol table with all defined functions and constants
+ Does: evaluate expression using the referenced value and return result
+
+
+**Main Kebap engines (external)**
+
+KPParser: Compile Kebap scripts into executable
+
+ Holds: Global symbol table with all functions and constants, parsed module with variable definitions
+ Does: compiles script block and gives parser for expressions
+
+KPSymbolTable: Central namespace for all Kebap definitions
+
+ Holds all functions and variables, and maps names to value
+
+
+
+
+### 2.2 Core Extension Capabilities
+
+**The following are offered in the new release version 1.1.0**
+- **User-defined functions and Global Variables**:
+ Write calibration logic in Kebap(light embedded script) without recompiling
+ Including:
+ - Functions of any-type
+ - global variables
+
+- **Modular calibration design**:
+ Import calibration scripts across configs
+- **Dual data streams**:
+ Access both raw and calibrated data simultaneously.
+ Endpoints can be fetched as calibrated or raw in the same request.
+
+## 3. Usage Guide
+
+### 3.1 KTF Configuration Syntax
+
+#### 3.1.1 Unimported script
+
+All lines you wish to be recognized and extracted as calibration script **must start with #% and must come before the channel definitions**.
+
+ Here is a simple example:
+
+ #% float times5(float x) { return 5 * x; }
+
+ later a channel endpoint could call it
+
+**Practical Example**:
+
+ Assumptions:
+ - you are using a digital Pirani gauge model giving original indicated pressure (not accounting for specific type of gas in system)
+ - We have a gas system that has helium, but because our pirani may under or over report pressure without that awareness,
+ we will calibrate readout out before any further analytical steps
+
+Use this conversion graph for guidance on why our functions are the way they are for this example.
+
+
+
+This is what our function script section would look like above the channel definitions
+
+```
+**Script section**
+#% float torr_He (float torr) {
+#% double torr_He_val = 0.0;
+#% if (torr < 1){
+#% torr_He_val = torr * 1.1;
+#% } else if (torr < 10) {
+#% torr_He_val = torr **0.7;
+#% } else {
+#% torr_He_val = torr **0.33 + 5;
+#% }
+#% return torr_He_val;
+#% }
+#% float conversion_f = 1013.25 / 760; /* Global constant: used in mbar_He function below */
+#%
+#% float mbar_He (float mbar) { return torr_He(mbar / conversion_f) * conversion_f; } /* Function using global constant conversion_f */
+
+{This is a simplified channel structure starting at channel definition. Please reference README.md to see an example of how a full channel structure looks.}
+
+**Channel definition section**
+# Module:
+# id: { name: prg, label: Pirani gauge }
+# channel:
+# id: { name: torr, label: Vacuum pressure in Torr }
+# x-dripline_endpoint:
+# tag: pirani
+# channel:
+# id: { name: mbar, label: pressure in Mbar }
+# default_calibration: torr: torr * conversion_f
+# channel:
+# id: { name: mbarHe, label: Helium corrected pressure in Mbar }
+# default_calibration: mbar: mbar_He(mbar)
+
+```
+
+Channels and what they represent:
+
+ 1. torr: Initial gauge pressure held in our database (Torr)
+ 2. mbar: Initial pressure converted(Mbar)
+ 3. mbarHe, Helium corrected pressure (Mbar). **Notice** it is dependent on two previous chained calibrations.
+
+This shows:
+
+ 1. Utilizing User Function:
+
+ Channels can reference and call user-defined functions without compiling the function script. The function script is extracted and parsed into Kebap before any channel calls. So each function is mapped and prepared first and can then be used for calibration, similar to a function call in programming.
+ Notice the input parameter must be defined and pointed out before being used.
+
+ ```ex:
+ @channel 'mbarHe'
+ Notice ---> { **mbar**: mbar_He(**mbar**) }
+ ```
+
+
+ The channel id, which has a name, identifies the output (calibrated or not) of the channel it is dependent on.
+
+ - part of resolving and referencing dependencies in chain calling
+
+ 2. Chaining:
+ Using the result/output of a channel as calibration input for another
+ honeybee + Kebap: resolve the dependency of channels before runtime to make this happen
+
+ The example channels: **mbarHe** --(uses)-> **mbar** --(uses)-> **torr** (change)
+
+
+#### 3.1.2 Global constants/variables
+
+Global constants and variables are defined in the script section (all starting with #%) alongside function definitions. They can be used:
+- **Within function definitions** to reduce code repetition
+- **In channel calibrations** to reference common conversion factors or parameters
+- **Across multiple functions** for shared constants
+
+**Reference the example from 3.1.1 above:**
+
+Notice the `conversion_f` global constant defined as `#% float conversion_f = 1013.25 / 760;`. This value is then used in the `mbar_He()` function definition to convert between torr and mbar units. Later, in the channel definitions, the `mbar` channel uses this same constant:
+
+```
+# channel:
+# id: { name: mbar, label: pressure in Mbar }
+# default_calibration: torr: torr * conversion_f
+```
+
+#### 3.1.3 Comments
+
+You can comment on your calibration scripts using three comment styles:
+- `//` - single line, comment until end of line
+- `#!` - single line, comment until end of line
+- `/* multi-line */` - comment spanning multiple lines
+
+
+**In Unimported Scripts (with #%):**
+
+Comments in the script section must be prefixed with `#%`:
+
+```
+#% // Conversion function for helium-corrected pressure
+#% float torr_He (float torr) {
+#% /* Piecewise calibration factors */
+#% ...
+#% }
+#%
+#% float conversion_f = 1013.25 / 760; #! Torr to mbar conversion factor
+```
+
+**In Imported Scripts (without #%):**
+
+When using separate imported files (see 3.1.4), comments are written normally:
+
+```
+// Conversion function for helium-corrected pressure
+float torr_He (float torr) {
+ /* Piecewise calibration factors */
+ ...
+}
+
+float conversion_f = 1013.25 / 760; #! Torr to mbar conversion factor
+```
+
+The difference: unimported scripts require `#%` prefix for all comments that are on its own lines, while imported scripts use plain comments without the prefix.
+
+
+
+
+#### 3.1.4 Importing calibration scripts
+
+Instead of keeping all function definitions and global constants in the same file as channel definitions, you can organize them into separate calibration files and import them.
+
+**NOTES**
+- Imported files should have the suffix **".ktfs"**.
+
+- Includes are processed at parse time (during config load), not at runtime. Included functions will be immediately available to all subsequent calibration definitions.
+- The symbol used for function script lines (`#%`) **IS NOT** needed in an external file, but the import statement in the main file must start with `#%`.
+
+**(RECOMMENDED)**
+**Example - Extracting from 3.1.1:**
+
+**File 1: Functions.ktfs** (extracted calibration logic)
+```
+// No #% markers in imported files
+float torr_He (float torr) {
+ double torr_He_val = 0.0;
+ if (torr < 1){
+ torr_He_val = torr * 1.1;
+ } else if (torr < 10) {
+ torr_He_val = torr **0.7;
+ } else {
+ torr_He_val = torr **0.33 + 5;
+ }
+ return torr_He_val;
+}
+
+float conversion_f = 1013.25 / 760;
+
+float mbar_He (float mbar) { return torr_He(mbar / conversion_f) * conversion_f; }
+```
+
+**File 2: SensorTable.ktf** (main configuration with import)
+```
+#% import "/path/to/Functions.ktfs";
+```
+**Everything the same as usual**
+```
+# Module:
+# id: { name: prg, label: Pirani gauge }
+# channel:
+ .
+ .
+ .
+
+```
+
+**Dual data streams**:
+
+Honeybee allows users to fetch multiple types of data from sensor endpoints in a single request. In our current database design, we are able to pull raw and calibrated values from the database, simultaneously fetching from the `value_raw` and `value_cal` columns.
+
+**Honeybee has a system-level default for what column value to extract, `value_raw`, which users are able to override using the CLI.**
+
+Syntax: add `--value-column=...` when running in the CLI.
+
+ex: ./install/bin/hb-get-data gass sccm **--value-column=value_cal** --config=/Users/nobeltsegai/Documents/CENPA/project-8/first-Mesh-Honeybee/SensorTable.ktf --from="2025-08-21T08:04:00Z" --to="2025-08-21T08:08:00Z"
+
+**Users are able to individually define the column level for each specified endpoint in the ktf file.**
+
+Examples:
+Currently the system default is `value_raw`, which is raw values from the database. We will continue with this assumption for the examples below.
+
+In the example below, this endpoint is mapped to the system default since `field` is omitted.
+```
+# channel:
+# id: { name: torr, label: Vacuum pressure in Torr }
+# x-dripline_endpoint:
+# tag: pirani
+```
+
+Example of pulling raw value for pirani readout:
+Note: in this instance, since the system default is `value_raw`, this is not necessary.
+```
+# channel:
+# id: { name: torr, label: Vacuum pressure in Torr }
+# x-dripline_endpoint:
+# tag: pirani
+# field: value_raw
+```
+
+Example of retrieving calibrated values for the pirani readout:
+```
+# channel:
+# id: { name: torr, label: Vacuum pressure in Torr }
+# x-dripline_endpoint:
+# tag: pirani
+# field: value_cal
+```
+
+You could also have multiple channels from the same endpoint (e.g., pirani) but with different field values.
+
+**Honeybee's Column selection hierarchy**:
+The priority order is:
+Sensor-level explicit field (dripline_endpoint_field in KTF config)
+ Requested/overridden default column (--value-column=... from CLI)
+ Application fallback (current default behavior when no override is provided)
+
+
+### 3.2 Additional Notes:
+
+- User defined function and global variables can be used within the function script just like a regular programming language
+
+ --> function calling functions
+ --> Variables being called within function
+
+- Current Issues:
+
+ - (Kebap) Lack of (true) line number propagation when encountering a bug from imported code
+ In the case of an error from code in the imported file, users get only the relative file line number. This is where the buggy function or variable is being called in the main KTF file.
+ - Currently Kebap lacks the functionality to carry sourcefile metadata for imports
+ - Temporary solution: user can still use their search command to find function/variable
+
+Resolving bugs:
+
+Things to check when running into issue:
+
+- Please make sure your Docker compose file is set up properly
+ matching port, access and etc.
+
+- Getting nan value readout:
+ - check the error output and see if its a post data extraction error(calibration stage or ...)
+
+ - if there is no error output in command line, please make sure your time window for db query data is correct
+ To check, open up a session into your database and check
+ SELECT MIN(timestamp), MAX(timestamp) FROM {table_name};
+
+- Ensure your binary is up-to-date and not lagging behind an older version, and follow README instructions for proper build instructions.
\ No newline at end of file
diff --git a/docs/images/classDiagram.svg b/docs/images/classDiagram.svg
new file mode 100644
index 0000000..dbda9c9
--- /dev/null
+++ b/docs/images/classDiagram.svg
@@ -0,0 +1,102 @@
+
\ No newline at end of file
diff --git a/docs/images/refImage.png b/docs/images/refImage.png
new file mode 100644
index 0000000..fab1dad
Binary files /dev/null and b/docs/images/refImage.png differ
diff --git a/docs/images/sequenceDiagram.svg b/docs/images/sequenceDiagram.svg
new file mode 100644
index 0000000..e9947bc
--- /dev/null
+++ b/docs/images/sequenceDiagram.svg
@@ -0,0 +1,102 @@
+
\ No newline at end of file
diff --git a/src/Honeybee/Applications/hb-get-data.cxx b/src/Honeybee/Applications/hb-get-data.cxx
index fe4f8bf..82a5b9f 100644
--- a/src/Honeybee/Applications/hb-get-data.cxx
+++ b/src/Honeybee/Applications/hb-get-data.cxx
@@ -7,6 +7,7 @@
#include
#include
#include "honeybee.hh"
+#include "error_logger.hh"
namespace hb = honeybee;
@@ -31,7 +32,11 @@ int main(int argc, char** argv)
std::cerr << " --delimiter=VALUE set channel name delimiter"<< std::endl;
std::cerr << " --delimiter-input=VALUE set channel name delimiter in the data store"<< std::endl;
std::cerr << " --delimiter-output=VALUE set channel name delimiter for output"<< std::endl;
+ std::cerr << " --value-column=NAME default data column (value_raw/value_cal/etc)"<< std::endl;
std::cerr << " --verbose make it verbose"<< std::endl;
+ std::cerr << " --log-mode=MODE all|first|counted|summary"<< std::endl;
+ std::cerr << " --log-metadata enable metadata/stage logger output"<< std::endl;
+ std::cerr << " --no-log-metadata disable metadata/stage logger output"<< std::endl;
return -1;
}
@@ -45,6 +50,7 @@ int main(int argc, char** argv)
std::string t_delimiter = args["--delimiter"].Or("");
std::string t_delimiter_input = args["--delimiter-input"].Or(t_delimiter);
std::string t_delimiter_output = args["--delimiter-output"].Or(t_delimiter.substr(0,1));
+ std::string t_value_column = args["--value-column"].Or("");
double t_to_ts = args["--to-ts"].Or(long(hb::datetime::now()));
std::string t_to = args["--to"].Or(hb::datetime(t_to_ts).as_string());
@@ -86,6 +92,28 @@ int main(int argc, char** argv)
hb::g_log_level = hb::e_log_level_debug;
}
+ auto& t_logger = hb::error_logger::instance();
+ std::string t_log_mode = args["--log-mode"].Or("");
+ if (t_log_mode == "all") {
+ t_logger.set_message_mode(hb::error_logger::e_message_all);
+ }
+ else if (t_log_mode == "first") {
+ t_logger.set_message_mode(hb::error_logger::e_message_first_only);
+ }
+ else if (t_log_mode == "counted") {
+ t_logger.set_message_mode(hb::error_logger::e_message_first_with_count);
+ }
+ else if (t_log_mode == "summary") {
+ t_logger.set_message_mode(hb::error_logger::e_message_summary);
+ }
+
+ if (! args["--log-metadata"].IsVoid()) {
+ t_logger.set_metadata_enabled(true);
+ }
+ if (! args["--no-log-metadata"].IsVoid()) {
+ t_logger.set_metadata_enabled(false);
+ }
+
//// Fetch ////
@@ -93,6 +121,9 @@ int main(int argc, char** argv)
t_honeybee_app.add_config_file(t_config_file);
t_honeybee_app.add_dripline_db(t_dripline_db);
t_honeybee_app.set_delimiter(t_delimiter_input, t_delimiter_output);
+ if (! t_value_column.empty()) {
+ t_honeybee_app.set_value_column_default(t_value_column);
+ }
for (auto& variable: t_variables) {
t_honeybee_app.add_variable(variable.first, variable.second);
}
@@ -141,6 +172,8 @@ int main(int argc, char** argv)
}
std::cout << std::endl << "}" << std::endl;
+ t_logger.create_summary();
+
return 0;
}
@@ -201,6 +234,8 @@ int main(int argc, char** argv)
else if (t_series_bundle.size() == 1) {
std::cout << t_series_bundle[0].to_csv(t_series_bundle.keys()[0]);
}
+
+ t_logger.create_summary();
return 0;
}
diff --git a/src/Honeybee/Applications/hb-list-sensors.cxx b/src/Honeybee/Applications/hb-list-sensors.cxx
index 7a051f8..663b71f 100644
--- a/src/Honeybee/Applications/hb-list-sensors.cxx
+++ b/src/Honeybee/Applications/hb-list-sensors.cxx
@@ -3,9 +3,11 @@
#include
#include
+#include
#include
#include
#include "honeybee.hh"
+#include "error_logger.hh"
namespace hb = honeybee;
@@ -28,6 +30,9 @@ int main(int argc, char** argv)
std::cerr << " --delimiter-input=VALUE set channel name delimiter in the data store"<< std::endl;
std::cerr << " --delimiter-output=VALUE set channel name delimiter for output"<< std::endl;
std::cerr << " --verbose make it verbose"<< std::endl;
+ std::cerr << " --log-mode=MODE all|first|counted|summary"<< std::endl;
+ std::cerr << " --log-metadata enable metadata/stage logger output"<< std::endl;
+ std::cerr << " --no-log-metadata disable metadata/stage logger output"<< std::endl;
return -1;
}
@@ -68,6 +73,28 @@ int main(int argc, char** argv)
if (! args["--verbose"].IsVoid()) {
hb::g_log_level = hb::e_log_level_info;
}
+
+ auto& t_logger = hb::error_logger::instance();
+ std::string t_log_mode = args["--log-mode"].Or("");
+ if (t_log_mode == "all") {
+ t_logger.set_message_mode(hb::error_logger::e_message_all);
+ }
+ else if (t_log_mode == "first") {
+ t_logger.set_message_mode(hb::error_logger::e_message_first_only);
+ }
+ else if (t_log_mode == "counted") {
+ t_logger.set_message_mode(hb::error_logger::e_message_first_with_count);
+ }
+ else if (t_log_mode == "summary") {
+ t_logger.set_message_mode(hb::error_logger::e_message_summary);
+ }
+
+ if (! args["--log-metadata"].IsVoid()) {
+ t_logger.set_metadata_enabled(true);
+ }
+ if (! args["--no-log-metadata"].IsVoid()) {
+ t_logger.set_metadata_enabled(false);
+ }
//// Construction ////
@@ -104,5 +131,7 @@ int main(int argc, char** argv)
}
std::cout << std::endl << "]" << std::endl;
+ t_logger.create_summary();
+
return 0;
}
diff --git a/src/Honeybee/Source/CMakeLists.txt b/src/Honeybee/Source/CMakeLists.txt
index e58d124..0595cf9 100644
--- a/src/Honeybee/Source/CMakeLists.txt
+++ b/src/Honeybee/Source/CMakeLists.txt
@@ -4,9 +4,13 @@ add_library(HoneybeeLib STATIC
data_source.cc
pgsql.cc
sensor_table.cc
+ sensor_config.cc
+ sensor_config_by_ktf.cc
+ kebap_calibration.cc
series.cc
utils.cc
evaluator.cc
+ error_logger.cc
)
set(MyPublicHeaders
@@ -15,9 +19,13 @@ set(MyPublicHeaders
data_source.hh
pgsql.hh
sensor_table.hh
+ sensor_config.hh
+ sensor_config_by_ktf.hh
+ kebap_calibration.hh
series.hh
utils.hh
evaluator.hh
+ error_logger.hh
)
target_compile_features(HoneybeeLib PRIVATE cxx_std_14)
diff --git a/src/Honeybee/Source/calibration.cc b/src/Honeybee/Source/calibration.cc
index 6220311..69f32ea 100644
--- a/src/Honeybee/Source/calibration.cc
+++ b/src/Honeybee/Source/calibration.cc
@@ -7,91 +7,10 @@
#include
#include
-#include
-#include "sensor_table.hh"
-#include "evaluator.hh"
#include "calibration.hh"
-
using namespace std;
using namespace honeybee;
+// Abstract base class - implementations in subclass
-calibration::calibration(const sensor& a_sensor, const sensor_table& a_sensor_table)
-{
- auto strip = [](const string& a_text)->string {
- string::size_type t_begin = 0, t_length = a_text.size();
- while (t_begin < t_length) {
- if (a_text[t_begin] != ' ') {
- break;
- }
- t_begin++;
- }
- while (t_length > t_begin) {
- if (a_text[t_length-1] != ' ') {
- break;
- }
- t_length--;
- }
- return a_text.substr(t_begin, t_length);
- };
-
- f_description = strip(a_sensor.get_calibration());
- f_is_identity = false;
- f_input = sensor{}.get_number();
- f_evaluator = 0;
- if (f_description.empty()) {
- return;
- }
-
- auto colon = f_description.find_first_of(':');
- f_variable_name = strip(f_description.substr(0, colon));
- string t_exp_text;
- if (colon != string::npos) {
- t_exp_text = strip(f_description.substr(colon+1));
- }
-
- name_chain t_input_name_chain = a_sensor.get_name();
- name_chain t_variable_name_chain = name_chain(f_variable_name, "./-_");
- if (t_input_name_chain.size() < t_variable_name_chain.size()) {
- t_input_name_chain = t_variable_name_chain;
- }
- else {
- for (unsigned i = 0; i < t_variable_name_chain.size(); i++) {
- t_input_name_chain[i] = t_variable_name_chain[i];
- }
- }
- auto t_candidates = a_sensor_table.find_like(t_input_name_chain);
- if (t_candidates.size() == 1) {
- f_input = t_candidates.front();
- }
- else if (t_candidates.size() > 0) {
- cerr << "ERROR: ambiguous calibration input: " << f_variable_name << endl;
- return;
- }
- else {
- f_input = a_sensor_table[t_variable_name_chain];
- }
- if (! f_input) {
- cerr << "ERROR: unable to find calibration input: " << f_variable_name << endl;
- return;
- }
-
- if ((f_variable_name == t_exp_text) || t_exp_text.empty()) {
- f_is_identity = true;
- return;
- }
-
- // replace the variable in the expression with "x"
- string t_pattern = regex_replace(f_variable_name, regex("\\."), "\\.");
- t_exp_text = regex_replace(t_exp_text, regex("(^|[^a-zA-Z_])(" + t_pattern + ")($|[^a-zA-Z0-9_])"), "$1x$3");
-
- f_evaluator = make_shared(t_exp_text);
- try {
- f_evaluator->operator()(0);
- }
- catch (std::exception &e) {
- cerr << "ERROR: bad calibration expression: " << e.what() << endl;
- f_evaluator = 0;
- }
-}
diff --git a/src/Honeybee/Source/calibration.hh b/src/Honeybee/Source/calibration.hh
index 7eb6ce4..7ab6cf2 100644
--- a/src/Honeybee/Source/calibration.hh
+++ b/src/Honeybee/Source/calibration.hh
@@ -11,33 +11,30 @@
#include
#include
#include "series.hh"
-#include "sensor_table.hh"
-#include "evaluator.hh"
namespace honeybee {
using namespace std;
+
+ class sensor;
+ class sensor_table;
class calibration {
public:
- calibration(): f_is_identity(false) {}
- calibration(const sensor& a_sensor, const sensor_table& a_sensor_table);
+ calibration() : f_input(0), f_is_identity(false) {}
+ virtual ~calibration() = default;
+
int get_input_sensor() const { return f_input; }
string get_description() const { return f_description; }
- double operator()(double x) const {
- if (f_is_identity) {
- return x;
- }
- if (! f_evaluator) {
- return std::numeric_limits::quiet_NaN();
- }
- return (*f_evaluator)(x);
- }
+
+ virtual double operator()(double x) = 0;
+ virtual string get_error_context() const = 0;
+
protected:
- string f_description, f_variable_name;
+ string f_description;
+ string f_variable_name;
int f_input;
bool f_is_identity;
- shared_ptr f_evaluator;
};
}
diff --git a/src/Honeybee/Source/data_source.cc b/src/Honeybee/Source/data_source.cc
index 49531c2..7986c01 100644
--- a/src/Honeybee/Source/data_source.cc
+++ b/src/Honeybee/Source/data_source.cc
@@ -9,9 +9,12 @@
#include
#include