From a03a6977447e4d66a0067f8f391d2f546adf585d Mon Sep 17 00:00:00 2001 From: Tom Clark Date: Sun, 10 Mar 2024 16:32:26 +0530 Subject: [PATCH 1/5] STY: Formatted with prettier --- power-curve-schema/schema.json | 131 +++++++++++++++++++-------------- 1 file changed, 75 insertions(+), 56 deletions(-) diff --git a/power-curve-schema/schema.json b/power-curve-schema/schema.json index 7940835..da655d3 100644 --- a/power-curve-schema/schema.json +++ b/power-curve-schema/schema.json @@ -247,7 +247,8 @@ "description": "The allowable design grid frequencies in Hz", "type": "array", "items": { - "type": "number", "exclusiveMinimum": 0 + "type": "number", + "exclusiveMinimum": 0 }, "examples": [[50], [50, 60]] } @@ -259,7 +260,13 @@ "type": "array", "items": { "type": "object", - "required": ["label", "name", "design_class", "turbulence", "standard_climate"], + "required": [ + "label", + "name", + "design_class", + "turbulence", + "standard_climate" + ], "properties": { "label": { "type": "string", @@ -279,11 +286,15 @@ "examples": ["Basis 1", "Basis 2", "Site XYZ Specific"] }, "certification": { - "type":"object", + "type": "object", "title": "Certification details", "description": "Information about the scheme under which this design basis was certified. This is not a required property, so if a turbine is as-yet uncertified, simply leave it out.", - "$comment": "We collect these three under a single 'certification' property as a convenitent way to require that either all or none are given", - "required": ["standard", "standard_edition","certificate_reference"], + "$comment": "We collect these three under a single 'certification' property as a convenient way to require that either all or none are given", + "required": [ + "standard", + "standard_edition", + "certificate_reference" + ], "examples": [ { "certificate_reference": "IECRE.WE.TC.20.0099-R6", @@ -295,13 +306,28 @@ "standard": { "$comment": "Note - use of anyOf allows specification of any string value, but adding an enum indicates the precise values to be selected should your value be in the prescribed list", "description": "The certification scheme under which the power curves were certified.", - "anyOf": [{"title": "Choose predefined scheme","enum": ["IEC", "DiBT"] },{ "title": "Specify other scheme", "type": "string" }] + "anyOf": [ + { + "title": "Choose predefined scheme", + "enum": ["IEC", "DiBT"] + }, + { "title": "Specify other scheme", "type": "string" } + ] }, "standard_edition": { "$comment": "Note - use of anyOf allows specification of any string value, but adding an enum indicates the precise values to be selected should your value be in the prescribed list", "description": "The edition of the standard used in turbine certification", "type": "string", - "anyOf": [{ "title": "Choose predefined standard edition","enum": ["2", "3", "4"] }, { "title": "Specify other standard edition", "type": "string" }] + "anyOf": [ + { + "title": "Choose predefined standard edition", + "enum": ["2", "3", "4"] + }, + { + "title": "Specify other standard edition", + "type": "string" + } + ] }, "certificate_reference": { "type": "string", @@ -320,7 +346,7 @@ "description": "A fully or partially predefined environmental class, (eg IEC or other scheme)", "type": "object", "oneOf": [ - { + { "title": "Standard IEC design class", "type": "object", "required": ["class_label"], @@ -328,11 +354,11 @@ "class_label": { "description": "Select from predefined IEC design classes I, II, and III.", "enum": ["I", "II", "III"] - } + } }, "$comment": "S (T, CC to be confirmed) is a custom class, use other objects, what should we do for class IV turbines? Are they custom?" }, - { + { "title": "Special or custom design class", "type": "object", "required": ["class_label"], @@ -341,7 +367,7 @@ "title": "Label", "description": "Specify IEC classes S, T, CC or an entirely custom design class", "enum": ["S", "T", "CC", "Custom"] - }, + }, "annual_average_wind_speed": { "type": "number", "title": "Annual average wind speed 'Vave'", @@ -397,7 +423,7 @@ } } ], - "examples": [0, 2, {"min":-2, "max": 2}] + "examples": [0, 2, { "min": -2, "max": 2 }] }, "design_lifetime": { "$comment": "Schema team - check if this also needs to be given for T, CC classes as well as S class", @@ -415,7 +441,7 @@ "title": "Turbulence category or distribution", "description": "Specify the IEC turbulence category or one of several custom distributions.", "anyOf": [ - { + { "title": "Standard IEC Turbulence Category", "type": "object", "$comment": "This is defined as a single-property object rather than a direct string because it's more explicit to include the category keyword (and allows for later adoption of other predefined profiles requiring more sophistication than a string)", @@ -423,8 +449,8 @@ "properties": { "category": { "title": "Category", - "description": "Specify a predefined IEC turbulence category", - "enum": ["A+", "A", "B", "C"] + "description": "Specify a predefined IEC turbulence category", + "enum": ["A+", "A", "B", "C"] } } }, @@ -436,7 +462,7 @@ "properties": { "category": { "title": "Category", - "description": "Specify the turbulence category to be custom", + "description": "Specify the turbulence category to be custom", "enum": ["Custom"] }, "reference_turbulence_intensity": { @@ -458,12 +484,17 @@ "title": "Normal and Extreme Turbulence Models varying with Wind Speed", "type": "object", "description": "Specify Normal and Extreme Turbulence Models (NTM, ETM) using turbulence intensity as a function of wind speed", - "required": ["category", "wind_speed", "normal_turbulence_intensity", "extreme_turbulence_intensity"], + "required": [ + "category", + "wind_speed", + "normal_turbulence_intensity", + "extreme_turbulence_intensity" + ], "properties": { "category": { "title": "Category", - "description": "Specify the turbulence category as custom", - "enum": ["Custom"] + "description": "Specify the turbulence category as custom", + "enum": ["Custom"] }, "wind_speed": { "type": "array", @@ -501,11 +532,17 @@ "title": "Normal and Extreme Turbulence Models varying with Wind Speed and Lifetime Hours", "type": "object", "description": "Specify Normal Turbulence Model as a function of wind speed and lifetime hours, and Extreme Turbulence Models (NTM, ETM) as a function of wind speed.", - "required": ["category", "wind_speed", "normal_turbulence_intensity", "normal_hours_per_lifetime", "extreme_turbulence_intensity"], + "required": [ + "category", + "wind_speed", + "normal_turbulence_intensity", + "normal_hours_per_lifetime", + "extreme_turbulence_intensity" + ], "properties": { "category": { - "description": "Set the turbulence category to custom", - "enum": ["Custom"] + "description": "Set the turbulence category to custom", + "enum": ["Custom"] }, "wind_speed": { "type": "array", @@ -554,7 +591,7 @@ } ], "examples": [ - { + { "category": "A" }, { @@ -578,7 +615,7 @@ ], "normal_hours_per_lifetime": [ [1633.89, 2145.8, 1551.13, 1434.6, 1321.1], - [804.2, 956.3, 756.3, 645.6,543.7], + [804.2, 956.3, 756.3, 645.6, 543.7], [30.5, 60.4, 43.8, 38.5, 27.6] ], "extreme_turbulence_intensity": [0.92, 0.6, 0.15] @@ -591,7 +628,7 @@ "properties": { "operating_temperature_range": { "type": "array", - "items" : { + "items": { "type": "number", "minimum": -273.15, "maximum": 1000 @@ -599,7 +636,7 @@ }, "survival_temperature_range": { "type": "array", - "items" : { + "items": { "type": "number", "minimum": -273.15, "maximum": 1000 @@ -620,7 +657,7 @@ "properties": { "operating_temperature_range": { "type": "array", - "items" : { + "items": { "type": "number", "minimum": -273.15, "maximum": 1000 @@ -628,7 +665,7 @@ }, "survival_temperature_range": { "type": "array", - "items" : { + "items": { "type": "number", "minimum": -273.15, "maximum": 1000 @@ -649,7 +686,7 @@ "properties": { "operating_temperature_range": { "type": "array", - "items" : { + "items": { "type": "number", "minimum": -273.15, "maximum": 1000 @@ -657,7 +694,7 @@ }, "survival_temperature_range": { "type": "array", - "items" : { + "items": { "type": "number", "minimum": -273.15, "maximum": 1000 @@ -781,11 +818,7 @@ "additionalItems": true, "items": { "type": "object", - "required": [ - "label", - "dimension", - "values" - ], + "required": ["label", "dimension", "values"], "properties": { "label": { "type": "string", @@ -828,9 +861,7 @@ "description": "Values of air density [kg/m^3] for which this power curve is tabulated" } }, - "required": [ - "values" - ] + "required": ["values"] } }, { @@ -853,9 +884,7 @@ "description": "Values of free-stream wind speed [m/s] at hub height for which this power curve is tabulated" } }, - "required": [ - "values" - ] + "required": ["values"] } }, { @@ -880,9 +909,7 @@ "description": "Values of turbulence intensity I [-] (expressed as a factor in the range 0,1 rather than a percentage) for which this power curve is tabulated" } }, - "required": [ - "values" - ] + "required": ["values"] } }, { @@ -905,9 +932,7 @@ "description": "Values of turbulence integral lengthscale l [m] for which this power curve is tabulated" } }, - "required": [ - "values" - ] + "required": ["values"] } }, { @@ -930,9 +955,7 @@ "description": "Values of the the Monin-Obukhov stability parameter zeta [-] for which this power curve is tabulated. Values of zero indicate neutral conditions, vegative condi" } }, - "required": [ - "values" - ] + "required": ["values"] } }, { @@ -955,9 +978,7 @@ "description": "Values of wind shear coefficient alpha [-] for which this power curve is tabulated" } }, - "required": [ - "values" - ] + "required": ["values"] } }, { @@ -980,9 +1001,7 @@ "description": "Values of wind direction [???? degrees clockwise from true north????] for which this power curve is tabulated" } }, - "required": [ - "values" - ] + "required": ["values"] } } ] From 772c4200fa94dab7da916c64b4c692ad8277ffb5 Mon Sep 17 00:00:00 2001 From: Tom Clark Date: Sun, 10 Mar 2024 17:38:33 +0530 Subject: [PATCH 2/5] DOC: Update and clarify comments --- power-curve-schema/schema.json | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/power-curve-schema/schema.json b/power-curve-schema/schema.json index da655d3..366ee02 100644 --- a/power-curve-schema/schema.json +++ b/power-curve-schema/schema.json @@ -304,7 +304,7 @@ ], "properties": { "standard": { - "$comment": "Note - use of anyOf allows specification of any string value, but adding an enum indicates the precise values to be selected should your value be in the prescribed list", + "$comment": "The use of anyOf allows specification of any string value, whilst adding an enum to indicate the precise values to be selected should your value be in the prescribed list of common items.", "description": "The certification scheme under which the power curves were certified.", "anyOf": [ { @@ -315,7 +315,7 @@ ] }, "standard_edition": { - "$comment": "Note - use of anyOf allows specification of any string value, but adding an enum indicates the precise values to be selected should your value be in the prescribed list", + "$comment": "The use of anyOf allows specification of any string value, whilst adding an enum to indicate the precise values to be selected should your value be in the prescribed list of common items.", "description": "The edition of the standard used in turbine certification", "type": "string", "anyOf": [ @@ -356,7 +356,7 @@ "enum": ["I", "II", "III"] } }, - "$comment": "S (T, CC to be confirmed) is a custom class, use other objects, what should we do for class IV turbines? Are they custom?" + "$comment": "TODO Schema team - what should we do for class IV turbines? Are they custom?" }, { "title": "Special or custom design class", @@ -653,7 +653,7 @@ "cold_climate": { "type": "object", "description": "Define operating and survival temperatures in cold climates", - "$comment": "Can we define why this is different in cold climates?", + "$comment": "TODO Schema team - Can we define why this is different in cold climates than it is in standard climates?", "properties": { "operating_temperature_range": { "type": "array", @@ -681,8 +681,8 @@ }, "hot_climate": { "type": "object", - "description": "Define operating and survival temperatures in cold climates", - "$comment": "Can we define why this is different in cold climates?", + "description": "Define operating and survival temperatures in hot climates", + "$comment": "TODO Schema team - Can we define why this is different in hot climates than it is in standard climates?", "properties": { "operating_temperature_range": { "type": "array", From f0719bfafad682bbb5a69fce80c129ef2a4749fb Mon Sep 17 00:00:00 2001 From: Tom Clark Date: Sun, 10 Mar 2024 17:41:35 +0530 Subject: [PATCH 3/5] DOC: Add comment on purpose of metadata subproperty --- power-curve-schema/schema.json | 1 + 1 file changed, 1 insertion(+) diff --git a/power-curve-schema/schema.json b/power-curve-schema/schema.json index 366ee02..e5eb77e 100644 --- a/power-curve-schema/schema.json +++ b/power-curve-schema/schema.json @@ -64,6 +64,7 @@ "title": "Document", "description": "Information about this document", "required": ["metadata"], + "$comment": "We've added metadata into a property of `document` to facilitate addition of more prescriptive or specific (ie non dublin-core) properties in the future", "properties": { "metadata": { "title": "Dublin-Core Metadata", From ea75c3a7c05b6eed7aef0ea6e8114d1458993918 Mon Sep 17 00:00:00 2001 From: Tom Clark Date: Sun, 10 Mar 2024 17:45:45 +0530 Subject: [PATCH 4/5] REF: Remove unused 1darray definition --- power-curve-schema/schema.json | 7 ------- 1 file changed, 7 deletions(-) diff --git a/power-curve-schema/schema.json b/power-curve-schema/schema.json index e5eb77e..81c77de 100644 --- a/power-curve-schema/schema.json +++ b/power-curve-schema/schema.json @@ -4,13 +4,6 @@ "title": "Turbine Power Curves", "description": "Define a set of power curves for a wind turbine.", "definitions": { - "1darray": { - "type": "array", - "items": { - "type": "number" - }, - "additionalItems": true - }, "2darray": { "type": "array", "items": { From d6ddd4beb4ef64187e33e26bf538b92f7e394923 Mon Sep 17 00:00:00 2001 From: Tom Clark Date: Mon, 11 Mar 2024 16:45:08 +0530 Subject: [PATCH 5/5] FEA: Add overrides, labeling improvements and improve docs --- docs/generate_terms.py | 19 ++ docs/terms.rst | 197 ++++++++++++------ .../examples/generic-117-3.json | 9 +- .../examples/generic-274-20.json | 152 +++++++------- power-curve-schema/schema.json | 182 ++++++++++------ test/conftest.py | 61 ++++-- test/test_power_curves.py | 166 ++++++++++++++- 7 files changed, 562 insertions(+), 224 deletions(-) diff --git a/docs/generate_terms.py b/docs/generate_terms.py index efd9e89..213bc82 100644 --- a/docs/generate_terms.py +++ b/docs/generate_terms.py @@ -59,6 +59,25 @@ "properties.design_bases.items.properties.hot_climate", "properties.design_bases.items.properties.hot_climate.properties.operating_temperature_range", "properties.design_bases.items.properties.hot_climate.properties.survival_temperature_range", + "properties.power_curves.properties.default_mode", + "properties.power_curves.properties.modes", + "properties.power_curves.properties.modes.items.properties.label", + "properties.power_curves.properties.modes.items.properties.name", + "properties.power_curves.properties.modes.items.properties.design_bases", + "properties.power_curves.properties.modes.items.properties.description", + "properties.power_curves.properties.modes.items.properties.cuts", + "properties.power_curves.properties.modes.items.properties.cuts.items.properties.kind", + "properties.power_curves.properties.modes.items.properties.cuts.items.properties.wind_speed", + "properties.power_curves.properties.modes.items.properties.cuts.items.properties.period", + "properties.power_curves.properties.modes.items.properties.parameters", + "properties.power_curves.properties.modes.items.properties.parameters.items.properties.label", + "properties.power_curves.properties.modes.items.properties.parameters.items.properties.dimension", + # TODO FIXME "properties.power_curves.properties.modes.items.properties.parameters.items.properties.values", + "properties.power_curves.properties.modes.items.properties.cp_is_coefficient", + "properties.power_curves.properties.modes.items.properties.ct_is_coefficient", + "properties.power_curves.properties.modes.items.properties.cp", + "properties.power_curves.properties.modes.items.properties.ct", + "properties.power_curves.properties.modes.items.properties.overrides", ] diff --git a/docs/terms.rst b/docs/terms.rst index ed9a821..a5ae147 100644 --- a/docs/terms.rst +++ b/docs/terms.rst @@ -109,69 +109,15 @@ The regulation type of the turbine. turbine.rated_power ~~~~~~~~~~~~~~~~~~~ -Nominal rated power of the turbine in W. Used for preliminary sizing and -search. This value may be overridden on a per-mode basis. - -Examples: - -.. code-block:: js - - 5000000 - turbine.cut_in_rpm ~~~~~~~~~~~~~~~~~~ -Nominal rotational speed at cut-in (specify 0 for stall-regulated -devices) [RPM]. This value may be overriden on a per-mode basis. - -Examples: - -.. code-block:: js - - 2 - turbine.available_hub_heights ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -Specify either a discrete list or a continuous range of available hub -heights [m]. This value may be overriden on a per-mode basis. - -Examples: - -.. code-block:: js - - { - "min": 120, - "max": 180 - } - -.. code-block:: js - - [ - 120, - 180 - ] - turbine.grid_frequencies ~~~~~~~~~~~~~~~~~~~~~~~~ -The allowable design grid frequencies in Hz - -Examples: - -.. code-block:: js - - [ - 50 - ] - -.. code-block:: js - - [ - 50, - 60 - ] - design_bases ------------ @@ -593,14 +539,16 @@ Model arrays. Wind speed range must cover the entire operating range design_bases.turbulence[3].normal_turbulence_intensity ++++++++++++++++++++++++++++++++++++++++++++++++++++++ -2d array containing normal value of I for each wind speed and hours bin, -specified as a fraction (eg 0.13) +2d array containing normal value of I for each wind speed (row) and +probability interval (column), specified as a fraction (eg 0.13). +Probability intervals represent evenly spaced bins covering the domain +[0,1]. design_bases.turbulence[3].normal_hours_per_lifetime ++++++++++++++++++++++++++++++++++++++++++++++++++++ -2d array containing the number of hours spent for each entry, -through-life, in the normal_turbulence_intensity array +2d array containing the number of hours spent, through-life, for each +wind speed (row) and probability interval (column) [h] design_bases.turbulence[3].extreme_turbulence_intensity +++++++++++++++++++++++++++++++++++++++++++++++++++++++ @@ -663,7 +611,7 @@ design_bases.cold_climate.survival_temperature_range design_bases.hot_climate ~~~~~~~~~~~~~~~~~~~~~~~~ -Define operating and survival temperatures in cold climates +Define operating and survival temperatures in hot climates Examples: @@ -686,3 +634,134 @@ design_bases.hot_climate.operating_temperature_range design_bases.hot_climate.survival_temperature_range +++++++++++++++++++++++++++++++++++++++++++++++++++ +power_curves.default_mode +~~~~~~~~~~~~~~~~~~~~~~~~~ + +The label of the mode that should be used by default (must match an +entry in 'modes') + +power_curves.modes +~~~~~~~~~~~~~~~~~~ + +Different modes that the turbine can operate in / switch between + +power_curves.modes.label +++++++++++++++++++++++++ + +A string key identifying the mode, e.g. `power_optimised_1` + +power_curves.modes.name ++++++++++++++++++++++++ + + A human-readable name for the mode, e.g. `Power Optimised 1 (PO1)` + +power_curves.modes.design_bases ++++++++++++++++++++++++++++++++ + +A list of the design basis labels relevant to this power curve + +power_curves.modes.description +++++++++++++++++++++++++++++++ + +Short human readable text describing the purpose of this mode, which +will be rendered into dropdowns and made searchable. + +Examples: + +.. code-block:: js + + "For general purpose operation in standard climates, or early stage site design" + +.. code-block:: js + + "For use in noise-reduced situations eg close to population areas or sites of special scientific interest" + +power_curves.modes.cuts ++++++++++++++++++++++++ + +A list of the cut in and out conditions relevant to this power curve + + +Select the kind of cut in characteristic to apply + + +The wind speed at which the cut in/out will apply [m/s] + + +The number of seconds that the reference wind speed is met to apply the +cut in/out action [s] + +power_curves.modes.parameters ++++++++++++++++++++++++++++++ + +Independent parameters for which the power curve is described + + +A slugified string key used to identify the parameter (e.g. +air-density). + + +Dimension of the power curve array along which this parameter varies +(0-based) + +power_curves.modes.cp_is_coefficient +++++++++++++++++++++++++++++++++++++ + +True if the `cp` array is in nondimensional coefficient form, False if +the `cp` array contains Power [W]. + +power_curves.modes.ct_is_coefficient +++++++++++++++++++++++++++++++++++++ + +True if the `ct` array is in nondimensional coefficient form, False if +the `ct` array contains Thrust [kgms^-2]. + +power_curves.modes.cp ++++++++++++++++++++++ + +The coefficient of power, defined as an N-D array at the sample points +described in 'Parameters' + +power_curves.modes.ct ++++++++++++++++++++++ + +The coefficient of thrust, defined as an N-D array at the sample points +described in 'Parameters' + +power_curves.modes.overrides +++++++++++++++++++++++++++++ + +Allows override of certain data in the `turbine` section, where that +data conflicts with requirements of a mode. For example, some operating +modes may reduce rated power, or require a more restrictive range of hub +heights for structural reasons + +Examples: + +.. code-block:: js + + { + "rated_power": 20000000.0 + } + +.. code-block:: js + + { + "available_hub_heights": [ + 100, + 120 + ] + } + +.. code-block:: js + + { + "cut_in_rpm": 2.1 + } + +.. code-block:: js + + { + "rated_rpm": 11.8 + } + diff --git a/power-curve-schema/examples/generic-117-3.json b/power-curve-schema/examples/generic-117-3.json index 1b8dac3..aaa5c65 100644 --- a/power-curve-schema/examples/generic-117-3.json +++ b/power-curve-schema/examples/generic-117-3.json @@ -100,13 +100,13 @@ { "label": "basis_3", "name": "Basis 3 - Custom turbulence definition", - "certification":{ + "certification": { "certificate_reference": "IECRE.WE.TC.20.0099-R6", "standard": "IEC", "standard_edition": "2" }, "design_class": { - "class_label":"II" + "class_label": "II" }, "design_lifetime": 20, "standard_climate": { @@ -131,7 +131,7 @@ ], "normal_hours_per_lifetime": [ [1633.89, 2145.8, 1551.13, 1434.6, 1321.1], - [804.2, 956.3, 756.3, 645.6,543.7], + [804.2, 956.3, 756.3, 645.6, 543.7], [30.5, 60.4, 43.8, 38.5, 27.6] ], "extreme_turbulence_intensity": [0.92, 0.6, 0.15] @@ -218,7 +218,8 @@ 0.115, 0.107, 0.098, 0.091, 0.085, 0.079, 0.074, 0.07, 0.066, 0.062, 0.058, 0.055, 0.052, 0.049, 0.046 ] - ] + ], + "overrides": {} } ] } diff --git a/power-curve-schema/examples/generic-274-20.json b/power-curve-schema/examples/generic-274-20.json index e8bde6c..fe6900e 100644 --- a/power-curve-schema/examples/generic-274-20.json +++ b/power-curve-schema/examples/generic-274-20.json @@ -26,7 +26,7 @@ "rated_rpm": 6, "cut_in_rpm": 1, "rotor_diameter": 274.0, - "available_hub_heights": [143], + "available_hub_heights": [140, 145, 150], "drive_type": "geared", "regulation_type": "pitch", "grid_frequencies": [50, 60] @@ -303,12 +303,13 @@ 0.071, 0.066, 0.062, 0.059, 0.055, 0.052, 0.046, 0.038, 0.032, 0.029, 0.027, 0.025, 0.024, 0.023, 0.021, 0.02, 0.019, 0.018 ] - ] + ], + "overrides": {} }, { "label": "mode_2", - "name": "Mode 2 (Max flow, close spacing)", - "description": "Applicable for sites with approximately 4 to 6 rotor diameters spacing", + "name": "Mode 2 (Derated low-noise)", + "description": "Applicable for sites where noise signature is priority", "design_bases": ["basis_1"], "rated_power": 20000000, "cuts": [ @@ -368,25 +369,25 @@ 64000.0, 290666.667, 612000.0, 1030666.67, 1560000.0, 2182666.67, 2924000.0, 3789333.33, 4813333.33, 5981333.33, 7309333.33, 8801333.33, 10457333.3, 12204000.0, 14121333.3, 16304000.0, - 18304000.0, 19516000.0, 19926666.700000003, 19993333.299999997, - 20000000.0, 20000000.0, 20000000.0, 20000000.0, 20000000.0, - 20000000.0, 20000000.0, 20000000.0, 20000000.0, 20000000.0, - 20000000.0, 20000000.0, 20000000.0, 20000000.0, 20000000.0, - 20000000.0, 20000000.0, 20000000.0, 20000000.0, 20000000.0, - 20000000.0, 19940000.0, 19340000.0, 17600000.0, 15476000.0, - 14133333.3, 13540000.0, 13406666.7, 13350666.7, 13185333.3, - 12926666.7, 12677333.3, 12516000.0, 12432000.0, 12402666.7 + 18000000.0, 18000000.0, 18000000.0, 18000000.0, 18000000.0, + 18000000.0, 18000000.0, 18000000.0, 18000000.0, 18000000.0, + 18000000.0, 18000000.0, 18000000.0, 18000000.0, 18000000.0, + 18000000.0, 18000000.0, 18000000.0, 18000000.0, 18000000.0, + 18000000.0, 18000000.0, 18000000.0, 18000000.0, 18000000.0, + 18000000.0, 18000000.0, 17600000.0, 15476000.0, 14133333.3, + 13540000.0, 13406666.7, 13350666.7, 13185333.3, 12926666.7, + 12677333.3, 12516000.0, 12432000.0, 12402666.7 ], [ 68000.0, 301333.333, 629333.333, 1060000.0, 1600000.0, 2237333.33, 2994666.67, 3881333.33, 4928000.0, 6122666.67, 7478666.67, 9000000.0, 10688000.0, 12469333.3, 14421333.3, 16597333.299999999, - 18536000.0, 19628000.0, 19950666.700000003, 19996000.0, 20000000.0, - 20000000.0, 20000000.0, 20000000.0, 20000000.0, 20000000.0, - 20000000.0, 20000000.0, 20000000.0, 20000000.0, 20000000.0, - 20000000.0, 20000000.0, 20000000.0, 20000000.0, 20000000.0, - 20000000.0, 20000000.0, 20000000.0, 20000000.0, 20000000.0, - 19952000.0, 19432000.0, 17752000.0, 15592000.0, 14178666.7, + 18000000.0, 18000000.0, 18000000.0, 18000000.0, 18000000.0, + 18000000.0, 18000000.0, 18000000.0, 18000000.0, 18000000.0, + 18000000.0, 18000000.0, 18000000.0, 18000000.0, 18000000.0, + 18000000.0, 18000000.0, 18000000.0, 18000000.0, 18000000.0, + 18000000.0, 18000000.0, 18000000.0, 18000000.0, 18000000.0, + 18000000.0, 18000000.0, 17752000.0, 15592000.0, 14178666.7, 13552000.0, 13409333.3, 13354666.7, 13190666.7, 12937333.3, 12684000.0, 12520000.0, 12434666.7, 12404000.0 ], @@ -394,84 +395,79 @@ 72000.0, 310666.667, 648000.0, 1088000.0, 1640000.0, 2293333.33, 3066666.67, 3973333.33, 5042666.67, 6262666.67, 7646666.67, 9200000.0, 10918666.7, 12733333.3, 14720000.0, 16882666.700000003, - 18769333.299999997, 19740000.0, 19976000.0, 19997333.299999997, - 20000000.0, 20000000.0, 20000000.0, 20000000.0, 20000000.0, - 20000000.0, 20000000.0, 20000000.0, 20000000.0, 20000000.0, - 20000000.0, 20000000.0, 20000000.0, 20000000.0, 20000000.0, - 20000000.0, 20000000.0, 20000000.0, 20000000.0, 20000000.0, - 20000000.0, 19964000.0, 19524000.0, 17904000.0, 15709333.3, - 14224000.0, 13564000.0, 13410666.7, 13357333.3, 13197333.3, - 12946666.7, 12690666.7, 12522666.7, 12436000.0, 12404000.0 + 18000000.0, 18000000.0, 18000000.0, 18000000.0, 18000000.0, + 18000000.0, 18000000.0, 18000000.0, 18000000.0, 18000000.0, + 18000000.0, 18000000.0, 18000000.0, 18000000.0, 18000000.0, + 18000000.0, 18000000.0, 18000000.0, 18000000.0, 18000000.0, + 18000000.0, 18000000.0, 18000000.0, 18000000.0, 18000000.0, + 18000000.0, 18000000.0, 17904000.0, 15709333.3, 14224000.0, + 13564000.0, 13410666.7, 13357333.3, 13197333.3, 12946666.7, + 12690666.7, 12522666.7, 12436000.0, 12404000.0 ], [ 76000.0, 321333.333, 665333.333, 1116000.0, 1681333.3299999998, 2348000.0, 3138666.67, 4065333.33, 5157333.33, 6401333.33, 7814666.67, 9397333.33, 11149333.3, 12994666.7, 15013333.3, - 17165333.299999997, 18970666.700000003, 19797333.299999997, - 19982666.700000003, 19998666.700000003, 20000000.0, 20000000.0, - 20000000.0, 20000000.0, 20000000.0, 20000000.0, 20000000.0, - 20000000.0, 20000000.0, 20000000.0, 20000000.0, 20000000.0, - 20000000.0, 20000000.0, 20000000.0, 20000000.0, 20000000.0, - 20000000.0, 20000000.0, 20000000.0, 20000000.0, 19970666.700000003, - 19590666.700000003, 18054666.700000003, 15830666.7, 14270666.7, - 13576000.0, 13412000.0, 13360000.0, 13202666.7, 12954666.7, - 12696000.0, 12526666.7, 12437333.3, 12404000.0 + 17165333.299999997, 18000000.0, 18000000.0, 18000000.0, 18000000.0, + 18000000.0, 18000000.0, 18000000.0, 18000000.0, 18000000.0, + 18000000.0, 18000000.0, 18000000.0, 18000000.0, 18000000.0, + 18000000.0, 18000000.0, 18000000.0, 18000000.0, 18000000.0, + 18000000.0, 18000000.0, 18000000.0, 18000000.0, 18000000.0, + 18000000.0, 18000000.0, 18000000.0, 18000000.0, 15830666.7, + 14270666.7, 13576000.0, 13412000.0, 13360000.0, 13202666.7, + 12954666.7, 12696000.0, 12526666.7, 12437333.3, 12404000.0 ], [ 80000.0, 332000.0, 684000.0, 1144000.0, 1721333.3299999998, 2402666.67, 3210666.67, 4157333.3300000005, 5270666.67, 6540000.0, 7981333.33, 9596000.0, 11378666.7, 13256000.0, 15308000.0, - 17442666.700000003, 19162666.700000003, 19854666.700000003, - 19989333.299999997, 19998666.700000003, 20000000.0, 20000000.0, - 20000000.0, 20000000.0, 20000000.0, 20000000.0, 20000000.0, - 20000000.0, 20000000.0, 20000000.0, 20000000.0, 20000000.0, - 20000000.0, 20000000.0, 20000000.0, 20000000.0, 20000000.0, - 20000000.0, 20000000.0, 20000000.0, 20000000.0, 19977333.299999997, - 19657333.299999997, 18204000.0, 15952000.0, 14317333.3, 13586666.7, - 13412000.0, 13362666.7, 13209333.3, 12961333.3, 12702666.7, - 12529333.3, 12438666.7, 12405333.3 + 17442666.700000003, 18000000.0, 18000000.0, 18000000.0, 18000000.0, + 18000000.0, 18000000.0, 18000000.0, 18000000.0, 18000000.0, + 18000000.0, 18000000.0, 18000000.0, 18000000.0, 18000000.0, + 18000000.0, 18000000.0, 18000000.0, 18000000.0, 18000000.0, + 18000000.0, 18000000.0, 18000000.0, 18000000.0, 18000000.0, + 18000000.0, 18000000.0, 18000000.0, 18000000.0, 15952000.0, + 14317333.3, 13586666.7, 13412000.0, 13362666.7, 13209333.3, + 12961333.3, 12702666.7, 12529333.3, 12438666.7, 12405333.3 ], [ 84000.0, 342666.667, 702666.667, 1172000.0, 1761333.3299999998, 2457333.33, 3281333.33, 4249333.33, 5385333.33, 6680000.0, 8149333.33, 9793333.33, 11608000.0, 13517333.3, 15601333.3, - 17718666.700000003, 19320000.0, 19910666.700000003, 19996000.0, - 20000000.0, 20000000.0, 20000000.0, 20000000.0, 20000000.0, - 20000000.0, 20000000.0, 20000000.0, 20000000.0, 20000000.0, - 20000000.0, 20000000.0, 20000000.0, 20000000.0, 20000000.0, - 20000000.0, 20000000.0, 20000000.0, 20000000.0, 20000000.0, - 20000000.0, 20000000.0, 19984000.0, 19724000.0, 18353333.299999997, - 16073333.3, 14364000.0, 13597333.3, 13413333.3, 13365333.3, - 13216000.0, 12969333.3, 12709333.3, 12533333.3, 12441333.3, - 12405333.3 + 17718666.700000003, 18000000.0, 18000000.0, 18000000.0, 18000000.0, + 18000000.0, 18000000.0, 18000000.0, 18000000.0, 18000000.0, + 18000000.0, 18000000.0, 18000000.0, 18000000.0, 18000000.0, + 18000000.0, 18000000.0, 18000000.0, 18000000.0, 18000000.0, + 18000000.0, 18000000.0, 18000000.0, 18000000.0, 18000000.0, + 18000000.0, 18000000.0, 18000000.0, 18000000.0, 16073333.3, + 14364000.0, 13597333.3, 13413333.3, 13365333.3, 13216000.0, + 12969333.3, 12709333.3, 12533333.3, 12441333.3, 12405333.3 ], [ 88000.0, 353333.333, 720000.0, 1200000.0, 1801333.3299999998, 2512000.0, 3353333.33, 4341333.33, 5500000.0, 6818666.67, 8316000.0, 9989333.33, 11834666.7, 13777333.3, 15861333.3, 17994666.700000003, - 19426666.700000003, 19934666.700000003, 19997333.299999997, - 20000000.0, 20000000.0, 20000000.0, 20000000.0, 20000000.0, - 20000000.0, 20000000.0, 20000000.0, 20000000.0, 20000000.0, - 20000000.0, 20000000.0, 20000000.0, 20000000.0, 20000000.0, - 20000000.0, 20000000.0, 20000000.0, 20000000.0, 20000000.0, - 20000000.0, 20000000.0, 19989333.299999997, 19770666.700000003, - 18498666.700000003, 16196000.0, 14412000.0, 13616000.0, 13416000.0, - 13368000.0, 13220000.0, 12977333.3, 12714666.7, 12537333.3, - 12442666.7, 12405333.3 + 18000000.0, 18000000.0, 18000000.0, 18000000.0, 18000000.0, + 18000000.0, 18000000.0, 18000000.0, 18000000.0, 18000000.0, + 18000000.0, 18000000.0, 18000000.0, 18000000.0, 18000000.0, + 18000000.0, 18000000.0, 18000000.0, 18000000.0, 18000000.0, + 18000000.0, 18000000.0, 18000000.0, 18000000.0, 18000000.0, + 18000000.0, 18000000.0, 18000000.0, 16196000.0, 14412000.0, + 13616000.0, 13416000.0, 13368000.0, 13220000.0, 12977333.3, + 12714666.7, 12537333.3, 12442666.7, 12405333.3 ], [ 92000.0, 364000.0, 738666.667, 1228000.0, 1842666.6700000002, 2568000.0, 3425333.33, 4432000.0, 5614666.67, 6957333.33, 8482666.67, 10185333.3, 12061333.3, 14037333.3, 16122666.7, - 18270666.700000003, 19533333.299999997, 19957333.299999997, - 19997333.299999997, 20000000.0, 20000000.0, 20000000.0, 20000000.0, - 20000000.0, 20000000.0, 20000000.0, 20000000.0, 20000000.0, - 20000000.0, 20000000.0, 20000000.0, 20000000.0, 20000000.0, - 20000000.0, 20000000.0, 20000000.0, 20000000.0, 20000000.0, - 20000000.0, 20000000.0, 20000000.0, 19993333.299999997, - 19817333.299999997, 18644000.0, 16317333.3, 14460000.0, 13636000.0, - 13417333.3, 13370666.7, 13225333.3, 12986666.7, 12718666.7, - 12541333.3, 12445333.3, 12406666.7 + 18000000.0, 18000000.0, 18000000.0, 18000000.0, 18000000.0, + 18000000.0, 18000000.0, 18000000.0, 18000000.0, 18000000.0, + 18000000.0, 18000000.0, 18000000.0, 18000000.0, 18000000.0, + 18000000.0, 18000000.0, 18000000.0, 18000000.0, 18000000.0, + 18000000.0, 18000000.0, 18000000.0, 18000000.0, 18000000.0, + 18000000.0, 18000000.0, 18000000.0, 18000000.0, 16317333.3, + 14460000.0, 13636000.0, 13417333.3, 13370666.7, 13225333.3, + 12986666.7, 12718666.7, 12541333.3, 12445333.3, 12406666.7 ] ], "ct": [ @@ -539,12 +535,15 @@ 0.066, 0.062, 0.059, 0.055, 0.052, 0.046, 0.038, 0.032, 0.029, 0.027, 0.025, 0.024, 0.023, 0.021, 0.02, 0.019, 0.018 ] - ] + ], + "overrides": { + "rated_power": 18000000 + } }, { "label": "mode_3", - "name": "Mode 3 (Max flow, wide spacing)", - "description": "Applicable for sites with approximately 6 to 10 rotor diameter spacing", + "name": "Mode 3 (High tower)", + "description": "A mode demonstrating exclusion of certain hub heights (eg for structural reasons)", "design_bases": ["basis_1"], "rated_power": 20000000, "cuts": [ @@ -779,7 +778,10 @@ 0.071, 0.066, 0.062, 0.059, 0.055, 0.052, 0.046, 0.038, 0.032, 0.029, 0.027, 0.025, 0.024, 0.023, 0.021, 0.02, 0.019, 0.018 ] - ] + ], + "overrides": { + "available_hub_heights": [140, 150] + } } ] } diff --git a/power-curve-schema/schema.json b/power-curve-schema/schema.json index 81c77de..0edca4d 100644 --- a/power-curve-schema/schema.json +++ b/power-curve-schema/schema.json @@ -48,6 +48,75 @@ "additionalItems": true }, "additionalItems": true + }, + "rated_power": { + "type": "number", + "title": "Rated power [W]", + "description": "Nominal rated power of the turbine in W. Used for preliminary sizing and search. This value may be overridden on a per-mode basis.", + "minimum": 0, + "examples": [5000000] + }, + "cut_in_rpm": { + "type": "number", + "title": "Rotational speed at cut-in [RPM]", + "description": "Nominal rotational speed at cut-in (specify 0 for stall-regulated devices) [RPM]. This value may be overriden on a per-mode basis.", + "minimum": 0, + "examples": [2] + }, + "rated_rpm": { + "type": "number", + "title": "Rotational speed at rated power [RPM]", + "description": "Nominal rotational speed at rated power (or at peak power for stall-regulated devices) [RPM]. This value may be overriden on a per-mode basis.", + "minimum": 0, + "examples": [12] + }, + "available_hub_heights": { + "title": "Available hub heights", + "description": "Specify either a discrete list or a continuous range of available hub heights [m]. This value may be overriden on a per-mode basis.", + "anyOf": [ + { + "title": "Specify a range of available hub heights [m]", + "type": "object", + "description": "Specify a range of available hub heights [m]", + "properties": { + "min": { + "type": "number", + "description": "Minium hub height [m]" + }, + "max": { + "type": "number", + "description": "Maximum hub height [m]" + } + }, + "required": ["min"] + }, + { + "title": "Specify a list of discrete available hub heights [m]", + "type": "array", + "description": "Specify a list of discrete available hub heights [m]", + "items": { + "type": "number", + "exclusiveMinimum": 0 + } + } + ], + "examples": [ + { + "min": 120, + "max": 180 + }, + [120, 180] + ] + }, + "grid_frequencies": { + "title": "Grid frequencies [Hz]", + "description": "The allowable design grid frequencies in Hz", + "type": "array", + "items": { + "type": "number", + "exclusiveMinimum": 0 + }, + "examples": [[50], [50, 60]] } }, "required": ["document", "turbine", "design_bases", "power_curves"], @@ -182,69 +251,19 @@ "enum": ["pitch", "stall", "other"] }, "rated_power": { - "type": "number", - "title": "Rated power [W]", - "description": "Nominal rated power of the turbine in W. Used for preliminary sizing and search. This value may be overridden on a per-mode basis.", - "examples": [5000000] + "$ref": "#/definitions/rated_power" }, "cut_in_rpm": { - "type": "number", - "title": "Rotational speed at cut-in [RPM]", - "description": "Nominal rotational speed at cut-in (specify 0 for stall-regulated devices) [RPM]. This value may be overriden on a per-mode basis.", - "examples": [2] + "$ref": "#/definitions/cut_in_rpm" }, "rated_rpm": { - "type": "number", - "title": "Rotational speed at rated power [RPM]", - "description": "Nominal rotational speed at rated power (or at peak power for stall-regulated devices) [RPM]. This value may be overriden on a per-mode basis.", - "examples": [12] + "$ref": "#/definitions/rated_rpm" }, "available_hub_heights": { - "title": "Available hub heights", - "description": "Specify either a discrete list or a continuous range of available hub heights [m]. This value may be overriden on a per-mode basis.", - "anyOf": [ - { - "title": "Specify a range of available hub heights [m]", - "type": "object", - "description": "Specify a range of available hub heights [m]", - "properties": { - "min": { - "type": "number", - "description": "Minium hub height [m]" - }, - "max": { - "type": "number", - "description": "Maximum hub height [m]" - } - }, - "required": ["min"] - }, - { - "title": "Specify a list of discrete available hub heights [m]", - "type": "array", - "description": "Specify a list of discrete available hub heights [m]", - "items": { - "type": "number" - } - } - ], - "examples": [ - { - "min": 120, - "max": 180 - }, - [120, 180] - ] + "$ref": "#/definitions/available_hub_heights" }, "grid_frequencies": { - "title": "Grid frequencies [Hz]", - "description": "The allowable design grid frequencies in Hz", - "type": "array", - "items": { - "type": "number", - "exclusiveMinimum": 0 - }, - "examples": [[50], [50, 60]] + "$ref": "#/definitions/grid_frequencies" } } }, @@ -715,6 +734,7 @@ "type": "string", "title": "Default mode", "description": "The label of the mode that should be used by default (must match an entry in 'modes')", + "pattern": "^[a-z0-9_]{1,40}$", "minLength": 1, "maxLength": 40 }, @@ -735,20 +755,21 @@ "cp_is_coefficient", "ct_is_coefficient", "cp", - "ct" + "ct", + "overrides" ], "properties": { "label": { "type": "string", "title": "Mode label", - "description": " A string key identifying the mode, e.g. `power_optimised_1`", + "description": "A string key identifying the mode, e.g. `power_optimised_1`", "pattern": "^[a-z0-9_]{1,40}$", "minLength": 1, "maxLength": 40 }, "name": { "type": "string", - "title": "Mode label", + "title": "Mode name", "description": " A human-readable name for the mode, e.g. `Power Optimised 1 (PO1)`", "minLength": 1, "maxLength": 40 @@ -765,12 +786,11 @@ "description": { "type": "string", "title": "Mode description", - "description": "Short human readable text which will be rendered into dropdowns and made searchable." - }, - "rated_power": { - "type": "number", - "title": "Mode rated power (W)", - "description": "Rated power of the turbine in this mode [W]" + "description": "Short human readable text describing the purpose of this mode, which will be rendered into dropdowns and made searchable.", + "examples": [ + "For general purpose operation in standard climates, or early stage site design", + "For use in noise-reduced situations eg close to population areas or sites of special scientific interest" + ] }, "cuts": { "title": "Cut in and cut out conditions", @@ -1052,6 +1072,40 @@ "$ref": "#/definitions/4darray" } ] + }, + "overrides": { + "title": "Mode-Specific Overrides", + "description": "Allows override of certain data in the `turbine` section, where that data conflicts with requirements of a mode. For example, some operating modes may reduce rated power, or require a more restrictive range of hub heights for structural reasons", + "type": "object", + "required": [], + "examples": [ + { + "rated_power": 20e6 + }, + { + "available_hub_heights": [100, 120] + }, + { + "cut_in_rpm": 2.1 + }, + { + "rated_rpm": 11.8 + } + ], + "properties": { + "rated_power": { + "$ref": "#/definitions/rated_power" + }, + "cut_in_rpm": { + "$ref": "#/definitions/cut_in_rpm" + }, + "rated_rpm": { + "$ref": "#/definitions/rated_rpm" + }, + "available_hub_heights": { + "$ref": "#/definitions/available_hub_heights" + } + } } } } diff --git a/test/conftest.py b/test/conftest.py index 548b9c2..5cf305c 100644 --- a/test/conftest.py +++ b/test/conftest.py @@ -8,8 +8,8 @@ import copy import json import os -import pytest +import pytest ROOT_DIR = os.path.dirname(os.path.dirname(__file__)) @@ -45,25 +45,49 @@ def generic_document_metadata(): } +@pytest.fixture +def valid_cuts(): + return [ + { + "kind": "low_cut_in", + "wind_speed": 3, + "period": 600 + }, + { + "kind": "low_cut_out", + "wind_speed": 2.5, + "period": 600 + }, + { + "kind": "high_cut_out", + "wind_speed": 25, + "period": 600 + }, + { + "kind": "high_cut_in", + "wind_speed": 23, + "period": 600 + } + ] + @pytest.fixture() -def one_dimensional_mode(): +def one_dimensional_mode(valid_cuts): return { - "label": "one-dimensional", + "label": "one_dimensional", + "name": "One Dimensional", + "design_bases": ['basis-1'], "description": "A typical mode where there are values for only the reference air density. In practicality this is the same as a two-dimensional example, just with a single air density value.", - "cut": { - "type": "in_out_re", - "value": [3, 25, 23] - }, + "cuts": valid_cuts, "parameters": [ { "label": "air-density", "dimension": 0, - "points": [1.225] + "values": [1.225] }, { "label": "wind-speed", "dimension": 1, - "points": [ + "values": [ 3.0, 3.5, 4.0, 4.5, 5.0, 5.5, 6.0, 6.5, 7.0, 7.5, 8.0, 8.5, 9.0,9.5, 10.0, 10.5, 11.0, 11.5, 12.0, 12.5, 13.0, 13.5, 14.0, 14.5,15.0, 15.5, 16.0, 16.5, 17.0, 17.5, 18.0, 18.5, 19.0, 19.5, 20.0,20.5, 21.0, 21.5, 22.0, 22.5, 23.0, 23.5, 24.0, 24.5, 25.0 ] } @@ -75,33 +99,34 @@ def one_dimensional_mode(): ], "ct": [ [0.873, 0.849, 0.834, 0.828, 0.827, 0.825, 0.82, 0.816, 0.805, 0.804, 0.794, 0.79, 0.789, 0.772, 0.733, 0.666, 0.58, 0.494, 0.421, 0.362, 0.316, 0.281, 0.249, 0.223, 0.199, 0.18, 0.164, 0.149, 0.137, 0.125, 0.115, 0.107, 0.098, 0.091, 0.085, 0.079, 0.074, 0.07, 0.066, 0.062, 0.058, 0.055, 0.052, 0.049, 0.046] - ] + ], + "overrides": {} } @pytest.fixture() -def two_dimensional_mode(): +def two_dimensional_mode(valid_cuts): return { - "label": "two-dimensional", + "label": "two_dimensional", + "name": "Two Dimensional", "description": "A typical mode where both air density and wind speed vary", - "cut": { - "type": "in_out_re", - "value": [3, 30, 30] - }, + "design_bases": ['basis-1'], + "cuts": valid_cuts, "parameters": [ { "label": "air-density", "dimension": 0, - "points": [1.1, 1.125, 1.15, 1.175, 1.2, 1.225, 1.25, 1.275] + "values": [1.1, 1.125, 1.15, 1.175, 1.2, 1.225, 1.25, 1.275] }, { "label": "wind-speed", "dimension": 1, - "points": [3.0, 3.5, 4.0, 4.5, 5.0, 5.5, 6.0, 6.5, 7.0, 7.5, 8.0, 8.5, 9.0, 9.5, 10.0, 10.5, 11.0, 11.5, 12.0, 12.5, 13.0, 13.5, 14.0, 14.5, 15.0, 15.5, 16.0, 16.5, 17.0, 17.5, 18.0, 18.5, 19.0, 19.5, 20.0, 20.5, 21.0, 21.5, 22.0, 22.5, 23.0, 23.5, 24.0, 24.5, 25.0, 25.5, 26.0, 26.5, 27.0, 27.5, 28.0, 28.5, 29.0, 29.5, 30.0] + "values": [3.0, 3.5, 4.0, 4.5, 5.0, 5.5, 6.0, 6.5, 7.0, 7.5, 8.0, 8.5, 9.0, 9.5, 10.0, 10.5, 11.0, 11.5, 12.0, 12.5, 13.0, 13.5, 14.0, 14.5, 15.0, 15.5, 16.0, 16.5, 17.0, 17.5, 18.0, 18.5, 19.0, 19.5, 20.0, 20.5, 21.0, 21.5, 22.0, 22.5, 23.0, 23.5, 24.0, 24.5, 25.0, 25.5, 26.0, 26.5, 27.0, 27.5, 28.0, 28.5, 29.0, 29.5, 30.0] } ], "cp_is_coefficient": False, "ct_is_coefficient": True, + "overrides": {}, "cp": [ [ 76000.0, 310666.667, 641333.333, 1073333.3299999998, diff --git a/test/test_power_curves.py b/test/test_power_curves.py index d8f2e78..66fa529 100644 --- a/test/test_power_curves.py +++ b/test/test_power_curves.py @@ -1,9 +1,12 @@ # Turn off pylint warnings unavoidable with pytest # pylint: disable=redefined-outer-name, line-too-long, redefined-builtin, missing-module-docstring +from copy import deepcopy + +import pytest from jsonschema import validate from jsonschema.exceptions import ValidationError -import pytest + from .helpers import get_subschema @@ -23,15 +26,23 @@ def test_missing_power_curves(subschema): def test_missing_default_mode(subschema, one_dimensional_mode): """Validation should fail if there is no default_mode value""" with pytest.raises(ValidationError) as e: - validate(instance={"power_curves": {"modes": [one_dimensional_mode]}}, schema=subschema) + validate( + instance={"power_curves": {"modes": [one_dimensional_mode]}}, + schema=subschema, + ) assert "'default_mode' is a required property" in str(e) def test_blank_default_mode(subschema, one_dimensional_mode): """Validation should fail if default_mode is blank""" with pytest.raises(ValidationError) as e: - validate(instance={"power_curves": {"default_mode": "", "modes": [one_dimensional_mode]}}, schema=subschema) - assert "is too short" in str(e) + validate( + instance={ + "power_curves": {"default_mode": "", "modes": [one_dimensional_mode]} + }, + schema=subschema, + ) + assert "does not match" in str(e) def test_missing_modes(subschema): @@ -50,3 +61,150 @@ def test_invalid_modes(subschema): ) assert "is not of type 'array'" in str(e) + + +def test_one_dimensional_mode(subschema, one_dimensional_mode): + """Validation should fail if there is no overrides section in a mode""" + + validate( + instance={ + "power_curves": { + "default_mode": "one_dimensional", + "modes": [one_dimensional_mode], + } + }, + schema=subschema, + ) + + +def test_two_dimensional_mode(subschema, two_dimensional_mode): + """Validation should fail if there is no overrides section in a mode""" + + validate( + instance={ + "power_curves": { + "default_mode": "two_dimensional", + "modes": [two_dimensional_mode], + } + }, + schema=subschema, + ) + + +def test_missing_mode_properties(subschema, one_dimensional_mode): + """Validation should fail if there is no overrides section in a mode""" + + for required in [ + "overrides", + "cuts", + "parameters", + "cp", + "ct", + "cp_is_coefficient", + "ct_is_coefficient", + ]: + partial = deepcopy(one_dimensional_mode) + partial.pop(required) + with pytest.raises(ValidationError) as e: + validate( + instance={ + "power_curves": { + "default_mode": "one_dimensional", + "modes": [partial], + } + }, + schema=subschema, + ) + assert f"'{required}' is a required property" in str(e) + + +def test_invalid_cuts(subschema, one_dimensional_mode): + """Validation should fail if cut kind, speed or period is invalid""" + + invalid = [ + ( + { + "kind": "not_a_cut", + "wind_speed": 25, + "period": 600, + }, + "is not one of", + ), + ( + { + "kind": "low_cut_in", + "wind_speed": "not a speed", + "period": 600, + }, + "is not of type 'number'", + ), + ( + { + "kind": "low_cut_in", + "wind_speed": 20, + "period": "not a period", + }, + "is not of type 'number'", + ), + ] + + for cut, reason in invalid: + one_dimensional_mode["cuts"][0] = cut + + with pytest.raises(ValidationError) as e: + validate( + instance={ + "power_curves": { + "default_mode": "one_dimensional", + "modes": [one_dimensional_mode], + } + }, + schema=subschema, + ) + + assert reason in str(e) + + +def test_invalid_overrides(subschema, one_dimensional_mode): + """Validation should fail if overrides are invalid""" + + invalid = [ + ( + {"rated_power": -10}, + "is less than", + ), + ( + { + "available_hub_heights": "not an array or hub heights dict", + }, + "is not valid under any of the given schemas", + ), + ( + { + "rated_rpm": "not an rpm value", + }, + "is not of type 'number'", + ), + ( + { + "cut_in_rpm": "not an rpm value", + }, + "is not of type 'number'", + ), + ] + + for overrides, reason in invalid: + one_dimensional_mode["overrides"] = overrides + + with pytest.raises(ValidationError) as e: + validate( + instance={ + "power_curves": { + "default_mode": "one_dimensional", + "modes": [one_dimensional_mode], + } + }, + schema=subschema, + ) + + assert reason in str(e)