--- title: "Calculation Models" slug: "calculation-models" updated: 2025-07-16T14:07:50Z published: 2025-07-16T14:07:50Z canonical: "docs.bazefield.com/calculation-models" --- > ## Documentation Index > Fetch the complete documentation index at: https://docs.bazefield.com/llms.txt > Use this file to discover all available pages before exploring further. # Calculation Models ## Overview **Calculation Models** in Bazefield are used to perform **complex interval calculations** within the **Bazefield Calculation Service**. They allow users to define reusable logic using templates and functions, enabling scalable and maintainable KPI generation across assets. --- ## How Calculation Models Work - **Common Functions**: The same **C# expression syntax** of standard Interval Calculations is available within Calculation Models - **Script-Based Logic**: Built using a [**Handlebars**](https://handlebarsjs.com/guide/)**-based script template** and one or more **function lists**. - **Interval Execution**: Operate like Interval Calculated Points, running at scheduled intervals. - **Reusable Components**: Functions can be shared across models and dynamically compiled per asset. --- ## Key Components ### ℹ️ Script Template Defines the variables used in the model using placeholders like: ```csharp string objectKey = "{{domainObject.objectKey}}"; ``` These are resolved at compile time based on asset metadata. ### ℹ️ Function Lists Reusable code blocks that can be imported into the script. For example: ```csharp if (TagCount([@WindSpeed]) > 0)    windSpeedValue = TagTimeAvg([@WindSpeed]); ``` ### ℹ️ Metadata Access Models can reference any asset and site attributes using Handlebars syntax like: - `{{domainObject.ratedPower}}` (retrieve the ratedPower of the current object context) - `{{parent.objectKey}}` (retrieve the key of the current object’s parent object) --- ## Configuration Workflow 1. **Create Model**: Define Acronym, Name, Model Type, applicable Object Type, and Script Template. 2. **Add Lookup Functions**: Import reusable logic blocks defined outside of the Calculation Model. 3. **Reference in Points**: Use `ScriptType = Interval_Calculation` and `Expression = $$CalculationModel$$`. Set `CalcModelRef` to the acronym of the calculation model. 4. **Compile**: Load the Point(s) into the Calculation Service to automatically resolve placeholders and assemble the final script. ![](https://cdn.document360.io/a0786c0f-b171-4b24-8860-c32eb7ef2738/Images/Documentation/image(229).png?sv=2026-02-06&spr=https&st=2026-11-06T20%3A55%3A49Z&se=2026-11-06T21%3A55%3A49Z&sr=c&sp=r&sig=pqwCIIvmTArGYoI65spnyRiEr%2B9N143lXRxCyetNT%2BM%3D) --- ## Example Use Case ### Turbine Theoretical Power Curve Lookup Calculation Model - Uses Nacelle wind speed reading to estimate expected energy based on user-uploaded reference power curve. - If Turbine Nacelle sensor reading is unavailable, falls back to alternative wind speed readings**:** neighbor turbine(s), Met Mast, or daily/weekly/annual average. - Compiled per asset using metadata like object keys, reference turbines, and site Annual Average Wind Speed (AAWS). ### Script Template *Defines the templatized logic for the Calculation Model* ```csharp //Theoretical Power based on best available WindSpeed and PC Lookup string objectKey = "{{domainObject.objectKey}}"; string parentObjectKey = "{{parent.objectKey}}"; double? theoreticalPower = null; double? windSpeedValue = null; double? annualAverageWindSpeed =null; string PMMWindSpeed = ""; {{#if parent.AAWS}} annualAverageWindSpeed = Double.Parse(ObjectMetadata.GetAttribute(parentObjectKey, "AAWS")); {{/if}} {{#if domainObject.referencePMM}} string PMMObjectKey = ObjectMetadata.GetAttribute(objectKey, "referencePMM"); PMMWindSpeed = PMMObjectKey + "-WindSpeed"; {{/if}} {{#each importedFunctions.lookupFunctions.Functions}} if (windSpeedValue == null) {   {{this.codeBlock}} } {{/each}} if (windSpeedValue != null) {   var refCurve = RefCurves.GetRefCurve(objectKey, "Contractual", "Default");   if (refCurve == null) refCurve = RefCurves.GetRefCurve(objectKey, null, "EnergyModel");   if (refCurve == null) refCurve = RefCurves.GetRefCurve(parentObjectKey, null, "EnergyModel");   theoreticalPower = RefCurves.LinearLookup(refCurve, windSpeedValue.Value); } return theoreticalPower; ``` ### Lookup Functions *Imported functions that will be used in the compiled Calculation Model* During runtime, the Lookup Functions will be evaluated in the order they are defined on the Calculation Model. They are generally used to “lookup” a value for a script variable in order of preference—such as for WindSpeed when you have multiple sensors like nacelle anemometer, neighboring turbine(s), and primary met mast. #### AssetWindSpeed Option 1: Retrieve the object’s WindSpeed reading. (Most desirable.) ```csharp if (TagCount([@WindSpeed]) > 0) windSpeedValue = TagTimeAvg([@WindSpeed]); ``` #### NeighborsAvgWindSpeed Option 2: Retrieve average WindSpeed reading from neighboring turbines. ```csharp var refObjectIds = JsvStringArrayToArray(ObjectMetadata.GetAttribute(objectKey, "referenceTurbines")); int count = 1; foreach(string refObjectId in refObjectIds) {   var refObjectKey = ObjectMetadata.GetAttribute(refObjectId, "objectKey");   if (TagCount(refObjectKey + "-WindSpeed") > 0) {      if (windSpeedValue != null) {         count = count+1;         windSpeedValue = windSpeedValue + TagTimeAvg(refObjectKey + "-WindSpeed");      }      if (windSpeedValue == null) windSpeedValue = TagTimeAvg(refObjectKey + "-WindSpeed");   } } if (windSpeedValue != null) windSpeedValue = windSpeedValue/count; ``` #### PMMWindSpeed Option 3: Retrieve the Primary Met Mast (PMM) WindSpeed reading. ```csharp if(PMMWindSpeed.Length > 0) if(TagCount(PMMWindSpeed) > 0) windSpeedValue = TagTimeAvg(PMMWindSpeed); ``` #### AssetWindSpeed1d Option 4: Calculate the Turbine’s 1 day average WindSpeed value. ```csharp if(TagAggregate(objectKey + "-WindSpeed", "COUNT", IntervalEnd().AddHours(-24), IntervalEnd()) > 0) windSpeedValue = TagAggregate(objectKey + "-WindSpeed", "AVERAGE", IntervalEnd().AddHours(-24), IntervalEnd()); ``` #### AssetWindSpeed7d Option 5: Calculate the Turbine’s 7 day average WindSpeed value. ```csharp if(TagAggregate(objectKey + "-WindSpeed", "COUNT", IntervalEnd().AddHours(-168), IntervalEnd()) > 0) windSpeedValue = TagAggregate(objectKey + "-WindSpeed", "AVERAGE", IntervalEnd().AddHours(-168), IntervalEnd()); ``` #### AssetWindSpeedAAWS Option 6: Retrieve the site Average Annual WindSpeed attribute. (Least desirable.) ```csharp windSpeedValue = annualAverageWindSpeed; ``` ### Compiled Calculation Model All Handlebars expressions and helpers are resolved. This means that the objectKey for the asset and site is resolved and that all the lookupFunctions are inserted. ```csharp //Theoretical Power based on best available WindSpeed and PC Lookup string objectKey = "WP1-T001"; string parentObjectKey = "WP1"; double? theoreticalPower = null; double? windSpeedValue = null; double? annualAverageWindSpeed =null; string PMMWindSpeed = ""; annualAverageWindSpeed = Double.Parse(ObjectMetadata.GetAttribute(parentObjectKey, "AAWS")); string PMMObjectKey = ObjectMetadata.GetAttribute(objectKey, "referencePMM"); PMMWindSpeed = PMMObjectKey + "-WindSpeed"; if (windSpeedValue == null) {   if (TagCount([@WindSpeed]) > 0) windSpeedValue = TagTimeAvg([@WindSpeed]); } if (windSpeedValue == null) {   if (TagCount([@WindSpeed]) > 0) windSpeedValue = TagTimeAvg([@WindSpeed]);   var refObjectIds = JsvStringArrayToArray(ObjectMetadata.GetAttribute(objectKey, "referenceTurbines"));   int count = 1;   foreach(string refObjectId in refObjectIds) {      var refObjectKey = ObjectMetadata.GetAttribute(refObjectId, "objectKey");      if (TagCount(refObjectKey + "-WindSpeed") > 0) {         if (windSpeedValue != null) {            count = count+1;            windSpeedValue = windSpeedValue + TagTimeAvg(refObjectKey + "-WindSpeed");         }         if (windSpeedValue == null) windSpeedValue = TagTimeAvg(refObjectKey + "-WindSpeed");      }   }   if (windSpeedValue != null) windSpeedValue = windSpeedValue/count; } if (windSpeedValue == null) {   if(PMMWindSpeed.Length > 0) if(TagCount(PMMWindSpeed) > 0) windSpeedValue = TagTimeAvg(PMMWindSpeed); } if (windSpeedValue == null) {   if(TagAggregate(objectKey + "-WindSpeed", "COUNT", IntervalEnd().AddHours(-24), IntervalEnd()) > 0) windSpeedValue = TagAggregate(objectKey + "-WindSpeed", "AVERAGE", IntervalEnd().AddHours(-24), IntervalEnd()); } if (windSpeedValue == null) {   if(TagAggregate(objectKey + "-WindSpeed", "COUNT", IntervalEnd().AddHours(-168), IntervalEnd()) > 0) windSpeedValue = TagAggregate(objectKey + "-WindSpeed", "AVERAGE", IntervalEnd().AddHours(-168), IntervalEnd()); } if (windSpeedValue == null) {   windSpeedValue = annualAverageWindSpeed; } if (windSpeedValue != null) {   var refCurve = RefCurves.GetRefCurve(objectKey, "Contractual", "Default");   if (refCurve == null) refCurve = RefCurves.GetRefCurve(objectKey, null, "EnergyModel");   if (refCurve == null) refCurve = RefCurves.GetRefCurve(parentObjectKey, null, "EnergyModel");   theoreticalPower = RefCurves.LinearLookup(refCurve, windSpeedValue.Value); } return theoreticalPower; ``` --- ## Why Calculation Models Matter ✔️ **Advanced Logic**: Go beyond one-line expressions with full scripting. ✔️ **Reusability**: Centralize and reuse logic across assets and projects. ✔️ **Scalability**: Dynamically compile per asset using metadata. ✔️ **Maintainability**: Update logic in one place and apply it fleet-wide.